Merge lp:~compiz-team/compiz/compiz.performance_1027211.2 into lp:compiz/0.9.9

Proposed by Sam Spilsbury on 2012-12-07
Status: Superseded
Proposed branch: lp:~compiz-team/compiz/compiz.performance_1027211.2
Merge into: lp:compiz/0.9.9
Diff against target: 2047 lines (+1631/-70)
20 files modified
include/core/CMakeLists.txt (+1/-0)
include/core/configurerequestbuffer.h (+73/-0)
include/core/window.h (+26/-7)
plugins/composite/src/window.cpp (+1/-5)
plugins/move/move.xml.in (+1/-1)
plugins/move/src/move.cpp (+12/-5)
plugins/move/src/move.h (+2/-0)
plugins/opengl/src/paint.cpp (+3/-0)
plugins/opengl/src/privates.h (+3/-0)
plugins/opengl/src/window.cpp (+2/-1)
src/CMakeLists.txt (+7/-0)
src/asyncserverwindow.h (+52/-0)
src/configurerequestbuffer-impl.h (+145/-0)
src/configurerequestbuffer.cpp (+354/-0)
src/event.cpp (+1/-1)
src/privatewindow.h (+45/-1)
src/syncserverwindow.h (+49/-0)
src/tests/CMakeLists.txt (+11/-0)
src/tests/test_configurerequestbuffer.cpp (+647/-0)
src/window.cpp (+196/-49)
To merge this branch: bzr merge lp:~compiz-team/compiz/compiz.performance_1027211.2
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing on 2012-12-07
Compiz Maintainers 2012-12-07 Pending
Review via email: mp+138682@code.launchpad.net

This proposal has been superseded by a proposal from 2012-12-07.

Commit Message

