Merge lp:~smspillaz/compiz-core/compiz-core.fix_969108.2 into lp:compiz-core

Proposed by Sam Spilsbury
Status: Superseded
Proposed branch: lp:~smspillaz/compiz-core/compiz-core.fix_969108.2
Merge into: lp:compiz-core
Diff against target: 1314 lines (+1104/-7)
12 files modified
include/core/screen.h (+1/-0)
plugins/CMakeLists.txt (+1/-0)
plugins/move/src/move.cpp (+41/-5)
plugins/move/src/move.h (+31/-2)
src/CMakeLists.txt (+5/-0)
src/queues/CMakeLists.txt (+61/-0)
src/queues/include/core/queues.h (+360/-0)
src/queues/src/queues.cpp (+113/-0)
src/queues/tests/CMakeLists.txt (+18/-0)
src/queues/tests/queues/src/test-queues.cpp (+231/-0)
src/queues/tests/test-queues.cpp (+34/-0)
src/queues/tests/test-queues.h (+208/-0)
To merge this branch: bzr merge lp:~smspillaz/compiz-core/compiz-core.fix_969108.2
Reviewer Review Type Date Requested Status
Daniel van Vugt Pending
Review via email: mp+100441@code.launchpad.net

This proposal supersedes a proposal from 2012-04-02.

This proposal has been superseded by a proposal from 2012-04-03.

Description of the change

== Problem ==

moveHandleMotionEvent could cause the window geometry to be updated several times a second which would have run-on effects in calling moveNotify a lot in the plugins. This would cause an unnessary performance hit.

== Solution ==

Added a new releasable queue structure, which allows observers to lock the queue and trigger releases at a later point and an accumulator to accumulate values to release in the future. Use this in order to queue up motion on windows and release in synchronization with repaints so that we only update the geometries where it matters.

== Tests ==

Test Suite included.

To post a comment you must log in.
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Again, I can't endorse a major rewrite of critical functionality this late.

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

Also, this 1000 lines of code seems to be aimed at solving a problem that I planned on solving myself in only a dozen or so lines. Is it really necessary to introduce such vast complexity?

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

1) This isn't a rewrite
2) The only functional changes are in the form of

42 if (state & CompAction::StateCancel)
43 - ms->w->move (ms->savedX - ms->w->geometry ().x (),
44 - ms->savedY - ms->w->geometry ().y (), false);
45 + ms->addMovement (MoveWindow::get (ms->w), CompPoint (ms->savedX - ms->w->geometry ().x (),
46 + ms->savedY - ms->w->geometry ().y ()));
47
48 ms->w->syncPosition ();
49
50 @@ -484,8 +486,7 @@
51
52 if (dx || dy)
53 {
54 - w->move (wX + dx - w->geometry ().x (),
55 - wY + dy - w->geometry ().y (), false);
56 + ms->addMovement (MoveWindow::get (w), CompPoint (dx, dy));
62
63 bool
64 +MoveWindow::doRelease (const CompPoint &d)
65 +{
66 + window->move (d.x (), d.y (), false);
67 + return true;
68 +}
69 +
70 +void
71 +MoveScreen::dispatchDamage (compiz::queues::QueueReleaseInterface *releasable)
72 +{
73 + MoveWindow *mw = static_cast <MoveWindow *> (releasable);
74 + mw->cWindow->addDamage ();
75 +}
76 +
77 +bool
78 MoveScreen::registerPaintHandler(compiz::composite::PaintHandler *pHnd)
79 {
80 hasCompositing = true;
81 @@ -677,9 +692,27 @@
82 MoveScreen::unregisterPaintHandler()
83 {
84 hasCompositing = false;
85 + queueLock.reset ();
86 cScreen->unregisterPaintHandler ();
87 }
88
89 +void
90 +MoveScreen::preparePaint (int ms)
91 +{
92 + if (queueLock)
93 + queueLock->unlock ();
94 +
95 + cScreen->preparePaint (ms);
96 + cScreen->preparePaintSetEnabled (this, false);
97 +}
98 +
99 +void
100 +MoveScreen::addMovement (MoveWindow *mw, const CompPoint &d)
101 +{
102 + cScreen->preparePaintSetEnabled (this, true);
103 + pendingMovements->addPending (d, mw);
104 +}
105 +
113 - yConstrained (false)
114 + yConstrained (false),
115 + pendingMovementsStorage (new compiz::queues::impl::AccumulatedMapStorage <CompPoint> ()),
116 + pendingMovements (new compiz::queues::impl::Queue <CompPoint> (boost::shared_static_cast <compiz::queues::QueueStorageInterface <CompPoint> > (pendingMovementsStorage)))
123 CompositeScreenInterface::setHandler (cScreen);
124 + queueLock = pendingMovements->obtainLock (boost::bind (&MoveScreen::dispatchDamage, this, _1));
125 + cScreen->preparePaintSetEnabled (this, false);

That's fairly small

3) The reason the diff is so large is because 100 of 1200 lines are cmake and 600 of the 1200 lines are tests
4) This solution is aimed at making releasable queues more generic
5) Its blocking other work

Plenty of good reasons to merge this before precise.

Revision history for this message
Tim Penhey (thumper) wrote : Posted in a previous version of this proposal

Making destructors pure virtual is only really necessary if there are no other pure virtual methods and you want to make the class abstract. Other than that they are just a PITA.

Revision history for this message
Mikkel Kamstrup Erlandsen (kamstrup) wrote : Posted in a previous version of this proposal

I don't know the compiz coding standards, but for abstract code like this I'd expect at the very least 2 comments: 1) In queue.cpp/h explaining what the general idea behind all the interfaces are, 2) in the move.cpp explaining what it is using the clever queues for (ie. why a bog standard list is not good enough)

Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

It isn't obvious what contracts the template interfaces QueueStorageInterface, QueueInterface, and QueueLockInterface represent. E.g. I'd expect a lock to have "lock()" and "unlock()" methods or similar. Do they need to be templates?

The pure destructors and NVPI clutter up the code.

In MoveScreen the new variables pendingMovementsStorage, pendingMovements and queueLock could be private. (I suspect others could too - what is it with compiz and public data members?)

I don't see why pendingMovementsStorage is a member variable - it's only use is in initalizing pendingMovements. In any case, it should be of the usage type - shared_ptr<QueueStorageInterface> not the implementation type.

