Warning: That file was not part of the compilation database. It may have many parsing errors.

1/****************************************************************************
2**
3** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
4** Copyright (C) 2016 The Qt Company Ltd.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the plugins of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include "qwindowscontext.h"
42#include "qwindowsintegration.h"
43#include "qwindowswindow.h"
44#include "qwindowskeymapper.h"
45#include "qwindowsmousehandler.h"
46#include "qwindowspointerhandler.h"
47#include "qtwindowsglobal.h"
48#include "qwindowsmenu.h"
49#include "qwindowsmime.h"
50#include "qwindowsinputcontext.h"
51#if QT_CONFIG(tabletevent)
52# include "qwindowstabletsupport.h"
53#endif
54#include "qwindowstheme.h"
55#include <private/qguiapplication_p.h>
56#if QT_CONFIG(accessibility)
57# include "uiautomation/qwindowsuiaaccessibility.h"
58#endif
59#if QT_CONFIG(sessionmanager)
60# include <private/qsessionmanager_p.h>
61# include "qwindowssessionmanager.h"
62#endif
63#include "qwindowsscreen.h"
64#include "qwindowstheme.h"
65
66#include <QtGui/qwindow.h>
67#include <qpa/qwindowsysteminterface.h>
68#include <qpa/qwindowsysteminterface_p.h>
69#include <qpa/qplatformnativeinterface.h>
70#include <QtGui/qguiapplication.h>
71#include <QtGui/qopenglcontext.h>
72
73#include <QtCore/qset.h>
74#include <QtCore/qhash.h>
75#include <QtCore/qstringlist.h>
76#include <QtCore/qdebug.h>
77#include <QtCore/qoperatingsystemversion.h>
78#include <QtCore/qsysinfo.h>
79#include <QtCore/qscopedpointer.h>
80#include <QtCore/quuid.h>
81#include <QtCore/private/qsystemlibrary_p.h>
82
83#include <QtEventDispatcherSupport/private/qwindowsguieventdispatcher_p.h>
84
85#include <stdlib.h>
86#include <stdio.h>
87#include <windowsx.h>
88#include <comdef.h>
89#include <dbt.h>
90#include <wtsapi32.h>
91
92QT_BEGIN_NAMESPACE
93
94Q_LOGGING_CATEGORY(lcQpaWindows, "qt.qpa.windows")
95Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events")
96Q_LOGGING_CATEGORY(lcQpaGl, "qt.qpa.gl")
97Q_LOGGING_CATEGORY(lcQpaMime, "qt.qpa.mime")
98Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.input.methods")
99Q_LOGGING_CATEGORY(lcQpaDialogs, "qt.qpa.dialogs")
100Q_LOGGING_CATEGORY(lcQpaMenus, "qt.qpa.menus")
101Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
102Q_LOGGING_CATEGORY(lcQpaAccessibility, "qt.qpa.accessibility")
103Q_LOGGING_CATEGORY(lcQpaUiAutomation, "qt.qpa.uiautomation")
104Q_LOGGING_CATEGORY(lcQpaTrayIcon, "qt.qpa.trayicon")
105
106int QWindowsContext::verbose = 0;
107
108#if !defined(LANG_SYRIAC)
109# define LANG_SYRIAC 0x5a
110#endif
111
112static inline bool useRTL_Extensions()
113{
114 // Since the IsValidLanguageGroup/IsValidLocale functions always return true on
115 // Vista, check the Keyboard Layouts for enabling RTL.
116 if (const int nLayouts = GetKeyboardLayoutList(0, nullptr)) {
117 QScopedArrayPointer<HKL> lpList(new HKL[nLayouts]);
118 GetKeyboardLayoutList(nLayouts, lpList.data());
119 for (int i = 0; i < nLayouts; ++i) {
120 switch (PRIMARYLANGID((quintptr)lpList[i])) {
121 case LANG_ARABIC:
122 case LANG_HEBREW:
123 case LANG_FARSI:
124 case LANG_SYRIAC:
125 return true;
126 default:
127 break;
128 }
129 }
130 }
131 return false;
132}
133
134#if QT_CONFIG(sessionmanager)
135static inline QWindowsSessionManager *platformSessionManager()
136{
137 auto *guiPrivate = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(qApp));
138 auto *managerPrivate = static_cast<QSessionManagerPrivate*>(QObjectPrivate::get(guiPrivate->session_manager));
139 return static_cast<QWindowsSessionManager *>(managerPrivate->platformSessionManager);
140}
141
142static inline bool sessionManagerInteractionBlocked()
143{
144 return platformSessionManager()->isInteractionBlocked();
145}
146#else // QT_CONFIG(sessionmanager)
147static inline bool sessionManagerInteractionBlocked() { return false; }
148#endif
149
150static inline int windowDpiAwareness(HWND hwnd)
151{
152 return QWindowsContext::user32dll.getWindowDpiAwarenessContext && QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext
153 ? QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext(QWindowsContext::user32dll.getWindowDpiAwarenessContext(hwnd))
154 : -1;
155}
156
157// Note: This only works within WM_NCCREATE
158static bool enableNonClientDpiScaling(HWND hwnd)
159{
160 bool result = false;
161 if (QWindowsContext::user32dll.enableNonClientDpiScaling && windowDpiAwareness(hwnd) == 2) {
162 result = QWindowsContext::user32dll.enableNonClientDpiScaling(hwnd) != FALSE;
163 if (!result) {
164 const DWORD errorCode = GetLastError();
165 qErrnoWarning(int(errorCode), "EnableNonClientDpiScaling() failed for HWND %p (%lu)",
166 hwnd, errorCode);
167 }
168 }
169 return result;
170}
171
172/*!
173 \class QWindowsUser32DLL
174 \brief Struct that contains dynamically resolved symbols of User32.dll.
175
176 The stub libraries shipped with the MinGW compiler miss some of the
177 functions. They need to be retrieved dynamically.
178
179 In addition, touch-related functions are available only from Windows onwards.
180 These need to resolved dynamically for Q_CC_MSVC as well.
181
182 \sa QWindowsShell32DLL
183
184 \internal
185 \ingroup qt-lighthouse-win
186*/
187
188void QWindowsUser32DLL::init()
189{
190 QSystemLibrary library(QStringLiteral("user32"));
191 setProcessDPIAware = (SetProcessDPIAware)library.resolve("SetProcessDPIAware");
192
193 addClipboardFormatListener = (AddClipboardFormatListener)library.resolve("AddClipboardFormatListener");
194 removeClipboardFormatListener = (RemoveClipboardFormatListener)library.resolve("RemoveClipboardFormatListener");
195
196 getDisplayAutoRotationPreferences = (GetDisplayAutoRotationPreferences)library.resolve("GetDisplayAutoRotationPreferences");
197 setDisplayAutoRotationPreferences = (SetDisplayAutoRotationPreferences)library.resolve("SetDisplayAutoRotationPreferences");
198
199 if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8) {
200 enableMouseInPointer = (EnableMouseInPointer)library.resolve("EnableMouseInPointer");
201 getPointerType = (GetPointerType)library.resolve("GetPointerType");
202 getPointerInfo = (GetPointerInfo)library.resolve("GetPointerInfo");
203 getPointerDeviceRects = (GetPointerDeviceRects)library.resolve("GetPointerDeviceRects");
204 getPointerTouchInfo = (GetPointerTouchInfo)library.resolve("GetPointerTouchInfo");
205 getPointerFrameTouchInfo = (GetPointerFrameTouchInfo)library.resolve("GetPointerFrameTouchInfo");
206 getPointerFrameTouchInfoHistory = (GetPointerFrameTouchInfoHistory)library.resolve("GetPointerFrameTouchInfoHistory");
207 getPointerPenInfo = (GetPointerPenInfo)library.resolve("GetPointerPenInfo");
208 getPointerPenInfoHistory = (GetPointerPenInfoHistory)library.resolve("GetPointerPenInfoHistory");
209 skipPointerFrameMessages = (SkipPointerFrameMessages)library.resolve("SkipPointerFrameMessages");
210 }
211
212 if (QOperatingSystemVersion::current()
213 >= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 14393)) {
214 adjustWindowRectExForDpi = (AdjustWindowRectExForDpi)library.resolve("AdjustWindowRectExForDpi");
215 enableNonClientDpiScaling = (EnableNonClientDpiScaling)library.resolve("EnableNonClientDpiScaling");
216 getWindowDpiAwarenessContext = (GetWindowDpiAwarenessContext)library.resolve("GetWindowDpiAwarenessContext");
217 getAwarenessFromDpiAwarenessContext = (GetAwarenessFromDpiAwarenessContext)library.resolve("GetAwarenessFromDpiAwarenessContext");
218 systemParametersInfoForDpi = (SystemParametersInfoForDpi)library.resolve("SystemParametersInfoForDpi");
219 }
220}
221
222bool QWindowsUser32DLL::supportsPointerApi()
223{
224 return enableMouseInPointer && getPointerType && getPointerInfo && getPointerDeviceRects
225 && getPointerTouchInfo && getPointerFrameTouchInfo && getPointerFrameTouchInfoHistory
226 && getPointerPenInfo && getPointerPenInfoHistory && skipPointerFrameMessages;
227}
228
229void QWindowsShcoreDLL::init()
230{
231 if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8_1)
232 return;
233 QSystemLibrary library(QStringLiteral("SHCore"));
234 getProcessDpiAwareness = (GetProcessDpiAwareness)library.resolve("GetProcessDpiAwareness");
235 setProcessDpiAwareness = (SetProcessDpiAwareness)library.resolve("SetProcessDpiAwareness");
236 getDpiForMonitor = (GetDpiForMonitor)library.resolve("GetDpiForMonitor");
237}
238
239QWindowsUser32DLL QWindowsContext::user32dll;
240QWindowsShcoreDLL QWindowsContext::shcoredll;
241
242QWindowsContext *QWindowsContext::m_instance = nullptr;
243
244/*!
245 \class QWindowsContext
246 \brief Singleton container for all relevant information.
247
248 Holds state information formerly stored in \c qapplication_win.cpp.
249
250 \internal
251 \ingroup qt-lighthouse-win
252*/
253
254typedef QHash<HWND, QWindowsWindow *> HandleBaseWindowHash;
255
256struct QWindowsContextPrivate {
257 QWindowsContextPrivate();
258
259 unsigned m_systemInfo = 0;
260 QSet<QString> m_registeredWindowClassNames;
261 HandleBaseWindowHash m_windows;
262 HDC m_displayContext = nullptr;
263 int m_defaultDPI = 96;
264 QWindowsKeyMapper m_keyMapper;
265 QWindowsMouseHandler m_mouseHandler;
266 QWindowsPointerHandler m_pointerHandler;
267 QWindowsMimeConverter m_mimeConverter;
268 QWindowsScreenManager m_screenManager;
269 QSharedPointer<QWindowCreationContext> m_creationContext;
270#if QT_CONFIG(tabletevent)
271 QScopedPointer<QWindowsTabletSupport> m_tabletSupport;
272#endif
273 const HRESULT m_oleInitializeResult;
274 QWindow *m_lastActiveWindow = nullptr;
275 bool m_asyncExpose = false;
276};
277
278QWindowsContextPrivate::QWindowsContextPrivate()
279 : m_oleInitializeResult(OleInitialize(nullptr))
280{
281 QWindowsContext::user32dll.init();
282 QWindowsContext::shcoredll.init();
283
284 if (m_pointerHandler.touchDevice() || m_mouseHandler.touchDevice())
285 m_systemInfo |= QWindowsContext::SI_SupportsTouch;
286 m_displayContext = GetDC(nullptr);
287 m_defaultDPI = GetDeviceCaps(m_displayContext, LOGPIXELSY);
288 if (useRTL_Extensions()) {
289 m_systemInfo |= QWindowsContext::SI_RTL_Extensions;
290 m_keyMapper.setUseRTLExtensions(true);
291 }
292 if (FAILED(m_oleInitializeResult)) {
293 qWarning() << "QWindowsContext: OleInitialize() failed: "
294 << QWindowsContext::comErrorString(m_oleInitializeResult);
295 }
296}
297
298QWindowsContext::QWindowsContext() :
299 d(new QWindowsContextPrivate)
300{
301#ifdef Q_CC_MSVC
302# pragma warning( disable : 4996 )
303#endif
304 m_instance = this;
305 // ### FIXME: Remove this once the logging system has other options of configurations.
306 const QByteArray bv = qgetenv("QT_QPA_VERBOSE");
307 if (!bv.isEmpty())
308 QLoggingCategory::setFilterRules(QString::fromLocal8Bit(bv));
309}
310
311QWindowsContext::~QWindowsContext()
312{
313#if QT_CONFIG(tabletevent)
314 d->m_tabletSupport.reset(); // Destroy internal window before unregistering classes.
315#endif
316 unregisterWindowClasses();
317 if (d->m_oleInitializeResult == S_OK || d->m_oleInitializeResult == S_FALSE)
318 OleUninitialize();
319
320 d->m_screenManager.clearScreens(); // Order: Potentially calls back to the windows.
321 if (d->m_displayContext)
322 ReleaseDC(nullptr, d->m_displayContext);
323 m_instance = nullptr;
324}
325
326bool QWindowsContext::initTouch()
327{
328 return initTouch(QWindowsIntegration::instance()->options());
329}
330
331bool QWindowsContext::initTouch(unsigned integrationOptions)
332{
333 if (d->m_systemInfo & QWindowsContext::SI_SupportsTouch)
334 return true;
335
336 QTouchDevice *touchDevice = (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) ?
337 d->m_pointerHandler.ensureTouchDevice() : d->m_mouseHandler.ensureTouchDevice();
338 if (!touchDevice)
339 return false;
340
341 if (!(integrationOptions & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch))
342 touchDevice->setCapabilities(touchDevice->capabilities() | QTouchDevice::MouseEmulation);
343
344 QWindowSystemInterface::registerTouchDevice(touchDevice);
345
346 d->m_systemInfo |= QWindowsContext::SI_SupportsTouch;
347
348 // A touch device was plugged while the app is running. Register all windows for touch.
349 if (QGuiApplicationPrivate::is_app_running) {
350 for (QWindowsWindow *w : qAsConst(d->m_windows))
351 w->registerTouchWindow();
352 }
353
354 return true;
355}
356
357bool QWindowsContext::initTablet(unsigned integrationOptions)
358{
359 Q_UNUSED(integrationOptions);
360#if QT_CONFIG(tabletevent)
361 d->m_tabletSupport.reset(QWindowsTabletSupport::create());
362 return true;
363#else
364 return false;
365#endif
366}
367
368bool QWindowsContext::initPointer(unsigned integrationOptions)
369{
370 if (integrationOptions & QWindowsIntegration::DontUseWMPointer)
371 return false;
372
373 if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8)
374 return false;
375
376 if (!QWindowsContext::user32dll.supportsPointerApi())
377 return false;
378
379 d->m_systemInfo |= QWindowsContext::SI_SupportsPointer;
380 return true;
381}
382
383void QWindowsContext::setTabletAbsoluteRange(int a)
384{
385#if QT_CONFIG(tabletevent)
386 if (!d->m_tabletSupport.isNull())
387 d->m_tabletSupport->setAbsoluteRange(a);
388#else
389 Q_UNUSED(a)
390#endif
391}
392
393void QWindowsContext::setDetectAltGrModifier(bool a)
394{
395 d->m_keyMapper.setDetectAltGrModifier(a);
396}
397
398int QWindowsContext::processDpiAwareness()
399{
400 int result;
401 if (QWindowsContext::shcoredll.getProcessDpiAwareness
402 && SUCCEEDED(QWindowsContext::shcoredll.getProcessDpiAwareness(nullptr, &result))) {
403 return result;
404 }
405 return -1;
406}
407
408void QWindowsContext::setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness)
409{
410 qCDebug(lcQpaWindows) << __FUNCTION__ << dpiAwareness;
411 if (QWindowsContext::shcoredll.isValid()) {
412 const HRESULT hr = QWindowsContext::shcoredll.setProcessDpiAwareness(dpiAwareness);
413 // E_ACCESSDENIED means set externally (MSVC manifest or external app loading Qt plugin).
414 // Silence warning in that case unless debug is enabled.
415 if (FAILED(hr) && (hr != E_ACCESSDENIED || lcQpaWindows().isDebugEnabled())) {
416 qWarning().noquote().nospace() << "SetProcessDpiAwareness("
417 << dpiAwareness << ") failed: " << QWindowsContext::comErrorString(hr)
418 << ", using " << QWindowsContext::processDpiAwareness();
419 }
420 } else {
421 if (dpiAwareness != QtWindows::ProcessDpiUnaware && QWindowsContext::user32dll.setProcessDPIAware) {
422 if (!QWindowsContext::user32dll.setProcessDPIAware())
423 qErrnoWarning("SetProcessDPIAware() failed");
424 }
425 }
426}
427
428QWindowsContext *QWindowsContext::instance()
429{
430 return m_instance;
431}
432
433unsigned QWindowsContext::systemInfo() const
434{
435 return d->m_systemInfo;
436}
437
438bool QWindowsContext::useRTLExtensions() const
439{
440 return d->m_keyMapper.useRTLExtensions();
441}
442
443QList<int> QWindowsContext::possibleKeys(const QKeyEvent *e) const
444{
445 return d->m_keyMapper.possibleKeys(e);
446}
447
448QSharedPointer<QWindowCreationContext> QWindowsContext::setWindowCreationContext(const QSharedPointer<QWindowCreationContext> &ctx)
449{
450 const QSharedPointer<QWindowCreationContext> old = d->m_creationContext;
451 d->m_creationContext = ctx;
452 return old;
453}
454
455QSharedPointer<QWindowCreationContext> QWindowsContext::windowCreationContext() const
456{
457 return d->m_creationContext;
458}
459
460int QWindowsContext::defaultDPI() const
461{
462 return d->m_defaultDPI;
463}
464
465HDC QWindowsContext::displayContext() const
466{
467 return d->m_displayContext;
468}
469
470QWindow *QWindowsContext::keyGrabber() const
471{
472 return d->m_keyMapper.keyGrabber();
473}
474
475void QWindowsContext::setKeyGrabber(QWindow *w)
476{
477 d->m_keyMapper.setKeyGrabber(w);
478}
479
480// Window class registering code (from qapplication_win.cpp)
481
482QString QWindowsContext::registerWindowClass(const QWindow *w)
483{
484 Q_ASSERT(w);
485 const Qt::WindowFlags flags = w->flags();
486 const Qt::WindowFlags type = flags & Qt::WindowType_Mask;
487 // Determine style and icon.
488 uint style = CS_DBLCLKS;
489 bool icon = true;
490 // The following will not set CS_OWNDC for any widget window, even if it contains a
491 // QOpenGLWidget or QQuickWidget later on. That cannot be detected at this stage.
492 if (w->surfaceType() == QSurface::OpenGLSurface || (flags & Qt::MSWindowsOwnDC))
493 style |= CS_OWNDC;
494 if (!(flags & Qt::NoDropShadowWindowHint)
495 && (type == Qt::Popup || w->property("_q_windowsDropShadow").toBool())) {
496 style |= CS_DROPSHADOW;
497 }
498 switch (type) {
499 case Qt::Tool:
500 case Qt::ToolTip:
501 case Qt::Popup:
502 style |= CS_SAVEBITS; // Save/restore background
503 icon = false;
504 break;
505 case Qt::Dialog:
506 if (!(flags & Qt::WindowSystemMenuHint))
507 icon = false; // QTBUG-2027, dialogs without system menu.
508 break;
509 }
510 // Create a unique name for the flag combination
511 QString cname;
512 cname += QLatin1String("Qt5QWindow");
513 switch (type) {
514 case Qt::Tool:
515 cname += QLatin1String("Tool");
516 break;
517 case Qt::ToolTip:
518 cname += QLatin1String("ToolTip");
519 break;
520 case Qt::Popup:
521 cname += QLatin1String("Popup");
522 break;
523 default:
524 break;
525 }
526 if (style & CS_DROPSHADOW)
527 cname += QLatin1String("DropShadow");
528 if (style & CS_SAVEBITS)
529 cname += QLatin1String("SaveBits");
530 if (style & CS_OWNDC)
531 cname += QLatin1String("OwnDC");
532 if (icon)
533 cname += QLatin1String("Icon");
534
535 return registerWindowClass(cname, qWindowsWndProc, style, GetSysColorBrush(COLOR_WINDOW), icon);
536}
537
538QString QWindowsContext::registerWindowClass(QString cname,
539 WNDPROC proc,
540 unsigned style,
541 HBRUSH brush,
542 bool icon)
543{
544 // since multiple Qt versions can be used in one process
545 // each one has to have window class names with a unique name
546 // The first instance gets the unmodified name; if the class
547 // has already been registered by another instance of Qt then
548 // add a UUID.
549 static int classExists = -1;
550
551 const auto appInstance = static_cast<HINSTANCE>(GetModuleHandle(nullptr));
552 if (classExists == -1) {
553 WNDCLASS wcinfo;
554 classExists = GetClassInfo(appInstance, reinterpret_cast<LPCWSTR>(cname.utf16()), &wcinfo);
555 classExists = classExists && wcinfo.lpfnWndProc != proc;
556 }
557
558 if (classExists)
559 cname += QUuid::createUuid().toString();
560
561 if (d->m_registeredWindowClassNames.contains(cname)) // already registered in our list
562 return cname;
563
564 WNDCLASSEX wc;
565 wc.cbSize = sizeof(WNDCLASSEX);
566 wc.style = style;
567 wc.lpfnWndProc = proc;
568 wc.cbClsExtra = 0;
569 wc.cbWndExtra = 0;
570 wc.hInstance = appInstance;
571 wc.hCursor = nullptr;
572 wc.hbrBackground = brush;
573 if (icon) {
574 wc.hIcon = static_cast<HICON>(LoadImage(appInstance, L"IDI_ICON1", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE));
575 if (wc.hIcon) {
576 int sw = GetSystemMetrics(SM_CXSMICON);
577 int sh = GetSystemMetrics(SM_CYSMICON);
578 wc.hIconSm = static_cast<HICON>(LoadImage(appInstance, L"IDI_ICON1", IMAGE_ICON, sw, sh, 0));
579 } else {
580 wc.hIcon = static_cast<HICON>(LoadImage(nullptr, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED));
581 wc.hIconSm = nullptr;
582 }
583 } else {
584 wc.hIcon = nullptr;
585 wc.hIconSm = nullptr;
586 }
587
588 wc.lpszMenuName = nullptr;
589 wc.lpszClassName = reinterpret_cast<LPCWSTR>(cname.utf16());
590 ATOM atom = RegisterClassEx(&wc);
591 if (!atom)
592 qErrnoWarning("QApplication::regClass: Registering window class '%s' failed.",
593 qPrintable(cname));
594
595 d->m_registeredWindowClassNames.insert(cname);
596 qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << ' ' << cname
597 << " style=0x" << Qt::hex << style << Qt::dec
598 << " brush=" << brush << " icon=" << icon << " atom=" << atom;
599 return cname;
600}
601
602void QWindowsContext::unregisterWindowClasses()
603{
604 const auto appInstance = static_cast<HINSTANCE>(GetModuleHandle(nullptr));
605
606 for (const QString &name : qAsConst(d->m_registeredWindowClassNames)) {
607 if (!UnregisterClass(reinterpret_cast<LPCWSTR>(name.utf16()), appInstance) && QWindowsContext::verbose)
608 qErrnoWarning("UnregisterClass failed for '%s'", qPrintable(name));
609 }
610 d->m_registeredWindowClassNames.clear();
611}
612
613int QWindowsContext::screenDepth() const
614{
615 return GetDeviceCaps(d->m_displayContext, BITSPIXEL);
616}
617
618QString QWindowsContext::windowsErrorMessage(unsigned long errorCode)
619{
620 QString rc = QString::fromLatin1("#%1: ").arg(errorCode);
621 ushort *lpMsgBuf;
622
623 const DWORD len = FormatMessage(
624 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
625 nullptr, errorCode, 0, reinterpret_cast<LPTSTR>(&lpMsgBuf), 0, nullptr);
626 if (len) {
627 rc = QString::fromUtf16(lpMsgBuf, int(len));
628 LocalFree(lpMsgBuf);
629 } else {
630 rc += QString::fromLatin1("<unknown error>");
631 }
632 return rc;
633}
634
635void QWindowsContext::addWindow(HWND hwnd, QWindowsWindow *w)
636{
637 d->m_windows.insert(hwnd, w);
638}
639
640void QWindowsContext::removeWindow(HWND hwnd)
641{
642 const HandleBaseWindowHash::iterator it = d->m_windows.find(hwnd);
643 if (it != d->m_windows.end()) {
644 if (d->m_keyMapper.keyGrabber() == it.value()->window())
645 d->m_keyMapper.setKeyGrabber(nullptr);
646 d->m_windows.erase(it);
647 }
648}
649
650QWindowsWindow *QWindowsContext::findPlatformWindow(const QWindowsMenuBar *mb) const
651{
652 for (auto it = d->m_windows.cbegin(), end = d->m_windows.cend(); it != end; ++it) {
653 if ((*it)->menuBar() == mb)
654 return *it;
655 }
656 return nullptr;
657}
658
659QWindowsWindow *QWindowsContext::findPlatformWindow(HWND hwnd) const
660{
661 return d->m_windows.value(hwnd);
662}
663
664QWindowsWindow *QWindowsContext::findClosestPlatformWindow(HWND hwnd) const
665{
666 QWindowsWindow *window = d->m_windows.value(hwnd);
667
668 // Requested hwnd may also be a child of a platform window in case of embedded native windows.
669 // Find the closest parent that has a platform window.
670 if (!window) {
671 for (HWND w = hwnd; w; w = GetParent(w)) {
672 window = d->m_windows.value(w);
673 if (window)
674 break;
675 }
676 }
677
678 return window;
679}
680
681QWindow *QWindowsContext::findWindow(HWND hwnd) const
682{
683 if (const QWindowsWindow *bw = findPlatformWindow(hwnd))
684 return bw->window();
685 return nullptr;
686}
687
688QWindow *QWindowsContext::windowUnderMouse() const
689{
690 return (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) ?
691 d->m_pointerHandler.windowUnderMouse() : d->m_mouseHandler.windowUnderMouse();
692}
693
694void QWindowsContext::clearWindowUnderMouse()
695{
696 if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer)
697 d->m_pointerHandler.clearWindowUnderMouse();
698 else
699 d->m_mouseHandler.clearWindowUnderMouse();
700}
701
702/*!
703 \brief Find a child window at a screen point.
704
705 Deep search for a QWindow at global point, skipping non-owned
706 windows (accessibility?). Implemented using ChildWindowFromPointEx()
707 instead of (historically used) WindowFromPoint() to get a well-defined
708 behaviour for hidden/transparent windows.
709
710 \a cwex_flags are flags of ChildWindowFromPointEx().
711 \a parent is the parent window, pass GetDesktopWindow() for top levels.
712*/
713
714static inline bool findPlatformWindowHelper(const POINT &screenPoint, unsigned cwexFlags,
715 const QWindowsContext *context,
716 HWND *hwnd, QWindowsWindow **result)
717{
718 POINT point = screenPoint;
719 screenToClient(*hwnd, &point);
720 // Returns parent if inside & none matched.
721 const HWND child = ChildWindowFromPointEx(*hwnd, point, cwexFlags);
722 if (!child || child == *hwnd)
723 return false;
724 if (QWindowsWindow *window = context->findPlatformWindow(child)) {
725 *result = window;
726 *hwnd = child;
727 return true;
728 }
729 // QTBUG-40555: despite CWP_SKIPINVISIBLE, it is possible to hit on invisible
730 // full screen windows of other applications that have WS_EX_TRANSPARENT set
731 // (for example created by screen sharing applications). In that case, try to
732 // find a Qt window by searching again with CWP_SKIPTRANSPARENT.
733 // Note that Qt 5 uses WS_EX_TRANSPARENT for Qt::WindowTransparentForInput
734 // as well.
735 if (!(cwexFlags & CWP_SKIPTRANSPARENT)
736 && (GetWindowLongPtr(child, GWL_EXSTYLE) & WS_EX_TRANSPARENT)) {
737 const HWND nonTransparentChild = ChildWindowFromPointEx(*hwnd, point, cwexFlags | CWP_SKIPTRANSPARENT);
738 if (QWindowsWindow *nonTransparentWindow = context->findPlatformWindow(nonTransparentChild)) {
739 *result = nonTransparentWindow;
740 *hwnd = nonTransparentChild;
741 return true;
742 }
743 }
744 *hwnd = child;
745 return true;
746}
747
748QWindowsWindow *QWindowsContext::findPlatformWindowAt(HWND parent,
749 const QPoint &screenPointIn,
750 unsigned cwex_flags) const
751{
752 QWindowsWindow *result = nullptr;
753 const POINT screenPoint = { screenPointIn.x(), screenPointIn.y() };
754 while (findPlatformWindowHelper(screenPoint, cwex_flags, this, &parent, &result)) {}
755 // QTBUG-40815: ChildWindowFromPointEx() can hit on special windows from
756 // screen recorder applications like ScreenToGif. Fall back to WindowFromPoint().
757 if (result == nullptr) {
758 if (const HWND window = WindowFromPoint(screenPoint))
759 result = findPlatformWindow(window);
760 }
761 return result;
762}
763
764bool QWindowsContext::isSessionLocked()
765{
766 bool result = false;
767 const DWORD sessionId = WTSGetActiveConsoleSessionId();
768 if (sessionId != 0xFFFFFFFF) {
769 LPTSTR buffer = nullptr;
770 DWORD size = 0;
771#if !defined(Q_CC_MINGW)
772 if (WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, sessionId,
773 WTSSessionInfoEx, &buffer, &size) == TRUE
774 && size > 0) {
775 const WTSINFOEXW *info = reinterpret_cast<WTSINFOEXW *>(buffer);
776 result = info->Level == 1 && info->Data.WTSInfoExLevel1.SessionFlags == WTS_SESSIONSTATE_LOCK;
777 WTSFreeMemory(buffer);
778 }
779#else // MinGW as of 7.3 does not have WTSINFOEXW in wtsapi32.h
780 // Retrieve the flags which are at offset 16 due to padding for 32/64bit alike.
781 if (WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, sessionId,
782 WTS_INFO_CLASS(25), &buffer, &size) == TRUE
783 && size >= 20) {
784 const DWORD *p = reinterpret_cast<DWORD *>(buffer);
785 const DWORD level = *p;
786 const DWORD sessionFlags = *(p + 4);
787 result = level == 1 && sessionFlags == 1;
788 WTSFreeMemory(buffer);
789 }
790#endif // Q_CC_MINGW
791 }
792 return result;
793}
794
795QWindowsMimeConverter &QWindowsContext::mimeConverter() const
796{
797 return d->m_mimeConverter;
798}
799
800QWindowsScreenManager &QWindowsContext::screenManager()
801{
802 return d->m_screenManager;
803}
804
805QWindowsTabletSupport *QWindowsContext::tabletSupport() const
806{
807#if QT_CONFIG(tabletevent)
808 return d->m_tabletSupport.data();
809#else
810 return 0;
811#endif
812}
813
814/*!
815 \brief Convenience to create a non-visible, message-only dummy
816 window for example used as clipboard watcher or for GL.
817*/
818
819HWND QWindowsContext::createDummyWindow(const QString &classNameIn,
820 const wchar_t *windowName,
821 WNDPROC wndProc, DWORD style)
822{
823 if (!wndProc)
824 wndProc = DefWindowProc;
825 QString className = registerWindowClass(classNameIn, wndProc);
826 return CreateWindowEx(0, reinterpret_cast<LPCWSTR>(className.utf16()),
827 windowName, style,
828 CW_USEDEFAULT, CW_USEDEFAULT,
829 CW_USEDEFAULT, CW_USEDEFAULT,
830 HWND_MESSAGE, nullptr, static_cast<HINSTANCE>(GetModuleHandle(nullptr)), nullptr);
831}
832
833// Re-engineered from the inline function _com_error::ErrorMessage().
834// We cannot use it directly since it uses swprintf_s(), which is not
835// present in the MSVCRT.DLL found on Windows XP (QTBUG-35617).
836static inline QString errorMessageFromComError(const _com_error &comError)
837{
838 TCHAR *message = nullptr;
839 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
840 nullptr, DWORD(comError.Error()), MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
841 message, 0, nullptr);
842 if (message) {
843 const QString result = QString::fromWCharArray(message).trimmed();
844 LocalFree(static_cast<HLOCAL>(message));
845 return result;
846 }
847 if (const WORD wCode = comError.WCode())
848 return QString::asprintf("IDispatch error #%u", uint(wCode));
849 return QString::asprintf("Unknown error 0x0%x", uint(comError.Error()));
850}
851
852/*!
853 \brief Common COM error strings.
854*/
855
856QByteArray QWindowsContext::comErrorString(HRESULT hr)
857{
858 QByteArray result = QByteArrayLiteral("COM error 0x")
859 + QByteArray::number(quintptr(hr), 16) + ' ';
860 switch (hr) {
861 case S_OK:
862 result += QByteArrayLiteral("S_OK");
863 break;
864 case S_FALSE:
865 result += QByteArrayLiteral("S_FALSE");
866 break;
867 case E_UNEXPECTED:
868 result += QByteArrayLiteral("E_UNEXPECTED");
869 break;
870 case E_ACCESSDENIED:
871 result += QByteArrayLiteral("E_ACCESSDENIED");
872 break;
873 case CO_E_ALREADYINITIALIZED:
874 result += QByteArrayLiteral("CO_E_ALREADYINITIALIZED");
875 break;
876 case CO_E_NOTINITIALIZED:
877 result += QByteArrayLiteral("CO_E_NOTINITIALIZED");
878 break;
879 case RPC_E_CHANGED_MODE:
880 result += QByteArrayLiteral("RPC_E_CHANGED_MODE");
881 break;
882 case OLE_E_WRONGCOMPOBJ:
883 result += QByteArrayLiteral("OLE_E_WRONGCOMPOBJ");
884 break;
885 case CO_E_NOT_SUPPORTED:
886 result += QByteArrayLiteral("CO_E_NOT_SUPPORTED");
887 break;
888 case E_NOTIMPL:
889 result += QByteArrayLiteral("E_NOTIMPL");
890 break;
891 case E_INVALIDARG:
892 result += QByteArrayLiteral("E_INVALIDARG");
893 break;
894 case E_NOINTERFACE:
895 result += QByteArrayLiteral("E_NOINTERFACE");
896 break;
897 case E_POINTER:
898 result += QByteArrayLiteral("E_POINTER");
899 break;
900 case E_HANDLE:
901 result += QByteArrayLiteral("E_HANDLE");
902 break;
903 case E_ABORT:
904 result += QByteArrayLiteral("E_ABORT");
905 break;
906 case E_FAIL:
907 result += QByteArrayLiteral("E_FAIL");
908 break;
909 case RPC_E_WRONG_THREAD:
910 result += QByteArrayLiteral("RPC_E_WRONG_THREAD");
911 break;
912 case RPC_E_THREAD_NOT_INIT:
913 result += QByteArrayLiteral("RPC_E_THREAD_NOT_INIT");
914 break;
915 default:
916 break;
917 }
918 _com_error error(hr);
919 result += QByteArrayLiteral(" (");
920 result += errorMessageFromComError(error);
921 result += ')';
922 return result;
923}
924
925bool QWindowsContext::systemParametersInfo(unsigned action, unsigned param, void *out,
926 unsigned dpi)
927{
928 const BOOL result = QWindowsContext::user32dll.systemParametersInfoForDpi != nullptr && dpi != 0
929 ? QWindowsContext::user32dll.systemParametersInfoForDpi(action, param, out, 0, dpi)
930 : SystemParametersInfo(action, param, out, 0);
931 return result == TRUE;
932}
933
934bool QWindowsContext::systemParametersInfoForScreen(unsigned action, unsigned param, void *out,
935 const QPlatformScreen *screen)
936{
937 return systemParametersInfo(action, param, out, screen ? unsigned(screen->logicalDpi().first) : 0u);
938}
939
940bool QWindowsContext::systemParametersInfoForWindow(unsigned action, unsigned param, void *out,
941 const QPlatformWindow *win)
942{
943 return systemParametersInfoForScreen(action, param, out, win ? win->screen() : nullptr);
944}
945
946bool QWindowsContext::nonClientMetrics(NONCLIENTMETRICS *ncm, unsigned dpi)
947{
948 memset(ncm, 0, sizeof(NONCLIENTMETRICS));
949 ncm->cbSize = sizeof(NONCLIENTMETRICS);
950 return systemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm->cbSize, ncm, dpi);
951}
952
953bool QWindowsContext::nonClientMetricsForScreen(NONCLIENTMETRICS *ncm,
954 const QPlatformScreen *screen)
955{
956 const int dpi = screen ? qRound(screen->logicalDpi().first) : 0;
957 return nonClientMetrics(ncm, unsigned(dpi));
958}
959
960bool QWindowsContext::nonClientMetricsForWindow(NONCLIENTMETRICS *ncm, const QPlatformWindow *win)
961{
962 return nonClientMetricsForScreen(ncm, win ? win->screen() : nullptr);
963}
964
965static inline QWindowsInputContext *windowsInputContext()
966{
967 return qobject_cast<QWindowsInputContext *>(QWindowsIntegration::instance()->inputContext());
968}
969
970
971// Child windows, fixed-size windows or pop-ups and similar should not be resized
972static inline bool resizeOnDpiChanged(const QWindow *w)
973{
974 bool result = false;
975 if (w->isTopLevel()) {
976 switch (w->type()) {
977 case Qt::Window:
978 case Qt::Dialog:
979 case Qt::Sheet:
980 case Qt::Drawer:
981 case Qt::Tool:
982 result = !w->flags().testFlag(Qt::MSWindowsFixedSizeDialogHint);
983 break;
984 default:
985 break;
986 }
987 }
988 return result;
989}
990
991bool QWindowsContext::shouldHaveNonClientDpiScaling(const QWindow *window)
992{
993 return QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10
994 && window->isTopLevel()
995 && !window->property(QWindowsWindow::embeddedNativeParentHandleProperty).isValid()
996#if QT_CONFIG(opengl) // /QTBUG-62901, EnableNonClientDpiScaling has problems with GL
997 && (window->surfaceType() != QSurface::OpenGLSurface
998 || QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL)
999#endif
1000 ;
1001}
1002
1003static inline bool isInputMessage(UINT m)
1004{
1005 switch (m) {
1006 case WM_IME_STARTCOMPOSITION:
1007 case WM_IME_ENDCOMPOSITION:
1008 case WM_IME_COMPOSITION:
1009 case WM_INPUT:
1010 case WM_TOUCH:
1011 case WM_MOUSEHOVER:
1012 case WM_MOUSELEAVE:
1013 case WM_NCMOUSEHOVER:
1014 case WM_NCMOUSELEAVE:
1015 case WM_SIZING:
1016 case WM_MOVING:
1017 case WM_SYSCOMMAND:
1018 case WM_COMMAND:
1019 case WM_DWMNCRENDERINGCHANGED:
1020 case WM_PAINT:
1021 return true;
1022 default:
1023 break;
1024 }
1025 return (m >= WM_MOUSEFIRST && m <= WM_MOUSELAST)
1026 || (m >= WM_NCMOUSEMOVE && m <= WM_NCXBUTTONDBLCLK)
1027 || (m >= WM_KEYFIRST && m <= WM_KEYLAST);
1028}
1029
1030/*!
1031 \brief Main windows procedure registered for windows.
1032
1033 \sa QWindowsGuiEventDispatcher
1034*/
1035
1036bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
1037 QtWindows::WindowsEventType et,
1038 WPARAM wParam, LPARAM lParam,
1039 LRESULT *result,
1040 QWindowsWindow **platformWindowPtr)
1041{
1042 *result = 0;
1043
1044 MSG msg;
1045 msg.hwnd = hwnd; // re-create MSG structure
1046 msg.message = message; // time and pt fields ignored
1047 msg.wParam = wParam;
1048 msg.lParam = lParam;
1049 msg.pt.x = msg.pt.y = 0;
1050 if (et != QtWindows::CursorEvent && (et & (QtWindows::MouseEventFlag | QtWindows::NonClientEventFlag))) {
1051 msg.pt.x = GET_X_LPARAM(lParam);
1052 msg.pt.y = GET_Y_LPARAM(lParam);
1053 // For non-client-area messages, these are screen coordinates (as expected
1054 // in the MSG structure), otherwise they are client coordinates.
1055 if (!(et & QtWindows::NonClientEventFlag)) {
1056 clientToScreen(msg.hwnd, &msg.pt);
1057 }
1058 } else {
1059 GetCursorPos(&msg.pt);
1060 }
1061
1062 QWindowsWindow *platformWindow = findPlatformWindow(hwnd);
1063 *platformWindowPtr = platformWindow;
1064
1065 // Run the native event filters. QTBUG-67095: Exclude input messages which are sent
1066 // by QEventDispatcherWin32::processEvents()
1067 if (!isInputMessage(msg.message) && filterNativeEvent(&msg, result))
1068 return true;
1069
1070 if (platformWindow && filterNativeEvent(platformWindow->window(), &msg, result))
1071 return true;
1072
1073 if (et & QtWindows::InputMethodEventFlag) {
1074 QWindowsInputContext *windowsInputContext = ::windowsInputContext();
1075 // Disable IME assuming this is a special implementation hooking into keyboard input.
1076 // "Real" IME implementations should use a native event filter intercepting IME events.
1077 if (!windowsInputContext) {
1078 QWindowsInputContext::setWindowsImeEnabled(platformWindow, false);
1079 return false;
1080 }
1081 switch (et) {
1082 case QtWindows::InputMethodStartCompositionEvent:
1083 return windowsInputContext->startComposition(hwnd);
1084 case QtWindows::InputMethodCompositionEvent:
1085 return windowsInputContext->composition(hwnd, lParam);
1086 case QtWindows::InputMethodEndCompositionEvent:
1087 return windowsInputContext->endComposition(hwnd);
1088 case QtWindows::InputMethodRequest:
1089 return windowsInputContext->handleIME_Request(wParam, lParam, result);
1090 default:
1091 break;
1092 }
1093 } // InputMethodEventFlag
1094
1095 switch (et) {
1096 case QtWindows::GestureEvent:
1097 if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
1098 return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateGestureEvent(platformWindow->window(), hwnd, et, msg, result);
1099 break;
1100 case QtWindows::InputMethodOpenCandidateWindowEvent:
1101 case QtWindows::InputMethodCloseCandidateWindowEvent:
1102 // TODO: Release/regrab mouse if a popup has mouse grab.
1103 return false;
1104 case QtWindows::DestroyEvent:
1105 if (platformWindow && !platformWindow->testFlag(QWindowsWindow::WithinDestroy)) {
1106 qWarning() << "External WM_DESTROY received for " << platformWindow->window()
1107 << ", parent: " << platformWindow->window()->parent()
1108 << ", transient parent: " << platformWindow->window()->transientParent();
1109 }
1110 return false;
1111 case QtWindows::ClipboardEvent:
1112 return false;
1113 case QtWindows::CursorEvent: // Sent to windows that do not have capture (see QTBUG-58590).
1114 if (QWindowsCursor::hasOverrideCursor()) {
1115 QWindowsCursor::enforceOverrideCursor();
1116 return true;
1117 }
1118 break;
1119 case QtWindows::UnknownEvent:
1120 return false;
1121 case QtWindows::AccessibleObjectFromWindowRequest:
1122#if QT_CONFIG(accessibility)
1123 return QWindowsUiaAccessibility::handleWmGetObject(hwnd, wParam, lParam, result);
1124#else
1125 return false;
1126#endif
1127 case QtWindows::DisplayChangedEvent:
1128 if (QWindowsTheme *t = QWindowsTheme::instance())
1129 t->displayChanged();
1130 QWindowsWindow::displayChanged();
1131 return d->m_screenManager.handleDisplayChange(wParam, lParam);
1132 case QtWindows::SettingChangedEvent:
1133 QWindowsWindow::settingsChanged();
1134 return d->m_screenManager.handleScreenChanges();
1135 default:
1136 break;
1137 }
1138
1139 // Before CreateWindowEx() returns, some events are sent,
1140 // for example WM_GETMINMAXINFO asking for size constraints for top levels.
1141 // Pass on to current creation context
1142 if (!platformWindow && !d->m_creationContext.isNull()) {
1143 switch (et) {
1144 case QtWindows::QuerySizeHints:
1145 d->m_creationContext->applyToMinMaxInfo(reinterpret_cast<MINMAXINFO *>(lParam));
1146 return true;
1147 case QtWindows::ResizeEvent:
1148 d->m_creationContext->obtainedSize = QSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
1149 return true;
1150 case QtWindows::MoveEvent:
1151 d->m_creationContext->obtainedPos = QPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
1152 return true;
1153 case QtWindows::NonClientCreate:
1154 if (shouldHaveNonClientDpiScaling(d->m_creationContext->window))
1155 enableNonClientDpiScaling(msg.hwnd);
1156 return false;
1157 case QtWindows::CalculateSize:
1158 return QWindowsGeometryHint::handleCalculateSize(d->m_creationContext->customMargins, msg, result);
1159 case QtWindows::GeometryChangingEvent:
1160 return QWindowsWindow::handleGeometryChangingMessage(&msg, d->m_creationContext->window,
1161 d->m_creationContext->margins + d->m_creationContext->customMargins);
1162 default:
1163 break;
1164 }
1165 }
1166 if (platformWindow) {
1167 // Suppress events sent during DestroyWindow() for native children.
1168 if (platformWindow->testFlag(QWindowsWindow::WithinDestroy))
1169 return false;
1170 if (QWindowsContext::verbose > 1)
1171 qCDebug(lcQpaEvents) << "Event window: " << platformWindow->window();
1172 } else {
1173 qWarning("%s: No Qt Window found for event 0x%x (%s), hwnd=0x%p.",
1174 __FUNCTION__, message,
1175 QWindowsGuiEventDispatcher::windowsMessageName(message), hwnd);
1176 return false;
1177 }
1178
1179 switch (et) {
1180 case QtWindows::DeviceChangeEvent:
1181 if (d->m_systemInfo & QWindowsContext::SI_SupportsTouch)
1182 break;
1183 // See if there are any touch devices added
1184 if (wParam == DBT_DEVNODES_CHANGED)
1185 initTouch();
1186 break;
1187 case QtWindows::KeyboardLayoutChangeEvent:
1188 if (QWindowsInputContext *wic = windowsInputContext())
1189 wic->handleInputLanguageChanged(wParam, lParam);
1190 Q_FALLTHROUGH();
1191 case QtWindows::KeyDownEvent:
1192 case QtWindows::KeyEvent:
1193 case QtWindows::InputMethodKeyEvent:
1194 case QtWindows::InputMethodKeyDownEvent:
1195 case QtWindows::AppCommandEvent:
1196 return sessionManagerInteractionBlocked() || d->m_keyMapper.translateKeyEvent(platformWindow->window(), hwnd, msg, result);
1197 case QtWindows::MenuAboutToShowEvent:
1198 if (sessionManagerInteractionBlocked())
1199 return true;
1200 if (QWindowsPopupMenu::notifyAboutToShow(reinterpret_cast<HMENU>(wParam)))
1201 return true;
1202 if (platformWindow == nullptr || platformWindow->menuBar() == nullptr)
1203 return false;
1204 return platformWindow->menuBar()->notifyAboutToShow(reinterpret_cast<HMENU>(wParam));
1205 case QtWindows::MenuCommandEvent:
1206 if (sessionManagerInteractionBlocked())
1207 return true;
1208 if (QWindowsPopupMenu::notifyTriggered(LOWORD(wParam)))
1209 return true;
1210 if (platformWindow == nullptr || platformWindow->menuBar() == nullptr)
1211 return false;
1212 return platformWindow->menuBar()->notifyTriggered(LOWORD(wParam));
1213 case QtWindows::MoveEvent:
1214 platformWindow->handleMoved();
1215 return true;
1216 case QtWindows::ResizeEvent:
1217 platformWindow->handleResized(static_cast<int>(wParam));
1218 return true;
1219 case QtWindows::QuerySizeHints:
1220 platformWindow->getSizeHints(reinterpret_cast<MINMAXINFO *>(lParam));
1221 return true;// maybe available on some SDKs revisit WM_NCCALCSIZE
1222 case QtWindows::CalculateSize:
1223 return QWindowsGeometryHint::handleCalculateSize(platformWindow->customMargins(), msg, result);
1224 case QtWindows::NonClientHitTest:
1225 return platformWindow->handleNonClientHitTest(QPoint(msg.pt.x, msg.pt.y), result);
1226 case QtWindows::GeometryChangingEvent:
1227 return platformWindow->QWindowsWindow::handleGeometryChanging(&msg);
1228 case QtWindows::ExposeEvent:
1229 return platformWindow->handleWmPaint(hwnd, message, wParam, lParam);
1230 case QtWindows::NonClientMouseEvent:
1231 if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer) && platformWindow->frameStrutEventsEnabled())
1232 return sessionManagerInteractionBlocked() || d->m_pointerHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
1233 else
1234 return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
1235 case QtWindows::NonClientPointerEvent:
1236 if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer) && platformWindow->frameStrutEventsEnabled())
1237 return sessionManagerInteractionBlocked() || d->m_pointerHandler.translatePointerEvent(platformWindow->window(), hwnd, et, msg, result);
1238 break;
1239 case QtWindows::EnterSizeMoveEvent:
1240 platformWindow->setFlag(QWindowsWindow::ResizeMoveActive);
1241 return true;
1242 case QtWindows::ExitSizeMoveEvent:
1243 platformWindow->clearFlag(QWindowsWindow::ResizeMoveActive);
1244 platformWindow->checkForScreenChanged();
1245 handleExitSizeMove(platformWindow->window());
1246 return true;
1247 case QtWindows::ScrollEvent:
1248 if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
1249 return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateScrollEvent(platformWindow->window(), hwnd, msg, result);
1250 break;
1251 case QtWindows::MouseWheelEvent:
1252 case QtWindows::MouseEvent:
1253 case QtWindows::LeaveEvent:
1254 {
1255 QWindow *window = platformWindow->window();
1256 while (window && (window->flags() & Qt::WindowTransparentForInput))
1257 window = window->parent();
1258 if (!window)
1259 return false;
1260 if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer)
1261 return sessionManagerInteractionBlocked() || d->m_pointerHandler.translateMouseEvent(window, hwnd, et, msg, result);
1262 else
1263 return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(window, hwnd, et, msg, result);
1264 }
1265 break;
1266 case QtWindows::TouchEvent:
1267 if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
1268 return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateTouchEvent(platformWindow->window(), hwnd, et, msg, result);
1269 break;
1270 case QtWindows::PointerEvent:
1271 if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer)
1272 return sessionManagerInteractionBlocked() || d->m_pointerHandler.translatePointerEvent(platformWindow->window(), hwnd, et, msg, result);
1273 break;
1274 case QtWindows::FocusInEvent: // see QWindowsWindow::requestActivateWindow().
1275 case QtWindows::FocusOutEvent:
1276 handleFocusEvent(et, platformWindow);
1277 return true;
1278 case QtWindows::ShowEventOnParentRestoring: // QTBUG-40696, prevent Windows from re-showing hidden transient children (dialogs).
1279 if (!platformWindow->window()->isVisible()) {
1280 *result = 0;
1281 return true;
1282 }
1283 break;
1284 case QtWindows::HideEvent:
1285 platformWindow->handleHidden();
1286 return false;// Indicate transient children should be hidden by windows (SW_PARENTCLOSING)
1287 case QtWindows::CloseEvent:
1288 QWindowSystemInterface::handleCloseEvent(platformWindow->window());
1289 return true;
1290 case QtWindows::ThemeChanged: {
1291 // Switch from Aero to Classic changes margins.
1292 if (QWindowsTheme *theme = QWindowsTheme::instance())
1293 theme->windowsThemeChanged(platformWindow->window());
1294 return true;
1295 }
1296 case QtWindows::CompositionSettingsChanged:
1297 platformWindow->handleCompositionSettingsChanged();
1298 return true;
1299 case QtWindows::ActivateWindowEvent:
1300 if (platformWindow->window()->flags() & Qt::WindowDoesNotAcceptFocus) {
1301 *result = LRESULT(MA_NOACTIVATE);
1302 return true;
1303 }
1304#if QT_CONFIG(tabletevent)
1305 if (!d->m_tabletSupport.isNull())
1306 d->m_tabletSupport->notifyActivate();
1307#endif // QT_CONFIG(tabletevent)
1308 if (platformWindow->testFlag(QWindowsWindow::BlockedByModal))
1309 if (const QWindow *modalWindow = QGuiApplication::modalWindow()) {
1310 QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(modalWindow);
1311 Q_ASSERT(platformWindow);
1312 platformWindow->alertWindow();
1313 }
1314 break;
1315 case QtWindows::MouseActivateWindowEvent:
1316 case QtWindows::PointerActivateWindowEvent:
1317 if (platformWindow->window()->flags() & Qt::WindowDoesNotAcceptFocus) {
1318 *result = LRESULT(MA_NOACTIVATE);
1319 return true;
1320 }
1321 break;
1322#ifndef QT_NO_CONTEXTMENU
1323 case QtWindows::ContextMenu:
1324 return handleContextMenuEvent(platformWindow->window(), msg);
1325#endif
1326 case QtWindows::WhatsThisEvent: {
1327#ifndef QT_NO_WHATSTHIS
1328 QWindowSystemInterface::handleEnterWhatsThisEvent();
1329 return true;
1330#endif
1331 } break;
1332 case QtWindows::DpiChangedEvent: {
1333 // Try to apply the suggested size first and then notify ScreenChanged
1334 // so that the resize event sent from QGuiApplication incorporates it
1335 // WM_DPICHANGED is sent with a size that avoids resize loops (by
1336 // snapping back to the previous screen, see QTBUG-65580).
1337 const bool doResize = resizeOnDpiChanged(platformWindow->window());
1338 if (doResize) {
1339 platformWindow->setFlag(QWindowsWindow::WithinDpiChanged);
1340 platformWindow->updateFullFrameMargins();
1341 const auto prcNewWindow = reinterpret_cast<RECT *>(lParam);
1342 qCDebug(lcQpaWindows) << __FUNCTION__ << "WM_DPICHANGED"
1343 << platformWindow->window() << *prcNewWindow;
1344 SetWindowPos(hwnd, nullptr, prcNewWindow->left, prcNewWindow->top,
1345 prcNewWindow->right - prcNewWindow->left,
1346 prcNewWindow->bottom - prcNewWindow->top, SWP_NOZORDER | SWP_NOACTIVATE);
1347 platformWindow->clearFlag(QWindowsWindow::WithinDpiChanged);
1348 }
1349 platformWindow->checkForScreenChanged(QWindowsWindow::FromDpiChange);
1350 return doResize;
1351 }
1352#if QT_CONFIG(sessionmanager)
1353 case QtWindows::QueryEndSessionApplicationEvent: {
1354 QWindowsSessionManager *sessionManager = platformSessionManager();
1355 if (sessionManager->isActive()) { // bogus message from windows
1356 *result = sessionManager->wasCanceled() ? 0 : 1;
1357 return true;
1358 }
1359
1360 sessionManager->setActive(true);
1361 sessionManager->blocksInteraction();
1362 sessionManager->clearCancellation();
1363
1364 auto *qGuiAppPriv = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(qApp));
1365 qGuiAppPriv->commitData();
1366
1367 if (lParam & ENDSESSION_LOGOFF)
1368 fflush(nullptr);
1369
1370 *result = sessionManager->wasCanceled() ? 0 : 1;
1371 return true;
1372 }
1373 case QtWindows::EndSessionApplicationEvent: {
1374 QWindowsSessionManager *sessionManager = platformSessionManager();
1375
1376 sessionManager->setActive(false);
1377 sessionManager->allowsInteraction();
1378 const bool endsession = wParam != 0;
1379
1380 // we receive the message for each toplevel window included internal hidden ones,
1381 // but the aboutToQuit signal should be emitted only once.
1382 auto *qGuiAppPriv = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(qApp));
1383 if (endsession && !qGuiAppPriv->aboutToQuitEmitted) {
1384 qGuiAppPriv->aboutToQuitEmitted = true;
1385 int index = QGuiApplication::staticMetaObject.indexOfSignal("aboutToQuit()");
1386 qApp->qt_metacall(QMetaObject::InvokeMetaMethod, index, nullptr);
1387 // since the process will be killed immediately quit() has no real effect
1388 QGuiApplication::quit();
1389 }
1390 return true;
1391 }
1392#endif // !defined(QT_NO_SESSIONMANAGER)
1393 default:
1394 break;
1395 }
1396 return false;
1397}
1398
1399/* Compress activation events. If the next focus window is already known
1400 * at the time the current one receives focus-out, pass that to
1401 * QWindowSystemInterface instead of sending 0 and ignore its consecutive
1402 * focus-in event.
1403 * This helps applications that do handling in focus-out events. */
1404void QWindowsContext::handleFocusEvent(QtWindows::WindowsEventType et,
1405 QWindowsWindow *platformWindow)
1406{
1407 QWindow *nextActiveWindow = nullptr;
1408 if (et == QtWindows::FocusInEvent) {
1409 QWindow *topWindow = QWindowsWindow::topLevelOf(platformWindow->window());
1410 QWindow *modalWindow = nullptr;
1411 if (QGuiApplicationPrivate::instance()->isWindowBlocked(topWindow, &modalWindow) && topWindow != modalWindow) {
1412 modalWindow->requestActivate();
1413 return;
1414 }
1415 // QTBUG-32867: Invoking WinAPI SetParent() can cause focus-in for the
1416 // window which is not desired for native child widgets.
1417 if (platformWindow->testFlag(QWindowsWindow::WithinSetParent)) {
1418 QWindow *currentFocusWindow = QGuiApplication::focusWindow();
1419 if (currentFocusWindow && currentFocusWindow != platformWindow->window()) {
1420 currentFocusWindow->requestActivate();
1421 return;
1422 }
1423 }
1424 nextActiveWindow = platformWindow->window();
1425 } else {
1426 // Focus out: Is the next window known and different
1427 // from the receiving the focus out.
1428 if (const HWND nextActiveHwnd = GetFocus())
1429 if (QWindowsWindow *nextActivePlatformWindow = findClosestPlatformWindow(nextActiveHwnd))
1430 if (nextActivePlatformWindow != platformWindow)
1431 nextActiveWindow = nextActivePlatformWindow->window();
1432 }
1433 if (nextActiveWindow != d->m_lastActiveWindow) {
1434 d->m_lastActiveWindow = nextActiveWindow;
1435 QWindowSystemInterface::handleWindowActivated(nextActiveWindow);
1436 }
1437}
1438
1439#ifndef QT_NO_CONTEXTMENU
1440bool QWindowsContext::handleContextMenuEvent(QWindow *window, const MSG &msg)
1441{
1442 bool mouseTriggered = false;
1443 QPoint globalPos;
1444 QPoint pos;
1445 if (msg.lParam != int(0xffffffff)) {
1446 mouseTriggered = true;
1447 globalPos.setX(msg.pt.x);
1448 globalPos.setY(msg.pt.y);
1449 pos = QWindowsGeometryHint::mapFromGlobal(msg.hwnd, globalPos);
1450
1451 RECT clientRect;
1452 if (GetClientRect(msg.hwnd, &clientRect)) {
1453 if (pos.x() < clientRect.left || pos.x() >= clientRect.right ||
1454 pos.y() < clientRect.top || pos.y() >= clientRect.bottom)
1455 {
1456 // This is the case that user has right clicked in the window's caption,
1457 // We should call DefWindowProc() to display a default shortcut menu
1458 // instead of sending a Qt window system event.
1459 return false;
1460 }
1461 }
1462 }
1463
1464 QWindowSystemInterface::handleContextMenuEvent(window, mouseTriggered, pos, globalPos,
1465 QWindowsKeyMapper::queryKeyboardModifiers());
1466 return true;
1467}
1468#endif
1469
1470void QWindowsContext::handleExitSizeMove(QWindow *window)
1471{
1472 // Windows can be moved/resized by:
1473 // 1) User moving a window by dragging the title bar: Causes a sequence
1474 // of WM_NCLBUTTONDOWN, WM_NCMOUSEMOVE but no WM_NCLBUTTONUP,
1475 // leaving the left mouse button 'pressed'
1476 // 2) User choosing Resize/Move from System menu and using mouse/cursor keys:
1477 // No mouse events are received
1478 // 3) Programmatically via QSizeGrip calling QPlatformWindow::startSystemResize/Move():
1479 // Mouse is left in pressed state after press on size grip (inside window),
1480 // no further mouse events are received
1481 // For cases 1,3, intercept WM_EXITSIZEMOVE to sync the buttons.
1482 const Qt::MouseButtons currentButtons = QWindowsMouseHandler::queryMouseButtons();
1483 const Qt::MouseButtons appButtons = QGuiApplication::mouseButtons();
1484 if (currentButtons == appButtons)
1485 return;
1486 const Qt::KeyboardModifiers keyboardModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
1487 const QPoint globalPos = QWindowsCursor::mousePosition();
1488 const QPlatformWindow *platWin = window->handle();
1489 const QPoint localPos = platWin->mapFromGlobal(globalPos);
1490 const QEvent::Type type = platWin->geometry().contains(globalPos)
1491 ? QEvent::MouseButtonRelease : QEvent::NonClientAreaMouseButtonRelease;
1492 for (Qt::MouseButton button : {Qt::LeftButton, Qt::RightButton, Qt::MiddleButton}) {
1493 if (appButtons.testFlag(button) && !currentButtons.testFlag(button)) {
1494 QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos,
1495 currentButtons, button, type,
1496 keyboardModifiers);
1497 }
1498 }
1499 if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer)
1500 d->m_pointerHandler.clearEvents();
1501 else
1502 d->m_mouseHandler.clearEvents();
1503}
1504
1505bool QWindowsContext::asyncExpose() const
1506{
1507 return d->m_asyncExpose;
1508}
1509
1510void QWindowsContext::setAsyncExpose(bool value)
1511{
1512 d->m_asyncExpose = value;
1513}
1514
1515QTouchDevice *QWindowsContext::touchDevice() const
1516{
1517 return (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) ?
1518 d->m_pointerHandler.touchDevice() : d->m_mouseHandler.touchDevice();
1519}
1520
1521static DWORD readDwordRegistrySetting(const wchar_t *regKey, const wchar_t *subKey, DWORD defaultValue)
1522{
1523 DWORD result = defaultValue;
1524 HKEY handle;
1525 if (RegOpenKeyEx(HKEY_CURRENT_USER, regKey, 0, KEY_READ, &handle) == ERROR_SUCCESS) {
1526 DWORD type;
1527 if (RegQueryValueEx(handle, subKey, nullptr, &type, nullptr, nullptr) == ERROR_SUCCESS
1528 && type == REG_DWORD) {
1529 DWORD value;
1530 DWORD size = sizeof(result);
1531 if (RegQueryValueEx(handle, subKey, nullptr, nullptr, reinterpret_cast<unsigned char *>(&value), &size) == ERROR_SUCCESS)
1532 result = value;
1533 }
1534 RegCloseKey(handle);
1535 }
1536 return result;
1537}
1538
1539DWORD QWindowsContext::readAdvancedExplorerSettings(const wchar_t *subKey, DWORD defaultValue)
1540{
1541 return readDwordRegistrySetting(L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
1542 subKey, defaultValue);
1543}
1544
1545static inline bool isEmptyRect(const RECT &rect)
1546{
1547 return rect.right - rect.left == 0 && rect.bottom - rect.top == 0;
1548}
1549
1550static inline QMargins marginsFromRects(const RECT &frame, const RECT &client)
1551{
1552 return QMargins(client.left - frame.left, client.top - frame.top,
1553 frame.right - client.right, frame.bottom - client.bottom);
1554}
1555
1556static RECT rectFromNcCalcSize(UINT message, WPARAM wParam, LPARAM lParam, int n)
1557{
1558 RECT result = {0, 0, 0, 0};
1559 if (message == WM_NCCALCSIZE && wParam)
1560 result = reinterpret_cast<const NCCALCSIZE_PARAMS *>(lParam)->rgrc[n];
1561 return result;
1562}
1563
1564static inline bool isMinimized(HWND hwnd)
1565{
1566 WINDOWPLACEMENT windowPlacement;
1567 windowPlacement.length = sizeof(WINDOWPLACEMENT);
1568 return GetWindowPlacement(hwnd, &windowPlacement) && windowPlacement.showCmd == SW_SHOWMINIMIZED;
1569}
1570
1571static inline bool isTopLevel(HWND hwnd)
1572{
1573 return (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_CHILD) == 0;
1574}
1575
1576/*!
1577 \brief Windows functions for actual windows.
1578
1579 There is another one for timers, sockets, etc in
1580 QEventDispatcherWin32.
1581
1582 \ingroup qt-lighthouse-win
1583*/
1584
1585extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1586{
1587 LRESULT result;
1588 const QtWindows::WindowsEventType et = windowsEventType(message, wParam, lParam);
1589 QWindowsWindow *platformWindow = nullptr;
1590 const RECT ncCalcSizeFrame = rectFromNcCalcSize(message, wParam, lParam, 0);
1591 const bool handled = QWindowsContext::instance()->windowsProc(hwnd, message, et, wParam, lParam, &result, &platformWindow);
1592 if (QWindowsContext::verbose > 1 && lcQpaEvents().isDebugEnabled()) {
1593 if (const char *eventName = QWindowsGuiEventDispatcher::windowsMessageName(message)) {
1594 qCDebug(lcQpaEvents).nospace() << "EVENT: hwd=" << hwnd << ' ' << eventName
1595 << " msg=0x" << Qt::hex << message << " et=0x" << et << Qt::dec << " wp="
1596 << int(wParam) << " at " << GET_X_LPARAM(lParam) << ','
1597 << GET_Y_LPARAM(lParam) << " handled=" << handled;
1598 }
1599 }
1600 if (!handled)
1601 result = DefWindowProc(hwnd, message, wParam, lParam);
1602
1603 // Capture WM_NCCALCSIZE on top level windows and obtain the window margins by
1604 // subtracting the rectangles before and after processing. This will correctly
1605 // capture client code overriding the message and allow for per-monitor margins
1606 // for High DPI (QTBUG-53255, QTBUG-40578).
1607 if (message == WM_NCCALCSIZE && !isEmptyRect(ncCalcSizeFrame) && isTopLevel(hwnd) && !isMinimized(hwnd)) {
1608 const QMargins margins =
1609 marginsFromRects(ncCalcSizeFrame, rectFromNcCalcSize(message, wParam, lParam, 0));
1610 if (margins.left() >= 0) {
1611 if (platformWindow) {
1612 qCDebug(lcQpaWindows) << __FUNCTION__ << "WM_NCCALCSIZE for" << hwnd << margins;
1613 platformWindow->setFullFrameMargins(margins);
1614 } else {
1615 const QSharedPointer<QWindowCreationContext> ctx = QWindowsContext::instance()->windowCreationContext();
1616 if (!ctx.isNull())
1617 ctx->margins = margins;
1618 }
1619 }
1620 }
1621 return result;
1622}
1623
1624
1625static inline QByteArray nativeEventType() { return QByteArrayLiteral("windows_generic_MSG"); }
1626
1627// Send to QAbstractEventDispatcher
1628bool QWindowsContext::filterNativeEvent(MSG *msg, LRESULT *result)
1629{
1630 QAbstractEventDispatcher *dispatcher = QAbstractEventDispatcher::instance();
1631#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
1632 qintptr filterResult = 0;
1633#else
1634 long filterResult = 0;
1635#endif
1636 if (dispatcher && dispatcher->filterNativeEvent(nativeEventType(), msg, &filterResult)) {
1637 *result = LRESULT(filterResult);
1638 return true;
1639 }
1640 return false;
1641}
1642
1643// Send to QWindowSystemInterface
1644bool QWindowsContext::filterNativeEvent(QWindow *window, MSG *msg, LRESULT *result)
1645{
1646#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
1647 qintptr filterResult = 0;
1648#else
1649 long filterResult = 0;
1650#endif
1651 if (QWindowSystemInterface::handleNativeEvent(window, nativeEventType(), msg, &filterResult)) {
1652 *result = LRESULT(filterResult);
1653 return true;
1654 }
1655 return false;
1656}
1657
1658QT_END_NAMESPACE
1659

Warning: That file was not part of the compilation database. It may have many parsing errors.