Merge lp:~kbailey4444/wingpanel/dodge-maximize into lp:~elementary-pantheon/wingpanel/trunk-0.3.x

Proposed by Keith Bailey on 2015-06-17
Status: Rejected
Rejected by: xapantu on 2015-09-07
Proposed branch: lp:~kbailey4444/wingpanel/dodge-maximize
Merge into: lp:~elementary-pantheon/wingpanel/trunk-0.3.x
Diff against target: 372 lines (+242/-9)
4 files modified
org.pantheon.desktop.wingpanel.gschema.xml (+15/-0)
src/Services/Settings.vala (+3/-0)
src/Widgets/BasePanel.vala (+208/-8)
src/Widgets/Panel.vala (+16/-1)
To merge this branch: bzr merge lp:~kbailey4444/wingpanel/dodge-maximize
Reviewer Review Type Date Requested Status
elementary Pantheon team 2015-06-17 Pending
Review via email: mp+262278@code.launchpad.net

Description of the change

Closes Bug #1079575 . Gives wingpanel the option to behave like plank's "Hide when focused window is maximized" mode. The panel will hide if the active window is maximized. The panel will show when the mouse hovers over the top of the screen. Here is a video of it in action. https://www.youtube.com/watch?v=Y08u_bcJL-U

To post a comment you must log in.
Keith Bailey (kbailey4444) wrote :

When might this be reviewed? I understand you've probably been busy with other code.

xapantu (xapantu) wrote :

Hi,

Unfortunately most development happens in this branch https://code.launchpad.net/~wingpanel-devs/wingpanel/wingpanel-rewrite-x11 (which is a rewrite of the existing wingpanel featuring new-from-scratch indicators)

So, while your code actually looks good, we are not going to merge it because it targets a branch which is not developped anymore. We don't want to do it because it would require too many efforts and will probably never be released.

Please check out the daily ppa (unstable, of course, be warned) if you want to implement it there ;)

Keith Bailey (kbailey4444) wrote :

Ok, thanks. I'll look into implementing it there.

On Mon, Sep 7, 2015 at 1:57 PM, xapantu <email address hidden> wrote:

> The proposal to merge lp:~kbailey4444/wingpanel/dodge-maximize into
> lp:wingpanel has been updated.
>
> Status: Needs review => Rejected
>
> For more details, see:
>
> https://code.launchpad.net/~kbailey4444/wingpanel/dodge-maximize/+merge/262278
> --
> You are the owner of lp:~kbailey4444/wingpanel/dodge-maximize.
>

Unmerged revisions

224. By Keith Bailey on 2015-06-17

fixed hover delays not updating.

223. By Keith Bailey on 2015-06-17

Now shows on hover like plank. Has show and hide delay settings for when the mouse enters or leaves.

222. By Keith Bailey on 2015-05-30

The panel now hides when the active window is maximized. Does not show when hovered like plank does.

221. By Keith Bailey on 2015-05-21