Allow plugins to throttle delivery of ConfigureWindow requests within reason (LP: #1027211)

Description of the Change

Allow plugins to throttle delivery of ConfigureWindow requests within reason (LP: #1027211)

(LP: #1027211) seems to be caused by vsync in the nvidia driver and posting lots of ConfigureWindow requests to the server. The driver really chokes on these for some reason. As a result, two things were happening:

1. The driver slows down quite significantly
2. We get more time to post more ConfigureWindow requests to the driver, which just slows it down even more until it grinds to a halt.

This branch does three things:
1. Introduces infrastructure for plugins to hold a "lock" on delivering ConfigureWindow requests until they choose to release it later (eg, on paint, or on ungrab), while still allowing core to override the plugin's decisions in cases where we actually need to post a ConfigureWindow request to the server in order to continue (eg, some other request is dependent on it). That code was TDD'ed into existence and has test coverage.
2. Optimizes reconfigureXWindow to only configure the frame window if the only thing that happened was that we moved the window. This means that we only buffer up one ConfigureWindow instead of three per call to reconfigureXWindow
3. Implements ConfigureRequestBuffer in both opengl and move. The default implementation in "opengl" is the "safe" version and releases its lock every time the window paints. That means that dragging around opengl rendered windows goes from a complete halt to a steady 12fps. In the move plugin, I've revived "lazy positioning" - off by default as it might be more unsafe, but this prevents all ConfigureWindow requests from being posted until the window is ungrabbed. That goes brings us from 12fps to 60fps.

One question that might arise here is whether or not this branch is fundamentally unsafe because we allow the server to get "out of sync" with us. That isn't as much of a problem these days as it used to be. Nowadays we never track the incoming positions from the server to give us a representation of our own internal state, instead that is represented by what we meant to post to the server. So the internal state can never get mucked up. In areas where we do actually need to have our internal state represent what was really last sent to the server, I've structured the code such that in order to do those things, you have to release the queued up ConfigureWindow requests first.

Again, throw this at the wall and see if it introduces any bad regressions. I haven't see any so far.

To post a comment you must log in.
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
3535. By Sam Spilsbury on 2012-12-07

Put lock in the list before freezing the buffer to avoid an assertion failure

3536. By Sam Spilsbury on 2012-12-07

Fix assertion failures

Unmerged revisions

3536. By Sam Spilsbury on 2012-12-07

Fix assertion failures

3535. By Sam Spilsbury on 2012-12-07

Put lock in the list before freezing the buffer to avoid an assertion failure

3534. By Sam Spilsbury on 2012-12-07

Revert an accidental change due to f'n'r

3533. By Sam Spilsbury on 2012-12-07

Update client code to take advantage of ConfigureBuffer wrapping
queryShapeRectangles

3532. By Sam Spilsbury on 2012-12-07

Fix broken assert

3531. By Sam Spilsbury on 2012-12-07

Merge lp:compiz

3530. By Sam Spilsbury on 2012-12-07

Bring back lazy positioning, make it off by default.

This basically "fixes" the various problems with nvidia being slow at
handling ConfigureWindow requests at the same time as doing synchronized
compositing, however it could come at the cost of some weird bugs. Keep
it off for now, and lets turn it on if there aren't any in testing

3529. By Sam Spilsbury on 2012-12-07

Handle XShapeQueryRectangles too and work around races with that

3528. By Sam Spilsbury on 2012-12-07

Remove const promise, be a little smarter about calling XConfigureWindow
the other times

3527. By Sam Spilsbury on 2012-12-07

Refactor the test code into test fixtures, remove lots of duplicated code

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/core/CMakeLists.txt'
2--- include/core/CMakeLists.txt 2012-10-17 06:25:59 +0000
3+++ include/core/CMakeLists.txt 2012-12-07 17:16:21 +0000
4@@ -1,6 +1,7 @@
5 set (_headers
6 action.h
7 atoms.h
8+ configurerequestbuffer.h
9 core.h
10 countedlist.h
11 global.h
12
13=== added file 'include/core/configurerequestbuffer.h'
14--- include/core/configurerequestbuffer.h 1970-01-01 00:00:00 +0000
15+++ include/core/configurerequestbuffer.h 2012-12-07 17:16:21 +0000
16@@ -0,0 +1,73 @@
17+/*
18+ * Copyright © 2012 Sam Spilsbury
19+ *
20+ * Permission to use, copy, modify, distribute, and sell this software
21+ * and its documentation for any purpose is hereby granted without
22+ * fee, provided that the above copyright notice appear in all copies
23+ * and that both that copyright notice and this permission notice
24+ * appear in supporting documentation, and that the name of
25+ * Canonical Ltd. not be used in advertising or publicity pertaining to
26+ * distribution of the software without specific, written prior permission.
27+ * Canonical Ltd. makes no representations about the suitability of this
28+ * software for any purpose. It is provided "as is" without express or
29+ * implied warranty.
30+ *
31+ * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
32+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
33+ * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
34+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
35+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
36+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
37+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
38+ *
39+ * Authored by: Sam Spilsbury <smspillaz@gmail.com>
40+ */
41+#ifndef _COMPIZ_CONFIGURE_REQUEST_BUFFER_H
42+#define _COMPIZ_CONFIGURE_REQUEST_BUFFER_H
43+
44+#include <boost/shared_ptr.hpp>
45+#include <X11/Xlib.h>
46+#include <syncserverwindow.h>
47+
48+namespace compiz
49+{
50+namespace window
51+{
52+namespace configure_buffers
53+{
54+class Releasable
55+{
56+ public:
57+
58+ typedef boost::shared_ptr <Releasable> Ptr;
59+
60+ virtual void release () = 0;
61+};
62+
63+class Buffer :
64+ public SyncServerWindow
65+{
66+ public:
67+
68+ typedef boost::shared_ptr <Buffer> Ptr;
69+
70+ virtual ~Buffer () {}
71+
72+ virtual void pushClientRequest (const XWindowChanges &xwc, unsigned int mask) = 0;
73+ virtual void pushWrapperRequest (const XWindowChanges &xwc, unsigned int mask) = 0;
74+ virtual void pushFrameRequest (const XWindowChanges &xwc, unsigned int mask) = 0;
75+
76+ virtual void pushSyntheticConfigureNotify () = 0;
77+
78+ virtual Releasable::Ptr obtainLock () = 0;
79+
80+ /* This API will all configure requests to be
81+ * released. It should only be used in situations
82+ * where you have a server grab and need
83+ * to have complete sync with the server */
84+ virtual void forceRelease () = 0;
85+};
86+}
87+}
88+}
89+#endif
90
91=== modified file 'include/core/window.h'
92--- include/core/window.h 2012-12-07 09:28:03 +0000
93+++ include/core/window.h 2012-12-07 17:16:21 +0000
94@@ -53,13 +53,26 @@
95 class PrivateWindow;
96 struct CompStartupSequence;
97
98-namespace compiz { namespace private_screen {
99- class Ping;
100- class GrabManager;
101- class OutputDevices;
102- class WindowManager;
103- class StartupSequence;
104-}}
105+namespace compiz
106+{
107+namespace window
108+{
109+namespace configure_buffers
110+{
111+class Releasable;
112+typedef boost::shared_ptr <Releasable> ReleasablePtr;
113+}
114+}
115+
116+namespace private_screen
117+{
118+class Ping;
119+class GrabManager;
120+class OutputDevices;
121+class WindowManager;
122+class StartupSequence;
123+}
124+}
125
126 #define ROOTPARENT(x) (((x)->frame ()) ? (x)->frame () : (x)->id ())
127
128@@ -524,6 +537,12 @@
129 bool updateStruts ();
130 const CompStruts *struts () const;
131
132+ bool queryAttributes (XWindowAttributes &);
133+ bool queryFrameAttributes (XWindowAttributes &);
134+
135+ compiz::window::configure_buffers::ReleasablePtr
136+ obtainLockOnConfigureRequests ();
137+
138 WRAPABLE_HND (0, WindowInterface, void, getOutputExtents,
139 CompWindowExtents&);
140 WRAPABLE_HND (1, WindowInterface, void, getAllowedActions,
141
142=== modified file 'plugins/composite/src/window.cpp'
143--- plugins/composite/src/window.cpp 2012-11-18 00:16:47 +0000
144+++ plugins/composite/src/window.cpp 2012-12-07 17:16:21 +0000
145@@ -181,11 +181,7 @@
146 bool
147 PrivateCompositeWindow::getAttributes (XWindowAttributes &attr)
148 {
149- if (XGetWindowAttributes (screen->dpy (),
150- ROOTPARENT (window), &attr))
151- return true;
152-
153- return false;
154+ return window->queryFrameAttributes (attr);
155 }
156
157 bool
158
159=== modified file 'plugins/move/move.xml.in'
160--- plugins/move/move.xml.in 2012-10-15 10:31:51 +0000
161+++ plugins/move/move.xml.in 2012-12-07 17:16:21 +0000
162@@ -42,7 +42,7 @@
163 <option name="lazy_positioning" type="bool">
164 <_short>Lazy Positioning</_short>
165 <_long>Do not update the server-side position of windows until finished moving</_long>
166- <default>true</default>
167+ <default>false</default>
168 </option>
169 </options>
170 </plugin>
171
172=== modified file 'plugins/move/src/move.cpp'
173--- plugins/move/src/move.cpp 2012-12-05 09:38:59 +0000
174+++ plugins/move/src/move.cpp 2012-12-07 17:16:21 +0000
175@@ -158,6 +158,14 @@
176 if (mw->gWindow)
177 mw->gWindow->glPaintSetEnabled (mw, true);
178 }
179+
180+ if (ms->optionGetLazyPositioning ())
181+ {
182+ MOVE_WINDOW (w);
183+
184+ if (mw->gWindow)
185+ mw->releasable = w->obtainLockOnConfigureRequests ();
186+ }
187 }
188 }
189
190@@ -173,6 +181,8 @@
191
192 if (ms->w)
193 {
194+ MOVE_WINDOW (ms->w);
195+
196 if (state & CompAction::StateCancel)
197 ms->w->move (ms->savedX - ms->w->geometry ().x (),
198 ms->savedY - ms->w->geometry ().y (), false);
199@@ -194,14 +204,14 @@
200
201 if (ms->moveOpacity != OPAQUE)
202 {
203- MOVE_WINDOW (ms->w);
204-
205 if (mw->cWindow)
206 mw->cWindow->addDamage ();
207 if (mw->gWindow)
208 mw->gWindow->glPaintSetEnabled (mw, false);
209 }
210
211+ mw->releasable.reset ();
212+
213 ms->w = 0;
214 ms->releaseButton = 0;
215 }
216@@ -489,9 +499,6 @@
217 w->move (wX + dx - w->geometry ().x (),
218 wY + dy - w->geometry ().y (), false);
219
220- if (!ms->optionGetLazyPositioning ())
221- w->syncPosition ();
222-
223 ms->x -= dx;
224 ms->y -= dy;
225 }
226
227=== modified file 'plugins/move/src/move.h'
228--- plugins/move/src/move.h 2012-09-07 22:48:26 +0000
229+++ plugins/move/src/move.h 2012-12-07 17:16:21 +0000
230@@ -27,6 +27,7 @@
231
232 #include <core/screen.h>
233 #include <core/pluginclasshandler.h>
234+#include <core/configurerequestbuffer.h>
235
236 #include <composite/composite.h>
237 #include <opengl/opengl.h>
238@@ -117,6 +118,7 @@
239 CompWindow *window;
240 GLWindow *gWindow;
241 CompositeWindow *cWindow;
242+ compiz::window::configure_buffers::Releasable::Ptr releasable;
243 };
244
245 #define MOVE_SCREEN(s) \
246
247=== modified file 'plugins/opengl/src/paint.cpp'
248--- plugins/opengl/src/paint.cpp 2012-12-04 08:47:32 +0000
249+++ plugins/opengl/src/paint.cpp 2012-12-07 17:16:21 +0000
250@@ -1283,6 +1283,9 @@
251 !priv->cWindow->damaged ())
252 return true;
253
254+ /* Release any queued ConfigureWindow requests now */
255+ priv->configureLock->release ();
256+
257 if (textures ().empty () && !bind ())
258 return false;
259
260
261=== modified file 'plugins/opengl/src/privates.h'
262--- plugins/opengl/src/privates.h 2012-11-08 09:29:42 +0000
263+++ plugins/opengl/src/privates.h 2012-12-07 17:16:21 +0000
264@@ -33,6 +33,7 @@
265 #include <composite/composite.h>
266 #include <opengl/opengl.h>
267 #include <core/atoms.h>
268+#include <core/configurerequestbuffer.h>
269
270 #ifdef USE_GLES
271 #include <opengl/framebufferobject.h>
272@@ -276,6 +277,8 @@
273 GLVertexBuffer::AutoProgram *autoProgram;
274
275 std::list<GLIcon> icons;
276+
277+ compiz::window::configure_buffers::Releasable::Ptr configureLock;
278 };
279
280 #endif
281
282=== modified file 'plugins/opengl/src/window.cpp'
283--- plugins/opengl/src/window.cpp 2012-10-16 04:49:19 +0000
284+++ plugins/opengl/src/window.cpp 2012-12-07 17:16:21 +0000
285@@ -86,7 +86,8 @@
286 bindFailed (false),
287 vertexBuffer (new GLVertexBuffer ()),
288 autoProgram(new GLWindowAutoProgram(this)),
289- icons ()
290+ icons (),
291+ configureLock (w->obtainLockOnConfigureRequests ())
292 {
293 paint.xScale = 1.0f;
294 paint.yScale = 1.0f;
295
296=== modified file 'src/CMakeLists.txt'
297--- src/CMakeLists.txt 2012-11-26 07:13:04 +0000
298+++ src/CMakeLists.txt 2012-12-07 17:16:21 +0000
299@@ -160,6 +160,12 @@
300 compiz_window_geometry
301 )
302
303+add_library (compiz_configurerequestbuffer STATIC
304+ configurerequestbuffer.cpp)
305+
306+target_link_libraries (compiz_configurerequestbuffer
307+ compiz_window_geometry)
308+
309 # workaround for build race
310 add_dependencies (compiz core-xml-file)
311
312@@ -192,6 +198,7 @@
313 compiz_servergrab
314 compiz_output
315 compiz_outputdevices
316+ compiz_configurerequestbuffer
317 -Wl,-no-whole-archive
318 # ${CORE_MOD_LIBRARIES}
319 )
320
321=== added file 'src/asyncserverwindow.h'
322--- src/asyncserverwindow.h 1970-01-01 00:00:00 +0000
323+++ src/asyncserverwindow.h 2012-12-07 17:16:21 +0000
324@@ -0,0 +1,52 @@
325+/*
326+ * Copyright © 2012 Sam Spilsbury
327+ *
328+ * Permission to use, copy, modify, distribute, and sell this software
329+ * and its documentation for any purpose is hereby granted without
330+ * fee, provided that the above copyright notice appear in all copies
331+ * and that both that copyright notice and this permission notice
332+ * appear in supporting documentation, and that the name of
333+ * Canonical Ltd. not be used in advertising or publicity pertaining to
334+ * distribution of the software without specific, written prior permission.
335+ * Canonical Ltd. makes no representations about the suitability of this
336+ * software for any purpose. It is provided "as is" without express or
337+ * implied warranty.
338+ *
339+ * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
340+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
341+ * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
342+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
343+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
344+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
345+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
346+ *
347+ * Authored by: Sam Spilsbury <smspillaz@gmail.com>
348+ */
349+#ifndef _COMPIZ_ASYNC_SERVER_WINDOW_H
350+#define _COMPIZ_ASYNC_SERVER_WINDOW_H
351+
352+#include <X11/Xlib.h>
353+
354+namespace compiz
355+{
356+namespace window
357+{
358+class AsyncServerWindow
359+{
360+ public:
361+
362+ virtual ~AsyncServerWindow () {};
363+
364+ virtual int requestConfigureOnClient (const XWindowChanges &xwc,
365+ unsigned int valueMask) = 0;
366+ virtual int requestConfigureOnWrapper (const XWindowChanges &xwc,
367+ unsigned int valueMask) = 0;
368+ virtual int requestConfigureOnFrame (const XWindowChanges &xwc,
369+ unsigned int valueMask) = 0;
370+ virtual void sendSyntheticConfigureNotify () = 0;
371+ virtual bool hasCustomShape () const = 0;
372+};
373+}
374+}
375+
376+#endif
377
378=== added file 'src/configurerequestbuffer-impl.h'
379--- src/configurerequestbuffer-impl.h 1970-01-01 00:00:00 +0000
380+++ src/configurerequestbuffer-impl.h 2012-12-07 17:16:21 +0000
381@@ -0,0 +1,145 @@
382+/*
383+ * Copyright © 2012 Sam Spilsbury
384+ *
385+ * Permission to use, copy, modify, distribute, and sell this software
386+ * and its documentation for any purpose is hereby granted without
387+ * fee, provided that the above copyright notice appear in all copies
388+ * and that both that copyright notice and this permission notice
389+ * appear in supporting documentation, and that the name of
390+ * Canonical Ltd. not be used in advertising or publicity pertaining to
391+ * distribution of the software without specific, written prior permission.
392+ * Canonical Ltd. makes no representations about the suitability of this
393+ * software for any purpose. It is provided "as is" without express or
394+ * implied warranty.
395+ *
396+ * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
397+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
398+ * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
399+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
400+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
401+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
402+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
403+ *
404+ * Authored by: Sam Spilsbury <smspillaz@gmail.com>
405+ */
406+#ifndef _COMPIZ_GEOMETRY_UPDATE_QUEUE_H
407+#define _COMPIZ_GEOMETRY_UPDATE_QUEUE_H
408+
409+#include <memory>
410+#include <vector>
411+#include <boost/weak_ptr.hpp>
412+#include <boost/shared_ptr.hpp>
413+#include <boost/function.hpp>
414+#include <X11/Xlib.h>
415+
416+#include <core/configurerequestbuffer.h>
417+
418+namespace compiz
419+{
420+namespace window
421+{
422+class AsyncServerWindow;
423+namespace configure_buffers
424+{
425+
426+class Lockable
427+{
428+ public:
429+
430+ typedef boost::shared_ptr <Lockable> Ptr;
431+ typedef boost::weak_ptr <Lockable> Weak;
432+
433+ virtual ~Lockable () {}
434+
435+ virtual void lock () = 0;
436+};
437+
438+class BufferLock :
439+ public Lockable,
440+ public Releasable
441+{
442+ public:
443+ typedef boost::shared_ptr <BufferLock> Ptr;
444+
445+ virtual ~BufferLock () {}
446+};
447+
448+class CountedFreeze
449+{
450+ public:
451+
452+ virtual ~CountedFreeze () {}
453+
454+ virtual void freeze () = 0;
455+ virtual void release () = 0;
456+
457+ virtual void untrackLock (compiz::window::configure_buffers::BufferLock *lock) = 0;
458+};
459+
460+class ConfigureRequestBuffer :
461+ public CountedFreeze,
462+ public Buffer
463+{
464+ public:
465+
466+ typedef boost::function <BufferLock::Ptr (CountedFreeze *)> LockFactory;
467+
468+ void freeze ();
469+ void release ();
470+
471+ void untrackLock (compiz::window::configure_buffers::BufferLock *lock);
472+
473+ void pushClientRequest (const XWindowChanges &xwc, unsigned int mask);
474+ void pushWrapperRequest (const XWindowChanges &xwc, unsigned int mask);
475+ void pushFrameRequest (const XWindowChanges &xwc, unsigned int mask);
476+ void pushSyntheticConfigureNotify ();
477+ compiz::window::configure_buffers::Releasable::Ptr obtainLock ();
478+
479+ /* Implement getAttributes and require that
480+ * the queue is released before calling through
481+ * to the SyncServerWindow */
482+ bool queryAttributes (XWindowAttributes &attrib);
483+ bool queryFrameAttributes (XWindowAttributes &attrib);
484+ XRectangle * queryShapeRectangles (int kind,
485+ int *count,
486+ int *ordering);
487+
488+ void forceRelease ();
489+
490+ static compiz::window::configure_buffers::Buffer::Ptr
491+ Create (AsyncServerWindow *asyncServerWindow,
492+ SyncServerWindow *syncServerWindow,
493+ const LockFactory &factory);
494+
495+ private:
496+
497+ ConfigureRequestBuffer (AsyncServerWindow *asyncServerWindow,
498+ SyncServerWindow *syncServerWindow,
499+ const LockFactory &factory);
500+
501+ class Private;
502+ std::auto_ptr <Private> priv;
503+};
504+
505+class ConfigureBufferLock :
506+ public compiz::window::configure_buffers::BufferLock
507+{
508+ public:
509+
510+ typedef boost::shared_ptr <ConfigureBufferLock> Ptr;
511+
512+ ConfigureBufferLock (CountedFreeze *);
513+ ~ConfigureBufferLock ();
514+
515+ void lock ();
516+ void release ();
517+
518+ private:
519+
520+ class Private;
521+ std::auto_ptr <Private> priv;
522+};
523+}
524+}
525+}
526+#endif
527
528=== added file 'src/configurerequestbuffer.cpp'
529--- src/configurerequestbuffer.cpp 1970-01-01 00:00:00 +0000
530+++ src/configurerequestbuffer.cpp 2012-12-07 17:16:21 +0000
531@@ -0,0 +1,354 @@
532+/*
533+ * Copyright © 2012 Sam Spilsbury
534+ *
535+ * Permission to use, copy, modify, distribute, and sell this software
536+ * and its documentation for any purpose is hereby granted without
537+ * fee, provided that the above copyright notice appear in all copies
538+ * and that both that copyright notice and this permission notice
539+ * appear in supporting documentation, and that the name of
540+ * Canonical Ltd. not be used in advertising or publicity pertaining to
541+ * distribution of the software without specific, written prior permission.
542+ * Canonical Ltd. makes no representations about the suitability of this
543+ * software for any purpose. It is provided "as is" without express or
544+ * implied warranty.
545+ *
546+ * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
547+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
548+ * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
549+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
550+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
551+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
552+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
553+ *
554+ * Authored by: Sam Spilsbury <smspillaz@gmail.com>
555+ */
556+#include <cassert>
557+#include <boost/foreach.hpp>
558+#include <boost/weak_ptr.hpp>
559+#include <boost/bind.hpp>
560+#include "asyncserverwindow.h"
561+#include "configurerequestbuffer-impl.h"
562+
563+#ifndef foreach
564+#define foreach BOOST_FOREACH
565+#endif
566+
567+namespace crb = compiz::window::configure_buffers;
568+namespace cw = compiz::window;
569+
570+class crb::ConfigureRequestBuffer::Private
571+{
572+ public:
573+
574+ typedef crb::Lockable::Weak LockObserver;
575+
576+ Private (cw::AsyncServerWindow *asyncServerWindow,
577+ cw::SyncServerWindow *syncServerWindow,
578+ const crb::ConfigureRequestBuffer::LockFactory &lockFactory) :
579+ clientChangeMask (0),
580+ wrapperChangeMask (0),
581+ frameChangeMask (0),
582+ sendSyntheticConfigure (false),
583+ lockCount (0),
584+ asyncServerWindow (asyncServerWindow),
585+ syncServerWindow (syncServerWindow),
586+ lockFactory (lockFactory)
587+ {
588+ }
589+
590+ void dispatchConfigure (bool force = false);
591+
592+ XWindowChanges clientChanges;
593+ unsigned int clientChangeMask;
594+
595+ XWindowChanges wrapperChanges;
596+ unsigned int wrapperChangeMask;
597+
598+ XWindowChanges frameChanges;
599+ unsigned int frameChangeMask;
600+
601+ bool sendSyntheticConfigure;
602+
603+ unsigned int lockCount;
604+
605+ cw::AsyncServerWindow *asyncServerWindow;
606+ cw::SyncServerWindow *syncServerWindow;
607+
608+ crb::ConfigureRequestBuffer::LockFactory lockFactory;
609+ std::vector <LockObserver> locks;
610+};
611+
612+void
613+crb::ConfigureRequestBuffer::Private::dispatchConfigure (bool force)
614+{
615+ const unsigned int allEventMasks = 0x7f;
616+ bool immediate = frameChangeMask & (CWStackMode | CWSibling);
617+ immediate |= (frameChangeMask & (CWWidth | CWHeight)) &&
618+ asyncServerWindow->hasCustomShape ();
619+ immediate |= force;
620+
621+ bool clientDispatch = (clientChangeMask & allEventMasks);
622+ bool wrapperDispatch = (wrapperChangeMask & allEventMasks);
623+ bool frameDispatch = (frameChangeMask & allEventMasks);
624+
625+ bool dispatch = !lockCount && (clientDispatch ||
626+ wrapperDispatch ||
627+ frameDispatch ||
628+ sendSyntheticConfigure);
629+
630+ if (dispatch || immediate)
631+ {
632+ if (frameDispatch)
633+ {
634+ asyncServerWindow->requestConfigureOnFrame (frameChanges,
635+ frameChangeMask);
636+ frameChangeMask = 0;
637+ }
638+
639+ if (wrapperDispatch)
640+ {
641+ asyncServerWindow->requestConfigureOnWrapper (wrapperChanges,
642+ wrapperChangeMask);
643+ wrapperChangeMask = 0;
644+ }
645+
646+ if (clientDispatch)
647+ {
648+ asyncServerWindow->requestConfigureOnClient (clientChanges,
649+ clientChangeMask);
650+ clientChangeMask = 0;
651+ }
652+
653+ if (sendSyntheticConfigure)
654+ {
655+ asyncServerWindow->sendSyntheticConfigureNotify ();
656+ sendSyntheticConfigure = false;
657+ }
658+
659+ foreach (const LockObserver &lock, locks)
660+ {
661+ crb::Lockable::Ptr strongLock (lock.lock ());
662+
663+ /* We might be in a lock's destructor so check
664+ * if this can really be re-locked, if not, its
665+ * no big deal as the lock is going away anyways
666+ */
667+ if (strongLock)
668+ strongLock->lock ();
669+ }
670+ }
671+}
672+
673+void
674+crb::ConfigureRequestBuffer::freeze ()
675+{
676+ priv->lockCount++;
677+
678+ assert (priv->lockCount <= priv->locks.size ());
679+}
680+
681+void
682+crb::ConfigureRequestBuffer::release ()
683+{
684+ assert (priv->lockCount);
685+
686+ priv->lockCount--;
687+
688+ priv->dispatchConfigure ();
689+}
690+
691+namespace
692+{
693+void applyChangeToXWC (const XWindowChanges &from,
694+ XWindowChanges &to,
695+ unsigned int mask)
696+{
697+ if (mask & CWX)
698+ to.x = from.x;
699+
700+ if (mask & CWY)
701+ to.y = from.y;
702+
703+ if (mask & CWWidth)
704+ to.width = from.width;
705+
706+ if (mask & CWHeight)
707+ to.height = from.height;
708+
709+ if (mask & CWBorderWidth)
710+ to.border_width = from.border_width;
711+
712+ if (mask & CWSibling)
713+ to.sibling = from.sibling;
714+
715+ if (mask & CWStackMode)
716+ to.stack_mode = from.stack_mode;
717+}
718+}
719+
720+void
721+crb::ConfigureRequestBuffer::pushClientRequest (const XWindowChanges &xwc,
722+ unsigned int mask)
723+{
724+ applyChangeToXWC (xwc, priv->clientChanges, mask);
725+ priv->clientChangeMask |= mask;
726+
727+ priv->dispatchConfigure ();
728+}
729+
730+void
731+crb::ConfigureRequestBuffer::pushWrapperRequest (const XWindowChanges &xwc,
732+ unsigned int mask)
733+{
734+ applyChangeToXWC (xwc, priv->wrapperChanges, mask);
735+ priv->wrapperChangeMask |= mask;
736+
737+ priv->dispatchConfigure ();
738+}
739+
740+void
741+crb::ConfigureRequestBuffer::pushFrameRequest (const XWindowChanges &xwc,
742+ unsigned int mask)
743+{
744+ applyChangeToXWC (xwc, priv->frameChanges, mask);
745+ priv->frameChangeMask |= mask;
746+
747+ priv->dispatchConfigure ();
748+}
749+
750+void
751+crb::ConfigureRequestBuffer::pushSyntheticConfigureNotify ()
752+{
753+ priv->sendSyntheticConfigure = true;
754+
755+ priv->dispatchConfigure ();
756+}
757+
758+crb::Releasable::Ptr
759+crb::ConfigureRequestBuffer::obtainLock ()
760+{
761+ crb::BufferLock::Ptr lock (priv->lockFactory (this));
762+
763+ priv->locks.push_back (crb::Lockable::Weak (lock));
764+ lock->lock ();
765+
766+ return lock;
767+}
768+
769+namespace
770+{
771+bool isLock (const crb::Lockable::Weak &lockable,
772+ crb::BufferLock *lock)
773+{
774+ crb::Lockable::Ptr strongLockable (lockable.lock ());
775+
776+ /* Asserting that the lock did not go away without telling
777+ * us first */
778+ assert (strongLockable.get ());
779+
780+ if (strongLockable.get () == lock)
781+ return true;
782+
783+ return false;
784+}
785+}
786+
787+void
788+crb::ConfigureRequestBuffer::untrackLock (crb::BufferLock *lock)
789+{
790+ std::remove_if (priv->locks.begin (),
791+ priv->locks.end (),
792+ boost::bind (isLock, _1, lock));
793+}
794+
795+bool crb::ConfigureRequestBuffer::queryAttributes (XWindowAttributes &attrib)
796+{
797+ priv->dispatchConfigure (true);
798+ return priv->syncServerWindow->queryAttributes (attrib);
799+}
800+
801+bool crb::ConfigureRequestBuffer::queryFrameAttributes (XWindowAttributes &attrib)
802+{
803+ priv->dispatchConfigure (true);
804+ return priv->syncServerWindow->queryFrameAttributes (attrib);
805+}
806+
807+/* This is more or less of a stop-gap for the fact that
808+ * when resizing window we re-query the window shape
809+ * and apply that to the frame. That's a separate unit of
810+ * work and should be dealt with separately. For now, force
811+ * a release of the queue whenever we do that so that
812+ * XShapeGetRectangles doesn't return an unexpected value
813+ */
814+XRectangle *
815+crb::ConfigureRequestBuffer::queryShapeRectangles (int kind,
816+ int *count,
817+ int *ordering)
818+{
819+ priv->dispatchConfigure (true);
820+ return priv->syncServerWindow->queryShapeRectangles (kind, count, ordering);
821+}
822+
823+void crb::ConfigureRequestBuffer::forceRelease ()
824+{
825+ priv->dispatchConfigure (true);
826+}
827+
828+crb::ConfigureRequestBuffer::ConfigureRequestBuffer (AsyncServerWindow *asyncServerWindow,
829+ SyncServerWindow *syncServerWindow,
830+ const crb::ConfigureRequestBuffer::LockFactory &factory) :
831+ priv (new crb::ConfigureRequestBuffer::Private (asyncServerWindow, syncServerWindow, factory))
832+{
833+}
834+
835+compiz::window::configure_buffers::Buffer::Ptr
836+crb::ConfigureRequestBuffer::Create (AsyncServerWindow *asyncServerWindow,
837+ SyncServerWindow *syncServerWindow,
838+ const LockFactory &factory)
839+{
840+ return crb::Buffer::Ptr (new crb::ConfigureRequestBuffer (asyncServerWindow,
841+ syncServerWindow,
842+ factory));
843+}
844+
845+class crb::ConfigureBufferLock::Private
846+{
847+ public:
848+
849+ Private (crb::CountedFreeze *freezable) :
850+ freezable (freezable),
851+ armed (false)
852+ {
853+ }
854+
855+ crb::CountedFreeze *freezable;
856+ bool armed;
857+};
858+
859+crb::ConfigureBufferLock::ConfigureBufferLock (crb::CountedFreeze *freezable) :
860+ priv (new crb::ConfigureBufferLock::Private (freezable))
861+{
862+}
863+
864+crb::ConfigureBufferLock::~ConfigureBufferLock ()
865+{
866+ release ();
867+}
868+
869+void
870+crb::ConfigureBufferLock::lock ()
871+{
872+ if (!priv->armed)
873+ priv->freezable->freeze ();
874+
875+ priv->armed = true;
876+}
877+
878+void
879+crb::ConfigureBufferLock::release ()
880+{
881+ if (priv->armed)
882+ priv->freezable->release ();
883+
884+ priv->armed = false;
885+}
886
887=== modified file 'src/event.cpp'
888--- src/event.cpp 2012-12-04 15:11:42 +0000
889+++ src/event.cpp 2012-12-07 17:16:21 +0000
890@@ -1928,7 +1928,7 @@
891
892 /* We should check the override_redirect flag here, because the
893 client might have changed it while being unmapped. */
894- if (XGetWindowAttributes (privateScreen.dpy, w->id (), &attr))
895+ if (w->queryAttributes (attr))
896 w->priv->setOverrideRedirect (attr.override_redirect != 0);
897
898 if (w->state () & CompWindowStateHiddenMask)
899
900=== modified file 'src/privatewindow.h'
901--- src/privatewindow.h 2012-11-28 18:14:56 +0000
902+++ src/privatewindow.h 2012-12-07 17:16:21 +0000
903@@ -35,6 +35,11 @@
904
905 #include <boost/shared_ptr.hpp>
906
907+#include <core/configurerequestbuffer.h>
908+
909+#include "syncserverwindow.h"
910+#include "asyncserverwindow.h"
911+
912 #define XWINDOWCHANGES_INIT {0, 0, 0, 0, 0, None, 0}
913
914 namespace compiz {namespace X11
915@@ -107,12 +112,47 @@
916
917 typedef CompWindowExtents CompFullscreenMonitorSet;
918
919-class PrivateWindow {
920+class X11SyncServerWindow :
921+ public compiz::window::SyncServerWindow
922+{
923+ public:
924+
925+ X11SyncServerWindow (Display *dpy,
926+ const Window *w,
927+ const Window *frame);
928+
929+ bool queryAttributes (XWindowAttributes &attrib);
930+ bool queryFrameAttributes (XWindowAttributes &attrib);
931+ XRectangle * queryShapeRectangles(int kind, int *count, int *ordering);
932+
933+ private:
934+
935+ Display *mDpy;
936+ const Window *mWindow;
937+ const Window *mFrame;
938+};
939+
940+class PrivateWindow :
941+ public compiz::window::SyncServerWindow,
942+ public compiz::window::AsyncServerWindow
943+{
944
945 public:
946 PrivateWindow ();
947 ~PrivateWindow ();
948
949+ bool queryAttributes (XWindowAttributes &attrib);
950+ bool queryFrameAttributes (XWindowAttributes &attrib);
951+ XRectangle * queryShapeRectangles (int kind, int *count, int *ordering);
952+ int requestConfigureOnClient (const XWindowChanges &xwc,
953+ unsigned int valueMask);
954+ int requestConfigureOnWrapper (const XWindowChanges &xwc,
955+ unsigned int valueMask);
956+ int requestConfigureOnFrame (const XWindowChanges &xwc,
957+ unsigned int valueMask);
958+ void sendSyntheticConfigureNotify ();
959+ bool hasCustomShape () const;
960+
961 void recalcNormalHints ();
962
963 void updateFrameWindow ();
964@@ -373,6 +413,7 @@
965
966 CompWindowExtents input;
967 CompWindowExtents serverInput;
968+ CompWindowExtents lastServerInput;
969 CompWindowExtents border;
970 CompWindowExtents output;
971
972@@ -398,6 +439,9 @@
973 Time lastCloseRequestTime;
974
975 bool nextMoveImmediate;
976+
977+ X11SyncServerWindow syncServerWindow;
978+ compiz::window::configure_buffers::Buffer::Ptr configureBuffer;
979 };
980
981 #endif
982
983=== added file 'src/serverwindow.h'
984=== added file 'src/syncserverwindow.h'
985--- src/syncserverwindow.h 1970-01-01 00:00:00 +0000
986+++ src/syncserverwindow.h 2012-12-07 17:16:21 +0000
987@@ -0,0 +1,49 @@
988+/*
989+ * Copyright © 2012 Sam Spilsbury
990+ *
991+ * Permission to use, copy, modify, distribute, and sell this software
992+ * and its documentation for any purpose is hereby granted without
993+ * fee, provided that the above copyright notice appear in all copies
994+ * and that both that copyright notice and this permission notice
995+ * appear in supporting documentation, and that the name of
996+ * Canonical Ltd. not be used in advertising or publicity pertaining to
997+ * distribution of the software without specific, written prior permission.
998+ * Canonical Ltd. makes no representations about the suitability of this
999+ * software for any purpose. It is provided "as is" without express or
1000+ * implied warranty.
1001+ *
1002+ * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1003+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
1004+ * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1005+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
1006+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
1007+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
1008+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1009+ *
1010+ * Authored by: Sam Spilsbury <smspillaz@gmail.com>
1011+ */
1012+#ifndef _COMPIZ_SYNC_SERVER_WINDOW_H
1013+#define _COMPIZ_SYNC_SERVER_WINDOW_H
1014+
1015+#include <X11/Xlib.h>
1016+
1017+namespace compiz
1018+{
1019+namespace window
1020+{
1021+class SyncServerWindow
1022+{
1023+ public:
1024+
1025+ virtual ~SyncServerWindow () {}
1026+
1027+ virtual bool queryAttributes (XWindowAttributes &attrib) = 0;
1028+ virtual bool queryFrameAttributes (XWindowAttributes &attrib) = 0;
1029+ virtual XRectangle * queryShapeRectangles (int kind,
1030+ int *count,
1031+ int *ordering) = 0;
1032+};
1033+}
1034+}
1035+
1036+#endif
1037
1038=== modified file 'src/tests/CMakeLists.txt'
1039--- src/tests/CMakeLists.txt 2012-11-26 07:13:04 +0000
1040+++ src/tests/CMakeLists.txt 2012-12-07 17:16:21 +0000
1041@@ -29,3 +29,14 @@
1042
1043 compiz_discover_tests(compiz_test_outputdevices COVERAGE compiz_core)
1044
1045+add_executable (compiz_test_configurerequestbuffer
1046+ test_configurerequestbuffer.cpp)
1047+
1048+target_link_libraries (compiz_test_configurerequestbuffer
1049+ compiz_configurerequestbuffer
1050+ ${GTEST_BOTH_LIBRARIES}
1051+ ${GMOCK_MAIN_LIBRARY}
1052+ ${GMOCK_LIBRARY}
1053+)
1054+
1055+compiz_discover_tests(compiz_test_configurerequestbuffer COVERAGE compiz_configurerequestbuffer)
1056
1057=== added file 'src/tests/test_configurerequestbuffer.cpp'
1058--- src/tests/test_configurerequestbuffer.cpp 1970-01-01 00:00:00 +0000
1059+++ src/tests/test_configurerequestbuffer.cpp 2012-12-07 17:16:21 +0000
1060@@ -0,0 +1,647 @@
1061+/*
1062+ * Copyright © 2012 Sam Spilsbury
1063+ *
1064+ * Permission to use, copy, modify, distribute, and sell this software
1065+ * and its documentation for any purpose is hereby granted without
1066+ * fee, provided that the above copyright notice appear in all copies
1067+ * and that both that copyright notice and this permission notice
1068+ * appear in supporting documentation, and that the name of
1069+ * Canonical Ltd. not be used in advertising or publicity pertaining to
1070+ * distribution of the software without specific, written prior permission.
1071+ * Canonical Ltd. makes no representations about the suitability of this
1072+ * software for any purpose. It is provided "as is" without express or
1073+ * implied warranty.
1074+ *
1075+ * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1076+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
1077+ * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1078+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
1079+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
1080+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
1081+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1082+ *
1083+ * Authored by: Sam Spilsbury <smspillaz@gmail.com>
1084+ */
1085+#include <deque>
1086+#include <boost/shared_ptr.hpp>
1087+#include <boost/make_shared.hpp>
1088+#include <boost/bind.hpp>
1089+#include <gmock/gmock.h>
1090+#include <gtest/gtest.h>
1091+#include <X11/Xlib.h>
1092+
1093+#include "configurerequestbuffer-impl.h"
1094+#include "asyncserverwindow.h"
1095+
1096+namespace crb = compiz::window::configure_buffers;
1097+namespace cw = compiz::window;
1098+
1099+using testing::_;
1100+using testing::NiceMock;
1101+using testing::Return;
1102+using testing::Invoke;
1103+using testing::WithArgs;
1104+using testing::SetArgReferee;
1105+using testing::DoAll;
1106+using testing::InSequence;
1107+using testing::ReturnNull;
1108+using testing::IsNull;
1109+
1110+class MockAsyncServerWindow :
1111+ public cw::AsyncServerWindow
1112+{
1113+ public:
1114+
1115+ MOCK_METHOD2 (requestConfigureOnClient, int (const XWindowChanges &, unsigned int));
1116+ MOCK_METHOD2 (requestConfigureOnFrame, int (const XWindowChanges &, unsigned int));
1117+ MOCK_METHOD2 (requestConfigureOnWrapper, int (const XWindowChanges &, unsigned int));
1118+ MOCK_METHOD0 (sendSyntheticConfigureNotify, void ());
1119+ MOCK_CONST_METHOD0 (hasCustomShape, bool ());
1120+};
1121+
1122+class MockSyncServerWindow :
1123+ public cw::SyncServerWindow
1124+{
1125+ public:
1126+
1127+ MOCK_METHOD1 (queryAttributes, bool (XWindowAttributes &));
1128+ MOCK_METHOD1 (queryFrameAttributes, bool (XWindowAttributes &));
1129+ MOCK_METHOD3 (queryShapeRectangles, XRectangle * (int, int *, int *));
1130+};
1131+
1132+namespace
1133+{
1134+int REQUEST_X = 1;
1135+int REQUEST_Y = 2;
1136+int REQUEST_WIDTH = 3;
1137+int REQUEST_HEIGHT = 4;
1138+int REQUEST_BORDER = 5;
1139+
1140+Window REQUEST_ABOVE = 6;
1141+unsigned int REQUEST_MODE = 7;
1142+
1143+crb::BufferLock::Ptr
1144+CreateNormalLock (crb::CountedFreeze *cf)
1145+{
1146+ return boost::make_shared <crb::ConfigureBufferLock> (cf);
1147+}
1148+
1149+}
1150+
1151+MATCHER_P2 (MaskXWC, xwc, vm, "Matches XWindowChanges")
1152+{
1153+ if (vm & CWX)
1154+ if (xwc.x != arg.x)
1155+ return false;
1156+
1157+ if (vm & CWY)
1158+ if (xwc.y != arg.y)
1159+ return false;
1160+
1161+ if (vm & CWWidth)
1162+ if (xwc.width != arg.width)
1163+ return false;
1164+
1165+ if (vm & CWHeight)
1166+ if (xwc.height != arg.height)
1167+ return false;
1168+
1169+ if (vm & CWBorderWidth)
1170+ if (xwc.border_width != arg.border_width)
1171+ return false;
1172+
1173+ if (vm & CWStackMode)
1174+ if (xwc.stack_mode != arg.stack_mode)
1175+ return false;
1176+
1177+ if (vm & CWSibling)
1178+ if (xwc.sibling != arg.sibling)
1179+ return false;
1180+
1181+ return true;
1182+}
1183+
1184+class ConfigureRequestBuffer :
1185+ public testing::Test
1186+{
1187+ public:
1188+
1189+ ConfigureRequestBuffer ()
1190+ {
1191+ /* Initialize xwc, we control it
1192+ * through the value masks */
1193+ xwc.x = REQUEST_X;
1194+ xwc.y = REQUEST_Y;
1195+ xwc.width = REQUEST_WIDTH;
1196+ xwc.height = REQUEST_HEIGHT;
1197+ xwc.border_width = REQUEST_BORDER;
1198+ xwc.sibling = REQUEST_ABOVE;
1199+ xwc.stack_mode = REQUEST_MODE;
1200+ }
1201+
1202+ protected:
1203+
1204+ XWindowChanges xwc;
1205+ MockAsyncServerWindow asyncServerWindow;
1206+ MockSyncServerWindow syncServerWindow;
1207+};
1208+
1209+class ConfigureRequestBufferDispatch :
1210+ public ConfigureRequestBuffer
1211+{
1212+ protected:
1213+
1214+ ConfigureRequestBufferDispatch () :
1215+ ConfigureRequestBuffer (),
1216+ factory (boost::bind (CreateNormalLock, _1)),
1217+ buffer (
1218+ crb::ConfigureRequestBuffer::Create (&asyncServerWindow,
1219+ &syncServerWindow,
1220+ factory))
1221+ {
1222+ }
1223+
1224+ crb::ConfigureRequestBuffer::LockFactory factory;
1225+ crb::Buffer::Ptr buffer;
1226+};
1227+
1228+TEST_F (ConfigureRequestBufferDispatch, PushDirectSyntheticConfigureNotify)
1229+{
1230+ EXPECT_CALL (asyncServerWindow, sendSyntheticConfigureNotify ());
1231+
1232+ buffer->pushSyntheticConfigureNotify ();
1233+}
1234+
1235+TEST_F (ConfigureRequestBufferDispatch, PushDirectClientUpdate)
1236+{
1237+ unsigned int valueMask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth |
1238+ CWSibling | CWStackMode;
1239+
1240+ EXPECT_CALL (asyncServerWindow, requestConfigureOnClient (MaskXWC (xwc, valueMask),
1241+ valueMask));
1242+
1243+ buffer->pushClientRequest (xwc, valueMask);
1244+}
1245+
1246+TEST_F (ConfigureRequestBufferDispatch, PushDirectWrapperUpdate)
1247+{
1248+ unsigned int valueMask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth |
1249+ CWSibling | CWStackMode;
1250+
1251+ EXPECT_CALL (asyncServerWindow, requestConfigureOnWrapper (MaskXWC (xwc, valueMask),
1252+ valueMask));
1253+
1254+ buffer->pushWrapperRequest (xwc, valueMask);
1255+}
1256+
1257+TEST_F (ConfigureRequestBufferDispatch, PushDirectFrameUpdate)
1258+{
1259+ unsigned int valueMask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth |
1260+ CWSibling | CWStackMode;
1261+
1262+ EXPECT_CALL (asyncServerWindow, hasCustomShape ()).WillOnce (Return (false));
1263+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (MaskXWC (xwc, valueMask),
1264+ valueMask));
1265+
1266+ buffer->pushFrameRequest (xwc, valueMask);
1267+}
1268+
1269+TEST_F (ConfigureRequestBufferDispatch, PushUpdateLocked)
1270+{
1271+ crb::Releasable::Ptr lock (buffer->obtainLock ());
1272+
1273+ unsigned int valueMask = 0;
1274+
1275+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1276+
1277+ buffer->pushFrameRequest (xwc, valueMask);
1278+}
1279+
1280+TEST_F (ConfigureRequestBufferDispatch, PushCombinedUpdateLocked)
1281+{
1282+ crb::Releasable::Ptr lock (buffer->obtainLock ());
1283+
1284+ unsigned int valueMask = CWX | CWY;
1285+
1286+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1287+
1288+ buffer->pushFrameRequest (xwc, valueMask);
1289+
1290+ valueMask |= CWWidth | CWHeight;
1291+
1292+ EXPECT_CALL (asyncServerWindow, hasCustomShape ()).WillRepeatedly (Return (false));
1293+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1294+
1295+ buffer->pushFrameRequest (xwc, valueMask);
1296+
1297+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (MaskXWC (xwc, valueMask),
1298+ valueMask));
1299+
1300+ lock->release ();
1301+}
1302+
1303+TEST_F (ConfigureRequestBufferDispatch, PushUpdateLockedReleaseInOrder)
1304+{
1305+ crb::Releasable::Ptr lock (buffer->obtainLock ());
1306+
1307+ unsigned int valueMask = CWX | CWY;
1308+
1309+ EXPECT_CALL (asyncServerWindow, hasCustomShape ()).WillRepeatedly (Return (false));
1310+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1311+ EXPECT_CALL (asyncServerWindow, requestConfigureOnWrapper (_, _)).Times (0);
1312+ EXPECT_CALL (asyncServerWindow, requestConfigureOnClient (_, _)).Times (0);
1313+
1314+ buffer->pushClientRequest (xwc, valueMask);
1315+ buffer->pushWrapperRequest (xwc, valueMask);
1316+ buffer->pushFrameRequest (xwc, valueMask);
1317+
1318+ InSequence s;
1319+
1320+ /* Always frame -> wrapper -> client */
1321+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (MaskXWC (xwc, valueMask),
1322+ valueMask));
1323+ EXPECT_CALL (asyncServerWindow, requestConfigureOnWrapper (MaskXWC (xwc, valueMask),
1324+ valueMask));
1325+ EXPECT_CALL (asyncServerWindow, requestConfigureOnClient (MaskXWC (xwc, valueMask),
1326+ valueMask));
1327+
1328+ lock->release ();
1329+}
1330+
1331+TEST_F (ConfigureRequestBufferDispatch, UnlockBuffer)
1332+{
1333+ crb::Releasable::Ptr lock (buffer->obtainLock ());
1334+
1335+ unsigned int valueMask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
1336+
1337+ EXPECT_CALL (asyncServerWindow, hasCustomShape ()).WillRepeatedly (Return (false));
1338+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1339+
1340+ buffer->pushFrameRequest (xwc, valueMask);
1341+
1342+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (MaskXWC (xwc, valueMask),
1343+ valueMask));
1344+
1345+ lock->release ();
1346+}
1347+
1348+TEST_F (ConfigureRequestBufferDispatch, ImplicitUnlockBuffer)
1349+{
1350+ crb::Releasable::Ptr lock (buffer->obtainLock ());
1351+
1352+ unsigned int valueMask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
1353+
1354+ EXPECT_CALL (asyncServerWindow, hasCustomShape ()).WillRepeatedly (Return (false));
1355+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1356+
1357+ buffer->pushFrameRequest (xwc, valueMask);
1358+
1359+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (MaskXWC (xwc, valueMask),
1360+ valueMask));
1361+}
1362+
1363+TEST_F (ConfigureRequestBufferDispatch, ForceImmediateConfigureOnRestack)
1364+{
1365+ crb::Releasable::Ptr lock (buffer->obtainLock ());
1366+
1367+ unsigned int valueMask = CWStackMode | CWSibling;
1368+
1369+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (MaskXWC (xwc, valueMask),
1370+ valueMask));
1371+
1372+ buffer->pushFrameRequest (xwc, valueMask);
1373+}
1374+
1375+TEST_F (ConfigureRequestBufferDispatch, ForceImmediateConfigureOnShapedWindowSizeChange)
1376+{
1377+ crb::Releasable::Ptr lock (buffer->obtainLock ());
1378+
1379+ unsigned int valueMask = CWWidth | CWHeight;
1380+
1381+ EXPECT_CALL (asyncServerWindow, hasCustomShape ()).WillOnce (Return (true));
1382+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (MaskXWC (xwc, valueMask),
1383+ valueMask));
1384+
1385+ buffer->pushFrameRequest (xwc, valueMask);
1386+}
1387+
1388+namespace
1389+{
1390+class MockLock :
1391+ public crb::BufferLock
1392+{
1393+ public:
1394+
1395+ /* We're currently importing the locks statefulness and coupling
1396+ * the caller with that */
1397+ MockLock () :
1398+ armed (false)
1399+ {
1400+ ON_CALL (*this, lock ()).WillByDefault (
1401+ Invoke (this, &MockLock::FreezeIfUnarmed));
1402+ ON_CALL (*this, release ()).WillByDefault (
1403+ Invoke (this, &MockLock::ReleaseIfArmed));
1404+ }
1405+
1406+ void OperateOver (crb::CountedFreeze *cf)
1407+ {
1408+ countedFreeze = cf;
1409+ }
1410+
1411+ void FreezeIfUnarmed ()
1412+ {
1413+ if (!armed)
1414+ {
1415+ countedFreeze->freeze ();
1416+ armed = true;
1417+ }
1418+ }
1419+
1420+ void ReleaseIfArmed ()
1421+ {
1422+ if (armed)
1423+ {
1424+ countedFreeze->release ();
1425+ armed = false;
1426+ }
1427+ }
1428+
1429+ typedef boost::shared_ptr <MockLock> Ptr;
1430+
1431+ MOCK_METHOD0 (lock, void ());
1432+ MOCK_METHOD0 (release, void ());
1433+
1434+ private:
1435+
1436+ crb::CountedFreeze *countedFreeze;
1437+ bool armed;
1438+};
1439+
1440+class MockLockFactory
1441+{
1442+ public:
1443+
1444+ crb::BufferLock::Ptr
1445+ CreateMockLock (crb::CountedFreeze *cf)
1446+ {
1447+ MockLock::Ptr mockLock (locks.front ());
1448+ mockLock->OperateOver (cf);
1449+
1450+ locks.pop_front ();
1451+
1452+ return mockLock;
1453+ }
1454+
1455+ void
1456+ QueueLockForCreation (const MockLock::Ptr &lock)
1457+ {
1458+ locks.push_back (lock);
1459+ }
1460+
1461+ private:
1462+
1463+ std::deque <MockLock::Ptr> locks;
1464+};
1465+}
1466+
1467+class ConfigureRequestBufferLockBehaviour :
1468+ public ConfigureRequestBuffer
1469+{
1470+ public:
1471+
1472+ ConfigureRequestBufferLockBehaviour () :
1473+ ConfigureRequestBuffer (),
1474+ lock (boost::make_shared <MockLock> ()),
1475+ factory (
1476+ boost::bind (&MockLockFactory::CreateMockLock,
1477+ &mockLockFactory,
1478+ _1)),
1479+ buffer (
1480+ crb::ConfigureRequestBuffer::Create (
1481+ &asyncServerWindow,
1482+ &syncServerWindow,
1483+ factory))
1484+
1485+ {
1486+ mockLockFactory.QueueLockForCreation (lock);
1487+ }
1488+
1489+ protected:
1490+
1491+ typedef NiceMock <MockAsyncServerWindow> NiceServerWindow;
1492+ typedef crb::ConfigureRequestBuffer::LockFactory LockFactory;
1493+
1494+ MockLock::Ptr lock;
1495+ MockLockFactory mockLockFactory;
1496+
1497+ LockFactory factory;
1498+ crb::Buffer::Ptr buffer;
1499+};
1500+
1501+TEST_F (ConfigureRequestBufferLockBehaviour, RearmBufferLockOnRelease)
1502+{
1503+ EXPECT_CALL (*lock, lock ());
1504+ crb::Releasable::Ptr releasable (buffer->obtainLock ());
1505+
1506+ unsigned int valueMask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
1507+
1508+ EXPECT_CALL (asyncServerWindow, hasCustomShape ()).WillRepeatedly (Return (false));
1509+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1510+
1511+ buffer->pushFrameRequest (xwc, valueMask);
1512+
1513+ /* We are releasing this lock */
1514+ EXPECT_CALL (*lock, release ());
1515+
1516+ /* Now the buffer will dispatch is configure request */
1517+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _));
1518+
1519+ /* Rearm locks on release */
1520+ EXPECT_CALL (*lock, lock ());
1521+
1522+ /* Directly release the queue */
1523+ releasable->release ();
1524+}
1525+
1526+TEST_F (ConfigureRequestBufferLockBehaviour, NoRearmBufferLockNoReleaseRequired)
1527+{
1528+ /* Locks get armed on construction */
1529+ EXPECT_CALL (*lock, lock ());
1530+ crb::Releasable::Ptr releasable (buffer->obtainLock ());
1531+
1532+ /* No call to requestConfigureOnFrame if there's nothing to be configured */
1533+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1534+
1535+ /* We are releasing this lock */
1536+ EXPECT_CALL (*lock, release ());
1537+
1538+ /* No rearm - we haven't released the whole buffer */
1539+ EXPECT_CALL (*lock, lock ()).Times (0);
1540+
1541+ /* Directly release the queue */
1542+ releasable->release ();
1543+}
1544+
1545+TEST_F (ConfigureRequestBufferLockBehaviour, RearmWhenPushReady)
1546+{
1547+ /* Locks get armed on construction */
1548+ EXPECT_CALL (*lock, lock ());
1549+ crb::Releasable::Ptr releasable (buffer->obtainLock ());
1550+
1551+ /* We are releasing this lock */
1552+ EXPECT_CALL (*lock, release ());
1553+
1554+ /* No call to requestConfigureOnFrame if there's nothing to be configured */
1555+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1556+
1557+ /* No rearm - we haven't released it */
1558+ EXPECT_CALL (*lock, lock ()).Times (0);
1559+
1560+ /* Directly release the queue */
1561+ releasable->release ();
1562+
1563+ /* Since we're now going to push something to a queue
1564+ * that's effectively not locked, the locks should now
1565+ * be released */
1566+ unsigned int valueMask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
1567+
1568+ /* Now rearm it */
1569+ EXPECT_CALL (asyncServerWindow, hasCustomShape ()).WillOnce (Return (false));
1570+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _));
1571+ EXPECT_CALL (*lock, lock ());
1572+
1573+ buffer->pushFrameRequest (xwc, valueMask);
1574+}
1575+
1576+TEST_F (ConfigureRequestBufferLockBehaviour, NoRearmBufferLockOnNoRelease)
1577+{
1578+ MockLock::Ptr second (boost::make_shared <MockLock> ());
1579+ mockLockFactory.QueueLockForCreation (second);
1580+
1581+ /* Locks get armed on construction */
1582+ EXPECT_CALL (*lock, lock ());
1583+ EXPECT_CALL (*second, lock ());
1584+
1585+ crb::Releasable::Ptr releasable (buffer->obtainLock ());
1586+ crb::Releasable::Ptr otherReleasable (buffer->obtainLock ());
1587+
1588+ /* We are releasing this lock */
1589+ EXPECT_CALL (*lock, release ());
1590+
1591+ /* No call to requestConfigureOnFrame if there's nothing to be configured */
1592+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1593+
1594+ /* No rearm - we haven't released it */
1595+ EXPECT_CALL (*lock, lock ()).Times (0);
1596+
1597+ releasable->release ();
1598+}
1599+
1600+TEST_F (ConfigureRequestBufferLockBehaviour, QueryAttributesDispatchAndRearm)
1601+{
1602+ /* Locks get armed on construction */
1603+ EXPECT_CALL (*lock, lock ());
1604+
1605+ crb::Releasable::Ptr releasable (buffer->obtainLock ());
1606+
1607+ unsigned int valueMask = CWX | CWY;
1608+
1609+ /* Queue locked */
1610+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1611+
1612+ buffer->pushFrameRequest (xwc, valueMask);
1613+
1614+ /* Queue forceably unlocked, locks rearmed */
1615+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _));
1616+ EXPECT_CALL (*lock, lock ());
1617+
1618+ /* Expect a call to XGetWindowAttributes */
1619+ EXPECT_CALL (syncServerWindow, queryShapeRectangles (_, _, _))
1620+ .WillOnce (
1621+ ReturnNull ());
1622+
1623+ int a, b;
1624+
1625+ EXPECT_THAT (buffer->queryShapeRectangles (0, &a, &b), IsNull ());
1626+}
1627+
1628+TEST_F (ConfigureRequestBufferLockBehaviour, QueryFrameAttributesDispatchAndRearm)
1629+{
1630+ /* Locks get armed on construction */
1631+ EXPECT_CALL (*lock, lock ());
1632+
1633+ crb::Releasable::Ptr releasable (buffer->obtainLock ());
1634+
1635+ unsigned int valueMask = CWX | CWY;
1636+
1637+ /* Queue locked */
1638+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1639+
1640+ buffer->pushFrameRequest (xwc, valueMask);
1641+
1642+ /* Queue forceably unlocked, locks rearmed */
1643+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _));
1644+ EXPECT_CALL (*lock, lock ());
1645+
1646+ /* Expect a call to XGetWindowAttributes */
1647+ XWindowAttributes xwa;
1648+ EXPECT_CALL (syncServerWindow, queryFrameAttributes (_))
1649+ .WillOnce (
1650+ DoAll (
1651+ SetArgReferee <0> (xwa),
1652+ Return (true)));
1653+
1654+ buffer->queryFrameAttributes (xwa);
1655+}
1656+
1657+TEST_F (ConfigureRequestBufferLockBehaviour, QueryShapeRectanglesDispatchAndRearm)
1658+{
1659+ /* Locks get armed on construction */
1660+ EXPECT_CALL (*lock, lock ());
1661+
1662+ crb::Releasable::Ptr releasable (buffer->obtainLock ());
1663+
1664+ unsigned int valueMask = CWX | CWY;
1665+
1666+ /* Queue locked */
1667+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1668+
1669+ buffer->pushFrameRequest (xwc, valueMask);
1670+
1671+ /* Queue forceably unlocked, locks rearmed */
1672+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _));
1673+ EXPECT_CALL (*lock, lock ());
1674+
1675+ /* Expect a call to XGetWindowAttributes */
1676+ XWindowAttributes xwa;
1677+ EXPECT_CALL (syncServerWindow, queryFrameAttributes (_))
1678+ .WillOnce (
1679+ DoAll (
1680+ SetArgReferee <0> (xwa),
1681+ Return (true)));
1682+
1683+ buffer->queryFrameAttributes (xwa);
1684+}
1685+
1686+TEST_F (ConfigureRequestBufferLockBehaviour, ForceReleaseDispatchAndRearm)
1687+{
1688+ /* Locks get armed on construction */
1689+ EXPECT_CALL (*lock, lock ());
1690+
1691+ crb::Releasable::Ptr releasable (buffer->obtainLock ());
1692+
1693+ unsigned int valueMask = CWX | CWY;
1694+
1695+ /* Queue locked */
1696+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1697+
1698+ buffer->pushFrameRequest (xwc, valueMask);
1699+
1700+ /* Queue forceably unlocked, locks rearmed */
1701+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _));
1702+ EXPECT_CALL (*lock, lock ());
1703+
1704+ /* Force release */
1705+ buffer->forceRelease ();
1706+}
1707+
1708
1709=== modified file 'src/window.cpp'
1710--- src/window.cpp 2012-12-07 09:28:03 +0000
1711+++ src/window.cpp 2012-12-07 17:16:21 +0000
1712@@ -37,6 +37,7 @@
1713 #include <math.h>
1714
1715 #include <boost/bind.hpp>
1716+#include <boost/make_shared.hpp>
1717
1718 #include <core/icon.h>
1719 #include <core/atoms.h>
1720@@ -45,8 +46,13 @@
1721 #include "privatescreen.h"
1722 #include "privatestackdebugger.h"
1723
1724+#include "configurerequestbuffer-impl.h"
1725+
1726 #include <boost/scoped_array.hpp>
1727
1728+namespace crb = compiz::window::configure_buffers;
1729+namespace cw = compiz::window;
1730+
1731 template class WrapableInterface<CompWindow, WindowInterface>;
1732
1733 PluginClassStorage::Indices windowPluginClassIndices (0);
1734@@ -912,10 +918,12 @@
1735 /* We should update the server here */
1736 XSync (screen->dpy (), false);
1737
1738- boundingShapeRects = XShapeGetRectangles (screen->dpy (), priv->id,
1739- ShapeBounding, &nBounding, &order);
1740- inputShapeRects = XShapeGetRectangles (screen->dpy (), priv->id,
1741- ShapeInput, &nInput, &order);
1742+ boundingShapeRects = priv->queryShapeRectangles (ShapeBounding,
1743+ &nBounding,
1744+ &order);
1745+ inputShapeRects = priv->queryShapeRectangles (ShapeInput,
1746+ &nBounding,
1747+ &order);
1748 }
1749
1750 r.x = -geom.border ();
1751@@ -2961,6 +2969,80 @@
1752 return pc->matchRequest (xwc, valueMask);
1753 }
1754
1755+bool
1756+PrivateWindow::queryAttributes (XWindowAttributes &attrib)
1757+{
1758+ return configureBuffer->queryAttributes (attrib);
1759+}
1760+
1761+bool
1762+PrivateWindow::queryFrameAttributes (XWindowAttributes &attrib)
1763+{
1764+ return configureBuffer->queryFrameAttributes (attrib);
1765+}
1766+
1767+XRectangle *
1768+PrivateWindow::queryShapeRectangles (int kind, int *count, int *ordering)
1769+{
1770+ return configureBuffer->queryShapeRectangles (kind, count, ordering);
1771+}
1772+
1773+int
1774+PrivateWindow::requestConfigureOnClient (const XWindowChanges &xwc,
1775+ unsigned int valueMask)
1776+{
1777+ int ret = XConfigureWindow (screen->dpy (),
1778+ id,
1779+ valueMask,
1780+ const_cast <XWindowChanges *> (&xwc));
1781+
1782+ return ret;
1783+}
1784+
1785+int
1786+PrivateWindow::requestConfigureOnWrapper (const XWindowChanges &xwc,
1787+ unsigned int valueMask)
1788+{
1789+ return XConfigureWindow (screen->dpy (),
1790+ wrapper,
1791+ valueMask,
1792+ const_cast <XWindowChanges *> (&xwc));
1793+}
1794+
1795+int
1796+PrivateWindow::requestConfigureOnFrame (const XWindowChanges &xwc,
1797+ unsigned int frameValueMask)
1798+{
1799+ XWindowChanges wc = xwc;
1800+
1801+ wc.x = serverFrameGeometry.x ();
1802+ wc.y = serverFrameGeometry.y ();
1803+ wc.width = serverFrameGeometry.width ();
1804+ wc.height = serverFrameGeometry.height ();
1805+
1806+ compiz::X11::PendingEvent::Ptr pc (
1807+ new compiz::X11::PendingConfigureEvent (
1808+ screen->dpy (),
1809+ priv->serverFrame,
1810+ frameValueMask, &wc));
1811+
1812+ pendingConfigures.add (pc);
1813+
1814+ return XConfigureWindow (screen->dpy (), serverFrame, frameValueMask, &wc);
1815+}
1816+
1817+void
1818+PrivateWindow::sendSyntheticConfigureNotify ()
1819+{
1820+ window->sendConfigureNotify ();
1821+}
1822+
1823+bool
1824+PrivateWindow::hasCustomShape () const
1825+{
1826+ return false;
1827+}
1828+
1829 void
1830 PrivateWindow::reconfigureXWindow (unsigned int valueMask,
1831 XWindowChanges *xwc)
1832@@ -3173,47 +3255,41 @@
1833 if (serverFrame)
1834 {
1835 if (frameValueMask)
1836- {
1837- XWindowChanges wc = *xwc;
1838-
1839- wc.x = serverFrameGeometry.x ();
1840- wc.y = serverFrameGeometry.y ();
1841- wc.width = serverFrameGeometry.width ();
1842- wc.height = serverFrameGeometry.height ();
1843-
1844- compiz::X11::PendingEvent::Ptr pc =
1845- boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
1846- new compiz::X11::PendingConfigureEvent (
1847- screen->dpy (), priv->serverFrame, frameValueMask, &wc)));
1848-
1849- pendingConfigures.add (pc);
1850-
1851- XConfigureWindow (screen->dpy (), serverFrame, frameValueMask, &wc);
1852- }
1853-
1854- valueMask &= ~(CWSibling | CWStackMode);
1855+ priv->configureBuffer->pushFrameRequest (*xwc, frameValueMask);
1856+
1857+ valueMask = frameValueMask & (CWWidth | CWHeight);
1858
1859 /* If the frame has changed position (eg, serverInput.top
1860 * or serverInput.left have changed) then we also need to
1861 * update the client and wrapper position */
1862- if (!(valueMask & CWX))
1863- valueMask |= frameValueMask & CWX;
1864- if (!(valueMask & CWY))
1865- valueMask |= frameValueMask & CWY;
1866+ if (lastServerInput.left != serverInput.left)
1867+ valueMask |= CWX;
1868+ if (lastServerInput.top != serverInput.top)
1869+ valueMask |= CWY;
1870+
1871+ if (lastServerInput.right != serverInput.right)
1872+ valueMask |= CWWidth;
1873+ if (lastServerInput.bottom != serverInput.bottom)
1874+ valueMask |= CWHeight;
1875
1876 if (valueMask)
1877 {
1878 xwc->x = serverInput.left;
1879 xwc->y = serverInput.top;
1880- XConfigureWindow (screen->dpy (), wrapper, valueMask, xwc);
1881-
1882- xwc->x = 0;
1883- xwc->y = 0;
1884+
1885+ lastServerInput = serverInput;
1886+
1887+ priv->configureBuffer->pushWrapperRequest (*xwc, valueMask);
1888 }
1889 }
1890
1891+ /* Client is reparented, the only things that can change
1892+ * are the width, height and border width */
1893+ if (serverFrame)
1894+ valueMask &= (CWWidth | CWHeight | CWBorderWidth);
1895+
1896 if (valueMask)
1897- XConfigureWindow (screen->dpy (), id, valueMask, xwc);
1898+ priv->configureBuffer->pushClientRequest (*xwc, valueMask);
1899
1900 /* Send the synthetic configure notify
1901 * after the real configure notify arrives
1902@@ -5655,6 +5731,24 @@
1903 return priv->struts;
1904 }
1905
1906+bool
1907+CompWindow::queryAttributes (XWindowAttributes &attrib)
1908+{
1909+ return priv->queryAttributes (attrib);
1910+}
1911+
1912+bool
1913+CompWindow::queryFrameAttributes (XWindowAttributes &attrib)
1914+{
1915+ return priv->queryFrameAttributes (attrib);
1916+}
1917+
1918+crb::Releasable::Ptr
1919+CompWindow::obtainLockOnConfigureRequests ()
1920+{
1921+ return priv->configureBuffer->obtainLock ();
1922+}
1923+
1924 int &
1925 CompWindow::saveMask () const
1926 {
1927@@ -6193,6 +6287,55 @@
1928 delete priv;
1929 }
1930
1931+X11SyncServerWindow::X11SyncServerWindow (Display *dpy,
1932+ const Window *w,
1933+ const Window *frame) :
1934+ mDpy (dpy),
1935+ mWindow (w),
1936+ mFrame (frame)
1937+{
1938+}
1939+
1940+bool
1941+X11SyncServerWindow::queryAttributes (XWindowAttributes &attrib)
1942+{
1943+ if (XGetWindowAttributes (mDpy, *mWindow, &attrib))
1944+ return true;
1945+
1946+ return false;
1947+}
1948+
1949+bool
1950+X11SyncServerWindow::queryFrameAttributes (XWindowAttributes &attrib)
1951+{
1952+ Window w = *mFrame ? *mFrame : *mWindow;
1953+
1954+ if (XGetWindowAttributes (mDpy, w, &attrib))
1955+ return true;
1956+
1957+ return false;
1958+}
1959+
1960+XRectangle *
1961+X11SyncServerWindow::queryShapeRectangles (int kind,
1962+ int *count,
1963+ int *ordering)
1964+{
1965+ return XShapeGetRectangles (mDpy, *mWindow,
1966+ kind,
1967+ count,
1968+ ordering);
1969+}
1970+
1971+namespace
1972+{
1973+crb::BufferLock::Ptr
1974+createConfigureBufferLock (crb::CountedFreeze *cf)
1975+{
1976+ return boost::make_shared <crb::ConfigureBufferLock> (cf);
1977+}
1978+}
1979+
1980 PrivateWindow::PrivateWindow () :
1981 priv (this),
1982 refcnt (1),
1983@@ -6264,27 +6407,27 @@
1984
1985 syncWait (false),
1986 closeRequests (false),
1987- lastCloseRequestTime (0)
1988+ lastCloseRequestTime (0),
1989+
1990+ syncServerWindow (screen->dpy (),
1991+ &id,
1992+ &serverFrame),
1993+ configureBuffer (
1994+ crb::ConfigureRequestBuffer::Create (
1995+ this,
1996+ &syncServerWindow,
1997+ boost::bind (createConfigureBufferLock, _1)))
1998 {
1999 input.left = 0;
2000 input.right = 0;
2001 input.top = 0;
2002 input.bottom = 0;
2003
2004- serverInput.left = 0;
2005- serverInput.right = 0;
2006- serverInput.top = 0;
2007- serverInput.bottom = 0;
2008-
2009- border.top = 0;
2010- border.bottom = 0;
2011- border.left = 0;
2012- border.right = 0;
2013-
2014- output.left = 0;
2015- output.right = 0;
2016- output.top = 0;
2017- output.bottom = 0;
2018+ /* Zero initialize */
2019+ serverInput = input;
2020+ lastServerInput = input;
2021+ border = input;
2022+ output = input;
2023
2024 syncWaitTimer.setTimes (1000, 1200);
2025 syncWaitTimer.setCallback (boost::bind (&PrivateWindow::handleSyncAlarm,
2026@@ -6554,7 +6697,11 @@
2027 XSync (dpy, false);
2028 XGrabServer (dpy);
2029
2030- if (!XGetWindowAttributes (dpy, id, &wa))
2031+ /* We need to flush all queued up requests */
2032+ foreach (CompWindow *w, screen->windows ())
2033+ w->priv->configureBuffer->forceRelease ();
2034+
2035+ if (!window->priv->queryAttributes (wa))
2036 {
2037 XUngrabServer (dpy);
2038 XSync (dpy, false);
2039@@ -6841,7 +6988,7 @@
2040 * a DestroyNotify for it yet, it is possible that restacking
2041 * operations could occurr relative to it so we need to hold it
2042 * in the stack for now. Ensure that it is marked override redirect */
2043- XGetWindowAttributes (screen->dpy (), serverFrame, &attrib);
2044+ window->priv->queryFrameAttributes (attrib);
2045
2046 /* Put the frame window "above" the client window
2047 * in the stack */

Subscribers

People subscribed via source and target branches