From b13b4a6b5c23830b23d0169b02dffc26230b0ec3 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 7 Jul 2020 21:33:34 +0400 Subject: [PATCH] Fix system window frame toggle on Linux. --- Telegram/SourceFiles/window/main_window.cpp | 4 +- .../SourceFiles/window/window_title_qt.cpp | 60 +++++++++++++++---- Telegram/SourceFiles/window/window_title_qt.h | 5 ++ 3 files changed, 58 insertions(+), 11 deletions(-) diff --git a/Telegram/SourceFiles/window/main_window.cpp b/Telegram/SourceFiles/window/main_window.cpp index 895c7c437..e567d9380 100644 --- a/Telegram/SourceFiles/window/main_window.cpp +++ b/Telegram/SourceFiles/window/main_window.cpp @@ -641,6 +641,8 @@ void MainWindow::launchDrag(std::unique_ptr data) { } } -MainWindow::~MainWindow() = default; +MainWindow::~MainWindow() { + _title.destroy(); +} } // namespace Window diff --git a/Telegram/SourceFiles/window/window_title_qt.cpp b/Telegram/SourceFiles/window/window_title_qt.cpp index e9417d03c..555a87355 100644 --- a/Telegram/SourceFiles/window/window_title_qt.cpp +++ b/Telegram/SourceFiles/window/window_title_qt.cpp @@ -10,11 +10,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/buttons.h" #include "ui/widgets/shadow.h" #include "styles/style_window.h" +#include "base/call_delayed.h" #include #include namespace Window { +namespace { + +// If we toggle frameless window hint in maximized window, and +// show it back too quickly, the mouse position inside the window +// won't be correct (from Qt-s point of view) until we Alt-Tab from +// that window. If we show the window back with this delay it works. +constexpr auto kShowAfterFramelessToggleDelay = crl::time(1000); + +} // namespace TitleWidgetQt::TitleWidgetQt(QWidget *parent) : TitleWidget(parent) @@ -45,11 +55,35 @@ TitleWidgetQt::TitleWidgetQt(QWidget *parent) QCoreApplication::instance()->installEventFilter(this); - window()->setWindowFlag(Qt::FramelessWindowHint, true); + _windowWasFrameless = (window()->windowFlags() & Qt::FramelessWindowHint) != 0; + if (!_windowWasFrameless) { + toggleFramelessWindow(true); + } setAttribute(Qt::WA_OpaquePaintEvent); resize(width(), _st.height); } +TitleWidgetQt::~TitleWidgetQt() { + restoreCursor(); + if (!_windowWasFrameless) { + toggleFramelessWindow(false); + } +} + +void TitleWidgetQt::toggleFramelessWindow(bool enabled) { + // setWindowFlag calls setParent(parentWidget(), newFlags), which + // always calls hide() explicitly, we have to show() the window back. + const auto top = window(); + const auto hidden = top->isHidden(); + top->setWindowFlag(Qt::FramelessWindowHint, enabled); + if (!hidden) { + base::call_delayed( + kShowAfterFramelessToggleDelay, + top, + [=] { top->show(); }); + } +} + void TitleWidgetQt::init() { connect( window()->windowHandle(), @@ -103,7 +137,7 @@ void TitleWidgetQt::mouseDoubleClickEvent(QMouseEvent *e) { bool TitleWidgetQt::eventFilter(QObject *obj, QEvent *e) { if (e->type() == QEvent::MouseMove || e->type() == QEvent::MouseButtonPress) { - if(window()->isAncestorOf(static_cast(obj))) { + if (window()->isAncestorOf(static_cast(obj))) { const auto mouseEvent = static_cast(e); const auto edges = edgesFromPos(mouseEvent->windowPos().toPoint()); @@ -111,7 +145,7 @@ bool TitleWidgetQt::eventFilter(QObject *obj, QEvent *e) { updateCursor(edges); } - if(e->type() == QEvent::MouseButtonPress + if (e->type() == QEvent::MouseButtonPress && mouseEvent->button() == Qt::LeftButton && window()->windowState() != Qt::WindowMaximized) { return startResize(edges); @@ -119,9 +153,7 @@ bool TitleWidgetQt::eventFilter(QObject *obj, QEvent *e) { } } else if (e->type() == QEvent::Leave) { if (window() == static_cast(obj)) { - while (QGuiApplication::overrideCursor()) { - QGuiApplication::restoreOverrideCursor(); - } + restoreCursor(); } } @@ -196,14 +228,22 @@ Qt::Edges TitleWidgetQt::edgesFromPos(const QPoint &pos) { } } +void TitleWidgetQt::restoreCursor() { + if (_cursorOverriden) { + _cursorOverriden = false; + QGuiApplication::restoreOverrideCursor(); + } +} + void TitleWidgetQt::updateCursor(Qt::Edges edges) { if (!edges || window()->windowState() == Qt::WindowMaximized) { - while (QGuiApplication::overrideCursor()) { - QGuiApplication::restoreOverrideCursor(); - } - + restoreCursor(); return; } else if (!QGuiApplication::overrideCursor()) { + _cursorOverriden = false; + } + if (!_cursorOverriden) { + _cursorOverriden = true; QGuiApplication::setOverrideCursor(QCursor()); } diff --git a/Telegram/SourceFiles/window/window_title_qt.h b/Telegram/SourceFiles/window/window_title_qt.h index 68d4dcbce..67a80945a 100644 --- a/Telegram/SourceFiles/window/window_title_qt.h +++ b/Telegram/SourceFiles/window/window_title_qt.h @@ -24,6 +24,7 @@ namespace Window { class TitleWidgetQt : public TitleWidget { public: TitleWidgetQt(QWidget *parent); + ~TitleWidgetQt(); void init() override; @@ -40,8 +41,10 @@ private: void updateButtonsState(); void updateControlsPosition(); + void toggleFramelessWindow(bool enabled); Qt::Edges edgesFromPos(const QPoint &pos); void updateCursor(Qt::Edges edges); + void restoreCursor(); bool startResize(Qt::Edges edges); const style::WindowTitle &_st; @@ -52,6 +55,8 @@ private: bool _maximizedState = false; bool _activeState = false; + bool _windowWasFrameless = false; + bool _cursorOverriden = false; };