win: add a little delay to some operations

Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2022-11-20 12:56:36 +08:00
parent 04f254556d
commit 648876b6b0
2 changed files with 27 additions and 17 deletions

View File

@ -27,6 +27,7 @@
#include <QtCore/qmutex.h> #include <QtCore/qmutex.h>
#include <QtCore/qvariant.h> #include <QtCore/qvariant.h>
#include <QtCore/qcoreapplication.h> #include <QtCore/qcoreapplication.h>
#include <QtCore/qtimer.h>
#include <QtGui/qwindow.h> #include <QtGui/qwindow.h>
#include "framelessmanager.h" #include "framelessmanager.h"
#include "framelessmanager_p.h" #include "framelessmanager_p.h"
@ -639,7 +640,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
const WPARAM wParam = msg->wParam; const WPARAM wParam = msg->wParam;
const LPARAM lParam = msg->lParam; const LPARAM lParam = msg->lParam;
switch (uMsg) { switch (uMsg) {
#if (QT_VERSION < QT_VERSION_CHECK(5, 9, 0)) #if (QT_VERSION < QT_VERSION_CHECK(5, 9, 0)) // Qt has done this for us since 5.9.0
case WM_NCCREATE: { case WM_NCCREATE: {
// Enable automatic DPI scaling for the non-client area of the window, // Enable automatic DPI scaling for the non-client area of the window,
// such as the caption bar, the scrollbars, and the menu bar. We need // such as the caption bar, the scrollbars, and the menu bar. We need
@ -1112,7 +1113,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
return true; return true;
} }
} }
#if (QT_VERSION < QT_VERSION_CHECK(6, 2, 2)) #if (QT_VERSION < QT_VERSION_CHECK(6, 2, 2)) // I contributed this to Qt since 6.2.2
case WM_WINDOWPOSCHANGING: { case WM_WINDOWPOSCHANGING: {
// Tell Windows to discard the entire contents of the client area, as re-using // Tell Windows to discard the entire contents of the client area, as re-using
// parts of the client area would lead to jitter during resize. // parts of the client area would lead to jitter during resize.
@ -1127,13 +1128,17 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
<< hwnd2str(hWnd) << ": QDpi(" << dpiX << ", " << dpiY << ")."; << hwnd2str(hWnd) << ": QDpi(" << dpiX << ", " << dpiY << ").";
// Sync the internal window frame margins with the latest DPI. // Sync the internal window frame margins with the latest DPI.
Utils::updateInternalWindowFrameMargins(data.params.getWindowHandle(), true); Utils::updateInternalWindowFrameMargins(data.params.getWindowHandle(), true);
// For some unknown reason, Qt sometimes won't re-paint the window contents after // Here we need a little delay because event filters are processed before
// the DPI changes, and in my experiments the controls should be moved to our // Qt's own window message handlers.
// desired geometry already, the only issue is we don't get the updated appearance QTimer::singleShot(50, [data](){ // Copy "data" intentionally, otherwise it'll go out of scope when Qt finally use it.
// of our window. And we can workaround this issue by simply triggering a resize // For some unknown reason, Qt sometimes won't re-paint the window contents after
// event manually. There's no need to increase/decrease the window size and then // the DPI changes, and in my experiments the controls should be moved to our
// change it back, just give Qt our current window size is sufficient enough. // desired geometry already, the only issue is we don't get the updated appearance
data.params.setWindowSize(data.params.getWindowSize()); // of our window. And we can workaround this issue by simply triggering a resize
// event manually. There's no need to increase/decrease the window size and then
// change it back, just give Qt our current window size is sufficient enough.
data.params.setWindowSize(data.params.getWindowSize());
});
} break; } break;
case WM_DWMCOMPOSITIONCHANGED: { case WM_DWMCOMPOSITIONCHANGED: {
// Re-apply the custom window frame if recovered from the basic theme. // Re-apply the custom window frame if recovered from the basic theme.

View File

@ -25,6 +25,7 @@
#include "framelessmanager_p.h" #include "framelessmanager_p.h"
#include <QtCore/qmutex.h> #include <QtCore/qmutex.h>
#include <QtCore/qcoreapplication.h> #include <QtCore/qcoreapplication.h>
#include <QtCore/qtimer.h>
#include <QtGui/qscreen.h> #include <QtGui/qscreen.h>
#include <QtGui/qwindow.h> #include <QtGui/qwindow.h>
#include <QtGui/qfontdatabase.h> #include <QtGui/qfontdatabase.h>
@ -217,14 +218,18 @@ void FramelessManagerPrivate::addWindow(const SystemParameters &params)
g_helper()->data[windowId].screenChangeConnection = g_helper()->data[windowId].screenChangeConnection =
connect(window, &QWindow::screenChanged, window, [windowId, window](QScreen *screen){ connect(window, &QWindow::screenChanged, window, [windowId, window](QScreen *screen){
Q_UNUSED(screen); Q_UNUSED(screen);
// Force a WM_NCCALCSIZE event to inform Windows about our custom window frame, // Add a little delay here, make sure it happens after Qt has processed the window
// this is only necessary when the window is being moved cross monitors. // messages.
Utils::triggerFrameChange(windowId); QTimer::singleShot(50, window, [windowId, window](){
// For some reason the window is not repainted correctly when moving cross monitors, // Force a WM_NCCALCSIZE event to inform Windows about our custom window frame,
// we workaround this issue by force a re-paint and re-layout of the window by triggering // this is only necessary when the window is being moved cross monitors.
// a resize event manually. Although the actual size does not change, the issue we Utils::triggerFrameChange(windowId);
// observed disappeared indeed, amazingly. // For some reason the window is not repainted correctly when moving cross monitors,
window->resize(window->size()); // we workaround this issue by force a re-paint and re-layout of the window by triggering
// a resize event manually. Although the actual size does not change, the issue we
// observed disappeared indeed, amazingly.
window->resize(window->size());
});
}); });
g_helper()->mutex.unlock(); g_helper()->mutex.unlock();
} }