not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / plasma / applets / systemtray / protocols / fdo / x11embedcontainer.cpp
blob3a5f3fbd418d824e359059f227947dcbd4d28399
1 /***************************************************************************
2 * x11embedcontainer.cpp *
3 * *
4 * Copyright (C) 2008 Jason Stubbs <jasonbstubbs@gmail.com> *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the *
18 * Free Software Foundation, Inc., *
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
20 ***************************************************************************/
22 #include "x11embedcontainer.h"
23 #include "x11embedpainter.h"
24 #include "fdoselectionmanager.h"
26 // KDE
27 #include <KDebug>
29 // Qt
30 #include <QtCore/QTime>
31 #include <QtCore/QTimer>
32 #include <QtGui/QPainter>
33 #include <QtGui/QPaintEngine>
34 #include <QtGui/QX11Info>
36 // Xlib
37 #include <config-X11.h>
39 #include <X11/Xlib.h>
40 #include <X11/extensions/Xrender.h>
42 #ifdef HAVE_XCOMPOSITE
43 # include <X11/extensions/Xcomposite.h>
44 #endif
47 namespace SystemTray
50 class X11EmbedContainer::Private
52 public:
53 Private(X11EmbedContainer *q)
54 : q(q),
55 picture(None),
56 updatesEnabled(true)
60 ~Private()
62 if (picture) {
63 XRenderFreePicture(QX11Info::display(), picture);
67 X11EmbedContainer *q;
69 XWindowAttributes attr;
70 Picture picture;
71 bool updatesEnabled;
75 X11EmbedContainer::X11EmbedContainer(QWidget *parent)
76 : QX11EmbedContainer(parent),
77 d(new Private(this))
79 connect(this, SIGNAL(clientIsEmbedded()),
80 this, SLOT(ensureValidSize()));
84 X11EmbedContainer::~X11EmbedContainer()
86 FdoSelectionManager::manager()->removeDamageWatch(this);
87 delete d;
91 void X11EmbedContainer::embedSystemTrayClient(WId clientId)
93 Display *display = QX11Info::display();
95 if (!XGetWindowAttributes(display, clientId, &d->attr)) {
96 emit error(QX11EmbedContainer::Unknown);
97 return;
100 XSetWindowAttributes sAttr;
101 sAttr.background_pixel = BlackPixel(display, DefaultScreen(display));
102 sAttr.border_pixel = BlackPixel(display, DefaultScreen(display));
103 sAttr.colormap = d->attr.colormap;
105 WId parentId = parentWidget() ? parentWidget()->winId() : DefaultRootWindow(display);
106 Window winId = XCreateWindow(display, parentId, 0, 0, d->attr.width, d->attr.height,
107 0, d->attr.depth, InputOutput, d->attr.visual,
108 CWBackPixel | CWBorderPixel | CWColormap, &sAttr);
109 create(winId);
111 #if defined(HAVE_XCOMPOSITE) && defined(HAVE_XFIXES) && defined(HAVE_XDAMAGE)
112 XRenderPictFormat *format = XRenderFindVisualFormat(display, d->attr.visual);
113 if (format && format->type == PictTypeDirect && format->direct.alphaMask &&
114 FdoSelectionManager::manager()->haveComposite())
116 // Redirect ARGB windows to offscreen storage so we can composite them ourselves
117 XRenderPictureAttributes attr;
118 attr.subwindow_mode = IncludeInferiors;
120 d->picture = XRenderCreatePicture(display, clientId, format, CPSubwindowMode, &attr);
121 XCompositeRedirectSubwindows(display, winId, CompositeRedirectManual);
122 FdoSelectionManager::manager()->addDamageWatch(this, clientId);
124 //kDebug() << "Embedded client uses an ARGB visual -> compositing.";
125 } else {
126 //kDebug() << "Embedded client is not using an ARGB visual.";
128 #endif
130 // repeat everything from QX11EmbedContainer's ctor that might be relevant
131 setFocusPolicy(Qt::StrongFocus);
132 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
133 setAcceptDrops(true);
134 setEnabled(false);
136 XSelectInput(display, winId,
137 KeyPressMask | KeyReleaseMask |
138 ButtonPressMask | ButtonReleaseMask | ButtonMotionMask |
139 KeymapStateMask |
140 PointerMotionMask |
141 EnterWindowMask | LeaveWindowMask |
142 FocusChangeMask |
143 ExposureMask |
144 StructureNotifyMask |
145 SubstructureNotifyMask);
147 XFlush(display);
149 embedClient(clientId);
151 // FIXME: This checks that the client is still valid. Qt won't pick it up
152 // if the client closes before embedding completes. However, what happens
153 // if the close happens after this point? Should checks happen on a timer
154 // until embedding completes perhaps?
155 if (!XGetWindowAttributes(QX11Info::display(), clientId, &d->attr)) {
156 emit error(QX11EmbedContainer::Unknown);
157 return;
162 void X11EmbedContainer::ensureValidSize()
164 QSize s = QSize(qBound(minimumSize().width(), width(), maximumSize().width()),
165 qBound(minimumSize().height(), height(), maximumSize().height()));
166 resize(s);
170 void X11EmbedContainer::setUpdatesEnabled(bool enabled)
172 d->updatesEnabled = enabled;
176 void X11EmbedContainer::paintEvent(QPaintEvent *event)
178 Q_UNUSED(event);
180 if (!d->updatesEnabled) {
181 return;
184 if (!d->picture) {
185 FdoSelectionManager::painter()->updateContainer(this);
186 return;
189 // Taking a detour via a QPixmap is unfortunately the only way we can get
190 // the window contents into Qt's backing store.
191 QPixmap pixmap(size());
192 if (pixmap.paintEngine()->type() != QPaintEngine::X11) {
193 #if defined(HAVE_XCOMPOSITE)
194 // If we're using the raster or OpenGL graphics systems, a QPixmap isn't an X pixmap,
195 // so we have to get the window contents into a QImage and then draw that.
196 Display *dpy = x11Info().display();
198 // XXX We really should keep a cached copy of the image client side, and only
199 // update it in response to a damage event.
200 Pixmap pixmap = XCompositeNameWindowPixmap(dpy, clientWinId());
201 XImage *ximage = XGetImage(dpy, pixmap, 0, 0, width(), height(), AllPlanes, ZPixmap);
202 XFreePixmap(dpy, pixmap);
203 // We actually check if we get the image from X11 since clientWinId can be any arbiter window (with crazy XWindowAttribute and the pixmap associated is bad)
204 if (!ximage)
205 return;
206 // This is safe to do since we only composite ARGB32 windows, and PictStandardARGB32
207 // matches QImage::Format_ARGB32_Premultiplied.
208 QImage image((const uchar*)ximage->data, ximage->width, ximage->height, ximage->bytes_per_line,
209 QImage::Format_ARGB32_Premultiplied);
211 QPainter p(this);
212 p.drawImage(0, 0, image);
214 XDestroyImage(ximage);
215 #endif
216 } else {
217 pixmap.fill(Qt::transparent);
219 XRenderComposite(x11Info().display(), PictOpSrc, d->picture, None, pixmap.x11PictureHandle(),
220 0, 0, 0, 0, 0, 0, width(), height());
222 QPainter p(this);
223 p.drawPixmap(0, 0, pixmap);
227 void X11EmbedContainer::setBackgroundPixmap(QPixmap background)
229 if (!clientWinId()) {
230 return;
233 Display *display = QX11Info::display();
234 Pixmap bg = XCreatePixmap(display, clientWinId(), width(), height(), d->attr.depth);
236 XRenderPictFormat *format = XRenderFindVisualFormat(display, d->attr.visual);
237 Picture picture = XRenderCreatePicture(display, bg, format, 0, 0);
239 XRenderComposite(display, PictOpSrc, background.x11PictureHandle(),
240 None, picture, 0, 0, 0, 0, 0, 0, width(), height());
242 XSetWindowBackgroundPixmap(display, clientWinId(), bg);
244 XRenderFreePicture(display, picture);
245 XFreePixmap(display, bg);
247 XClearArea(display, clientWinId(), 0, 0, 0, 0, True);
252 #include "x11embedcontainer.moc"