Merge lp:~smspillaz/compiz-core/compiz-core.fix_969101 into lp:compiz-core

Proposed by Sam Spilsbury on 2012-03-31
Status: Merged
Merged at revision: 3086
Proposed branch: lp:~smspillaz/compiz-core/compiz-core.fix_969101
Merge into: lp:compiz-core
Diff against target: 1083 lines (+784/-123)
8 files modified
plugins/decor/CMakeLists.txt (+5/-1)
plugins/decor/src/clip-groups/CMakeLists.txt (+62/-0)
plugins/decor/src/clip-groups/include/clip-groups.h (+100/-0)
plugins/decor/src/clip-groups/src/clip-groups.cpp (+76/-0)
plugins/decor/src/clip-groups/tests/CMakeLists.txt (+14/-0)
plugins/decor/src/clip-groups/tests/clip-groups/src/test-decor-clip-groups.cpp (+395/-0)
plugins/decor/src/decor.cpp (+92/-121)
plugins/decor/src/decor.h (+40/-1)
To merge this branch: bzr merge lp:~smspillaz/compiz-core/compiz-core.fix_969101
Reviewer Review Type Date Requested Status
Daniel van Vugt Approve on 2012-04-05
Alan Griffiths 2012-03-31 Approve on 2012-04-02
Review via email: mp+100270@code.launchpad.net

This proposal supersedes a proposal from 2012-03-30.

Description of the change

== Problem ==

See LP#969101 - DecorWindow::computeShadowRegion is called like 20000 times per 800 moves, which is bad and not necessary considering what it is used for. Also the implementation kinda sucked

== Solution ==

Refactor shadow clipping into a clip group and clippable interfaces. Clip groups represent a single "layer" for shadowing purposes where all the shadows are clipped against the union of the input rects of the windows belonging to that layer. Only update items in the clip group when a relevant one has changed.

MatchedDecorClipGroup etc provide a "guarded" entrance so that only relevant windows are let in.

== Tests ==

Unit tests included.

To post a comment you must log in.
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

The killer: tests are not added to "make test"

Also, pure virtual functions should be private (not protected).

And there's no point to making destructors pure => "virtual ~DecorClippableInterface () {}"

Comment only: I (and almost everyone except Herb) don't see the point of NVPI.

review: Needs Fixing
Daniel van Vugt (vanvugt) wrote :

Tests OK. No obvious regressions.

However it does terrify me to be changing such a vast (and important) region of code so close to release. I can't retain confidence in the release if we merge this before precise, so I'll leave the decision to someone else.

review: Abstain
Daniel van Vugt (vanvugt) wrote :

Approved, on the condition that it doesn't get merged till 0.9.8.

Sam Spilsbury (smspillaz) wrote :

1) Its fully tested
2) It vastly improves performance
3) The vast majority of the diff size is in the tests
4) It improves code design
5) Its blocking another very important piece of code from landing

I think those are plenty good reasons to merge this /before/ precise

Took it for a test spin here and it works very well. Tried all sorts of weird window combinations with maximaized, semi-maximized, etc. All worked.

This branch seems to have as a side effect also fixing the bug where lingering shadow outlines would be briefly left behind when scrubbing panel app/indicator menus very fast. Only tested this on fast (sandybridge) hardware though, and not on my slower netbook. Is this correct or am I dreaming things up?

Alan Griffiths (alan-griffiths) wrote :

I agree with Sam that the "after" code is cleaner and that the majority of the diff is low risk (adding tests & build script).

I'd quibble with making destructors pure, and NVPI but it seems to run fine.

Cleaner, unit tested code... what's not to like?

review: Approve
Sam Spilsbury (smspillaz) wrote :

> Took it for a test spin here and it works very well. Tried all sorts of weird
> window combinations with maximaized, semi-maximized, etc. All worked.
>
> This branch seems to have as a side effect also fixing the bug where lingering
> shadow outlines would be briefly left behind when scrubbing panel
> app/indicator menus very fast. Only tested this on fast (sandybridge) hardware
> though, and not on my slower netbook. Is this correct or am I dreaming things
> up?

That is a bug in the animation plugin. Not sure what to do about it really.

Daniel van Vugt (vanvugt) wrote :

Confirmed this performance improvement seems to unblock the issue with:
lp:~smspillaz/compiz-core/compiz-core.work_923683

