Windows QPA plugin: Fix logging.
[profile/ivi/qtbase.git] / src / plugins / platforms / windows / qwindowscontext.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qwindowscontext.h"
43 #include "qwindowswindow.h"
44 #include "qwindowskeymapper.h"
45 #include "qwindowsguieventdispatcher.h"
46 #include "qwindowsmousehandler.h"
47 #include "qtwindowsglobal.h"
48 #include "qwindowsmime.h"
49 #include "qwindowsinputcontext.h"
50 #include "accessible/qwindowsaccessibility.h"
51 #include "qwindowsscreen.h"
52 #include "qwindowstheme.h"
53
54 #include <QtGui/QWindow>
55 #include <QtGui/QWindowSystemInterface>
56 #include <QtGui/QPlatformNativeInterface>
57 #include <QtGui/QGuiApplication>
58
59 #include <QtCore/QSet>
60 #include <QtCore/QHash>
61 #include <QtCore/QStringList>
62 #include <QtCore/QDebug>
63 #include <QtCore/QSysInfo>
64 #include <QtCore/QScopedArrayPointer>
65 #include <QtCore/private/qsystemlibrary_p.h>
66
67 #include <stdlib.h>
68 #include <stdio.h>
69 #include <windowsx.h>
70
71 QT_BEGIN_NAMESPACE
72
73 // Verbosity of components
74 int QWindowsContext::verboseIntegration = 0;
75 int QWindowsContext::verboseWindows = 0;
76 int QWindowsContext::verboseEvents = 0;
77 int QWindowsContext::verboseBackingStore = 0;
78 int QWindowsContext::verboseFonts = 0;
79 int QWindowsContext::verboseGL = 0;
80 int QWindowsContext::verboseOLE = 0;
81 int QWindowsContext::verboseInputMethods = 0;
82 int QWindowsContext::verboseDialogs = 0;
83 int QWindowsContext::verboseTheming = 0;
84
85 // Get verbosity of components from "foo:2,bar:3"
86 static inline int componentVerbose(const char *v, const char *keyWord)
87 {
88     if (const char *k = strstr(v, keyWord)) {
89         k += qstrlen(keyWord);
90         if (*k == ':') {
91             ++k;
92             if (isdigit(*k))
93                 return *k - '0';
94         }
95     }
96     return 0;
97 }
98
99 static inline bool hasTouchSupport(QSysInfo::WinVersion wv)
100 {
101     enum { QT_SM_DIGITIZER = 94, QT_NID_INTEGRATED_TOUCH = 0x1,
102            QT_NID_EXTERNAL_TOUCH = 0x02, QT_NID_MULTI_INPUT = 0x40 };
103
104     return wv < QSysInfo::WV_WINDOWS7 ? false :
105            (GetSystemMetrics(QT_SM_DIGITIZER) & (QT_NID_INTEGRATED_TOUCH | QT_NID_EXTERNAL_TOUCH | QT_NID_MULTI_INPUT)) != 0;
106 }
107
108 #if !defined(LANG_SYRIAC)
109 #    define LANG_SYRIAC 0x5a
110 #endif
111
112 static inline bool useRTL_Extensions(QSysInfo::WinVersion ver)
113 {
114     if ((ver & QSysInfo::WV_NT_based) && (ver >= QSysInfo::WV_VISTA)) {
115         // Since the IsValidLanguageGroup/IsValidLocale functions always return true on
116         // Vista, check the Keyboard Layouts for enabling RTL.
117         if (const UINT nLayouts = GetKeyboardLayoutList(0, 0)) {
118             QScopedArrayPointer<HKL> lpList(new HKL[nLayouts]);
119             GetKeyboardLayoutList(nLayouts, lpList.data());
120             for (UINT i = 0; i < nLayouts; ++i) {
121                 switch (PRIMARYLANGID((quintptr)lpList[i])) {
122                 case LANG_ARABIC:
123                 case LANG_HEBREW:
124                 case LANG_FARSI:
125                 case LANG_SYRIAC:
126                     return true;
127                 default:
128                     break;
129                 }
130             }
131         }
132         return false;
133     } // NT/Vista
134     // Pre-NT: figure out whether a RTL language is installed
135     return IsValidLanguageGroup(LGRPID_ARABIC, LGRPID_INSTALLED)
136                             || IsValidLanguageGroup(LGRPID_HEBREW, LGRPID_INSTALLED)
137                             || IsValidLocale(MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), SORT_DEFAULT), LCID_INSTALLED)
138                             || IsValidLocale(MAKELCID(MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT), SORT_DEFAULT), LCID_INSTALLED)
139                             || IsValidLocale(MAKELCID(MAKELANGID(LANG_SYRIAC, SUBLANG_DEFAULT), SORT_DEFAULT), LCID_INSTALLED)
140                             || IsValidLocale(MAKELCID(MAKELANGID(LANG_FARSI, SUBLANG_DEFAULT), SORT_DEFAULT), LCID_INSTALLED);
141 }
142
143 /*!
144     \class QWindowsUser32DLL
145     \brief Struct that contains dynamically resolved symbols of User32.dll.
146
147     The stub libraries shipped with the MinGW compiler miss some of the
148     functions. They need to be retrieved dynamically.
149
150     In addition, touch-related functions are available only from Windows onwards.
151     These need to resolved dynamically for Q_CC_MSVC as well.
152
153     \sa QWindowsShell32DLL
154
155     \ingroup qt-lighthouse-win
156 */
157
158 QWindowsUser32DLL::QWindowsUser32DLL() :
159     setLayeredWindowAttributes(0), updateLayeredWindow(0),
160     updateLayeredWindowIndirect(0),
161     isHungAppWindow(0),
162     registerTouchWindow(0), getTouchInputInfo(0), closeTouchInputHandle(0)
163 {
164 }
165
166 void QWindowsUser32DLL::init()
167 {
168     QSystemLibrary library(QStringLiteral("user32"));
169     // MinGW (g++ 3.4.5) accepts only C casts.
170     setLayeredWindowAttributes = (SetLayeredWindowAttributes)(library.resolve("SetLayeredWindowAttributes"));
171     updateLayeredWindow = (UpdateLayeredWindow)(library.resolve("UpdateLayeredWindow"));
172     if (!setLayeredWindowAttributes || !updateLayeredWindow)
173         qFatal("This version of Windows is not supported (User32.dll is missing the symbols 'SetLayeredWindowAttributes', 'UpdateLayeredWindow').");
174
175     updateLayeredWindowIndirect = (UpdateLayeredWindowIndirect)(library.resolve("UpdateLayeredWindowIndirect"));
176     isHungAppWindow = (IsHungAppWindow)library.resolve("IsHungAppWindow");
177 }
178
179 bool QWindowsUser32DLL::initTouch()
180 {
181     QSystemLibrary library(QStringLiteral("user32"));
182     registerTouchWindow = (RegisterTouchWindow)(library.resolve("RegisterTouchWindow"));
183     getTouchInputInfo = (GetTouchInputInfo)(library.resolve("GetTouchInputInfo"));
184     closeTouchInputHandle = (CloseTouchInputHandle)(library.resolve("CloseTouchInputHandle"));
185     return registerTouchWindow && getTouchInputInfo && getTouchInputInfo;
186 }
187
188 /*!
189     \class QWindowsShell32DLL
190     \brief Struct that contains dynamically resolved symbols of Shell32.dll.
191
192     The stub libraries shipped with the MinGW compiler miss some of the
193     functions. They need to be retrieved dynamically.
194
195     \sa QWindowsUser32DLL
196
197     \ingroup qt-lighthouse-win
198 */
199
200 QWindowsShell32DLL::QWindowsShell32DLL() : sHCreateItemFromParsingName(0)
201 {
202 }
203
204 void QWindowsShell32DLL::init()
205 {
206     QSystemLibrary library(QStringLiteral("shell32"));
207     sHCreateItemFromParsingName = (SHCreateItemFromParsingName)(library.resolve("SHCreateItemFromParsingName"));
208 }
209
210 QWindowsUser32DLL QWindowsContext::user32dll;
211 QWindowsShell32DLL QWindowsContext::shell32dll;
212
213 QWindowsContext *QWindowsContext::m_instance = 0;
214
215 /*!
216     \class QWindowsContext
217     \brief Singleton container for all relevant information.
218
219     Holds state information formerly stored in \c qapplication_win.cpp.
220     \ingroup qt-lighthouse-win
221 */
222
223 typedef QHash<HWND, QWindowsWindow *> HandleBaseWindowHash;
224
225 struct QWindowsContextPrivate {
226     typedef QPlatformNativeInterface::EventFilter EventFilter;
227
228     enum EventFilterType
229     {
230         GenericWindowsEventFilter,
231         EventFilterTypeCount
232     };
233
234     QWindowsContextPrivate();
235
236     unsigned m_systemInfo;
237     QSet<QString> m_registeredWindowClassNames;
238     HandleBaseWindowHash m_windows;
239     HDC m_displayContext;
240     const int m_defaultDPI;
241     QWindowsKeyMapper m_keyMapper;
242     QWindowsMouseHandler m_mouseHandler;
243     QWindowsMimeConverter m_mimeConverter;
244     QWindowsScreenManager m_screenManager;
245     QSharedPointer<QWindowCreationContext> m_creationContext;
246     const HRESULT m_oleInitializeResult;
247     const QByteArray m_eventType;
248     EventFilter m_eventFilters[EventFilterTypeCount];
249 };
250
251 QWindowsContextPrivate::QWindowsContextPrivate() :
252     m_systemInfo(0),
253     m_displayContext(GetDC(0)),
254     m_defaultDPI(GetDeviceCaps(m_displayContext,LOGPIXELSY)),
255     m_oleInitializeResult(OleInitialize(NULL)),
256     m_eventType(QByteArrayLiteral("windows_generic_MSG"))
257 {
258     QWindowsContext::user32dll.init();
259     QWindowsContext::shell32dll.init();
260
261     const QSysInfo::WinVersion ver = QSysInfo::windowsVersion();
262
263     if (hasTouchSupport(ver) && QWindowsContext::user32dll.initTouch())
264         m_systemInfo |= QWindowsContext::SI_SupportsTouch;
265
266     if (useRTL_Extensions(ver)) {
267         m_systemInfo |= QWindowsContext::SI_RTL_Extensions;
268         m_keyMapper.setUseRTLExtensions(true);
269     }
270     qFill(m_eventFilters, m_eventFilters + EventFilterTypeCount, EventFilter(0));
271 }
272
273 QWindowsContext::QWindowsContext() :
274     d(new QWindowsContextPrivate)
275 {
276 #ifdef Q_CC_MSVC
277 #    pragma warning( disable : 4996 )
278 #endif
279     m_instance = this;
280     if (const char *v = getenv("QT_QPA_VERBOSE")) {
281         QWindowsContext::verboseIntegration = componentVerbose(v, "integration");
282         QWindowsContext::verboseWindows = componentVerbose(v, "windows");
283         QWindowsContext::verboseEvents = componentVerbose(v, "events");
284         QWindowsContext::verboseBackingStore = componentVerbose(v, "backingstore");
285         QWindowsContext::verboseFonts = componentVerbose(v, "fonts");
286         QWindowsContext::verboseGL = componentVerbose(v, "gl");
287         QWindowsContext::verboseOLE = componentVerbose(v, "ole");
288         QWindowsContext::verboseInputMethods = componentVerbose(v, "im");
289         QWindowsContext::verboseDialogs = componentVerbose(v, "dialogs");
290         QWindowsContext::verboseTheming = componentVerbose(v, "theming");
291     }
292 }
293
294 QWindowsContext::~QWindowsContext()
295 {
296     unregisterWindowClasses();
297     if (d->m_oleInitializeResult == S_OK || d->m_oleInitializeResult == S_FALSE)
298         OleUninitialize();
299
300     d->m_screenManager.clearScreens(); // Order: Potentially calls back to the windows.
301     m_instance = 0;
302 }
303
304 QWindowsContext *QWindowsContext::instance()
305 {
306     return m_instance;
307 }
308
309 unsigned QWindowsContext::systemInfo() const
310 {
311     return d->m_systemInfo;
312 }
313
314 void QWindowsContext::setWindowCreationContext(const QSharedPointer<QWindowCreationContext> &ctx)
315 {
316     d->m_creationContext = ctx;
317 }
318
319 int QWindowsContext::defaultDPI() const
320 {
321     return d->m_defaultDPI;
322 }
323
324 HDC QWindowsContext::displayContext() const
325 {
326     return d->m_displayContext;
327 }
328
329 QWindow *QWindowsContext::keyGrabber() const
330 {
331     return d->m_keyMapper.keyGrabber();
332 }
333
334 void QWindowsContext::setKeyGrabber(QWindow *w)
335 {
336     d->m_keyMapper.setKeyGrabber(w);
337 }
338
339 // Window class registering code (from qapplication_win.cpp)
340 // If 0 is passed as the widget pointer, register a window class
341 // for QWidget as default. This is used in QGLTemporaryContext
342 // during GL initialization, where we don't want to use temporary
343 // QWidgets or QGLWidgets, neither do we want to have separate code
344 // to register window classes.
345
346 QString QWindowsContext::registerWindowClass(const QWindow *w, bool isGL)
347 {
348     const Qt::WindowFlags flags = w ? w->windowFlags() : (Qt::WindowFlags)0;
349     const Qt::WindowFlags type = flags & Qt::WindowType_Mask;
350
351     uint style = 0;
352     bool icon = false;
353     QString cname = QStringLiteral("Qt5");
354     if (w && isGL) {
355         cname += QStringLiteral("QGLWindow");
356         style = CS_DBLCLKS|CS_OWNDC;
357         icon  = true;
358     } else if (w && (flags & Qt::MSWindowsOwnDC)) {
359         cname += QStringLiteral("QWindowOwnDC");
360         style = CS_DBLCLKS|CS_OWNDC;
361         icon  = true;
362     } else if (w && (type == Qt::Tool || type == Qt::ToolTip)) {
363         style = CS_DBLCLKS;
364         if (w->inherits("QTipLabel") || w->inherits("QAlphaWidget")) {
365             if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP
366                 && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based))) {
367                 style |= CS_DROPSHADOW;
368             }
369             cname += QStringLiteral("QToolTip");
370         } else {
371             cname += QStringLiteral("QTool");
372         }
373         style |= CS_SAVEBITS;
374         icon = false;
375     } else if (w && (type == Qt::Popup)) {
376         cname += QStringLiteral("QPopup");
377         style = CS_DBLCLKS|CS_SAVEBITS;
378         if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP
379             && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)))
380             style |= CS_DROPSHADOW;
381         icon = false;
382     } else {
383         cname += QStringLiteral("QWindow");
384         style = CS_DBLCLKS;
385         icon  = true;
386     }
387
388     HBRUSH brush = 0;
389     if (w && !isGL)
390         brush = GetSysColorBrush(COLOR_WINDOW);
391     return registerWindowClass(cname, qWindowsWndProc, style, brush, icon);
392 }
393
394 QString QWindowsContext::registerWindowClass(QString cname,
395                                              WNDPROC proc,
396                                              unsigned style,
397                                              HBRUSH brush,
398                                              bool icon)
399 {
400     // since multiple Qt versions can be used in one process
401     // each one has to have window class names with a unique name
402     // The first instance gets the unmodified name; if the class
403     // has already been registered by another instance of Qt then
404     // add an instance-specific ID, the address of the window proc.
405     static int classExists = -1;
406
407     const HINSTANCE appInstance = (HINSTANCE)GetModuleHandle(0);
408     if (classExists == -1) {
409         WNDCLASS wcinfo;
410         classExists = GetClassInfo(appInstance, (wchar_t*)cname.utf16(), &wcinfo);
411         classExists = classExists && wcinfo.lpfnWndProc != proc;
412     }
413
414     if (classExists)
415         cname += QString::number((quintptr)proc);
416
417     if (d->m_registeredWindowClassNames.contains(cname))        // already registered in our list
418         return cname;
419
420     WNDCLASSEX wc;
421     wc.cbSize       = sizeof(WNDCLASSEX);
422     wc.style        = style;
423     wc.lpfnWndProc  = proc;
424     wc.cbClsExtra   = 0;
425     wc.cbWndExtra   = 0;
426     wc.hInstance    = appInstance;
427     if (icon) {
428         wc.hIcon = (HICON)LoadImage(appInstance, L"IDI_ICON1", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
429         if (wc.hIcon) {
430             int sw = GetSystemMetrics(SM_CXSMICON);
431             int sh = GetSystemMetrics(SM_CYSMICON);
432             wc.hIconSm = (HICON)LoadImage(appInstance, L"IDI_ICON1", IMAGE_ICON, sw, sh, 0);
433         } else {
434             wc.hIcon = (HICON)LoadImage(0, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
435             wc.hIconSm = 0;
436         }
437     } else {
438         wc.hIcon    = 0;
439         wc.hIconSm  = 0;
440     }
441     wc.hCursor      = 0;
442     wc.hbrBackground = brush;
443     wc.lpszMenuName  = 0;
444     wc.lpszClassName = (wchar_t*)cname.utf16();
445     ATOM atom = RegisterClassEx(&wc);
446
447     if (!atom)
448         qErrnoWarning("QApplication::regClass: Registering window class '%s' failed.",
449                       qPrintable(cname));
450
451     d->m_registeredWindowClassNames.insert(cname);
452     if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows)
453         qDebug().nospace() << __FUNCTION__ << ' ' << cname
454                  << " style=0x" << QString::number(style, 16)
455                  << " brush=" << brush << " icon=" << icon << " atom=" << atom;
456     return cname;
457 }
458
459 void QWindowsContext::unregisterWindowClasses()
460 {
461     const HINSTANCE appInstance = (HINSTANCE)GetModuleHandle(0);
462
463     foreach (const QString &name,  d->m_registeredWindowClassNames) {
464         if (QWindowsContext::verboseIntegration)
465             qDebug() << __FUNCTION__ << name;
466         UnregisterClass((wchar_t*)name.utf16(), appInstance);
467     }
468     d->m_registeredWindowClassNames.clear();
469 }
470
471 int QWindowsContext::screenDepth() const
472 {
473     return GetDeviceCaps(d->m_displayContext, BITSPIXEL);
474 }
475
476 QString QWindowsContext::windowsErrorMessage(unsigned long errorCode)
477 {
478     QString rc = QString::fromLatin1("#%1: ").arg(errorCode);
479     ushort *lpMsgBuf;
480
481     const int len = FormatMessage(
482             FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
483             NULL, errorCode, 0, (LPTSTR)&lpMsgBuf, 0, NULL);
484     if (len) {
485         rc = QString::fromUtf16(lpMsgBuf, len);
486         LocalFree(lpMsgBuf);
487     } else {
488         rc += QString::fromLatin1("<unknown error>");
489     }
490     return rc;
491 }
492
493 void QWindowsContext::addWindow(HWND hwnd, QWindowsWindow *w)
494 {
495     d->m_windows.insert(hwnd, w);
496 }
497
498 void QWindowsContext::removeWindow(HWND hwnd)
499 {
500     const HandleBaseWindowHash::iterator it = d->m_windows.find(hwnd);
501     if (it != d->m_windows.end()) {
502         if (d->m_keyMapper.keyGrabber() == it.value()->window())
503             d->m_keyMapper.setKeyGrabber(0);
504         d->m_windows.erase(it);
505     }
506 }
507
508 QWindowsWindow *QWindowsContext::findPlatformWindow(HWND hwnd) const
509 {
510     return d->m_windows.value(hwnd);
511 }
512
513 QWindow *QWindowsContext::findWindow(HWND hwnd) const
514 {
515     if (const QWindowsWindow *bw = findPlatformWindow(hwnd))
516             return bw->window();
517     return 0;
518 }
519
520 QWindow *QWindowsContext::windowUnderMouse() const
521 {
522     return d->m_mouseHandler.windowUnderMouse();
523 }
524
525 /*!
526     \brief Find a child window at a screen point.
527
528     Deep search for a QWindow at global point, skipping non-owned
529     windows (accessibility?). Implemented using ChildWindowFromPointEx()
530     instead of (historically used) WindowFromPoint() to get a well-defined
531     behaviour for hidden/transparent windows.
532
533     \a cwex_flags are flags of ChildWindowFromPointEx().
534     \a parent is the parent window, pass GetDesktopWindow() for top levels.
535 */
536
537 QWindowsWindow *QWindowsContext::findPlatformWindowAt(HWND parent,
538                                                           const QPoint &screenPointIn,
539                                                           unsigned cwex_flags) const
540 {
541     QWindowsWindow *result = 0;
542     const POINT screenPoint = { screenPointIn.x(), screenPointIn.y() };
543     while (true) {
544         POINT point = screenPoint;
545         ScreenToClient(parent, &point);
546         // Returns parent if inside & none matched.
547         const HWND child = ChildWindowFromPointEx(parent, point, cwex_flags);
548         if (child && child != parent) {
549             if (QWindowsWindow *window = findPlatformWindow(child))
550                 result = window;
551             parent = child;
552         } else {
553             break;
554         }
555     }
556     return result;
557 }
558
559 QWindowsMimeConverter &QWindowsContext::mimeConverter() const
560 {
561     return d->m_mimeConverter;
562 }
563
564 QWindowsScreenManager &QWindowsContext::screenManager()
565 {
566     return d->m_screenManager;
567 }
568
569 /*!
570     \brief Convenience to create a non-visible, message-only dummy
571     window for example used as clipboard watcher or for GL.
572 */
573
574 HWND QWindowsContext::createDummyWindow(const QString &classNameIn,
575                                         const wchar_t *windowName,
576                                         WNDPROC wndProc, DWORD style)
577 {
578     if (!wndProc)
579         wndProc = DefWindowProc;
580     QString className = registerWindowClass(classNameIn, wndProc);
581     return CreateWindowEx(0, (wchar_t*)className.utf16(),
582                           windowName, style,
583                           CW_USEDEFAULT, CW_USEDEFAULT,
584                           CW_USEDEFAULT, CW_USEDEFAULT,
585                           HWND_MESSAGE, NULL, (HINSTANCE)GetModuleHandle(0), NULL);
586 }
587
588 /*!
589     \brief Common COM error strings.
590 */
591
592 QByteArray QWindowsContext::comErrorString(HRESULT hr)
593 {
594     switch (hr) {
595     case S_OK:
596         return QByteArray("S_OK");
597     case S_FALSE:
598         return QByteArray("S_FALSE");
599     case E_UNEXPECTED:
600         return QByteArray("E_UNEXPECTED");
601     case CO_E_ALREADYINITIALIZED:
602         return QByteArray("CO_E_ALREADYINITIALIZED");
603     case CO_E_NOTINITIALIZED:
604         return QByteArray("CO_E_NOTINITIALIZED");
605     case RPC_E_CHANGED_MODE:
606         return QByteArray("RPC_E_CHANGED_MODE");
607     case OLE_E_WRONGCOMPOBJ:
608         return QByteArray("OLE_E_WRONGCOMPOBJ");
609     case CO_E_NOT_SUPPORTED:
610         return QByteArray("CO_E_NOT_SUPPORTED");
611     case E_NOTIMPL:
612         return QByteArray("E_NOTIMPL");
613     case E_INVALIDARG:
614         return QByteArray("");
615     case E_NOINTERFACE:
616         return QByteArray("");
617     case E_POINTER:
618         return QByteArray("");
619     case E_HANDLE:
620         return QByteArray("");
621     case E_ABORT:
622         return QByteArray("");
623     case E_FAIL:
624         return QByteArray("");
625     case E_ACCESSDENIED:
626         return QByteArray("");
627     default:
628         break;
629     }
630     return "Unknown error 0x" + QByteArray::number(quint64(hr), 16);
631 }
632
633 /*!
634      \brief Set event filter.
635
636      \sa QWindowsNativeInterface
637 */
638
639 QWindowsContext::EventFilter QWindowsContext::setEventFilter(const QByteArray &eventType, EventFilter filter)
640 {
641     int eventFilterType = -1;
642     if (eventType == d->m_eventType)
643         eventFilterType = QWindowsContextPrivate::GenericWindowsEventFilter;
644     if (eventFilterType < 0) {
645         qWarning("%s: Attempt to set unsupported event filter '%s'.",
646                  __FUNCTION__, eventType.constData());
647         return 0;
648     }
649     const EventFilter previous = d->m_eventFilters[eventFilterType];
650     d->m_eventFilters[eventFilterType] = filter;
651     return previous;
652 }
653
654 /*!
655      \brief Main windows procedure registered for windows.
656
657      \sa QWindowsGuiEventDispatcher
658 */
659
660 bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
661                                   QtWindows::WindowsEventType et,
662                                   WPARAM wParam, LPARAM lParam, LRESULT *result)
663 {
664     *result = 0;
665
666     MSG msg;
667     msg.hwnd = hwnd;         // re-create MSG structure
668     msg.message = message;   // time and pt fields ignored
669     msg.wParam = wParam;
670     msg.lParam = lParam;
671     msg.pt.x = GET_X_LPARAM(lParam);
672     msg.pt.y = GET_Y_LPARAM(lParam);
673
674     long filterResult = 0;
675     if (d->m_eventFilters[QWindowsContextPrivate::GenericWindowsEventFilter]) {
676         if (d->m_eventFilters[QWindowsContextPrivate::GenericWindowsEventFilter](&msg, &filterResult)) {
677             *result = LRESULT(filterResult);
678             return true;
679         }
680     }
681     // Events without an associated QWindow or events we are not interested in.
682     switch (et) {
683     case QtWindows::InputMethodStartCompositionEvent:
684         return QWindowsInputContext::instance()->startComposition(hwnd);
685     case QtWindows::InputMethodCompositionEvent:
686         return QWindowsInputContext::instance()->composition(hwnd, lParam);
687     case QtWindows::InputMethodEndCompositionEvent:
688         return QWindowsInputContext::instance()->endComposition(hwnd);
689     case QtWindows::InputMethodRequest:
690         return QWindowsInputContext::instance()->handleIME_Request(wParam, lParam, result);
691     case QtWindows::InputMethodOpenCandidateWindowEvent:
692     case QtWindows::InputMethodCloseCandidateWindowEvent:
693         // TODO: Release/regrab mouse if a popup has mouse grab.
694         return false;
695     case QtWindows::ClipboardEvent:
696     case QtWindows::DestroyEvent:
697
698     case QtWindows::UnknownEvent:
699         return false;
700     case QtWindows::AccessibleObjectFromWindowRequest:
701         return QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(hwnd, wParam, lParam, result);
702     case QtWindows::DisplayChangedEvent:
703         return d->m_screenManager.handleDisplayChange(wParam, lParam);
704     default:
705         break;
706     }
707
708     QWindowsWindow *platformWindow = findPlatformWindow(hwnd);
709     // Before CreateWindowEx() returns, some events are sent,
710     // for example WM_GETMINMAXINFO asking for size constraints for top levels.
711     // Pass on to current creation context
712     if (!platformWindow && !d->m_creationContext.isNull()) {
713         switch (et) {
714         case QtWindows::QuerySizeHints:
715             d->m_creationContext->applyToMinMaxInfo(reinterpret_cast<MINMAXINFO *>(lParam));
716             return true;
717         case QtWindows::ResizeEvent:
718             d->m_creationContext->obtainedGeometry.setSize(QSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
719             return true;
720         case QtWindows::MoveEvent:
721             d->m_creationContext->obtainedGeometry.moveTo(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
722             return true;
723         case QtWindows::CalculateSize:
724             return false;
725         default:
726             break;
727         }
728     }
729     if (platformWindow) {
730         if (QWindowsContext::verboseEvents > 1)
731             qDebug().nospace() << "Event window: " << platformWindow->window();
732     } else {
733         qWarning("%s: No Qt Window found for event 0x%x (%s), hwnd=0x%p.",
734                  __FUNCTION__, message,
735                  QWindowsGuiEventDispatcher::windowsMessageName(message), hwnd);
736         return false;
737     }
738
739     filterResult = 0;
740     if (QWindowSystemInterface::handleNativeEvent(platformWindow->window(), d->m_eventType, &msg, &filterResult)) {
741         *result = LRESULT(filterResult);
742         return true;
743     }
744
745     switch (et) {
746     case QtWindows::KeyDownEvent:
747     case QtWindows::KeyEvent:
748     case QtWindows::InputMethodKeyEvent:
749     case QtWindows::InputMethodKeyDownEvent:
750         return d->m_keyMapper.translateKeyEvent(platformWindow->window(), hwnd, msg, result);
751     case QtWindows::MoveEvent:
752         platformWindow->handleMoved();
753         return true;
754     case QtWindows::ResizeEvent:
755         platformWindow->handleResized((int)wParam);
756         return true;
757     case QtWindows::QuerySizeHints:
758         platformWindow->getSizeHints(reinterpret_cast<MINMAXINFO *>(lParam));
759         return true;
760     case QtWindows::CalculateSize:
761         // NCCALCSIZE_PARAMS structure if wParam==TRUE
762         if (wParam && QWindowsContext::verboseWindows) {
763             const NCCALCSIZE_PARAMS *ncp = reinterpret_cast<NCCALCSIZE_PARAMS *>(lParam);
764             qDebug() << platformWindow->window() << *ncp;
765         }
766         break;
767     case QtWindows::ExposeEvent:
768         return platformWindow->handleWmPaint(hwnd, message, wParam, lParam);
769     case QtWindows::MouseWheelEvent:
770     case QtWindows::MouseEvent:
771     case QtWindows::NonClientMouseEvent:
772     case QtWindows::LeaveEvent:
773         return d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
774     case QtWindows::TouchEvent:
775         return d->m_mouseHandler.translateTouchEvent(platformWindow->window(), hwnd, et, msg, result);
776     case QtWindows::FocusInEvent: // see QWindowsWindow::requestActivateWindow().
777         QWindowSystemInterface::handleWindowActivated(platformWindow->window());
778         return true;
779     case QtWindows::FocusOutEvent:
780         QWindowSystemInterface::handleWindowActivated(0);
781         return true;
782     case QtWindows::ShowEvent:
783         platformWindow->handleShown();
784         return true;
785     case QtWindows::HideEvent:
786         platformWindow->handleHidden();
787         return true;
788     case QtWindows::CloseEvent:
789         QWindowSystemInterface::handleCloseEvent(platformWindow->window());
790         return true;
791     case QtWindows::ThemeChanged: // ### fixme: Compress these events?
792         if (QWindowsTheme *theme = QWindowsTheme::instance())
793             theme->windowsThemeChanged(platformWindow->window());
794         return true;
795     case QtWindows::ActivateWindowEvent:
796         if (platformWindow->testFlag(QWindowsWindow::BlockedByModal))
797             if (const QWindow *modalWindow = QGuiApplication::modalWindow())
798                 QWindowsWindow::baseWindowOf(modalWindow)->alertWindow();
799         break;
800     default:
801         break;
802     }
803     return false;
804 }
805
806 /*!
807     \brief Windows functions for actual windows.
808
809     There is another one for timers, sockets, etc in
810     QEventDispatcherWin32.
811
812     \ingroup qt-lighthouse-win
813 */
814
815 extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
816 {
817     LRESULT result;
818     const QtWindows::WindowsEventType et = windowsEventType(message, wParam);
819     const bool handled = QWindowsContext::instance()->windowsProc(hwnd, message, et, wParam, lParam, &result);
820     if (QWindowsContext::verboseEvents > 1)
821         if (const char *eventName = QWindowsGuiEventDispatcher::windowsMessageName(message))
822             qDebug("EVENT: hwd=%p %s msg=0x%x et=0x%x wp=%d at %d,%d handled=%d",
823                    hwnd, eventName, message, et, int(wParam),
824                    GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), handled);
825     if (!handled)
826         result = DefWindowProc(hwnd, message, wParam, lParam);
827     return result;
828 }
829
830 QT_END_NAMESPACE