From 6fc13caad2afb99d60926d5a211504b7b648a866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Tue, 7 Oct 2025 16:42:11 -0700 Subject: [PATCH 1/6] ProcessInfoView: handle process actions --- src/Monitor.vala | 2 -- .../ProcessInfoView/ProcessInfoView.vala | 30 +++++++++++++++---- .../ProcessTreeView/CPUProcessTreeView.vala | 12 -------- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/Monitor.vala b/src/Monitor.vala index 3dc481cb7..6c7b2e38a 100644 --- a/src/Monitor.vala +++ b/src/Monitor.vala @@ -67,8 +67,6 @@ namespace Monitor { set_accels_for_action ("app.quit", { "q" }); set_accels_for_action ("win.search", { "f" }); - set_accels_for_action ("process.end", { "e" }); - set_accels_for_action ("process.kill", { "k" }); var dbusserver = DBusServer.get_default (); dbusserver.show.connect (() => activate ()); diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index 72bd83ab6..2690f5578 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -60,6 +60,10 @@ public class Monitor.ProcessInfoView : Gtk.Box { orientation = Gtk.Orientation.VERTICAL; hexpand = true; + var application = (Gtk.Application) GLib.Application.get_default (); + application.set_accels_for_action ("process.end", { "E" }); + application.set_accels_for_action ("process.kill", { "K" }); + permission_error_infobar = new Gtk.InfoBar () { message_type = Gtk.MessageType.ERROR, revealed = false, @@ -98,12 +102,18 @@ public class Monitor.ProcessInfoView : Gtk.Box { grid.attach (process_info_io_stats, 0, 4, 1, 1); end_process_button = new Gtk.Button.with_label (_("Shut Down…")) { - tooltip_markup = Granite.markup_accel_tooltip ({ "E" }) + action_name = "process.end" }; + end_process_button.tooltip_markup = Granite.markup_accel_tooltip ( + application.get_accels_for_action (end_process_button.action_name) + ); kill_process_button = new Gtk.Button.with_label (_("Force Quit…")) { - tooltip_markup = Granite.markup_accel_tooltip ({ "K" }) + action_name = "process.kill" }; + kill_process_button.tooltip_markup = Granite.markup_accel_tooltip ( + application.get_accels_for_action (kill_process_button.action_name) + ); kill_process_button.add_css_class (Granite.CssClass.DESTRUCTIVE); process_action_bar = new Gtk.Box (HORIZONTAL, 12) { @@ -115,7 +125,10 @@ public class Monitor.ProcessInfoView : Gtk.Box { process_action_bar.append (end_process_button); process_action_bar.append (kill_process_button); - kill_process_button.clicked.connect (() => { + grid.attach (process_action_bar, 0, 5); + + var kill_action = new SimpleAction ("kill", null); + kill_action.activate.connect (() => { var confirmation_dialog = new Granite.MessageDialog ( _("Force “%s” to quit without initiating shutdown tasks?").printf (process_info_header.application_name.label), _("This may lead to data loss. Only Force Quit if Shut Down has failed."), @@ -142,13 +155,14 @@ public class Monitor.ProcessInfoView : Gtk.Box { confirmation_dialog.present (); }); - end_process_button.clicked.connect (() => { + var end_action = new SimpleAction ("end", null); + end_action.activate.connect (() => { var confirmation_dialog = new Granite.MessageDialog ( _("Ask “%s” to shut down?").printf (process_info_header.application_name.label), _("The process will be asked to initiate shutdown tasks and close. In some cases the process may not quit."), new ThemedIcon ("system-shutdown"), Gtk.ButtonsType.CANCEL - ) { + ) { badge_icon = new ThemedIcon ("dialog-question"), modal = true, transient_for = (Gtk.Window) get_root () @@ -169,7 +183,11 @@ public class Monitor.ProcessInfoView : Gtk.Box { confirmation_dialog.present (); }); - grid.attach (process_action_bar, 0, 5); + var action_group = new SimpleActionGroup (); + action_group.add_action (kill_action); + action_group.add_action (end_action); + + insert_action_group ("process", action_group); } private void show_permission_error_infobar (string error) { diff --git a/src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala b/src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala index e49c1476e..51d3c2ef2 100644 --- a/src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala +++ b/src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala @@ -81,18 +81,6 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { cursor_changed.connect (_cursor_changed); // model.process_manager.updated.connect (_cursor_changed); - var end_process_action = new GLib.SimpleAction ("end", null); - end_process_action.activate.connect (end_process); - - var kill_process_action = new GLib.SimpleAction ("kill", null); - kill_process_action.activate.connect (kill_process); - - var action_group = new SimpleActionGroup (); - action_group.add_action (end_process_action); - action_group.add_action (kill_process_action); - - insert_action_group ("process", action_group); - var key_controller = new Gtk.EventControllerKey (); add_controller (key_controller); key_controller.key_released.connect ((keyval, keycode, state) => { From d3b5cf8f9bc12618e77c9ad061b5c99e29caf05f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Wed, 8 Oct 2025 11:36:31 -0700 Subject: [PATCH 2/6] Put accels back in application --- src/Monitor.vala | 2 ++ src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala | 6 ++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Monitor.vala b/src/Monitor.vala index 6c7b2e38a..837aee965 100644 --- a/src/Monitor.vala +++ b/src/Monitor.vala @@ -67,6 +67,8 @@ namespace Monitor { set_accels_for_action ("app.quit", { "q" }); set_accels_for_action ("win.search", { "f" }); + set_accels_for_action ("process.end", { "E" }); + set_accels_for_action ("process.kill", { "K" }); var dbusserver = DBusServer.get_default (); dbusserver.show.connect (() => activate ()); diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index 829f999ef..99eac3993 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -53,11 +53,9 @@ public class Monitor.ProcessInfoView : Gtk.Box { private ProcessInfoCPURAM process_info_cpu_ram; construct { - permission_error_label = new Gtk.Label (Utils.NO_DATA); - var application = (Gtk.Application) GLib.Application.get_default (); - application.set_accels_for_action ("process.end", { "E" }); - application.set_accels_for_action ("process.kill", { "K" }); + + permission_error_label = new Gtk.Label (Utils.NO_DATA); permission_error_infobar = new Gtk.InfoBar () { message_type = ERROR, From 784ff8d1bd2af7251c98a3a8e137b998f389dd2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Wed, 8 Oct 2025 11:37:27 -0700 Subject: [PATCH 3/6] revert case change --- src/Monitor.vala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Monitor.vala b/src/Monitor.vala index 837aee965..3dc481cb7 100644 --- a/src/Monitor.vala +++ b/src/Monitor.vala @@ -67,8 +67,8 @@ namespace Monitor { set_accels_for_action ("app.quit", { "q" }); set_accels_for_action ("win.search", { "f" }); - set_accels_for_action ("process.end", { "E" }); - set_accels_for_action ("process.kill", { "K" }); + set_accels_for_action ("process.end", { "e" }); + set_accels_for_action ("process.kill", { "k" }); var dbusserver = DBusServer.get_default (); dbusserver.show.connect (() => activate ()); From 6ec859ba3a5b0464614df0cd0cc2b825b18aa796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Wed, 8 Oct 2025 11:42:59 -0700 Subject: [PATCH 4/6] move actions to functions --- .../ProcessInfoView/ProcessInfoView.vala | 124 +++++++++--------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index 99eac3993..4cd395670 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -53,8 +53,6 @@ public class Monitor.ProcessInfoView : Gtk.Box { private ProcessInfoCPURAM process_info_cpu_ram; construct { - var application = (Gtk.Application) GLib.Application.get_default (); - permission_error_label = new Gtk.Label (Utils.NO_DATA); permission_error_infobar = new Gtk.InfoBar () { @@ -75,19 +73,17 @@ public class Monitor.ProcessInfoView : Gtk.Box { process_info_io_stats = new ProcessInfoIOStats (); + var app = (Gtk.Application) GLib.Application.get_default (); + var end_process_button = new Gtk.Button.with_label (_("Shut Down…")) { - action_name = "process.end" + action_name = "process.end", + tooltip_markup = Granite.markup_accel_tooltip (app.get_accels_for_action ("process.end")) }; - end_process_button.tooltip_markup = Granite.markup_accel_tooltip ( - application.get_accels_for_action (end_process_button.action_name) - ); var kill_process_button = new Gtk.Button.with_label (_("Force Quit…")) { - action_name = "process.kill" + action_name = "process.kill", + tooltip_markup = Granite.markup_accel_tooltip (app.get_accels_for_action ("process.kill")) }; - kill_process_button.tooltip_markup = Granite.markup_accel_tooltip ( - application.get_accels_for_action (kill_process_button.action_name) - ); kill_process_button.add_css_class (Granite.CssClass.DESTRUCTIVE); process_action_bar = new Granite.Box (HORIZONTAL) { @@ -117,60 +113,10 @@ public class Monitor.ProcessInfoView : Gtk.Box { append (box); var kill_action = new SimpleAction ("kill", null); - kill_action.activate.connect (() => { - var confirmation_dialog = new Granite.MessageDialog ( - _("Force “%s” to quit without initiating shutdown tasks?").printf (process.application_name), - _("This may lead to data loss. Only Force Quit if Shut Down has failed."), - new ThemedIcon ("computer-fail"), - Gtk.ButtonsType.CANCEL - ) { - badge_icon = new ThemedIcon ("process-stop"), - modal = true, - transient_for = (Gtk.Window) get_root () - }; - - var accept_button = confirmation_dialog.add_button (_("Force Quit"), Gtk.ResponseType.ACCEPT); - accept_button.add_css_class (Granite.CssClass.DESTRUCTIVE); - - confirmation_dialog.response.connect ((response) => { - if (response == Gtk.ResponseType.ACCEPT) { - // @TODO: maybe add a toast that process killed - process.kill (); - } - - confirmation_dialog.close (); - }); - - confirmation_dialog.present (); - }); + kill_action.activate.connect (action_kill); var end_action = new SimpleAction ("end", null); - end_action.activate.connect (() => { - var confirmation_dialog = new Granite.MessageDialog ( - _("Ask “%s” to shut down?").printf (process.application_name), - _("The process will be asked to initiate shutdown tasks and close. In some cases the process may not quit."), - new ThemedIcon ("system-shutdown"), - Gtk.ButtonsType.CANCEL - ) { - badge_icon = new ThemedIcon ("dialog-question"), - modal = true, - transient_for = (Gtk.Window) get_root () - }; - - var accept_button = confirmation_dialog.add_button (_("Shut Down"), Gtk.ResponseType.ACCEPT); - accept_button.add_css_class (Granite.CssClass.SUGGESTED); - - confirmation_dialog.response.connect ((response) => { - if (response == Gtk.ResponseType.ACCEPT) { - // TODO: maybe add a toast that process killed - process.end (); - } - - confirmation_dialog.close (); - }); - - confirmation_dialog.present (); - }); + end_action.activate.connect (action_end); var action_group = new SimpleActionGroup (); action_group.add_action (kill_action); @@ -179,6 +125,60 @@ public class Monitor.ProcessInfoView : Gtk.Box { insert_action_group ("process", action_group); } + private void action_end () { + var confirmation_dialog = new Granite.MessageDialog ( + _("Ask “%s” to shut down?").printf (process.application_name), + _("The process will be asked to initiate shutdown tasks and close. In some cases the process may not quit."), + new ThemedIcon ("system-shutdown"), + Gtk.ButtonsType.CANCEL + ) { + badge_icon = new ThemedIcon ("dialog-question"), + modal = true, + transient_for = (Gtk.Window) get_root () + }; + + var accept_button = confirmation_dialog.add_button (_("Shut Down"), Gtk.ResponseType.ACCEPT); + accept_button.add_css_class (Granite.CssClass.SUGGESTED); + + confirmation_dialog.response.connect ((response) => { + if (response == Gtk.ResponseType.ACCEPT) { + // TODO: maybe add a toast that process killed + process.end (); + } + + confirmation_dialog.close (); + }); + + confirmation_dialog.present (); + } + + private void action_kill () { + var confirmation_dialog = new Granite.MessageDialog ( + _("Force “%s” to quit without initiating shutdown tasks?").printf (process.application_name), + _("This may lead to data loss. Only Force Quit if Shut Down has failed."), + new ThemedIcon ("computer-fail"), + Gtk.ButtonsType.CANCEL + ) { + badge_icon = new ThemedIcon ("process-stop"), + modal = true, + transient_for = (Gtk.Window) get_root () + }; + + var accept_button = confirmation_dialog.add_button (_("Force Quit"), Gtk.ResponseType.ACCEPT); + accept_button.add_css_class (Granite.CssClass.DESTRUCTIVE); + + confirmation_dialog.response.connect ((response) => { + if (response == Gtk.ResponseType.ACCEPT) { + // @TODO: maybe add a toast that process killed + process.kill (); + } + + confirmation_dialog.close (); + }); + + confirmation_dialog.present (); + } + private void show_permission_error_infobar (string error) { if (!permission_error_infobar.revealed) { permission_error_label.label = error; From 714ec03ac631a3e07de4fcbf1c8dd8485a3117d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Wed, 8 Oct 2025 12:12:50 -0700 Subject: [PATCH 5/6] move actions up to ProcessView and add key controller --- .../ProcessInfoView/ProcessInfoView.vala | 66 --------------- src/Views/ProcessView/ProcessView.vala | 84 +++++++++++++++++++ 2 files changed, 84 insertions(+), 66 deletions(-) diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index 4cd395670..d32fcaa3a 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -111,72 +111,6 @@ public class Monitor.ProcessInfoView : Gtk.Box { hexpand = true; append (permission_error_infobar); append (box); - - var kill_action = new SimpleAction ("kill", null); - kill_action.activate.connect (action_kill); - - var end_action = new SimpleAction ("end", null); - end_action.activate.connect (action_end); - - var action_group = new SimpleActionGroup (); - action_group.add_action (kill_action); - action_group.add_action (end_action); - - insert_action_group ("process", action_group); - } - - private void action_end () { - var confirmation_dialog = new Granite.MessageDialog ( - _("Ask “%s” to shut down?").printf (process.application_name), - _("The process will be asked to initiate shutdown tasks and close. In some cases the process may not quit."), - new ThemedIcon ("system-shutdown"), - Gtk.ButtonsType.CANCEL - ) { - badge_icon = new ThemedIcon ("dialog-question"), - modal = true, - transient_for = (Gtk.Window) get_root () - }; - - var accept_button = confirmation_dialog.add_button (_("Shut Down"), Gtk.ResponseType.ACCEPT); - accept_button.add_css_class (Granite.CssClass.SUGGESTED); - - confirmation_dialog.response.connect ((response) => { - if (response == Gtk.ResponseType.ACCEPT) { - // TODO: maybe add a toast that process killed - process.end (); - } - - confirmation_dialog.close (); - }); - - confirmation_dialog.present (); - } - - private void action_kill () { - var confirmation_dialog = new Granite.MessageDialog ( - _("Force “%s” to quit without initiating shutdown tasks?").printf (process.application_name), - _("This may lead to data loss. Only Force Quit if Shut Down has failed."), - new ThemedIcon ("computer-fail"), - Gtk.ButtonsType.CANCEL - ) { - badge_icon = new ThemedIcon ("process-stop"), - modal = true, - transient_for = (Gtk.Window) get_root () - }; - - var accept_button = confirmation_dialog.add_button (_("Force Quit"), Gtk.ResponseType.ACCEPT); - accept_button.add_css_class (Granite.CssClass.DESTRUCTIVE); - - confirmation_dialog.response.connect ((response) => { - if (response == Gtk.ResponseType.ACCEPT) { - // @TODO: maybe add a toast that process killed - process.kill (); - } - - confirmation_dialog.close (); - }); - - confirmation_dialog.present (); } private void show_permission_error_infobar (string error) { diff --git a/src/Views/ProcessView/ProcessView.vala b/src/Views/ProcessView/ProcessView.vala index 93b07c8f7..b8f808abf 100644 --- a/src/Views/ProcessView/ProcessView.vala +++ b/src/Views/ProcessView/ProcessView.vala @@ -47,6 +47,90 @@ public class Monitor.ProcessView : Granite.Bin { child = paned; notify["needle"].connect (filter_model.refilter); + + var kill_action = new SimpleAction ("kill", null); + kill_action.activate.connect (action_kill); + + var end_action = new SimpleAction ("end", null); + end_action.activate.connect (action_end); + + var action_group = new SimpleActionGroup (); + action_group.add_action (kill_action); + action_group.add_action (end_action); + + insert_action_group ("process", action_group); + + var key_controller = new Gtk.EventControllerKey (); + key_controller.key_pressed.connect ((keyval, keycode, state) => { + if ((state & Gdk.ModifierType.CONTROL_MASK) != 0) { + switch (keyval) { + case Gdk.Key.k: + activate_action ("process.kill", null); + return Gdk.EVENT_STOP; + case Gdk.Key.e: + activate_action ("process.end", null); + return Gdk.EVENT_STOP; + } + } + + return Gdk.EVENT_PROPAGATE; + }); + + add_controller (key_controller); + } + + private void action_end () { + var confirmation_dialog = new Granite.MessageDialog ( + _("Ask “%s” to shut down?").printf (process_info_view.process.application_name), + _("The process will be asked to initiate shutdown tasks and close. In some cases the process may not quit."), + new ThemedIcon ("system-shutdown"), + Gtk.ButtonsType.CANCEL + ) { + badge_icon = new ThemedIcon ("dialog-question"), + modal = true, + transient_for = (Gtk.Window) get_root () + }; + + var accept_button = confirmation_dialog.add_button (_("Shut Down"), Gtk.ResponseType.ACCEPT); + accept_button.add_css_class (Granite.CssClass.SUGGESTED); + + confirmation_dialog.response.connect ((response) => { + if (response == Gtk.ResponseType.ACCEPT) { + // TODO: maybe add a toast that process killed + process_info_view.process.end (); + } + + confirmation_dialog.close (); + }); + + confirmation_dialog.present (); + } + + private void action_kill () { + var confirmation_dialog = new Granite.MessageDialog ( + _("Force “%s” to quit without initiating shutdown tasks?").printf (process_info_view.process.application_name), + _("This may lead to data loss. Only Force Quit if Shut Down has failed."), + new ThemedIcon ("computer-fail"), + Gtk.ButtonsType.CANCEL + ) { + badge_icon = new ThemedIcon ("process-stop"), + modal = true, + transient_for = (Gtk.Window) get_root () + }; + + var accept_button = confirmation_dialog.add_button (_("Force Quit"), Gtk.ResponseType.ACCEPT); + accept_button.add_css_class (Granite.CssClass.DESTRUCTIVE); + + confirmation_dialog.response.connect ((response) => { + if (response == Gtk.ResponseType.ACCEPT) { + // @TODO: maybe add a toast that process killed + process_info_view.process.kill (); + } + + confirmation_dialog.close (); + }); + + confirmation_dialog.present (); } public void on_process_selected (Process process) { From 765074f68e89e95b4abc35e34ef79b8556aaff04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Wed, 8 Oct 2025 13:12:22 -0700 Subject: [PATCH 6/6] Disable actions appropriately --- src/Views/ProcessView/ProcessView.vala | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Views/ProcessView/ProcessView.vala b/src/Views/ProcessView/ProcessView.vala index b8f808abf..0b7abda9d 100644 --- a/src/Views/ProcessView/ProcessView.vala +++ b/src/Views/ProcessView/ProcessView.vala @@ -11,6 +11,9 @@ public class Monitor.ProcessView : Granite.Bin { private ProcessInfoView process_info_view; private TreeViewModel treeview_model; + private SimpleAction end_action; + private SimpleAction kill_action; + construct { treeview_model = new TreeViewModel (); @@ -48,10 +51,10 @@ public class Monitor.ProcessView : Granite.Bin { notify["needle"].connect (filter_model.refilter); - var kill_action = new SimpleAction ("kill", null); + kill_action = new SimpleAction ("kill", null); kill_action.activate.connect (action_kill); - var end_action = new SimpleAction ("end", null); + end_action = new SimpleAction ("end", null); end_action.activate.connect (action_end); var action_group = new SimpleActionGroup (); @@ -136,6 +139,9 @@ public class Monitor.ProcessView : Granite.Bin { public void on_process_selected (Process process) { process_info_view.process = process; process_info_view.visible = true; + + end_action.set_enabled (process.uid == Posix.getuid ()); + kill_action.set_enabled (process.uid == Posix.getuid ()); } public void update () {