Merge lp:~compiz-team/compiz/compiz.fix_1119608 into lp:compiz/0.9.9

Proposed by Sam Spilsbury
Status: Merged
Approved by: Brandon Schaefer
Approved revision: 3628
Merged at revision: 3618
Proposed branch: lp:~compiz-team/compiz/compiz.fix_1119608
Merge into: lp:compiz/0.9.9
Diff against target: 2244 lines (+1519/-197)
23 files modified
gtk/window-decorator/cairo.c (+3/-12)
gtk/window-decorator/decorator.c (+12/-13)
gtk/window-decorator/events.c (+0/-11)
gtk/window-decorator/gdk.c (+25/-1)
gtk/window-decorator/gtk-window-decorator.c (+3/-5)
gtk/window-decorator/gtk-window-decorator.h (+6/-2)
gtk/window-decorator/metacity.c (+0/-15)
gtk/window-decorator/switcher.c (+7/-1)
gtk/window-decorator/wnck.c (+0/-16)
include/decoration.h (+6/-1)
libdecoration/decoration.c (+9/-7)
plugins/decor/src/decor.cpp (+79/-18)
plugins/decor/src/decor.h (+13/-3)
plugins/decor/src/pixmap-requests/include/pixmap-requests.h (+127/-35)
plugins/decor/src/pixmap-requests/src/pixmap-requests.cpp (+106/-3)
plugins/decor/src/pixmap-requests/tests/CMakeLists.txt (+10/-1)
plugins/decor/src/pixmap-requests/tests/compiz_decor_pixmap_requests_mock.cpp (+113/-0)
plugins/decor/src/pixmap-requests/tests/compiz_decor_pixmap_requests_mock.h (+179/-0)
plugins/decor/src/pixmap-requests/tests/integration/CMakeLists.txt (+1/-0)
plugins/decor/src/pixmap-requests/tests/integration/xorg-gtest/CMakeLists.txt (+41/-0)
plugins/decor/src/pixmap-requests/tests/integration/xorg-gtest/compiz_test_decor_pixmap_protocol_integration.cpp (+483/-0)
plugins/decor/src/pixmap-requests/tests/test-decor-pixmap-requests.cpp (+295/-52)
tests/system/xorg-gtest/tests/CMakeLists.txt (+1/-1)
To merge this branch: bzr merge lp:~compiz-team/compiz/compiz.fix_1119608
Reviewer Review Type Date Requested Status
Brandon Schaefer (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+149458@code.launchpad.net

This proposal supersedes a proposal from 2013-02-19.

Commit message

Redesign the optional pixmap deletion protocol to make the consumer responsible for deleting the pixmaps.

The previous optional protocol had the consumer send a message back to the producer when a pixmap was ready to be deleted, and then the producer would take it from its pool of pixmaps marked for deletion and delete it there. That protocol did not really work out in practise though, because of a race condition where the consumer would never become aware of a new pixmap (because the new pixmap value was read synchronously instead of delivered asynchronously) and then that pixmap would just sit there in the consumer's memory and never be deleted. The new optional protocol makes the consumer responsible for freeing the pixmap once the producer has marked it ready for deletion. That way the consumer can keep on using the pixmap until it needs to delete it. This is important on drivers that use loose binding, because the texture contents are undefined as soon as the pixmap is freed on the server side.

In order to represent that, there were a few new objects added. The first is a "communicator" object which handles all of the requests that come from the decorator through ClientMessage events and dispatch to the right place. The next are the individual message handlers, which determine whether or not the pixmap can be deleted immediately or if it should go into the pixmap release pool. The final is the release pool, which stores in-use pixmaps in a list which can then be marked for deletion when the texture they are bound to goes away.

Unit and Integration tests were added to demonstrate the code and protocol behaviour.

(LP: #1119608)

Description of the change

Redesign the optional pixmap deletion protocol to make the consumer responsible for deleting the pixmaps.

The previous optional protocol had the consumer send a message back to the producer when a pixmap was ready to be deleted, and then the producer would take it from its pool of pixmaps marked for deletion and delete it there. That protocol did not really work out in practise though, because of a race condition where the consumer would never become aware of a new pixmap (because the new pixmap value was read synchronously instead of delivered asynchronously) and then that pixmap would just sit there in the consumer's memory and never be deleted. The new optional protocol makes the consumer responsible for freeing the pixmap once the producer has marked it ready for deletion. That way the consumer can keep on using the pixmap until it needs to delete it. This is important on drivers that use loose binding, because the texture contents are undefined as soon as the pixmap is freed on the server side.

In order to represent that, there were a few new objects added. The first is a "communicator" object which handles all of the requests that come from the decorator through ClientMessage events and dispatch to the right place. The next are the individual message handlers, which determine whether or not the pixmap can be deleted immediately or if it should go into the pixmap release pool. The final is the release pool, which stores in-use pixmaps in a list which can then be marked for deletion when the texture they are bound to goes away.

Unit and Integration tests were added to demonstrate the code and protocol behaviour.

(LP: #1119608)

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Martin Mrazik (mrazik) wrote : Posted in a previous version of this proposal

Sorry. I had to abort the build due to some jenkins issues we are experiencing. Will re-trigger it later.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Brandon Schaefer (brandontschaefer) wrote : Posted in a previous version of this proposal

Overall looks good, a few things:

Some warning when compiling:
http://paste.ubuntu.com/1683356/

CI had some test seg fault (which I don't get here), so possibly taking a look into that.

Just some minor things here:

78 - default_frames[i].d->pixmap = create_pixmap (default_frames[i].d->width, default_frames[i].d->height, frame->style_window_rgba);
79 + default_frames[i].d->pixmap = create_native_pixmap_and_wrap (default_frames[i].d->width, default_frames[i].d->height, frame->style_window_rgba);

Just looks like a small indentation error.

119 + if (w == 0 || h == 0)
120 + abort ();

I've seen w or h on windows get to -1 before, should we possibly change it to w <= 0 || h <= 0?

446 + foreach (const Decoration::Ptr &d, mList)

Though I do love this macro, I would love a range for loop but compiz doesn't use c++0x :(. (just a comment)

622 +#include <boost/noncopyable.hpp>

I don't see you inherit from this noncopyable class, do we need this header?

695 + int destroyUnusedPixmap (Pixmap pixmap) { return decor_post_delete_pixmap (mDisplay,
696 + 0,
697 + pixmap); }

Just needs little bit of lining up of the params :).

review: Needs Fixing
Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

> Overall looks good, a few things:
>

Thanks for the quick feedback.

> Some warning when compiling:
> http://paste.ubuntu.com/1683356/

Fixed.

>
> CI had some test seg fault (which I don't get here), so possibly taking a look
> into that.

I think that should be fixed now. I wasn't running the tests through the wrapper.

>
> Just some minor things here:
>
> 78 - default_frames[i].d->pixmap = create_pixmap
> (default_frames[i].d->width, default_frames[i].d->height,
> frame->style_window_rgba);
> 79 + default_frames[i].d->pixmap = create_native_pixmap_and_wrap
> (default_frames[i].d->width, default_frames[i].d->height,
> frame->style_window_rgba);
>
> Just looks like a small indentation error.

Fixed.

>
>
> 119 + if (w == 0 || h == 0)
> 120 + abort ();
>
> I've seen w or h on windows get to -1 before, should we possibly change it to
> w <= 0 || h <= 0?

Fixed.

>
> 446 + foreach (const Decoration::Ptr &d, mList)
>
> Though I do love this macro, I would love a range for loop but compiz doesn't
> use c++0x :(. (just a comment)

Likewise, but we should do them all in one go. Its just BOOST_FOREACH.

>
> 622 +#include <boost/noncopyable.hpp>
>
> I don't see you inherit from this noncopyable class, do we need this header?

Nice catch, forgot to do it.

>
> 695 + int destroyUnusedPixmap (Pixmap pixmap) { return
> decor_post_delete_pixmap (mDisplay,
> 696 + 0,
> 697 + pixmap); }
>
> Just needs little bit of lining up of the params :).

The class was unused anyways so I got rid of it.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
3628. By Sam Spilsbury

Add xorg-gtest env

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Brandon Schaefer (brandontschaefer) wrote : Posted in a previous version of this proposal

Everything looks good to me, im approving this but waiting for CI to give the green light for a merge.

review: Approve
Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

opps wrong MP, looks like CI did its job :)

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/cairo.c'
2--- gtk/window-decorator/cairo.c 2012-09-18 11:32:20 +0000
3+++ gtk/window-decorator/cairo.c 2013-02-20 07:34:20 +0000
4@@ -317,19 +317,10 @@
5 color.g = style->bg[GTK_STATE_NORMAL].green / 65535.0;
6 color.b = style->bg[GTK_STATE_NORMAL].blue / 65535.0;
7
8- if (d->frame_window)
9- {
10- GdkColormap *cmap;
11-
12- cmap = get_colormap_for_drawable (GDK_DRAWABLE (d->pixmap));
13- gdk_drawable_set_colormap (GDK_DRAWABLE (d->pixmap), cmap);
14- gdk_drawable_set_colormap (GDK_DRAWABLE (d->buffer_pixmap), cmap);
15- drawable = GDK_DRAWABLE (d->buffer_pixmap);
16- }
17- else if (d->buffer_pixmap)
18- drawable = GDK_DRAWABLE (d->buffer_pixmap);
19+ if (d->buffer_pixmap)
20+ drawable = d->buffer_pixmap;
21 else
22- drawable = GDK_DRAWABLE (d->pixmap);
23+ drawable = d->pixmap;
24
25 cr = gdk_cairo_create (GDK_DRAWABLE (drawable));
26 if (!cr)
27
28=== modified file 'gtk/window-decorator/decorator.c'
29--- gtk/window-decorator/decorator.c 2012-11-20 08:11:44 +0000
30+++ gtk/window-decorator/decorator.c 2013-02-20 07:34:20 +0000
31@@ -649,9 +649,9 @@
32 /* Get the correct depth for the frame window in reparenting mode, otherwise
33 * enforce 32 */
34 if (d->frame_window)
35- pixmap = create_pixmap (d->width, d->height, d->frame->style_window_rgb);
36+ pixmap = create_native_pixmap_and_wrap (d->width, d->height, d->frame->style_window_rgb);
37 else
38- pixmap = create_pixmap (d->width, d->height, d->frame->style_window_rgba);
39+ pixmap = create_native_pixmap_and_wrap (d->width, d->height, d->frame->style_window_rgba);
40
41 gdk_flush ();
42
43@@ -686,16 +686,12 @@
44
45 /* Destroy the old pixmaps and pictures */
46 if (d->pixmap)
47- {
48- gpointer key = GINT_TO_POINTER (GDK_PIXMAP_XID (d->pixmap));
49-
50- if (d->old_pixmaps == NULL)
51- d->old_pixmaps = g_hash_table_new_full (NULL, NULL, NULL,
52- g_object_unref);
53-
54- g_hash_table_insert (destroyed_pixmaps_table, key, d);
55- g_hash_table_insert (d->old_pixmaps, key, d->pixmap);
56- }
57+ g_object_unref (d->pixmap);
58+
59+ if (d->x11Pixmap)
60+ decor_post_delete_pixmap (xdisplay,
61+ wnck_window_get_xid (d->win),
62+ d->x11Pixmap);
63
64 if (d->buffer_pixmap)
65 g_object_unref (G_OBJECT (d->buffer_pixmap));
66@@ -708,6 +704,7 @@
67
68 /* Assign new pixmaps and pictures */
69 d->pixmap = pixmap;
70+ d->x11Pixmap = GDK_PIXMAP_XID (d->pixmap);
71 d->buffer_pixmap = buffer_pixmap;
72 d->cr = gdk_cairo_create (pixmap);
73
74@@ -1435,7 +1432,9 @@
75 extents.top += frame->titlebar_height;
76
77 default_frames[i].d->draw = theme_draw_window_decoration;
78- default_frames[i].d->pixmap = create_pixmap (default_frames[i].d->width, default_frames[i].d->height, frame->style_window_rgba);
79+ default_frames[i].d->pixmap = create_native_pixmap_and_wrap (default_frames[i].d->width,
80+ default_frames[i].d->height,
81+ frame->style_window_rgba);
82
83 unsigned int j, k;
84
85
86=== modified file 'gtk/window-decorator/events.c'
87--- gtk/window-decorator/events.c 2012-10-06 16:11:05 +0000
88+++ gtk/window-decorator/events.c 2013-02-20 07:34:20 +0000
89@@ -1093,17 +1093,6 @@
90 if (win)
91 update_window_decoration_size (win);
92 }
93- else if (xevent->xclient.message_type == decor_delete_pixmap_atom)
94- {
95- gconstpointer key = GINT_TO_POINTER (xevent->xclient.data.l[0]);
96- decor_t *d = g_hash_table_lookup (destroyed_pixmaps_table, key);
97-
98- if (d != NULL)
99- {
100- g_hash_table_remove (d->old_pixmaps, key);
101- g_hash_table_remove (destroyed_pixmaps_table, key);
102- }
103- }
104 default:
105 break;
106 }
107
108=== modified file 'gtk/window-decorator/gdk.c'
109--- gtk/window-decorator/gdk.c 2012-05-27 04:32:55 +0000
110+++ gtk/window-decorator/gdk.c 2013-02-20 07:34:20 +0000
111@@ -92,6 +92,26 @@
112 }
113
114 GdkPixmap *
115+create_native_pixmap_and_wrap (int w,
116+ int h,
117+ GtkWidget *parent_style_window)
118+{
119+ GdkWindow *window;
120+
121+ if (w <= 0 || h <= 0)
122+ abort ();
123+
124+ window = gtk_widget_get_window (parent_style_window);
125+ GdkPixmap *pixmap =
126+ gdk_pixmap_foreign_new (XCreatePixmap (gdk_x11_display_get_xdisplay (gdk_display_get_default ()),
127+ GDK_WINDOW_XID (window), w, h,
128+ gdk_drawable_get_depth (window)));
129+ GdkColormap *cmap = get_colormap_for_drawable (GDK_DRAWABLE (pixmap));
130+ gdk_drawable_set_colormap (GDK_DRAWABLE (pixmap), cmap);
131+ return pixmap;
132+}
133+
134+GdkPixmap *
135 create_pixmap (int w,
136 int h,
137 GtkWidget *parent_style_window)
138@@ -102,5 +122,9 @@
139 abort ();
140
141 window = gtk_widget_get_window (parent_style_window);
142- return gdk_pixmap_new (GDK_DRAWABLE (window), w, h, -1 /* CopyFromParent */);
143+ GdkPixmap *pixmap = gdk_pixmap_new (GDK_DRAWABLE (window), w, h, -1 /* CopyFromParent */);
144+
145+ GdkColormap *cmap = get_colormap_for_drawable (GDK_DRAWABLE (pixmap));
146+ gdk_drawable_set_colormap (GDK_DRAWABLE (pixmap), cmap);
147+ return pixmap;
148 }
149
150=== modified file 'gtk/window-decorator/gtk-window-decorator.c'
151--- gtk/window-decorator/gtk-window-decorator.c 2012-10-06 16:11:05 +0000
152+++ gtk/window-decorator/gtk-window-decorator.c 2013-02-20 07:34:20 +0000
153@@ -136,7 +136,6 @@
154 GtkWidget *switcher_label;
155
156 GHashTable *frame_table;
157-GHashTable *destroyed_pixmaps_table;
158 GtkWidget *action_menu = NULL;
159 gboolean action_menu_mapped = FALSE;
160 decor_color_t _title_color[2];
161@@ -267,9 +266,9 @@
162 net_wm_state_atom = XInternAtom (xdisplay,"_NET_WM_STATE", 0);
163 net_wm_state_modal_atom = XInternAtom (xdisplay, "_NET_WM_STATE_MODAL", 0);
164
165- decor_request_atom = XInternAtom (xdisplay, "_COMPIZ_DECOR_REQUEST", 0);
166- decor_pending_atom = XInternAtom (xdisplay, "_COMPIZ_DECOR_PENDING", 0);
167- decor_delete_pixmap_atom = XInternAtom (xdisplay, "_COMPIZ_DECOR_DELETE_PIXMAP", 0);
168+ decor_request_atom = XInternAtom (xdisplay, DECOR_REQUEST_PIXMAP_ATOM_NAME, 0);
169+ decor_pending_atom = XInternAtom (xdisplay, DECOR_PIXMAP_PENDING_ATOM_NAME, 0);
170+ decor_delete_pixmap_atom = XInternAtom (xdisplay, DECOR_DELETE_PIXMAP_ATOM_NAME, 0);
171
172 status = decor_acquire_dm_session (xdisplay,
173 gdk_screen_get_number (gdkscreen),
174@@ -343,7 +342,6 @@
175 xformat_rgb = XRenderFindStandardFormat (xdisplay, PictStandardRGB24);
176
177 frame_table = g_hash_table_new (NULL, NULL);
178- destroyed_pixmaps_table = g_hash_table_new (NULL, NULL);
179
180 if (!create_tooltip_window ())
181 {
182
183=== modified file 'gtk/window-decorator/gtk-window-decorator.h'
184--- gtk/window-decorator/gtk-window-decorator.h 2012-10-06 16:11:05 +0000
185+++ gtk/window-decorator/gtk-window-decorator.h 2013-02-20 07:34:20 +0000
186@@ -392,13 +392,13 @@
187 event_window button_windows[BUTTON_NUM];
188 Box *last_pos_entered;
189 guint button_states[BUTTON_NUM];
190+ Pixmap x11Pixmap;
191 GdkPixmap *pixmap;
192 GdkPixmap *buffer_pixmap;
193 GdkWindow *frame_window;
194 GtkWidget *decor_window;
195 GtkWidget *decor_event_box;
196 GtkWidget *decor_image;
197- GHashTable *old_pixmaps;
198 cairo_t *cr;
199 decor_layout_t border_layout;
200 decor_context_t *context;
201@@ -470,7 +470,6 @@
202
203 /* list of all decorations */
204 extern GHashTable *frame_table;
205-extern GHashTable *destroyed_pixmaps_table;
206
207 /* action menu */
208 extern GtkWidget *action_menu;
209@@ -801,6 +800,11 @@
210 GtkWidget *parent_style_window);
211
212 GdkPixmap *
213+create_native_pixmap_and_wrap (int w,
214+ int h,
215+ GtkWidget *parent_style_window);
216+
217+GdkPixmap *
218 pixmap_new_from_pixbuf (GdkPixbuf *pixbuf, GtkWidget *parent);
219
220 /* metacity.c */
221
222=== modified file 'gtk/window-decorator/metacity.c'
223--- gtk/window-decorator/metacity.c 2012-09-10 12:59:17 +0000
224+++ gtk/window-decorator/metacity.c 2013-02-20 07:34:20 +0000
225@@ -616,15 +616,6 @@
226 if (!d->pixmap || !d->picture)
227 return;
228
229- if (d->frame_window)
230- {
231- GdkColormap *cmap;
232-
233- cmap = get_colormap_for_drawable (GDK_DRAWABLE (d->pixmap));
234- gdk_drawable_set_colormap (GDK_DRAWABLE (d->pixmap), cmap);
235- gdk_drawable_set_colormap (GDK_DRAWABLE (d->buffer_pixmap), cmap);
236- }
237-
238 if (decoration_alpha == 1.0)
239 alpha = 1.0;
240
241@@ -692,13 +683,7 @@
242 XRenderPictFormat *format;
243
244 if (d->frame_window)
245- {
246- GdkColormap *cmap;
247-
248- cmap = get_colormap_for_drawable (GDK_DRAWABLE (d->pixmap));
249 pixmap = create_pixmap (rect.width, size, d->frame->style_window_rgb);
250- gdk_drawable_set_colormap (GDK_DRAWABLE (pixmap), cmap);
251- }
252 else
253 pixmap = create_pixmap (rect.width, size, d->frame->style_window_rgba);
254
255
256=== modified file 'gtk/window-decorator/switcher.c'
257--- gtk/window-decorator/switcher.c 2011-10-13 12:07:34 +0000
258+++ gtk/window-decorator/switcher.c 2013-02-20 07:34:20 +0000
259@@ -472,7 +472,7 @@
260 switcher_selected_window = selected;
261 }
262
263- pixmap = create_pixmap (width, height, d->frame->style_window_rgba);
264+ pixmap = create_native_pixmap_and_wrap (width, height, d->frame->style_window_rgba);
265 if (!pixmap)
266 return FALSE;
267
268@@ -486,6 +486,11 @@
269 if (d->pixmap)
270 g_object_unref (G_OBJECT (d->pixmap));
271
272+ if (d->x11Pixmap)
273+ decor_post_delete_pixmap (xdisplay,
274+ wnck_window_get_xid (d->win),
275+ d->x11Pixmap);
276+
277 if (d->buffer_pixmap)
278 g_object_unref (G_OBJECT (d->buffer_pixmap));
279
280@@ -496,6 +501,7 @@
281 XRenderFreePicture (xdisplay, d->picture);
282
283 d->pixmap = pixmap;
284+ d->x11Pixmap = GDK_PIXMAP_XID (d->pixmap);
285 d->buffer_pixmap = buffer_pixmap;
286 d->cr = gdk_cairo_create (pixmap);
287
288
289=== modified file 'gtk/window-decorator/wnck.c'
290--- gtk/window-decorator/wnck.c 2012-11-05 20:50:59 +0000
291+++ gtk/window-decorator/wnck.c 2013-02-20 07:34:20 +0000
292@@ -455,22 +455,12 @@
293 d->created = TRUE;
294 }
295
296-gboolean
297-clean_destroyed_pixmaps (gpointer key, gpointer value, gpointer d)
298-{
299- return value == d;
300-}
301-
302 void
303 remove_frame_window (WnckWindow *win)
304 {
305 decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
306 Display *xdisplay;
307
308- g_hash_table_foreach_remove (destroyed_pixmaps_table,
309- clean_destroyed_pixmaps,
310- d);
311-
312 xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
313
314 if (!d->frame_window)
315@@ -507,12 +497,6 @@
316 d->buffer_pixmap = NULL;
317 }
318
319- if (d->old_pixmaps)
320- {
321- g_hash_table_destroy (d->old_pixmaps);
322- d->old_pixmaps = NULL;
323- }
324-
325 if (d->cr)
326 {
327 cairo_destroy (d->cr);
328
329=== modified file 'include/decoration.h'
330--- include/decoration.h 2012-09-05 14:25:35 +0000
331+++ include/decoration.h 2013-02-20 07:34:20 +0000
332@@ -50,6 +50,10 @@
333 #define DECOR_TYPE_PIXMAP_ATOM_NAME "_COMPIZ_WINDOW_DECOR_TYPE_PIXMAP"
334 #define DECOR_TYPE_WINDOW_ATOM_NAME "_COMPIZ_WINDOW_DECOR_TYPE_WINDOW"
335
336+#define DECOR_REQUEST_PIXMAP_ATOM_NAME "_COMPIZ_DECOR_REQUEST"
337+#define DECOR_PIXMAP_PENDING_ATOM_NAME "_COMPIZ_DECOR_PENDING"
338+#define DECOR_DELETE_PIXMAP_ATOM_NAME "_COMPIZ_DECOR_DELETE_PIXMAP"
339+
340 #define WINDOW_DECORATION_TYPE_PIXMAP (1 << 0)
341 #define WINDOW_DECORATION_TYPE_WINDOW (1 << 1)
342
343@@ -495,12 +499,13 @@
344 int
345 decor_post_pending (Display *xdisplay,
346 Window client,
347+ unsigned int frame_type,
348 unsigned int frame_state,
349- unsigned int frame_type,
350 unsigned int frame_actions);
351
352 int
353 decor_post_delete_pixmap (Display *xdisplay,
354+ Window window,
355 Pixmap pixmap);
356
357 int
358
359=== modified file 'libdecoration/decoration.c'
360--- libdecoration/decoration.c 2013-01-28 20:52:39 +0000
361+++ libdecoration/decoration.c 2013-02-20 07:34:20 +0000
362@@ -2890,13 +2890,13 @@
363 int
364 decor_post_pending (Display *xdisplay,
365 Window client,
366+ unsigned int frame_type,
367 unsigned int frame_state,
368- unsigned int frame_type,
369 unsigned int frame_actions)
370 {
371 XEvent event;
372
373- Atom decor_pending = XInternAtom (xdisplay, "_COMPIZ_DECOR_PENDING", FALSE);
374+ Atom decor_pending = XInternAtom (xdisplay, DECOR_PIXMAP_PENDING_ATOM_NAME, FALSE);
375
376 /* Send a client message indicating that a new
377 * decoration can be generated for this window
378@@ -2926,7 +2926,7 @@
379 {
380 XEvent event;
381
382- Atom decor_request = XInternAtom (xdisplay, "_COMPIZ_DECOR_REQUEST", FALSE);
383+ Atom decor_request = XInternAtom (xdisplay, DECOR_REQUEST_PIXMAP_ATOM_NAME, FALSE);
384
385 /* Send a client message indicating that a new
386 * decoration can be generated for this window
387@@ -2949,17 +2949,18 @@
388
389 int
390 decor_post_delete_pixmap (Display *xdisplay,
391+ Window window,
392 Pixmap pixmap)
393 {
394 XEvent event;
395
396- Atom decor_delete_pixmap = XInternAtom (xdisplay, "_COMPIZ_DECOR_DELETE_PIXMAP", FALSE);
397+ Atom decor_delete_pixmap = XInternAtom (xdisplay, DECOR_DELETE_PIXMAP_ATOM_NAME, FALSE);
398
399- /* Send a client message indicating that a new
400- * decoration can be generated for this window
401+ /* Send a client message indicating that this
402+ * pixmap is no longer in use and can be removed
403 */
404 event.xclient.type = ClientMessage;
405- event.xclient.window = DefaultRootWindow (xdisplay);
406+ event.xclient.window = window;
407 event.xclient.message_type = decor_delete_pixmap;
408 event.xclient.format = 32;
409 event.xclient.data.l[0] = pixmap;
410@@ -2973,6 +2974,7 @@
411
412 return 1;
413 }
414+
415 int
416 decor_acquire_dm_session (Display *xdisplay,
417 int screen,
418
419=== modified file 'plugins/decor/src/decor.cpp'
420--- plugins/decor/src/decor.cpp 2013-02-19 20:38:17 +0000
421+++ plugins/decor/src/decor.cpp 2013-02-20 07:34:20 +0000
422@@ -391,8 +391,7 @@
423 return t;
424 }
425
426- X11PixmapDeletor::Ptr dl = boost::make_shared <X11PixmapDeletor> (screen->dpy ());
427- DecorPixmap::Ptr pm = boost::make_shared <DecorPixmap> (pixmap, dl);
428+ DecorPixmap::Ptr pm = boost::make_shared <DecorPixmap> (pixmap, mReleasePool);
429
430 DecorTexture *texture = new DecorTexture (boost::shared_static_cast <DecorPixmapInterface> (pm));
431
432@@ -1285,7 +1284,7 @@
433 DecorationInterface::Ptr
434 DecorationList::findMatchingDecoration (unsigned int frameType,
435 unsigned int frameState,
436- unsigned int frameActions)
437+ unsigned int frameActions) const
438 {
439 foreach (const Decoration::Ptr &d, mList)
440 {
441@@ -1298,6 +1297,18 @@
442 return DecorationInterface::Ptr ();
443 }
444
445+DecorationInterface::Ptr
446+DecorationList::findMatchingDecoration (Pixmap p) const
447+{
448+ foreach (const Decoration::Ptr &d, mList)
449+ {
450+ if (d->texture->pixmap->getPixmap () == p)
451+ return d;
452+ }
453+
454+ return DecorationInterface::Ptr ();
455+}
456+
457 /*
458 * DecorationList::findMatchingDecoration
459 *
460@@ -2334,6 +2345,42 @@
461 isSwitcher = false;
462 }
463
464+DecorPixmapRequestorInterface *
465+DecorScreen::findWindowRequestor (Window window)
466+{
467+ if (window == screen->root ())
468+ {
469+ return &mRequestor;
470+ }
471+ else
472+ {
473+ CompWindow *w = screen->findWindow (window);
474+
475+ if (w)
476+ return &(DecorWindow::get (w)->mRequestor);
477+
478+ return NULL;
479+ }
480+}
481+
482+DecorationListFindMatchingInterface *
483+DecorScreen::findWindowDecorations (Window window)
484+{
485+ if (window == screen->root ())
486+ {
487+ return &decor[DECOR_ACTIVE];
488+ }
489+ else
490+ {
491+ CompWindow *w = screen->findWindow (window);
492+
493+ if (w)
494+ return &(DecorWindow::get (w)->decor);
495+
496+ return NULL;
497+ }
498+}
499+
500
501 /*
502 * DecorScreen::handleEvent
503@@ -2376,18 +2423,8 @@
504 dw->update (true);
505 }
506 }
507- /* A decoration is pending creation, allow it to be created */
508- if (event->xclient.message_type == decorPendingAtom)
509- {
510- CompWindow *w = screen->findWindow (event->xclient.window);
511-
512- if (w)
513- {
514- DecorWindow *dw = DecorWindow::get (w);
515-
516- dw->mRequestor.handlePending (event->xclient.data.l);
517- }
518- }
519+
520+ mCommunicator.handleClientMessage (event->xclient);
521 break;
522 default:
523 /* Check for damage events. If the output or input window
524@@ -3010,7 +3047,31 @@
525 screen->root (),
526 NULL)),
527 mMenusClipGroup (CompMatch ("type=Dock | type=DropdownMenu | type=PopupMenu")),
528- mRequestor (screen->dpy (), screen->root (), &(decor[DECOR_ACTIVE]))
529+ mRequestor (screen->dpy (), screen->root (), &(decor[DECOR_ACTIVE])),
530+ mReleasePool (new PixmapReleasePool (
531+ boost::bind (XFreePixmap,
532+ screen->dpy (),
533+ _1))),
534+ mPendingHandler (boost::bind (&DecorScreen::findWindowRequestor,
535+ this,
536+ _1)),
537+ mUnusedHandler (boost::bind (&DecorScreen::findWindowDecorations,
538+ this,
539+ _1),
540+ mReleasePool,
541+ boost::bind (XFreePixmap,
542+ screen->dpy (),
543+ _1)),
544+ mCommunicator (XInternAtom (screen->dpy (), DECOR_PIXMAP_PENDING_ATOM_NAME, FALSE),
545+ XInternAtom (screen->dpy (), DECOR_DELETE_PIXMAP_ATOM_NAME, FALSE),
546+ boost::bind (&PendingHandler::handleMessage,
547+ &mPendingHandler,
548+ _1,
549+ _2),
550+ boost::bind (&UnusedHandler::handleMessage,
551+ &mUnusedHandler,
552+ _1,
553+ _2))
554 {
555 supportingDmCheckAtom =
556 XInternAtom (s->dpy (), DECOR_SUPPORTING_DM_CHECK_ATOM_NAME, 0);
557@@ -3033,9 +3094,9 @@
558 decorSwitchWindowAtom =
559 XInternAtom (s->dpy (), DECOR_SWITCH_WINDOW_ATOM_NAME, 0);
560 decorPendingAtom =
561- XInternAtom (s->dpy (), "_COMPIZ_DECOR_PENDING", 0);
562+ XInternAtom (s->dpy (), DECOR_PIXMAP_PENDING_ATOM_NAME, 0);
563 decorRequestAtom =
564- XInternAtom (s->dpy (), "_COMPIZ_DECOR_REQUEST", 0);
565+ XInternAtom (s->dpy (), DECOR_REQUEST_PIXMAP_ATOM_NAME, 0);
566 requestFrameExtentsAtom =
567 XInternAtom (s->dpy (), "_NET_REQUEST_FRAME_EXTENTS", 0);
568 shadowColorAtom =
569
570=== modified file 'plugins/decor/src/decor.h'
571--- plugins/decor/src/decor.h 2012-09-07 22:37:20 +0000
572+++ plugins/decor/src/decor.h 2013-02-20 07:34:20 +0000
573@@ -159,9 +159,10 @@
574 {
575 public:
576 bool updateDecoration (Window id, Atom decorAtom, DecorPixmapRequestorInterface *requestor);
577- DecorationInterface::Ptr findMatchingDecoration(unsigned int frameType,
578- unsigned int frameState,
579- unsigned int frameActions);
580+ DecorationInterface::Ptr findMatchingDecoration (unsigned int frameType,
581+ unsigned int frameState,
582+ unsigned int frameActions) const;
583+ DecorationInterface::Ptr findMatchingDecoration (Pixmap p) const;
584 const Decoration::Ptr & findMatchingDecoration (CompWindow *w, bool sizeCheck);
585 void clear ()
586 {
587@@ -220,6 +221,11 @@
588 bool registerPaintHandler (compiz::composite::PaintHandler *pHnd);
589 void unregisterPaintHandler ();
590
591+ private:
592+
593+ DecorPixmapRequestorInterface * findWindowRequestor (Window);
594+ DecorationListFindMatchingInterface * findWindowDecorations (Window);
595+
596 public:
597
598 CompositeScreen *cScreen;
599@@ -255,6 +261,10 @@
600
601 MatchedDecorClipGroup mMenusClipGroup;
602 X11DecorPixmapRequestor mRequestor;
603+ PixmapReleasePool::Ptr mReleasePool;
604+ PendingHandler mPendingHandler;
605+ UnusedHandler mUnusedHandler;
606+ protocol::Communicator mCommunicator;
607 };
608
609 class DecorWindow :
610
611=== modified file 'plugins/decor/src/pixmap-requests/include/pixmap-requests.h'
612--- plugins/decor/src/pixmap-requests/include/pixmap-requests.h 2012-05-10 15:40:25 +0000
613+++ plugins/decor/src/pixmap-requests/include/pixmap-requests.h 2013-02-20 07:34:20 +0000
614@@ -26,14 +26,19 @@
615 #ifndef _COMPIZ_DECOR_PIXMAP_REQUESTS_H
616 #define _COMPIZ_DECOR_PIXMAP_REQUESTS_H
617
618+#include <list>
619+
620 #include <boost/shared_ptr.hpp>
621 #include <boost/shared_array.hpp>
622 #include <boost/make_shared.hpp>
623+#include <boost/noncopyable.hpp>
624+#include <boost/function.hpp>
625 #include <decoration.h>
626
627 #include <X11/Xlib.h>
628
629-class DecorPixmapInterface
630+class DecorPixmapInterface :
631+ boost::noncopyable
632 {
633 public:
634
635@@ -44,7 +49,8 @@
636 virtual Pixmap getPixmap () = 0;
637 };
638
639-class DecorPixmapReceiverInterface
640+class DecorPixmapReceiverInterface :
641+ boost::noncopyable
642 {
643 public:
644
645@@ -57,7 +63,8 @@
646 /* So far, nothing particularly interesting here
647 * we just need a way to pass around pointers for
648 * testing */
649-class DecorationInterface
650+class DecorationInterface :
651+ boost::noncopyable
652 {
653 public:
654
655@@ -71,34 +78,50 @@
656 virtual unsigned int getFrameActions () const = 0;
657 };
658
659-class DecorPixmapDeletionInterface
660-{
661- public:
662-
663- typedef boost::shared_ptr <DecorPixmapDeletionInterface> Ptr;
664-
665- virtual ~DecorPixmapDeletionInterface () {}
666-
667- virtual int postDeletePixmap (Pixmap pixmap) = 0;
668-};
669-
670-class X11PixmapDeletor :
671- public DecorPixmapDeletionInterface
672-{
673- public:
674-
675- typedef boost::shared_ptr <X11PixmapDeletor> Ptr;
676-
677- X11PixmapDeletor (Display *dpy) :
678- mDisplay (dpy)
679- {
680- }
681-
682- int postDeletePixmap (Pixmap pixmap) { return decor_post_delete_pixmap (mDisplay, pixmap); }
683+class PixmapDestroyQueue :
684+ boost::noncopyable
685+{
686+ public:
687+
688+ typedef boost::shared_ptr <PixmapDestroyQueue> Ptr;
689+
690+ virtual ~PixmapDestroyQueue () {}
691+
692+ virtual int destroyUnusedPixmap (Pixmap pixmap) = 0;
693+};
694+
695+class UnusedPixmapQueue :
696+ boost::noncopyable
697+{
698+ public:
699+
700+ typedef boost::shared_ptr <UnusedPixmapQueue> Ptr;
701+
702+ virtual ~UnusedPixmapQueue () {}
703+
704+ virtual void markUnused (Pixmap pixmap) = 0;
705+};
706+
707+class PixmapReleasePool :
708+ public PixmapDestroyQueue,
709+ public UnusedPixmapQueue
710+{
711+ public:
712+
713+ typedef boost::function <int (Pixmap)> FreePixmapFunc;
714+
715+ typedef boost::shared_ptr <PixmapReleasePool> Ptr;
716+
717+ PixmapReleasePool (const FreePixmapFunc &freePixmap);
718+
719+ void markUnused (Pixmap pixmap);
720+ int destroyUnusedPixmap (Pixmap pixmap);
721
722 private:
723
724- Display *mDisplay;
725+ std::list <Pixmap> mPendingUnusedNotificationPixmaps;
726+ FreePixmapFunc mFreePixmap;
727+
728 };
729
730 class DecorPixmap :
731@@ -108,7 +131,7 @@
732
733 typedef boost::shared_ptr <DecorPixmap> Ptr;
734
735- DecorPixmap (Pixmap p, DecorPixmapDeletionInterface::Ptr deletor);
736+ DecorPixmap (Pixmap p, PixmapDestroyQueue::Ptr deletor);
737 ~DecorPixmap ();
738
739 Pixmap getPixmap ();
740@@ -116,10 +139,11 @@
741 private:
742
743 Pixmap mPixmap;
744- DecorPixmapDeletionInterface::Ptr mDeletor;
745+ PixmapDestroyQueue::Ptr mDeletor;
746 };
747
748-class DecorPixmapRequestorInterface
749+class DecorPixmapRequestorInterface :
750+ boost::noncopyable
751 {
752 public:
753
754@@ -129,7 +153,7 @@
755 unsigned int frameState,
756 unsigned int frameActions) = 0;
757
758- virtual void handlePending (long *data) = 0;
759+ virtual void handlePending (const long *data) = 0;
760 };
761
762 class DecorationListFindMatchingInterface
763@@ -140,8 +164,76 @@
764
765 virtual DecorationInterface::Ptr findMatchingDecoration (unsigned int frameType,
766 unsigned int frameState,
767- unsigned int frameActions) = 0;
768-};
769+ unsigned int frameActions) const = 0;
770+ virtual DecorationInterface::Ptr findMatchingDecoration (Pixmap pixmap) const = 0;
771+};
772+
773+namespace compiz
774+{
775+namespace decor
776+{
777+typedef boost::function <DecorationListFindMatchingInterface * (Window)> DecorListForWindow;
778+typedef boost::function <DecorPixmapRequestorInterface * (Window)> RequestorForWindow;
779+
780+class PendingHandler :
781+ virtual boost::noncopyable
782+{
783+ public:
784+
785+ PendingHandler (const RequestorForWindow &);
786+
787+ void handleMessage (Window window, const long *data);
788+
789+ private:
790+
791+ RequestorForWindow mRequestorForWindow;
792+};
793+
794+class UnusedHandler :
795+ virtual boost::noncopyable
796+{
797+ public:
798+
799+ UnusedHandler (const DecorListForWindow &,
800+ const UnusedPixmapQueue::Ptr &,
801+ const PixmapReleasePool::FreePixmapFunc &);
802+
803+ void handleMessage (Window, Pixmap);
804+
805+ private:
806+
807+ DecorListForWindow mListForWindow;
808+ UnusedPixmapQueue::Ptr mQueue;
809+ PixmapReleasePool::FreePixmapFunc mFreePixmap;
810+};
811+
812+namespace protocol
813+{
814+typedef boost::function <void (Window, const long *)> PendingMessage;
815+typedef boost::function <void (Window, Pixmap)> PixmapUnusedMessage;
816+
817+class Communicator :
818+ virtual boost::noncopyable
819+{
820+ public:
821+
822+ Communicator (Atom pendingMsg,
823+ Atom unusedMsg,
824+ const PendingMessage &,
825+ const PixmapUnusedMessage &);
826+
827+ void handleClientMessage (const XClientMessageEvent &);
828+
829+ private:
830+
831+ Atom mPendingMsgAtom;
832+ Atom mUnusedMsgAtom;
833+ PendingMessage mPendingHandler;
834+ PixmapUnusedMessage mPixmapUnusedHander;
835+};
836+}
837+}
838+}
839
840 class X11DecorPixmapRequestor :
841 public DecorPixmapRequestorInterface
842@@ -156,7 +248,7 @@
843 unsigned int frameState,
844 unsigned int frameActions);
845
846- void handlePending (long *data);
847+ void handlePending (const long *data);
848
849 private:
850
851
852=== modified file 'plugins/decor/src/pixmap-requests/src/pixmap-requests.cpp'
853--- plugins/decor/src/pixmap-requests/src/pixmap-requests.cpp 2012-05-10 15:40:25 +0000
854+++ plugins/decor/src/pixmap-requests/src/pixmap-requests.cpp 2013-02-20 07:34:20 +0000
855@@ -6,7 +6,10 @@
856 #define foreach BOOST_FOREACH
857 #endif
858
859-DecorPixmap::DecorPixmap (Pixmap pixmap, DecorPixmapDeletionInterface::Ptr d) :
860+namespace cd = compiz::decor;
861+namespace cdp = compiz::decor::protocol;
862+
863+DecorPixmap::DecorPixmap (Pixmap pixmap, PixmapDestroyQueue::Ptr d) :
864 mPixmap (pixmap),
865 mDeletor (d)
866 {
867@@ -14,7 +17,7 @@
868
869 DecorPixmap::~DecorPixmap ()
870 {
871- mDeletor->postDeletePixmap (mPixmap);
872+ mDeletor->destroyUnusedPixmap (mPixmap);
873 }
874
875 Pixmap
876@@ -78,7 +81,7 @@
877 }
878
879 void
880-X11DecorPixmapRequestor::handlePending (long *data)
881+X11DecorPixmapRequestor::handlePending (const long *data)
882 {
883 DecorationInterface::Ptr d = mListFinder->findMatchingDecoration (static_cast <unsigned int> (data[0]),
884 static_cast <unsigned int> (data[1]),
885@@ -91,3 +94,103 @@
886 static_cast <unsigned int> (data[1]),
887 static_cast <unsigned int> (data[2]));
888 }
889+
890+namespace
891+{
892+typedef PixmapReleasePool::FreePixmapFunc FreePixmapFunc;
893+}
894+
895+PixmapReleasePool::PixmapReleasePool (const FreePixmapFunc &freePixmap) :
896+ mFreePixmap (freePixmap)
897+{
898+}
899+
900+void
901+PixmapReleasePool::markUnused (Pixmap pixmap)
902+{
903+ mPendingUnusedNotificationPixmaps.push_back (pixmap);
904+ mPendingUnusedNotificationPixmaps.unique ();
905+}
906+
907+int
908+PixmapReleasePool::destroyUnusedPixmap (Pixmap pixmap)
909+{
910+ std::list <Pixmap>::iterator it =
911+ std::find (mPendingUnusedNotificationPixmaps.begin (),
912+ mPendingUnusedNotificationPixmaps.end (),
913+ pixmap);
914+
915+ if (it != mPendingUnusedNotificationPixmaps.end ())
916+ {
917+ Pixmap pixmap (*it);
918+ mPendingUnusedNotificationPixmaps.erase (it);
919+
920+ mFreePixmap (pixmap);
921+ }
922+
923+ return 0;
924+}
925+
926+cd::PendingHandler::PendingHandler (const cd::RequestorForWindow &requestorForWindow) :
927+ mRequestorForWindow (requestorForWindow)
928+{
929+}
930+
931+void
932+cd::PendingHandler::handleMessage (Window window, const long *data)
933+{
934+ DecorPixmapRequestorInterface *requestor = mRequestorForWindow (window);
935+
936+ if (requestor)
937+ requestor->handlePending (data);
938+}
939+
940+cd::UnusedHandler::UnusedHandler (const cd::DecorListForWindow &listForWindow,
941+ const UnusedPixmapQueue::Ptr &queue,
942+ const FreePixmapFunc &freePixmap) :
943+ mListForWindow (listForWindow),
944+ mQueue (queue),
945+ mFreePixmap (freePixmap)
946+{
947+}
948+
949+void
950+cd::UnusedHandler::handleMessage (Window window, Pixmap pixmap)
951+{
952+ DecorationListFindMatchingInterface *findMatching = mListForWindow (window);
953+
954+ if (findMatching)
955+ {
956+ DecorationInterface::Ptr decoration (findMatching->findMatchingDecoration (pixmap));
957+
958+ if (decoration)
959+ {
960+ mQueue->markUnused (pixmap);
961+ return;
962+ }
963+ }
964+
965+ /* If a decoration was not found, then this pixmap is no longer in use
966+ * and we should free it */
967+ mFreePixmap (pixmap);
968+}
969+
970+cdp::Communicator::Communicator (Atom pendingMsg,
971+ Atom unusedMsg,
972+ const cdp::PendingMessage &pending,
973+ const cdp::PixmapUnusedMessage &pixmapUnused) :
974+ mPendingMsgAtom (pendingMsg),
975+ mUnusedMsgAtom (unusedMsg),
976+ mPendingHandler (pending),
977+ mPixmapUnusedHander (pixmapUnused)
978+{
979+}
980+
981+void
982+cdp::Communicator::handleClientMessage (const XClientMessageEvent &xce)
983+{
984+ if (xce.message_type == mPendingMsgAtom)
985+ mPendingHandler (xce.window, xce.data.l);
986+ else if (xce.message_type == mUnusedMsgAtom)
987+ mPixmapUnusedHander (xce.window, xce.data.l[0]);
988+}
989
990=== modified file 'plugins/decor/src/pixmap-requests/tests/CMakeLists.txt'
991--- plugins/decor/src/pixmap-requests/tests/CMakeLists.txt 2012-08-01 00:42:38 +0000
992+++ plugins/decor/src/pixmap-requests/tests/CMakeLists.txt 2013-02-20 07:34:20 +0000
993@@ -1,10 +1,17 @@
994 include_directories(${CMAKE_CURRENT_SOURCE_DIR})
995
996+add_library (compiz_decor_pixmap_requests_mock STATIC
997+ ${CMAKE_CURRENT_SOURCE_DIR}/compiz_decor_pixmap_requests_mock.cpp)
998+
999+target_link_libraries (compiz_decor_pixmap_requests_mock
1000+ compiz_decor_pixmap_requests)
1001+
1002 add_executable (compiz_test_decor_pixmap_requests
1003- ${CMAKE_CURRENT_SOURCE_DIR}/pixmap-requests/src/test-decor-pixmap-requests.cpp)
1004+ ${CMAKE_CURRENT_SOURCE_DIR}/test-decor-pixmap-requests.cpp)
1005
1006 target_link_libraries (compiz_test_decor_pixmap_requests
1007 compiz_decor_pixmap_requests
1008+ compiz_decor_pixmap_requests_mock
1009 decoration
1010 ${GTEST_BOTH_LIBRARIES}
1011 ${GMOCK_LIBRARY}
1012@@ -13,3 +20,5 @@
1013 )
1014
1015 compiz_discover_tests (compiz_test_decor_pixmap_requests COVERAGE compiz_decor_pixmap_requests)
1016+
1017+add_subdirectory (integration)
1018
1019=== added file 'plugins/decor/src/pixmap-requests/tests/compiz_decor_pixmap_requests_mock.cpp'
1020--- plugins/decor/src/pixmap-requests/tests/compiz_decor_pixmap_requests_mock.cpp 1970-01-01 00:00:00 +0000
1021+++ plugins/decor/src/pixmap-requests/tests/compiz_decor_pixmap_requests_mock.cpp 2013-02-20 07:34:20 +0000
1022@@ -0,0 +1,113 @@
1023+/*
1024+ * Copyright © 2012 Canonical Ltd.
1025+ * Copyright © 2013 Sam Spilsbury <smspillaz@gmail.com>
1026+ *
1027+ * Permission to use, copy, modify, distribute, and sell this software
1028+ * and its documentation for any purpose is hereby granted without
1029+ * fee, provided that the above copyright notice appear in all copies
1030+ * and that both that copyright notice and this permission notice
1031+ * appear in supporting documentation, and that the name of
1032+ * Canonical Ltd. not be used in advertising or publicity pertaining to
1033+ * distribution of the software without specific, written prior permission.
1034+ * Canonical Ltd. makes no representations about the suitability of this
1035+ * software for any purpose. It is provided "as is" without express or
1036+ * implied warranty.
1037+ *
1038+ * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1039+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
1040+ * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1041+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
1042+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
1043+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
1044+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1045+ *
1046+ * Authored by: Sam Spilsbury <sam.spilsbury@canonical.com>
1047+ */
1048+
1049+#include "compiz_decor_pixmap_requests_mock.h"
1050+
1051+/* These exist purely because the implicit details of the
1052+ * constructors of the MOCK_METHODs are quite complex. We can
1053+ * save compilation time by generating those constructors once,
1054+ * and linking, rather than generating multiple definitions and
1055+ * having the linker eliminate them */
1056+
1057+MockDecorPixmapDeletor::MockDecorPixmapDeletor ()
1058+{
1059+}
1060+
1061+MockDecorPixmapDeletor::~MockDecorPixmapDeletor ()
1062+{
1063+}
1064+
1065+MockDecorPixmapReceiver::MockDecorPixmapReceiver ()
1066+{
1067+}
1068+
1069+MockDecorPixmapReceiver::~MockDecorPixmapReceiver ()
1070+{
1071+}
1072+
1073+MockDecoration::MockDecoration ()
1074+{
1075+}
1076+
1077+MockDecoration::~MockDecoration ()
1078+{
1079+}
1080+
1081+MockDecorationListFindMatching::MockDecorationListFindMatching ()
1082+{
1083+}
1084+
1085+MockDecorationListFindMatching::~MockDecorationListFindMatching ()
1086+{
1087+}
1088+
1089+MockDecorPixmapRequestor::MockDecorPixmapRequestor ()
1090+{
1091+}
1092+
1093+MockDecorPixmapRequestor::~MockDecorPixmapRequestor ()
1094+{
1095+}
1096+
1097+XlibPixmapMock::XlibPixmapMock ()
1098+{
1099+}
1100+
1101+XlibPixmapMock::~XlibPixmapMock ()
1102+{
1103+}
1104+
1105+MockFindRequestor::MockFindRequestor ()
1106+{
1107+}
1108+
1109+MockFindRequestor::~MockFindRequestor ()
1110+{
1111+}
1112+
1113+MockFindList::MockFindList ()
1114+{
1115+}
1116+
1117+MockFindList::~MockFindList ()
1118+{
1119+}
1120+
1121+MockUnusedPixmapQueue::MockUnusedPixmapQueue ()
1122+{
1123+}
1124+
1125+MockUnusedPixmapQueue::~MockUnusedPixmapQueue ()
1126+{
1127+}
1128+
1129+MockProtocolDispatchFuncs::MockProtocolDispatchFuncs ()
1130+{
1131+}
1132+
1133+MockProtocolDispatchFuncs::~MockProtocolDispatchFuncs ()
1134+{
1135+}
1136
1137=== added file 'plugins/decor/src/pixmap-requests/tests/compiz_decor_pixmap_requests_mock.h'
1138--- plugins/decor/src/pixmap-requests/tests/compiz_decor_pixmap_requests_mock.h 1970-01-01 00:00:00 +0000
1139+++ plugins/decor/src/pixmap-requests/tests/compiz_decor_pixmap_requests_mock.h 2013-02-20 07:34:20 +0000
1140@@ -0,0 +1,179 @@
1141+/*
1142+ * Copyright © 2012 Canonical Ltd.
1143+ * Copyright © 2013 Sam Spilsbury <smspillaz@gmail.com>
1144+ *
1145+ * Permission to use, copy, modify, distribute, and sell this software
1146+ * and its documentation for any purpose is hereby granted without
1147+ * fee, provided that the above copyright notice appear in all copies
1148+ * and that both that copyright notice and this permission notice
1149+ * appear in supporting documentation, and that the name of
1150+ * Canonical Ltd. not be used in advertising or publicity pertaining to
1151+ * distribution of the software without specific, written prior permission.
1152+ * Canonical Ltd. makes no representations about the suitability of this
1153+ * software for any purpose. It is provided "as is" without express or
1154+ * implied warranty.
1155+ *
1156+ * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1157+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
1158+ * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1159+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
1160+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
1161+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
1162+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1163+ *
1164+ * Authored by: Sam Spilsbury <sam.spilsbury@canonical.com>
1165+ */
1166+
1167+#ifndef _COMPIZ_DECOR_PIXMAP_REQUESTS_MOCK_H
1168+#define _COMPIZ_DECOR_PIXMAP_REQUESTS_MOCK_H
1169+
1170+#include <gmock/gmock.h>
1171+#include <boost/bind.hpp>
1172+
1173+#include <X11/Xlib.h>
1174+#include "pixmap-requests.h"
1175+
1176+class MockDecorPixmapDeletor :
1177+ public PixmapDestroyQueue
1178+{
1179+ public:
1180+
1181+ MockDecorPixmapDeletor ();
1182+ ~MockDecorPixmapDeletor ();
1183+
1184+ MOCK_METHOD1 (destroyUnusedPixmap, int (Pixmap p));
1185+};
1186+
1187+class MockDecorPixmapReceiver :
1188+ public DecorPixmapReceiverInterface
1189+{
1190+ public:
1191+
1192+ MockDecorPixmapReceiver ();
1193+ ~MockDecorPixmapReceiver ();
1194+
1195+ MOCK_METHOD0 (pending, void ());
1196+ MOCK_METHOD0 (update, void ());
1197+};
1198+
1199+class MockDecoration :
1200+ public DecorationInterface
1201+{
1202+ public:
1203+
1204+ MockDecoration ();
1205+ ~MockDecoration ();
1206+
1207+ MOCK_METHOD0 (receiverInterface, DecorPixmapReceiverInterface & ());
1208+ MOCK_CONST_METHOD0 (getFrameType, unsigned int ());
1209+ MOCK_CONST_METHOD0 (getFrameState, unsigned int ());
1210+ MOCK_CONST_METHOD0 (getFrameActions, unsigned int ());
1211+};
1212+
1213+class MockDecorationListFindMatching :
1214+ public DecorationListFindMatchingInterface
1215+{
1216+ public:
1217+
1218+ MockDecorationListFindMatching ();
1219+ ~MockDecorationListFindMatching ();
1220+
1221+ MOCK_CONST_METHOD3 (findMatchingDecoration, DecorationInterface::Ptr (unsigned int, unsigned int, unsigned int));
1222+ MOCK_CONST_METHOD1 (findMatchingDecoration, DecorationInterface::Ptr (Pixmap));
1223+};
1224+
1225+class MockDecorPixmapRequestor :
1226+ public DecorPixmapRequestorInterface
1227+{
1228+ public:
1229+
1230+ MockDecorPixmapRequestor ();
1231+ ~MockDecorPixmapRequestor ();
1232+
1233+ MOCK_METHOD3 (postGenerateRequest, int (unsigned int, unsigned int, unsigned int));
1234+ MOCK_METHOD1 (handlePending, void (const long *));
1235+};
1236+
1237+class XlibPixmapMock
1238+{
1239+ public:
1240+
1241+ XlibPixmapMock ();
1242+ ~XlibPixmapMock ();
1243+
1244+ MOCK_METHOD1(freePixmap, int (Pixmap));
1245+};
1246+
1247+class MockFindRequestor
1248+{
1249+ public:
1250+
1251+ MockFindRequestor ();
1252+ ~MockFindRequestor ();
1253+
1254+ MOCK_METHOD1 (findRequestor, DecorPixmapRequestorInterface * (Window));
1255+};
1256+
1257+class MockFindList
1258+{
1259+ public:
1260+
1261+ MockFindList ();
1262+ ~MockFindList ();
1263+
1264+ MOCK_METHOD1 (findList, DecorationListFindMatchingInterface * (Window));
1265+};
1266+
1267+class MockUnusedPixmapQueue :
1268+ public UnusedPixmapQueue
1269+{
1270+ public:
1271+
1272+ MockUnusedPixmapQueue ();
1273+ ~MockUnusedPixmapQueue ();
1274+
1275+ typedef boost::shared_ptr <MockUnusedPixmapQueue> Ptr;
1276+
1277+ MOCK_METHOD1 (markUnused, void (Pixmap));
1278+};
1279+
1280+class StubReceiver :
1281+ public DecorPixmapReceiverInterface
1282+{
1283+ public:
1284+
1285+ void pending () {}
1286+ void update () {}
1287+};
1288+
1289+class StubDecoration :
1290+ public DecorationInterface
1291+{
1292+ public:
1293+
1294+ DecorPixmapReceiverInterface & receiverInterface ()
1295+ {
1296+ return mReceiver;
1297+ }
1298+
1299+ unsigned int getFrameType () const { return 0; }
1300+ unsigned int getFrameState () const { return 0; }
1301+ unsigned int getFrameActions () const { return 0; }
1302+
1303+ private:
1304+
1305+ StubReceiver mReceiver;
1306+};
1307+
1308+class MockProtocolDispatchFuncs
1309+{
1310+ public:
1311+
1312+ MockProtocolDispatchFuncs ();
1313+ ~MockProtocolDispatchFuncs ();
1314+
1315+ MOCK_METHOD2 (handlePending, void (Window, const long *));
1316+ MOCK_METHOD2 (handleUnused, void (Window, Pixmap));
1317+};
1318+
1319+#endif
1320
1321=== added directory 'plugins/decor/src/pixmap-requests/tests/integration'
1322=== added file 'plugins/decor/src/pixmap-requests/tests/integration/CMakeLists.txt'
1323--- plugins/decor/src/pixmap-requests/tests/integration/CMakeLists.txt 1970-01-01 00:00:00 +0000
1324+++ plugins/decor/src/pixmap-requests/tests/integration/CMakeLists.txt 2013-02-20 07:34:20 +0000
1325@@ -0,0 +1,1 @@
1326+add_subdirectory (xorg-gtest)
1327
1328=== added directory 'plugins/decor/src/pixmap-requests/tests/integration/xorg-gtest'
1329=== added file 'plugins/decor/src/pixmap-requests/tests/integration/xorg-gtest/CMakeLists.txt'
1330--- plugins/decor/src/pixmap-requests/tests/integration/xorg-gtest/CMakeLists.txt 1970-01-01 00:00:00 +0000
1331+++ plugins/decor/src/pixmap-requests/tests/integration/xorg-gtest/CMakeLists.txt 2013-02-20 07:34:20 +0000
1332@@ -0,0 +1,41 @@
1333+include (FindPkgConfig)
1334+
1335+if (BUILD_XORG_GTEST)
1336+
1337+ include_directories (${compiz_SOURCE_DIR}/tests/shared
1338+ ${COMPIZ_XORG_SYSTEM_TEST_INCLUDE_DIR}
1339+ ${X11_INCLUDE_DIRS}
1340+ ${XORG_SERVER_INCLUDE_XORG_GTEST}
1341+ ${XORG_SERVER_GTEST_SRC}
1342+ ${GTEST_INCLUDE_DIRS}
1343+ ${COMPIZ_DECOR_PIXMAP_PROTOCOL_INTEGRATION_INCLUDE_DIRS})
1344+
1345+ link_directories (${X11_XI_LIBRARY_DIRS}
1346+ ${COMPIZ_COMPOSITE_DAMAGETRACKING_INTEGRATION_LIBRARY_DIRS})
1347+
1348+ add_executable (compiz_test_decor_pixmap_protocol_integration
1349+ ${CMAKE_CURRENT_SOURCE_DIR}/compiz_test_decor_pixmap_protocol_integration.cpp)
1350+
1351+ set (COMPIZ_DECOR_PIXMAP_PROTOCOL_XORG_INTEGRATION_TEST_LIBRARIES
1352+ xorg_gtest_all
1353+ xorg_gtest_main
1354+ compiz_xorg_gtest_system_test
1355+ compiz_decor_pixmap_requests
1356+ compiz_decor_pixmap_requests_mock
1357+ decoration
1358+ ${GMOCK_LIBRARY}
1359+ ${GMOCK_MAIN_LIBRARY}
1360+ ${GTEST_BOTH_LIBRARIES}
1361+ ${CMAKE_THREAD_LIBS_INIT}
1362+ ${XORG_SERVER_LIBRARIES}
1363+ ${X11_XI_LIBRARIES}
1364+ ${COMPIZ_DECOR_PIXMAP_PROTOCOL_INTEGRATION_LIBRARIES})
1365+
1366+ target_link_libraries (compiz_test_decor_pixmap_protocol_integration
1367+ ${COMPIZ_DECOR_PIXMAP_PROTOCOL_XORG_INTEGRATION_TEST_LIBRARIES})
1368+
1369+ compiz_discover_tests (compiz_test_decor_pixmap_protocol_integration WITH_XORG_GTEST COVERAGE
1370+ compiz_decor_pixmap_requests)
1371+
1372+endif (BUILD_XORG_GTEST)
1373+
1374
1375=== added file 'plugins/decor/src/pixmap-requests/tests/integration/xorg-gtest/compiz_test_decor_pixmap_protocol_integration.cpp'
1376--- plugins/decor/src/pixmap-requests/tests/integration/xorg-gtest/compiz_test_decor_pixmap_protocol_integration.cpp 1970-01-01 00:00:00 +0000
1377+++ plugins/decor/src/pixmap-requests/tests/integration/xorg-gtest/compiz_test_decor_pixmap_protocol_integration.cpp 2013-02-20 07:34:20 +0000
1378@@ -0,0 +1,483 @@
1379+/*
1380+ * Compiz XOrg GTest Decoration Pixmap Protocol Integration Tests
1381+ *
1382+ * Copyright (C) 2013 Sam Spilsbury.
1383+ *
1384+ * This library is free software; you can redistribute it and/or
1385+ * modify it under the terms of the GNU Lesser General Public
1386+ * License as published by the Free Software Foundation; either
1387+ * version 2.1 of the License, or (at your option) any later version.
1388+
1389+ * This library is distributed in the hope that it will be useful,
1390+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1391+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1392+ * Lesser General Public License for more details.
1393+
1394+ * You should have received a copy of the GNU Lesser General Public
1395+ * License along with this library; if not, write to the Free Software
1396+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1397+ *
1398+ * Authored By:
1399+ * Sam Spilsbury <smspillaz@gmail.com>
1400+ */
1401+#include <gtest/gtest.h>
1402+#include <gmock/gmock.h>
1403+
1404+#include <boost/function.hpp>
1405+#include <boost/bind.hpp>
1406+
1407+#include <boost/shared_ptr.hpp>
1408+#include <boost/make_shared.hpp>
1409+
1410+#include <X11/Xlib.h>
1411+#include <X11/Xatom.h>
1412+
1413+#include "decoration.h"
1414+
1415+#include <xorg/gtest/xorg-gtest.h>
1416+#include <compiz-xorg-gtest.h>
1417+
1418+#include "pixmap-requests.h"
1419+#include "compiz_decor_pixmap_requests_mock.h"
1420+
1421+namespace xt = xorg::testing;
1422+namespace ct = compiz::testing;
1423+namespace cd = compiz::decor;
1424+namespace cdp = compiz::decor::protocol;
1425+
1426+using ::testing::AtLeast;
1427+using ::testing::ReturnNull;
1428+using ::testing::Return;
1429+using ::testing::MatcherInterface;
1430+using ::testing::MatchResultListener;
1431+using ::testing::_;
1432+
1433+class DecorPixmapProtocol :
1434+ public xorg::testing::Test
1435+{
1436+ public:
1437+
1438+ typedef boost::function <void (const XClientMessageEvent &)> ClientMessageReceiver;
1439+
1440+ void SetUp ();
1441+
1442+ void WaitForClientMessageOnAndDeliverTo (Window client,
1443+ Atom message,
1444+ const ClientMessageReceiver &receiver);
1445+
1446+ protected:
1447+
1448+ Atom deletePixmapMessage;
1449+ Atom pendingMessage;
1450+};
1451+
1452+namespace
1453+{
1454+bool Advance (Display *d, bool result)
1455+{
1456+ return ct::AdvanceToNextEventOnSuccess (d, result);
1457+}
1458+
1459+Window MOCK_WINDOW = 1;
1460+Pixmap MOCK_PIXMAP = 2;
1461+
1462+class MockClientMessageReceiver
1463+{
1464+ public:
1465+
1466+ MOCK_METHOD1 (receiveMsg, void (const XClientMessageEvent &));
1467+};
1468+
1469+class DisplayFetch
1470+{
1471+ public:
1472+
1473+ virtual ~DisplayFetch () {}
1474+
1475+ virtual ::Display * Display () const = 0;
1476+};
1477+
1478+class XFreePixmapWrapper
1479+{
1480+ public:
1481+
1482+ XFreePixmapWrapper (const DisplayFetch &df) :
1483+ mDisplayFetch (df)
1484+ {
1485+ }
1486+
1487+ int FreePixmap (Pixmap pixmap)
1488+ {
1489+ return XFreePixmap (mDisplayFetch.Display (), pixmap);
1490+ }
1491+
1492+ private:
1493+
1494+ const DisplayFetch &mDisplayFetch;
1495+};
1496+
1497+class XErrorTracker
1498+{
1499+ public:
1500+
1501+ XErrorTracker ();
1502+ ~XErrorTracker ();
1503+
1504+ MOCK_METHOD1 (errorHandler, void (int));
1505+
1506+ private:
1507+
1508+ XErrorHandler handler;
1509+
1510+ static int handleXError (Display *dpy, XErrorEvent *ev);
1511+ static XErrorTracker *tracker;
1512+};
1513+
1514+XErrorTracker * XErrorTracker::tracker = NULL;
1515+
1516+XErrorTracker::XErrorTracker ()
1517+{
1518+ tracker = this;
1519+ handler = XSetErrorHandler (handleXError);
1520+}
1521+
1522+XErrorTracker::~XErrorTracker ()
1523+{
1524+ tracker = NULL;
1525+ XSetErrorHandler (handler);
1526+}
1527+
1528+int
1529+XErrorTracker::handleXError (Display *dpy, XErrorEvent *ev)
1530+{
1531+ tracker->errorHandler (ev->error_code);
1532+ return 0;
1533+}
1534+
1535+bool PixmapValid (Display *d, Pixmap p)
1536+{
1537+ Window root;
1538+ unsigned int width, height, border, depth;
1539+ int x, y;
1540+
1541+ XErrorTracker tracker;
1542+
1543+ EXPECT_CALL (tracker, errorHandler (BadDrawable)).Times (AtLeast (0));
1544+
1545+ bool success = XGetGeometry (d, p, &root, &x, &y,
1546+ &width, &height, &border, &depth);
1547+
1548+ return success;
1549+}
1550+}
1551+
1552+void
1553+DecorPixmapProtocol::SetUp ()
1554+{
1555+ xorg::testing::Test::SetUp ();
1556+
1557+ XSelectInput (Display (),
1558+ DefaultRootWindow (Display ()),
1559+ StructureNotifyMask);
1560+
1561+ deletePixmapMessage = XInternAtom (Display (), DECOR_DELETE_PIXMAP_ATOM_NAME, 0);
1562+ pendingMessage = XInternAtom (Display (), DECOR_PIXMAP_PENDING_ATOM_NAME, 0);
1563+}
1564+
1565+class DeliveryMatcher :
1566+ public ct::XEventMatcher
1567+{
1568+ public:
1569+
1570+ DeliveryMatcher (Atom message,
1571+ const DecorPixmapProtocol::ClientMessageReceiver &receiver) :
1572+ mMessage (message),
1573+ mReceiver (receiver)
1574+ {
1575+ }
1576+
1577+ bool MatchAndExplain (const XEvent &xce,
1578+ MatchResultListener *listener) const
1579+ {
1580+ if (xce.xclient.message_type == mMessage)
1581+ {
1582+ mReceiver (reinterpret_cast <const XClientMessageEvent &> (xce));
1583+ return true;
1584+ }
1585+ else
1586+ return false;
1587+ }
1588+
1589+ void DescribeTo (std::ostream *os) const
1590+ {
1591+ *os << "Message delivered";
1592+ }
1593+
1594+ private:
1595+
1596+ Atom mMessage;
1597+ DecorPixmapProtocol::ClientMessageReceiver mReceiver;
1598+};
1599+
1600+void
1601+DecorPixmapProtocol::WaitForClientMessageOnAndDeliverTo (Window client,
1602+ Atom message,
1603+ const ClientMessageReceiver &receiver)
1604+{
1605+ ::Display *d = Display ();
1606+
1607+ DeliveryMatcher delivery (message, receiver);
1608+ ASSERT_TRUE (Advance (d, ct::WaitForEventOfTypeOnWindowMatching (d,
1609+ client,
1610+ ClientMessage,
1611+ -1,
1612+ -1,
1613+ delivery)));
1614+}
1615+
1616+TEST_F (DecorPixmapProtocol, PostDeleteCausesClientMessage)
1617+{
1618+ MockClientMessageReceiver receiver;
1619+ ::Display *d = Display ();
1620+
1621+ decor_post_delete_pixmap (d,
1622+ MOCK_WINDOW,
1623+ MOCK_PIXMAP);
1624+
1625+ EXPECT_CALL (receiver, receiveMsg (_)).Times (1);
1626+
1627+ WaitForClientMessageOnAndDeliverTo (MOCK_WINDOW,
1628+ deletePixmapMessage,
1629+ boost::bind (&MockClientMessageReceiver::receiveMsg,
1630+ &receiver,
1631+ _1));
1632+}
1633+
1634+TEST_F (DecorPixmapProtocol, PostDeleteDispatchesClientMessageToReceiver)
1635+{
1636+ MockProtocolDispatchFuncs dispatch;
1637+ cdp::Communicator communicator (pendingMessage,
1638+ deletePixmapMessage,
1639+ boost::bind (&MockProtocolDispatchFuncs::handlePending,
1640+ &dispatch,
1641+ _1,
1642+ _2),
1643+ boost::bind (&MockProtocolDispatchFuncs::handleUnused,
1644+ &dispatch,
1645+ _1,
1646+ _2));
1647+
1648+ decor_post_delete_pixmap (Display (),
1649+ MOCK_WINDOW,
1650+ MOCK_PIXMAP);
1651+
1652+ EXPECT_CALL (dispatch, handleUnused (MOCK_WINDOW, MOCK_PIXMAP)).Times (1);
1653+
1654+ WaitForClientMessageOnAndDeliverTo (MOCK_WINDOW,
1655+ deletePixmapMessage,
1656+ boost::bind (&cdp::Communicator::handleClientMessage,
1657+ &communicator,
1658+ _1));
1659+}
1660+
1661+/* Test end to end. Post the delete message and cause the pixmap to be freed */
1662+
1663+class DecorPixmapProtocolEndToEnd :
1664+ public DecorPixmapProtocol,
1665+ public DisplayFetch
1666+{
1667+ public:
1668+
1669+ DecorPixmapProtocolEndToEnd () :
1670+ freePixmap (*this),
1671+ releasePool (new PixmapReleasePool (
1672+ boost::bind (&XFreePixmapWrapper::FreePixmap,
1673+ &freePixmap,
1674+ _1))),
1675+ pendingHandler (boost::bind (&MockFindRequestor::findRequestor,
1676+ &mockFindRequestor,
1677+ _1)),
1678+ unusedHandler (boost::bind (&MockFindList::findList,
1679+ &mockFindList,
1680+ _1),
1681+ releasePool,
1682+ boost::bind (&XFreePixmapWrapper::FreePixmap,
1683+ &freePixmap,
1684+ _1)),
1685+ stubDecoration (new StubDecoration ())
1686+ {
1687+ }
1688+
1689+ void SetUp ()
1690+ {
1691+ DecorPixmapProtocol::SetUp ();
1692+
1693+ communicator.reset (new cdp::Communicator (
1694+ pendingMessage,
1695+ deletePixmapMessage,
1696+ boost::bind (&cd::PendingHandler::handleMessage,
1697+ &pendingHandler,
1698+ _1,
1699+ _2),
1700+ boost::bind (&cd::UnusedHandler::handleMessage,
1701+ &unusedHandler,
1702+ _1,
1703+ _2)));
1704+ }
1705+
1706+ ::Display *
1707+ Display () const
1708+ {
1709+ return DecorPixmapProtocol::Display ();
1710+ }
1711+
1712+ XFreePixmapWrapper freePixmap;
1713+ PixmapReleasePool::Ptr releasePool;
1714+ cd::PendingHandler pendingHandler;
1715+ cd::UnusedHandler unusedHandler;
1716+ boost::shared_ptr <cdp::Communicator> communicator;
1717+ MockFindList mockFindList;
1718+ MockFindRequestor mockFindRequestor;
1719+ StubDecoration::Ptr stubDecoration;
1720+ MockDecorPixmapRequestor mockRequestor;
1721+ MockDecorationListFindMatching mockFindMatching;
1722+
1723+};
1724+
1725+class DecorPixmapProtocolDeleteEndToEnd :
1726+ public DecorPixmapProtocolEndToEnd
1727+{
1728+ public:
1729+
1730+ void SetUp ()
1731+ {
1732+ DecorPixmapProtocolEndToEnd::SetUp ();
1733+
1734+ ::Display *d = Display ();
1735+
1736+ pixmap = XCreatePixmap (d,
1737+ DefaultRootWindow (d),
1738+ 1,
1739+ 1,
1740+ DefaultDepth (d,
1741+ DefaultScreen (d)));
1742+
1743+ decor_post_delete_pixmap (d,
1744+ MOCK_WINDOW,
1745+ pixmap);
1746+ }
1747+
1748+ void TearDown ()
1749+ {
1750+ if (PixmapValid (Display (), pixmap))
1751+ XFreePixmap (Display (), pixmap);
1752+ }
1753+
1754+ protected:
1755+
1756+ Pixmap pixmap;
1757+};
1758+
1759+TEST_F (DecorPixmapProtocolDeleteEndToEnd, TestFreeNotFoundWindowPixmapImmediately)
1760+{
1761+ ::Display *d = Display ();
1762+
1763+ EXPECT_CALL (mockFindList, findList (MOCK_WINDOW)).WillOnce (ReturnNull ());
1764+
1765+ /* Deliver it to the communicator */
1766+ WaitForClientMessageOnAndDeliverTo (MOCK_WINDOW,
1767+ deletePixmapMessage,
1768+ boost::bind (&cdp::Communicator::handleClientMessage,
1769+ communicator.get (),
1770+ _1));
1771+
1772+ /* Check if the pixmap is still valid */
1773+ EXPECT_FALSE (PixmapValid (d, pixmap));
1774+}
1775+
1776+TEST_F (DecorPixmapProtocolDeleteEndToEnd, TestFreeUnusedPixmapImmediately)
1777+{
1778+ ::Display *d = Display ();
1779+
1780+ EXPECT_CALL (mockFindMatching, findMatchingDecoration (pixmap)).WillOnce (Return (DecorationInterface::Ptr ()));
1781+ EXPECT_CALL (mockFindList, findList (MOCK_WINDOW)).WillOnce (Return (&mockFindMatching));
1782+ /* Deliver it to the communicator */
1783+ WaitForClientMessageOnAndDeliverTo (MOCK_WINDOW,
1784+ deletePixmapMessage,
1785+ boost::bind (&cdp::Communicator::handleClientMessage,
1786+ communicator.get (),
1787+ _1));
1788+
1789+ /* Check if the pixmap is still valid */
1790+ EXPECT_FALSE (PixmapValid (d, pixmap));
1791+}
1792+
1793+TEST_F (DecorPixmapProtocolDeleteEndToEnd, TestQueuePixmapIfUsed)
1794+{
1795+ ::Display *d = Display ();
1796+
1797+ EXPECT_CALL (mockFindMatching, findMatchingDecoration (pixmap)).WillOnce (Return (stubDecoration));
1798+ EXPECT_CALL (mockFindList, findList (MOCK_WINDOW)).WillOnce (Return (&mockFindMatching));
1799+ /* Deliver it to the communicator */
1800+ WaitForClientMessageOnAndDeliverTo (MOCK_WINDOW,
1801+ deletePixmapMessage,
1802+ boost::bind (&cdp::Communicator::handleClientMessage,
1803+ communicator.get (),
1804+ _1));
1805+
1806+ /* Check if the pixmap is still valid */
1807+ EXPECT_TRUE (PixmapValid (d, pixmap));
1808+
1809+ /* Call destroyUnusedPixmap on the release pool, it should release
1810+ * the pixmap which was otherwise unused */
1811+ releasePool->destroyUnusedPixmap (pixmap);
1812+
1813+ /* Pixmap should now be invalid */
1814+ EXPECT_FALSE (PixmapValid (d, pixmap));
1815+}
1816+
1817+class DecorPixmapProtocolPendingEndToEnd :
1818+ public DecorPixmapProtocolEndToEnd
1819+{
1820+ public:
1821+
1822+ DecorPixmapProtocolPendingEndToEnd () :
1823+ frameType (1),
1824+ frameState (2),
1825+ frameActions (3)
1826+ {
1827+ }
1828+
1829+ void SetUp ()
1830+ {
1831+ DecorPixmapProtocolEndToEnd::SetUp ();
1832+
1833+ ::Display *d = Display ();
1834+
1835+ decor_post_pending (d, MOCK_WINDOW, frameType, frameState, frameActions);
1836+ }
1837+
1838+ protected:
1839+
1840+ unsigned int frameType, frameState, frameActions;
1841+};
1842+
1843+MATCHER_P3 (MatchArrayValues3, v1, v2, v3, "Matches three array values")
1844+{
1845+ return static_cast <unsigned int> (arg[0]) == v1 &&
1846+ static_cast <unsigned int> (arg[1]) == v2 &&
1847+ static_cast <unsigned int> (arg[2]) == v3;
1848+}
1849+
1850+TEST_F (DecorPixmapProtocolPendingEndToEnd, TestPostPendingMarksAsPendingOnClient)
1851+{
1852+ EXPECT_CALL (mockFindRequestor, findRequestor (MOCK_WINDOW)).WillOnce (Return (&mockRequestor));
1853+ EXPECT_CALL (mockRequestor, handlePending (MatchArrayValues3 (frameType, frameState, frameActions)));
1854+
1855+ /* Deliver it to the communicator */
1856+ WaitForClientMessageOnAndDeliverTo (MOCK_WINDOW,
1857+ pendingMessage,
1858+ boost::bind (&cdp::Communicator::handleClientMessage,
1859+ communicator.get (),
1860+ _1));
1861+}
1862
1863=== renamed file 'plugins/decor/src/pixmap-requests/tests/pixmap-requests/src/test-decor-pixmap-requests.cpp' => 'plugins/decor/src/pixmap-requests/tests/test-decor-pixmap-requests.cpp'
1864--- plugins/decor/src/pixmap-requests/tests/pixmap-requests/src/test-decor-pixmap-requests.cpp 2012-05-10 15:40:25 +0000
1865+++ plugins/decor/src/pixmap-requests/tests/test-decor-pixmap-requests.cpp 2013-02-20 07:34:20 +0000
1866@@ -25,67 +25,29 @@
1867
1868 #include <gtest/gtest.h>
1869 #include <gmock/gmock.h>
1870+#include <boost/bind.hpp>
1871 #include <iostream>
1872+
1873+#include <X11/Xlib.h>
1874 #include "pixmap-requests.h"
1875+#include "compiz_decor_pixmap_requests_mock.h"
1876
1877+using ::testing::AtLeast;
1878+using ::testing::Pointee;
1879 using ::testing::Return;
1880-
1881-class DecorPixmapRequestsTest :
1882- public ::testing::Test
1883-{
1884-};
1885-
1886-class MockDecorPixmapDeletor :
1887- public DecorPixmapDeletionInterface
1888-{
1889- public:
1890-
1891- MOCK_METHOD1 (postDeletePixmap, int (Pixmap p));
1892-};
1893-
1894-class MockDecorPixmapReceiver :
1895- public DecorPixmapReceiverInterface
1896-{
1897- public:
1898-
1899- MOCK_METHOD0 (pending, void ());
1900- MOCK_METHOD0 (update, void ());
1901-};
1902-
1903-class MockDecoration :
1904- public DecorationInterface
1905-{
1906- public:
1907-
1908- MOCK_METHOD0 (receiverInterface, DecorPixmapReceiverInterface & ());
1909- MOCK_CONST_METHOD0 (getFrameType, unsigned int ());
1910- MOCK_CONST_METHOD0 (getFrameState, unsigned int ());
1911- MOCK_CONST_METHOD0 (getFrameActions, unsigned int ());
1912-};
1913-
1914-class MockDecorationListFindMatching :
1915- public DecorationListFindMatchingInterface
1916-{
1917- public:
1918-
1919- MOCK_METHOD3 (findMatchingDecoration, DecorationInterface::Ptr (unsigned int, unsigned int, unsigned int));
1920-};
1921-
1922-class MockDecorPixmapRequestor :
1923- public DecorPixmapRequestorInterface
1924-{
1925- public:
1926-
1927- MOCK_METHOD3 (postGenerateRequest, int (unsigned int, unsigned int, unsigned int));
1928- MOCK_METHOD1 (handlePending, void (long *));
1929-};
1930+using ::testing::ReturnNull;
1931+using ::testing::IsNull;
1932+using ::testing::_;
1933+
1934+namespace cd = compiz::decor;
1935+namespace cdp = compiz::decor::protocol;
1936
1937 TEST(DecorPixmapRequestsTest, TestDestroyPixmapDeletes)
1938 {
1939 boost::shared_ptr <MockDecorPixmapDeletor> mockDeletor = boost::make_shared <MockDecorPixmapDeletor> ();
1940- DecorPixmap pm (1, boost::shared_static_cast<DecorPixmapDeletionInterface> (mockDeletor));
1941+ DecorPixmap pm (1, boost::shared_static_cast<PixmapDestroyQueue> (mockDeletor));
1942
1943- EXPECT_CALL (*(mockDeletor.get ()), postDeletePixmap (1)).WillOnce (Return (1));
1944+ EXPECT_CALL (*(mockDeletor.get ()), destroyUnusedPixmap (1)).WillOnce (Return (1));
1945 }
1946
1947 TEST(DecorPixmapRequestsTest, TestPendingGeneratesRequest)
1948@@ -158,3 +120,284 @@
1949 receiver.pending ();
1950 receiver.update ();
1951 }
1952+
1953+class DecorPixmapReleasePool :
1954+ public ::testing::Test
1955+{
1956+ public:
1957+
1958+ DecorPixmapReleasePool () :
1959+ mockFreeFunc (boost::bind (&XlibPixmapMock::freePixmap,
1960+ &xlibPixmapMock,
1961+ _1)),
1962+ releasePool (mockFreeFunc)
1963+ {
1964+ }
1965+
1966+ XlibPixmapMock xlibPixmapMock;
1967+ PixmapReleasePool::FreePixmapFunc mockFreeFunc;
1968+
1969+ PixmapReleasePool releasePool;
1970+};
1971+
1972+TEST_F (DecorPixmapReleasePool, MarkUnusedNoFree)
1973+{
1974+ /* Never free pixmaps on markUnused */
1975+
1976+ EXPECT_CALL (xlibPixmapMock, freePixmap (_)).Times (0);
1977+
1978+ releasePool.markUnused (static_cast <Pixmap> (1));
1979+}
1980+
1981+TEST_F (DecorPixmapReleasePool, NoFreeOnPostDeleteIfNotInList)
1982+{
1983+ EXPECT_CALL (xlibPixmapMock, freePixmap (_)).Times (0);
1984+
1985+ releasePool.destroyUnusedPixmap (static_cast <Pixmap> (1));
1986+}
1987+
1988+TEST_F (DecorPixmapReleasePool, FreeOnPostDeleteIfMarkedUnused)
1989+{
1990+ EXPECT_CALL (xlibPixmapMock, freePixmap (1)).Times (1);
1991+
1992+ releasePool.markUnused (static_cast <Pixmap> (1));
1993+ releasePool.destroyUnusedPixmap (static_cast <Pixmap> (1));
1994+}
1995+
1996+TEST_F (DecorPixmapReleasePool, FreeOnPostDeleteIfMarkedUnusedOnceOnly)
1997+{
1998+ EXPECT_CALL (xlibPixmapMock, freePixmap (1)).Times (1);
1999+
2000+ releasePool.markUnused (static_cast <Pixmap> (1));
2001+ releasePool.destroyUnusedPixmap (static_cast <Pixmap> (1));
2002+ releasePool.destroyUnusedPixmap (static_cast <Pixmap> (1));
2003+}
2004+
2005+TEST_F (DecorPixmapReleasePool, UnusedUniqueness)
2006+{
2007+ EXPECT_CALL (xlibPixmapMock, freePixmap (1)).Times (1);
2008+
2009+ releasePool.markUnused (static_cast <Pixmap> (1));
2010+ releasePool.markUnused (static_cast <Pixmap> (1));
2011+ releasePool.destroyUnusedPixmap (static_cast <Pixmap> (1));
2012+ releasePool.destroyUnusedPixmap (static_cast <Pixmap> (1));
2013+}
2014+
2015+class DecorPendingMessageHandler :
2016+ public ::testing::Test
2017+{
2018+ public:
2019+
2020+ DecorPendingMessageHandler () :
2021+ pendingHandler (boost::bind (&MockFindRequestor::findRequestor,
2022+ &mockRequestorFind,
2023+ _1))
2024+ {
2025+ }
2026+
2027+ MockFindRequestor mockRequestorFind;
2028+ MockDecorPixmapRequestor mockRequestor;
2029+
2030+ cd::PendingHandler pendingHandler;
2031+};
2032+
2033+namespace
2034+{
2035+Window mockWindow = 1;
2036+}
2037+
2038+TEST_F (DecorPendingMessageHandler, NoPendingIfNotFound)
2039+{
2040+ EXPECT_CALL (mockRequestor, handlePending (_)).Times (0);
2041+ EXPECT_CALL (mockRequestorFind, findRequestor (mockWindow)).WillOnce (ReturnNull ());
2042+
2043+ long data = 1;
2044+ pendingHandler.handleMessage (mockWindow, &data);
2045+}
2046+
2047+TEST_F (DecorPendingMessageHandler, PendingIfFound)
2048+{
2049+ long data = 1;
2050+
2051+ EXPECT_CALL (mockRequestor, handlePending (Pointee (data)));
2052+ EXPECT_CALL (mockRequestorFind, findRequestor (mockWindow)).WillOnce (Return (&mockRequestor));
2053+
2054+ pendingHandler.handleMessage (mockWindow, &data);
2055+}
2056+
2057+class DecorUnusedMessageHandler :
2058+ public ::testing::Test
2059+{
2060+ public:
2061+
2062+ DecorUnusedMessageHandler () :
2063+ mockUnusedPixmapQueue (new MockUnusedPixmapQueue ()),
2064+ unusedHandler (boost::bind (&MockFindList::findList,
2065+ &mockListFind,
2066+ _1),
2067+ mockUnusedPixmapQueue,
2068+ boost::bind (&XlibPixmapMock::freePixmap,
2069+ &xlibPixmapMock,
2070+ _1))
2071+ {
2072+ }
2073+
2074+ MockFindList mockListFind;
2075+ MockDecorationListFindMatching mockListFinder;
2076+ MockUnusedPixmapQueue::Ptr mockUnusedPixmapQueue;
2077+ XlibPixmapMock xlibPixmapMock;
2078+
2079+ cd::UnusedHandler unusedHandler;
2080+};
2081+
2082+namespace
2083+{
2084+Pixmap mockPixmap = 2;
2085+}
2086+
2087+TEST_F (DecorUnusedMessageHandler, FreeImmediatelyWindowNotFound)
2088+{
2089+ /* Don't verify calls to mockListFind */
2090+ EXPECT_CALL (mockListFind, findList (_)).Times (AtLeast (0));
2091+
2092+ /* Just free the pixmap immediately if no window was found */
2093+ EXPECT_CALL (xlibPixmapMock, freePixmap (mockPixmap)).Times (1);
2094+
2095+ ON_CALL (mockListFind, findList (mockWindow)).WillByDefault (ReturnNull ());
2096+ unusedHandler.handleMessage (mockWindow, mockPixmap);
2097+}
2098+
2099+TEST_F (DecorUnusedMessageHandler, FreeImmediatelyIfNoDecorationFound)
2100+{
2101+ /* Don't verify calls to mockListFind or mockListFinder */
2102+ EXPECT_CALL (mockListFind, findList (_)).Times (AtLeast (0));
2103+ EXPECT_CALL (mockListFinder, findMatchingDecoration (_)).Times (AtLeast (0));
2104+
2105+ EXPECT_CALL (xlibPixmapMock, freePixmap (mockPixmap)).Times (1);
2106+
2107+ ON_CALL (mockListFind, findList (mockWindow))
2108+ .WillByDefault (Return (&mockListFinder));
2109+ ON_CALL (mockListFinder, findMatchingDecoration (mockPixmap))
2110+ .WillByDefault (Return (DecorationInterface::Ptr ()));
2111+
2112+ unusedHandler.handleMessage (mockWindow, mockPixmap);
2113+}
2114+
2115+TEST_F (DecorUnusedMessageHandler, AddToQueueIfInUse)
2116+{
2117+ /* Don't verify calls to mockListFind or mockListFinder */
2118+ EXPECT_CALL (mockListFind, findList (_)).Times (AtLeast (0));
2119+ EXPECT_CALL (mockListFinder, findMatchingDecoration (_)).Times (AtLeast (0));
2120+
2121+ DecorationInterface::Ptr mockDecoration (new StubDecoration ());
2122+
2123+ /* Do not immediately free the pixmap */
2124+ EXPECT_CALL (xlibPixmapMock, freePixmap (mockPixmap)).Times (0);
2125+ EXPECT_CALL (*mockUnusedPixmapQueue, markUnused (mockPixmap)).Times (1);
2126+
2127+ ON_CALL (mockListFind, findList (mockWindow))
2128+ .WillByDefault (Return (&mockListFinder));
2129+ ON_CALL (mockListFinder, findMatchingDecoration (mockPixmap))
2130+ .WillByDefault (Return (mockDecoration));
2131+
2132+ unusedHandler.handleMessage (mockWindow, mockPixmap);
2133+}
2134+
2135+namespace
2136+{
2137+Atom pendingMsg = 3;
2138+Atom unusedMsg = 4;
2139+}
2140+
2141+class DecorProtocolCommunicator :
2142+ public ::testing::Test
2143+{
2144+ public:
2145+
2146+ DecorProtocolCommunicator () :
2147+ handlePendingFunc (boost::bind (&MockProtocolDispatchFuncs::handlePending,
2148+ &mockProtoDispatch,
2149+ _1,
2150+ _2)),
2151+ handleUnusedFunc (boost::bind (&MockProtocolDispatchFuncs::handleUnused,
2152+ &mockProtoDispatch,
2153+ _1,
2154+ _2)),
2155+ protocolCommunicator (pendingMsg,
2156+ unusedMsg,
2157+ handlePendingFunc,
2158+ handleUnusedFunc)
2159+ {
2160+ }
2161+
2162+ void ClientMessageData (XClientMessageEvent &msg,
2163+ Window window,
2164+ Atom atom,
2165+ long l1,
2166+ long l2,
2167+ long l3,
2168+ long l4)
2169+ {
2170+ msg.window = window;
2171+ msg.message_type = atom;
2172+ msg.data.l[0] = l1;
2173+ msg.data.l[1] = l2;
2174+ msg.data.l[2] = l3;
2175+ msg.data.l[3] = l4;
2176+ }
2177+
2178+ MockProtocolDispatchFuncs mockProtoDispatch;
2179+ cdp::PendingMessage handlePendingFunc;
2180+ cdp::PixmapUnusedMessage handleUnusedFunc;
2181+
2182+ cdp::Communicator protocolCommunicator;
2183+};
2184+
2185+MATCHER_P (MatchArray3, v, "Contains values")
2186+{
2187+ return arg[0] == v[0] &&
2188+ arg[1] == v[1] &&
2189+ arg[2] == v[2];
2190+}
2191+
2192+TEST_F (DecorProtocolCommunicator, TestDispatchToPendingHandler)
2193+{
2194+ long data[3];
2195+
2196+ data[0] = 1;
2197+ data[1] = 2;
2198+ data[2] = 3;
2199+
2200+ XClientMessageEvent ev;
2201+ ClientMessageData (ev,
2202+ mockWindow,
2203+ pendingMsg,
2204+ data[0],
2205+ data[1],
2206+ data[2],
2207+ 0);
2208+
2209+ EXPECT_CALL (mockProtoDispatch, handlePending (mockWindow,
2210+ MatchArray3 (data)))
2211+ .Times (1);
2212+
2213+ protocolCommunicator.handleClientMessage (ev);
2214+}
2215+
2216+TEST_F (DecorProtocolCommunicator, TestDispatchToUnusedHandler)
2217+{
2218+ XClientMessageEvent ev;
2219+ ClientMessageData (ev,
2220+ mockWindow,
2221+ unusedMsg,
2222+ mockPixmap,
2223+ 0,
2224+ 0,
2225+ 0);
2226+
2227+ EXPECT_CALL (mockProtoDispatch, handleUnused (mockWindow,
2228+ mockPixmap))
2229+ .Times (1);
2230+
2231+ protocolCommunicator.handleClientMessage (ev);
2232+}
2233
2234=== modified file 'tests/system/xorg-gtest/tests/CMakeLists.txt'
2235--- tests/system/xorg-gtest/tests/CMakeLists.txt 2013-02-19 12:00:19 +0000
2236+++ tests/system/xorg-gtest/tests/CMakeLists.txt 2013-02-20 07:34:20 +0000
2237@@ -52,6 +52,6 @@
2238 target_link_libraries (compiz_xorg_gtest_test_shape_handling
2239 ${COMPIZ_XORG_GTEST_LIBRARIES})
2240
2241- compiz_discover_tests (compiz_xorg_gtest_test_shape_handling)
2242+ compiz_discover_tests (compiz_xorg_gtest_test_shape_handling WITH_XORG_GTEST)
2243
2244 endif (BUILD_XORG_GTEST AND X11_XI_FOUND)

Subscribers

People subscribed via source and target branches