diff --git a/ui/colors.palette b/ui/colors.palette index 6231b0f..f13b568 100644 --- a/ui/colors.palette +++ b/ui/colors.palette @@ -538,6 +538,7 @@ notificationBg: windowBg; // custom notification window background // calls callBg: #26282cf2; // old phone call popup background callBgOpaque: #1b1f23 | callBg; // phone call popup background +callBgButton: #1b1f2356 | callBg; // phone call window control buttons bg callNameFg: #ffffff; // phone call popup name text callFingerprintBg: #00000066; // phone call popup emoji fingerprint background callStatusFg: #aaabac; // phone call popup status text diff --git a/ui/platform/ui_platform_window.cpp b/ui/platform/ui_platform_window.cpp index 9e38667..a7ebaa5 100644 --- a/ui/platform/ui_platform_window.cpp +++ b/ui/platform/ui_platform_window.cpp @@ -6,7 +6,7 @@ // #include "ui/platform/ui_platform_window.h" -#include "ui/rp_widget.h" +#include "ui/widgets/window.h" #include #include @@ -41,34 +41,74 @@ void BasicWindowHelper::setGeometry(QRect rect) { _window->setGeometry(rect); } -void BasicWindowHelper::setBodyTitleArea(Fn testMethod) { +void BasicWindowHelper::showFullScreen() { + _window->showFullScreen(); +} + +void BasicWindowHelper::showNormal() { + _window->showNormal(); +} + +void BasicWindowHelper::setBodyTitleArea( + Fn testMethod) { Expects(!_bodyTitleAreaTestMethod); if (!testMethod) { return; } _bodyTitleAreaTestMethod = std::move(testMethod); - if (customBodyTitleAreaHandling()) { - return; - } body()->events() | rpl::start_with_next([=](not_null e) { + const auto hitTest = [&] { + return bodyTitleAreaHit( + static_cast(e.get())->pos()); + }; if (e->type() == QEvent::MouseButtonDblClick) { - if (bodyTitleAreaHit(static_cast(e.get())->pos())) { + _mousePressed = false; + const auto hit = hitTest(); + if (hit & WindowTitleHitTestFlag::Maximize) { const auto state = _window->windowState(); if (state & Qt::WindowMaximized) { _window->setWindowState(state & ~Qt::WindowMaximized); } else { _window->setWindowState(state | Qt::WindowMaximized); } + } else if (hit & WindowTitleHitTestFlag::FullScreen) { + if (_window->isFullScreen()) { + showNormal(); + } else { + showFullScreen(); + } } + } else if (e->type() == QEvent::MouseButtonRelease) { + _mousePressed = false; + } else if (e->type() == QEvent::MouseButtonPress + && (static_cast(e.get())->button() + == Qt::LeftButton)) { + _mousePressed = true; + +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) || defined DESKTOP_APP_QT_PATCHED +#ifndef Q_OS_MAC // On macOS startSystemMove() doesn't work from here. } else if (e->type() == QEvent::MouseMove) { const auto mouseEvent = static_cast(e.get()); - if (bodyTitleAreaHit(mouseEvent->pos()) - && (mouseEvent->buttons() & Qt::LeftButton)) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) || defined DESKTOP_APP_QT_PATCHED + if (_mousePressed +#ifndef Q_OS_WIN // We handle fullscreen startSystemMove() only on Windows. + && !_window->isFullScreen() +#endif // !Q_OS_WIN + && (hitTest() & WindowTitleHitTestFlag::Move)) { + +#ifdef Q_OS_WIN + if (_window->isFullScreen()) { + // On Windows we just jump out of fullscreen + // like we do automatically for dragging a window + // by title bar in a maximized state. + showNormal(); + } +#endif // Q_OS_WIN + _mousePressed = false; _window->windowHandle()->startSystemMove(); -#endif // Qt >= 5.15 || DESKTOP_APP_QT_PATCHED } +#endif // !Q_OS_MAC +#endif // Qt >= 5.15 || DESKTOP_APP_QT_PATCHED } }, body()->lifetime()); } diff --git a/ui/platform/ui_platform_window.h b/ui/platform/ui_platform_window.h index 533875f..8932b05 100644 --- a/ui/platform/ui_platform_window.h +++ b/ui/platform/ui_platform_window.h @@ -6,6 +6,8 @@ // #pragma once +#include "base/flags.h" + namespace style { struct WindowTitle; } // namespace style @@ -13,12 +15,15 @@ struct WindowTitle; namespace Ui { class RpWidget; +enum class WindowTitleHitTestFlag; +using WindowTitleHitTestFlags = base::flags; namespace Platform { class BasicWindowHelper { public: explicit BasicWindowHelper(not_null window); + virtual ~BasicWindowHelper() = default; [[nodiscard]] virtual not_null body(); virtual void setTitle(const QString &title); @@ -26,24 +31,26 @@ public: virtual void setMinimumSize(QSize size); virtual void setFixedSize(QSize size); virtual void setGeometry(QRect rect); - virtual ~BasicWindowHelper() = default; + virtual void showFullScreen(); + virtual void showNormal(); - void setBodyTitleArea(Fn testMethod); + void setBodyTitleArea(Fn testMethod); protected: [[nodiscard]] not_null window() const { return _window; } - [[nodiscard]] bool bodyTitleAreaHit(QPoint point) const { - return _bodyTitleAreaTestMethod && _bodyTitleAreaTestMethod(point); - } - [[nodiscard]] virtual bool customBodyTitleAreaHandling() { - return false; + [[nodiscard]] WindowTitleHitTestFlags bodyTitleAreaHit( + QPoint point) const { + return _bodyTitleAreaTestMethod + ? _bodyTitleAreaTestMethod(point) + : WindowTitleHitTestFlag(); } private: const not_null _window; - Fn _bodyTitleAreaTestMethod; + Fn _bodyTitleAreaTestMethod; + bool _mousePressed = false; }; diff --git a/ui/platform/win/ui_window_win.cpp b/ui/platform/win/ui_window_win.cpp index 3428e1e..5e2652b 100644 --- a/ui/platform/win/ui_window_win.cpp +++ b/ui/platform/win/ui_window_win.cpp @@ -135,6 +135,22 @@ void WindowHelper::setGeometry(QRect rect) { window()->setGeometry(rect.marginsAdded({ 0, _title->height(), 0, 0 })); } +void WindowHelper::showFullScreen() { + if (!_isFullScreen) { + _isFullScreen = true; + updateMargins(); + } + window()->showFullScreen(); +} + +void WindowHelper::showNormal() { + window()->showNormal(); + if (_isFullScreen) { + _isFullScreen = false; + updateMargins(); + } +} + void WindowHelper::init() { style::PaletteChanged( ) | rpl::start_with_next([=] { @@ -313,9 +329,7 @@ bool WindowHelper::handleNativeEvent( if (!window()->rect().contains(mapped)) { *result = HTTRANSPARENT; } else if (!_title->geometry().contains(mapped)) { - *result = bodyTitleAreaHit(mapped - QPoint(0, _title->height())) - ? HTCAPTION - : HTCLIENT; + *result = HTCLIENT; } else switch (_title->hitTest(_title->pos() + mapped)) { case HitTestResult::Client: case HitTestResult::SysButton: *result = HTCLIENT; break; @@ -444,6 +458,9 @@ void WindowHelper::updateMargins() { _marginsDelta = QMargins(); } + if (_isFullScreen) { + margins = QMargins(); + } if (const auto native = QGuiApplication::platformNativeInterface()) { native->setWindowProperty( window()->windowHandle()->handle(), diff --git a/ui/platform/win/ui_window_win.h b/ui/platform/win/ui_window_win.h index d8003bc..c74eb0b 100644 --- a/ui/platform/win/ui_window_win.h +++ b/ui/platform/win/ui_window_win.h @@ -27,15 +27,13 @@ public: void setMinimumSize(QSize size) override; void setFixedSize(QSize size) override; void setGeometry(QRect rect) override; + void showFullScreen() override; + void showNormal() override; private: class NativeFilter; friend class NativeFilter; - bool customBodyTitleAreaHandling() override { - return true; - } - void init(); void updateMargins(); void updateSystemMenu(); @@ -56,6 +54,7 @@ private: bool _updatingMargins = false; QMargins _marginsDelta; HMENU _menu = nullptr; + bool _isFullScreen = false; }; diff --git a/ui/widgets/window.cpp b/ui/widgets/window.cpp index 2b8538e..382d4fb 100644 --- a/ui/widgets/window.cpp +++ b/ui/widgets/window.cpp @@ -48,7 +48,16 @@ void Window::setGeometry(QRect rect) { _helper->setGeometry(rect); } -void Window::setBodyTitleArea(Fn testMethod) { +void Window::showFullScreen() { + _helper->showFullScreen(); +} + +void Window::showNormal() { + _helper->showNormal(); +} + +void Window::setBodyTitleArea( + Fn testMethod) { _helper->setBodyTitleArea(std::move(testMethod)); } diff --git a/ui/widgets/window.h b/ui/widgets/window.h index 3d2c6a8..73dcd17 100644 --- a/ui/widgets/window.h +++ b/ui/widgets/window.h @@ -7,6 +7,7 @@ #pragma once #include "ui/rp_widget.h" +#include "base/flags.h" namespace style { struct WindowTitle; @@ -17,6 +18,17 @@ namespace Platform { class BasicWindowHelper; } // namespace Platform +enum class WindowTitleHitTestFlag { + None = 0x00, + Move = 0x01, + Maximize = 0x02, + FullScreen = 0x04, +}; +inline constexpr bool is_flag_type(WindowTitleHitTestFlag) { + return true; +} +using WindowTitleHitTestFlags = base::flags; + class Window : public RpWidget { public: explicit Window(QWidget *parent = nullptr); @@ -30,7 +42,9 @@ public: void setMinimumSize(QSize size); void setFixedSize(QSize size); void setGeometry(QRect rect); - void setBodyTitleArea(Fn testMethod); + void showFullScreen(); + void showNormal(); + void setBodyTitleArea(Fn testMethod); private: const std::unique_ptr _helper;