Merge lp:~hikiko/unity/unity.shadows-on-existing-pixmaps into lp:unity

Proposed by Eleni Maria Stea
Status: Merged
Approved by: Marco Trevisan (Treviño)
Approved revision: no longer in the source branch.
Merged at revision: 4161
Proposed branch: lp:~hikiko/unity/unity.shadows-on-existing-pixmaps
Merge into: lp:unity
Diff against target: 387 lines (+241/-11)
8 files modified
decorations/CMakeLists.txt (+1/-0)
decorations/DecoratedWindow.cpp (+61/-4)
decorations/DecorationsManager.cpp (+27/-0)
decorations/DecorationsPriv.h (+5/-1)
decorations/DecorationsShape.cpp (+102/-0)
decorations/DecorationsShape.h (+43/-0)
plugins/unityshell/src/unityshell.cpp (+1/-1)
unity-shared/CompizUtils.cpp (+1/-5)
To merge this branch: bzr merge lp:~hikiko/unity/unity.shadows-on-existing-pixmaps
Reviewer Review Type Date Requested Status
Marco Trevisan (Treviño) Approve
PS Jenkins bot (community) continuous-integration Approve
Andrea Azzarone Pending
Unity Team Pending
Review via email: mp+284068@code.launchpad.net

Commit message

DecoratedWindow: Added shadows for shaped windows

Description of the change

Added shadows for shaped windows.

To post a comment you must log in.
Revision history for this message
Eleni Maria Stea (hikiko) wrote :

Just found a problem there.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Eleni Maria Stea (hikiko) wrote :

Just noticed that in some cases the shadow gets clipped by the extents of the shadow window resulting in a visual glitch. I'm going to review the code one more time.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

I've done based my branch on this, fixing some of the issues of this branch.

