1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
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 The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qwindowsnativeinterface.h"
41 #include "qwindowsclipboard.h"
42 #include "qwindowswindow.h"
43 #include "qwindowsscreen.h"
44 #include "qwindowscontext.h"
45 #include "qwindowscursor.h"
46 #include "qwindowsopenglcontext.h"
47 #include "qwindowsopengltester.h"
48 #include "qwindowsintegration.h"
49 #include "qwindowsmime.h"
50 #include "qwindowstheme.h"
51 #include "qwin10helpers.h"
52 
53 #include <QtGui/qwindow.h>
54 #include <QtGui/qopenglcontext.h>
55 #include <QtGui/qscreen.h>
56 #include <qpa/qplatformscreen.h>
57 #include <QtFontDatabaseSupport/private/qwindowsfontdatabase_p.h>
58 
59 QT_BEGIN_NAMESPACE
60 
61 enum ResourceType {
62     RenderingContextType,
63     EglContextType,
64     EglDisplayType,
65     EglConfigType,
66     HandleType,
67     GlHandleType,
68     GetDCType,
69     ReleaseDCType,
70     VkSurface
71 };
72 
resourceType(const QByteArray & key)73 static int resourceType(const QByteArray &key)
74 {
75     static const char *names[] = { // match ResourceType
76         "renderingcontext",
77         "eglcontext",
78         "egldisplay",
79         "eglconfig",
80         "handle",
81         "glhandle",
82         "getdc",
83         "releasedc",
84         "vkSurface"
85     };
86     const char ** const end = names + sizeof(names) / sizeof(names[0]);
87     const char **result = std::find(names, end, key);
88     if (result == end)
89         result = std::find(names, end, key.toLower());
90     return int(result - names);
91 }
92 
93 QWindowsWindowFunctions::WindowActivationBehavior QWindowsNativeInterface::m_windowActivationBehavior =
94     QWindowsWindowFunctions::DefaultActivateWindow;
95 
nativeResourceForWindow(const QByteArray & resource,QWindow * window)96 void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
97 {
98     if (!window || !window->handle()) {
99         qWarning("%s: '%s' requested for null window or window without handle.", __FUNCTION__, resource.constData());
100         return nullptr;
101     }
102     auto *bw = static_cast<QWindowsWindow *>(window->handle());
103     int type = resourceType(resource);
104     if (type == HandleType)
105         return bw->handle();
106     switch (window->surfaceType()) {
107     case QWindow::RasterSurface:
108     case QWindow::RasterGLSurface:
109         if (type == GetDCType)
110             return bw->getDC();
111         if (type == ReleaseDCType) {
112             bw->releaseDC();
113             return nullptr;
114         }
115         break;
116     case QWindow::VulkanSurface:
117 #if QT_CONFIG(vulkan)
118         if (type == VkSurface)
119             return bw->surface(nullptr, nullptr); // returns the address of the VkSurfaceKHR, not the value, as expected
120 #endif
121         break;
122     default:
123         break;
124     }
125     qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData());
126     return nullptr;
127 }
128 
nativeResourceForScreen(const QByteArray & resource,QScreen * screen)129 void *QWindowsNativeInterface::nativeResourceForScreen(const QByteArray &resource, QScreen *screen)
130 {
131     if (!screen || !screen->handle()) {
132         qWarning("%s: '%s' requested for null screen or screen without handle.", __FUNCTION__, resource.constData());
133         return nullptr;
134     }
135     auto *bs = static_cast<QWindowsScreen *>(screen->handle());
136     int type = resourceType(resource);
137     if (type == HandleType)
138         return bs->handle();
139 
140     qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData());
141     return nullptr;
142 }
143 
144 #ifndef QT_NO_CURSOR
nativeResourceForCursor(const QByteArray & resource,const QCursor & cursor)145 void *QWindowsNativeInterface::nativeResourceForCursor(const QByteArray &resource, const QCursor &cursor)
146 {
147     if (resource == QByteArrayLiteral("hcursor")) {
148         if (const QScreen *primaryScreen = QGuiApplication::primaryScreen()) {
149             if (const QPlatformCursor *pCursor= primaryScreen->handle()->cursor())
150                 return static_cast<const QWindowsCursor *>(pCursor)->hCursor(cursor);
151         }
152     }
153     return nullptr;
154 }
155 #endif // !QT_NO_CURSOR
156 
157 static const char customMarginPropertyC[] = "WindowsCustomMargins";
158 
windowProperty(QPlatformWindow * window,const QString & name) const159 QVariant QWindowsNativeInterface::windowProperty(QPlatformWindow *window, const QString &name) const
160 {
161     auto *platformWindow = static_cast<QWindowsWindow *>(window);
162     if (name == QLatin1String(customMarginPropertyC))
163         return QVariant::fromValue(platformWindow->customMargins());
164     return QVariant();
165 }
166 
windowProperty(QPlatformWindow * window,const QString & name,const QVariant & defaultValue) const167 QVariant QWindowsNativeInterface::windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const
168 {
169     const QVariant result = windowProperty(window, name);
170     return result.isValid() ? result : defaultValue;
171 }
172 
setWindowProperty(QPlatformWindow * window,const QString & name,const QVariant & value)173 void QWindowsNativeInterface::setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value)
174 {
175     auto *platformWindow = static_cast<QWindowsWindow *>(window);
176     if (name == QLatin1String(customMarginPropertyC))
177         platformWindow->setCustomMargins(qvariant_cast<QMargins>(value));
178 }
179 
windowProperties(QPlatformWindow * window) const180 QVariantMap QWindowsNativeInterface::windowProperties(QPlatformWindow *window) const
181 {
182     QVariantMap result;
183     const QString customMarginProperty = QLatin1String(customMarginPropertyC);
184     result.insert(customMarginProperty, windowProperty(window, customMarginProperty));
185     return result;
186 }
187 
nativeResourceForIntegration(const QByteArray & resource)188 void *QWindowsNativeInterface::nativeResourceForIntegration(const QByteArray &resource)
189 {
190 #ifdef QT_NO_OPENGL
191     Q_UNUSED(resource)
192 #else
193     if (resourceType(resource) == GlHandleType) {
194         if (const QWindowsStaticOpenGLContext *sc = QWindowsIntegration::staticOpenGLContext())
195             return sc->moduleHandle();
196     }
197 #endif
198 
199     return nullptr;
200 }
201 
202 #ifndef QT_NO_OPENGL
nativeResourceForContext(const QByteArray & resource,QOpenGLContext * context)203 void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context)
204 {
205     if (!context || !context->handle()) {
206         qWarning("%s: '%s' requested for null context or context without handle.", __FUNCTION__, resource.constData());
207         return nullptr;
208     }
209 
210     auto *glcontext = static_cast<QWindowsOpenGLContext *>(context->handle());
211     switch (resourceType(resource)) {
212     case RenderingContextType: // Fall through.
213     case EglContextType:
214         return glcontext->nativeContext();
215     case EglDisplayType:
216         return glcontext->nativeDisplay();
217     case EglConfigType:
218         return glcontext->nativeConfig();
219     default:
220         break;
221     }
222 
223     qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData());
224     return nullptr;
225 }
226 #endif // !QT_NO_OPENGL
227 
228 /*!
229     \brief Creates a non-visible window handle for filtering messages.
230 */
231 
createMessageWindow(const QString & classNameTemplate,const QString & windowName,void * eventProc) const232 void *QWindowsNativeInterface::createMessageWindow(const QString &classNameTemplate,
233                                                    const QString &windowName,
234                                                    void *eventProc) const
235 {
236     QWindowsContext *ctx = QWindowsContext::instance();
237     const HWND hwnd = ctx->createDummyWindow(classNameTemplate,
238                                              (wchar_t*)windowName.utf16(),
239                                              (WNDPROC)eventProc);
240     return hwnd;
241 }
242 
243 /*!
244     \brief Registers a unique window class with a callback function based on \a classNameIn.
245 */
246 
registerWindowClass(const QString & classNameIn,void * eventProc) const247 QString QWindowsNativeInterface::registerWindowClass(const QString &classNameIn, void *eventProc) const
248 {
249     return QWindowsContext::instance()->registerWindowClass(classNameIn, (WNDPROC)eventProc);
250 }
251 
asyncExpose() const252 bool QWindowsNativeInterface::asyncExpose() const
253 {
254     return QWindowsContext::instance()->asyncExpose();
255 }
256 
setAsyncExpose(bool value)257 void QWindowsNativeInterface::setAsyncExpose(bool value)
258 {
259     QWindowsContext::instance()->setAsyncExpose(value);
260 }
261 
registerWindowsMime(void * mimeIn)262 void QWindowsNativeInterface::registerWindowsMime(void *mimeIn)
263 {
264     QWindowsContext::instance()->mimeConverter().registerMime(reinterpret_cast<QWindowsMime *>(mimeIn));
265 }
266 
unregisterWindowsMime(void * mimeIn)267 void QWindowsNativeInterface::unregisterWindowsMime(void *mimeIn)
268 {
269     QWindowsContext::instance()->mimeConverter().unregisterMime(reinterpret_cast<QWindowsMime *>(mimeIn));
270 }
271 
registerMimeType(const QString & mimeType)272 int QWindowsNativeInterface::registerMimeType(const QString &mimeType)
273 {
274     return QWindowsMime::registerMimeType(mimeType);
275 }
276 
logFontToQFont(const void * logFont,int verticalDpi)277 QFont QWindowsNativeInterface::logFontToQFont(const void *logFont, int verticalDpi)
278 {
279     return QWindowsFontDatabase::LOGFONT_to_QFont(*reinterpret_cast<const LOGFONT *>(logFont), verticalDpi);
280 }
281 
isTabletMode()282 bool QWindowsNativeInterface::isTabletMode()
283 {
284 #if QT_CONFIG(clipboard)
285     if (const QWindowsClipboard *clipboard = QWindowsClipboard::instance())
286         return qt_windowsIsTabletMode(clipboard->clipboardViewer());
287 #endif
288     return false;
289 }
290 
platformFunction(const QByteArray & function) const291 QFunctionPointer QWindowsNativeInterface::platformFunction(const QByteArray &function) const
292 {
293     if (function == QWindowsWindowFunctions::setTouchWindowTouchTypeIdentifier())
294         return QFunctionPointer(QWindowsWindow::setTouchWindowTouchTypeStatic);
295     if (function == QWindowsWindowFunctions::setHasBorderInFullScreenIdentifier())
296         return QFunctionPointer(QWindowsWindow::setHasBorderInFullScreenStatic);
297     if (function == QWindowsWindowFunctions::setHasBorderInFullScreenDefaultIdentifier())
298         return QFunctionPointer(QWindowsWindow::setHasBorderInFullScreenDefault);
299     if (function == QWindowsWindowFunctions::setWindowActivationBehaviorIdentifier())
300         return QFunctionPointer(QWindowsNativeInterface::setWindowActivationBehavior);
301     if (function == QWindowsWindowFunctions::isTabletModeIdentifier())
302         return QFunctionPointer(QWindowsNativeInterface::isTabletMode);
303     return nullptr;
304 }
305 
gpu() const306 QVariant QWindowsNativeInterface::gpu() const
307 {
308     return GpuDescription::detect().toVariant();
309 }
310 
gpuList() const311 QVariant QWindowsNativeInterface::gpuList() const
312 {
313     QVariantList result;
314     const auto gpus = GpuDescription::detectAll();
315     for (const auto &gpu : gpus)
316         result.append(gpu.toVariant());
317     return result;
318 }
319 
isDarkMode() const320 bool QWindowsNativeInterface::isDarkMode() const
321 {
322     return QWindowsContext::isDarkMode();
323 }
324 
325 // Dark mode support level 2 (style)
isDarkModeStyle() const326 bool QWindowsNativeInterface::isDarkModeStyle() const
327 {
328     return (QWindowsIntegration::instance()->options() & QWindowsIntegration::DarkModeStyle) != 0;
329 }
330 
331 QT_END_NAMESPACE
332