From 9e852559690dffd7e8b148d7d404d7e117c3bec9 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Tue, 1 Aug 2023 14:27:32 +0200 Subject: [PATCH 1/7] Add context menu --- meson.build | 4 +- src/Launcher.vala | 107 ++++++++++++++++++++++++++++++++++++++------ src/MainWindow.vala | 53 +++++++++++++++++++--- 3 files changed, 144 insertions(+), 20 deletions(-) diff --git a/meson.build b/meson.build index e648ecb2..0f2f8430 100644 --- a/meson.build +++ b/meson.build @@ -13,13 +13,15 @@ gio_unix_dep = dependency('gio-unix-2.0') glib_dep = dependency('glib-2.0') gobject_dep = dependency('gobject-2.0') gtk_dep = dependency('gtk4') +granite_dep = dependency('granite-7') dependencies = [ gio_dep, gio_unix_dep, glib_dep, gobject_dep, - gtk_dep + gtk_dep, + granite_dep ] meson.add_install_script('meson/post_install.py') diff --git a/src/Launcher.vala b/src/Launcher.vala index 042a8d0d..6f5e25bb 100644 --- a/src/Launcher.vala +++ b/src/Launcher.vala @@ -11,6 +11,9 @@ public class Dock.Launcher : Gtk.Button { private static Gtk.CssProvider css_provider; + private Gtk.Button close_button; + private Gtk.PopoverMenu popover; + public Launcher (GLib.DesktopAppInfo app_info) { Object (app_info: app_info); } @@ -28,6 +31,56 @@ public class Dock.Launcher : Gtk.Button { windows = new GLib.List (); get_style_context ().add_provider (css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); + var pinned_menu_item = new MenuItem (null, "win." + app_info.get_id () + "pinned"); + pinned_menu_item.set_attribute_value ("custom", "pinned-item"); + + var close_menu_item = new MenuItem (null, null); + close_menu_item.set_attribute_value ("custom", "close-item"); + + var action_section = new Menu (); + foreach (var action in app_info.list_actions ()) { + action_section.append ( + app_info.get_action_name (action), + MainWindow.ACTION_PREFIX + MainWindow.LAUNCHER_ACTION_TEMPLATE.printf (app_info.get_id (), action) + ); + } + + var model = new Menu (); + model.append_item (pinned_menu_item); + model.append_item (close_menu_item); // Placeholder, currently doesn't work + if (action_section.get_n_items () > 0) { + model.append_section (null, action_section); + } + + var pinned_label = new Gtk.Label ("Keep in Dock") { + xalign = 0, + hexpand = true + }; + + var pinned_check_button = new Gtk.CheckButton (); + + var pinned_box = new Gtk.Box (HORIZONTAL, 3); + pinned_box.append (pinned_label); + pinned_box.append (pinned_check_button); + + var pinned_button = new Gtk.ToggleButton () { + child = pinned_box + }; + pinned_button.add_css_class (Granite.STYLE_CLASS_MENUITEM); + + close_button = new Gtk.Button () { + visible = false, + child = new Gtk.Label (_("Close")) { halign = START } + }; + close_button.add_css_class (Granite.STYLE_CLASS_MENUITEM); + + popover = new Gtk.PopoverMenu.from_model (model) { + position = TOP + }; + popover.set_parent (this); + popover.add_child (pinned_button, "pinned-item"); + popover.add_child (close_button, "close-item"); + var image = new Gtk.Image () { gicon = app_info.get_icon () }; @@ -36,33 +89,59 @@ public class Dock.Launcher : Gtk.Button { child = image; tooltip_text = app_info.get_display_name (); - clicked.connect (() => { - try { - add_css_class ("bounce"); + bind_property ("pinned", pinned_button, "active", BIDIRECTIONAL | SYNC_CREATE); + pinned_button.bind_property ("active", pinned_check_button, "active", SYNC_CREATE); + + notify["pinned"].connect (() => ((MainWindow) get_root ()).sync_pinned ()); + + var gesture_click = new Gtk.GestureClick () { + button = Gdk.BUTTON_SECONDARY + }; + add_controller (gesture_click); + gesture_click.released.connect (popover.popup); + + clicked.connect (() => launch()); - var context = Gdk.Display.get_default ().get_app_launch_context (); - context.set_timestamp (Gdk.CURRENT_TIME); + close_button.clicked.connect (() => { + // TODO + }); + } + ~Launcher () { + popover.unparent (); + popover.dispose (); + } + + public void launch (string? action = null) { + try { + add_css_class ("bounce"); + + var context = Gdk.Display.get_default ().get_app_launch_context (); + context.set_timestamp (Gdk.CURRENT_TIME); + + if (action != null) { + app_info.launch_action (action, context); + } else { app_info.launch (null, context); - } catch (Error e) { - critical (e.message); } - Timeout.add (400, () => { - remove_css_class ("bounce"); - - return Source.REMOVE; - }); + } catch (Error e) { + critical (e.message); + } + Timeout.add (400, () => { + remove_css_class ("bounce"); + return Source.REMOVE; }); } public void update_windows (owned GLib.List? new_windows) { if (new_windows == null) { windows = new GLib.List (); - return; + } else { + windows = (owned) new_windows; } - windows = (owned) new_windows; + close_button.visible = !windows.is_empty (); } public AppWindow? find_window (uint64 window_uid) { diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 44200d8d..697346dd 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -4,6 +4,11 @@ */ public class Dock.MainWindow : Gtk.ApplicationWindow { + // First %s is the app id second %s the action name + public const string LAUNCHER_ACTION_TEMPLATE = "%s.%s"; + public const string ACTION_GROUP_PREFIX = "win"; + public const string ACTION_PREFIX = ACTION_GROUP_PREFIX + "."; + private static Gtk.CssProvider css_provider; private Gtk.Box box; @@ -67,6 +72,11 @@ public class Dock.MainWindow : Gtk.ApplicationWindow { unowned var app_id = app_info.get_id (); app_to_launcher.insert (app_id, launcher); box.append (launcher); + foreach (var action in app_info.list_actions ()) { + var simple_action = new SimpleAction (LAUNCHER_ACTION_TEMPLATE.printf (app_id, action), null); + simple_action.activate.connect (() => launcher.launch (action)); + add_action (simple_action); + } return app_to_launcher[app_id]; } @@ -110,14 +120,47 @@ public class Dock.MainWindow : Gtk.ApplicationWindow { app_to_launcher.foreach_remove ((app_id, launcher) => { var window_list = launcher_window_list.take (launcher); launcher.update_windows ((owned) window_list); - if (launcher.windows.is_empty ()) { - if (!launcher.pinned) { - launcher.unparent (); - return true; - } + if (launcher.windows.is_empty () && !launcher.pinned) { + remove_launcher (launcher, false); + return true; } return false; }); } + + public void remove_launcher (Launcher launcher, bool from_map = true) { + foreach (var action in list_actions ()) { + if (action.has_prefix (launcher.app_info.get_id ())) { + remove_action (action); + } + } + box.remove (launcher); + + if (from_map) { + app_to_launcher.remove (launcher.app_info.get_id ()); + } + } + + public void sync_pinned () { + string[] new_pinned_ids = {}; + + Launcher child = (Launcher) box.get_first_child (); + while (child != null) { + if (child.pinned) { + new_pinned_ids += child.app_info.get_id (); + } + + var current_child = child; + child = (Launcher) child.get_next_sibling (); + + if (!current_child.pinned && current_child.windows.is_empty ()) { + remove_launcher (current_child); + } + } + + + var settings = new Settings ("io.elementary.dock"); + settings.set_strv ("launchers", new_pinned_ids); + } } From 5fe6179eb1f85cdfacc94333ba6e3fe62dddff29 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Tue, 1 Aug 2023 15:05:13 +0200 Subject: [PATCH 2/7] Cleanup --- src/Launcher.vala | 4 ++-- src/MainWindow.vala | 12 +++++------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/Launcher.vala b/src/Launcher.vala index 6f5e25bb..6f08a90c 100644 --- a/src/Launcher.vala +++ b/src/Launcher.vala @@ -31,7 +31,7 @@ public class Dock.Launcher : Gtk.Button { windows = new GLib.List (); get_style_context ().add_provider (css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); - var pinned_menu_item = new MenuItem (null, "win." + app_info.get_id () + "pinned"); + var pinned_menu_item = new MenuItem (null, null); pinned_menu_item.set_attribute_value ("custom", "pinned-item"); var close_menu_item = new MenuItem (null, null); @@ -100,7 +100,7 @@ public class Dock.Launcher : Gtk.Button { add_controller (gesture_click); gesture_click.released.connect (popover.popup); - clicked.connect (() => launch()); + clicked.connect (() => launch ()); close_button.clicked.connect (() => { // TODO diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 697346dd..34882421 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -145,16 +145,14 @@ public class Dock.MainWindow : Gtk.ApplicationWindow { public void sync_pinned () { string[] new_pinned_ids = {}; - Launcher child = (Launcher) box.get_first_child (); + unowned Launcher child = (Launcher) box.get_first_child (); while (child != null) { - if (child.pinned) { - new_pinned_ids += child.app_info.get_id (); - } - - var current_child = child; + unowned var current_child = child; child = (Launcher) child.get_next_sibling (); - if (!current_child.pinned && current_child.windows.is_empty ()) { + if (current_child.pinned) { + new_pinned_ids += current_child.app_info.get_id (); + } else if (!current_child.pinned && current_child.windows.is_empty ()) { remove_launcher (current_child); } } From efc546fd1d85c536ce389e0ff105dcb21025785f Mon Sep 17 00:00:00 2001 From: Leonhard <106322251+leolost2605@users.noreply.github.com> Date: Wed, 8 Nov 2023 14:12:35 +0100 Subject: [PATCH 3/7] Update src/Launcher.vala MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Danielle Foré --- src/Launcher.vala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Launcher.vala b/src/Launcher.vala index 6f08a90c..480ccf59 100644 --- a/src/Launcher.vala +++ b/src/Launcher.vala @@ -75,6 +75,7 @@ public class Dock.Launcher : Gtk.Button { close_button.add_css_class (Granite.STYLE_CLASS_MENUITEM); popover = new Gtk.PopoverMenu.from_model (model) { + autohide = true, position = TOP }; popover.set_parent (this); From dbbc6abe6001102705d4ac8b5b7756d708049f5a Mon Sep 17 00:00:00 2001 From: Leonhard Date: Wed, 8 Nov 2023 14:19:23 +0100 Subject: [PATCH 4/7] Remove close button, keep keep in dock at bottom --- src/Launcher.vala | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/src/Launcher.vala b/src/Launcher.vala index 480ccf59..497d0ec8 100644 --- a/src/Launcher.vala +++ b/src/Launcher.vala @@ -11,7 +11,6 @@ public class Dock.Launcher : Gtk.Button { private static Gtk.CssProvider css_provider; - private Gtk.Button close_button; private Gtk.PopoverMenu popover; public Launcher (GLib.DesktopAppInfo app_info) { @@ -31,12 +30,6 @@ public class Dock.Launcher : Gtk.Button { windows = new GLib.List (); get_style_context ().add_provider (css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); - var pinned_menu_item = new MenuItem (null, null); - pinned_menu_item.set_attribute_value ("custom", "pinned-item"); - - var close_menu_item = new MenuItem (null, null); - close_menu_item.set_attribute_value ("custom", "close-item"); - var action_section = new Menu (); foreach (var action in app_info.list_actions ()) { action_section.append ( @@ -45,12 +38,17 @@ public class Dock.Launcher : Gtk.Button { ); } + var pinned_menu_item = new MenuItem (null, null); + pinned_menu_item.set_attribute_value ("custom", "pinned-item"); + + var pinned_section = new Menu (); + pinned_section.append_item (pinned_menu_item); + var model = new Menu (); - model.append_item (pinned_menu_item); - model.append_item (close_menu_item); // Placeholder, currently doesn't work if (action_section.get_n_items () > 0) { model.append_section (null, action_section); } + model.append_section (null, pinned_section); var pinned_label = new Gtk.Label ("Keep in Dock") { xalign = 0, @@ -68,19 +66,12 @@ public class Dock.Launcher : Gtk.Button { }; pinned_button.add_css_class (Granite.STYLE_CLASS_MENUITEM); - close_button = new Gtk.Button () { - visible = false, - child = new Gtk.Label (_("Close")) { halign = START } - }; - close_button.add_css_class (Granite.STYLE_CLASS_MENUITEM); - popover = new Gtk.PopoverMenu.from_model (model) { autohide = true, position = TOP }; popover.set_parent (this); popover.add_child (pinned_button, "pinned-item"); - popover.add_child (close_button, "close-item"); var image = new Gtk.Image () { gicon = app_info.get_icon () @@ -102,10 +93,6 @@ public class Dock.Launcher : Gtk.Button { gesture_click.released.connect (popover.popup); clicked.connect (() => launch ()); - - close_button.clicked.connect (() => { - // TODO - }); } ~Launcher () { @@ -141,8 +128,6 @@ public class Dock.Launcher : Gtk.Button { } else { windows = (owned) new_windows; } - - close_button.visible = !windows.is_empty (); } public AppWindow? find_window (uint64 window_uid) { From ec5c575b452a4b5b9128a96713b99f5d2076381e Mon Sep 17 00:00:00 2001 From: Leonhard Date: Thu, 9 Nov 2023 12:49:58 +0100 Subject: [PATCH 5/7] Use stateful actions --- src/Launcher.vala | 28 ++++------------------------ src/MainWindow.vala | 12 ++++++++++++ 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/src/Launcher.vala b/src/Launcher.vala index 497d0ec8..5392e696 100644 --- a/src/Launcher.vala +++ b/src/Launcher.vala @@ -38,11 +38,11 @@ public class Dock.Launcher : Gtk.Button { ); } - var pinned_menu_item = new MenuItem (null, null); - pinned_menu_item.set_attribute_value ("custom", "pinned-item"); - var pinned_section = new Menu (); - pinned_section.append_item (pinned_menu_item); + pinned_section.append ( + _("Keep in Dock"), + MainWindow.ACTION_PREFIX + MainWindow.LAUNCHER_PINNED_ACTION_TEMPLATE.printf (app_info.get_id ()) + ); var model = new Menu (); if (action_section.get_n_items () > 0) { @@ -50,28 +50,11 @@ public class Dock.Launcher : Gtk.Button { } model.append_section (null, pinned_section); - var pinned_label = new Gtk.Label ("Keep in Dock") { - xalign = 0, - hexpand = true - }; - - var pinned_check_button = new Gtk.CheckButton (); - - var pinned_box = new Gtk.Box (HORIZONTAL, 3); - pinned_box.append (pinned_label); - pinned_box.append (pinned_check_button); - - var pinned_button = new Gtk.ToggleButton () { - child = pinned_box - }; - pinned_button.add_css_class (Granite.STYLE_CLASS_MENUITEM); - popover = new Gtk.PopoverMenu.from_model (model) { autohide = true, position = TOP }; popover.set_parent (this); - popover.add_child (pinned_button, "pinned-item"); var image = new Gtk.Image () { gicon = app_info.get_icon () @@ -81,9 +64,6 @@ public class Dock.Launcher : Gtk.Button { child = image; tooltip_text = app_info.get_display_name (); - bind_property ("pinned", pinned_button, "active", BIDIRECTIONAL | SYNC_CREATE); - pinned_button.bind_property ("active", pinned_check_button, "active", SYNC_CREATE); - notify["pinned"].connect (() => ((MainWindow) get_root ()).sync_pinned ()); var gesture_click = new Gtk.GestureClick () { diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 34882421..98a93cb0 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -6,6 +6,7 @@ public class Dock.MainWindow : Gtk.ApplicationWindow { // First %s is the app id second %s the action name public const string LAUNCHER_ACTION_TEMPLATE = "%s.%s"; + public const string LAUNCHER_PINNED_ACTION_TEMPLATE = "%s-pinned"; public const string ACTION_GROUP_PREFIX = "win"; public const string ACTION_PREFIX = ACTION_GROUP_PREFIX + "."; @@ -72,11 +73,22 @@ public class Dock.MainWindow : Gtk.ApplicationWindow { unowned var app_id = app_info.get_id (); app_to_launcher.insert (app_id, launcher); box.append (launcher); + + var pinned_action = new SimpleAction.stateful ( + LAUNCHER_PINNED_ACTION_TEMPLATE.printf (app_id), + null, + new Variant.boolean (launcher.pinned) + ); + launcher.notify["pinned"].connect (() => pinned_action.set_state (launcher.pinned)); + pinned_action.change_state.connect ((new_state) => launcher.pinned = (bool) new_state); + add_action (pinned_action); + foreach (var action in app_info.list_actions ()) { var simple_action = new SimpleAction (LAUNCHER_ACTION_TEMPLATE.printf (app_id, action), null); simple_action.activate.connect (() => launcher.launch (action)); add_action (simple_action); } + return app_to_launcher[app_id]; } From 5aa9c55360fe701a0a8b3144155a738244281c6c Mon Sep 17 00:00:00 2001 From: Leonhard Date: Thu, 9 Nov 2023 12:54:34 +0100 Subject: [PATCH 6/7] Add comment --- src/MainWindow.vala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 98a93cb0..32100d9d 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -6,6 +6,7 @@ public class Dock.MainWindow : Gtk.ApplicationWindow { // First %s is the app id second %s the action name public const string LAUNCHER_ACTION_TEMPLATE = "%s.%s"; + // %s is the app id public const string LAUNCHER_PINNED_ACTION_TEMPLATE = "%s-pinned"; public const string ACTION_GROUP_PREFIX = "win"; public const string ACTION_PREFIX = ACTION_GROUP_PREFIX + "."; From 0538e3f55e7f00c5c6746b59170c9c20bb5cdc31 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Thu, 9 Nov 2023 12:56:16 +0100 Subject: [PATCH 7/7] Formatting --- src/Launcher.vala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Launcher.vala b/src/Launcher.vala index 5392e696..2c1cfa19 100644 --- a/src/Launcher.vala +++ b/src/Launcher.vala @@ -95,6 +95,7 @@ public class Dock.Launcher : Gtk.Button { } catch (Error e) { critical (e.message); } + Timeout.add (400, () => { remove_css_class ("bounce");