Daniel van Vugt (vanvugt) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'plugins/decor/CMakeLists.txt'
--- plugins/decor/CMakeLists.txt 2011-01-25 00:31:51 +0000
+++ plugins/decor/CMakeLists.txt 2012-03-31 03:35:24 +0000
@@ -3,7 +3,11 @@
3include (CompizPlugin)3include (CompizPlugin)
4include (CompizCommon)4include (CompizCommon)
55
6compiz_plugin(decor PLUGINDEPS composite opengl LIBRARIES decoration)6include_directories (${CMAKE_CURRENT_SOURCE_DIR}/src/clip-groups/include/)
7
8compiz_plugin(decor PLUGINDEPS composite opengl LIBRARIES decoration compiz_decor_clip_groups)
9
10add_subdirectory (src/clip-groups)
711
8if (COMPIZ_BUILD_WITH_RPATH AND NOT COMPIZ_DISABLE_PLUGIN_DECOR)12if (COMPIZ_BUILD_WITH_RPATH AND NOT COMPIZ_DISABLE_PLUGIN_DECOR)
913
1014
=== added directory 'plugins/decor/src/clip-groups'
=== added file 'plugins/decor/src/clip-groups/CMakeLists.txt'
--- plugins/decor/src/clip-groups/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ plugins/decor/src/clip-groups/CMakeLists.txt 2012-03-31 03:35:24 +0000
@@ -0,0 +1,62 @@
1pkg_check_modules (
2 GLIBMM
3 REQUIRED
4 glibmm-2.4 glib-2.0
5)
6
7INCLUDE_DIRECTORIES (
8 ${CMAKE_CURRENT_SOURCE_DIR}/include
9 ${CMAKE_CURRENT_SOURCE_DIR}/src
10
11 ${compiz_SOURCE_DIR}/src/point/include
12 ${compiz_SOURCE_DIR}/src/rect/include
13 ${compiz_SOURCE_DIR}/src/window/geometry/include
14 ${compiz_SOURCE_DIR}/src/window/geometry-saver/include
15 ${compiz_SOURCE_DIR}/src/window/extents/include
16 ${compiz_SOURCE_DIR}/include
17
18 ${Boost_INCLUDE_DIRS}
19
20 ${GLIBMM_INCLUDE_DIRS}
21)
22
23LINK_DIRECTORIES (${GLIBMM_LIBRARY_DIRS})
24
25SET (
26 PUBLIC_HEADERS
27)
28
29SET (
30 PRIVATE_HEADERS
31 ${CMAKE_CURRENT_SOURCE_DIR}/include/clip-groups.h
32)
33
34SET(
35 SRCS
36 ${CMAKE_CURRENT_SOURCE_DIR}/src/clip-groups.cpp
37)
38
39ADD_LIBRARY(
40 compiz_decor_clip_groups STATIC
41
42 ${SRCS}
43
44 ${PUBLIC_HEADERS}
45 ${PRIVATE_HEADERS}
46)
47
48if (COMPIZ_BUILD_TESTING)
49ADD_SUBDIRECTORY( ${CMAKE_CURRENT_SOURCE_DIR}/tests )
50endif (COMPIZ_BUILD_TESTING)
51
52SET_TARGET_PROPERTIES(
53 compiz_decor_clip_groups PROPERTIES
54 PUBLIC_HEADER "${PUBLIC_HEADERS}"
55)
56
57TARGET_LINK_LIBRARIES(
58 compiz_decor_clip_groups
59
60 compiz_core
61 ${GLIBMM_LIBRARIES}
62)
063
=== added directory 'plugins/decor/src/clip-groups/include'
=== added file 'plugins/decor/src/clip-groups/include/clip-groups.h'
--- plugins/decor/src/clip-groups/include/clip-groups.h 1970-01-01 00:00:00 +0000
+++ plugins/decor/src/clip-groups/include/clip-groups.h 2012-03-31 03:35:24 +0000
@@ -0,0 +1,100 @@
1/*
2 * Copyright (C) 2001 Havoc Pennington
3 * Copyright (C) 2002, 2003 Red Hat, Inc.
4 * Copyright (C) 2003 Rob Adams
5 * Copyright (C) 2005 Novell, Inc.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
21 */
22
23#ifndef _COMPIZ_DECOR_CLIP_GROUPS_H
24#define _COMPIZ_DECOR_CLIP_GROUPS_H
25
26#include <vector>
27#include <core/rect.h>
28#include <core/region.h>
29#include <core/match.h>
30
31namespace compiz
32{
33 namespace decor
34 {
35 class DecorClipGroupInterface;
36
37 class DecorClippableInterface
38 {
39 public:
40
41 virtual ~DecorClippableInterface () = 0;
42 void updateShadow (const CompRegion &r) { doUpdateShadow (r); }
43 void setOwner (DecorClipGroupInterface *i) { doSetOwner (i); }
44 bool matches (const CompMatch &m) { return doMatches (m); }
45 const CompRegion & outputRegion () { return getOutputRegion (); }
46 const CompRegion & inputRegion () { return getInputRegion (); }
47 void updateGroupShadows () { doUpdateGroupShadows (); }
48
49 private:
50
51 virtual void doUpdateShadow (const CompRegion &) = 0;
52 virtual void doSetOwner (DecorClipGroupInterface *i) = 0;
53 virtual bool doMatches (const CompMatch &m) = 0;
54 virtual const CompRegion & getOutputRegion () = 0;
55 virtual const CompRegion & getInputRegion () = 0;
56 virtual void doUpdateGroupShadows () = 0;
57 };
58
59 class DecorClipGroupInterface
60 {
61 public:
62
63 virtual ~DecorClipGroupInterface () = 0;
64
65 bool pushClippable (DecorClippableInterface *dc) { return doPushClippable (dc); }
66 bool popClippable (DecorClippableInterface *dc) { return doPopClippable (dc); }
67 void regenerateClipRegion () { doRegenerateClipRegion (); }
68 const CompRegion & clipRegion () { return getClipRegion (); }
69 void updateAllShadows () { return doUpdateAllShadows (); }
70
71 private:
72
73 virtual bool doPushClippable (DecorClippableInterface *dc) = 0;
74 virtual bool doPopClippable (DecorClippableInterface *dc) = 0;
75 virtual void doRegenerateClipRegion () = 0;
76 virtual const CompRegion & getClipRegion () = 0;
77 virtual void doUpdateAllShadows () = 0;
78 };
79
80 namespace impl
81 {
82 class GenericDecorClipGroup :
83 public DecorClipGroupInterface
84 {
85 private:
86
87 bool doPushClippable (DecorClippableInterface *dc);
88 bool doPopClippable (DecorClippableInterface *dc);
89 void doRegenerateClipRegion ();
90 const CompRegion & getClipRegion ();
91 void doUpdateAllShadows ();
92
93 std::vector <DecorClippableInterface *> mClippables;
94 CompRegion mRegion;
95 };
96 }
97 }
98}
99
100#endif
0101
=== added directory 'plugins/decor/src/clip-groups/src'
=== added file 'plugins/decor/src/clip-groups/src/clip-groups.cpp'
--- plugins/decor/src/clip-groups/src/clip-groups.cpp 1970-01-01 00:00:00 +0000
+++ plugins/decor/src/clip-groups/src/clip-groups.cpp 2012-03-31 03:35:24 +0000
@@ -0,0 +1,76 @@
1#include "clip-groups.h"
2#include <boost/foreach.hpp>
3#include <algorithm>
4
5#ifndef foreach
6#define foreach BOOST_FOREACH
7#endif
8
9using namespace compiz::decor;
10using namespace compiz::decor::impl;
11
12DecorClippableInterface::~DecorClippableInterface () {}
13DecorClipGroupInterface::~DecorClipGroupInterface () {}
14
15bool
16GenericDecorClipGroup::doPushClippable (DecorClippableInterface *dc)
17{
18 std::vector <DecorClippableInterface *>::iterator it = std::find (mClippables.begin (),
19 mClippables.end (),
20 dc);
21
22 if (it == mClippables.end ())
23 {
24 mClippables.push_back (dc);
25 regenerateClipRegion ();
26 dc->setOwner (this);
27
28 return true;
29 }
30
31 return false;
32}
33
34bool
35GenericDecorClipGroup::doPopClippable (DecorClippableInterface *dc)
36{
37 std::vector <DecorClippableInterface *>::iterator it = std::find (mClippables.begin (),
38 mClippables.end (),
39 dc);
40
41 if (it != mClippables.end ())
42 {
43 dc->setOwner (NULL);
44 dc->updateShadow (emptyRegion);
45 mClippables.erase (it);
46 regenerateClipRegion ();
47
48 return true;
49 }
50
51 return false;
52}
53
54void
55GenericDecorClipGroup::doRegenerateClipRegion ()
56{
57 mRegion -= infiniteRegion;
58
59 foreach (DecorClippableInterface *clippable, mClippables)
60 {
61 mRegion += clippable->inputRegion ();
62 }
63}
64
65const CompRegion &
66GenericDecorClipGroup::getClipRegion ()
67{
68 return mRegion;
69}
70
71void
72GenericDecorClipGroup::doUpdateAllShadows ()
73{
74 foreach (DecorClippableInterface *clippable, mClippables)
75 clippable->updateShadow (mRegion);
76}
077
=== added directory 'plugins/decor/src/clip-groups/tests'
=== added file 'plugins/decor/src/clip-groups/tests/CMakeLists.txt'
--- plugins/decor/src/clip-groups/tests/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ plugins/decor/src/clip-groups/tests/CMakeLists.txt 2012-03-31 03:35:24 +0000
@@ -0,0 +1,14 @@
1include_directories(${CMAKE_CURRENT_SOURCE_DIR})
2
3add_executable (compiz_test_decor_clip_groups
4 ${CMAKE_CURRENT_SOURCE_DIR}/clip-groups/src/test-decor-clip-groups.cpp)
5
6target_link_libraries (compiz_test_decor_clip_groups
7 compiz_decor_clip_groups
8 ${GTEST_BOTH_LIBRARIES}
9 ${GMOCK_LIBRARY}
10 ${GMOCK_MAIN_LIBRARY}
11 ${CMAKE_THREAD_LIBS_INIT} # Link in pthread.
12 )
13
14gtest_add_tests (compiz_test_decor_clip_groups "" ${CMAKE_CURRENT_SOURCE_DIR}/clip-groups/src/test-decor-clip-groups.cpp)
015
=== added directory 'plugins/decor/src/clip-groups/tests/clip-groups'
=== added directory 'plugins/decor/src/clip-groups/tests/clip-groups/src'
=== added file 'plugins/decor/src/clip-groups/tests/clip-groups/src/test-decor-clip-groups.cpp'
--- plugins/decor/src/clip-groups/tests/clip-groups/src/test-decor-clip-groups.cpp 1970-01-01 00:00:00 +0000
+++ plugins/decor/src/clip-groups/tests/clip-groups/src/test-decor-clip-groups.cpp 2012-03-31 03:35:24 +0000
@@ -0,0 +1,395 @@
1/*
2 * Copyright © 2012 Canonical Ltd.
3 *
4 * Permission to use, copy, modify, distribute, and sell this software
5 * and its documentation for any purpose is hereby granted without
6 * fee, provided that the above copyright notice appear in all copies
7 * and that both that copyright notice and this permission notice
8 * appear in supporting documentation, and that the name of
9 * Canonical Ltd. not be used in advertising or publicity pertaining to
10 * distribution of the software without specific, written prior permission.
11 * Canonical Ltd. makes no representations about the suitability of this
12 * software for any purpose. It is provided "as is" without express or
13 * implied warranty.
14 *
15 * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
17 * NO EVENT SHALL CANONICAL, LTD. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
21 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 *
23 * Authored by: Sam Spilsbury <sam.spilsbury@canonical.com>
24 */
25
26#include <gtest/gtest.h>
27#include <gmock/gmock.h>
28#include <iostream>
29#include "clip-groups.h"
30
31using ::testing::Invoke;
32using ::testing::_;
33using ::testing::StrictMock;
34
35using namespace compiz::decor;
36
37class CompDecorClipGroupsTest :
38 public ::testing::Test
39{
40};
41
42class FakeDecorClippable :
43 public DecorClippableInterface
44{
45 public:
46 FakeDecorClippable (const CompRegion &inputRegion,
47 const CompRegion &outputRegion,
48 DecorClippableInterface *parent,
49 bool matches) :
50 mInputRegion (inputRegion),
51 mOutputRegion (outputRegion),
52 mParent (parent),
53 mOwner (NULL),
54 mMatches (matches)
55 {
56 }
57
58 ~FakeDecorClippable ()
59 {
60 if (mOwner)
61 mOwner->popClippable (mParent);
62 }
63
64 const CompRegion &
65 getShadowRegion ()
66 {
67 return mShadowRegion;
68 }
69
70 private:
71
72 void doUpdateShadow (const CompRegion &r)
73 {
74 mShadowRegion = mOutputRegion.intersected (r - mInputRegion);
75 }
76
77 void doSetOwner (DecorClipGroupInterface *i)
78 {
79 mOwner = i;
80 }
81
82 bool doMatches (const CompMatch &m)
83 {
84 return mMatches;
85 }
86
87 const CompRegion & getOutputRegion () { return mOutputRegion; }
88 const CompRegion & getInputRegion () { return mInputRegion; }
89
90 void doUpdateGroupShadows ()
91 {
92 if (mOwner)
93 mOwner->updateAllShadows ();
94 }
95
96 CompRegion mInputRegion;
97 CompRegion mOutputRegion;
98
99 CompRegion mShadowRegion;
100
101 DecorClippableInterface *mParent;
102 DecorClipGroupInterface *mOwner;
103
104 bool mMatches;
105};
106
107class MockDecorClippable :
108 public DecorClippableInterface
109{
110 public:
111
112 MOCK_METHOD1 (doUpdateShadow, void (const CompRegion &));
113 MOCK_METHOD1 (doSetOwner, void (DecorClipGroupInterface *));
114 MOCK_METHOD1 (doMatches, bool (const CompMatch &));
115 MOCK_METHOD0 (getOutputRegion, const CompRegion & ());
116 MOCK_METHOD0 (getInputRegion, const CompRegion & ());
117 MOCK_METHOD0 (doUpdateGroupShadows, void ());
118
119 void Delegate (DecorClippableInterface &other)
120 {
121 ON_CALL (*this, doUpdateShadow (_)).WillByDefault (Invoke (&other, &DecorClippableInterface::updateShadow));
122 ON_CALL (*this, doSetOwner (_)).WillByDefault (Invoke (&other, &DecorClippableInterface::setOwner));
123 ON_CALL (*this, doMatches (_)).WillByDefault (Invoke (&other, &DecorClippableInterface::matches));
124 ON_CALL (*this, getOutputRegion ()).WillByDefault (Invoke (&other, &DecorClippableInterface::outputRegion));
125 ON_CALL (*this, getInputRegion ()).WillByDefault (Invoke (&other, &DecorClippableInterface::inputRegion));
126 ON_CALL (*this, doUpdateGroupShadows ()).WillByDefault (Invoke (&other, &DecorClippableInterface::updateGroupShadows));
127 }
128};
129
130void PrintTo(const CompRegion &reg, ::std::ostream *os)
131{
132 const CompRect &br = reg.boundingRect ();
133 *os << "Bounding Rect " << br.x () << " " << br.y () << " " << br.width () << " " << br.height () << std::endl;
134 const CompRect::vector &rv = reg.rects ();
135 for (CompRect::vector::const_iterator it = rv.begin ();
136 it != rv.end ();
137 it++)
138 {
139 const CompRect &r = *it;
140 *os << " - Rect : " << r.x () << " " << r.y () << " " << r.width () << " " << r.height () << std::endl;
141 }
142}
143
144TEST_F(CompDecorClipGroupsTest, TestPushClippable)
145{
146 impl::GenericDecorClipGroup cg;
147 StrictMock <MockDecorClippable> mdc;
148 FakeDecorClippable fdc (CompRegion (50, 50, 100, 100),
149 CompRegion (0, 0, 100, 100),
150 &mdc,
151 true);
152
153 mdc.Delegate (fdc);
154
155 EXPECT_CALL (mdc, getInputRegion ());
156 EXPECT_CALL (mdc, doSetOwner (_)).Times (2);
157 EXPECT_CALL (mdc, doUpdateShadow (_));
158
159 cg.pushClippable (&mdc);
160}
161
162TEST_F(CompDecorClipGroupsTest, TestPushClippableUpdatesRegion)
163{
164 impl::GenericDecorClipGroup cg;
165 StrictMock <MockDecorClippable> mdc;
166 FakeDecorClippable fdc (CompRegion (50, 50, 100, 100),
167 CompRegion (0, 0, 100, 100),
168 &mdc,
169 true);
170
171 mdc.Delegate (fdc);
172
173 EXPECT_CALL (mdc, getInputRegion ()).Times (2);
174 EXPECT_CALL (mdc, doSetOwner (_)).Times (2);
175 EXPECT_CALL (mdc, doUpdateShadow (_));
176
177 cg.pushClippable (&mdc);
178
179 EXPECT_EQ (cg.clipRegion (), mdc.inputRegion ());
180}
181
182MATCHER_P (CompRegionEq, other, "")
183{
184 return (arg ^ other).isEmpty ();
185}
186
187TEST_F(CompDecorClipGroupsTest, TestPush2ClippableUpdatesRegion)
188{
189 impl::GenericDecorClipGroup cg;
190 StrictMock <MockDecorClippable> mdc;
191 FakeDecorClippable fdc (CompRegion (50, 50, 100, 100),
192 CompRegion (0, 0, 100, 100),
193 &mdc,
194 true);
195
196 mdc.Delegate (fdc);
197
198 StrictMock <MockDecorClippable> mdc2;
199 FakeDecorClippable fdc2 (CompRegion (250, 250, 100, 100),
200 CompRegion (200, 200, 100, 100),
201 &mdc2,
202 true);
203
204 mdc2.Delegate (fdc2);
205
206 EXPECT_CALL (mdc, getInputRegion ()).Times (4);
207 EXPECT_CALL (mdc, doSetOwner (&cg));
208 EXPECT_CALL (mdc, doSetOwner (NULL));
209 EXPECT_CALL (mdc, doUpdateShadow (_)).Times (1);
210
211 EXPECT_CALL (mdc2, getInputRegion ()).Times (2);
212 EXPECT_CALL (mdc2, doSetOwner (&cg));
213 EXPECT_CALL (mdc2, doSetOwner (NULL));
214 EXPECT_CALL (mdc2, doUpdateShadow (_)).Times (1);
215
216 cg.pushClippable (&mdc);
217 cg.pushClippable (&mdc2);
218
219 CompRegion accumulated;
220
221 accumulated += mdc.inputRegion ();
222 accumulated += mdc2.inputRegion ();
223
224 EXPECT_THAT (cg.clipRegion (), CompRegionEq (accumulated));
225}
226
227TEST_F(CompDecorClipGroupsTest, TestPush3ClippableUpdatesRegion)
228{
229 impl::GenericDecorClipGroup cg;
230 StrictMock <MockDecorClippable> mdc;
231 FakeDecorClippable fdc (CompRegion (50, 50, 100, 100),
232 CompRegion (0, 0, 100, 100),
233 &mdc,
234 true);
235
236 mdc.Delegate (fdc);
237
238 StrictMock <MockDecorClippable> mdc2;
239 FakeDecorClippable fdc2 (CompRegion (150, 150, 100, 100),
240 CompRegion (100, 100, 100, 100),
241 &mdc2,
242 true);
243
244 mdc2.Delegate (fdc2);
245
246 StrictMock <MockDecorClippable> mdc3;
247 FakeDecorClippable fdc3 (CompRegion (250, 250, 100, 100),
248 CompRegion (200, 200, 100, 100),
249 &mdc3,
250 true);
251
252 mdc3.Delegate (fdc3);
253
254 EXPECT_CALL (mdc, getInputRegion ()).Times (6);
255 EXPECT_CALL (mdc, doSetOwner (&cg));
256 EXPECT_CALL (mdc, doSetOwner (NULL));
257 EXPECT_CALL (mdc, doUpdateShadow (_)).Times (1);
258
259 EXPECT_CALL (mdc2, getInputRegion ()).Times (4);
260 EXPECT_CALL (mdc2, doSetOwner (&cg));
261 EXPECT_CALL (mdc2, doSetOwner (NULL));
262 EXPECT_CALL (mdc2, doUpdateShadow (_)).Times (1);
263
264 EXPECT_CALL (mdc3, getInputRegion ()).Times (2);
265 EXPECT_CALL (mdc3, doSetOwner (&cg));
266 EXPECT_CALL (mdc3, doSetOwner (NULL));
267 EXPECT_CALL (mdc3, doUpdateShadow (_)).Times (1);
268
269 cg.pushClippable (&mdc);
270 cg.pushClippable (&mdc2);
271 cg.pushClippable (&mdc3);
272
273 CompRegion accumulated;
274
275 accumulated += mdc.inputRegion ();
276 accumulated += mdc2.inputRegion ();
277 accumulated += mdc3.inputRegion ();
278
279 EXPECT_THAT (cg.clipRegion (), CompRegionEq (accumulated));
280}
281
282TEST_F(CompDecorClipGroupsTest, TestPush2ClippableUpdatesShadow)
283{
284 impl::GenericDecorClipGroup cg;
285 StrictMock <MockDecorClippable> mdc;
286 FakeDecorClippable fdc (CompRegion (50, 50, 25, 25),
287 CompRegion (25, 25, 100, 100),
288 &mdc,
289 true);
290
291 mdc.Delegate (fdc);
292
293 StrictMock <MockDecorClippable> mdc2;
294 FakeDecorClippable fdc2 (CompRegion (75, 75, 50, 50),
295 CompRegion (25, 25, 100, 100),
296 &mdc2,
297 true);
298
299 mdc2.Delegate (fdc2);
300
301 EXPECT_CALL (mdc, getInputRegion ()).Times (4);
302 EXPECT_CALL (mdc, doSetOwner (&cg));
303 EXPECT_CALL (mdc, doSetOwner (NULL));
304 EXPECT_CALL (mdc, doUpdateShadow (_)).Times (2);
305
306 EXPECT_CALL (mdc2, getInputRegion ()).Times (2);
307 EXPECT_CALL (mdc2, doSetOwner (&cg));
308 EXPECT_CALL (mdc2, doSetOwner (NULL));
309 EXPECT_CALL (mdc2, doUpdateShadow (_)).Times (2);
310
311 cg.pushClippable (&mdc);
312 cg.pushClippable (&mdc2);
313
314 cg.updateAllShadows ();
315
316 CompRegion accumulated;
317
318 accumulated += mdc.inputRegion ();
319 accumulated += mdc2.inputRegion ();
320
321 EXPECT_THAT (cg.clipRegion (), CompRegionEq (accumulated));
322
323 CompRegion fdcRegion (75, 75, 50, 50);
324
325 EXPECT_THAT (fdc.getShadowRegion (), CompRegionEq (fdcRegion));
326
327 CompRegion fdc2Region (50, 50, 25, 25);
328
329 EXPECT_THAT (fdc2.getShadowRegion (), CompRegionEq (fdc2Region));
330}
331
332TEST_F(CompDecorClipGroupsTest, TestPush3ClippableUpdatesRegionPop1)
333{
334 impl::GenericDecorClipGroup cg;
335 StrictMock <MockDecorClippable> mdc;
336 FakeDecorClippable fdc (CompRegion (50, 50, 100, 100),
337 CompRegion (0, 0, 100, 100),
338 &mdc,
339 true);
340
341 mdc.Delegate (fdc);
342
343 StrictMock <MockDecorClippable> mdc2;
344 FakeDecorClippable fdc2 (CompRegion (150, 150, 100, 100),
345 CompRegion (100, 100, 100, 100),
346 &mdc2,
347 true);
348
349 mdc2.Delegate (fdc2);
350
351 StrictMock <MockDecorClippable> mdc3;
352 FakeDecorClippable fdc3 (CompRegion (250, 250, 100, 100),
353 CompRegion (200, 200, 100, 100),
354 &mdc3,
355 true);
356
357 mdc3.Delegate (fdc3);
358
359 EXPECT_CALL (mdc, getInputRegion ()).Times (7);
360 EXPECT_CALL (mdc, doSetOwner (&cg));
361 EXPECT_CALL (mdc, doSetOwner (NULL));
362 EXPECT_CALL (mdc, doUpdateShadow (_)).Times (1);
363
364 EXPECT_CALL (mdc2, getInputRegion ()).Times (5);
365 EXPECT_CALL (mdc2, doSetOwner (&cg));
366 EXPECT_CALL (mdc2, doSetOwner (NULL));
367 EXPECT_CALL (mdc2, doUpdateShadow (_)).Times (1);
368
369 EXPECT_CALL (mdc3, getInputRegion ()).Times (2);
370 EXPECT_CALL (mdc3, doSetOwner (&cg));
371 EXPECT_CALL (mdc3, doSetOwner (NULL));
372 EXPECT_CALL (mdc3, doUpdateShadow (_)).Times (1);
373
374 cg.pushClippable (&mdc);
375 cg.pushClippable (&mdc2);
376 cg.pushClippable (&mdc3);
377
378 CompRegion accumulated;
379
380 accumulated += mdc.inputRegion ();
381 accumulated += mdc2.inputRegion ();
382 accumulated += mdc3.inputRegion ();
383
384 EXPECT_THAT (cg.clipRegion (), CompRegionEq (accumulated));
385
386 cg.popClippable (&mdc3);
387
388 accumulated = CompRegion ();
389
390 accumulated += mdc.inputRegion ();
391 accumulated += mdc2.inputRegion ();
392
393 EXPECT_THAT (cg.clipRegion (), CompRegionEq (accumulated));
394}
395
0396
=== modified file 'plugins/decor/src/decor.cpp'
--- plugins/decor/src/decor.cpp 2012-03-22 17:00:51 +0000
+++ plugins/decor/src/decor.cpp 2012-03-31 03:35:24 +0000
@@ -42,6 +42,57 @@
4242
43COMPIZ_PLUGIN_20090315 (decor, DecorPluginVTable)43COMPIZ_PLUGIN_20090315 (decor, DecorPluginVTable)
4444
45MatchedDecorClipGroup::MatchedDecorClipGroup (const CompMatch &match) :
46 mMatch (match)
47{
48}
49
50bool
51MatchedDecorClipGroup::doPushClippable (DecorClippableInterface *dc)
52{
53 if (dc->matches (mMatch))
54 return mClipGroupImpl.pushClippable (dc);
55
56 return false;
57}
58
59void
60DecorWindow::doUpdateShadow (const CompRegion &reg)
61{
62 shadowRegion = outputRegion () - (reg - inputRegion ());
63}
64
65void
66DecorWindow::doSetOwner (DecorClipGroupInterface *i)
67{
68 mClipGroup = i;
69}
70
71bool
72DecorWindow::doMatches (const CompMatch &m)
73{
74 return const_cast <CompMatch &> (m).evaluate (window) && !window->invisible ();
75}
76
77const CompRegion &
78DecorWindow::getOutputRegion ()
79{
80 return mOutputRegion;
81}
82
83const CompRegion &
84DecorWindow::getInputRegion ()
85{
86 return mInputRegion;
87}
88
89void
90DecorWindow::doUpdateGroupShadows ()
91{
92 if (mClipGroup)
93 mClipGroup->updateAllShadows ();
94}
95
45/* From core */96/* From core */
4697
47/*98/*
@@ -69,89 +120,6 @@
69 return false;120 return false;
70}121}
71122
72/*
73 * DecorWindow::computeShadowRegion
74 *
75 * This function computes the current clip region for the
76 * shadow that should be draw on glDraw.
77 *
78 * Make shadows look nice, don't paint shadows on top of
79 * things they don't make sense on top of, eg, menus
80 * need shadows but they don't need to be painted when
81 * another menu is adjacent and covering the shadow
82 * region. Also panel shadows are nice, but not
83 * when they obscure client window shadows
84 *
85 * We need to use the current clip region here
86 * and take an intersection of that to ensure
87 * that we don't unintentionally expand the clip
88 * region that core already reduced by doing
89 * occlusion detection
90 */
91void
92DecorWindow::computeShadowRegion ()
93{
94 shadowRegion = CompRegion (window->outputRect ());
95
96 if (window->type () == CompWindowTypeDropdownMenuMask ||
97 window->type () == CompWindowTypePopupMenuMask)
98 {
99 /* Other transient menus should clip
100 * this menu's shadows, also the panel
101 * which is a transient parent should
102 * too */
103
104 CompWindowList::iterator it = std::find (screen->windows ().begin (),
105 screen->windows ().end (),
106 window);
107
108 for (it--; it != screen->windows ().end (); it--)
109 {
110 if (!(*it)->isViewable ())
111 continue;
112
113 if (!((*it)->type () == CompWindowTypeDropdownMenuMask ||
114 (*it)->type () == CompWindowTypePopupMenuMask ||
115 (*it)->type () == CompWindowTypeDockMask))
116 continue;
117
118 /* window needs to be a transient parent */
119 if (!isAncestorTo (window, (*it)))
120 continue;
121
122 CompRegion inter (shadowRegion);
123 inter &= (*it)->borderRect ();
124
125 if (!inter.isEmpty ())
126 shadowRegion -= inter;
127 }
128
129 /* If the region didn't change, then it is safe to
130 * say that that this window was probably the first
131 * menu in the "chain" of dropdown menus that comes
132 * from a menu-bar - in that case there isn't any
133 * window that the shadow would necessarily occlude
134 * here so clip the shadow to the top of the input
135 * rect.
136 *
137 * FIXME: We need a better way to detect exactly
138 * where the menubar is for the dropdown menu,
139 * that will look a lot better.
140 */
141 if (window->type () == CompWindowTypeDropdownMenuMask &&
142 shadowRegion == CompRegionRef (window->outputRect ().region ()))
143 {
144 CompRect area (window->outputRect ().x1 (),
145 window->outputRect ().y1 (),
146 window->outputRect ().width (),
147 window->inputRect ().y1 () -
148 window->outputRect ().y1 ());
149
150 shadowRegion -= area;
151 }
152 }
153}
154
155/*123/*
156 * DecorWindow::glDraw124 * DecorWindow::glDraw
157 *125 *
@@ -1508,7 +1476,7 @@
1508 if (dScreen->cmActive)1476 if (dScreen->cmActive)
1509 {1477 {
1510 cWindow->damageOutputExtents ();1478 cWindow->damageOutputExtents ();
1511 computeShadowRegion ();1479 updateGroupShadows ();
1512 }1480 }
15131481
1514 /* Determine how much we moved the window for the old1482 /* Determine how much we moved the window for the old
@@ -2183,7 +2151,17 @@
2183 break;2151 break;
2184 }2152 }
21852153
2154 /* For non-switcher windows we need to update the decoration
2155 * anyways, since the window is unmapped. Also need to
2156 * update the shadow clip regions for panels and other windows */
2157 update (true);
2158 if (dScreen->mMenusClipGroup.pushClippable (this))
2159 updateGroupShadows ();
2160
2161 break;
2162
2186 case CompWindowNotifyUnmap:2163 case CompWindowNotifyUnmap:
2164 {
21872165
2188 /* When the switcher is unmapped, it has no frame window2166 /* When the switcher is unmapped, it has no frame window
2189 * so the frame window for it needs to unmapped manually */2167 * so the frame window for it needs to unmapped manually */
@@ -2198,14 +2176,15 @@
2198 * anyways, since the window is unmapped. Also need to2176 * anyways, since the window is unmapped. Also need to
2199 * update the shadow clip regions for panels and other windows */2177 * update the shadow clip regions for panels and other windows */
2200 update (true);2178 update (true);
2201 if (dScreen->cmActive)2179
2202 {2180 /* Preserve the group shadow update ptr */
2203 foreach (CompWindow *cw, DecorScreen::get (screen)->cScreen->getWindowPaintList ())2181 DecorClipGroupInterface *clipGroup = mClipGroup;
2204 {2182
2205 DecorWindow::get (cw)->computeShadowRegion ();2183 if (dScreen->mMenusClipGroup.popClippable (this))
2206 }2184 if (clipGroup)
2207 }2185 clipGroup->updateAllShadows ();
2208 break;2186 break;
2187 }
2209 case CompWindowNotifyUnreparent:2188 case CompWindowNotifyUnreparent:
2210 {2189 {
2211 /* Compiz detaches the frame window from2190 /* Compiz detaches the frame window from
@@ -2397,18 +2376,6 @@
2397 if (w)2376 if (w)
2398 DecorWindow::get (w)->update (true);2377 DecorWindow::get (w)->update (true);
2399 }2378 }
2400 /* On a transient change, we need to recompute shadow regions
2401 * for eg, menus */
2402 else if (event->xproperty.atom == XA_WM_TRANSIENT_FOR)
2403 {
2404 if (cmActive)
2405 {
2406 foreach (CompWindow *cw, cScreen->getWindowPaintList ())
2407 {
2408 DecorWindow::get (cw)->computeShadowRegion ();
2409 }
2410 }
2411 }
2412 else2379 else
2413 {2380 {
2414 if (event->xproperty.window == screen->root ())2381 if (event->xproperty.window == screen->root ())
@@ -2736,14 +2703,11 @@
2736 }2703 }
2737 updateReg = true;2704 updateReg = true;
27382705
2739 if (dScreen->cmActive)2706 mInputRegion.translate (dx, dy);
2740 {2707 mOutputRegion.translate (dx, dy);
2741 foreach (CompWindow *cw,2708
2742 DecorScreen::get (screen)->cScreen->getWindowPaintList ())2709 if (dScreen->cmActive && mClipGroup)
2743 {2710 updateGroupShadows ();
2744 DecorWindow::get (cw)->computeShadowRegion ();
2745 }
2746 }
27472711
2748 window->moveNotify (dx, dy, immediate);2712 window->moveNotify (dx, dy, immediate);
2749}2713}
@@ -2796,14 +2760,10 @@
2796 updateDecorationScale ();2760 updateDecorationScale ();
2797 updateReg = true;2761 updateReg = true;
27982762
2799 if (dScreen->cmActive)2763 mInputRegion = CompRegion (window->inputRect ());
2800 {2764 mOutputRegion = CompRegion (window->outputRect ());
2801 foreach (CompWindow *cw,2765 if (dScreen->cmActive && mClipGroup)
2802 DecorScreen::get (screen)->cScreen->getWindowPaintList ())2766 updateGroupShadows ();
2803 {
2804 DecorWindow::get (cw)->computeShadowRegion ();
2805 }
2806 }
28072767
2808 window->resizeNotify (dx, dy, dwidth, dheight);2768 window->resizeNotify (dx, dy, dwidth, dheight);
2809}2769}
@@ -2971,7 +2931,8 @@
2971 0,2931 0,
2972 None,2932 None,
2973 boost::shared_array <decor_quad_t> (NULL),2933 boost::shared_array <decor_quad_t> (NULL),
2974 0))2934 0)),
2935 mMenusClipGroup (CompMatch ("type=Dock | type=DropdownMenu | type=Menu | type=PopupMenu"))
2975{2936{
2976 supportingDmCheckAtom =2937 supportingDmCheckAtom =
2977 XInternAtom (s->dpy (), DECOR_SUPPORTING_DM_CHECK_ATOM_NAME, 0);2938 XInternAtom (s->dpy (), DECOR_SUPPORTING_DM_CHECK_ATOM_NAME, 0);
@@ -3045,7 +3006,10 @@
3045 unshading (false),3006 unshading (false),
3046 shading (false),3007 shading (false),
3047 isSwitcher (false),3008 isSwitcher (false),
3048 frameExtentsRequested (false)3009 frameExtentsRequested (false),
3010 mClipGroup (NULL),
3011 mOutputRegion (window->outputRect ()),
3012 mInputRegion (window->inputRect ())
3049{3013{
3050 WindowInterface::setHandler (window);3014 WindowInterface::setHandler (window);
30513015
@@ -3074,6 +3038,10 @@
3074 }3038 }
30753039
3076 window->resizeNotifySetEnabled (this, true);3040 window->resizeNotifySetEnabled (this, true);
3041
3042 if (!window->invisible ())
3043 if (dScreen->mMenusClipGroup.pushClippable (this))
3044 updateGroupShadows ();
3077}3045}
30783046
3079/* 3047/*
@@ -3090,6 +3058,9 @@
3090 if (wd)3058 if (wd)
3091 WindowDecoration::destroy (wd);3059 WindowDecoration::destroy (wd);
30923060
3061 if (mClipGroup)
3062 mClipGroup->popClippable (this);
3063
3093 decor.mList.clear ();3064 decor.mList.clear ();
3094}3065}
30953066
30963067
=== modified file 'plugins/decor/src/decor.h'
--- plugins/decor/src/decor.h 2012-02-29 08:38:22 +0000
+++ plugins/decor/src/decor.h 2012-03-31 03:35:24 +0000
@@ -33,6 +33,8 @@
33#include <core/atoms.h>33#include <core/atoms.h>
34#include <core/windowextents.h>34#include <core/windowextents.h>
3535
36#include <clip-groups.h>
37
36#include "decor_options.h"38#include "decor_options.h"
3739
38#define DECOR_SCREEN(s) DecorScreen *ds = DecorScreen::get(s)40#define DECOR_SCREEN(s) DecorScreen *ds = DecorScreen::get(s)
@@ -50,6 +52,27 @@
50#define DECOR_ACTIVE 152#define DECOR_ACTIVE 1
51#define DECOR_NUM 253#define DECOR_NUM 2
5254
55using namespace compiz::decor;
56
57class MatchedDecorClipGroup :
58 public DecorClipGroupInterface
59{
60 public:
61
62 MatchedDecorClipGroup (const CompMatch &match);
63
64 private:
65
66 bool doPushClippable (DecorClippableInterface *dc);
67 bool doPopClippable (DecorClippableInterface *dc) { return mClipGroupImpl.popClippable (dc); }
68 void doRegenerateClipRegion () { return mClipGroupImpl.regenerateClipRegion (); }
69 const CompRegion & getClipRegion () { return mClipGroupImpl.clipRegion (); }
70 void doUpdateAllShadows () { return mClipGroupImpl.updateAllShadows (); }
71
72 impl::GenericDecorClipGroup mClipGroupImpl;
73 CompMatch mMatch;
74};
75
53class DecorTexture {76class DecorTexture {
5477
55 public:78 public:
@@ -204,13 +227,16 @@
204 std::map<Window, DecorWindow *> frames;227 std::map<Window, DecorWindow *> frames;
205228
206 CompTimer decoratorStart;229 CompTimer decoratorStart;
230
231 MatchedDecorClipGroup mMenusClipGroup;
207};232};
208233
209class DecorWindow :234class DecorWindow :
210 public WindowInterface,235 public WindowInterface,
211 public CompositeWindowInterface,236 public CompositeWindowInterface,
212 public GLWindowInterface,237 public GLWindowInterface,
213 public PluginClassHandler<DecorWindow,CompWindow>238 public PluginClassHandler<DecorWindow,CompWindow>,
239 public DecorClippableInterface
214{240{
215 public:241 public:
216 DecorWindow (CompWindow *w);242 DecorWindow (CompWindow *w);
@@ -260,6 +286,15 @@
260 static bool matchState (CompWindow *w, unsigned int decorState);286 static bool matchState (CompWindow *w, unsigned int decorState);
261 static bool matchActions (CompWindow *w, unsigned int decorActions);287 static bool matchActions (CompWindow *w, unsigned int decorActions);
262288
289 private:
290
291 void doUpdateShadow (const CompRegion &);
292 void doSetOwner (DecorClipGroupInterface *i);
293 bool doMatches (const CompMatch &m);
294 const CompRegion & getOutputRegion ();
295 const CompRegion & getInputRegion ();
296 void doUpdateGroupShadows ();
297
263 public:298 public:
264299
265 CompWindow *window;300 CompWindow *window;
@@ -296,6 +331,10 @@
296 bool isSwitcher;331 bool isSwitcher;
297332
298 bool frameExtentsRequested;333 bool frameExtentsRequested;
334
335 DecorClipGroupInterface *mClipGroup;
336 CompRegion mOutputRegion;
337 CompRegion mInputRegion;
299};338};
300339
301class DecorPluginVTable :340class DecorPluginVTable :

Subscribers

People subscribed via source and target branches