Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add context menu #182

Merged
merged 8 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
107 changes: 93 additions & 14 deletions src/Launcher.vala
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -28,6 +31,56 @@ public class Dock.Launcher : Gtk.Button {
windows = new GLib.List<AppWindow> ();
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");
leolost2605 marked this conversation as resolved.
Show resolved Hide resolved

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);
leolost2605 marked this conversation as resolved.
Show resolved Hide resolved

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
};
leolost2605 marked this conversation as resolved.
Show resolved Hide resolved
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 ()
};
Expand All @@ -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<AppWindow>? new_windows) {
if (new_windows == null) {
windows = new GLib.List<AppWindow> ();
return;
} else {
windows = (owned) new_windows;
}

windows = (owned) new_windows;
close_button.visible = !windows.is_empty ();
}

public AppWindow? find_window (uint64 window_uid) {
Expand Down
51 changes: 46 additions & 5 deletions src/MainWindow.vala
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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];
}

Expand Down Expand Up @@ -110,14 +120,45 @@ 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 = {};

unowned Launcher child = (Launcher) box.get_first_child ();
while (child != null) {
unowned var current_child = child;
child = (Launcher) child.get_next_sibling ();

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);
}
}


var settings = new Settings ("io.elementary.dock");
settings.set_strv ("launchers", new_pinned_ids);
}
}