aboutsummaryrefslogtreecommitdiff
path: root/util/fbcompose/XRenderScreen.cc
diff options
context:
space:
mode:
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}