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>
bb10
parent
71a1ff39bc
commit
1ea1abeb91
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()))
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Reference in New Issue