QWindowKit  1.5.1.0
Cross-platform window customization framework
Loading...
Searching...
No Matches
windows10borderhandler_p.h
1// Copyright (C) 2023-present Stdware Collections (https://www.github.com/stdware)
2// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao)
3// SPDX-License-Identifier: Apache-2.0
4
5#ifndef WINDOWS10BORDERHANDLER_P_H
6#define WINDOWS10BORDERHANDLER_P_H
7
8//
9// W A R N I N G !!!
10// -----------------
11//
12// This file is not part of the QWindowKit API. It is used purely as an
13// implementation detail. This header file may change from version to
14// version without notice, or may even be removed.
15//
16
17#include <QtGui/QWindow>
18#include <QtGui/QMouseEvent>
19
20#include <QWKCore/qwindowkit_windows.h>
21#include <QWKCore/private/qwkglobal_p.h>
22#include <QWKCore/private/abstractwindowcontext_p.h>
23
24namespace QWK {
25
26 class Windows10BorderHandler : public NativeEventFilter, public SharedEventFilter {
27 public:
28 inline Windows10BorderHandler(AbstractWindowContext *ctx) : ctx(ctx) {
29 ctx->installNativeEventFilter(this);
30 ctx->installSharedEventFilter(this);
31 }
32
33 inline void setupNecessaryAttributes() {
34 if (!isWin11OrGreater()) {
35 // https://github.com/microsoft/terminal/blob/71a6f26e6ece656084e87de1a528c4a8072eeabd/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp#L940
36 // Must extend top frame to client area
37 static QVariant defaultMargins = QVariant::fromValue(QMargins(0, 1, 0, 0));
38 ctx->setWindowAttribute(QStringLiteral("extra-margins"), defaultMargins);
39 }
40
41 // Enable dark mode by default, otherwise the system borders are white
42 ctx->setWindowAttribute(QStringLiteral("dark-mode"), true);
43 }
44
45 inline bool isNormalWindow() const {
46 return !(ctx->window()->windowStates() &
47 (Qt::WindowMinimized | Qt::WindowMaximized | Qt::WindowFullScreen));
48 }
49
50 inline void drawBorderEmulated(QPainter *painter, const QRect &rect) {
51 QRegion region(rect);
52 void *args[] = {
53 painter,
54 const_cast<QRect *>(&rect),
55 &region,
56 };
57 ctx->virtual_hook(AbstractWindowContext::DrawWindows10BorderHook_Emulated, args);
58 }
59
60 inline void drawBorderNative() {
61 ctx->virtual_hook(AbstractWindowContext::DrawWindows10BorderHook_Native, nullptr);
62 }
63
64 inline int borderThickness() const {
65 return ctx->windowAttribute(QStringLiteral("border-thickness")).toInt();
66 }
67
68 inline void updateExtraMargins(bool windowActive) {
69 if (isWin11OrGreater()) {
70 return;
71 }
72
73 // ### FIXME: transparent seam
74 if (windowActive) {
75 // Restore margins when the window is active
76 static QVariant defaultMargins = QVariant::fromValue(QMargins(0, 1, 0, 0));
77 ctx->setWindowAttribute(QStringLiteral("extra-margins"), defaultMargins);
78 return;
79 }
80
81 // https://github.com/microsoft/terminal/blob/71a6f26e6ece656084e87de1a528c4a8072eeabd/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp#L904
82 // When the window is inactive, there is a transparency bug in the top
83 // border, and we need to extend the non-client area to the whole title
84 // bar.
85 QRect frame = ctx->windowAttribute(QStringLiteral("window-rect")).toRect();
86 QMargins margins{0, -frame.top(), 0, 0};
87 ctx->setWindowAttribute(QStringLiteral("extra-margins"), QVariant::fromValue(margins));
88 }
89
90 virtual void updateGeometry() = 0;
91
92 virtual bool isWindowActive() const {
93 return ctx->window()->isActive();
94 }
95
96 protected:
97 bool nativeEventFilter(const QByteArray &eventType, void *message,
98 QT_NATIVE_EVENT_RESULT_TYPE *result) override {
99 Q_UNUSED(eventType)
100
101 const auto msg = static_cast<const MSG *>(message);
102 switch (msg->message) {
103 case WM_DPICHANGED: {
104 updateGeometry();
105 updateExtraMargins(isWindowActive());
106 break;
107 }
108
109 case WM_ACTIVATE: {
110 updateExtraMargins(LOWORD(msg->wParam) != WA_INACTIVE);
111 break;
112 }
113
114 case WM_THEMECHANGED:
115 case WM_SYSCOLORCHANGE:
116 case WM_DWMCOLORIZATIONCOLORCHANGED: {
117 // If we do not refresh this property, the native border will turn white
118 // permanently (like the dark mode is turned off) after the user changes
119 // the accent color in system personalization settings.
120 // So we need this ugly hack to re-apply dark mode to get rid of this
121 // strange Windows bug.
122 if (ctx->windowAttribute(QStringLiteral("dark-mode")).toBool()) {
123 ctx->setWindowAttribute(QStringLiteral("dark-mode"), true);
124 }
125 break;
126 }
127
128 default:
129 break;
130 }
131 return false;
132 }
133
134 bool sharedEventFilter(QObject *obj, QEvent *event) override {
135 Q_UNUSED(obj)
136
137 if (event->type() == QEvent::WinIdChange) {
138 if (ctx->windowId()) {
139 setupNecessaryAttributes();
140 updateGeometry();
141 }
142 }
143 return false;
144 }
145
146 protected:
147 AbstractWindowContext *ctx;
148 };
149
150}
151
152#endif // WINDOWS10BORDERHANDLER_P_H
QWindowKit namespace.
Definition abstractwindowcontext.cpp:13