From 841908fe3105edfff9a0c87d58e24c8531c638b1 Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Sat, 18 Jul 2020 09:06:29 +0400 Subject: [PATCH] Read decoration layout property from gtk --- Telegram/CMakeLists.txt | 1 + Telegram/SourceFiles/core/application.cpp | 2 + Telegram/SourceFiles/core/core_settings.h | 14 ++++ .../SourceFiles/platform/linux/linux_libs.cpp | 10 +++ .../platform/linux/specific_linux.cpp | 63 +++++++++++++++ .../SourceFiles/platform/mac/specific_mac.mm | 11 +++ .../SourceFiles/platform/platform_specific.h | 3 + .../SourceFiles/platform/win/specific_win.cpp | 11 +++ .../window/window_controls_layout.h | 24 ++++++ .../SourceFiles/window/window_title_qt.cpp | 79 ++++++++++++++++++- Telegram/SourceFiles/window/window_title_qt.h | 4 + 11 files changed, 218 insertions(+), 4 deletions(-) create mode 100644 Telegram/SourceFiles/window/window_controls_layout.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 4577e61f2..6ffc7d897 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -1089,6 +1089,7 @@ PRIVATE window/window_connecting_widget.h window/window_controller.cpp window/window_controller.h + window/window_controls_layout.h window/window_filters_menu.cpp window/window_filters_menu.h window/window_history_hider.cpp diff --git a/Telegram/SourceFiles/core/application.cpp b/Telegram/SourceFiles/core/application.cpp index cda0041f6..ecb567702 100644 --- a/Telegram/SourceFiles/core/application.cpp +++ b/Telegram/SourceFiles/core/application.cpp @@ -205,6 +205,8 @@ void Application::run() { return; } + Core::App().settings().setWindowControlsLayout(Platform::WindowControlsLayout()); + _translator = std::make_unique(); QCoreApplication::instance()->installTranslator(_translator.get()); diff --git a/Telegram/SourceFiles/core/core_settings.h b/Telegram/SourceFiles/core/core_settings.h index b7560cf38..95d9b597d 100644 --- a/Telegram/SourceFiles/core/core_settings.h +++ b/Telegram/SourceFiles/core/core_settings.h @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "window/themes/window_themes_embedded.h" +#include "window/window_controls_layout.h" enum class SendFilesWay; enum class RectPart; @@ -440,6 +441,18 @@ public: [[nodiscard]] rpl::producer systemDarkModeEnabledChanges() const { return _systemDarkModeEnabled.changes(); } + void setWindowControlsLayout(Window::ControlsLayout value) { + _windowControlsLayout = value; + } + [[nodiscard]] Window::ControlsLayout windowControlsLayout() const { + return _windowControlsLayout.current(); + } + [[nodiscard]] rpl::producer windowControlsLayoutValue() const { + return _windowControlsLayout.value(); + } + [[nodiscard]] rpl::producer windowControlsLayoutChanges() const { + return _windowControlsLayout.changes(); + } [[nodiscard]] static bool ThirdColumnByDefault(); [[nodiscard]] float64 DefaultDialogsWidthRatio(); @@ -510,6 +523,7 @@ private: rpl::variable _nativeWindowFrame = false; rpl::variable> _systemDarkMode = std::nullopt; rpl::variable _systemDarkModeEnabled = false; + rpl::variable _windowControlsLayout; bool _tabbedReplacedWithInfo = false; // per-window rpl::event_stream _tabbedReplacedWithInfoValue; // per-window diff --git a/Telegram/SourceFiles/platform/linux/linux_libs.cpp b/Telegram/SourceFiles/platform/linux/linux_libs.cpp index c6590d3e0..0991ceef4 100644 --- a/Telegram/SourceFiles/platform/linux/linux_libs.cpp +++ b/Telegram/SourceFiles/platform/linux/linux_libs.cpp @@ -181,6 +181,12 @@ void DarkModeChanged() { Core::App().settings().setSystemDarkMode(Platform::IsDarkMode()); }); } + +void DecorationLayoutChanged() { + Core::Sandbox::Instance().customEnterFromEventLoop([] { + Core::App().settings().setWindowControlsLayout(Platform::WindowControlsLayout()); + }); +} #endif // !TDESKTOP_DISABLE_GTK_INTEGRATION } // namespace @@ -289,6 +295,10 @@ void start() { if (!gtk_check_version(3, 0, 0)) { g_signal_connect(settings, "notify::gtk-application-prefer-dark-theme", G_CALLBACK(DarkModeChanged), nullptr); } + + if (!gtk_check_version(3, 12, 0)) { + g_signal_connect(settings, "notify::gtk-decoration-layout", G_CALLBACK(DecorationLayoutChanged), nullptr); + } } else { LOG(("Could not load gtk-3 or gtk-x11-2.0!")); } diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.cpp b/Telegram/SourceFiles/platform/linux/specific_linux.cpp index 1092ea370..008de8bf8 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/specific_linux.cpp @@ -580,6 +580,18 @@ bool StartWaylandResize(QWindow *window, Qt::Edges edges) { return false; } +Window::Control GtkKeywordToWindowControl(const QString &keyword) { + if (keyword == qstr("minimize")) { + return Window::Control::Minimize; + } else if (keyword == qstr("maximize")) { + return Window::Control::Maximize; + } else if (keyword == qstr("close")) { + return Window::Control::Close; + } + + return Window::Control::Unknown; +} + } // namespace void SetApplicationIcon(const QIcon &icon) { @@ -939,6 +951,57 @@ bool StartSystemResize(QWindow *window, Qt::Edges edges) { } } +Window::ControlsLayout WindowControlsLayout() { +#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION + if (Libs::GtkSettingSupported() + && Libs::GtkLoaded() + && Libs::gtk_check_version != nullptr + && !Libs::gtk_check_version(3, 12, 0)) { + const auto decorationLayout = Libs::GtkSetting("gtk-decoration-layout").split(':'); + + std::vector controlsLeft; + ranges::transform( + decorationLayout[0].split(','), + ranges::back_inserter(controlsLeft), + GtkKeywordToWindowControl + ); + + std::vector controlsRight; + if (decorationLayout.size() > 1) { + ranges::transform( + decorationLayout[1].split(','), + ranges::back_inserter(controlsRight), + GtkKeywordToWindowControl + ); + } + + Window::ControlsLayout controls; + controls.left = controlsLeft; + controls.right = controlsRight; + + return controls; + } +#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION + + Window::ControlsLayout controls; + + if (DesktopEnvironment::IsUnity()) { + controls.left = { + Window::Control::Close, + Window::Control::Minimize, + Window::Control::Maximize, + }; + } else { + controls.right = { + Window::Control::Minimize, + Window::Control::Maximize, + Window::Control::Close, + }; + } + + return controls; +} + } // namespace Platform namespace { diff --git a/Telegram/SourceFiles/platform/mac/specific_mac.mm b/Telegram/SourceFiles/platform/mac/specific_mac.mm index 30255ea91..91f98ea9d 100644 --- a/Telegram/SourceFiles/platform/mac/specific_mac.mm +++ b/Telegram/SourceFiles/platform/mac/specific_mac.mm @@ -283,6 +283,17 @@ void IgnoreApplicationActivationRightNow() { objc_ignoreApplicationActivationRightNow(); } +Window::ControlsLayout WindowControlsLayout() { + Window::ControlsLayout controls; + controls.left = { + Window::Control::Close, + Window::Control::Minimize, + Window::Control::Maximize, + }; + + return controls; +} + } // namespace Platform void psNewVersion() { diff --git a/Telegram/SourceFiles/platform/platform_specific.h b/Telegram/SourceFiles/platform/platform_specific.h index acbb45564..efd75cd63 100644 --- a/Telegram/SourceFiles/platform/platform_specific.h +++ b/Telegram/SourceFiles/platform/platform_specific.h @@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "window/window_controls_layout.h" + namespace Platform { void start(); @@ -52,6 +54,7 @@ bool TrayIconSupported(); QImage GetImageFromClipboard(); bool StartSystemMove(QWindow *window); bool StartSystemResize(QWindow *window, Qt::Edges edges); +Window::ControlsLayout WindowControlsLayout(); namespace ThirdParty { diff --git a/Telegram/SourceFiles/platform/win/specific_win.cpp b/Telegram/SourceFiles/platform/win/specific_win.cpp index 256fa4204..df6d316e5 100644 --- a/Telegram/SourceFiles/platform/win/specific_win.cpp +++ b/Telegram/SourceFiles/platform/win/specific_win.cpp @@ -418,6 +418,17 @@ bool AutostartSupported() { return !IsWindowsStoreBuild(); } +Window::ControlsLayout WindowControlsLayout() { + Window::ControlsLayout controls; + controls.right = { + Window::Control::Minimize, + Window::Control::Maximize, + Window::Control::Close, + }; + + return controls; +} + } // namespace Platform namespace { diff --git a/Telegram/SourceFiles/window/window_controls_layout.h b/Telegram/SourceFiles/window/window_controls_layout.h new file mode 100644 index 000000000..cb8c47bd7 --- /dev/null +++ b/Telegram/SourceFiles/window/window_controls_layout.h @@ -0,0 +1,24 @@ +/* +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 Window { + +enum class Control { + Unknown, + Minimize, + Maximize, + Close, +}; + +struct ControlsLayout { + std::vector left; + std::vector right; +}; + +} // namespace Window diff --git a/Telegram/SourceFiles/window/window_title_qt.cpp b/Telegram/SourceFiles/window/window_title_qt.cpp index c14472b3d..02cd57498 100644 --- a/Telegram/SourceFiles/window/window_title_qt.cpp +++ b/Telegram/SourceFiles/window/window_title_qt.cpp @@ -10,6 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "platform/platform_specific.h" #include "ui/widgets/buttons.h" #include "ui/widgets/shadow.h" +#include "core/core_settings.h" +#include "core/application.h" #include "styles/style_window.h" #include "base/call_delayed.h" @@ -54,6 +56,11 @@ TitleWidgetQt::TitleWidgetQt(QWidget *parent) }); _close->setPointerCursor(false); + Core::App().settings().windowControlsLayoutChanges( + ) | rpl::start_with_next([=] { + updateControlsPosition(); + }, lifetime()); + QCoreApplication::instance()->installEventFilter(this); _windowWasFrameless = (window()->windowFlags() & Qt::FramelessWindowHint) != 0; @@ -106,10 +113,74 @@ void TitleWidgetQt::paintEvent(QPaintEvent *e) { } void TitleWidgetQt::updateControlsPosition() { - auto right = 0; - _close->moveToRight(right, 0); right += _close->width(); - _maximizeRestore->moveToRight(right, 0); right += _maximizeRestore->width(); - _minimize->moveToRight(right, 0); + const auto controlsLayout = Core::App().settings().windowControlsLayout(); + const auto controlsLeft = controlsLayout.left; + const auto controlsRight = controlsLayout.right; + + if (ranges::contains(controlsLeft, Control::Minimize) + || ranges::contains(controlsRight, Control::Minimize)) { + _minimize->show(); + } else { + _minimize->hide(); + } + + if (ranges::contains(controlsLeft, Control::Maximize) + || ranges::contains(controlsRight, Control::Maximize)) { + _maximizeRestore->show(); + } else { + _maximizeRestore->hide(); + } + + if (ranges::contains(controlsLeft, Control::Close) + || ranges::contains(controlsRight, Control::Close)) { + _close->show(); + } else { + _close->hide(); + } + + updateControlsPositionBySide(controlsLeft, false); + updateControlsPositionBySide(controlsRight, true); +} + +void TitleWidgetQt::updateControlsPositionBySide( + const std::vector &controls, + bool right) { + const auto preparedControls = right + ? (ranges::view::reverse(controls) | ranges::to_vector) + : controls; + + auto position = 0; + for (const auto &control : preparedControls) { + switch (control) { + case Control::Minimize: + if (right) { + _minimize->moveToRight(position, 0); + } else { + _minimize->moveToLeft(position, 0); + } + + position += _minimize->width(); + break; + case Control::Maximize: + if (right) { + _maximizeRestore->moveToRight(position, 0); + } else { + _maximizeRestore->moveToLeft(position, 0); + } + + position += _maximizeRestore->width(); + break; + case Control::Close: + if (right) { + _close->moveToRight(position, 0); + } else { + _close->moveToLeft(position, 0); + } + + position += _close->width(); + break; + } + } } void TitleWidgetQt::resizeEvent(QResizeEvent *e) { diff --git a/Telegram/SourceFiles/window/window_title_qt.h b/Telegram/SourceFiles/window/window_title_qt.h index 3b90489cb..c3536587d 100644 --- a/Telegram/SourceFiles/window/window_title_qt.h +++ b/Telegram/SourceFiles/window/window_title_qt.h @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "window/window_title.h" +#include "window/window_controls_layout.h" #include "base/object_ptr.h" namespace style { @@ -40,6 +41,9 @@ private: void windowStateChanged(Qt::WindowState state = Qt::WindowNoState); void updateButtonsState(); void updateControlsPosition(); + void updateControlsPositionBySide( + const std::vector &controls, + bool right); void toggleFramelessWindow(bool enabled); Qt::Edges edgesFromPos(const QPoint &pos);