Merge lp:~elementary-pantheon/wingpanel/background-opacity-gala into lp:~elementary-pantheon/wingpanel/trunk-0.3.x

Proposed by Tom Beckmann
Status: Merged
Approved by: Danielle Foré
Approved revision: 159
Merged at revision: 155
Proposed branch: lp:~elementary-pantheon/wingpanel/background-opacity-gala
Merge into: lp:~elementary-pantheon/wingpanel/trunk-0.3.x
Diff against target: 469 lines (+260/-24)
7 files modified
CMakeLists.txt (+6/-1)
org.pantheon.desktop.wingpanel.gschema.xml (+11/-1)
src/Services/BackgroundManager.vala (+110/-0)
src/Services/Settings.vala (+2/-0)
src/Widgets/BasePanel.vala (+111/-19)
src/Widgets/Panel.vala (+16/-3)
src/WingpanelApp.vala (+4/-0)
To merge this branch: bzr merge lp:~elementary-pantheon/wingpanel/background-opacity-gala
Reviewer Review Type Date Requested Status
Victor Martinez (community) Approve
Danielle Foré Needs Fixing
Review via email: mp+210347@code.launchpad.net

This proposal supersedes a proposal from 2014-03-09.

Commit message

Uses the gala dbus API to get the alpha value of the background. Adds a transition when changing alpha and uses wnck to check for maximized windows on the current screen

Description of the change

This is a new version of the branch written by Jacob Parker, which uses the proposed gala dbus API to get the alpha value of the background. It also adds a transition when changing alpha and uses wnck to check for maximized windows on the current screen as requested in https://bugs.launchpad.net/wingpanel/+bug/1011830.

We may want to consider checking the area which is filled with windows instead of just if there's a maximized one, but that's up to the designers to decide.

To post a comment you must log in.
Revision history for this message
Victor Martinez (victored) wrote : Posted in a previous version of this proposal

is lp:wingpanel intentionally the target branch?

(instead of lp:wingpanel/0.3.x, which would make the diff much smaller)

Revision history for this message
Tom Beckmann (tombeckmann) wrote :

No, it wasn't. Thanks for notifying me :)

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

Going opaque with maximized windows is working for me, which is cool.

But it's not changing opacity with the wallpaper. I'm getting this output:

wingpanel_services_settings_get_background_alpha: assertion 'self != NULL' failed

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

I've noticed that killing the panel (after changing wallpaper) causes it to change. But it looks pretty binary. I'm only getting either completely transparent or like 80% opacity. Nothing at all in between.

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

The algorithm currently works with a min variance and mean color value. If it's below that it just uses 0.7 alpha. I could try with some interpolation, but I'm not sure if I can get it to work properly. I just took the alrogithm by Jacob Parker here, too.

Revision history for this message
Tom Beckmann (tombeckmann) wrote :

Also, when there's a maximized window, do you want full opaque or the 0.7 we use for the light wallpapers too?

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

Okay, I'm actually fine with doing 0 or some value as long as we make that value a lot lighter. Cassidy and I think that 0.3 works pretty well.

Yeah, I think it would better to go fully opaque when it's maximized.

So with the above change, the only real problem I have is that I have to kill the panel to get it to change instead of it changing when I change the wallpaper.

157. By Tom Beckmann

use 0.3 as min alpha value, go fully opaque when there is a maximized window

Revision history for this message
Tom Beckmann (tombeckmann) wrote :

Could you run "dbus-monitor | grep BackgroundChanged" in a terminal, change the background and look if something happens in the terminal? There should be some messages popping up.

I changed the min alpha value, the one that is taken when the wallpaper is found to be too light, to 0.3 now. Wingpanel will go fully opaque now when there's a maximized window. To me it appears very dark now, maybe you'll want to test if that is really the best way to do it. Also, maybe you could see if the logic for testing for a maximized window is already good enough or if we want to do something more complex. It will only go opaque currently if there's some window on the current workspace maximized. It won't go opaque for example when there are multiple non maximized windows obscuring the whole desktop.

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

Hey Tom,

I don't have any output there. Is there something I need to do to start the dbus service?

the black looks right for me, but I also have a black display :p

158. By Victor Martinez

Fix null Settings instance in BasePanel and correct coding style issues

159. By Victor Martinez

replace tabs by four spaces

Revision history for this message
Victor Martinez (victored) wrote :

Tom, this branch works great!

I've fixed the failed-assertion issue pointed out by Daniel above, which was related to a null Settings instance in BasePanel.

