Merge lp:~smspillaz/compiz-core/compiz-core.decor_sync_996901 into lp:compiz-core/0.9.8

Proposed by Sam Spilsbury
Status: Merged
Merged at revision: 3137
Proposed branch: lp:~smspillaz/compiz-core/compiz-core.decor_sync_996901
Merge into: lp:compiz-core/0.9.8
Diff against target: 1474 lines (+856/-67)
15 files modified
gtk/window-decorator/decorator.c (+55/-25)
gtk/window-decorator/events.c (+12/-1)
gtk/window-decorator/gtk-window-decorator.c (+9/-0)
gtk/window-decorator/gtk-window-decorator.h (+8/-0)
gtk/window-decorator/wnck.c (+13/-11)
include/decoration.h (+18/-0)
libdecoration/decoration.c (+86/-0)
plugins/decor/CMakeLists.txt (+3/-1)
plugins/decor/src/decor.cpp (+99/-22)
plugins/decor/src/decor.h (+35/-7)
plugins/decor/src/pixmap-requests/CMakeLists.txt (+62/-0)
plugins/decor/src/pixmap-requests/include/pixmap-requests.h (+188/-0)
plugins/decor/src/pixmap-requests/src/pixmap-requests.cpp (+93/-0)
plugins/decor/src/pixmap-requests/tests/CMakeLists.txt (+15/-0)
plugins/decor/src/pixmap-requests/tests/pixmap-requests/src/test-decor-pixmap-requests.cpp (+160/-0)
To merge this branch: bzr merge lp:~smspillaz/compiz-core/compiz-core.decor_sync_996901
Reviewer Review Type Date Requested Status
Daniel van Vugt Approve
Alan Griffiths Approve
Review via email: mp+105344@code.launchpad.net

Commit message

Add synchronization primitives to the decoration protocol so that there isn't
a race where we bind a texture that's being freed. (LP: #454218) (LP: #929989)

Also fix a crash in the first attempt at this (LP: #996901)

Description of the change

Add synchronization primitives to the decoration protocol so that there isn't a race where we bind a texture that's being freed.

Things changed

 * update_window_decoration_size made semi-private, users should use request_update_window_decoration_size instead, which prepares for a pixmap update and sends a message to the decorated process that a new pixmap is waiting.
 * decor_post_pending : tells the decorated process that a new decoration is pending
 * decor_post_request : tells the decorator that a new pixmap can be drawn to
 * decor_post_delete_pixmap : tells the decorator that a pixmap is no longer in use by the decorated process and can be deleted by the server

I also did some necessary refactoring so we could get this under test, namely:

DecorPixmap class (implements DecorPixmapInterface): a simple RAII class which ensures that a DecorPixmapDeletionInterface is invoked to delete the server side pixmap when the DecorPixmap class is destructed

X11DecorPixmapReceiver class (implements DecorPixmapReceiverInterface): a per-decoration owned class which tracks the update state of the pixmap owned by the decoration from the decorator, calls through to appropriate methods on a DecorPixmapRequestorInterface to request new pixmaps (ensuring that chattyness is reduced to when a) the decorator tells us that a new pixmap is ready and b) when a new pixmap was already pending and we need to fetch the newest one)

X11DecorPixmapRequestor class (implements DecorPixmapRequestorInterface): a per-window owned class which handles dispatch to the decorator (eg decor_post_pending) and requests from the decorator in _COMPIZ_DECOR_PENDING messages to communicate when decorations should be redrawn at new sizes

X11PixmapDeletor class (implements DecorPixmapDeletionInterface): a per-pixmap class which sends decor_post_delete_pixmap to the decorator when a pixmap is no longer in use by the decor plugin

DecorationListFindMatchingInterface: an interface implemented by DecorationList to find a decoration matching a specified criteria

DecorationInterface: an interface implemented by Decoration to get the receiver and properties about that decoration.

Tests included (Google Mock)

Resubmitted to cover a potential race condition in LP#996901

To post a comment you must log in.
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

Looks sensible - but so did the version that caused problems.

Revision history for this message
Sam Spilsbury (smspillaz) wrote :

> Looks sensible - but so did the version that caused problems.

A race condition in the untested part of the code. we should look into getting gtk-window-decorator under test thought I fear there might be some larger architectural changes there that we just don't have time to do :(

Revision history for this message
triplesqaurednine (triplesquarednine) wrote :

@Sam,

I just tested this branch and it works.

if you like i can still test r3131 to see what the actual problem was, but it would appear your changes in this branch work.

cheerz

Revision history for this message
Sam Spilsbury (smspillaz) wrote :

> @Sam,
>
> I just tested this branch and it works.
>
> if you like i can still test r3131 to see what the actual problem was, but it
> would appear your changes in this branch work.
>
> cheerz

It's probably worth mentioning as it would be a needle in the haystack in the diff due to the speedy revert

 635 if (!d->decorated)
 636 return FALSE;
 637

There was a race where a window could have its decoration resources freed by the time compiz got back to us about whether or not it was ok to re-update decorations.

As a side note, this particular part of the code has always suffered from such race conditions which can lead to random crashes. It is worth looking into a way that we can fix this, but like I said earlier, I fear that larger architectural changes may be required.

Revision history for this message
Alan Griffiths (alan-griffiths) :
review: Approve
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Unfortunately, I find gtk-window-decorator crashes with this branch whenever I minimize a window:

(gdb) bt
#0 max_window_name_width (win=0x243c0e0) at /home/dan/bzr/compiz-core/tmp.sync/gtk/window-decorator/decorator.c:420
#1 0x000000000041a377 in request_update_window_decoration_size (win=0x243c0e0) at /home/dan/bzr/compiz-core/tmp.sync/gtk/window-decorator/decorator.c:589
#2 0x00000000004173c7 in active_window_changed (screen=0x2366810) at /home/dan/bzr/compiz-core/tmp.sync/gtk/window-decorator/wnck.c:645
#3 0x00007fd8312ad354 in g_cclosure_marshal_VOID__OBJECTv () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#4 0x00007fd8312a9eca in ?? () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#5 0x00007fd8312c2741 in g_signal_emit_valist () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#6 0x00007fd8312c3242 in g_signal_emit () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#7 0x00007fd8329404d0 in ?? () from /usr/lib/libwnck-1.so.22
#8 0x00007fd8329413f4 in ?? () from /usr/lib/libwnck-1.so.22
#9 0x00007fd830fecc9a in g_main_context_dispatch () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#10 0x00007fd830fed060 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#11 0x00007fd830fed45a in g_main_loop_run () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#12 0x00007fd8324242f7 in gtk_main () from /usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0
#13 0x000000000040af84 in main (argc=2, argv=0x7fff0347f138) at /home/dan/bzr/compiz-core/tmp.sync/gtk/window-decorator/gtk-window-decorator.c:460
(gdb)

review: Needs Fixing
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

valgrind confirms the first memory error before the crash has the same stack as gdb reports above.

3134. By Sam Spilsbury

