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

View file

@ -153,8 +153,8 @@ public:
// Windows interface. // Windows interface.
bool hasActiveWindow(not_null<Main::Session*> session) const; bool hasActiveWindow(not_null<Main::Session*> session) const;
[[nodiscard]] bool savingPositionFor(
// Don't auto-switch. not_null<Window::Controller*> window) const;
[[nodiscard]] Window::Controller *activeWindow() const; [[nodiscard]] Window::Controller *activeWindow() const;
[[nodiscard]] Window::Controller *activePrimaryWindow() const; [[nodiscard]] Window::Controller *activePrimaryWindow() const;
[[nodiscard]] Window::Controller *separateWindowForAccount( [[nodiscard]] Window::Controller *separateWindowForAccount(
@ -397,6 +397,7 @@ private:
std::unique_ptr<Window::Controller>> _secondaryWindows; std::unique_ptr<Window::Controller>> _secondaryWindows;
Window::Controller *_lastActiveWindow = nullptr; Window::Controller *_lastActiveWindow = nullptr;
Window::Controller *_lastActivePrimaryWindow = nullptr; Window::Controller *_lastActivePrimaryWindow = nullptr;
Window::Controller *_windowInSettings = nullptr;
std::unique_ptr<Media::View::OverlayWidget> _mediaView; std::unique_ptr<Media::View::OverlayWidget> _mediaView;
const std::unique_ptr<Lang::Instance> _langpack; 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 "tray.h"
#include "styles/style_widgets.h" #include "styles/style_widgets.h"
#include "styles/style_window.h" #include "styles/style_window.h"
#include "styles/style_dialogs.h" // ChildSkip().x() for new child windows.
#include <QtCore/QMimeData> #include <QtCore/QMimeData>
#include <QtGui/QGuiApplication> #include <QtGui/QGuiApplication>
@ -51,6 +52,42 @@ namespace {
constexpr auto kSaveWindowPositionTimeout = crl::time(1000); 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 } // namespace
const QImage &Logo() { const QImage &Logo() {
@ -587,34 +624,43 @@ void MainWindow::recountGeometryConstraints() {
fixOrder(); fixOrder();
} }
Core::WindowPosition MainWindow::positionFromSettings() const { WindowPosition MainWindow::initialPosition() const {
auto position = Core::App().settings().windowPosition(); const auto active = Core::App().activeWindow();
DEBUG_LOG(("Window Pos: Initializing first %1, %2, %3, %4 " return (!active || active == &controller())
"(scale %5%, maximized %6)") ? AdjustToScale(Core::App().settings().windowPosition())
.arg(position.x) : active->widget()->nextInitialChildPosition(isPrimary());
.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;
} }
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 primaryScreen = QGuiApplication::primaryScreen();
const auto primaryAvailable = primaryScreen const auto primaryAvailable = primaryScreen
? primaryScreen->availableGeometry() ? primaryScreen->availableGeometry()
@ -735,9 +781,7 @@ void MainWindow::initGeometry() {
if (initGeometryFromSystem()) { if (initGeometryFromSystem()) {
return; return;
} }
const auto geometry = countInitialGeometry(isPrimary() const auto geometry = countInitialGeometry(initialPosition());
? positionFromSettings()
: SecondaryInitPosition());
DEBUG_LOG(("Window Pos: Setting first %1, %2, %3, %4" DEBUG_LOG(("Window Pos: Setting first %1, %2, %3, %4"
).arg(geometry.x() ).arg(geometry.x()
).arg(geometry.y() ).arg(geometry.y()
@ -829,7 +873,7 @@ void MainWindow::savePosition(Qt::WindowState state) {
if (state == Qt::WindowMinimized if (state == Qt::WindowMinimized
|| !isVisible() || !isVisible()
|| !isPrimary() // #TODO windows || !Core::App().savingPositionFor(&controller())
|| !positionInited()) { || !positionInited()) {
return; return;
} }
@ -874,51 +918,38 @@ void MainWindow::savePosition(Qt::WindowState state) {
} }
} }
Core::WindowPosition MainWindow::withScreenInPosition( WindowPosition MainWindow::withScreenInPosition(
Core::WindowPosition position) const { WindowPosition position) const {
auto centerX = position.x + position.w / 2; const auto my = screen();
auto centerY = position.y + position.h / 2; const auto chosen = my ? my : QGuiApplication::primaryScreen();
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;
}
}
if (!chosen) { if (!chosen) {
return position; 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" DEBUG_LOG(("Window Pos: Screen found, geometry: %1, %2, %3, %4"
).arg(screenGeometry.x() ).arg(geometry.x()
).arg(screenGeometry.y() ).arg(geometry.y()
).arg(screenGeometry.width() ).arg(geometry.width()
).arg(screenGeometry.height())); ).arg(geometry.height()));
position.x -= screenGeometry.x(); position.x -= geometry.x();
position.y -= screenGeometry.y(); position.y -= geometry.y();
position.moncrc = screenNameChecksum(chosen->name()); position.moncrc = screenNameChecksum(chosen->name());
return position; 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() { bool MainWindow::minimizeToTray() {
if (Core::Quitting() || !Core::App().tray().has()) { if (Core::Quitting() || !Core::App().tray().has()) {
return false; return false;

View file

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