From 81addcc1edddaefa19080ad90c27df49f92b53a6 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 17 Jul 2013 14:39:42 +0200 Subject: XCB: Set WM_CLASS. Set the instance name and class name of the application windows. Task-number: QTBUG-29396 Change-Id: Ia1fb492ab169108c3779deb8964bb731b322dd89 Reviewed-by: Uli Schlachter Reviewed-by: Shawn Rutledge --- src/plugins/platforms/xcb/qxcbconnection.cpp | 1 + src/plugins/platforms/xcb/qxcbconnection.h | 1 + src/plugins/platforms/xcb/qxcbintegration.cpp | 44 +++++++++++++++++++++++++++ src/plugins/platforms/xcb/qxcbintegration.h | 4 +++ src/plugins/platforms/xcb/qxcbwindow.cpp | 7 +++++ 5 files changed, 57 insertions(+) (limited to 'src/plugins/platforms/xcb') diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index f944b65a57..01af23377e 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -1232,6 +1232,7 @@ static const char * xcb_atomnames = { // ICCCM window state "WM_STATE\0" "WM_CHANGE_STATE\0" + "WM_CLASS\0" // Session management "WM_CLIENT_LEADER\0" diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 883ee95e22..2a5ff0b1cb 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -102,6 +102,7 @@ namespace QXcbAtom { // ICCCM window state WM_STATE, WM_CHANGE_STATE, + WM_CLASS, // Session management WM_CLIENT_LEADER, diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 77c265fd09..cf7e99023a 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -369,4 +369,48 @@ QVariant QXcbIntegration::styleHint(QPlatformIntegration::StyleHint hint) const return QPlatformIntegration::styleHint(hint); } +static QString argv0BaseName() +{ + QString result; + const QStringList arguments = QCoreApplication::arguments(); + if (!arguments.isEmpty() && !arguments.front().isEmpty()) { + result = arguments.front(); + const int lastSlashPos = result.lastIndexOf(QLatin1Char('/')); + if (lastSlashPos != -1) + result.remove(0, lastSlashPos + 1); + } + return result; +} + +static const char resourceNameVar[] = "RESOURCE_NAME"; + +QByteArray QXcbIntegration::wmClass() const +{ + if (m_wmClass.isEmpty()) { + // Instance name according to ICCCM 4.1.2.5 + QString name; + if (name.isEmpty() && qEnvironmentVariableIsSet(resourceNameVar)) + name = QString::fromLocal8Bit(qgetenv(resourceNameVar)); + if (name.isEmpty()) + name = argv0BaseName(); + + // Note: QCoreApplication::applicationName() cannot be called from the QGuiApplication constructor, + // hence this delayed initialization. + QString className = QCoreApplication::applicationName(); + if (className.isEmpty()) { + className = argv0BaseName(); + if (!className.isEmpty() && className.at(0).isLower()) + className[0] = className.at(0).toUpper(); + } + + if (!name.isEmpty() && !className.isEmpty()) { + m_wmClass = name.toLocal8Bit(); + m_wmClass.append('\0'); + m_wmClass.append(className.toLocal8Bit()); + m_wmClass.append('\0'); + } + } + return m_wmClass; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index 7042628203..07b6b8d678 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -99,6 +99,8 @@ public: QXcbConnection *defaultConnection() const { return m_connections.first(); } + QByteArray wmClass() const; + private: QList m_connections; @@ -115,6 +117,8 @@ private: QScopedPointer m_services; friend class QXcbConnection; // access QPlatformIntegration::screenAdded() + + mutable QByteArray m_wmClass; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 3a19788316..3b818d78d8 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -379,6 +379,13 @@ void QXcbWindow::create() m_syncValue.hi = 0; m_syncValue.lo = 0; + const QByteArray wmClass = static_cast(QGuiApplicationPrivate::platformIntegration())->wmClass(); + if (!wmClass.isEmpty()) { + Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, + m_window, atom(QXcbAtom::WM_CLASS), + XCB_ATOM_STRING, 8, wmClass.size(), wmClass.constData())); + } + if (m_usingSyncProtocol) { m_syncCounter = xcb_generate_id(xcb_connection()); Q_XCB_CALL(xcb_sync_create_counter(xcb_connection(), m_syncCounter, m_syncValue)); -- cgit v1.2.3