Added dodge maximize to settings and gschema

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'org.pantheon.desktop.wingpanel.gschema.xml'
2--- org.pantheon.desktop.wingpanel.gschema.xml 2014-07-24 16:03:50 +0000
3+++ org.pantheon.desktop.wingpanel.gschema.xml 2015-06-17 22:29:30 +0000
4@@ -25,5 +25,20 @@
5 <summary>Automatically update background alpha.</summary>
6 <description>Automatically update the background alpha to zero if it will be readable, else 0.8.</description>
7 </key>
8+ <key type="b" name="dodge-maximized">
9+ <default>false</default>
10+ <summary>Whether to hide the panel when there is an active maximized window.</summary>
11+ <description>Whether to hide the panel when there is an active maximized window.</description>
12+ </key>
13+ <key type="i" name="hover-show-delay">
14+ <default>500</default>
15+ <summary>The number of milliseconds after mouse enter to show the panel.</summary>
16+ <description>The number of milliseconds after mouse enter to show the panel. Only relevant if dodge-maximized is enabled. If the mouse is not inside the panel after the delay, the panel will not be shown.</description>
17+ </key>
18+ <key type="i" name="hover-hide-delay">
19+ <default>500</default>
20+ <summary>The number of milliseconds after mouse leave to hide the panel.</summary>
21+ <description>The number of milliseconds after mouse leave to hide the panel. Only relevant if dodge-maximized is enabled. If the mouse is not outside the panel after the delay, the panel will not be hidden.</description>
22+ </key>
23 </schema>
24 </schemalist>
25
26=== modified file 'src/Services/Settings.vala'
27--- src/Services/Settings.vala 2014-07-24 16:03:50 +0000
28+++ src/Services/Settings.vala 2015-06-17 22:29:30 +0000
29@@ -25,6 +25,9 @@
30 public string default_launcher { get; set; }
31 public double background_alpha { get; set; }
32 public bool auto_adjust_alpha { get; set; }
33+ public bool dodge_maximized {get; set; }
34+ public int hover_show_delay {get; set; }
35+ public int hover_hide_delay {get; set; }
36
37 public Settings () {
38 base ("org.pantheon.desktop.wingpanel");
39
40=== modified file 'src/Widgets/BasePanel.vala'
41--- src/Widgets/BasePanel.vala 2015-01-15 10:45:40 +0000
42+++ src/Widgets/BasePanel.vala 2015-06-17 22:29:30 +0000
43@@ -43,7 +43,6 @@
44 private int panel_width;
45 private int panel_displacement = -40;
46 private int monitor_num;
47- private uint animation_timer = 0;
48
49 private double legible_alpha_value = -1.0;
50 private double panel_alpha = 0.0;
51@@ -52,6 +51,11 @@
52 private int fade_duration;
53 private int64 start_time;
54
55+ private bool hiding = false;
56+ private bool showing = false;
57+ private bool first_run = true;
58+ private bool struts_set = false;
59+
60 private Settings? gala_settings = null;
61 private enum Duration {
62 DEFAULT,
63@@ -113,6 +117,11 @@
64 gala_settings.changed.connect (get_duration_values);
65 }
66
67+ wnck_screen.active_window_changed.connect (active_window_changed);
68+ add_events(Gdk.EventMask.ENTER_NOTIFY_MASK | Gdk.EventMask.LEAVE_NOTIFY_MASK);
69+ enter_notify_event.connect(mouse_entered);
70+ leave_notify_event.connect(mouse_left);
71+
72 get_duration_values ();
73
74 update_panel_alpha (Duration.DEFAULT);
75@@ -166,6 +175,144 @@
76 }
77 }
78
79+ private void active_window_changed (Wnck.Window? prev_active_window) {
80+ unowned Wnck.Window? active_window = wnck_screen.get_active_window();
81+ if (settings.dodge_maximized)
82+ update_visibility_active_change (active_window);
83+
84+ if (prev_active_window != null)
85+ prev_active_window.state_changed.disconnect (active_window_state_changed);
86+ if (active_window != null)
87+ active_window.state_changed.connect (active_window_state_changed);
88+ }
89+
90+ private void active_window_state_changed (Wnck.Window? window,
91+ Wnck.WindowState changed_mask, Wnck.WindowState new_state) {
92+ if (settings.dodge_maximized)
93+ update_visibility_active_change (window);
94+ }
95+
96+ private void update_visibility_active_change (Wnck.Window? active_window) {
97+ if (should_hide_active_change (active_window)) {
98+ disable_struts ();
99+ start_hide ();
100+ } else {
101+ set_struts ();
102+ start_show ();
103+ }
104+ }
105+
106+ private bool should_hide_active_change (Wnck.Window? active_window) {
107+ unowned Wnck.Workspace active_workspace = wnck_screen.get_active_workspace ();
108+
109+ return ((active_window != null) && !active_window.is_minimized () && right_type (active_window)
110+ && active_window.is_visible_on_workspace (active_workspace)
111+ && (active_window.get_window_type () == Wnck.WindowType.DIALOG) ?
112+ would_intersect_shown_panel (active_window) :
113+ (in_panel_x_range (active_window) && is_maximized_at_all (active_window)));
114+ }
115+
116+ private bool would_intersect_shown_panel (Wnck.Window? window) {
117+ Gdk.Rectangle shown_panel_rect = Gdk.Rectangle ();
118+ shown_panel_rect.x = panel_x;
119+ shown_panel_rect.y = panel_y;
120+ shown_panel_rect.width = panel_width;
121+ shown_panel_rect.height = panel_height;
122+
123+ int xp, yp, widthp, heightp;
124+ window.get_geometry (out xp, out yp, out widthp, out heightp);
125+
126+ Gdk.Rectangle window_rect = Gdk.Rectangle ();
127+ window_rect.x = xp;
128+ window_rect.width = widthp;
129+ if (struts_set && is_maximized_at_all (window)) {
130+ window_rect.y = yp - panel_height;
131+ window_rect.height = heightp + panel_height;
132+ } else {
133+ window_rect.y = yp;
134+ window_rect.height = heightp;
135+ }
136+
137+ return window_rect.intersect (shown_panel_rect, null);
138+ }
139+
140+ private bool in_panel_x_range (Wnck.Window? window) {
141+ int xp, yp, widthp, heightp;
142+ window.get_geometry (out xp, out yp, out widthp, out heightp);
143+ if (xp > panel_x)
144+ return (panel_x + panel_width > xp);
145+ else if (xp < panel_x)
146+ return (xp + widthp > panel_x);
147+ else
148+ return (xp + widthp > 0 && panel_x + panel_width > 0);
149+ }
150+
151+ private bool right_type (Wnck.Window? active_window) {
152+ unowned Wnck.WindowType type = active_window.get_window_type ();
153+ return (type == Wnck.WindowType.NORMAL || type == Wnck.WindowType.DIALOG
154+ || type == Wnck.WindowType.TOOLBAR || type == Wnck.WindowType.UTILITY);
155+ }
156+
157+ private bool is_maximized_at_all (Wnck.Window window) {
158+ return (window.is_maximized_horizontally ()
159+ || window.is_maximized_vertically ());
160+ }
161+
162+ private bool mouse_entered (Gdk.EventCrossing event) {
163+ if (settings.dodge_maximized) {
164+ // if enter from hidden
165+ if (event.y == panel_height-1) {
166+ uint interval = settings.hover_show_delay < 0 ? 0 : settings.hover_show_delay;
167+ Timeout.add (interval, entered_callback);
168+ } else
169+ start_show ();
170+ }
171+ return true;
172+ }
173+
174+ private bool entered_callback () {
175+ Gdk.DeviceManager device_manager = get_display ().get_device_manager ();
176+ Gdk.Device device = device_manager.get_client_pointer ();
177+ int mouse_x, mouse_y;
178+ get_window ().get_device_position (device, out mouse_x, out mouse_y, null);
179+
180+ if (mouse_y == panel_height-1)
181+ start_show ();
182+ return false;
183+ }
184+
185+ private bool mouse_left (Gdk.EventCrossing event) {
186+ int mouse_x = (int) Math.ceil (event.x);
187+ int mouse_y = (int) Math.ceil (event.y);
188+
189+ if (settings.dodge_maximized)
190+ update_visibility_hover (mouse_x, mouse_y);
191+ return true;
192+ }
193+
194+ protected void update_visibility_hover (int mouse_x, int mouse_y) {
195+ if (!hovered (mouse_x, mouse_y) && should_hide_active_change (wnck_screen.get_active_window ())) {
196+ uint interval = settings.hover_hide_delay < 0 ? 0 : settings.hover_hide_delay;
197+ Timeout.add (interval, left_callback);
198+ }
199+ }
200+
201+ private bool left_callback () {
202+ Gdk.DeviceManager device_manager = get_display ().get_device_manager ();
203+ Gdk.Device device = device_manager.get_client_pointer ();
204+ int mouse_x, mouse_y;
205+ get_window ().get_device_position (device, out mouse_x, out mouse_y, null);
206+
207+ if (!hovered (mouse_x, mouse_y) && should_hide_active_change (wnck_screen.get_active_window ()))
208+ start_hide ();
209+ return false;
210+ }
211+
212+ private bool hovered (int mouse_x, int mouse_y) {
213+ return (mouse_x >= 0 && mouse_x < panel_width
214+ && mouse_y < panel_height && mouse_y >= 0);
215+ }
216+
217 private void window_geometry_changed_open (Wnck.Window window) {
218 if (window_fills_workarea (window)) {
219 update_panel_alpha (Duration.OPEN);
220@@ -210,8 +357,9 @@
221 int window_x, window_y, window_width, window_height;
222 window.get_geometry (out window_x, out window_y, out window_width, out window_height);
223
224+ // window y might be less (further up) than workarea y right after set_struts
225 if (window.is_maximized_vertically () && !window.is_minimized ()
226- && window_y == monitor_workarea_y
227+ && window_y <= monitor_workarea_y
228 && (window_x == monitor_workarea_x
229 || window_x == monitor_workarea.x + monitor_workarea_width / 2)
230 && (window_width == monitor_workarea_width
231@@ -247,9 +395,10 @@
232 cr.fill ();
233
234 // Slide in
235- if (animation_timer == 0) {
236+ if (first_run) {
237+ first_run = false;
238 panel_displacement = -panel_height;
239- animation_timer = Timeout.add (300 / panel_height, animation_callback);
240+ start_show ();
241 }
242
243 var child = get_child ();
244@@ -319,17 +468,41 @@
245
246 return false;
247 }
248-
249- private bool animation_callback () {
250- if (panel_displacement >= 0 )
251+
252+ private void start_show () {
253+ showing = true;
254+ hiding = false;
255+ Timeout.add (300 / panel_height, show_animation);
256+ }
257+
258+ private void start_hide () {
259+ hiding = true;
260+ showing = false;
261+ Timeout.add (300 / panel_height, hide_animation);
262+ }
263+
264+ private bool show_animation () {
265+ if (!showing || (panel_displacement >= 0)) {
266+ showing = false;
267 return false;
268-
269+ }
270 panel_displacement += 1;
271 move (panel_x, panel_y + panel_displacement);
272 shadow.move (panel_x, panel_y + panel_height + panel_displacement);
273 return true;
274 }
275
276+ private bool hide_animation () {
277+ if (!hiding || panel_displacement <= -panel_height+1) {
278+ hiding = false;
279+ return false;
280+ }
281+ panel_displacement -= 1;
282+ move (panel_x, panel_y + panel_displacement);
283+ shadow.move (panel_x, panel_y + panel_height + panel_displacement);
284+ return true;
285+ }
286+
287 private bool active_workspace_has_maximized_window () {
288 int scale_factor = this.get_scale_factor ();
289 var workspace = wnck_screen.get_active_workspace ();
290@@ -400,6 +573,33 @@
291 32, X.PropMode.Replace, (uchar[]) struts, struts.length);
292 display.change_property (xid, display.intern_atom ("_NET_WM_STRUT", false), X.XA_CARDINAL,
293 32, X.PropMode.Replace, (uchar[]) first_struts, first_struts.length);
294+ struts_set = true;
295+ }
296+
297+ private void disable_struts () {
298+ if (!get_realized ())
299+ return;
300+
301+ // Since uchar is 8 bits in vala but the struts are 32 bits
302+ // we have to allocate 4 times as much and do bit-masking
303+ var struts = new ulong[Struts.N_VALUES];
304+
305+ struts[Struts.TOP] = 0;
306+ struts[Struts.TOP_START] = 0;
307+ struts[Struts.TOP_END] = 0;
308+
309+ var first_struts = new ulong[Struts.BOTTOM + 1];
310+ for (var i = 0; i < first_struts.length; i++)
311+ first_struts[i] = struts[i];
312+
313+ unowned X.Display display = Gdk.X11Display.get_xdisplay (get_display ());
314+ var xid = Gdk.X11Window.get_xid (get_window ());
315+
316+ display.change_property (xid, display.intern_atom ("_NET_WM_STRUT_PARTIAL", false), X.XA_CARDINAL,
317+ 32, X.PropMode.Replace, (uchar[]) struts, struts.length);
318+ display.change_property (xid, display.intern_atom ("_NET_WM_STRUT", false), X.XA_CARDINAL,
319+ 32, X.PropMode.Replace, (uchar[]) first_struts, first_struts.length);
320+ struts_set = false;
321 }
322
323 private void panel_resize (bool redraw) {
324
325=== modified file 'src/Widgets/Panel.vala'
326--- src/Widgets/Panel.vala 2015-03-06 05:47:18 +0000
327+++ src/Widgets/Panel.vala 2015-06-17 22:29:30 +0000
328@@ -26,6 +26,7 @@
329 private MenuBar left_menubar;
330 private MenuBar center_menubar;
331 private Gtk.Box container;
332+ private AppsButton apps_button;
333
334 public Panel (Gtk.Application app, Services.Settings settings, IndicatorLoader indicator_loader) {
335 base (settings);
336@@ -42,6 +43,9 @@
337 style_context.add_class (StyleClass.PANEL);
338 style_context.add_class (Gtk.STYLE_CLASS_MENUBAR);
339
340+ apps_button = new AppsButton (settings);
341+ apps_button.state_flags_changed.connect (apps_button_state_changed);
342+
343 // Add default widgets
344 add_defaults (settings);
345
346@@ -87,6 +91,17 @@
347 critical ("Indicator entry '%s' has no parent. Not removing from panel.", entry.get_entry_name ());
348 }
349
350+ private void apps_button_state_changed () {
351+ Gdk.DeviceManager device_manager = this.get_display ().get_device_manager ();
352+ Gdk.Device device = device_manager.get_client_pointer ();
353+ int mouse_x, mouse_y;
354+ this.get_window ().get_device_position (device, out mouse_x, out mouse_y, null);
355+
356+ if (!apps_button.active && settings.dodge_maximized) {
357+ update_visibility_hover (mouse_x, mouse_y);
358+ }
359+ }
360+
361 private void add_defaults (Services.Settings settings) {
362 left_menubar = new MenuBar ();
363 center_menubar = new MenuBar ();
364@@ -94,7 +109,7 @@
365
366 right_menubar.halign = Gtk.Align.END;
367
368- left_menubar.append (new Widgets.AppsButton (settings));
369+ left_menubar.append (apps_button);
370
371 container.pack_start (left_menubar);
372 container.pack_end (right_menubar);

Subscribers

People subscribed via source and target branches