From 832d47121feb6b1ce0a07ac23c2c43df86b4c227 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 17 Feb 2023 20:12:29 +0400 Subject: [PATCH] Save media viewer position to Settings. --- Telegram/SourceFiles/core/core_settings.cpp | 68 +++++- Telegram/SourceFiles/core/core_settings.h | 20 ++ .../SourceFiles/media/view/media_view.style | 7 + .../media/view/media_view_overlay_widget.cpp | 216 +++++++++++++++--- .../media/view/media_view_overlay_widget.h | 9 +- .../platform/linux/main_window_linux.h | 4 + .../platform/mac/main_window_mac.h | 4 + .../platform/win/main_window_win.cpp | 27 +-- .../platform/win/main_window_win.h | 3 +- Telegram/SourceFiles/window/main_window.cpp | 155 +++++++------ Telegram/SourceFiles/window/main_window.h | 19 +- Telegram/lib_ui | 2 +- 12 files changed, 390 insertions(+), 144 deletions(-) diff --git a/Telegram/SourceFiles/core/core_settings.cpp b/Telegram/SourceFiles/core/core_settings.cpp index 8d3671b696..79e560f8ef 100644 --- a/Telegram/SourceFiles/core/core_settings.cpp +++ b/Telegram/SourceFiles/core/core_settings.cpp @@ -38,6 +38,18 @@ namespace { return result; } +void LogPosition(const WindowPosition &position, const QString &name) { + DEBUG_LOG(("%1 Pos: Writing to storage %2, %3, %4, %5" + " (scale %6%, maximized %7)") + .arg(name) + .arg(position.x) + .arg(position.y) + .arg(position.w) + .arg(position.h) + .arg(position.scale) + .arg(position.maximized)); +} + [[nodiscard]] QByteArray Serialize(const WindowPosition &position) { auto result = QByteArray(); const auto size = 7 * sizeof(qint32); @@ -54,14 +66,6 @@ namespace { << qint32(position.maximized) << qint32(position.scale); } - DEBUG_LOG(("Window Pos: Writing to storage %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))); return result; } @@ -85,6 +89,35 @@ namespace { } // namespace +[[nodiscard]] WindowPosition AdjustToScale( + WindowPosition position, + const QString &name) { + DEBUG_LOG(("%1 Pos: Initializing first %2, %3, %4, %5 " + "(scale %6%, maximized %7)") + .arg(name) + .arg(position.x) + .arg(position.y) + .arg(position.w) + .arg(position.h) + .arg(position.scale) + .arg(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; +} + Settings::Settings() : _sendSubmitWay(Ui::InputSubmitSettings::Enter) , _floatPlayerColumn(Window::Column::Second) @@ -97,6 +130,9 @@ Settings::~Settings() = default; QByteArray Settings::serialize() const { const auto themesAccentColors = _themesAccentColors.serialize(); const auto windowPosition = Serialize(_windowPosition); + LogPosition(_windowPosition, u"Window"_q); + const auto mediaViewPosition = Serialize(_mediaViewPosition); + LogPosition(_mediaViewPosition, u"Viewer"_q); const auto proxy = _proxy.serialize(); const auto skipLanguages = _skipTranslationLanguages.current(); @@ -160,7 +196,8 @@ QByteArray Settings::serialize() const { + (skipLanguages.size() * sizeof(quint64)) + sizeof(qint32) + sizeof(quint64) - + sizeof(qint32) * 3; + + sizeof(qint32) * 3 + + Serialize::bytearraySize(mediaViewPosition); auto result = QByteArray(); result.reserve(size); @@ -291,7 +328,8 @@ QByteArray Settings::serialize() const { << quint64(QLocale::Language(_translateToRaw.current())) << qint32(_windowTitleContent.current().hideChatName ? 1 : 0) << qint32(_windowTitleContent.current().hideAccountName ? 1 : 0) - << qint32(_windowTitleContent.current().hideTotalUnread ? 1 : 0); + << qint32(_windowTitleContent.current().hideTotalUnread ? 1 : 0) + << mediaViewPosition; } return result; } @@ -394,6 +432,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) { qint32 hideChatName = _windowTitleContent.current().hideChatName ? 1 : 0; qint32 hideAccountName = _windowTitleContent.current().hideAccountName ? 1 : 0; qint32 hideTotalUnread = _windowTitleContent.current().hideTotalUnread ? 1 : 0; + QByteArray mediaViewPosition; stream >> themesAccentColors; if (!stream.atEnd()) { @@ -619,6 +658,9 @@ void Settings::addFromSerialized(const QByteArray &serialized) { >> hideAccountName >> hideTotalUnread; } + if (!stream.atEnd()) { + stream >> mediaViewPosition; + } if (stream.status() != QDataStream::Ok) { LOG(("App Error: " "Bad data for Core::Settings::constructFromSerialized()")); @@ -809,6 +851,12 @@ void Settings::addFromSerialized(const QByteArray &serialized) { .hideAccountName = (hideAccountName == 1), .hideTotalUnread = (hideTotalUnread == 1), }; + if (!mediaViewPosition.isEmpty()) { + _mediaViewPosition = Deserialize(mediaViewPosition); + if (!_mediaViewPosition.w && !_mediaViewPosition.maximized) { + _mediaViewPosition = { .maximized = 2 }; + } + } } QString Settings::getSoundPath(const QString &key) const { diff --git a/Telegram/SourceFiles/core/core_settings.h b/Telegram/SourceFiles/core/core_settings.h index 95490bbb15..b65fd31182 100644 --- a/Telegram/SourceFiles/core/core_settings.h +++ b/Telegram/SourceFiles/core/core_settings.h @@ -52,8 +52,20 @@ struct WindowPosition { int y = 0; int w = 0; int h = 0; + + friend inline constexpr auto operator<=>( + WindowPosition, + WindowPosition) = default; + + [[nodiscard]] QRect rect() const { + return QRect(x, y, w, h); + } }; +[[nodiscard]] WindowPosition AdjustToScale( + WindowPosition position, + const QString &name); + struct WindowTitleContent { bool hideChatName : 1 = false; bool hideAccountName : 1 = false; @@ -759,6 +771,13 @@ public: void setRememberedDeleteMessageOnlyForYou(bool value); [[nodiscard]] bool rememberedDeleteMessageOnlyForYou() const; + [[nodiscard]] const WindowPosition &mediaViewPosition() const { + return _mediaViewPosition; + } + void setMediaViewPosition(const WindowPosition &position) { + _mediaViewPosition = position; + } + [[nodiscard]] static bool ThirdColumnByDefault(); [[nodiscard]] static float64 DefaultDialogsWidthRatio(); [[nodiscard]] static qint32 SerializePlaybackSpeed(float64 speed) { @@ -880,6 +899,7 @@ private: rpl::variable> _skipTranslationLanguages; rpl::event_stream<> _skipTranslationLanguagesChanges; bool _rememberedDeleteMessageOnlyForYou = false; + WindowPosition _mediaViewPosition = { .maximized = 2 }; bool _tabbedReplacedWithInfo = false; // per-window rpl::event_stream _tabbedReplacedWithInfoValue; // per-window diff --git a/Telegram/SourceFiles/media/view/media_view.style b/Telegram/SourceFiles/media/view/media_view.style index 80a7e85028..be94ae6170 100644 --- a/Telegram/SourceFiles/media/view/media_view.style +++ b/Telegram/SourceFiles/media/view/media_view.style @@ -262,6 +262,13 @@ mediaviewGroupWidthMax: 160px; mediaviewGroupSkip: 3px; mediaviewGroupSkipCurrent: 12px; +mediaviewMinWidth: 480px; +mediaviewMinHeight: 360px; +mediaviewDefaultLeft: 160px; +mediaviewDefaultTop: 120px; +mediaviewDefaultWidth: 800px; +mediaviewDefaultHeight: 600px; + themePreviewSize: size(903px, 584px); themePreviewBg: windowBg; themePreviewOverlayOpacity: 0.8; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index e00f0edcdb..3e16da7330 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -88,7 +88,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_media_view.h" #include "styles/style_chat.h" #include "styles/style_menu_icons.h" -#include "styles/style_window.h" // windowDefaultWidth / windowDefaultHeight #include "styles/style_calls.h" #ifdef Q_OS_MAC @@ -137,6 +136,26 @@ private: }; +[[nodiscard]] Core::WindowPosition DefaultPosition() { + const auto moncrc = [&] { + if (const auto active = Core::App().activeWindow()) { + const auto widget = active->widget(); + if (const auto screen = widget->screen()) { + return Platform::ScreenNameChecksum(screen->name()); + } + } + return Core::App().settings().windowPosition().moncrc; + }(); + return { + .moncrc = moncrc, + .scale = cScale(), + .x = st::mediaviewDefaultLeft, + .y = st::mediaviewDefaultTop, + .w = st::mediaviewDefaultWidth, + .h = st::mediaviewDefaultHeight, + }; +} + PipDelegate::PipDelegate(QWidget *parent, not_null session) : _parent(parent) , _session(session) { @@ -299,8 +318,7 @@ OverlayWidget::PipWrap::PipWrap( } OverlayWidget::OverlayWidget() -: _supportWindowMode(true) -, _wrap(std::make_unique()) +: _wrap(std::make_unique()) , _window(_wrap->window()) , _helper(Platform::CreateOverlayWidgetHelper(_window.get(), [=](bool maximized) { toggleFullScreen(maximized); @@ -309,7 +327,8 @@ OverlayWidget::OverlayWidget() , _surface( Ui::GL::CreateSurface(_body, chooseRenderer(_wrap->backend()))) , _widget(_surface->rpWidget()) -, _fullscreen(true || !_supportWindowMode) +, _fullscreen(Core::App().settings().mediaViewPosition().maximized == 2) +, _windowed(Core::App().settings().mediaViewPosition().maximized == 0) , _docDownload(_body, tr::lng_media_download(tr::now), st::mediaviewFileLink) , _docSaveAs(_body, tr::lng_mediaview_save_as(tr::now), st::mediaviewFileLink) , _docCancel(_body, tr::lng_cancel(tr::now), st::mediaviewFileLink) @@ -365,6 +384,15 @@ OverlayWidget::OverlayWidget() .arg(position.x()) .arg(position.y())); moveToScreen(true); + if (_windowed) { + savePosition(); + } else { + moveToScreen(true); + } + } else if (type == QEvent::Resize) { + if (_windowed) { + savePosition(); + } } else if (type == QEvent::Close && !Core::Sandbox::Instance().isSavingSession() && !Core::Quitting()) { @@ -505,31 +533,34 @@ void OverlayWidget::setupWindow() { return Flag::Move | Flag(0); }); - if (_supportWindowMode) { - const auto callback = [=](Qt::WindowState state) { - if (state == Qt::WindowMinimized || Platform::IsMac()) { - return; - } else if (state == Qt::WindowFullScreen) { - _fullscreen = true; - _windowed = false; - } else if (state == Qt::WindowMaximized) { + const auto callback = [=](Qt::WindowState state) { + if (state == Qt::WindowMinimized || Platform::IsMac()) { + return; + } else if (state == Qt::WindowMaximized) { + if (_fullscreen || _windowed) { _fullscreen = _windowed = false; - } else { - _fullscreen = false; - _windowed = true; + savePosition(); } - }; - QObject::connect( - _window->windowHandle(), - &QWindow::windowStateChanged, - callback); - } + } else if (_fullscreen || _windowed) { + return; + } else if (state == Qt::WindowFullScreen) { + _fullscreen = true; + savePosition(); + } else { + _windowed = true; + savePosition(); + } + }; + QObject::connect( + _window->windowHandle(), + &QWindow::windowStateChanged, + callback); _window->setAttribute(Qt::WA_NoSystemBackground, true); _window->setAttribute(Qt::WA_TranslucentBackground, true); _window->setMinimumSize( - { st::windowMinHeight, st::windowMinWidth }); + { st::mediaviewMinWidth, st::mediaviewMinHeight }); _window->shownValue( ) | rpl::start_with_next([=](bool shown) { @@ -555,7 +586,7 @@ void OverlayWidget::refreshLang() { } void OverlayWidget::moveToScreen(bool inMove) { - if (!_fullscreen) { + if (!_fullscreen || _wasWindowedMode) { return; } const auto widgetScreen = [&](auto &&widget) -> QScreen* { @@ -587,10 +618,111 @@ void OverlayWidget::moveToScreen(bool inMove) { updateGeometry(inMove); } -void OverlayWidget::updateGeometry(bool inMove) { - if (Platform::IsWayland() || Platform::IsWindows() || !_fullscreen) { +void OverlayWidget::initFullScreen() { + if (_fullscreenInited) { return; } + _fullscreenInited = true; + switch (Core::App().settings().mediaViewPosition().maximized) { + case 2: + _fullscreen = true; + _windowed = false; + break; + case 1: + _fullscreen = Platform::IsMac(); + _windowed = false; + break; + } +} + +void OverlayWidget::initNormalGeometry() { + if (_normalGeometryInited) { + return; + } + _normalGeometryInited = true; + const auto saved = Core::App().settings().mediaViewPosition(); + const auto adjusted = Core::AdjustToScale(saved, u"Viewer"_q); + const auto initial = DefaultPosition(); + _normalGeometry = initial.rect(); + if (const auto active = Core::App().activeWindow()) { + _normalGeometry = active->widget()->countInitialGeometry( + adjusted, + initial, + { st::mediaviewMinWidth, st::mediaviewMinHeight }); + } +} + +void OverlayWidget::savePosition() { + if (isHidden() || isMinimized() || !_normalGeometryInited) { + return; + } + const auto &savedPosition = Core::App().settings().mediaViewPosition(); + auto realPosition = savedPosition; + if (_fullscreen) { + realPosition.maximized = 2; + realPosition.moncrc = 0; + DEBUG_LOG(("Viewer Pos: Saving fullscreen position.")); + } else if (!_windowed) { + realPosition.maximized = 1; + realPosition.moncrc = 0; + DEBUG_LOG(("Viewer Pos: Saving maximized position.")); + } else { + auto r = _window->geometry(); + realPosition.x = r.x(); + realPosition.y = r.y(); + realPosition.w = r.width(); + realPosition.h = r.height(); + realPosition.scale = cScale(); + realPosition.maximized = 0; + realPosition.moncrc = 0; + DEBUG_LOG(("Viewer Pos: " + "Saving non-maximized position: %1, %2, %3, %4" + ).arg(realPosition.x + ).arg(realPosition.y + ).arg(realPosition.w + ).arg(realPosition.h)); + } + realPosition = Window::PositionWithScreen( + realPosition, + _window, + { st::mediaviewMinWidth, st::mediaviewMinHeight }); + if (realPosition.w >= st::mediaviewMinWidth + && realPosition.h >= st::mediaviewMinHeight + && realPosition != savedPosition) { + DEBUG_LOG(("Viewer Pos: " + "Writing: %1, %2, %3, %4 (scale %5%, maximized %6)") + .arg(realPosition.x) + .arg(realPosition.y) + .arg(realPosition.w) + .arg(realPosition.h) + .arg(realPosition.scale) + .arg(Logs::b(realPosition.maximized))); + Core::App().settings().setMediaViewPosition(realPosition); + Core::App().saveSettingsDelayed(); + } +} + +void OverlayWidget::updateGeometry(bool inMove) { + initFullScreen(); + if (_fullscreen) { + updateGeometryToScreen(inMove); + } else if (_windowed && _normalGeometryInited) { + _window->setGeometry(_normalGeometry); + } + if constexpr (!Platform::IsMac()) { + if (_fullscreen) { + if (!isHidden() && !isMinimized()) { + _window->showFullScreen(); + } + } else if (!_windowed) { + if (!isHidden() && !isMinimized()) { + _window->showMaximized(); + } + } + } +} + +void OverlayWidget::updateGeometryToScreen(bool inMove) { const auto available = _window->screen()->geometry(); const auto openglWidget = _opengl ? static_cast(_widget.get()) @@ -624,9 +756,7 @@ void OverlayWidget::updateGeometry(bool inMove) { } void OverlayWidget::updateControlsGeometry() { - const auto navSkip = _supportWindowMode - ? st::mediaviewHeaderTop - : st::mediaviewControlSize; + const auto navSkip = st::mediaviewHeaderTop; _closeNav = QRect(width() - st::mediaviewControlSize, 0, st::mediaviewControlSize, st::mediaviewControlSize); _closeNavIcon = style::centerrect(_closeNav, st::mediaviewClose); _leftNav = QRect(0, navSkip, st::mediaviewControlSize, height() - 2 * navSkip); @@ -1617,19 +1747,22 @@ void OverlayWidget::minimize() { } void OverlayWidget::toggleFullScreen(bool fullscreen) { + _fullscreen = fullscreen; + _windowed = !fullscreen; + initNormalGeometry(); if constexpr (Platform::IsMac()) { - _fullscreen = fullscreen; - _windowed = !fullscreen; _helper->beforeShow(_fullscreen); - if (_fullscreen) { - moveToScreen(); - } + updateGeometry(); _helper->afterShow(_fullscreen); - } else if (fullscreen) { + } else if (_fullscreen) { + updateGeometry(); _window->showFullScreen(); } else { _window->showNormal(); + updateGeometry(); + _wasWindowedMode = true; } + savePosition(); } void OverlayWidget::activateControls() { @@ -1707,7 +1840,9 @@ void OverlayWidget::subscribeToScreenGeometry() { base::qt_signal_producer( screen, &QScreen::geometryChanged - ) | rpl::start_with_next([=] { + ) | rpl::filter([=] { + return !isHidden() && !isMinimized() && _fullscreen; + }) | rpl::start_with_next([=] { updateGeometry(); }, _screenGeometryLifetime); } @@ -2573,7 +2708,7 @@ void OverlayWidget::update(const QRegion ®ion) { } bool OverlayWidget::isActive() const { - return !isHidden() && !isMinimized() && Ui::InFocusChain(_window); + return !isHidden() && !isMinimized() && _window->isActiveWindow(); } bool OverlayWidget::isHidden() const { @@ -2910,8 +3045,11 @@ void OverlayWidget::displayFinished() { void OverlayWidget::showAndActivate() { _body->show(); + initNormalGeometry(); + updateGeometry(); if (_windowed || Platform::IsMac()) { _window->showNormal(); + _wasWindowedMode = true; } else if (_fullscreen) { _window->showFullScreen(); } else { @@ -3995,7 +4133,7 @@ void OverlayWidget::paintControls( st::mediaviewRight }, { OverClose, - !_supportWindowMode, + false, _closeNav, _closeNavIcon, st::mediaviewClose }, @@ -4702,8 +4840,10 @@ void OverlayWidget::updateOver(QPoint pos) { updateOverState(OverIcon); } else if (_moreNav.contains(pos)) { updateOverState(OverMore); - } else if (!_supportWindowMode && _closeNav.contains(pos)) { +#if 0 // close + } else if (_closeNav.contains(pos)) { updateOverState(OverClose); +#endif } else if (documentContentShown() && finalContentRect().contains(pos)) { if ((_document->isVideoFile() || _document->isVideoMessage()) && _streamed) { updateOverState(OverVideo); diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h index 51a429d465..f947fff199 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h @@ -241,8 +241,12 @@ private: void assignMediaPointer(not_null photo); void updateOver(QPoint mpos); + void initFullScreen(); + void initNormalGeometry(); + void savePosition(); void moveToScreen(bool inMove = false); void updateGeometry(bool inMove = false); + void updateGeometryToScreen(bool inMove = false); bool moveToNext(int delta); void preloadData(int delta); @@ -454,7 +458,6 @@ private: Window::SessionController *findWindow(bool switchTo = true) const; - const bool _supportWindowMode = false; bool _opengl = false; const std::unique_ptr _wrap; const not_null _window; @@ -462,6 +465,10 @@ private: const not_null _body; const std::unique_ptr _surface; const not_null _widget; + QRect _normalGeometry; + bool _wasWindowedMode = false; + bool _fullscreenInited = false; + bool _normalGeometryInited = false; bool _fullscreen = true; bool _windowed = false; diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.h b/Telegram/SourceFiles/platform/linux/main_window_linux.h index 8b74da57d6..173a033426 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.h +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.h @@ -65,4 +65,8 @@ private: }; +[[nodiscard]] int32 ScreenNameChecksum(const QString &name) { + return Window::DefaultScreenNameChecksum(name); +} + } // namespace Platform diff --git a/Telegram/SourceFiles/platform/mac/main_window_mac.h b/Telegram/SourceFiles/platform/mac/main_window_mac.h index 81579cf6ea..da640bc78f 100644 --- a/Telegram/SourceFiles/platform/mac/main_window_mac.h +++ b/Telegram/SourceFiles/platform/mac/main_window_mac.h @@ -85,4 +85,8 @@ private: }; +[[nodiscard]] int32 ScreenNameChecksum(const QString &name) { + return Window::DefaultScreenNameChecksum(name); +} + } // namespace Platform diff --git a/Telegram/SourceFiles/platform/win/main_window_win.cpp b/Telegram/SourceFiles/platform/win/main_window_win.cpp index 004d2c4245..4cdb5021c2 100644 --- a/Telegram/SourceFiles/platform/win/main_window_win.cpp +++ b/Telegram/SourceFiles/platform/win/main_window_win.cpp @@ -412,17 +412,6 @@ void MainWindow::validateDwmPreviewColors() { _dwmPreview.reset(); } -int32 MainWindow::screenNameChecksum(const QString &name) const { - constexpr int DeviceNameSize = base::array_size(MONITORINFOEX().szDevice); - wchar_t buffer[DeviceNameSize] = { 0 }; - if (name.size() < DeviceNameSize) { - name.toWCharArray(buffer); - } else { - memcpy(buffer, name.toStdWString().data(), sizeof(buffer)); - } - return base::crc32(buffer, sizeof(buffer)); -} - void MainWindow::forceIconRefresh() { const auto refresher = std::make_unique(this); refresher->setWindowFlags( @@ -483,10 +472,7 @@ bool MainWindow::hasTabletView() const { } bool MainWindow::initGeometryFromSystem() { - if (!hasTabletView()) { - return false; - } - if (!screen()) { + if (!hasTabletView() || !screen()) { return false; } Ui::RpWidget::setGeometry(screen()->availableGeometry()); @@ -708,4 +694,15 @@ MainWindow::~MainWindow() { destroyCachedIcons(); } +int32 ScreenNameChecksum(const QString &name) { + constexpr int DeviceNameSize = base::array_size(MONITORINFOEX().szDevice); + wchar_t buffer[DeviceNameSize] = { 0 }; + if (name.size() < DeviceNameSize) { + name.toWCharArray(buffer); + } else { + memcpy(buffer, name.toStdWString().data(), sizeof(buffer)); + } + return base::crc32(buffer, sizeof(buffer)); +} + } // namespace Platform diff --git a/Telegram/SourceFiles/platform/win/main_window_win.h b/Telegram/SourceFiles/platform/win/main_window_win.h index ecfbe40f71..9459fe50f4 100644 --- a/Telegram/SourceFiles/platform/win/main_window_win.h +++ b/Telegram/SourceFiles/platform/win/main_window_win.h @@ -41,7 +41,6 @@ public: protected: void initHook() override; - int32 screenNameChecksum(const QString &name) const override; void unreadCounterChangedHook() override; void workmodeUpdated(Core::Settings::WorkMode mode) override; @@ -100,4 +99,6 @@ private: }; +[[nodiscard]] int32 ScreenNameChecksum(const QString &name); + } // namespace Platform diff --git a/Telegram/SourceFiles/window/main_window.cpp b/Telegram/SourceFiles/window/main_window.cpp index b98756dc3e..3fa20cb60e 100644 --- a/Telegram/SourceFiles/window/main_window.cpp +++ b/Telegram/SourceFiles/window/main_window.cpp @@ -56,32 +56,6 @@ 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 @@ -629,7 +603,9 @@ void MainWindow::recountGeometryConstraints() { WindowPosition MainWindow::initialPosition() const { const auto active = Core::App().activeWindow(); return (!active || active == &controller()) - ? AdjustToScale(Core::App().settings().windowPosition()) + ? Core::AdjustToScale( + Core::App().settings().windowPosition(), + u"Window"_q) : active->widget()->nextInitialChildPosition(isPrimary()); } @@ -673,28 +649,38 @@ QRect MainWindow::countInitialGeometry(WindowPosition position) { const auto initialHeight = Core::Settings::ThirdColumnByDefault() ? st::windowBigDefaultHeight : st::windowDefaultHeight; - const auto initial = QRect( - primaryAvailable.x() + std::max( - (primaryAvailable.width() - initialWidth) / 2, - 0), - primaryAvailable.y() + std::max( - (primaryAvailable.height() - initialHeight) / 2, - 0), - initialWidth, - initialHeight); + const auto initial = WindowPosition{ + .x = (primaryAvailable.x() + + std::max((primaryAvailable.width() - initialWidth) / 2, 0)), + .y = (primaryAvailable.y() + + std::max((primaryAvailable.height() - initialHeight) / 2, 0)), + .w = initialWidth, + .h = initialHeight, + }; + return countInitialGeometry( + position, + initial, + { st::windowMinWidth, st::windowMinHeight }); +} + +QRect MainWindow::countInitialGeometry( + WindowPosition position, + WindowPosition initial, + QSize minSize) const { if (!position.w || !position.h) { - return initial; + return initial.rect(); } const auto screen = [&]() -> QScreen* { for (const auto screen : QGuiApplication::screens()) { - if (position.moncrc == screenNameChecksum(screen->name())) { + const auto sum = Platform::ScreenNameChecksum(screen->name()); + if (position.moncrc == sum) { return screen; } } return nullptr; }(); if (!screen) { - return initial; + return initial.rect(); } const auto frame = frameMargins(); const auto screenGeometry = screen->geometry(); @@ -728,7 +714,7 @@ QRect MainWindow::countInitialGeometry(WindowPosition position) { const auto w = spaceForInner.width(); const auto h = spaceForInner.height(); if (w < st::windowMinWidth || h < st::windowMinHeight) { - return initial; + return initial.rect(); } if (position.x < x) position.x = x; if (position.y < y) position.y = y; @@ -768,14 +754,14 @@ QRect MainWindow::countInitialGeometry(WindowPosition position) { > screenGeometry.x() + screenGeometry.width()) || (position.y + st::windowMinHeight > screenGeometry.y() + screenGeometry.height())) { - return initial; + return initial.rect(); } DEBUG_LOG(("Window Pos: Resulting geometry is %1, %2, %3, %4" ).arg(position.x ).arg(position.y ).arg(position.w ).arg(position.h)); - return QRect(position.x, position.y, position.w, position.h); + return position.rect(); } void MainWindow::initGeometry() { @@ -796,11 +782,6 @@ void MainWindow::positionUpdated() { _positionUpdatedTimer.callOnce(kSaveWindowPositionTimeout); } -int32 MainWindow::screenNameChecksum(const QString &name) const { - const auto bytes = name.toUtf8(); - return base::crc32(bytes.constData(), bytes.size()); -} - void MainWindow::setPositionInited() { _positionInited = true; } @@ -936,34 +917,10 @@ void MainWindow::savePosition(Qt::WindowState state) { WindowPosition MainWindow::withScreenInPosition( WindowPosition position) const { - const auto my = screen(); - const auto chosen = my ? my : QGuiApplication::primaryScreen(); - if (!chosen) { - return position; - } - 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(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; + return PositionWithScreen( + position, + this, + { st::windowMinWidth, st::windowMinHeight }); } bool MainWindow::minimizeToTray() { @@ -1086,4 +1043,52 @@ MainWindow::~MainWindow() { hide(); } +int32 DefaultScreenNameChecksum(const QString &name) { + const auto bytes = name.toUtf8(); + return base::crc32(bytes.constData(), bytes.size()); +} + +WindowPosition PositionWithScreen( + WindowPosition position, + const QScreen *chosen, + QSize minimal) { + if (!chosen) { + return position; + } + const auto available = chosen->availableGeometry(); + if (available.width() < minimal.width() + || available.height() < minimal.height()) { + 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(geometry.x() + ).arg(geometry.y() + ).arg(geometry.width() + ).arg(geometry.height())); + position.x -= geometry.x(); + position.y -= geometry.y(); + position.moncrc = Platform::ScreenNameChecksum(chosen->name()); + return position; +} + +WindowPosition PositionWithScreen( + WindowPosition position, + not_null widget, + QSize minimal) { + const auto screen = widget->screen(); + return PositionWithScreen( + position, + screen ? screen : QGuiApplication::primaryScreen(), + minimal); +} + } // namespace Window diff --git a/Telegram/SourceFiles/window/main_window.h b/Telegram/SourceFiles/window/main_window.h index 8393498a66..d5f87d16eb 100644 --- a/Telegram/SourceFiles/window/main_window.h +++ b/Telegram/SourceFiles/window/main_window.h @@ -134,6 +134,11 @@ public: updateGlobalMenuHook(); } + [[nodiscard]] QRect countInitialGeometry( + Core::WindowPosition position, + Core::WindowPosition initial, + QSize minSize) const; + protected: void leaveEventHook(QEvent *e) override; @@ -174,9 +179,6 @@ protected: return false; } - // This one is overriden in Windows for historical reasons. - virtual int32 screenNameChecksum(const QString &name) const; - void setPositionInited(); virtual QRect computeDesktopRect() const; @@ -218,4 +220,15 @@ private: }; +[[nodiscard]] int32 DefaultScreenNameChecksum(const QString &name); + +[[nodiscard]] Core::WindowPosition PositionWithScreen( + Core::WindowPosition position, + const QScreen *chosen, + QSize minimal); +[[nodiscard]] Core::WindowPosition PositionWithScreen( + Core::WindowPosition position, + not_null widget, + QSize minimal); + } // namespace Window diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 3b69ec499c..74ab66cfa9 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 3b69ec499ccc7f4208a6413fbeb6f5ebe84f3f55 +Subproject commit 74ab66cfa9c05745ca513504940e59f6fd68eff3