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
qeglfsx11integration.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
6#include <QThread>
7
8#include <X11/Xlib.h>
9#include <X11/Xlib-xcb.h>
10
11/* Make no mistake: This is not a replacement for the xcb platform plugin.
12 This here is barely an extremely useful tool for developing eglfs itself because
13 it allows to do so without any requirements for devices or drivers. */
14
15QT_BEGIN_NAMESPACE
16
17class EventReader : public QThread
18{
19public:
20 EventReader(QEglFSX11Integration *integration)
21 : m_integration(integration) { }
22
23 void run() override;
24
25private:
26 QEglFSX11Integration *m_integration;
27};
28
29Q_CONSTINIT static QBasicAtomicInt running = Q_BASIC_ATOMIC_INITIALIZER(0);
30
31void EventReader::run()
32{
33 xcb_generic_event_t *event = nullptr;
34 while (running.loadRelaxed() && (event = xcb_wait_for_event(m_integration->connection()))) {
35 uint response_type = event->response_type & ~0x80;
36 switch (response_type) {
37 case XCB_CLIENT_MESSAGE: {
38 xcb_client_message_event_t *client = (xcb_client_message_event_t *) event;
39 const xcb_atom_t *atoms = m_integration->atoms();
40 if (client->format == 32
41 && client->type == atoms[Atoms::WM_PROTOCOLS]
42 && client->data.data32[0] == atoms[Atoms::WM_DELETE_WINDOW]) {
43 QWindow *window = m_integration->platformWindow() ? m_integration->platformWindow()->window() : nullptr;
44 if (window)
45 QWindowSystemInterface::handleCloseEvent(window);
46 }
47 break;
48 }
49 default:
50 break;
51 }
52 }
53}
54
55void QEglFSX11Integration::sendConnectionEvent(xcb_atom_t a)
56{
57 xcb_client_message_event_t event;
58 memset(&event, 0, sizeof(event));
59
60 event.response_type = XCB_CLIENT_MESSAGE;
61 event.format = 32;
62 event.sequence = 0;
63 event.window = m_connectionEventListener;
64 event.type = a;
65
66 xcb_send_event(m_connection, false, m_connectionEventListener, XCB_EVENT_MASK_NO_EVENT, (const char *)&event);
67 xcb_flush(m_connection);
68}
69
70#define DISPLAY ((Display *) m_display)
71
73{
74 m_display = XOpenDisplay(nullptr);
75 if (Q_UNLIKELY(!m_display))
76 qFatal("Could not open display");
77
78 XSetEventQueueOwner(DISPLAY, XCBOwnsEventQueue);
79 m_connection = XGetXCBConnection(DISPLAY);
80
81 running.ref();
82
83 xcb_screen_iterator_t it = xcb_setup_roots_iterator(xcb_get_setup(m_connection));
84
85 m_connectionEventListener = xcb_generate_id(m_connection);
86 xcb_create_window(m_connection, XCB_COPY_FROM_PARENT,
87 m_connectionEventListener, it.data->root,
88 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY,
89 it.data->root_visual, 0, nullptr);
90
91 m_eventReader = new EventReader(this);
92 m_eventReader->start();
93}
94
96{
97 running.deref();
98
99 sendConnectionEvent(XCB_ATOM_NONE);
100
101 m_eventReader->wait();
102 delete m_eventReader;
103 m_eventReader = nullptr;
104
105 XCloseDisplay(DISPLAY);
106 m_display = nullptr;
107 m_connection = nullptr;
108}
109
114
116{
117 if (m_screenSize.isEmpty()) {
118 QList<QByteArray> env = qgetenv("EGLFS_X11_SIZE").split('x');
119 if (env.size() == 2) {
120 m_screenSize = QSize(env.at(0).toInt(), env.at(1).toInt());
121 } else {
122 XWindowAttributes a;
123 if (XGetWindowAttributes(DISPLAY, DefaultRootWindow(DISPLAY), &a))
124 m_screenSize = QSize(a.width, a.height);
125 }
126 }
127 return m_screenSize;
128}
129
131 const QSize &size,
132 const QSurfaceFormat &format)
133{
134 Q_UNUSED(format);
135
136 m_platformWindow = platformWindow;
137
138 xcb_screen_iterator_t it = xcb_setup_roots_iterator(xcb_get_setup(m_connection));
139 m_window = xcb_generate_id(m_connection);
140 xcb_create_window(m_connection, XCB_COPY_FROM_PARENT, m_window, it.data->root,
141 0, 0, size.width(), size.height(), 0,
142 XCB_WINDOW_CLASS_INPUT_OUTPUT, it.data->root_visual,
143 0, nullptr);
144
145 xcb_intern_atom_cookie_t cookies[Atoms::N_ATOMS];
146 static const char *atomNames[Atoms::N_ATOMS] = {
147 "_NET_WM_NAME",
148 "UTF8_STRING",
149 "WM_PROTOCOLS",
150 "WM_DELETE_WINDOW",
151 "_NET_WM_STATE",
152 "_NET_WM_STATE_FULLSCREEN"
153 };
154
155 for (int i = 0; i < Atoms::N_ATOMS; ++i) {
156 cookies[i] = xcb_intern_atom(m_connection, false, strlen(atomNames[i]), atomNames[i]);
157 xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(m_connection, cookies[i], nullptr);
158 m_atoms[i] = reply->atom;
159 free(reply);
160 }
161
162 // Set window title
163 xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_window,
164 m_atoms[Atoms::_NET_WM_NAME], m_atoms[Atoms::UTF8_STRING], 8, 5, "EGLFS");
165
166 // Enable WM_DELETE_WINDOW
167 xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_window,
168 m_atoms[Atoms::WM_PROTOCOLS], XCB_ATOM_ATOM, 32, 1, &m_atoms[Atoms::WM_DELETE_WINDOW]);
169
170 // Go fullscreen.
171 xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_window,
172 m_atoms[Atoms::_NET_WM_STATE], XCB_ATOM_ATOM, 32, 1, &m_atoms[Atoms::_NET_WM_STATE_FULLSCREEN]);
173
174 xcb_map_window(m_connection, m_window);
175
176 xcb_flush(m_connection);
177
178 return qt_egl_cast<EGLNativeWindowType>(m_window);
179}
180
181void QEglFSX11Integration::destroyNativeWindow(EGLNativeWindowType window)
182{
183 xcb_destroy_window(m_connection, qt_egl_cast<xcb_window_t>(window));
184}
185
186bool QEglFSX11Integration::hasCapability(QPlatformIntegration::Capability cap) const
187{
188 Q_UNUSED(cap);
189 return false;
190}
191
192QT_END_NAMESPACE
const xcb_atom_t * atoms() const
EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) override
EGLNativeDisplayType platformDisplay() const override
QSize screenSize() const override
bool hasCapability(QPlatformIntegration::Capability cap) const override
void destroyNativeWindow(EGLNativeWindowType window) override
#define DISPLAY