So I'm approving this as it is, while fixes are in https://code.launchpad.net/~3v1n0/unity/shadows-on-existing-pixmaps-cleanup/+merge/301099 (which it would be nice if you could review it)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'decorations/CMakeLists.txt'
2--- decorations/CMakeLists.txt 2014-03-27 19:32:34 +0000
3+++ decorations/CMakeLists.txt 2016-05-30 06:49:43 +0000
4@@ -35,6 +35,7 @@
5 DecorationsMenuDropdown.cpp
6 DecorationsForceQuitDialog.cpp
7 DecorationsDataPool.cpp
8+ DecorationsShape.cpp
9 )
10
11 add_library (decorations-lib STATIC ${DECORATION_SOURCES})
12
13=== modified file 'decorations/DecoratedWindow.cpp'
14--- decorations/DecoratedWindow.cpp 2016-04-01 00:50:30 +0000
15+++ decorations/DecoratedWindow.cpp 2016-05-30 06:49:43 +0000
16@@ -31,6 +31,8 @@
17 #include "WindowManager.h"
18 #include "UnitySettings.h"
19
20+#include <X11/extensions/shape.h>
21+
22 namespace unity
23 {
24 namespace decoration
25@@ -506,9 +508,9 @@
26 {
27 auto const& mi = manager_->impl_;
28 if (active() || parent_->scaled())
29- return mi->active_shadow_pixmap_->texture();
30+ return win_->region().numRects() > 1 ? shaped_shadow_pixmap_->texture() : mi->active_shadow_pixmap_->texture();
31
32- return mi->inactive_shadow_pixmap_->texture();
33+ return win_->region().numRects() > 1 ? shaped_shadow_pixmap_->texture() : mi->inactive_shadow_pixmap_->texture();
34 }
35
36 unsigned Window::Impl::ShadowRadius() const
37@@ -676,6 +678,53 @@
38 }
39 }
40
41+void Window::Impl::ComputeShapedShadowQuad()
42+{
43+ if (!(deco_elements_ & cu::DecorationElement::SHADOW))
44+ {
45+ if (!last_shadow_rect_.isEmpty())
46+ last_shadow_rect_.setGeometry(0, 0, 0, 0);
47+
48+ return;
49+ }
50+
51+ nux::Color color = active() ? manager_->active_shadow_color() : manager_->inactive_shadow_color();
52+ unsigned int radius = active() ? manager_->active_shadow_radius() : manager_->inactive_shadow_radius();
53+ DecorationsShape shape;
54+ shape.initShape(win_->id());
55+ shaped_shadow_pixmap_ = manager_->impl_->BuildShapedShadowTexture(radius, color, shape);
56+
57+ const auto* texture = ShadowTexture();
58+
59+ if (!texture || !texture->width() || !texture->height())
60+ return;
61+
62+ CompRect border = win_->borderRect();
63+ nux::Point2D<int> shadow_offset = manager_->shadow_offset();
64+// ideally it would be -radius for the *2 part see comment in Manager::Impl::BuildShapedShadowTexture
65+// in DecorationsManager.cpp Make sure to keep these factors in sync.
66+ int x = border.x() + shadow_offset.x - radius * 2 + shape.getXoffs();
67+ int y = border.y() + shadow_offset.y - radius * 2 + shape.getYoffs();
68+ int width = texture->width();
69+ int height = texture->height();
70+
71+ auto* quad = &shadow_quads_[Quads::Pos(0)];
72+ quad->box.setGeometry(x, y, width, height);
73+ quad->matrix = texture->matrix();
74+ quad->matrix.x0 = -COMP_TEX_COORD_X(quad->matrix, quad->box.x1());
75+ quad->matrix.y0 = -COMP_TEX_COORD_Y(quad->matrix, quad->box.y1());
76+
77+ CompRect shaped_shadow_rect(x, y, width, height);
78+ if (shaped_shadow_rect != last_shadow_rect_) {
79+ auto const& win_region = win_->region();
80+ quad->region = CompRegion(quad->box) - win_region;
81+
82+ last_shadow_rect_ = shaped_shadow_rect;
83+ win_->updateWindowOutputExtents();
84+ }
85+ cwin_->addDamage(true);
86+}
87+
88 void Window::Impl::Paint(GLMatrix const& transformation,
89 GLWindowPaintAttrib const& attrib,
90 CompRegion const& region, unsigned mask)
91@@ -714,7 +763,12 @@
92
93 glwin_->vertexBuffer()->begin();
94
95- for (unsigned i = 0; i < shadow_quads_.size(); ++i)
96+ // numRects is != 1 when the window is shaped
97+ unsigned int num_quads = shadow_quads_.size();
98+ if (win_->region().numRects() != 1)
99+ num_quads = 1;
100+
101+ for (unsigned int i = 0; i < num_quads; ++i)
102 {
103 auto& quad = shadow_quads_[Quads::Pos(i)];
104 glwin_->glAddGeometry(quad.matrices, quad.region, clip_region);
105@@ -949,7 +1003,10 @@
106 void Window::UpdateDecorationPosition()
107 {
108 impl_->UpdateMonitor();
109- impl_->ComputeShadowQuads();
110+ if (impl_->win_->region().numRects() > 1)
111+ impl_->ComputeShapedShadowQuad();
112+ else
113+ impl_->ComputeShadowQuads();
114 impl_->UpdateWindowEdgesGeo();
115 impl_->UpdateDecorationTextures();
116 impl_->UpdateForceQuitDialogPosition();
117
118=== modified file 'decorations/DecorationsManager.cpp'
119--- decorations/DecorationsManager.cpp 2016-03-09 17:28:36 +0000
120+++ decorations/DecorationsManager.cpp 2016-05-30 06:49:43 +0000
121@@ -23,6 +23,8 @@
122 #include <NuxGraphics/CairoGraphics.h>
123 #include <UnityCore/DBusIndicators.h>
124 #include <X11/Xatom.h>
125+#include <X11/extensions/shape.h>
126+
127 #include "WindowManager.h"
128
129 namespace unity
130@@ -80,6 +82,31 @@
131 return shadow_ctx;
132 }
133
134+cu::PixmapTexture::Ptr Manager::Impl::BuildShapedShadowTexture(unsigned int radius, nux::Color const& color, DecorationsShape const& shape) {
135+ //Ideally it would be shape.getWidth + radius * 2 but Cairographics::BlurSurface isn't bounded by the radius
136+ //and we need to compensate by using a larger texture. Make sure to modify Window::Impl::ComputeShapedShadowQuad in
137+ //DecoratedWindow.cpp if you change the factor.
138+ int blur_margin_factor = 2;
139+ int img_width = shape.getWidth() + radius * 2 * blur_margin_factor;
140+ int img_height = shape.getHeight() + radius * 2 * blur_margin_factor;
141+ nux::CairoGraphics img(CAIRO_FORMAT_ARGB32, img_width, img_height);
142+ auto* img_ctx = img.GetInternalContext();
143+
144+ for (int i=0; i<shape.getRectangleCount(); i++) {
145+ XRectangle rect = shape.getRectangle(i);
146+ cairo_rectangle(img_ctx, rect.x + radius * blur_margin_factor - shape.getXoffs(), rect.y + radius * blur_margin_factor - shape.getYoffs(), rect.width, rect.height);
147+ cairo_set_source_rgba(img_ctx, color.red, color.green, color.blue, color.alpha);
148+ cairo_fill(img_ctx);
149+ }
150+ img.BlurSurface(radius);
151+
152+ cu::CairoContext shadow_ctx(img_width, img_height);
153+ cairo_set_source_surface(shadow_ctx, img.GetSurface(), 0, 0);
154+ cairo_paint(shadow_ctx);
155+
156+ return shadow_ctx;
157+}
158+
159 void Manager::Impl::BuildActiveShadowTexture()
160 {
161 active_shadow_pixmap_ = BuildShadowTexture(manager_->active_shadow_radius(), manager_->active_shadow_color());
162
163=== modified file 'decorations/DecorationsPriv.h'
164--- decorations/DecorationsPriv.h 2016-04-01 00:50:30 +0000
165+++ decorations/DecorationsPriv.h 2016-05-30 06:49:43 +0000
166@@ -28,8 +28,8 @@
167 #include <core/core.h>
168 #include <opengl/opengl.h>
169 #include <composite/composite.h>
170-#include <X11/extensions/shape.h>
171
172+#include "DecorationsShape.h"
173 #include "DecorationsDataPool.h"
174 #include "DecorationsManager.h"
175 #include "DecorationsInputMixer.h"
176@@ -121,6 +121,7 @@
177 std::string const& GetMenusPanelID() const;
178
179 void ComputeShadowQuads();
180+ void ComputeShapedShadowQuad();
181 void UpdateDecorationTextures();
182 void UpdateWindowEdgesGeo();
183 void UpdateForceQuitDialogPosition();
184@@ -165,6 +166,8 @@
185 Item::Ptr edge_borders_;
186
187 EMConverter::Ptr cv_;
188+
189+ cu::PixmapTexture::Ptr shaped_shadow_pixmap_;
190 };
191
192 struct Manager::Impl : sigc::trackable
193@@ -189,6 +192,7 @@
194 void BuildActiveShadowTexture();
195 void BuildInactiveShadowTexture();
196 cu::PixmapTexture::Ptr BuildShadowTexture(unsigned radius, nux::Color const&);
197+ cu::PixmapTexture::Ptr BuildShapedShadowTexture(unsigned int radius, nux::Color const& color, DecorationsShape const& shape);
198 void OnShadowOptionsChanged(bool active);
199 void OnWindowFrameChanged(bool, ::Window, std::weak_ptr<decoration::Window> const&);
200 bool OnMenuKeyActivated(std::string const&);
201
202=== added file 'decorations/DecorationsShape.cpp'
203--- decorations/DecorationsShape.cpp 1970-01-01 00:00:00 +0000
204+++ decorations/DecorationsShape.cpp 2016-05-30 06:49:43 +0000
205@@ -0,0 +1,102 @@
206+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
207+/*
208+ * Copyright (C) 2016 Canonical Ltd
209+ *
210+ * This program is free software: you can redistribute it and/or modify
211+ * it under the terms of the GNU General Public License version 3 as
212+ * published by the Free Software Foundation.
213+ *
214+ * This program is distributed in the hope that it will be useful,
215+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
216+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
217+ * GNU General Public License for more details.
218+ *
219+ * You should have received a copy of the GNU General Public License
220+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
221+ *
222+ * Authored by: Eleni Maria Stea <elenimaria.stea@canonical.com>
223+ */
224+
225+#include <string.h>
226+#include <X11/extensions/shape.h>
227+#include "DecoratedWindow.h"
228+#include "DecorationsShape.h"
229+
230+bool DecorationsShape::initShape(XID win)
231+{
232+ Bool buse, cuse;
233+ int bx, by, cx, cy;
234+ unsigned int bw, bh, cw, ch;
235+ Display *dpy = screen->dpy();
236+
237+ XShapeQueryExtents(dpy, win, &buse, &bx, &by, &bw, &bh, &cuse, &cx, &cy, &cw, &ch);
238+
239+ int kind;
240+ if (buse) {
241+ width = bw;
242+ height = bh;
243+ xoffs = bx;
244+ yoffs = by;
245+ kind = ShapeBounding;
246+ }
247+ else if (cuse) {
248+ width = cw;
249+ height = ch;
250+ xoffs = cx;
251+ yoffs = cy;
252+ kind = ShapeClip;
253+ }
254+ else {
255+ fprintf(stderr, "XShapeQueryExtend returned no extends.\n");
256+ return false;
257+ }
258+
259+ int rect_count, rect_order;
260+ XRectangle *rectangles;
261+ if (!(rectangles = XShapeGetRectangles(dpy, win, kind, &rect_count, &rect_order))) {
262+ fprintf(stderr, "Failed to get shape rectangles\n");
263+ return false;
264+ }
265+
266+ for (int i=0; i< rect_count; i++) {
267+ rects.push_back(rectangles[i]);
268+ }
269+
270+ XFree(rectangles);
271+ return true;
272+}
273+
274+const XRectangle& DecorationsShape::getRectangle(int idx) const
275+{
276+ return rects[idx];
277+}
278+
279+int DecorationsShape::getRectangleCount() const
280+{
281+ return (int)rects.size();
282+}
283+
284+int DecorationsShape::getWidth() const
285+{
286+ return width;
287+}
288+
289+int DecorationsShape::getHeight() const
290+{
291+ return height;
292+}
293+
294+int DecorationsShape::getXoffs() const
295+{
296+ return xoffs;
297+}
298+
299+int DecorationsShape::getYoffs() const
300+{
301+ return yoffs;
302+}
303+void DecorationsShape::clear()
304+{
305+ width = height = 0;
306+ rects.clear();
307+}
308
309=== added file 'decorations/DecorationsShape.h'
310--- decorations/DecorationsShape.h 1970-01-01 00:00:00 +0000
311+++ decorations/DecorationsShape.h 2016-05-30 06:49:43 +0000
312@@ -0,0 +1,43 @@
313+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
314+/*
315+ * Copyright (C) 2016 Canonical Ltd
316+ *
317+ * This program is free software: you can redistribute it and/or modify
318+ * it under the terms of the GNU General Public License version 3 as
319+ * published by the Free Software Foundation.
320+ *
321+ * This program is distributed in the hope that it will be useful,
322+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
323+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
324+ * GNU General Public License for more details.
325+ *
326+ * You should have received a copy of the GNU General Public License
327+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
328+ *
329+ * Authored by: Eleni Maria Stea <elenimaria.stea@canonical.com>
330+ */
331+
332+#ifndef DECORATIONS_SHAPE_H_
333+#define DECORATIONS_SHAPE_H_
334+
335+#include "WindowManager.h"
336+#include "DecoratedWindow.h"
337+
338+class DecorationsShape
339+{
340+private:
341+ std::vector<XRectangle> rects;
342+ int width, height;
343+ int xoffs, yoffs;
344+
345+public:
346+ bool initShape(XID win);
347+ const XRectangle& getRectangle(int idx) const;
348+ int getRectangleCount() const;
349+ int getWidth() const;
350+ int getHeight() const;
351+ int getXoffs() const;
352+ int getYoffs() const;
353+ void clear();
354+};
355+#endif //DECORATIONS_SHAPE_H_
356
357=== modified file 'plugins/unityshell/src/unityshell.cpp'
358--- plugins/unityshell/src/unityshell.cpp 2016-05-17 02:56:14 +0000
359+++ plugins/unityshell/src/unityshell.cpp 2016-05-30 06:49:43 +0000
360@@ -3009,9 +3009,9 @@
361 wAttrib.opacity = 0.0;
362 int old_index = gWindow->glPaintGetCurrentIndex();
363 gWindow->glPaintSetCurrentIndex(MAXSHORT);
364+ deco_win_->Paint(matrix, wAttrib, region, mask);
365 bool ret = gWindow->glPaint(wAttrib, matrix, region, mask);
366 gWindow->glPaintSetCurrentIndex(old_index);
367- deco_win_->Paint(matrix, wAttrib, region, mask);
368 return ret;
369 }
370 }
371
372=== modified file 'unity-shared/CompizUtils.cpp'
373--- unity-shared/CompizUtils.cpp 2015-11-02 14:58:01 +0000
374+++ unity-shared/CompizUtils.cpp 2016-05-30 06:49:43 +0000
375@@ -211,11 +211,7 @@
376 }
377 }
378
379- if (region.boundingRect() != win->geometry()) // Shaped windows
380- return elements;
381-
382- if (rectangular)
383- elements |= DecorationElement::SHADOW;
384+ elements |= DecorationElement::SHADOW;
385
386 if (!win->overrideRedirect() &&
387 (win->type() & DECORABLE_WINDOW_TYPES) &&