1 /***************************************************************************
2 * x11embedcontainer.cpp *
4 * Copyright (C) 2008 Jason Stubbs <jasonbstubbs@gmail.com> *
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. *
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. *
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"
30 #include <QtCore/QTime>
31 #include <QtCore/QTimer>
32 #include <QtGui/QPainter>
33 #include <QtGui/QPaintEngine>
34 #include <QtGui/QX11Info>
37 #include <config-X11.h>
40 #include <X11/extensions/Xrender.h>
42 #ifdef HAVE_XCOMPOSITE
43 # include <X11/extensions/Xcomposite.h>
50 class X11EmbedContainer::Private
53 Private(X11EmbedContainer
*q
)
63 XRenderFreePicture(QX11Info::display(), picture
);
69 XWindowAttributes attr
;
75 X11EmbedContainer::X11EmbedContainer(QWidget
*parent
)
76 : QX11EmbedContainer(parent
),
79 connect(this, SIGNAL(clientIsEmbedded()),
80 this, SLOT(ensureValidSize()));
84 X11EmbedContainer::~X11EmbedContainer()
86 FdoSelectionManager::manager()->removeDamageWatch(this);
91 void X11EmbedContainer::embedSystemTrayClient(WId clientId
)
93 Display
*display
= QX11Info::display();
95 if (!XGetWindowAttributes(display
, clientId
, &d
->attr
)) {
96 emit
error(QX11EmbedContainer::Unknown
);
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
);
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.";
126 //kDebug() << "Embedded client is not using an ARGB visual.";
130 // repeat everything from QX11EmbedContainer's ctor that might be relevant
131 setFocusPolicy(Qt::StrongFocus
);
132 setSizePolicy(QSizePolicy::Expanding
, QSizePolicy::Expanding
);
133 setAcceptDrops(true);
136 XSelectInput(display
, winId
,
137 KeyPressMask
| KeyReleaseMask
|
138 ButtonPressMask
| ButtonReleaseMask
| ButtonMotionMask
|
141 EnterWindowMask
| LeaveWindowMask
|
144 StructureNotifyMask
|
145 SubstructureNotifyMask
);
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
);
162 void X11EmbedContainer::ensureValidSize()
164 QSize s
= QSize(qBound(minimumSize().width(), width(), maximumSize().width()),
165 qBound(minimumSize().height(), height(), maximumSize().height()));
170 void X11EmbedContainer::setUpdatesEnabled(bool enabled
)
172 d
->updatesEnabled
= enabled
;
176 void X11EmbedContainer::paintEvent(QPaintEvent
*event
)
180 if (!d
->updatesEnabled
) {
185 FdoSelectionManager::painter()->updateContainer(this);
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)
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
);
212 p
.drawImage(0, 0, image
);
214 XDestroyImage(ximage
);
217 pixmap
.fill(Qt::transparent
);
219 XRenderComposite(x11Info().display(), PictOpSrc
, d
->picture
, None
, pixmap
.x11PictureHandle(),
220 0, 0, 0, 0, 0, 0, width(), height());
223 p
.drawPixmap(0, 0, pixmap
);
227 void X11EmbedContainer::setBackgroundPixmap(QPixmap background
)
229 if (!clientWinId()) {
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"