Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qeglfsintegration.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include <QtCore/qtextstream.h>
6#include <QtGui/private/qguiapplication_p.h>
7
8#include <qpa/qplatformwindow.h>
9#include <QtGui/QSurfaceFormat>
10#include <QtGui/QScreen>
11#ifndef QT_NO_OPENGL
12# include <QtGui/QOpenGLContext>
13# include <QtGui/QOffscreenSurface>
14#endif
15#include <QtGui/QWindow>
16#include <QtCore/QLoggingCategory>
17#include <qpa/qwindowsysteminterface.h>
18#include <qpa/qplatforminputcontextfactory_p.h>
19
21#include "qeglfswindow_p.h"
22#include "qeglfshooks_p.h"
23#ifndef QT_NO_OPENGL
24# include "qeglfscontext_p.h"
25# include "qeglfscursor_p.h"
26#endif
28
29#include <QtGui/private/qeglconvenience_p.h>
30#ifndef QT_NO_OPENGL
31# include <QtGui/private/qeglplatformcontext_p.h>
32# include <QtGui/private/qeglpbuffer_p.h>
33#endif
34
35#include <QtGui/private/qgenericunixfontdatabase_p.h>
36#include <QtGui/private/qgenericunixtheme_p.h>
37#include <QtGui/private/qgenericunixeventdispatcher_p.h>
38#include <QtFbSupport/private/qfbvthandler_p.h>
39#ifndef QT_NO_OPENGL
40# include <QtOpenGL/private/qopenglcompositorbackingstore_p.h>
41#endif
42#include <qpa/qplatformservices.h>
43
44#if QT_CONFIG(libinput)
45#include <QtInputSupport/private/qlibinputhandler_p.h>
46#endif
47
48#if QT_CONFIG(evdev)
49#include <QtInputSupport/private/qevdevmousemanager_p.h>
50#include <QtInputSupport/private/qevdevkeyboardmanager_p.h>
51#include <QtInputSupport/private/qevdevtouchmanager_p.h>
52#elif QT_CONFIG(vxworksevdev)
53#include <QtInputSupport/private/qvxkeyboardmanager_p.h>
54#include <QtInputSupport/private/qvxmousemanager_p.h>
55#include <QtInputSupport/private/qvxtouchmanager_p.h>
56#endif
57
58#if QT_CONFIG(tslib)
59#include <QtInputSupport/private/qtslib_p.h>
60#endif
61
62#if QT_CONFIG(integrityhid)
63#include <QtInputSupport/qintegrityhidmanager.h>
64#endif
65
66static void initResources()
67{
68#ifndef QT_NO_CURSOR
69 Q_INIT_RESOURCE(cursor);
70#endif
71}
72
73QT_BEGIN_NAMESPACE
74
75using namespace Qt::StringLiterals;
76
77QEglFSIntegration::QEglFSIntegration()
78 : m_display(EGL_NO_DISPLAY),
79 m_inputContext(nullptr),
80 m_fontDb(new QGenericUnixFontDatabase),
81 m_disableInputHandlers(false)
82{
83 m_disableInputHandlers = qEnvironmentVariableIntValue("QT_QPA_EGLFS_DISABLE_INPUT");
84
85 initResources();
86}
87
88void QEglFSIntegration::initialize()
89{
90 qt_egl_device_integration()->platformInit();
91
92 m_display = qt_egl_device_integration()->createDisplay(nativeDisplay());
93 if (Q_UNLIKELY(m_display == EGL_NO_DISPLAY))
94 qFatal("Could not open egl display");
95
96 EGLint major, minor;
97 if (Q_UNLIKELY(!eglInitialize(m_display, &major, &minor)))
98 qFatal("Could not initialize egl display");
99
100 m_inputContext = QPlatformInputContextFactory::create();
101
102 m_vtHandler.reset(new QFbVtHandler);
103
104 if (qt_egl_device_integration()->usesDefaultScreen())
105 QWindowSystemInterface::handleScreenAdded(new QEglFSScreen(display()));
106 else
107 qt_egl_device_integration()->screenInit();
108
109 // Input code may rely on the screens, so do it only after the screen init.
110 if (!m_disableInputHandlers)
111 createInputHandlers();
112}
113
114void QEglFSIntegration::destroy()
115{
116 const auto toplevels = qGuiApp->topLevelWindows();
117 for (QWindow *w : toplevels)
118 w->destroy();
119
120 qt_egl_device_integration()->screenDestroy();
121
122 if (m_display != EGL_NO_DISPLAY)
123 eglTerminate(m_display);
124
125 qt_egl_device_integration()->platformDestroy();
126}
127
128QAbstractEventDispatcher *QEglFSIntegration::createEventDispatcher() const
129{
130 return createUnixEventDispatcher();
131}
132
133QPlatformServices *QEglFSIntegration::services() const
134{
135 if (m_services.isNull())
136 m_services.reset(new QPlatformServices);
137
138 return m_services.data();
139}
140
141QPlatformFontDatabase *QEglFSIntegration::fontDatabase() const
142{
143 return m_fontDb.data();
144}
145
146QPlatformTheme *QEglFSIntegration::createPlatformTheme(const QString &name) const
147{
148 return QGenericUnixTheme::createUnixTheme(name);
149}
150
151QPlatformBackingStore *QEglFSIntegration::createPlatformBackingStore(QWindow *window) const
152{
153#ifndef QT_NO_OPENGL
154 QOpenGLCompositorBackingStore *bs = new QOpenGLCompositorBackingStore(window);
155 if (!window->handle())
156 window->create();
157 static_cast<QEglFSWindow *>(window->handle())->setBackingStore(bs);
158 m_bs = bs;
159 return bs;
160#else
161 Q_UNUSED(window);
162 return nullptr;
163#endif
164}
165
166QPlatformWindow *QEglFSIntegration::createPlatformWindow(QWindow *window) const
167{
168 QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
169 QEglFSWindow *w = qt_egl_device_integration()->createWindow(window);
170 w->create();
171
172 const auto showWithoutActivating = window->property("_q_showWithoutActivating");
173 if (showWithoutActivating.isValid() && showWithoutActivating.toBool())
174 return w;
175
176 // Activate only the window for the primary screen to make input work
177 if (window->type() != Qt::ToolTip && window->screen() == QGuiApplication::primaryScreen())
178 w->requestActivateWindow();
179
180 if (window->isTopLevel())
181 w->setBackingStore(static_cast<QOpenGLCompositorBackingStore *>(m_bs));
182
183 return w;
184}
185
186#ifndef QT_NO_OPENGL
187QPlatformOpenGLContext *QEglFSIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
188{
189 EGLDisplay dpy = context->screen() ? static_cast<QEglFSScreen *>(context->screen()->handle())->display() : display();
190 QPlatformOpenGLContext *share = context->shareHandle();
191
192 QEglFSContext *ctx;
193 QSurfaceFormat adjustedFormat = qt_egl_device_integration()->surfaceFormatFor(context->format());
194 EGLConfig config = QEglFSDeviceIntegration::chooseConfig(dpy, adjustedFormat);
195 ctx = new QEglFSContext(adjustedFormat, share, dpy, &config);
196
197 return ctx;
198}
199
200QOpenGLContext *QEglFSIntegration::createOpenGLContext(EGLContext context, EGLDisplay contextDisplay, QOpenGLContext *shareContext) const
201{
202 return QEGLPlatformContext::createFrom<QEglFSContext>(context, contextDisplay, display(), shareContext);
203}
204
205QPlatformOffscreenSurface *QEglFSIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
206{
207 EGLDisplay dpy = surface->screen() ? static_cast<QEglFSScreen *>(surface->screen()->handle())->display() : display();
208 QSurfaceFormat fmt = qt_egl_device_integration()->surfaceFormatFor(surface->requestedFormat());
209 if (qt_egl_device_integration()->supportsPBuffers()) {
210 QEGLPlatformContext::Flags flags;
211 if (!qt_egl_device_integration()->supportsSurfacelessContexts())
212 flags |= QEGLPlatformContext::NoSurfaceless;
213 return new QEGLPbuffer(dpy, fmt, surface, flags);
214 } else {
215 return new QEglFSOffscreenWindow(dpy, fmt, surface);
216 }
217 // Never return null. Multiple QWindows are not supported by this plugin.
218}
219#endif // QT_NO_OPENGL
220
221bool QEglFSIntegration::hasCapability(QPlatformIntegration::Capability cap) const
222{
223 // We assume that devices will have more and not less capabilities
224 if (qt_egl_device_integration()->hasCapability(cap))
225 return true;
226
227 switch (cap) {
228 case ThreadedPixmaps: return true;
229#ifndef QT_NO_OPENGL
230 case OpenGL: return true;
231 case ThreadedOpenGL: return true;
232#else
233 case OpenGL: return false;
234 case ThreadedOpenGL: return false;
235#endif
236 case WindowManagement: return false;
237 case OpenGLOnRasterSurface: return true;
238 case OffscreenSurface: return true;
239 default: return QPlatformIntegration::hasCapability(cap);
240 }
241}
242
243QPlatformNativeInterface *QEglFSIntegration::nativeInterface() const
244{
245 return const_cast<QEglFSIntegration *>(this);
246}
247
259
260static int resourceType(const QByteArray &key)
261{
262 static const QByteArray names[] = { // match ResourceType
263 QByteArrayLiteral("egldisplay"),
264 QByteArrayLiteral("eglwindow"),
265 QByteArrayLiteral("eglcontext"),
266 QByteArrayLiteral("eglconfig"),
267 QByteArrayLiteral("nativedisplay"),
268 QByteArrayLiteral("display"),
269 QByteArrayLiteral("server_wl_display"),
270 QByteArrayLiteral("eglsurface"),
271 QByteArrayLiteral("vksurface")
272 };
273 const QByteArray *end = names + sizeof(names) / sizeof(names[0]);
274 const QByteArray *result = std::find(names, end, key);
275 if (result == end)
276 result = std::find(names, end, key.toLower());
277 return int(result - names);
278}
279
280void *QEglFSIntegration::nativeResourceForIntegration(const QByteArray &resource)
281{
282 void *result = nullptr;
283
284 switch (resourceType(resource)) {
285 case EglDisplay:
286 result = display();
287 break;
288 case NativeDisplay:
289 result = reinterpret_cast<void*>(nativeDisplay());
290 break;
291 case WaylandDisplay:
292 result = qt_egl_device_integration()->wlDisplay();
293 break;
294 default:
295 result = qt_egl_device_integration()->nativeResourceForIntegration(resource);
296 break;
297 }
298
299 return result;
300}
301
302void *QEglFSIntegration::nativeResourceForScreen(const QByteArray &resource, QScreen *screen)
303{
304 void *result = nullptr;
305
306 switch (resourceType(resource)) {
307 case XlibDisplay:
308 // Play nice when using the x11 hooks: Be compatible with xcb that allows querying
309 // the X Display pointer, which is nothing but our native display.
310 result = reinterpret_cast<void*>(nativeDisplay());
311 break;
312 default:
313 result = qt_egl_device_integration()->nativeResourceForScreen(resource, screen);
314 break;
315 }
316
317 return result;
318}
319
320void *QEglFSIntegration::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
321{
322 void *result = nullptr;
323
324 switch (resourceType(resource)) {
325 case EglDisplay:
326 if (window && window->handle())
327 result = static_cast<QEglFSScreen *>(window->handle()->screen())->display();
328 else
329 result = display();
330 break;
331 case EglWindow:
332 if (window && window->handle())
333 result = reinterpret_cast<void*>(static_cast<QEglFSWindow *>(window->handle())->eglWindow());
334 break;
335 case EglSurface:
336 if (window && window->handle())
337 result = reinterpret_cast<void*>(static_cast<QEglFSWindow *>(window->handle())->surface());
338 break;
339 default:
340 break;
341 }
342
343 return result;
344}
345
346#ifndef QT_NO_OPENGL
347void *QEglFSIntegration::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context)
348{
349 void *result = nullptr;
350
351 switch (resourceType(resource)) {
352 case EglContext:
353 if (context->handle())
354 result = static_cast<QEglFSContext *>(context->handle())->eglContext();
355 break;
356 case EglConfig:
357 if (context->handle())
358 result = static_cast<QEglFSContext *>(context->handle())->eglConfig();
359 break;
360 case EglDisplay:
361 if (context->handle())
362 result = static_cast<QEglFSContext *>(context->handle())->eglDisplay();
363 break;
364 default:
365 break;
366 }
367
368 return result;
369}
370
371static void *eglContextForContext(QOpenGLContext *context)
372{
373 Q_ASSERT(context);
374
375 QEglFSContext *handle = static_cast<QEglFSContext *>(context->handle());
376 if (!handle)
377 return nullptr;
378
379 return handle->eglContext();
380}
381#endif
382
383QPlatformNativeInterface::NativeResourceForContextFunction QEglFSIntegration::nativeResourceFunctionForContext(const QByteArray &resource)
384{
385#ifndef QT_NO_OPENGL
386 if (resource.compare("get_egl_context", Qt::CaseInsensitive) == 0)
387 return NativeResourceForContextFunction(eglContextForContext);
388#else
389 Q_UNUSED(resource);
390#endif
391 return nullptr;
392}
393
394QFunctionPointer QEglFSIntegration::platformFunction(const QByteArray &function) const
395{
396 return qt_egl_device_integration()->platformFunction(function);
397}
398
399QVariant QEglFSIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
400{
401 if (hint == QPlatformIntegration::ShowIsFullScreen)
402 return true;
403
404 return QPlatformIntegration::styleHint(hint);
405}
406
407#if QT_CONFIG(evdev) || QT_CONFIG(vxworksevdev)
408void QEglFSIntegration::loadKeymap(const QString &filename)
409{
410 if (m_kbdMgr)
411 m_kbdMgr->loadKeymap(filename);
412 else
413 qWarning("QEglFSIntegration: Cannot load keymap, no keyboard handler found");
414}
415
416void QEglFSIntegration::switchLang()
417{
418 if (m_kbdMgr)
419 m_kbdMgr->switchLang();
420 else
421 qWarning("QEglFSIntegration: Cannot switch language, no keyboard handler found");
422}
423#endif
424
425void QEglFSIntegration::createInputHandlers()
426{
427#if QT_CONFIG(libinput)
428 if (!qEnvironmentVariableIntValue("QT_QPA_EGLFS_NO_LIBINPUT")) {
429 new QLibInputHandler("libinput"_L1, QString());
430 return;
431 }
432#endif
433
434#if QT_CONFIG(tslib)
435 bool useTslib = qEnvironmentVariableIntValue("QT_QPA_EGLFS_TSLIB");
436 if (useTslib)
437 new QTsLibMouseHandler("TsLib"_L1, QString() /* spec */);
438#endif
439
440#if QT_CONFIG(evdev)
441 m_kbdMgr = new QEvdevKeyboardManager("EvdevKeyboard"_L1, QString() /* spec */, this);
442 new QEvdevMouseManager("EvdevMouse"_L1, QString() /* spec */, this);
443#if QT_CONFIG(tslib)
444 if (!useTslib)
445#endif
446 new QEvdevTouchManager("EvdevTouch"_L1, QString() /* spec */, this);
447#elif QT_CONFIG(vxworksevdev)
448 m_kbdMgr = new QVxKeyboardManager("VxKeyboard"_L1, QString() /* spec */, this);
449 new QVxMouseManager("VxMouse"_L1, QString() /* spec */, this);
450 new QVxTouchManager("VxTouch"_L1, QString() /* spec */, this);
451#endif
452
453#if QT_CONFIG(integrityhid)
454 new QIntegrityHIDManager("HID", "", this);
455#endif
456}
457
458EGLNativeDisplayType QEglFSIntegration::nativeDisplay() const
459{
460 return qt_egl_device_integration()->platformDisplay();
461}
462
463QT_END_NAMESPACE
static void initResources()
@ WaylandDisplay
@ NativeDisplay
@ XlibDisplay
static int resourceType(const QByteArray &key)
static void * eglContextForContext(QOpenGLContext *context)