Minor improvements.

1. Add more comments.
2. Add a function to change window geometry through Win32 API/
3. Add a function to move the window to the center of the desktop.

Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2020-05-01 19:37:57 +08:00
parent a4423334ec
commit 63315acf75
2 changed files with 117 additions and 22 deletions

View File

@ -405,18 +405,34 @@ BOOL IsDwmCompositionEnabled() {
return SUCCEEDED(m_lpDwmIsCompositionEnabled(&enabled)) && enabled; return SUCCEEDED(m_lpDwmIsCompositionEnabled(&enabled)) && enabled;
} }
BOOL IsFullScreen(HWND handle) { WINDOWINFO GetInfoForWindow(HWND handle) {
if (handle && m_lpIsWindow(handle)) {
WINDOWINFO windowInfo; WINDOWINFO windowInfo;
SecureZeroMemory(&windowInfo, sizeof(windowInfo)); SecureZeroMemory(&windowInfo, sizeof(windowInfo));
windowInfo.cbSize = sizeof(windowInfo); windowInfo.cbSize = sizeof(windowInfo);
if (handle && m_lpIsWindow(handle)) {
m_lpGetWindowInfo(handle, &windowInfo); m_lpGetWindowInfo(handle, &windowInfo);
}
return windowInfo;
}
MONITORINFO GetMonitorInfoForWindow(HWND handle) {
MONITORINFO monitorInfo; MONITORINFO monitorInfo;
SecureZeroMemory(&monitorInfo, sizeof(monitorInfo)); SecureZeroMemory(&monitorInfo, sizeof(monitorInfo));
monitorInfo.cbSize = sizeof(monitorInfo); monitorInfo.cbSize = sizeof(monitorInfo);
if (handle && m_lpIsWindow(handle)) {
const HMONITOR monitor = const HMONITOR monitor =
m_lpMonitorFromWindow(handle, MONITOR_DEFAULTTONEAREST); m_lpMonitorFromWindow(handle, MONITOR_DEFAULTTONEAREST);
if (monitor) {
m_lpGetMonitorInfoW(monitor, &monitorInfo); m_lpGetMonitorInfoW(monitor, &monitorInfo);
}
}
return monitorInfo;
}
BOOL IsFullScreen(HWND handle) {
if (handle && m_lpIsWindow(handle)) {
const WINDOWINFO windowInfo = GetInfoForWindow(handle);
const MONITORINFO monitorInfo = GetMonitorInfoForWindow(handle);
// The only way to judge whether a window is fullscreen or not // The only way to judge whether a window is fullscreen or not
// is to compare it's size with the screen's size, there is no official // is to compare it's size with the screen's size, there is no official
// Win32 API to do this for us. // Win32 API to do this for us.
@ -606,6 +622,17 @@ void UpdateFrameMarginsForWindow(HWND handle) {
const DWMNCRENDERINGPOLICY ncrp = DWMNCRP_ENABLED; const DWMNCRENDERINGPOLICY ncrp = DWMNCRP_ENABLED;
m_lpDwmSetWindowAttribute(handle, DWMWA_NCRENDERING_POLICY, &ncrp, m_lpDwmSetWindowAttribute(handle, DWMWA_NCRENDERING_POLICY, &ncrp,
sizeof(ncrp)); sizeof(ncrp));
// Use negative values have the same effect, however, it will
// cause the window become transparent when it's maximizing or
// restoring from maximized. Just like flashing. Fixing it by
// passing positive values.
// The system won't draw the frame shadow if the window doesn't
// have a frame, so we have to extend the frame a bit to let the
// system draw the shadow. We won't see any frame even we have
// extended it because we have turned the whole window area into
// the client area in WM_NCCALCSIZE so we won't see it due to
// it's covered by the client area (in other words, it's still
// there, we just can't see it).
margins = {0, 0, 1, 0}; margins = {0, 0, 1, 0};
} }
m_lpDwmExtendFrameIntoClientArea(handle, &margins); m_lpDwmExtendFrameIntoClientArea(handle, &margins);
@ -698,7 +725,9 @@ void WinNativeEventFilter::setFramelessWindows(QVector<HWND> windows) {
} }
void WinNativeEventFilter::addFramelessWindow(HWND window, void WinNativeEventFilter::addFramelessWindow(HWND window,
const WINDOWDATA *data) { const WINDOWDATA *data,
bool center, int x, int y,
int width, int height) {
ResolveWin32APIs(); ResolveWin32APIs();
if (window && m_lpIsWindow(window) && if (window && m_lpIsWindow(window) &&
!m_framelessWindows.contains(window)) { !m_framelessWindows.contains(window)) {
@ -706,6 +735,12 @@ void WinNativeEventFilter::addFramelessWindow(HWND window,
createUserData(window, data); createUserData(window, data);
install(); install();
} }
if ((x > 0) && (y > 0) && (width > 0) && (height > 0)) {
setWindowGeometry(window, x, y, width, height);
}
if (center) {
moveWindowToDesktopCenter(window);
}
} }
void WinNativeEventFilter::removeFramelessWindow(HWND window) { void WinNativeEventFilter::removeFramelessWindow(HWND window) {
@ -901,8 +936,6 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType,
m_lpSHAppBarMessage(ABM_GETSTATE, &abd); m_lpSHAppBarMessage(ABM_GETSTATE, &abd);
// First, check if we have an auto-hide taskbar at all: // First, check if we have an auto-hide taskbar at all:
if (taskbarState & ABS_AUTOHIDE) { if (taskbarState & ABS_AUTOHIDE) {
const HMONITOR windowMonitor = m_lpMonitorFromWindow(
msg->hwnd, MONITOR_DEFAULTTONEAREST);
bool top = false, bottom = false, left = false, bool top = false, bottom = false, left = false,
right = false; right = false;
// Due to ABM_GETAUTOHIDEBAREX only exists from Win8.1, // Due to ABM_GETAUTOHIDEBAREX only exists from Win8.1,
@ -910,10 +943,8 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType,
// running on Windows 7 or Windows 8. // running on Windows 7 or Windows 8.
if (QOperatingSystemVersion::current() >= if (QOperatingSystemVersion::current() >=
QOperatingSystemVersion::Windows8_1) { QOperatingSystemVersion::Windows8_1) {
MONITORINFO monitorInfo; const MONITORINFO monitorInfo =
SecureZeroMemory(&monitorInfo, sizeof(monitorInfo)); GetMonitorInfoForWindow(msg->hwnd);
monitorInfo.cbSize = sizeof(monitorInfo);
m_lpGetMonitorInfoW(windowMonitor, &monitorInfo);
// This helper can be used to determine if there's a // This helper can be used to determine if there's a
// auto-hide taskbar on the given edge of the monitor // auto-hide taskbar on the given edge of the monitor
// we're currently on. // we're currently on.
@ -942,6 +973,9 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType,
_abd.cbSize = sizeof(_abd); _abd.cbSize = sizeof(_abd);
_abd.hWnd = m_lpFindWindowW(L"Shell_TrayWnd", nullptr); _abd.hWnd = m_lpFindWindowW(L"Shell_TrayWnd", nullptr);
if (_abd.hWnd) { if (_abd.hWnd) {
const HMONITOR windowMonitor =
m_lpMonitorFromWindow(msg->hwnd,
MONITOR_DEFAULTTONEAREST);
const HMONITOR taskbarMonitor = const HMONITOR taskbarMonitor =
m_lpMonitorFromWindow(_abd.hWnd, m_lpMonitorFromWindow(_abd.hWnd,
MONITOR_DEFAULTTOPRIMARY); MONITOR_DEFAULTTOPRIMARY);
@ -1145,12 +1179,7 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType,
} }
case WM_GETMINMAXINFO: { case WM_GETMINMAXINFO: {
// Don't cover the taskbar when maximized. // Don't cover the taskbar when maximized.
const HMONITOR monitor = const MONITORINFO monitorInfo = GetMonitorInfoForWindow(msg->hwnd);
m_lpMonitorFromWindow(msg->hwnd, MONITOR_DEFAULTTONEAREST);
MONITORINFO monitorInfo;
SecureZeroMemory(&monitorInfo, sizeof(monitorInfo));
monitorInfo.cbSize = sizeof(monitorInfo);
m_lpGetMonitorInfoW(monitor, &monitorInfo);
const RECT rcWorkArea = monitorInfo.rcWork; const RECT rcWorkArea = monitorInfo.rcWork;
const RECT rcMonitorArea = monitorInfo.rcMonitor; const RECT rcMonitorArea = monitorInfo.rcMonitor;
auto &mmi = *reinterpret_cast<LPMINMAXINFO>(msg->lParam); auto &mmi = *reinterpret_cast<LPMINMAXINFO>(msg->lParam);
@ -1212,6 +1241,27 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType,
case WM_DWMCOMPOSITIONCHANGED: case WM_DWMCOMPOSITIONCHANGED:
UpdateFrameMarginsForWindow(msg->hwnd); UpdateFrameMarginsForWindow(msg->hwnd);
break; break;
case WM_DPICHANGED:
// Sent when the effective dots per inch (dpi) for a window has
// changed. You won't get this message until Windows 8.1
// wParam: The HIWORD of the wParam contains the Y-axis value of
// the new dpi of the window. The LOWORD of the wParam contains
// the X-axis value of the new DPI of the window. For example,
// 96, 120, 144, or 192. The values of the X-axis and the Y-axis
// are identical for Windows apps.
// lParam: A pointer to a RECT structure that provides a suggested
// size and position of the current window scaled for the new DPI.
// The expectation is that apps will reposition and resize windows
// based on the suggestions provided by lParam when handling this
// message.
// Return value: If an application processes this message, it
// should return zero.
// See MSDN for more accurate and detailed information:
// https://docs.microsoft.com/en-us/windows/win32/hidpi/wm-dpichanged
// Note: Qt will do the scaling automatically, there is no need
// to do this yourself. See:
// https://code.qt.io/cgit/qt/qtbase.git/tree/src/plugins/platforms/windows/qwindowscontext.cpp
break;
default: default:
break; break;
} }
@ -1337,3 +1387,32 @@ int WinNativeEventFilter::getSystemMetric(HWND handle, SystemMetric metric,
} }
return -1; return -1;
} }
void WinNativeEventFilter::setWindowGeometry(HWND handle, const int x,
const int y, const int width,
const int height) {
if (handle && m_lpIsWindow(handle) && (x > 0) && (y > 0) && (width > 0) &&
(height > 0)) {
const qreal dpr = GetDevicePixelRatioForWindow(handle);
m_lpMoveWindow(handle, x, y, std::round(width * dpr),
std::round(height * dpr), TRUE);
}
}
void WinNativeEventFilter::moveWindowToDesktopCenter(HWND handle) {
if (handle && m_lpIsWindow(handle)) {
const WINDOWINFO windowInfo = GetInfoForWindow(handle);
const MONITORINFO monitorInfo = GetMonitorInfoForWindow(handle);
// If we want to move a window to the center of the desktop,
// I think we should use rcMonitor, the monitor's whole area,
// to calculate the new coordinates of our window, not rcWork.
const LONG mw =
monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left;
const LONG mh =
monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top;
const LONG ww = windowInfo.rcWindow.right - windowInfo.rcWindow.left;
const LONG wh = windowInfo.rcWindow.bottom - windowInfo.rcWindow.top;
m_lpMoveWindow(handle, std::round((mw - ww) / 2.0),
std::round((mh - wh) / 2.0), ww, wh, TRUE);
}
}

View File

@ -59,8 +59,13 @@ public:
static QVector<HWND> framelessWindows(); static QVector<HWND> framelessWindows();
static void setFramelessWindows(QVector<HWND> windows); static void setFramelessWindows(QVector<HWND> windows);
// Make the given window become frameless. // Make the given window become frameless.
// The width and height will be scaled automatically according to DPI. Don't
// scale them yourself. Just pass the original value. If you don't want to
// change them, pass negative values to the parameters.
static void addFramelessWindow(HWND window, static void addFramelessWindow(HWND window,
const WINDOWDATA *data = nullptr); const WINDOWDATA *data = nullptr,
bool center = false, int x = -1, int y = -1,
int width = -1, int height = -1);
static void removeFramelessWindow(HWND window); static void removeFramelessWindow(HWND window);
static void clearFramelessWindows(); static void clearFramelessWindows();
@ -74,6 +79,8 @@ public:
static WINDOWDATA *windowData(HWND window); static WINDOWDATA *windowData(HWND window);
// Change settings globally, not a specific window. // Change settings globally, not a specific window.
// These values will be scaled automatically according to DPI, don't scale
// them yourself. Just pass the original value.
static void setBorderWidth(int bw); static void setBorderWidth(int bw);
static void setBorderHeight(int bh); static void setBorderHeight(int bh);
static void setTitlebarHeight(int tbh); static void setTitlebarHeight(int tbh);
@ -89,6 +96,15 @@ public:
static void updateWindow(HWND handle, bool triggerFrameChange = true, static void updateWindow(HWND handle, bool triggerFrameChange = true,
bool redraw = true); bool redraw = true);
// Change the geometry of a window through Win32 API.
// The width and height will be scaled automatically according to DPI. So
// just pass the original value.
static void setWindowGeometry(HWND handle, const int x, const int y,
const int width, const int height);
// Move the window to the center of the desktop.
static void moveWindowToDesktopCenter(HWND handle);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
bool nativeEventFilter(const QByteArray &eventType, void *message, bool nativeEventFilter(const QByteArray &eventType, void *message,
qintptr *result) override; qintptr *result) override;