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

Proposed by Sam Spilsbury
Status: Superseded
Proposed branch: lp:~compiz-team/compiz/compiz.performance_1027211.2.1
Merge into: lp:compiz/0.9.9
Diff against target: 4239 lines (+3352/-121) (has conflicts)
43 files modified
CMakeLists.txt (+16/-0)
include/core/CMakeLists.txt (+1/-0)
include/core/configurerequestbuffer.h (+73/-0)
include/core/window.h (+26/-7)
plugins/CMakeLists.txt (+1/-17)
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 (+5/-2)
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 (+363/-0)
src/event.cpp (+1/-1)
src/plugin.cpp (+7/-0)
src/plugin/tests/CMakeLists.txt (+1/-0)
src/plugin/tests/test-plugin.cpp (+29/-0)
src/privatewindow.h (+45/-1)
src/syncserverwindow.h (+49/-0)
src/tests/CMakeLists.txt (+11/-0)
src/tests/test_configurerequestbuffer.cpp (+667/-0)
src/window.cpp (+192/-44)
tests/acceptance-tests/xorg-gtest/tests/compiz_acceptance_replace_current_wm.cpp (+5/-0)
tests/system/xorg-gtest/CMakeLists.txt (+37/-0)
tests/system/xorg-gtest/communicator/CMakeLists.txt (+17/-0)
tests/system/xorg-gtest/communicator/compiz_xorg_gtest_communicator.cpp (+200/-0)
tests/system/xorg-gtest/communicator/compiz_xorg_gtest_communicator.h (+67/-0)
tests/system/xorg-gtest/tests/CMakeLists.txt (+12/-1)
tests/system/xorg-gtest/tests/compiz_xorg_gtest_configure_window.cpp (+567/-0)
tests/system/xorg-gtest/tests/compiz_xorg_gtest_ewmh.cpp (+2/-1)
tests/system/xorg-gtest/tests/compiz_xorg_gtest_icccm.cpp (+15/-3)
tests/system/xorg-gtest/tests/plugins/CMakeLists.txt (+10/-0)
tests/system/xorg-gtest/tests/plugins/testhelper/CMakeLists.txt (+7/-0)
tests/system/xorg-gtest/tests/plugins/testhelper/src/testhelper.cpp (+231/-0)
tests/system/xorg-gtest/tests/plugins/testhelper/src/testhelper.h (+95/-0)
tests/system/xorg-gtest/tests/plugins/testhelper/testhelper.xml.in (+6/-0)
tests/xorg-gtest/include/compiz-xorg-gtest.h (+62/-4)
tests/xorg-gtest/src/CMakeLists.txt (+57/-0)
tests/xorg-gtest/src/compiz-xorg-gtest-config.h.in (+3/-2)
tests/xorg-gtest/src/compiz-xorg-gtest.cpp (+247/-26)
Text conflict in tests/system/xorg-gtest/CMakeLists.txt
Text conflict in tests/xorg-gtest/src/CMakeLists.txt
To merge this branch: bzr merge lp:~compiz-team/compiz/compiz.performance_1027211.2.1
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
MC Return Pending
Compiz Maintainers Pending
Review via email: mp+149298@code.launchpad.net

This proposal supersedes a proposal from 2012-12-13.

This proposal has been superseded by a proposal from 2013-02-20.

Commit message

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.

Description of the change

Resubmitted with (LP: #1089279 fixed)

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.

Demonstrable numbers: moving opengl-rendered window around with vsync enabled in the driver goes from a constantly-diminishing 1FPS to staying consistent at around 12FPS, with 60FPS if "lazy positioning" is enabled in the move plugin (disabled by default)

I've also added some further integration testing framework around this - with a "testhelper" plugin to facilitate communication between the test and compiz for requests that aren't usually exposed over EWMH or ICCCM.

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
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: Approve (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Confirmed moving windows is much improved. There is no improvement with resizing though. I still encounter exactly the same freezes as mentioned previously:
  1. XSync() inside PrivateWindow::updateRegion()
  2. XShapeGetRectangles()
So please either:
  (a) Don't touch XShape* in this proposal, and leave resize fixes for a later proposal; or
  (b) Fix XShape* properly.
Given the large size of this proposal already, and that a proper fix for XShape should be to simply call it much less often (i.e. only for shaped windows), I recommend (a).

Secondly, I do support the concept of disabling lazy positioning in theory but would have to get my test machine (Atom) for that upgraded and working again before I approve it.

review: Needs Fixing
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Also, without too much verbosity, why is it we need to implement window movement completely synchronously? My understanding is that waiting and locking should never be required when the user moves a window.

A window move should simply involve two events:
  1. Motion event -> move plugin -> send request to X server (XConfigureWindow I think).
and some time later (should not care when):
  2. XConfigureNotify (or whatever) -> core plugin -> compiz window position updated.

If this is lazy positioning then maybe I do support it. But historically we seem to have a lot more code than should be necessary to implement movement so I'm not sure.

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

I mean; my understanding of lazy positioning is that we update the compiz position without waiting for the server to tell us it's done. Therefore the above method counts as non-lazy movement, but also does not require any waiting or locking. I think this is contrary to the proposed and established non-lazy algorithm that does sync for some reason.

If we want to keep lazy mode as an option and it does bypass the server as I suspect then OK. However I think at least non-lazy mode should be implemented as above, so that either way you never need to lock or sync to move a window.

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

On Mon, Dec 10, 2012 at 2:16 PM, Daniel van Vugt
<email address hidden> wrote:
> Review: Needs Fixing
>
> Confirmed moving windows is much improved. There is no improvement with resizing though. I still encounter exactly the same freezes as mentioned previously:
> 1. XSync() inside PrivateWindow::updateRegion()
> 2. XShapeGetRectangles()
> So please either:
> (a) Don't touch XShape* in this proposal, and leave resize fixes for a later proposal; or
> (b) Fix XShape* properly.
> Given the large size of this proposal already, and that a proper fix for XShape should be to simply call it much less often (i.e. only for shaped windows), I recommend (a).

Ah, we actually need to touch it otherwise this proposal won't work
without it, though its not a very big touch, and more or less just a
wrapper around it to make sure that when it is called, we release the
geometry queue for that window.

The reason for that being that XShapeGetRectangles is dependent on us
having the most recent server size of the window actually posted to
the server by that point. If it isn't, then you'll get the wrong
client shape, and that will be incorrectly applied to the frame!

>
> Secondly, I do support the concept of disabling lazy positioning in theory but would have to get my test machine (Atom) for that upgraded and working again before I approve it.
>
> --
> https://code.launchpad.net/~compiz-team/compiz/compiz.performance_1027211.2/+merge/138800
> Your team Compiz Maintainers is subscribed to branch lp:compiz.

--
Sam Spilsbury

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

On Mon, Dec 10, 2012 at 2:41 PM, Daniel van Vugt
<email address hidden> wrote:
> Also, without too much verbosity, why is it we need to implement window movement completely synchronously? My understanding is that waiting and locking should never be required when the user moves a window.
>
> A window move should simply involve two events:
> 1. Motion event -> move plugin -> send request to X server (XConfigureWindow I think).
> and some time later (should not care when):
> 2. XConfigureNotify (or whatever) -> core plugin -> compiz window position updated.
>
> I mean; my understanding of lazy positioning is that we update the compiz position without waiting for the server to tell us it's done. Therefore the above method counts as non-lazy movement, but also does not require any waiting or locking. I think this is contrary to the proposed and established non-lazy algorithm that does sync for some reason.
>
> If we want to keep lazy mode as an option and it does bypass the server as I suspect then OK. However I think at least non-lazy mode should be implemented as above, so that either way you never need to lock or sync to move a window.

Ah, I think there's a mixup of terminology here.

We're still completely async, both this branch and before this branch.
ConfigureWindow requests are in themselves async, you can post as many
as you want. There's absolutely no waiting for the server.

The problem is that the nvidia driver can't handle it. So instead of
sending it lots and lots of ConfigureWindow requests, we let plugins
"lock out" core from doing that until it makes sense for us to do it.
This means that:

1. In the case of "lazy positioning" being disabled, we just wait
until just before the next frame and post the request
2. In the case of "lazy positioning" enabled, we wait until the window
is ungrabbed.

Both are overridden in cases where we have to ask the server
something. But that's not too often.

> --
> https://code.launchpad.net/~compiz-team/compiz/compiz.performance_1027211.2/+merge/138800
> Your team Compiz Maintainers is subscribed to branch lp:compiz.

--
Sam Spilsbury

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

It will take me a while to get the code compiled 32-bit and running on the Atom where I tested all the previous lazy-mode regressions. Until then, some style issues:

1. This is hard to read. I recommend (but don't require) all on one line...
48 +namespace compiz
49 +{
50 +namespace window
51 +{
52 +namespace configure_buffers
53 +{

2. MOVE_WINDOW (w) - Using macros to declare local variables via side-effect is dangerous and very hard to understand if you're new to compiz. I suggest not doing this in future code. Instead use an explicit:
    MoveWindow *mw = MoveWindow::get(w);

3. From a high-level perspective, even if the implementation turns out to be right then I think maybe more analysis was required. This fix is an example of where the medicine could be worse than the disease. It's only useful to nvidia because nvidia is buggy IMHO. And the price to pay is more abstraction and complication that hinders maintainability of the code. We might be better off not trying to "fix" window movement any further. Though resizing needs work still.

review: Needs Fixing
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

OK, verified window movement is absolutely perfect on the Atom with this change. So no non-lazy-mode regression to worry about.

Just need (want) to reconsider the style issues and the philosophical point above.

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

FYI, window resizing on the Atom (i915) freezes just like with Nvidia so that's another good test platform.

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

> It will take me a while to get the code compiled 32-bit and running on the
> Atom where I tested all the previous lazy-mode regressions. Until then, some
> style issues:
>
> 1. This is hard to read. I recommend (but don't require) all on one line...
> 48 +namespace compiz
> 49 +{
> 50 +namespace window
> 51 +{
> 52 +namespace configure_buffers
> 53 +{
>
> 2. MOVE_WINDOW (w) - Using macros to declare local variables via side-effect
> is dangerous and very hard to understand if you're new to compiz. I suggest
> not doing this in future code. Instead use an explicit:
> MoveWindow *mw = MoveWindow::get(w);

+1

>
> 3. From a high-level perspective, even if the implementation turns out to be
> right then I think maybe more analysis was required. This fix is an example of
> where the medicine could be worse than the disease. It's only useful to nvidia
> because nvidia is buggy IMHO. And the price to pay is more abstraction and
> complication that hinders maintainability of the code. We might be better off
> not trying to "fix" window movement any further. Though resizing needs work
> still.

It is a little more abstract and complex, yes, however having an unusable system on nvidia is not an acceptable alternative either.

I don't think the code is "unmaintainable", I think it just works in a way that is a tad more complex and different to the way that you would expect. Its fully tested and encapsulated from the other code, so future maintainers don't need to worry about inadvertently breaking it (except for their usage of the client hooks).

In addition, if there are any problems you can just "turn it off" - just don't take a lock on the configure request queue in the opengl plugin.

Speaking of medicine worse than the disease, you just named one of my favourite pieces of music :P (http://www.youtube.com/watch?v=htGmTJNsOr0)

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

>
> +1
>
> >
> > 3. From a high-level perspective, even if the implementation turns out to be
> > right then I think maybe more analysis was required. This fix is an example
> of
> > where the medicine could be worse than the disease. It's only useful to
> nvidia
> > because nvidia is buggy IMHO. And the price to pay is more abstraction and
> > complication that hinders maintainability of the code. We might be better
> off
> > not trying to "fix" window movement any further. Though resizing needs work
> > still.
>
> It is a little more abstract and complex, yes, however having an unusable
> system on nvidia is not an acceptable alternative either.
>
> I don't think the code is "unmaintainable", I think it just works in a way
> that is a tad more complex and different to the way that you would expect. Its
> fully tested and encapsulated from the other code, so future maintainers don't
> need to worry about inadvertently breaking it (except for their usage of the
> client hooks).
>

On the same note.

Over my many years of developing compiz, I've often found that the little quirks between drivers, opengl, the way the xserver works, the way specs are implemented etc often means the issues aren't that simple, so its means that the implementation is almost never going to be simple.

If you have a look at any window manager, they are often large and complicated beasts, doing lots of things that you wouldn't even expect a window manager to have to do.

However, window managers often start small and grow to accomadate the quirks in their surrounding environment. The best approach, in my opinion, is to encapsulate complexity into clearly defined areas of the code, so that your handing of corner cases doesn't pollute your main buisness logic or get tangled in-between it. While doing that, ensure that the corner cases are tested codepaths that future maintainers can rely upon the tests when making changes.

This is something that I think compiz really succeeds at. While our test coverage is pretty absymal at best, no other non-niche window manager I can think of is as well tested as compiz is. And its starting to pay off - I've been able to rely on the test suite alone for making some changes now, which is something that I was never able to do.

That being said, I think you're right into looking into any more workarounds for the nvidia problems with ConfigureWindow requests and simultaneous redirected GL. We've found the main cause and root of the problem now, so lets stick with this implementation and work on other things. Window movement is 60FPS here with this applied, so I doubt we can make it any faster :)

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

OK, forget the style issues. I don't want to spend any more hours on testing more revisions.

review: Approve
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Sorry, I had to revert this merge in r3528. It caused too many regressions. See bug 1089279.

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

Ah, I thought there might be some regressions.

Thanks, I'll get on to it.

On Thu, Dec 13, 2012 at 4:50 PM, Daniel van Vugt
<email address hidden> wrote:
> Review: Needs Fixing
>
>
> --
> https://code.launchpad.net/~compiz-team/compiz/compiz.performance_1027211.2/+merge/138800
> Your team Compiz Maintainers is subscribed to branch lp:compiz.

--
Sam Spilsbury

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

I've fixed (LP: #1089279) by forcing any changes to the size of the window to release the queue immediately. Also to be on the safe side, I've made it so that changes to clients or the wrapper window release the queue immediately. We can have a look into those a bit later.

I can understand if you don't want to merge this for this year and wait until later until we have more testing. I've been setting up a ppa with a bunch of performance related things at ppa:smspillaz/compiz-experimental .

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
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

Somehow this was merged. It shouldn't have been, see https://lists.launchpad.net/unity-dev/msg00597.html

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
MC Return (mc-return) wrote : Posted in a previous version of this proposal

Tested this. Moved around and resized windows. Could not spot any obvious regressions.
+1

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
3559. By Sam Spilsbury

Merge lp:compiz

3560. By Sam Spilsbury

The Find* modules might go inside the xorg-gtest build process before we get a chance to set COMPIZ_INTERNAL_INCLUDES, set it first

3561. By Sam Spilsbury

Specify whether or not the plugin should be installed

3562. By Sam Spilsbury

NOINSTALL is not a library

3563. By Sam Spilsbury

Minor indent fix

3564. By Sam Spilsbury

Also ensure we don't install any schemas, metadata, data, images etc

3565. By Sam Spilsbury

s/plugin/COMPIZ_CURRENT_PLUGIN/

3566. By Sam Spilsbury

Merge lp:compiz

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2013-02-15 11:28:27 +0000
3+++ CMakeLists.txt 2013-02-19 15:13:21 +0000
4@@ -179,6 +179,22 @@
5
6 endif (COMPIZ_BUILD_TESTING)
7
8+set (COMPIZ_INTERNAL_INCLUDES
9+ ${CMAKE_CURRENT_SOURCE_DIR}/include
10+ ${CMAKE_CURRENT_SOURCE_DIR}/src
11+ ${CMAKE_CURRENT_SOURCE_DIR}/src/timer/include
12+ ${CMAKE_CURRENT_SOURCE_DIR}/src/string/include
13+ ${CMAKE_CURRENT_SOURCE_DIR}/src/pluginclasshandler/include
14+ ${CMAKE_CURRENT_SOURCE_DIR}/src/point/include
15+ ${CMAKE_CURRENT_SOURCE_DIR}/src/rect/include
16+ ${CMAKE_CURRENT_SOURCE_DIR}/src/servergrab/include
17+ ${CMAKE_CURRENT_SOURCE_DIR}/src/region/include
18+ ${CMAKE_CURRENT_SOURCE_DIR}/src/window/geometry/include
19+ ${CMAKE_CURRENT_SOURCE_DIR}/src/window/geometry-saver/include
20+ ${CMAKE_CURRENT_SOURCE_DIR}/src/window/extents/include
21+ ${CMAKE_CURRENT_SOURCE_DIR}/src/window/constrainment/include
22+ ${CMAKE_CURRENT_SOURCE_DIR}/src/logmessage/include)
23+
24 # Add the rest of compiz
25 add_subdirectory (cmake)
26 add_subdirectory (include)
27
28=== modified file 'include/core/CMakeLists.txt'
29--- include/core/CMakeLists.txt 2012-12-13 10:12:23 +0000
30+++ include/core/CMakeLists.txt 2013-02-19 15:13:21 +0000
31@@ -1,6 +1,7 @@
32 set (_headers
33 action.h
34 atoms.h
35+ configurerequestbuffer.h
36 core.h
37 countedlist.h
38 global.h
39
40=== added file 'include/core/configurerequestbuffer.h'
41--- include/core/configurerequestbuffer.h 1970-01-01 00:00:00 +0000
42+++ include/core/configurerequestbuffer.h 2013-02-19 15:13:21 +0000
43@@ -0,0 +1,73 @@
44+/*
45+ * Copyright © 2012 Sam Spilsbury
46+ *
47+ * Permission to use, copy, modify, distribute, and sell this software
48+ * and its documentation for any purpose is hereby granted without
49+ * fee, provided that the above copyright notice appear in all copies
50+ * and that both that copyright notice and this permission notice
51+ * appear in supporting documentation, and that the name of
52+ * Canonical Ltd. not be used in advertising or publicity pertaining to
53+ * distribution of the software without specific, written prior permission.
54+ * Canonical Ltd. makes no representations about the suitability of this
55+ * software for any purpose. It is provided "as is" without express or
56+ * implied warranty.
57+ *
58+ * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
59+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
60+ * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
61+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
62+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
63+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
64+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
65+ *
66+ * Authored by: Sam Spilsbury <smspillaz@gmail.com>
67+ */
68+#ifndef _COMPIZ_CONFIGURE_REQUEST_BUFFER_H
69+#define _COMPIZ_CONFIGURE_REQUEST_BUFFER_H
70+
71+#include <boost/shared_ptr.hpp>
72+#include <X11/Xlib.h>
73+#include <syncserverwindow.h>
74+
75+namespace compiz
76+{
77+namespace window
78+{
79+namespace configure_buffers
80+{
81+class Releasable
82+{
83+ public:
84+
85+ typedef boost::shared_ptr <Releasable> Ptr;
86+
87+ virtual void release () = 0;
88+};
89+
90+class Buffer :
91+ public SyncServerWindow
92+{
93+ public:
94+
95+ typedef boost::shared_ptr <Buffer> Ptr;
96+
97+ virtual ~Buffer () {}
98+
99+ virtual void pushClientRequest (const XWindowChanges &xwc, unsigned int mask) = 0;
100+ virtual void pushWrapperRequest (const XWindowChanges &xwc, unsigned int mask) = 0;
101+ virtual void pushFrameRequest (const XWindowChanges &xwc, unsigned int mask) = 0;
102+
103+ virtual void pushSyntheticConfigureNotify () = 0;
104+
105+ virtual Releasable::Ptr obtainLock () = 0;
106+
107+ /* This API will all configure requests to be
108+ * released. It should only be used in situations
109+ * where you have a server grab and need
110+ * to have complete sync with the server */
111+ virtual void forceRelease () = 0;
112+};
113+}
114+}
115+}
116+#endif
117
118=== modified file 'include/core/window.h'
119--- include/core/window.h 2013-01-03 16:06:41 +0000
120+++ include/core/window.h 2013-02-19 15:13:21 +0000
121@@ -54,13 +54,26 @@
122 class PrivateWindow;
123 struct CompStartupSequence;
124
125-namespace compiz { namespace private_screen {
126- class Ping;
127- class GrabManager;
128- class OutputDevices;
129- class WindowManager;
130- class StartupSequence;
131-}}
132+namespace compiz
133+{
134+namespace window
135+{
136+namespace configure_buffers
137+{
138+class Releasable;
139+typedef boost::shared_ptr <Releasable> ReleasablePtr;
140+}
141+}
142+
143+namespace private_screen
144+{
145+class Ping;
146+class GrabManager;
147+class OutputDevices;
148+class WindowManager;
149+class StartupSequence;
150+}
151+}
152
153 #define ROOTPARENT(x) (((x)->frame ()) ? (x)->frame () : (x)->id ())
154
155@@ -529,6 +542,12 @@
156 bool updateStruts ();
157 const CompStruts *struts () const;
158
159+ bool queryAttributes (XWindowAttributes &);
160+ bool queryFrameAttributes (XWindowAttributes &);
161+
162+ compiz::window::configure_buffers::ReleasablePtr
163+ obtainLockOnConfigureRequests ();
164+
165 WRAPABLE_HND (0, WindowInterface, void, getOutputExtents,
166 CompWindowExtents&);
167 WRAPABLE_HND (1, WindowInterface, void, getAllowedActions,
168
169=== modified file 'plugins/CMakeLists.txt'
170--- plugins/CMakeLists.txt 2013-02-12 02:43:44 +0000
171+++ plugins/CMakeLists.txt 2013-02-19 15:13:21 +0000
172@@ -7,23 +7,7 @@
173
174 add_definitions ( -DHAVE_CONFIG_H)
175
176-include_directories(
177- ${CMAKE_CURRENT_SOURCE_DIR}/../include
178-
179- ${CMAKE_CURRENT_SOURCE_DIR}/../src
180- ${CMAKE_CURRENT_SOURCE_DIR}/../src/timer/include
181- ${CMAKE_CURRENT_SOURCE_DIR}/../src/string/include
182- ${CMAKE_CURRENT_SOURCE_DIR}/../src/pluginclasshandler/include
183- ${CMAKE_CURRENT_SOURCE_DIR}/../src/point/include
184- ${CMAKE_CURRENT_SOURCE_DIR}/../src/rect/include
185- ${CMAKE_CURRENT_SOURCE_DIR}/../src/servergrab/include
186- ${CMAKE_CURRENT_SOURCE_DIR}/../src/region/include
187- ${CMAKE_CURRENT_SOURCE_DIR}/../src/window/geometry/include
188- ${CMAKE_CURRENT_SOURCE_DIR}/../src/window/geometry-saver/include
189- ${CMAKE_CURRENT_SOURCE_DIR}/../src/window/extents/include
190- ${CMAKE_CURRENT_SOURCE_DIR}/../src/window/constrainment/include
191- ${CMAKE_CURRENT_SOURCE_DIR}/../logmessage/include
192-)
193+include_directories (${COMPIZ_INTERNAL_INCLUDES})
194
195 # temporarily disable plugins that aren't ported yet
196 set (COMPIZ_DISABLE_PLUGIN_ANIMATIONADDON ON)
197
198=== modified file 'plugins/composite/src/window.cpp'
199--- plugins/composite/src/window.cpp 2012-12-13 10:12:23 +0000
200+++ plugins/composite/src/window.cpp 2013-02-19 15:13:21 +0000
201@@ -181,11 +181,7 @@
202 bool
203 PrivateCompositeWindow::getAttributes (XWindowAttributes &attr)
204 {
205- if (XGetWindowAttributes (screen->dpy (),
206- ROOTPARENT (window), &attr))
207- return true;
208-
209- return false;
210+ return window->queryFrameAttributes (attr);
211 }
212
213 bool
214
215=== modified file 'plugins/move/move.xml.in'
216--- plugins/move/move.xml.in 2012-12-13 10:12:23 +0000
217+++ plugins/move/move.xml.in 2013-02-19 15:13:21 +0000
218@@ -42,7 +42,7 @@
219 <option name="lazy_positioning" type="bool">
220 <_short>Lazy Positioning</_short>
221 <_long>Do not update the server-side position of windows until finished moving</_long>
222- <default>true</default>
223+ <default>false</default>
224 </option>
225 </options>
226 </plugin>
227
228=== modified file 'plugins/move/src/move.cpp'
229--- plugins/move/src/move.cpp 2012-12-13 10:12:23 +0000
230+++ plugins/move/src/move.cpp 2013-02-19 15:13:21 +0000
231@@ -158,6 +158,14 @@
232 if (mw->gWindow)
233 mw->gWindow->glPaintSetEnabled (mw, true);
234 }
235+
236+ if (ms->optionGetLazyPositioning ())
237+ {
238+ MOVE_WINDOW (w);
239+
240+ if (mw->gWindow)
241+ mw->releasable = w->obtainLockOnConfigureRequests ();
242+ }
243 }
244 }
245
246@@ -173,6 +181,8 @@
247
248 if (ms->w)
249 {
250+ MOVE_WINDOW (ms->w);
251+
252 if (state & CompAction::StateCancel)
253 ms->w->move (ms->savedX - ms->w->geometry ().x (),
254 ms->savedY - ms->w->geometry ().y (), false);
255@@ -194,14 +204,14 @@
256
257 if (ms->moveOpacity != OPAQUE)
258 {
259- MOVE_WINDOW (ms->w);
260-
261 if (mw->cWindow)
262 mw->cWindow->addDamage ();
263 if (mw->gWindow)
264 mw->gWindow->glPaintSetEnabled (mw, false);
265 }
266
267+ mw->releasable.reset ();
268+
269 ms->w = 0;
270 ms->releaseButton = 0;
271 }
272@@ -489,9 +499,6 @@
273 w->move (wX + dx - w->geometry ().x (),
274 wY + dy - w->geometry ().y (), false);
275
276- if (!ms->optionGetLazyPositioning ())
277- w->syncPosition ();
278-
279 ms->x -= dx;
280 ms->y -= dy;
281 }
282
283=== modified file 'plugins/move/src/move.h'
284--- plugins/move/src/move.h 2012-12-13 10:12:23 +0000
285+++ plugins/move/src/move.h 2013-02-19 15:13:21 +0000
286@@ -27,6 +27,7 @@
287
288 #include <core/screen.h>
289 #include <core/pluginclasshandler.h>
290+#include <core/configurerequestbuffer.h>
291
292 #include <composite/composite.h>
293 #include <opengl/opengl.h>
294@@ -117,6 +118,7 @@
295 CompWindow *window;
296 GLWindow *gWindow;
297 CompositeWindow *cWindow;
298+ compiz::window::configure_buffers::Releasable::Ptr releasable;
299 };
300
301 #define MOVE_SCREEN(s) \
302
303=== modified file 'plugins/opengl/src/paint.cpp'
304--- plugins/opengl/src/paint.cpp 2013-01-01 10:04:50 +0000
305+++ plugins/opengl/src/paint.cpp 2013-02-19 15:13:21 +0000
306@@ -418,6 +418,11 @@
307 if (w->destroyed ())
308 continue;
309
310+ gw = GLWindow::get (w);
311+
312+ /* Release any queued ConfigureWindow requests now */
313+ gw->priv->configureLock->release ();
314+
315 if (unredirected.find (w) != unredirected.end ())
316 continue;
317
318@@ -427,8 +432,6 @@
319 continue;
320 }
321
322- gw = GLWindow::get (w);
323-
324 const CompRegion &clip =
325 (!(mask & PAINT_SCREEN_NO_OCCLUSION_DETECTION_MASK)) ?
326 gw->clip () : region;
327
328=== modified file 'plugins/opengl/src/privates.h'
329--- plugins/opengl/src/privates.h 2013-01-01 09:41:41 +0000
330+++ plugins/opengl/src/privates.h 2013-02-19 15:13:21 +0000
331@@ -33,6 +33,7 @@
332 #include <composite/composite.h>
333 #include <opengl/opengl.h>
334 #include <core/atoms.h>
335+#include <core/configurerequestbuffer.h>
336
337 #ifdef USE_GLES
338 #include <opengl/framebufferobject.h>
339@@ -283,6 +284,8 @@
340 GLVertexBuffer::AutoProgram *autoProgram;
341
342 std::list<GLIcon> icons;
343+
344+ compiz::window::configure_buffers::Releasable::Ptr configureLock;
345 };
346
347 #endif
348
349=== modified file 'plugins/opengl/src/window.cpp'
350--- plugins/opengl/src/window.cpp 2012-12-13 10:12:23 +0000
351+++ plugins/opengl/src/window.cpp 2013-02-19 15:13:21 +0000
352@@ -86,7 +86,8 @@
353 bindFailed (false),
354 vertexBuffer (new GLVertexBuffer ()),
355 autoProgram(new GLWindowAutoProgram(this)),
356- icons ()
357+ icons (),
358+ configureLock (w->obtainLockOnConfigureRequests ())
359 {
360 paint.xScale = 1.0f;
361 paint.yScale = 1.0f;
362
363=== modified file 'src/CMakeLists.txt'
364--- src/CMakeLists.txt 2012-12-13 10:12:23 +0000
365+++ src/CMakeLists.txt 2013-02-19 15:13:21 +0000
366@@ -160,6 +160,12 @@
367 compiz_window_geometry
368 )
369
370+add_library (compiz_configurerequestbuffer STATIC
371+ configurerequestbuffer.cpp)
372+
373+target_link_libraries (compiz_configurerequestbuffer
374+ compiz_window_geometry)
375+
376 # workaround for build race
377 add_dependencies (compiz core-xml-file)
378
379@@ -192,6 +198,7 @@
380 compiz_servergrab
381 compiz_output
382 compiz_outputdevices
383+ compiz_configurerequestbuffer
384 -Wl,-no-whole-archive
385 # ${CORE_MOD_LIBRARIES}
386 )
387
388=== added file 'src/asyncserverwindow.h'
389--- src/asyncserverwindow.h 1970-01-01 00:00:00 +0000
390+++ src/asyncserverwindow.h 2013-02-19 15:13:21 +0000
391@@ -0,0 +1,52 @@
392+/*
393+ * Copyright © 2012 Sam Spilsbury
394+ *
395+ * Permission to use, copy, modify, distribute, and sell this software
396+ * and its documentation for any purpose is hereby granted without
397+ * fee, provided that the above copyright notice appear in all copies
398+ * and that both that copyright notice and this permission notice
399+ * appear in supporting documentation, and that the name of
400+ * Canonical Ltd. not be used in advertising or publicity pertaining to
401+ * distribution of the software without specific, written prior permission.
402+ * Canonical Ltd. makes no representations about the suitability of this
403+ * software for any purpose. It is provided "as is" without express or
404+ * implied warranty.
405+ *
406+ * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
407+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
408+ * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
409+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
410+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
411+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
412+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
413+ *
414+ * Authored by: Sam Spilsbury <smspillaz@gmail.com>
415+ */
416+#ifndef _COMPIZ_ASYNC_SERVER_WINDOW_H
417+#define _COMPIZ_ASYNC_SERVER_WINDOW_H
418+
419+#include <X11/Xlib.h>
420+
421+namespace compiz
422+{
423+namespace window
424+{
425+class AsyncServerWindow
426+{
427+ public:
428+
429+ virtual ~AsyncServerWindow () {};
430+
431+ virtual int requestConfigureOnClient (const XWindowChanges &xwc,
432+ unsigned int valueMask) = 0;
433+ virtual int requestConfigureOnWrapper (const XWindowChanges &xwc,
434+ unsigned int valueMask) = 0;
435+ virtual int requestConfigureOnFrame (const XWindowChanges &xwc,
436+ unsigned int valueMask) = 0;
437+ virtual void sendSyntheticConfigureNotify () = 0;
438+ virtual bool hasCustomShape () const = 0;
439+};
440+}
441+}
442+
443+#endif
444
445=== added file 'src/configurerequestbuffer-impl.h'
446--- src/configurerequestbuffer-impl.h 1970-01-01 00:00:00 +0000
447+++ src/configurerequestbuffer-impl.h 2013-02-19 15:13:21 +0000
448@@ -0,0 +1,145 @@
449+/*
450+ * Copyright © 2012 Sam Spilsbury
451+ *
452+ * Permission to use, copy, modify, distribute, and sell this software
453+ * and its documentation for any purpose is hereby granted without
454+ * fee, provided that the above copyright notice appear in all copies
455+ * and that both that copyright notice and this permission notice
456+ * appear in supporting documentation, and that the name of
457+ * Canonical Ltd. not be used in advertising or publicity pertaining to
458+ * distribution of the software without specific, written prior permission.
459+ * Canonical Ltd. makes no representations about the suitability of this
460+ * software for any purpose. It is provided "as is" without express or
461+ * implied warranty.
462+ *
463+ * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
464+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
465+ * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
466+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
467+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
468+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
469+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
470+ *
471+ * Authored by: Sam Spilsbury <smspillaz@gmail.com>
472+ */
473+#ifndef _COMPIZ_GEOMETRY_UPDATE_QUEUE_H
474+#define _COMPIZ_GEOMETRY_UPDATE_QUEUE_H
475+
476+#include <memory>
477+#include <vector>
478+#include <boost/weak_ptr.hpp>
479+#include <boost/shared_ptr.hpp>
480+#include <boost/function.hpp>
481+#include <X11/Xlib.h>
482+
483+#include <core/configurerequestbuffer.h>
484+
485+namespace compiz
486+{
487+namespace window
488+{
489+class AsyncServerWindow;
490+namespace configure_buffers
491+{
492+
493+class Lockable
494+{
495+ public:
496+
497+ typedef boost::shared_ptr <Lockable> Ptr;
498+ typedef boost::weak_ptr <Lockable> Weak;
499+
500+ virtual ~Lockable () {}
501+
502+ virtual void lock () = 0;
503+};
504+
505+class BufferLock :
506+ public Lockable,
507+ public Releasable
508+{
509+ public:
510+ typedef boost::shared_ptr <BufferLock> Ptr;
511+
512+ virtual ~BufferLock () {}
513+};
514+
515+class CountedFreeze
516+{
517+ public:
518+
519+ virtual ~CountedFreeze () {}
520+
521+ virtual void freeze () = 0;
522+ virtual void release () = 0;
523+
524+ virtual void untrackLock (compiz::window::configure_buffers::BufferLock *lock) = 0;
525+};
526+
527+class ConfigureRequestBuffer :
528+ public CountedFreeze,
529+ public Buffer
530+{
531+ public:
532+
533+ typedef boost::function <BufferLock::Ptr (CountedFreeze *)> LockFactory;
534+
535+ void freeze ();
536+ void release ();
537+
538+ void untrackLock (compiz::window::configure_buffers::BufferLock *lock);
539+
540+ void pushClientRequest (const XWindowChanges &xwc, unsigned int mask);
541+ void pushWrapperRequest (const XWindowChanges &xwc, unsigned int mask);
542+ void pushFrameRequest (const XWindowChanges &xwc, unsigned int mask);
543+ void pushSyntheticConfigureNotify ();
544+ compiz::window::configure_buffers::Releasable::Ptr obtainLock ();
545+
546+ /* Implement getAttributes and require that
547+ * the queue is released before calling through
548+ * to the SyncServerWindow */
549+ bool queryAttributes (XWindowAttributes &attrib);
550+ bool queryFrameAttributes (XWindowAttributes &attrib);
551+ XRectangle * queryShapeRectangles (int kind,
552+ int *count,
553+ int *ordering);
554+
555+ void forceRelease ();
556+
557+ static compiz::window::configure_buffers::Buffer::Ptr
558+ Create (AsyncServerWindow *asyncServerWindow,
559+ SyncServerWindow *syncServerWindow,
560+ const LockFactory &factory);
561+
562+ private:
563+
564+ ConfigureRequestBuffer (AsyncServerWindow *asyncServerWindow,
565+ SyncServerWindow *syncServerWindow,
566+ const LockFactory &factory);
567+
568+ class Private;
569+ std::auto_ptr <Private> priv;
570+};
571+
572+class ConfigureBufferLock :
573+ public compiz::window::configure_buffers::BufferLock
574+{
575+ public:
576+
577+ typedef boost::shared_ptr <ConfigureBufferLock> Ptr;
578+
579+ ConfigureBufferLock (CountedFreeze *);
580+ ~ConfigureBufferLock ();
581+
582+ void lock ();
583+ void release ();
584+
585+ private:
586+
587+ class Private;
588+ std::auto_ptr <Private> priv;
589+};
590+}
591+}
592+}
593+#endif
594
595=== added file 'src/configurerequestbuffer.cpp'
596--- src/configurerequestbuffer.cpp 1970-01-01 00:00:00 +0000
597+++ src/configurerequestbuffer.cpp 2013-02-19 15:13:21 +0000
598@@ -0,0 +1,363 @@
599+/*
600+ * Copyright © 2012 Sam Spilsbury
601+ *
602+ * Permission to use, copy, modify, distribute, and sell this software
603+ * and its documentation for any purpose is hereby granted without
604+ * fee, provided that the above copyright notice appear in all copies
605+ * and that both that copyright notice and this permission notice
606+ * appear in supporting documentation, and that the name of
607+ * Canonical Ltd. not be used in advertising or publicity pertaining to
608+ * distribution of the software without specific, written prior permission.
609+ * Canonical Ltd. makes no representations about the suitability of this
610+ * software for any purpose. It is provided "as is" without express or
611+ * implied warranty.
612+ *
613+ * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
614+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
615+ * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
616+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
617+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
618+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
619+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
620+ *
621+ * Authored by: Sam Spilsbury <smspillaz@gmail.com>
622+ */
623+#include <cstdio>
624+#include <cassert>
625+#include <boost/foreach.hpp>
626+#include <boost/weak_ptr.hpp>
627+#include <boost/bind.hpp>
628+#include "asyncserverwindow.h"
629+#include "configurerequestbuffer-impl.h"
630+
631+#ifndef foreach
632+#define foreach BOOST_FOREACH
633+#endif
634+
635+namespace crb = compiz::window::configure_buffers;
636+namespace cw = compiz::window;
637+
638+class crb::ConfigureRequestBuffer::Private
639+{
640+ public:
641+
642+ typedef crb::Lockable::Weak LockObserver;
643+
644+ Private (cw::AsyncServerWindow *asyncServerWindow,
645+ cw::SyncServerWindow *syncServerWindow,
646+ const crb::ConfigureRequestBuffer::LockFactory &lockFactory) :
647+ clientChangeMask (0),
648+ wrapperChangeMask (0),
649+ frameChangeMask (0),
650+ sendSyntheticConfigure (false),
651+ lockCount (0),
652+ asyncServerWindow (asyncServerWindow),
653+ syncServerWindow (syncServerWindow),
654+ lockFactory (lockFactory)
655+ {
656+ }
657+
658+ void dispatchConfigure (bool force = false);
659+
660+ XWindowChanges clientChanges;
661+ unsigned int clientChangeMask;
662+
663+ XWindowChanges wrapperChanges;
664+ unsigned int wrapperChangeMask;
665+
666+ XWindowChanges frameChanges;
667+ unsigned int frameChangeMask;
668+
669+ bool sendSyntheticConfigure;
670+
671+ unsigned int lockCount;
672+
673+ cw::AsyncServerWindow *asyncServerWindow;
674+ cw::SyncServerWindow *syncServerWindow;
675+
676+ crb::ConfigureRequestBuffer::LockFactory lockFactory;
677+ std::vector <LockObserver> locks;
678+};
679+
680+void
681+crb::ConfigureRequestBuffer::Private::dispatchConfigure (bool force)
682+{
683+ const unsigned int allEventMasks = 0x7f;
684+ bool immediate = frameChangeMask & (CWStackMode | CWSibling);
685+
686+ /* This is a stop-gap solution for not having a plugin API to
687+ * query the window shape. Once we have that, we can safely
688+ * remove these and require the queue to be unlocked when that
689+ * happens. Its a separate unit of work for improving resize
690+ * performance anyways.
691+ */
692+ immediate |= (frameChangeMask & (CWWidth | CWHeight | CWBorderWidth));
693+ immediate |= (wrapperChangeMask & (CWWidth | CWHeight | CWBorderWidth | CWX | CWY));
694+ immediate |= (clientChangeMask & (CWWidth | CWHeight | CWBorderWidth | CWX | CWY));
695+ immediate |= force;
696+
697+ bool clientDispatch = (clientChangeMask & allEventMasks);
698+ bool wrapperDispatch = (wrapperChangeMask & allEventMasks);
699+ bool frameDispatch = (frameChangeMask & allEventMasks);
700+
701+ bool dispatch = !lockCount && (clientDispatch ||
702+ wrapperDispatch ||
703+ frameDispatch ||
704+ sendSyntheticConfigure);
705+
706+ if (dispatch || immediate)
707+ {
708+ if (frameDispatch)
709+ {
710+ asyncServerWindow->requestConfigureOnFrame (frameChanges,
711+ frameChangeMask);
712+ frameChangeMask = 0;
713+ }
714+
715+ if (wrapperDispatch)
716+ {
717+ asyncServerWindow->requestConfigureOnWrapper (wrapperChanges,
718+ wrapperChangeMask);
719+ wrapperChangeMask = 0;
720+ }
721+
722+ if (clientDispatch)
723+ {
724+ asyncServerWindow->requestConfigureOnClient (clientChanges,
725+ clientChangeMask);
726+ clientChangeMask = 0;
727+ }
728+
729+ if (sendSyntheticConfigure)
730+ {
731+ asyncServerWindow->sendSyntheticConfigureNotify ();
732+ sendSyntheticConfigure = false;
733+ }
734+
735+ foreach (const LockObserver &lock, locks)
736+ {
737+ crb::Lockable::Ptr strongLock (lock.lock ());
738+
739+ /* We might be in a lock's destructor so check
740+ * if this can really be re-locked, if not, its
741+ * no big deal as the lock is going away anyways
742+ */
743+ if (strongLock)
744+ strongLock->lock ();
745+ }
746+ }
747+}
748+
749+void
750+crb::ConfigureRequestBuffer::freeze ()
751+{
752+ priv->lockCount++;
753+
754+ assert (priv->lockCount <= priv->locks.size ());
755+}
756+
757+void
758+crb::ConfigureRequestBuffer::release ()
759+{
760+ assert (priv->lockCount);
761+
762+ priv->lockCount--;
763+
764+ priv->dispatchConfigure ();
765+}
766+
767+namespace
768+{
769+void applyChangeToXWC (const XWindowChanges &from,
770+ XWindowChanges &to,
771+ unsigned int mask)
772+{
773+ if (mask & CWX)
774+ to.x = from.x;
775+
776+ if (mask & CWY)
777+ to.y = from.y;
778+
779+ if (mask & CWWidth)
780+ to.width = from.width;
781+
782+ if (mask & CWHeight)
783+ to.height = from.height;
784+
785+ if (mask & CWBorderWidth)
786+ to.border_width = from.border_width;
787+
788+ if (mask & CWSibling)
789+ to.sibling = from.sibling;
790+
791+ if (mask & CWStackMode)
792+ to.stack_mode = from.stack_mode;
793+}
794+}
795+
796+void
797+crb::ConfigureRequestBuffer::pushClientRequest (const XWindowChanges &xwc,
798+ unsigned int mask)
799+{
800+ applyChangeToXWC (xwc, priv->clientChanges, mask);
801+ priv->clientChangeMask |= mask;
802+
803+ priv->dispatchConfigure ();
804+}
805+
806+void
807+crb::ConfigureRequestBuffer::pushWrapperRequest (const XWindowChanges &xwc,
808+ unsigned int mask)
809+{
810+ applyChangeToXWC (xwc, priv->wrapperChanges, mask);
811+ priv->wrapperChangeMask |= mask;
812+
813+ priv->dispatchConfigure ();
814+}
815+
816+void
817+crb::ConfigureRequestBuffer::pushFrameRequest (const XWindowChanges &xwc,
818+ unsigned int mask)
819+{
820+ applyChangeToXWC (xwc, priv->frameChanges, mask);
821+ priv->frameChangeMask |= mask;
822+
823+ priv->dispatchConfigure ();
824+}
825+
826+void
827+crb::ConfigureRequestBuffer::pushSyntheticConfigureNotify ()
828+{
829+ priv->sendSyntheticConfigure = true;
830+
831+ priv->dispatchConfigure ();
832+}
833+
834+crb::Releasable::Ptr
835+crb::ConfigureRequestBuffer::obtainLock ()
836+{
837+ crb::BufferLock::Ptr lock (priv->lockFactory (this));
838+
839+ priv->locks.push_back (crb::Lockable::Weak (lock));
840+ lock->lock ();
841+
842+ return lock;
843+}
844+
845+namespace
846+{
847+bool isLock (const crb::Lockable::Weak &lockable,
848+ crb::BufferLock *lock)
849+{
850+ crb::Lockable::Ptr strongLockable (lockable.lock ());
851+
852+ /* Asserting that the lock did not go away without telling
853+ * us first */
854+ assert (strongLockable.get ());
855+
856+ if (strongLockable.get () == lock)
857+ return true;
858+
859+ return false;
860+}
861+}
862+
863+void
864+crb::ConfigureRequestBuffer::untrackLock (crb::BufferLock *lock)
865+{
866+ std::remove_if (priv->locks.begin (),
867+ priv->locks.end (),
868+ boost::bind (isLock, _1, lock));
869+}
870+
871+bool crb::ConfigureRequestBuffer::queryAttributes (XWindowAttributes &attrib)
872+{
873+ priv->dispatchConfigure (true);
874+ return priv->syncServerWindow->queryAttributes (attrib);
875+}
876+
877+bool crb::ConfigureRequestBuffer::queryFrameAttributes (XWindowAttributes &attrib)
878+{
879+ priv->dispatchConfigure (true);
880+ return priv->syncServerWindow->queryFrameAttributes (attrib);
881+}
882+
883+/* This is more or less of a stop-gap for the fact that
884+ * when resizing window we re-query the window shape
885+ * and apply that to the frame. That's a separate unit of
886+ * work and should be dealt with separately. For now, force
887+ * a release of the queue whenever we do that so that
888+ * XShapeGetRectangles doesn't return an unexpected value
889+ */
890+XRectangle *
891+crb::ConfigureRequestBuffer::queryShapeRectangles (int kind,
892+ int *count,
893+ int *ordering)
894+{
895+ priv->dispatchConfigure (true);
896+ return priv->syncServerWindow->queryShapeRectangles (kind, count, ordering);
897+}
898+
899+void crb::ConfigureRequestBuffer::forceRelease ()
900+{
901+ priv->dispatchConfigure (true);
902+}
903+
904+crb::ConfigureRequestBuffer::ConfigureRequestBuffer (AsyncServerWindow *asyncServerWindow,
905+ SyncServerWindow *syncServerWindow,
906+ const crb::ConfigureRequestBuffer::LockFactory &factory) :
907+ priv (new crb::ConfigureRequestBuffer::Private (asyncServerWindow, syncServerWindow, factory))
908+{
909+}
910+
911+compiz::window::configure_buffers::Buffer::Ptr
912+crb::ConfigureRequestBuffer::Create (AsyncServerWindow *asyncServerWindow,
913+ SyncServerWindow *syncServerWindow,
914+ const LockFactory &factory)
915+{
916+ return crb::Buffer::Ptr (new crb::ConfigureRequestBuffer (asyncServerWindow,
917+ syncServerWindow,
918+ factory));
919+}
920+
921+class crb::ConfigureBufferLock::Private
922+{
923+ public:
924+
925+ Private (crb::CountedFreeze *freezable) :
926+ freezable (freezable),
927+ armed (false)
928+ {
929+ }
930+
931+ crb::CountedFreeze *freezable;
932+ bool armed;
933+};
934+
935+crb::ConfigureBufferLock::ConfigureBufferLock (crb::CountedFreeze *freezable) :
936+ priv (new crb::ConfigureBufferLock::Private (freezable))
937+{
938+}
939+
940+crb::ConfigureBufferLock::~ConfigureBufferLock ()
941+{
942+ release ();
943+}
944+
945+void
946+crb::ConfigureBufferLock::lock ()
947+{
948+ if (!priv->armed)
949+ priv->freezable->freeze ();
950+
951+ priv->armed = true;
952+}
953+
954+void
955+crb::ConfigureBufferLock::release ()
956+{
957+ if (priv->armed)
958+ priv->freezable->release ();
959+
960+ priv->armed = false;
961+}
962
963=== modified file 'src/event.cpp'
964--- src/event.cpp 2013-01-03 16:06:41 +0000
965+++ src/event.cpp 2013-02-19 15:13:21 +0000
966@@ -1947,7 +1947,7 @@
967
968 /* We should check the override_redirect flag here, because the
969 client might have changed it while being unmapped. */
970- if (XGetWindowAttributes (privateScreen.dpy, w->id (), &attr))
971+ if (w->queryAttributes (attr))
972 w->priv->setOverrideRedirect (attr.override_redirect != 0);
973
974 if (w->state () & CompWindowStateHiddenMask)
975
976=== modified file 'src/plugin.cpp'
977--- src/plugin.cpp 2013-01-24 14:18:03 +0000
978+++ src/plugin.cpp 2013-02-19 15:13:21 +0000
979@@ -398,6 +398,7 @@
980 CompPlugin *
981 CompPlugin::load (const char *name)
982 {
983+ char *compiz_plugin_dir_override = getenv ("COMPIZ_PLUGIN_DIR");
984 std::auto_ptr<CompPlugin>p(new CompPlugin ());
985
986 p->devPrivate.uval = 0;
987@@ -406,6 +407,12 @@
988
989 compLogMessage (here, CompLogLevelInfo, "Loading plugin: %s", name);
990
991+ if (compiz_plugin_dir_override)
992+ {
993+ if (loaderLoadPlugin (p.get (), compiz_plugin_dir_override, name))
994+ return p.release ();
995+ }
996+
997 if (char* home = getenv ("HOME"))
998 {
999 boost::scoped_array<char> plugindir(new char [strlen (home) + strlen (HOME_PLUGINDIR) + 3]);
1000
1001=== modified file 'src/plugin/tests/CMakeLists.txt'
1002--- src/plugin/tests/CMakeLists.txt 2012-08-01 00:42:38 +0000
1003+++ src/plugin/tests/CMakeLists.txt 2013-02-19 15:13:21 +0000
1004@@ -5,6 +5,7 @@
1005
1006 ${compiz_SOURCE_DIR}/include
1007 ${compiz_SOURCE_DIR}/src
1008+ ${compiz_SOURCE_DIR}/tests/shared
1009 )
1010
1011 add_definitions (
1012
1013=== modified file 'src/plugin/tests/test-plugin.cpp'
1014--- src/plugin/tests/test-plugin.cpp 2012-06-24 09:00:27 +0000
1015+++ src/plugin/tests/test-plugin.cpp 2013-02-19 15:13:21 +0000
1016@@ -9,6 +9,7 @@
1017
1018 #include <gtest/gtest.h>
1019 #include <gmock/gmock.h>
1020+#include <gtest_shared_tmpenv.h>
1021
1022 namespace {
1023
1024@@ -136,6 +137,34 @@
1025 CompPlugin::unload(cp);
1026 }
1027
1028+TEST(PluginTest, load_plugin_from_COMPIZ_PLUGIN_DIR_env_succeeds)
1029+{
1030+ const char *COMPIZ_PLUGIN_DIR_VALUE = "/path/to/plugin/dir";
1031+ TmpEnv env ("COMPIZ_PLUGIN_DIR", COMPIZ_PLUGIN_DIR_VALUE);
1032+ MockPluginFilesystem mockfs;
1033+
1034+ using namespace testing;
1035+
1036+ EXPECT_CALL(mockfs, LoadPlugin(Ne((void*)0), EndsWith(COMPIZ_PLUGIN_DIR_VALUE), StrEq("dummy"))).
1037+ WillOnce(Return(true));
1038+
1039+ EXPECT_CALL(mockfs, LoadPlugin(Ne((void*)0), EndsWith(HOME_PLUGINDIR), StrEq("dummy"))).
1040+ Times(AtMost(0));
1041+
1042+ EXPECT_CALL(mockfs, LoadPlugin(Ne((void*)0), EndsWith(PLUGINDIR), StrEq("dummy"))).
1043+ Times(AtMost(0));
1044+
1045+ EXPECT_CALL(mockfs, LoadPlugin(Ne((void*)0), Eq((void*)0), StrEq("dummy"))).
1046+ Times(AtMost(0));
1047+
1048+ EXPECT_CALL(mockfs, UnloadPlugin(_)).Times(1);
1049+
1050+ CompPlugin* cp = CompPlugin::load("dummy");
1051+ ASSERT_NE((void*)0, cp);
1052+
1053+ CompPlugin::unload(cp);
1054+}
1055+
1056 TEST(PluginTest, load_plugin_from_void_succeeds)
1057 {
1058 MockPluginFilesystem mockfs;
1059
1060=== modified file 'src/privatewindow.h'
1061--- src/privatewindow.h 2013-01-03 16:06:41 +0000
1062+++ src/privatewindow.h 2013-02-19 15:13:21 +0000
1063@@ -35,6 +35,11 @@
1064
1065 #include <boost/shared_ptr.hpp>
1066
1067+#include <core/configurerequestbuffer.h>
1068+
1069+#include "syncserverwindow.h"
1070+#include "asyncserverwindow.h"
1071+
1072 #define XWINDOWCHANGES_INIT {0, 0, 0, 0, 0, None, 0}
1073
1074 namespace compiz {namespace X11
1075@@ -107,12 +112,47 @@
1076
1077 typedef CompWindowExtents CompFullscreenMonitorSet;
1078
1079-class PrivateWindow {
1080+class X11SyncServerWindow :
1081+ public compiz::window::SyncServerWindow
1082+{
1083+ public:
1084+
1085+ X11SyncServerWindow (Display *dpy,
1086+ const Window *w,
1087+ const Window *frame);
1088+
1089+ bool queryAttributes (XWindowAttributes &attrib);
1090+ bool queryFrameAttributes (XWindowAttributes &attrib);
1091+ XRectangle * queryShapeRectangles(int kind, int *count, int *ordering);
1092+
1093+ private:
1094+
1095+ Display *mDpy;
1096+ const Window *mWindow;
1097+ const Window *mFrame;
1098+};
1099+
1100+class PrivateWindow :
1101+ public compiz::window::SyncServerWindow,
1102+ public compiz::window::AsyncServerWindow
1103+{
1104
1105 public:
1106 PrivateWindow ();
1107 ~PrivateWindow ();
1108
1109+ bool queryAttributes (XWindowAttributes &attrib);
1110+ bool queryFrameAttributes (XWindowAttributes &attrib);
1111+ XRectangle * queryShapeRectangles (int kind, int *count, int *ordering);
1112+ int requestConfigureOnClient (const XWindowChanges &xwc,
1113+ unsigned int valueMask);
1114+ int requestConfigureOnWrapper (const XWindowChanges &xwc,
1115+ unsigned int valueMask);
1116+ int requestConfigureOnFrame (const XWindowChanges &xwc,
1117+ unsigned int valueMask);
1118+ void sendSyntheticConfigureNotify ();
1119+ bool hasCustomShape () const;
1120+
1121 void recalcNormalHints ();
1122
1123 void updateFrameWindow ();
1124@@ -382,6 +422,7 @@
1125
1126 CompWindowExtents input;
1127 CompWindowExtents serverInput;
1128+ CompWindowExtents lastServerInput;
1129 CompWindowExtents border;
1130 CompWindowExtents output;
1131
1132@@ -407,6 +448,9 @@
1133 Time lastCloseRequestTime;
1134
1135 bool nextMoveImmediate;
1136+
1137+ X11SyncServerWindow syncServerWindow;
1138+ compiz::window::configure_buffers::Buffer::Ptr configureBuffer;
1139 };
1140
1141 #endif
1142
1143=== added file 'src/serverwindow.h'
1144=== added file 'src/syncserverwindow.h'
1145--- src/syncserverwindow.h 1970-01-01 00:00:00 +0000
1146+++ src/syncserverwindow.h 2013-02-19 15:13:21 +0000
1147@@ -0,0 +1,49 @@
1148+/*
1149+ * Copyright © 2012 Sam Spilsbury
1150+ *
1151+ * Permission to use, copy, modify, distribute, and sell this software
1152+ * and its documentation for any purpose is hereby granted without
1153+ * fee, provided that the above copyright notice appear in all copies
1154+ * and that both that copyright notice and this permission notice
1155+ * appear in supporting documentation, and that the name of
1156+ * Canonical Ltd. not be used in advertising or publicity pertaining to
1157+ * distribution of the software without specific, written prior permission.
1158+ * Canonical Ltd. makes no representations about the suitability of this
1159+ * software for any purpose. It is provided "as is" without express or
1160+ * implied warranty.
1161+ *
1162+ * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1163+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
1164+ * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1165+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
1166+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
1167+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
1168+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1169+ *
1170+ * Authored by: Sam Spilsbury <smspillaz@gmail.com>
1171+ */
1172+#ifndef _COMPIZ_SYNC_SERVER_WINDOW_H
1173+#define _COMPIZ_SYNC_SERVER_WINDOW_H
1174+
1175+#include <X11/Xlib.h>
1176+
1177+namespace compiz
1178+{
1179+namespace window
1180+{
1181+class SyncServerWindow
1182+{
1183+ public:
1184+
1185+ virtual ~SyncServerWindow () {}
1186+
1187+ virtual bool queryAttributes (XWindowAttributes &attrib) = 0;
1188+ virtual bool queryFrameAttributes (XWindowAttributes &attrib) = 0;
1189+ virtual XRectangle * queryShapeRectangles (int kind,
1190+ int *count,
1191+ int *ordering) = 0;
1192+};
1193+}
1194+}
1195+
1196+#endif
1197
1198=== modified file 'src/tests/CMakeLists.txt'
1199--- src/tests/CMakeLists.txt 2013-01-03 16:06:41 +0000
1200+++ src/tests/CMakeLists.txt 2013-02-19 15:13:21 +0000
1201@@ -30,3 +30,14 @@
1202
1203 compiz_discover_tests(compiz_test_outputdevices COVERAGE compiz_core)
1204
1205+add_executable (compiz_test_configurerequestbuffer
1206+ test_configurerequestbuffer.cpp)
1207+
1208+target_link_libraries (compiz_test_configurerequestbuffer
1209+ compiz_configurerequestbuffer
1210+ ${GTEST_BOTH_LIBRARIES}
1211+ ${GMOCK_MAIN_LIBRARY}
1212+ ${GMOCK_LIBRARY}
1213+)
1214+
1215+compiz_discover_tests(compiz_test_configurerequestbuffer COVERAGE compiz_configurerequestbuffer)
1216
1217=== added file 'src/tests/test_configurerequestbuffer.cpp'
1218--- src/tests/test_configurerequestbuffer.cpp 1970-01-01 00:00:00 +0000
1219+++ src/tests/test_configurerequestbuffer.cpp 2013-02-19 15:13:21 +0000
1220@@ -0,0 +1,667 @@
1221+/*
1222+ * Copyright © 2012 Sam Spilsbury
1223+ *
1224+ * Permission to use, copy, modify, distribute, and sell this software
1225+ * and its documentation for any purpose is hereby granted without
1226+ * fee, provided that the above copyright notice appear in all copies
1227+ * and that both that copyright notice and this permission notice
1228+ * appear in supporting documentation, and that the name of
1229+ * Canonical Ltd. not be used in advertising or publicity pertaining to
1230+ * distribution of the software without specific, written prior permission.
1231+ * Canonical Ltd. makes no representations about the suitability of this
1232+ * software for any purpose. It is provided "as is" without express or
1233+ * implied warranty.
1234+ *
1235+ * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1236+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
1237+ * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1238+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
1239+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
1240+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
1241+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1242+ *
1243+ * Authored by: Sam Spilsbury <smspillaz@gmail.com>
1244+ */
1245+#include <deque>
1246+#include <boost/shared_ptr.hpp>
1247+#include <boost/make_shared.hpp>
1248+#include <boost/bind.hpp>
1249+#include <gmock/gmock.h>
1250+#include <gtest/gtest.h>
1251+#include <X11/Xlib.h>
1252+
1253+#include "configurerequestbuffer-impl.h"
1254+#include "asyncserverwindow.h"
1255+
1256+namespace crb = compiz::window::configure_buffers;
1257+namespace cw = compiz::window;
1258+
1259+using testing::_;
1260+using testing::NiceMock;
1261+using testing::Return;
1262+using testing::Invoke;
1263+using testing::WithArgs;
1264+using testing::SetArgReferee;
1265+using testing::DoAll;
1266+using testing::InSequence;
1267+using testing::ReturnNull;
1268+using testing::IsNull;
1269+
1270+class MockAsyncServerWindow :
1271+ public cw::AsyncServerWindow
1272+{
1273+ public:
1274+
1275+ MOCK_METHOD2 (requestConfigureOnClient, int (const XWindowChanges &, unsigned int));
1276+ MOCK_METHOD2 (requestConfigureOnFrame, int (const XWindowChanges &, unsigned int));
1277+ MOCK_METHOD2 (requestConfigureOnWrapper, int (const XWindowChanges &, unsigned int));
1278+ MOCK_METHOD0 (sendSyntheticConfigureNotify, void ());
1279+ MOCK_CONST_METHOD0 (hasCustomShape, bool ());
1280+};
1281+
1282+class MockSyncServerWindow :
1283+ public cw::SyncServerWindow
1284+{
1285+ public:
1286+
1287+ MOCK_METHOD1 (queryAttributes, bool (XWindowAttributes &));
1288+ MOCK_METHOD1 (queryFrameAttributes, bool (XWindowAttributes &));
1289+ MOCK_METHOD3 (queryShapeRectangles, XRectangle * (int, int *, int *));
1290+};
1291+
1292+namespace
1293+{
1294+int REQUEST_X = 1;
1295+int REQUEST_Y = 2;
1296+int REQUEST_WIDTH = 3;
1297+int REQUEST_HEIGHT = 4;
1298+int REQUEST_BORDER = 5;
1299+
1300+Window REQUEST_ABOVE = 6;
1301+unsigned int REQUEST_MODE = 7;
1302+
1303+crb::BufferLock::Ptr
1304+CreateNormalLock (crb::CountedFreeze *cf)
1305+{
1306+ return boost::make_shared <crb::ConfigureBufferLock> (cf);
1307+}
1308+
1309+}
1310+
1311+MATCHER_P2 (MaskXWC, xwc, vm, "Matches XWindowChanges")
1312+{
1313+ if (vm & CWX)
1314+ if (xwc.x != arg.x)
1315+ return false;
1316+
1317+ if (vm & CWY)
1318+ if (xwc.y != arg.y)
1319+ return false;
1320+
1321+ if (vm & CWWidth)
1322+ if (xwc.width != arg.width)
1323+ return false;
1324+
1325+ if (vm & CWHeight)
1326+ if (xwc.height != arg.height)
1327+ return false;
1328+
1329+ if (vm & CWBorderWidth)
1330+ if (xwc.border_width != arg.border_width)
1331+ return false;
1332+
1333+ if (vm & CWStackMode)
1334+ if (xwc.stack_mode != arg.stack_mode)
1335+ return false;
1336+
1337+ if (vm & CWSibling)
1338+ if (xwc.sibling != arg.sibling)
1339+ return false;
1340+
1341+ return true;
1342+}
1343+
1344+class ConfigureRequestBuffer :
1345+ public testing::Test
1346+{
1347+ public:
1348+
1349+ ConfigureRequestBuffer ()
1350+ {
1351+ /* Initialize xwc, we control it
1352+ * through the value masks */
1353+ xwc.x = REQUEST_X;
1354+ xwc.y = REQUEST_Y;
1355+ xwc.width = REQUEST_WIDTH;
1356+ xwc.height = REQUEST_HEIGHT;
1357+ xwc.border_width = REQUEST_BORDER;
1358+ xwc.sibling = REQUEST_ABOVE;
1359+ xwc.stack_mode = REQUEST_MODE;
1360+ }
1361+
1362+ protected:
1363+
1364+ XWindowChanges xwc;
1365+ MockAsyncServerWindow asyncServerWindow;
1366+ MockSyncServerWindow syncServerWindow;
1367+};
1368+
1369+class ConfigureRequestBufferDispatch :
1370+ public ConfigureRequestBuffer
1371+{
1372+ protected:
1373+
1374+ ConfigureRequestBufferDispatch () :
1375+ ConfigureRequestBuffer (),
1376+ factory (boost::bind (CreateNormalLock, _1)),
1377+ buffer (
1378+ crb::ConfigureRequestBuffer::Create (&asyncServerWindow,
1379+ &syncServerWindow,
1380+ factory))
1381+ {
1382+ }
1383+
1384+ crb::ConfigureRequestBuffer::LockFactory factory;
1385+ crb::Buffer::Ptr buffer;
1386+};
1387+
1388+TEST_F (ConfigureRequestBufferDispatch, PushDirectSyntheticConfigureNotify)
1389+{
1390+ EXPECT_CALL (asyncServerWindow, sendSyntheticConfigureNotify ());
1391+
1392+ buffer->pushSyntheticConfigureNotify ();
1393+}
1394+
1395+TEST_F (ConfigureRequestBufferDispatch, PushDirectClientUpdate)
1396+{
1397+ unsigned int valueMask = CWX | CWY | CWBorderWidth |
1398+ CWSibling | CWStackMode;
1399+
1400+ EXPECT_CALL (asyncServerWindow, requestConfigureOnClient (MaskXWC (xwc, valueMask),
1401+ valueMask));
1402+
1403+ buffer->pushClientRequest (xwc, valueMask);
1404+}
1405+
1406+TEST_F (ConfigureRequestBufferDispatch, PushDirectWrapperUpdate)
1407+{
1408+ unsigned int valueMask = CWX | CWY | CWBorderWidth |
1409+ CWSibling | CWStackMode;
1410+
1411+ EXPECT_CALL (asyncServerWindow, requestConfigureOnWrapper (MaskXWC (xwc, valueMask),
1412+ valueMask));
1413+
1414+ buffer->pushWrapperRequest (xwc, valueMask);
1415+}
1416+
1417+TEST_F (ConfigureRequestBufferDispatch, PushDirectFrameUpdate)
1418+{
1419+ unsigned int valueMask = CWX | CWY | CWBorderWidth |
1420+ CWSibling | CWStackMode;
1421+
1422+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (MaskXWC (xwc, valueMask),
1423+ valueMask));
1424+
1425+ buffer->pushFrameRequest (xwc, valueMask);
1426+}
1427+
1428+TEST_F (ConfigureRequestBufferDispatch, PushUpdateLocked)
1429+{
1430+ crb::Releasable::Ptr lock (buffer->obtainLock ());
1431+
1432+ unsigned int valueMask = 0;
1433+
1434+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1435+
1436+ buffer->pushFrameRequest (xwc, valueMask);
1437+}
1438+
1439+TEST_F (ConfigureRequestBufferDispatch, PushCombinedUpdateLocked)
1440+{
1441+ crb::Releasable::Ptr lock (buffer->obtainLock ());
1442+
1443+ unsigned int valueMask = CWX;
1444+
1445+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1446+
1447+ buffer->pushFrameRequest (xwc, valueMask);
1448+
1449+ valueMask |= CWY;
1450+
1451+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1452+
1453+ buffer->pushFrameRequest (xwc, valueMask);
1454+
1455+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (MaskXWC (xwc, valueMask),
1456+ valueMask));
1457+
1458+ lock->release ();
1459+}
1460+
1461+/*
1462+ * This test is disabled until we can expose the QueryShapeRectangles API
1463+ * to plugins
1464+ */
1465+TEST_F (ConfigureRequestBufferDispatch, DISABLED_PushUpdateLockedReleaseInOrder)
1466+{
1467+ crb::Releasable::Ptr lock (buffer->obtainLock ());
1468+
1469+ unsigned int valueMask = CWX | CWY;
1470+
1471+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1472+ EXPECT_CALL (asyncServerWindow, requestConfigureOnWrapper (_, _)).Times (0);
1473+ EXPECT_CALL (asyncServerWindow, requestConfigureOnClient (_, _)).Times (0);
1474+
1475+ buffer->pushClientRequest (xwc, valueMask);
1476+ buffer->pushWrapperRequest (xwc, 0);
1477+ buffer->pushFrameRequest (xwc, 0);
1478+
1479+ InSequence s;
1480+
1481+ /* Always frame -> wrapper -> client */
1482+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (MaskXWC (xwc, valueMask),
1483+ valueMask));
1484+ EXPECT_CALL (asyncServerWindow, requestConfigureOnWrapper (MaskXWC (xwc, valueMask),
1485+ valueMask));
1486+ EXPECT_CALL (asyncServerWindow, requestConfigureOnClient (MaskXWC (xwc, valueMask),
1487+ valueMask));
1488+
1489+ lock->release ();
1490+}
1491+
1492+TEST_F (ConfigureRequestBufferDispatch, UnlockBuffer)
1493+{
1494+ crb::Releasable::Ptr lock (buffer->obtainLock ());
1495+
1496+ unsigned int valueMask = CWX | CWY;
1497+
1498+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1499+
1500+ buffer->pushFrameRequest (xwc, valueMask);
1501+
1502+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (MaskXWC (xwc, valueMask),
1503+ valueMask));
1504+
1505+ lock->release ();
1506+}
1507+
1508+TEST_F (ConfigureRequestBufferDispatch, ImplicitUnlockBuffer)
1509+{
1510+ crb::Releasable::Ptr lock (buffer->obtainLock ());
1511+
1512+ unsigned int valueMask = CWX | CWY;
1513+
1514+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1515+
1516+ buffer->pushFrameRequest (xwc, valueMask);
1517+
1518+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (MaskXWC (xwc, valueMask),
1519+ valueMask));
1520+}
1521+
1522+TEST_F (ConfigureRequestBufferDispatch, ForceImmediateConfigureOnRestack)
1523+{
1524+ crb::Releasable::Ptr lock (buffer->obtainLock ());
1525+
1526+ unsigned int valueMask = CWStackMode | CWSibling;
1527+
1528+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (MaskXWC (xwc, valueMask),
1529+ valueMask));
1530+
1531+ buffer->pushFrameRequest (xwc, valueMask);
1532+}
1533+
1534+TEST_F (ConfigureRequestBufferDispatch, ForceImmediateConfigureOnWindowSizeChange)
1535+{
1536+ crb::Releasable::Ptr lock (buffer->obtainLock ());
1537+
1538+ unsigned int valueMask = CWWidth | CWHeight | CWBorderWidth;
1539+
1540+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (MaskXWC (xwc, valueMask),
1541+ valueMask));
1542+
1543+ buffer->pushFrameRequest (xwc, valueMask);
1544+}
1545+
1546+TEST_F (ConfigureRequestBufferDispatch, ForceImmediateConfigureOnClientReposition)
1547+{
1548+ crb::Releasable::Ptr lock (buffer->obtainLock ());
1549+
1550+ unsigned int valueMask = CWX | CWY;
1551+
1552+ EXPECT_CALL (asyncServerWindow, requestConfigureOnClient (MaskXWC (xwc, valueMask),
1553+ valueMask));
1554+
1555+ buffer->pushClientRequest (xwc, valueMask);
1556+}
1557+
1558+TEST_F (ConfigureRequestBufferDispatch, ForceImmediateConfigureOnWrapperReposition)
1559+{
1560+ crb::Releasable::Ptr lock (buffer->obtainLock ());
1561+
1562+ unsigned int valueMask = CWX | CWY;
1563+
1564+ EXPECT_CALL (asyncServerWindow, requestConfigureOnWrapper (MaskXWC (xwc, valueMask),
1565+ valueMask));
1566+
1567+ buffer->pushWrapperRequest (xwc, valueMask);
1568+}
1569+
1570+namespace
1571+{
1572+class MockLock :
1573+ public crb::BufferLock
1574+{
1575+ public:
1576+
1577+ /* We're currently importing the locks statefulness and coupling
1578+ * the caller with that */
1579+ MockLock () :
1580+ armed (false)
1581+ {
1582+ ON_CALL (*this, lock ()).WillByDefault (
1583+ Invoke (this, &MockLock::FreezeIfUnarmed));
1584+ ON_CALL (*this, release ()).WillByDefault (
1585+ Invoke (this, &MockLock::ReleaseIfArmed));
1586+ }
1587+
1588+ void OperateOver (crb::CountedFreeze *cf)
1589+ {
1590+ countedFreeze = cf;
1591+ }
1592+
1593+ void FreezeIfUnarmed ()
1594+ {
1595+ if (!armed)
1596+ {
1597+ countedFreeze->freeze ();
1598+ armed = true;
1599+ }
1600+ }
1601+
1602+ void ReleaseIfArmed ()
1603+ {
1604+ if (armed)
1605+ {
1606+ countedFreeze->release ();
1607+ armed = false;
1608+ }
1609+ }
1610+
1611+ typedef boost::shared_ptr <MockLock> Ptr;
1612+
1613+ MOCK_METHOD0 (lock, void ());
1614+ MOCK_METHOD0 (release, void ());
1615+
1616+ private:
1617+
1618+ crb::CountedFreeze *countedFreeze;
1619+ bool armed;
1620+};
1621+
1622+class MockLockFactory
1623+{
1624+ public:
1625+
1626+ crb::BufferLock::Ptr
1627+ CreateMockLock (crb::CountedFreeze *cf)
1628+ {
1629+ MockLock::Ptr mockLock (locks.front ());
1630+ mockLock->OperateOver (cf);
1631+
1632+ locks.pop_front ();
1633+
1634+ return mockLock;
1635+ }
1636+
1637+ void
1638+ QueueLockForCreation (const MockLock::Ptr &lock)
1639+ {
1640+ locks.push_back (lock);
1641+ }
1642+
1643+ private:
1644+
1645+ std::deque <MockLock::Ptr> locks;
1646+};
1647+}
1648+
1649+class ConfigureRequestBufferLockBehaviour :
1650+ public ConfigureRequestBuffer
1651+{
1652+ public:
1653+
1654+ ConfigureRequestBufferLockBehaviour () :
1655+ ConfigureRequestBuffer (),
1656+ lock (boost::make_shared <MockLock> ()),
1657+ factory (
1658+ boost::bind (&MockLockFactory::CreateMockLock,
1659+ &mockLockFactory,
1660+ _1)),
1661+ buffer (
1662+ crb::ConfigureRequestBuffer::Create (
1663+ &asyncServerWindow,
1664+ &syncServerWindow,
1665+ factory))
1666+
1667+ {
1668+ mockLockFactory.QueueLockForCreation (lock);
1669+ }
1670+
1671+ protected:
1672+
1673+ typedef NiceMock <MockAsyncServerWindow> NiceServerWindow;
1674+ typedef crb::ConfigureRequestBuffer::LockFactory LockFactory;
1675+
1676+ MockLock::Ptr lock;
1677+ MockLockFactory mockLockFactory;
1678+
1679+ LockFactory factory;
1680+ crb::Buffer::Ptr buffer;
1681+};
1682+
1683+TEST_F (ConfigureRequestBufferLockBehaviour, RearmBufferLockOnRelease)
1684+{
1685+ EXPECT_CALL (*lock, lock ());
1686+ crb::Releasable::Ptr releasable (buffer->obtainLock ());
1687+
1688+ unsigned int valueMask = CWX | CWY;
1689+
1690+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1691+
1692+ buffer->pushFrameRequest (xwc, valueMask);
1693+
1694+ /* We are releasing this lock */
1695+ EXPECT_CALL (*lock, release ());
1696+
1697+ /* Now the buffer will dispatch is configure request */
1698+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _));
1699+
1700+ /* Rearm locks on release */
1701+ EXPECT_CALL (*lock, lock ());
1702+
1703+ /* Directly release the queue */
1704+ releasable->release ();
1705+}
1706+
1707+TEST_F (ConfigureRequestBufferLockBehaviour, NoRearmBufferLockNoReleaseRequired)
1708+{
1709+ /* Locks get armed on construction */
1710+ EXPECT_CALL (*lock, lock ());
1711+ crb::Releasable::Ptr releasable (buffer->obtainLock ());
1712+
1713+ /* No call to requestConfigureOnFrame if there's nothing to be configured */
1714+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1715+
1716+ /* We are releasing this lock */
1717+ EXPECT_CALL (*lock, release ());
1718+
1719+ /* No rearm - we haven't released the whole buffer */
1720+ EXPECT_CALL (*lock, lock ()).Times (0);
1721+
1722+ /* Directly release the queue */
1723+ releasable->release ();
1724+}
1725+
1726+TEST_F (ConfigureRequestBufferLockBehaviour, RearmWhenPushReady)
1727+{
1728+ /* Locks get armed on construction */
1729+ EXPECT_CALL (*lock, lock ());
1730+ crb::Releasable::Ptr releasable (buffer->obtainLock ());
1731+
1732+ /* We are releasing this lock */
1733+ EXPECT_CALL (*lock, release ());
1734+
1735+ /* No call to requestConfigureOnFrame if there's nothing to be configured */
1736+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1737+
1738+ /* No rearm - we haven't released it */
1739+ EXPECT_CALL (*lock, lock ()).Times (0);
1740+
1741+ /* Directly release the queue */
1742+ releasable->release ();
1743+
1744+ /* Since we're now going to push something to a queue
1745+ * that's effectively not locked, the locks should now
1746+ * be released */
1747+ unsigned int valueMask = CWX | CWY;
1748+
1749+ /* Now rearm it */
1750+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _));
1751+ EXPECT_CALL (*lock, lock ());
1752+
1753+ buffer->pushFrameRequest (xwc, valueMask);
1754+}
1755+
1756+TEST_F (ConfigureRequestBufferLockBehaviour, NoRearmBufferLockOnNoRelease)
1757+{
1758+ MockLock::Ptr second (boost::make_shared <MockLock> ());
1759+ mockLockFactory.QueueLockForCreation (second);
1760+
1761+ /* Locks get armed on construction */
1762+ EXPECT_CALL (*lock, lock ());
1763+ EXPECT_CALL (*second, lock ());
1764+
1765+ crb::Releasable::Ptr releasable (buffer->obtainLock ());
1766+ crb::Releasable::Ptr otherReleasable (buffer->obtainLock ());
1767+
1768+ /* We are releasing this lock */
1769+ EXPECT_CALL (*lock, release ());
1770+
1771+ /* No call to requestConfigureOnFrame if there's nothing to be configured */
1772+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1773+
1774+ /* No rearm - we haven't released it */
1775+ EXPECT_CALL (*lock, lock ()).Times (0);
1776+
1777+ releasable->release ();
1778+}
1779+
1780+TEST_F (ConfigureRequestBufferLockBehaviour, QueryAttributesDispatchAndRearm)
1781+{
1782+ /* Locks get armed on construction */
1783+ EXPECT_CALL (*lock, lock ());
1784+
1785+ crb::Releasable::Ptr releasable (buffer->obtainLock ());
1786+
1787+ unsigned int valueMask = CWX | CWY;
1788+
1789+ /* Queue locked */
1790+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1791+
1792+ buffer->pushFrameRequest (xwc, valueMask);
1793+
1794+ /* Queue forceably unlocked, locks rearmed */
1795+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _));
1796+ EXPECT_CALL (*lock, lock ());
1797+
1798+ /* Expect a call to XGetWindowAttributes */
1799+ EXPECT_CALL (syncServerWindow, queryShapeRectangles (_, _, _))
1800+ .WillOnce (
1801+ ReturnNull ());
1802+
1803+ int a, b;
1804+
1805+ EXPECT_THAT (buffer->queryShapeRectangles (0, &a, &b), IsNull ());
1806+}
1807+
1808+TEST_F (ConfigureRequestBufferLockBehaviour, QueryFrameAttributesDispatchAndRearm)
1809+{
1810+ /* Locks get armed on construction */
1811+ EXPECT_CALL (*lock, lock ());
1812+
1813+ crb::Releasable::Ptr releasable (buffer->obtainLock ());
1814+
1815+ unsigned int valueMask = CWX | CWY;
1816+
1817+ /* Queue locked */
1818+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1819+
1820+ buffer->pushFrameRequest (xwc, valueMask);
1821+
1822+ /* Queue forceably unlocked, locks rearmed */
1823+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _));
1824+ EXPECT_CALL (*lock, lock ());
1825+
1826+ /* Expect a call to XGetWindowAttributes */
1827+ XWindowAttributes xwa;
1828+ EXPECT_CALL (syncServerWindow, queryFrameAttributes (_))
1829+ .WillOnce (
1830+ DoAll (
1831+ SetArgReferee <0> (xwa),
1832+ Return (true)));
1833+
1834+ buffer->queryFrameAttributes (xwa);
1835+}
1836+
1837+TEST_F (ConfigureRequestBufferLockBehaviour, QueryShapeRectanglesDispatchAndRearm)
1838+{
1839+ /* Locks get armed on construction */
1840+ EXPECT_CALL (*lock, lock ());
1841+
1842+ crb::Releasable::Ptr releasable (buffer->obtainLock ());
1843+
1844+ unsigned int valueMask = CWX | CWY;
1845+
1846+ /* Queue locked */
1847+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1848+
1849+ buffer->pushFrameRequest (xwc, valueMask);
1850+
1851+ /* Queue forceably unlocked, locks rearmed */
1852+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _));
1853+ EXPECT_CALL (*lock, lock ());
1854+
1855+ /* Expect a call to XGetWindowAttributes */
1856+ XWindowAttributes xwa;
1857+ EXPECT_CALL (syncServerWindow, queryFrameAttributes (_))
1858+ .WillOnce (
1859+ DoAll (
1860+ SetArgReferee <0> (xwa),
1861+ Return (true)));
1862+
1863+ buffer->queryFrameAttributes (xwa);
1864+}
1865+
1866+TEST_F (ConfigureRequestBufferLockBehaviour, ForceReleaseDispatchAndRearm)
1867+{
1868+ /* Locks get armed on construction */
1869+ EXPECT_CALL (*lock, lock ());
1870+
1871+ crb::Releasable::Ptr releasable (buffer->obtainLock ());
1872+
1873+ unsigned int valueMask = CWX | CWY;
1874+
1875+ /* Queue locked */
1876+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _)).Times (0);
1877+
1878+ buffer->pushFrameRequest (xwc, valueMask);
1879+
1880+ /* Queue forceably unlocked, locks rearmed */
1881+ EXPECT_CALL (asyncServerWindow, requestConfigureOnFrame (_, _));
1882+ EXPECT_CALL (*lock, lock ());
1883+
1884+ /* Force release */
1885+ buffer->forceRelease ();
1886+}
1887+
1888
1889=== modified file 'src/window.cpp'
1890--- src/window.cpp 2013-02-18 22:51:33 +0000
1891+++ src/window.cpp 2013-02-19 15:13:21 +0000
1892@@ -37,6 +37,7 @@
1893 #include <math.h>
1894
1895 #include <boost/bind.hpp>
1896+#include <boost/make_shared.hpp>
1897
1898 #include <core/icon.h>
1899 #include <core/atoms.h>
1900@@ -45,8 +46,13 @@
1901 #include "privatescreen.h"
1902 #include "privatestackdebugger.h"
1903
1904+#include "configurerequestbuffer-impl.h"
1905+
1906 #include <boost/scoped_array.hpp>
1907
1908+namespace crb = compiz::window::configure_buffers;
1909+namespace cw = compiz::window;
1910+
1911 template class WrapableInterface<CompWindow, WindowInterface>;
1912
1913 PluginClassStorage::Indices windowPluginClassIndices (0);
1914@@ -3028,6 +3034,80 @@
1915 return pc->matchRequest (xwc, valueMask);
1916 }
1917
1918+bool
1919+PrivateWindow::queryAttributes (XWindowAttributes &attrib)
1920+{
1921+ return configureBuffer->queryAttributes (attrib);
1922+}
1923+
1924+bool
1925+PrivateWindow::queryFrameAttributes (XWindowAttributes &attrib)
1926+{
1927+ return configureBuffer->queryFrameAttributes (attrib);
1928+}
1929+
1930+XRectangle *
1931+PrivateWindow::queryShapeRectangles (int kind, int *count, int *ordering)
1932+{
1933+ return configureBuffer->queryShapeRectangles (kind, count, ordering);
1934+}
1935+
1936+int
1937+PrivateWindow::requestConfigureOnClient (const XWindowChanges &xwc,
1938+ unsigned int valueMask)
1939+{
1940+ int ret = XConfigureWindow (screen->dpy (),
1941+ id,
1942+ valueMask,
1943+ const_cast <XWindowChanges *> (&xwc));
1944+
1945+ return ret;
1946+}
1947+
1948+int
1949+PrivateWindow::requestConfigureOnWrapper (const XWindowChanges &xwc,
1950+ unsigned int valueMask)
1951+{
1952+ return XConfigureWindow (screen->dpy (),
1953+ wrapper,
1954+ valueMask,
1955+ const_cast <XWindowChanges *> (&xwc));
1956+}
1957+
1958+int
1959+PrivateWindow::requestConfigureOnFrame (const XWindowChanges &xwc,
1960+ unsigned int frameValueMask)
1961+{
1962+ XWindowChanges wc = xwc;
1963+
1964+ wc.x = serverFrameGeometry.x ();
1965+ wc.y = serverFrameGeometry.y ();
1966+ wc.width = serverFrameGeometry.width ();
1967+ wc.height = serverFrameGeometry.height ();
1968+
1969+ compiz::X11::PendingEvent::Ptr pc (
1970+ new compiz::X11::PendingConfigureEvent (
1971+ screen->dpy (),
1972+ priv->serverFrame,
1973+ frameValueMask, &wc));
1974+
1975+ pendingConfigures.add (pc);
1976+
1977+ return XConfigureWindow (screen->dpy (), serverFrame, frameValueMask, &wc);
1978+}
1979+
1980+void
1981+PrivateWindow::sendSyntheticConfigureNotify ()
1982+{
1983+ window->sendConfigureNotify ();
1984+}
1985+
1986+bool
1987+PrivateWindow::hasCustomShape () const
1988+{
1989+ return false;
1990+}
1991+
1992 void
1993 PrivateWindow::reconfigureXWindow (unsigned int valueMask,
1994 XWindowChanges *xwc)
1995@@ -3240,47 +3320,41 @@
1996 if (serverFrame)
1997 {
1998 if (frameValueMask)
1999- {
2000- XWindowChanges wc = *xwc;
2001-
2002- wc.x = serverFrameGeometry.x ();
2003- wc.y = serverFrameGeometry.y ();
2004- wc.width = serverFrameGeometry.width ();
2005- wc.height = serverFrameGeometry.height ();
2006-
2007- compiz::X11::PendingEvent::Ptr pc =
2008- boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
2009- new compiz::X11::PendingConfigureEvent (
2010- screen->dpy (), priv->serverFrame, frameValueMask, &wc)));
2011-
2012- pendingConfigures.add (pc);
2013-
2014- XConfigureWindow (screen->dpy (), serverFrame, frameValueMask, &wc);
2015- }
2016-
2017- valueMask &= ~(CWSibling | CWStackMode);
2018+ priv->configureBuffer->pushFrameRequest (*xwc, frameValueMask);
2019+
2020+ valueMask = frameValueMask & (CWWidth | CWHeight);
2021
2022 /* If the frame has changed position (eg, serverInput.top
2023 * or serverInput.left have changed) then we also need to
2024 * update the client and wrapper position */
2025- if (!(valueMask & CWX))
2026- valueMask |= frameValueMask & CWX;
2027- if (!(valueMask & CWY))
2028- valueMask |= frameValueMask & CWY;
2029+ if (lastServerInput.left != serverInput.left)
2030+ valueMask |= CWX;
2031+ if (lastServerInput.top != serverInput.top)
2032+ valueMask |= CWY;
2033+
2034+ if (lastServerInput.right - lastServerInput.left !=
2035+ serverInput.right - serverInput.left)
2036+ valueMask |= CWWidth;
2037+ if (lastServerInput.bottom - lastServerInput.top !=
2038+ serverInput.bottom - serverInput.top)
2039+ valueMask |= CWHeight;
2040
2041 if (valueMask)
2042 {
2043 xwc->x = serverInput.left;
2044 xwc->y = serverInput.top;
2045- XConfigureWindow (screen->dpy (), wrapper, valueMask, xwc);
2046
2047- xwc->x = 0;
2048- xwc->y = 0;
2049+ priv->configureBuffer->pushWrapperRequest (*xwc, valueMask);
2050 }
2051 }
2052
2053+ /* Client is reparented, the only things that can change
2054+ * are the width, height and border width */
2055+ if (serverFrame)
2056+ valueMask &= (CWWidth | CWHeight | CWBorderWidth);
2057+
2058 if (valueMask)
2059- XConfigureWindow (screen->dpy (), id, valueMask, xwc);
2060+ priv->configureBuffer->pushClientRequest (*xwc, valueMask);
2061
2062 /* Send the synthetic configure notify
2063 * after the real configure notify arrives
2064@@ -5811,6 +5885,24 @@
2065 return priv->struts;
2066 }
2067
2068+bool
2069+CompWindow::queryAttributes (XWindowAttributes &attrib)
2070+{
2071+ return priv->queryAttributes (attrib);
2072+}
2073+
2074+bool
2075+CompWindow::queryFrameAttributes (XWindowAttributes &attrib)
2076+{
2077+ return priv->queryFrameAttributes (attrib);
2078+}
2079+
2080+crb::Releasable::Ptr
2081+CompWindow::obtainLockOnConfigureRequests ()
2082+{
2083+ return priv->configureBuffer->obtainLock ();
2084+}
2085+
2086 int &
2087 CompWindow::saveMask () const
2088 {
2089@@ -6349,6 +6441,55 @@
2090 delete priv;
2091 }
2092
2093+X11SyncServerWindow::X11SyncServerWindow (Display *dpy,
2094+ const Window *w,
2095+ const Window *frame) :
2096+ mDpy (dpy),
2097+ mWindow (w),
2098+ mFrame (frame)
2099+{
2100+}
2101+
2102+bool
2103+X11SyncServerWindow::queryAttributes (XWindowAttributes &attrib)
2104+{
2105+ if (XGetWindowAttributes (mDpy, *mWindow, &attrib))
2106+ return true;
2107+
2108+ return false;
2109+}
2110+
2111+bool
2112+X11SyncServerWindow::queryFrameAttributes (XWindowAttributes &attrib)
2113+{
2114+ Window w = *mFrame ? *mFrame : *mWindow;
2115+
2116+ if (XGetWindowAttributes (mDpy, w, &attrib))
2117+ return true;
2118+
2119+ return false;
2120+}
2121+
2122+XRectangle *
2123+X11SyncServerWindow::queryShapeRectangles (int kind,
2124+ int *count,
2125+ int *ordering)
2126+{
2127+ return XShapeGetRectangles (mDpy, *mWindow,
2128+ kind,
2129+ count,
2130+ ordering);
2131+}
2132+
2133+namespace
2134+{
2135+crb::BufferLock::Ptr
2136+createConfigureBufferLock (crb::CountedFreeze *cf)
2137+{
2138+ return boost::make_shared <crb::ConfigureBufferLock> (cf);
2139+}
2140+}
2141+
2142 PrivateWindow::PrivateWindow () :
2143 priv (this),
2144 refcnt (1),
2145@@ -6420,27 +6561,27 @@
2146
2147 syncWait (false),
2148 closeRequests (false),
2149- lastCloseRequestTime (0)
2150+ lastCloseRequestTime (0),
2151+
2152+ syncServerWindow (screen->dpy (),
2153+ &id,
2154+ &serverFrame),
2155+ configureBuffer (
2156+ crb::ConfigureRequestBuffer::Create (
2157+ this,
2158+ &syncServerWindow,
2159+ boost::bind (createConfigureBufferLock, _1)))
2160 {
2161 input.left = 0;
2162 input.right = 0;
2163 input.top = 0;
2164 input.bottom = 0;
2165
2166- serverInput.left = 0;
2167- serverInput.right = 0;
2168- serverInput.top = 0;
2169- serverInput.bottom = 0;
2170-
2171- border.top = 0;
2172- border.bottom = 0;
2173- border.left = 0;
2174- border.right = 0;
2175-
2176- output.left = 0;
2177- output.right = 0;
2178- output.top = 0;
2179- output.bottom = 0;
2180+ /* Zero initialize */
2181+ serverInput = input;
2182+ lastServerInput = input;
2183+ border = input;
2184+ output = input;
2185
2186 syncWaitTimer.setTimes (1000, 1200);
2187 syncWaitTimer.setCallback (boost::bind (&PrivateWindow::handleSyncAlarm,
2188@@ -6648,6 +6789,9 @@
2189 * whenever the frame extents update
2190 * so that plugins can re-position appropriately */
2191 moveNotify (0, 0, true);
2192+
2193+ /* Once we have updated everything, re-set lastServerInput */
2194+ priv->lastServerInput = priv->serverInput;
2195 }
2196
2197 /* Use b for _NET_WM_FRAME_EXTENTS here because
2198@@ -6710,7 +6854,11 @@
2199 XSync (dpy, false);
2200 XGrabServer (dpy);
2201
2202- if (!XGetWindowAttributes (dpy, id, &wa))
2203+ /* We need to flush all queued up requests */
2204+ foreach (CompWindow *w, screen->windows ())
2205+ w->priv->configureBuffer->forceRelease ();
2206+
2207+ if (!window->priv->queryAttributes (wa))
2208 {
2209 XUngrabServer (dpy);
2210 XSync (dpy, false);
2211@@ -6997,7 +7145,7 @@
2212 * a DestroyNotify for it yet, it is possible that restacking
2213 * operations could occurr relative to it so we need to hold it
2214 * in the stack for now. Ensure that it is marked override redirect */
2215- XGetWindowAttributes (screen->dpy (), serverFrame, &attrib);
2216+ window->priv->queryFrameAttributes (attrib);
2217
2218 /* Put the frame window "above" the client window
2219 * in the stack */
2220
2221=== modified file 'tests/acceptance-tests/xorg-gtest/tests/compiz_acceptance_replace_current_wm.cpp'
2222--- tests/acceptance-tests/xorg-gtest/tests/compiz_acceptance_replace_current_wm.cpp 2012-12-05 03:40:20 +0000
2223+++ tests/acceptance-tests/xorg-gtest/tests/compiz_acceptance_replace_current_wm.cpp 2013-02-19 15:13:21 +0000
2224@@ -101,6 +101,7 @@
2225 TmpEnv env ("XORG_GTEST_CHILD_STDOUT", "1");
2226 ProcessPtr compiz (boost::make_shared <ct::CompizProcess> (Display (),
2227 ct::CompizProcess::WaitForStartupMessage,
2228+ ct::CompizProcess::PluginList (),
2229 3000));
2230
2231 pid_t firstProcessPid = compiz->Pid ();
2232@@ -130,6 +131,7 @@
2233 TmpEnv env ("XORG_GTEST_CHILD_STDOUT", "1");
2234 ProcessPtr firstCompiz (boost::make_shared <ct::CompizProcess> (Display (),
2235 ct::CompizProcess::WaitForStartupMessage,
2236+ ct::CompizProcess::PluginList (),
2237 3000));
2238
2239 /* Expect it to exit */
2240@@ -142,6 +144,7 @@
2241 static_cast <ct::CompizProcess::StartupFlags> (
2242 ct::CompizProcess::WaitForStartupMessage |
2243 ct::CompizProcess::ReplaceCurrentWM),
2244+ ct::CompizProcess::PluginList (),
2245 maximumWaitTime));
2246
2247 if (!task->ReadMsgFromTask (PROCESS_EXITED_MSG, maximumWaitTime))
2248@@ -223,6 +226,7 @@
2249 TmpEnv env ("XORG_GTEST_CHILD_STDOUT", "1");
2250 ProcessPtr firstCompiz (boost::make_shared <ct::CompizProcess> (dpy,
2251 ct::CompizProcess::WaitForStartupMessage,
2252+ ct::CompizProcess::PluginList (),
2253 3000));
2254
2255 SlowDownTask::GetProcessState procState (boost::bind (&ct::CompizProcess::State,
2256@@ -244,6 +248,7 @@
2257 static_cast <ct::CompizProcess::StartupFlags> (
2258 ct::CompizProcess::ReplaceCurrentWM |
2259 ct::CompizProcess::WaitForStartupMessage),
2260+ ct::CompizProcess::PluginList (),
2261 maximumWaitTime));
2262
2263 /* Wait until the first one goes away */
2264
2265=== modified file 'tests/system/xorg-gtest/CMakeLists.txt'
2266--- tests/system/xorg-gtest/CMakeLists.txt 2013-02-12 04:33:31 +0000
2267+++ tests/system/xorg-gtest/CMakeLists.txt 2013-02-19 15:13:21 +0000
2268@@ -1,5 +1,42 @@
2269+<<<<<<< TREE
2270 if (BUILD_XORG_GTEST)
2271
2272+=======
2273+include (FindPkgConfig)
2274+
2275+pkg_check_modules (XORG_SERVER xorg-gtest xorg-server x11)
2276+
2277+option (BUILD_XORG_GTEST "Build Xorg GTest integration tests" OFF)
2278+
2279+if (XORG_SERVER_FOUND AND BUILD_XORG_GTEST)
2280+
2281+ execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=prefix xorg-gtest OUTPUT_VARIABLE _xorg_gtest_prefix)
2282+ execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=includedir xorg-gtest OUTPUT_VARIABLE _xorg_gtest_include_dir)
2283+ execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=sourcedir xorg-gtest OUTPUT_VARIABLE _xorg_gtest_source_dir)
2284+ execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=CPPflags xorg-gtest OUTPUT_VARIABLE _xorg_gtest_cflags)
2285+
2286+ string (STRIP ${_xorg_gtest_prefix} _xorg_gtest_prefix)
2287+ string (STRIP ${_xorg_gtest_include_dir} _xorg_gtest_include_dir)
2288+ string (STRIP ${_xorg_gtest_source_dir} _xorg_gtest_source_dir)
2289+ string (STRIP ${_xorg_gtest_cflags} _xorg_gtest_cflags)
2290+
2291+ set (XORG_SERVER_INCLUDE_XORG_GTEST ${_xorg_gtest_include_dir} CACHE PATH "Path to Xorg GTest Headers")
2292+ set (XORG_SERVER_GTEST_SRC ${_xorg_gtest_source_dir} CACHE PATH "Path to Xorg GTest Sources")
2293+ set (COMPIZ_XORG_SYSTEM_TEST_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE PATH "Path to Compiz Xorg GTest Headers")
2294+ set (COMPIZ_OVERRIDE_PLUGIN_PATH ${CMAKE_CURRENT_BINARY_DIR}/tests/plugins/testhelper CACHE PATH "Override plugin path for system tests" FORCE)
2295+
2296+ message (STATUS "Found xorg-gtest sources at " ${XORG_SERVER_GTEST_SRC})
2297+
2298+ set (COMPIZ_XORG_GTEST_COMMUNICATOR_INCLUDE_DIR
2299+ ${CMAKE_CURRENT_SOURCE_DIR}/communicator/)
2300+ set (COMPIZ_XORG_GTEST_COMMUNICATOR_LIBRARY_DIR
2301+ ${CMAKE_CURRENT_BINARY_DIR}/communicator)
2302+ set (COMPIZ_XORG_GTEST_COMMUNICATOR_LIBRARY
2303+ compiz_xorg_gtest_communicator)
2304+
2305+ add_subdirectory (communicator)
2306+ add_subdirectory (src)
2307+>>>>>>> MERGE-SOURCE
2308 add_subdirectory (tests)
2309
2310 endif (BUILD_XORG_GTEST)
2311
2312=== added directory 'tests/system/xorg-gtest/communicator'
2313=== added file 'tests/system/xorg-gtest/communicator/CMakeLists.txt'
2314--- tests/system/xorg-gtest/communicator/CMakeLists.txt 1970-01-01 00:00:00 +0000
2315+++ tests/system/xorg-gtest/communicator/CMakeLists.txt 2013-02-19 15:13:21 +0000
2316@@ -0,0 +1,17 @@
2317+include (FindPkgConfig)
2318+
2319+pkg_check_modules (COMPIZ_XORG_GTEST_COMMUNICATOR x11)
2320+
2321+if (COMPIZ_XORG_GTEST_COMMUNICATOR_FOUND)
2322+
2323+ include_directories (${COMPIZ_XORG_GTEST_COMMUNICATOR_INCLUDE_DIRS}
2324+ ${CMAKE_CURRENT_SOURCE_DIR})
2325+ link_directories (${COMPIZ_XORG_GTEST_COMMUNICATOR_LIBRARY_DIRS})
2326+
2327+ add_library (${COMPIZ_XORG_GTEST_COMMUNICATOR_LIBRARY} STATIC
2328+ ${CMAKE_CURRENT_SOURCE_DIR}/compiz_xorg_gtest_communicator.cpp)
2329+
2330+ target_link_libraries (${COMPIZ_XORG_GTEST_COMMUNICATOR_LIBRARY}
2331+ ${COMPIZ_XORG_GTEST_COMMUNICATOR_LIBRARIES})
2332+
2333+endif (COMPIZ_XORG_GTEST_COMMUNICATOR_FOUND)
2334
2335=== added file 'tests/system/xorg-gtest/communicator/compiz_xorg_gtest_communicator.cpp'
2336--- tests/system/xorg-gtest/communicator/compiz_xorg_gtest_communicator.cpp 1970-01-01 00:00:00 +0000
2337+++ tests/system/xorg-gtest/communicator/compiz_xorg_gtest_communicator.cpp 2013-02-19 15:13:21 +0000
2338@@ -0,0 +1,200 @@
2339+/*
2340+* Copyright © 2013 Sam Spilsbury
2341+*
2342+* Permission to use, copy, modify, distribute, and sell this software
2343+* and its documentation for any purpose is hereby granted without
2344+* fee, provided that the above copyright notice appear in all copies
2345+* and that both that copyright notice and this permission notice
2346+* appear in supporting documentation, and that the name of
2347+* Novell, Inc. not be used in advertising or publicity pertaining to
2348+* distribution of the software without specific, written prior permission.
2349+* Novell, Inc. makes no representations about the suitability of this
2350+* software for any purpose. It is provided "as is" without express or
2351+* implied warranty.
2352+*
2353+* NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
2354+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
2355+* NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
2356+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
2357+* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
2358+* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
2359+* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2360+*
2361+* Author: Sam Spilsbury <smspillaz@gmail.com>
2362+*/
2363+
2364+#include <cstdio>
2365+#include <cstring>
2366+#include <map>
2367+#include <string>
2368+#include <sstream>
2369+#include <stdexcept>
2370+#include <poll.h>
2371+#include <X11/Xlib.h>
2372+#include <compiz_xorg_gtest_communicator.h>
2373+
2374+namespace compiz
2375+{
2376+namespace testing
2377+{
2378+namespace messages
2379+{
2380+namespace internal
2381+{
2382+const char *messages[] =
2383+{
2384+ "_COMPIZ_TEST_HELPER_READY",
2385+ "_COMPIZ_TEST_HELPER_REGISTER_CLIENT",
2386+ "_COMPIZ_TEST_HELPER_LOCK_CONFIGURE_REQUESTS",
2387+ "_COMPIZ_TEST_HELPER_CHANGE_FRAME_EXTENTS",
2388+ "_COMPIZ_TEST_HELPER_FRAME_EXTENTS_CHANGED",
2389+ "_COMPIZ_TEST_HELPER_CONFIGURE_WINDOW",
2390+ "_COMPIZ_TEST_HELPER_WINDOW_CONFIGURE_PROCESSED",
2391+ "_COMPIZ_TEST_HELPER_WINDOW_READY"
2392+};
2393+}
2394+
2395+const char *TEST_HELPER_READY_MSG = internal::messages[0];
2396+const char *TEST_HELPER_REGISTER_CLIENT = internal::messages[1];
2397+const char *TEST_HELPER_LOCK_CONFIGURE_REQUESTS = internal::messages[2];
2398+const char *TEST_HELPER_CHANGE_FRAME_EXTENTS = internal::messages[3];
2399+const char *TEST_HELPER_FRAME_EXTENTS_CHANGED = internal::messages[4];
2400+const char *TEST_HELPER_CONFIGURE_WINDOW = internal::messages[5];
2401+const char *TEST_HELPER_WINDOW_CONFIGURE_PROCESSED = internal::messages[6];
2402+const char *TEST_HELPER_WINDOW_READY = internal::messages[7];
2403+}
2404+}
2405+}
2406+
2407+namespace ct = compiz::testing;
2408+namespace ctmi = compiz::testing::messages::internal;
2409+
2410+class ct::MessageAtoms::Private
2411+{
2412+ public:
2413+
2414+ std::map <const char *, Atom> atoms;
2415+};
2416+
2417+ct::MessageAtoms::MessageAtoms (Display *display) :
2418+ priv (new ct::MessageAtoms::Private)
2419+{
2420+ int nAtoms = sizeof (ctmi::messages) / sizeof (const char *);
2421+ Atom atoms[nAtoms];
2422+
2423+ if (!XInternAtoms (display,
2424+ const_cast <char **> (ctmi::messages),
2425+ sizeof (ctmi::messages) / sizeof (const char *),
2426+ 0,
2427+ atoms))
2428+ throw std::runtime_error ("XInternAtoms generated an error");
2429+
2430+ for (int i = 0; i < nAtoms; ++i)
2431+ priv->atoms[ctmi::messages[i]] = atoms[i];
2432+}
2433+
2434+Atom
2435+ct::MessageAtoms::FetchForString (const char *message)
2436+{
2437+ std::map <const char *, Atom>::iterator it (priv->atoms.find (message));
2438+
2439+ if (it == priv->atoms.end ())
2440+ {
2441+ std::stringstream ss;
2442+
2443+ ss << "Atom for message " << message << " does not exist";
2444+ throw std::runtime_error (ss.str ());
2445+ }
2446+
2447+ return it->second;
2448+}
2449+
2450+namespace
2451+{
2452+bool FindClientMessage (Display *display,
2453+ XEvent &event,
2454+ Atom message)
2455+{
2456+ while (XPending (display))
2457+ {
2458+ XNextEvent (display, &event);
2459+
2460+ if (event.type == ClientMessage)
2461+ {
2462+ if (event.xclient.message_type == message)
2463+ return true;
2464+ }
2465+ }
2466+
2467+ return false;
2468+}
2469+}
2470+
2471+bool
2472+ct::ReceiveMessage (Display *display,
2473+ Atom message,
2474+ XEvent &event,
2475+ int timeout)
2476+{
2477+ if (FindClientMessage (display, event, message))
2478+ return true;
2479+ else
2480+ {
2481+ XSync (display, false);
2482+
2483+ struct pollfd pfd;
2484+ pfd.events = POLLIN | POLLHUP | POLLERR;
2485+ pfd.revents = 0;
2486+ pfd.fd = ConnectionNumber (display);
2487+
2488+ poll (&pfd, 1, timeout);
2489+
2490+ /* Make sure we get something */
2491+ if ((pfd.revents & POLLIN) &&
2492+ !(pfd.revents & (POLLHUP | POLLERR)))
2493+ {
2494+ return ReceiveMessage (display, message, event, timeout);
2495+ }
2496+ else
2497+ return false;
2498+ }
2499+
2500+ return false;
2501+}
2502+
2503+void
2504+ct::SendClientMessage (Display *display,
2505+ Atom message,
2506+ Window destination,
2507+ Window target,
2508+ const std::vector<long> &data)
2509+{
2510+ if (data.size () > 5)
2511+ throw std::runtime_error ("data size must be less than 5");
2512+
2513+ XEvent event;
2514+
2515+ memset (&event, 0, sizeof (XEvent));
2516+
2517+ event.type = ClientMessage;
2518+
2519+ event.xclient.display = display;
2520+ event.xclient.send_event = 1;
2521+ event.xclient.serial = 0;
2522+
2523+ event.xclient.message_type = message;
2524+ event.xclient.window = target;
2525+ event.xclient.format = 32;
2526+
2527+ int count = 0;
2528+ for (std::vector <long>::const_iterator it = data.begin ();
2529+ it != data.end ();
2530+ ++it)
2531+ event.xclient.data.l[count++] = *it;
2532+
2533+ XSendEvent (display,
2534+ destination,
2535+ 0,
2536+ StructureNotifyMask,
2537+ &event);
2538+};
2539
2540=== added file 'tests/system/xorg-gtest/communicator/compiz_xorg_gtest_communicator.h'
2541--- tests/system/xorg-gtest/communicator/compiz_xorg_gtest_communicator.h 1970-01-01 00:00:00 +0000
2542+++ tests/system/xorg-gtest/communicator/compiz_xorg_gtest_communicator.h 2013-02-19 15:13:21 +0000
2543@@ -0,0 +1,67 @@
2544+/*
2545+* Copyright © 2013 Sam Spilsbury
2546+*
2547+* Permission to use, copy, modify, distribute, and sell this software
2548+* and its documentation for any purpose is hereby granted without
2549+* fee, provided that the above copyright notice appear in all copies
2550+* and that both that copyright notice and this permission notice
2551+* appear in supporting documentation, and that the name of
2552+* Novell, Inc. not be used in advertising or publicity pertaining to
2553+* distribution of the software without specific, written prior permission.
2554+* Novell, Inc. makes no representations about the suitability of this
2555+* software for any purpose. It is provided "as is" without express or
2556+* implied warranty.
2557+*
2558+* NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
2559+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
2560+* NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
2561+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
2562+* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
2563+* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
2564+* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2565+*
2566+* Author: Sam Spilsbury <smspillaz@gmail.com>
2567+*/
2568+#ifndef _COMPIZ_XORG_GTEST_COMMUNICATOR_H
2569+#define _COMPIZ_XORG_GTEST_COMMUNICATOR_H
2570+
2571+#include <memory>
2572+#include <vector>
2573+
2574+namespace compiz
2575+{
2576+namespace testing
2577+{
2578+namespace messages
2579+{
2580+extern const char *TEST_HELPER_READY_MSG;
2581+extern const char *TEST_HELPER_REGISTER_CLIENT;
2582+extern const char *TEST_HELPER_LOCK_CONFIGURE_REQUESTS;
2583+extern const char *TEST_HELPER_CHANGE_FRAME_EXTENTS;
2584+extern const char *TEST_HELPER_FRAME_EXTENTS_CHANGED;
2585+extern const char *TEST_HELPER_CONFIGURE_WINDOW;
2586+extern const char *TEST_HELPER_WINDOW_CONFIGURE_PROCESSED;
2587+extern const char *TEST_HELPER_WINDOW_READY;
2588+}
2589+
2590+
2591+class MessageAtoms
2592+{
2593+ public:
2594+
2595+ MessageAtoms (Display *);
2596+
2597+ Atom FetchForString (const char *string);
2598+
2599+ private:
2600+
2601+ class Private;
2602+ std::auto_ptr <Private> priv;
2603+};
2604+
2605+bool ReceiveMessage (Display *, Atom, XEvent &, int timeout = 1000);
2606+void SendClientMessage (Display *, Atom, Window, Window, const std::vector <long> &data);
2607+}
2608+}
2609+
2610+#endif
2611
2612=== modified file 'tests/system/xorg-gtest/tests/CMakeLists.txt'
2613--- tests/system/xorg-gtest/tests/CMakeLists.txt 2013-02-19 12:00:19 +0000
2614+++ tests/system/xorg-gtest/tests/CMakeLists.txt 2013-02-19 15:13:21 +0000
2615@@ -2,12 +2,15 @@
2616
2617 if (BUILD_XORG_GTEST AND X11_XI_FOUND)
2618
2619+ add_subdirectory (plugins)
2620+
2621 include_directories (${compiz_SOURCE_DIR}/tests/shared
2622 ${COMPIZ_XORG_SYSTEM_TEST_INCLUDE_DIR}
2623 ${X11_INCLUDE_DIRS}
2624 ${XORG_SERVER_INCLUDE_XORG_GTEST}
2625 ${XORG_SERVER_GTEST_SRC}
2626- ${GTEST_INCLUDE_DIRS})
2627+ ${GTEST_INCLUDE_DIRS}
2628+ ${COMPIZ_XORG_GTEST_COMMUNICATOR_INCLUDE_DIR})
2629
2630 link_directories (${X11_XI_LIBRARY_DIRS}
2631 ${compiz_BINARY_DIR}/tests/shared/src)
2632@@ -15,6 +18,9 @@
2633 add_executable (compiz_xorg_gtest_test_window_stacking
2634 ${CMAKE_CURRENT_SOURCE_DIR}/compiz_xorg_gtest_test_window_stacking.cpp)
2635
2636+ add_executable (compiz_xorg_gtest_test_configure_window
2637+ ${CMAKE_CURRENT_SOURCE_DIR}/compiz_xorg_gtest_configure_window.cpp)
2638+
2639 add_executable (compiz_xorg_gtest_test_icccm
2640 ${CMAKE_CURRENT_SOURCE_DIR}/compiz_xorg_gtest_icccm.cpp)
2641
2642@@ -54,4 +60,9 @@
2643
2644 compiz_discover_tests (compiz_xorg_gtest_test_shape_handling)
2645
2646+ target_link_libraries (compiz_xorg_gtest_test_configure_window
2647+ ${COMPIZ_XORG_GTEST_LIBRARIES})
2648+
2649+ compiz_discover_tests (compiz_xorg_gtest_test_configure_window)
2650+
2651 endif (BUILD_XORG_GTEST AND X11_XI_FOUND)
2652
2653=== added file 'tests/system/xorg-gtest/tests/compiz_xorg_gtest_configure_window.cpp'
2654--- tests/system/xorg-gtest/tests/compiz_xorg_gtest_configure_window.cpp 1970-01-01 00:00:00 +0000
2655+++ tests/system/xorg-gtest/tests/compiz_xorg_gtest_configure_window.cpp 2013-02-19 15:13:21 +0000
2656@@ -0,0 +1,567 @@
2657+/*
2658+ * Compiz XOrg GTest, ConfigureWindow handling
2659+ *
2660+ * Copyright (C) 2012 Sam Spilsbury (smspillaz@gmail.com)
2661+ *
2662+* Permission to use, copy, modify, distribute, and sell this software
2663+* and its documentation for any purpose is hereby granted without
2664+* fee, provided that the above copyright notice appear in all copies
2665+* and that both that copyright notice and this permission notice
2666+* appear in supporting documentation, and that the name of
2667+* Novell, Inc. not be used in advertising or publicity pertaining to
2668+* distribution of the software without specific, written prior permission.
2669+* Novell, Inc. makes no representations about the suitability of this
2670+* software for any purpose. It is provided "as is" without express or
2671+* implied warranty.
2672+*
2673+* NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
2674+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
2675+* NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
2676+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
2677+* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
2678+* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
2679+* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2680+ *
2681+ * Authored By:
2682+ * Sam Spilsbury <smspillaz@gmail.com>
2683+ */
2684+#include <list>
2685+#include <string>
2686+#include <stdexcept>
2687+#include <gtest/gtest.h>
2688+#include <gmock/gmock.h>
2689+#include <boost/function.hpp>
2690+#include <boost/bind.hpp>
2691+#include <xorg/gtest/xorg-gtest.h>
2692+#include <compiz-xorg-gtest.h>
2693+#include <compiz_xorg_gtest_communicator.h>
2694+
2695+#include <gtest_shared_tmpenv.h>
2696+
2697+#include <X11/Xlib.h>
2698+#include <X11/Xatom.h>
2699+
2700+using ::testing::MatchResultListener;
2701+using ::testing::MakeMatcher;
2702+using ::testing::Matcher;
2703+
2704+namespace ct = compiz::testing;
2705+
2706+namespace
2707+{
2708+
2709+bool Advance (Display *d, bool r)
2710+{
2711+ return ct::AdvanceToNextEventOnSuccess (d, r);
2712+}
2713+
2714+Window GetTopParent (Display *display,
2715+ Window w)
2716+{
2717+ Window rootReturn;
2718+ Window parentReturn = w;
2719+ Window *childrenReturn;
2720+ unsigned int nChildrenReturn;
2721+
2722+ Window lastParent = 0;
2723+
2724+ do
2725+ {
2726+ lastParent = parentReturn;
2727+
2728+ XQueryTree (display,
2729+ lastParent,
2730+ &rootReturn,
2731+ &parentReturn,
2732+ &childrenReturn,
2733+ &nChildrenReturn);
2734+ XFree (childrenReturn);
2735+ } while (parentReturn != rootReturn);
2736+
2737+ return lastParent;
2738+}
2739+
2740+bool QueryGeometry (Display *dpy,
2741+ Window w,
2742+ int &x,
2743+ int &y,
2744+ unsigned int &width,
2745+ unsigned int &height)
2746+{
2747+ Window rootRet;
2748+ unsigned int depth, border;
2749+
2750+ if (!XGetGeometry (dpy,
2751+ w,
2752+ &rootRet,
2753+ &x,
2754+ &y,
2755+ &width,
2756+ &height,
2757+ &depth,
2758+ &border))
2759+ return false;
2760+
2761+ return true;
2762+}
2763+
2764+bool WaitForReparentAndMap (Display *dpy,
2765+ Window w)
2766+{
2767+ bool ret = Advance (dpy, ct::WaitForEventOfTypeOnWindow (dpy,
2768+ w,
2769+ ReparentNotify,
2770+ -1,
2771+ -1));
2772+ EXPECT_TRUE (ret);
2773+ if (!ret)
2774+ return false;
2775+
2776+
2777+ ret = Advance (dpy, ct::WaitForEventOfTypeOnWindow (dpy,
2778+ w,
2779+ MapNotify,
2780+ -1,
2781+ -1));
2782+ EXPECT_TRUE (ret);
2783+ if (!ret)
2784+ return false;
2785+
2786+ return true;
2787+}
2788+
2789+struct ReparentedWindow
2790+{
2791+ Window client;
2792+ Window frame;
2793+};
2794+
2795+typedef boost::function <void (Window)> CreateWaitFunc;
2796+
2797+ReparentedWindow
2798+GetNewWindowAndFrame (Display *dpy, const CreateWaitFunc &waitForCreation)
2799+{
2800+ ReparentedWindow w;
2801+
2802+ w.client = ct::CreateNormalWindow (dpy);
2803+ waitForCreation (w.client);
2804+
2805+ XMapRaised (dpy, w.client);
2806+ WaitForReparentAndMap (dpy, w.client);
2807+
2808+ w.frame = GetTopParent (dpy, w.client);
2809+
2810+ XSelectInput (dpy, w.frame, StructureNotifyMask);
2811+
2812+ return w;
2813+}
2814+
2815+bool
2816+WaitForConfigureNotify (Display *dpy,
2817+ Window w,
2818+ int x,
2819+ int y,
2820+ int width,
2821+ int height,
2822+ int border,
2823+ Window above,
2824+ unsigned int mask)
2825+{
2826+ ct::ConfigureNotifyXEventMatcher matcher (above, border, x, y, width, height,
2827+ mask);
2828+
2829+ return Advance (dpy, ct::WaitForEventOfTypeOnWindowMatching (dpy,
2830+ w,
2831+ ConfigureNotify,
2832+ -1,
2833+ -1,
2834+ matcher));
2835+}
2836+
2837+}
2838+
2839+class CompizXorgSystemConfigureWindowTest :
2840+ public ct::AutostartCompizXorgSystemTestWithTestHelper
2841+{
2842+ public:
2843+
2844+ CompizXorgSystemConfigureWindowTest () :
2845+ /* See note in the acceptance tests about this */
2846+ env ("XORG_GTEST_CHILD_STDOUT", "1")
2847+ {
2848+ }
2849+
2850+ void SendConfigureRequest (Window w, int x, int y, int width, int height, int mask);
2851+ void SendSetFrameExtentsRequest (Window w, int left, int right, int top, int bottom);
2852+ void SendConfigureLockRequest (Window w, bool lockRequests);
2853+ bool VerifyConfigureResponse (Window w, int x, int y, int width, int height);
2854+ bool VerifySetFrameExtentsResponse (Window w, int left, int right, int top, int bottom);
2855+ bool VerifyWindowSize (Window w, int x, int y, int width, int height);
2856+
2857+ protected:
2858+
2859+ ReparentedWindow CreateWindow (::Display *);
2860+ int GetEventMask ();
2861+
2862+ private:
2863+
2864+ TmpEnv env;
2865+};
2866+
2867+int
2868+CompizXorgSystemConfigureWindowTest::GetEventMask ()
2869+{
2870+ return ct::AutostartCompizXorgSystemTestWithTestHelper::GetEventMask () |
2871+ SubstructureNotifyMask;
2872+}
2873+
2874+void
2875+CompizXorgSystemConfigureWindowTest::SendConfigureRequest (Window w,
2876+ int x,
2877+ int y,
2878+ int width,
2879+ int height,
2880+ int mask)
2881+{
2882+ ::Display *dpy = Display ();
2883+
2884+ std::vector <long> data;
2885+ data.push_back (x);
2886+ data.push_back (y);
2887+ data.push_back (width);
2888+ data.push_back (height);
2889+ data.push_back (mask);
2890+
2891+ ct::SendClientMessage (dpy,
2892+ FetchAtom (ct::messages::TEST_HELPER_CONFIGURE_WINDOW),
2893+ DefaultRootWindow (dpy),
2894+ w,
2895+ data);
2896+}
2897+
2898+void
2899+CompizXorgSystemConfigureWindowTest::SendSetFrameExtentsRequest (Window w,
2900+ int left,
2901+ int right,
2902+ int top,
2903+ int bottom)
2904+{
2905+ ::Display *dpy = Display ();
2906+
2907+ std::vector <long> data;
2908+ data.push_back (left);
2909+ data.push_back (right);
2910+ data.push_back (top);
2911+ data.push_back (bottom);
2912+
2913+ ct::SendClientMessage (dpy,
2914+ FetchAtom (ct::messages::TEST_HELPER_CHANGE_FRAME_EXTENTS),
2915+ DefaultRootWindow (dpy),
2916+ w,
2917+ data);
2918+}
2919+
2920+void
2921+CompizXorgSystemConfigureWindowTest::SendConfigureLockRequest (Window w,
2922+ bool lockRequests)
2923+{
2924+ ::Display *dpy = Display ();
2925+
2926+ std::vector <long> data;
2927+ data.push_back (lockRequests ? 1 : 0);
2928+
2929+ ct::SendClientMessage (dpy,
2930+ FetchAtom (ct::messages::TEST_HELPER_LOCK_CONFIGURE_REQUESTS),
2931+ DefaultRootWindow (dpy),
2932+ w,
2933+ data);
2934+}
2935+
2936+bool
2937+CompizXorgSystemConfigureWindowTest::VerifyConfigureResponse (Window w,
2938+ int x,
2939+ int y,
2940+ int width,
2941+ int height)
2942+{
2943+ ::Display *dpy = Display ();
2944+ XEvent event;
2945+
2946+ while (ct::ReceiveMessage (dpy,
2947+ FetchAtom (ct::messages::TEST_HELPER_WINDOW_CONFIGURE_PROCESSED),
2948+ event))
2949+ {
2950+ bool requestAcknowledged =
2951+ x == event.xclient.data.l[0] &&
2952+ y == event.xclient.data.l[1] &&
2953+ width == event.xclient.data.l[2] &&
2954+ height == event.xclient.data.l[3];
2955+
2956+ if (requestAcknowledged)
2957+ return true;
2958+
2959+ }
2960+
2961+ return false;
2962+}
2963+
2964+bool
2965+CompizXorgSystemConfigureWindowTest::VerifySetFrameExtentsResponse (Window w,
2966+ int left,
2967+ int right,
2968+ int top,
2969+ int bottom)
2970+{
2971+ ::Display *dpy = Display ();
2972+ XEvent event;
2973+
2974+ while (ct::ReceiveMessage (dpy,
2975+ FetchAtom (ct::messages::TEST_HELPER_FRAME_EXTENTS_CHANGED),
2976+ event))
2977+ {
2978+ bool requestAcknowledged =
2979+ left == event.xclient.data.l[0] &&
2980+ right == event.xclient.data.l[1] &&
2981+ top == event.xclient.data.l[2] &&
2982+ bottom == event.xclient.data.l[3];
2983+
2984+ if (requestAcknowledged)
2985+ return true;
2986+
2987+ }
2988+
2989+ return false;
2990+}
2991+
2992+bool
2993+CompizXorgSystemConfigureWindowTest::VerifyWindowSize (Window w,
2994+ int x,
2995+ int y,
2996+ int width,
2997+ int height)
2998+{
2999+ ::Display *dpy = Display ();
3000+
3001+ int xRet, yRet;
3002+ unsigned int widthRet, heightRet;
3003+ if (!QueryGeometry (dpy, w, xRet, yRet, widthRet, heightRet))
3004+ return false;
3005+
3006+ EXPECT_EQ (x, xRet);
3007+ EXPECT_EQ (y, yRet);
3008+ EXPECT_EQ (width, widthRet);
3009+ EXPECT_EQ (height, heightRet);
3010+
3011+ return true;
3012+}
3013+
3014+ReparentedWindow
3015+CompizXorgSystemConfigureWindowTest::CreateWindow (::Display *dpy)
3016+{
3017+ return GetNewWindowAndFrame (dpy,
3018+ boost::bind (&CompizXorgSystemConfigureWindowTest::WaitForWindowCreation,
3019+ this,
3020+ _1));
3021+}
3022+
3023+TEST_F (CompizXorgSystemConfigureWindowTest, ConfigureAndReponseUnlocked)
3024+{
3025+ ::Display *dpy = Display ();
3026+
3027+ int x = 1;
3028+ int y = 1;
3029+ int width = 100;
3030+ int height = 200;
3031+ int mask = CWX | CWY | CWWidth | CWHeight;
3032+
3033+ ReparentedWindow w = CreateWindow (dpy);
3034+
3035+ SendConfigureRequest (w.client, x, y, width, height, mask);
3036+
3037+ /* Wait for a response */
3038+ ASSERT_TRUE (VerifyConfigureResponse (w.client, x, y, width, height));
3039+
3040+ /* Query the window size again */
3041+ ASSERT_TRUE (VerifyWindowSize (w.frame, x, y, width, height));
3042+
3043+}
3044+
3045+TEST_F (CompizXorgSystemConfigureWindowTest, FrameExtentsAndReponseUnlocked)
3046+{
3047+ ::Display *dpy = Display ();
3048+
3049+ int left = 1;
3050+ int right = 2;
3051+ int top = 3;
3052+ int bottom = 4;
3053+
3054+ ReparentedWindow w = CreateWindow (dpy);
3055+
3056+ int x, y;
3057+ unsigned int width, height;
3058+ ASSERT_TRUE (QueryGeometry (dpy, w.client, x, y, width, height));
3059+
3060+ SendSetFrameExtentsRequest (w.client, left, right, top, bottom);
3061+
3062+ /* Wait for a response */
3063+ ASSERT_TRUE (VerifySetFrameExtentsResponse (w.client, left, right, top, bottom));
3064+
3065+ /* Client geometry is always unchanged */
3066+ ASSERT_TRUE (VerifyWindowSize (w.client, x, y, width, height));
3067+
3068+ /* Frame geometry is frame geometry offset by extents */
3069+ x -= left;
3070+ y -= top;
3071+ width += left + right;
3072+ height += top + bottom;
3073+
3074+ ASSERT_TRUE (VerifyWindowSize (w.frame, x, y, width, height));
3075+}
3076+
3077+TEST_F (CompizXorgSystemConfigureWindowTest, MoveFrameLocked)
3078+{
3079+ ::Display *dpy = Display ();
3080+
3081+ int x = 1;
3082+ int y = 1;
3083+ int width = 0; int height = 0;
3084+ int mask = CWX | CWY;
3085+
3086+ ReparentedWindow w = CreateWindow (dpy);
3087+
3088+ int currentX, currentY;
3089+ unsigned int currentWidth, currentHeight;
3090+ ASSERT_TRUE (QueryGeometry (dpy,
3091+ w.frame,
3092+ currentX,
3093+ currentY,
3094+ currentWidth,
3095+ currentHeight));
3096+
3097+ SendConfigureLockRequest (w.client, true);
3098+ SendConfigureRequest (w.client, x, y, width, height, mask);
3099+
3100+ /* Wait for a response */
3101+ ASSERT_TRUE (VerifyConfigureResponse (w.client, x, y, width, height));
3102+
3103+ /* Query the window size again - it should be the same */
3104+ ASSERT_TRUE (VerifyWindowSize (w.frame,
3105+ currentX,
3106+ currentY,
3107+ currentWidth,
3108+ currentHeight));
3109+
3110+
3111+ SendConfigureLockRequest (w.client, false);
3112+
3113+ /* Expect buffer to be released */
3114+ ASSERT_TRUE (WaitForConfigureNotify (dpy,
3115+ w.frame,
3116+ x,
3117+ y,
3118+ 0,
3119+ 0,
3120+ 0,
3121+ 0,
3122+ mask));
3123+
3124+}
3125+
3126+TEST_F (CompizXorgSystemConfigureWindowTest, ResizeFrameLocked)
3127+{
3128+ ::Display *dpy = Display ();
3129+
3130+ int x = 0;
3131+ int y = 0;
3132+ int width = 200; int height = 300;
3133+ int mask = CWWidth | CWHeight;
3134+
3135+ ReparentedWindow w = CreateWindow (dpy);
3136+
3137+ int currentX, currentY;
3138+ unsigned int currentWidth, currentHeight;
3139+ ASSERT_TRUE (QueryGeometry (dpy,
3140+ w.frame,
3141+ currentX,
3142+ currentY,
3143+ currentWidth,
3144+ currentHeight));
3145+
3146+ SendConfigureLockRequest (w.client, true);
3147+ SendConfigureRequest (w.client, x, y, width, height, mask);
3148+
3149+ /* Expect buffer to be released immediately */
3150+ ASSERT_TRUE (WaitForConfigureNotify (dpy,
3151+ w.frame,
3152+ 0,
3153+ 0,
3154+ width,
3155+ height,
3156+ 0,
3157+ 0,
3158+ mask));
3159+
3160+ /* Wait for a response */
3161+ ASSERT_TRUE (VerifyConfigureResponse (w.client, x, y, width, height));
3162+
3163+ SendConfigureLockRequest (w.client, false);
3164+
3165+ /* Query the window size again - it should be the same */
3166+ ASSERT_TRUE (VerifyWindowSize (w.frame,
3167+ currentX,
3168+ currentY,
3169+ width,
3170+ height));
3171+}
3172+
3173+TEST_F (CompizXorgSystemConfigureWindowTest, SetFrameExtentsLocked)
3174+{
3175+ ::Display *dpy = Display ();
3176+
3177+ /* Give the client window a 1px border, this will cause
3178+ * the client to move within the frame window by 1, 1 ,
3179+ * the frame window to move by -1, -1 and resize by 2, 2 */
3180+ int left = 1;
3181+ int right = 1;
3182+ int top = 1;
3183+ int bottom = 1;
3184+ int frameMask = CWX | CWY | CWWidth | CWHeight;
3185+
3186+ ReparentedWindow w = CreateWindow (dpy);
3187+
3188+ int currentX, currentY;
3189+ unsigned int currentWidth, currentHeight;
3190+ ASSERT_TRUE (QueryGeometry (dpy,
3191+ w.frame,
3192+ currentX,
3193+ currentY,
3194+ currentWidth,
3195+ currentHeight));
3196+
3197+ SendConfigureLockRequest (w.client, true);
3198+ SendSetFrameExtentsRequest (w.client, left, right, top, bottom);
3199+
3200+ /* Expect buffer to be released immediately */
3201+ ASSERT_TRUE (WaitForConfigureNotify (dpy,
3202+ w.frame,
3203+ currentX - left,
3204+ currentY - top,
3205+ currentWidth + (left + right),
3206+ currentHeight + (top + bottom),
3207+ 0,
3208+ 0,
3209+ frameMask));
3210+
3211+
3212+ /* Wait for a response */
3213+ ASSERT_TRUE (VerifySetFrameExtentsResponse (w.client, left, right, top, bottom));
3214+
3215+ SendConfigureLockRequest (w.client, false);
3216+
3217+ /* Query the window size again - it should be the same */
3218+ ASSERT_TRUE (VerifyWindowSize (w.frame,
3219+ currentX - left,
3220+ currentY - top,
3221+ currentWidth + (left + right),
3222+ currentHeight + (top + bottom)));
3223+}
3224
3225=== modified file 'tests/system/xorg-gtest/tests/compiz_xorg_gtest_ewmh.cpp'
3226--- tests/system/xorg-gtest/tests/compiz_xorg_gtest_ewmh.cpp 2013-01-16 01:48:25 +0000
3227+++ tests/system/xorg-gtest/tests/compiz_xorg_gtest_ewmh.cpp 2013-02-19 15:13:21 +0000
3228@@ -94,7 +94,8 @@
3229 {
3230 ::Display *dpy = Display ();
3231 StartCompiz (static_cast <ct::CompizProcess::StartupFlags> (
3232- ct::CompizProcess::ReplaceCurrentWM));
3233+ ct::CompizProcess::ReplaceCurrentWM),
3234+ ct::CompizProcess::PluginList ());
3235
3236 ct::PropertyNotifyXEventMatcher desktopHintsProperty (dpy,
3237 "_NET_DESKTOP_GEOMETRY");
3238
3239=== modified file 'tests/system/xorg-gtest/tests/compiz_xorg_gtest_icccm.cpp'
3240--- tests/system/xorg-gtest/tests/compiz_xorg_gtest_icccm.cpp 2013-02-15 11:28:27 +0000
3241+++ tests/system/xorg-gtest/tests/compiz_xorg_gtest_icccm.cpp 2013-02-19 15:13:21 +0000
3242@@ -95,6 +95,12 @@
3243 {
3244 public:
3245
3246+ CompizXorgSystemICCCM () :
3247+ /* See note in the acceptance tests about this */
3248+ env ("XORG_GTEST_CHILD_STDOUT", "1")
3249+ {
3250+ }
3251+
3252 virtual void SetUp ()
3253 {
3254 ct::CompizXorgSystemTest::SetUp ();
3255@@ -109,6 +115,8 @@
3256 }
3257
3258 private:
3259+
3260+ TmpEnv env;
3261 };
3262
3263 TEST_F (CompizXorgSystemICCCM, SomeoneElseHasSubstructureRedirectMask)
3264@@ -116,7 +124,8 @@
3265 StartCompiz (static_cast <ct::CompizProcess::StartupFlags> (
3266 ct::CompizProcess::ExpectStartupFailure |
3267 ct::CompizProcess::ReplaceCurrentWM |
3268- ct::CompizProcess::WaitForStartupMessage));
3269+ ct::CompizProcess::WaitForStartupMessage),
3270+ ct::CompizProcess::PluginList ());
3271
3272 WaitForSuccessDeathTask::GetProcessState processState (boost::bind (&CompizXorgSystemICCCM::CompizProcessState,
3273 this));
3274@@ -152,7 +161,8 @@
3275
3276 StartCompiz (static_cast <ct::CompizProcess::StartupFlags> (
3277 ct::CompizProcess::ReplaceCurrentWM |
3278- ct::CompizProcess::WaitForStartupMessage));
3279+ ct::CompizProcess::WaitForStartupMessage),
3280+ ct::CompizProcess::PluginList ());
3281 }
3282 };
3283
3284@@ -233,7 +243,9 @@
3285 REQUEST_X,
3286 REQUEST_Y,
3287 REQUEST_WIDTH,
3288- REQUEST_HEIGHT);
3289+ REQUEST_HEIGHT,
3290+ configureRequestEvent->value_mask &
3291+ ~(CWSibling | CWStackMode));
3292
3293 /* Should get a ConfigureNotify with the right parameters */
3294 EXPECT_TRUE (Advance (dpy, ct::WaitForEventOfTypeOnWindowMatching (dpy,
3295
3296=== added directory 'tests/system/xorg-gtest/tests/plugins'
3297=== added file 'tests/system/xorg-gtest/tests/plugins/CMakeLists.txt'
3298--- tests/system/xorg-gtest/tests/plugins/CMakeLists.txt 1970-01-01 00:00:00 +0000
3299+++ tests/system/xorg-gtest/tests/plugins/CMakeLists.txt 2013-02-19 15:13:21 +0000
3300@@ -0,0 +1,10 @@
3301+set (COMPIZ_CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
3302+set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${COMPIZ_CMAKE_MODULE_PATH})
3303+include (CompizDefaults)
3304+include (CompizCommon)
3305+
3306+set (COMPIZ_FOUND "true")
3307+
3308+include_directories (${COMPIZ_INTERNAL_INCLUDES})
3309+
3310+add_subdirectory (testhelper)
3311
3312=== added directory 'tests/system/xorg-gtest/tests/plugins/testhelper'
3313=== added file 'tests/system/xorg-gtest/tests/plugins/testhelper/CMakeLists.txt'
3314--- tests/system/xorg-gtest/tests/plugins/testhelper/CMakeLists.txt 1970-01-01 00:00:00 +0000
3315+++ tests/system/xorg-gtest/tests/plugins/testhelper/CMakeLists.txt 2013-02-19 15:13:21 +0000
3316@@ -0,0 +1,7 @@
3317+find_package (Compiz REQUIRED)
3318+
3319+include (CompizPlugin)
3320+
3321+include_directories (${COMPIZ_XORG_GTEST_COMMUNICATOR_INCLUDE_DIR})
3322+
3323+compiz_plugin (testhelper LIBRARIES ${COMPIZ_XORG_GTEST_COMMUNICATOR_LIBRARY})
3324
3325=== added directory 'tests/system/xorg-gtest/tests/plugins/testhelper/src'
3326=== added file 'tests/system/xorg-gtest/tests/plugins/testhelper/src/testhelper.cpp'
3327--- tests/system/xorg-gtest/tests/plugins/testhelper/src/testhelper.cpp 1970-01-01 00:00:00 +0000
3328+++ tests/system/xorg-gtest/tests/plugins/testhelper/src/testhelper.cpp 2013-02-19 15:13:21 +0000
3329@@ -0,0 +1,231 @@
3330+/*
3331+* Copyright © 2013 Sam Spilsbury
3332+*
3333+* Permission to use, copy, modify, distribute, and sell this software
3334+* and its documentation for any purpose is hereby granted without
3335+* fee, provided that the above copyright notice appear in all copies
3336+* and that both that copyright notice and this permission notice
3337+* appear in supporting documentation, and that the name of
3338+* Novell, Inc. not be used in advertising or publicity pertaining to
3339+* distribution of the software without specific, written prior permission.
3340+* Novell, Inc. makes no representations about the suitability of this
3341+* software for any purpose. It is provided "as is" without express or
3342+* implied warranty.
3343+*
3344+* NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
3345+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
3346+* NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
3347+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
3348+* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
3349+* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
3350+* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
3351+*
3352+* Author: Sam Spilsbury <smspillaz@gmail.com>
3353+*/
3354+
3355+#include <boost/shared_ptr.hpp>
3356+#include <boost/bind.hpp>
3357+#include "testhelper.h"
3358+
3359+COMPIZ_PLUGIN_20090315 (testhelper, TestHelperPluginVTable)
3360+
3361+namespace
3362+{
3363+template <typename T>
3364+void XFreeT (T *t)
3365+{
3366+ XFree (t);
3367+}
3368+}
3369+
3370+namespace ct = compiz::testing;
3371+namespace ctm = compiz::testing::messages;
3372+
3373+void
3374+TestHelperScreen::handleEvent (XEvent *event)
3375+{
3376+ if (event->type == ClientMessage)
3377+ {
3378+ if (event->xclient.window != screen->root ())
3379+ {
3380+ std::map <Atom, ClientMessageHandler>::iterator it =
3381+ mMessageHandlers.find (event->xclient.message_type);
3382+
3383+ if (it != mMessageHandlers.end ())
3384+ {
3385+ ClientMessageHandler handler (it->second);
3386+ CompWindow *w = screen->findWindow (event->xclient.window);
3387+
3388+ XClientMessageEvent *xce = &event->xclient;
3389+ long *data = xce->data.l;
3390+
3391+ if (w)
3392+ ((*TestHelperWindow::get (w)).*(handler)) (data);
3393+ }
3394+ }
3395+ }
3396+
3397+ screen->handleEvent (event);
3398+}
3399+
3400+void
3401+TestHelperScreen::watchForMessage (Atom message, ClientMessageHandler handler)
3402+{
3403+ if (mMessageHandlers.find (message) != mMessageHandlers.end ())
3404+ {
3405+ boost::shared_ptr <char> name (XGetAtomName (screen->dpy (), message),
3406+ boost::bind (XFreeT <char>, _1));
3407+ compLogMessage ("testhelper", CompLogLevelWarn,
3408+ "a message handler was already defined for %s",
3409+ name.get ());
3410+ return;
3411+ }
3412+
3413+ mMessageHandlers[message] = handler;
3414+}
3415+
3416+void
3417+TestHelperScreen::removeMessageWatch (Atom message)
3418+{
3419+ std::map <Atom, ClientMessageHandler>::iterator it =
3420+ mMessageHandlers.find (message);
3421+
3422+ if (it != mMessageHandlers.end ())
3423+ mMessageHandlers.erase (it);
3424+}
3425+
3426+Atom
3427+TestHelperScreen::fetchAtom (const char *message)
3428+{
3429+ return mAtomStore.FetchForString (message);
3430+}
3431+
3432+void
3433+TestHelperWindow::configureAndReport (long *data)
3434+{
3435+ XWindowChanges xwc;
3436+ XWindowChanges saved;
3437+
3438+ xwc.x = data[0];
3439+ xwc.y = data[1];
3440+ xwc.width = data[2];
3441+ xwc.height = data[3];
3442+ int mask = data[4];
3443+
3444+ /* configureXWindow has a nasty side-effect of
3445+ * changing xwc to the client-window co-ordinates,
3446+ * so we should back it up first */
3447+ saved = xwc;
3448+
3449+ window->configureXWindow (mask, &xwc);
3450+
3451+ xwc = saved;
3452+
3453+ std::vector <long> response;
3454+
3455+ response.push_back (xwc.x);
3456+ response.push_back (xwc.y);
3457+ response.push_back (xwc.width);
3458+ response.push_back (xwc.height);
3459+
3460+ TestHelperScreen *ts = TestHelperScreen::get (screen);
3461+ const Atom atom = ts->fetchAtom (ctm::TEST_HELPER_WINDOW_CONFIGURE_PROCESSED);
3462+
3463+ ct::SendClientMessage (screen->dpy (),
3464+ atom,
3465+ screen->root (),
3466+ window->id (),
3467+ response);
3468+}
3469+
3470+void
3471+TestHelperWindow::setFrameExtentsAndReport (long *data)
3472+{
3473+ CompWindowExtents input;
3474+
3475+ input.left = data[0];
3476+ input.right = data[1];
3477+ input.top = data[2];
3478+ input.bottom = data[3];
3479+
3480+ window->setWindowFrameExtents (&input, &input);
3481+
3482+ std::vector <long> response;
3483+
3484+ response.push_back (input.left);
3485+ response.push_back (input.right);
3486+ response.push_back (input.top);
3487+ response.push_back (input.bottom);
3488+
3489+ TestHelperScreen *ts = TestHelperScreen::get (screen);
3490+ const Atom atom = ts->fetchAtom (ctm::TEST_HELPER_FRAME_EXTENTS_CHANGED);
3491+
3492+ ct::SendClientMessage (screen->dpy (),
3493+ atom,
3494+ screen->root (),
3495+ window->id (),
3496+ response);
3497+}
3498+
3499+void
3500+TestHelperWindow::setConfigureLock (long *data)
3501+{
3502+ bool enabled = data[0] ? true : false;
3503+
3504+ if (enabled && !configureLock)
3505+ configureLock = window->obtainLockOnConfigureRequests ();
3506+ else if (!enabled && configureLock)
3507+ {
3508+ configureLock->release ();
3509+ configureLock.reset ();
3510+ }
3511+}
3512+
3513+TestHelperWindow::TestHelperWindow (CompWindow *w) :
3514+ PluginClassHandler <TestHelperWindow, CompWindow> (w),
3515+ window (w),
3516+ configureLock ()
3517+{
3518+ WindowInterface::setHandler (w);
3519+
3520+ TestHelperScreen *ts = TestHelperScreen::get (screen);
3521+
3522+ std::vector <long> data;
3523+ data.push_back (static_cast <long> (window->id ()));
3524+ ct::SendClientMessage (screen->dpy (),
3525+ ts->fetchAtom (ctm::TEST_HELPER_WINDOW_READY),
3526+ screen->root (),
3527+ screen->root (),
3528+ data);
3529+}
3530+
3531+TestHelperScreen::TestHelperScreen (CompScreen *s) :
3532+ PluginClassHandler <TestHelperScreen, CompScreen> (s),
3533+ screen (s),
3534+ mAtomStore (s->dpy ())
3535+{
3536+ ScreenInterface::setHandler (s);
3537+
3538+ /* Register the message handlers on each window */
3539+ watchForMessage (fetchAtom (ctm::TEST_HELPER_CONFIGURE_WINDOW),
3540+ &TestHelperWindow::configureAndReport);
3541+ watchForMessage (fetchAtom (ctm::TEST_HELPER_CHANGE_FRAME_EXTENTS),
3542+ &TestHelperWindow::setFrameExtentsAndReport);
3543+ watchForMessage (fetchAtom (ctm::TEST_HELPER_LOCK_CONFIGURE_REQUESTS),
3544+ &TestHelperWindow::setConfigureLock);
3545+
3546+ ct::SendClientMessage (s->dpy (),
3547+ mAtomStore.FetchForString (ctm::TEST_HELPER_READY_MSG),
3548+ s->root (),
3549+ s->root (),
3550+ std::vector <long> ());
3551+}
3552+
3553+bool
3554+TestHelperPluginVTable::init ()
3555+{
3556+ if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION))
3557+ return false;
3558+
3559+ return true;
3560+}
3561
3562=== added file 'tests/system/xorg-gtest/tests/plugins/testhelper/src/testhelper.h'
3563--- tests/system/xorg-gtest/tests/plugins/testhelper/src/testhelper.h 1970-01-01 00:00:00 +0000
3564+++ tests/system/xorg-gtest/tests/plugins/testhelper/src/testhelper.h 2013-02-19 15:13:21 +0000
3565@@ -0,0 +1,95 @@
3566+/*
3567+* Copyright © 2013 Sam Spilsbury
3568+*
3569+* Permission to use, copy, modify, distribute, and sell this software
3570+* and its documentation for any purpose is hereby granted without
3571+* fee, provided that the above copyright notice appear in all copies
3572+* and that both that copyright notice and this permission notice
3573+* appear in supporting documentation, and that the name of
3574+* Novell, Inc. not be used in advertising or publicity pertaining to
3575+* distribution of the software without specific, written prior permission.
3576+* Novell, Inc. makes no representations about the suitability of this
3577+* software for any purpose. It is provided "as is" without express or
3578+* implied warranty.
3579+*
3580+* NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
3581+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
3582+* NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
3583+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
3584+* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
3585+* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
3586+* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
3587+*
3588+* Author: Sam Spilsbury <smspillaz@gmail.com>
3589+*/
3590+#ifndef _COMPIZ_TESTHELPER_H
3591+#define _COMPIZ_TESTHELPER_H
3592+
3593+#include <map>
3594+#include <boost/function.hpp>
3595+
3596+#include <X11/Xatom.h>
3597+
3598+#include <core/core.h>
3599+#include <core/pluginclasshandler.h>
3600+#include <core/configurerequestbuffer.h>
3601+
3602+#include <compiz_xorg_gtest_communicator.h>
3603+
3604+#include "testhelper_options.h"
3605+
3606+class TestHelperWindow;
3607+
3608+class TestHelperScreen :
3609+ public PluginClassHandler <TestHelperScreen, CompScreen>,
3610+ public ScreenInterface,
3611+ public TesthelperOptions
3612+{
3613+ public:
3614+
3615+ typedef void (TestHelperWindow::*ClientMessageHandler) (long *);
3616+
3617+ TestHelperScreen (CompScreen *);
3618+
3619+ void handleEvent (XEvent *event);
3620+
3621+ void watchForMessage (Atom, ClientMessageHandler);
3622+ void removeMessageWatch (Atom);
3623+
3624+ Atom fetchAtom (const char *);
3625+
3626+
3627+ private:
3628+
3629+ CompScreen *screen;
3630+ compiz::testing::MessageAtoms mAtomStore;
3631+ std::map <Atom, ClientMessageHandler> mMessageHandlers;
3632+};
3633+
3634+class TestHelperWindow :
3635+ public PluginClassHandler <TestHelperWindow, CompWindow>,
3636+ public WindowInterface
3637+{
3638+ public:
3639+
3640+ TestHelperWindow (CompWindow *);
3641+
3642+ void configureAndReport (long *);
3643+ void setFrameExtentsAndReport (long *);
3644+ void setConfigureLock (long *);
3645+
3646+ private:
3647+
3648+ CompWindow *window;
3649+ compiz::window::configure_buffers::Releasable::Ptr configureLock;
3650+};
3651+
3652+class TestHelperPluginVTable :
3653+ public CompPlugin::VTableForScreenAndWindow <TestHelperScreen, TestHelperWindow>
3654+{
3655+ public:
3656+
3657+ bool init ();
3658+};
3659+
3660+#endif
3661
3662=== added file 'tests/system/xorg-gtest/tests/plugins/testhelper/testhelper.xml.in'
3663--- tests/system/xorg-gtest/tests/plugins/testhelper/testhelper.xml.in 1970-01-01 00:00:00 +0000
3664+++ tests/system/xorg-gtest/tests/plugins/testhelper/testhelper.xml.in 2013-02-19 15:13:21 +0000
3665@@ -0,0 +1,6 @@
3666+<?xml version="1.0" encoding="UTF-8"?>
3667+<compiz>
3668+ <plugin name="testhelper" useBcop="true">
3669+ <options/>
3670+ </plugin>
3671+</compiz>
3672
3673=== modified file 'tests/xorg-gtest/include/compiz-xorg-gtest.h'
3674--- tests/xorg-gtest/include/compiz-xorg-gtest.h 2013-01-11 06:27:22 +0000
3675+++ tests/xorg-gtest/include/compiz-xorg-gtest.h 2013-02-19 15:13:21 +0000
3676@@ -37,6 +37,24 @@
3677 {
3678 typedef ::testing::MatcherInterface <const XEvent &> XEventMatcher;
3679
3680+ class PrivateClientMessageXEventMatcher;
3681+ class ClientMessageXEventMatcher :
3682+ public compiz::testing::XEventMatcher
3683+ {
3684+ public:
3685+
3686+ ClientMessageXEventMatcher (Display *display,
3687+ Atom message,
3688+ Window target);
3689+
3690+ virtual bool MatchAndExplain (const XEvent &event, MatchResultListener *listener) const;
3691+ virtual void DescribeTo (std::ostream *os) const;
3692+
3693+ private:
3694+
3695+ std::auto_ptr <PrivateClientMessageXEventMatcher> priv;
3696+ };
3697+
3698 class PrivatePropertyNotifyXEventMatcher;
3699 class PropertyNotifyXEventMatcher :
3700 public compiz::testing::XEventMatcher
3701@@ -65,7 +83,8 @@
3702 int x,
3703 int y,
3704 unsigned int width,
3705- unsigned int height);
3706+ unsigned int height,
3707+ unsigned int mask);
3708
3709 virtual bool MatchAndExplain (const XEvent &event, MatchResultListener *listener) const;
3710 virtual void DescribeTo (std::ostream *os) const;
3711@@ -132,7 +151,12 @@
3712 ExpectStartupFailure = (1 << 2)
3713 } StartupFlags;
3714
3715- CompizProcess (Display *dpy, StartupFlags, unsigned int waitTimeout);
3716+ typedef std::vector <std::string> PluginList;
3717+
3718+ CompizProcess (Display *dpy,
3719+ StartupFlags,
3720+ const PluginList &plugins,
3721+ unsigned int waitTimeout);
3722 ~CompizProcess ();
3723 xorg::testing::Process::State State ();
3724 pid_t Pid ();
3725@@ -153,18 +177,52 @@
3726 virtual void TearDown ();
3727
3728 xorg::testing::Process::State CompizProcessState ();
3729- void StartCompiz (CompizProcess::StartupFlags flags);
3730+ void StartCompiz (CompizProcess::StartupFlags flags,
3731+ const CompizProcess::PluginList &plugins);
3732
3733 private:
3734 std::auto_ptr <PrivateCompizXorgSystemTest> priv;
3735 };
3736
3737+ class PrivateAutostartCompizXorgSystemTest;
3738 class AutostartCompizXorgSystemTest :
3739 public CompizXorgSystemTest
3740 {
3741 public:
3742
3743- virtual void SetUp ();
3744+ AutostartCompizXorgSystemTest ();
3745+
3746+ virtual CompizProcess::StartupFlags GetStartupFlags ();
3747+ virtual int GetEventMask ();
3748+ virtual CompizProcess::PluginList GetPluginList ();
3749+ virtual void SetUp ();
3750+
3751+ private:
3752+ std::auto_ptr <PrivateAutostartCompizXorgSystemTest> priv;
3753+ };
3754+
3755+ class PrivateAutostartCompizXorgSystemTestWithTestHelper;
3756+ class AutostartCompizXorgSystemTestWithTestHelper :
3757+ public AutostartCompizXorgSystemTest
3758+ {
3759+ public:
3760+
3761+ AutostartCompizXorgSystemTestWithTestHelper ();
3762+
3763+ virtual CompizProcess::PluginList GetPluginList ();
3764+
3765+ protected:
3766+
3767+ Atom FetchAtom (const char *);
3768+ void WaitForWindowCreation (Window w);
3769+
3770+ virtual int GetEventMask ();
3771+
3772+ private:
3773+
3774+ virtual void SetUp ();
3775+
3776+ std::auto_ptr <PrivateAutostartCompizXorgSystemTestWithTestHelper> priv;
3777 };
3778 }
3779 }
3780
3781=== modified file 'tests/xorg-gtest/src/CMakeLists.txt'
3782--- tests/xorg-gtest/src/CMakeLists.txt 2013-02-15 11:28:27 +0000
3783+++ tests/xorg-gtest/src/CMakeLists.txt 2013-02-19 15:13:21 +0000
3784@@ -1,2 +1,59 @@
3785+<<<<<<< TREE
3786 add_executable (xorg_gtest_wrapper
3787 ${CMAKE_CURRENT_SOURCE_DIR}/xorg_gtest_wrapper.cpp)
3788+=======
3789+set (COMPIZ_LD_LIBRARY_PATH ${CMAKE_BINARY_DIR}/src CACHE STRING "" FORCE)
3790+set (COMPIZ_BINARY ${CMAKE_BINARY_DIR}/src/compiz CACHE STRING "" FORCE)
3791+
3792+configure_file (${CMAKE_CURRENT_SOURCE_DIR}/compiz-xorg-gtest-config.h.in
3793+ ${CMAKE_CURRENT_BINARY_DIR}/compiz-xorg-gtest-config.h
3794+ @ONLY)
3795+
3796+add_definitions (${_xorg_gtest_cflags})
3797+
3798+include_directories (${COMPIZ_XORG_SYSTEM_TEST_INCLUDE_DIR}
3799+ ${XORG_SERVER_INCLUDE_DIRS}
3800+ ${GTEST_INCLUDE_DIRS}
3801+ ${XORG_SERVER_INCLUDE_XORG_GTEST}
3802+ ${XORG_SERVER_GTEST_SRC}
3803+ ${CMAKE_CURRENT_BINARY_DIR}
3804+ ${COMPIZ_XORG_GTEST_COMMUNICATOR_INCLUDE_DIR}
3805+ ${compiz_SOURCE_DIR}/tests/shared)
3806+
3807+link_directories (${XORG_SERVER_LIBRARY_DIRS})
3808+
3809+# This actually includes xorg-gtest-all and the defines
3810+set (_xorg_gtest_all_srcs
3811+ ${XORG_SERVER_GTEST_SRC}/src/xorg-gtest-all.cpp)
3812+
3813+set (_xorg_gtest_main_srcs
3814+ ${XORG_SERVER_GTEST_SRC}/src/xorg-gtest_main.cpp)
3815+
3816+add_library (xorg_gtest_all STATIC
3817+ ${_xorg_gtest_all_srcs})
3818+
3819+add_library (xorg_gtest_main STATIC
3820+ ${_xorg_gtest_main_srcs})
3821+
3822+add_library (compiz_xorg_gtest_system_test STATIC
3823+ ${CMAKE_CURRENT_SOURCE_DIR}/compiz-xorg-gtest.cpp)
3824+
3825+target_link_libraries (xorg_gtest_all
3826+ ${GTEST_BOTH_LIBRARIES}
3827+ ${CMAKE_THREAD_LIBS_INIT}
3828+ ${XORG_SERVER_LIBRARIES})
3829+
3830+target_link_libraries (xorg_gtest_main
3831+ ${GTEST_BOTH_LIBRARIES}
3832+ ${CMAKE_THREAD_LIBS_INIT}
3833+ ${XORG_SERVER_LIBRARIES})
3834+
3835+target_link_libraries (compiz_xorg_gtest_system_test
3836+ xorg_gtest_all
3837+ xorg_gtest_main
3838+ ${GTEST_BOTH_LIBRARIES}
3839+ ${CMAKE_THREAD_LIBS_INIT}
3840+ ${XORG_SERVER_LIBRARIES}
3841+ ${X11_XI_LIBRARIES}
3842+ ${COMPIZ_XORG_GTEST_COMMUNICATOR_LIBRARY})
3843+>>>>>>> MERGE-SOURCE
3844
3845=== modified file 'tests/xorg-gtest/src/compiz-xorg-gtest-config.h.in'
3846--- tests/xorg-gtest/src/compiz-xorg-gtest-config.h.in 2012-09-18 13:17:09 +0000
3847+++ tests/xorg-gtest/src/compiz-xorg-gtest-config.h.in 2013-02-19 15:13:21 +0000
3848@@ -25,8 +25,9 @@
3849
3850 namespace
3851 {
3852- const std::string compizLDLibraryPath ("@COMPIZ_LD_LIBRARY_PATH@");//("/home/smspillaz/Source/Compiz/dev/dev/merges/compiz/proposed/compiz/build/src/");
3853- const std::string compizBinaryPath ("@COMPIZ_BINARY@");//("/home/smspillaz/Source/Compiz/dev/dev/merges/compiz/proposed/compiz/build/src/compiz");
3854+ const std::string compizLDLibraryPath ("@COMPIZ_LD_LIBRARY_PATH@");
3855+ const std::string compizBinaryPath ("@COMPIZ_BINARY@");
3856+ const std::string compizOverridePluginPath ("@COMPIZ_OVERRIDE_PLUGIN_PATH@");
3857 }
3858
3859 #endif
3860
3861=== modified file 'tests/xorg-gtest/src/compiz-xorg-gtest.cpp'
3862--- tests/xorg-gtest/src/compiz-xorg-gtest.cpp 2013-02-19 01:06:21 +0000
3863+++ tests/xorg-gtest/src/compiz-xorg-gtest.cpp 2013-02-19 15:13:21 +0000
3864@@ -22,12 +22,16 @@
3865 */
3866 #include <list>
3867 #include <stdexcept>
3868+#include <sstream>
3869 #include <iomanip>
3870 #include <gtest/gtest.h>
3871 #include <gmock/gmock.h>
3872 #include <boost/shared_ptr.hpp>
3873+#include <gtest_shared_tmpenv.h>
3874+#include <gtest_shared_characterwrapper.h>
3875 #include <xorg/gtest/xorg-gtest.h>
3876 #include <compiz-xorg-gtest.h>
3877+#include <compiz_xorg_gtest_communicator.h>
3878 #include <X11/Xlib.h>
3879 #include <X11/Xatom.h>
3880 #include <X11/extensions/shape.h>
3881@@ -49,7 +53,6 @@
3882 const unsigned int WINDOW_CLASS = InputOutput;
3883 Visual *WINDOW_VISUAL = CopyFromParent;
3884
3885-
3886 const long WINDOW_ATTRIB_VALUE_MASK = 0;
3887
3888 void RemoveEventFromQueue (Display *dpy)
3889@@ -142,6 +145,10 @@
3890 return true;
3891 }
3892
3893+ std::stringstream ss;
3894+ matcher.DescribeTo (&ss);
3895+ ADD_FAILURE () << "Expected event matching: " << ss.str ();
3896+
3897 return false;
3898 }
3899
3900@@ -221,6 +228,54 @@
3901 };
3902 }
3903
3904+class ct::PrivateClientMessageXEventMatcher
3905+{
3906+ public:
3907+
3908+ PrivateClientMessageXEventMatcher (Display *display,
3909+ Atom message,
3910+ Window target) :
3911+ display (display),
3912+ message (message),
3913+ target (target)
3914+ {
3915+ }
3916+
3917+ Display *display;
3918+ Atom message;
3919+ Window target;
3920+};
3921+
3922+ct::ClientMessageXEventMatcher::ClientMessageXEventMatcher (Display *display,
3923+ Atom message,
3924+ Window target) :
3925+ priv (new ct::PrivateClientMessageXEventMatcher (display, message, target))
3926+{
3927+}
3928+
3929+bool
3930+ct::ClientMessageXEventMatcher::MatchAndExplain (const XEvent &event, MatchResultListener *listener) const
3931+{
3932+ const XClientMessageEvent *xce = reinterpret_cast <const XClientMessageEvent *> (&event);
3933+
3934+ if (xce->message_type == priv->message &&
3935+ xce->window == priv->target)
3936+ return true;
3937+
3938+ return false;
3939+}
3940+
3941+void
3942+ct::ClientMessageXEventMatcher::DescribeTo (std::ostream *os) const
3943+{
3944+ CharacterWrapper name (XGetAtomName (priv->display,
3945+ priv->message));
3946+ *os << "matches ClientMessage with type " << name
3947+ << " on window "
3948+ << std::hex << static_cast <long> (priv->target)
3949+ << std::dec << std::endl;
3950+}
3951+
3952 class ct::PrivatePropertyNotifyXEventMatcher
3953 {
3954 public:
3955@@ -268,13 +323,15 @@
3956 int x,
3957 int y,
3958 unsigned int width,
3959- unsigned int height) :
3960+ unsigned int height,
3961+ unsigned int mask) :
3962 mAbove (above),
3963 mBorder (border),
3964 mX (x),
3965 mY (y),
3966 mWidth (width),
3967- mHeight (height)
3968+ mHeight (height),
3969+ mMask (mask)
3970 {
3971 }
3972
3973@@ -284,6 +341,7 @@
3974 int mY;
3975 int mWidth;
3976 int mHeight;
3977+ unsigned int mMask;
3978 };
3979
3980 ct::ConfigureNotifyXEventMatcher::ConfigureNotifyXEventMatcher (Window above,
3981@@ -291,13 +349,15 @@
3982 int x,
3983 int y,
3984 unsigned int width,
3985- unsigned int height) :
3986+ unsigned int height,
3987+ unsigned int mask) :
3988 priv (new ct::PrivateConfigureNotifyXEventMatcher (above,
3989 border,
3990 x,
3991 y,
3992 width,
3993- height))
3994+ height,
3995+ mask))
3996 {
3997 }
3998
3999@@ -306,24 +366,58 @@
4000 {
4001 const XConfigureEvent *ce = reinterpret_cast <const XConfigureEvent *> (&event);
4002
4003- return ce->above == priv->mAbove &&
4004- ce->border_width == priv->mBorder &&
4005- ce->x == priv->mX &&
4006- ce->y == priv->mY &&
4007- ce->width == priv->mWidth &&
4008- ce->height == priv->mHeight;
4009+ if (priv->mMask & CWSibling)
4010+ if (ce->above != priv->mAbove)
4011+ return false;
4012+
4013+ if (priv->mMask & CWBorderWidth)
4014+ if (ce->border_width != priv->mBorder)
4015+ return false;
4016+
4017+ if (priv->mMask & CWX)
4018+ if (ce->x != priv->mX)
4019+ return false;
4020+
4021+ if (priv->mMask & CWY)
4022+ if (ce->y != priv->mY)
4023+ return false;
4024+
4025+ if (priv->mMask & CWWidth)
4026+ if (ce->width != priv->mWidth)
4027+ return false;
4028+
4029+ if (priv->mMask & CWHeight)
4030+ if (ce->height != priv->mHeight)
4031+ return false;
4032+
4033+ return true;
4034 }
4035
4036 void
4037 ct::ConfigureNotifyXEventMatcher::DescribeTo (std::ostream *os) const
4038 {
4039+ std::stringstream x, y, width, height, border, sibling;
4040+
4041+ if (priv->mMask & CWX)
4042+ x << " x: " << priv->mX;
4043+
4044+ if (priv->mMask & CWY)
4045+ y << " y: " << priv->mY;
4046+
4047+ if (priv->mMask & CWWidth)
4048+ width << " width: " << priv->mWidth;
4049+
4050+ if (priv->mMask & CWHeight)
4051+ height << " height: " << priv->mHeight;
4052+
4053+ if (priv->mMask & CWBorderWidth)
4054+ border << " border: " << priv->mBorder;
4055+
4056+ if (priv->mMask & CWSibling)
4057+ sibling << " above: " << std::hex << priv->mAbove << std::dec;
4058+
4059 *os << "Matches ConfigureNotify with parameters : " << std::endl <<
4060- " x: " << priv->mX <<
4061- " y: " << priv->mY <<
4062- " width: " << priv->mWidth <<
4063- " height: " << priv->mHeight <<
4064- " border: " << priv->mBorder <<
4065- " above: " << std::hex << priv->mAbove << std::dec;
4066+ x.str () << y.str () << width.str () << height.str () << border.str () << sibling.str ();
4067 }
4068
4069 class ct::PrivateShapeNotifyXEventMatcher
4070@@ -450,9 +544,10 @@
4071 XSelectInput (dpy, root, attrib.your_event_mask);
4072 }
4073
4074-ct::CompizProcess::CompizProcess (::Display *dpy,
4075- ct::CompizProcess::StartupFlags flags,
4076- unsigned int waitTimeout) :
4077+ct::CompizProcess::CompizProcess (::Display *dpy,
4078+ ct::CompizProcess::StartupFlags flags,
4079+ const ct::CompizProcess::PluginList &plugins,
4080+ unsigned int waitTimeout) :
4081 priv (new PrivateCompizProcess (flags))
4082 {
4083 xorg::testing::Process::SetEnv ("LD_LIBRARY_PATH", compizLDLibraryPath, true);
4084@@ -464,6 +559,12 @@
4085
4086 args.push_back ("--send-startup-message");
4087
4088+ /* Copy in plugin list */
4089+ for (ct::CompizProcess::PluginList::const_iterator it = plugins.begin ();
4090+ it != plugins.end ();
4091+ ++it)
4092+ args.push_back (*it);
4093+
4094 priv->mProcess.Start (compizBinaryPath, args);
4095 EXPECT_EQ (priv->mProcess.GetState (), xorg::testing::Process::RUNNING);
4096
4097@@ -571,16 +672,136 @@
4098 }
4099
4100 void
4101-ct::CompizXorgSystemTest::StartCompiz (ct::CompizProcess::StartupFlags flags)
4102-{
4103- priv->mProcess.reset (new ct::CompizProcess (Display (), flags, 3000));
4104+ct::CompizXorgSystemTest::StartCompiz (ct::CompizProcess::StartupFlags flags,
4105+ const ct::CompizProcess::PluginList &plugins)
4106+{
4107+ priv->mProcess.reset (new ct::CompizProcess (Display (), flags, plugins, 3000));
4108+}
4109+
4110+class ct::PrivateAutostartCompizXorgSystemTest
4111+{
4112+ public:
4113+
4114+ PrivateAutostartCompizXorgSystemTest () :
4115+ overridePluginDirEnv ("COMPIZ_PLUGIN_DIR", compizOverridePluginPath.c_str ())
4116+ {
4117+ }
4118+
4119+ TmpEnv overridePluginDirEnv;
4120+};
4121+
4122+ct::AutostartCompizXorgSystemTest::AutostartCompizXorgSystemTest () :
4123+ priv (new ct::PrivateAutostartCompizXorgSystemTest ())
4124+{
4125+}
4126+
4127+ct::CompizProcess::StartupFlags
4128+ct::AutostartCompizXorgSystemTest::GetStartupFlags ()
4129+{
4130+ return static_cast <ct::CompizProcess::StartupFlags> (
4131+ ct::CompizProcess::ReplaceCurrentWM |
4132+ ct::CompizProcess::WaitForStartupMessage);
4133+}
4134+
4135+int
4136+ct::AutostartCompizXorgSystemTest::GetEventMask ()
4137+{
4138+ return 0;
4139+}
4140+
4141+ct::CompizProcess::PluginList
4142+ct::AutostartCompizXorgSystemTest::GetPluginList ()
4143+{
4144+ return ct::CompizProcess::PluginList ();
4145 }
4146
4147 void
4148 ct::AutostartCompizXorgSystemTest::SetUp ()
4149 {
4150 ct::CompizXorgSystemTest::SetUp ();
4151- StartCompiz (static_cast <ct::CompizProcess::StartupFlags> (
4152- ct::CompizProcess::ReplaceCurrentWM |
4153- ct::CompizProcess::WaitForStartupMessage));
4154+
4155+ ::Display *display = Display ();
4156+ XSelectInput (display, DefaultRootWindow (display),
4157+ GetEventMask ());
4158+
4159+ StartCompiz (GetStartupFlags (),
4160+ GetPluginList ());
4161+}
4162+
4163+class ct::PrivateAutostartCompizXorgSystemTestWithTestHelper
4164+{
4165+ public:
4166+
4167+ std::auto_ptr <ct::MessageAtoms> mMessages;
4168+};
4169+
4170+void
4171+ct::AutostartCompizXorgSystemTestWithTestHelper::WaitForWindowCreation (Window w)
4172+{
4173+ ::Display *dpy = Display ();
4174+
4175+ XEvent event;
4176+
4177+ bool requestAcknowledged = false;
4178+ while (ct::ReceiveMessage (dpy,
4179+ FetchAtom (ct::messages::TEST_HELPER_WINDOW_READY),
4180+ event))
4181+ {
4182+ requestAcknowledged =
4183+ w == static_cast <unsigned long> (event.xclient.data.l[0]);
4184+
4185+ if (requestAcknowledged)
4186+ break;
4187+
4188+ }
4189+
4190+ ASSERT_TRUE (requestAcknowledged);
4191+}
4192+
4193+Atom
4194+ct::AutostartCompizXorgSystemTestWithTestHelper::FetchAtom (const char *message)
4195+{
4196+ return priv->mMessages->FetchForString (message);
4197+}
4198+
4199+ct::AutostartCompizXorgSystemTestWithTestHelper::AutostartCompizXorgSystemTestWithTestHelper () :
4200+ priv (new ct::PrivateAutostartCompizXorgSystemTestWithTestHelper)
4201+{
4202+}
4203+
4204+int
4205+ct::AutostartCompizXorgSystemTestWithTestHelper::GetEventMask ()
4206+{
4207+ return AutostartCompizXorgSystemTest::GetEventMask () |
4208+ StructureNotifyMask;
4209+}
4210+
4211+void
4212+ct::AutostartCompizXorgSystemTestWithTestHelper::SetUp ()
4213+{
4214+ ct::AutostartCompizXorgSystemTest::SetUp ();
4215+ priv->mMessages.reset (new ct::MessageAtoms (Display ()));
4216+
4217+ ::Display *dpy = Display ();
4218+ Window root = DefaultRootWindow (dpy);
4219+
4220+ Atom ready = priv->mMessages->FetchForString (ct::messages::TEST_HELPER_READY_MSG);
4221+ ct::ClientMessageXEventMatcher matcher (dpy, ready, root);
4222+
4223+ ASSERT_TRUE (ct::AdvanceToNextEventOnSuccess (
4224+ dpy,
4225+ ct::WaitForEventOfTypeOnWindowMatching (dpy,
4226+ root,
4227+ ClientMessage,
4228+ -1,
4229+ -1,
4230+ matcher)));
4231+}
4232+
4233+ct::CompizProcess::PluginList
4234+ct::AutostartCompizXorgSystemTestWithTestHelper::GetPluginList ()
4235+{
4236+ ct::CompizProcess::PluginList list;
4237+ list.push_back ("testhelper");
4238+ return list;
4239 }

Subscribers

People subscribed via source and target branches