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 <QtCore/qtextstream.h>
41#include <QtGui/private/qguiapplication_p.h>
42
43#include <qpa/qplatformwindow.h>
44#include <QtGui/QSurfaceFormat>
45#include <QtGui/QScreen>
46#ifndef QT_NO_OPENGL
47# include <QtGui/QOpenGLContext>
48# include <QtGui/QOffscreenSurface>
49#endif
50#include <QtGui/QWindow>
51#include <QtCore/QLoggingCategory>
52#include <qpa/qwindowsysteminterface.h>
53#include <qpa/qplatforminputcontextfactory_p.h>
54
55#include "qeglfsintegration_p.h"
56#include "qeglfswindow_p.h"
57#include "qeglfshooks_p.h"
58#ifndef QT_NO_OPENGL
59# include "qeglfscontext_p.h"
60# include "qeglfscursor_p.h"
61#endif
62#include "qeglfsoffscreenwindow_p.h"
63
64#include <QtEglSupport/private/qeglconvenience_p.h>
65#ifndef QT_NO_OPENGL
66# include <QtEglSupport/private/qeglplatformcontext_p.h>
67# include <QtEglSupport/private/qeglpbuffer_p.h>
68#endif
69
70#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
71#include <QtServiceSupport/private/qgenericunixservices_p.h>
72#include <QtThemeSupport/private/qgenericunixthemes_p.h>
73#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>
74#include <QtFbSupport/private/qfbvthandler_p.h>
75#ifndef QT_NO_OPENGL
76# include <QtPlatformCompositorSupport/private/qopenglcompositorbackingstore_p.h>
77#endif
78
79#include <QtPlatformHeaders/QEGLNativeContext>
80
81#if QT_CONFIG(libinput)
82#include <QtInputSupport/private/qlibinputhandler_p.h>
83#endif
84
85#if QT_CONFIG(evdev)
86#include <QtInputSupport/private/qevdevmousemanager_p.h>
87#include <QtInputSupport/private/qevdevkeyboardmanager_p.h>
88#include <QtInputSupport/private/qevdevtouchmanager_p.h>
89#endif
90
91#if QT_CONFIG(tslib)
92#include <QtInputSupport/private/qtslib_p.h>
93#endif
94
95#if QT_CONFIG(integrityhid)
96#include <QtInputSupport/qintegrityhidmanager.h>
97#endif
98
99#include <QtPlatformHeaders/qeglfsfunctions.h>
100
101static void initResources()
102{
103#ifndef QT_NO_CURSOR
104 Q_INIT_RESOURCE(cursor);
105#endif
106}
107
108QT_BEGIN_NAMESPACE
109
110QEglFSIntegration::QEglFSIntegration()
111 : m_display(EGL_NO_DISPLAY),
112 m_inputContext(nullptr),
113 m_fontDb(new QGenericUnixFontDatabase),
114 m_services(new QGenericUnixServices),
115 m_kbdMgr(nullptr),
116 m_disableInputHandlers(false)
117{
118 m_disableInputHandlers = qEnvironmentVariableIntValue(varName: "QT_QPA_EGLFS_DISABLE_INPUT");
119
120 initResources();
121}
122
123void QEglFSIntegration::initialize()
124{
125 qt_egl_device_integration()->platformInit();
126
127 m_display = qt_egl_device_integration()->createDisplay(nativeDisplay: nativeDisplay());
128 if (Q_UNLIKELY(m_display == EGL_NO_DISPLAY))
129 qFatal(msg: "Could not open egl display");
130
131 EGLint major, minor;
132 if (Q_UNLIKELY(!eglInitialize(m_display, &major, &minor)))
133 qFatal(msg: "Could not initialize egl display");
134
135 m_inputContext = QPlatformInputContextFactory::create();
136
137 m_vtHandler.reset(other: new QFbVtHandler);
138
139 if (qt_egl_device_integration()->usesDefaultScreen())
140 QWindowSystemInterface::handleScreenAdded(screen: new QEglFSScreen(display()));
141 else
142 qt_egl_device_integration()->screenInit();
143
144 // Input code may rely on the screens, so do it only after the screen init.
145 if (!m_disableInputHandlers)
146 createInputHandlers();
147}
148
149void QEglFSIntegration::destroy()
150{
151 foreach (QWindow *w, qGuiApp->topLevelWindows())
152 w->destroy();
153
154 qt_egl_device_integration()->screenDestroy();
155
156 if (m_display != EGL_NO_DISPLAY)
157 eglTerminate(dpy: m_display);
158
159 qt_egl_device_integration()->platformDestroy();
160}
161
162QAbstractEventDispatcher *QEglFSIntegration::createEventDispatcher() const
163{
164 return createUnixEventDispatcher();
165}
166
167QPlatformServices *QEglFSIntegration::services() const
168{
169 return m_services.data();
170}
171
172QPlatformFontDatabase *QEglFSIntegration::fontDatabase() const
173{
174 return m_fontDb.data();
175}
176
177QPlatformTheme *QEglFSIntegration::createPlatformTheme(const QString &name) const
178{
179 return QGenericUnixTheme::createUnixTheme(name);
180}
181
182QPlatformBackingStore *QEglFSIntegration::createPlatformBackingStore(QWindow *window) const
183{
184#ifndef QT_NO_OPENGL
185 QOpenGLCompositorBackingStore *bs = new QOpenGLCompositorBackingStore(window);
186 if (!window->handle())
187 window->create();
188 static_cast<QEglFSWindow *>(window->handle())->setBackingStore(bs);
189 return bs;
190#else
191 Q_UNUSED(window);
192 return nullptr;
193#endif
194}
195
196QPlatformWindow *QEglFSIntegration::createPlatformWindow(QWindow *window) const
197{
198 QWindowSystemInterface::flushWindowSystemEvents(flags: QEventLoop::ExcludeUserInputEvents);
199 QEglFSWindow *w = qt_egl_device_integration()->createWindow(window);
200 w->create();
201
202 const auto showWithoutActivating = window->property(name: "_q_showWithoutActivating");
203 if (showWithoutActivating.isValid() && showWithoutActivating.toBool())
204 return w;
205
206 // Activate only the window for the primary screen to make input work
207 if (window->type() != Qt::ToolTip && window->screen() == QGuiApplication::primaryScreen())
208 w->requestActivateWindow();
209
210 return w;
211}
212
213#ifndef QT_NO_OPENGL
214QPlatformOpenGLContext *QEglFSIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
215{
216 EGLDisplay dpy = context->screen() ? static_cast<QEglFSScreen *>(context->screen()->handle())->display() : display();
217 QPlatformOpenGLContext *share = context->shareHandle();
218 QVariant nativeHandle = context->nativeHandle();
219
220 QEglFSContext *ctx;
221 QSurfaceFormat adjustedFormat = qt_egl_device_integration()->surfaceFormatFor(inputFormat: context->format());
222 if (nativeHandle.isNull()) {
223 EGLConfig config = QEglFSDeviceIntegration::chooseConfig(display: dpy, format: adjustedFormat);
224 ctx = new QEglFSContext(adjustedFormat, share, dpy, &config, QVariant());
225 } else {
226 ctx = new QEglFSContext(adjustedFormat, share, dpy, nullptr, nativeHandle);
227 }
228 nativeHandle = QVariant::fromValue<QEGLNativeContext>(value: QEGLNativeContext(ctx->eglContext(), dpy));
229
230 context->setNativeHandle(nativeHandle);
231 return ctx;
232}
233
234QPlatformOffscreenSurface *QEglFSIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
235{
236 EGLDisplay dpy = surface->screen() ? static_cast<QEglFSScreen *>(surface->screen()->handle())->display() : display();
237 QSurfaceFormat fmt = qt_egl_device_integration()->surfaceFormatFor(inputFormat: surface->requestedFormat());
238 if (qt_egl_device_integration()->supportsPBuffers()) {
239 QEGLPlatformContext::Flags flags;
240 if (!qt_egl_device_integration()->supportsSurfacelessContexts())
241 flags |= QEGLPlatformContext::NoSurfaceless;
242 return new QEGLPbuffer(dpy, fmt, surface, flags);
243 } else {
244 return new QEglFSOffscreenWindow(dpy, fmt, surface);
245 }
246 // Never return null. Multiple QWindows are not supported by this plugin.
247}
248#endif // QT_NO_OPENGL
249
250#if QT_CONFIG(vulkan)
251QPlatformVulkanInstance *QEglFSIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const
252{
253 return qt_egl_device_integration()->createPlatformVulkanInstance(instance);
254}
255#endif
256
257bool QEglFSIntegration::hasCapability(QPlatformIntegration::Capability cap) const
258{
259 // We assume that devices will have more and not less capabilities
260 if (qt_egl_device_integration()->hasCapability(cap))
261 return true;
262
263 switch (cap) {
264 case ThreadedPixmaps: return true;
265#ifndef QT_NO_OPENGL
266 case OpenGL: return true;
267 case ThreadedOpenGL: return true;
268 case RasterGLSurface: return true;
269#else
270 case OpenGL: return false;
271 case ThreadedOpenGL: return false;
272 case RasterGLSurface: return false;
273#endif
274 case WindowManagement: return false;
275 case OpenGLOnRasterSurface: return true;
276 default: return QPlatformIntegration::hasCapability(cap);
277 }
278}
279
280QPlatformNativeInterface *QEglFSIntegration::nativeInterface() const
281{
282 return const_cast<QEglFSIntegration *>(this);
283}
284
285enum ResourceType {
286 EglDisplay,
287 EglWindow,
288 EglContext,
289 EglConfig,
290 NativeDisplay,
291 XlibDisplay,
292 WaylandDisplay,
293 EglSurface,
294 VkSurface
295};
296
297static int resourceType(const QByteArray &key)
298{
299 static const QByteArray names[] = { // match ResourceType
300 QByteArrayLiteral("egldisplay"),
301 QByteArrayLiteral("eglwindow"),
302 QByteArrayLiteral("eglcontext"),
303 QByteArrayLiteral("eglconfig"),
304 QByteArrayLiteral("nativedisplay"),
305 QByteArrayLiteral("display"),
306 QByteArrayLiteral("server_wl_display"),
307 QByteArrayLiteral("eglsurface"),
308 QByteArrayLiteral("vksurface")
309 };
310 const QByteArray *end = names + sizeof(names) / sizeof(names[0]);
311 const QByteArray *result = std::find(first: names, last: end, val: key);
312 if (result == end)
313 result = std::find(first: names, last: end, val: key.toLower());
314 return int(result - names);
315}
316
317void *QEglFSIntegration::nativeResourceForIntegration(const QByteArray &resource)
318{
319 void *result = nullptr;
320
321 switch (resourceType(key: resource)) {
322 case EglDisplay:
323 result = display();
324 break;
325 case NativeDisplay:
326 result = reinterpret_cast<void*>(nativeDisplay());
327 break;
328 case WaylandDisplay:
329 result = qt_egl_device_integration()->wlDisplay();
330 break;
331 default:
332 result = qt_egl_device_integration()->nativeResourceForIntegration(name: resource);
333 break;
334 }
335
336 return result;
337}
338
339void *QEglFSIntegration::nativeResourceForScreen(const QByteArray &resource, QScreen *screen)
340{
341 void *result = nullptr;
342
343 switch (resourceType(key: resource)) {
344 case XlibDisplay:
345 // Play nice when using the x11 hooks: Be compatible with xcb that allows querying
346 // the X Display pointer, which is nothing but our native display.
347 result = reinterpret_cast<void*>(nativeDisplay());
348 break;
349 default:
350 result = qt_egl_device_integration()->nativeResourceForScreen(resource, screen);
351 break;
352 }
353
354 return result;
355}
356
357void *QEglFSIntegration::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
358{
359 void *result = nullptr;
360
361 switch (resourceType(key: resource)) {
362 case EglDisplay:
363 if (window && window->handle())
364 result = static_cast<QEglFSScreen *>(window->handle()->screen())->display();
365 else
366 result = display();
367 break;
368 case EglWindow:
369 if (window && window->handle())
370 result = reinterpret_cast<void*>(static_cast<QEglFSWindow *>(window->handle())->eglWindow());
371 break;
372 case EglSurface:
373 if (window && window->handle())
374 result = reinterpret_cast<void*>(static_cast<QEglFSWindow *>(window->handle())->surface());
375 break;
376#if QT_CONFIG(vulkan)
377 case VkSurface:
378 if (window && window->handle() && window->surfaceType() == QSurface::VulkanSurface)
379 result = static_cast<QEglFSWindow *>(window->handle())->vulkanSurfacePtr();
380 break;
381#endif
382 default:
383 break;
384 }
385
386 return result;
387}
388
389#ifndef QT_NO_OPENGL
390void *QEglFSIntegration::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context)
391{
392 void *result = nullptr;
393
394 switch (resourceType(key: resource)) {
395 case EglContext:
396 if (context->handle())
397 result = static_cast<QEglFSContext *>(context->handle())->eglContext();
398 break;
399 case EglConfig:
400 if (context->handle())
401 result = static_cast<QEglFSContext *>(context->handle())->eglConfig();
402 break;
403 case EglDisplay:
404 if (context->handle())
405 result = static_cast<QEglFSContext *>(context->handle())->eglDisplay();
406 break;
407 default:
408 break;
409 }
410
411 return result;
412}
413
414static void *eglContextForContext(QOpenGLContext *context)
415{
416 Q_ASSERT(context);
417
418 QEglFSContext *handle = static_cast<QEglFSContext *>(context->handle());
419 if (!handle)
420 return nullptr;
421
422 return handle->eglContext();
423}
424#endif
425
426QPlatformNativeInterface::NativeResourceForContextFunction QEglFSIntegration::nativeResourceFunctionForContext(const QByteArray &resource)
427{
428#ifndef QT_NO_OPENGL
429 if (resource.compare(c: "get_egl_context", cs: Qt::CaseInsensitive) == 0)
430 return NativeResourceForContextFunction(eglContextForContext);
431#else
432 Q_UNUSED(resource);
433#endif
434 return nullptr;
435}
436
437QFunctionPointer QEglFSIntegration::platformFunction(const QByteArray &function) const
438{
439#if QT_CONFIG(evdev)
440 if (function == QEglFSFunctions::loadKeymapTypeIdentifier())
441 return QFunctionPointer(loadKeymapStatic);
442 else if (function == QEglFSFunctions::switchLangTypeIdentifier())
443 return QFunctionPointer(switchLangStatic);
444#endif
445
446 return qt_egl_device_integration()->platformFunction(function);
447}
448
449void QEglFSIntegration::loadKeymapStatic(const QString &filename)
450{
451#if QT_CONFIG(evdev)
452 QEglFSIntegration *self = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration());
453 if (self->m_kbdMgr)
454 self->m_kbdMgr->loadKeymap(file: filename);
455 else
456 qWarning(msg: "QEglFSIntegration: Cannot load keymap, no keyboard handler found");
457#else
458 Q_UNUSED(filename);
459#endif
460}
461
462void QEglFSIntegration::switchLangStatic()
463{
464#if QT_CONFIG(evdev)
465 QEglFSIntegration *self = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration());
466 if (self->m_kbdMgr)
467 self->m_kbdMgr->switchLang();
468 else
469 qWarning(msg: "QEglFSIntegration: Cannot switch language, no keyboard handler found");
470#endif
471}
472
473void QEglFSIntegration::createInputHandlers()
474{
475#if QT_CONFIG(libinput)
476 if (!qEnvironmentVariableIntValue(varName: "QT_QPA_EGLFS_NO_LIBINPUT")) {
477 new QLibInputHandler(QLatin1String("libinput"), QString());
478 return;
479 }
480#endif
481
482#if QT_CONFIG(tslib)
483 bool useTslib = qEnvironmentVariableIntValue("QT_QPA_EGLFS_TSLIB");
484 if (useTslib)
485 new QTsLibMouseHandler(QLatin1String("TsLib"), QString() /* spec */);
486#endif
487
488#if QT_CONFIG(evdev)
489 m_kbdMgr = new QEvdevKeyboardManager(QLatin1String("EvdevKeyboard"), QString() /* spec */, this);
490 new QEvdevMouseManager(QLatin1String("EvdevMouse"), QString() /* spec */, this);
491#if QT_CONFIG(tslib)
492 if (!useTslib)
493#endif
494 new QEvdevTouchManager(QLatin1String("EvdevTouch"), QString() /* spec */, this);
495#endif
496
497#if QT_CONFIG(integrityhid)
498 new QIntegrityHIDManager("HID", "", this);
499#endif
500}
501
502EGLNativeDisplayType QEglFSIntegration::nativeDisplay() const
503{
504 return qt_egl_device_integration()->platformDisplay();
505}
506
507QT_END_NAMESPACE
508

source code of qtbase/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp