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:
301 case MouseCursorPositioning:
303 case OffscreenSurface:
304 return m_connection->glIntegration() && m_connection->glIntegration()->canCreatePlatformOffscreenSurface();
306 case SwitchableWidgetComposition:
308 return m_connection->glIntegration()
309 && m_connection->glIntegration()->supportsSwitchableWidgetComposition();
312 default:
return QPlatformIntegration::hasCapability(cap);
316QAbstractEventDispatcher *QXcbIntegration::createEventDispatcher()
const
318 return QXcbEventDispatcher::createEventDispatcher(connection());
327void QXcbIntegration::initialize()
329 const auto defaultInputContext =
"compose"_L1;
332 auto icStrs = QPlatformInputContextFactory::requested();
333 if (icStrs.isEmpty())
334 icStrs = { defaultInputContext };
335 m_inputContext.reset(QPlatformInputContextFactory::create(icStrs));
336 if (!m_inputContext && !icStrs.contains(defaultInputContext)
337 && icStrs != QStringList{
"none"_L1})
338 m_inputContext.reset(QPlatformInputContextFactory::create(defaultInputContext));
340 connection()->keyboard()->initialize();
342 auto notifyThemeChanged = [](QXcbVirtualDesktop *,
const QByteArray &,
const QVariant &,
void *) {
343 QWindowSystemInterface::handleThemeChange();
346 auto *xsettings = connection()->primaryScreen()->xSettings();
347 xsettings->registerCallbackForProperty(xsNetCursorBlink, notifyThemeChanged,
this);
348 xsettings->registerCallbackForProperty(xsNetCursorBlinkTime, notifyThemeChanged,
this);
349 xsettings->registerCallbackForProperty(xsNetDoubleClickTime, notifyThemeChanged,
this);
350 xsettings->registerCallbackForProperty(xsNetDoubleClickDistance, notifyThemeChanged,
this);
351 xsettings->registerCallbackForProperty(xsNetDndDragThreshold, notifyThemeChanged,
this);
354void QXcbIntegration::moveToScreen(QWindow *window,
int screen)
360QPlatformFontDatabase *QXcbIntegration::fontDatabase()
const
362 return m_fontDatabase.data();
365QPlatformNativeInterface * QXcbIntegration::nativeInterface()
const
367 return m_nativeInterface.data();
370#ifndef QT_NO_CLIPBOARD
371QPlatformClipboard *QXcbIntegration::clipboard()
const
373 return m_connection->clipboard();
377#if QT_CONFIG(draganddrop)
378#include <private/qsimpledrag_p.h>
379QPlatformDrag *QXcbIntegration::drag()
const
381 static const bool useSimpleDrag = qEnvironmentVariableIsSet(
"QT_XCB_USE_SIMPLE_DRAG");
382 if (Q_UNLIKELY(useSimpleDrag)) {
383 static QSimpleDrag *simpleDrag =
nullptr;
385 simpleDrag =
new QSimpleDrag();
389 return m_connection->drag();
393QPlatformInputContext *QXcbIntegration::inputContext()
const
395 return m_inputContext.data();
398#if QT_CONFIG(accessibility)
399QPlatformAccessibility *QXcbIntegration::accessibility()
const
401#if !defined(QT_NO_ACCESSIBILITY_ATSPI_BRIDGE)
402 if (!m_accessibility) {
403 Q_ASSERT_X(QCoreApplication::eventDispatcher(),
"QXcbIntegration",
404 "Initializing accessibility without event-dispatcher!");
405 m_accessibility.reset(
new QSpiAccessibleBridge());
409 return m_accessibility.data();
413QPlatformServices *QXcbIntegration::services()
const
415 return m_services.data();
418QPlatformKeyMapper *QXcbIntegration::keyMapper()
const
420 return m_connection->keyboard();
423QStringList QXcbIntegration::themeNames()
const
425 return QGenericUnixTheme::themeNames();
428QPlatformTheme *QXcbIntegration::createPlatformTheme(
const QString &name)
const
430 return QGenericUnixTheme::createUnixTheme(name);
433#define RETURN_VALID_XSETTINGS(key) {
434 auto value = connection()->primaryScreen()->xSettings()->setting(key);
435 if (value.isValid()) return value; \
436}
438QVariant QXcbIntegration::styleHint(QPlatformIntegration::StyleHint hint)
const
441 case QPlatformIntegration::CursorFlashTime: {
444 if (connection()->primaryScreen()->xSettings()->setting(xsNetCursorBlink).toInt(&ok) == 0 && ok)
450 case QPlatformIntegration::MouseDoubleClickInterval:
453 case QPlatformIntegration::MouseDoubleClickDistance:
456 case QPlatformIntegration::KeyboardInputInterval:
457 case QPlatformIntegration::StartDragTime:
458 case QPlatformIntegration::KeyboardAutoRepeatRate:
459 case QPlatformIntegration::PasswordMaskDelay:
460 case QPlatformIntegration::StartDragVelocity:
461 case QPlatformIntegration::UseRtlExtensions:
462 case QPlatformIntegration::PasswordMaskCharacter:
463 case QPlatformIntegration::FlickMaximumVelocity:
464 case QPlatformIntegration::FlickDeceleration:
467 case QPlatformIntegration::FlickStartDistance:
468 case QPlatformIntegration::StartDragDistance: {
473 if (
const QXcbScreen *screen = connection()->primaryScreen()) {
474 if (screen->logicalDpi().first > dpi)
475 dpi = screen->logicalDpi().first;
476 if (screen->logicalDpi().second > dpi)
477 dpi = screen->logicalDpi().second;
479 return (hint == QPlatformIntegration::FlickStartDistance ? qreal(15) : qreal(10)) * dpi / qreal(100);
481 case QPlatformIntegration::ShowIsFullScreen:
485 case QPlatformIntegration::ReplayMousePressOutsidePopup:
490 return QPlatformIntegration::styleHint(hint);
496 const QStringList arguments = QCoreApplication::arguments();
497 if (!arguments.isEmpty() && !arguments.front().isEmpty()) {
498 result = arguments.front();
499 const int lastSlashPos = result.lastIndexOf(u'/');
500 if (lastSlashPos != -1)
501 result.remove(0, lastSlashPos + 1);
508QByteArray QXcbIntegration::wmClass()
const
510 if (m_wmClass.isEmpty()) {
514 name = QString::fromLocal8Bit(m_instanceName);
515 if (name.isEmpty() && qEnvironmentVariableIsSet(resourceNameVar))
516 name = qEnvironmentVariable(resourceNameVar);
518 name = argv0BaseName();
522 QString className = QCoreApplication::applicationName();
523 if (className.isEmpty()) {
524 className = argv0BaseName();
525 if (!className.isEmpty() && className.at(0).isLower())
526 className[0] = className.at(0).toUpper();
529 if (!name.isEmpty() && !className.isEmpty())
530 m_wmClass = std::move(name).toLocal8Bit() +
'\0' + std::move(className).toLocal8Bit() +
'\0';
536QPlatformSessionManager *QXcbIntegration::createPlatformSessionManager(
const QString &id,
const QString &key)
const
538 return new QXcbSessionManager(id, key);
542void QXcbIntegration::sync()
544 m_connection->sync();
548void QXcbIntegration::beep()
const
550 QScreen *priScreen = QGuiApplication::primaryScreen();
553 QPlatformScreen *screen = priScreen->handle();
556 xcb_connection_t *connection =
static_cast<QXcbScreen *>(screen)->xcb_connection();
557 xcb_bell(connection, 0);
558 xcb_flush(connection);
562QPlatformVulkanInstance *QXcbIntegration::createPlatformVulkanInstance(QVulkanInstance *instance)
const
564 return new QXcbVulkanInstance(instance);
568void QXcbIntegration::setApplicationBadge(qint64 number)
570 auto unixServices =
dynamic_cast<QDesktopUnixServices *>(services());
571 unixServices->setApplicationBadge(number);
576 return "x11:"_L1 + QString::number(window->winId(), 16);
581 const QByteArray serviceValue = service.toLatin1();
582 const QByteArray pathValue = path.toLatin1();
584 xcb_change_property(xcb_connection(),
585 XCB_PROP_MODE_REPLACE, window->winId(),
586 atom(QXcbAtom::Atom_KDE_NET_WM_APPMENU_SERVICE_NAME),
588 serviceValue.length(),
589 serviceValue.constData());
591 xcb_change_property(xcb_connection(),
592 XCB_PROP_MODE_REPLACE, window->winId(),
593 atom(QXcbAtom::Atom_KDE_NET_WM_APPMENU_OBJECT_PATH),
596 pathValue.constData());
601 xcb_delete_property(xcb_connection(), window->winId(), atom(QXcbAtom::Atom_KDE_NET_WM_APPMENU_SERVICE_NAME));
602 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[]