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
qxcbnativeinterface.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
7#include "qxcbcursor.h"
8#include "qxcbscreen.h"
9#include "qxcbwindow.h"
12
13#include <private/qguiapplication_p.h>
14#include <QtCore/QMap>
15
16#include <QtCore/QDebug>
17
18#include <QtGui/qopenglcontext.h>
19#include <QtGui/qscreen.h>
20
21#include <stdio.h>
22
23#include <algorithm>
24
26
27#if QT_CONFIG(vulkan)
28#include "qxcbvulkanwindow.h"
29#endif
30
32
33// return QXcbNativeInterface::ResourceType for the key.
34static int resourceType(const QByteArray &key)
35{
36 static const QByteArray names[] = { // match QXcbNativeInterface::ResourceType
37 QByteArrayLiteral("display"),
38 QByteArrayLiteral("connection"), QByteArrayLiteral("screen"),
39 QByteArrayLiteral("apptime"),
40 QByteArrayLiteral("appusertime"), QByteArrayLiteral("hintstyle"),
41 QByteArrayLiteral("startupid"), QByteArrayLiteral("traywindow"),
42 QByteArrayLiteral("gettimestamp"), QByteArrayLiteral("x11screen"),
43 QByteArrayLiteral("rootwindow"),
44 QByteArrayLiteral("subpixeltype"), QByteArrayLiteral("antialiasingenabled"),
45 QByteArrayLiteral("atspibus"),
46 QByteArrayLiteral("compositingenabled"),
47 QByteArrayLiteral("vksurface"),
48 QByteArrayLiteral("generatepeekerid"),
49 QByteArrayLiteral("removepeekerid"),
50 QByteArrayLiteral("peekeventqueue")
51 };
52 const QByteArray *end = names + sizeof(names) / sizeof(names[0]);
53 const QByteArray *result = std::find(names, end, key);
54 return int(result - names);
55}
56
57QXcbNativeInterface::QXcbNativeInterface()
58{
59}
60
61static inline QXcbSystemTrayTracker *systemTrayTracker(const QScreen *s)
62{
63 if (!s)
64 return nullptr;
65
66 return static_cast<const QXcbScreen *>(s->handle())->connection()->systemTrayTracker();
67}
68
69void *QXcbNativeInterface::nativeResourceForIntegration(const QByteArray &resourceString)
70{
71 QByteArray lowerCaseResource = resourceString.toLower();
72 void *result = handlerNativeResourceForIntegration(lowerCaseResource);
73 if (result)
74 return result;
75
76 switch (resourceType(lowerCaseResource)) {
77 case StartupId:
78 result = startupId();
79 break;
80 case X11Screen:
81 result = x11Screen();
82 break;
83 case RootWindow:
84 result = rootWindow();
85 break;
86 case XDisplay:
87 result = display();
88 break;
89 case AtspiBus:
90 result = atspiBus();
91 break;
92 case Connection:
93 result = connection();
94 break;
95 default:
96 break;
97 }
98
99 return result;
100}
101
102void *QXcbNativeInterface::nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context)
103{
104 QByteArray lowerCaseResource = resourceString.toLower();
105 void *result = handlerNativeResourceForContext(lowerCaseResource, context);
106 return result;
107}
108
109void *QXcbNativeInterface::nativeResourceForScreen(const QByteArray &resourceString, QScreen *screen)
110{
111 if (!screen) {
112 qWarning("nativeResourceForScreen: null screen");
113 return nullptr;
114 }
115
116 QByteArray lowerCaseResource = resourceString.toLower();
117 void *result = handlerNativeResourceForScreen(lowerCaseResource, screen);
118 if (result)
119 return result;
120
121 const QXcbScreen *xcbScreen = static_cast<QXcbScreen *>(screen->handle());
122 switch (resourceType(lowerCaseResource)) {
123 case XDisplay:
124#if QT_CONFIG(xcb_xlib)
125 result = xcbScreen->connection()->xlib_display();
126#endif
127 break;
128 case AppTime:
129 result = appTime(xcbScreen);
130 break;
131 case AppUserTime:
132 result = appUserTime(xcbScreen);
133 break;
134 case ScreenHintStyle:
135 result = reinterpret_cast<void *>(xcbScreen->hintStyle() + 1);
136 break;
137 case ScreenSubpixelType:
138 result = reinterpret_cast<void *>(xcbScreen->subpixelType() + 1);
139 break;
140 case ScreenAntialiasingEnabled:
141 result = reinterpret_cast<void *>(xcbScreen->antialiasingEnabled() + 1);
142 break;
143 case TrayWindow:
144 if (QXcbSystemTrayTracker *s = systemTrayTracker(screen))
145 result = (void *)quintptr(s->trayWindow());
146 break;
147 case GetTimestamp:
148 result = getTimestamp(xcbScreen);
149 break;
150 case RootWindow:
151 result = reinterpret_cast<void *>(xcbScreen->root());
152 break;
153 case CompositingEnabled:
154 if (QXcbVirtualDesktop *vd = xcbScreen->virtualDesktop())
155 result = vd->compositingActive() ? this : nullptr;
156 break;
157 default:
158 break;
159 }
160 return result;
161}
162
163void *QXcbNativeInterface::nativeResourceForWindow(const QByteArray &resourceString, QWindow *window)
164{
165 QByteArray lowerCaseResource = resourceString.toLower();
166 void *result = handlerNativeResourceForWindow(lowerCaseResource, window);
167 if (result)
168 return result;
169
170 switch (resourceType(lowerCaseResource)) {
171 case XDisplay:
172 result = displayForWindow(window);
173 break;
174 case Connection:
175 result = connectionForWindow(window);
176 break;
177 case Screen:
178 result = screenForWindow(window);
179 break;
180#if QT_CONFIG(vulkan)
181 case VkSurface:
182 if (window->surfaceType() == QSurface::VulkanSurface && window->handle()) {
183 // return a pointer to the VkSurfaceKHR value, not the value itself
184 result = static_cast<QXcbVulkanWindow *>(window->handle())->surface();
185 }
186 break;
187#endif
188 default:
189 break;
190 }
191
192 return result;
193}
194
195void *QXcbNativeInterface::nativeResourceForBackingStore(const QByteArray &resourceString, QBackingStore *backingStore)
196{
197 const QByteArray lowerCaseResource = resourceString.toLower();
198 void *result = handlerNativeResourceForBackingStore(lowerCaseResource,backingStore);
199 return result;
200}
201
202#ifndef QT_NO_CURSOR
203void *QXcbNativeInterface::nativeResourceForCursor(const QByteArray &resource, const QCursor &cursor)
204{
205 if (resource == QByteArrayLiteral("xcbcursor")) {
206 if (const QScreen *primaryScreen = QGuiApplication::primaryScreen()) {
207 if (const QPlatformCursor *pCursor= primaryScreen->handle()->cursor()) {
208 xcb_cursor_t xcbCursor = static_cast<const QXcbCursor *>(pCursor)->xcbCursor(cursor);
209 return reinterpret_cast<void *>(quintptr(xcbCursor));
210 }
211 }
212 }
213 return nullptr;
214}
215#endif // !QT_NO_CURSOR
216
217QPlatformNativeInterface::NativeResourceForIntegrationFunction QXcbNativeInterface::nativeResourceFunctionForIntegration(const QByteArray &resource)
218{
219 const QByteArray lowerCaseResource = resource.toLower();
220 QPlatformNativeInterface::NativeResourceForIntegrationFunction func = handlerNativeResourceFunctionForIntegration(lowerCaseResource);
221 if (func)
222 return func;
223
224 if (lowerCaseResource == "setstartupid")
225 return NativeResourceForIntegrationFunction(reinterpret_cast<void *>(setStartupId));
226 if (lowerCaseResource == "generatepeekerid")
227 return NativeResourceForIntegrationFunction(reinterpret_cast<void *>(generatePeekerId));
228 if (lowerCaseResource == "removepeekerid")
229 return NativeResourceForIntegrationFunction(reinterpret_cast<void *>(removePeekerId));
230 if (lowerCaseResource == "peekeventqueue")
231 return NativeResourceForIntegrationFunction(reinterpret_cast<void *>(peekEventQueue));
232
233 return nullptr;
234}
235
236QPlatformNativeInterface::NativeResourceForContextFunction QXcbNativeInterface::nativeResourceFunctionForContext(const QByteArray &resource)
237{
238 const QByteArray lowerCaseResource = resource.toLower();
239 QPlatformNativeInterface::NativeResourceForContextFunction func = handlerNativeResourceFunctionForContext(lowerCaseResource);
240 if (func)
241 return func;
242 return nullptr;
243}
244
245QPlatformNativeInterface::NativeResourceForScreenFunction QXcbNativeInterface::nativeResourceFunctionForScreen(const QByteArray &resource)
246{
247 const QByteArray lowerCaseResource = resource.toLower();
248 NativeResourceForScreenFunction func = handlerNativeResourceFunctionForScreen(lowerCaseResource);
249 if (func)
250 return func;
251
252 if (lowerCaseResource == "setapptime")
253 return NativeResourceForScreenFunction(reinterpret_cast<void *>(setAppTime));
254 else if (lowerCaseResource == "setappusertime")
255 return NativeResourceForScreenFunction(reinterpret_cast<void *>(setAppUserTime));
256 return nullptr;
257}
258
259QPlatformNativeInterface::NativeResourceForWindowFunction QXcbNativeInterface::nativeResourceFunctionForWindow(const QByteArray &resource)
260{
261 const QByteArray lowerCaseResource = resource.toLower();
262 NativeResourceForWindowFunction func = handlerNativeResourceFunctionForWindow(lowerCaseResource);
263 return func;
264}
265
266QPlatformNativeInterface::NativeResourceForBackingStoreFunction QXcbNativeInterface::nativeResourceFunctionForBackingStore(const QByteArray &resource)
267{
268 const QByteArray lowerCaseResource = resource.toLower();
269 NativeResourceForBackingStoreFunction func = handlerNativeResourceFunctionForBackingStore(lowerCaseResource);
270 return func;
271}
272
273QFunctionPointer QXcbNativeInterface::platformFunction(const QByteArray &function) const
274{
275 const QByteArray lowerCaseFunction = function.toLower();
276 if (QFunctionPointer func = handlerPlatformFunction(lowerCaseFunction))
277 return func;
278
279 return nullptr;
280}
281
282void *QXcbNativeInterface::appTime(const QXcbScreen *screen)
283{
284 if (!screen)
285 return nullptr;
286
287 return reinterpret_cast<void *>(quintptr(screen->connection()->time()));
288}
289
290void *QXcbNativeInterface::appUserTime(const QXcbScreen *screen)
291{
292 if (!screen)
293 return nullptr;
294
295 return reinterpret_cast<void *>(quintptr(screen->connection()->netWmUserTime()));
296}
297
298void *QXcbNativeInterface::getTimestamp(const QXcbScreen *screen)
299{
300 if (!screen)
301 return nullptr;
302
303 return reinterpret_cast<void *>(quintptr(screen->connection()->getTimestamp()));
304}
305
306void *QXcbNativeInterface::startupId()
307{
308 QXcbIntegration* integration = QXcbIntegration::instance();
309 QXcbConnection *connection = integration->connection();
310 if (connection)
311 return reinterpret_cast<void *>(const_cast<char *>(connection->startupId().constData()));
312 return nullptr;
313}
314
315void *QXcbNativeInterface::x11Screen()
316{
317 QXcbIntegration *integration = QXcbIntegration::instance();
318 QXcbConnection *connection = integration->connection();
319 if (connection)
320 return reinterpret_cast<void *>(connection->primaryScreenNumber());
321 return nullptr;
322}
323
324void *QXcbNativeInterface::rootWindow()
325{
326 QXcbIntegration *integration = QXcbIntegration::instance();
327 QXcbConnection *connection = integration->connection();
328 if (connection)
329 return reinterpret_cast<void *>(connection->rootWindow());
330 return nullptr;
331}
332
333Display *QXcbNativeInterface::display() const
334{
335#if QT_CONFIG(xcb_xlib)
336 QXcbIntegration *integration = QXcbIntegration::instance();
337 if (QXcbConnection *connection = integration->connection())
338 return reinterpret_cast<Display *>(connection->xlib_display());
339#endif
340 return nullptr;
341}
342
343xcb_connection_t *QXcbNativeInterface::connection() const
344{
345 QXcbIntegration *integration = QXcbIntegration::instance();
346 return integration->connection()->xcb_connection();
347}
348
349void *QXcbNativeInterface::atspiBus()
350{
351 QXcbIntegration *integration = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration());
352 QXcbConnection *connection = integration->connection();
353 if (connection) {
354 auto atspiBusAtom = connection->atom(QXcbAtom::AtomAT_SPI_BUS);
355 auto reply = Q_XCB_REPLY(xcb_get_property, connection->xcb_connection(),
356 false, connection->rootWindow(),
357 atspiBusAtom, XCB_ATOM_STRING, 0, 128);
358 if (!reply)
359 return nullptr;
360
361 char *data = (char *)xcb_get_property_value(reply.get());
362 int length = xcb_get_property_value_length(reply.get());
363 return new QByteArray(data, length);
364 }
365
366 return nullptr;
367}
368
369void QXcbNativeInterface::setAppTime(QScreen* screen, xcb_timestamp_t time)
370{
371 if (screen) {
372 static_cast<QXcbScreen *>(screen->handle())->connection()->setTime(time);
373 }
374}
375
376void QXcbNativeInterface::setAppUserTime(QScreen* screen, xcb_timestamp_t time)
377{
378 if (screen) {
379 static_cast<QXcbScreen *>(screen->handle())->connection()->setNetWmUserTime(time);
380 }
381}
382
383qint32 QXcbNativeInterface::generatePeekerId()
384{
385 QXcbIntegration *integration = QXcbIntegration::instance();
386 return integration->connection()->eventQueue()->generatePeekerId();
387}
388
389bool QXcbNativeInterface::removePeekerId(qint32 peekerId)
390{
391 QXcbIntegration *integration = QXcbIntegration::instance();
392 return integration->connection()->eventQueue()->removePeekerId(peekerId);
393}
394
395bool QXcbNativeInterface::peekEventQueue(QXcbEventQueue::PeekerCallback peeker, void *peekerData,
396 QXcbEventQueue::PeekOptions option, qint32 peekerId)
397{
398 QXcbIntegration *integration = QXcbIntegration::instance();
399 return integration->connection()->eventQueue()->peekEventQueue(peeker, peekerData, option, peekerId);
400}
401
402void QXcbNativeInterface::setStartupId(const char *data)
403{
404 QByteArray startupId(data);
405 QXcbIntegration *integration = QXcbIntegration::instance();
406 QXcbConnection *connection = integration->connection();
407 if (connection)
408 connection->setStartupId(startupId);
409}
410
411QXcbScreen *QXcbNativeInterface::qPlatformScreenForWindow(QWindow *window)
412{
413 QXcbScreen *screen;
414 if (window) {
415 QScreen *qs = window->screen();
416 screen = static_cast<QXcbScreen *>(qs ? qs->handle() : nullptr);
417 } else {
418 QScreen *qs = QGuiApplication::primaryScreen();
419 screen = static_cast<QXcbScreen *>(qs ? qs->handle() : nullptr);
420 }
421 return screen;
422}
423
424void *QXcbNativeInterface::displayForWindow(QWindow *window)
425{
426#if QT_CONFIG(xcb_xlib)
427 QXcbScreen *screen = qPlatformScreenForWindow(window);
428 return screen ? screen->connection()->xlib_display() : nullptr;
429#else
430 Q_UNUSED(window);
431 return nullptr;
432#endif
433}
434
435void *QXcbNativeInterface::connectionForWindow(QWindow *window)
436{
437 QXcbScreen *screen = qPlatformScreenForWindow(window);
438 return screen ? screen->xcb_connection() : nullptr;
439}
440
441void *QXcbNativeInterface::screenForWindow(QWindow *window)
442{
443 QXcbScreen *screen = qPlatformScreenForWindow(window);
444 return screen ? screen->screen() : nullptr;
445}
446
447void QXcbNativeInterface::addHandler(QXcbNativeInterfaceHandler *handler)
448{
449 m_handlers.removeAll(handler);
450 m_handlers.prepend(handler);
451}
452
453void QXcbNativeInterface::removeHandler(QXcbNativeInterfaceHandler *handler)
454{
455 m_handlers.removeAll(handler);
456}
457
458QPlatformNativeInterface::NativeResourceForIntegrationFunction QXcbNativeInterface::handlerNativeResourceFunctionForIntegration(const QByteArray &resource) const
459{
460 for (int i = 0; i < m_handlers.size(); i++) {
461 QXcbNativeInterfaceHandler *handler = m_handlers.at(i);
462 NativeResourceForIntegrationFunction result = handler->nativeResourceFunctionForIntegration(resource);
463 if (result)
464 return result;
465 }
466 return nullptr;
467}
468
469QPlatformNativeInterface::NativeResourceForContextFunction QXcbNativeInterface::handlerNativeResourceFunctionForContext(const QByteArray &resource) const
470{
471 for (int i = 0; i < m_handlers.size(); i++) {
472 QXcbNativeInterfaceHandler *handler = m_handlers.at(i);
473 NativeResourceForContextFunction result = handler->nativeResourceFunctionForContext(resource);
474 if (result)
475 return result;
476 }
477 return nullptr;
478}
479
480QPlatformNativeInterface::NativeResourceForScreenFunction QXcbNativeInterface::handlerNativeResourceFunctionForScreen(const QByteArray &resource) const
481{
482 for (int i = 0; i < m_handlers.size(); i++) {
483 QXcbNativeInterfaceHandler *handler = m_handlers.at(i);
484 NativeResourceForScreenFunction result = handler->nativeResourceFunctionForScreen(resource);
485 if (result)
486 return result;
487 }
488 return nullptr;
489}
490
491QPlatformNativeInterface::NativeResourceForWindowFunction QXcbNativeInterface::handlerNativeResourceFunctionForWindow(const QByteArray &resource) const
492{
493 for (int i = 0; i < m_handlers.size(); i++) {
494 QXcbNativeInterfaceHandler *handler = m_handlers.at(i);
495 NativeResourceForWindowFunction result = handler->nativeResourceFunctionForWindow(resource);
496 if (result)
497 return result;
498 }
499 return nullptr;
500}
501
502QPlatformNativeInterface::NativeResourceForBackingStoreFunction QXcbNativeInterface::handlerNativeResourceFunctionForBackingStore(const QByteArray &resource) const
503{
504 for (int i = 0; i < m_handlers.size(); i++) {
505 QXcbNativeInterfaceHandler *handler = m_handlers.at(i);
506 NativeResourceForBackingStoreFunction result = handler->nativeResourceFunctionForBackingStore(resource);
507 if (result)
508 return result;
509 }
510 return nullptr;
511}
512
513QFunctionPointer QXcbNativeInterface::handlerPlatformFunction(const QByteArray &function) const
514{
515 for (int i = 0; i < m_handlers.size(); i++) {
516 QXcbNativeInterfaceHandler *handler = m_handlers.at(i);
517 QFunctionPointer func = handler->platformFunction(function);
518 if (func)
519 return func;
520 }
521 return nullptr;
522}
523
524void *QXcbNativeInterface::handlerNativeResourceForIntegration(const QByteArray &resource) const
525{
526 NativeResourceForIntegrationFunction func = handlerNativeResourceFunctionForIntegration(resource);
527 if (func)
528 return func();
529 return nullptr;
530}
531
532void *QXcbNativeInterface::handlerNativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) const
533{
534 NativeResourceForContextFunction func = handlerNativeResourceFunctionForContext(resource);
535 if (func)
536 return func(context);
537 return nullptr;
538}
539
540void *QXcbNativeInterface::handlerNativeResourceForScreen(const QByteArray &resource, QScreen *screen) const
541{
542 NativeResourceForScreenFunction func = handlerNativeResourceFunctionForScreen(resource);
543 if (func)
544 return func(screen);
545 return nullptr;
546}
547
548void *QXcbNativeInterface::handlerNativeResourceForWindow(const QByteArray &resource, QWindow *window) const
549{
550 NativeResourceForWindowFunction func = handlerNativeResourceFunctionForWindow(resource);
551 if (func)
552 return func(window);
553 return nullptr;
554}
555
556void *QXcbNativeInterface::handlerNativeResourceForBackingStore(const QByteArray &resource, QBackingStore *backingStore) const
557{
558 NativeResourceForBackingStoreFunction func = handlerNativeResourceFunctionForBackingStore(resource);
559 if (func)
560 return func(backingStore);
561 return nullptr;
562}
563
564static void dumpNativeWindowsRecursion(const QXcbConnection *connection, xcb_window_t window,
565 int level, QTextStream &str)
566{
567 if (level)
568 str << QByteArray(2 * level, ' ');
569
570 xcb_connection_t *conn = connection->xcb_connection();
571 auto geomReply = Q_XCB_REPLY(xcb_get_geometry, conn, window);
572 if (!geomReply)
573 return;
574 const QRect geom(geomReply->x, geomReply->y, geomReply->width, geomReply->height);
575 if (!geom.isValid() || (geom.width() <= 3 && geom.height() <= 3))
576 return; // Skip helper/dummy windows.
577 str << "0x";
578 const int oldFieldWidth = str.fieldWidth();
579 const QChar oldPadChar =str.padChar();
580 str.setFieldWidth(8);
581 str.setPadChar(u'0');
582 str << Qt::hex << window;
583 str.setFieldWidth(oldFieldWidth);
584 str.setPadChar(oldPadChar);
585 str << Qt::dec << " \""
586 << QXcbWindow::windowTitle(connection, window) << "\" "
587 << geom.width() << 'x' << geom.height() << Qt::forcesign << geom.x() << geom.y()
588 << Qt::noforcesign << '\n';
589
590 auto reply = Q_XCB_REPLY(xcb_query_tree, conn, window);
591 if (reply) {
592 const int count = xcb_query_tree_children_length(reply.get());
593 const xcb_window_t *children = xcb_query_tree_children(reply.get());
594 for (int i = 0; i < count; ++i)
595 dumpNativeWindowsRecursion(connection, children[i], level + 1, str);
596 }
597}
598
599QString QXcbNativeInterface::dumpConnectionNativeWindows(const QXcbConnection *connection, WId root) const
600{
601 QString result;
602 QTextStream str(&result);
603 if (root) {
604 dumpNativeWindowsRecursion(connection, xcb_window_t(root), 0, str);
605 } else {
606 for (const QXcbScreen *screen : connection->screens()) {
607 str << "Screen: \"" << screen->name() << "\"\n";
608 dumpNativeWindowsRecursion(connection, screen->root(), 0, str);
609 str << '\n';
610 }
611 }
612 return result;
613}
614
615QString QXcbNativeInterface::dumpNativeWindows(WId root) const
616{
617 return dumpConnectionNativeWindows(QXcbIntegration::instance()->connection(), root);
618}
619
620QT_END_NAMESPACE
621
622#include "moc_qxcbnativeinterface.cpp"
#define Q_XCB_REPLY(call,...)
static QXcbSystemTrayTracker * systemTrayTracker(const QScreen *s)
static QT_BEGIN_NAMESPACE int resourceType(const QByteArray &key)
static void dumpNativeWindowsRecursion(const QXcbConnection *connection, xcb_window_t window, int level, QTextStream &str)