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:
303 case SwitchableWidgetComposition:
305 return m_connection->glIntegration()
306 && m_connection->glIntegration()->supportsSwitchableWidgetComposition();
309 default:
return QPlatformIntegration::hasCapability(cap);
313QAbstractEventDispatcher *QXcbIntegration::createEventDispatcher()
const
315 return QXcbEventDispatcher::createEventDispatcher(connection());
324void QXcbIntegration::initialize()
326 const auto defaultInputContext =
"compose"_L1;
329 auto icStrs = QPlatformInputContextFactory::requested();
330 if (icStrs.isEmpty())
331 icStrs = { defaultInputContext };
332 m_inputContext.reset(QPlatformInputContextFactory::create(icStrs));
333 if (!m_inputContext && !icStrs.contains(defaultInputContext)
334 && icStrs != QStringList{
"none"_L1})
335 m_inputContext.reset(QPlatformInputContextFactory::create(defaultInputContext));
337 connection()->keyboard()->initialize();
339 auto notifyThemeChanged = [](QXcbVirtualDesktop *,
const QByteArray &,
const QVariant &,
void *) {
340 QWindowSystemInterface::handleThemeChange();
343 auto *xsettings = connection()->primaryScreen()->xSettings();
344 xsettings->registerCallbackForProperty(xsNetCursorBlink, notifyThemeChanged,
this);
345 xsettings->registerCallbackForProperty(xsNetCursorBlinkTime, notifyThemeChanged,
this);
346 xsettings->registerCallbackForProperty(xsNetDoubleClickTime, notifyThemeChanged,
this);
347 xsettings->registerCallbackForProperty(xsNetDoubleClickDistance, notifyThemeChanged,
this);
348 xsettings->registerCallbackForProperty(xsNetDndDragThreshold, notifyThemeChanged,
this);
351void QXcbIntegration::moveToScreen(QWindow *window,
int screen)
357QPlatformFontDatabase *QXcbIntegration::fontDatabase()
const
359 return m_fontDatabase.data();
362QPlatformNativeInterface * QXcbIntegration::nativeInterface()
const
364 return m_nativeInterface.data();
367#ifndef QT_NO_CLIPBOARD
368QPlatformClipboard *QXcbIntegration::clipboard()
const
370 return m_connection->clipboard();
374#if QT_CONFIG(draganddrop)
375#include <private/qsimpledrag_p.h>
376QPlatformDrag *QXcbIntegration::drag()
const
378 static const bool useSimpleDrag = qEnvironmentVariableIsSet(
"QT_XCB_USE_SIMPLE_DRAG");
379 if (Q_UNLIKELY(useSimpleDrag)) {
380 static QSimpleDrag *simpleDrag =
nullptr;
382 simpleDrag =
new QSimpleDrag();
386 return m_connection->drag();
390QPlatformInputContext *QXcbIntegration::inputContext()
const
392 return m_inputContext.data();
395#if QT_CONFIG(accessibility)
396QPlatformAccessibility *QXcbIntegration::accessibility()
const
398#if !defined(QT_NO_ACCESSIBILITY_ATSPI_BRIDGE)
399 if (!m_accessibility) {
400 Q_ASSERT_X(QCoreApplication::eventDispatcher(),
"QXcbIntegration",
401 "Initializing accessibility without event-dispatcher!");
402 m_accessibility.reset(
new QSpiAccessibleBridge());
406 return m_accessibility.data();
410QPlatformServices *QXcbIntegration::services()
const
412 return m_services.data();
415QPlatformKeyMapper *QXcbIntegration::keyMapper()
const
417 return m_connection->keyboard();
420QStringList QXcbIntegration::themeNames()
const
422 return QGenericUnixTheme::themeNames();
425QPlatformTheme *QXcbIntegration::createPlatformTheme(
const QString &name)
const
427 return QGenericUnixTheme::createUnixTheme(name);
430#define RETURN_VALID_XSETTINGS(key) {
431 auto value = connection()->primaryScreen()->xSettings()->setting(key);
432 if (value.isValid()) return value; \
433}
435QVariant QXcbIntegration::styleHint(QPlatformIntegration::StyleHint hint)
const
438 case QPlatformIntegration::CursorFlashTime: {
441 if (connection()->primaryScreen()->xSettings()->setting(xsNetCursorBlink).toInt(&ok) == 0 && ok)
447 case QPlatformIntegration::MouseDoubleClickInterval:
450 case QPlatformIntegration::MouseDoubleClickDistance:
453 case QPlatformIntegration::KeyboardInputInterval:
454 case QPlatformIntegration::StartDragTime:
455 case QPlatformIntegration::KeyboardAutoRepeatRate:
456 case QPlatformIntegration::PasswordMaskDelay:
457 case QPlatformIntegration::StartDragVelocity:
458 case QPlatformIntegration::UseRtlExtensions:
459 case QPlatformIntegration::PasswordMaskCharacter:
460 case QPlatformIntegration::FlickMaximumVelocity:
461 case QPlatformIntegration::FlickDeceleration:
464 case QPlatformIntegration::FlickStartDistance:
465 case QPlatformIntegration::StartDragDistance: {
470 if (
const QXcbScreen *screen = connection()->primaryScreen()) {
471 if (screen->logicalDpi().first > dpi)
472 dpi = screen->logicalDpi().first;
473 if (screen->logicalDpi().second > dpi)
474 dpi = screen->logicalDpi().second;
476 return (hint == QPlatformIntegration::FlickStartDistance ? qreal(15) : qreal(10)) * dpi / qreal(100);
478 case QPlatformIntegration::ShowIsFullScreen:
482 case QPlatformIntegration::ReplayMousePressOutsidePopup:
487 return QPlatformIntegration::styleHint(hint);
493 const QStringList arguments = QCoreApplication::arguments();
494 if (!arguments.isEmpty() && !arguments.front().isEmpty()) {
495 result = arguments.front();
496 const int lastSlashPos = result.lastIndexOf(u'/');
497 if (lastSlashPos != -1)
498 result.remove(0, lastSlashPos + 1);
505QByteArray QXcbIntegration::wmClass()
const
507 if (m_wmClass.isEmpty()) {
511 name = QString::fromLocal8Bit(m_instanceName);
512 if (name.isEmpty() && qEnvironmentVariableIsSet(resourceNameVar))
513 name = qEnvironmentVariable(resourceNameVar);
515 name = argv0BaseName();
519 QString className = QCoreApplication::applicationName();
520 if (className.isEmpty()) {
521 className = argv0BaseName();
522 if (!className.isEmpty() && className.at(0).isLower())
523 className[0] = className.at(0).toUpper();
526 if (!name.isEmpty() && !className.isEmpty())
527 m_wmClass = std::move(name).toLocal8Bit() +
'\0' + std::move(className).toLocal8Bit() +
'\0';
533QPlatformSessionManager *QXcbIntegration::createPlatformSessionManager(
const QString &id,
const QString &key)
const
535 return new QXcbSessionManager(id, key);
539void QXcbIntegration::sync()
541 m_connection->sync();
545void QXcbIntegration::beep()
const
547 QScreen *priScreen = QGuiApplication::primaryScreen();
550 QPlatformScreen *screen = priScreen->handle();
553 xcb_connection_t *connection =
static_cast<QXcbScreen *>(screen)->xcb_connection();
554 xcb_bell(connection, 0);
555 xcb_flush(connection);
559QPlatformVulkanInstance *QXcbIntegration::createPlatformVulkanInstance(QVulkanInstance *instance)
const
561 return new QXcbVulkanInstance(instance);
565void QXcbIntegration::setApplicationBadge(qint64 number)
567 auto unixServices =
dynamic_cast<QDesktopUnixServices *>(services());
568 unixServices->setApplicationBadge(number);
573 return "x11:"_L1 + QString::number(window->winId(), 16);
578 const QByteArray serviceValue = service.toLatin1();
579 const QByteArray pathValue = path.toLatin1();
581 xcb_change_property(xcb_connection(),
582 XCB_PROP_MODE_REPLACE, window->winId(),
585 serviceValue.length(),
586 serviceValue.constData());
588 xcb_change_property(xcb_connection(),
589 XCB_PROP_MODE_REPLACE, window->winId(),
593 pathValue.constData());
@ Atom_KDE_NET_WM_APPMENU_SERVICE_NAME
@ 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[]