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
342 return QPlatformIntegration::hasCapability(cap);
347 QPlatformPixmap *QWindowsIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const
349 return new QRasterPlatformPixmap(type);
352 QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) const
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)
361 << __FUNCTION__ << '<' << window << '\n'
362 << " Requested: " << requested.geometry << "frame incl.: "
363 << QWindowsGeometryHint::positionIncludesFrame(window)
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';
372 if (requested.flags != obtained.flags)
373 window->setWindowFlags(obtained.flags);
374 return new QWindowsWindow(window, obtained);
377 QPlatformBackingStore *QWindowsIntegration::createPlatformBackingStore(QWindow *window) const
379 if (QWindowsContext::verboseIntegration)
380 qDebug() << __FUNCTION__ << window;
381 return new QWindowsBackingStore(window);
385 QPlatformOpenGLContext
386 *QWindowsIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
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();
395 d->m_staticEGLContext = QSharedPointer<QWindowsEGLStaticContext>(staticContext);
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();
406 #endif // !QT_OPENGL_ES_2
408 #endif // !QT_NO_OPENGL
410 /* Workaround for QTBUG-24205: In 'Auto', pick the FreeType engine for
411 * QML2 applications. */
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()
418 // check if the QtQuick library is loaded
420 HMODULE handle = GetModuleHandle(L"QtQuick" QT_LIBINFIX L"d5.dll");
422 HMODULE handle = GetModuleHandle(L"QtQuick" QT_LIBINFIX L"5.dll");
424 return (handle != NULL);
428 QPlatformFontDatabase *QWindowsIntegration::fontDatabase() const
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;
440 d->m_fontDatabase = new QWindowsFontDatabase;
442 if (isQMLApplication()) {
443 if (QWindowsContext::verboseIntegration) {
444 qDebug() << "QML application detected, using FreeType rendering";
446 d->m_fontDatabase = new QWindowsFontDatabaseFT;
449 d->m_fontDatabase = new QWindowsFontDatabase;
452 #endif // QT_NO_FREETYPE
454 return d->m_fontDatabase;
457 #ifdef SPI_GETKEYBOARDSPEED
458 static inline int keyBoardAutoRepeatRateMS()
461 if (SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &time, 0))
462 return time ? 1000 / static_cast<int>(time) : 500;
467 QVariant QWindowsIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
470 case QPlatformIntegration::CursorFlashTime:
471 if (const unsigned timeMS = GetCaretBlinkTime())
472 return QVariant(int(timeMS));
474 #ifdef SPI_GETKEYBOARDSPEED
475 case KeyboardAutoRepeatRate:
476 return QVariant(keyBoardAutoRepeatRateMS());
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())
492 case QPlatformIntegration::UseRtlExtensions:
493 return QVariant(d->m_context.useRTLExtensions());
495 return QPlatformIntegration::styleHint(hint);
498 Qt::KeyboardModifiers QWindowsIntegration::queryKeyboardModifiers() const
500 return QWindowsKeyMapper::queryKeyboardModifiers();
503 QList<int> QWindowsIntegration::possibleKeys(const QKeyEvent *e) const
505 return d->m_context.possibleKeys(e);
508 QPlatformNativeInterface *QWindowsIntegration::nativeInterface() const
510 return &d->m_nativeInterface;
513 #ifndef QT_NO_CLIPBOARD
514 QPlatformClipboard * QWindowsIntegration::clipboard() const
516 return &d->m_clipboard;
518 #endif // !QT_NO_CLIPBOARD
520 QPlatformDrag *QWindowsIntegration::drag() const
525 QPlatformInputContext * QWindowsIntegration::inputContext() const
527 return &d->m_inputContext;
530 #ifndef QT_NO_ACCESSIBILITY
531 QPlatformAccessibility *QWindowsIntegration::accessibility() const
533 return &d->m_accessibility;
537 QWindowsIntegration *QWindowsIntegration::instance()
539 return static_cast<QWindowsIntegration *>(QGuiApplicationPrivate::platformIntegration());
542 unsigned QWindowsIntegration::options() const
547 QAbstractEventDispatcher * QWindowsIntegration::guiThreadEventDispatcher() const
549 return d->m_eventDispatcher;
552 QStringList QWindowsIntegration::themeNames() const
554 return QStringList(QLatin1String(QWindowsTheme::name));
557 QPlatformTheme *QWindowsIntegration::createPlatformTheme(const QString &name) const
559 if (name == QLatin1String(QWindowsTheme::name))
560 return new QWindowsTheme;
561 return QPlatformIntegration::createPlatformTheme(name);
564 QPlatformServices *QWindowsIntegration::services() const
566 return &d->m_services;
571 #include "qwindowsintegration.moc"