summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Faure <faure@kde.org>2013-04-15 23:52:32 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-04-23 21:02:50 +0200
commit1ea1abeb91f544b4cf595d229249ee859090bee5 (patch)
tree745075108bd4b70f50e89f8be9d94ce749e762de
parent71a1ff39bcf67117e94b669aa0ee059bf1f03b3a (diff)
Implement startup notification spec again.
This functionality was in Qt4's qapplication_x11.cpp and was missing from the XCB QPA plugin. Ported the code from xlib to xcb. This code was actually tested (with plasma), unlike the Qt-4.8 code which skipped every other character... for (uint i = 0; i < 20 && i + sent <= length; i++) xevent.xclient.data.b[i] = message[i + sent++]; Provide a QPA native-function for accessing the startup id, for cases where an application doesn't show a window, but starts another app instead, or asks a running app to show the window on its behalf. Change-Id: If392179efddd70a51c45a8fab4fb9d753913094a Reviewed-by: David Faure (KDE) <faure@kde.org>
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp4
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h5
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.cpp30
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.h5
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp34
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp4
8 files changed, 85 insertions, 1 deletions
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 1504bd99d2..cb80fdfbd3 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -344,6 +344,10 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, const char
m_drag = new QXcbDrag(this);
#endif
+ m_startupId = qgetenv("DESKTOP_STARTUP_ID");
+ if (!m_startupId.isNull())
+ qunsetenv("DESKTOP_STARTUP_ID");
+
sync();
}
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index f69a8a9f35..8ab65fc2bc 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -388,6 +388,9 @@ public:
QXcbWindow *focusWindow() const { return m_focusWindow; }
void setFocusWindow(QXcbWindow *);
+ QByteArray startupId() const { return m_startupId; }
+ void clearStartupId() { m_startupId.clear(); }
+
private slots:
void processXcbEvents();
@@ -516,6 +519,8 @@ private:
Qt::MouseButtons m_buttons;
QXcbWindow *m_focusWindow;
+
+ QByteArray m_startupId;
};
#define DISPLAY_FROM_XCB(object) ((Display *)(object->connection()->xlib_display()))
diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h
index 6db9d82cca..451dc43475 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.h
+++ b/src/plugins/platforms/xcb/qxcbintegration.h
@@ -95,6 +95,8 @@ public:
QStringList themeNames() const;
QPlatformTheme *createPlatformTheme(const QString &name) const;
+ QXcbConnection *defaultConnection() const { return m_connections.first(); }
+
private:
QList<QXcbConnection *> m_connections;
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
index 6ac69a8335..da60cfd2bd 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
@@ -42,6 +42,7 @@
#include "qxcbnativeinterface.h"
#include "qxcbscreen.h"
+#include "qxcbintegration.h"
#include <private/qguiapplication_p.h>
#include <QtCore/QMap>
@@ -78,6 +79,7 @@ public:
insert("apptime",QXcbNativeInterface::AppTime);
insert("appusertime",QXcbNativeInterface::AppUserTime);
insert("hintstyle", QXcbNativeInterface::ScreenHintStyle);
+ insert("startupid", QXcbNativeInterface::StartupId);
}
};
@@ -99,6 +101,25 @@ void QXcbNativeInterface::beep() // For QApplication::beep()
#endif
}
+void *QXcbNativeInterface::nativeResourceForIntegration(const QByteArray &resourceString)
+{
+ QByteArray lowerCaseResource = resourceString.toLower();
+ if (!qXcbResourceMap()->contains(lowerCaseResource))
+ return 0;
+
+ ResourceType resource = qXcbResourceMap()->value(lowerCaseResource);
+ void *result = 0;
+ switch (resource) {
+ case StartupId:
+ result = startupId();
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
void *QXcbNativeInterface::nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context)
{
QByteArray lowerCaseResource = resourceString.toLower();
@@ -196,6 +217,15 @@ void *QXcbNativeInterface::appUserTime(const QXcbScreen *screen)
return reinterpret_cast<void *>(quintptr(screen->connection()->netWmUserTime()));
}
+void *QXcbNativeInterface::startupId()
+{
+ QXcbIntegration* integration = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration());
+ QXcbConnection *defaultConnection = integration->defaultConnection();
+ if (defaultConnection)
+ return reinterpret_cast<void *>(const_cast<char *>(defaultConnection->startupId().constData()));
+ return 0;
+}
+
void QXcbNativeInterface::setAppTime(QScreen* screen, xcb_timestamp_t time)
{
static_cast<QXcbScreen *>(screen->handle())->connection()->setTime(time);
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h
index 919a21d00d..e27bfa5a46 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.h
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h
@@ -65,11 +65,13 @@ public:
GLXContext,
AppTime,
AppUserTime,
- ScreenHintStyle
+ ScreenHintStyle,
+ StartupId
};
QXcbNativeInterface();
+ void *nativeResourceForIntegration(const QByteArray &resource) Q_DECL_OVERRIDE;
void *nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context);
void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen);
void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window);
@@ -86,6 +88,7 @@ public:
void *graphicsDeviceForWindow(QWindow *window);
void *appTime(const QXcbScreen *screen);
void *appUserTime(const QXcbScreen *screen);
+ void *startupId();
static void setAppTime(QScreen *screen, xcb_timestamp_t time);
static void setAppUserTime(QScreen *screen, xcb_timestamp_t time);
static void *eglContextForContext(QOpenGLContext *context);
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index 38b4c873ad..a6ead49a27 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -233,6 +233,40 @@ QWindow *QXcbScreen::topLevelAt(const QPoint &p) const
return 0;
}
+void QXcbScreen::windowShown(QXcbWindow *window)
+{
+ // Freedesktop.org Startup Notification
+ if (!connection()->startupId().isEmpty() && window->window()->isTopLevel()) {
+ sendStartupMessage(QByteArrayLiteral("remove: ID=") + connection()->startupId());
+ connection()->clearStartupId();
+ }
+}
+
+void QXcbScreen::sendStartupMessage(const QByteArray &message) const
+{
+ xcb_window_t rootWindow = root();
+
+ xcb_client_message_event_t ev;
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 8;
+ ev.type = connection()->atom(QXcbAtom::_NET_STARTUP_INFO_BEGIN);
+ ev.window = rootWindow;
+ int sent = 0;
+ int length = message.length() + 1; // include NUL byte
+ const char *data = message.constData();
+ do {
+ if (sent == 20)
+ ev.type = connection()->atom(QXcbAtom::_NET_STARTUP_INFO);
+
+ const int start = sent;
+ const int numBytes = qMin(length - start, 20);
+ memcpy(ev.data.data8, data + start, numBytes);
+ xcb_send_event(connection()->xcb_connection(), false, rootWindow, XCB_EVENT_MASK_PROPERTY_CHANGE, (const char *) &ev);
+
+ sent += numBytes;
+ } while (sent < length);
+}
+
const xcb_visualtype_t *QXcbScreen::visualForId(xcb_visualid_t visualid) const
{
QMap<xcb_visualid_t, xcb_visualtype_t>::const_iterator it = m_visuals.find(visualid);
diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h
index c3b13fd1ea..0382be8a29 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.h
+++ b/src/plugins/platforms/xcb/qxcbscreen.h
@@ -87,6 +87,7 @@ public:
xcb_window_t clientLeader() const { return m_clientLeader; }
+ void windowShown(QXcbWindow *window);
QString windowManagerName() const { return m_windowManagerName; }
bool syncRequestSupported() const { return m_syncRequestSupported; }
@@ -105,6 +106,7 @@ private:
static bool xResource(const QByteArray &identifier,
const QByteArray &expectedIdentifier,
int *value);
+ void sendStartupMessage(const QByteArray &message) const;
xcb_screen_t *m_screen;
xcb_randr_crtc_t m_crtc;
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index f2ec4ce4b0..4090758d36 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -46,6 +46,7 @@
#include <QtGui/QIcon>
#include <QtGui/QRegion>
+#include "qxcbintegration.h"
#include "qxcbconnection.h"
#include "qxcbscreen.h"
#include "qxcbdrag.h"
@@ -653,6 +654,9 @@ void QXcbWindow::show()
updateNetWmUserTime(connection()->time());
Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window));
+
+ m_screen->windowShown(this);
+
xcb_flush(xcb_connection());
connection()->sync();