Merge lp:~roryj/gala/maskcorners-plugin into lp:gala

Proposed by Rory
Status: Merged
Approved by: Rico Tzschichholz
Approved revision: 430
Merged at revision: 430
Proposed branch: lp:~roryj/gala/maskcorners-plugin
Merge into: lp:gala
Diff against target: 322 lines (+278/-0)
6 files modified
configure.ac (+1/-0)
data/org.pantheon.desktop.gala.gschema.xml.in.in (+21/-0)
plugins/Makefile.am (+1/-0)
plugins/maskcorners/Main.vala (+171/-0)
plugins/maskcorners/Makefile.am (+59/-0)
plugins/maskcorners/Settings.vala (+25/-0)
To merge this branch: bzr merge lp:~roryj/gala/maskcorners-plugin
Reviewer Review Type Date Requested Status
Rico Tzschichholz Approve
Danielle Foré Approve
Review via email: mp+246855@code.launchpad.net

Commit message

Implement Mask Corners plugin.

Description of the change

Implement Mask Corners plugin.

By default, corners are masked on all monitors and are disabled when an app goes fullscreen.

To post a comment you must log in.
Revision history for this message
Danielle Foré (danrabbit) wrote :

So this is pretty pimp. Very subtle. Some things I noticed:

* The little nudge feedback when attempting to move past the last workspace is not masked.
* When you zoom back in from multi-tasking view, you can see the workspace preview is not masked.
* Any radius over 4 is broken

Another question though: Does this plugin need to be shipped with Gala? There's currently no mechanism for enabling and disabling plugins in Gala. Maybe it would be better to ship as a separate package and let the package manager be the plugin manager through the "enhances" attribute.

review: Needs Fixing
Revision history for this message
Danielle Foré (danrabbit) wrote :

I think a sane upper limit should be set on the radius. Currently you can set ridiculous sizes like 800. I think after 32 you start having some issues with like not being able to click DE elements.

Revision history for this message
Rory (roryj) wrote :

