Use better initial geometry for new windows.

This commit is contained in:
John Preston 2023-02-02 20:19:32 +04:00
parent 933f1944c7
commit 0495cf4187
4 changed files with 119 additions and 73 deletions

View File

@ -91,6 +91,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/connection_box.h"
#include "boxes/premium_limits_box.h"
#include "ui/boxes/confirm_box.h"
#include "styles/style_window.h"
#include <QtCore/QStandardPaths>
#include <QtCore/QMimeDatabase>
@ -185,7 +186,7 @@ Application::~Application() {
}
setLastActiveWindow(nullptr);
_lastActivePrimaryWindow = nullptr;
_windowInSettings = _lastActivePrimaryWindow = nullptr;
_closingAsyncWindows.clear();
_secondaryWindows.clear();
_primaryWindows.clear();
@ -289,7 +290,7 @@ void Application::run() {
_primaryWindows.emplace(nullptr, std::make_unique<Window::Controller>());
setLastActiveWindow(_primaryWindows.front().second.get());
_lastActivePrimaryWindow = _lastActiveWindow;
_windowInSettings = _lastActivePrimaryWindow = _lastActiveWindow;
_domain->activeChanges(
) | rpl::start_with_next([=](not_null<Main::Account*> account) {
@ -1162,6 +1163,11 @@ void Application::localPasscodeChanged() {
checkAutoLock(crl::now());
}
bool Application::savingPositionFor(
not_null<Window::Controller*> window) const {
return !_windowInSettings || (_windowInSettings == window);
}
bool Application::hasActiveWindow(not_null<Main::Session*> session) const {
if (Quitting() || !_lastActiveWindow) {
return false;
@ -1319,6 +1325,9 @@ void Application::closeWindow(not_null<Window::Controller*> window) {
if (_lastActivePrimaryWindow == window) {
_lastActivePrimaryWindow = next;
}
if (_windowInSettings == window) {
_windowInSettings = next;
}
if (_lastActiveWindow == window) {
setLastActiveWindow(next);
if (_lastActiveWindow) {
@ -1331,6 +1340,7 @@ void Application::closeWindow(not_null<Window::Controller*> window) {
if (i->second.get() == window) {
Assert(_lastActiveWindow != window);
Assert(_lastActivePrimaryWindow != window);
Assert(_windowInSettings != window);
i = _primaryWindows.erase(i);
} else {
++i;

View File

@ -153,8 +153,8 @@ public:
// Windows interface.
bool hasActiveWindow(not_null<Main::Session*> session) const;
// Don't auto-switch.
[[nodiscard]] bool savingPositionFor(
not_null<Window::Controller*> window) const;
[[nodiscard]] Window::Controller *activeWindow() const;
[[nodiscard]] Window::Controller *activePrimaryWindow() const;
[[nodiscard]] Window::Controller *separateWindowForAccount(
@ -397,6 +397,7 @@ private:
std::unique_ptr<Window::Controller>> _secondaryWindows;
Window::Controller *_lastActiveWindow = nullptr;
Window::Controller *_lastActivePrimaryWindow = nullptr;
Window::Controller *_windowInSettings = nullptr;
std::unique_ptr<Media::View::OverlayWidget> _mediaView;
const std::unique_ptr<Lang::Instance> _langpack;

View File

@ -39,6 +39,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "tray.h"
#include "styles/style_widgets.h"
#include "styles/style_window.h"
#include "styles/style_dialogs.h" // ChildSkip().x() for new child windows.
#include <QtCore/QMimeData>
#include <QtGui/QGuiApplication>
@ -51,6 +52,42 @@ namespace {
constexpr auto kSaveWindowPositionTimeout = crl::time(1000);
using Core::WindowPosition;
[[nodiscard]] WindowPosition AdjustToScale(WindowPosition position) {
DEBUG_LOG(("Window Pos: Initializing first %1, %2, %3, %4 "
"(scale %5%, maximized %6)")
.arg(position.x)
.arg(position.y)
.arg(position.w)
.arg(position.h)
.arg(position.scale)
.arg(Logs::b(position.maximized)));
if (!position.scale) {
return position;
}
const auto scaleFactor = cScale() / float64(position.scale);
if (scaleFactor != 1.) {
// Change scale while keeping the position center in place.
position.x += position.w / 2;
position.y += position.h / 2;
position.w *= scaleFactor;
position.h *= scaleFactor;
position.x -= position.w / 2;
position.y -= position.h / 2;
}
return position;
}
[[nodiscard]] QPoint ChildSkip() {
const auto skipx = st::defaultDialogRow.padding.left()
+ st::defaultDialogRow.photoSize
+ st::defaultDialogRow.padding.left();
const auto skipy = st::windowTitleHeight;
return { skipx, skipy };
}
} // namespace
const QImage &Logo() {
@ -587,34 +624,43 @@ void MainWindow::recountGeometryConstraints() {
fixOrder();
}
Core::WindowPosition MainWindow::positionFromSettings() const {
auto position = Core::App().settings().windowPosition();
DEBUG_LOG(("Window Pos: Initializing first %1, %2, %3, %4 "
"(scale %5%, maximized %6)")
.arg(position.x)
.arg(position.y)
.arg(position.w)
.arg(position.h)
.arg(position.scale)
.arg(Logs::b(position.maximized)));
if (!position.scale) {
return position;
}
const auto scaleFactor = cScale() / float64(position.scale);
if (scaleFactor != 1.) {
// Change scale while keeping the position center in place.
position.x += position.w / 2;
position.y += position.h / 2;
position.w *= scaleFactor;
position.h *= scaleFactor;
position.x -= position.w / 2;
position.y -= position.h / 2;
}
return position;
WindowPosition MainWindow::initialPosition() const {
const auto active = Core::App().activeWindow();
return (!active || active == &controller())
? AdjustToScale(Core::App().settings().windowPosition())
: active->widget()->nextInitialChildPosition(isPrimary());
}
QRect MainWindow::countInitialGeometry(Core::WindowPosition position) {
WindowPosition MainWindow::nextInitialChildPosition(bool primary) {
const auto rect = geometry().marginsRemoved(frameMargins());
const auto position = rect.topLeft();
const auto adjust = [&](int value) {
return primary ? value : (value * 3 / 4);
};
const auto width = adjust(st::windowDefaultWidth);
const auto height = adjust(st::windowDefaultHeight);
const auto skip = ChildSkip();
const auto delta = _lastChildIndex
? (_lastMyChildCreatePosition - position)
: skip;
if (qAbs(delta.x()) >= skip.x() || qAbs(delta.y()) >= skip.y()) {
_lastChildIndex = 1;
} else {
++_lastChildIndex;
}
_lastMyChildCreatePosition = position;
const auto use = position + (skip * _lastChildIndex);
return withScreenInPosition({
.scale = cScale(),
.x = position.x(),
.y = position.y(),
.w = width,
.h = height,
});
}
QRect MainWindow::countInitialGeometry(WindowPosition position) {
const auto primaryScreen = QGuiApplication::primaryScreen();
const auto primaryAvailable = primaryScreen
? primaryScreen->availableGeometry()
@ -735,9 +781,7 @@ void MainWindow::initGeometry() {
if (initGeometryFromSystem()) {
return;
}
const auto geometry = countInitialGeometry(isPrimary()
? positionFromSettings()
: SecondaryInitPosition());
const auto geometry = countInitialGeometry(initialPosition());
DEBUG_LOG(("Window Pos: Setting first %1, %2, %3, %4"
).arg(geometry.x()
).arg(geometry.y()
@ -829,7 +873,7 @@ void MainWindow::savePosition(Qt::WindowState state) {
if (state == Qt::WindowMinimized
|| !isVisible()
|| !isPrimary() // #TODO windows
|| !Core::App().savingPositionFor(&controller())
|| !positionInited()) {
return;
}
@ -874,51 +918,38 @@ void MainWindow::savePosition(Qt::WindowState state) {
}
}
Core::WindowPosition MainWindow::withScreenInPosition(
Core::WindowPosition position) const {
auto centerX = position.x + position.w / 2;
auto centerY = position.y + position.h / 2;
int minDelta = 0;
QScreen *chosen = nullptr;
const auto screens = QGuiApplication::screens();
for (auto screen : screens) {
auto delta = (screen->geometry().center() - QPoint(centerX, centerY)).manhattanLength();
if (!chosen || delta < minDelta) {
minDelta = delta;
chosen = screen;
}
}
WindowPosition MainWindow::withScreenInPosition(
WindowPosition position) const {
const auto my = screen();
const auto chosen = my ? my : QGuiApplication::primaryScreen();
if (!chosen) {
return position;
}
auto screenGeometry = chosen->geometry();
const auto available = chosen->availableGeometry();
if (available.width() < st::windowMinWidth
|| available.height() < st::windowMinHeight) {
return position;
}
accumulate_min(position.w, available.width());
accumulate_min(position.h, available.height());
if (position.x + position.w > available.x() + available.width()) {
position.x = available.x() + available.width() - position.w;
}
if (position.y + position.h > available.y() + available.height()) {
position.y = available.y() + available.height() - position.h;
}
const auto geometry = chosen->geometry();
DEBUG_LOG(("Window Pos: Screen found, geometry: %1, %2, %3, %4"
).arg(screenGeometry.x()
).arg(screenGeometry.y()
).arg(screenGeometry.width()
).arg(screenGeometry.height()));
position.x -= screenGeometry.x();
position.y -= screenGeometry.y();
).arg(geometry.x()
).arg(geometry.y()
).arg(geometry.width()
).arg(geometry.height()));
position.x -= geometry.x();
position.y -= geometry.y();
position.moncrc = screenNameChecksum(chosen->name());
return position;
}
Core::WindowPosition MainWindow::SecondaryInitPosition() {
const auto active = Core::App().activeWindow();
if (!active) {
return {};
}
const auto geometry = active->widget()->geometry();
const auto skip = st::windowMinWidth / 6;
return active->widget()->withScreenInPosition({
.scale = cScale(),
.x = geometry.x() + skip,
.y = geometry.y() + skip,
.w = st::windowMinWidth,
.h = st::windowDefaultHeight,
});
}
bool MainWindow::minimizeToTray() {
if (Core::Quitting() || !Core::App().tray().has()) {
return false;

View File

@ -77,7 +77,6 @@ public:
[[nodiscard]] QRect desktopRect() const;
[[nodiscard]] Core::WindowPosition withScreenInPosition(
Core::WindowPosition position) const;
[[nodiscard]] static Core::WindowPosition SecondaryInitPosition();
void init();
@ -191,7 +190,9 @@ private:
void updateMinimumSize();
void updatePalette();
[[nodiscard]] Core::WindowPosition positionFromSettings() const;
[[nodiscard]] Core::WindowPosition initialPosition() const;
[[nodiscard]] Core::WindowPosition nextInitialChildPosition(
bool primary);
[[nodiscard]] QRect countInitialGeometry(Core::WindowPosition position);
void initGeometry();
@ -213,6 +214,9 @@ private:
bool _maximizedBeforeHide = false;
QPoint _lastMyChildCreatePosition;
int _lastChildIndex = 0;
mutable QRect _monitorRect;
mutable crl::time _monitorLastGot = 0;