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