I will have a look into the multitasking view issues, but that will require making changes in MultitaskingView, not this plugin (for which I may need Tom Beckmann's help!).

With the latest commit, changing the radius should work.

I have mainly been following what Tom did with his alternate-alt-tab plugin, but the way gala plugins are currently implemented, gala must be built with the plugin so the plugin cannot be packaged separately.

Revision history for this message
Danielle Foré (danrabbit) wrote :

Been using this with 6px radius. Very cool. I like it a lot

review: Approve
Revision history for this message
Rico Tzschichholz (ricotz) wrote :

Make the codestyle match gala's source.

review: Needs Fixing
Revision history for this message
Rory (roryj) wrote :

Have change the codestyle to match gala's source.

I would be interested to know why gala has a different codestyle to other elementary projects and the official codestyle doc.

Revision history for this message
Rico Tzschichholz (ricotz) wrote :

Avoid doing the same operation/thing multiple times in a method.

Cache external objects in "unowned local vars" if possible and reuse them. (e.g. wm.get_screen())

Cache local values and reuse them. (e.g. *.to_string())

I would prefer printf syntax to enforce type-safety. (e.g. "bla %i-%s".printf (int, string))

Tranforming "if COND { LOGIC } ... return" into "if !COND return; LOGIC" often avoids to indent.

Keep code itself sorted if possible (CONST, STATIC, CTOR, construct, DTOR, public methods, private methods) (quite often reasonable to do)

Lists in Makefiles are usually sorted alphabetically. (configure.ac and plugins/Makefile.am)

Be consistent with your coding paradigms.

In the end squash your branch into one commit.

review: Needs Fixing
Revision history for this message
Rico Tzschichholz (ricotz) wrote :

I am also not a fan of explicitly using "private" just omit it. This make it even more distinguishable from public ones, imo.

Revision history for this message
Rico Tzschichholz (ricotz) wrote :

Instead of creating 4 separate actors for every corner. Better create one and use rotated ClutterClones of it.

review: Needs Fixing
Revision history for this message
Rico Tzschichholz (ricotz) wrote :

Also there is the one-class-per-file convention.

Revision history for this message
Rory (roryj) wrote :

I think I've implemented everything you stated. Thank you very much for the help! :D

lp:~roryj/gala/maskcorners-plugin updated
430. By Rory

Implement Mask Corners plugin

Revision history for this message
Rico Tzschichholz (ricotz) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'configure.ac'
2--- configure.ac 2015-01-03 19:55:40 +0000
3+++ configure.ac 2015-02-05 20:16:27 +0000
4@@ -257,6 +257,7 @@
5 data/icons/Makefile
6 vapi/Makefile
7 plugins/Makefile
8+plugins/maskcorners/Makefile
9 plugins/notify/Makefile
10 plugins/zoom/Makefile
11 po/Makefile.in
12
13=== modified file 'data/org.pantheon.desktop.gala.gschema.xml.in.in'
14--- data/org.pantheon.desktop.gala.gschema.xml.in.in 2015-01-04 09:37:05 +0000
15+++ data/org.pantheon.desktop.gala.gschema.xml.in.in 2015-02-05 20:16:27 +0000
16@@ -237,4 +237,25 @@
17 <_description>Structure: ['{APP-NAME}:{PRIORITY (show/hide)},{SOUNDS on/off}', ...]</_description>
18 </key>
19 </schema>
20+
21+ <schema path="/org/pantheon/desktop/gala/mask-corners/" id="org.pantheon.desktop.gala.mask-corners" gettext-domain="@GETTEXT_PACKAGE@">
22+ <key type="b" name="enable">
23+ <default>true</default>
24+ <_summary>Enable rounded corner mask</_summary>
25+ </key>
26+ <key type="i" name="corner-radius">
27+ <default>4</default>
28+ <range min="1" max="32"/>
29+ <_summary>Corner radius</_summary>
30+ </key>
31+ <key type="b" name="disable-on-fullscreen">
32+ <default>true</default>
33+ <_summary>Disable corner mask on fullscreen</_summary>
34+ <description>If enabled, when an application is fullscreen (fills the monitor), the corner masks will be disabled on that monitor.</description>
35+ </key>
36+ <key type="b" name="only-on-primary">
37+ <default>false</default>
38+ <_summary>Only show corner masks on primary monitor</_summary>
39+ </key>
40+ </schema>
41 </schemalist>
42
43=== modified file 'plugins/Makefile.am'
44--- plugins/Makefile.am 2014-07-18 08:24:26 +0000
45+++ plugins/Makefile.am 2015-02-05 20:16:27 +0000
46@@ -1,4 +1,5 @@
47 SUBDIRS = \
48+ maskcorners \
49 notify \
50 zoom \
51 $(NULL)
52
53=== added directory 'plugins/maskcorners'
54=== added file 'plugins/maskcorners/Main.vala'
55--- plugins/maskcorners/Main.vala 1970-01-01 00:00:00 +0000
56+++ plugins/maskcorners/Main.vala 2015-02-05 20:16:27 +0000
57@@ -0,0 +1,171 @@
58+//
59+// Copyright (C) 2015 Rory J Sanderson
60+//
61+// This program is free software: you can redistribute it and/or modify
62+// it under the terms of the GNU General Public License as published by
63+// the Free Software Foundation, either version 3 of the License, or
64+// (at your option) any later version.
65+//
66+// This program is distributed in the hope that it will be useful,
67+// but WITHOUT ANY WARRANTY; without even the implied warranty of
68+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
69+// GNU General Public License for more details.
70+//
71+// You should have received a copy of the GNU General Public License
72+// along with this program. If not, see <http://www.gnu.org/licenses/>.
73+//
74+
75+using Clutter;
76+using Meta;
77+
78+namespace Gala.Plugins.MaskCorners
79+{
80+ public class Main : Gala.Plugin
81+ {
82+ Gala.WindowManager? wm = null;
83+ Screen screen;
84+ Settings settings;
85+
86+ List<Actor>[] cornermasks;
87+ int corner_radius = 4;
88+
89+ public override void initialize (Gala.WindowManager wm)
90+ {
91+ this.wm = wm;
92+ screen = wm.get_screen ();
93+ settings = Settings.get_default ();
94+
95+ setup_cornermasks ();
96+
97+ settings.changed.connect (resetup_cornermasks);
98+ }
99+
100+ public override void destroy ()
101+ {
102+ destroy_cornermasks ();
103+ }
104+
105+ void setup_cornermasks ()
106+ {
107+ if (!settings.enable)
108+ return;
109+
110+ int n_monitors = screen.get_n_monitors ();
111+ cornermasks = new List<Actor>[n_monitors];
112+ corner_radius = settings.corner_radius;
113+
114+ if (settings.only_on_primary) {
115+ add_cornermasks (screen.get_primary_monitor ());
116+ } else {
117+ for (int m = 0; m < n_monitors; m++)
118+ add_cornermasks (m);
119+ }
120+
121+ if (settings.disable_on_fullscreen)
122+ screen.in_fullscreen_changed.connect (fullscreen_changed);
123+
124+ screen.monitors_changed.connect (resetup_cornermasks);
125+ }
126+
127+ void destroy_cornermasks ()
128+ {
129+ screen.monitors_changed.disconnect (resetup_cornermasks);
130+ screen.in_fullscreen_changed.disconnect (fullscreen_changed);
131+
132+ foreach (unowned List<Actor> list in cornermasks) {
133+ foreach (Actor actor in list)
134+ actor.destroy ();
135+ }
136+ }
137+
138+ void resetup_cornermasks ()
139+ {
140+ destroy_cornermasks ();
141+ setup_cornermasks ();
142+ }
143+
144+ void fullscreen_changed ()
145+ {
146+ for (int i = 0; i < screen.get_n_monitors (); i++) {
147+ foreach (Actor actor in cornermasks[i]) {
148+ if (screen.get_monitor_in_fullscreen (i))
149+ actor.hide ();
150+ else
151+ actor.show ();
152+ }
153+ }
154+ }
155+
156+ void add_cornermasks (int monitor_no)
157+ {
158+ var monitor_geometry = screen.get_monitor_geometry (monitor_no);
159+
160+ Canvas canvas = new Canvas ();
161+ canvas.set_size (corner_radius, corner_radius);
162+ canvas.draw.connect (draw_cornermask);
163+ canvas.invalidate ();
164+
165+ Actor actor = new Actor ();
166+ actor.set_content (canvas);
167+ actor.set_size (corner_radius, corner_radius);
168+ actor.set_position (monitor_geometry.x, monitor_geometry.y);
169+ actor.set_pivot_point ((float) 0.5, (float) 0.5);
170+
171+ cornermasks[monitor_no].append (actor);
172+ wm.stage.add_child (actor);
173+
174+ for (int p = 1; p < 4; p++) {
175+ Clone clone = new Clone (actor);
176+ clone.rotation_angle_z = p * 90;
177+
178+ switch (p) {
179+ case 1:
180+ clone.set_position (monitor_geometry.x + monitor_geometry.width, monitor_geometry.y);
181+ break;
182+ case 2:
183+ clone.set_position (monitor_geometry.x + monitor_geometry.width, monitor_geometry.y + monitor_geometry.height);
184+ break;
185+ case 3:
186+ clone.set_position (monitor_geometry.x, monitor_geometry.y + monitor_geometry.height);
187+ break;
188+ }
189+
190+ cornermasks[monitor_no].append (clone);
191+ wm.stage.add_child (clone);
192+ }
193+ }
194+
195+ bool draw_cornermask (Cairo.Context context)
196+ {
197+ var buffer = new Granite.Drawing.BufferSurface (corner_radius, corner_radius);
198+ var buffer_context = buffer.context;
199+
200+ buffer_context.arc (corner_radius, corner_radius, corner_radius, Math.PI, 1.5 * Math.PI);
201+ buffer_context.line_to (0, 0);
202+ buffer_context.line_to (0, corner_radius);
203+ buffer_context.set_source_rgb (0, 0, 0);
204+ buffer_context.fill ();
205+
206+ context.set_operator (Cairo.Operator.CLEAR);
207+ context.paint ();
208+ context.set_operator (Cairo.Operator.OVER);
209+ context.set_source_surface (buffer.surface, 0, 0);
210+ context.paint ();
211+
212+ return true;
213+ }
214+ }
215+}
216+
217+public Gala.PluginInfo register_plugin ()
218+{
219+ return
220+ {
221+ "Mask Corners",
222+ "Gala Developers",
223+ typeof (Gala.Plugins.MaskCorners.Main),
224+ Gala.PluginFunction.ADDITION,
225+ Gala.LoadPriority.IMMEDIATE
226+ };
227+}
228+
229
230=== added file 'plugins/maskcorners/Makefile.am'
231--- plugins/maskcorners/Makefile.am 1970-01-01 00:00:00 +0000
232+++ plugins/maskcorners/Makefile.am 2015-02-05 20:16:27 +0000
233@@ -0,0 +1,59 @@
234+include $(top_srcdir)/Makefile.common
235+
236+VAPIDIR = $(top_srcdir)/vapi
237+
238+BUILT_SOURCES = libgala_maskcorners_la_vala.stamp
239+
240+libgala_maskcorners_la_LTLIBRARIES = libgala-maskcorners.la
241+
242+libgala_maskcorners_ladir = $(pkglibdir)/plugins
243+
244+libgala_maskcorners_la_LDFLAGS = \
245+ $(PLUGIN_LDFLAGS) \
246+ $(GALA_CORE_LDFLAGS) \
247+ $(top_builddir)/lib/libgala.la \
248+ $(NULL)
249+
250+libgala_maskcorners_la_CFLAGS = \
251+ $(GALA_CORE_CFLAGS) \
252+ -include config.h \
253+ -w \
254+ -I$(top_builddir)/lib \
255+ $(NULL)
256+
257+libgala_maskcorners_la_VALAFLAGS = \
258+ $(GALA_CORE_VALAFLAGS) \
259+ $(top_builddir)/lib/gala.vapi \
260+ --vapidir $(VAPIDIR) \
261+ $(VAPIDIR)/config.vapi \
262+ $(NULL)
263+
264+libgala_maskcorners_la_LIBADD = \
265+ $(GALA_CORE_LIBS) \
266+ $(NULL)
267+
268+libgala_maskcorners_la_VALASOURCES = \
269+ Main.vala \
270+ Settings.vala \
271+ $(NULL)
272+
273+nodist_libgala_maskcorners_la_SOURCES = \
274+ $(BUILT_SOURCES) \
275+ $(libgala_maskcorners_la_VALASOURCES:.vala=.c) \
276+ $(NULL)
277+
278+libgala_maskcorners_la_vala.stamp: $(libgala_maskcorners_la_VALASOURCES)
279+ $(AM_V_VALA)$(VALAC) \
280+ $(libgala_maskcorners_la_VALAFLAGS) \
281+ -C \
282+ $(filter %.vala %.c,$^)
283+ $(AM_V_at)touch $@
284+
285+CLEANFILES = \
286+ $(nodist_libgala_maskcorners_la_SOURCES) \
287+ $(NULL)
288+
289+EXTRA_DIST = \
290+ $(libgala_maskcorners_la_VALASOURCES) \
291+ $(NULL)
292+
293
294=== added file 'plugins/maskcorners/Settings.vala'
295--- plugins/maskcorners/Settings.vala 1970-01-01 00:00:00 +0000
296+++ plugins/maskcorners/Settings.vala 2015-02-05 20:16:27 +0000
297@@ -0,0 +1,25 @@
298+namespace Gala.Plugins.MaskCorners
299+{
300+ class Settings : Granite.Services.Settings
301+ {
302+ static Settings? instance = null;
303+
304+ public static Settings get_default ()
305+ {
306+ if (instance == null)
307+ instance = new Settings ();
308+
309+ return instance;
310+ }
311+
312+ public bool enable { get; set; default = true; }
313+ public int corner_radius { get; set; default = 4; }
314+ public bool disable_on_fullscreen { get; set; default = true; }
315+ public bool only_on_primary { get; set; default = false; }
316+
317+ Settings ()
318+ {
319+ base (Config.SCHEMA + ".mask-corners");
320+ }
321+ }
322+}

Subscribers

People subscribed via source and target branches