3f030ffca7653b2490ded15310dd7f31949d7a99
[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     default:
342         return QPlatformIntegration::hasCapability(cap);
343     }
344     return false;
345 }
346
347 QPlatformPixmap *QWindowsIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const
348 {
349     return new QRasterPlatformPixmap(type);
350 }
351
352 QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) const
353 {
354     QWindowsWindow::WindowData requested;
355     requested.flags = window->windowFlags();
356     requested.geometry = window->geometry();
357     const QWindowsWindow::WindowData obtained
358             = QWindowsWindow::WindowData::create(window, requested, window->windowTitle());
359     if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows)
360         qDebug().nospace()
361             << __FUNCTION__ << '<' << window << '\n'
362             << "    Requested: " << requested.geometry << "frame incl.: "
363             << QWindowsGeometryHint::positionIncludesFrame(window)
364             <<   " Flags="
365             << QWindowsWindow::debugWindowFlags(requested.flags) << '\n'
366             << "    Obtained : " << obtained.geometry << " Margins "
367             << obtained.frame  << " Flags="
368             << QWindowsWindow::debugWindowFlags(obtained.flags)
369             << " Handle=" << obtained.hwnd << '\n';
370     if (!obtained.hwnd)
371         return 0;
372     if (requested.flags != obtained.flags)
373         window->setWindowFlags(obtained.flags);
374     return new QWindowsWindow(window, obtained);
375 }
376
377 QPlatformBackingStore *QWindowsIntegration::createPlatformBackingStore(QWindow *window) const
378 {
379     if (QWindowsContext::verboseIntegration)
380         qDebug() << __FUNCTION__ << window;
381     return new QWindowsBackingStore(window);
382 }
383
384 #ifndef QT_NO_OPENGL
385 QPlatformOpenGLContext
386     *QWindowsIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
387 {
388     if (QWindowsContext::verboseIntegration)
389         qDebug() << __FUNCTION__ << context->format();
390 #ifdef QT_OPENGL_ES_2
391     if (d->m_staticEGLContext.isNull()) {
392         QWindowsEGLStaticContext *staticContext = QWindowsEGLStaticContext::create();
393         if (!staticContext)
394             return 0;
395         d->m_staticEGLContext = QSharedPointer<QWindowsEGLStaticContext>(staticContext);
396     }
397     return new QWindowsEGLContext(d->m_staticEGLContext, context->format(), context->shareHandle());
398 #else  // QT_OPENGL_ES_2
399     if (d->m_staticOpenGLContext.isNull())
400         d->m_staticOpenGLContext =
401             QSharedPointer<QOpenGLStaticContext>(QOpenGLStaticContext::create());
402     QScopedPointer<QWindowsGLContext> result(new QWindowsGLContext(d->m_staticOpenGLContext, context));
403     if (result->isValid())
404         return result.take();
405     return 0;
406 #endif // !QT_OPENGL_ES_2
407 }
408 #endif // !QT_NO_OPENGL
409
410 /* Workaround for QTBUG-24205: In 'Auto', pick the FreeType engine for
411  * QML2 applications. */
412
413 #ifdef Q_OS_WINCE
414 // It's not easy to detect if we are running a QML application
415 // Let's try to do so by checking if the QtQuick module is loaded.
416 inline bool isQMLApplication()
417 {
418     // check if the QtQuick library is loaded
419 #ifdef _DEBUG
420     HMODULE handle = GetModuleHandle(L"QtQuick" QT_LIBINFIX L"d5.dll");
421 #else
422     HMODULE handle = GetModuleHandle(L"QtQuick" QT_LIBINFIX L"5.dll");
423 #endif
424     return (handle != NULL);
425 }
426 #endif
427
428 QPlatformFontDatabase *QWindowsIntegration::fontDatabase() const
429 {
430     if (!d->m_fontDatabase) {
431 #ifdef QT_NO_FREETYPE
432         d->m_fontDatabase = new QWindowsFontDatabase();
433 #else // QT_NO_FREETYPE
434         if (d->m_options & QWindowsIntegration::FontDatabaseFreeType) {
435             d->m_fontDatabase = new QWindowsFontDatabaseFT;
436         } else if (d->m_options & QWindowsIntegration::FontDatabaseNative){
437             d->m_fontDatabase = new QWindowsFontDatabase;
438         } else {
439 #ifndef Q_OS_WINCE
440             d->m_fontDatabase = new QWindowsFontDatabase;
441 #else
442             if (isQMLApplication()) {
443                 if (QWindowsContext::verboseIntegration) {
444                     qDebug() << "QML application detected, using FreeType rendering";
445                 }
446                 d->m_fontDatabase = new QWindowsFontDatabaseFT;
447             }
448             else
449                 d->m_fontDatabase = new QWindowsFontDatabase;
450 #endif
451         }
452 #endif // QT_NO_FREETYPE
453     }
454     return d->m_fontDatabase;
455 }
456
457 #ifdef SPI_GETKEYBOARDSPEED
458 static inline int keyBoardAutoRepeatRateMS()
459 {
460   DWORD time = 0;
461   if (SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &time, 0))
462       return time ? 1000 / static_cast<int>(time) : 500;
463   return 30;
464 }
465 #endif
466
467 QVariant QWindowsIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
468 {
469     switch (hint) {
470     case QPlatformIntegration::CursorFlashTime:
471         if (const unsigned timeMS = GetCaretBlinkTime())
472             return QVariant(int(timeMS));
473         break;
474 #ifdef SPI_GETKEYBOARDSPEED
475     case KeyboardAutoRepeatRate:
476         return QVariant(keyBoardAutoRepeatRateMS());
477 #endif
478     case QPlatformIntegration::StartDragTime:
479     case QPlatformIntegration::StartDragDistance:
480     case QPlatformIntegration::KeyboardInputInterval:
481     case QPlatformIntegration::ShowIsFullScreen:
482     case QPlatformIntegration::PasswordMaskDelay:
483     case QPlatformIntegration::StartDragVelocity:
484     case QPlatformIntegration::SynthesizeMouseFromTouchEvents:
485         break; // Not implemented
486     case QPlatformIntegration::FontSmoothingGamma:
487         return QVariant(QWindowsFontDatabase::fontSmoothingGamma());
488     case QPlatformIntegration::MouseDoubleClickInterval:
489         if (const int ms = GetDoubleClickTime())
490             return QVariant(ms);
491         break;
492     case QPlatformIntegration::UseRtlExtensions:
493         return QVariant(d->m_context.useRTLExtensions());
494     }
495     return QPlatformIntegration::styleHint(hint);
496 }
497
498 Qt::KeyboardModifiers QWindowsIntegration::queryKeyboardModifiers() const
499 {
500     return QWindowsKeyMapper::queryKeyboardModifiers();
501 }
502
503 QList<int> QWindowsIntegration::possibleKeys(const QKeyEvent *e) const
504 {
505     return d->m_context.possibleKeys(e);
506 }
507
508 QPlatformNativeInterface *QWindowsIntegration::nativeInterface() const
509 {
510     return &d->m_nativeInterface;
511 }
512
513 #ifndef QT_NO_CLIPBOARD
514 QPlatformClipboard * QWindowsIntegration::clipboard() const
515 {
516     return &d->m_clipboard;
517 }
518 #endif // !QT_NO_CLIPBOARD
519
520 QPlatformDrag *QWindowsIntegration::drag() const
521 {
522     return &d->m_drag;
523 }
524
525 QPlatformInputContext * QWindowsIntegration::inputContext() const
526 {
527     return &d->m_inputContext;
528 }
529
530 #ifndef QT_NO_ACCESSIBILITY
531 QPlatformAccessibility *QWindowsIntegration::accessibility() const
532 {
533     return &d->m_accessibility;
534 }
535 #endif
536
537 QWindowsIntegration *QWindowsIntegration::instance()
538 {
539     return static_cast<QWindowsIntegration *>(QGuiApplicationPrivate::platformIntegration());
540 }
541
542 unsigned QWindowsIntegration::options() const
543 {
544     return d->m_options;
545 }
546
547 QAbstractEventDispatcher * QWindowsIntegration::guiThreadEventDispatcher() const
548 {
549     return d->m_eventDispatcher;
550 }
551
552 QStringList QWindowsIntegration::themeNames() const
553 {
554     return QStringList(QLatin1String(QWindowsTheme::name));
555 }
556
557 QPlatformTheme *QWindowsIntegration::createPlatformTheme(const QString &name) const
558 {
559     if (name == QLatin1String(QWindowsTheme::name))
560         return new QWindowsTheme;
561     return QPlatformIntegration::createPlatformTheme(name);
562 }
563
564 QPlatformServices *QWindowsIntegration::services() const
565 {
566     return &d->m_services;
567 }
568
569 QT_END_NAMESPACE
570
571 #include "qwindowsintegration.moc"