[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: playground/base/plasma/applets/systray-refactor
From: Fredrik Höglund <fredrik () kde ! org>
Date: 2008-10-06 23:45:57
Message-ID: 1223336757.831591.565.nullmailer () svn ! kde ! org
[Download RAW message or body]
SVN commit 868734 by fredrik:
Implement support for _NET_SYSTEM_TRAY_VISUAL and proper handling of
ARGB32 systray windows.
M +2 -1 CMakeLists.txt
M +124 -3 protocols/fdo/fdoselectionmanager.cpp
M +4 -0 protocols/fdo/fdoselectionmanager.h
M +60 -4 protocols/fdo/x11embedcontainer.cpp
--- trunk/playground/base/plasma/applets/systray-refactor/CMakeLists.txt #868733:868734
@@ -33,7 +33,8 @@
kde4_add_plugin(plasma_applet_systemtray ${systemtray_SRCS})
include_directories(${CMAKE_SOURCE_DIR})
-target_link_libraries(plasma_applet_systemtray ${KDE4_KDEUI_LIBS} plasma ${X11_LIBRARIES} \
Xrender) +target_link_libraries(plasma_applet_systemtray ${KDE4_KDEUI_LIBS} plasma \
${X11_LIBRARIES} ${X11_Xrender_LIB} + ${X11_Xfixes_LIB} ${X11_Xdamage_LIB} \
${X11_Xcomposite_LIB})
install(TARGETS plasma_applet_systemtray DESTINATION ${PLUGIN_INSTALL_DIR})
install(FILES plasma-applet-systemtray.desktop DESTINATION ${SERVICES_INSTALL_DIR})
--- trunk/playground/base/plasma/applets/systray-refactor/protocols/fdo/fdoselectionmanager.cpp \
#868733:868734 @@ -25,8 +25,7 @@
#include <KDebug>
-#include <X11/Xlib.h>
-
+#include <QtCore/QCoreApplication>
#include <QtCore/QHash>
#include <QtCore/QTimer>
@@ -35,7 +34,25 @@
#include <KGlobal>
+// ### Change to config-X11.h before moving to kdebase!
+#include <config-plasma.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/Xrender.h>
+
+#ifdef HAVE_XFIXES
+# include <X11/extensions/Xfixes.h>
+#endif
+
+#ifdef HAVE_XDAMAGE
+# include <X11/extensions/Xdamage.h>
+#endif
+
+#ifdef HAVE_XCOMPOSITE
+# include <X11/extensions/Xcomposite.h>
+#endif
+
#define SYSTEM_TRAY_REQUEST_DOCK 0
#define SYSTEM_TRAY_BEGIN_MESSAGE 1
#define SYSTEM_TRAY_CANCEL_MESSAGE 2
@@ -46,7 +63,43 @@
namespace FDO
{
+#if defined(HAVE_XFIXES) && defined(HAVE_XDAMAGE) && defined(HAVE_XCOMPOSITE)
+struct DamageWatch
+{
+ QWidget *container;
+ Damage damage;
+};
+static int damageEventBase;
+static QMap<WId, DamageWatch*> damageWatches;
+static QCoreApplication::EventFilter oldEventFilter;
+
+// Global event filter for intercepting damage events
+static bool x11EventFilter(void *message, long int *result)
+{
+ XEvent *event = reinterpret_cast<XEvent*>(message);
+ if (event->type == damageEventBase + XDamageNotify) {
+ XDamageNotifyEvent *e = reinterpret_cast<XDamageNotifyEvent*>(event);
+ if (DamageWatch *damageWatch = damageWatches.value(e->drawable)) {
+ // Create a new region and empty the damage region into it.
+ // The window is small enough that we don't really care about the region;
+ // we'll just throw it away and schedule a full repaint of the container.
+ XserverRegion region = XFixesCreateRegion(e->display, 0, 0);
+ XDamageSubtract(e->display, e->damage, None, region);
+ XFixesDestroyRegion(e->display, region);
+ damageWatch->container->update();
+ }
+ }
+
+ if (oldEventFilter && oldEventFilter != &x11EventFilter) {
+ return oldEventFilter(message, result);
+ } else {
+ return false;
+ }
+}
+#endif
+
+
class SelectionManager::Singleton
{
public:
@@ -69,12 +122,25 @@
{
public:
Private(SelectionManager *q)
- : q(q)
+ : q(q), haveComposite(false)
{
display = QX11Info::display();
selectionAtom = XInternAtom(display, "_NET_SYSTEM_TRAY_S" + \
QByteArray::number(QX11Info::appScreen()), false);
opcodeAtom = XInternAtom(display, "_NET_SYSTEM_TRAY_OPCODE", false);
messageAtom = XInternAtom(display, "_NET_SYSTEM_TRAY_MESSAGE_DATA", false);
+ visualAtom = XInternAtom(display, "_NET_SYSTEM_TRAY_VISUAL", false);
+
+#if defined(HAVE_XFIXES) && defined(HAVE_XDAMAGE) && defined(HAVE_XCOMPOSITE)
+ int eventBase, errorBase;
+ bool haveXfixes = XFixesQueryExtension(display, &eventBase, &errorBase);
+ bool haveXdamage = XDamageQueryExtension(display, &damageEventBase, &errorBase);
+ bool haveXComposite = XCompositeQueryExtension(display, &eventBase, &errorBase);
+
+ if (haveXfixes && haveXdamage && haveXComposite) {
+ haveComposite = true;
+ oldEventFilter = QCoreApplication::instance()->setEventFilter(x11EventFilter);
+ }
+#endif
}
void createNotification(WId winId);
@@ -88,12 +154,14 @@
Atom selectionAtom;
Atom opcodeAtom;
Atom messageAtom;
+ Atom visualAtom;
QHash<WId, MessageRequest> messageRequests;
QHash<WId, Task*> tasks;
QHash<WId, Notification*> notifications;
SelectionManager *q;
+ bool haveComposite;
};
@@ -115,10 +183,43 @@
SelectionManager::~SelectionManager()
{
+ if (d->haveComposite) {
+ QCoreApplication::instance()->setEventFilter(oldEventFilter);
+ }
delete d;
}
+void SelectionManager::addDamageWatch(QWidget *container, WId client)
+{
+ DamageWatch *damage = new DamageWatch;
+ damage->container = container;
+ damage->damage = XDamageCreate(QX11Info::display(), client, XDamageReportNonEmpty);
+ damageWatches.insert(client, damage);
+}
+
+
+void SelectionManager::removeDamageWatch(QWidget *container)
+{
+ for (QMap<WId, DamageWatch*>::Iterator it = damageWatches.begin(); it != \
damageWatches.end(); ++it) + {
+ DamageWatch *damage = *(it);
+ if (damage->container == container) {
+ XDamageDestroy(QX11Info::display(), damage->damage);
+ damageWatches.erase(it);
+ delete damage;
+ break;
+ }
+ }
+}
+
+
+bool SelectionManager::haveComposite() const
+{
+ return d->haveComposite;
+}
+
+
bool SelectionManager::x11Event(XEvent *event)
{
if (event->type == ClientMessage) {
@@ -156,6 +257,26 @@
return;
}
+ // Prefer the ARGB32 visual if available
+ int nvi;
+ VisualID visual = XVisualIDFromVisual((Visual*)QX11Info::appVisual());
+ XVisualInfo templ;
+ templ.screen = DefaultScreen(d->display);
+ templ.depth = 32;
+ templ.c_class = TrueColor;
+ XVisualInfo *xvi = XGetVisualInfo(d->display, VisualScreenMask | VisualDepthMask | \
VisualClassMask, + &templ, &nvi);
+ for (int i = 0; i < nvi; i++) {
+ XRenderPictFormat *format = XRenderFindVisualFormat(d->display, xvi[i].visual);
+ if (format->type == PictTypeDirect && format->direct.alphaMask) {
+ visual = xvi[i].visualid;
+ break;
+ }
+ }
+
+ XChangeProperty(d->display, winId(), d->visualAtom, XA_VISUALID, 32,
+ PropModeReplace, (const unsigned char*)&visual, 1);
+
WId root = QX11Info::appRootWindow();
XClientMessageEvent xev;
--- trunk/playground/base/plasma/applets/systray-refactor/protocols/fdo/fdoselectionmanager.h \
#868733:868734 @@ -44,6 +44,10 @@
class Singleton;
static SelectionManager* self();
+ void addDamageWatch(QWidget *container, WId client);
+ void removeDamageWatch(QWidget *container);
+ bool haveComposite() const;
+
signals:
void taskCreated(SystemTray::Task *task);
void notificationCreated(SystemTray::Notification *notification);
--- trunk/playground/base/plasma/applets/systray-refactor/protocols/fdo/x11embedcontainer.cpp \
#868733:868734 @@ -20,13 +20,27 @@
***************************************************************************/
#include "x11embedcontainer.h"
+#include "fdoselectionmanager.h"
+// KDE
+#include <KDebug>
+
+// Qt
+#include <QtCore/QTimer>
+#include <QtGui/QPainter>
+#include <QtGui/QX11Info>
+
+// Xlib
+// #### Change to config-X11.h before moving to kdebase!
+#include <config-plasma.h>
+
#include <X11/Xlib.h>
#include <X11/extensions/Xrender.h>
-#include <QtCore/QTimer>
+#ifdef HAVE_XCOMPOSITE
+# include <X11/extensions/Xcomposite.h>
+#endif
-#include <QtGui/QX11Info>
namespace SystemTray
@@ -40,9 +54,16 @@
public:
Private(X11EmbedContainer *q)
: q(q),
+ picture(None),
updatingBackground(false)
{
}
+ ~Private()
+ {
+ if (picture) {
+ XRenderFreePicture(QX11Info::display(), picture);
+ }
+ }
void updateClientBackground();
void sendExposeToClient();
@@ -50,6 +71,7 @@
X11EmbedContainer *q;
XWindowAttributes attr;
+ Picture picture;
QImage bgImage;
bool updatingBackground;
};
@@ -66,6 +88,7 @@
X11EmbedContainer::~X11EmbedContainer()
{
+ SelectionManager::self()->removeDamageWatch(this);
delete d;
}
@@ -90,6 +113,25 @@
CWBackPixel | CWBorderPixel | CWColormap, &sAttr);
create(winId);
+#if defined(HAVE_XCOMPOSITE) && defined(HAVE_XFIXES) && defined(HAVE_XDAMAGE)
+ XRenderPictFormat *format = XRenderFindVisualFormat(display, d->attr.visual);
+ if (format->type == PictTypeDirect && format->direct.alphaMask &&
+ SelectionManager::self()->haveComposite())
+ {
+ // Redirect ARGB windows to offscreen storage so we can composite them ourselves
+ XRenderPictureAttributes attr;
+ attr.subwindow_mode = IncludeInferiors;
+
+ d->picture = XRenderCreatePicture(display, clientId, format, CPSubwindowMode, &attr);
+ XCompositeRedirectSubwindows(display, winId, CompositeRedirectManual);
+ SelectionManager::self()->addDamageWatch(this, clientId);
+
+ kDebug() << "Embedded client uses an ARGB visual -> compositing.";
+ } else {
+ kDebug() << "Embedded client is not using an ARGB visual.";
+ }
+#endif
+
// repeat everything from QX11EmbedContainer's ctor that might be relevant
setFocusPolicy(Qt::StrongFocus);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
@@ -134,9 +176,23 @@
{
Q_UNUSED(event);
- if (!d->updatingBackground) {
- QTimer::singleShot(0, this, SLOT(updateBackgroundImage()));
+ if (!d->picture) {
+ if (!d->updatingBackground) {
+ QTimer::singleShot(0, this, SLOT(updateBackgroundImage()));
+ }
+ return;
}
+
+ // Taking a detour via a QPixmap is unfortunately the only way we can get
+ // the window contents into Qt's backing store.
+ QPixmap pixmap(size());
+ pixmap.fill(Qt::transparent);
+
+ XRenderComposite(x11Info().display(), PictOpSrc, d->picture, None, \
pixmap.x11PictureHandle(), + 0, 0, 0, 0, 0, 0, width(), height());
+
+ QPainter p(this);
+ p.drawPixmap(0, 0, pixmap);
}
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic