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: 4386 lines (+3345/-156)
49 files modified
CMakeLists.txt (+16/-0)
cmake/CompizGSettings.cmake (+12/-1)
cmake/CompizPlugin.cmake (+34/-19)
cmake/plugin_extensions/CompizGenGSettings.cmake (+7/-1)
cmake/plugin_extensions/CompizGenGconf.cmake (+3/-1)
cmake/plugin_extensions/CompizGenInstallData.cmake (+6/-4)
cmake/plugin_extensions/CompizGenInstallImages.cmake (+7/-4)
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/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/xorg-gtest/CMakeLists.txt (+13/-1)
tests/xorg-gtest/communicator/CMakeLists.txt (+17/-0)
tests/xorg-gtest/communicator/compiz_xorg_gtest_communicator.cpp (+200/-0)
tests/xorg-gtest/communicator/compiz_xorg_gtest_communicator.h (+67/-0)
tests/xorg-gtest/include/compiz-xorg-gtest.h (+62/-4)
tests/xorg-gtest/plugins/CMakeLists.txt (+10/-0)
tests/xorg-gtest/plugins/testhelper/CMakeLists.txt (+7/-0)
tests/xorg-gtest/plugins/testhelper/src/testhelper.cpp (+231/-0)
tests/xorg-gtest/plugins/testhelper/src/testhelper.h (+95/-0)
tests/xorg-gtest/plugins/testhelper/testhelper.xml.in (+6/-0)
tests/xorg-gtest/src/CMakeLists.txt (+0/-2)
tests/xorg-gtest/src/compiz-xorg-gtest-config.h.in (+3/-2)
tests/xorg-gtest/src/compiz-xorg-gtest.cpp (+252/-28)
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
Compiz Maintainers Pending
MC Return Pending
Review via email: mp+149878@code.launchpad.net

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

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

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 : 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: 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: Needs Fixing (continuous-integration)
Revision history for this message
MC Return (mc-return) wrote : Posted in a previous version of this proposal

There is a minor indentation problem in move.xml.in:

299 - <default>true</default>
300 + <default>false</default>

You are using 16 spaces here, instead of 2 tabs.

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: 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 :
review: Needs Fixing (continuous-integration)

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

Subscribers

People subscribed via source and target branches