I also made a couple of corrections regarding the coding style, since the branch was using Gala's in some portions.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2013-10-16 09:36:11 +0000
3+++ CMakeLists.txt 2014-03-17 21:44:46 +0000
4@@ -37,13 +37,14 @@
5 gobject-2.0
6 glib-2.0
7 gio-2.0
8- gee-1.0
9+ gee-0.8
10 gdk-x11-3.0
11 x11
12 gtk+-3.0
13 granite
14 indicator3-0.4
15 libido3-0.1
16+ libwnck-3.0
17 )
18
19 set (WINGPANEL_DEPS_NOVALA
20@@ -72,6 +73,8 @@
21 link_libraries(${DEPS_LIBRARIES} ${DEPS_NOVALA_LIBRARIES})
22 link_directories(${DEPS_LIBRARY_DIRS} ${DEPS_NOVALA_DIRS})
23
24+add_definitions (-DWNCK_I_KNOW_THIS_IS_UNSTABLE)
25+
26 # Handle Vala Compilation
27 find_package(Vala REQUIRED)
28 include(ValaVersion)
29@@ -101,6 +104,7 @@
30 src/Services/AppLauncherService.vala
31 src/Services/LauncherRunner.vala
32 src/Services/IndicatorSorter.vala
33+ src/Services/BackgroundManager.vala
34 PACKAGES
35 ${WINGPANEL_DEPS}
36 CUSTOM_VAPIS
37@@ -120,6 +124,7 @@
38
39 # Create the Executable
40 add_executable(${EXEC_NAME} ${VALA_C})
41+target_link_libraries(${EXEC_NAME} m)
42
43 # Installation
44 install (TARGETS ${EXEC_NAME} RUNTIME DESTINATION bin)
45
46=== modified file 'org.pantheon.desktop.wingpanel.gschema.xml'
47--- org.pantheon.desktop.wingpanel.gschema.xml 2012-07-08 03:02:36 +0000
48+++ org.pantheon.desktop.wingpanel.gschema.xml 2014-03-17 21:44:46 +0000
49@@ -13,7 +13,17 @@
50 <key type="s" name="default-launcher">
51 <default>"slingshot-launcher"</default>
52 <summary>The default program to use as App launcher.</summary>
53- <description>Description</description>
54+ <description>The default program to use as App launcher.</description>
55+ </key>
56+ <key type="d" name="background-alpha">
57+ <default>0.8</default>
58+ <summary>Background opacity variable.</summary>
59+ <description>Background opacity variable (must be between zero and one).</description>
60+ </key>
61+ <key type="b" name="auto-adjust-alpha">
62+ <default>true</default>
63+ <summary>Automatically update background alpha.</summary>
64+ <description>Automatically update the background alpha to zero if it will be readable, else 0.8.</description>
65 </key>
66 </schema>
67 </schemalist>
68
69=== added file 'src/Services/BackgroundManager.vala'
70--- src/Services/BackgroundManager.vala 1970-01-01 00:00:00 +0000
71+++ src/Services/BackgroundManager.vala 2014-03-17 21:44:46 +0000
72@@ -0,0 +1,110 @@
73+// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
74+//
75+// Copyright (C) 2014 Wingpanel Developers
76+//
77+// This program is free software: you can redistribute it and/or modify
78+// it under the terms of the GNU General Public License as published by
79+// the Free Software Foundation, either version 3 of the License, or
80+// (at your option) any later version.
81+//
82+// This program is distributed in the hope that it will be useful,
83+// but WITHOUT ANY WARRANTY; without even the implied warranty of
84+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
85+// GNU General Public License for more details.
86+//
87+// You should have received a copy of the GNU General Public License
88+// along with this program. If not, see <http://www.gnu.org/licenses/>.
89+
90+namespace Wingpanel.Services {
91+ struct ColorInformation {
92+ double average_red;
93+ double average_green;
94+ double average_blue;
95+ double mean;
96+ double variance;
97+ }
98+
99+ [DBus (name = "org.pantheon.gala")]
100+ interface GalaDBus : Object {
101+ public signal void background_changed ();
102+ public async abstract ColorInformation get_background_color_information (int monitor,
103+ int x, int y, int width, int height) throws IOError;
104+ }
105+
106+ public class BackgroundManager : Object {
107+ public static const double MIN_ALPHA = 0.3;
108+
109+ private const int HEIGHT = 50;
110+ private const double MIN_VARIANCE = 50;
111+ private const double MIN_LUM = 25;
112+
113+ /**
114+ * Emitted when the background changed. It supplies the alpha value that
115+ * can be used with this wallpaper while maintining legibility
116+ */
117+ public signal void update_background_alpha (double legible_alpha_value);
118+
119+ private Services.Settings settings;
120+ private Gdk.Screen screen;
121+ private GalaDBus gala_dbus;
122+
123+ public BackgroundManager (Services.Settings settings, Gdk.Screen screen) {
124+ this.settings = settings;
125+ this.screen = screen;
126+ establish_connection ();
127+ }
128+
129+ private void establish_connection () {
130+ try {
131+ gala_dbus = Bus.get_proxy_sync (BusType.SESSION,
132+ "org.pantheon.gala",
133+ "/org/pantheon/gala");
134+ gala_dbus.background_changed.connect (on_background_change);
135+ on_background_change ();
136+ } catch (Error e) {
137+ gala_dbus = null;
138+ warning ("Auto-adjustment of background opacity not available, " +
139+ "connecting to gala dbus failed: %s", e.message);
140+ return;
141+ }
142+ }
143+
144+ private void on_background_change () {
145+ if (!settings.auto_adjust_alpha)
146+ return;
147+
148+ calculate_alpha.begin ((obj, res) => {
149+ var alpha = calculate_alpha.end (res);
150+ update_background_alpha (alpha);
151+ });
152+ }
153+
154+ private async double calculate_alpha () {
155+ double alpha = 0;
156+ Gdk.Rectangle monitor_geometry;
157+ ColorInformation? color_info = null;
158+
159+ var primary = screen.get_primary_monitor ();
160+ screen.get_monitor_geometry (primary, out monitor_geometry);
161+
162+ try {
163+ color_info = yield gala_dbus.get_background_color_information (
164+ primary, // monitor index
165+ 0, // x of reference rect
166+ 0, // y of rect
167+ monitor_geometry.width, // width of rect
168+ HEIGHT); // height of rect
169+ } catch (Error e) {
170+ warning (e.message);
171+ alpha = MIN_ALPHA;
172+ }
173+
174+ if (color_info != null
175+ && (color_info.mean > MIN_LUM
176+ || color_info.variance > MIN_VARIANCE))
177+ alpha = MIN_ALPHA;
178+
179+ return alpha;
180+ }
181+ }
182+}
183
184=== modified file 'src/Services/Settings.vala'
185--- src/Services/Settings.vala 2013-04-14 07:54:25 +0000
186+++ src/Services/Settings.vala 2014-03-17 21:44:46 +0000
187@@ -23,6 +23,8 @@
188 public string[] blacklist { get; set; }
189 public bool show_launcher { get; set; }
190 public string default_launcher { get; set; }
191+ public double background_alpha { get; set; }
192+ public bool auto_adjust_alpha { get; set; }
193
194 public Settings () {
195 base ("org.pantheon.desktop.wingpanel");
196
197=== modified file 'src/Widgets/BasePanel.vala'
198--- src/Widgets/BasePanel.vala 2013-08-07 10:18:24 +0000
199+++ src/Widgets/BasePanel.vala 2014-03-17 21:44:46 +0000
200@@ -1,17 +1,17 @@
201 // -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
202-//
203-// Copyright (C) 2011-2013 Wingpanel Developers
204-//
205+//
206+// Copyright (C) 2011-2014 Wingpanel Developers
207+//
208 // This program is free software: you can redistribute it and/or modify
209 // it under the terms of the GNU General Public License as published by
210 // the Free Software Foundation, either version 3 of the License, or
211 // (at your option) any later version.
212-//
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+//
220 // You should have received a copy of the GNU General Public License
221 // along with this program. If not, see <http://www.gnu.org/licenses/>.
222
223@@ -32,6 +32,8 @@
224 N_VALUES
225 }
226
227+ protected Services.Settings settings { get; private set; }
228+
229 private const int SHADOW_SIZE = 4;
230
231 private int panel_height = 0;
232@@ -41,9 +43,19 @@
233 private int panel_displacement = -40;
234 private uint animation_timer = 0;
235
236+ private double legible_alpha_value = -1.0;
237+ private double panel_alpha = 0.0;
238+ private double panel_current_alpha = 0.0;
239+ private uint panel_alpha_timer = 0;
240+ const int FPS = 60;
241+ const double ALPHA_ANIMATION_STEP = 0.05;
242+
243 private PanelShadow shadow = new PanelShadow ();
244-
245- public BasePanel () {
246+ private Wnck.Screen wnck_screen;
247+
248+ public BasePanel (Services.Settings settings) {
249+ this.settings = settings;
250+
251 decorated = false;
252 resizable = false;
253 skip_taskbar_hint = true;
254@@ -58,6 +70,28 @@
255 screen.monitors_changed.connect (on_monitors_changed);
256
257 destroy.connect (Gtk.main_quit);
258+
259+ wnck_screen = Wnck.Screen.get_default ();
260+ wnck_screen.active_workspace_changed.connect (update_panel_alpha);
261+ wnck_screen.window_opened.connect ((window) => {
262+ if (window.get_window_type () == Wnck.WindowType.NORMAL)
263+ window.state_changed.connect (window_state_changed);
264+ });
265+ wnck_screen.window_closed.connect ((window) => {
266+ if (window.get_window_type () == Wnck.WindowType.NORMAL)
267+ window.state_changed.disconnect (window_state_changed);
268+ });
269+
270+ update_panel_alpha ();
271+ }
272+
273+ private void window_state_changed (Wnck.Window window,
274+ Wnck.WindowState changed_mask, Wnck.WindowState new_state) {
275+ if ((changed_mask & Wnck.WindowState.MAXIMIZED_HORIZONTALLY) != 0
276+ || (changed_mask & Wnck.WindowState.MAXIMIZED_VERTICALLY) != 0
277+ && (window.get_workspace () == wnck_screen.get_active_workspace ()
278+ || window.is_sticky ()))
279+ update_panel_alpha ();
280 }
281
282 protected abstract Gtk.StyleContext get_draw_style_context ();
283@@ -79,7 +113,11 @@
284 }
285
286 var ctx = get_draw_style_context ();
287- ctx.render_background (cr, size.x, size.y, size.width, size.height);
288+ var background_color = ctx.get_background_color (Gtk.StateFlags.NORMAL);
289+ background_color.alpha = panel_current_alpha;
290+ Gdk.cairo_set_source_rgba (cr, background_color);
291+ cr.rectangle (size.x, size.y, size.width, size.height);
292+ cr.fill ();
293
294 // Slide in
295 if (animation_timer == 0) {
296@@ -92,21 +130,75 @@
297 if (child != null)
298 propagate_draw (child, cr);
299
300- if (!shadow.visible)
301+ if (panel_alpha > 1E-3) {
302+ shadow.show ();
303 shadow.show_all ();
304+ } else
305+ shadow.hide ();
306
307 return true;
308 }
309
310+ public void update_opacity (double alpha) {
311+ legible_alpha_value = alpha;
312+ update_panel_alpha ();
313+ }
314+
315+ private void update_panel_alpha () {
316+ panel_alpha = settings.background_alpha;
317+ if (settings.auto_adjust_alpha) {
318+ if (active_workspace_has_maximized_window ())
319+ panel_alpha = 1.0;
320+ else if (legible_alpha_value >= 0)
321+ panel_alpha = legible_alpha_value;
322+ }
323+
324+ if (panel_current_alpha != panel_alpha)
325+ panel_alpha_timer = Gdk.threads_add_timeout (1000 / FPS, draw_timeout);
326+ }
327+
328+ private bool draw_timeout () {
329+ queue_draw ();
330+
331+ if (panel_current_alpha > panel_alpha) {
332+ panel_current_alpha -= ALPHA_ANIMATION_STEP;
333+ panel_current_alpha = double.max (panel_current_alpha, panel_alpha);
334+ } else if (panel_current_alpha < panel_alpha) {
335+ panel_current_alpha += ALPHA_ANIMATION_STEP;
336+ panel_current_alpha = double.min (panel_current_alpha, panel_alpha);
337+ }
338+
339+ if (panel_current_alpha != panel_alpha)
340+ return true;
341+
342+ if (panel_alpha_timer > 0) {
343+ Source.remove (panel_alpha_timer);
344+ panel_alpha_timer = 0;
345+ }
346+
347+ return false;
348+ }
349+
350 private bool animation_callback () {
351- if (panel_displacement >= 0 ) {
352+ if (panel_displacement >= 0 )
353 return false;
354- } else {
355- panel_displacement += 1;
356- move (panel_x, panel_y + panel_displacement);
357- shadow.move (panel_x, panel_y + panel_height + panel_displacement);
358- return true;
359+
360+ panel_displacement += 1;
361+ move (panel_x, panel_y + panel_displacement);
362+ shadow.move (panel_x, panel_y + panel_height + panel_displacement);
363+ return true;
364+ }
365+
366+ private bool active_workspace_has_maximized_window () {
367+ var workspace = wnck_screen.get_active_workspace ();
368+
369+ foreach (var window in wnck_screen.get_windows ()) {
370+ if ((window.is_pinned () || window.get_workspace () == workspace)
371+ && window.is_maximized ())
372+ return true;
373 }
374+
375+ return false;
376 }
377
378 private void on_monitors_changed () {
379@@ -144,9 +236,9 @@
380 screen.get_monitor_geometry (screen.get_primary_monitor (), out monitor_dimensions);
381
382 // if we have multiple monitors, we must check if the panel would be placed inbetween
383- // monitors. If that's the case we have to move it to the topmost, or we'll make the
384+ // monitors. If that's the case we have to move it to the topmost, or we'll make the
385 // upper monitor unusable because of the struts.
386- // First check if there are monitors overlapping horizontally and if they are higher
387+ // First check if there are monitors overlapping horizontally and if they are higher
388 // our current highest, make this one the new highest and test all again
389 if (screen.get_n_monitors () > 1) {
390 Gdk.Rectangle dimensions;
391@@ -156,8 +248,8 @@
392 && dimensions.x < monitor_dimensions.x + monitor_dimensions.width)
393 || (dimensions.x + dimensions.width > monitor_dimensions.x
394 && dimensions.x + dimensions.width <= monitor_dimensions.x + monitor_dimensions.width)
395- || (dimensions.x < monitor_dimensions.x
396- && dimensions.x + dimensions.width > monitor_dimensions.x + monitor_dimensions.width))
397+ || (dimensions.x < monitor_dimensions.x
398+ && dimensions.x + dimensions.width > monitor_dimensions.x + monitor_dimensions.width))
399 && dimensions.y < monitor_dimensions.y) {
400 warning ("Not placing wingpanel on the primary monitor because of problems" +
401 " with multimonitor setups");
402
403=== modified file 'src/Widgets/Panel.vala'
404--- src/Widgets/Panel.vala 2013-09-13 08:51:05 +0000
405+++ src/Widgets/Panel.vala 2014-03-17 21:44:46 +0000
406@@ -2,7 +2,7 @@
407 /***
408 BEGIN LICENSE
409
410- Copyright (C) 2011-2012 Wingpanel Developers
411+ Copyright (C) 2011-2014 Wingpanel Developers
412 This program is free software: you can redistribute it and/or modify it
413 under the terms of the GNU Lesser General Public License version 3, as published
414 by the Free Software Foundation.
415@@ -32,10 +32,11 @@
416 private IndicatorLoader indicator_loader;
417
418 public Panel (Gtk.Application app, Services.Settings settings, IndicatorLoader indicator_loader) {
419+ base (settings);
420+
421+ this.indicator_loader = indicator_loader;
422 set_application (app);
423
424- this.indicator_loader = indicator_loader;
425-
426 container = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
427 left_wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
428 right_wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
429@@ -112,6 +113,18 @@
430 var gpr = new Gtk.SizeGroup (Gtk.SizeGroupMode.HORIZONTAL);
431 gpr.add_widget (left_wrapper);
432 gpr.add_widget (right_wrapper);
433+
434+ // make sure those are all transparent when we later adjust the transparency
435+ // in the panel's draw callback
436+ clock.override_background_color (Gtk.StateFlags.NORMAL, Gdk.RGBA () {
437+ red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0
438+ });
439+ menubar.override_background_color (Gtk.StateFlags.NORMAL, Gdk.RGBA () {
440+ red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0
441+ });
442+ apps_menubar.override_background_color (Gtk.StateFlags.NORMAL, Gdk.RGBA () {
443+ red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0
444+ });
445 }
446 }
447 }
448
449=== modified file 'src/WingpanelApp.vala'
450--- src/WingpanelApp.vala 2013-09-13 08:51:05 +0000
451+++ src/WingpanelApp.vala 2014-03-17 21:44:46 +0000
452@@ -18,6 +18,7 @@
453 public class Wingpanel.App : Granite.Application {
454 private IndicatorLoader indicator_loader;
455 private Widgets.BasePanel panel;
456+ private Services.BackgroundManager background_manager;
457
458 construct {
459 build_data_dir = Build.DATADIR;
460@@ -41,6 +42,9 @@
461 panel = new Widgets.Panel (this, settings, indicator_loader);
462
463 panel.show_all ();
464+
465+ background_manager = new Services.BackgroundManager (settings, panel.get_screen ());
466+ background_manager.update_background_alpha.connect (panel.update_opacity);
467 }
468
469 protected override void activate () {

Subscribers

People subscribed via source and target branches