16#if QT_CONFIG(draganddrop)
21#ifndef QT_NO_SESSIONMANAGER
28#include <QtGui/private/qgenericunixfontdatabase_p.h>
29#include <QtGui/private/qdesktopunixservices_p.h>
33#include <QtGui/private/qguiapplication_p.h>
35#if QT_CONFIG(xcb_xlib)
41#include <qpa/qplatforminputcontextfactory_p.h>
42#include <private/qgenericunixtheme_p.h>
44#include <private/qkdetheme_p.h>
46#include <qpa/qplatforminputcontext.h>
48#include <QtGui/QOpenGLContext>
49#include <QtGui/QScreen>
50#include <QtGui/QOffscreenSurface>
51#if QT_CONFIG(accessibility)
52#include <qpa/qplatformaccessibility.h>
53#if QT_CONFIG(accessibility_atspi_bridge)
54#include <QtGui/private/qspiaccessiblebridge_p.h>
58#include <QtCore/QFileInfo>
61#include "qxcbvulkaninstance.h"
62#include "qxcbvulkanwindow.h"
67using namespace Qt::StringLiterals;
73#if defined(Q_OS_LINUX)
74 const QString parentProc =
"/proc/"_L1 + QString::number(getppid());
75 const QFileInfo parentProcExe(parentProc +
"/exe"_L1);
76 if (parentProcExe.isSymLink())
77 return parentProcExe.symLinkTarget().endsWith(
"/gdb"_L1);
78 QFile f(parentProc +
"/cmdline"_L1);
79 if (!f.open(QIODevice::ReadOnly))
83 while (f.getChar(&c) && c) {
104QXcbIntegration *QXcbIntegration::m_instance =
nullptr;
106QXcbIntegration::QXcbIntegration(
const QStringList ¶meters,
int &argc,
char **argv)
107 : m_services(
new QXcbUnixServices)
108 , m_instanceName(
nullptr)
110 , m_defaultVisualId(UINT_MAX)
112 Q_UNUSED(parameters);
115 qApp->setAttribute(Qt::AA_CompressHighFrequencyEvents,
true);
117 qRegisterMetaType<QXcbWindow*>();
118#if QT_CONFIG(xcb_xlib)
121 m_nativeInterface.reset(
new QXcbNativeInterface);
124 const char *displayName =
nullptr;
125 bool noGrabArg =
false;
126 bool doGrabArg =
false;
129 for (
int i = 1; i < argc; i++) {
130 QByteArray arg(argv[i]);
131 if (arg.startsWith(
"--"))
133 if (arg ==
"-display" && i < argc - 1)
134 displayName = argv[++i];
135 else if (arg ==
"-name" && i < argc - 1)
136 m_instanceName = argv[++i];
137 else if (arg ==
"-nograb")
139 else if (arg ==
"-dograb")
141 else if (arg ==
"-visual" && i < argc - 1) {
143 m_defaultVisualId = QByteArray(argv[++i]).toUInt(&ok, 0);
145 m_defaultVisualId = UINT_MAX;
153 bool underDebugger = runningUnderDebugger();
154 if (noGrabArg && doGrabArg && underDebugger) {
155 qWarning(
"Both -nograb and -dograb command line arguments specified. Please pick one. -nograb takes precedence");
159 if (!noGrabArg && !doGrabArg && underDebugger) {
160 qCDebug(lcQpaXcb,
"Qt: gdb: -nograb added to command-line options.\n"
161 "\t Use the -dograb option to enforce grabbing.");
163 m_canGrab = (!underDebugger && !noGrabArg) || (underDebugger && doGrabArg);
165 static bool canNotGrabEnv = qEnvironmentVariableIsSet(
"QT_XCB_NO_GRAB_SERVER");
169 m_connection =
new QXcbConnection(m_nativeInterface.data(), m_canGrab, m_defaultVisualId, displayName);
170 if (!m_connection->isConnected()) {
172 m_connection =
nullptr;
175 m_services->setConnection(m_connection);
177 m_fontDatabase.reset(
new QGenericUnixFontDatabase());
180QXcbIntegration::~QXcbIntegration()
183 m_connection =
nullptr;
184 m_instance =
nullptr;
187QPlatformPixmap *QXcbIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type)
const
189 return QPlatformIntegration::createPlatformPixmap(type);
192QPlatformWindow *QXcbIntegration::createPlatformWindow(QWindow *window)
const
194 QXcbGlIntegration *glIntegration =
nullptr;
195 const bool isTrayIconWindow = QXcbWindow::isTrayIconWindow(window);
196 if (!isTrayIconWindow) {
197 if (window->supportsOpenGL()) {
198 glIntegration = connection()->glIntegration();
200 QXcbWindow *xcbWindow = glIntegration->createWindow(window);
205 }
else if (window->surfaceType() == QSurface::VulkanSurface) {
206 QXcbWindow *xcbWindow =
new QXcbVulkanWindow(window);
213 Q_ASSERT(isTrayIconWindow || !window->supportsOpenGL()
214 || (!glIntegration && window->surfaceType() == QSurface::RasterSurface));
215 QXcbWindow *xcbWindow =
new QXcbWindow(window);
220QPlatformWindow *QXcbIntegration::createForeignWindow(QWindow *window, WId nativeHandle)
const
222 return new QXcbForeignWindow(window, nativeHandle);
226QPlatformOpenGLContext *QXcbIntegration::createPlatformOpenGLContext(QOpenGLContext *context)
const
228 QXcbGlIntegration *glIntegration = m_connection->glIntegration();
229 if (!glIntegration) {
230 qWarning(
"QXcbIntegration: Cannot create platform OpenGL context, neither GLX nor EGL are enabled");
233 return glIntegration->createPlatformOpenGLContext(context);
236# if QT_CONFIG(xcb_glx_plugin)
237QOpenGLContext *QXcbIntegration::createOpenGLContext(GLXContext context,
void *visualInfo, QOpenGLContext *shareContext)
const
239 using namespace QNativeInterface::Private;
240 if (
auto *glxIntegration =
dynamic_cast<QGLXIntegration*>(m_connection->glIntegration()))
241 return glxIntegration->createOpenGLContext(context, visualInfo, shareContext);
248QOpenGLContext *QXcbIntegration::createOpenGLContext(EGLContext context, EGLDisplay display, QOpenGLContext *shareContext)
const
250 using namespace QNativeInterface::Private;
251 if (
auto *eglIntegration =
dynamic_cast<QEGLIntegration*>(m_connection->glIntegration()))
252 return eglIntegration->createOpenGLContext(context, display, shareContext);
260QPlatformBackingStore *QXcbIntegration::createPlatformBackingStore(QWindow *window)
const
262 QPlatformBackingStore *backingStore =
nullptr;
264 const bool isTrayIconWindow = QXcbWindow::isTrayIconWindow(window);
265 if (isTrayIconWindow) {
266 backingStore =
new QXcbSystemTrayBackingStore(window);
268 backingStore =
new QXcbBackingStore(window);
270 Q_ASSERT(backingStore);
274QPlatformOffscreenSurface *QXcbIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface)
const
276 QXcbScreen *screen =
static_cast<QXcbScreen *>(surface->screen()->handle());
277 QXcbGlIntegration *glIntegration = screen->connection()->glIntegration();
278 if (!glIntegration) {
279 qWarning(
"QXcbIntegration: Cannot create platform offscreen surface, neither GLX nor EGL are enabled");
282 return glIntegration->createPlatformOffscreenSurface(surface);
285bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap)
const
291 if (
const auto *integration = connection()->glIntegration())
292 return cap != ThreadedOpenGL || integration->supportsThreadedOpenGL();
296 case ThreadedPixmaps:
298 case MultipleWindows:
302 case MouseCursorPositioning:
304 case OffscreenSurface:
305 return m_connection->glIntegration() && m_connection->glIntegration()->canCreatePlatformOffscreenSurface();
307 case SwitchableWidgetComposition:
309 return m_connection->glIntegration()
310 && m_connection->glIntegration()->supportsSwitchableWidgetComposition();
313 default:
return QPlatformIntegration::hasCapability(cap);
317QAbstractEventDispatcher *QXcbIntegration::createEventDispatcher()
const
319 return QXcbEventDispatcher::createEventDispatcher(connection());
328void QXcbIntegration::initialize()
330 const auto defaultInputContext =
"compose"_L1;
333 auto icStrs = QPlatformInputContextFactory::requested();
334 if (icStrs.isEmpty())
335 icStrs = { defaultInputContext };
336 m_inputContext.reset(QPlatformInputContextFactory::create(icStrs));
337 if (!m_inputContext && !icStrs.contains(defaultInputContext)
338 && icStrs != QStringList{
"none"_L1})
339 m_inputContext.reset(QPlatformInputContextFactory::create(defaultInputContext));
341 connection()->keyboard()->initialize();
343 auto notifyThemeChanged = [](QXcbVirtualDesktop *,
const QByteArray &,
const QVariant &,
void *) {
344 QWindowSystemInterface::handleThemeChange();
347 auto *xsettings = connection()->primaryScreen()->xSettings();
348 xsettings->registerCallbackForProperty(xsNetCursorBlink, notifyThemeChanged,
this);
349 xsettings->registerCallbackForProperty(xsNetCursorBlinkTime, notifyThemeChanged,
this);
350 xsettings->registerCallbackForProperty(xsNetDoubleClickTime, notifyThemeChanged,
this);
351 xsettings->registerCallbackForProperty(xsNetDoubleClickDistance, notifyThemeChanged,
this);
352 xsettings->registerCallbackForProperty(xsNetDndDragThreshold, notifyThemeChanged,
this);
355void QXcbIntegration::moveToScreen(QWindow *window,
int screen)
361QPlatformFontDatabase *QXcbIntegration::fontDatabase()
const
363 return m_fontDatabase.data();
366QPlatformNativeInterface * QXcbIntegration::nativeInterface()
const
368 return m_nativeInterface.data();
371#ifndef QT_NO_CLIPBOARD
372QPlatformClipboard *QXcbIntegration::clipboard()
const
374 return m_connection->clipboard();
378#if QT_CONFIG(draganddrop)
379#include <private/qsimpledrag_p.h>
380QPlatformDrag *QXcbIntegration::drag()
const
382 static const bool useSimpleDrag = qEnvironmentVariableIsSet(
"QT_XCB_USE_SIMPLE_DRAG");
383 if (Q_UNLIKELY(useSimpleDrag)) {
384 static QSimpleDrag *simpleDrag =
nullptr;
386 simpleDrag =
new QSimpleDrag();
390 return m_connection->drag();
394QPlatformInputContext *QXcbIntegration::inputContext()
const
396 return m_inputContext.data();
399#if QT_CONFIG(accessibility)
400QPlatformAccessibility *QXcbIntegration::accessibility()
const
402#if !defined(QT_NO_ACCESSIBILITY_ATSPI_BRIDGE)
403 if (!m_accessibility) {
404 Q_ASSERT_X(QCoreApplication::eventDispatcher(),
"QXcbIntegration",
405 "Initializing accessibility without event-dispatcher!");
406 m_accessibility.reset(
new QSpiAccessibleBridge());
410 return m_accessibility.data();
414QPlatformServices *QXcbIntegration::services()
const
416 return m_services.data();
419QPlatformKeyMapper *QXcbIntegration::keyMapper()
const
421 return m_connection->keyboard();
424QStringList QXcbIntegration::themeNames()
const
426 return QGenericUnixTheme::themeNames();
429QPlatformTheme *QXcbIntegration::createPlatformTheme(
const QString &name)
const
431 return QGenericUnixTheme::createUnixTheme(name);
434#define RETURN_VALID_XSETTINGS(key) {
435 auto value = connection()->primaryScreen()->xSettings()->setting(key);
436 if (value.isValid()) return value; \
437}
439QVariant QXcbIntegration::styleHint(QPlatformIntegration::StyleHint hint)
const
442 case QPlatformIntegration::CursorFlashTime: {
445 if (connection()->primaryScreen()->xSettings()->setting(xsNetCursorBlink).toInt(&ok) == 0 && ok)
451 case QPlatformIntegration::MouseDoubleClickInterval:
454 case QPlatformIntegration::MouseDoubleClickDistance:
457 case QPlatformIntegration::KeyboardInputInterval:
458 case QPlatformIntegration::StartDragTime:
459 case QPlatformIntegration::KeyboardAutoRepeatRate:
460 case QPlatformIntegration::PasswordMaskDelay:
461 case QPlatformIntegration::StartDragVelocity:
462 case QPlatformIntegration::UseRtlExtensions:
463 case QPlatformIntegration::PasswordMaskCharacter:
464 case QPlatformIntegration::FlickMaximumVelocity:
465 case QPlatformIntegration::FlickDeceleration:
468 case QPlatformIntegration::FlickStartDistance:
469 case QPlatformIntegration::StartDragDistance: {
474 if (
const QXcbScreen *screen = connection()->primaryScreen()) {
475 if (screen->logicalDpi().first > dpi)
476 dpi = screen->logicalDpi().first;
477 if (screen->logicalDpi().second > dpi)
478 dpi = screen->logicalDpi().second;
480 return (hint == QPlatformIntegration::FlickStartDistance ? qreal(15) : qreal(10)) * dpi / qreal(100);
482 case QPlatformIntegration::ShowIsFullScreen:
486 case QPlatformIntegration::ReplayMousePressOutsidePopup:
491 return QPlatformIntegration::styleHint(hint);
497 const QStringList arguments = QCoreApplication::arguments();
498 if (!arguments.isEmpty() && !arguments.front().isEmpty()) {
499 result = arguments.front();
500 const int lastSlashPos = result.lastIndexOf(u'/');
501 if (lastSlashPos != -1)
502 result.remove(0, lastSlashPos + 1);
509QByteArray QXcbIntegration::wmClass()
const
511 if (m_wmClass.isEmpty()) {
515 name = QString::fromLocal8Bit(m_instanceName);
516 if (name.isEmpty() && qEnvironmentVariableIsSet(resourceNameVar))
517 name = qEnvironmentVariable(resourceNameVar);
519 name = argv0BaseName();
523 QString className = QCoreApplication::applicationName();
524 if (className.isEmpty()) {
525 className = argv0BaseName();
526 if (!className.isEmpty() && className.at(0).isLower())
527 className[0] = className.at(0).toUpper();
530 if (!name.isEmpty() && !className.isEmpty())
531 m_wmClass = std::move(name).toLocal8Bit() +
'\0' + std::move(className).toLocal8Bit() +
'\0';
537QPlatformSessionManager *QXcbIntegration::createPlatformSessionManager(
const QString &id,
const QString &key)
const
539 return new QXcbSessionManager(id, key);
543void QXcbIntegration::sync()
545 m_connection->sync();
549void QXcbIntegration::beep()
const
551 QScreen *priScreen = QGuiApplication::primaryScreen();
554 QPlatformScreen *screen = priScreen->handle();
557 xcb_connection_t *connection =
static_cast<QXcbScreen *>(screen)->xcb_connection();
558 xcb_bell(connection, 0);
559 xcb_flush(connection);
563QPlatformVulkanInstance *QXcbIntegration::createPlatformVulkanInstance(QVulkanInstance *instance)
const
565 return new QXcbVulkanInstance(instance);
569void QXcbIntegration::setApplicationBadge(qint64 number)
571 auto unixServices =
dynamic_cast<QDesktopUnixServices *>(services());
572 unixServices->setApplicationBadge(number);
577 return "x11:"_L1 + QString::number(window->winId(), 16);
582 const QByteArray serviceValue = service.toLatin1();
583 const QByteArray pathValue = path.toLatin1();
585 xcb_change_property(xcb_connection(),
586 XCB_PROP_MODE_REPLACE, window->winId(),
587 atom(QXcbAtom::Atom_KDE_NET_WM_APPMENU_SERVICE_NAME),
589 serviceValue.length(),
590 serviceValue.constData());
592 xcb_change_property(xcb_connection(),
593 XCB_PROP_MODE_REPLACE, window->winId(),
594 atom(QXcbAtom::Atom_KDE_NET_WM_APPMENU_OBJECT_PATH),
597 pathValue.constData());
602 xcb_delete_property(xcb_connection(), window->winId(), atom(QXcbAtom::Atom_KDE_NET_WM_APPMENU_SERVICE_NAME));
603 xcb_delete_property(xcb_connection(), window->winId(), atom(QXcbAtom::Atom_KDE_NET_WM_APPMENU_OBJECT_PATH));
QString portalWindowIdentifier(QWindow *window) override
void unregisterDBusMenuForWindow(QWindow *window) override
void registerDBusMenuForWindow(QWindow *window, const QString &service, const QString &path) override
Combined button and popup list for selecting options.
static const auto xsNetDoubleClickDistance
static QString argv0BaseName()
static const auto xsNetCursorBlink
static const auto xsNetDoubleClickTime
static bool runningUnderDebugger()
static const auto xsNetDndDragThreshold
static const auto xsNetCursorBlinkTime
#define RETURN_VALID_XSETTINGS(key)
static const char resourceNameVar[]