Added MultipleWindows platform capability.
[profile/ivi/qtbase.git] / src / plugins / platforms / windows / qwindowsintegration.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 "qwindowsintegration.h"
43 #include "qwindowsbackingstore.h"
44 #include "qwindowswindow.h"
45 #include "qwindowscontext.h"
46 #if defined(QT_OPENGL_ES_2)
47 #  include "qwindowseglcontext.h"
48 #  include <QtGui/QOpenGLContext>
49 #elif !defined(QT_NO_OPENGL)
50 #  include "qwindowsglcontext.h"
51 #endif
52 #include "qwindowsscreen.h"
53 #include "qwindowstheme.h"
54 #include "qwindowsservices.h"
55 #ifndef QT_NO_FREETYPE
56 #  include "qwindowsfontdatabase_ft.h"
57 #endif
58 #include "qwindowsfontdatabase.h"
59 #include "qwindowsguieventdispatcher.h"
60 #ifndef QT_NO_CLIPBOARD
61 #  include "qwindowsclipboard.h"
62 #endif
63 #include "qwindowsdrag.h"
64 #include "qwindowsinputcontext.h"
65 #include "qwindowskeymapper.h"
66 #  ifndef QT_NO_ACCESSIBILITY
67 #include "accessible/qwindowsaccessibility.h"
68 #endif
69
70 #include <qpa/qplatformnativeinterface.h>
71 #include <qpa/qwindowsysteminterface.h>
72 #include <QtGui/QBackingStore>
73 #include <QtGui/private/qpixmap_raster_p.h>
74 #include <QtGui/private/qguiapplication_p.h>
75
76 #include <QtCore/private/qeventdispatcher_win_p.h>
77 #include <QtCore/QDebug>
78
79 QT_BEGIN_NAMESPACE
80
81 /*!
82     \class QWindowsNativeInterface
83     \brief Provides access to native handles.
84
85     Currently implemented keys
86     \list
87     \li handle (HWND)
88     \li getDC (DC)
89     \li releaseDC Releases the previously acquired DC and returns 0.
90     \endlist
91
92     \internal
93     \ingroup qt-lighthouse-win
94 */
95
96 class QWindowsNativeInterface : public QPlatformNativeInterface
97 {
98     Q_OBJECT
99     Q_PROPERTY(bool asyncExpose READ asyncExpose WRITE setAsyncExpose)
100 public:
101 #ifndef QT_NO_OPENGL
102     virtual void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context);
103 #endif
104     virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window);
105     virtual void *nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs);
106
107     Q_INVOKABLE void *createMessageWindow(const QString &classNameTemplate,
108                                           const QString &windowName,
109                                           void *eventProc) const;
110     bool asyncExpose() const;
111     void setAsyncExpose(bool value);
112 };
113
114 void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
115 {
116     if (!window || !window->handle()) {
117         qWarning("%s: '%s' requested for null window or window without handle.", __FUNCTION__, resource.constData());
118         return 0;
119     }
120     QWindowsWindow *bw = static_cast<QWindowsWindow *>(window->handle());
121     if (resource == "handle")
122         return bw->handle();
123     if (window->surfaceType() == QWindow::RasterSurface) {
124         if (resource == "getDC")
125             return bw->getDC();
126         if (resource == "releaseDC") {
127             bw->releaseDC();
128             return 0;
129         }
130     }
131     qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData());
132     return 0;
133 }
134
135 void *QWindowsNativeInterface::nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs)
136 {
137     if (!bs || !bs->handle()) {
138         qWarning("%s: '%s' requested for null backingstore or backingstore without handle.", __FUNCTION__, resource.constData());
139         return 0;
140     }
141     QWindowsBackingStore *wbs = static_cast<QWindowsBackingStore *>(bs->handle());
142     if (resource == "getDC")
143         return wbs->getDC();
144     qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData());
145     return 0;
146 }
147
148 #ifndef QT_NO_OPENGL
149 void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context)
150 {
151     if (!context || !context->handle()) {
152         qWarning("%s: '%s' requested for null context or context without handle.", __FUNCTION__, resource.constData());
153         return 0;
154     }
155 #ifdef QT_OPENGL_ES_2
156     QWindowsEGLContext *windowsEglContext = static_cast<QWindowsEGLContext *>(context->handle());
157     if (resource == QByteArrayLiteral("eglDisplay"))
158         return windowsEglContext->eglDisplay();
159     if (resource == QByteArrayLiteral("eglContext"))
160         return windowsEglContext->eglContext();
161     if (resource == QByteArrayLiteral("eglConfig"))
162         return windowsEglContext->eglConfig();
163 #else // QT_OPENGL_ES_2
164     QWindowsGLContext *windowsContext = static_cast<QWindowsGLContext *>(context->handle());
165     if (resource == QByteArrayLiteral("renderingContext"))
166         return windowsContext->renderingContext();
167 #endif // !QT_OPENGL_ES_2
168
169     qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData());
170     return 0;
171 }
172 #endif // !QT_NO_OPENGL
173
174 /*!
175     \brief Creates a non-visible window handle for filtering messages.
176 */
177
178 void *QWindowsNativeInterface::createMessageWindow(const QString &classNameTemplate,
179                                                    const QString &windowName,
180                                                    void *eventProc) const
181 {
182     QWindowsContext *ctx = QWindowsContext::instance();
183     const HWND hwnd = ctx->createDummyWindow(classNameTemplate,
184                                              (wchar_t*)windowName.utf16(),
185                                              (WNDPROC)eventProc);
186     return hwnd;
187 }
188
189 bool QWindowsNativeInterface::asyncExpose() const
190 {
191     return QWindowsContext::instance()->asyncExpose();
192 }
193
194 void QWindowsNativeInterface::setAsyncExpose(bool value)
195 {
196     QWindowsContext::instance()->setAsyncExpose(value);
197 }
198
199 /*!
200     \class QWindowsIntegration
201     \brief QPlatformIntegration implementation for Windows.
202     \internal
203
204     \section1 Programming Considerations
205
206     The platform plugin should run on Desktop Windows from Windows XP onwards
207     and Windows Embedded.
208
209     It should compile with:
210     \list
211     \li Microsoft Visual Studio 2008 or later (using the Microsoft Windows SDK,
212         (\c Q_CC_MSVC).
213     \li Stock \l{http://mingw.org/}{MinGW} (\c Q_CC_MINGW).
214         This version ships with headers that are missing a lot of WinAPI.
215     \li MinGW distributions using GCC 4.7 or higher and a recent MinGW-w64 runtime API,
216         such as \l{http://tdm-gcc.tdragon.net/}{TDM-GCC}, or
217         \l{http://mingwbuilds.sourceforge.net/}{MinGW-builds}
218         (\c Q_CC_MINGW and \c __MINGW64_VERSION_MAJOR indicating the version).
219         MinGW-w64 provides more complete headers (compared to stock MinGW from mingw.org),
220         including a considerable part of the Windows SDK.
221     \li Visual Studio 2008 for Windows Embedded (\c Q_OS_WINCE).
222     \endlist
223
224     The file \c qtwindows_additional.h contains defines and declarations that
225     are missing in MinGW. When encountering missing declarations, it should
226     be added there so that \c #ifdefs for MinGW can be avoided. Similarly,
227     \c qplatformfunctions_wince.h contains defines and declarations for
228     Windows Embedded.
229
230     When using a function from the WinAPI, the minimum supported Windows version
231     and Windows Embedded support should be checked. If the function is not supported
232     on Windows XP or is not present in the MinGW-headers, it should be dynamically
233     resolved. For this purpose, QWindowsContext has static structs like
234     QWindowsUser32DLL and QWindowsShell32DLL. All function pointers should go to
235     these structs to avoid lookups in several places.
236
237     \ingroup qt-lighthouse-win
238 */
239
240 struct QWindowsIntegrationPrivate
241 {
242 #if defined(QT_OPENGL_ES_2)
243     typedef QSharedPointer<QWindowsEGLStaticContext> QEGLStaticContextPtr;
244 #elif !defined(QT_NO_OPENGL)
245     typedef QSharedPointer<QOpenGLStaticContext> QOpenGLStaticContextPtr;
246 #endif
247
248     explicit QWindowsIntegrationPrivate(const QStringList &paramList);
249     ~QWindowsIntegrationPrivate();
250
251     const unsigned m_options;
252     QWindowsContext m_context;
253     QPlatformFontDatabase *m_fontDatabase;
254     QWindowsNativeInterface m_nativeInterface;
255 #ifndef QT_NO_CLIPBOARD
256     QWindowsClipboard m_clipboard;
257 #endif
258     QWindowsDrag m_drag;
259     QWindowsGuiEventDispatcher *m_eventDispatcher;
260 #if defined(QT_OPENGL_ES_2)
261     QEGLStaticContextPtr m_staticEGLContext;
262 #elif !defined(QT_NO_OPENGL)
263     QOpenGLStaticContextPtr m_staticOpenGLContext;
264 #endif
265     QWindowsInputContext m_inputContext;
266 #ifndef QT_NO_ACCESSIBILITY
267     QWindowsAccessibility m_accessibility;
268 #endif
269     QWindowsServices m_services;
270 };
271
272 static inline unsigned parseOptions(const QStringList &paramList)
273 {
274     unsigned options = 0;
275     foreach (const QString &param, paramList) {
276         if (param.startsWith(QLatin1String("fontengine="))) {
277             if (param.endsWith(QLatin1String("freetype"))) {
278                 options |= QWindowsIntegration::FontDatabaseFreeType;
279             } else if (param.endsWith(QLatin1String("native"))) {
280                 options |= QWindowsIntegration::FontDatabaseNative;
281             }
282         } else if (param.startsWith(QLatin1String("dialogs="))) {
283             if (param.endsWith(QLatin1String("xp"))) {
284                 options |= QWindowsIntegration::XpNativeDialogs;
285             } else if (param.endsWith(QLatin1String("none"))) {
286                 options |= QWindowsIntegration::NoNativeDialogs;
287             }
288         } else if (param == QLatin1String("gl=gdi")) {
289             options |= QWindowsIntegration::DisableArb;
290         }
291     }
292     return options;
293 }
294
295 QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList &paramList)
296     : m_options(parseOptions(paramList))
297     , m_fontDatabase(0)
298     , m_eventDispatcher(new QWindowsGuiEventDispatcher)
299 {
300 }
301
302 QWindowsIntegrationPrivate::~QWindowsIntegrationPrivate()
303 {
304     if (m_fontDatabase)
305         delete m_fontDatabase;
306 }
307
308 QWindowsIntegration::QWindowsIntegration(const QStringList &paramList) :
309     d(new QWindowsIntegrationPrivate(paramList))
310 {
311     QGuiApplicationPrivate::instance()->setEventDispatcher(d->m_eventDispatcher);
312 #ifndef QT_NO_CLIPBOARD
313     d->m_clipboard.registerViewer();
314 #endif
315     d->m_context.screenManager().handleScreenChanges();
316 }
317
318 QWindowsIntegration::~QWindowsIntegration()
319 {
320     if (QWindowsContext::verboseIntegration)
321         qDebug("%s", __FUNCTION__);
322 }
323
324 bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) const
325 {
326     switch (cap) {
327     case ThreadedPixmaps:
328         return true;
329 #ifndef QT_NO_OPENGL
330     case OpenGL:
331         return true;
332     case ThreadedOpenGL:
333 #  ifdef QT_OPENGL_ES_2
334         return QWindowsEGLContext::hasThreadedOpenGLCapability();
335 #  else
336         return true;
337 #  endif // QT_OPENGL_ES_2
338 #endif // !QT_NO_OPENGL
339     case WindowMasks:
340         return true;
341     case MultipleWindows:
342         return true;
343     default:
344         return QPlatformIntegration::hasCapability(cap);
345     }
346     return false;
347 }
348
349 QPlatformPixmap *QWindowsIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const
350 {
351     return new QRasterPlatformPixmap(type);
352 }
353
354 QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) const
355 {
356     QWindowsWindow::WindowData requested;
357     requested.flags = window->windowFlags();
358     requested.geometry = window->geometry();
359     const QWindowsWindow::WindowData obtained
360             = QWindowsWindow::WindowData::create(window, requested, window->windowTitle());
361     if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows)
362         qDebug().nospace()
363             << __FUNCTION__ << '<' << window << '\n'
364             << "    Requested: " << requested.geometry << "frame incl.: "
365             << QWindowsGeometryHint::positionIncludesFrame(window)
366             <<   " Flags="
367             << QWindowsWindow::debugWindowFlags(requested.flags) << '\n'
368             << "    Obtained : " << obtained.geometry << " Margins "
369             << obtained.frame  << " Flags="
370             << QWindowsWindow::debugWindowFlags(obtained.flags)
371             << " Handle=" << obtained.hwnd << '\n';
372     if (!obtained.hwnd)
373         return 0;
374     if (requested.flags != obtained.flags)
375         window->setWindowFlags(obtained.flags);
376     return new QWindowsWindow(window, obtained);
377 }
378
379 QPlatformBackingStore *QWindowsIntegration::createPlatformBackingStore(QWindow *window) const
380 {
381     if (QWindowsContext::verboseIntegration)
382         qDebug() << __FUNCTION__ << window;
383     return new QWindowsBackingStore(window);
384 }
385
386 #ifndef QT_NO_OPENGL
387 QPlatformOpenGLContext
388     *QWindowsIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
389 {
390     if (QWindowsContext::verboseIntegration)
391         qDebug() << __FUNCTION__ << context->format();
392 #ifdef QT_OPENGL_ES_2
393     if (d->m_staticEGLContext.isNull()) {
394         QWindowsEGLStaticContext *staticContext = QWindowsEGLStaticContext::create();
395         if (!staticContext)
396             return 0;
397         d->m_staticEGLContext = QSharedPointer<QWindowsEGLStaticContext>(staticContext);
398     }
399     return new QWindowsEGLContext(d->m_staticEGLContext, context->format(), context->shareHandle());
400 #else  // QT_OPENGL_ES_2
401     if (d->m_staticOpenGLContext.isNull())
402         d->m_staticOpenGLContext =
403             QSharedPointer<QOpenGLStaticContext>(QOpenGLStaticContext::create());
404     QScopedPointer<QWindowsGLContext> result(new QWindowsGLContext(d->m_staticOpenGLContext, context));
405     if (result->isValid())
406         return result.take();
407     return 0;
408 #endif // !QT_OPENGL_ES_2
409 }
410 #endif // !QT_NO_OPENGL
411
412 /* Workaround for QTBUG-24205: In 'Auto', pick the FreeType engine for
413  * QML2 applications. */
414
415 #ifdef Q_OS_WINCE
416 // It's not easy to detect if we are running a QML application
417 // Let's try to do so by checking if the QtQuick module is loaded.
418 inline bool isQMLApplication()
419 {
420     // check if the QtQuick library is loaded
421 #ifdef _DEBUG
422     HMODULE handle = GetModuleHandle(L"QtQuick" QT_LIBINFIX L"d5.dll");
423 #else
424     HMODULE handle = GetModuleHandle(L"QtQuick" QT_LIBINFIX L"5.dll");
425 #endif
426     return (handle != NULL);
427 }
428 #endif
429
430 QPlatformFontDatabase *QWindowsIntegration::fontDatabase() const
431 {
432     if (!d->m_fontDatabase) {
433 #ifdef QT_NO_FREETYPE
434         d->m_fontDatabase = new QWindowsFontDatabase();
435 #else // QT_NO_FREETYPE
436         if (d->m_options & QWindowsIntegration::FontDatabaseFreeType) {
437             d->m_fontDatabase = new QWindowsFontDatabaseFT;
438         } else if (d->m_options & QWindowsIntegration::FontDatabaseNative){
439             d->m_fontDatabase = new QWindowsFontDatabase;
440         } else {
441 #ifndef Q_OS_WINCE
442             d->m_fontDatabase = new QWindowsFontDatabase;
443 #else
444             if (isQMLApplication()) {
445                 if (QWindowsContext::verboseIntegration) {
446                     qDebug() << "QML application detected, using FreeType rendering";
447                 }
448                 d->m_fontDatabase = new QWindowsFontDatabaseFT;
449             }
450             else
451                 d->m_fontDatabase = new QWindowsFontDatabase;
452 #endif
453         }
454 #endif // QT_NO_FREETYPE
455     }
456     return d->m_fontDatabase;
457 }
458
459 #ifdef SPI_GETKEYBOARDSPEED
460 static inline int keyBoardAutoRepeatRateMS()
461 {
462   DWORD time = 0;
463   if (SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &time, 0))
464       return time ? 1000 / static_cast<int>(time) : 500;
465   return 30;
466 }
467 #endif
468
469 QVariant QWindowsIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
470 {
471     switch (hint) {
472     case QPlatformIntegration::CursorFlashTime:
473         if (const unsigned timeMS = GetCaretBlinkTime())
474             return QVariant(int(timeMS));
475         break;
476 #ifdef SPI_GETKEYBOARDSPEED
477     case KeyboardAutoRepeatRate:
478         return QVariant(keyBoardAutoRepeatRateMS());
479 #endif
480     case QPlatformIntegration::StartDragTime:
481     case QPlatformIntegration::StartDragDistance:
482     case QPlatformIntegration::KeyboardInputInterval:
483     case QPlatformIntegration::ShowIsFullScreen:
484     case QPlatformIntegration::PasswordMaskDelay:
485     case QPlatformIntegration::StartDragVelocity:
486     case QPlatformIntegration::SynthesizeMouseFromTouchEvents:
487         break; // Not implemented
488     case QPlatformIntegration::FontSmoothingGamma:
489         return QVariant(QWindowsFontDatabase::fontSmoothingGamma());
490     case QPlatformIntegration::MouseDoubleClickInterval:
491         if (const int ms = GetDoubleClickTime())
492             return QVariant(ms);
493         break;
494     case QPlatformIntegration::UseRtlExtensions:
495         return QVariant(d->m_context.useRTLExtensions());
496     }
497     return QPlatformIntegration::styleHint(hint);
498 }
499
500 Qt::KeyboardModifiers QWindowsIntegration::queryKeyboardModifiers() const
501 {
502     return QWindowsKeyMapper::queryKeyboardModifiers();
503 }
504
505 QList<int> QWindowsIntegration::possibleKeys(const QKeyEvent *e) const
506 {
507     return d->m_context.possibleKeys(e);
508 }
509
510 QPlatformNativeInterface *QWindowsIntegration::nativeInterface() const
511 {
512     return &d->m_nativeInterface;
513 }
514
515 #ifndef QT_NO_CLIPBOARD
516 QPlatformClipboard * QWindowsIntegration::clipboard() const
517 {
518     return &d->m_clipboard;
519 }
520 #endif // !QT_NO_CLIPBOARD
521
522 QPlatformDrag *QWindowsIntegration::drag() const
523 {
524     return &d->m_drag;
525 }
526
527 QPlatformInputContext * QWindowsIntegration::inputContext() const
528 {
529     return &d->m_inputContext;
530 }
531
532 #ifndef QT_NO_ACCESSIBILITY
533 QPlatformAccessibility *QWindowsIntegration::accessibility() const
534 {
535     return &d->m_accessibility;
536 }
537 #endif
538
539 QWindowsIntegration *QWindowsIntegration::instance()
540 {
541     return static_cast<QWindowsIntegration *>(QGuiApplicationPrivate::platformIntegration());
542 }
543
544 unsigned QWindowsIntegration::options() const
545 {
546     return d->m_options;
547 }
548
549 QAbstractEventDispatcher * QWindowsIntegration::guiThreadEventDispatcher() const
550 {
551     return d->m_eventDispatcher;
552 }
553
554 QStringList QWindowsIntegration::themeNames() const
555 {
556     return QStringList(QLatin1String(QWindowsTheme::name));
557 }
558
559 QPlatformTheme *QWindowsIntegration::createPlatformTheme(const QString &name) const
560 {
561     if (name == QLatin1String(QWindowsTheme::name))
562         return new QWindowsTheme;
563     return QPlatformIntegration::createPlatformTheme(name);
564 }
565
566 QPlatformServices *QWindowsIntegration::services() const
567 {
568     return &d->m_services;
569 }
570
571 QT_END_NAMESPACE
572
573 #include "qwindowsintegration.moc"