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 OffscreenSurface:
303 return m_connection->glIntegration() && m_connection->glIntegration()->canCreatePlatformOffscreenSurface();
305 case SwitchableWidgetComposition:
307 return m_connection->glIntegration()
308 && m_connection->glIntegration()->supportsSwitchableWidgetComposition();
311 default:
return QPlatformIntegration::hasCapability(cap);
315QAbstractEventDispatcher *QXcbIntegration::createEventDispatcher()
const
317 return QXcbEventDispatcher::createEventDispatcher(connection());
326void QXcbIntegration::initialize()
328 const auto defaultInputContext =
"compose"_L1;
331 auto icStrs = QPlatformInputContextFactory::requested();
332 if (icStrs.isEmpty())
333 icStrs = { defaultInputContext };
334 m_inputContext.reset(QPlatformInputContextFactory::create(icStrs));
335 if (!m_inputContext && !icStrs.contains(defaultInputContext)
336 && icStrs != QStringList{
"none"_L1})
337 m_inputContext.reset(QPlatformInputContextFactory::create(defaultInputContext));
339 connection()->keyboard()->initialize();
341 auto notifyThemeChanged = [](QXcbVirtualDesktop *,
const QByteArray &,
const QVariant &,
void *) {
342 QWindowSystemInterface::handleThemeChange();
345 auto *xsettings = connection()->primaryScreen()->xSettings();
346 xsettings->registerCallbackForProperty(xsNetCursorBlink, notifyThemeChanged,
this);
347 xsettings->registerCallbackForProperty(xsNetCursorBlinkTime, notifyThemeChanged,
this);
348 xsettings->registerCallbackForProperty(xsNetDoubleClickTime, notifyThemeChanged,
this);
349 xsettings->registerCallbackForProperty(xsNetDoubleClickDistance, notifyThemeChanged,
this);
350 xsettings->registerCallbackForProperty(xsNetDndDragThreshold, notifyThemeChanged,
this);
353void QXcbIntegration::moveToScreen(QWindow *window,
int screen)
359QPlatformFontDatabase *QXcbIntegration::fontDatabase()
const
361 return m_fontDatabase.data();
364QPlatformNativeInterface * QXcbIntegration::nativeInterface()
const
366 return m_nativeInterface.data();
369#ifndef QT_NO_CLIPBOARD
370QPlatformClipboard *QXcbIntegration::clipboard()
const
372 return m_connection->clipboard();
376#if QT_CONFIG(draganddrop)
377#include <private/qsimpledrag_p.h>
378QPlatformDrag *QXcbIntegration::drag()
const
380 static const bool useSimpleDrag = qEnvironmentVariableIsSet(
"QT_XCB_USE_SIMPLE_DRAG");
381 if (Q_UNLIKELY(useSimpleDrag)) {
382 static QSimpleDrag *simpleDrag =
nullptr;
384 simpleDrag =
new QSimpleDrag();
388 return m_connection->drag();
392QPlatformInputContext *QXcbIntegration::inputContext()
const
394 return m_inputContext.data();
397#if QT_CONFIG(accessibility)
398QPlatformAccessibility *QXcbIntegration::accessibility()
const
400#if !defined(QT_NO_ACCESSIBILITY_ATSPI_BRIDGE)
401 if (!m_accessibility) {
402 Q_ASSERT_X(QCoreApplication::eventDispatcher(),
"QXcbIntegration",
403 "Initializing accessibility without event-dispatcher!");
404 m_accessibility.reset(
new QSpiAccessibleBridge());
408 return m_accessibility.data();
412QPlatformServices *QXcbIntegration::services()
const
414 return m_services.data();
417QPlatformKeyMapper *QXcbIntegration::keyMapper()
const
419 return m_connection->keyboard();
422QStringList QXcbIntegration::themeNames()
const
424 return QGenericUnixTheme::themeNames();
427QPlatformTheme *QXcbIntegration::createPlatformTheme(
const QString &name)
const
429 return QGenericUnixTheme::createUnixTheme(name);
432#define RETURN_VALID_XSETTINGS(key) {
433 auto value = connection()->primaryScreen()->xSettings()->setting(key);
434 if (value.isValid()) return value; \
435}
437QVariant QXcbIntegration::styleHint(QPlatformIntegration::StyleHint hint)
const
440 case QPlatformIntegration::CursorFlashTime: {
443 if (connection()->primaryScreen()->xSettings()->setting(xsNetCursorBlink).toInt(&ok) == 0 && ok)
449 case QPlatformIntegration::MouseDoubleClickInterval:
452 case QPlatformIntegration::MouseDoubleClickDistance:
455 case QPlatformIntegration::KeyboardInputInterval:
456 case QPlatformIntegration::StartDragTime:
457 case QPlatformIntegration::KeyboardAutoRepeatRate:
458 case QPlatformIntegration::PasswordMaskDelay:
459 case QPlatformIntegration::StartDragVelocity:
460 case QPlatformIntegration::UseRtlExtensions:
461 case QPlatformIntegration::PasswordMaskCharacter:
462 case QPlatformIntegration::FlickMaximumVelocity:
463 case QPlatformIntegration::FlickDeceleration:
466 case QPlatformIntegration::FlickStartDistance:
467 case QPlatformIntegration::StartDragDistance: {
472 if (
const QXcbScreen *screen = connection()->primaryScreen()) {
473 if (screen->logicalDpi().first > dpi)
474 dpi = screen->logicalDpi().first;
475 if (screen->logicalDpi().second > dpi)
476 dpi = screen->logicalDpi().second;
478 return (hint == QPlatformIntegration::FlickStartDistance ? qreal(15) : qreal(10)) * dpi / qreal(100);
480 case QPlatformIntegration::ShowIsFullScreen:
484 case QPlatformIntegration::ReplayMousePressOutsidePopup:
489 return QPlatformIntegration::styleHint(hint);
495 const QStringList arguments = QCoreApplication::arguments();
496 if (!arguments.isEmpty() && !arguments.front().isEmpty()) {
497 result = arguments.front();
498 const int lastSlashPos = result.lastIndexOf(u'/');
499 if (lastSlashPos != -1)
500 result.remove(0, lastSlashPos + 1);
507QByteArray QXcbIntegration::wmClass()
const
509 if (m_wmClass.isEmpty()) {
513 name = QString::fromLocal8Bit(m_instanceName);
514 if (name.isEmpty() && qEnvironmentVariableIsSet(resourceNameVar))
515 name = qEnvironmentVariable(resourceNameVar);
517 name = argv0BaseName();
521 QString className = QCoreApplication::applicationName();
522 if (className.isEmpty()) {
523 className = argv0BaseName();
524 if (!className.isEmpty() && className.at(0).isLower())
525 className[0] = className.at(0).toUpper();
528 if (!name.isEmpty() && !className.isEmpty())
529 m_wmClass = std::move(name).toLocal8Bit() +
'\0' + std::move(className).toLocal8Bit() +
'\0';
535QPlatformSessionManager *QXcbIntegration::createPlatformSessionManager(
const QString &id,
const QString &key)
const
537 return new QXcbSessionManager(id, key);
541void QXcbIntegration::sync()
543 m_connection->sync();
547void QXcbIntegration::beep()
const
549 QScreen *priScreen = QGuiApplication::primaryScreen();
552 QPlatformScreen *screen = priScreen->handle();
555 xcb_connection_t *connection =
static_cast<QXcbScreen *>(screen)->xcb_connection();
556 xcb_bell(connection, 0);
557 xcb_flush(connection);
561QPlatformVulkanInstance *QXcbIntegration::createPlatformVulkanInstance(QVulkanInstance *instance)
const
563 return new QXcbVulkanInstance(instance);
567void QXcbIntegration::setApplicationBadge(qint64 number)
569 auto unixServices =
dynamic_cast<QDesktopUnixServices *>(services());
570 unixServices->setApplicationBadge(number);
575 return "x11:"_L1 + QString::number(window->winId(), 16);
580 const QByteArray serviceValue = service.toLatin1();
581 const QByteArray pathValue = path.toLatin1();
583 xcb_change_property(xcb_connection(),
584 XCB_PROP_MODE_REPLACE, window->winId(),
587 serviceValue.length(),
588 serviceValue.constData());
590 xcb_change_property(xcb_connection(),
591 XCB_PROP_MODE_REPLACE, window->winId(),
595 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[]