From fd833dff350a988d75a9bf43f0a8ce3f6cb61a46 Mon Sep 17 00:00:00 2001 From: John Preston Date: Sat, 23 Mar 2024 12:42:22 +0400 Subject: [PATCH] Save IV window geometry. --- Telegram/CMakeLists.txt | 2 + Telegram/SourceFiles/core/application.cpp | 23 +++- Telegram/SourceFiles/core/application.h | 3 + Telegram/SourceFiles/core/core_settings.cpp | 15 ++- Telegram/SourceFiles/core/core_settings.h | 8 ++ .../view/media/history_view_web_page.cpp | 2 +- Telegram/SourceFiles/iv/iv_controller.cpp | 15 ++- Telegram/SourceFiles/iv/iv_controller.h | 7 +- Telegram/SourceFiles/iv/iv_delegate.h | 19 +++ Telegram/SourceFiles/iv/iv_delegate_impl.cpp | 120 ++++++++++++++++++ Telegram/SourceFiles/iv/iv_delegate_impl.h | 27 ++++ Telegram/SourceFiles/iv/iv_instance.cpp | 23 +++- Telegram/SourceFiles/iv/iv_instance.h | 14 +- Telegram/SourceFiles/window/window.style | 5 + Telegram/cmake/td_iv.cmake | 1 + 15 files changed, 271 insertions(+), 13 deletions(-) create mode 100644 Telegram/SourceFiles/iv/iv_delegate.h create mode 100644 Telegram/SourceFiles/iv/iv_delegate_impl.cpp create mode 100644 Telegram/SourceFiles/iv/iv_delegate_impl.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 55c5cbf82..41489fffa 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -995,6 +995,8 @@ PRIVATE intro/intro_step.h intro/intro_widget.cpp intro/intro_widget.h + iv/iv_delegate_impl.cpp + iv/iv_delegate_impl.h iv/iv_instance.cpp iv/iv_instance.h lang/lang_cloud_manager.cpp diff --git a/Telegram/SourceFiles/core/application.cpp b/Telegram/SourceFiles/core/application.cpp index 06691b5c9..3f643b6dd 100644 --- a/Telegram/SourceFiles/core/application.cpp +++ b/Telegram/SourceFiles/core/application.cpp @@ -44,6 +44,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_updates.h" #include "calls/calls_instance.h" #include "countries/countries_manager.h" +#include "iv/iv_delegate_impl.h" #include "iv/iv_instance.h" #include "lang/lang_file_parser.h" #include "lang/lang_translator.h" @@ -163,7 +164,8 @@ Application::Application() , _domain(std::make_unique(cDataFile())) , _exportManager(std::make_unique()) , _calls(std::make_unique()) -, _iv(std::make_unique()) +, _iv(std::make_unique( + Ui::CreateChild(this))) , _langpack(std::make_unique()) , _langCloudManager(std::make_unique(langpack())) , _emojiKeywords(std::make_unique()) @@ -1368,6 +1370,25 @@ Window::Controller *Application::windowFor( return activePrimaryWindow(); } +Window::Controller *Application::findWindow( + not_null widget) const { + const auto window = widget->window(); + if (_lastActiveWindow && _lastActiveWindow->widget() == window) { + return _lastActiveWindow; + } + for (const auto &[account, primary] : _primaryWindows) { + if (primary->widget() == window) { + return primary.get(); + } + } + for (const auto &[history, secondary] : _secondaryWindows) { + if (secondary->widget() == window) { + return secondary.get(); + } + } + return nullptr; +} + Window::Controller *Application::activeWindow() const { return _lastActiveWindow; } diff --git a/Telegram/SourceFiles/core/application.h b/Telegram/SourceFiles/core/application.h index 123d1010a..08a29a35e 100644 --- a/Telegram/SourceFiles/core/application.h +++ b/Telegram/SourceFiles/core/application.h @@ -47,6 +47,7 @@ class Session; namespace Iv { class Instance; +class DelegateImpl; } // namespace Iv namespace Ui { @@ -165,6 +166,8 @@ public: bool hasActiveWindow(not_null session) const; [[nodiscard]] bool savingPositionFor( not_null window) const; + [[nodiscard]] Window::Controller *findWindow( + not_null widget) const; [[nodiscard]] Window::Controller *activeWindow() const; [[nodiscard]] Window::Controller *activePrimaryWindow() const; [[nodiscard]] Window::Controller *separateWindowForAccount( diff --git a/Telegram/SourceFiles/core/core_settings.cpp b/Telegram/SourceFiles/core/core_settings.cpp index 787339246..b4f770876 100644 --- a/Telegram/SourceFiles/core/core_settings.cpp +++ b/Telegram/SourceFiles/core/core_settings.cpp @@ -134,6 +134,8 @@ QByteArray Settings::serialize() const { LogPosition(_windowPosition, u"Window"_q); const auto mediaViewPosition = Serialize(_mediaViewPosition); LogPosition(_mediaViewPosition, u"Viewer"_q); + const auto ivPosition = Serialize(_ivPosition); + LogPosition(_ivPosition, u"IV"_q); const auto proxy = _proxy.serialize(); const auto skipLanguages = _skipTranslationLanguages.current(); @@ -209,7 +211,8 @@ QByteArray Settings::serialize() const { + Serialize::stringSize(_playbackDeviceId.current()) + Serialize::stringSize(_captureDeviceId.current()) + Serialize::stringSize(_callPlaybackDeviceId.current()) - + Serialize::stringSize(_callCaptureDeviceId.current()); + + Serialize::stringSize(_callCaptureDeviceId.current()) + + Serialize::bytearraySize(ivPosition); auto result = QByteArray(); result.reserve(size); @@ -353,7 +356,8 @@ QByteArray Settings::serialize() const { << _playbackDeviceId.current() << _captureDeviceId.current() << _callPlaybackDeviceId.current() - << _callCaptureDeviceId.current(); + << _callCaptureDeviceId.current() + << ivPosition; } Ensures(result.size() == size); @@ -469,6 +473,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) { base::flat_set recentEmojiSkip; qint32 trayIconMonochrome = (_trayIconMonochrome.current() ? 1 : 0); qint32 ttlVoiceClickTooltipHidden = _ttlVoiceClickTooltipHidden.current() ? 1 : 0; + QByteArray ivPosition; stream >> themesAccentColors; if (!stream.atEnd()) { @@ -747,6 +752,9 @@ void Settings::addFromSerialized(const QByteArray &serialized) { ? QString() : legacyCallCaptureDeviceId; } + if (!stream.atEnd()) { + stream >> ivPosition; + } if (stream.status() != QDataStream::Ok) { LOG(("App Error: " "Bad data for Core::Settings::constructFromSerialized()")); @@ -945,6 +953,9 @@ void Settings::addFromSerialized(const QByteArray &serialized) { _recentEmojiSkip = std::move(recentEmojiSkip); _trayIconMonochrome = (trayIconMonochrome == 1); _ttlVoiceClickTooltipHidden = (ttlVoiceClickTooltipHidden == 1); + if (!ivPosition.isEmpty()) { + _ivPosition = Deserialize(ivPosition); + } } QString Settings::getSoundPath(const QString &key) const { diff --git a/Telegram/SourceFiles/core/core_settings.h b/Telegram/SourceFiles/core/core_settings.h index 82aa7c427..93e0727d7 100644 --- a/Telegram/SourceFiles/core/core_settings.h +++ b/Telegram/SourceFiles/core/core_settings.h @@ -863,6 +863,13 @@ public: _ttlVoiceClickTooltipHidden = value; } + [[nodiscard]] const WindowPosition &ivPosition() const { + return _ivPosition; + } + void setIvPosition(const WindowPosition &position) { + _ivPosition = position; + } + [[nodiscard]] static bool ThirdColumnByDefault(); [[nodiscard]] static float64 DefaultDialogsWidthRatio(); @@ -990,6 +997,7 @@ private: std::optional _macRoundIconDigest; rpl::variable _storiesClickTooltipHidden = false; rpl::variable _ttlVoiceClickTooltipHidden = false; + WindowPosition _ivPosition; bool _tabbedReplacedWithInfo = false; // per-window rpl::event_stream _tabbedReplacedWithInfoValue; // per-window diff --git a/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp b/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp index c50c9ddf7..2cf19510a 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp @@ -127,7 +127,7 @@ constexpr auto kMaxOriginalEntryLines = 8192; if (const auto controller = my.sessionWindow.get()) { if (const auto iv = webpage->iv.get()) { const auto hash = ExtractHash(webpage, text); - Core::App().iv().show(controller->uiShow(), iv, hash); + Core::App().iv().show(controller, iv, hash); return; } else { HiddenUrlClickHandler::Open(webpage->url, context.other); diff --git a/Telegram/SourceFiles/iv/iv_controller.cpp b/Telegram/SourceFiles/iv/iv_controller.cpp index 66eef977d..fcbab153a 100644 --- a/Telegram/SourceFiles/iv/iv_controller.cpp +++ b/Telegram/SourceFiles/iv/iv_controller.cpp @@ -194,8 +194,11 @@ namespace { } // namespace -Controller::Controller(Fn showShareBox) -: _updateStyles([=] { +Controller::Controller( + not_null delegate, + Fn showShareBox) +: _delegate(delegate) +, _updateStyles([=] { const auto str = EscapeForScriptString(ComputeStyles()); if (_webview) { _webview->eval("IV.updateStyles('" + str + "');"); @@ -359,9 +362,15 @@ void Controller::createWindow() { updateTitleGeometry(width); }, _subtitle->lifetime()); - window->setGeometry({ 200, 200, 600, 800 }); + window->setGeometry(_delegate->ivGeometry()); window->setMinimumSize({ st::windowMinWidth, st::windowMinHeight }); + window->geometryValue( + ) | rpl::distinct_until_changed( + ) | rpl::skip(1) | rpl::start_with_next([=] { + _delegate->ivSaveGeometry(window); + }, window->lifetime()); + _container = Ui::CreateChild(window->window()); rpl::combine( window->sizeValue(), diff --git a/Telegram/SourceFiles/iv/iv_controller.h b/Telegram/SourceFiles/iv/iv_controller.h index f8352f0d3..85132b12b 100644 --- a/Telegram/SourceFiles/iv/iv_controller.h +++ b/Telegram/SourceFiles/iv/iv_controller.h @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/invoke_queued.h" #include "base/object_ptr.h" #include "base/unique_qptr.h" +#include "iv/iv_delegate.h" #include "ui/effects/animations.h" #include "ui/text/text.h" @@ -46,7 +47,9 @@ struct ShareBoxDescriptor { class Controller final { public: - explicit Controller(Fn showShareBox); + Controller( + not_null delegate, + Fn showShareBox); ~Controller(); struct Event { @@ -115,6 +118,8 @@ private: void showShareMenu(); void destroyShareMenu(); + const not_null _delegate; + std::unique_ptr _window; std::unique_ptr _subtitleWrap; rpl::variable _subtitleText; diff --git a/Telegram/SourceFiles/iv/iv_delegate.h b/Telegram/SourceFiles/iv/iv_delegate.h new file mode 100644 index 000000000..fd94cac0a --- /dev/null +++ b/Telegram/SourceFiles/iv/iv_delegate.h @@ -0,0 +1,19 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +namespace Iv { + +class Delegate { +public: + virtual void ivSetLastSourceWindow(not_null window) = 0; + [[nodiscard]] virtual QRect ivGeometry() const = 0; + virtual void ivSaveGeometry(not_null window) = 0; +}; + +} // namespace Iv diff --git a/Telegram/SourceFiles/iv/iv_delegate_impl.cpp b/Telegram/SourceFiles/iv/iv_delegate_impl.cpp new file mode 100644 index 000000000..5ac753d17 --- /dev/null +++ b/Telegram/SourceFiles/iv/iv_delegate_impl.cpp @@ -0,0 +1,120 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "iv/iv_delegate_impl.h" + +#include "core/application.h" +#include "core/core_settings.h" +#include "mainwindow.h" +#include "window/main_window.h" +#include "window/window_controller.h" +#include "styles/style_window.h" + +#include +#include +#include + +namespace Iv { +namespace { + +[[nodiscard]] Core::WindowPosition DefaultPosition() { + auto center = qApp->primaryScreen()->geometry().center(); + const auto moncrc = [&] { + if (const auto active = Core::App().activeWindow()) { + const auto widget = active->widget(); + center = widget->geometry().center(); + if (const auto screen = widget->screen()) { + return Platform::ScreenNameChecksum(screen->name()); + } + } + return Core::App().settings().windowPosition().moncrc; + }(); + return { + .moncrc = moncrc, + .scale = cScale(), + .x = (center.x() - st::ivWidthDefault / 2), + .y = (center.y() - st::ivHeightDefault / 2), + .w = st::ivWidthDefault, + .h = st::ivHeightDefault, + }; +} + +} // namespace + +void DelegateImpl::ivSetLastSourceWindow(not_null window) { + _lastSourceWindow = window; +} + +QRect DelegateImpl::ivGeometry() const { + const auto found = _lastSourceWindow + ? Core::App().findWindow(_lastSourceWindow) + : nullptr; + + const auto saved = Core::App().settings().ivPosition(); + const auto adjusted = Core::AdjustToScale(saved, u"IV"_q); + const auto initial = DefaultPosition(); + auto result = initial.rect(); + if (const auto window = found ? found : Core::App().activeWindow()) { + result = window->widget()->countInitialGeometry( + adjusted, + initial, + { st::ivWidthMin, st::ivHeightMin }); + } + return result; +} + +void DelegateImpl::ivSaveGeometry(not_null window) { + if (!window->windowHandle()) { + return; + } + const auto state = window->windowHandle()->windowState(); + if (state == Qt::WindowMinimized) { + return; + } + const auto &savedPosition = Core::App().settings().ivPosition(); + auto realPosition = savedPosition; + if (state == Qt::WindowMaximized) { + realPosition.maximized = 1; + realPosition.moncrc = 0; + DEBUG_LOG(("IV 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(("IV 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::ivWidthMin, st::ivHeightMin }); + if (realPosition.w >= st::ivWidthMin + && realPosition.h >= st::ivHeightMin + && realPosition != savedPosition) { + DEBUG_LOG(("IV 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().setIvPosition(realPosition); + Core::App().saveSettingsDelayed(); + } +} + +} // namespace Iv diff --git a/Telegram/SourceFiles/iv/iv_delegate_impl.h b/Telegram/SourceFiles/iv/iv_delegate_impl.h new file mode 100644 index 000000000..32b15ae8f --- /dev/null +++ b/Telegram/SourceFiles/iv/iv_delegate_impl.h @@ -0,0 +1,27 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "iv/iv_delegate.h" + +namespace Iv { + +class DelegateImpl final : public Delegate { +public: + DelegateImpl() = default; + + void ivSetLastSourceWindow(not_null window) override; + [[nodiscard]] QRect ivGeometry() const override; + void ivSaveGeometry(not_null window) override; + +private: + QPointer _lastSourceWindow; + +}; + +} // namespace Iv diff --git a/Telegram/SourceFiles/iv/iv_instance.cpp b/Telegram/SourceFiles/iv/iv_instance.cpp index 50545ed32..517415435 100644 --- a/Telegram/SourceFiles/iv/iv_instance.cpp +++ b/Telegram/SourceFiles/iv/iv_instance.cpp @@ -62,6 +62,7 @@ constexpr auto kKeepLoadingParts = 8; class Shown final : public base::has_weak_ptr { public: Shown( + not_null delegate, std::shared_ptr show, not_null data, QString hash); @@ -143,6 +144,7 @@ private: int64 total = 0); void requestFail(Webview::DataRequest request); + const not_null _delegate; const not_null _session; std::shared_ptr _show; QString _id; @@ -166,10 +168,12 @@ private: }; Shown::Shown( + not_null delegate, std::shared_ptr show, not_null data, QString hash) -: _session(&show->session()) +: _delegate(delegate) +, _session(&show->session()) , _show(show) { prepare(data, hash); } @@ -398,7 +402,9 @@ void Shown::createController() { const auto showShareBox = [=](ShareBoxDescriptor &&descriptor) { return shareBox(std::move(descriptor)); }; - _controller = std::make_unique(std::move(showShareBox)); + _controller = std::make_unique( + _delegate, + std::move(showShareBox)); _controller->events( ) | rpl::start_to_stream(_events, _controller->lifetime()); @@ -795,10 +801,19 @@ void Shown::minimize() { } } -Instance::Instance() = default; +Instance::Instance(not_null delegate) : _delegate(delegate) { +} Instance::~Instance() = default; +void Instance::show( + not_null controller, + not_null data, + QString hash) { + _delegate->ivSetLastSourceWindow(controller->widget()); + show(controller->uiShow(), data, hash); +} + void Instance::show( std::shared_ptr show, not_null data, @@ -813,7 +828,7 @@ void Instance::show( _shown->moveTo(data, hash); return; } - _shown = std::make_unique(show, data, hash); + _shown = std::make_unique(_delegate, show, data, hash); _shownSession = session; _shown->events() | rpl::start_with_next([=](Controller::Event event) { using Type = Controller::Event::Type; diff --git a/Telegram/SourceFiles/iv/iv_instance.h b/Telegram/SourceFiles/iv/iv_instance.h index 6e14527e6..ba3d8f72c 100644 --- a/Telegram/SourceFiles/iv/iv_instance.h +++ b/Telegram/SourceFiles/iv/iv_instance.h @@ -7,11 +7,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "iv/iv_delegate.h" + namespace Main { class Session; class SessionShow; } // namespace Main +namespace Window { +class SessionController; +} // namespace Window + namespace Iv { class Data; @@ -19,9 +25,13 @@ class Shown; class Instance final { public: - Instance(); + explicit Instance(not_null delegate); ~Instance(); + void show( + not_null controller, + not_null data, + QString hash); void show( std::shared_ptr show, not_null data, @@ -42,6 +52,8 @@ private: void processJoinChannel(const QString &context); void requestFull(not_null session, const QString &id); + const not_null _delegate; + std::unique_ptr _shown; Main::Session *_shownSession = nullptr; base::flat_set> _tracking; diff --git a/Telegram/SourceFiles/window/window.style b/Telegram/SourceFiles/window/window.style index 8afc8d243..8b13c0a36 100644 --- a/Telegram/SourceFiles/window/window.style +++ b/Telegram/SourceFiles/window/window.style @@ -319,6 +319,11 @@ windowArchiveToast: Toast(defaultToast) { maxWidth: boxWideWidth; } +ivWidthMin: 380px; +ivHeightMin: 480px; +ivWidthDefault: 600px; +ivHeightDefault: 800px; + // Windows specific winQuitIcon: icon {{ "win_quit", windowFg }}; diff --git a/Telegram/cmake/td_iv.cmake b/Telegram/cmake/td_iv.cmake index 1ef5a9604..602abf41c 100644 --- a/Telegram/cmake/td_iv.cmake +++ b/Telegram/cmake/td_iv.cmake @@ -15,6 +15,7 @@ PRIVATE iv/iv_controller.h iv/iv_data.cpp iv/iv_data.h + iv/iv_delegate.h iv/iv_pch.h iv/iv_prepare.cpp iv/iv_prepare.h