aboutsummaryrefslogtreecommitdiff
path: root/util/fbcompose/XRenderScreen.cc
diff options
context:
space:
mode:
authorGediminas Liktaras <gliktaras@gmail.com>2011-12-08 13:34:09 (GMT)
committerPaul Tagliamonte <paultag@fluxbox.org>2011-12-10 16:13:19 (GMT)
commitcd339169d1961eb508ea89cee2609ec6d0fc0c15 (patch)
tree01acd158a03fb17a72e067ff0b36701da75e49dc /util/fbcompose/XRenderScreen.cc
parent85ac5c4b2c6a526992f483a6e91867dc2f82a19e (diff)
downloadfluxbox_paul-cd339169d1961eb508ea89cee2609ec6d0fc0c15.zip
fluxbox_paul-cd339169d1961eb508ea89cee2609ec6d0fc0c15.tar.bz2
fbcompose - A compositing addon for fluxbox window manager.
fbcompose(1) is an optional compositing addon for fluxbox window manager. It augments fluxbox with a number of graphical features. Most notably, fbcompose allows fluxbox to properly display applications that require compositing (docky, for example), adds support for true window transparency (as opposed to fluxbox's pseudo transparency) and provides a plugin framework to extend the compositor's functionality. As this is still a beta version of the compositor, the bugs are likely.
Diffstat (limited to 'util/fbcompose/XRenderScreen.cc')
-rw-r--r--util/fbcompose/XRenderScreen.cc356
1 files changed, 356 insertions, 0 deletions
diff --git a/util/fbcompose/XRenderScreen.cc b/util/fbcompose/XRenderScreen.cc
new file mode 100644
index 0000000..2450576
--- /dev/null
+++ b/util/fbcompose/XRenderScreen.cc
@@ -0,0 +1,356 @@
1/** XRenderScreen.cc file for the fluxbox compositor. */
2
3// Copyright (c) 2011 Gediminas Liktaras (gliktaras at gmail dot com)
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in
13// all copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21// THE SOFTWARE.
22
23#include "XRenderScreen.hh"
24
25#include "CompositorConfig.hh"
26#include "Logging.hh"
27#include "Utility.hh"
28#include "XRenderWindow.hh"
29
30#include <X11/extensions/shape.h>
31#include <X11/extensions/Xcomposite.h>
32#include <X11/extensions/Xfixes.h>
33#include <X11/Xutil.h>
34
35using namespace FbCompositor;
36
37
38//--- MACROS -------------------------------------------------------------------
39
40// Macro for plugin iteration.
41#define forEachPlugin(i, plugin) \
42 (plugin) = ((pluginManager().plugins().size() > 0) \
43 ? (dynamic_cast<XRenderPlugin*>(pluginManager().plugins()[0])) \
44 : NULL); \
45 for(size_t (i) = 0; \
46 ((i) < pluginManager().plugins().size()); \
47 (i)++, \
48 (plugin) = (((i) < pluginManager().plugins().size()) \
49 ? (dynamic_cast<XRenderPlugin*>(pluginManager().plugins()[(i)])) \
50 : NULL))
51
52
53//--- CONSTRUCTORS AND DESTRUCTORS ---------------------------------------------
54
55// Constructor.
56XRenderScreen::XRenderScreen(int screen_number, const CompositorConfig &config):
57 BaseScreen(screen_number, Plugin_XRender, config),
58 m_pict_filter(config.xRenderPictFilter()) {
59
60 m_plugin_damage = XFixesCreateRegion(display(), NULL, 0);
61
62 initRenderingSurface();
63 updateBackgroundPicture();
64}
65
66// Destructor.
67XRenderScreen::~XRenderScreen() {
68 if (m_plugin_damage) {
69 XFixesDestroyRegion(display(), m_plugin_damage);
70 }
71
72 XUnmapWindow(display(), m_rendering_window);
73 XDestroyWindow(display(), m_rendering_window);
74}
75
76
77//--- INITIALIZATION FUNCTIONS -------------------------------------------------
78
79// Initializes the rendering surface.
80void XRenderScreen::initRenderingSurface() {
81 // Get all the elements, needed for the creation of the rendering surface.
82 Window comp_overlay = XCompositeGetOverlayWindow(display(), rootWindow().window());
83
84 XVisualInfo visual_info;
85 if (!XMatchVisualInfo(display(), screenNumber(), 32, TrueColor, &visual_info)) {
86 throw InitException("Cannot find the required visual.");
87 }
88
89 XSetWindowAttributes wa;
90 wa.border_pixel = XBlackPixel(display(), screenNumber()); // Without this XCreateWindow gives BadMatch error.
91 wa.colormap = XCreateColormap(display(), rootWindow().window(), visual_info.visual, AllocNone);
92 long wa_mask = CWBorderPixel | CWColormap;
93
94 // Create the rendering surface.
95 m_rendering_window = XCreateWindow(display(), comp_overlay, 0, 0, rootWindow().width(), rootWindow().height(), 0,
96 visual_info.depth, InputOutput, visual_info.visual, wa_mask, &wa);
97 XmbSetWMProperties(display(), m_rendering_window, "fbcompose", "fbcompose", NULL, 0, NULL, NULL, NULL);
98 XMapWindow(display(), m_rendering_window);
99
100 // Make sure the overlays do not consume any input events.
101 XserverRegion empty_region = XFixesCreateRegion(display(), NULL, 0);
102 XFixesSetWindowShapeRegion(display(), comp_overlay, ShapeInput, 0, 0, empty_region);
103 XFixesSetWindowShapeRegion(display(), m_rendering_window, ShapeInput, 0, 0, empty_region);
104 XFixesDestroyRegion(display(), empty_region);
105
106 ignoreWindow(comp_overlay);
107 ignoreWindow(m_rendering_window);
108
109 // Create an XRender picture for the rendering window.
110 XRenderPictureAttributes pa;
111 pa.subwindow_mode = IncludeInferiors;
112 long pa_mask = CPSubwindowMode;
113
114 XRenderPictFormat *rendering_pict_format = XRenderFindVisualFormat(display(), visual_info.visual);
115 if (!rendering_pict_format) {
116 throw InitException("Cannot find the required picture format.");
117 }
118
119 m_rendering_picture = new XRenderPicture(*this, rendering_pict_format, m_pict_filter);
120 m_rendering_picture->setWindow(m_rendering_window, pa, pa_mask);
121
122 // Create the back buffer.
123 XRenderPictFormat *back_buffer_pict_format = XRenderFindStandardFormat(display(), PictStandardARGB32);
124 Pixmap back_buffer_pixmap = XCreatePixmap(display(), rootWindow().window(), rootWindow().width(), rootWindow().height(), 32);
125
126 m_back_buffer_picture = new XRenderPicture(*this, back_buffer_pict_format, m_pict_filter);
127 m_back_buffer_picture->setPixmap(back_buffer_pixmap, true, pa, pa_mask);
128}
129
130
131//--- SCREEN MANIPULATION ------------------------------------------------------
132
133// Notifies the screen of a background change.
134void XRenderScreen::setRootPixmapChanged() {
135 BaseScreen::setRootPixmapChanged();
136 m_root_changed = true;
137}
138
139// Notifies the screen of a root window change.
140void XRenderScreen::setRootWindowSizeChanged() {
141 BaseScreen::setRootWindowSizeChanged();
142 m_root_changed = true;
143
144 XRenderPictureAttributes pa;
145 pa.subwindow_mode = IncludeInferiors;
146 long pa_mask = CPSubwindowMode;
147
148 XResizeWindow(display(), m_rendering_window, rootWindow().width(), rootWindow().height());
149 m_rendering_picture->setWindow(m_rendering_window, pa, pa_mask); // We need to recreate the picture.
150
151 Pixmap back_buffer_pixmap = XCreatePixmap(display(), rootWindow().window(), rootWindow().width(), rootWindow().height(), 32);
152 m_back_buffer_picture->setPixmap(back_buffer_pixmap, true, pa, pa_mask);
153}
154
155
156// Update the background picture.
157void XRenderScreen::updateBackgroundPicture() {
158 XRenderPictFormat *pict_format;
159 if (wmSetRootWindowPixmap()) {
160 pict_format = XRenderFindVisualFormat(display(), rootWindow().visual());
161 } else {
162 pict_format = XRenderFindStandardFormat(display(), PictStandardARGB32);
163 }
164
165 if (!pict_format) {
166 throw RuntimeException("Cannot find the required picture format.");
167 }
168
169 XRenderPictureAttributes pa;
170 pa.subwindow_mode = IncludeInferiors;
171 long pa_mask = CPSubwindowMode;
172
173 if (!m_root_picture) {
174 m_root_picture = new XRenderPicture(*this, pict_format, m_pict_filter);
175 } else {
176 m_root_picture->setPictFormat(pict_format);
177 }
178 m_root_picture->setPixmap(rootWindowPixmap(), false, pa, pa_mask);
179 m_root_changed = false;
180}
181
182
183//--- SCREEN RENDERING ---------------------------------------------------------
184
185// Renders the screen's contents.
186void XRenderScreen::renderScreen() {
187 clipBackBufferToDamage();
188
189 renderBackground();
190
191 std::list<BaseCompWindow*>::const_iterator it = allWindows().begin();
192 while (it != allWindows().end()) {
193 if (!(*it)->isIgnored() && (*it)->isMapped()) {
194 renderWindow(*(dynamic_cast<XRenderWindow*>(*it)));
195 }
196 ++it;
197 }
198
199 if ((reconfigureRectangle().width != 0) && (reconfigureRectangle().height != 0)) {
200 renderReconfigureRect();
201 }
202
203 renderExtraJobs();
204
205 swapBuffers();
206}
207
208// Clips the backbuffer picture to damaged area.
209void XRenderScreen::clipBackBufferToDamage() {
210 XRenderPlugin *plugin = NULL;
211
212 m_plugin_damage_rects.clear();
213 forEachPlugin(i, plugin) {
214 const std::vector<XRectangle> &window_damage = plugin->damagedAreas();
215 m_plugin_damage_rects.insert(m_plugin_damage_rects.end(), window_damage.begin(), window_damage.end());
216 }
217 XFixesSetRegion(display(), m_plugin_damage, (XRectangle*)(m_plugin_damage_rects.data()), m_plugin_damage_rects.size());
218
219 XserverRegion all_damage = damagedScreenArea();
220 XFixesUnionRegion(display(), all_damage, all_damage, m_plugin_damage);
221
222 XFixesSetPictureClipRegion(display(), m_back_buffer_picture->pictureHandle(), 0, 0, all_damage);
223}
224
225// Perform a rendering job on the back buffer picture.
226void XRenderScreen::executeRenderingJob(const XRenderRenderingJob &job) {
227 if (job.operation != PictOpClear) {
228 Picture source = ((job.source_picture) ? (job.source_picture->pictureHandle()) : (None));
229 Picture mask = ((job.mask_picture) ? (job.mask_picture->pictureHandle()) : (None));
230
231 XRenderComposite(display(), job.operation, source, mask,
232 m_back_buffer_picture->pictureHandle(), job.source_x, job.source_y,
233 job.mask_x, job.mask_y, job.destination_x, job.destination_y, job.width, job.height);
234 }
235}
236
237// Render the desktop wallpaper.
238// TODO: Simply make the window transparent.
239void XRenderScreen::renderBackground() {
240 // React to desktop background change.
241 if (m_root_changed) {
242 updateBackgroundPicture();
243 }
244
245 // Draw the desktop.
246 XRenderComposite(display(), PictOpSrc, m_root_picture->pictureHandle(), None, m_back_buffer_picture->pictureHandle(),
247 0, 0, 0, 0, 0, 0, rootWindow().width(), rootWindow().height());
248
249 // Additional rendering actions.
250 XRenderPlugin *plugin = NULL;
251 XRenderRenderingJob job;
252
253 forEachPlugin(i, plugin) {
254 std::vector<XRenderRenderingJob> jobs = plugin->postBackgroundRenderingActions();
255 for (size_t j = 0; j < jobs.size(); j++) {
256 executeRenderingJob(jobs[j]);
257 }
258 }
259}
260
261// Perform extra rendering jobs from plugins.
262void XRenderScreen::renderExtraJobs() {
263 XRenderPlugin *plugin = NULL;
264 XRenderRenderingJob job;
265
266 forEachPlugin(i, plugin) {
267 std::vector<XRenderRenderingJob> jobs = plugin->extraRenderingActions();
268 for (size_t j = 0; j < jobs.size(); j++) {
269 executeRenderingJob(jobs[j]);
270 }
271 plugin->postExtraRenderingActions();
272 }
273}
274
275// Render the reconfigure rectangle.
276void XRenderScreen::renderReconfigureRect() {
277 XRenderPlugin *plugin = NULL;
278 XRectangle rect = reconfigureRectangle();
279
280 XSetForeground(display(), m_back_buffer_picture->gcHandle(), XWhitePixel(display(), screenNumber()));
281 XSetFunction(display(), m_back_buffer_picture->gcHandle(), GXxor);
282 XSetLineAttributes(display(), m_back_buffer_picture->gcHandle(), 1, LineSolid, CapNotLast, JoinMiter);
283
284 forEachPlugin(i, plugin) {
285 plugin->recRectRenderingJobInit(rect, m_back_buffer_picture->gcHandle());
286 }
287 XDrawRectangles(display(), m_back_buffer_picture->drawableHandle(),
288 m_back_buffer_picture->gcHandle(), &rect, 1);
289}
290
291// Render a particular window onto the screen.
292void XRenderScreen::renderWindow(XRenderWindow &window) {
293 XRenderPlugin *plugin = NULL;
294 XRenderRenderingJob job;
295
296 // Update window contents.
297 if (window.isDamaged()) {
298 window.updateContents();
299 }
300
301 // This might happen if the window is mapped and unmapped in the same
302 // frame, but the compositor hasn't received the unmap event yet.
303 if ((window.contentPicture()->pictureHandle() == None)
304 || (window.maskPicture()->pictureHandle() == None)) {
305 return;
306 }
307
308 // Extra rendering actions before window is drawn.
309 forEachPlugin(i, plugin) {
310 std::vector<XRenderRenderingJob> jobs = plugin->preWindowRenderingActions(window);
311 for (size_t j = 0; j < jobs.size(); j++) {
312 executeRenderingJob(jobs[j]);
313 }
314 }
315
316 // Draw the window.
317 job.operation = PictOpOver;
318 job.source_picture = window.contentPicture();
319 job.mask_picture = window.maskPicture();
320 job.source_x = 0;
321 job.source_y = 0;
322 job.mask_x = 0;
323 job.mask_y = 0;
324 job.destination_x = window.x();
325 job.destination_y = window.y();
326 job.width = window.realWidth();
327 job.height = window.realHeight();
328
329 forEachPlugin(i, plugin) {
330 plugin->windowRenderingJobInit(window, job);
331 }
332 executeRenderingJob(job);
333
334 // Extra rendering actions after window is drawn.
335 forEachPlugin(i, plugin) {
336 std::vector<XRenderRenderingJob> jobs = plugin->postWindowRenderingActions(window);
337 for (size_t j = 0; j < jobs.size(); j++) {
338 executeRenderingJob(jobs[j]);
339 }
340 }
341}
342
343// Swap back and front buffers.
344void XRenderScreen::swapBuffers() {
345 XRenderComposite(display(), PictOpSrc, m_back_buffer_picture->pictureHandle(), None, m_rendering_picture->pictureHandle(),
346 0, 0, 0, 0, 0, 0, rootWindow().width(), rootWindow().height());
347}
348
349
350//--- SPECIALIZED WINDOW MANIPULATION FUNCTIONS --------------------------------
351
352// Creates a window object from its XID.
353BaseCompWindow *XRenderScreen::createWindowObject(Window window) {
354 XRenderWindow *new_window = new XRenderWindow(*this, window, m_pict_filter);
355 return new_window;
356}