1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the plugins of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
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"
52 #include "qwindowsscreen.h"
53 #include "qwindowstheme.h"
54 #include "qwindowsservices.h"
55 #ifndef QT_NO_FREETYPE
56 # include "qwindowsfontdatabase_ft.h"
58 #include "qwindowsfontdatabase.h"
59 #include "qwindowsguieventdispatcher.h"
60 #ifndef QT_NO_CLIPBOARD
61 # include "qwindowsclipboard.h"
63 #include "qwindowsdrag.h"
64 #include "qwindowsinputcontext.h"
65 #include "qwindowskeymapper.h"
66 # ifndef QT_NO_ACCESSIBILITY
67 #include "accessible/qwindowsaccessibility.h"
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>
76 #include <QtCore/private/qeventdispatcher_win_p.h>
77 #include <QtCore/QDebug>
82 \class QWindowsNativeInterface
83 \brief Provides access to native handles.
85 Currently implemented keys
89 \li releaseDC Releases the previously acquired DC and returns 0.
93 \ingroup qt-lighthouse-win
96 class QWindowsNativeInterface : public QPlatformNativeInterface
99 Q_PROPERTY(bool asyncExpose READ asyncExpose WRITE setAsyncExpose)
102 virtual void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context);
104 virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window);
105 virtual void *nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs);
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);
114 void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
116 if (!window || !window->handle()) {
117 qWarning("%s: '%s' requested for null window or window without handle.", __FUNCTION__, resource.constData());
120 QWindowsWindow *bw = static_cast<QWindowsWindow *>(window->handle());
121 if (resource == "handle")
123 if (window->surfaceType() == QWindow::RasterSurface) {
124 if (resource == "getDC")
126 if (resource == "releaseDC") {
131 qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData());
135 void *QWindowsNativeInterface::nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs)
137 if (!bs || !bs->handle()) {
138 qWarning("%s: '%s' requested for null backingstore or backingstore without handle.", __FUNCTION__, resource.constData());
141 QWindowsBackingStore *wbs = static_cast<QWindowsBackingStore *>(bs->handle());
142 if (resource == "getDC")
144 qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData());
149 void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context)
151 if (!context || !context->handle()) {
152 qWarning("%s: '%s' requested for null context or context without handle.", __FUNCTION__, resource.constData());
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
169 qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData());
172 #endif // !QT_NO_OPENGL
175 \brief Creates a non-visible window handle for filtering messages.
178 void *QWindowsNativeInterface::createMessageWindow(const QString &classNameTemplate,
179 const QString &windowName,
180 void *eventProc) const
182 QWindowsContext *ctx = QWindowsContext::instance();
183 const HWND hwnd = ctx->createDummyWindow(classNameTemplate,
184 (wchar_t*)windowName.utf16(),
189 bool QWindowsNativeInterface::asyncExpose() const
191 return QWindowsContext::instance()->asyncExpose();
194 void QWindowsNativeInterface::setAsyncExpose(bool value)
196 QWindowsContext::instance()->setAsyncExpose(value);
200 \class QWindowsIntegration
201 \brief QPlatformIntegration implementation for Windows.
204 \section1 Programming Considerations
206 The platform plugin should run on Desktop Windows from Windows XP onwards
207 and Windows Embedded.
209 It should compile with:
211 \li Microsoft Visual Studio 2008 or later (using the Microsoft Windows SDK,
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).
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
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.
237 \ingroup qt-lighthouse-win
240 struct QWindowsIntegrationPrivate
242 #if defined(QT_OPENGL_ES_2)
243 typedef QSharedPointer<QWindowsEGLStaticContext> QEGLStaticContextPtr;
244 #elif !defined(QT_NO_OPENGL)
245 typedef QSharedPointer<QOpenGLStaticContext> QOpenGLStaticContextPtr;
248 explicit QWindowsIntegrationPrivate(const QStringList ¶mList);
249 ~QWindowsIntegrationPrivate();
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;
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;
265 QWindowsInputContext m_inputContext;
266 #ifndef QT_NO_ACCESSIBILITY
267 QWindowsAccessibility m_accessibility;
269 QWindowsServices m_services;
272 static inline unsigned parseOptions(const QStringList ¶mList)
274 unsigned options = 0;
275 foreach (const QString ¶m, 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;
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;
288 } else if (param == QLatin1String("gl=gdi")) {
289 options |= QWindowsIntegration::DisableArb;
295 QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList ¶mList)
296 : m_options(parseOptions(paramList))
298 , m_eventDispatcher(new QWindowsGuiEventDispatcher)
302 QWindowsIntegrationPrivate::~QWindowsIntegrationPrivate()
305 delete m_fontDatabase;
308 QWindowsIntegration::QWindowsIntegration(const QStringList ¶mList) :
309 d(new QWindowsIntegrationPrivate(paramList))
311 QGuiApplicationPrivate::instance()->setEventDispatcher(d->m_eventDispatcher);
312 #ifndef QT_NO_CLIPBOARD
313 d->m_clipboard.registerViewer();
315 d->m_context.screenManager().handleScreenChanges();
318 QWindowsIntegration::~QWindowsIntegration()
320 if (QWindowsContext::verboseIntegration)
321 qDebug("%s", __FUNCTION__);
324 bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) const
327 case ThreadedPixmaps:
333 # ifdef QT_OPENGL_ES_2
334 return QWindowsEGLContext::hasThreadedOpenGLCapability();
337 # endif // QT_OPENGL_ES_2
338 #endif // !QT_NO_OPENGL
341 case MultipleWindows:
344 return QPlatformIntegration::hasCapability(cap);
349 QPlatformPixmap *QWindowsIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const
351 return new QRasterPlatformPixmap(type);
354 QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) const
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)
363 << __FUNCTION__ << '<' << window << '\n'
364 << " Requested: " << requested.geometry << "frame incl.: "
365 << QWindowsGeometryHint::positionIncludesFrame(window)
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';
374 if (requested.flags != obtained.flags)
375 window->setWindowFlags(obtained.flags);
376 return new QWindowsWindow(window, obtained);
379 QPlatformBackingStore *QWindowsIntegration::createPlatformBackingStore(QWindow *window) const
381 if (QWindowsContext::verboseIntegration)
382 qDebug() << __FUNCTION__ << window;
383 return new QWindowsBackingStore(window);
387 QPlatformOpenGLContext
388 *QWindowsIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
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();
397 d->m_staticEGLContext = QSharedPointer<QWindowsEGLStaticContext>(staticContext);
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();
408 #endif // !QT_OPENGL_ES_2
410 #endif // !QT_NO_OPENGL
412 /* Workaround for QTBUG-24205: In 'Auto', pick the FreeType engine for
413 * QML2 applications. */
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()
420 // check if the QtQuick library is loaded
422 HMODULE handle = GetModuleHandle(L"QtQuick" QT_LIBINFIX L"d5.dll");
424 HMODULE handle = GetModuleHandle(L"QtQuick" QT_LIBINFIX L"5.dll");
426 return (handle != NULL);
430 QPlatformFontDatabase *QWindowsIntegration::fontDatabase() const
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;
442 d->m_fontDatabase = new QWindowsFontDatabase;
444 if (isQMLApplication()) {
445 if (QWindowsContext::verboseIntegration) {
446 qDebug() << "QML application detected, using FreeType rendering";
448 d->m_fontDatabase = new QWindowsFontDatabaseFT;
451 d->m_fontDatabase = new QWindowsFontDatabase;
454 #endif // QT_NO_FREETYPE
456 return d->m_fontDatabase;
459 #ifdef SPI_GETKEYBOARDSPEED
460 static inline int keyBoardAutoRepeatRateMS()
463 if (SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &time, 0))
464 return time ? 1000 / static_cast<int>(time) : 500;
469 QVariant QWindowsIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
472 case QPlatformIntegration::CursorFlashTime:
473 if (const unsigned timeMS = GetCaretBlinkTime())
474 return QVariant(int(timeMS));
476 #ifdef SPI_GETKEYBOARDSPEED
477 case KeyboardAutoRepeatRate:
478 return QVariant(keyBoardAutoRepeatRateMS());
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())
494 case QPlatformIntegration::UseRtlExtensions:
495 return QVariant(d->m_context.useRTLExtensions());
497 return QPlatformIntegration::styleHint(hint);
500 Qt::KeyboardModifiers QWindowsIntegration::queryKeyboardModifiers() const
502 return QWindowsKeyMapper::queryKeyboardModifiers();
505 QList<int> QWindowsIntegration::possibleKeys(const QKeyEvent *e) const
507 return d->m_context.possibleKeys(e);
510 QPlatformNativeInterface *QWindowsIntegration::nativeInterface() const
512 return &d->m_nativeInterface;
515 #ifndef QT_NO_CLIPBOARD
516 QPlatformClipboard * QWindowsIntegration::clipboard() const
518 return &d->m_clipboard;
520 #endif // !QT_NO_CLIPBOARD
522 QPlatformDrag *QWindowsIntegration::drag() const
527 QPlatformInputContext * QWindowsIntegration::inputContext() const
529 return &d->m_inputContext;
532 #ifndef QT_NO_ACCESSIBILITY
533 QPlatformAccessibility *QWindowsIntegration::accessibility() const
535 return &d->m_accessibility;
539 QWindowsIntegration *QWindowsIntegration::instance()
541 return static_cast<QWindowsIntegration *>(QGuiApplicationPrivate::platformIntegration());
544 unsigned QWindowsIntegration::options() const
549 QAbstractEventDispatcher * QWindowsIntegration::guiThreadEventDispatcher() const
551 return d->m_eventDispatcher;
554 QStringList QWindowsIntegration::themeNames() const
556 return QStringList(QLatin1String(QWindowsTheme::name));
559 QPlatformTheme *QWindowsIntegration::createPlatformTheme(const QString &name) const
561 if (name == QLatin1String(QWindowsTheme::name))
562 return new QWindowsTheme;
563 return QPlatformIntegration::createPlatformTheme(name);
566 QPlatformServices *QWindowsIntegration::services() const
568 return &d->m_services;
573 #include "qwindowsintegration.moc"