diff --git a/meson.build b/meson.build
index c69b81a..7519893 100644
--- a/meson.build
+++ b/meson.build
@@ -14,7 +14,8 @@ add_project_arguments([
add_project_arguments([
'-DGETTEXT_PACKAGE="wingpanel"',
- '-DG_LOG_DOMAIN="wingpanel"'
+ '-DG_LOG_DOMAIN="wingpanel"',
+ '-DWNCK_I_KNOW_THIS_IS_UNSTABLE'
],
language: 'c'
)
@@ -30,6 +31,7 @@ gio_dep = dependency('gio-2.0')
gio_unix_dep = dependency('gio-unix-2.0')
gmodule_dep = dependency('gmodule-2.0')
gtk_dep = dependency('gtk+-3.0', version: '>=3.10')
+libwnck_dep = dependency('libwnck-3.0', version: '>=3.14')
gee_dep = dependency('gee-0.8')
granite_dep = dependency('granite')
diff --git a/schemas/io.elementary.desktop.wingpanel.gschema.xml b/schemas/io.elementary.desktop.wingpanel.gschema.xml
index a309a1d..aa150f7 100644
--- a/schemas/io.elementary.desktop.wingpanel.gschema.xml
+++ b/schemas/io.elementary.desktop.wingpanel.gschema.xml
@@ -6,5 +6,23 @@
Sets if the panel uses transparency.
Disable this to provide higher contrasts and make indicators better readable.
+
+
+
+
+
+
+
+
+ 'Disabled'
+ Sets if and how the panel will autohide.
+ Enable this to increase available desktop area and reduce clutter.
+
+
+
+ 200
+ Sets how long before the panel will autohide in milliseconds.
+ Increase or decrease this value to your preference.
+
diff --git a/src/PanelWindow.vala b/src/PanelWindow.vala
index c334fd0..0b56f3b 100644
--- a/src/PanelWindow.vala
+++ b/src/PanelWindow.vala
@@ -29,6 +29,13 @@ public class Wingpanel.PanelWindow : Gtk.Window {
private int panel_height;
private bool expanded = false;
private int panel_displacement;
+ private uint timeout;
+ private bool hiding = false;
+ private bool delay = false;
+ private static GLib.Settings panel_settings = new GLib.Settings ("io.elementary.desktop.wingpanel");
+ private string autohide_mode = panel_settings.get_string ("autohide");
+ private int autohide_delay = panel_settings.get_int ("delay");
+ private Wnck.Screen wnck_screen = Wnck.Screen.get_default ();
public PanelWindow (Gtk.Application application) {
Object (
@@ -78,16 +85,72 @@ public class Wingpanel.PanelWindow : Gtk.Window {
application.set_accels_for_action ("app.cycle", {"Tab"});
application.set_accels_for_action ("app.cycle-back", {"Tab"});
+ panel_settings.changed["autohide"].connect (() => {
+ autohide_mode = panel_settings.get_string ("autohide");
+ update_autohide_mode ();
+ });
+
+ panel_settings.changed["delay"].connect (() => {
+ autohide_delay = panel_settings.get_int ("delay");
+ });
+
add (panel);
}
private bool animation_step () {
- if (panel_displacement <= panel_height * (-1)) {
- return false;
+ if (hiding) {
+ if (popover_manager.current_indicator != null) {
+ timeout = 0;
+ return false;
+ }
+ if (panel_displacement >= -1) {
+ timeout = 0;
+ update_struts ();
+ this.enter_notify_event.connect (show_panel);
+ this.motion_notify_event.connect (show_panel);
+ delay = true;
+ return false;
+ }
+ panel_displacement++;
+ } else {
+ if (panel_displacement <= panel_height * -1) {
+ timeout = 0;
+ switch (autohide_mode) {
+ case "Autohide":
+ update_struts ();
+ this.leave_notify_event.connect (hide_panel);
+ this.focus_out_event.connect (hide_panel);
+ break;
+ case "Float":
+ this.leave_notify_event.connect (hide_panel);
+ this.focus_out_event.connect (hide_panel);
+ break;
+ case "Dodge":
+ update_struts ();
+ if (should_hide_active_change (wnck_screen.get_active_window ())) {
+ this.leave_notify_event.connect (hide_panel);
+ this.focus_out_event.connect (hide_panel);
+ }
+
+ break;
+ case "Dodge-Float":
+ if (should_hide_active_change (wnck_screen.get_active_window ())) {
+ this.leave_notify_event.connect (hide_panel);
+ this.focus_out_event.connect (hide_panel);
+ }
+
+ break;
+ default:
+ this.leave_notify_event.disconnect (hide_panel);
+ this.focus_out_event.disconnect (hide_panel);
+ update_struts ();
+ break;
+ }
+ return false;
+ }
+ panel_displacement--;
}
- panel_displacement--;
-
update_panel_dimensions ();
return true;
@@ -98,7 +161,134 @@ public class Wingpanel.PanelWindow : Gtk.Window {
Services.BackgroundManager.initialize (this.monitor_number, panel_height);
- Timeout.add (300 / panel_height, animation_step);
+ panel_displacement--;
+ update_panel_dimensions ();
+ update_autohide_mode ();
+ }
+
+ private void active_window_changed (Wnck.Window? prev_active_window) {
+ unowned Wnck.Window? active_window = wnck_screen.get_active_window ();
+ 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_workspace_changed (Wnck.Workspace? prev_active_workspace) {
+ unowned Wnck.Window? active_window = wnck_screen.get_active_window ();
+ update_visibility_active_change (active_window);
+ }
+
+ private void viewports_changed (Wnck.Screen? screen) {
+ unowned Wnck.Window? active_window = wnck_screen.get_active_window ();
+ update_visibility_active_change (active_window);
+ }
+
+ private void active_window_state_changed (Wnck.Window? window,
+ Wnck.WindowState changed_mask, Wnck.WindowState new_state) {
+ update_visibility_active_change (window);
+ }
+
+ private void update_visibility_active_change (Wnck.Window? active_window) {
+ if (should_hide_active_change (active_window)) {
+ this.leave_notify_event.connect (hide_panel);
+ this.focus_out_event.connect (hide_panel);
+ delay = false;
+ hide_panel ();
+ } else {
+ this.leave_notify_event.disconnect (hide_panel);
+ this.focus_out_event.disconnect (hide_panel);
+ delay = false;
+ show_panel ();
+ }
+ }
+
+ 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.is_in_viewport (active_workspace)
+ && is_maximized_at_all (active_window));
+ }
+
+ 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 ()
+ || window.is_fullscreen ());
+ }
+
+ private bool hide_panel () {
+ if (timeout > 0) {
+ Source.remove (timeout);
+ }
+ hiding = true;
+ if (delay) {
+ Thread.usleep (autohide_delay * 1000);
+ }
+ timeout = Timeout.add (100 / panel_height, animation_step);
+ return true;
+ }
+
+ private bool show_panel () {
+ if (timeout > 0) {
+ Source.remove (timeout);
+ }
+ this.enter_notify_event.disconnect (show_panel);
+ this.motion_notify_event.disconnect (show_panel);
+ hiding = false;
+ if (autohide_mode != "Disabled") {
+ if (delay) {
+ Thread.usleep (autohide_delay * 1000);
+ }
+ timeout = Timeout.add (100 / panel_height, animation_step);
+ } else {
+ timeout = Timeout.add (300 / panel_height, animation_step);
+ }
+ return true;
+ }
+
+ private void update_autohide_mode () {
+ switch (autohide_mode) {
+ case "Autohide":
+ case "Float":
+ delay = true;
+ wnck_screen.active_window_changed.disconnect (active_window_changed);
+ wnck_screen.active_workspace_changed.disconnect (active_workspace_changed);
+ wnck_screen.viewports_changed.disconnect (viewports_changed);
+ hide_panel ();
+ break;
+ case "Dodge":
+ case "Dodge-Float":
+ delay = false;
+ if (!should_hide_active_change (wnck_screen.get_active_window ())) {
+ this.leave_notify_event.disconnect (hide_panel);
+ this.focus_out_event.disconnect (hide_panel);
+ show_panel ();
+ } else {
+ hide_panel ();
+ }
+ wnck_screen.active_window_changed.connect (active_window_changed);
+ wnck_screen.active_workspace_changed.connect (active_workspace_changed);
+ wnck_screen.viewports_changed.connect (viewports_changed);
+ break;
+ default:
+ this.leave_notify_event.connect (hide_panel);
+ this.focus_out_event.connect (hide_panel);
+ wnck_screen.active_window_changed.disconnect (active_window_changed);
+ wnck_screen.active_workspace_changed.disconnect (active_workspace_changed);
+ wnck_screen.viewports_changed.disconnect (viewports_changed);
+ show_panel ();
+ break;
+ }
}
private void update_panel_dimensions () {
@@ -116,9 +306,29 @@ public class Wingpanel.PanelWindow : Gtk.Window {
monitor_x = monitor_dimensions.x;
monitor_y = monitor_dimensions.y;
- this.move (monitor_x, monitor_y - (panel_height + panel_displacement));
+ int wx, wy;
+ get_position (out wx, out wy);
+
+ /**
+ * Instead of constantly moving the window for the animation,
+ * we will only move the window when it has been hidden / shown
+ * The actual animation is handed off to the panel widget.
+ */
+ if (panel_displacement == -1) {
+ int y = monitor_y - (panel_height + panel_displacement);
+ if (wx != monitor_x || wy != y) {
+ move (monitor_x, y);
+ }
+
+ panel.draw_y = 0;
+ } else {
+ if (wx != 0 || wy != 0) {
+ move (0, 0);
+ }
+
+ panel.draw_y = monitor_y - (panel_height + panel_displacement);
+ }
- update_struts ();
}
private void update_visual () {
diff --git a/src/Widgets/Panel.vala b/src/Widgets/Panel.vala
index 90aeb78..79b0c0e 100644
--- a/src/Widgets/Panel.vala
+++ b/src/Widgets/Panel.vala
@@ -27,6 +27,18 @@ public class Wingpanel.Widgets.Panel : Gtk.EventBox {
private Gtk.StyleContext style_context;
private Gtk.CssProvider? style_provider = null;
+ private int _draw_y = 0;
+ public int draw_y {
+ get {
+ return _draw_y;
+ }
+
+ set {
+ _draw_y = value;
+ queue_draw ();
+ }
+ }
+
private static Gtk.CssProvider resource_provider;
public Panel (Services.PopoverManager popover_manager) {
@@ -73,6 +85,11 @@ public class Wingpanel.Widgets.Panel : Gtk.EventBox {
Services.BackgroundManager.get_default ().background_state_changed.connect (update_background);
}
+ public override bool draw (Cairo.Context ctx) {
+ ctx.translate (0, draw_y);
+ return base.draw (ctx);
+ }
+
static construct {
resource_provider = new Gtk.CssProvider ();
resource_provider.load_from_resource ("io/elementary/wingpanel/panel.css");
diff --git a/src/meson.build b/src/meson.build
index c3708dd..4357d4e 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -15,6 +15,7 @@ wingpanel_files = files(
wingpanel_deps = [
libwingpanel_dep,
granite_dep,
+ libwnck_dep,
gdk_x11_dep
]
executable(meson.project_name(),