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