=== modified file 'org.pantheon.desktop.wingpanel.gschema.xml'
--- org.pantheon.desktop.wingpanel.gschema.xml 2014-07-24 16:03:50 +0000
+++ org.pantheon.desktop.wingpanel.gschema.xml 2015-06-17 22:29:30 +0000
@@ -25,5 +25,20 @@
Automatically update background alpha.
Automatically update the background alpha to zero if it will be readable, else 0.8.
+
+ false
+ Whether to hide the panel when there is an active maximized window.
+ Whether to hide the panel when there is an active maximized window.
+
+
+ 500
+ The number of milliseconds after mouse enter to show the panel.
+ 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.
+
+
+ 500
+ The number of milliseconds after mouse leave to hide the panel.
+ 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.
+
=== modified file 'src/Services/Settings.vala'
--- src/Services/Settings.vala 2014-07-24 16:03:50 +0000
+++ src/Services/Settings.vala 2015-06-17 22:29:30 +0000
@@ -25,6 +25,9 @@
public string default_launcher { get; set; }
public double background_alpha { get; set; }
public bool auto_adjust_alpha { get; set; }
+ public bool dodge_maximized {get; set; }
+ public int hover_show_delay {get; set; }
+ public int hover_hide_delay {get; set; }
public Settings () {
base ("org.pantheon.desktop.wingpanel");
=== modified file 'src/Widgets/BasePanel.vala'
--- src/Widgets/BasePanel.vala 2015-01-15 10:45:40 +0000
+++ src/Widgets/BasePanel.vala 2015-06-17 22:29:30 +0000
@@ -43,7 +43,6 @@
private int panel_width;
private int panel_displacement = -40;
private int monitor_num;
- private uint animation_timer = 0;
private double legible_alpha_value = -1.0;
private double panel_alpha = 0.0;
@@ -52,6 +51,11 @@
private int fade_duration;
private int64 start_time;
+ private bool hiding = false;
+ private bool showing = false;
+ private bool first_run = true;
+ private bool struts_set = false;
+
private Settings? gala_settings = null;
private enum Duration {
DEFAULT,
@@ -113,6 +117,11 @@
gala_settings.changed.connect (get_duration_values);
}
+ wnck_screen.active_window_changed.connect (active_window_changed);
+ add_events(Gdk.EventMask.ENTER_NOTIFY_MASK | Gdk.EventMask.LEAVE_NOTIFY_MASK);
+ enter_notify_event.connect(mouse_entered);
+ leave_notify_event.connect(mouse_left);
+
get_duration_values ();
update_panel_alpha (Duration.DEFAULT);
@@ -166,6 +175,144 @@
}
}
+ private void active_window_changed (Wnck.Window? prev_active_window) {
+ unowned Wnck.Window? active_window = wnck_screen.get_active_window();
+ if (settings.dodge_maximized)
+ update_visibility_active_change (active_window);
+
+ if (prev_active_window != null)
+ prev_active_window.state_changed.disconnect (active_window_state_changed);
+ if (active_window != null)
+ active_window.state_changed.connect (active_window_state_changed);
+ }
+
+ private void active_window_state_changed (Wnck.Window? window,
+ Wnck.WindowState changed_mask, Wnck.WindowState new_state) {
+ if (settings.dodge_maximized)
+ update_visibility_active_change (window);
+ }
+
+ private void update_visibility_active_change (Wnck.Window? active_window) {
+ if (should_hide_active_change (active_window)) {
+ disable_struts ();
+ start_hide ();
+ } else {
+ set_struts ();
+ start_show ();
+ }
+ }
+
+ private bool should_hide_active_change (Wnck.Window? active_window) {
+ unowned Wnck.Workspace active_workspace = wnck_screen.get_active_workspace ();
+
+ return ((active_window != null) && !active_window.is_minimized () && right_type (active_window)
+ && active_window.is_visible_on_workspace (active_workspace)
+ && (active_window.get_window_type () == Wnck.WindowType.DIALOG) ?
+ would_intersect_shown_panel (active_window) :
+ (in_panel_x_range (active_window) && is_maximized_at_all (active_window)));
+ }
+
+ private bool would_intersect_shown_panel (Wnck.Window? window) {
+ Gdk.Rectangle shown_panel_rect = Gdk.Rectangle ();
+ shown_panel_rect.x = panel_x;
+ shown_panel_rect.y = panel_y;
+ shown_panel_rect.width = panel_width;
+ shown_panel_rect.height = panel_height;
+
+ int xp, yp, widthp, heightp;
+ window.get_geometry (out xp, out yp, out widthp, out heightp);
+
+ Gdk.Rectangle window_rect = Gdk.Rectangle ();
+ window_rect.x = xp;
+ window_rect.width = widthp;
+ if (struts_set && is_maximized_at_all (window)) {
+ window_rect.y = yp - panel_height;
+ window_rect.height = heightp + panel_height;
+ } else {
+ window_rect.y = yp;
+ window_rect.height = heightp;
+ }
+
+ return window_rect.intersect (shown_panel_rect, null);
+ }
+
+ private bool in_panel_x_range (Wnck.Window? window) {
+ int xp, yp, widthp, heightp;
+ window.get_geometry (out xp, out yp, out widthp, out heightp);
+ if (xp > panel_x)
+ return (panel_x + panel_width > xp);
+ else if (xp < panel_x)
+ return (xp + widthp > panel_x);
+ else
+ return (xp + widthp > 0 && panel_x + panel_width > 0);
+ }
+
+ private bool right_type (Wnck.Window? active_window) {
+ unowned Wnck.WindowType type = active_window.get_window_type ();
+ return (type == Wnck.WindowType.NORMAL || type == Wnck.WindowType.DIALOG
+ || type == Wnck.WindowType.TOOLBAR || type == Wnck.WindowType.UTILITY);
+ }
+
+ private bool is_maximized_at_all (Wnck.Window window) {
+ return (window.is_maximized_horizontally ()
+ || window.is_maximized_vertically ());
+ }
+
+ private bool mouse_entered (Gdk.EventCrossing event) {
+ if (settings.dodge_maximized) {
+ // if enter from hidden
+ if (event.y == panel_height-1) {
+ uint interval = settings.hover_show_delay < 0 ? 0 : settings.hover_show_delay;
+ Timeout.add (interval, entered_callback);
+ } else
+ start_show ();
+ }
+ return true;
+ }
+
+ private bool entered_callback () {
+ Gdk.DeviceManager device_manager = get_display ().get_device_manager ();
+ Gdk.Device device = device_manager.get_client_pointer ();
+ int mouse_x, mouse_y;
+ get_window ().get_device_position (device, out mouse_x, out mouse_y, null);
+
+ if (mouse_y == panel_height-1)
+ start_show ();
+ return false;
+ }
+
+ private bool mouse_left (Gdk.EventCrossing event) {
+ int mouse_x = (int) Math.ceil (event.x);
+ int mouse_y = (int) Math.ceil (event.y);
+
+ if (settings.dodge_maximized)
+ update_visibility_hover (mouse_x, mouse_y);
+ return true;
+ }
+
+ protected void update_visibility_hover (int mouse_x, int mouse_y) {
+ if (!hovered (mouse_x, mouse_y) && should_hide_active_change (wnck_screen.get_active_window ())) {
+ uint interval = settings.hover_hide_delay < 0 ? 0 : settings.hover_hide_delay;
+ Timeout.add (interval, left_callback);
+ }
+ }
+
+ private bool left_callback () {
+ Gdk.DeviceManager device_manager = get_display ().get_device_manager ();
+ Gdk.Device device = device_manager.get_client_pointer ();
+ int mouse_x, mouse_y;
+ get_window ().get_device_position (device, out mouse_x, out mouse_y, null);
+
+ if (!hovered (mouse_x, mouse_y) && should_hide_active_change (wnck_screen.get_active_window ()))
+ start_hide ();
+ return false;
+ }
+
+ private bool hovered (int mouse_x, int mouse_y) {
+ return (mouse_x >= 0 && mouse_x < panel_width
+ && mouse_y < panel_height && mouse_y >= 0);
+ }
+
private void window_geometry_changed_open (Wnck.Window window) {
if (window_fills_workarea (window)) {
update_panel_alpha (Duration.OPEN);
@@ -210,8 +357,9 @@
int window_x, window_y, window_width, window_height;
window.get_geometry (out window_x, out window_y, out window_width, out window_height);
+ // window y might be less (further up) than workarea y right after set_struts
if (window.is_maximized_vertically () && !window.is_minimized ()
- && window_y == monitor_workarea_y
+ && window_y <= monitor_workarea_y
&& (window_x == monitor_workarea_x
|| window_x == monitor_workarea.x + monitor_workarea_width / 2)
&& (window_width == monitor_workarea_width
@@ -247,9 +395,10 @@
cr.fill ();
// Slide in
- if (animation_timer == 0) {
+ if (first_run) {
+ first_run = false;
panel_displacement = -panel_height;
- animation_timer = Timeout.add (300 / panel_height, animation_callback);
+ start_show ();
}
var child = get_child ();
@@ -319,17 +468,41 @@
return false;
}
-
- private bool animation_callback () {
- if (panel_displacement >= 0 )
+
+ private void start_show () {
+ showing = true;
+ hiding = false;
+ Timeout.add (300 / panel_height, show_animation);
+ }
+
+ private void start_hide () {
+ hiding = true;
+ showing = false;
+ Timeout.add (300 / panel_height, hide_animation);
+ }
+
+ private bool show_animation () {
+ if (!showing || (panel_displacement >= 0)) {
+ showing = false;
return false;
-
+ }
panel_displacement += 1;
move (panel_x, panel_y + panel_displacement);
shadow.move (panel_x, panel_y + panel_height + panel_displacement);
return true;
}
+ private bool hide_animation () {
+ if (!hiding || panel_displacement <= -panel_height+1) {
+ hiding = false;
+ return false;
+ }
+ panel_displacement -= 1;
+ move (panel_x, panel_y + panel_displacement);
+ shadow.move (panel_x, panel_y + panel_height + panel_displacement);
+ return true;
+ }
+
private bool active_workspace_has_maximized_window () {
int scale_factor = this.get_scale_factor ();
var workspace = wnck_screen.get_active_workspace ();
@@ -400,6 +573,33 @@
32, X.PropMode.Replace, (uchar[]) struts, struts.length);
display.change_property (xid, display.intern_atom ("_NET_WM_STRUT", false), X.XA_CARDINAL,
32, X.PropMode.Replace, (uchar[]) first_struts, first_struts.length);
+ struts_set = true;
+ }
+
+ private void disable_struts () {
+ if (!get_realized ())
+ return;
+
+ // Since uchar is 8 bits in vala but the struts are 32 bits
+ // we have to allocate 4 times as much and do bit-masking
+ var struts = new ulong[Struts.N_VALUES];
+
+ struts[Struts.TOP] = 0;
+ struts[Struts.TOP_START] = 0;
+ struts[Struts.TOP_END] = 0;
+
+ var first_struts = new ulong[Struts.BOTTOM + 1];
+ for (var i = 0; i < first_struts.length; i++)
+ first_struts[i] = struts[i];
+
+ unowned X.Display display = Gdk.X11Display.get_xdisplay (get_display ());
+ var xid = Gdk.X11Window.get_xid (get_window ());
+
+ display.change_property (xid, display.intern_atom ("_NET_WM_STRUT_PARTIAL", false), X.XA_CARDINAL,
+ 32, X.PropMode.Replace, (uchar[]) struts, struts.length);
+ display.change_property (xid, display.intern_atom ("_NET_WM_STRUT", false), X.XA_CARDINAL,
+ 32, X.PropMode.Replace, (uchar[]) first_struts, first_struts.length);
+ struts_set = false;
}
private void panel_resize (bool redraw) {
=== modified file 'src/Widgets/Panel.vala'
--- src/Widgets/Panel.vala 2015-03-06 05:47:18 +0000
+++ src/Widgets/Panel.vala 2015-06-17 22:29:30 +0000
@@ -26,6 +26,7 @@
private MenuBar left_menubar;
private MenuBar center_menubar;
private Gtk.Box container;
+ private AppsButton apps_button;
public Panel (Gtk.Application app, Services.Settings settings, IndicatorLoader indicator_loader) {
base (settings);
@@ -42,6 +43,9 @@
style_context.add_class (StyleClass.PANEL);
style_context.add_class (Gtk.STYLE_CLASS_MENUBAR);
+ apps_button = new AppsButton (settings);
+ apps_button.state_flags_changed.connect (apps_button_state_changed);
+
// Add default widgets
add_defaults (settings);
@@ -87,6 +91,17 @@
critical ("Indicator entry '%s' has no parent. Not removing from panel.", entry.get_entry_name ());
}
+ private void apps_button_state_changed () {
+ Gdk.DeviceManager device_manager = this.get_display ().get_device_manager ();
+ Gdk.Device device = device_manager.get_client_pointer ();
+ int mouse_x, mouse_y;
+ this.get_window ().get_device_position (device, out mouse_x, out mouse_y, null);
+
+ if (!apps_button.active && settings.dodge_maximized) {
+ update_visibility_hover (mouse_x, mouse_y);
+ }
+ }
+
private void add_defaults (Services.Settings settings) {
left_menubar = new MenuBar ();
center_menubar = new MenuBar ();
@@ -94,7 +109,7 @@
right_menubar.halign = Gtk.Align.END;
- left_menubar.append (new Widgets.AppsButton (settings));
+ left_menubar.append (apps_button);
container.pack_start (left_menubar);
container.pack_end (right_menubar);