Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qwindowscontext.cpp
Go to the documentation of this file.
1// Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
2// Copyright (C) 2016 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qwindowscontext.h"
7#include "qwindowswindow.h"
8#include "qwindowskeymapper.h"
12#include "qtwindowsglobal.h"
13#include "qwindowsmenu.h"
16#if QT_CONFIG(tabletevent)
18#endif
19#include "qwindowstheme.h"
20#include <private/qguiapplication_p.h>
21#if QT_CONFIG(accessibility)
23#endif
24#if QT_CONFIG(sessionmanager)
25# include <private/qsessionmanager_p.h>
27#endif
28#include "qwindowsscreen.h"
29#include "qwindowstheme.h"
30
31#include <QtGui/qwindow.h>
32#include <qpa/qwindowsysteminterface.h>
33#include <qpa/qwindowsysteminterface_p.h>
34#include <qpa/qplatformnativeinterface.h>
35#include <QtGui/qguiapplication.h>
36#include <QtGui/qopenglcontext.h>
37#include <QtGui/qpointingdevice.h>
38
39#include <QtCore/qset.h>
40#include <QtCore/qhash.h>
41#include <QtCore/qlibraryinfo.h>
42#include <QtCore/qstringlist.h>
43#include <QtCore/qdebug.h>
44#include <QtCore/qsysinfo.h>
45#include <QtCore/qscopedpointer.h>
46#include <QtCore/quuid.h>
47#include <QtCore/private/qwinregistry_p.h>
48#include <QtCore/private/qfactorycacheregistration_p.h>
49#include <QtCore/private/qsystemerror_p.h>
50
51#include <QtGui/private/qwindowsguieventdispatcher_p.h>
52
53#include <stdlib.h>
54#include <stdio.h>
55#include <windowsx.h>
56#include <dbt.h>
57#include <wtsapi32.h>
58#include <shellscalingapi.h>
59
61
62using namespace Qt::StringLiterals;
63
64Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window")
65Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events")
66Q_LOGGING_CATEGORY(lcQpaGl, "qt.qpa.gl")
67Q_LOGGING_CATEGORY(lcQpaMime, "qt.qpa.mime")
68Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.input.methods")
69Q_LOGGING_CATEGORY(lcQpaDialogs, "qt.qpa.dialogs")
70Q_LOGGING_CATEGORY(lcQpaMenus, "qt.qpa.menus")
71Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
72Q_LOGGING_CATEGORY(lcQpaAccessibility, "qt.qpa.accessibility")
73Q_LOGGING_CATEGORY(lcQpaUiAutomation, "qt.qpa.uiautomation")
74Q_LOGGING_CATEGORY(lcQpaTrayIcon, "qt.qpa.trayicon")
75Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.screen")
76
77int QWindowsContext::verbose = 0;
78
79#if !defined(LANG_SYRIAC)
80# define LANG_SYRIAC 0x5a
81#endif
82
83static inline bool useRTL_Extensions()
84{
85 // Since the IsValidLanguageGroup/IsValidLocale functions always return true on
86 // Vista, check the Keyboard Layouts for enabling RTL.
87 if (const int nLayouts = GetKeyboardLayoutList(0, nullptr)) {
88 QScopedArrayPointer<HKL> lpList(new HKL[nLayouts]);
89 GetKeyboardLayoutList(nLayouts, lpList.data());
90 for (int i = 0; i < nLayouts; ++i) {
91 switch (PRIMARYLANGID((quintptr)lpList[i])) {
92 case LANG_ARABIC:
93 case LANG_HEBREW:
94 case LANG_FARSI:
95 case LANG_SYRIAC:
96 return true;
97 default:
98 break;
99 }
100 }
101 }
102 return false;
103}
104
105#if QT_CONFIG(sessionmanager)
106static inline QWindowsSessionManager *platformSessionManager()
107{
108 auto *guiPrivate = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(qApp));
109 auto *managerPrivate = static_cast<QSessionManagerPrivate*>(QObjectPrivate::get(guiPrivate->session_manager));
110 return static_cast<QWindowsSessionManager *>(managerPrivate->platformSessionManager);
111}
112
113static inline bool sessionManagerInteractionBlocked()
114{
115 return platformSessionManager()->isInteractionBlocked();
116}
117#else // QT_CONFIG(sessionmanager)
118static inline bool sessionManagerInteractionBlocked() { return false; }
119#endif
120
121QWindowsContext *QWindowsContext::m_instance = nullptr;
122
134
135 unsigned m_systemInfo = 0;
138 HDC m_displayContext = nullptr;
139 int m_defaultDPI = 96;
146#if QT_CONFIG(tabletevent)
148#endif
151 bool m_asyncExpose = false;
152 HPOWERNOTIFY m_powerNotification = nullptr;
153 HWND m_powerDummyWindow = nullptr;
154 static bool m_darkMode;
155 static bool m_v2DpiAware;
156};
157
160
162 : m_oleInitializeResult(OleInitialize(nullptr))
163{
166 m_displayContext = GetDC(nullptr);
167 m_defaultDPI = GetDeviceCaps(m_displayContext, LOGPIXELSY);
168 if (useRTL_Extensions()) {
171 }
173 if (FAILED(m_oleInitializeResult)) {
174 qWarning() << "QWindowsContext: OleInitialize() failed: "
175 << QSystemError::windowsComString(m_oleInitializeResult);
176 }
177}
178
181{
182#ifdef Q_CC_MSVC
183# pragma warning( disable : 4996 )
184#endif
185 m_instance = this;
186 // ### FIXME: Remove this once the logging system has other options of configurations.
187 const QByteArray bv = qgetenv("QT_QPA_VERBOSE");
188 if (!bv.isEmpty())
190}
191
193{
194#if QT_CONFIG(tabletevent)
195 d->m_tabletSupport.reset(); // Destroy internal window before unregistering classes.
196#endif
197
198 if (d->m_powerNotification)
199 UnregisterPowerSettingNotification(d->m_powerNotification);
200
201 if (d->m_powerDummyWindow)
202 DestroyWindow(d->m_powerDummyWindow);
203
204 unregisterWindowClasses();
205 if (d->m_oleInitializeResult == S_OK || d->m_oleInitializeResult == S_FALSE) {
206#ifdef QT_USE_FACTORY_CACHE_REGISTRATION
207 detail::QWinRTFactoryCacheRegistration::clearAllCaches();
208#endif
209 OleUninitialize();
210 }
211
212 d->m_screenManager.clearScreens(); // Order: Potentially calls back to the windows.
213 if (d->m_displayContext)
214 ReleaseDC(nullptr, d->m_displayContext);
215 m_instance = nullptr;
216}
217
219{
220 return initTouch(QWindowsIntegration::instance()->options());
221}
222
223bool QWindowsContext::initTouch(unsigned integrationOptions)
224{
226 return true;
227 const bool usePointerHandler = (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) != 0;
228 auto touchDevice = usePointerHandler ? d->m_pointerHandler.touchDevice() : d->m_mouseHandler.touchDevice();
229 if (touchDevice.isNull()) {
230 const bool mouseEmulation =
232 touchDevice = QWindowsPointerHandler::createTouchDevice(mouseEmulation);
233 }
234 if (touchDevice.isNull())
235 return false;
236 d->m_pointerHandler.setTouchDevice(touchDevice);
237 d->m_mouseHandler.setTouchDevice(touchDevice);
239
241
242 // A touch device was plugged while the app is running. Register all windows for touch.
244
245 return true;
246}
247
249{
252 for (QWindowsWindow *w : std::as_const(d->m_windows))
253 w->registerTouchWindow();
254 }
255}
256
258{
259#if QT_CONFIG(tabletevent)
260 d->m_tabletSupport.reset(QWindowsTabletSupport::create());
261 return true;
262#else
263 return false;
264#endif
265}
266
268{
269#if QT_CONFIG(tabletevent)
270 d->m_tabletSupport.reset();
271 return true;
272#else
273 return false;
274#endif
275}
276
277bool QWindowsContext::initPointer(unsigned integrationOptions)
278{
279 if (integrationOptions & QWindowsIntegration::DontUseWMPointer)
280 return false;
281
283 return true;
284}
285
286extern "C" LRESULT QT_WIN_CALLBACK qWindowsPowerWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
287{
288 if (message != WM_POWERBROADCAST || wParam != PBT_POWERSETTINGCHANGE)
289 return DefWindowProc(hwnd, message, wParam, lParam);
290
291 static bool initialized = false; // ignore the initial change
292 if (!initialized) {
293 initialized = true;
294 return DefWindowProc(hwnd, message, wParam, lParam);
295 }
296
297 auto setting = reinterpret_cast<const POWERBROADCAST_SETTING *>(lParam);
298 if (setting) {
299 auto data = reinterpret_cast<const DWORD *>(&setting->Data);
300 if (*data == 1) {
301 // Repaint the windows when returning from sleeping display mode.
302 const auto tlw = QGuiApplication::topLevelWindows();
303 for (auto w : tlw) {
304 if (w->isVisible() && w->windowState() != Qt::WindowMinimized) {
305 if (auto tw = QWindowsWindow::windowsWindowOf(w)) {
306 if (HWND hwnd = tw->handle()) {
307 InvalidateRect(hwnd, nullptr, false);
308 }
309 }
310 }
311 }
312 }
313 }
314 return DefWindowProc(hwnd, message, wParam, lParam);
315}
316
318{
319 if (d->m_powerNotification)
320 return false;
321
322 d->m_powerDummyWindow = createDummyWindow(QStringLiteral("PowerDummyWindow"), L"QtPowerDummyWindow", qWindowsPowerWindowProc);
323 if (!d->m_powerDummyWindow)
324 return false;
325
326 d->m_powerNotification = RegisterPowerSettingNotification(d->m_powerDummyWindow, &GUID_MONITOR_POWER_ON, DEVICE_NOTIFY_WINDOW_HANDLE);
327 if (!d->m_powerNotification) {
328 DestroyWindow(d->m_powerDummyWindow);
329 d->m_powerDummyWindow = nullptr;
330 return false;
331 }
332 return true;
333}
334
336{
337#if QT_CONFIG(tabletevent)
339#else
340 Q_UNUSED(a);
341#endif
342}
343
345{
347}
348
349[[nodiscard]] static inline QtWindows::DpiAwareness
351{
352 // IsValidDpiAwarenessContext() will handle the NULL pointer case.
353 if (!IsValidDpiAwarenessContext(context))
355 if (AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED))
357 if (AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2))
359 if (AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE))
361 if (AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_SYSTEM_AWARE))
363 if (AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE))
366}
367
369{
370 if (!hwnd)
372 const auto context = GetWindowDpiAwarenessContext(hwnd);
374}
375
377{
378 // Although we have GetDpiAwarenessContextForProcess(), however,
379 // it's only available on Win10 1903+, which is a little higher
380 // than Qt's minimum supported version (1809), so we can't use it.
381 // Luckily, MS docs said GetThreadDpiAwarenessContext() will also
382 // return the default DPI_AWARENESS_CONTEXT for the process if
383 // SetThreadDpiAwarenessContext() was never called. So we can use
384 // it as an equivalent.
385 const auto context = GetThreadDpiAwarenessContext();
387}
388
389[[nodiscard]] static inline DPI_AWARENESS_CONTEXT
391{
392 switch (dpiAwareness) {
394 return nullptr;
405 }
406 return nullptr;
407}
408
409#ifndef QT_NO_DEBUG_STREAM
411{
412 const QDebugStateSaver saver(d);
413 QString message = u"QtWindows::DpiAwareness::"_s;
414 switch (dpiAwareness) {
416 message += u"Invalid"_s;
417 break;
419 message += u"Unaware"_s;
420 break;
422 message += u"System"_s;
423 break;
425 message += u"PerMonitor"_s;
426 break;
428 message += u"PerMonitorVersion2"_s;
429 break;
431 message += u"Unaware_GdiScaled"_s;
432 break;
433 }
434 d.nospace().noquote() << message;
435 return d;
436}
437#endif
438
440{
441 qCDebug(lcQpaWindow) << __FUNCTION__ << dpiAwareness;
442 if (processDpiAwareness() == dpiAwareness)
443 return true;
444 const auto context = qtDpiAwarenessToDpiAwarenessContext(dpiAwareness);
445 if (!IsValidDpiAwarenessContext(context)) {
446 qCWarning(lcQpaWindow) << dpiAwareness << "is not supported by current system.";
447 return false;
448 }
449 if (!SetProcessDpiAwarenessContext(context)) {
450 qCWarning(lcQpaWindow).noquote().nospace()
451 << "SetProcessDpiAwarenessContext() failed: "
452 << QSystemError::windowsString()
453 << "\nQt's default DPI awareness context is "
454 << "DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2. If you know what you "
455 << "are doing, you can overwrite this default using qt.conf "
456 << "(https://doc.qt.io/qt-6/highdpi.html#configuring-windows).";
457 return false;
458 }
461 return true;
462}
463
465{
467}
468
470{
471 return m_instance;
472}
473
475{
476 return d->m_systemInfo;
477}
478
480{
481 return d->m_keyMapper.useRTLExtensions();
482}
483
485{
486 return d->m_keyMapper.possibleKeys(e);
487}
488
490{
491 return d->m_windows;
492}
493
495{
498 return old;
499}
500
502{
503 return d->m_creationContext;
504}
505
507{
508 return d->m_defaultDPI;
509}
510
512{
513 return d->m_displayContext;
514}
515
517{
518 return d->m_keyMapper.keyGrabber();
519}
520
522{
524}
525
527{
528 static QString result;
529 if (result.isEmpty()) {
531 str << "Qt" << QT_VERSION_MAJOR << QT_VERSION_MINOR << QT_VERSION_PATCH;
533 str << 'd';
534#ifdef QT_NAMESPACE
535# define xstr(s) str(s)
536# define str(s) #s
537 str << xstr(QT_NAMESPACE);
538#endif
539 }
540 return result;
541}
542
543// Window class registering code (from qapplication_win.cpp)
544
546{
547 Q_ASSERT(w);
548 const Qt::WindowFlags flags = w->flags();
549 const Qt::WindowFlags type = flags & Qt::WindowType_Mask;
550 // Determine style and icon.
551 uint style = CS_DBLCLKS;
552 bool icon = true;
553 // The following will not set CS_OWNDC for any widget window, even if it contains a
554 // QOpenGLWidget or QQuickWidget later on. That cannot be detected at this stage.
555 if (w->surfaceType() == QSurface::OpenGLSurface || (flags & Qt::MSWindowsOwnDC))
556 style |= CS_OWNDC;
558 && (type == Qt::Popup || w->property("_q_windowsDropShadow").toBool())) {
559 style |= CS_DROPSHADOW;
560 }
561 switch (type) {
562 case Qt::Tool:
563 case Qt::ToolTip:
564 case Qt::Popup:
565 style |= CS_SAVEBITS; // Save/restore background
566 icon = false;
567 break;
568 case Qt::Dialog:
570 icon = false; // QTBUG-2027, dialogs without system menu.
571 break;
572 }
573 // Create a unique name for the flag combination
574 QString cname = classNamePrefix();
575 cname += "QWindow"_L1;
576 switch (type) {
577 case Qt::Tool:
578 cname += "Tool"_L1;
579 break;
580 case Qt::ToolTip:
581 cname += "ToolTip"_L1;
582 break;
583 case Qt::Popup:
584 cname += "Popup"_L1;
585 break;
586 default:
587 break;
588 }
589 if (style & CS_DROPSHADOW)
590 cname += "DropShadow"_L1;
591 if (style & CS_SAVEBITS)
592 cname += "SaveBits"_L1;
593 if (style & CS_OWNDC)
594 cname += "OwnDC"_L1;
595 if (icon)
596 cname += "Icon"_L1;
597
598 return registerWindowClass(cname, qWindowsWndProc, style, nullptr, icon);
599}
600
602 WNDPROC proc,
603 unsigned style,
604 HBRUSH brush,
605 bool icon)
606{
607 // since multiple Qt versions can be used in one process
608 // each one has to have window class names with a unique name
609 // The first instance gets the unmodified name; if the class
610 // has already been registered by another instance of Qt then
611 // add a UUID. The check needs to be performed for each name
612 // in case new message windows are added (QTBUG-81347).
613 // Note: GetClassInfo() returns != 0 when a class exists.
614 const auto appInstance = static_cast<HINSTANCE>(GetModuleHandle(nullptr));
615 WNDCLASS wcinfo;
616 const bool classExists = GetClassInfo(appInstance, reinterpret_cast<LPCWSTR>(cname.utf16()), &wcinfo) != FALSE
617 && wcinfo.lpfnWndProc != proc;
618
619 if (classExists)
620 cname += QUuid::createUuid().toString();
621
622 if (d->m_registeredWindowClassNames.contains(cname)) // already registered in our list
623 return cname;
624
625 WNDCLASSEX wc;
626 wc.cbSize = sizeof(WNDCLASSEX);
627 wc.style = style;
628 wc.lpfnWndProc = proc;
629 wc.cbClsExtra = 0;
630 wc.cbWndExtra = 0;
631 wc.hInstance = appInstance;
632 wc.hCursor = nullptr;
633 wc.hbrBackground = brush;
634 if (icon) {
635 wc.hIcon = static_cast<HICON>(LoadImage(appInstance, L"IDI_ICON1", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE));
636 if (wc.hIcon) {
637 int sw = GetSystemMetrics(SM_CXSMICON);
638 int sh = GetSystemMetrics(SM_CYSMICON);
639 wc.hIconSm = static_cast<HICON>(LoadImage(appInstance, L"IDI_ICON1", IMAGE_ICON, sw, sh, 0));
640 } else {
641 wc.hIcon = static_cast<HICON>(LoadImage(nullptr, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED));
642 wc.hIconSm = nullptr;
643 }
644 } else {
645 wc.hIcon = nullptr;
646 wc.hIconSm = nullptr;
647 }
648
649 wc.lpszMenuName = nullptr;
650 wc.lpszClassName = reinterpret_cast<LPCWSTR>(cname.utf16());
651 ATOM atom = RegisterClassEx(&wc);
652 if (!atom)
653 qErrnoWarning("QApplication::regClass: Registering window class '%s' failed.",
654 qPrintable(cname));
655
657 qCDebug(lcQpaWindow).nospace() << __FUNCTION__ << ' ' << cname
658 << " style=0x" << Qt::hex << style << Qt::dec
659 << " brush=" << brush << " icon=" << icon << " atom=" << atom;
660 return cname;
661}
662
663void QWindowsContext::unregisterWindowClasses()
664{
665 const auto appInstance = static_cast<HINSTANCE>(GetModuleHandle(nullptr));
666
667 for (const QString &name : std::as_const(d->m_registeredWindowClassNames)) {
668 if (!UnregisterClass(reinterpret_cast<LPCWSTR>(name.utf16()), appInstance) && QWindowsContext::verbose)
669 qErrnoWarning("UnregisterClass failed for '%s'", qPrintable(name));
670 }
672}
673
675{
676 return GetDeviceCaps(d->m_displayContext, BITSPIXEL);
677}
678
680{
681 d->m_windows.insert(hwnd, w);
682}
683
685{
687 if (it != d->m_windows.end()) {
688 if (d->m_keyMapper.keyGrabber() == it.value()->window())
689 d->m_keyMapper.setKeyGrabber(nullptr);
690 d->m_windows.erase(it);
691 }
692}
693
695{
696 for (auto it = d->m_windows.cbegin(), end = d->m_windows.cend(); it != end; ++it) {
697 if ((*it)->menuBar() == mb)
698 return *it;
699 }
700 return nullptr;
701}
702
704{
705 return d->m_windows.value(hwnd);
706}
707
709{
711
712 // Requested hwnd may also be a child of a platform window in case of embedded native windows.
713 // Find the closest parent that has a platform window.
714 if (!window) {
715 for (HWND w = hwnd; w; w = GetParent(w)) {
716 window = d->m_windows.value(w);
717 if (window)
718 break;
719 }
720 }
721
722 return window;
723}
724
726{
727 if (const QWindowsWindow *bw = findPlatformWindow(hwnd))
728 return bw->window();
729 return nullptr;
730}
731
733{
736}
737
739{
742 else
744}
745
758static inline bool findPlatformWindowHelper(const POINT &screenPoint, unsigned cwexFlags,
760 HWND *hwnd, QWindowsWindow **result)
761{
762 POINT point = screenPoint;
763 screenToClient(*hwnd, &point);
764 // Returns parent if inside & none matched.
765 const HWND child = ChildWindowFromPointEx(*hwnd, point, cwexFlags);
766 if (!child || child == *hwnd)
767 return false;
768 if (QWindowsWindow *window = context->findPlatformWindow(child)) {
769 *result = window;
770 *hwnd = child;
771 return true;
772 }
773 // QTBUG-40555: despite CWP_SKIPINVISIBLE, it is possible to hit on invisible
774 // full screen windows of other applications that have WS_EX_TRANSPARENT set
775 // (for example created by screen sharing applications). In that case, try to
776 // find a Qt window by searching again with CWP_SKIPTRANSPARENT.
777 // Note that Qt 5 uses WS_EX_TRANSPARENT for Qt::WindowTransparentForInput
778 // as well.
779 if (!(cwexFlags & CWP_SKIPTRANSPARENT)
780 && (GetWindowLongPtr(child, GWL_EXSTYLE) & WS_EX_TRANSPARENT)) {
781 const HWND nonTransparentChild = ChildWindowFromPointEx(*hwnd, point, cwexFlags | CWP_SKIPTRANSPARENT);
782 if (!nonTransparentChild || nonTransparentChild == *hwnd)
783 return false;
784 if (QWindowsWindow *nonTransparentWindow = context->findPlatformWindow(nonTransparentChild)) {
785 *result = nonTransparentWindow;
786 *hwnd = nonTransparentChild;
787 return true;
788 }
789 }
790 *hwnd = child;
791 return true;
792}
793
795 const QPoint &screenPointIn,
796 unsigned cwex_flags) const
797{
798 QWindowsWindow *result = nullptr;
799 const POINT screenPoint = { screenPointIn.x(), screenPointIn.y() };
800 while (findPlatformWindowHelper(screenPoint, cwex_flags, this, &parent, &result)) {}
801 // QTBUG-40815: ChildWindowFromPointEx() can hit on special windows from
802 // screen recorder applications like ScreenToGif. Fall back to WindowFromPoint().
803 if (result == nullptr) {
804 if (const HWND window = WindowFromPoint(screenPoint))
806 }
807 return result;
808}
809
811{
812 bool result = false;
813 const DWORD sessionId = WTSGetActiveConsoleSessionId();
814 if (sessionId != 0xFFFFFFFF) {
815 LPTSTR buffer = nullptr;
816 DWORD size = 0;
817#if !defined(Q_CC_MINGW)
818 if (WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, sessionId,
819 WTSSessionInfoEx, &buffer, &size) == TRUE
820 && size > 0) {
821 const WTSINFOEXW *info = reinterpret_cast<WTSINFOEXW *>(buffer);
822 result = info->Level == 1 && info->Data.WTSInfoExLevel1.SessionFlags == WTS_SESSIONSTATE_LOCK;
823 WTSFreeMemory(buffer);
824 }
825#else // MinGW as of 7.3 does not have WTSINFOEXW in wtsapi32.h
826 // Retrieve the flags which are at offset 16 due to padding for 32/64bit alike.
827 if (WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, sessionId,
828 WTS_INFO_CLASS(25), &buffer, &size) == TRUE
829 && size >= 20) {
830 const DWORD *p = reinterpret_cast<DWORD *>(buffer);
831 const DWORD level = *p;
832 const DWORD sessionFlags = *(p + 4);
833 result = level == 1 && sessionFlags == 1;
834 WTSFreeMemory(buffer);
835 }
836#endif // Q_CC_MINGW
837 }
838 return result;
839}
840
842{
843 return d->m_mimeConverter;
844}
845
847{
848 return d->m_screenManager;
849}
850
852{
853#if QT_CONFIG(tabletevent)
854 return d->m_tabletSupport.data();
855#else
856 return 0;
857#endif
858}
859
866 const wchar_t *windowName,
867 WNDPROC wndProc, DWORD style)
868{
869 if (!wndProc)
870 wndProc = DefWindowProc;
871 QString className = registerWindowClass(classNamePrefix() + classNameIn, wndProc);
872 return CreateWindowEx(0, reinterpret_cast<LPCWSTR>(className.utf16()),
873 windowName, style,
874 CW_USEDEFAULT, CW_USEDEFAULT,
875 CW_USEDEFAULT, CW_USEDEFAULT,
876 HWND_MESSAGE, nullptr, static_cast<HINSTANCE>(GetModuleHandle(nullptr)), nullptr);
877}
878
880{
881 // Force WM_NCCALCSIZE to adjust margin
882 SetWindowPos(hwnd, nullptr, 0, 0, 0, 0,
883 SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
884}
885
886bool QWindowsContext::systemParametersInfo(unsigned action, unsigned param, void *out,
887 unsigned dpi)
888{
889 const BOOL result = dpi != 0
890 ? SystemParametersInfoForDpi(action, param, out, 0, dpi)
891 : SystemParametersInfo(action, param, out, 0);
892 return result == TRUE;
893}
894
895bool QWindowsContext::systemParametersInfoForScreen(unsigned action, unsigned param, void *out,
896 const QPlatformScreen *screen)
897{
898 return systemParametersInfo(action, param, out, screen ? unsigned(screen->logicalDpi().first) : 0u);
899}
900
901bool QWindowsContext::systemParametersInfoForWindow(unsigned action, unsigned param, void *out,
902 const QPlatformWindow *win)
903{
904 return systemParametersInfoForScreen(action, param, out, win ? win->screen() : nullptr);
905}
906
907bool QWindowsContext::nonClientMetrics(NONCLIENTMETRICS *ncm, unsigned dpi)
908{
909 memset(ncm, 0, sizeof(NONCLIENTMETRICS));
910 ncm->cbSize = sizeof(NONCLIENTMETRICS);
911 return systemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm->cbSize, ncm, dpi);
912}
913
915 const QPlatformScreen *screen)
916{
917 const int dpi = screen ? qRound(screen->logicalDpi().first) : 0;
918 return nonClientMetrics(ncm, unsigned(dpi));
919}
920
922{
923 return nonClientMetricsForScreen(ncm, win ? win->screen() : nullptr);
924}
925
927{
928 return qobject_cast<QWindowsInputContext *>(QWindowsIntegration::instance()->inputContext());
929}
930
932{
933 // DPI aware V2 processes always have NonClientDpiScaling enabled.
935 return true;
936
937 return window->isTopLevel()
939#if QT_CONFIG(opengl) // /QTBUG-62901, EnableNonClientDpiScaling has problems with GL
940 && (window->surfaceType() != QSurface::OpenGLSurface
942#endif
943 ;
944}
945
946static inline bool isInputMessage(UINT m)
947{
948 switch (m) {
949 case WM_IME_STARTCOMPOSITION:
950 case WM_IME_ENDCOMPOSITION:
951 case WM_IME_COMPOSITION:
952 case WM_INPUT:
953 case WM_TOUCH:
954 case WM_MOUSEHOVER:
955 case WM_MOUSELEAVE:
956 case WM_NCMOUSEHOVER:
957 case WM_NCMOUSELEAVE:
958 case WM_SIZING:
959 case WM_MOVING:
960 case WM_SYSCOMMAND:
961 case WM_COMMAND:
962 case WM_DWMNCRENDERINGCHANGED:
963 case WM_PAINT:
964 return true;
965 default:
966 break;
967 }
968 return (m >= WM_MOUSEFIRST && m <= WM_MOUSELAST)
969 || (m >= WM_NCMOUSEMOVE && m <= WM_NCXBUTTONDBLCLK)
970 || (m >= WM_KEYFIRST && m <= WM_KEYLAST);
971}
972
973// Note: This only works within WM_NCCREATE
974static bool enableNonClientDpiScaling(HWND hwnd)
975{
976 bool result = false;
978 result = EnableNonClientDpiScaling(hwnd) != FALSE;
979 if (!result) {
980 const DWORD errorCode = GetLastError();
981 qErrnoWarning(int(errorCode), "EnableNonClientDpiScaling() failed for HWND %p (%lu)",
982 hwnd, errorCode);
983 }
984 }
985 return result;
986}
987
996 WPARAM wParam, LPARAM lParam,
997 LRESULT *result,
998 QWindowsWindow **platformWindowPtr)
999{
1000 *result = 0;
1001
1002 MSG msg;
1003 msg.hwnd = hwnd; // re-create MSG structure
1004 msg.message = message; // time and pt fields ignored
1005 msg.wParam = wParam;
1006 msg.lParam = lParam;
1007 msg.pt.x = msg.pt.y = 0;
1009 msg.pt.x = GET_X_LPARAM(lParam);
1010 msg.pt.y = GET_Y_LPARAM(lParam);
1011 // For non-client-area messages, these are screen coordinates (as expected
1012 // in the MSG structure), otherwise they are client coordinates.
1013 if (!(et & QtWindows::NonClientEventFlag)) {
1014 clientToScreen(msg.hwnd, &msg.pt);
1015 }
1016 } else {
1017 GetCursorPos(&msg.pt);
1018 }
1019
1020 QWindowsWindow *platformWindow = findPlatformWindow(hwnd);
1021 *platformWindowPtr = platformWindow;
1022
1023 // Run the native event filters. QTBUG-67095: Exclude input messages which are sent
1024 // by QEventDispatcherWin32::processEvents()
1025 if (!isInputMessage(msg.message) && filterNativeEvent(&msg, result))
1026 return true;
1027
1028 if (platformWindow && filterNativeEvent(platformWindow->window(), &msg, result))
1029 return true;
1030
1033 // Disable IME assuming this is a special implementation hooking into keyboard input.
1034 // "Real" IME implementations should use a native event filter intercepting IME events.
1035 if (!windowsInputContext) {
1036 QWindowsInputContext::setWindowsImeEnabled(platformWindow, false);
1037 return false;
1038 }
1039 switch (et) {
1043 return windowsInputContext->composition(hwnd, lParam);
1045 return windowsInputContext->endComposition(hwnd);
1047 return windowsInputContext->handleIME_Request(wParam, lParam, result);
1048 default:
1049 break;
1050 }
1051 } // InputMethodEventFlag
1052
1053 switch (et) {
1056 return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateGestureEvent(platformWindow->window(), hwnd, et, msg, result);
1057 break;
1060 // TODO: Release/regrab mouse if a popup has mouse grab.
1061 return false;
1063 if (platformWindow && !platformWindow->testFlag(QWindowsWindow::WithinDestroy)) {
1064 qWarning() << "External WM_DESTROY received for " << platformWindow->window()
1065 << ", parent: " << platformWindow->window()->parent()
1066 << ", transient parent: " << platformWindow->window()->transientParent();
1067 }
1068 return false;
1070 return false;
1071 case QtWindows::CursorEvent: // Sent to windows that do not have capture (see QTBUG-58590).
1074 return true;
1075 }
1076 break;
1078 return false;
1080#if QT_CONFIG(accessibility)
1081 return QWindowsUiaAccessibility::handleWmGetObject(hwnd, wParam, lParam, result);
1082#else
1083 return false;
1084#endif
1087 // Only refresh the window theme if the user changes the personalize settings.
1088 if ((wParam == 0) && (lParam != 0) // lParam sometimes may be NULL.
1089 && (wcscmp(reinterpret_cast<LPCWSTR>(lParam), L"ImmersiveColorSet") == 0)) {
1090 const bool darkMode = QWindowsTheme::queryDarkMode();
1091 const bool darkModeChanged = darkMode != QWindowsContextPrivate::m_darkMode;
1093 auto integration = QWindowsIntegration::instance();
1094 integration->updateApplicationBadge();
1095 if (integration->darkModeHandling().testFlag(QWindowsApplication::DarkModeStyle)) {
1098 }
1099 if (darkModeChanged) {
1100 if (integration->darkModeHandling().testFlag(QWindowsApplication::DarkModeWindowFrames)) {
1101 for (QWindowsWindow *w : d->m_windows)
1102 w->setDarkBorder(QWindowsContextPrivate::m_darkMode);
1103 }
1104 }
1105 }
1107 }
1108 default:
1109 break;
1110 }
1111
1112 // Before CreateWindowEx() returns, some events are sent,
1113 // for example WM_GETMINMAXINFO asking for size constraints for top levels.
1114 // Pass on to current creation context
1115 if (!platformWindow && !d->m_creationContext.isNull()) {
1116 switch (et) {
1118 d->m_creationContext->applyToMinMaxInfo(reinterpret_cast<MINMAXINFO *>(lParam));
1119 return true;
1121 d->m_creationContext->obtainedSize = QSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
1122 return true;
1124 d->m_creationContext->obtainedPos = QPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
1125 return true;
1128 // DPI aware V2 processes always have NonClientDpiScaling enabled
1129 // and there is no need to make an API call to manually enable.
1131 enableNonClientDpiScaling(msg.hwnd);
1132 }
1133 return false;
1139 default:
1140 break;
1141 }
1142 }
1143 if (platformWindow) {
1144 // Suppress events sent during DestroyWindow() for native children.
1145 if (platformWindow->testFlag(QWindowsWindow::WithinDestroy))
1146 return false;
1148 qCDebug(lcQpaEvents) << "Event window: " << platformWindow->window();
1149 } else {
1150 qWarning("%s: No Qt Window found for event 0x%x (%s), hwnd=0x%p.",
1151 __FUNCTION__, message,
1153 return false;
1154 }
1155
1156 switch (et) {
1159 break;
1160 // See if there are any touch devices added
1161 if (wParam == DBT_DEVNODES_CHANGED)
1162 initTouch();
1163 break;
1166 wic->handleInputLanguageChanged(wParam, lParam);
1167 Q_FALLTHROUGH();
1173 return sessionManagerInteractionBlocked() || d->m_keyMapper.translateKeyEvent(platformWindow->window(), hwnd, msg, result);
1176 return true;
1177 if (QWindowsPopupMenu::notifyAboutToShow(reinterpret_cast<HMENU>(wParam)))
1178 return true;
1179 if (platformWindow == nullptr || platformWindow->menuBar() == nullptr)
1180 return false;
1181 return platformWindow->menuBar()->notifyAboutToShow(reinterpret_cast<HMENU>(wParam));
1184 return true;
1185 if (QWindowsPopupMenu::notifyTriggered(LOWORD(wParam)))
1186 return true;
1187 if (platformWindow == nullptr || platformWindow->menuBar() == nullptr)
1188 return false;
1189 return platformWindow->menuBar()->notifyTriggered(LOWORD(wParam));
1191 platformWindow->handleMoved();
1192 return true;
1194 platformWindow->handleResized(static_cast<int>(wParam), lParam);
1195 return true;
1197 platformWindow->getSizeHints(reinterpret_cast<MINMAXINFO *>(lParam));
1198 return true;// maybe available on some SDKs revisit WM_NCCALCSIZE
1200 return QWindowsGeometryHint::handleCalculateSize(platformWindow->customMargins(), msg, result);
1202 return platformWindow->handleNonClientHitTest(QPoint(msg.pt.x, msg.pt.y), result);
1204 return platformWindow->handleGeometryChanging(&msg);
1206 return platformWindow->handleWmPaint(hwnd, message, wParam, lParam, result);
1208 if (!platformWindow->frameStrutEventsEnabled())
1209 break;
1211 return sessionManagerInteractionBlocked() || d->m_pointerHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
1212 else
1213 return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
1215 if (!platformWindow->frameStrutEventsEnabled())
1216 break;
1218 return sessionManagerInteractionBlocked() || d->m_pointerHandler.translatePointerEvent(platformWindow->window(), hwnd, et, msg, result);
1219 break;
1221 platformWindow->setFlag(QWindowsWindow::ResizeMoveActive);
1222 if (!IsZoomed(hwnd))
1223 platformWindow->updateRestoreGeometry();
1224 return true;
1226 platformWindow->clearFlag(QWindowsWindow::ResizeMoveActive);
1227 platformWindow->checkForScreenChanged();
1228 handleExitSizeMove(platformWindow->window());
1229 if (!IsZoomed(hwnd))
1230 platformWindow->updateRestoreGeometry();
1231 return true;
1234 return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateScrollEvent(platformWindow->window(), hwnd, msg, result);
1235 break;
1239 {
1240 QWindow *window = platformWindow->window();
1241 while (window && (window->flags() & Qt::WindowTransparentForInput))
1242 window = window->parent();
1243 if (!window)
1244 return false;
1247 else
1249 }
1250 break;
1253 return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateTouchEvent(platformWindow->window(), hwnd, et, msg, result);
1254 break;
1257 return sessionManagerInteractionBlocked() || d->m_pointerHandler.translatePointerEvent(platformWindow->window(), hwnd, et, msg, result);
1258 break;
1259 case QtWindows::FocusInEvent: // see QWindowsWindow::requestActivateWindow().
1261 handleFocusEvent(et, platformWindow);
1262 return true;
1263 case QtWindows::ShowEventOnParentRestoring: // QTBUG-40696, prevent Windows from re-showing hidden transient children (dialogs).
1264 if (!platformWindow->window()->isVisible()) {
1265 *result = 0;
1266 return true;
1267 }
1268 break;
1270 platformWindow->handleHidden();
1271 return false;// Indicate transient children should be hidden by windows (SW_PARENTCLOSING)
1273 QWindowSystemInterface::handleCloseEvent(platformWindow->window());
1274 return true;
1276 // Switch from Aero to Classic changes margins.
1278 theme->windowsThemeChanged(platformWindow->window());
1279 return true;
1280 }
1282 platformWindow->handleCompositionSettingsChanged();
1283 return true;
1285 if (platformWindow->window()->flags() & Qt::WindowDoesNotAcceptFocus) {
1286 *result = LRESULT(MA_NOACTIVATE);
1287 return true;
1288 }
1289#if QT_CONFIG(tabletevent)
1290 if (!d->m_tabletSupport.isNull())
1291 d->m_tabletSupport->notifyActivate();
1292#endif // QT_CONFIG(tabletevent)
1293 if (platformWindow->testFlag(QWindowsWindow::BlockedByModal))
1294 if (const QWindow *modalWindow = QGuiApplication::modalWindow()) {
1295 QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(modalWindow);
1296 Q_ASSERT(platformWindow);
1297 platformWindow->alertWindow();
1298 }
1299 break;
1302 if (platformWindow->window()->flags() & Qt::WindowDoesNotAcceptFocus) {
1303 *result = LRESULT(MA_NOACTIVATE);
1304 return true;
1305 }
1306 break;
1307#ifndef QT_NO_CONTEXTMENU
1309 return handleContextMenuEvent(platformWindow->window(), msg);
1310#endif
1312#ifndef QT_NO_WHATSTHIS
1313 QWindowSystemInterface::handleEnterWhatsThisEvent();
1314 return true;
1315#endif
1316 } break;
1318 platformWindow->handleDpiScaledSize(wParam, lParam, result);
1319 return true;
1321 platformWindow->handleDpiChanged(hwnd, wParam, lParam);
1322 return true;
1324 platformWindow->handleDpiChangedAfterParent(hwnd);
1325 return true;
1326#if QT_CONFIG(sessionmanager)
1328 QWindowsSessionManager *sessionManager = platformSessionManager();
1329 if (sessionManager->isActive()) { // bogus message from windows
1330 *result = sessionManager->wasCanceled() ? 0 : 1;
1331 return true;
1332 }
1333
1334 sessionManager->setActive(true);
1335 sessionManager->blocksInteraction();
1336 sessionManager->clearCancellation();
1337
1338 auto *qGuiAppPriv = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(qApp));
1339 qGuiAppPriv->commitData();
1340
1341 if (lParam & ENDSESSION_LOGOFF)
1342 fflush(nullptr);
1343
1344 *result = sessionManager->wasCanceled() ? 0 : 1;
1345 return true;
1346 }
1348 QWindowsSessionManager *sessionManager = platformSessionManager();
1349
1350 sessionManager->setActive(false);
1351 sessionManager->allowsInteraction();
1352 const bool endsession = wParam != 0;
1353
1354 // we receive the message for each toplevel window included internal hidden ones,
1355 // but the aboutToQuit signal should be emitted only once.
1356 auto *qGuiAppPriv = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(qApp));
1357 if (endsession && !qGuiAppPriv->aboutToQuitEmitted) {
1358 qGuiAppPriv->aboutToQuitEmitted = true;
1359 int index = QGuiApplication::staticMetaObject.indexOfSignal("aboutToQuit()");
1360 qApp->qt_metacall(QMetaObject::InvokeMetaMethod, index, nullptr);
1361 // since the process will be killed immediately quit() has no real effect
1363 }
1364 return true;
1365 }
1366#endif // !defined(QT_NO_SESSIONMANAGER)
1368 // Apply application badge if this is the first time we have a taskbar
1369 // button, or after Explorer restart.
1371 break;
1372 default:
1373 break;
1374 }
1375 return false;
1376}
1377
1378/* Compress activation events. If the next focus window is already known
1379 * at the time the current one receives focus-out, pass that to
1380 * QWindowSystemInterface instead of sending 0 and ignore its consecutive
1381 * focus-in event.
1382 * This helps applications that do handling in focus-out events. */
1383void QWindowsContext::handleFocusEvent(QtWindows::WindowsEventType et,
1384 QWindowsWindow *platformWindow)
1385{
1386 QWindow *nextActiveWindow = nullptr;
1387 if (et == QtWindows::FocusInEvent) {
1388 QWindow *topWindow = QWindowsWindow::topLevelOf(platformWindow->window());
1389 QWindow *modalWindow = nullptr;
1390 if (QGuiApplicationPrivate::instance()->isWindowBlocked(topWindow, &modalWindow) && topWindow != modalWindow) {
1391 modalWindow->requestActivate();
1392 return;
1393 }
1394 // QTBUG-32867: Invoking WinAPI SetParent() can cause focus-in for the
1395 // window which is not desired for native child widgets.
1396 if (platformWindow->testFlag(QWindowsWindow::WithinSetParent)) {
1397 QWindow *currentFocusWindow = QGuiApplication::focusWindow();
1398 if (currentFocusWindow && currentFocusWindow != platformWindow->window()) {
1399 currentFocusWindow->requestActivate();
1400 return;
1401 }
1402 }
1403 nextActiveWindow = platformWindow->window();
1404 } else {
1405 // Focus out: Is the next window known and different
1406 // from the receiving the focus out.
1407 if (const HWND nextActiveHwnd = GetFocus())
1408 if (QWindowsWindow *nextActivePlatformWindow = findClosestPlatformWindow(nextActiveHwnd))
1409 if (nextActivePlatformWindow != platformWindow)
1410 nextActiveWindow = nextActivePlatformWindow->window();
1411 }
1412 if (nextActiveWindow != d->m_lastActiveWindow) {
1413 d->m_lastActiveWindow = nextActiveWindow;
1415 }
1416}
1417
1418#ifndef QT_NO_CONTEXTMENU
1419bool QWindowsContext::handleContextMenuEvent(QWindow *window, const MSG &msg)
1420{
1421 bool mouseTriggered = false;
1422 QPoint globalPos;
1423 QPoint pos;
1424 if (msg.lParam != int(0xffffffff)) {
1425 mouseTriggered = true;
1426 globalPos.setX(msg.pt.x);
1427 globalPos.setY(msg.pt.y);
1428 pos = QWindowsGeometryHint::mapFromGlobal(msg.hwnd, globalPos);
1429
1430 RECT clientRect;
1431 if (GetClientRect(msg.hwnd, &clientRect)) {
1432 if (pos.x() < clientRect.left || pos.x() >= clientRect.right ||
1433 pos.y() < clientRect.top || pos.y() >= clientRect.bottom)
1434 {
1435 // This is the case that user has right clicked in the window's caption,
1436 // We should call DefWindowProc() to display a default shortcut menu
1437 // instead of sending a Qt window system event.
1438 return false;
1439 }
1440 }
1441 }
1442
1443 QWindowSystemInterface::handleContextMenuEvent(window, mouseTriggered, pos, globalPos,
1445 return true;
1446}
1447#endif
1448
1449void QWindowsContext::handleExitSizeMove(QWindow *window)
1450{
1451 // Windows can be moved/resized by:
1452 // 1) User moving a window by dragging the title bar: Causes a sequence
1453 // of WM_NCLBUTTONDOWN, WM_NCMOUSEMOVE but no WM_NCLBUTTONUP,
1454 // leaving the left mouse button 'pressed'
1455 // 2) User choosing Resize/Move from System menu and using mouse/cursor keys:
1456 // No mouse events are received
1457 // 3) Programmatically via QSizeGrip calling QPlatformWindow::startSystemResize/Move():
1458 // Mouse is left in pressed state after press on size grip (inside window),
1459 // no further mouse events are received
1460 // For cases 1,3, intercept WM_EXITSIZEMOVE to sync the buttons.
1461 const Qt::MouseButtons currentButtons = QWindowsMouseHandler::queryMouseButtons();
1462 const Qt::MouseButtons appButtons = QGuiApplication::mouseButtons();
1463 if (currentButtons == appButtons)
1464 return;
1465 const Qt::KeyboardModifiers keyboardModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
1466 const QPoint globalPos = QWindowsCursor::mousePosition();
1467 const QPlatformWindow *platWin = window->handle();
1468 const QPoint localPos = platWin->mapFromGlobal(globalPos);
1469 const QEvent::Type type = platWin->geometry().contains(globalPos)
1472 if (appButtons.testFlag(button) && !currentButtons.testFlag(button)) {
1474 currentButtons, button, type, keyboardModifiers);
1475 }
1476 }
1479 else
1481}
1482
1484{
1485 return d->m_asyncExpose;
1486}
1487
1489{
1490 d->m_asyncExpose = value;
1491}
1492
1493DWORD QWindowsContext::readAdvancedExplorerSettings(const wchar_t *subKey, DWORD defaultValue)
1494{
1495 const auto value =
1496 QWinRegistryKey(HKEY_CURRENT_USER,
1497 LR"(Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced)")
1498 .dwordValue(subKey);
1499 return value.second ? value.first : defaultValue;
1500}
1501
1502static inline bool isEmptyRect(const RECT &rect)
1503{
1504 return rect.right - rect.left == 0 && rect.bottom - rect.top == 0;
1505}
1506
1507static inline QMargins marginsFromRects(const RECT &frame, const RECT &client)
1508{
1509 return QMargins(client.left - frame.left, client.top - frame.top,
1510 frame.right - client.right, frame.bottom - client.bottom);
1511}
1512
1513static RECT rectFromNcCalcSize(UINT message, WPARAM wParam, LPARAM lParam, int n)
1514{
1515 RECT result = {0, 0, 0, 0};
1516 if (message == WM_NCCALCSIZE && wParam)
1517 result = reinterpret_cast<const NCCALCSIZE_PARAMS *>(lParam)->rgrc[n];
1518 return result;
1519}
1520
1521static inline bool isMinimized(HWND hwnd)
1522{
1523 WINDOWPLACEMENT windowPlacement;
1524 windowPlacement.length = sizeof(WINDOWPLACEMENT);
1525 return GetWindowPlacement(hwnd, &windowPlacement) && windowPlacement.showCmd == SW_SHOWMINIMIZED;
1526}
1527
1528static inline bool isTopLevel(HWND hwnd)
1529{
1530 return (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_CHILD) == 0;
1531}
1532
1541extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1542{
1543 LRESULT result;
1544 const QtWindows::WindowsEventType et = windowsEventType(message, wParam, lParam);
1545 QWindowsWindow *platformWindow = nullptr;
1546 const RECT ncCalcSizeFrame = rectFromNcCalcSize(message, wParam, lParam, 0);
1547 const bool handled = QWindowsContext::instance()->windowsProc(hwnd, message, et, wParam, lParam, &result, &platformWindow);
1548 if (QWindowsContext::verbose > 1 && lcQpaEvents().isDebugEnabled()) {
1549 if (const char *eventName = QWindowsGuiEventDispatcher::windowsMessageName(message)) {
1550 qCDebug(lcQpaEvents).nospace() << "EVENT: hwd=" << hwnd << ' ' << eventName
1551 << " msg=0x" << Qt::hex << message << " et=0x" << et << Qt::dec << " wp="
1552 << int(wParam) << " at " << GET_X_LPARAM(lParam) << ','
1553 << GET_Y_LPARAM(lParam) << " handled=" << handled;
1554 }
1555 }
1556 if (!handled)
1557 result = DefWindowProc(hwnd, message, wParam, lParam);
1558
1559 // Capture WM_NCCALCSIZE on top level windows and obtain the window margins by
1560 // subtracting the rectangles before and after processing. This will correctly
1561 // capture client code overriding the message and allow for per-monitor margins
1562 // for High DPI (QTBUG-53255, QTBUG-40578).
1563 if (message == WM_NCCALCSIZE && !isEmptyRect(ncCalcSizeFrame) && isTopLevel(hwnd) && !isMinimized(hwnd)) {
1564 const QMargins margins =
1565 marginsFromRects(ncCalcSizeFrame, rectFromNcCalcSize(message, wParam, lParam, 0));
1566 if (margins.left() >= 0) {
1567 if (platformWindow) {
1568 qCDebug(lcQpaWindow) << __FUNCTION__ << "WM_NCCALCSIZE for" << hwnd << margins;
1569 platformWindow->setFullFrameMargins(margins);
1570 } else {
1572 if (!ctx.isNull())
1573 ctx->margins = margins;
1574 }
1575 }
1576 }
1577 return result;
1578}
1579
1580
1581static inline QByteArray nativeEventType() { return QByteArrayLiteral("windows_generic_MSG"); }
1582
1583// Send to QAbstractEventDispatcher
1585{
1587 qintptr filterResult = 0;
1588 if (dispatcher && dispatcher->filterNativeEvent(nativeEventType(), msg, &filterResult)) {
1589 *result = LRESULT(filterResult);
1590 return true;
1591 }
1592 return false;
1593}
1594
1595// Send to QWindowSystemInterface
1597{
1598 qintptr filterResult = 0;
1599 if (QWindowSystemInterface::handleNativeEvent(window, nativeEventType(), msg, &filterResult)) {
1600 *result = LRESULT(filterResult);
1601 return true;
1602 }
1603 return false;
1604}
1605
static JNINativeMethod methods[]
static QAbstractEventDispatcher * instance(QThread *thread=nullptr)
Returns a pointer to the event dispatcher object for the specified thread.
bool filterNativeEvent(const QByteArray &eventType, void *message, qintptr *result)
Sends message through the event filters that were set by installNativeEventFilter().
\inmodule QtCore
Definition qbytearray.h:57
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
Definition qbytearray.h:106
static void quit()
\threadsafe
\inmodule QtCore
\inmodule QtCore
Type
This enum type defines the valid event types in Qt.
Definition qcoreevent.h:51
@ NonClientAreaMouseButtonRelease
Definition qcoreevent.h:214
@ MouseButtonRelease
Definition qcoreevent.h:61
static QGuiApplicationPrivate * instance()
static QWindowList topLevelWindows()
Returns a list of the top-level windows in the application.
static QWindow * modalWindow()
Returns the most recently shown modal window.
static QWindow * focusWindow()
Returns the QWindow that receives events tied to focus, such as key events.
static Qt::MouseButtons mouseButtons()
Returns the current state of the buttons on the mouse.
const_iterator cbegin() const noexcept
Definition qhash.h:1204
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
Definition qhash.h:1258
iterator erase(const_iterator it)
Definition qhash.h:1223
T value(const Key &key) const noexcept
Definition qhash.h:1044
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1206
const_iterator cend() const noexcept
Definition qhash.h:1208
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1283
The QKeyEvent class describes a key event.
Definition qevent.h:423
static bool isDebugBuild() noexcept Q_DECL_CONST_FUNCTION
Definition qlist.h:74
static void setFilterRules(const QString &rules)
Configures which categories and message types should be enabled through a set of rules.
\inmodule QtCore
Definition qmargins.h:23
constexpr int left() const noexcept
Returns the left margin.
Definition qmargins.h:110
Native interface to QPlatformWindow. \inmodule QtGui.
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:153
static OpenGLModuleType openGLModuleType()
Returns the underlying OpenGL implementation type.
The QPlatformScreen class provides an abstraction for visual displays.
The QPlatformWindow class provides an abstraction for top-level windows.
virtual QPoint mapFromGlobal(const QPoint &pos) const
Translates the global screen coordinate pos to window coordinates using native methods.
QWindow * window() const
Returns the window which belongs to the QPlatformWindow.
virtual QRect geometry() const
Returns the current geometry of a window.
\inmodule QtCore\reentrant
Definition qpoint.h:23
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:127
constexpr void setY(int y) noexcept
Sets the y coordinate of this point to the given y coordinate.
Definition qpoint.h:142
constexpr int y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:132
constexpr void setX(int x) noexcept
Sets the x coordinate of this point to the given x coordinate.
Definition qpoint.h:137
bool contains(const QRect &r, bool proper=false) const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qrect.cpp:851
\inmodule QtCore
\inmodule QtCore
T * data() const noexcept
Returns the value of the pointer referenced by this object.
Definition qset.h:18
void clear()
Definition qset.h:61
bool contains(const T &value) const
Definition qset.h:71
iterator insert(const T &value)
Definition qset.h:155
\inmodule QtCore
bool isNull() const noexcept
Returns true if this object refers to \nullptr.
\inmodule QtCore
Definition qsize.h:25
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
const ushort * utf16() const
Returns the QString as a '\0\'-terminated array of unsigned shorts.
Definition qstring.cpp:6737
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5788
@ OpenGLSurface
Definition qsurface.h:32
\inmodule QtCore
static QUuid createUuid()
On any platform other than Windows, this function returns a new UUID with variant QUuid::DCE and vers...
Definition quuid.cpp:947
QString toString(StringFormat mode=WithBraces) const
Definition quuid.cpp:602
QScreen * screen() const
Returns the screen the widget is on.
Definition qwidget.cpp:2503
QPair< DWORD, bool > dwordValue(QStringView subKey) const
static bool handleNativeEvent(QWindow *window, const QByteArray &eventType, void *message, qintptr *result)
Passes a native event identified by eventType to the window.
static void handleThemeChange(QWindow *window=nullptr)
static void handleContextMenuEvent(QWindow *window, bool mouseTriggered, const QPoint &pos, const QPoint &globalPos, Qt::KeyboardModifiers modifiers)
static bool handleMouseEvent(QWindow *window, const QPointF &local, const QPointF &global, Qt::MouseButtons state, Qt::MouseButton button, QEvent::Type type, Qt::KeyboardModifiers mods=Qt::NoModifier, Qt::MouseEventSource source=Qt::MouseEventNotSynthesized)
static void registerInputDevice(const QInputDevice *device)
static bool handleCloseEvent(QWindow *window)
static void handleWindowActivated(QWindow *window, Qt::FocusReason r=Qt::OtherFocusReason)
\inmodule QtGui
Definition qwindow.h:63
Singleton container for all relevant information.
static bool isDarkMode()
QSharedPointer< QWindowCreationContext > windowCreationContext() const
QWindowsScreenManager & screenManager()
static QString classNamePrefix()
QWindowsWindow * findClosestPlatformWindow(HWND) const
QWindow * findWindow(HWND) const
bool asyncExpose() const
void addWindow(HWND, QWindowsWindow *w)
static bool systemParametersInfoForScreen(unsigned action, unsigned param, void *out, const QPlatformScreen *screen=nullptr)
static DWORD readAdvancedExplorerSettings(const wchar_t *subKey, DWORD defaultValue)
static bool setProcessDpiAwareness(QtWindows::DpiAwareness dpiAwareness)
HDC displayContext() const
static bool shouldHaveNonClientDpiScaling(const QWindow *window)
QWindowsTabletSupport * tabletSupport() const
static bool systemParametersInfoForWindow(unsigned action, unsigned param, void *out, const QPlatformWindow *win=nullptr)
QString registerWindowClass(const QWindow *w)
static void setTabletAbsoluteRange(int a)
static void forceNcCalcSize(HWND hwnd)
QWindowsWindow * findPlatformWindowAt(HWND parent, const QPoint &screenPoint, unsigned cwex_flags) const
void setKeyGrabber(QWindow *hwnd)
static bool nonClientMetrics(NONCLIENTMETRICS *ncm, unsigned dpi=0)
QList< int > possibleKeys(const QKeyEvent *e) const
HWND createDummyWindow(const QString &classNameIn, const wchar_t *windowName, WNDPROC wndProc=nullptr, DWORD style=WS_OVERLAPPED)
Convenience to create a non-visible, message-only dummy window for example used as clipboard watcher ...
void setAsyncExpose(bool value)
QSharedPointer< QWindowCreationContext > setWindowCreationContext(const QSharedPointer< QWindowCreationContext > &ctx)
static QtWindows::DpiAwareness windowDpiAwareness(HWND hwnd)
bool windowsProc(HWND hwnd, UINT message, QtWindows::WindowsEventType et, WPARAM wParam, LPARAM lParam, LRESULT *result, QWindowsWindow **platformWindowPtr)
Main windows procedure registered for windows.
unsigned systemInfo() const
static QtWindows::DpiAwareness processDpiAwareness()
QWindowsWindow * findPlatformWindow(HWND) const
QWindow * keyGrabber() const
QWindow * windowUnderMouse() const
bool useRTLExtensions() const
bool initPointer(unsigned integrationOptions)
static bool systemParametersInfo(unsigned action, unsigned param, void *out, unsigned dpi=0)
QWindowsMimeRegistry & mimeConverter() const
static bool nonClientMetricsForWindow(NONCLIENTMETRICS *ncm, const QPlatformWindow *win=nullptr)
static bool isSessionLocked()
int screenDepth() const
bool initPowerNotificationHandler()
HandleBaseWindowHash & windows()
static QWindowsContext * instance()
static bool nonClientMetricsForScreen(NONCLIENTMETRICS *ncm, const QPlatformScreen *screen=nullptr)
static bool filterNativeEvent(MSG *msg, LRESULT *result)
void setDetectAltGrModifier(bool a)
static bool hasOverrideCursor()
static QPoint mousePosition()
static void enforceOverrideCursor()
static const char * windowsMessageName(UINT msg)
Windows Input context implementation.
bool composition(HWND hwnd, LPARAM lParam)
Notify focus object about markup or final text.
static void setWindowsImeEnabled(QWindowsWindow *platformWindow, bool enabled)
bool handleIME_Request(WPARAM wparam, LPARAM lparam, LRESULT *result)
static QWindowsIntegration * instance()
Translates Windows keys to QWindowSystemInterface events.
bool translateKeyEvent(QWindow *widget, HWND hwnd, const MSG &msg, LRESULT *result)
To be called from the window procedure.
void setUseRTLExtensions(bool e)
QWindow * keyGrabber() const
bool useRTLExtensions() const
void setKeyGrabber(QWindow *w)
static Qt::KeyboardModifiers queryKeyboardModifiers()
void setDetectAltGrModifier(bool a)
QList< int > possibleKeys(const QKeyEvent *e) const
Windows native menu bar.
Manages the list of QWindowsMimeConverter instances.
Windows mouse handler.
static Qt::MouseButtons queryMouseButtons()
bool translateScrollEvent(QWindow *window, HWND hwnd, MSG msg, LRESULT *result)
bool translateTouchEvent(QWindow *widget, HWND hwnd, QtWindows::WindowsEventType t, MSG msg, LRESULT *result)
void setTouchDevice(const QPointingDevicePtr &d)
QWindow * windowUnderMouse() const
bool translateGestureEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType, MSG msg, LRESULT *)
const QPointingDevicePtr & touchDevice() const
bool translateMouseEvent(QWindow *widget, HWND hwnd, QtWindows::WindowsEventType t, MSG msg, LRESULT *result)
QWindow * windowUnderMouse() const
static QPointingDevicePtr createTouchDevice(bool mouseEmulation)
const QPointingDevicePtr & touchDevice() const
bool translatePointerEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result)
bool translateMouseEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result)
void setTouchDevice(const QPointingDevicePtr &d)
static bool notifyAboutToShow(HMENU hmenu)
static bool notifyTriggered(uint id)
Manages a list of QWindowsScreen.
bool handleScreenChanges()
Synchronizes the screen list, adds new screens, removes deleted ones and propagates resolution change...
Tablet support for Windows.
static void setAbsoluteRange(int a)
static QWindowsTabletSupport * create()
static bool queryDarkMode()
static QWindowsTheme * instance()
Raster or OpenGL Window.
static QWindowsWindow * windowsWindowOf(const QWindow *w)
bool testFlag(unsigned f) const
static void settingsChanged()
static bool handleGeometryChangingMessage(MSG *message, const QWindow *qWindow, const QMargins &marginsDp)
static const char * embeddedNativeParentHandleProperty
static QWindow * topLevelOf(QWindow *w)
@ WithinSetParent
Automatic mouse capture on button press.
void setFullFrameMargins(const QMargins &newMargins)
EGLContext ctx
QString str
[2]
QPushButton * button
[2]
double e
QSet< QString >::iterator it
rect
[4]
void qErrnoWarning(const char *msg,...)
Combined button and popup list for selecting options.
WindowsEventType
Enumerations for WM_XX events.
@ PointerActivateWindowEvent
@ InputMethodEndCompositionEvent
@ QueryEndSessionApplicationEvent
@ ShowEventOnParentRestoring
@ InputMethodCompositionEvent
@ KeyboardLayoutChangeEvent
@ InputMethodOpenCandidateWindowEvent
@ MouseActivateWindowEvent
@ DpiChangedAfterParentEvent
@ InputMethodStartCompositionEvent
@ EndSessionApplicationEvent
@ CompositionSettingsChanged
@ InputMethodCloseCandidateWindowEvent
@ AccessibleObjectFromWindowRequest
@ WindowMinimized
Definition qnamespace.h:252
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
MouseButton
Definition qnamespace.h:55
@ LeftButton
Definition qnamespace.h:57
@ RightButton
Definition qnamespace.h:58
@ MiddleButton
Definition qnamespace.h:59
QTextStream & dec(QTextStream &stream)
Calls QTextStream::setIntegerBase(10) on stream and returns stream.
@ WindowDoesNotAcceptFocus
Definition qnamespace.h:235
@ MSWindowsOwnDC
Definition qnamespace.h:221
@ ToolTip
Definition qnamespace.h:212
@ Popup
Definition qnamespace.h:210
@ WindowType_Mask
Definition qnamespace.h:219
@ Dialog
Definition qnamespace.h:207
@ NoDropShadowWindowHint
Definition qnamespace.h:243
@ WindowTransparentForInput
Definition qnamespace.h:233
@ Tool
Definition qnamespace.h:211
@ WindowSystemMenuHint
Definition qnamespace.h:226
@ ActiveWindowFocusReason
Definition brush.cpp:5
static void * context
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
#define Q_FALLTHROUGH()
#define qApp
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define WM_TOUCH
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:281
#define qWarning
Definition qlogging.h:162
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
const GLfloat * m
GLenum GLuint GLint level
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLuint GLuint end
GLenum GLuint buffer
GLenum type
GLbitfield flags
GLuint GLsizei const GLchar * message
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum const GLint * param
GLuint name
GLfloat n
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
GLenum GLenum GLenum input
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define qPrintable(string)
Definition qstring.h:1391
#define QStringLiteral(str)
#define CS_DROPSHADOW
Definition qt_windows.h:97
QScreen * screen
[1]
Definition main.cpp:29
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
#define Q_UNUSED(x)
#define DPI_AWARENESS_CONTEXT_UNAWARE
QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamIn, LPARAM lParamIn)
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
#define DPI_AWARENESS_CONTEXT_SYSTEM_AWARE
#define DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED
size_t quintptr
Definition qtypes.h:72
unsigned int uint
Definition qtypes.h:29
ptrdiff_t qintptr
Definition qtypes.h:71
struct tagMSG MSG
long HRESULT
LRESULT QT_WIN_CALLBACK qWindowsPowerWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
#define LANG_SYRIAC
static bool enableNonClientDpiScaling(HWND hwnd)
static bool isInputMessage(UINT m)
static DPI_AWARENESS_CONTEXT qtDpiAwarenessToDpiAwarenessContext(QtWindows::DpiAwareness dpiAwareness)
static bool useRTL_Extensions()
static bool sessionManagerInteractionBlocked()
static QWindowsInputContext * windowsInputContext()
static QtWindows::DpiAwareness dpiAwarenessContextToQtDpiAwareness(DPI_AWARENESS_CONTEXT context)
QDebug operator<<(QDebug d, QtWindows::DpiAwareness dpiAwareness)
static bool findPlatformWindowHelper(const POINT &screenPoint, unsigned cwexFlags, const QWindowsContext *context, HWND *hwnd, QWindowsWindow **result)
Find a child window at a screen point.
LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND, UINT, WPARAM, LPARAM)
static void clientToScreen(HWND hwnd, POINT *wP)
static void screenToClient(HWND hwnd, POINT *wP)
const char className[16]
[1]
Definition qwizard.cpp:100
QWidget * win
Definition settings.cpp:6
QFileInfo info(fileName)
[8]
QTextStream out(stdout)
[7]
application x qt windows mime
[2]
QObject::connect nullptr
QLayoutItem * child
[0]
aWidget window() -> setWindowTitle("New Window Title")
[2]
QFrame frame
[0]
const QWindow * window
void applyToMinMaxInfo(MINMAXINFO *mmi) const
QWindowsMouseHandler m_mouseHandler
const HRESULT m_oleInitializeResult
QWindowsKeyMapper m_keyMapper
QSet< QString > m_registeredWindowClassNames
QSharedPointer< QWindowCreationContext > m_creationContext
QWindowsPointerHandler m_pointerHandler
QWindowsScreenManager m_screenManager
QWindowsMimeRegistry m_mimeConverter
QWindowsContext::HandleBaseWindowHash m_windows
static QPoint mapFromGlobal(const HWND hwnd, const QPoint &)
static bool handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result)
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent
virtual HRESULT STDMETHODCALLTYPE GetFocus(__RPC__deref_out_opt IRawElementProviderFragment **pRetVal)=0