Revert "Make maximized geometry handling less bugged on Windows"

This reverts commit b05b7bd502.
This commit is contained in:
Ilya Fedin 2022-06-17 19:45:03 +04:00 committed by John Preston
parent 74cd53e1d1
commit 30810032dc
2 changed files with 155 additions and 71 deletions

View file

@ -20,10 +20,12 @@
#include <QtGui/QWindow>
#include <QtWidgets/QStyleFactory>
#include <QtWidgets/QApplication>
#include <qpa/qplatformnativeinterface.h>
#include <dwmapi.h>
#include <uxtheme.h>
#include <windowsx.h>
Q_DECLARE_METATYPE(QMargins);
namespace Ui {
namespace Platform {
@ -37,10 +39,6 @@ constexpr auto kDWMWA_TEXT_COLOR = DWORD(36);
UINT(__stdcall *GetDpiForWindow)(_In_ HWND hwnd);
int(__stdcall *GetSystemMetricsForDpi)(
_In_ int nIndex,
_In_ UINT dpi);
[[nodiscard]] bool GetDpiForWindowSupported() {
static const auto Result = [&] {
#define LOAD_SYMBOL(lib, name) base::Platform::LoadMethod(lib, #name, name)
@ -51,16 +49,6 @@ int(__stdcall *GetSystemMetricsForDpi)(
return Result;
}
[[nodiscard]] bool GetSystemMetricsForDpiSupported() {
static const auto Result = [&] {
#define LOAD_SYMBOL(lib, name) base::Platform::LoadMethod(lib, #name, name)
const auto user32 = base::Platform::SafeLoadLibrary(L"User32.dll");
return LOAD_SYMBOL(user32, GetSystemMetricsForDpi);
#undef LOAD_SYMBOL
}();
return Result;
}
[[nodiscard]] bool IsCompositionEnabled() {
auto result = BOOL(FALSE);
const auto success = (DwmIsCompositionEnabled(&result) == S_OK);
@ -119,11 +107,29 @@ int(__stdcall *GetSystemMetricsForDpi)(
return bAutoHidden;
}
void FixAeroSnap(HWND handle) {
SetWindowLongPtr(
handle,
GWL_STYLE,
GetWindowLongPtr(handle, GWL_STYLE) | WS_CAPTION | WS_THICKFRAME);
}
[[nodiscard]] HWND ResolveWindowHandle(not_null<QWidget*> widget) {
if (!::Platform::IsWindows8OrGreater()) {
widget->setWindowFlag(Qt::FramelessWindowHint);
}
const auto result = GetWindowHandle(widget);
if (!::Platform::IsWindows8OrGreater()) {
FixAeroSnap(result);
}
return result;
}
} // namespace
WindowHelper::WindowHelper(not_null<RpWidget*> window)
: BasicWindowHelper(window)
, _handle(GetWindowHandle(window))
, _handle(ResolveWindowHandle(window))
, _title(Ui::CreateChild<TitleWidget>(window.get()))
, _body(Ui::CreateChild<RpWidget>(window.get()))
, _shadow(std::in_place, window, st::windowShadowFg->c)
@ -175,11 +181,10 @@ void WindowHelper::setTitleStyle(const style::WindowTitle &st) {
void WindowHelper::setNativeFrame(bool enabled) {
if (!::Platform::IsWindows8OrGreater()) {
const auto style = GetWindowLongPtr(_handle, GWL_STYLE);
SetWindowLongPtr(
_handle,
GWL_STYLE,
enabled ? (style | WS_CAPTION) : (style & ~WS_CAPTION));
window()->windowHandle()->setFlag(Qt::FramelessWindowHint, !enabled);
if (!enabled) {
FixAeroSnap(_handle);
}
}
_title->setVisible(!enabled);
if (enabled) {
@ -189,7 +194,9 @@ void WindowHelper::setNativeFrame(bool enabled) {
_shadow->setResizeEnabled(!fixedSize());
initialShadowUpdate();
}
updateMargins();
updateWindowFrameColors();
fixMaximizedWindow();
SetWindowPos(
_handle,
0,
@ -246,6 +253,7 @@ void WindowHelper::setGeometry(QRect rect) {
void WindowHelper::showFullScreen() {
if (!_isFullScreen) {
_isFullScreen = true;
updateMargins();
updateCornersRounding();
}
window()->showFullScreen();
@ -255,6 +263,7 @@ void WindowHelper::showNormal() {
window()->showNormal();
if (_isFullScreen) {
_isFullScreen = false;
updateMargins();
updateCornersRounding();
}
}
@ -299,6 +308,8 @@ void WindowHelper::init() {
size.height() - (titleShown ? titleHeight : 0));
}, _body->lifetime());
updateMargins();
if (!::Platform::IsWindows8OrGreater()) {
SetWindowTheme(_handle, L" ", L" ");
QApplication::setStyle(QStyleFactory::create("Windows"));
@ -372,7 +383,7 @@ bool WindowHelper::handleNativeEvent(
} return true;
case WM_NCCALCSIZE: {
if (_title->isHidden() || window()->isFullScreen() || !wParam) {
if (_title->isHidden() || !wParam) {
return false;
}
WINDOWPLACEMENT wp;
@ -380,38 +391,31 @@ bool WindowHelper::handleNativeEvent(
if (GetWindowPlacement(_handle, &wp)
&& (wp.showCmd == SW_SHOWMAXIMIZED)) {
const auto r = &((LPNCCALCSIZE_PARAMS)lParam)->rgrc[0];
const auto dpi = _dpi.current();
const auto style = GetWindowLongPtr(_handle, GWL_STYLE);
const auto borderWidth = ((GetSystemMetricsForDpiSupported() && dpi)
? GetSystemMetricsForDpi(SM_CXSIZEFRAME, dpi)
+ GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi)
: GetSystemMetrics(SM_CXSIZEFRAME)
+ GetSystemMetrics(SM_CXPADDEDBORDER))
- ((style & WS_CAPTION) ? 0 : 1);
r->left += borderWidth;
r->right -= borderWidth;
r->top += borderWidth;
r->bottom -= borderWidth;
const auto hMonitor = MonitorFromWindow(
_handle,
const auto hMonitor = MonitorFromPoint(
{ (r->left + r->right) / 2, (r->top + r->bottom) / 2 },
MONITOR_DEFAULTTONEAREST);
MONITORINFO mi;
mi.cbSize = sizeof(mi);
UINT uEdge = (UINT)-1;
if (GetMonitorInfo(hMonitor, &mi)
&& IsTaskbarAutoHidden(&mi.rcMonitor, &uEdge)) {
switch (uEdge) {
case ABE_LEFT: r->left += 1; break;
case ABE_RIGHT: r->right -= 1; break;
case ABE_TOP: r->top += 1; break;
case ABE_BOTTOM: r->bottom -= 1; break;
if (hMonitor) {
MONITORINFO mi;
mi.cbSize = sizeof(mi);
if (GetMonitorInfo(hMonitor, &mi)) {
*r = mi.rcWork;
UINT uEdge = (UINT)-1;
if (IsTaskbarAutoHidden(&mi.rcMonitor, &uEdge)) {
switch (uEdge) {
case ABE_LEFT: r->left += 1; break;
case ABE_RIGHT: r->right -= 1; break;
case ABE_TOP: r->top += 1; break;
case ABE_BOTTOM: r->bottom -= 1; break;
}
}
}
}
if (result) *result = 0;
} else {
if (result) *result = WVR_REDRAW;
}
} return true;
return true;
}
case WM_NCRBUTTONUP: {
if (_title->isHidden()) {
@ -473,6 +477,7 @@ bool WindowHelper::handleNativeEvent(
}
window()->windowHandle()->windowStateChanged(state);
}
updateMargins();
if (_shadow) {
_title->refreshAdditionalPaddings(_handle);
const auto changes = (wParam == SIZE_MINIMIZED
@ -486,27 +491,6 @@ bool WindowHelper::handleNativeEvent(
} return false;
case WM_SHOWWINDOW: {
const auto style = GetWindowLongPtr(_handle, GWL_STYLE);
if (!::Platform::IsWindows8OrGreater()
&& !_title->isHidden()
&& (style & WS_CAPTION)) {
SetWindowLongPtr(
_handle,
GWL_STYLE,
style & ~WS_CAPTION);
SetWindowPos(
_handle,
0,
0,
0,
0,
0,
SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE);
}
if (_shadow) {
const auto style = GetWindowLongPtr(_handle, GWL_STYLE);
const auto changes = WindowShadow::Change::Resized
@ -529,9 +513,12 @@ bool WindowHelper::handleNativeEvent(
return false;
}
POINT p{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
ScreenToClient(_handle, &p);
const auto mapped = QPoint(p.x, p.y) / window()->devicePixelRatioF();
const auto p = MAKEPOINTS(lParam);
auto r = RECT();
GetWindowRect(_handle, &r);
const auto mapped = QPoint(
p.x - r.left + _marginsDelta.left(),
p.y - r.top + _marginsDelta.top());
*result = [&] {
if (!window()->rect().contains(mapped)) {
return HTTRANSPARENT;
@ -691,6 +678,99 @@ void WindowHelper::updateWindowFrameColors(bool active) {
sizeof(COLORREF));
}
void WindowHelper::updateMargins() {
if (_updatingMargins) return;
_updatingMargins = true;
const auto guard = gsl::finally([&] { _updatingMargins = false; });
RECT r, a;
GetClientRect(_handle, &r);
a = r;
const auto style = GetWindowLongPtr(_handle, GWL_STYLE);
const auto styleEx = GetWindowLongPtr(_handle, GWL_EXSTYLE);
AdjustWindowRectEx(&a, style, false, styleEx);
auto margins = QMargins(
a.left - r.left,
a.top - r.top,
r.right - a.right,
r.bottom - a.bottom);
if (style & WS_MAXIMIZE) {
RECT w, m;
GetWindowRect(_handle , &w);
m = w;
HMONITOR hMonitor = MonitorFromRect(&w, MONITOR_DEFAULTTONEAREST);
if (hMonitor) {
MONITORINFO mi;
mi.cbSize = sizeof(mi);
GetMonitorInfo(hMonitor, &mi);
m = mi.rcWork;
}
_marginsDelta = QMargins(
w.left - m.left,
w.top - m.top,
m.right - w.right,
m.bottom - w.bottom);
margins.setLeft(margins.left() - _marginsDelta.left());
margins.setRight(margins.right() - _marginsDelta.right());
margins.setBottom(margins.bottom() - _marginsDelta.bottom());
margins.setTop(margins.top() - _marginsDelta.top());
} else if (!_marginsDelta.isNull()) {
RECT w;
GetWindowRect(_handle, &w);
SetWindowPos(
_handle,
0,
0,
0,
w.right - w.left - _marginsDelta.left() - _marginsDelta.right(),
w.bottom - w.top - _marginsDelta.top() - _marginsDelta.bottom(),
(SWP_NOMOVE
| SWP_NOSENDCHANGING
| SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOREPOSITION));
_marginsDelta = QMargins();
}
if (_isFullScreen || _title->isHidden()) {
margins = QMargins();
if (_title->isHidden()) {
_marginsDelta = QMargins();
}
}
if (const auto native = QGuiApplication::platformNativeInterface()) {
native->setWindowProperty(
window()->windowHandle()->handle(),
"WindowsCustomMargins",
QVariant::fromValue<QMargins>(margins));
}
}
void WindowHelper::fixMaximizedWindow() {
auto r = RECT();
GetClientRect(_handle, &r);
const auto style = GetWindowLongPtr(_handle, GWL_STYLE);
const auto styleEx = GetWindowLongPtr(_handle, GWL_EXSTYLE);
AdjustWindowRectEx(&r, style, false, styleEx);
if (style & WS_MAXIMIZE) {
auto w = RECT();
GetWindowRect(_handle, &w);
if (const auto hMonitor = MonitorFromRect(&w, MONITOR_DEFAULTTONEAREST)) {
MONITORINFO mi;
mi.cbSize = sizeof(mi);
GetMonitorInfo(hMonitor, &mi);
const auto m = mi.rcWork;
SetWindowPos(_handle, 0, 0, 0, m.right - m.left - _marginsDelta.left() - _marginsDelta.right(), m.bottom - m.top - _marginsDelta.top() - _marginsDelta.bottom(), SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREPOSITION);
}
}
}
HWND GetWindowHandle(not_null<QWidget*> widget) {
const auto toplevel = widget->window();
toplevel->createWinId();

View file

@ -51,10 +51,12 @@ public:
private:
void init();
void updateMargins();
void updateWindowFrameColors();
void updateWindowFrameColors(bool active);
void initialShadowUpdate();
void updateCornersRounding();
void fixMaximizedWindow();
[[nodiscard]] bool handleNativeEvent(
UINT msg,
WPARAM wParam,
@ -79,6 +81,8 @@ private:
rpl::event_stream<HitTestResult> _systemButtonDown;
std::optional<WindowShadow> _shadow;
rpl::variable<uint> _dpi;
QMargins _marginsDelta;
bool _updatingMargins = false;
bool _isFullScreen = false;
};