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

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

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