There is no need for pendingMovements to be allocated on the heap instead of being a member variable. (The same change for pendingMovementsStorage which would require a signature change for compiz::queues::impl::Queue::Queue - but that's minor.)

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

> It isn't obvious what contracts the template interfaces QueueStorageInterface,
> QueueInterface, and QueueLockInterface represent. E.g. I'd expect a lock to
> have "lock()" and "unlock()" methods or similar. Do they need to be
> templates?

QueueReleaseInterface, QueueInterface and QueueStorageInterface need to know the type that is being stored. As such, they are templates.

QueueLockInterface takes a lock on a QueueUnlockableInterface on construction. Eg, the very act of constructing a QueueLockInterface means that it will receive callbacks and block dispatching of the queue items until the client calls unlock () on it, at which point will call a method in QueueUnlockableInterface to decrement the lock count.

QueueStorageInterface is the abstraction of how queued items are stored.

QueueInterface is the interface to the Queue itself, eg, pushing data into the queue.

>
> The pure destructors and NVPI clutter up the code.
>
> In MoveScreen the new variables pendingMovementsStorage, pendingMovements and
> queueLock could be private. (I suspect others could too - what is it with
> compiz and public data members?)

Ack, although I believe we're using this from MoveWindow.

>
> I don't see why pendingMovementsStorage is a member variable - it's only use
> is in initalizing pendingMovements. In any case, it should be of the usage
> type - shared_ptr<QueueStorageInterface> not the implementation type.

You are correct.

I believe the reason I made it a member was merely for convenience, without that, this line

pendingMovements (new compiz::queues::impl::Queue <CompPoint> (boost::shared_static_cast <compiz::queues::QueueStorageInterface <CompPoint> > (pendingMovementsStorage)))

would look something like

pendingMovements (new compiz::queues::impl::Queue <CompPoint> (boost::shared_static_cast <compiz::queues::QueueStorageInterface <CompPoint> > (compiz::queues::impl::AccumulatedMapStorage <CompPoint>::Ptr ((new compiz::queues::impl::AccumulatedMapStorage <CompPoint> ()))))

(which is a bit of a monstrosity :( )

>
> There is no need for pendingMovements to be allocated on the heap instead of
> being a member variable. (The same change for pendingMovementsStorage which
> would require a signature change for compiz::queues::impl::Queue::Queue - but
> that's minor.)

I think the reason why I had it on the heap was because if it was on the stack then this would mean we'd pass QueueStorageInterface by const reference and we'd have to copy the temporary into the member variable inside of ::Queue . That would mean adding copying semantics to something which shouldn't really be copied anyways (QueueStorageInterface describes /how/ the queue data should be stored, it isn't a value type in itself).

pendingMovements on the other hand could be on the stack.

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

> I don't know the compiz coding standards, but for abstract code like this I'd
> expect at the very least 2 comments: 1) In queue.cpp/h explaining what the
> general idea behind all the interfaces are, 2) in the move.cpp explaining what
> it is using the clever queues for (ie. why a bog standard list is not good
> enough)

Yes, I will add such comments. Thanks Mikkel

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

> Making destructors pure virtual is only really necessary if there are no other
> pure virtual methods and you want to make the class abstract. Other than that
> they are just a PITA.

Ack

Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

> > It isn't obvious what contracts the template interfaces
> QueueStorageInterface,
> > QueueInterface, and QueueLockInterface represent. E.g. I'd expect a lock to
> > have "lock()" and "unlock()" methods or similar. Do they need to be
> > templates?
>
> QueueReleaseInterface, QueueInterface and QueueStorageInterface need to know
> the type that is being stored. As such, they are templates.

Yes, but they are only instantiated on one type in real code. (And another in the tests.)

> >
> > The pure destructors and NVPI clutter up the code.
> >
> > In MoveScreen the new variables pendingMovementsStorage, pendingMovements
> and
> > queueLock could be private. (I suspect others could too - what is it with
> > compiz and public data members?)
>
> Ack, although I believe we're using this from MoveWindow.

Not in the code I see.

> > I don't see why pendingMovementsStorage is a member variable - it's only use
> > is in initalizing pendingMovements. In any case, it should be of the usage
> > type - shared_ptr<QueueStorageInterface> not the implementation type.
>
> You are correct.
>
> I believe the reason I made it a member was merely for convenience, without
> that, this line
>
> pendingMovements (new compiz::queues::impl::Queue <CompPoint>
> (boost::shared_static_cast <compiz::queues::QueueStorageInterface <CompPoint>
> > (pendingMovementsStorage)))
>
> would look something like
>
> pendingMovements (new compiz::queues::impl::Queue <CompPoint>
> (boost::shared_static_cast <compiz::queues::QueueStorageInterface <CompPoint>
> > (compiz::queues::impl::AccumulatedMapStorage <CompPoint>::Ptr ((new
> compiz::queues::impl::AccumulatedMapStorage <CompPoint> ()))))

Or without the pointless cast...

pendingMovements (new compiz::queues::impl::Queue <CompPoint> (compiz::queues::impl::QueueStorageInterface <CompPoint>::Ptr ((new compiz::queues::impl::AccumulatedMapStorage <CompPoint> ())))

And if you don't repeat compiz::queues::impl:: all the time.

pendingMovements (new cqi::Queue <CompPoint> (cqi::QueueStorageInterface <CompPoint>::Ptr ((new cqi::AccumulatedMapStorage <CompPoint> ())))

> > There is no need for pendingMovements to be allocated on the heap instead of
> > being a member variable. (The same change for pendingMovementsStorage which
> > would require a signature change for compiz::queues::impl::Queue::Queue -
> but
> > that's minor.)
>
> I think the reason why I had it on the heap was because if it was on the stack
> then this would mean we'd pass QueueStorageInterface by const reference and
> we'd have to copy the temporary into the member variable inside of ::Queue .
> That would mean adding copying semantics to something which shouldn't really
> be copied anyways (QueueStorageInterface describes /how/ the queue data should
> be stored, it isn't a value type in itself).

I think there's a misunderstanding. But that's moot in view of the above discussion.

> pendingMovements on the other hand could be on the stack.

A data member. Then the "monsterous" line becomes:

pendingMovements (cqi::QueueStorageInterface <CompPoint>::Ptr ((new cqi::AccumulatedMapStorage <CompPoint> ()))

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

Code cleaned up. Resubmitted ... though it looks like I have more to do. Fun.

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

> QueueReleaseInterface, QueueInterface and QueueStorageInterface need to know
> the type that is being stored. As such, they are templates.

> Yes, but they are only instantiated on one type in real code. (And another in the tests.)

I plan to use this in other parts of the code. It was almost generic as it was, and is quite useful as a separate mechanism IMO

Will use namespace aliases as recommended

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

Code cleaned up and resubmitted again

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

Seems to work. And the functionality seems a good idea.

But, now we can read what they do, the names of the queues classes seem a bit awkward...

"QueueInterface" does only a small subset of what I'd expect a queue to do and adding "Interface" to the name seems verbose (not that I like Microsoft's "I" prefix either). "Appender" may be better?

"QueueLockInterface" this doesn't behave as I expect from a lock. It is a pre-release callback to request permission to release the queue.

(I find the other names problematic too - but don't want to go on too much.)

On the design side, I don't like the fact that downcasts are required by the code using these classes. As a general principle templates should allow this to be avoided by propagating type information.

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

> Seems to work. And the functionality seems a good idea.
>
> But, now we can read what they do, the names of the queues classes seem a bit
> awkward...
>
> "QueueInterface" does only a small subset of what I'd expect a queue to do and
> adding "Interface" to the name seems verbose (not that I like Microsoft's "I"
> prefix either). "Appender" may be better?

The I/Interface/Whatever discussion needs to be had somewhere else.

>
> "QueueLockInterface" this doesn't behave as I expect from a lock. It is a
> pre-release callback to request permission to release the queue.

QueueHoldInterface ?

>
> (I find the other names problematic too - but don't want to go on too much.)
>
> On the design side, I don't like the fact that downcasts are required by the
> code using these classes. As a general principle templates should allow this
> to be avoided by propagating type information.

550 + mItems[static_cast <QueueReleaseInterface *> (i)] += t;
551 +
552 + return true;
553 + }
554 +
555 + void doRelease ()
556 + {
557 + typename std::map <QueueReleaseInterface *, T>::iterator it = mItems.begin ();
558 +
559 + for (; it != mItems.end (); it++)
560 + {
561 + QueueReleasableInterface <T> *releasable = static_cast <QueueReleasableInterface <T> *> (it->first);

These two are avoidable. I'll try something else. As for the downcast to MoveWindow, it should be possible to avoid that one by changing the boost::function to another interface like a QueueItemReadyCallback or perhaps adding an notifyItemReady (); to QueueReleaseInterface

3086. By Sam Spilsbury

Also notify interested data receivers they have data pending

3087. By Sam Spilsbury

Remove downcasts where possible

3088. By Sam Spilsbury

Actually hook up to itemPending

Unmerged revisions

3088. By Sam Spilsbury

Actually hook up to itemPending

3087. By Sam Spilsbury

Remove downcasts where possible

3086. By Sam Spilsbury

Also notify interested data receivers they have data pending

3085. By Sam Spilsbury

Remove the shared static cast

3084. By Sam Spilsbury

Namespace alias

3083. By Sam Spilsbury

Removed AccumulatedMapStorage member

3082. By Sam Spilsbury

Made pendingMovements not a shared ptr

3081. By Sam Spilsbury

Made pendingMovements private

3080. By Sam Spilsbury

Removed virtual destructors

3079. By Sam Spilsbury

Added documentation for the contract provided by queues

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'build'
2=== added directory 'build/src'
3=== modified file 'include/core/screen.h'
4--- include/core/screen.h 2012-03-12 12:35:52 +0000
5+++ include/core/screen.h 2012-04-02 15:10:24 +0000
6@@ -39,6 +39,7 @@
7 #include <core/valueholder.h>
8
9 #include <boost/scoped_ptr.hpp>
10+#include <boost/shared_ptr.hpp>
11
12 class CompScreenImpl;
13 class PrivateScreen;
14
15=== modified file 'plugins/CMakeLists.txt'
16--- plugins/CMakeLists.txt 2012-01-20 09:46:31 +0000
17+++ plugins/CMakeLists.txt 2012-04-02 15:10:24 +0000
18@@ -16,6 +16,7 @@
19 ${CMAKE_CURRENT_SOURCE_DIR}/../src/pluginclasshandler/include
20 ${CMAKE_CURRENT_SOURCE_DIR}/../src/point/include
21 ${CMAKE_CURRENT_SOURCE_DIR}/../src/rect/include
22+ ${CMAKE_CURRENT_SOURCE_DIR}/../src/queues/include
23 ${CMAKE_CURRENT_SOURCE_DIR}/../src/window/geometry/include
24 ${CMAKE_CURRENT_SOURCE_DIR}/../src/window/geometry-saver/include
25 ${CMAKE_CURRENT_SOURCE_DIR}/../src/window/extents/include
26
27=== modified file 'plugins/move/src/move.cpp'
28--- plugins/move/src/move.cpp 2012-02-16 05:31:28 +0000
29+++ plugins/move/src/move.cpp 2012-04-02 15:10:24 +0000
30@@ -27,6 +27,8 @@
31 #include <stdlib.h>
32 #include <string.h>
33
34+#include <boost/cast.hpp>
35+
36 #include <X11/cursorfont.h>
37
38 #include <core/atoms.h>
39@@ -169,8 +171,8 @@
40 if (ms->w)
41 {
42 if (state & CompAction::StateCancel)
43- ms->w->move (ms->savedX - ms->w->geometry ().x (),
44- ms->savedY - ms->w->geometry ().y (), false);
45+ ms->addMovement (MoveWindow::get (ms->w), CompPoint (ms->savedX - ms->w->geometry ().x (),
46+ ms->savedY - ms->w->geometry ().y ()));
47
48 ms->w->syncPosition ();
49
50@@ -484,8 +486,7 @@
51
52 if (dx || dy)
53 {
54- w->move (wX + dx - w->geometry ().x (),
55- wY + dy - w->geometry ().y (), false);
56+ ms->addMovement (MoveWindow::get (w), CompPoint (dx, dy));
57
58 if (!ms->optionGetLazyPositioning ())
59 w->syncPosition ();
60@@ -666,6 +667,20 @@
61 }
62
63 bool
64+MoveWindow::doRelease (const CompPoint &d)
65+{
66+ window->move (d.x (), d.y (), false);
67+ return true;
68+}
69+
70+void
71+MoveScreen::dispatchDamage (cq::QueueReleaseInterface *releasable)
72+{
73+ MoveWindow *mw = static_cast <MoveWindow *> (releasable);
74+ mw->cWindow->addDamage ();
75+}
76+
77+bool
78 MoveScreen::registerPaintHandler(compiz::composite::PaintHandler *pHnd)
79 {
80 hasCompositing = true;
81@@ -677,9 +692,27 @@
82 MoveScreen::unregisterPaintHandler()
83 {
84 hasCompositing = false;
85+ queueLock.reset ();
86 cScreen->unregisterPaintHandler ();
87 }
88
89+void
90+MoveScreen::preparePaint (int ms)
91+{
92+ if (queueLock)
93+ queueLock->unlock ();
94+
95+ cScreen->preparePaint (ms);
96+ cScreen->preparePaintSetEnabled (this, false);
97+}
98+
99+void
100+MoveScreen::addMovement (MoveWindow *mw, const CompPoint &d)
101+{
102+ cScreen->preparePaintSetEnabled (this, true);
103+ pendingMovements.addPending (d, mw);
104+}
105+
106 MoveScreen::MoveScreen (CompScreen *screen) :
107 PluginClassHandler<MoveScreen,CompScreen> (screen),
108 cScreen (CompositeScreen::get (screen)),
109@@ -689,7 +722,8 @@
110 releaseButton (0),
111 grab (NULL),
112 hasCompositing (false),
113- yConstrained (false)
114+ yConstrained (false),
115+ pendingMovements (cqi::AccumulatedMapStorage<CompPoint>::Ptr (new cqi::AccumulatedMapStorage <CompPoint> ()))
116 {
117 updateOpacity ();
118
119@@ -701,6 +735,8 @@
120 if (cScreen)
121 {
122 CompositeScreenInterface::setHandler (cScreen);
123+ queueLock = pendingMovements.obtainLock (boost::bind (&MoveScreen::dispatchDamage, this, _1));
124+ cScreen->preparePaintSetEnabled (this, false);
125 hasCompositing =
126 cScreen->compositingActive ();
127 }
128
129=== modified file 'plugins/move/src/move.h'
130--- plugins/move/src/move.h 2012-02-01 17:49:07 +0000
131+++ plugins/move/src/move.h 2012-04-02 15:10:24 +0000
132@@ -27,10 +27,13 @@
133
134 #include <core/screen.h>
135 #include <core/pluginclasshandler.h>
136+#include <core/queues.h>
137
138 #include <composite/composite.h>
139 #include <opengl/opengl.h>
140
141+namespace cqi = compiz::queues::impl;
142+namespace cq = compiz::queues;
143
144 #define NUM_KEYS (sizeof (mKeys) / sizeof (mKeys[0]))
145
146@@ -50,6 +53,8 @@
147 { "Down", 0, 1 }
148 };
149
150+class MoveWindow;
151+
152 class MoveScreen :
153 public ScreenInterface,
154 public CompositeScreenInterface,
155@@ -68,6 +73,10 @@
156
157 bool registerPaintHandler (compiz::composite::PaintHandler *pHnd);
158 void unregisterPaintHandler ();
159+ void preparePaint (int ms);
160+
161+ void addMovement (MoveWindow *mw, const CompPoint &d);
162+ void dispatchDamage (cq::QueueReleaseInterface *);
163
164 CompWindow *w;
165 int savedX;
166@@ -94,29 +103,49 @@
167 bool hasCompositing;
168
169 bool yConstrained;
170+
171+ private:
172+
173+ cqi::Queue <CompPoint> pendingMovements;
174+ boost::shared_ptr <cq::QueueLockInterface> queueLock;
175 };
176
177 class MoveWindow :
178 public GLWindowInterface,
179- public PluginClassHandler<MoveWindow,CompWindow>
180+ public PluginClassHandler<MoveWindow,CompWindow>,
181+ public cq::QueueReleasableInterface <CompPoint>
182 {
183 public:
184 MoveWindow (CompWindow *window) :
185 PluginClassHandler<MoveWindow,CompWindow> (window),
186 window (window),
187 gWindow (GLWindow::get (window)),
188- cWindow (CompositeWindow::get (window))
189+ cWindow (CompositeWindow::get (window)),
190+ mRemoveInterface (NULL)
191 {
192 if (gWindow)
193 GLWindowInterface::setHandler (gWindow, false);
194 };
195
196+ ~MoveWindow ()
197+ {
198+ if (mRemoveInterface)
199+ mRemoveInterface->removeReleasable (this);
200+ }
201+
202 bool glPaint (const GLWindowPaintAttrib &, const GLMatrix &,
203 const CompRegion &, unsigned int);
204
205 CompWindow *window;
206 GLWindow *gWindow;
207 CompositeWindow *cWindow;
208+
209+ private:
210+
211+ bool doRelease (const CompPoint &d);
212+ void doSetRemoveInterface (cq::QueueReleaseRemoveInterface *removeInterface) { mRemoveInterface = removeInterface; }
213+
214+ cq::QueueReleaseRemoveInterface *mRemoveInterface;
215 };
216
217 #define MOVE_SCREEN(s) \
218
219=== modified file 'src/CMakeLists.txt'
220--- src/CMakeLists.txt 2012-03-13 10:17:02 +0000
221+++ src/CMakeLists.txt 2012-04-02 15:10:24 +0000
222@@ -8,6 +8,7 @@
223 add_subdirectory( point )
224 add_subdirectory( rect )
225 add_subdirectory( window )
226+add_subdirectory( queues )
227
228 IF (COMPIZ_BUILD_TESTING)
229 add_subdirectory( privatescreen/tests )
230@@ -54,6 +55,9 @@
231 ${CMAKE_CURRENT_SOURCE_DIR}/point/include
232 ${CMAKE_CURRENT_SOURCE_DIR}/point/src
233
234+ ${CMAKE_CURRENT_SOURCE_DIR}/queues/include
235+ ${CMAKE_CURRENT_SOURCE_DIR}/queues/src
236+
237 ${CMAKE_CURRENT_SOURCE_DIR}/rect/include
238 ${CMAKE_CURRENT_SOURCE_DIR}/rect/src
239
240@@ -159,6 +163,7 @@
241 compiz_window_geometry_saver
242 compiz_window_extents
243 compiz_window_constrainment
244+ compiz_queues
245 -Wl,-no-whole-archive
246 # ${CORE_MOD_LIBRARIES}
247 )
248
249=== added directory 'src/queues'
250=== added file 'src/queues/CMakeLists.txt'
251--- src/queues/CMakeLists.txt 1970-01-01 00:00:00 +0000
252+++ src/queues/CMakeLists.txt 2012-04-02 15:10:24 +0000
253@@ -0,0 +1,61 @@
254+pkg_check_modules (
255+ GLIBMM
256+ REQUIRED
257+ glibmm-2.4 glib-2.0
258+)
259+
260+INCLUDE_DIRECTORIES (
261+ ${CMAKE_CURRENT_SOURCE_DIR}/include
262+ ${CMAKE_CURRENT_SOURCE_DIR}/src
263+
264+ ${CMAKE_CURRENT_SOURCE_DIR}/queues/include
265+ ${CMAKE_CURRENT_SOURCE_DIR}/queues/src
266+
267+ ${compiz_SOURCE_DIR}/include
268+
269+ ${Boost_INCLUDE_DIRS}
270+
271+ ${GLIBMM_INCLUDE_DIRS}
272+)
273+
274+LINK_DIRECTORIES (${GLIBMM_LIBRARY_DIRS})
275+
276+SET (
277+ PUBLIC_HEADERS
278+ ${CMAKE_CURRENT_SOURCE_DIR}/include/core/queues.h
279+)
280+
281+SET (
282+ PRIVATE_HEADERS
283+)
284+
285+SET(
286+ SRCS
287+ ${CMAKE_CURRENT_SOURCE_DIR}/src/queues.cpp
288+)
289+
290+ADD_LIBRARY(
291+ compiz_queues STATIC
292+
293+ ${SRCS}
294+
295+ ${PUBLIC_HEADERS}
296+ ${PRIVATE_HEADERS}
297+)
298+
299+IF (COMPIZ_BUILD_TESTING)
300+ADD_SUBDIRECTORY( ${CMAKE_CURRENT_SOURCE_DIR}/tests )
301+ENDIF (COMPIZ_BUILD_TESTING)
302+
303+SET_TARGET_PROPERTIES(
304+ compiz_queues PROPERTIES
305+ PUBLIC_HEADER "${PUBLIC_HEADERS}"
306+)
307+
308+install (FILES ${PUBLIC_HEADERS} DESTINATION ${COMPIZ_CORE_INCLUDE_DIR})
309+
310+TARGET_LINK_LIBRARIES(
311+ compiz_queues
312+
313+ ${GLIBMM_LIBRARIES}
314+)
315
316=== added directory 'src/queues/include'
317=== added directory 'src/queues/include/core'
318=== added file 'src/queues/include/core/queues.h'
319--- src/queues/include/core/queues.h 1970-01-01 00:00:00 +0000
320+++ src/queues/include/core/queues.h 2012-04-02 15:10:24 +0000
321@@ -0,0 +1,360 @@
322+/*
323+ * Copyright © 2012 Canonical Ltd.
324+ *
325+ * Permission to use, copy, modify, distribute, and sell this software
326+ * and its documentation for any purpose is hereby granted without
327+ * fee, provided that the above copyright notice appear in all copies
328+ * and that both that copyright notice and this permission notice
329+ * appear in supporting documentation, and that the name of
330+ * Canonical Ltd. not be used in advertising or publicity pertaining to
331+ * distribution of the software without specific, written prior permission.
332+ * Canonical Ltd. makes no representations about the suitability of this
333+ * software for any purpose. It is provided "as is" without express or
334+ * implied warranty.
335+ *
336+ * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
337+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
338+ * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
339+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
340+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
341+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
342+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
343+ *
344+ * Authored by: Sam Spilsbury <sam.spilsbury@canonical.com>
345+ */
346+
347+#ifndef _COMPQUEUES_H
348+#define _COMPQUEUES_H
349+
350+#include <vector>
351+#include <map>
352+#include <boost/shared_ptr.hpp>
353+#include <boost/function.hpp>
354+#include <boost/bind.hpp>
355+#include <boost/noncopyable.hpp>
356+
357+namespace compiz
358+{
359+ namespace queues
360+ {
361+ class QueueReleaseInterface;
362+
363+ /**
364+ * A QueueReleaseRemoveInterface describes an interface
365+ * provided to an object inheriting QueueReleaseInterface
366+ * to call back into the queue storage to remove queued items
367+ * relating to a QueueReleaseInterface when the object implementing
368+ * the QueueReleaseInterface is destroyed
369+ */
370+ class QueueReleaseRemoveInterface
371+ {
372+ public:
373+
374+ virtual ~QueueReleaseRemoveInterface () {}
375+
376+ void removeReleasable (QueueReleaseInterface *r) { doRemoveReleasable (r); }
377+
378+ protected:
379+
380+ virtual void doRemoveReleasable (QueueReleaseInterface *) = 0;
381+ };
382+
383+ /**
384+ * A QueueReleaseInterface is implemented by an object interested in some
385+ * data on the object in the future when an object implementing a QueueInterface
386+ * decides it is appropriate to release that data. This class is a base to the
387+ * template QueueReleasableInterface which knows about the data type being released */
388+ class QueueReleaseInterface
389+ {
390+ public:
391+
392+ virtual ~QueueReleaseInterface () {}
393+
394+ void setRemoveInterface (QueueReleaseRemoveInterface *r) { doSetRemoveInterface (r); }
395+
396+ protected:
397+
398+ virtual void doSetRemoveInterface (QueueReleaseRemoveInterface *) = 0;
399+ };
400+
401+ /**
402+ * A QueueReleasableInterface is implemented by an object interested in some
403+ * future data when an object implementing a QueueInterface decides it is appropriate
404+ * to dispatch this data. release () is a callback into the object to inform it that
405+ * new data is ready to be proccessed
406+ */
407+ template <class T>
408+ class QueueReleasableInterface :
409+ public QueueReleaseInterface
410+ {
411+ public:
412+
413+ virtual ~QueueReleasableInterface () {}
414+
415+ bool release (const T &t) { return doRelease (t); }
416+
417+ protected:
418+
419+ virtual bool doRelease (const T &t) = 0;
420+ };
421+
422+ /**
423+ * A QueueLockInterface is implemented by an object which wishes to hold a lock
424+ * on a QueueInterface to prevent it from releasing data until the owner of the
425+ * QueueLockInterface decides is appropriate. QueueLockInterfaces provide an unlock ()
426+ * method to indicate that data which is held in the queue is ok by the owner to be
427+ * processed. callback () is invoked by a QueueInterface which wishes to indicate
428+ * that some data on a QueueReleaseInterface is pending processing but not yet
429+ * released (so that the owner may decide whether or not it is appropriate to release
430+ * the lock)
431+ */
432+ class QueueLockInterface
433+ {
434+ public:
435+
436+ virtual ~QueueLockInterface () {}
437+
438+ typedef boost::shared_ptr <QueueLockInterface> Ptr;
439+
440+ bool unlock () { return doUnlock (); }
441+ void callback (QueueReleaseInterface *releasable) { return doCallback (releasable); }
442+
443+ private:
444+
445+ virtual bool doUnlock () = 0;
446+ virtual void doCallback (QueueReleaseInterface *releasable) = 0;
447+ };
448+
449+ /**
450+ * A QueueUnlockInterface is implemented by an object which has data to be dispatched
451+ * to other interested owners. QueueUnlockInterface is provided to implementors of
452+ * QueueLockInterface as a means to call-back and decrement the lock count of the queue.
453+ * Locks must also register their existence on the unlock interface
454+ */
455+ class QueueUnlockInterface
456+ {
457+ public:
458+
459+ virtual ~QueueUnlockInterface () {}
460+
461+ void release () { doRelease (); }
462+ bool registerLock (QueueLockInterface *lock) { return doRegisterLock (lock); }
463+ bool unregisterLock (QueueLockInterface *lock) { return doUnregisterLock (lock); }
464+
465+ private:
466+
467+ virtual void doRelease () = 0;
468+ virtual bool doRegisterLock (QueueLockInterface *) = 0;
469+ virtual bool doUnregisterLock (QueueLockInterface *) = 0;
470+ };
471+
472+ typedef boost::function <void (QueueReleaseInterface *)> pendingItemsFunc;
473+
474+ /**
475+ * A QueueLockGeneratorInterface provides an interface to construct a lock - the implementation
476+ * determines what type of lock to construct, and what the lock has control over
477+ */
478+ class QueueLockGeneratorInterface
479+ {
480+ public:
481+
482+ virtual ~QueueLockGeneratorInterface () {}
483+ boost::shared_ptr <QueueLockInterface> obtainLock (const pendingItemsFunc &func) { return doObtainLock (func); }
484+
485+ private:
486+
487+ virtual boost::shared_ptr <QueueLockInterface> doObtainLock (const pendingItemsFunc &) = 0;
488+ };
489+
490+ /**
491+ * A QueueInterface provides the front-end for adding data to a queue to be dispatched
492+ * on a QueueReleasableInterface at some point in the future.
493+ */
494+ template <class T>
495+ class QueueInterface
496+ {
497+ public:
498+
499+ virtual ~QueueInterface () {}
500+
501+ void addPending (const T &t,
502+ QueueReleasableInterface <T> *r) { doAddPending (t, r); }
503+
504+ protected:
505+
506+ virtual void doAddPending (const T &,
507+ QueueReleasableInterface <T> *) = 0;
508+ };
509+
510+ /**
511+ * A QueueStorageInterface is an abstraction as to how data should be stored in a QueueInterface
512+ * and how it should be released when data is ready to be dispatched
513+ */
514+ template <class T>
515+ class QueueStorageInterface :
516+ public QueueReleaseRemoveInterface
517+ {
518+ public:
519+
520+ virtual ~QueueStorageInterface () {}
521+
522+ typedef boost::shared_ptr <QueueStorageInterface <T> > Ptr;
523+
524+ bool store (QueueReleasableInterface<T> *r, const T &t) { return doStore (r, t); }
525+ void release () { doRelease (); }
526+
527+ protected:
528+
529+ virtual bool doStore (QueueReleasableInterface<T> *i, const T &) = 0;
530+ virtual void doRelease () = 0;
531+ };
532+
533+ namespace impl
534+ {
535+
536+ typedef boost::function <void ()> notifyReleaseFunc;
537+
538+ template <class T>
539+ class AccumulatedMapStorage :
540+ public QueueStorageInterface <T>
541+ {
542+ public:
543+
544+ typedef typename boost::shared_ptr <AccumulatedMapStorage <T> > Ptr;
545+
546+ private:
547+
548+ bool doStore (QueueReleasableInterface<T> *i, const T &t)
549+ {
550+ mItems[static_cast <QueueReleaseInterface *> (i)] += t;
551+
552+ return true;
553+ }
554+
555+ void doRelease ()
556+ {
557+ typename std::map <QueueReleaseInterface *, T>::iterator it = mItems.begin ();
558+
559+ for (; it != mItems.end (); it++)
560+ {
561+ QueueReleasableInterface <T> *releasable = static_cast <QueueReleasableInterface <T> *> (it->first);
562+
563+ releasable->release (it->second);
564+ }
565+
566+ mItems.clear ();
567+ }
568+
569+ void doRemoveReleasable (compiz::queues::QueueReleaseInterface *r)
570+ {
571+ typename std::map <QueueReleaseInterface *, T>::iterator it = mItems.find (r);
572+
573+ if (it != mItems.end ())
574+ mItems.erase (it);
575+ }
576+
577+ std::map <QueueReleaseInterface *, T> mItems;
578+ };
579+
580+ class QueueLock :
581+ public QueueLockInterface
582+ {
583+ public:
584+
585+ QueueLock (QueueUnlockInterface *unlockable, const pendingItemsFunc &f);
586+ ~QueueLock ();
587+
588+ private:
589+
590+ bool doUnlock ();
591+ void doCallback (QueueReleaseInterface *releasable);
592+
593+ QueueUnlockInterface *mUnlockable;
594+ pendingItemsFunc mPendingDispatch;
595+ };
596+
597+ class QueueImpl :
598+ public QueueUnlockInterface,
599+ public QueueLockGeneratorInterface
600+ {
601+ public:
602+
603+ QueueImpl (const notifyReleaseFunc &f) :
604+ mNotifyFunc (f)
605+ {
606+ }
607+
608+ void reset ();
609+ void notify (compiz::queues::QueueReleaseInterface *);
610+
611+ private:
612+
613+ void doRelease ();
614+ bool doRegisterLock (QueueLockInterface *lock);
615+ bool doUnregisterLock (QueueLockInterface *lock);
616+
617+ QueueLockInterface::Ptr doObtainLock (const pendingItemsFunc &);
618+
619+ notifyReleaseFunc mNotifyFunc;
620+ std::vector <QueueLockInterface *> mLocks;
621+ unsigned int mLockCount;
622+ };
623+
624+ template <class T>
625+ class Queue :
626+ boost::noncopyable,
627+ public QueueInterface <T>,
628+ public QueueLockGeneratorInterface,
629+ public QueueUnlockInterface
630+
631+ {
632+ public:
633+
634+ Queue (const typename QueueStorageInterface<T>::Ptr &storage) :
635+ mImpl (boost::bind (&QueueStorageInterface<T>::release, storage.get ())),
636+ mStorage (storage)
637+ {
638+ }
639+
640+ private:
641+
642+ void doAddPending (const T &t,
643+ QueueReleasableInterface <T> *release)
644+ {
645+ release->setRemoveInterface (static_cast <QueueReleaseRemoveInterface *> (mStorage.get ()));
646+
647+ mStorage->store (release, t);
648+ mImpl.reset ();
649+ mImpl.notify (release);
650+ mImpl.release ();
651+ }
652+
653+ boost::shared_ptr <QueueLockInterface> doObtainLock (const pendingItemsFunc &f)
654+ {
655+ return mImpl.obtainLock (f);
656+ }
657+
658+ void doRelease ()
659+ {
660+ return mImpl.release ();
661+ }
662+
663+ bool doRegisterLock (QueueLockInterface *lock)
664+ {
665+ return mImpl.registerLock (lock);
666+ }
667+
668+ bool doUnregisterLock (QueueLockInterface *lock)
669+ {
670+ return mImpl.unregisterLock (lock);
671+ }
672+
673+ QueueImpl mImpl;
674+ typename compiz::queues::QueueStorageInterface<T>::Ptr mStorage;
675+ };
676+ }
677+ }
678+}
679+
680+
681+#endif
682
683=== added directory 'src/queues/src'
684=== added file 'src/queues/src/queues.cpp'
685--- src/queues/src/queues.cpp 1970-01-01 00:00:00 +0000
686+++ src/queues/src/queues.cpp 2012-04-02 15:10:24 +0000
687@@ -0,0 +1,113 @@
688+/*
689+ * Copyright © 2012 Canonical Ltd.
690+ *
691+ * Permission to use, copy, modify, distribute, and sell this software
692+ * and its documentation for any purpose is hereby granted without
693+ * fee, provided that the above copyright notice appear in all copies
694+ * and that both that copyright notice and this permission notice
695+ * appear in supporting documentation, and that the name of
696+ * Canonical Ltd. not be used in advertising or publicity pertaining to
697+ * distribution of the software without specific, written prior permission.
698+ * Canonical Ltd. makes no representations about the suitability of this
699+ * software for any purpose. It is provided "as is" without express or
700+ * implied warranty.
701+ *
702+ * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
703+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
704+ * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
705+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
706+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
707+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
708+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
709+ *
710+ * Authored by: Sam Spilsbury <sam.spilsbury@canonical.com>
711+ */
712+
713+#include <core/queues.h>
714+#include <cstdio>
715+
716+using namespace compiz::queues;
717+using namespace compiz::queues::impl;
718+
719+void
720+QueueImpl::reset ()
721+{
722+ mLockCount = mLocks.size () + 1;
723+}
724+
725+void
726+QueueImpl::notify (QueueReleaseInterface *releasable)
727+{
728+ for (std::vector <QueueLockInterface *>::iterator it = mLocks.begin (); it != mLocks.end (); it++)
729+ (*it)->callback (releasable);
730+}
731+
732+void
733+QueueImpl::doRelease ()
734+{
735+ if (!mLockCount)
736+ return;
737+
738+ mLockCount--;
739+
740+ if (mLockCount)
741+ return;
742+
743+ /* Release all queued items */
744+ mNotifyFunc ();
745+}
746+
747+bool
748+QueueImpl::doRegisterLock (QueueLockInterface *lock)
749+{
750+ std::vector<QueueLockInterface *>::iterator it = std::find (mLocks.begin (), mLocks.end (), lock);
751+
752+ if (it != mLocks.end ())
753+ return false;
754+
755+ mLocks.push_back (lock);
756+ return true;
757+}
758+
759+bool
760+QueueImpl::doUnregisterLock (QueueLockInterface *lock)
761+{
762+ std::vector<QueueLockInterface *>::iterator it = std::find (mLocks.begin (), mLocks.end (), lock);
763+
764+ if (it == mLocks.end ())
765+ return false;
766+
767+ mLocks.erase (it);
768+ return true;
769+}
770+
771+QueueLockInterface::Ptr
772+QueueImpl::doObtainLock (const pendingItemsFunc &f)
773+{
774+ return QueueLockInterface::Ptr (new QueueLock (this, f));
775+}
776+
777+QueueLock::QueueLock (QueueUnlockInterface *unlockable, const pendingItemsFunc &pending) :
778+ mUnlockable (unlockable),
779+ mPendingDispatch (pending)
780+{
781+ mUnlockable->registerLock (this);
782+}
783+
784+QueueLock::~QueueLock ()
785+{
786+ mUnlockable->unregisterLock (this);
787+}
788+
789+bool
790+QueueLock::doUnlock ()
791+{
792+ mUnlockable->release ();
793+ return true;
794+}
795+
796+void
797+QueueLock::doCallback (QueueReleaseInterface *releasable)
798+{
799+ mPendingDispatch (releasable);
800+}
801
802=== added directory 'src/queues/tests'
803=== added file 'src/queues/tests/CMakeLists.txt'
804--- src/queues/tests/CMakeLists.txt 1970-01-01 00:00:00 +0000
805+++ src/queues/tests/CMakeLists.txt 2012-04-02 15:10:24 +0000
806@@ -0,0 +1,18 @@
807+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
808+
809+add_library (compiz_queues_test
810+ ${CMAKE_CURRENT_SOURCE_DIR}/test-queues.cpp)
811+
812+add_executable (compiz_test_queues
813+ ${CMAKE_CURRENT_SOURCE_DIR}/queues/src/test-queues.cpp)
814+
815+target_link_libraries (compiz_test_queues
816+ compiz_queues_test
817+ compiz_queues
818+ ${GTEST_BOTH_LIBRARIES}
819+ ${GMOCK_LIBRARY}
820+ ${GMOCK_MAIN_LIBRARY}
821+ ${CMAKE_THREAD_LIBS_INIT} # Link in pthread.
822+ )
823+
824+gtest_add_tests (compiz_test_queues "" ${CMAKE_CURRENT_SOURCE_DIR}/queues/src/test-queues.cpp)
825
826=== added directory 'src/queues/tests/queues'
827=== added directory 'src/queues/tests/queues/src'
828=== added file 'src/queues/tests/queues/src/test-queues.cpp'
829--- src/queues/tests/queues/src/test-queues.cpp 1970-01-01 00:00:00 +0000
830+++ src/queues/tests/queues/src/test-queues.cpp 2012-04-02 15:10:24 +0000
831@@ -0,0 +1,231 @@
832+/*
833+ * Copyright © 2011 Canonical Ltd.
834+ *
835+ * Permission to use, copy, modify, distribute, and sell this software
836+ * and its documentation for any purpose is hereby granted without
837+ * fee, provided that the above copyright notice appear in all copies
838+ * and that both that copyright notice and this permission notice
839+ * appear in supporting documentation, and that the name of
840+ * Canonical Ltd. not be used in advertising or publicity pertaining to
841+ * distribution of the software without specific, written prior permission.
842+ * Canonical Ltd. makes no representations about the suitability of this
843+ * software for any purpose. It is provided "as is" without express or
844+ * implied warranty.
845+ *
846+ * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
847+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
848+ * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
849+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
850+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
851+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
852+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
853+ *
854+ * Authored by: Sam Spilsbury <sam.spilsbury@canonical.com>
855+ */
856+
857+#include "test-queues.h"
858+#include <boost/cast.hpp>
859+
860+class CompQueuesTestQueues :
861+ public CompQueuesTest
862+{
863+ public:
864+
865+ CompQueuesTestQueues ();
866+ ~CompQueuesTestQueues ();
867+
868+};
869+
870+CompQueuesTestQueues::CompQueuesTestQueues ()
871+{
872+}
873+
874+CompQueuesTestQueues::~CompQueuesTestQueues ()
875+{
876+}
877+
878+TEST_F(CompQueuesTestQueues, TestSetRemoveReleasables)
879+{
880+ boost::shared_ptr <MockQueueStorage <int> > mockStorage (new MockQueueStorage <int> ());
881+ impl::Queue <int> q (boost::shared_static_cast <QueueStorageInterface <int> > (mockStorage));
882+
883+ MockQueueReleasable <int> releasable;
884+
885+ releasable.DelegateToFake ();
886+
887+ EXPECT_CALL (releasable, doSetRemoveInterface (_));
888+ EXPECT_CALL (*mockStorage, doStore (_, 7));
889+ EXPECT_CALL (*mockStorage, doRelease ());
890+ EXPECT_CALL (*mockStorage, doRemoveReleasable (_));
891+
892+ q.addPending (7, &releasable);
893+}
894+
895+TEST_F(CompQueuesTestQueues, TestReleaseNoLocks)
896+{
897+ boost::shared_ptr <MockQueueStorage <int> > mockStorage (new MockQueueStorage <int> ());
898+ impl::Queue <int> q (boost::shared_static_cast <QueueStorageInterface <int> > (mockStorage));
899+
900+ MockQueueReleasable <int> releasable;
901+
902+ releasable.DelegateToFake ();
903+
904+ EXPECT_CALL (releasable, doSetRemoveInterface (_));
905+ EXPECT_CALL (*mockStorage, doStore (_, 7));
906+ EXPECT_CALL (*mockStorage, doRelease ());
907+ EXPECT_CALL (*mockStorage, doRemoveReleasable (_));
908+
909+ q.addPending (7, &releasable);
910+}
911+
912+TEST_F(CompQueuesTestQueues, TestReleaseWithLockUnlock)
913+{
914+ boost::shared_ptr <impl::AccumulatedMapStorage <int> > actualStorage (new impl::AccumulatedMapStorage <int> ());
915+ boost::shared_ptr <MockQueueStorage <int> > mockStorage (new MockQueueStorage <int> ());
916+
917+ mockStorage->Delegate (static_cast <QueueStorageInterface <int> *> (actualStorage.get ()));
918+
919+ impl::Queue <int> q (boost::shared_static_cast <QueueStorageInterface <int> > (mockStorage));
920+ QueueLockGeneratorDelegate <impl::QueueLock> gen (static_cast <QueueUnlockInterface *> (&q));
921+ StrictMock <MockPendingItems> pi;
922+
923+ MockQueue <int> mq;
924+
925+ mq.Delegate (&q, &gen);
926+
927+ boost::function <void (QueueReleaseInterface *)> callback (boost::bind (&PendingItemsInterface::pending, static_cast <PendingItemsInterface *> (&pi), _1));
928+
929+ EXPECT_CALL (mq, doObtainLock (_));
930+
931+ QueueLockInterface::Ptr lock (mq.obtainLock (callback));
932+
933+ StrictMock <MockQueueReleasable <int> > releasable;
934+
935+ releasable.DelegateToFake ();
936+
937+ EXPECT_CALL (releasable, doSetRemoveInterface (_));
938+ EXPECT_CALL (*mockStorage, doStore (_, 7));
939+ EXPECT_CALL (*mockStorage, doRemoveReleasable (_));
940+ EXPECT_CALL (pi, doPending (_));
941+
942+ q.addPending (7, &releasable);
943+
944+ EXPECT_CALL (*mockStorage, doRelease ());
945+ EXPECT_CALL (releasable, doRelease (7));
946+
947+ lock->unlock ();
948+}
949+
950+TEST_F(CompQueuesTestQueues, TestReleaseWithLockNoUnlock)
951+{
952+ boost::shared_ptr <impl::AccumulatedMapStorage <int> > actualStorage (new impl::AccumulatedMapStorage <int> ());
953+ boost::shared_ptr <MockQueueStorage <int> > mockStorage (new MockQueueStorage <int> ());
954+
955+ mockStorage->Delegate (static_cast <QueueStorageInterface <int> *> (actualStorage.get ()));
956+
957+ impl::Queue <int> q (boost::shared_static_cast <QueueStorageInterface <int> > (mockStorage));
958+ QueueLockGeneratorDelegate <impl::QueueLock> gen (static_cast <QueueUnlockInterface *> (&q));
959+ StrictMock <MockPendingItems> pi;
960+
961+ MockQueue <int> mq;
962+
963+ mq.Delegate (&q, &gen);
964+
965+ boost::function <void (QueueReleaseInterface *)> callback (boost::bind (&PendingItemsInterface::pending, static_cast <PendingItemsInterface *> (&pi), _1));
966+
967+ EXPECT_CALL (mq, doObtainLock (_));
968+
969+ QueueLockInterface::Ptr lock (mq.obtainLock (callback));
970+
971+ StrictMock <MockQueueReleasable <int> > releasable;
972+
973+ releasable.DelegateToFake ();
974+
975+ EXPECT_CALL (releasable, doSetRemoveInterface (_));
976+ EXPECT_CALL (*mockStorage, doStore (_, 7));
977+ EXPECT_CALL (*mockStorage, doRemoveReleasable (_));
978+ EXPECT_CALL (pi, doPending (_));
979+
980+ q.addPending (7, &releasable);
981+}
982+
983+TEST_F(CompQueuesTestQueues, TestRemoveReleasableLocked)
984+{
985+ boost::shared_ptr <impl::AccumulatedMapStorage <int> > actualStorage (new impl::AccumulatedMapStorage <int> ());
986+ boost::shared_ptr <MockQueueStorage <int> > mockStorage (new MockQueueStorage <int> ());
987+
988+ mockStorage->Delegate (static_cast <QueueStorageInterface <int> *> (actualStorage.get ()));
989+
990+ impl::Queue <int> q (boost::shared_static_cast <QueueStorageInterface <int> > (mockStorage));
991+ QueueLockGeneratorDelegate <impl::QueueLock> gen (static_cast <QueueUnlockInterface *> (&q));
992+ StrictMock <MockPendingItems> pi;
993+
994+ MockQueue <int> mq;
995+
996+ mq.Delegate (&q, &gen);
997+
998+ boost::function <void (QueueReleaseInterface *)> callback (boost::bind (&PendingItemsInterface::pending, static_cast <PendingItemsInterface *> (&pi), _1));
999+
1000+ EXPECT_CALL (mq, doObtainLock (_));
1001+
1002+ QueueLockInterface::Ptr lock (mq.obtainLock (callback));
1003+
1004+ boost::shared_ptr <StrictMock <MockQueueReleasable <int> > > releasable (new StrictMock <MockQueueReleasable <int> > ());
1005+
1006+ releasable->DelegateToFake ();
1007+
1008+ EXPECT_CALL (*releasable, doSetRemoveInterface (_));
1009+ EXPECT_CALL (*mockStorage, doStore (_, 7));
1010+ EXPECT_CALL (*mockStorage, doRemoveReleasable (_));
1011+ EXPECT_CALL (pi, doPending (_));
1012+
1013+ q.addPending (7, releasable.get ());
1014+
1015+ releasable.reset ();
1016+
1017+ EXPECT_CALL (*mockStorage, doRelease ());
1018+
1019+ lock->unlock ();
1020+}
1021+
1022+TEST_F(CompQueuesTestQueues, TestAccumulation)
1023+{
1024+ boost::shared_ptr <impl::AccumulatedMapStorage <int> > actualStorage (new impl::AccumulatedMapStorage <int> ());
1025+ boost::shared_ptr <MockQueueStorage <int> > mockStorage (new MockQueueStorage <int> ());
1026+
1027+ mockStorage->Delegate (static_cast <QueueStorageInterface <int> *> (actualStorage.get ()));
1028+
1029+ impl::Queue <int> q (boost::shared_static_cast <QueueStorageInterface <int> > (mockStorage));
1030+ QueueLockGeneratorDelegate <impl::QueueLock> gen (static_cast <QueueUnlockInterface *> (&q));
1031+ StrictMock <MockPendingItems> pi;
1032+
1033+ MockQueue <int> mq;
1034+
1035+ mq.Delegate (&q, &gen);
1036+
1037+ boost::function <void (QueueReleaseInterface *)> callback (boost::bind (&PendingItemsInterface::pending, static_cast <PendingItemsInterface *> (&pi), _1));
1038+
1039+ EXPECT_CALL (mq, doObtainLock (_));
1040+
1041+ QueueLockInterface::Ptr lock (mq.obtainLock (callback));
1042+
1043+ StrictMock <MockQueueReleasable <int> > releasable;
1044+
1045+ releasable.DelegateToFake ();
1046+
1047+ EXPECT_CALL (releasable, doSetRemoveInterface (_)).Times (3);
1048+ EXPECT_CALL (*mockStorage, doStore (_, 7));
1049+ EXPECT_CALL (*mockStorage, doStore (_, 8));
1050+ EXPECT_CALL (*mockStorage, doStore (_, 9));
1051+ EXPECT_CALL (*mockStorage, doRemoveReleasable (_));
1052+ EXPECT_CALL (pi, doPending (_)).Times (3);
1053+
1054+ q.addPending (7, &releasable);
1055+ q.addPending (8, &releasable);
1056+ q.addPending (9, &releasable);
1057+
1058+ EXPECT_CALL (*mockStorage, doRelease ());
1059+ EXPECT_CALL (releasable, doRelease (24));
1060+
1061+ lock->unlock ();
1062+}
1063
1064=== added file 'src/queues/tests/test-queues.cpp'
1065--- src/queues/tests/test-queues.cpp 1970-01-01 00:00:00 +0000
1066+++ src/queues/tests/test-queues.cpp 2012-04-02 15:10:24 +0000
1067@@ -0,0 +1,34 @@
1068+/*
1069+ * Copyright © 2011 Canonical Ltd.
1070+ *
1071+ * Permission to use, copy, modify, distribute, and sell this software
1072+ * and its documentation for any purpose is hereby granted without
1073+ * fee, provided that the above copyright notice appear in all copies
1074+ * and that both that copyright notice and this permission notice
1075+ * appear in supporting documentation, and that the name of
1076+ * Canonical Ltd. not be used in advertising or publicity pertaining to
1077+ * distribution of the software without specific, written prior permission.
1078+ * Canonical Ltd. makes no representations about the suitability of this
1079+ * software for any purpose. It is provided "as is" without express or
1080+ * implied warranty.
1081+ *
1082+ * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1083+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
1084+ * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1085+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
1086+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
1087+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
1088+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1089+ *
1090+ * Authored by: Sam Spilsbury <sam.spilsbury@canonical.com>
1091+ */
1092+
1093+#include "test-queues.h"
1094+
1095+CompQueuesTest::CompQueuesTest ()
1096+{
1097+}
1098+
1099+CompQueuesTest::~CompQueuesTest ()
1100+{
1101+}
1102
1103=== added file 'src/queues/tests/test-queues.h'
1104--- src/queues/tests/test-queues.h 1970-01-01 00:00:00 +0000
1105+++ src/queues/tests/test-queues.h 2012-04-02 15:10:24 +0000
1106@@ -0,0 +1,208 @@
1107+/*
1108+ * Copyright © 2011 Canonical Ltd.
1109+ *
1110+ * Permission to use, copy, modify, distribute, and sell this software
1111+ * and its documentation for any purpose is hereby granted without
1112+ * fee, provided that the above copyright notice appear in all copies
1113+ * and that both that copyright notice and this permission notice
1114+ * appear in supporting documentation, and that the name of
1115+ * Canonical Ltd. not be used in advertising or publicity pertaining to
1116+ * distribution of the software without specific, written prior permission.
1117+ * Canonical Ltd. makes no representations about the suitability of this
1118+ * software for any purpose. It is provided "as is" without express or
1119+ * implied warranty.
1120+ *
1121+ * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1122+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
1123+ * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1124+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
1125+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
1126+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
1127+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1128+ *
1129+ * Authored by: Sam Spilsbury <sam.spilsbury@canonical.com>
1130+ */
1131+
1132+#ifndef _COMPIZ_TEST_QUEUES_H
1133+#define _COMPIZ_TEST_QUEUES_H
1134+
1135+#include <gmock/gmock.h>
1136+#include <gtest/gtest.h>
1137+#include <core/queues.h>
1138+#include <iostream>
1139+#include <boost/bind.hpp>
1140+
1141+using ::testing::Invoke;
1142+using ::testing::_;
1143+using ::testing::StrictMock;
1144+using ::testing::AtLeast;
1145+
1146+class CompQueuesTest : public ::testing::Test
1147+{
1148+public:
1149+
1150+ CompQueuesTest ();
1151+ virtual ~CompQueuesTest ();
1152+
1153+};
1154+
1155+using namespace compiz::queues;
1156+
1157+class MockQueueReleaseRemovable :
1158+ public QueueReleaseRemoveInterface
1159+{
1160+ public:
1161+
1162+
1163+};
1164+
1165+class ReleaseRemovableDelegate :
1166+ public QueueReleaseInterface
1167+{
1168+ public:
1169+
1170+ ReleaseRemovableDelegate (void *releasable) :
1171+ mReleasable (releasable)
1172+ {
1173+ }
1174+
1175+ ~ReleaseRemovableDelegate ()
1176+ {
1177+ if (mInterface)
1178+ mInterface->removeReleasable (static_cast <QueueReleaseInterface *> (mReleasable));
1179+ }
1180+
1181+ void doSetRemoveInterface (QueueReleaseRemoveInterface *interface)
1182+ {
1183+ mInterface = interface;
1184+ }
1185+
1186+ private:
1187+
1188+ QueueReleaseRemoveInterface *mInterface;
1189+ void *mReleasable;
1190+};
1191+
1192+template <class T>
1193+class MockQueueReleasable :
1194+ public QueueReleasableInterface <T>
1195+{
1196+ public:
1197+
1198+ MOCK_METHOD1_T (doSetRemoveInterface, void (QueueReleaseRemoveInterface *));
1199+ MOCK_METHOD1_T (doRelease, bool (const T &));
1200+
1201+ MockQueueReleasable () :
1202+ mRemovableDelegate (this)
1203+ {
1204+ }
1205+
1206+ void DelegateToFake ()
1207+ {
1208+ ON_CALL (*this, doSetRemoveInterface (_)).WillByDefault (Invoke (&mRemovableDelegate, &ReleaseRemovableDelegate::doSetRemoveInterface));
1209+ }
1210+
1211+ private:
1212+
1213+ ReleaseRemovableDelegate mRemovableDelegate;
1214+};
1215+
1216+class MockQueueLock :
1217+ public QueueLockInterface
1218+{
1219+ public:
1220+
1221+ MOCK_METHOD0 (doUnlock, bool ());
1222+ MOCK_METHOD0 (doCallback, void ());
1223+};
1224+
1225+class MockQueueUnlockable :
1226+ public QueueUnlockInterface
1227+{
1228+ public:
1229+
1230+ MOCK_METHOD0 (doRelease, void ());
1231+ MOCK_METHOD1 (doRegisterLock, bool (QueueLockInterface *));
1232+ MOCK_METHOD1 (doUnregisterLock, bool (QueueLockInterface *));
1233+};
1234+
1235+template <class T>
1236+class QueueLockGeneratorDelegate :
1237+ public QueueLockGeneratorInterface
1238+{
1239+ public:
1240+
1241+ QueueLockGeneratorDelegate (QueueUnlockInterface *unlockable) :
1242+ mUnlockable (unlockable)
1243+ {
1244+ }
1245+
1246+ boost::shared_ptr <QueueLockInterface> doObtainLock (const pendingItemsFunc &f)
1247+ {
1248+ return typename boost::shared_ptr <T> (new T (mUnlockable, f));
1249+ }
1250+
1251+ private:
1252+
1253+ QueueUnlockInterface *mUnlockable;
1254+};
1255+
1256+class PendingItemsInterface
1257+{
1258+ public:
1259+
1260+ void pending (QueueReleaseInterface *lock) { doPending (lock); }
1261+
1262+ protected:
1263+
1264+ virtual void doPending (QueueReleaseInterface *lock) = 0;
1265+};
1266+
1267+class MockPendingItems :
1268+ public PendingItemsInterface
1269+{
1270+ public:
1271+
1272+ MOCK_METHOD1 (doPending, void (QueueReleaseInterface *));
1273+};
1274+
1275+template <class T>
1276+class MockQueue :
1277+ public QueueInterface <T>,
1278+ public QueueLockGeneratorInterface
1279+{
1280+ public:
1281+
1282+ MOCK_METHOD2_T (doAddPending, void (const T &, QueueReleasableInterface <T> *r));
1283+ MOCK_METHOD1_T (doObtainLock, boost::shared_ptr <QueueLockInterface> (const pendingItemsFunc &));
1284+
1285+
1286+ void Delegate (QueueInterface <T> *queue, QueueLockGeneratorInterface *gen)
1287+ {
1288+ if (queue)
1289+ ON_CALL (*this, doAddPending (_, _)).WillByDefault (Invoke (static_cast <QueueInterface <T> *> (queue), &QueueInterface <T>::addPending));
1290+
1291+ if (gen)
1292+ ON_CALL (*this, doObtainLock (_)).WillByDefault (Invoke (static_cast <QueueLockGeneratorInterface *> (gen), &QueueLockGeneratorInterface::obtainLock));
1293+ }
1294+};
1295+
1296+template <class T>
1297+class MockQueueStorage :
1298+ public QueueStorageInterface <T>
1299+{
1300+ public:
1301+
1302+ MOCK_METHOD1_T (doRemoveReleasable, void (QueueReleaseInterface *));
1303+ MOCK_METHOD2_T (doStore, bool (QueueReleasableInterface <T> *, const T &));
1304+ MOCK_METHOD0_T (doRelease, void ());
1305+
1306+ void Delegate (QueueStorageInterface <T> *storage)
1307+ {
1308+ ON_CALL (*this, doRemoveReleasable (_)).WillByDefault (Invoke (storage, &QueueStorageInterface<T>::removeReleasable));
1309+ ON_CALL (*this, doStore (_, _)).WillByDefault (Invoke (storage, &QueueStorageInterface<T>::store));
1310+ ON_CALL (*this, doRelease ()).WillByDefault (Invoke (storage, &QueueStorageInterface<T>::release));
1311+ }
1312+};
1313+
1314+#endif

Subscribers

People subscribed via source and target branches