Allow Ui::Window to become fullscreen.

This commit is contained in:
John Preston 2020-08-12 20:45:57 +04:00
parent 608b25bd32
commit 3d5108a878
7 changed files with 114 additions and 27 deletions

View file

@ -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

View file

@ -6,7 +6,7 @@
//
#include "ui/platform/ui_platform_window.h"
#include "ui/rp_widget.h"
#include "ui/widgets/window.h"
#include <QtGui/QWindow>
#include <QtGui/QtEvents>
@ -41,34 +41,74 @@ void BasicWindowHelper::setGeometry(QRect rect) {
_window->setGeometry(rect);
}
void BasicWindowHelper::setBodyTitleArea(Fn<bool(QPoint)> testMethod) {
void BasicWindowHelper::showFullScreen() {
_window->showFullScreen();
}
void BasicWindowHelper::showNormal() {
_window->showNormal();
}
void BasicWindowHelper::setBodyTitleArea(
Fn<WindowTitleHitTestFlags(QPoint)> testMethod) {
Expects(!_bodyTitleAreaTestMethod);
if (!testMethod) {
return;
}
_bodyTitleAreaTestMethod = std::move(testMethod);
if (customBodyTitleAreaHandling()) {
return;
}
body()->events() | rpl::start_with_next([=](not_null<QEvent*> e) {
const auto hitTest = [&] {
return bodyTitleAreaHit(
static_cast<QMouseEvent*>(e.get())->pos());
};
if (e->type() == QEvent::MouseButtonDblClick) {
if (bodyTitleAreaHit(static_cast<QMouseEvent*>(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<QMouseEvent*>(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<QMouseEvent*>(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());
}

View file

@ -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<WindowTitleHitTestFlag>;
namespace Platform {
class BasicWindowHelper {
public:
explicit BasicWindowHelper(not_null<RpWidget*> window);
virtual ~BasicWindowHelper() = default;
[[nodiscard]] virtual not_null<RpWidget*> 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<bool(QPoint)> testMethod);
void setBodyTitleArea(Fn<WindowTitleHitTestFlags(QPoint)> testMethod);
protected:
[[nodiscard]] not_null<RpWidget*> 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<RpWidget*> _window;
Fn<bool(QPoint)> _bodyTitleAreaTestMethod;
Fn<WindowTitleHitTestFlags(QPoint)> _bodyTitleAreaTestMethod;
bool _mousePressed = false;
};

View file

@ -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(),

View file

@ -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;
};

View file

@ -48,7 +48,16 @@ void Window::setGeometry(QRect rect) {
_helper->setGeometry(rect);
}
void Window::setBodyTitleArea(Fn<bool(QPoint)> testMethod) {
void Window::showFullScreen() {
_helper->showFullScreen();
}
void Window::showNormal() {
_helper->showNormal();
}
void Window::setBodyTitleArea(
Fn<WindowTitleHitTestFlags(QPoint)> testMethod) {
_helper->setBodyTitleArea(std::move(testMethod));
}

View file

@ -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<WindowTitleHitTestFlag>;
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<bool(QPoint)> testMethod);
void showFullScreen();
void showNormal();
void setBodyTitleArea(Fn<WindowTitleHitTestFlags(QPoint)> testMethod);
private:
const std::unique_ptr<Platform::BasicWindowHelper> _helper;