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 "qxcbintegration.h"
5#include "qxcbconnection.h"
6#include "qxcbscreen.h"
7#include "qxcbwindow.h"
8#include "qxcbcursor.h"
9#include "qxcbkeyboard.h"
10#include "qxcbbackingstore.h"
11#include "qxcbnativeinterface.h"
12#include "qxcbclipboard.h"
13#include "qxcbeventqueue.h"
14#include "qxcbeventdispatcher.h"
15#if QT_CONFIG(draganddrop)
16#include "qxcbdrag.h"
17#endif
18#include "qxcbglintegration.h"
19
20#ifndef QT_NO_SESSIONMANAGER
21#include "qxcbsessionmanager.h"
22#endif
23#include "qxcbxsettings.h"
24
25#include <xcb/xcb.h>
26
27#include <QtGui/private/qgenericunixfontdatabase_p.h>
28#include <QtGui/private/qdesktopunixservices_p.h>
29
30#include <stdio.h>
31
32#include <QtGui/private/qguiapplication_p.h>
33
34#if QT_CONFIG(xcb_xlib)
35#define register /* C++17 deprecated register */
36#include <X11/Xlib.h>
37#undef register
38#endif
39#if QT_CONFIG(xcb_native_painting)
40#include "qxcbnativepainting.h"
41#include "qpixmap_x11_p.h"
42#include "qbackingstore_x11_p.h"
43#endif
44
45#include <qpa/qplatforminputcontextfactory_p.h>
46#include <private/qgenericunixtheme_p.h>
47#if QT_CONFIG(dbus)
48#include <private/qkdetheme_p.h>
49#endif
50#include <qpa/qplatforminputcontext.h>
51
52#include <QtGui/QOpenGLContext>
53#include <QtGui/QScreen>
54#include <QtGui/QOffscreenSurface>
55#if QT_CONFIG(accessibility)
56#include <qpa/qplatformaccessibility.h>
57#if QT_CONFIG(accessibility_atspi_bridge)
58#include <QtGui/private/qspiaccessiblebridge_p.h>
59#endif
60#endif
61
62#include <QtCore/QFileInfo>
63
64#if QT_CONFIG(vulkan)
65#include "qxcbvulkaninstance.h"
66#include "qxcbvulkanwindow.h"
67#endif
68
69QT_BEGIN_NAMESPACE
70
71using namespace Qt::StringLiterals;
72
73// Find out if our parent process is gdb by looking at the 'exe' symlink under /proc,.
74// or, for older Linuxes, read out 'cmdline'.
75static bool runningUnderDebugger()
76{
77#if defined(Q_OS_LINUX)
78 const QString parentProc = "/proc/"_L1 + QString::number(getppid());
79 const QFileInfo parentProcExe(parentProc + "/exe"_L1);
80 if (parentProcExe.isSymLink())
81 return parentProcExe.symLinkTarget().endsWith(s: "/gdb"_L1);
82 QFile f(parentProc + "/cmdline"_L1);
83 if (!f.open(flags: QIODevice::ReadOnly))
84 return false;
85 QByteArray s;
86 char c;
87 while (f.getChar(c: &c) && c) {
88 if (c == '/')
89 s.clear();
90 else
91 s += c;
92 }
93 return s == "gdb";
94#else
95 return false;
96#endif
97}
98
99class QXcbUnixServices : public QDesktopUnixServices, public QXcbObject
100{
101public:
102 QString portalWindowIdentifier(QWindow *window) override;
103 void registerDBusMenuForWindow(QWindow *window, const QString &service, const QString &path) override;
104 void unregisterDBusMenuForWindow(QWindow *window) override;
105};
106
107
108QXcbIntegration *QXcbIntegration::m_instance = nullptr;
109
110QXcbIntegration::QXcbIntegration(const QStringList &parameters, int &argc, char **argv)
111 : m_services(new QXcbUnixServices)
112 , m_instanceName(nullptr)
113 , m_canGrab(true)
114 , m_defaultVisualId(UINT_MAX)
115{
116 Q_UNUSED(parameters);
117
118 m_instance = this;
119 qApp->setAttribute(attribute: Qt::AA_CompressHighFrequencyEvents, on: true);
120
121 qRegisterMetaType<QXcbWindow*>();
122#if QT_CONFIG(xcb_xlib)
123 XInitThreads();
124#endif
125 m_nativeInterface.reset(other: new QXcbNativeInterface);
126
127 // Parse arguments
128 const char *displayName = nullptr;
129 bool noGrabArg = false;
130 bool doGrabArg = false;
131 if (argc) {
132 int j = 1;
133 for (int i = 1; i < argc; i++) {
134 QByteArray arg(argv[i]);
135 if (arg.startsWith(bv: "--"))
136 arg.remove(index: 0, len: 1);
137 if (arg == "-display" && i < argc - 1)
138 displayName = argv[++i];
139 else if (arg == "-name" && i < argc - 1)
140 m_instanceName = argv[++i];
141 else if (arg == "-nograb")
142 noGrabArg = true;
143 else if (arg == "-dograb")
144 doGrabArg = true;
145 else if (arg == "-visual" && i < argc - 1) {
146 bool ok = false;
147 m_defaultVisualId = QByteArray(argv[++i]).toUInt(ok: &ok, base: 0);
148 if (!ok)
149 m_defaultVisualId = UINT_MAX;
150 }
151 else
152 argv[j++] = argv[i];
153 }
154 argc = j;
155 } // argc
156
157 bool underDebugger = runningUnderDebugger();
158 if (noGrabArg && doGrabArg && underDebugger) {
159 qWarning(msg: "Both -nograb and -dograb command line arguments specified. Please pick one. -nograb takes precedence");
160 doGrabArg = false;
161 }
162
163 if (!noGrabArg && !doGrabArg && underDebugger) {
164 qCDebug(lcQpaXcb, "Qt: gdb: -nograb added to command-line options.\n"
165 "\t Use the -dograb option to enforce grabbing.");
166 }
167 m_canGrab = (!underDebugger && !noGrabArg) || (underDebugger && doGrabArg);
168
169 static bool canNotGrabEnv = qEnvironmentVariableIsSet(varName: "QT_XCB_NO_GRAB_SERVER");
170 if (canNotGrabEnv)
171 m_canGrab = false;
172
173 m_connection = new QXcbConnection(m_nativeInterface.data(), m_canGrab, m_defaultVisualId, displayName);
174 if (!m_connection->isConnected()) {
175 delete m_connection;
176 m_connection = nullptr;
177 return;
178 }
179 m_services->setConnection(m_connection);
180
181 m_fontDatabase.reset(other: new QGenericUnixFontDatabase());
182
183#if QT_CONFIG(xcb_native_painting)
184 if (nativePaintingEnabled()) {
185 qCDebug(lcQpaXcb, "QXCB USING NATIVE PAINTING");
186 qt_xcb_native_x11_info_init(connection());
187 }
188#endif
189}
190
191QXcbIntegration::~QXcbIntegration()
192{
193 delete m_connection;
194 m_connection = nullptr;
195 m_instance = nullptr;
196}
197
198QPlatformPixmap *QXcbIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const
199{
200#if QT_CONFIG(xcb_native_painting)
201 if (nativePaintingEnabled())
202 return new QX11PlatformPixmap(type);
203#endif
204
205 return QPlatformIntegration::createPlatformPixmap(type);
206}
207
208QPlatformWindow *QXcbIntegration::createPlatformWindow(QWindow *window) const
209{
210 QXcbGlIntegration *glIntegration = nullptr;
211 const bool isTrayIconWindow = QXcbWindow::isTrayIconWindow(window);
212 if (window->type() != Qt::Desktop && !isTrayIconWindow) {
213 if (window->supportsOpenGL()) {
214 glIntegration = connection()->glIntegration();
215 if (glIntegration) {
216 QXcbWindow *xcbWindow = glIntegration->createWindow(window);
217 xcbWindow->create();
218 return xcbWindow;
219 }
220#if QT_CONFIG(vulkan)
221 } else if (window->surfaceType() == QSurface::VulkanSurface) {
222 QXcbWindow *xcbWindow = new QXcbVulkanWindow(window);
223 xcbWindow->create();
224 return xcbWindow;
225#endif
226 }
227 }
228
229 Q_ASSERT(window->type() == Qt::Desktop || isTrayIconWindow || !window->supportsOpenGL()
230 || (!glIntegration && window->surfaceType() == QSurface::RasterGLSurface)); // for VNC
231 QXcbWindow *xcbWindow = new QXcbWindow(window);
232 xcbWindow->create();
233 return xcbWindow;
234}
235
236QPlatformWindow *QXcbIntegration::createForeignWindow(QWindow *window, WId nativeHandle) const
237{
238 return new QXcbForeignWindow(window, nativeHandle);
239}
240
241#ifndef QT_NO_OPENGL
242QPlatformOpenGLContext *QXcbIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
243{
244 QXcbGlIntegration *glIntegration = m_connection->glIntegration();
245 if (!glIntegration) {
246 qWarning(msg: "QXcbIntegration: Cannot create platform OpenGL context, neither GLX nor EGL are enabled");
247 return nullptr;
248 }
249 return glIntegration->createPlatformOpenGLContext(context);
250}
251
252# if QT_CONFIG(xcb_glx_plugin)
253QOpenGLContext *QXcbIntegration::createOpenGLContext(GLXContext context, void *visualInfo, QOpenGLContext *shareContext) const
254{
255 using namespace QNativeInterface::Private;
256 if (auto *glxIntegration = dynamic_cast<QGLXIntegration*>(m_connection->glIntegration()))
257 return glxIntegration->createOpenGLContext(context, visualInfo, shareContext);
258 else
259 return nullptr;
260}
261# endif
262
263#if QT_CONFIG(egl)
264QOpenGLContext *QXcbIntegration::createOpenGLContext(EGLContext context, EGLDisplay display, QOpenGLContext *shareContext) const
265{
266 using namespace QNativeInterface::Private;
267 if (auto *eglIntegration = dynamic_cast<QEGLIntegration*>(m_connection->glIntegration()))
268 return eglIntegration->createOpenGLContext(context, display, shareContext);
269 else
270 return nullptr;
271}
272#endif
273
274#endif // QT_NO_OPENGL
275
276QPlatformBackingStore *QXcbIntegration::createPlatformBackingStore(QWindow *window) const
277{
278 QPlatformBackingStore *backingStore = nullptr;
279
280 const bool isTrayIconWindow = QXcbWindow::isTrayIconWindow(window);
281 if (isTrayIconWindow) {
282 backingStore = new QXcbSystemTrayBackingStore(window);
283#if QT_CONFIG(xcb_native_painting)
284 } else if (nativePaintingEnabled()) {
285 backingStore = new QXcbNativeBackingStore(window);
286#endif
287 } else {
288 backingStore = new QXcbBackingStore(window);
289 }
290 Q_ASSERT(backingStore);
291 return backingStore;
292}
293
294QPlatformOffscreenSurface *QXcbIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
295{
296 QXcbScreen *screen = static_cast<QXcbScreen *>(surface->screen()->handle());
297 QXcbGlIntegration *glIntegration = screen->connection()->glIntegration();
298 if (!glIntegration) {
299 qWarning(msg: "QXcbIntegration: Cannot create platform offscreen surface, neither GLX nor EGL are enabled");
300 return nullptr;
301 }
302 return glIntegration->createPlatformOffscreenSurface(surface);
303}
304
305bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
306{
307 switch (cap) {
308 case OpenGL:
309 case ThreadedOpenGL:
310 {
311 if (const auto *integration = connection()->glIntegration())
312 return cap != ThreadedOpenGL || integration->supportsThreadedOpenGL();
313 return false;
314 }
315
316 case ThreadedPixmaps:
317 case WindowMasks:
318 case MultipleWindows:
319 case ForeignWindows:
320 case SyncState:
321 case RasterGLSurface:
322 return true;
323
324 case SwitchableWidgetComposition:
325 {
326 return m_connection->glIntegration()
327 && m_connection->glIntegration()->supportsSwitchableWidgetComposition();
328 }
329
330 default: return QPlatformIntegration::hasCapability(cap);
331 }
332}
333
334QAbstractEventDispatcher *QXcbIntegration::createEventDispatcher() const
335{
336 return QXcbEventDispatcher::createEventDispatcher(connection: connection());
337}
338
339using namespace Qt::Literals::StringLiterals;
340static const auto xsNetCursorBlink = "Net/CursorBlink"_ba;
341static const auto xsNetCursorBlinkTime = "Net/CursorBlinkTime"_ba;
342static const auto xsNetDoubleClickTime = "Net/DoubleClickTime"_ba;
343static const auto xsNetDoubleClickDistance = "Net/DoubleClickDistance"_ba;
344static const auto xsNetDndDragThreshold = "Net/DndDragThreshold"_ba;
345
346void QXcbIntegration::initialize()
347{
348 const auto defaultInputContext = "compose"_L1;
349 // Perform everything that may potentially need the event dispatcher (timers, socket
350 // notifiers) here instead of the constructor.
351 auto icStrs = QPlatformInputContextFactory::requested();
352 if (icStrs.isEmpty())
353 icStrs = { defaultInputContext };
354 m_inputContext.reset(other: QPlatformInputContextFactory::create(keys: icStrs));
355 if (!m_inputContext && !icStrs.contains(str: defaultInputContext)
356 && icStrs != QStringList{"none"_L1})
357 m_inputContext.reset(other: QPlatformInputContextFactory::create(key: defaultInputContext));
358
359 connection()->keyboard()->initialize();
360
361 auto notifyThemeChanged = [](QXcbVirtualDesktop *, const QByteArray &, const QVariant &, void *) {
362 QWindowSystemInterface::handleThemeChange();
363 };
364
365 auto *xsettings = connection()->primaryScreen()->xSettings();
366 xsettings->registerCallbackForProperty(property: xsNetCursorBlink, func: notifyThemeChanged, handle: this);
367 xsettings->registerCallbackForProperty(property: xsNetCursorBlinkTime, func: notifyThemeChanged, handle: this);
368 xsettings->registerCallbackForProperty(property: xsNetDoubleClickTime, func: notifyThemeChanged, handle: this);
369 xsettings->registerCallbackForProperty(property: xsNetDoubleClickDistance, func: notifyThemeChanged, handle: this);
370 xsettings->registerCallbackForProperty(property: xsNetDndDragThreshold, func: notifyThemeChanged, handle: this);
371}
372
373void QXcbIntegration::moveToScreen(QWindow *window, int screen)
374{
375 Q_UNUSED(window);
376 Q_UNUSED(screen);
377}
378
379QPlatformFontDatabase *QXcbIntegration::fontDatabase() const
380{
381 return m_fontDatabase.data();
382}
383
384QPlatformNativeInterface * QXcbIntegration::nativeInterface() const
385{
386 return m_nativeInterface.data();
387}
388
389#ifndef QT_NO_CLIPBOARD
390QPlatformClipboard *QXcbIntegration::clipboard() const
391{
392 return m_connection->clipboard();
393}
394#endif
395
396#if QT_CONFIG(draganddrop)
397#include <private/qsimpledrag_p.h>
398QPlatformDrag *QXcbIntegration::drag() const
399{
400 static const bool useSimpleDrag = qEnvironmentVariableIsSet(varName: "QT_XCB_USE_SIMPLE_DRAG");
401 if (Q_UNLIKELY(useSimpleDrag)) { // This is useful for testing purposes
402 static QSimpleDrag *simpleDrag = nullptr;
403 if (!simpleDrag)
404 simpleDrag = new QSimpleDrag();
405 return simpleDrag;
406 }
407
408 return m_connection->drag();
409}
410#endif
411
412QPlatformInputContext *QXcbIntegration::inputContext() const
413{
414 return m_inputContext.data();
415}
416
417#if QT_CONFIG(accessibility)
418QPlatformAccessibility *QXcbIntegration::accessibility() const
419{
420#if !defined(QT_NO_ACCESSIBILITY_ATSPI_BRIDGE)
421 if (!m_accessibility) {
422 Q_ASSERT_X(QCoreApplication::eventDispatcher(), "QXcbIntegration",
423 "Initializing accessibility without event-dispatcher!");
424 m_accessibility.reset(other: new QSpiAccessibleBridge());
425 }
426#endif
427
428 return m_accessibility.data();
429}
430#endif
431
432QPlatformServices *QXcbIntegration::services() const
433{
434 return m_services.data();
435}
436
437QPlatformKeyMapper *QXcbIntegration::keyMapper() const
438{
439 return m_connection->keyboard();
440}
441
442QStringList QXcbIntegration::themeNames() const
443{
444 return QGenericUnixTheme::themeNames();
445}
446
447QPlatformTheme *QXcbIntegration::createPlatformTheme(const QString &name) const
448{
449 return QGenericUnixTheme::createUnixTheme(name);
450}
451
452#define RETURN_VALID_XSETTINGS(key) { \
453 auto value = connection()->primaryScreen()->xSettings()->setting(key); \
454 if (value.isValid()) return value; \
455}
456
457QVariant QXcbIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
458{
459 switch (hint) {
460 case QPlatformIntegration::CursorFlashTime: {
461 bool ok = false;
462 // If cursor blinking is off, returns 0 to keep the cursor awlays display.
463 if (connection()->primaryScreen()->xSettings()->setting(xsNetCursorBlink).toInt(ok: &ok) == 0 && ok)
464 return 0;
465
466 RETURN_VALID_XSETTINGS(xsNetCursorBlinkTime);
467 break;
468 }
469 case QPlatformIntegration::MouseDoubleClickInterval:
470 RETURN_VALID_XSETTINGS(xsNetDoubleClickTime);
471 break;
472 case QPlatformIntegration::MouseDoubleClickDistance:
473 RETURN_VALID_XSETTINGS(xsNetDoubleClickDistance);
474 break;
475 case QPlatformIntegration::KeyboardInputInterval:
476 case QPlatformIntegration::StartDragTime:
477 case QPlatformIntegration::KeyboardAutoRepeatRate:
478 case QPlatformIntegration::PasswordMaskDelay:
479 case QPlatformIntegration::StartDragVelocity:
480 case QPlatformIntegration::UseRtlExtensions:
481 case QPlatformIntegration::PasswordMaskCharacter:
482 case QPlatformIntegration::FlickMaximumVelocity:
483 case QPlatformIntegration::FlickDeceleration:
484 // TODO using various xcb, gnome or KDE settings
485 break; // Not implemented, use defaults
486 case QPlatformIntegration::FlickStartDistance:
487 case QPlatformIntegration::StartDragDistance: {
488 RETURN_VALID_XSETTINGS(xsNetDndDragThreshold);
489 // The default (in QPlatformTheme::defaultThemeHint) is 10 pixels, but
490 // on a high-resolution screen it makes sense to increase it.
491 qreal dpi = 100;
492 if (const QXcbScreen *screen = connection()->primaryScreen()) {
493 if (screen->logicalDpi().first > dpi)
494 dpi = screen->logicalDpi().first;
495 if (screen->logicalDpi().second > dpi)
496 dpi = screen->logicalDpi().second;
497 }
498 return (hint == QPlatformIntegration::FlickStartDistance ? qreal(15) : qreal(10)) * dpi / qreal(100);
499 }
500 case QPlatformIntegration::ShowIsFullScreen:
501 // X11 always has support for windows, but the
502 // window manager could prevent it (e.g. matchbox)
503 return false;
504 case QPlatformIntegration::ReplayMousePressOutsidePopup:
505 return false;
506 default:
507 break;
508 }
509 return QPlatformIntegration::styleHint(hint);
510}
511
512static QString argv0BaseName()
513{
514 QString result;
515 const QStringList arguments = QCoreApplication::arguments();
516 if (!arguments.isEmpty() && !arguments.front().isEmpty()) {
517 result = arguments.front();
518 const int lastSlashPos = result.lastIndexOf(c: u'/');
519 if (lastSlashPos != -1)
520 result.remove(i: 0, len: lastSlashPos + 1);
521 }
522 return result;
523}
524
525static const char resourceNameVar[] = "RESOURCE_NAME";
526
527QByteArray QXcbIntegration::wmClass() const
528{
529 if (m_wmClass.isEmpty()) {
530 // Instance name according to ICCCM 4.1.2.5
531 QString name;
532 if (m_instanceName)
533 name = QString::fromLocal8Bit(ba: m_instanceName);
534 if (name.isEmpty() && qEnvironmentVariableIsSet(varName: resourceNameVar))
535 name = qEnvironmentVariable(varName: resourceNameVar);
536 if (name.isEmpty())
537 name = argv0BaseName();
538
539 // Note: QCoreApplication::applicationName() cannot be called from the QGuiApplication constructor,
540 // hence this delayed initialization.
541 QString className = QCoreApplication::applicationName();
542 if (className.isEmpty()) {
543 className = argv0BaseName();
544 if (!className.isEmpty() && className.at(i: 0).isLower())
545 className[0] = className.at(i: 0).toUpper();
546 }
547
548 if (!name.isEmpty() && !className.isEmpty())
549 m_wmClass = std::move(name).toLocal8Bit() + '\0' + std::move(className).toLocal8Bit() + '\0';
550 }
551 return m_wmClass;
552}
553
554#if QT_CONFIG(xcb_sm)
555QPlatformSessionManager *QXcbIntegration::createPlatformSessionManager(const QString &id, const QString &key) const
556{
557 return new QXcbSessionManager(id, key);
558}
559#endif
560
561void QXcbIntegration::sync()
562{
563 m_connection->sync();
564}
565
566// For QApplication::beep()
567void QXcbIntegration::beep() const
568{
569 QScreen *priScreen = QGuiApplication::primaryScreen();
570 if (!priScreen)
571 return;
572 QPlatformScreen *screen = priScreen->handle();
573 if (!screen)
574 return;
575 xcb_connection_t *connection = static_cast<QXcbScreen *>(screen)->xcb_connection();
576 xcb_bell(c: connection, percent: 0);
577 xcb_flush(c: connection);
578}
579
580bool QXcbIntegration::nativePaintingEnabled() const
581{
582#if QT_CONFIG(xcb_native_painting)
583 static bool enabled = qEnvironmentVariableIsSet("QT_XCB_NATIVE_PAINTING");
584 return enabled;
585#else
586 return false;
587#endif
588}
589
590#if QT_CONFIG(vulkan)
591QPlatformVulkanInstance *QXcbIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const
592{
593 return new QXcbVulkanInstance(instance);
594}
595#endif
596
597void QXcbIntegration::setApplicationBadge(qint64 number)
598{
599 auto unixServices = dynamic_cast<QDesktopUnixServices *>(services());
600 unixServices->setApplicationBadge(number);
601}
602
603QString QXcbUnixServices::portalWindowIdentifier(QWindow *window)
604{
605 return "x11:"_L1 + QString::number(window->winId(), base: 16);
606}
607
608void QXcbUnixServices::registerDBusMenuForWindow(QWindow *window, const QString &service, const QString &path)
609{
610 const QByteArray serviceValue = service.toLatin1();
611 const QByteArray pathValue = path.toLatin1();
612
613 xcb_change_property(c: xcb_connection(),
614 mode: XCB_PROP_MODE_REPLACE, window: window->winId(),
615 property: atom(atom: QXcbAtom::Atom_KDE_NET_WM_APPMENU_SERVICE_NAME),
616 type: XCB_ATOM_STRING, format: 8,
617 data_len: serviceValue.length(),
618 data: serviceValue.constData());
619
620 xcb_change_property(c: xcb_connection(),
621 mode: XCB_PROP_MODE_REPLACE, window: window->winId(),
622 property: atom(atom: QXcbAtom::Atom_KDE_NET_WM_APPMENU_OBJECT_PATH),
623 type: XCB_ATOM_STRING, format: 8,
624 data_len: pathValue.length(),
625 data: pathValue.constData());
626}
627
628void QXcbUnixServices::unregisterDBusMenuForWindow(QWindow *window)
629{
630 xcb_delete_property(c: xcb_connection(), window: window->winId(), property: atom(atom: QXcbAtom::Atom_KDE_NET_WM_APPMENU_SERVICE_NAME));
631 xcb_delete_property(c: xcb_connection(), window: window->winId(), property: atom(atom: QXcbAtom::Atom_KDE_NET_WM_APPMENU_OBJECT_PATH));
632}
633
634QT_END_NAMESPACE
635

source code of qtbase/src/plugins/platforms/xcb/qxcbintegration.cpp