Also don't bother asking the compositor to update the decoration
when the window is undecorated anyways

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Approved revision 3134.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'gtk/window-decorator/decorator.c'
2--- gtk/window-decorator/decorator.c 2012-05-09 22:31:15 +0000
3+++ gtk/window-decorator/decorator.c 2012-05-15 07:20:22 +0000
4@@ -564,6 +564,52 @@
5 }
6 }
7
8+/*
9+ * request_update_window_decoration_size
10+ * Description: asks the rendering process to allow a size update
11+ * for pixmap synchronization */
12+
13+
14+gboolean
15+request_update_window_decoration_size (WnckWindow *win)
16+{
17+ decor_t *d;
18+ gint width, height;
19+ gint x, y, w, h, name_width;
20+
21+ if (win == NULL)
22+ return FALSE;
23+
24+ d = g_object_get_data (G_OBJECT (win), "decor");
25+
26+ if (!d->decorated)
27+ return FALSE;
28+
29+ /* Get the geometry of the window, we'll need it later */
30+ wnck_window_get_client_window_geometry (win, &x, &y, &w, &h);
31+
32+ /* Get the width of the name */
33+ name_width = max_window_name_width (win);
34+
35+ /* Ask the theme to tell us how much space it needs. If this is not successful
36+ * update the decoration name and return false */
37+ if (!(*theme_calc_decoration_size) (d, w, h, name_width, &width, &height))
38+ {
39+ update_window_decoration_name (win);
40+ return FALSE;
41+ }
42+
43+ d->width = width;
44+ d->height = height;
45+
46+ decor_post_pending (gdk_x11_display_get_xdisplay (gdk_display_get_default ()),
47+ wnck_window_get_xid (win),
48+ populate_frame_type (d),
49+ populate_frame_state (d),
50+ populate_frame_actions (d));
51+
52+ return TRUE;
53+}
54
55 /*
56 * update_window_decoration_size
57@@ -581,8 +627,6 @@
58 decor_t *d;
59 GdkPixmap *pixmap, *buffer_pixmap = NULL;
60 Picture picture;
61- gint width, height;
62- gint x, y, w, h, name_width;
63 Display *xdisplay;
64 XRenderPictFormat *format;
65
66@@ -591,30 +635,19 @@
67
68 d = g_object_get_data (G_OBJECT (win), "decor");
69
70+ if (!d->decorated)
71+ return FALSE;
72+
73 xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
74
75- /* Get the geometry of the window, we'll need it later */
76- wnck_window_get_client_window_geometry (win, &x, &y, &w, &h);
77-
78- /* Get the width of the name */
79- name_width = max_window_name_width (win);
80-
81- /* Ask the theme to tell us how much space it needs. If this is not successful
82- * update the decoration name and return false */
83- if (!(*theme_calc_decoration_size) (d, w, h, name_width, &width, &height))
84- {
85- update_window_decoration_name (win);
86- return FALSE;
87- }
88-
89 gdk_error_trap_push ();
90
91 /* Get the correct depth for the frame window in reparenting mode, otherwise
92 * enforce 32 */
93 if (d->frame_window)
94- pixmap = create_pixmap (width, height, d->frame->style_window_rgb);
95+ pixmap = create_pixmap (d->width, d->height, d->frame->style_window_rgb);
96 else
97- pixmap = create_pixmap (width, height, d->frame->style_window_rgba);
98+ pixmap = create_pixmap (d->width, d->height, d->frame->style_window_rgba);
99
100 gdk_flush ();
101
102@@ -628,9 +661,9 @@
103 gdk_error_trap_push ();
104
105 if (d->frame_window)
106- buffer_pixmap = create_pixmap (width, height, d->frame->style_window_rgb);
107+ buffer_pixmap = create_pixmap (d->width, d->height, d->frame->style_window_rgb);
108 else
109- buffer_pixmap = create_pixmap (width, height, d->frame->style_window_rgba);
110+ buffer_pixmap = create_pixmap (d->width, d->height, d->frame->style_window_rgba);
111
112 gdk_flush ();
113
114@@ -649,7 +682,7 @@
115
116 /* Destroy the old pixmaps and pictures */
117 if (d->pixmap)
118- g_object_unref (G_OBJECT (d->pixmap));
119+ g_hash_table_insert (destroyed_pixmaps_table, GINT_TO_POINTER (GDK_PIXMAP_XID (d->pixmap)), d->pixmap);
120
121 if (d->buffer_pixmap)
122 g_object_unref (G_OBJECT (d->buffer_pixmap));
123@@ -667,9 +700,6 @@
124
125 d->picture = picture;
126
127- d->width = width;
128- d->height = height;
129-
130 d->prop_xid = wnck_window_get_xid (win);
131
132 update_window_decoration_name (win);
133@@ -1205,7 +1235,7 @@
134 d->context = NULL;
135 d->width = d->height = 0;
136
137- update_window_decoration_size (win);
138+ request_update_window_decoration_size (win);
139 update_event_windows (win);
140 }
141 }
142
143=== modified file 'gtk/window-decorator/events.c'
144--- gtk/window-decorator/events.c 2012-05-09 22:31:15 +0000
145+++ gtk/window-decorator/events.c 2012-05-15 07:20:22 +0000
146@@ -1014,7 +1014,7 @@
147 update_window_decoration_state (win);
148 update_window_decoration_actions (win);
149 update_window_decoration_icon (win);
150- update_window_decoration_size (win);
151+ request_update_window_decoration_size (win);
152 update_event_windows (win);
153 }
154 else
155@@ -1069,6 +1069,17 @@
156 }
157 }
158 }
159+ else if (xevent->xclient.message_type == decor_request_atom)
160+ {
161+ WnckWindow *win = wnck_window_get (xevent->xclient.window);
162+
163+ if (win)
164+ update_window_decoration_size (win);
165+ }
166+ else if (xevent->xclient.message_type == decor_delete_pixmap_atom)
167+ {
168+ g_hash_table_remove (destroyed_pixmaps_table, GINT_TO_POINTER (xevent->xclient.data.l[0]));
169+ }
170 default:
171 break;
172 }
173
174=== modified file 'gtk/window-decorator/gtk-window-decorator.c'
175--- gtk/window-decorator/gtk-window-decorator.c 2012-05-09 22:31:15 +0000
176+++ gtk/window-decorator/gtk-window-decorator.c 2012-05-15 07:20:22 +0000
177@@ -48,6 +48,9 @@
178 Atom toolkit_action_atom;
179 Atom toolkit_action_window_menu_atom;
180 Atom toolkit_action_force_quit_dialog_atom;
181+Atom decor_request_atom;
182+Atom decor_pending_atom;
183+Atom decor_delete_pixmap_atom;
184
185 Atom net_wm_state_atom;
186 Atom net_wm_state_modal_atom;
187@@ -103,6 +106,7 @@
188 GtkWidget *switcher_label;
189
190 GHashTable *frame_table;
191+GHashTable *destroyed_pixmaps_table;
192 GtkWidget *action_menu = NULL;
193 gboolean action_menu_mapped = FALSE;
194 decor_color_t _title_color[2];
195@@ -305,6 +309,10 @@
196 net_wm_state_atom = XInternAtom (xdisplay,"_NET_WM_STATE", 0);
197 net_wm_state_modal_atom = XInternAtom (xdisplay, "_NET_WM_STATE_MODAL", 0);
198
199+ decor_request_atom = XInternAtom (xdisplay, "_COMPIZ_DECOR_REQUEST", 0);
200+ decor_pending_atom = XInternAtom (xdisplay, "_COMPIZ_DECOR_PENDING", 0);
201+ decor_delete_pixmap_atom = XInternAtom (xdisplay, "_COMPIZ_DECOR_DELETE_PIXMAP", 0);
202+
203 status = decor_acquire_dm_session (xdisplay,
204 gdk_screen_get_number (gdkscreen),
205 "gwd", replace, &dm_sn_timestamp);
206@@ -390,6 +398,7 @@
207 xformat_rgb = XRenderFindStandardFormat (xdisplay, PictStandardRGB24);
208
209 frame_table = g_hash_table_new (NULL, NULL);
210+ destroyed_pixmaps_table = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref);
211
212 if (!create_tooltip_window ())
213 {
214
215=== modified file 'gtk/window-decorator/gtk-window-decorator.h'
216--- gtk/window-decorator/gtk-window-decorator.h 2012-05-09 22:31:15 +0000
217+++ gtk/window-decorator/gtk-window-decorator.h 2012-05-15 07:20:22 +0000
218@@ -306,6 +306,9 @@
219 extern Atom toolkit_action_force_quit_dialog_atom;
220 extern Atom net_wm_state_atom;
221 extern Atom net_wm_state_modal_atom;
222+extern Atom decor_request_atom;
223+extern Atom decor_pending_atom;
224+extern Atom decor_delete_pixmap_atom;
225
226 extern Time dm_sn_timestamp;
227
228@@ -511,6 +514,7 @@
229
230 /* list of all decorations */
231 extern GHashTable *frame_table;
232+extern GHashTable *destroyed_pixmaps_table;
233
234 /* action menu */
235 extern GtkWidget *action_menu;
236@@ -628,9 +632,13 @@
237 void
238 destroy_bare_frame ();
239
240+/* Don't use directly */
241 gboolean
242 update_window_decoration_size (WnckWindow *win);
243
244+gboolean
245+request_update_window_decoration_size (WnckWindow *win);
246+
247 void
248 update_window_decoration_name (WnckWindow *win);
249
250
251=== modified file 'gtk/window-decorator/wnck.c'
252--- gtk/window-decorator/wnck.c 2012-05-09 22:31:15 +0000
253+++ gtk/window-decorator/wnck.c 2012-05-15 07:20:22 +0000
254@@ -80,7 +80,7 @@
255
256 if (d->decorated)
257 {
258- if (!update_window_decoration_size (win))
259+ if (!request_update_window_decoration_size (win))
260 queue_decor_draw (d);
261 }
262 }
263@@ -102,7 +102,7 @@
264 d->client_width = width;
265 d->client_height = height;
266
267- update_window_decoration_size (win);
268+ request_update_window_decoration_size (win);
269 update_event_windows (win);
270 }
271 }
272@@ -128,7 +128,7 @@
273 if (d->decorated)
274 {
275 update_window_decoration_state (win);
276- if (!update_window_decoration_size (win))
277+ if (!request_update_window_decoration_size (win))
278 queue_decor_draw (d);
279
280 update_event_windows (win);
281@@ -143,7 +143,7 @@
282 if (d->decorated)
283 {
284 update_window_decoration_actions (win);
285- if (!update_window_decoration_size (win))
286+ if (!request_update_window_decoration_size (win))
287 queue_decor_draw (d);
288
289 update_event_windows (win);
290@@ -422,7 +422,7 @@
291 update_window_decoration_state (win);
292 update_window_decoration_actions (win);
293 update_window_decoration_icon (win);
294- update_window_decoration_size (win);
295+ request_update_window_decoration_size (win);
296
297 update_event_windows (win);
298 }
299@@ -585,7 +585,7 @@
300 if (win)
301 {
302 d = g_object_get_data (G_OBJECT (win), "decor");
303- if (d && d->pixmap)
304+ if (d)
305 {
306 d->active = wnck_window_is_active (win);
307
308@@ -642,8 +642,9 @@
309 * then we need to redraw the decoration anyways
310 * since the image would have changed */
311 if (d->win != NULL &&
312- !update_window_decoration_size (d->win) &&
313- d->decorated)
314+ !request_update_window_decoration_size (d->win) &&
315+ d->decorated &&
316+ d->pixmap)
317 queue_decor_draw (d);
318
319 }
320@@ -653,7 +654,7 @@
321 if (win)
322 {
323 d = g_object_get_data (G_OBJECT (win), "decor");
324- if (d && d->pixmap)
325+ if (d)
326 {
327 d->active = wnck_window_is_active (win);
328
329@@ -710,8 +711,9 @@
330 * then we need to redraw the decoration anyways
331 * since the image would have changed */
332 if (d->win != NULL &&
333- !update_window_decoration_size (d->win) &&
334- d->decorated)
335+ !request_update_window_decoration_size (d->win) &&
336+ d->decorated &&
337+ d->pixmap)
338 queue_decor_draw (d);
339
340 }
341
342=== modified file 'include/decoration.h'
343--- include/decoration.h 2012-05-09 22:31:15 +0000
344+++ include/decoration.h 2012-05-15 07:20:22 +0000
345@@ -492,6 +492,24 @@
346 XEvent *event,
347 Time dm_sn_timestamp);
348
349+int
350+decor_post_pending (Display *xdisplay,
351+ Window client,
352+ unsigned int frame_state,
353+ unsigned int frame_type,
354+ unsigned int frame_actions);
355+
356+int
357+decor_post_delete_pixmap (Display *xdisplay,
358+ Pixmap pixmap);
359+
360+int
361+decor_post_generate_request (Display *xdisplay,
362+ Window client,
363+ unsigned int frame_type,
364+ unsigned int frame_state,
365+ unsigned int frame_actions);
366+
367 #ifdef __cplusplus
368 }
369 #endif
370
371=== modified file 'libdecoration/decoration.c'
372--- libdecoration/decoration.c 2012-05-09 22:31:15 +0000
373+++ libdecoration/decoration.c 2012-05-15 07:20:22 +0000
374@@ -2877,6 +2877,92 @@
375 }
376
377 int
378+decor_post_pending (Display *xdisplay,
379+ Window client,
380+ unsigned int frame_state,
381+ unsigned int frame_type,
382+ unsigned int frame_actions)
383+{
384+ XEvent event;
385+
386+ Atom decor_pending = XInternAtom (xdisplay, "_COMPIZ_DECOR_PENDING", FALSE);
387+
388+ /* Send a client message indicating that a new
389+ * decoration can be generated for this window
390+ */
391+ event.xclient.type = ClientMessage;
392+ event.xclient.window = client;
393+ event.xclient.message_type = decor_pending;
394+ event.xclient.format = 32;
395+ event.xclient.data.l[0] = frame_type;
396+ event.xclient.data.l[1] = frame_state;
397+ event.xclient.data.l[2] = frame_actions;
398+ event.xclient.data.l[3] = 0;
399+ event.xclient.data.l[4] = 0;
400+
401+ XSendEvent (xdisplay, DefaultRootWindow (xdisplay), 0,
402+ StructureNotifyMask, &event);
403+
404+ return 1;
405+}
406+
407+int
408+decor_post_generate_request (Display *xdisplay,
409+ Window client,
410+ unsigned int frame_type,
411+ unsigned int frame_state,
412+ unsigned int frame_actions)
413+{
414+ XEvent event;
415+
416+ Atom decor_request = XInternAtom (xdisplay, "_COMPIZ_DECOR_REQUEST", FALSE);
417+
418+ /* Send a client message indicating that a new
419+ * decoration can be generated for this window
420+ */
421+ event.xclient.type = ClientMessage;
422+ event.xclient.window = client;
423+ event.xclient.message_type = decor_request;
424+ event.xclient.format = 32;
425+ event.xclient.data.l[0] = frame_type;
426+ event.xclient.data.l[1] = frame_state;
427+ event.xclient.data.l[2] = frame_actions;
428+ event.xclient.data.l[3] = 0;
429+ event.xclient.data.l[4] = 0;
430+
431+ XSendEvent (xdisplay, DefaultRootWindow (xdisplay), 0,
432+ StructureNotifyMask, &event);
433+
434+ return 1;
435+}
436+
437+int
438+decor_post_delete_pixmap (Display *xdisplay,
439+ Pixmap pixmap)
440+{
441+ XEvent event;
442+
443+ Atom decor_delete_pixmap = XInternAtom (xdisplay, "_COMPIZ_DECOR_DELETE_PIXMAP", FALSE);
444+
445+ /* Send a client message indicating that a new
446+ * decoration can be generated for this window
447+ */
448+ event.xclient.type = ClientMessage;
449+ event.xclient.window = DefaultRootWindow (xdisplay);
450+ event.xclient.message_type = decor_delete_pixmap;
451+ event.xclient.format = 32;
452+ event.xclient.data.l[0] = pixmap;
453+ event.xclient.data.l[1] = 0;
454+ event.xclient.data.l[2] = 0;
455+ event.xclient.data.l[3] = 0;
456+ event.xclient.data.l[4] = 0;
457+
458+ XSendEvent (xdisplay, DefaultRootWindow (xdisplay), 0,
459+ StructureNotifyMask, &event);
460+
461+ return 1;
462+}
463+int
464 decor_acquire_dm_session (Display *xdisplay,
465 int screen,
466 const char *name,
467
468=== modified file 'plugins/decor/CMakeLists.txt'
469--- plugins/decor/CMakeLists.txt 2012-05-09 22:31:15 +0000
470+++ plugins/decor/CMakeLists.txt 2012-05-15 07:20:22 +0000
471@@ -4,10 +4,12 @@
472 include (CompizCommon)
473
474 include_directories (${CMAKE_CURRENT_SOURCE_DIR}/src/clip-groups/include/)
475+include_directories (${CMAKE_CURRENT_SOURCE_DIR}/src/pixmap-requests/include/)
476
477-compiz_plugin(decor PLUGINDEPS composite opengl LIBRARIES decoration compiz_decor_clip_groups)
478+compiz_plugin(decor PLUGINDEPS composite opengl LIBRARIES decoration compiz_decor_clip_groups compiz_decor_pixmap_requests)
479
480 add_subdirectory (src/clip-groups)
481+add_subdirectory (src/pixmap-requests)
482
483 if (COMPIZ_BUILD_WITH_RPATH AND NOT COMPIZ_DISABLE_PLUGIN_DECOR)
484
485
486=== modified file 'plugins/decor/src/decor.cpp'
487--- plugins/decor/src/decor.cpp 2012-05-09 22:31:15 +0000
488+++ plugins/decor/src/decor.cpp 2012-05-15 07:20:22 +0000
489@@ -311,7 +311,6 @@
490 }
491
492 static bool bindFailed;
493-
494 /*
495 * DecorTexture::DecorTexture
496 *
497@@ -322,7 +321,7 @@
498 * for this pixmap
499 */
500
501-DecorTexture::DecorTexture (Pixmap pixmap) :
502+DecorTexture::DecorTexture (DecorPixmapInterface::Ptr pixmap) :
503 status (true),
504 refCount (1),
505 pixmap (pixmap),
506@@ -332,7 +331,7 @@
507 Window root;
508 int i;
509
510- if (!XGetGeometry (screen->dpy (), pixmap, &root,
511+ if (!XGetGeometry (screen->dpy (), pixmap->getPixmap (), &root,
512 &i, &i, &width, &height, &ui, &depth))
513 {
514 status = false;
515@@ -340,7 +339,7 @@
516 }
517
518 bindFailed = false;
519- textures = GLTexture::bindPixmapToTexture (pixmap, width, height, depth);
520+ textures = GLTexture::bindPixmapToTexture (pixmap->getPixmap (), width, height, depth);
521 if (textures.size () != 1)
522 {
523 bindFailed = true;
524@@ -351,7 +350,7 @@
525 if (!DecorScreen::get (screen)->optionGetMipmap ())
526 textures[0]->setMipmap (false);
527
528- damage = XDamageCreate (screen->dpy (), pixmap,
529+ damage = XDamageCreate (screen->dpy (), pixmap->getPixmap (),
530 XDamageReportRawRectangles);
531 }
532
533@@ -386,13 +385,16 @@
534 return NULL;
535
536 foreach (DecorTexture *t, textures)
537- if (t->pixmap == pixmap)
538+ if (t->pixmap->getPixmap () == pixmap)
539 {
540 t->refCount++;
541 return t;
542 }
543
544- DecorTexture *texture = new DecorTexture (pixmap);
545+ X11PixmapDeletor::Ptr dl = boost::make_shared <X11PixmapDeletor> (screen->dpy ());
546+ DecorPixmap::Ptr pm = boost::make_shared <DecorPixmap> (pixmap, dl);
547+
548+ DecorTexture *texture = new DecorTexture (boost::shared_static_cast <DecorPixmapInterface> (pm));
549
550 if (!texture->status)
551 {
552@@ -528,7 +530,8 @@
553 long *prop,
554 unsigned int size,
555 unsigned int type,
556- unsigned int nOffset)
557+ unsigned int nOffset,
558+ DecorPixmapRequestorInterface *requestor)
559 {
560 unsigned int frameType, frameState, frameActions;
561 Pixmap pixmap = None;
562@@ -576,7 +579,7 @@
563 throw std::exception ();
564 }
565
566- return Decoration::Ptr (new Decoration (type, border, input, maxBorder, maxInput, frameType, frameState, frameActions, minWidth, minHeight, pixmap, quad, nQuad));
567+ return Decoration::Ptr (new Decoration (type, border, input, maxBorder, maxInput, frameType, frameState, frameActions, minWidth, minHeight, pixmap, quad, nQuad, id, requestor));
568 }
569
570 Decoration::Decoration (int type,
571@@ -591,7 +594,9 @@
572 unsigned int minHeight,
573 Pixmap pixmap,
574 const boost::shared_array <decor_quad_t> &quad,
575- unsigned int nQuad) :
576+ unsigned int nQuad,
577+ Window owner,
578+ DecorPixmapRequestorInterface *requestor) :
579 texture (DecorScreen::get (screen)->getTexture (pixmap)),
580 border (border.left, border.right, border.top, border.bottom),
581 input (input.left, input.right, input.top, input.bottom),
582@@ -604,7 +609,9 @@
583 frameActions (frameActions),
584 quad (quad),
585 nQuad (nQuad),
586- type (type)
587+ type (type),
588+ updateState (0),
589+ mPixmapReceiver (requestor, this)
590 {
591 int left, right, top, bottom;
592 int x1, y1, x2, y2;
593@@ -665,6 +672,30 @@
594 DecorScreen::get (screen)->releaseTexture (texture);
595 }
596
597+DecorPixmapReceiverInterface &
598+Decoration::receiverInterface ()
599+{
600+ return mPixmapReceiver;
601+}
602+
603+unsigned int
604+Decoration::getFrameType () const
605+{
606+ return frameType;
607+}
608+
609+unsigned int
610+Decoration::getFrameState () const
611+{
612+ return frameState;
613+}
614+
615+unsigned int
616+Decoration::getFrameActions () const
617+{
618+ return frameActions;
619+}
620+
621 /*
622 * DecorationList is a class which allows multiple decorations
623 * to be stored in a list and read from a window property, which
624@@ -700,7 +731,8 @@
625
626 bool
627 DecorationList::updateDecoration (Window id,
628- Atom decorAtom)
629+ Atom decorAtom,
630+ DecorPixmapRequestorInterface *requestor)
631 {
632 unsigned long n, nleft;
633 unsigned char *data;
634@@ -709,6 +741,12 @@
635 int result, format;
636 unsigned int type;
637
638+ /* Dispatch any new updates */
639+ foreach (const Decoration::Ptr &d, mList)
640+ {
641+ d->mPixmapReceiver.update ();
642+ }
643+
644 result = XGetWindowProperty (screen->dpy (), id,
645 decorAtom, 0L,
646 PROP_HEADER_SIZE + 6 * (BASE_PROP_SIZE +
647@@ -778,7 +816,9 @@
648 maxBorder.top = d->maxBorder.top;
649 maxBorder.bottom = d->maxBorder.bottom;
650
651- int num = decor_match_pixmap (prop, n, &d->texture->pixmap, &input, &border, &maxInput, &maxBorder,
652+ Pixmap pm = d->texture->pixmap->getPixmap ();
653+
654+ int num = decor_match_pixmap (prop, n, &pm, &input, &border, &maxInput, &maxBorder,
655 d->minWidth, d->minHeight, d->frameType, d->frameState, d->frameActions,
656 d->quad.get (), d->nQuad);
657 if (num != -1)
658@@ -796,7 +836,7 @@
659 try
660 {
661 std::list <Decoration::Ptr>::iterator it = mList.begin ();
662- Decoration::Ptr d = Decoration::create (id, prop, n, type, i);
663+ Decoration::Ptr d = Decoration::create (id, prop, n, type, i, requestor);
664
665 /* Try to replace an existing decoration */
666 for (; it != mList.end (); it++)
667@@ -881,7 +921,7 @@
668 {
669 bindFailed = false;
670
671- decor.updateDecoration (window->id (), dScreen->winDecorAtom);
672+ decor.updateDecoration (window->id (), dScreen->winDecorAtom, &mRequestor);
673 if (bindFailed)
674 pixmapFailed = true;
675 else
676@@ -1250,6 +1290,22 @@
677 return (decorActions == 0);
678 }
679
680+DecorationInterface::Ptr
681+DecorationList::findMatchingDecoration (unsigned int frameType,
682+ unsigned int frameState,
683+ unsigned int frameActions)
684+{
685+ foreach (const Decoration::Ptr &d, mList)
686+ {
687+ if (d->frameType == frameType &&
688+ d->frameState == frameState &&
689+ d->frameActions == frameActions)
690+ return boost::shared_static_cast <DecorationInterface> (d);
691+ }
692+
693+ return DecorationInterface::Ptr ();
694+}
695+
696 /*
697 * DecorationList::findMatchingDecoration
698 *
699@@ -2074,7 +2130,7 @@
700 {
701 for (i = 0; i < DECOR_NUM; i++)
702 {
703- decor[i].updateDecoration (screen->root (), decorAtom[i]);
704+ decor[i].updateDecoration (screen->root (), decorAtom[i], &mRequestor);
705 }
706 }
707 else
708@@ -2286,6 +2342,7 @@
709 isSwitcher = false;
710 }
711
712+
713 /*
714 * DecorScreen::handleEvent
715 *
716@@ -2320,6 +2377,18 @@
717 if (w)
718 DecorWindow::get (w)->update (true);
719 }
720+ /* A decoration is pending creation, allow it to be created */
721+ if (event->xclient.message_type == decorPendingAtom)
722+ {
723+ CompWindow *w = screen->findWindow (event->xclient.window);
724+
725+ if (w)
726+ {
727+ DecorWindow *dw = DecorWindow::get (w);
728+
729+ dw->mRequestor.handlePending (event->xclient.data.l);
730+ }
731+ }
732 default:
733 /* Check for damage events. If the output or input window
734 * or a texture is updated then damage output extents.
735@@ -2334,7 +2403,7 @@
736
737 foreach (DecorTexture *t, textures)
738 {
739- if (t->pixmap == de->drawable)
740+ if (t->pixmap->getPixmap () == de->drawable)
741 {
742 foreach (CompWindow *w, screen->windows ())
743 {
744@@ -2394,7 +2463,6 @@
745 DECOR_WINDOW (w);
746
747 dw->updateDecoration ();
748-
749 dw->update (true);
750 }
751 }
752@@ -2427,7 +2495,8 @@
753 if (event->xproperty.atom == decorAtom[i])
754 {
755 decor[i].updateDecoration (screen->root (),
756- decorAtom[i]);
757+ decorAtom[i],
758+ &mRequestor);
759
760 foreach (CompWindow *w, screen->windows ())
761 DecorWindow::get (w)->update (true);
762@@ -2944,8 +3013,11 @@
763 0,
764 None,
765 boost::shared_array <decor_quad_t> (NULL),
766- 0)),
767- mMenusClipGroup (CompMatch ("type=Dock | type=DropdownMenu | type=PopupMenu"))
768+ 0,
769+ screen->root (),
770+ NULL)),
771+ mMenusClipGroup (CompMatch ("type=Dock | type=DropdownMenu | type=PopupMenu")),
772+ mRequestor (screen->dpy (), screen->root (), &(decor[DECOR_ACTIVE]))
773 {
774 supportingDmCheckAtom =
775 XInternAtom (s->dpy (), DECOR_SUPPORTING_DM_CHECK_ATOM_NAME, 0);
776@@ -2967,6 +3039,10 @@
777 XInternAtom (s->dpy (), DECOR_TYPE_WINDOW_ATOM_NAME, 0);
778 decorSwitchWindowAtom =
779 XInternAtom (s->dpy (), DECOR_SWITCH_WINDOW_ATOM_NAME, 0);
780+ decorPendingAtom =
781+ XInternAtom (s->dpy (), "_COMPIZ_DECOR_PENDING", 0);
782+ decorRequestAtom =
783+ XInternAtom (s->dpy (), "_COMPIZ_DECOR_REQUEST", 0);
784 requestFrameExtentsAtom =
785 XInternAtom (s->dpy (), "_NET_REQUEST_FRAME_EXTENTS", 0);
786 shadowColorAtom =
787@@ -3023,7 +3099,8 @@
788 frameExtentsRequested (false),
789 mClipGroup (NULL),
790 mOutputRegion (window->outputRect ()),
791- mInputRegion (window->inputRect ())
792+ mInputRegion (window->inputRect ()),
793+ mRequestor (screen->dpy (), w->id (), &decor)
794 {
795 WindowInterface::setHandler (window);
796
797
798=== modified file 'plugins/decor/src/decor.h'
799--- plugins/decor/src/decor.h 2012-05-09 22:31:15 +0000
800+++ plugins/decor/src/decor.h 2012-05-15 07:20:22 +0000
801@@ -25,6 +25,7 @@
802
803 #include <boost/shared_ptr.hpp>
804 #include <boost/shared_array.hpp>
805+#include <boost/make_shared.hpp>
806 #include <core/window.h>
807 #include <core/pluginclasshandler.h>
808
809@@ -34,6 +35,7 @@
810 #include <core/windowextents.h>
811
812 #include <clip-groups.h>
813+#include <pixmap-requests.h>
814
815 #include "decor_options.h"
816
817@@ -76,30 +78,36 @@
818 class DecorTexture {
819
820 public:
821- DecorTexture (Pixmap pixmap);
822+ DecorTexture (DecorPixmapInterface::Ptr pixmap);
823 ~DecorTexture ();
824
825 public:
826 bool status;
827 int refCount;
828- Pixmap pixmap;
829+ DecorPixmapInterface::Ptr pixmap;
830 Damage damage;
831 GLTexture::List textures;
832 };
833
834 class DecorWindow;
835
836-class Decoration {
837+class Decoration :
838+ public DecorationInterface
839+{
840
841 public:
842
843 typedef boost::shared_ptr <Decoration> Ptr;
844
845+ static const unsigned int UpdateRequested = 1 << 0;
846+ static const unsigned int UpdatesPending = 1 << 1;
847+
848 static Decoration::Ptr create (Window id,
849 long *prop,
850 unsigned int size,
851 unsigned int type,
852- unsigned int nOffset);
853+ unsigned int nOffset,
854+ DecorPixmapRequestorInterface *requestor);
855
856 Decoration (int type,
857 const decor_extents_t &border,
858@@ -113,10 +121,18 @@
859 unsigned int minHeight,
860 Pixmap pixmap,
861 const boost::shared_array <decor_quad_t> &quad,
862- unsigned int nQuad);
863+ unsigned int nQuad,
864+ Window owner,
865+ DecorPixmapRequestorInterface *);
866
867 ~Decoration ();
868
869+ DecorPixmapReceiverInterface & receiverInterface ();
870+
871+ unsigned int getFrameType () const;
872+ unsigned int getFrameState () const;
873+ unsigned int getFrameActions () const;
874+
875 public:
876 int refCount;
877 DecorTexture *texture;
878@@ -133,12 +149,19 @@
879 boost::shared_array <decor_quad_t> quad;
880 int nQuad;
881 int type;
882+
883+ unsigned int updateState;
884+ X11DecorPixmapReceiver mPixmapReceiver;
885 };
886
887-class DecorationList
888+class DecorationList :
889+ public DecorationListFindMatchingInterface
890 {
891 public:
892- bool updateDecoration (Window id, Atom decorAtom);
893+ bool updateDecoration (Window id, Atom decorAtom, DecorPixmapRequestorInterface *requestor);
894+ DecorationInterface::Ptr findMatchingDecoration(unsigned int frameType,
895+ unsigned int frameState,
896+ unsigned int frameActions);
897 const Decoration::Ptr & findMatchingDecoration (CompWindow *w, bool sizeCheck);
898 void clear ()
899 {
900@@ -215,6 +238,8 @@
901 Atom shadowColorAtom;
902 Atom shadowInfoAtom;
903 Atom decorSwitchWindowAtom;
904+ Atom decorPendingAtom;
905+ Atom decorRequestAtom;
906
907 Window dmWin;
908 int dmSupports;
909@@ -229,6 +254,7 @@
910 CompTimer decoratorStart;
911
912 MatchedDecorClipGroup mMenusClipGroup;
913+ X11DecorPixmapRequestor mRequestor;
914 };
915
916 class DecorWindow :
917@@ -334,6 +360,8 @@
918 DecorClipGroupInterface *mClipGroup;
919 CompRegion mOutputRegion;
920 CompRegion mInputRegion;
921+
922+ X11DecorPixmapRequestor mRequestor;
923 };
924
925 class DecorPluginVTable :
926
927=== added directory 'plugins/decor/src/pixmap-requests'
928=== added file 'plugins/decor/src/pixmap-requests/CMakeLists.txt'
929--- plugins/decor/src/pixmap-requests/CMakeLists.txt 1970-01-01 00:00:00 +0000
930+++ plugins/decor/src/pixmap-requests/CMakeLists.txt 2012-05-15 07:20:22 +0000
931@@ -0,0 +1,62 @@
932+pkg_check_modules (
933+ GLIBMM
934+ REQUIRED
935+ glibmm-2.4 glib-2.0
936+)
937+
938+INCLUDE_DIRECTORIES (
939+ ${CMAKE_CURRENT_SOURCE_DIR}/include
940+ ${CMAKE_CURRENT_SOURCE_DIR}/src
941+
942+ ${compiz_SOURCE_DIR}/src/point/include
943+ ${compiz_SOURCE_DIR}/src/rect/include
944+ ${compiz_SOURCE_DIR}/src/window/geometry/include
945+ ${compiz_SOURCE_DIR}/src/window/geometry-saver/include
946+ ${compiz_SOURCE_DIR}/src/window/extents/include
947+ ${compiz_SOURCE_DIR}/include
948+
949+ ${Boost_INCLUDE_DIRS}
950+
951+ ${GLIBMM_INCLUDE_DIRS}
952+)
953+
954+LINK_DIRECTORIES (${GLIBMM_LIBRARY_DIRS})
955+
956+SET (
957+ PUBLIC_HEADERS
958+)
959+
960+SET (
961+ PRIVATE_HEADERS
962+ ${CMAKE_CURRENT_SOURCE_DIR}/include/pixmap-requests.h
963+)
964+
965+SET(
966+ SRCS
967+ ${CMAKE_CURRENT_SOURCE_DIR}/src/pixmap-requests.cpp
968+)
969+
970+ADD_LIBRARY(
971+ compiz_decor_pixmap_requests STATIC
972+
973+ ${SRCS}
974+
975+ ${PUBLIC_HEADERS}
976+ ${PRIVATE_HEADERS}
977+)
978+
979+if (COMPIZ_BUILD_TESTING)
980+ADD_SUBDIRECTORY( ${CMAKE_CURRENT_SOURCE_DIR}/tests )
981+endif (COMPIZ_BUILD_TESTING)
982+
983+SET_TARGET_PROPERTIES(
984+ compiz_decor_pixmap_requests PROPERTIES
985+ PUBLIC_HEADER "${PUBLIC_HEADERS}"
986+)
987+
988+TARGET_LINK_LIBRARIES(
989+ compiz_decor_pixmap_requests
990+
991+ compiz_core
992+ ${GLIBMM_LIBRARIES}
993+)
994
995=== added directory 'plugins/decor/src/pixmap-requests/include'
996=== added file 'plugins/decor/src/pixmap-requests/include/pixmap-requests.h'
997--- plugins/decor/src/pixmap-requests/include/pixmap-requests.h 1970-01-01 00:00:00 +0000
998+++ plugins/decor/src/pixmap-requests/include/pixmap-requests.h 2012-05-15 07:20:22 +0000
999@@ -0,0 +1,188 @@
1000+/*
1001+ * Copyright © 2005 Novell, Inc.
1002+ *
1003+ * Permission to use, copy, modify, distribute, and sell this software
1004+ * and its documentation for any purpose is hereby granted without
1005+ * fee, provided that the above copyright notice appear in all copies
1006+ * and that both that copyright notice and this permission notice
1007+ * appear in supporting documentation, and that the name of
1008+ * Novell, Inc. not be used in advertising or publicity pertaining to
1009+ * distribution of the software without specific, written prior permission.
1010+ * Novell, Inc. makes no representations about the suitability of this
1011+ * software for any purpose. It is provided "as is" without express or
1012+ * implied warranty.
1013+ *
1014+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1015+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
1016+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1017+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
1018+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
1019+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
1020+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1021+ *
1022+ * Author: David Reveman <davidr@novell.com>
1023+ */
1024+
1025+#ifndef _COMPIZ_DECOR_PIXMAP_REQUESTS_H
1026+#define _COMPIZ_DECOR_PIXMAP_REQUESTS_H
1027+
1028+#include <boost/shared_ptr.hpp>
1029+#include <boost/shared_array.hpp>
1030+#include <boost/make_shared.hpp>
1031+#include <decoration.h>
1032+
1033+#include <X11/Xlib.h>
1034+
1035+class DecorPixmapInterface
1036+{
1037+ public:
1038+
1039+ typedef boost::shared_ptr <DecorPixmapInterface> Ptr;
1040+
1041+ virtual ~DecorPixmapInterface () {};
1042+
1043+ virtual Pixmap getPixmap () = 0;
1044+};
1045+
1046+class DecorPixmapReceiverInterface
1047+{
1048+ public:
1049+
1050+ virtual ~DecorPixmapReceiverInterface () {}
1051+
1052+ virtual void pending () = 0;
1053+ virtual void update () = 0;
1054+};
1055+
1056+/* So far, nothing particularly interesting here
1057+ * we just need a way to pass around pointers for
1058+ * testing */
1059+class DecorationInterface
1060+{
1061+ public:
1062+
1063+ typedef boost::shared_ptr <DecorationInterface> Ptr;
1064+
1065+ virtual ~DecorationInterface () {}
1066+
1067+ virtual DecorPixmapReceiverInterface & receiverInterface () = 0;
1068+ virtual unsigned int getFrameType () const = 0;
1069+ virtual unsigned int getFrameState () const = 0;
1070+ virtual unsigned int getFrameActions () const = 0;
1071+};
1072+
1073+class DecorPixmapDeletionInterface
1074+{
1075+ public:
1076+
1077+ typedef boost::shared_ptr <DecorPixmapDeletionInterface> Ptr;
1078+
1079+ virtual ~DecorPixmapDeletionInterface () {}
1080+
1081+ virtual int postDeletePixmap (Pixmap pixmap) = 0;
1082+};
1083+
1084+class X11PixmapDeletor :
1085+ public DecorPixmapDeletionInterface
1086+{
1087+ public:
1088+
1089+ typedef boost::shared_ptr <X11PixmapDeletor> Ptr;
1090+
1091+ X11PixmapDeletor (Display *dpy) :
1092+ mDisplay (dpy)
1093+ {
1094+ }
1095+
1096+ int postDeletePixmap (Pixmap pixmap) { return decor_post_delete_pixmap (mDisplay, pixmap); }
1097+
1098+ private:
1099+
1100+ Display *mDisplay;
1101+};
1102+
1103+class DecorPixmap :
1104+ public DecorPixmapInterface
1105+{
1106+ public:
1107+
1108+ typedef boost::shared_ptr <DecorPixmap> Ptr;
1109+
1110+ DecorPixmap (Pixmap p, DecorPixmapDeletionInterface::Ptr deletor);
1111+ ~DecorPixmap ();
1112+
1113+ Pixmap getPixmap ();
1114+
1115+ private:
1116+
1117+ Pixmap mPixmap;
1118+ DecorPixmapDeletionInterface::Ptr mDeletor;
1119+};
1120+
1121+class DecorPixmapRequestorInterface
1122+{
1123+ public:
1124+
1125+ virtual ~DecorPixmapRequestorInterface () {}
1126+
1127+ virtual int postGenerateRequest (unsigned int frameType,
1128+ unsigned int frameState,
1129+ unsigned int frameActions) = 0;
1130+
1131+ virtual void handlePending (long *data) = 0;
1132+};
1133+
1134+class DecorationListFindMatchingInterface
1135+{
1136+ public:
1137+
1138+ virtual ~DecorationListFindMatchingInterface () {}
1139+
1140+ virtual DecorationInterface::Ptr findMatchingDecoration (unsigned int frameType,
1141+ unsigned int frameState,
1142+ unsigned int frameActions) = 0;
1143+};
1144+
1145+class X11DecorPixmapRequestor :
1146+ public DecorPixmapRequestorInterface
1147+{
1148+ public:
1149+
1150+ X11DecorPixmapRequestor (Display *dpy,
1151+ Window xid,
1152+ DecorationListFindMatchingInterface *listFinder);
1153+
1154+ int postGenerateRequest (unsigned int frameType,
1155+ unsigned int frameState,
1156+ unsigned int frameActions);
1157+
1158+ void handlePending (long *data);
1159+
1160+ private:
1161+
1162+ Display *mDpy;
1163+ Window mWindow;
1164+ DecorationListFindMatchingInterface *mListFinder;
1165+};
1166+
1167+class X11DecorPixmapReceiver :
1168+ public DecorPixmapReceiverInterface
1169+{
1170+ public:
1171+
1172+ static const unsigned int UpdateRequested = 1 << 0;
1173+ static const unsigned int UpdatesPending = 1 << 1;
1174+
1175+ X11DecorPixmapReceiver (DecorPixmapRequestorInterface *,
1176+ DecorationInterface *decor);
1177+
1178+ void pending ();
1179+ void update ();
1180+ private:
1181+
1182+ unsigned int mUpdateState;
1183+ DecorPixmapRequestorInterface *mDecorPixmapRequestor;
1184+ DecorationInterface *mDecoration;
1185+};
1186+
1187+#endif
1188
1189=== added directory 'plugins/decor/src/pixmap-requests/src'
1190=== added file 'plugins/decor/src/pixmap-requests/src/pixmap-requests.cpp'
1191--- plugins/decor/src/pixmap-requests/src/pixmap-requests.cpp 1970-01-01 00:00:00 +0000
1192+++ plugins/decor/src/pixmap-requests/src/pixmap-requests.cpp 2012-05-15 07:20:22 +0000
1193@@ -0,0 +1,93 @@
1194+#include "pixmap-requests.h"
1195+#include <boost/foreach.hpp>
1196+#include <algorithm>
1197+
1198+#ifndef foreach
1199+#define foreach BOOST_FOREACH
1200+#endif
1201+
1202+DecorPixmap::DecorPixmap (Pixmap pixmap, DecorPixmapDeletionInterface::Ptr d) :
1203+ mPixmap (pixmap),
1204+ mDeletor (d)
1205+{
1206+}
1207+
1208+DecorPixmap::~DecorPixmap ()
1209+{
1210+ mDeletor->postDeletePixmap (mPixmap);
1211+}
1212+
1213+Pixmap
1214+DecorPixmap::getPixmap ()
1215+{
1216+ return mPixmap;
1217+}
1218+
1219+X11DecorPixmapReceiver::X11DecorPixmapReceiver (DecorPixmapRequestorInterface *requestor,
1220+ DecorationInterface *decor) :
1221+ mUpdateState (0),
1222+ mDecorPixmapRequestor (requestor),
1223+ mDecoration (decor)
1224+{
1225+}
1226+
1227+void
1228+X11DecorPixmapReceiver::pending ()
1229+{
1230+ if (mUpdateState & X11DecorPixmapReceiver::UpdateRequested)
1231+ mUpdateState |= X11DecorPixmapReceiver::UpdatesPending;
1232+ else
1233+ {
1234+ mUpdateState |= X11DecorPixmapReceiver::UpdateRequested;
1235+
1236+ mDecorPixmapRequestor->postGenerateRequest (mDecoration->getFrameType (),
1237+ mDecoration->getFrameState (),
1238+ mDecoration->getFrameActions ());
1239+ }
1240+}
1241+
1242+void X11DecorPixmapReceiver::update ()
1243+{
1244+ if (mUpdateState & X11DecorPixmapReceiver::UpdatesPending)
1245+ mDecorPixmapRequestor->postGenerateRequest (mDecoration->getFrameType (),
1246+ mDecoration->getFrameState (),
1247+ mDecoration->getFrameActions ());
1248+
1249+ mUpdateState = 0;
1250+}
1251+
1252+X11DecorPixmapRequestor::X11DecorPixmapRequestor (Display *dpy,
1253+ Window window,
1254+ DecorationListFindMatchingInterface *listFinder) :
1255+ mDpy (dpy),
1256+ mWindow (window),
1257+ mListFinder (listFinder)
1258+{
1259+}
1260+
1261+int
1262+X11DecorPixmapRequestor::postGenerateRequest (unsigned int frameType,
1263+ unsigned int frameState,
1264+ unsigned int frameActions)
1265+{
1266+ return decor_post_generate_request (mDpy,
1267+ mWindow,
1268+ frameType,
1269+ frameState,
1270+ frameActions);
1271+}
1272+
1273+void
1274+X11DecorPixmapRequestor::handlePending (long *data)
1275+{
1276+ DecorationInterface::Ptr d = mListFinder->findMatchingDecoration (static_cast <unsigned int> (data[0]),
1277+ static_cast <unsigned int> (data[1]),
1278+ static_cast <unsigned int> (data[2]));
1279+
1280+ if (d)
1281+ d->receiverInterface ().pending ();
1282+ else
1283+ postGenerateRequest (static_cast <unsigned int> (data[0]),
1284+ static_cast <unsigned int> (data[1]),
1285+ static_cast <unsigned int> (data[2]));
1286+}
1287
1288=== added directory 'plugins/decor/src/pixmap-requests/tests'
1289=== added file 'plugins/decor/src/pixmap-requests/tests/CMakeLists.txt'
1290--- plugins/decor/src/pixmap-requests/tests/CMakeLists.txt 1970-01-01 00:00:00 +0000
1291+++ plugins/decor/src/pixmap-requests/tests/CMakeLists.txt 2012-05-15 07:20:22 +0000
1292@@ -0,0 +1,15 @@
1293+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
1294+
1295+add_executable (compiz_test_decor_pixmap_requests
1296+ ${CMAKE_CURRENT_SOURCE_DIR}/pixmap-requests/src/test-decor-pixmap-requests.cpp)
1297+
1298+target_link_libraries (compiz_test_decor_pixmap_requests
1299+ compiz_decor_pixmap_requests
1300+ decoration
1301+ ${GTEST_BOTH_LIBRARIES}
1302+ ${GMOCK_LIBRARY}
1303+ ${GMOCK_MAIN_LIBRARY}
1304+ ${CMAKE_THREAD_LIBS_INIT} # Link in pthread.
1305+ )
1306+
1307+gtest_add_tests (compiz_test_decor_pixmap_requests "" ${CMAKE_CURRENT_SOURCE_DIR}/pixmap-requests/src/test-decor-pixmap-requests.cpp)
1308
1309=== added directory 'plugins/decor/src/pixmap-requests/tests/pixmap-requests'
1310=== added directory 'plugins/decor/src/pixmap-requests/tests/pixmap-requests/src'
1311=== added file 'plugins/decor/src/pixmap-requests/tests/pixmap-requests/src/test-decor-pixmap-requests.cpp'
1312--- plugins/decor/src/pixmap-requests/tests/pixmap-requests/src/test-decor-pixmap-requests.cpp 1970-01-01 00:00:00 +0000
1313+++ plugins/decor/src/pixmap-requests/tests/pixmap-requests/src/test-decor-pixmap-requests.cpp 2012-05-15 07:20:22 +0000
1314@@ -0,0 +1,160 @@
1315+/*
1316+ * Copyright © 2012 Canonical Ltd.
1317+ *
1318+ * Permission to use, copy, modify, distribute, and sell this software
1319+ * and its documentation for any purpose is hereby granted without
1320+ * fee, provided that the above copyright notice appear in all copies
1321+ * and that both that copyright notice and this permission notice
1322+ * appear in supporting documentation, and that the name of
1323+ * Canonical Ltd. not be used in advertising or publicity pertaining to
1324+ * distribution of the software without specific, written prior permission.
1325+ * Canonical Ltd. makes no representations about the suitability of this
1326+ * software for any purpose. It is provided "as is" without express or
1327+ * implied warranty.
1328+ *
1329+ * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1330+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
1331+ * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1332+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
1333+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
1334+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
1335+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1336+ *
1337+ * Authored by: Sam Spilsbury <sam.spilsbury@canonical.com>
1338+ */
1339+
1340+#include <gtest/gtest.h>
1341+#include <gmock/gmock.h>
1342+#include <iostream>
1343+#include "pixmap-requests.h"
1344+
1345+using ::testing::Return;
1346+
1347+class DecorPixmapRequestsTest :
1348+ public ::testing::Test
1349+{
1350+};
1351+
1352+class MockDecorPixmapDeletor :
1353+ public DecorPixmapDeletionInterface
1354+{
1355+ public:
1356+
1357+ MOCK_METHOD1 (postDeletePixmap, int (Pixmap p));
1358+};
1359+
1360+class MockDecorPixmapReceiver :
1361+ public DecorPixmapReceiverInterface
1362+{
1363+ public:
1364+
1365+ MOCK_METHOD0 (pending, void ());
1366+ MOCK_METHOD0 (update, void ());
1367+};
1368+
1369+class MockDecoration :
1370+ public DecorationInterface
1371+{
1372+ public:
1373+
1374+ MOCK_METHOD0 (receiverInterface, DecorPixmapReceiverInterface & ());
1375+ MOCK_CONST_METHOD0 (getFrameType, unsigned int ());
1376+ MOCK_CONST_METHOD0 (getFrameState, unsigned int ());
1377+ MOCK_CONST_METHOD0 (getFrameActions, unsigned int ());
1378+};
1379+
1380+class MockDecorationListFindMatching :
1381+ public DecorationListFindMatchingInterface
1382+{
1383+ public:
1384+
1385+ MOCK_METHOD3 (findMatchingDecoration, DecorationInterface::Ptr (unsigned int, unsigned int, unsigned int));
1386+};
1387+
1388+class MockDecorPixmapRequestor :
1389+ public DecorPixmapRequestorInterface
1390+{
1391+ public:
1392+
1393+ MOCK_METHOD3 (postGenerateRequest, int (unsigned int, unsigned int, unsigned int));
1394+ MOCK_METHOD1 (handlePending, void (long *));
1395+};
1396+
1397+TEST(DecorPixmapRequestsTest, TestDestroyPixmapDeletes)
1398+{
1399+ boost::shared_ptr <MockDecorPixmapDeletor> mockDeletor = boost::make_shared <MockDecorPixmapDeletor> ();
1400+ DecorPixmap pm (1, boost::shared_static_cast<DecorPixmapDeletionInterface> (mockDeletor));
1401+
1402+ EXPECT_CALL (*(mockDeletor.get ()), postDeletePixmap (1)).WillOnce (Return (1));
1403+}
1404+
1405+TEST(DecorPixmapRequestsTest, TestPendingGeneratesRequest)
1406+{
1407+ MockDecorPixmapRequestor mockRequestor;
1408+ MockDecoration mockDecoration;
1409+ X11DecorPixmapReceiver receiver (&mockRequestor, &mockDecoration);
1410+
1411+ EXPECT_CALL (mockDecoration, getFrameActions ()).WillOnce (Return (3));
1412+ EXPECT_CALL (mockDecoration, getFrameState ()).WillOnce (Return (2));
1413+ EXPECT_CALL (mockDecoration, getFrameType ()).WillOnce (Return (1));
1414+
1415+ EXPECT_CALL (mockRequestor, postGenerateRequest (1, 2, 3));
1416+
1417+ receiver.pending ();
1418+}
1419+
1420+TEST(DecorPixmapRequestsTest, TestPendingGeneratesOnlyOneRequest)
1421+{
1422+ MockDecorPixmapRequestor mockRequestor;
1423+ MockDecoration mockDecoration;
1424+ X11DecorPixmapReceiver receiver (&mockRequestor, &mockDecoration);
1425+
1426+ EXPECT_CALL (mockDecoration, getFrameActions ()).WillOnce (Return (3));
1427+ EXPECT_CALL (mockDecoration, getFrameState ()).WillOnce (Return (2));
1428+ EXPECT_CALL (mockDecoration, getFrameType ()).WillOnce (Return (1));
1429+
1430+ EXPECT_CALL (mockRequestor, postGenerateRequest (1, 2, 3));
1431+
1432+ receiver.pending ();
1433+ receiver.pending ();
1434+}
1435+
1436+TEST(DecorPixmapRequestsTest, TestUpdateGeneratesRequestIfNewOnePending)
1437+{
1438+ MockDecorPixmapRequestor mockRequestor;
1439+ MockDecoration mockDecoration;
1440+ X11DecorPixmapReceiver receiver (&mockRequestor, &mockDecoration);
1441+
1442+ EXPECT_CALL (mockDecoration, getFrameActions ()).WillOnce (Return (3));
1443+ EXPECT_CALL (mockDecoration, getFrameState ()).WillOnce (Return (2));
1444+ EXPECT_CALL (mockDecoration, getFrameType ()).WillOnce (Return (1));
1445+
1446+ EXPECT_CALL (mockRequestor, postGenerateRequest (1, 2, 3));
1447+
1448+ receiver.pending ();
1449+ receiver.pending ();
1450+
1451+ EXPECT_CALL (mockDecoration, getFrameActions ()).WillOnce (Return (3));
1452+ EXPECT_CALL (mockDecoration, getFrameState ()).WillOnce (Return (2));
1453+ EXPECT_CALL (mockDecoration, getFrameType ()).WillOnce (Return (1));
1454+
1455+ EXPECT_CALL (mockRequestor, postGenerateRequest (1, 2, 3));
1456+
1457+ receiver.update ();
1458+}
1459+
1460+TEST(DecorPixmapRequestsTest, TestUpdateGeneratesNoRequestIfNoNewOnePending)
1461+{
1462+ MockDecorPixmapRequestor mockRequestor;
1463+ MockDecoration mockDecoration;
1464+ X11DecorPixmapReceiver receiver (&mockRequestor, &mockDecoration);
1465+
1466+ EXPECT_CALL (mockDecoration, getFrameActions ()).WillOnce (Return (3));
1467+ EXPECT_CALL (mockDecoration, getFrameState ()).WillOnce (Return (2));
1468+ EXPECT_CALL (mockDecoration, getFrameType ()).WillOnce (Return (1));
1469+
1470+ EXPECT_CALL (mockRequestor, postGenerateRequest (1, 2, 3));
1471+
1472+ receiver.pending ();
1473+ receiver.update ();
1474+}

Subscribers

People subscribed via source and target branches