From 8e29dfde29fa7a5cd8d1f3e06324f820177edc7c Mon Sep 17 00:00:00 2001 From: Ryo Nakano <26003928+ryonakano@users.noreply.github.com> Date: Sun, 22 Dec 2019 19:30:46 +0900 Subject: [PATCH 01/96] Lint codes with vala-lint --- src/Indicator/Indicator.vala | 6 +-- src/Indicator/Services/DBusClient.vala | 2 +- src/MainWindow.vala | 8 +-- src/Managers/AppManager.vala | 72 +++++++++++++------------- src/Managers/Process.vala | 4 +- src/Models/GenericModel.vala | 32 ++++++------ src/Monitor.vala | 4 +- src/Resources/CPU.vala | 56 ++++++++++---------- src/Resources/Core.vala | 18 +++---- src/Resources/Memory.vala | 4 +- src/Services/Shortcuts.vala | 4 +- src/Widgets/OverallView.vala | 20 +++---- src/Widgets/Search.vala | 14 ++--- src/Widgets/Statusbar/Statusbar.vala | 2 +- 14 files changed, 121 insertions(+), 125 deletions(-) diff --git a/src/Indicator/Indicator.vala b/src/Indicator/Indicator.vala index 2af66860..6fa42614 100644 --- a/src/Indicator/Indicator.vala +++ b/src/Indicator/Indicator.vala @@ -7,7 +7,7 @@ public class Monitor.Indicator : Wingpanel.Indicator { private DBusClient dbusclient; construct { - Gtk.IconTheme.get_default().add_resource_path("/com/github/stsdc/monitor/icons"); + Gtk.IconTheme.get_default ().add_resource_path ("/com/github/stsdc/monitor/icons"); settings = new Settings ("com.github.stsdc.monitor.settings"); this.visible = false; display_widget = new Widgets.DisplayWidget (); @@ -18,9 +18,9 @@ public class Monitor.Indicator : Wingpanel.Indicator { dbusclient.monitor_vanished.connect (() => this.visible = false); dbusclient.monitor_appeared.connect (() => this.visible = settings.get_boolean ("indicator-state")); - dbusclient.interface.indicator_state.connect((state) => this.visible = state); + dbusclient.interface.indicator_state.connect ((state) => this.visible = state); - dbusclient.interface.update.connect((sysres) => { + dbusclient.interface.update.connect ((sysres) => { display_widget.cpu_widget.percentage = sysres.cpu_percentage; display_widget.memory_widget.percentage = sysres.memory_percentage; }); diff --git a/src/Indicator/Services/DBusClient.vala b/src/Indicator/Services/DBusClient.vala index dd5f6c7d..116f66cf 100644 --- a/src/Indicator/Services/DBusClient.vala +++ b/src/Indicator/Services/DBusClient.vala @@ -6,7 +6,7 @@ public interface Monitor.DBusClientInterface : Object { public signal void indicator_state (bool state); } -public class Monitor.DBusClient : Object{ +public class Monitor.DBusClient : Object { public DBusClientInterface? interface = null; private static GLib.Once instance; diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 624f6c2b..399f2e0d 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -58,7 +58,7 @@ this.add (main_box); updater = Updater.get_default (); - dbusserver = DBusServer.get_default(); + dbusserver = DBusServer.get_default (); updater.update.connect ((sysres) => { statusbar.update (sysres); @@ -66,10 +66,10 @@ dbusserver.indicator_state (MonitorApp.settings.get_boolean ("indicator-state")); }); - dbusserver.quit.connect (() => app.quit()); + dbusserver.quit.connect (() => app.quit ()); dbusserver.show.connect (() => { - this.deiconify(); - this.present(); + this.deiconify (); + this.present (); setup_window_state (); this.show_all (); }); diff --git a/src/Managers/AppManager.vala b/src/Managers/AppManager.vala index c4b0d56b..3420c88c 100644 --- a/src/Managers/AppManager.vala +++ b/src/Managers/AppManager.vala @@ -7,79 +7,79 @@ namespace Monitor { public int[] pids; public uint32 xid; } - /** - * Wrapper for Bamf.Matcher - */ - public class AppManager { - public signal void application_opened (App app); - public signal void application_closed (App app); + /** + * Wrapper for Bamf.Matcher + */ + public class AppManager { + public signal void application_opened (App app); + public signal void application_closed (App app); - static AppManager? app_manager = null; + static AppManager? app_manager = null; private Bamf.Matcher? matcher; private Gee.ArrayList transient_xids; - public static AppManager get_default () { - if (app_manager == null) - app_manager = new AppManager (); - return app_manager; - } + public static AppManager get_default () { + if (app_manager == null) + app_manager = new AppManager (); + return app_manager; + } - public AppManager () { + public AppManager () { transient_xids = new Gee.ArrayList (); - matcher = Bamf.Matcher.get_default (); + matcher = Bamf.Matcher.get_default (); matcher.view_opened.connect_after (handle_view_opened); - matcher.view_closed.connect_after (handle_view_closed); - } + matcher.view_closed.connect_after (handle_view_closed); + } - ~AppManager () { - matcher.view_opened.disconnect (handle_view_opened); - matcher.view_closed.disconnect (handle_view_closed); - matcher = null; - } + ~AppManager () { + matcher.view_opened.disconnect (handle_view_opened); + matcher.view_closed.disconnect (handle_view_closed); + matcher = null; + } // Function retrieves a Bamf.view, checks if it's a window, // then extracts name, icon, desktop_file and pid. After that, // sends signal. - private void handle_view_opened (Bamf.View view) { + private void handle_view_opened (Bamf.View view) { if (view is Bamf.Window && is_main_window (view)) { int[] win_pids = {}; var window = (Bamf.Window)view; var app = matcher.get_application_for_window (window); - win_pids += (int)window.get_pid(); + win_pids += (int)window.get_pid (); if (has_desktop_file (app.get_desktop_file ())) { - debug ("Handle View Opened: %s", view.get_name()); + debug ("Handle View Opened: %s", view.get_name ()); application_opened ( App () { name = app.get_name (), icon = app.get_icon (), desktop_file = app.get_desktop_file (), pids = win_pids, - xid = app.get_xids ().index(0) + xid = app.get_xids ().index (0) } ); } } - } + } - private void handle_view_closed (Bamf.View view) { + private void handle_view_closed (Bamf.View view) { if (view is Bamf.Window && is_main_window (view)) { int[] win_pids = {}; var window = (Bamf.Window)view; var app = matcher.get_application_for_window (window); - win_pids += (int)window.get_pid(); + win_pids += (int)window.get_pid (); if (has_desktop_file (app.get_desktop_file ())) { - debug ("Handle View Closed: %s", view.get_name()); + debug ("Handle View Closed: %s", view.get_name ()); application_closed ( App () { name = app.get_name (), icon = app.get_icon (), desktop_file = app.get_desktop_file (), pids = win_pids, - xid = app.get_xids ().index(0) + xid = app.get_xids ().index (0) } ); } @@ -107,7 +107,7 @@ namespace Monitor { icon = bamf_app.get_icon (), desktop_file = bamf_app.get_desktop_file (), pids = win_pids, - xid = bamf_app.get_xids ().index(0) + xid = bamf_app.get_xids ().index (0) }; } } @@ -116,21 +116,21 @@ namespace Monitor { private bool is_main_window (Bamf.View view) { var window_type = ((Bamf.Window)view).get_window_type (); - debug ("Window type: %d, Is transient: %d", window_type, (int)is_transient(view)); + debug ("Window type: %d, Is transient: %d", window_type, (int)is_transient (view)); return (window_type == Bamf.WindowType.NORMAL || - window_type == Bamf.WindowType.DOCK) && !is_transient(view); + window_type == Bamf.WindowType.DOCK) && !is_transient (view); } // if window is transient add its xid to array and return true private bool is_transient (Bamf.View view) { - if(transient_xids.size > 0 && transient_xids.contains(((Bamf.Window)view).get_xid())) { + if (transient_xids.size > 0 && transient_xids.contains (((Bamf.Window)view).get_xid ())) { return true; } if (((Bamf.Window)view).get_transient () != null) { - transient_xids.add (((Bamf.Window)view).get_xid()); + transient_xids.add (((Bamf.Window)view).get_xid ()); return true; } return false; } - } + } } diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index 3a0bb76e..75b44347 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -1,5 +1,3 @@ - - namespace Monitor { public class Process { @@ -118,7 +116,7 @@ namespace Monitor { mem_usage = (proc_mem.resident - proc_mem.share) / 1024; // in KiB if (Gdk.Display.get_default () is Gdk.X11.Display) { - Wnck.ResourceUsage resu = Wnck.ResourceUsage.pid_read (Gdk.Display.get_default(), pid); + Wnck.ResourceUsage resu = Wnck.ResourceUsage.pid_read (Gdk.Display.get_default (), pid); mem_usage += (resu.total_bytes_estimate / 1024); } } catch (Error e) { diff --git a/src/Models/GenericModel.vala b/src/Models/GenericModel.vala index 65a40297..f60dd492 100644 --- a/src/Models/GenericModel.vala +++ b/src/Models/GenericModel.vala @@ -20,9 +20,9 @@ namespace Monitor { typeof (int64), typeof (int), }; - set_column_types(types); + set_column_types (types); - helper = new ModelHelper(this); + helper = new ModelHelper (this); process_manager = ProcessManager.get_default (); process_manager.process_added.connect ((process) => add_process (process)); @@ -33,8 +33,8 @@ namespace Monitor { app_manager.application_opened.connect ((app) => { add_app (app); }); app_manager.application_closed.connect ((app) => { remove_app (app); }); - Idle.add (() => { add_running_apps (); return false; } ); - Idle.add (() => { add_running_processes (); return false; } ); + Idle.add (() => { add_running_apps (); return false; }); + Idle.add (() => { add_running_processes (); return false; }); add_background_apps_row (); } @@ -171,37 +171,37 @@ namespace Monitor { Value pid_value; get_value (child_iter, Column.PID, out pid_value); pid_value_prev = pid_value; - debug( "reparent %d", pid_value.get_int ()); + debug ("reparent %d", pid_value.get_int ()); add_process_to_row (background_apps_iter, pid_value.get_int ()); } } private void remove_process (int pid) { - debug ("remove process %d from model".printf(pid)); + debug ("remove process %d from model".printf (pid)); // if process rows has pid if (process_rows.has_key (pid)) { var row = process_rows.get (pid); Gtk.TreeIter iter = row.iter; - + debug ("remove process: user_data %d, stamp %d", (int) iter.user_data, iter.stamp); - + Value pid_value; get_value (iter, Column.PID, out pid_value); - + // Column.NAME, for example returns (null) // Column.PID return 0 - - debug("removing %d", pid_value.get_int()); - + + debug ("removing %d", pid_value.get_int ()); + // sometimes iter has null values // this potentially should prevent segfaults - if (pid_value.get_int() != 0) { + if (pid_value.get_int () != 0) { reparent (ref iter); // remove row from model remove (ref iter); } - + // remove row from row cache process_rows.unset (pid); } @@ -300,7 +300,7 @@ namespace Monitor { if (pid > 0) { var process = process_manager.get_process (pid); process.kill (); - info ("Kill:%d",process.pid); + info ("Kill:%d", process.pid); } } @@ -308,7 +308,7 @@ namespace Monitor { if (pid > 0) { var process = process_manager.get_process (pid); process.end (); - info ("End:%d",process.pid); + info ("End:%d", process.pid); } } } diff --git a/src/Monitor.vala b/src/Monitor.vala index 64f72390..38aaee1f 100644 --- a/src/Monitor.vala +++ b/src/Monitor.vala @@ -7,7 +7,7 @@ namespace Monitor { private static bool start_in_background = false; private static bool status_background = false; - private const GLib.OptionEntry[] cmd_options = { + private const GLib.OptionEntry[] CMD_OPTIONS = { // --start-in-background { "start-in-background", 'b', 0, OptionArg.NONE, ref start_in_background, "Start in background with wingpanel indicator", null }, // list terminator @@ -66,7 +66,7 @@ namespace Monitor { try { var opt_context = new OptionContext (""); opt_context.set_help_enabled (true); - opt_context.add_main_entries (cmd_options, null); + opt_context.add_main_entries (CMD_OPTIONS, null); opt_context.parse (ref args); } catch (OptionError e) { print ("Error: %s\n", e.message); diff --git a/src/Resources/CPU.vala b/src/Resources/CPU.vala index f65bfb5b..7a84897b 100644 --- a/src/Resources/CPU.vala +++ b/src/Resources/CPU.vala @@ -1,36 +1,36 @@ - public class Monitor.CPU : Object { - private float last_used; - private float last_total; - private float load; - - GTop.Cpu? cpu; - - public int percentage { - get { - update (); - return (int) (Math.round(load * 100)); - } - } - construct { - last_used = 0; - last_total = 0; +public class Monitor.CPU : Object { + private float last_used; + private float last_total; + private float load; + + GTop.Cpu? cpu; + + public int percentage { + get { + update (); + return (int) (Math.round (load * 100)); } + } + construct { + last_used = 0; + last_total = 0; + } - public CPU () { } + public CPU () { } - private void update () { - GTop.get_cpu (out cpu); + private void update () { + GTop.get_cpu (out cpu); - var used = (float) (cpu.user + cpu.sys + cpu.nice + cpu.irq + cpu.softirq); - var idle = (float) (cpu.idle + cpu.iowait); - var total = used + idle; + var used = (float) (cpu.user + cpu.sys + cpu.nice + cpu.irq + cpu.softirq); + var idle = (float) (cpu.idle + cpu.iowait); + var total = used + idle; - var diff_used = used - last_used; - var diff_total = total - last_total; + var diff_used = used - last_used; + var diff_total = total - last_total; - load = diff_used.abs () / diff_total.abs (); + load = diff_used.abs () / diff_total.abs (); - last_used = used; - last_total = total; - } + last_used = used; + last_total = total; } +} diff --git a/src/Resources/Core.vala b/src/Resources/Core.vala index bd23100c..bed3b5b0 100644 --- a/src/Resources/Core.vala +++ b/src/Resources/Core.vala @@ -1,6 +1,6 @@ namespace Monitor { //from Monilet - public class Core : GLib.Object { + public class Core : GLib.Object { private float last_total; private float last_used; @@ -11,23 +11,21 @@ namespace Monitor { get { update_percentage_used (); return _percentage_used; } } - public Core (int number){ - Object (number : number); + public Core (int number) { + Object (number: number); last_used = 0; last_total = 0; } - private void update_percentage_used (){ + private void update_percentage_used () { GTop.Cpu cpu; GTop.get_cpu (out cpu); - var used = cpu.xcpu_user[number] + - cpu.xcpu_nice[number] + - cpu.xcpu_sys[number]; + var used = cpu.xcpu_user[number] + cpu.xcpu_nice[number] + cpu.xcpu_sys[number]; - var difference_used = (float) used - last_used; - var difference_total = (float) cpu.xcpu_total[number] - last_total; - var pre_percentage = difference_used.abs () / difference_total.abs (); // calculate the pre percentage + var difference_used = (float) used - last_used; + var difference_total = (float) cpu.xcpu_total[number] - last_total; + var pre_percentage = difference_used.abs () / difference_total.abs (); // calculate the pre percentage _percentage_used = pre_percentage * 100; diff --git a/src/Resources/Memory.vala b/src/Resources/Memory.vala index 0ba335b0..b5a63a01 100644 --- a/src/Resources/Memory.vala +++ b/src/Resources/Memory.vala @@ -9,7 +9,7 @@ namespace Monitor { public int percentage { get { update (); - return (int) (Math.round((used / total) * 100)); + return (int) (Math.round ((used / total) * 100)); } } @@ -22,7 +22,7 @@ namespace Monitor { private void update () { GTop.get_mem (out mem); - total = (double) (mem.total / 1024 / 1024) / 1000; + total = (double) (mem.total / 1024 / 1024) / 1000; used = (double) (mem.user / 1024 / 1024) / 1000; } } diff --git a/src/Services/Shortcuts.vala b/src/Services/Shortcuts.vala index ec7323d9..9d327b3a 100644 --- a/src/Services/Shortcuts.vala +++ b/src/Services/Shortcuts.vala @@ -10,12 +10,12 @@ namespace Monitor { handled = false; char typed = e.str[0]; - if (typed.isalnum () && !window.headerbar.search.is_focus ) { + if (typed.isalnum () && !window.headerbar.search.is_focus) { window.headerbar.search.activate_entry (e.str); handled = true; } - if((e.state & Gdk.ModifierType.CONTROL_MASK) != 0) { + if ((e.state & Gdk.ModifierType.CONTROL_MASK) != 0) { switch (e.keyval) { case Gdk.Key.f: window.headerbar.search.activate_entry (); diff --git a/src/Widgets/OverallView.vala b/src/Widgets/OverallView.vala index 2a4e530c..438f4208 100644 --- a/src/Widgets/OverallView.vala +++ b/src/Widgets/OverallView.vala @@ -1,4 +1,3 @@ - namespace Monitor { public class OverallView : Gtk.TreeView { @@ -11,10 +10,9 @@ namespace Monitor { const string NO_DATA = "\u2014"; - public OverallView (GenericModel model) { this.model = model; - regex = /(?i:^.*\.(xpm|png)$)/; + regex = /(?i:^.*\.(xpm|png)$)/; //vala-lint=space-before-paren // setup name column name_column = new Gtk.TreeViewColumn (); @@ -73,6 +71,7 @@ namespace Monitor { set_model (model); } + public void icon_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer icon_cell, Gtk.TreeModel model, Gtk.TreeIter iter) { Value icon_name; model.get_value (iter, Column.ICON, out icon_name); @@ -89,6 +88,7 @@ namespace Monitor { (icon_cell as Gtk.CellRendererPixbuf).icon_name = (string) icon_name; } } + public void cpu_usage_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter) { // grab the value that was store in the model and convert it down to a usable format Value cpu_usage_value; @@ -155,9 +155,9 @@ namespace Monitor { Gtk.TreeIter iter; Gtk.TreeModel model; int pid = 0; - var selection = this.get_selection ().get_selected_rows(out model).nth_data(0); - model.get_iter (out iter, selection); - model.get (iter, Column.PID, out pid); + var selection = this.get_selection ().get_selected_rows (out model).nth_data (0); + model.get_iter (out iter, selection); + model.get (iter, Column.PID, out pid); return pid; } @@ -165,14 +165,14 @@ namespace Monitor { public void expanded () { Gtk.TreeModel model; - var selection = this.get_selection ().get_selected_rows(out model).nth_data(0); - this.expand_row (selection, false); + var selection = this.get_selection ().get_selected_rows (out model).nth_data (0); + this.expand_row (selection, false); } public void collapse () { Gtk.TreeModel model; - var selection = this.get_selection ().get_selected_rows(out model).nth_data(0); - this.collapse_row (selection); + var selection = this.get_selection ().get_selected_rows (out model).nth_data (0); + this.collapse_row (selection); } public void kill_process () { diff --git a/src/Widgets/Search.vala b/src/Widgets/Search.vala index cf54fcb8..358e92b0 100644 --- a/src/Widgets/Search.vala +++ b/src/Widgets/Search.vala @@ -1,6 +1,6 @@ namespace Monitor { - public class Search : Gtk.SearchEntry { + public class Search : Gtk.SearchEntry { public MainWindow window { get; construct; } private Gtk.TreeModelFilter filter_model; private OverallView process_view; @@ -16,7 +16,7 @@ namespace Monitor { filter_model = new Gtk.TreeModelFilter (window.generic_model, null); connect_signal (); - filter_model.set_visible_func(filter_func); + filter_model.set_visible_func (filter_func); process_view.set_model (filter_model); var sort_model = new Gtk.TreeModelSort.with_model (filter_model); @@ -50,17 +50,17 @@ namespace Monitor { int pid_haystack; bool found = false; var needle = this.text; - if ( needle.length == 0 ) { + if (needle.length == 0) { return true; } - model.get( iter, Column.NAME, out name_haystack, -1 ); - model.get( iter, Column.PID, out pid_haystack, -1 ); + model.get (iter, Column.NAME, out name_haystack, -1); + model.get (iter, Column.PID, out pid_haystack, -1); // sometimes name_haystack is null if (name_haystack != null) { - bool name_found = name_haystack.casefold().contains(needle.casefold()) || false; - bool pid_found = pid_haystack.to_string().casefold().contains(needle.casefold()) || false; + bool name_found = name_haystack.casefold ().contains (needle.casefold ()) || false; + bool pid_found = pid_haystack.to_string ().casefold ().contains (needle.casefold ()) || false; found = name_found || pid_found; } diff --git a/src/Widgets/Statusbar/Statusbar.vala b/src/Widgets/Statusbar/Statusbar.vala index 1f35151d..f8084306 100644 --- a/src/Widgets/Statusbar/Statusbar.vala +++ b/src/Widgets/Statusbar/Statusbar.vala @@ -6,7 +6,7 @@ public class Monitor.Statusbar : Gtk.ActionBar { construct { var cpu_icon = new Gtk.Image.from_icon_name ("cpu-symbolic", Gtk.IconSize.SMALL_TOOLBAR); cpu_icon.tooltip_text = _ ("CPU"); - + var ram_icon = new Gtk.Image.from_icon_name ("ram-symbolic", Gtk.IconSize.SMALL_TOOLBAR); ram_icon.tooltip_text = _ ("Memory"); From a2ac789f5ad38ef47cf8d3163143bb3b2925fe49 Mon Sep 17 00:00:00 2001 From: stsdc Date: Fri, 27 Dec 2019 01:54:24 +0100 Subject: [PATCH 02/96] WIP: show only processes --- meson.build | 2 + src/MainWindow.vala | 10 +- src/Managers/Process.vala | 2 + src/Managers/ProcessManager.vala | 4 +- src/Models/GenericModel.vala | 10 +- src/Models/Model.vala | 219 ++++++++++++++++++++++++++++ src/Models/ModelHelper.vala | 2 +- src/Widgets/CPUProcessTreeView.vala | 121 +++++++++++++++ src/Widgets/Search.vala | 2 +- 9 files changed, 358 insertions(+), 14 deletions(-) create mode 100644 src/Models/Model.vala create mode 100644 src/Widgets/CPUProcessTreeView.vala diff --git a/meson.build b/meson.build index ce056adc..455fed97 100644 --- a/meson.build +++ b/meson.build @@ -51,11 +51,13 @@ executable( 'src/Utils.vala', 'src/Widgets/OverallView.vala', + 'src/Widgets/CPUProcessTreeView.vala', 'src/Widgets/Search.vala', 'src/Widgets/Headerbar.vala', 'src/Widgets/Statusbar/Statusbar.vala', 'src/Models/GenericModel.vala', + 'src/Models/Model.vala', 'src/Models/ModelHelper.vala', 'src/Managers/AppManager.vala', diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 624f6c2b..930f83b4 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -6,10 +6,12 @@ public Headerbar headerbar; // private Gtk.Button process_info_button; private Gtk.ScrolledWindow process_view_window; - public OverallView process_view; + + public CPUProcessTreeView process_view; + private Statusbar statusbar; - public GenericModel generic_model; + public Model generic_model; public Gtk.TreeModelSort sort_model; public Gtk.TreeModelFilter filter; @@ -42,8 +44,8 @@ // add a process view process_view_window = new Gtk.ScrolledWindow (null, null); - generic_model = new GenericModel (); - process_view = new OverallView (generic_model); + generic_model = new Model (); + process_view = new CPUProcessTreeView (generic_model); headerbar = new Headerbar (this); set_titlebar (headerbar); diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index 3a0bb76e..43642cf7 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -102,6 +102,8 @@ namespace Monitor { ppid = uid.ppid; // pid of parent process pgrp = uid.pgrp; // process group id + // debug("%d is a child of %d", pid, ppid); + // Get CPU usage by process GTop.ProcTime proc_time; diff --git a/src/Managers/ProcessManager.vala b/src/Managers/ProcessManager.vala index 3743728d..1cdb0a1a 100644 --- a/src/Managers/ProcessManager.vala +++ b/src/Managers/ProcessManager.vala @@ -14,7 +14,7 @@ namespace Monitor { uint64[] cpu_last_useds = new uint64[32]; uint64[] cpu_last_totals = new uint64[32]; - private Gee.HashMap process_list; + private Gee.TreeMap process_list; private Gee.HashSet kernel_process_blacklist; public signal void process_added (Process process); @@ -23,7 +23,7 @@ namespace Monitor { // Construct a new ProcessManager public ProcessManager () { - process_list = new Gee.HashMap (); + process_list = new Gee.TreeMap (); kernel_process_blacklist = new Gee.HashSet (); update_processes.begin (); diff --git a/src/Models/GenericModel.vala b/src/Models/GenericModel.vala index 65a40297..33cf46e3 100644 --- a/src/Models/GenericModel.vala +++ b/src/Models/GenericModel.vala @@ -8,19 +8,17 @@ namespace Monitor { private Gee.Map process_rows; private Gtk.TreeIter background_apps_iter; public Gtk.TreeStore model { get; private set; } - private Type[] types; construct { app_rows = new Gee.HashMap (); process_rows = new Gee.HashMap (); - types = new Type[] { + set_column_types(new Type[] { typeof (string), typeof (string), typeof (double), typeof (int64), typeof (int), - }; - set_column_types(types); + }); helper = new ModelHelper(this); @@ -184,7 +182,7 @@ namespace Monitor { var row = process_rows.get (pid); Gtk.TreeIter iter = row.iter; - debug ("remove process: user_data %d, stamp %d", (int) iter.user_data, iter.stamp); + // debug ("remove process: user_data %d, stamp %d", (int) iter.user_data, iter.stamp); Value pid_value; get_value (iter, Column.PID, out pid_value); @@ -293,7 +291,7 @@ namespace Monitor { private void add_background_apps_row () { append (out background_apps_iter, null); - helper.set_static_columns (background_apps_iter, "system-run", _("Background Applications")); + helper.set_static_columns (background_apps_iter, "system-run", _("Background Applications"), 0); } public void kill_process (int pid) { diff --git a/src/Models/Model.vala b/src/Models/Model.vala new file mode 100644 index 00000000..5666ca5b --- /dev/null +++ b/src/Models/Model.vala @@ -0,0 +1,219 @@ +public class Monitor.Model : Gtk.TreeStore { + ModelHelper helper; + private ProcessManager process_manager; + private Gee.Map process_rows; + + Gtk.TreeIter main_iter; + + construct { + + process_rows = new Gee.HashMap (); + + set_column_types (new Type[] { + typeof (string), + typeof (string), + typeof (double), + typeof (int64), + typeof (int), + }); + + helper = new ModelHelper (this); + + process_manager = ProcessManager.get_default (); + process_manager.process_added.connect ((process) => add_process (process)); + process_manager.process_removed.connect ((pid) => remove_process (pid)); + process_manager.updated.connect (update_model); + + Idle.add (() => { add_running_processes (); return false; }); + + } + + private void add_running_processes () { + debug ("add_running_processes"); + var running_processes = process_manager.get_process_list (); + foreach (var process in running_processes.values) { + add_process (process); + } + } + + private bool add_process (Process process) { + if (process_rows.has_key (process.pid)) { + // process already in process rows, no need to add + debug ("Process %d already in model", process.pid); + return false; + } + + if (process != null && process.pid != 1) { + debug ("Add process %d Parent PID: %d", process.pid, process.ppid); + + if (process.ppid > 1) { + // is a sub process of something + if (process_rows.has_key (process.ppid)) { + // is a subprocess of something in the rows + add_process_to_row (process_rows[process.ppid].iter, process.pid); + } else { + add_process_to_row (null, process.pid); + debug ("Is a subprocess of something but has no parent"); + } + // if parent not in yet, then child will be added in after + } else { + // isn't a subprocess of anything, put it into background processes + // it can be moved afterwards to an application + add_process_to_row (null, process.pid); + } + + return true; + } + + return false; + } + + private void update_model () { + foreach (int pid in process_rows.keys) { + update_process (pid); + } + } + + private void update_process (int pid) { + var process = process_manager.get_process (pid); + + if (process_rows.has_key (pid) && process != null) { + Gtk.TreeIter process_iter = process_rows[pid].iter; + helper.set_dynamic_columns (process_iter, process.cpu_usage, process.mem_usage); + } + } + + + private void get_children_total (Gtk.TreeIter iter, ref int64 memory, ref double cpu) { + // go through all children and add up CPU/Memory usage + // TODO: this is a naive way to do things + Gtk.TreeIter child_iter; + + if (iter_children (out child_iter, iter)) { + do { + get_children_total (child_iter, ref memory, ref cpu); + Value cpu_value; + Value memory_value; + get_value (child_iter, Column.CPU, out cpu_value); + get_value (child_iter, Column.MEMORY, out memory_value); + memory += memory_value.get_int64 (); + cpu += cpu_value.get_double (); + } while (iter_next (ref child_iter)); + } + } + + + // THE BUG IS SOMEWHERE IN HERE + // reparent children to background processes + private void reparent (ref Gtk.TreeIter iter) { + Gtk.TreeIter child_iter; + Value pid_value_prev; + + while (iter_children (out child_iter, iter)) { + Value pid_value; + get_value (child_iter, Column.PID, out pid_value); + pid_value_prev = pid_value; + debug ("reparent %d", pid_value.get_int ()); + var iter2 = Gtk.TreeIter (); + add_process_to_row (iter2, pid_value.get_int ()); + } + } + + private void remove_process (int pid) { + debug ("remove process %d from model".printf (pid)); + // if process rows has pid + if (process_rows.has_key (pid)) { + var row = process_rows.get (pid); + Gtk.TreeIter iter = row.iter; + + // debug ("remove process: user_data %d, stamp %d", (int) iter.user_data, iter.stamp); + + Value pid_value; + get_value (iter, Column.PID, out pid_value); + + // Column.NAME, for example returns (null) + // Column.PID return 0 + + debug ("removing %d", pid_value.get_int ()); + + // sometimes iter has null values + // this potentially should prevent segfaults + if (pid_value.get_int () != 0) { + reparent (ref iter); + // remove row from model + remove (ref iter); + } + + // remove row from row cache + process_rows.unset (pid); + } + } + + + + // Addes a process to an existing row; + // reparenting it and it's children if it already exists. + private bool add_process_to_row (Gtk.TreeIter ? row, int pid) { + var process = process_manager.get_process (pid); + debug ("add_process_to_row pid:%d", pid); + + if (process != null) { + // if process is already in list, then we need to reparent it and it's children + // can't remove it now because we need to remove all of the children first. + Gtk.TreeIter ? old_location = null; + if (process_rows.has_key (pid)) { + old_location = process_rows[pid].iter; + } + + // add the process to the model + Gtk.TreeIter iter; + append (out iter, row); + + helper.set_static_columns (iter, "application-x-executable", process.command, process.pid); + + helper.set_dynamic_columns (iter, process.cpu_usage, process.mem_usage); + + // add the process to our cache of process_rows + var process_row = new ApplicationProcessRow (iter); + process_rows.set (pid, process_row); + + // add all subprocesses to this row, recursively + var sub_processes = process_manager.get_sub_processes (pid); + foreach (var sub_pid in sub_processes) { + // only add subprocesses that either arn't in yet or are parented to the old location + // i.e. skip if subprocess is already in but isn't an ancestor of this process row + if (process_rows.has_key (sub_pid) && ( + (old_location != null && !is_ancestor (old_location, process_rows[sub_pid].iter)) + || old_location == null)) { + continue; + } + add_process_to_row (iter, sub_pid); + } + + // remove old row where the process used to be + if (old_location != null) { + remove (ref old_location); + } + + return true; + } + + return false; + } + + public void kill_process (int pid) { + if (pid > 0) { + var process = process_manager.get_process (pid); + process.kill (); + info ("Kill:%d",process.pid); + } + } + + public void end_process (int pid) { + if (pid > 0) { + var process = process_manager.get_process (pid); + process.end (); + info ("End:%d",process.pid); + } + } +} diff --git a/src/Models/ModelHelper.vala b/src/Models/ModelHelper.vala index 6c1d700c..e472403b 100644 --- a/src/Models/ModelHelper.vala +++ b/src/Models/ModelHelper.vala @@ -19,7 +19,7 @@ namespace Monitor { public ModelHelper (Gtk.TreeStore model) { this.model = model; } - public void set_static_columns (Gtk.TreeIter iter, string icon, string name, int pid=0) { + public void set_static_columns (Gtk.TreeIter iter, string icon, string name, int pid) { model.set (iter, Column.NAME, name, Column.ICON, icon, diff --git a/src/Widgets/CPUProcessTreeView.vala b/src/Widgets/CPUProcessTreeView.vala new file mode 100644 index 00000000..247500a3 --- /dev/null +++ b/src/Widgets/CPUProcessTreeView.vala @@ -0,0 +1,121 @@ +public class Monitor.CPUProcessTreeView : Gtk.TreeView { + private new Model model; + private Gtk.TreeViewColumn name_column; + private Gtk.TreeViewColumn pid_column; + private Regex? regex; + + const string NO_DATA = "\u2014"; + + + public CPUProcessTreeView (Model model) { + this.model = model; + regex = /(?i:^.*\.(xpm|png)$)/; + + // setup name column + name_column = new Gtk.TreeViewColumn (); + name_column.title = _("Process Name"); + name_column.expand = true; + name_column.min_width = 250; + name_column.set_sort_column_id (Column.NAME); + + var icon_cell = new Gtk.CellRendererPixbuf (); + name_column.pack_start (icon_cell, false); + // name_column.add_attribute (icon_cell, "icon_name", Column.ICON); + name_column.set_cell_data_func (icon_cell, icon_cell_layout); + + var name_cell = new Gtk.CellRendererText (); + name_cell.ellipsize = Pango.EllipsizeMode.END; + name_cell.set_fixed_height_from_font (1); + name_column.pack_start (name_cell, false); + name_column.add_attribute (name_cell, "text", Column.NAME); + insert_column (name_column, -1); + + // setup PID column + var pid_cell = new Gtk.CellRendererText (); + pid_cell.xalign = 0.5f; + pid_column = new Gtk.TreeViewColumn.with_attributes (_("PID"), pid_cell); + pid_column.set_cell_data_func (pid_cell, pid_cell_layout); + pid_column.expand = false; + pid_column.alignment = 0.5f; + pid_column.set_sort_column_id (Column.PID); + pid_column.add_attribute (pid_cell, "text", Column.PID); + insert_column (pid_column, -1); + + // resize all of the columns + columns_autosize (); + + set_model (model); + } + public void icon_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer icon_cell, Gtk.TreeModel model, Gtk.TreeIter iter) { + Value icon_name; + model.get_value (iter, Column.ICON, out icon_name); + if (regex.match ((string) icon_name)) { + string path = ((string) icon_name); + + try { + Gdk.Pixbuf icon = new Gdk.Pixbuf.from_file_at_size (path, 16, -1); + (icon_cell as Gtk.CellRendererPixbuf).pixbuf = icon; + } catch (Error e) { + warning (e.message); + } + } else { + (icon_cell as Gtk.CellRendererPixbuf).icon_name = (string) icon_name; + } + } + + private void pid_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter) { + Value pid_value; + model.get_value (iter, Column.PID, out pid_value); + int pid = pid_value.get_int (); + // format the double into a string + if (pid == 0) { + (cell as Gtk.CellRendererText).text = NO_DATA; + } + } + + public void focus_on_first_row () { + Gtk.TreePath tree_path = new Gtk.TreePath.from_indices (0); + this.set_cursor (tree_path, null, false); + grab_focus (); + } + + public void focus_on_child_row () { + Gtk.TreePath tree_path = new Gtk.TreePath.from_indices (0, 0); + this.set_cursor (tree_path, null, false); + grab_focus (); + } + + public int get_pid_of_selected () { + Gtk.TreeIter iter; + Gtk.TreeModel model; + int pid = 0; + var selection = this.get_selection ().get_selected_rows(out model).nth_data(0); + model.get_iter (out iter, selection); + model.get (iter, Column.PID, out pid); + return pid; + } + + // How about GtkTreeSelection ? + + public void expanded () { + Gtk.TreeModel model; + var selection = this.get_selection ().get_selected_rows(out model).nth_data(0); + this.expand_row (selection, false); + } + + public void collapse () { + Gtk.TreeModel model; + var selection = this.get_selection ().get_selected_rows(out model).nth_data(0); + this.collapse_row (selection); + } + + public void kill_process () { + int pid = get_pid_of_selected (); + model.kill_process (pid); + } + + public void end_process () { + int pid = get_pid_of_selected (); + model.end_process (pid); + } +} diff --git a/src/Widgets/Search.vala b/src/Widgets/Search.vala index cf54fcb8..68fb170e 100644 --- a/src/Widgets/Search.vala +++ b/src/Widgets/Search.vala @@ -3,7 +3,7 @@ namespace Monitor { public class Search : Gtk.SearchEntry { public MainWindow window { get; construct; } private Gtk.TreeModelFilter filter_model; - private OverallView process_view; + private CPUProcessTreeView process_view; public Search (MainWindow window) { Object (window: window); From 557b1d5ff2330286b9d795dfdb1b75b3f6de6307 Mon Sep 17 00:00:00 2001 From: stsdc Date: Sun, 29 Dec 2019 23:36:57 +0100 Subject: [PATCH 03/96] drop nested list view --- meson.build | 10 +- src/MainWindow.vala | 1 + src/Models/GenericModel.vala | 314 ---------------------------- src/Models/Model.vala | 175 +++------------- src/Models/ModelHelper.vala | 37 ---- src/Widgets/CPUProcessTreeView.vala | 64 ++++++ src/Widgets/OverallView.vala | 189 ----------------- 7 files changed, 97 insertions(+), 693 deletions(-) delete mode 100644 src/Models/GenericModel.vala delete mode 100644 src/Models/ModelHelper.vala delete mode 100644 src/Widgets/OverallView.vala diff --git a/meson.build b/meson.build index 455fed97..7aadb97c 100644 --- a/meson.build +++ b/meson.build @@ -40,7 +40,9 @@ icons_gresource = gnome.compile_resources( c_args = [ '-include', 'config.h', '-DWNCK_I_KNOW_THIS_IS_UNSTABLE', - '-w' + '-w', + # '-g', + # '--save-temps' ] executable( @@ -50,15 +52,15 @@ executable( 'src/MainWindow.vala', 'src/Utils.vala', - 'src/Widgets/OverallView.vala', + # 'src/Widgets/OverallView.vala', 'src/Widgets/CPUProcessTreeView.vala', 'src/Widgets/Search.vala', 'src/Widgets/Headerbar.vala', 'src/Widgets/Statusbar/Statusbar.vala', - 'src/Models/GenericModel.vala', + # 'src/Models/GenericModel.vala', 'src/Models/Model.vala', - 'src/Models/ModelHelper.vala', + # 'src/Models/ModelHelper.vala', 'src/Managers/AppManager.vala', 'src/Managers/ProcessManager.vala', diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 930f83b4..bfeb019a 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -12,6 +12,7 @@ private Statusbar statusbar; public Model generic_model; + // public Model generic_model; public Gtk.TreeModelSort sort_model; public Gtk.TreeModelFilter filter; diff --git a/src/Models/GenericModel.vala b/src/Models/GenericModel.vala deleted file mode 100644 index 33cf46e3..00000000 --- a/src/Models/GenericModel.vala +++ /dev/null @@ -1,314 +0,0 @@ -namespace Monitor { - - public class GenericModel : Gtk.TreeStore { - ModelHelper helper; - private AppManager app_manager; - private ProcessManager process_manager; - private Gee.Map app_rows; - private Gee.Map process_rows; - private Gtk.TreeIter background_apps_iter; - public Gtk.TreeStore model { get; private set; } - construct { - app_rows = new Gee.HashMap (); - process_rows = new Gee.HashMap (); - - set_column_types(new Type[] { - typeof (string), - typeof (string), - typeof (double), - typeof (int64), - typeof (int), - }); - - helper = new ModelHelper(this); - - process_manager = ProcessManager.get_default (); - process_manager.process_added.connect ((process) => add_process (process)); - process_manager.process_removed.connect ((pid) => remove_process (pid)); - process_manager.updated.connect (update_model); - - app_manager = AppManager.get_default (); - app_manager.application_opened.connect ((app) => { add_app (app); }); - app_manager.application_closed.connect ((app) => { remove_app (app); }); - - Idle.add (() => { add_running_apps (); return false; } ); - Idle.add (() => { add_running_processes (); return false; } ); - - add_background_apps_row (); - } - - public GenericModel () { } - - private void add_running_apps () { - debug ("add_running_applications"); - // get all running applications and add them to the tree store - var running_applications = app_manager.get_running_applications (); - foreach (var app in running_applications) { - add_app (app); - } - } - - private void add_running_processes () { - debug ("add_running_processes"); - var running_processes = process_manager.get_process_list (); - foreach (var process in running_processes.values) { - add_process (process); - } - } - - private void update_model () { - foreach (int pid in process_rows.keys) { - update_process (pid); - } - - foreach (var desktop_file in app_rows.keys) { - update_app (desktop_file); - } - update_app_row (background_apps_iter); - } - - private void update_process (int pid) { - var process = process_manager.get_process (pid); - - if (process_rows.has_key (pid) && process != null) { - Gtk.TreeIter process_iter = process_rows[pid].iter; - helper.set_dynamic_columns (process_iter, process.cpu_usage, process.mem_usage); - } - } - - private void update_app (string desktop_file) { - if (!app_rows.has_key (desktop_file)) - return; - - var app_iter = app_rows[desktop_file].iter; - update_app_row (app_iter); - } - - private void update_app_row (Gtk.TreeIter iter) { - int64 total_mem = 0; - double total_cpu = 0; - get_children_total (iter, ref total_mem, ref total_cpu); - helper.set_dynamic_columns (iter, total_cpu, total_mem); - } - - private void get_children_total (Gtk.TreeIter iter, ref int64 memory, ref double cpu) { - // go through all children and add up CPU/Memory usage - // TODO: this is a naive way to do things - Gtk.TreeIter child_iter; - - if (iter_children (out child_iter, iter)) { - do { - get_children_total (child_iter, ref memory, ref cpu); - Value cpu_value; - Value memory_value; - get_value (child_iter, Column.CPU, out cpu_value); - get_value (child_iter, Column.MEMORY, out memory_value); - memory += memory_value.get_int64 (); - cpu += cpu_value.get_double (); - } while (iter_next (ref child_iter)); - } - } - - private void add_app (App app) { - if (app_rows.has_key (app.desktop_file)) { - // App already in application rows, no need to add - debug ("Skip App"); - return; - } - // add the application to the model - Gtk.TreeIter iter; - append (out iter, null); - helper.set_static_columns (iter, app.icon, app.name, app.pids[0]); - - // add the application to our cache of app_rows - var row = new ApplicationProcessRow (iter); - app_rows.set (app.desktop_file, row); - - // go through the windows of the application and add all of the pids - foreach (var pid in app.pids) { - debug ("Add App: %s %d", app.name, pid); - add_process_to_row (iter, pid); - } - update_app (app.desktop_file); - } - - private bool remove_app (App app) { - debug ("Remove App: %s", app.name); - - // check if desktop file is in our row cache - if (!app_rows.has_key (app.desktop_file)) { - return false; - } - var app_iter = app_rows[app.desktop_file].iter; - - // reparent children to background processes; let the ProcessManager take care of removing them - Gtk.TreeIter child_iter; - while (iter_children (out child_iter, app_iter)) { - Value pid_value; - get_value (child_iter, Column.PID, out pid_value); - debug ("Reparent Process to Background: %d", pid_value.get_int ()); - add_process_to_row (background_apps_iter, pid_value.get_int ()); - } - - // remove row from model - remove (ref app_iter); - - // remove row from row cache - app_rows.unset (app.desktop_file); - - return true; - } - - // THE BUG IS SOMEWHERE IN HERE - // reparent children to background processes - private void reparent (ref Gtk.TreeIter iter) { - Gtk.TreeIter child_iter; - Value pid_value_prev; - - while (iter_children (out child_iter, iter)) { - Value pid_value; - get_value (child_iter, Column.PID, out pid_value); - pid_value_prev = pid_value; - debug( "reparent %d", pid_value.get_int ()); - - add_process_to_row (background_apps_iter, pid_value.get_int ()); - } - } - - private void remove_process (int pid) { - debug ("remove process %d from model".printf(pid)); - // if process rows has pid - if (process_rows.has_key (pid)) { - var row = process_rows.get (pid); - Gtk.TreeIter iter = row.iter; - - // debug ("remove process: user_data %d, stamp %d", (int) iter.user_data, iter.stamp); - - Value pid_value; - get_value (iter, Column.PID, out pid_value); - - // Column.NAME, for example returns (null) - // Column.PID return 0 - - debug("removing %d", pid_value.get_int()); - - // sometimes iter has null values - // this potentially should prevent segfaults - if (pid_value.get_int() != 0) { - reparent (ref iter); - // remove row from model - remove (ref iter); - } - - // remove row from row cache - process_rows.unset (pid); - } - } - - private bool add_process (Process process) { - debug ("add_process %d to model", process.pid); - if (process_rows.has_key (process.pid)) { - // process already in process rows, no need to add - debug ("Skipping Add Process %d", process.pid); - return false; - } - - // var process = process_manager.get_process (pid); - - if (process != null && process.pid != 1) { - debug ("Parent PID: %d", process.ppid); - if (process.ppid > 1) { - // is a sub process of something - if (process_rows.has_key (process.ppid)) { - // is a subprocess of something in the rows - add_process_to_row (process_rows[process.ppid].iter, process.pid); - } else { - add_process_to_row (background_apps_iter, process.pid); - debug ("Is a subprocess of something but has no parent"); - } - // if parent not in yet, then child will be added in after - } else { - // isn't a subprocess of anything, put it into background processes - // it can be moved afterwards to an application - add_process_to_row (background_apps_iter, process.pid); - } - - return true; - } - - return false; - } - - // Addes a process to an existing row; - // reparenting it and it's children if it already exists. - private bool add_process_to_row (Gtk.TreeIter row, int pid) { - var process = process_manager.get_process (pid); - debug ("add_process_to_row pid:%d", pid); - - if (process != null) { - // if process is already in list, then we need to reparent it and it's children - // can't remove it now because we need to remove all of the children first. - Gtk.TreeIter? old_location = null; - if (process_rows.has_key (pid)) { - old_location = process_rows[pid].iter; - } - - // add the process to the model - Gtk.TreeIter iter; - append (out iter, row); - - helper.set_static_columns (iter, "application-x-executable", process.command, process.pid); - - helper.set_dynamic_columns (iter, process.cpu_usage, process.mem_usage); - - // add the process to our cache of process_rows - var process_row = new ApplicationProcessRow (iter); - process_rows.set (pid, process_row); - - // add all subprocesses to this row, recursively - var sub_processes = process_manager.get_sub_processes (pid); - foreach (var sub_pid in sub_processes) { - // only add subprocesses that either arn't in yet or are parented to the old location - // i.e. skip if subprocess is already in but isn't an ancestor of this process row - if (process_rows.has_key (sub_pid) && ( - (old_location != null && !is_ancestor (old_location, process_rows[sub_pid].iter)) - || old_location == null)) { - continue; - } - add_process_to_row (iter, sub_pid); - } - - // remove old row where the process used to be - if (old_location != null) { - remove (ref old_location); - } - - return true; - } - - return false; - } - - private void add_background_apps_row () { - append (out background_apps_iter, null); - helper.set_static_columns (background_apps_iter, "system-run", _("Background Applications"), 0); - } - - public void kill_process (int pid) { - if (pid > 0) { - var process = process_manager.get_process (pid); - process.kill (); - info ("Kill:%d",process.pid); - } - } - - public void end_process (int pid) { - if (pid > 0) { - var process = process_manager.get_process (pid); - process.end (); - info ("End:%d",process.pid); - } - } - } - -} diff --git a/src/Models/Model.vala b/src/Models/Model.vala index 5666ca5b..a4249592 100644 --- a/src/Models/Model.vala +++ b/src/Models/Model.vala @@ -1,13 +1,10 @@ public class Monitor.Model : Gtk.TreeStore { ModelHelper helper; private ProcessManager process_manager; - private Gee.Map process_rows; - - Gtk.TreeIter main_iter; + private Gee.Map process_rows; construct { - - process_rows = new Gee.HashMap (); + process_rows = new Gee.HashMap (); set_column_types (new Type[] { typeof (string), @@ -25,7 +22,6 @@ public class Monitor.Model : Gtk.TreeStore { process_manager.updated.connect (update_model); Idle.add (() => { add_running_processes (); return false; }); - } private void add_running_processes () { @@ -37,85 +33,38 @@ public class Monitor.Model : Gtk.TreeStore { } private bool add_process (Process process) { - if (process_rows.has_key (process.pid)) { - // process already in process rows, no need to add - debug ("Process %d already in model", process.pid); - return false; - } - - if (process != null && process.pid != 1) { + if (process != null && !process_rows.has_key (process.pid)) { debug ("Add process %d Parent PID: %d", process.pid, process.ppid); + // add the process to the model + Gtk.TreeIter iter; + append (out iter, null); // null means top-level - if (process.ppid > 1) { - // is a sub process of something - if (process_rows.has_key (process.ppid)) { - // is a subprocess of something in the rows - add_process_to_row (process_rows[process.ppid].iter, process.pid); - } else { - add_process_to_row (null, process.pid); - debug ("Is a subprocess of something but has no parent"); - } - // if parent not in yet, then child will be added in after - } else { - // isn't a subprocess of anything, put it into background processes - // it can be moved afterwards to an application - add_process_to_row (null, process.pid); - } + set (iter, + Column.NAME, process.command, + Column.ICON, "application-x-executable", + Column.PID, process.pid, + Column.CPU, process.cpu_usage, + Column.MEMORY, process.mem_usage, + -1); + // add the process to our cache of process_rows + process_rows.set (process.pid, iter); return true; } - return false; } private void update_model () { foreach (int pid in process_rows.keys) { - update_process (pid); - } - } - - private void update_process (int pid) { - var process = process_manager.get_process (pid); - - if (process_rows.has_key (pid) && process != null) { - Gtk.TreeIter process_iter = process_rows[pid].iter; - helper.set_dynamic_columns (process_iter, process.cpu_usage, process.mem_usage); - } - } - - - private void get_children_total (Gtk.TreeIter iter, ref int64 memory, ref double cpu) { - // go through all children and add up CPU/Memory usage - // TODO: this is a naive way to do things - Gtk.TreeIter child_iter; - - if (iter_children (out child_iter, iter)) { - do { - get_children_total (child_iter, ref memory, ref cpu); - Value cpu_value; - Value memory_value; - get_value (child_iter, Column.CPU, out cpu_value); - get_value (child_iter, Column.MEMORY, out memory_value); - memory += memory_value.get_int64 (); - cpu += cpu_value.get_double (); - } while (iter_next (ref child_iter)); - } - } - - - // THE BUG IS SOMEWHERE IN HERE - // reparent children to background processes - private void reparent (ref Gtk.TreeIter iter) { - Gtk.TreeIter child_iter; - Value pid_value_prev; - - while (iter_children (out child_iter, iter)) { - Value pid_value; - get_value (child_iter, Column.PID, out pid_value); - pid_value_prev = pid_value; - debug ("reparent %d", pid_value.get_int ()); - var iter2 = Gtk.TreeIter (); - add_process_to_row (iter2, pid_value.get_int ()); + Process process = process_manager.get_process (pid); + Gtk.TreeIter iter = process_rows[pid]; + set (iter, + Column.NAME, process.command, + Column.ICON, "application-x-executable", + Column.PID, process.pid, + Column.CPU, process.cpu_usage, + Column.MEMORY, process.mem_usage, + -1); } } @@ -123,84 +72,12 @@ public class Monitor.Model : Gtk.TreeStore { debug ("remove process %d from model".printf (pid)); // if process rows has pid if (process_rows.has_key (pid)) { - var row = process_rows.get (pid); - Gtk.TreeIter iter = row.iter; - - // debug ("remove process: user_data %d, stamp %d", (int) iter.user_data, iter.stamp); - - Value pid_value; - get_value (iter, Column.PID, out pid_value); - - // Column.NAME, for example returns (null) - // Column.PID return 0 - - debug ("removing %d", pid_value.get_int ()); - - // sometimes iter has null values - // this potentially should prevent segfaults - if (pid_value.get_int () != 0) { - reparent (ref iter); - // remove row from model - remove (ref iter); - } - - // remove row from row cache + var cached_iter = process_rows.get (pid); + remove (ref cached_iter); process_rows.unset (pid); } } - - - // Addes a process to an existing row; - // reparenting it and it's children if it already exists. - private bool add_process_to_row (Gtk.TreeIter ? row, int pid) { - var process = process_manager.get_process (pid); - debug ("add_process_to_row pid:%d", pid); - - if (process != null) { - // if process is already in list, then we need to reparent it and it's children - // can't remove it now because we need to remove all of the children first. - Gtk.TreeIter ? old_location = null; - if (process_rows.has_key (pid)) { - old_location = process_rows[pid].iter; - } - - // add the process to the model - Gtk.TreeIter iter; - append (out iter, row); - - helper.set_static_columns (iter, "application-x-executable", process.command, process.pid); - - helper.set_dynamic_columns (iter, process.cpu_usage, process.mem_usage); - - // add the process to our cache of process_rows - var process_row = new ApplicationProcessRow (iter); - process_rows.set (pid, process_row); - - // add all subprocesses to this row, recursively - var sub_processes = process_manager.get_sub_processes (pid); - foreach (var sub_pid in sub_processes) { - // only add subprocesses that either arn't in yet or are parented to the old location - // i.e. skip if subprocess is already in but isn't an ancestor of this process row - if (process_rows.has_key (sub_pid) && ( - (old_location != null && !is_ancestor (old_location, process_rows[sub_pid].iter)) - || old_location == null)) { - continue; - } - add_process_to_row (iter, sub_pid); - } - - // remove old row where the process used to be - if (old_location != null) { - remove (ref old_location); - } - - return true; - } - - return false; - } - public void kill_process (int pid) { if (pid > 0) { var process = process_manager.get_process (pid); diff --git a/src/Models/ModelHelper.vala b/src/Models/ModelHelper.vala deleted file mode 100644 index e472403b..00000000 --- a/src/Models/ModelHelper.vala +++ /dev/null @@ -1,37 +0,0 @@ -namespace Monitor { - - public enum Column { - ICON, - NAME, - CPU, - MEMORY, - PID, - } - - // can't use TreeIter in HashMap for some reason, wrap it in a class - public class ApplicationProcessRow { - public Gtk.TreeIter iter; - public ApplicationProcessRow (Gtk.TreeIter iter) { this.iter = iter; } - } - - public class ModelHelper { - private Gtk.TreeStore model; - - public ModelHelper (Gtk.TreeStore model) { this.model = model; } - - public void set_static_columns (Gtk.TreeIter iter, string icon, string name, int pid) { - model.set (iter, - Column.NAME, name, - Column.ICON, icon, - Column.PID, pid, - -1); - } - - public void set_dynamic_columns (Gtk.TreeIter iter, double cpu, uint64 mem) { - model.set (iter, - Column.CPU, cpu, - Column.MEMORY, mem, - -1); - } - } -} diff --git a/src/Widgets/CPUProcessTreeView.vala b/src/Widgets/CPUProcessTreeView.vala index 247500a3..c7649fe9 100644 --- a/src/Widgets/CPUProcessTreeView.vala +++ b/src/Widgets/CPUProcessTreeView.vala @@ -2,6 +2,8 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { private new Model model; private Gtk.TreeViewColumn name_column; private Gtk.TreeViewColumn pid_column; + private Gtk.TreeViewColumn cpu_column; + private Gtk.TreeViewColumn memory_column; private Regex? regex; const string NO_DATA = "\u2014"; @@ -30,6 +32,28 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { name_column.add_attribute (name_cell, "text", Column.NAME); insert_column (name_column, -1); + // setup cpu column + var cpu_cell = new Gtk.CellRendererText (); + cpu_cell.xalign = 0.5f; + + cpu_column = new Gtk.TreeViewColumn.with_attributes (_("CPU"), cpu_cell); + cpu_column.expand = false; + cpu_column.set_cell_data_func (cpu_cell, cpu_usage_cell_layout); + cpu_column.alignment = 0.5f; + cpu_column.set_sort_column_id (Column.CPU); + insert_column (cpu_column, -1); + + // setup memory column + var memory_cell = new Gtk.CellRendererText (); + memory_cell.xalign = 0.5f; + + memory_column = new Gtk.TreeViewColumn.with_attributes (_("Memory"), memory_cell); + memory_column.expand = false; + memory_column.set_cell_data_func (memory_cell, memory_usage_cell_layout); + memory_column.alignment = 0.5f; + memory_column.set_sort_column_id (Column.MEMORY); + insert_column (memory_column, -1); + // setup PID column var pid_cell = new Gtk.CellRendererText (); pid_cell.xalign = 0.5f; @@ -63,6 +87,46 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { } } + public void cpu_usage_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter) { + // grab the value that was store in the model and convert it down to a usable format + Value cpu_usage_value; + model.get_value (iter, Column.CPU, out cpu_usage_value); + double cpu_usage = cpu_usage_value.get_double (); + + // format the double into a string + if (cpu_usage < 0.0) + (cell as Gtk.CellRendererText).text = NO_DATA; + else + (cell as Gtk.CellRendererText).text = "%.0f%%".printf (cpu_usage * 100.0); + } + + public void memory_usage_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter) { + // grab the value that was store in the model and convert it down to a usable format + Value memory_usage_value; + model.get_value (iter, Column.MEMORY, out memory_usage_value); + int64 memory_usage = memory_usage_value.get_int64 (); + double memory_usage_double = (double) memory_usage; + string units = _("KiB"); + + // convert to MiB if needed + if (memory_usage_double > 1024.0) { + memory_usage_double /= 1024.0; + units = _("MiB"); + } + + // convert to GiB if needed + if (memory_usage_double > 1024.0) { + memory_usage_double /= 1024.0; + units = _("GiB"); + } + + // format the double into a string + if (memory_usage == 0) + (cell as Gtk.CellRendererText).text = NO_DATA; + else + (cell as Gtk.CellRendererText).text = "%.1f %s".printf (memory_usage_double, units); + } + private void pid_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter) { Value pid_value; model.get_value (iter, Column.PID, out pid_value); diff --git a/src/Widgets/OverallView.vala b/src/Widgets/OverallView.vala deleted file mode 100644 index 2a4e530c..00000000 --- a/src/Widgets/OverallView.vala +++ /dev/null @@ -1,189 +0,0 @@ - -namespace Monitor { - - public class OverallView : Gtk.TreeView { - private new GenericModel model; - private Gtk.TreeViewColumn name_column; - private Gtk.TreeViewColumn cpu_column; - private Gtk.TreeViewColumn memory_column; - private Gtk.TreeViewColumn pid_column; - private Regex? regex; - - const string NO_DATA = "\u2014"; - - - public OverallView (GenericModel model) { - this.model = model; - regex = /(?i:^.*\.(xpm|png)$)/; - - // setup name column - name_column = new Gtk.TreeViewColumn (); - name_column.title = _("Process Name"); - name_column.expand = true; - name_column.min_width = 250; - name_column.set_sort_column_id (Column.NAME); - - var icon_cell = new Gtk.CellRendererPixbuf (); - name_column.pack_start (icon_cell, false); - // name_column.add_attribute (icon_cell, "icon_name", Column.ICON); - name_column.set_cell_data_func (icon_cell, icon_cell_layout); - - var name_cell = new Gtk.CellRendererText (); - name_cell.ellipsize = Pango.EllipsizeMode.END; - name_cell.set_fixed_height_from_font (1); - name_column.pack_start (name_cell, false); - name_column.add_attribute (name_cell, "text", Column.NAME); - insert_column (name_column, -1); - - // setup cpu column - var cpu_cell = new Gtk.CellRendererText (); - cpu_cell.xalign = 0.5f; - - cpu_column = new Gtk.TreeViewColumn.with_attributes (_("CPU"), cpu_cell); - cpu_column.expand = false; - cpu_column.set_cell_data_func (cpu_cell, cpu_usage_cell_layout); - cpu_column.alignment = 0.5f; - cpu_column.set_sort_column_id (Column.CPU); - insert_column (cpu_column, -1); - - // setup memory column - var memory_cell = new Gtk.CellRendererText (); - memory_cell.xalign = 0.5f; - - memory_column = new Gtk.TreeViewColumn.with_attributes (_("Memory"), memory_cell); - memory_column.expand = false; - memory_column.set_cell_data_func (memory_cell, memory_usage_cell_layout); - memory_column.alignment = 0.5f; - memory_column.set_sort_column_id (Column.MEMORY); - insert_column (memory_column, -1); - - // setup PID column - var pid_cell = new Gtk.CellRendererText (); - pid_cell.xalign = 0.5f; - pid_column = new Gtk.TreeViewColumn.with_attributes (_("PID"), pid_cell); - pid_column.set_cell_data_func (pid_cell, pid_cell_layout); - pid_column.expand = false; - pid_column.alignment = 0.5f; - pid_column.set_sort_column_id (Column.PID); - pid_column.add_attribute (pid_cell, "text", Column.PID); - insert_column (pid_column, -1); - - // resize all of the columns - columns_autosize (); - - set_model (model); - } - public void icon_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer icon_cell, Gtk.TreeModel model, Gtk.TreeIter iter) { - Value icon_name; - model.get_value (iter, Column.ICON, out icon_name); - if (regex.match ((string) icon_name)) { - string path = ((string) icon_name); - - try { - Gdk.Pixbuf icon = new Gdk.Pixbuf.from_file_at_size (path, 16, -1); - (icon_cell as Gtk.CellRendererPixbuf).pixbuf = icon; - } catch (Error e) { - warning (e.message); - } - } else { - (icon_cell as Gtk.CellRendererPixbuf).icon_name = (string) icon_name; - } - } - public void cpu_usage_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter) { - // grab the value that was store in the model and convert it down to a usable format - Value cpu_usage_value; - model.get_value (iter, Column.CPU, out cpu_usage_value); - double cpu_usage = cpu_usage_value.get_double (); - - // format the double into a string - if (cpu_usage < 0.0) - (cell as Gtk.CellRendererText).text = NO_DATA; - else - (cell as Gtk.CellRendererText).text = "%.0f%%".printf (cpu_usage * 100.0); - } - - public void memory_usage_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter) { - // grab the value that was store in the model and convert it down to a usable format - Value memory_usage_value; - model.get_value (iter, Column.MEMORY, out memory_usage_value); - int64 memory_usage = memory_usage_value.get_int64 (); - double memory_usage_double = (double) memory_usage; - string units = _("KiB"); - - // convert to MiB if needed - if (memory_usage_double > 1024.0) { - memory_usage_double /= 1024.0; - units = _("MiB"); - } - - // convert to GiB if needed - if (memory_usage_double > 1024.0) { - memory_usage_double /= 1024.0; - units = _("GiB"); - } - - // format the double into a string - if (memory_usage == 0) - (cell as Gtk.CellRendererText).text = NO_DATA; - else - (cell as Gtk.CellRendererText).text = "%.1f %s".printf (memory_usage_double, units); - } - - private void pid_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter) { - Value pid_value; - model.get_value (iter, Column.PID, out pid_value); - int pid = pid_value.get_int (); - // format the double into a string - if (pid == 0) { - (cell as Gtk.CellRendererText).text = NO_DATA; - } - } - - public void focus_on_first_row () { - Gtk.TreePath tree_path = new Gtk.TreePath.from_indices (0); - this.set_cursor (tree_path, null, false); - grab_focus (); - } - - public void focus_on_child_row () { - Gtk.TreePath tree_path = new Gtk.TreePath.from_indices (0, 0); - this.set_cursor (tree_path, null, false); - grab_focus (); - } - - public int get_pid_of_selected () { - Gtk.TreeIter iter; - Gtk.TreeModel model; - int pid = 0; - var selection = this.get_selection ().get_selected_rows(out model).nth_data(0); - model.get_iter (out iter, selection); - model.get (iter, Column.PID, out pid); - return pid; - } - - // How about GtkTreeSelection ? - - public void expanded () { - Gtk.TreeModel model; - var selection = this.get_selection ().get_selected_rows(out model).nth_data(0); - this.expand_row (selection, false); - } - - public void collapse () { - Gtk.TreeModel model; - var selection = this.get_selection ().get_selected_rows(out model).nth_data(0); - this.collapse_row (selection); - } - - public void kill_process () { - int pid = get_pid_of_selected (); - model.kill_process (pid); - } - - public void end_process () { - int pid = get_pid_of_selected (); - model.end_process (pid); - } - - } -} From 6a2d43b65b160a1cc22bc020f9fec93dd2793edc Mon Sep 17 00:00:00 2001 From: stsdc Date: Sun, 5 Jan 2020 00:54:49 +0100 Subject: [PATCH 04/96] remove helper --- src/Models/Model.vala | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Models/Model.vala b/src/Models/Model.vala index a4249592..c7c83ed8 100644 --- a/src/Models/Model.vala +++ b/src/Models/Model.vala @@ -1,5 +1,12 @@ +public enum Monitor.Column { + ICON, + NAME, + CPU, + MEMORY, + PID, +} + public class Monitor.Model : Gtk.TreeStore { - ModelHelper helper; private ProcessManager process_manager; private Gee.Map process_rows; @@ -14,8 +21,6 @@ public class Monitor.Model : Gtk.TreeStore { typeof (int), }); - helper = new ModelHelper (this); - process_manager = ProcessManager.get_default (); process_manager.process_added.connect ((process) => add_process (process)); process_manager.process_removed.connect ((pid) => remove_process (pid)); From 33b04505b2945361c60d57f5eee8ea4bd93597bf Mon Sep 17 00:00:00 2001 From: stsdc Date: Sun, 5 Jan 2020 00:54:55 +0100 Subject: [PATCH 05/96] read io data --- src/Managers/Process.vala | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index 43642cf7..713c44b1 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -24,6 +24,13 @@ namespace Monitor { // Full command from cmdline file public string command { get; private set; } + // Attempt to count the number of bytes which this process + // really did cause to be fetched from the storage layer + // http://man7.org/linux/man-pages/man5/proc.5.html + public uint64 read_bytes { get; private set; } + + public Gee.Map io_data { get; private set; } + /** * CPU usage of this process from the last time that it was updated, measured in percent * @@ -45,6 +52,8 @@ namespace Monitor { pid = _pid; last_total = 0; + io_data = new Gee.HashMap (); + exists = read_stat (0, 1) && read_cmdline (); } @@ -52,6 +61,7 @@ namespace Monitor { // Returns if the update was successful public bool update (uint64 cpu_total, uint64 cpu_last_total) { exists = read_stat (cpu_total, cpu_last_total); + parse_io(); return exists; } @@ -76,6 +86,29 @@ namespace Monitor { return false; } + private bool parse_io () { + var io_file = File.new_for_path ("/proc/%d/io".printf (pid)); + + if (!io_file.query_exists ()) { + return false; + } + + try { + var dis = new DataInputStream (io_file.read ()); + string? line; + + while ((line = dis.read_line ()) != null){ + var splitted_line = line.split (":"); + io_data.set(splitted_line[0], (uint64)splitted_line[1]); + } + + } catch (Error e) { + warning ("Can't read process io: '%s'", e.message); + return false; + } + return true; + } + // Reads the /proc/%pid%/stat file and updates the process with the information therein. private bool read_stat (uint64 cpu_total, uint64 cpu_last_total) { /* grab the stat file from /proc/%pid%/stat */ From 774bccac3bac93ac3ae87403af373ca58ff1498d Mon Sep 17 00:00:00 2001 From: stsdc Date: Sun, 5 Jan 2020 18:11:48 +0100 Subject: [PATCH 06/96] problem with struct --- meson.build | 1 + src/Managers/Process.vala | 61 +++++++++++++++++++++++++++----- src/Managers/ProcessStructs.vala | 0 3 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 src/Managers/ProcessStructs.vala diff --git a/meson.build b/meson.build index 7aadb97c..ef23bf68 100644 --- a/meson.build +++ b/meson.build @@ -65,6 +65,7 @@ executable( 'src/Managers/AppManager.vala', 'src/Managers/ProcessManager.vala', 'src/Managers/Process.vala', + 'src/Managers/ProcessStructs.vala', 'src/Services/Shortcuts.vala', 'src/Services/DBusServer.vala', diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index 713c44b1..6920b97e 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -2,7 +2,17 @@ namespace Monitor { - public class Process { + struct IO { + public uint64 rchar; + public uint64 wchar; + public uint64 syscr; + public uint64 syscw; + public uint64 read_bytes; + public uint64 write_bytes; + public uint64 cancelled_write_bytes; + } + + public class Process : GLib.Object { // The size of each RSS page, in bytes // private static long PAGESIZE = Posix.sysconf (Posix._SC_PAGESIZE); @@ -24,12 +34,12 @@ namespace Monitor { // Full command from cmdline file public string command { get; private set; } - // Attempt to count the number of bytes which this process - // really did cause to be fetched from the storage layer - // http://man7.org/linux/man-pages/man5/proc.5.html - public uint64 read_bytes { get; private set; } + // Attempt to count the number of bytes which this process + // really did cause to be fetched from the storage layer + // http://man7.org/linux/man-pages/man5/proc.5.html + // public uint64 read_bytes { get; private set; } + IO io { get; set; } - public Gee.Map io_data { get; private set; } /** * CPU usage of this process from the last time that it was updated, measured in percent @@ -52,11 +62,18 @@ namespace Monitor { pid = _pid; last_total = 0; - io_data = new Gee.HashMap (); + io = {}; + io.wchar = 111111; + debug((string)io.wchar); exists = read_stat (0, 1) && read_cmdline (); } + construct { + io = {}; + io.wchar = 111111; + debug((string)io.wchar); } + // Updates the process to get latest information // Returns if the update was successful public bool update (uint64 cpu_total, uint64 cpu_last_total) { @@ -99,7 +116,35 @@ namespace Monitor { while ((line = dis.read_line ()) != null){ var splitted_line = line.split (":"); - io_data.set(splitted_line[0], (uint64)splitted_line[1]); + switch (splitted_line[0]) { + case "wchar": + io.wchar = (uint64)splitted_line[1]; + // debug("wchar %s", splitted_line[1]); + // debug("wchar %s", (string)io.wchar); + break; + case "rchar": + io.rchar = (uint64)splitted_line[1]; + break; + case "syscr": + io.syscr = (uint64)splitted_line[1]; + break; + case "syscw": + io.syscw = (uint64)splitted_line[1]; + break; + case "read_bytes": + io.read_bytes = (uint64)splitted_line[1]; + break; + case "write_bytes": + io.write_bytes = (uint64)splitted_line[1]; + break; + case "cancelled_write_bytes": + io.cancelled_write_bytes = (uint64)splitted_line[1]; + break; + default: + warning ("Unknown value in /proc/%d/io", pid); + break; + } + } } catch (Error e) { diff --git a/src/Managers/ProcessStructs.vala b/src/Managers/ProcessStructs.vala new file mode 100644 index 00000000..e69de29b From d45b7698dfc9d31bf2eab411a5d5c8127fe1163d Mon Sep 17 00:00:00 2001 From: stsdc Date: Mon, 6 Jan 2020 21:24:05 +0100 Subject: [PATCH 07/96] saving io data to struct --- src/Managers/Process.vala | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index 6920b97e..2bd414e1 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -38,7 +38,7 @@ namespace Monitor { // really did cause to be fetched from the storage layer // http://man7.org/linux/man-pages/man5/proc.5.html // public uint64 read_bytes { get; private set; } - IO io { get; set; } + IO io; /** @@ -63,16 +63,10 @@ namespace Monitor { last_total = 0; io = {}; - io.wchar = 111111; - debug((string)io.wchar); exists = read_stat (0, 1) && read_cmdline (); } - construct { - io = {}; - io.wchar = 111111; - debug((string)io.wchar); } // Updates the process to get latest information // Returns if the update was successful @@ -119,8 +113,6 @@ namespace Monitor { switch (splitted_line[0]) { case "wchar": io.wchar = (uint64)splitted_line[1]; - // debug("wchar %s", splitted_line[1]); - // debug("wchar %s", (string)io.wchar); break; case "rchar": io.rchar = (uint64)splitted_line[1]; From 12f6f48faac1414bb3f00f1f87cb02283bbefc8d Mon Sep 17 00:00:00 2001 From: Mario Rodrigo Date: Tue, 7 Jan 2020 10:10:31 +0100 Subject: [PATCH 08/96] update spanish translations --- po/es.po | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/po/es.po b/po/es.po index 24795026..ce0e1604 100644 --- a/po/es.po +++ b/po/es.po @@ -55,11 +55,11 @@ msgstr "Terminar proceso" #: src/Widgets/Headerbar.vala:30 #, fuzzy msgid "Kill Process" -msgstr "" +msgstr "Matar proceso" #: src/Widgets/Headerbar.vala:32 msgid "Kill selected process" -msgstr "" +msgstr "Matar los procesos seleccionados" #: src/Widgets/Headerbar.vala:42 msgid "Settings" @@ -68,7 +68,7 @@ msgstr "Preferencias" #: src/Widgets/Headerbar.vala:56 #, fuzzy msgid "Show an indicator:" -msgstr "Mostrar icone de panel" +msgstr "Mostrar un icono en el panel" #: src/Widgets/Headerbar.vala:62 msgid "Start in background:" From 66853565d66174a10ddc720434ce0238779ae755 Mon Sep 17 00:00:00 2001 From: Mario Rodrigo Date: Tue, 7 Jan 2020 10:55:18 +0100 Subject: [PATCH 09/96] update spanish translations with suggested changes --- po/es.po | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/po/es.po b/po/es.po index ce0e1604..46610ccb 100644 --- a/po/es.po +++ b/po/es.po @@ -43,17 +43,14 @@ msgid "Monitor" msgstr "Monitor" #: src/Widgets/Headerbar.vala:23 -#, fuzzy msgid "End Process" msgstr "Terminar proceso" #: src/Widgets/Headerbar.vala:26 -#, fuzzy msgid "End selected process" msgstr "Terminar proceso" #: src/Widgets/Headerbar.vala:30 -#, fuzzy msgid "Kill Process" msgstr "Matar proceso" @@ -66,13 +63,12 @@ msgid "Settings" msgstr "Preferencias" #: src/Widgets/Headerbar.vala:56 -#, fuzzy msgid "Show an indicator:" -msgstr "Mostrar un icono en el panel" +msgstr "Mostrar un icono en el panel:" #: src/Widgets/Headerbar.vala:62 msgid "Start in background:" -msgstr "Arrancar en segundo plano" +msgstr "Arrancar en segundo plano:" #. setup name column #: src/Widgets/OverallView.vala:21 @@ -108,7 +104,6 @@ msgid "Search Process" msgstr "Buscar proceso" #: src/Widgets/Search.vala:15 -#, fuzzy msgid "Type process name or PID to search" msgstr "Introduce el nombre del proceso o el PID" From ab8950025bb2d715a2ab4ed45e8b8e9208203a9f Mon Sep 17 00:00:00 2001 From: stsdc Date: Wed, 8 Jan 2020 01:29:32 +0100 Subject: [PATCH 10/96] some refactoring --- src/Widgets/{ => Headerbar}/Headerbar.vala | 0 src/Widgets/{ => Headerbar}/Search.vala | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/Widgets/{ => Headerbar}/Headerbar.vala (100%) rename src/Widgets/{ => Headerbar}/Search.vala (100%) diff --git a/src/Widgets/Headerbar.vala b/src/Widgets/Headerbar/Headerbar.vala similarity index 100% rename from src/Widgets/Headerbar.vala rename to src/Widgets/Headerbar/Headerbar.vala diff --git a/src/Widgets/Search.vala b/src/Widgets/Headerbar/Search.vala similarity index 100% rename from src/Widgets/Search.vala rename to src/Widgets/Headerbar/Search.vala From d0e7819602b2d0a763ef8362e18b6786a1105844 Mon Sep 17 00:00:00 2001 From: stsdc Date: Wed, 8 Jan 2020 01:30:04 +0100 Subject: [PATCH 11/96] save process stat in stat struct --- meson.build | 4 +- src/Managers/Process.vala | 78 ++++++++++++++------------------ src/Managers/ProcessManager.vala | 8 ++-- src/Managers/ProcessStructs.vala | 68 ++++++++++++++++++++++++++++ src/Models/Model.vala | 14 +++--- 5 files changed, 115 insertions(+), 57 deletions(-) diff --git a/meson.build b/meson.build index ef23bf68..040e0684 100644 --- a/meson.build +++ b/meson.build @@ -54,8 +54,8 @@ executable( # 'src/Widgets/OverallView.vala', 'src/Widgets/CPUProcessTreeView.vala', - 'src/Widgets/Search.vala', - 'src/Widgets/Headerbar.vala', + 'src/Widgets/Headerbar/Search.vala', + 'src/Widgets/Headerbar/Headerbar.vala', 'src/Widgets/Statusbar/Statusbar.vala', # 'src/Models/GenericModel.vala', diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index 2bd414e1..ec94e5b7 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -2,16 +2,6 @@ namespace Monitor { - struct IO { - public uint64 rchar; - public uint64 wchar; - public uint64 syscr; - public uint64 syscw; - public uint64 read_bytes; - public uint64 write_bytes; - public uint64 cancelled_write_bytes; - } - public class Process : GLib.Object { // The size of each RSS page, in bytes // private static long PAGESIZE = Posix.sysconf (Posix._SC_PAGESIZE); @@ -19,26 +9,14 @@ namespace Monitor { // Whether or not the PID leads to something public bool exists { get; private set; } - // Process ID - public int pid { get; private set; } - - // Parent Process ID - public int ppid { get; private set; } - - // Process Group ID; 0 if a kernal process/thread - public int pgrp { get; private set; } - - // Command from stat file, truncated to 16 chars - public string comm { get; private set; } - // Full command from cmdline file public string command { get; private set; } - // Attempt to count the number of bytes which this process - // really did cause to be fetched from the storage layer - // http://man7.org/linux/man-pages/man5/proc.5.html - // public uint64 read_bytes { get; private set; } - IO io; + // Contains info about io + ProcessIO io; + + // Contains status info + public ProcessStatus stat; /** @@ -59,10 +37,13 @@ namespace Monitor { // Construct a new process public Process (int _pid) { - pid = _pid; + // pid = _pid; last_total = 0; io = {}; + stat = {}; + stat.pid = _pid; + exists = read_stat (0, 1) && read_cmdline (); } @@ -81,7 +62,7 @@ namespace Monitor { // Returns if kill was successful public bool kill () { // Sends a kill signal that cannot be ignored - if (Posix.kill (pid, Posix.Signal.KILL) == 0) { + if (Posix.kill (stat.pid, Posix.Signal.KILL) == 0) { return true; } return false; @@ -91,14 +72,14 @@ namespace Monitor { // Returns if end was successful public bool end () { // Sends a terminate signal - if (Posix.kill (pid, Posix.Signal.TERM) == 0) { + if (Posix.kill (stat.pid, Posix.Signal.TERM) == 0) { return true; } return false; } private bool parse_io () { - var io_file = File.new_for_path ("/proc/%d/io".printf (pid)); + var io_file = File.new_for_path ("/proc/%d/io".printf (stat.pid)); if (!io_file.query_exists ()) { return false; @@ -133,14 +114,19 @@ namespace Monitor { io.cancelled_write_bytes = (uint64)splitted_line[1]; break; default: - warning ("Unknown value in /proc/%d/io", pid); + warning ("Unknown value in /proc/%d/io", stat.pid); break; } } } catch (Error e) { - warning ("Can't read process io: '%s'", e.message); + if (e.code != 14) { + // if the error is not `no access to file`, because regular user + // TODO: remove `magic` number + + warning ("Can't read process io: '%s' %d", e.message, e.code); + } return false; } return true; @@ -149,7 +135,7 @@ namespace Monitor { // Reads the /proc/%pid%/stat file and updates the process with the information therein. private bool read_stat (uint64 cpu_total, uint64 cpu_last_total) { /* grab the stat file from /proc/%pid%/stat */ - var stat_file = File.new_for_path ("/proc/%d/stat".printf (pid)); + var stat_file = File.new_for_path ("/proc/%d/stat".printf (stat.pid)); /* make sure that it exists, not an error if it doesn't */ if (!stat_file.query_exists ()) { @@ -166,18 +152,22 @@ namespace Monitor { return false; } + /* split the contents into an array and parse each value that we care about */ + var splitted_stat = stat_contents.split (" "); + stat.comm = splitted_stat[1][1 : -1]; + stat.ppid = int.parse (splitted_stat[3]); + stat.pgrp = int.parse (splitted_stat[4]); + // Get process UID GTop.ProcUid uid; - GTop.get_proc_uid (out uid, pid); - ppid = uid.ppid; // pid of parent process - pgrp = uid.pgrp; // process group id - - // debug("%d is a child of %d", pid, ppid); + GTop.get_proc_uid (out uid, stat.pid); + // stat.ppid = uid.ppid; // pid of parent process + // stat.pgrp = uid.pgrp; // process group id // Get CPU usage by process GTop.ProcTime proc_time; - GTop.get_proc_time (out proc_time, pid); + GTop.get_proc_time (out proc_time, stat.pid); cpu_usage = ((double)(proc_time.rtime - cpu_last_used)) / (cpu_total - cpu_last_total); cpu_last_used = proc_time.rtime; @@ -186,11 +176,11 @@ namespace Monitor { GTop.get_mem (out mem); GTop.ProcMem proc_mem; - GTop.get_proc_mem (out proc_mem, pid); + GTop.get_proc_mem (out proc_mem, stat.pid); mem_usage = (proc_mem.resident - proc_mem.share) / 1024; // in KiB if (Gdk.Display.get_default () is Gdk.X11.Display) { - Wnck.ResourceUsage resu = Wnck.ResourceUsage.pid_read (Gdk.Display.get_default(), pid); + Wnck.ResourceUsage resu = Wnck.ResourceUsage.pid_read (Gdk.Display.get_default(), stat.pid); mem_usage += (resu.total_bytes_estimate / 1024); } } catch (Error e) { @@ -206,7 +196,7 @@ namespace Monitor { */ private bool read_cmdline () { // grab the cmdline file from /proc/%pid%/cmdline - var cmdline_file = File.new_for_path ("/proc/%d/cmdline".printf (pid)); + var cmdline_file = File.new_for_path ("/proc/%d/cmdline".printf (stat.pid)); // make sure that it exists if (!cmdline_file.query_exists ()) { @@ -236,7 +226,7 @@ namespace Monitor { //TODO: need to make sure that this works GTop.ProcState proc_state; - GTop.get_proc_state (out proc_state, pid); + GTop.get_proc_state (out proc_state, stat.pid); command = cmdline_contents; diff --git a/src/Managers/ProcessManager.vala b/src/Managers/ProcessManager.vala index 1cdb0a1a..d86e15c0 100644 --- a/src/Managers/ProcessManager.vala +++ b/src/Managers/ProcessManager.vala @@ -60,8 +60,8 @@ namespace Monitor { // go through and add all of the processes with PPID set to this one foreach (var process in process_list.values) { - if (process.ppid == pid) { - sub_processes.add (process.pid); + if (process.stat.ppid == pid) { + sub_processes.add (process.stat.pid); } } @@ -110,7 +110,7 @@ namespace Monitor { foreach (var process in process_list.values) { if (!process.update (cpu_data.total, cpu_last_total)) { /* process doesn't exist any more, flag it for removal! */ - remove_me.add (process.pid); + remove_me.add (process.stat.pid); } } @@ -151,7 +151,7 @@ namespace Monitor { var process = new Process (pid); if (process.exists) { - if (process.pgrp != 0) { + if (process.stat.pgrp != 0) { // regular process, add it to our cache process_list.set (pid, process); diff --git a/src/Managers/ProcessStructs.vala b/src/Managers/ProcessStructs.vala index e69de29b..4fc2adf6 100644 --- a/src/Managers/ProcessStructs.vala +++ b/src/Managers/ProcessStructs.vala @@ -0,0 +1,68 @@ +// For more info look at: http://man7.org/linux/man-pages/man5/proc.5.html + +struct Monitor.ProcessIO { + + // characters read + public uint64 rchar; + + // characters written + public uint64 wchar; + + // read syscalls + public uint64 syscr; + + // write syscalls + public uint64 syscw; + + // Attempt to count the number of bytes which this process + // really did cause to be fetched from the storage layer + public uint64 read_bytes; + + // Attempt to count the number of bytes which this process + // caused to be sent to the storage layer. + public uint64 write_bytes; + + public uint64 cancelled_write_bytes; +} + +public struct Monitor.ProcessStatus { + // process ID + public int pid; + + // The filename of the executable, in parentheses. + // This is visible whether or not the executable is + // swapped out. + public string comm; + + public char state; + + // The PID of the parent of this process. + public int ppid; + + // The process group ID of the process. + public int pgrp; + + // The session ID of the process. + public uint session; + + // The controlling terminal of the process. + // (The minor device number is contained in + // the combination of bits 31 to 20 and 7 to 0; + // the major device number is in bits 15 to 8.) + public uint tty_nr; + + // The ID of the foreground process group of the con‐ + // trolling terminal of the process. + public uint tpgid; + + // The nice value, a value in the + // range 19 (low priority) to -20 (high priority). + public int nice; + + // Number of threads in this process + public uint num_threads; + + // The time the process started after system boot. + public uint64 starttime; + +} \ No newline at end of file diff --git a/src/Models/Model.vala b/src/Models/Model.vala index c7c83ed8..c06841e1 100644 --- a/src/Models/Model.vala +++ b/src/Models/Model.vala @@ -38,8 +38,8 @@ public class Monitor.Model : Gtk.TreeStore { } private bool add_process (Process process) { - if (process != null && !process_rows.has_key (process.pid)) { - debug ("Add process %d Parent PID: %d", process.pid, process.ppid); + if (process != null && !process_rows.has_key (process.stat.pid)) { + debug ("Add process %d Parent PID: %d", process.stat.pid, process.stat.ppid); // add the process to the model Gtk.TreeIter iter; append (out iter, null); // null means top-level @@ -47,13 +47,13 @@ public class Monitor.Model : Gtk.TreeStore { set (iter, Column.NAME, process.command, Column.ICON, "application-x-executable", - Column.PID, process.pid, + Column.PID, process.stat.pid, Column.CPU, process.cpu_usage, Column.MEMORY, process.mem_usage, -1); // add the process to our cache of process_rows - process_rows.set (process.pid, iter); + process_rows.set (process.stat.pid, iter); return true; } return false; @@ -66,7 +66,7 @@ public class Monitor.Model : Gtk.TreeStore { set (iter, Column.NAME, process.command, Column.ICON, "application-x-executable", - Column.PID, process.pid, + Column.PID, process.stat.pid, Column.CPU, process.cpu_usage, Column.MEMORY, process.mem_usage, -1); @@ -87,7 +87,7 @@ public class Monitor.Model : Gtk.TreeStore { if (pid > 0) { var process = process_manager.get_process (pid); process.kill (); - info ("Kill:%d",process.pid); + info ("Kill:%d",process.stat.pid); } } @@ -95,7 +95,7 @@ public class Monitor.Model : Gtk.TreeStore { if (pid > 0) { var process = process_manager.get_process (pid); process.end (); - info ("End:%d",process.pid); + info ("End:%d",process.stat.pid); } } } From 1b3ef1b9f244a95e5b4601bf5849ddfdfadbcddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= Date: Fri, 10 Jan 2020 15:27:36 +0100 Subject: [PATCH 12/96] add paned view --- meson.build | 4 ++- src/MainWindow.vala | 14 +++++------ src/Monitor.vala | 2 +- src/Services/Shortcuts.vala | 10 ++++---- src/Widgets/Headerbar/Headerbar.vala | 4 +-- src/Widgets/Headerbar/Search.vala | 14 +++++------ .../{ => ProcessView}/CPUProcessTreeView.vala | 0 src/Widgets/ProcessView/ProcessInfoView.vala | 12 +++++++++ src/Widgets/ProcessView/ProcessView.vala | 25 +++++++++++++++++++ 9 files changed, 62 insertions(+), 23 deletions(-) rename src/Widgets/{ => ProcessView}/CPUProcessTreeView.vala (100%) create mode 100644 src/Widgets/ProcessView/ProcessInfoView.vala create mode 100644 src/Widgets/ProcessView/ProcessView.vala diff --git a/meson.build b/meson.build index 040e0684..e34afb59 100644 --- a/meson.build +++ b/meson.build @@ -53,10 +53,12 @@ executable( 'src/Utils.vala', # 'src/Widgets/OverallView.vala', - 'src/Widgets/CPUProcessTreeView.vala', + 'src/Widgets/ProcessView/CPUProcessTreeView.vala', 'src/Widgets/Headerbar/Search.vala', 'src/Widgets/Headerbar/Headerbar.vala', 'src/Widgets/Statusbar/Statusbar.vala', + 'src/Widgets/ProcessView/ProcessInfoView.vala', + 'src/Widgets/ProcessView/ProcessView.vala', # 'src/Models/GenericModel.vala', 'src/Models/Model.vala', diff --git a/src/MainWindow.vala b/src/MainWindow.vala index bfeb019a..d5728142 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -5,9 +5,11 @@ // Widgets public Headerbar headerbar; // private Gtk.Button process_info_button; - private Gtk.ScrolledWindow process_view_window; + private Gtk.ScrolledWindow process_tree_view_window; - public CPUProcessTreeView process_view; + public ProcessView process_view; + + public CPUProcessTreeView process_tree_view; private Statusbar statusbar; @@ -43,20 +45,18 @@ // TODO: Granite.Widgets.ModeButton to switch between view modes - // add a process view - process_view_window = new Gtk.ScrolledWindow (null, null); generic_model = new Model (); - process_view = new CPUProcessTreeView (generic_model); + process_tree_view = new CPUProcessTreeView (generic_model); headerbar = new Headerbar (this); set_titlebar (headerbar); - process_view_window.add (process_view); + process_view = new ProcessView (process_tree_view); statusbar = new Statusbar (); var main_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); - main_box.pack_start (process_view_window, true, true, 0); + main_box.pack_start (process_view, true, true, 0); main_box.pack_start (statusbar, false, true, 0); this.add (main_box); diff --git a/src/Monitor.vala b/src/Monitor.vala index 64f72390..213f42d7 100644 --- a/src/Monitor.vala +++ b/src/Monitor.vala @@ -49,7 +49,7 @@ namespace Monitor { window.show_all (); } - window.process_view.focus_on_first_row (); + window.process_tree_view.focus_on_first_row (); var quit_action = new SimpleAction ("quit", null); add_action (quit_action); diff --git a/src/Services/Shortcuts.vala b/src/Services/Shortcuts.vala index ec7323d9..c8d98a0a 100644 --- a/src/Services/Shortcuts.vala +++ b/src/Services/Shortcuts.vala @@ -22,11 +22,11 @@ namespace Monitor { handled = true; break; case Gdk.Key.e: - window.process_view.end_process (); + window.process_tree_view.end_process (); handled = true; break; case Gdk.Key.k: - window.process_view.kill_process (); + window.process_tree_view.kill_process (); handled = true; break; case Gdk.Key.comma: @@ -42,15 +42,15 @@ namespace Monitor { switch (e.keyval) { case Gdk.Key.Return: - window.process_view.focus_on_first_row (); + window.process_tree_view.focus_on_first_row (); handled = true; break; case Gdk.Key.Left: - window.process_view.collapse (); + window.process_tree_view.collapse (); handled = true; break; case Gdk.Key.Right: - window.process_view.expanded (); + window.process_tree_view.expanded (); handled = true; break; default: diff --git a/src/Widgets/Headerbar/Headerbar.vala b/src/Widgets/Headerbar/Headerbar.vala index 9204bffa..8792739b 100644 --- a/src/Widgets/Headerbar/Headerbar.vala +++ b/src/Widgets/Headerbar/Headerbar.vala @@ -22,13 +22,13 @@ namespace Monitor { end_process_button = new Gtk.Button.with_label (_("End Process")); end_process_button.margin_end = 10; - end_process_button.clicked.connect (window.process_view.end_process); + end_process_button.clicked.connect (window.process_tree_view.end_process); end_process_button.tooltip_markup = Granite.markup_accel_tooltip ({"E"}, _("End selected process")); var end_process_button_context = end_process_button.get_style_context (); end_process_button_context.add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); kill_process_button = new Gtk.Button.with_label (_("Kill Process")); - kill_process_button.clicked.connect (window.process_view.kill_process); + kill_process_button.clicked.connect (window.process_tree_view.kill_process); kill_process_button.tooltip_markup = Granite.markup_accel_tooltip ({"K"}, _("Kill selected process")); var kill_process_button_context = kill_process_button.get_style_context (); kill_process_button_context.add_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION); diff --git a/src/Widgets/Headerbar/Search.vala b/src/Widgets/Headerbar/Search.vala index 68fb170e..e1a1c5eb 100644 --- a/src/Widgets/Headerbar/Search.vala +++ b/src/Widgets/Headerbar/Search.vala @@ -3,31 +3,31 @@ namespace Monitor { public class Search : Gtk.SearchEntry { public MainWindow window { get; construct; } private Gtk.TreeModelFilter filter_model; - private CPUProcessTreeView process_view; + private CPUProcessTreeView process_tree_view; public Search (MainWindow window) { Object (window: window); } construct { - this.process_view = window.process_view; + this.process_tree_view = window.process_tree_view; this.placeholder_text = _("Search Process"); this.tooltip_markup = Granite.markup_accel_tooltip ({"F"}, _("Type process name or PID to search")); filter_model = new Gtk.TreeModelFilter (window.generic_model, null); connect_signal (); filter_model.set_visible_func(filter_func); - process_view.set_model (filter_model); + process_tree_view.set_model (filter_model); var sort_model = new Gtk.TreeModelSort.with_model (filter_model); - process_view.set_model (sort_model); + process_tree_view.set_model (sort_model); } private void connect_signal () { this.search_changed.connect (() => { // collapse tree only when search is focused and changed if (this.is_focus) { - process_view.collapse_all (); + process_tree_view.collapse_all (); } filter_model.refilter (); @@ -36,7 +36,7 @@ namespace Monitor { window.headerbar.set_header_buttons_sensitivity (filter_model.iter_n_children (null) != 0); // focus on child row to avoid the app crashes by clicking "Kill/End Process" buttons in headerbar - process_view.focus_on_child_row (); + process_tree_view.focus_on_child_row (); this.grab_focus (); if (this.text != "") { @@ -75,7 +75,7 @@ namespace Monitor { } if (child_found && needle.length > 0) { - process_view.expand_all (); + process_tree_view.expand_all (); } return found || child_found; diff --git a/src/Widgets/CPUProcessTreeView.vala b/src/Widgets/ProcessView/CPUProcessTreeView.vala similarity index 100% rename from src/Widgets/CPUProcessTreeView.vala rename to src/Widgets/ProcessView/CPUProcessTreeView.vala diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala new file mode 100644 index 00000000..852c2fb0 --- /dev/null +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -0,0 +1,12 @@ +public class Monitor.ProcessInfoView : Gtk.HBox { + // public Process process; + + public ProcessInfoView() { + // process = _process; + + var process_name = new Gtk.Label("some_process"); + + add (process_name); + + } +} \ No newline at end of file diff --git a/src/Widgets/ProcessView/ProcessView.vala b/src/Widgets/ProcessView/ProcessView.vala new file mode 100644 index 00000000..d7d5bad6 --- /dev/null +++ b/src/Widgets/ProcessView/ProcessView.vala @@ -0,0 +1,25 @@ +public class Monitor.ProcessView : Gtk.Box { + public CPUProcessTreeView process_tree_view; + public ProcessInfoView process_info_view; + + construct { + + process_info_view = new ProcessInfoView (); + + } + + public ProcessView(CPUProcessTreeView process_tree_view) { + + // making tree view scrollable + var process_tree_view_scrolled = new Gtk.ScrolledWindow (null, null); + process_tree_view_scrolled.add (process_tree_view); + + var paned = new Gtk.Paned (Gtk.Orientation.HORIZONTAL); + paned.pack1 (process_tree_view_scrolled, false, false); + paned.pack2 (process_info_view, false, false); + paned.set_position (500); + paned.set_hexpand (true); + + add (paned); + } +} \ No newline at end of file From bf6428df0a59e909b529398044932aea14c8b3e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= Date: Fri, 10 Jan 2020 17:30:56 +0100 Subject: [PATCH 13/96] updating Process info with pid --- src/MainWindow.vala | 6 +----- src/Models/Model.vala | 4 +++- src/Monitor.vala | 2 +- src/Services/Shortcuts.vala | 10 ++++----- src/Widgets/Headerbar/Headerbar.vala | 4 ++-- src/Widgets/Headerbar/Search.vala | 2 +- .../ProcessView/CPUProcessTreeView.vala | 21 +++++++++++++++++++ src/Widgets/ProcessView/ProcessInfoView.vala | 19 ++++++++++++----- src/Widgets/ProcessView/ProcessView.vala | 10 ++++++++- 9 files changed, 57 insertions(+), 21 deletions(-) diff --git a/src/MainWindow.vala b/src/MainWindow.vala index d5728142..a472674f 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -5,11 +5,9 @@ // Widgets public Headerbar headerbar; // private Gtk.Button process_info_button; - private Gtk.ScrolledWindow process_tree_view_window; public ProcessView process_view; - public CPUProcessTreeView process_tree_view; private Statusbar statusbar; @@ -46,13 +44,11 @@ // TODO: Granite.Widgets.ModeButton to switch between view modes generic_model = new Model (); - process_tree_view = new CPUProcessTreeView (generic_model); + process_view = new ProcessView (generic_model); headerbar = new Headerbar (this); set_titlebar (headerbar); - process_view = new ProcessView (process_tree_view); - statusbar = new Statusbar (); var main_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); diff --git a/src/Models/Model.vala b/src/Models/Model.vala index c06841e1..6d80824a 100644 --- a/src/Models/Model.vala +++ b/src/Models/Model.vala @@ -7,7 +7,7 @@ public enum Monitor.Column { } public class Monitor.Model : Gtk.TreeStore { - private ProcessManager process_manager; + public ProcessManager process_manager; private Gee.Map process_rows; construct { @@ -27,6 +27,8 @@ public class Monitor.Model : Gtk.TreeStore { process_manager.updated.connect (update_model); Idle.add (() => { add_running_processes (); return false; }); + + } private void add_running_processes () { diff --git a/src/Monitor.vala b/src/Monitor.vala index 213f42d7..b1dbe11e 100644 --- a/src/Monitor.vala +++ b/src/Monitor.vala @@ -49,7 +49,7 @@ namespace Monitor { window.show_all (); } - window.process_tree_view.focus_on_first_row (); + window.process_view.process_tree_view.focus_on_first_row (); var quit_action = new SimpleAction ("quit", null); add_action (quit_action); diff --git a/src/Services/Shortcuts.vala b/src/Services/Shortcuts.vala index c8d98a0a..b1ba504d 100644 --- a/src/Services/Shortcuts.vala +++ b/src/Services/Shortcuts.vala @@ -22,11 +22,11 @@ namespace Monitor { handled = true; break; case Gdk.Key.e: - window.process_tree_view.end_process (); + window.process_view.process_tree_view.end_process (); handled = true; break; case Gdk.Key.k: - window.process_tree_view.kill_process (); + window.process_view.process_tree_view.kill_process (); handled = true; break; case Gdk.Key.comma: @@ -42,15 +42,15 @@ namespace Monitor { switch (e.keyval) { case Gdk.Key.Return: - window.process_tree_view.focus_on_first_row (); + window.process_view.process_tree_view.focus_on_first_row (); handled = true; break; case Gdk.Key.Left: - window.process_tree_view.collapse (); + window.process_view.process_tree_view.collapse (); handled = true; break; case Gdk.Key.Right: - window.process_tree_view.expanded (); + window.process_view.process_tree_view.expanded (); handled = true; break; default: diff --git a/src/Widgets/Headerbar/Headerbar.vala b/src/Widgets/Headerbar/Headerbar.vala index 8792739b..e7fece06 100644 --- a/src/Widgets/Headerbar/Headerbar.vala +++ b/src/Widgets/Headerbar/Headerbar.vala @@ -22,13 +22,13 @@ namespace Monitor { end_process_button = new Gtk.Button.with_label (_("End Process")); end_process_button.margin_end = 10; - end_process_button.clicked.connect (window.process_tree_view.end_process); + end_process_button.clicked.connect (window.process_view.process_tree_view.end_process); end_process_button.tooltip_markup = Granite.markup_accel_tooltip ({"E"}, _("End selected process")); var end_process_button_context = end_process_button.get_style_context (); end_process_button_context.add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); kill_process_button = new Gtk.Button.with_label (_("Kill Process")); - kill_process_button.clicked.connect (window.process_tree_view.kill_process); + kill_process_button.clicked.connect (window.process_view.process_tree_view.kill_process); kill_process_button.tooltip_markup = Granite.markup_accel_tooltip ({"K"}, _("Kill selected process")); var kill_process_button_context = kill_process_button.get_style_context (); kill_process_button_context.add_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION); diff --git a/src/Widgets/Headerbar/Search.vala b/src/Widgets/Headerbar/Search.vala index e1a1c5eb..e1bb4574 100644 --- a/src/Widgets/Headerbar/Search.vala +++ b/src/Widgets/Headerbar/Search.vala @@ -10,7 +10,7 @@ namespace Monitor { } construct { - this.process_tree_view = window.process_tree_view; + this.process_tree_view = window.process_view.process_tree_view; this.placeholder_text = _("Search Process"); this.tooltip_markup = Granite.markup_accel_tooltip ({"F"}, _("Type process name or PID to search")); diff --git a/src/Widgets/ProcessView/CPUProcessTreeView.vala b/src/Widgets/ProcessView/CPUProcessTreeView.vala index c7649fe9..8639589a 100644 --- a/src/Widgets/ProcessView/CPUProcessTreeView.vala +++ b/src/Widgets/ProcessView/CPUProcessTreeView.vala @@ -8,6 +8,7 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { const string NO_DATA = "\u2014"; + public signal void update_selected_process (Process process); public CPUProcessTreeView (Model model) { this.model = model; @@ -69,6 +70,10 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { columns_autosize (); set_model (model); + + + cursor_changed.connect (_cursor_changed); + model.process_manager.updated.connect (_cursor_changed); } public void icon_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer icon_cell, Gtk.TreeModel model, Gtk.TreeIter iter) { Value icon_name; @@ -182,4 +187,20 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { int pid = get_pid_of_selected (); model.end_process (pid); } + + // when row is selected send signal to update process_info_view + public void _cursor_changed () { + Gtk.TreeModel tree_model; + Gtk.TreeIter iter; + int pid = 0; + var selection = get_selection ().get_selected_rows(out tree_model).nth_data(0); + + if (selection != null) { + tree_model.get_iter (out iter, selection); + tree_model.get (iter, Column.PID, out pid); + Process process = model.process_manager.get_process(pid); + update_selected_process (process); + } + + } } diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index 852c2fb0..96c2611b 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -1,12 +1,21 @@ public class Monitor.ProcessInfoView : Gtk.HBox { - // public Process process; + public Gtk.Label name; + public Gtk.Label command; + public Gtk.Label pid; public ProcessInfoView() { - // process = _process; - var process_name = new Gtk.Label("some_process"); + name = new Gtk.Label(_("N/A")); + command = new Gtk.Label(_("N/A")); + pid = new Gtk.Label(_("N/A")); - add (process_name); - + add (name); + add (command); + add (pid); + } + + public void update (Process process) { + pid.set_text (("%d").printf (process.stat.pid)); + debug ("yolo"); } } \ No newline at end of file diff --git a/src/Widgets/ProcessView/ProcessView.vala b/src/Widgets/ProcessView/ProcessView.vala index d7d5bad6..1f466f24 100644 --- a/src/Widgets/ProcessView/ProcessView.vala +++ b/src/Widgets/ProcessView/ProcessView.vala @@ -1,5 +1,6 @@ public class Monitor.ProcessView : Gtk.Box { public CPUProcessTreeView process_tree_view; + public ProcessInfoView process_info_view; construct { @@ -8,7 +9,10 @@ public class Monitor.ProcessView : Gtk.Box { } - public ProcessView(CPUProcessTreeView process_tree_view) { + public ProcessView (Model model) { + + process_tree_view = new CPUProcessTreeView (model); + process_tree_view.update_selected_process.connect ((process) => update (process)); // making tree view scrollable var process_tree_view_scrolled = new Gtk.ScrolledWindow (null, null); @@ -22,4 +26,8 @@ public class Monitor.ProcessView : Gtk.Box { add (paned); } + + public void update (Process process) { + process_info_view.update(process); + } } \ No newline at end of file From ecd5d6e58c070454acb06d56a62fca34b6479c58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= Date: Fri, 10 Jan 2020 18:27:10 +0100 Subject: [PATCH 14/96] layout in ProcessInfoView for icon and process name --- src/Widgets/ProcessView/ProcessInfoView.vala | 34 ++++++++++++++++---- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index 96c2611b..a3c74cc6 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -1,21 +1,41 @@ -public class Monitor.ProcessInfoView : Gtk.HBox { - public Gtk.Label name; +public class Monitor.ProcessInfoView : Gtk.Grid { + public Gtk.Label application_name; + public string ? icon_name; public Gtk.Label command; public Gtk.Label pid; + private Gtk.Grid grid; + public ProcessInfoView() { + margin = 12; + + var icon = new Gtk.Image.from_icon_name ("application-x-executable", Gtk.IconSize.DIALOG); + icon.valign = Gtk.Align.END; + + application_name = new Gtk.Label(_("N/A")); + application_name.get_style_context ().add_class ("h2"); - name = new Gtk.Label(_("N/A")); command = new Gtk.Label(_("N/A")); + command.halign = Gtk.Align.START; + pid = new Gtk.Label(_("N/A")); - add (name); - add (command); - add (pid); + // add (name); + // add (command); + // add (pid); + + grid = new Gtk.Grid (); + grid.get_style_context ().add_class ("horizontal"); + grid.column_spacing = 12; + + grid.attach (icon, 0, 0, 1, 2); + grid.attach (application_name, 1, 0, 1, 1); + grid.attach (command, 1, 1, 1, 1); + + add (grid); } public void update (Process process) { pid.set_text (("%d").printf (process.stat.pid)); - debug ("yolo"); } } \ No newline at end of file From 184106261e4773371edf8038f1b3614bcaeedab0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= Date: Fri, 10 Jan 2020 22:04:52 +0100 Subject: [PATCH 15/96] WIP: getting apps info --- src/Managers/ProcessManager.vala | 68 ++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/Managers/ProcessManager.vala b/src/Managers/ProcessManager.vala index d86e15c0..e015bd37 100644 --- a/src/Managers/ProcessManager.vala +++ b/src/Managers/ProcessManager.vala @@ -17,6 +17,9 @@ namespace Monitor { private Gee.TreeMap process_list; private Gee.HashSet kernel_process_blacklist; + private static HashTable? apps_info; + private static HashTable? appid_map; + public signal void process_added (Process process); public signal void process_removed (int pid); public signal void updated (); @@ -25,12 +28,77 @@ namespace Monitor { public ProcessManager () { process_list = new Gee.TreeMap (); kernel_process_blacklist = new Gee.HashSet (); + + apps_info = new HashTable (str_hash, str_equal); + populate_apps_info (); + update_processes.begin (); // move timeout outside Timeout.add (2000, handle_timeout); } + public static void populate_apps_info() { + apps_info = new HashTable (str_hash, str_equal); + appid_map = new HashTable (str_hash, str_equal); + + var _apps_info = AppInfo.get_all (); + + foreach (AppInfo info in _apps_info) { + debug ("%s\n", info.get_name ()); + // GLib.DesktopAppInfo? dai = info as GLib.DesktopAppInfo; + + // if (dai != null) { + // string id = dai.get_string ("X-Flatpak"); + // if (id != null) + // appid_map.insert (id, info); + // } + + // string cmd = info.get_commandline (); + + // if (cmd == null) + // continue; + + // sanitize_cmd (ref cmd); + // apps_info.insert (cmd, info); + } + } + + // private static void sanitize_cmd(ref string? commandline) { + // if (commandline == null) + // return; + + // // flatpak: parse the command line of the containerized program + // if (commandline.contains("flatpak run")) { + // var index = commandline.index_of ("--command=") + 10; + // commandline = commandline.substring (index); + // } + + // // TODO: unify this with the logic in get_full_process_cmd + // // commandline = Process.first_component (commandline); + // // commandline = Path.get_basename (commandline); + // // commandline = Process.sanitize_name (commandline); + + // // Workaround for google-chrome + // if (commandline.contains ("google-chrome-stable")) + // commandline = "chrome"; + // } + + // public static AppInfo? app_info_for_process (Process p) { + // AppInfo? info = null; + + // if (p.command != null) + // info = apps_info[p.command]; + + // if (info == null && p.app_id != null) + // info = appid_map[p.app_id]; + + // return info; + // } + + + + /** * Gets a process by its pid, making sure that it's updated. */ From 0aac2515d1077c33dabb1c74e19d2ab89833255c Mon Sep 17 00:00:00 2001 From: stsdc Date: Sat, 11 Jan 2020 01:39:04 +0100 Subject: [PATCH 16/96] using AppInfo to display application name if process is an app --- meson.build | 1 + src/Managers/Process.vala | 2 ++ src/Managers/ProcessManager.vala | 38 +++++++++++++------- src/Managers/ProcessUtils.vala | 23 ++++++++++++ src/Widgets/ProcessView/ProcessInfoView.vala | 2 ++ 5 files changed, 54 insertions(+), 12 deletions(-) create mode 100644 src/Managers/ProcessUtils.vala diff --git a/meson.build b/meson.build index e34afb59..03972b58 100644 --- a/meson.build +++ b/meson.build @@ -59,6 +59,7 @@ executable( 'src/Widgets/Statusbar/Statusbar.vala', 'src/Widgets/ProcessView/ProcessInfoView.vala', 'src/Widgets/ProcessView/ProcessView.vala', + 'src/Managers/ProcessUtils.vala', # 'src/Models/GenericModel.vala', 'src/Models/Model.vala', diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index ec94e5b7..f2c896d4 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -12,6 +12,8 @@ namespace Monitor { // Full command from cmdline file public string command { get; private set; } + public string application_name; + // Contains info about io ProcessIO io; diff --git a/src/Managers/ProcessManager.vala b/src/Managers/ProcessManager.vala index e015bd37..abe8230f 100644 --- a/src/Managers/ProcessManager.vala +++ b/src/Managers/ProcessManager.vala @@ -16,9 +16,8 @@ namespace Monitor { private Gee.TreeMap process_list; private Gee.HashSet kernel_process_blacklist; + private Gee.HashMap apps_info_list; - private static HashTable? apps_info; - private static HashTable? appid_map; public signal void process_added (Process process); public signal void process_removed (int pid); @@ -28,8 +27,8 @@ namespace Monitor { public ProcessManager () { process_list = new Gee.TreeMap (); kernel_process_blacklist = new Gee.HashSet (); + apps_info_list = new Gee.HashMap (); - apps_info = new HashTable (str_hash, str_equal); populate_apps_info (); update_processes.begin (); @@ -38,14 +37,15 @@ namespace Monitor { Timeout.add (2000, handle_timeout); } - public static void populate_apps_info() { - apps_info = new HashTable (str_hash, str_equal); - appid_map = new HashTable (str_hash, str_equal); + public void populate_apps_info() { var _apps_info = AppInfo.get_all (); - foreach (AppInfo info in _apps_info) { - debug ("%s\n", info.get_name ()); + foreach (AppInfo app_info in _apps_info) { + + string commandline = (app_info.get_commandline ()); + debug ("%s\n", commandline); + // GLib.DesktopAppInfo? dai = info as GLib.DesktopAppInfo; // if (dai != null) { @@ -54,13 +54,12 @@ namespace Monitor { // appid_map.insert (id, info); // } - // string cmd = info.get_commandline (); - // if (cmd == null) - // continue; + if (commandline == null) + continue; // sanitize_cmd (ref cmd); - // apps_info.insert (cmd, info); + apps_info_list.set (commandline, app_info); } } @@ -218,6 +217,19 @@ namespace Monitor { // create the process var process = new Process (pid); + string sanitized_commandline = ProcessUtils.sanitize_commandline (process.command); + + foreach (var key in apps_info_list.keys) { + if (key.contains (sanitized_commandline)) { + process.application_name = apps_info_list.get (key).get_name (); + } + } + + // if it's not an app, show short commandline + if (process.application_name == null) { + process.application_name = ProcessUtils.sanitize_commandline (process.command); + } + if (process.exists) { if (process.stat.pgrp != 0) { // regular process, add it to our cache @@ -252,5 +264,7 @@ namespace Monitor { kernel_process_blacklist.remove (pid); } } + + } } diff --git a/src/Managers/ProcessUtils.vala b/src/Managers/ProcessUtils.vala new file mode 100644 index 00000000..f5ef56f6 --- /dev/null +++ b/src/Managers/ProcessUtils.vala @@ -0,0 +1,23 @@ +public class Monitor.ProcessUtils { + + + private static bool is_shell (string chunk) { + if ("sh" in chunk || "bash" in chunk || "zsh" in chunk) { + return true; + } + return false; + } + + + public static string sanitize_commandline (string commandline) { + // splitting command; might include many options + var splitted_commandline = commandline.split (" "); + + // check if started by any shell + if (is_shell(splitted_commandline[0])) { + return Path.get_basename (splitted_commandline[1]); + } + + return Path.get_basename (splitted_commandline[0]); + } +} \ No newline at end of file diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index a3c74cc6..108d410a 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -36,6 +36,8 @@ public class Monitor.ProcessInfoView : Gtk.Grid { } public void update (Process process) { + application_name.set_text (("%s").printf (process.application_name)); + // debug ("%s, %s", process.command, process.app_info.get_name ()); pid.set_text (("%d").printf (process.stat.pid)); } } \ No newline at end of file From d025900638587cbc39c8958a8f76c5d6435cc72a Mon Sep 17 00:00:00 2001 From: stsdc Date: Sat, 11 Jan 2020 01:59:52 +0100 Subject: [PATCH 17/96] fix is started by shell --- src/Managers/ProcessManager.vala | 13 +++++-------- src/Managers/ProcessUtils.vala | 3 ++- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/Managers/ProcessManager.vala b/src/Managers/ProcessManager.vala index abe8230f..5aeb81c7 100644 --- a/src/Managers/ProcessManager.vala +++ b/src/Managers/ProcessManager.vala @@ -44,7 +44,7 @@ namespace Monitor { foreach (AppInfo app_info in _apps_info) { string commandline = (app_info.get_commandline ()); - debug ("%s\n", commandline); + // debug ("%s\n", commandline); // GLib.DesktopAppInfo? dai = info as GLib.DesktopAppInfo; @@ -217,19 +217,16 @@ namespace Monitor { // create the process var process = new Process (pid); - string sanitized_commandline = ProcessUtils.sanitize_commandline (process.command); + // placeholding shortened commandline + process.application_name = ProcessUtils.sanitize_commandline (process.command); + // checking maybe it's an application foreach (var key in apps_info_list.keys) { - if (key.contains (sanitized_commandline)) { + if (key.contains (process.application_name)) { process.application_name = apps_info_list.get (key).get_name (); } } - // if it's not an app, show short commandline - if (process.application_name == null) { - process.application_name = ProcessUtils.sanitize_commandline (process.command); - } - if (process.exists) { if (process.stat.pgrp != 0) { // regular process, add it to our cache diff --git a/src/Managers/ProcessUtils.vala b/src/Managers/ProcessUtils.vala index f5ef56f6..73698767 100644 --- a/src/Managers/ProcessUtils.vala +++ b/src/Managers/ProcessUtils.vala @@ -2,7 +2,8 @@ public class Monitor.ProcessUtils { private static bool is_shell (string chunk) { - if ("sh" in chunk || "bash" in chunk || "zsh" in chunk) { + if ("sh" == chunk || "bash" == chunk || "zsh" == chunk) { + debug (chunk); return true; } return false; From d172889d9da0fca8baf85b520104732b709cd975 Mon Sep 17 00:00:00 2001 From: stsdc Date: Sat, 11 Jan 2020 22:20:55 +0100 Subject: [PATCH 18/96] add custom stylesheet --- data/Application.css | 15 +++++++++++++++ data/css.gresource.xml | 6 ++++++ meson.build | 12 +++++++++--- src/Monitor.vala | 4 ++++ 4 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 data/Application.css create mode 100644 data/css.gresource.xml diff --git a/data/Application.css b/data/Application.css new file mode 100644 index 00000000..175b632f --- /dev/null +++ b/data/Application.css @@ -0,0 +1,15 @@ +.badge, +.badge:hover, +.badge:selected, +.badge:selected:focus, +.badge:hover:selected { + background-image: none; + background-color: alpha(@text_color, 0.1); + box-shadow: none; + color: alpha(@text_color, 0.7); + font-weight: 700; + border-radius: 10px; + padding: 0 6px; + margin: 0 3px; + border-width: 0; +} \ No newline at end of file diff --git a/data/css.gresource.xml b/data/css.gresource.xml new file mode 100644 index 00000000..63daa2e3 --- /dev/null +++ b/data/css.gresource.xml @@ -0,0 +1,6 @@ + + + + Application.css + + \ No newline at end of file diff --git a/meson.build b/meson.build index 03972b58..173d9c56 100644 --- a/meson.build +++ b/meson.build @@ -31,10 +31,15 @@ configure_file(output: 'config.h', configuration: config_data) config_h_dir = include_directories('.') icons_gresource = gnome.compile_resources( - 'gresource_icons', - 'data/icons/icons.indicator.gresource.xml', + 'gresource_icons', 'data/icons/icons.indicator.gresource.xml', source_dir: 'data/icons', - c_name: 'as' + c_name: 'as1' +) + +css_gresource = gnome.compile_resources( + 'gresource_css', 'data/css.gresource.xml', + source_dir: 'data', + c_name: 'as2' ) c_args = [ @@ -48,6 +53,7 @@ c_args = [ executable( meson.project_name(), icons_gresource, + css_gresource, 'src/Monitor.vala', 'src/MainWindow.vala', 'src/Utils.vala', diff --git a/src/Monitor.vala b/src/Monitor.vala index b1dbe11e..95c8cfae 100644 --- a/src/Monitor.vala +++ b/src/Monitor.vala @@ -59,6 +59,10 @@ namespace Monitor { window.destroy (); } }); + + var provider = new Gtk.CssProvider (); + provider.load_from_resource ("/com/github/stsdc/monitor/Application.css"); + Gtk.StyleContext.add_provider_for_screen (Gdk.Screen.get_default (), provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); } public static int main (string [] args) { From d3685a314712e263987da942724432c3469108e6 Mon Sep 17 00:00:00 2001 From: stsdc Date: Sun, 12 Jan 2020 01:22:59 +0100 Subject: [PATCH 19/96] display command --- data/Application.css | 27 ++++++-- src/Widgets/ProcessView/ProcessInfoView.vala | 72 ++++++++++++++++---- 2 files changed, 81 insertions(+), 18 deletions(-) diff --git a/data/Application.css b/data/Application.css index 175b632f..34c16e3b 100644 --- a/data/Application.css +++ b/data/Application.css @@ -1,8 +1,8 @@ -.badge, -.badge:hover, -.badge:selected, -.badge:selected:focus, -.badge:hover:selected { +.process_info .badge, +.process_info .badge:hover, +.process_info .badge:selected, +.process_info .badge:selected:focus, +.process_info .badge:hover:selected { background-image: none; background-color: alpha(@text_color, 0.1); box-shadow: none; @@ -12,4 +12,19 @@ padding: 0 6px; margin: 0 3px; border-width: 0; -} \ No newline at end of file +} + +.command_wrapper { + background-color: #fdf6e3; + border-radius: 3px; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.20); + padding: 5px; + padding-right: 190px; +} + +.command text { + background-color: #fdf6e3; +} +.command { + font-family: monospace; +} diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index 108d410a..5da11a66 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -1,43 +1,91 @@ -public class Monitor.ProcessInfoView : Gtk.Grid { +public class Monitor.ProcessInfoView : Gtk.Box { public Gtk.Label application_name; public string ? icon_name; - public Gtk.Label command; + public Gtk.TextView command; public Gtk.Label pid; + public Gtk.Label ppid; + public Gtk.Label pgrp; + public Gtk.Label status; private Gtk.Grid grid; public ProcessInfoView() { + // get_style_context ().add_class ("process_info"); margin = 12; + orientation = Gtk.Orientation.VERTICAL; + hexpand = true; + // row_spacing = 24; var icon = new Gtk.Image.from_icon_name ("application-x-executable", Gtk.IconSize.DIALOG); + icon.set_pixel_size (64); icon.valign = Gtk.Align.END; application_name = new Gtk.Label(_("N/A")); application_name.get_style_context ().add_class ("h2"); + application_name.halign = Gtk.Align.START; + application_name.valign = Gtk.Align.START; - command = new Gtk.Label(_("N/A")); - command.halign = Gtk.Align.START; - pid = new Gtk.Label(_("N/A")); + status = new Gtk.Label(_("S")); + status.halign = Gtk.Align.START; + status.get_style_context ().add_class (Granite.STYLE_CLASS_BADGE); - // add (name); - // add (command); - // add (pid); + pid = new Gtk.Label(_("PID:N/A")); + pid.halign = Gtk.Align.START; + pid.get_style_context ().add_class (Granite.STYLE_CLASS_BADGE); + + ppid = new Gtk.Label(_("PPID:N/A")); + ppid.halign = Gtk.Align.START; + ppid.get_style_context ().add_class (Granite.STYLE_CLASS_BADGE); + + pgrp = new Gtk.Label(_("PGRP:N/A")); + pgrp.halign = Gtk.Align.START; + pgrp.get_style_context ().add_class (Granite.STYLE_CLASS_BADGE); + + var wrapper = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0); + wrapper.add (status); + wrapper.add (pid); + wrapper.add (pgrp); + wrapper.add (ppid); + + + command = new Gtk.TextView (); + command.buffer.text = "N/A"; + command.pixels_below_lines = 3; + command.set_wrap_mode (Gtk.WrapMode.WORD); + command.get_style_context ().add_class ("command"); + + var command_wrapper = new Gtk.Box(Gtk.Orientation.VERTICAL, 0); + command_wrapper.get_style_context ().add_class ("command_wrapper"); + command_wrapper.margin_top = 24; + command_wrapper.add (command); grid = new Gtk.Grid (); grid.get_style_context ().add_class ("horizontal"); grid.column_spacing = 12; + grid.attach (icon, 0, 0, 1, 2); - grid.attach (application_name, 1, 0, 1, 1); - grid.attach (command, 1, 1, 1, 1); + grid.attach (application_name, 1, 0, 3, 1); + grid.attach (wrapper, 1, 1, 1, 1); + // attach (grid, 0, 0, 1, 1); + // attach (command, 0, 1, 1, 1); add (grid); + add (command_wrapper); } public void update (Process process) { application_name.set_text (("%s").printf (process.application_name)); - // debug ("%s, %s", process.command, process.app_info.get_name ()); - pid.set_text (("%d").printf (process.stat.pid)); + pid.set_text (("PID:%d").printf (process.stat.pid)); + ppid.set_text (("PPID:%d").printf (process.stat.ppid)); + pgrp.set_text (("PGRP:%d").printf (process.stat.pgrp)); + + command.buffer.text = process.command; + } + + public void pid_widget () { + + } } \ No newline at end of file From 04733fa2b0557b7103bab3f8a0d5ec2c42898963 Mon Sep 17 00:00:00 2001 From: stsdc Date: Mon, 13 Jan 2020 23:54:14 +0100 Subject: [PATCH 20/96] fix some styling --- data/Application.css | 11 +++--- src/Widgets/ProcessView/ProcessInfoView.vala | 37 +++++++++++--------- src/Widgets/ProcessView/ProcessView.vala | 2 +- 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/data/Application.css b/data/Application.css index 34c16e3b..b0188444 100644 --- a/data/Application.css +++ b/data/Application.css @@ -1,8 +1,8 @@ -.process_info .badge, -.process_info .badge:hover, -.process_info .badge:selected, -.process_info .badge:selected:focus, -.process_info .badge:hover:selected { +.badge, +.badge:hover, +.badge:selected, +.badge:selected:focus, +.badge:hover:selected { background-image: none; background-color: alpha(@text_color, 0.1); box-shadow: none; @@ -19,7 +19,6 @@ border-radius: 3px; box-shadow: 0 1px 1px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.20); padding: 5px; - padding-right: 190px; } .command text { diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index 5da11a66..7c9a6e6a 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -9,7 +9,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { private Gtk.Grid grid; - public ProcessInfoView() { + public ProcessInfoView () { // get_style_context ().add_class ("process_info"); margin = 12; orientation = Gtk.Orientation.VERTICAL; @@ -20,44 +20,48 @@ public class Monitor.ProcessInfoView : Gtk.Box { icon.set_pixel_size (64); icon.valign = Gtk.Align.END; - application_name = new Gtk.Label(_("N/A")); + application_name = new Gtk.Label (_ ("N/A")); application_name.get_style_context ().add_class ("h2"); application_name.halign = Gtk.Align.START; application_name.valign = Gtk.Align.START; - status = new Gtk.Label(_("S")); + status = new Gtk.Label (_ ("S")); status.halign = Gtk.Align.START; status.get_style_context ().add_class (Granite.STYLE_CLASS_BADGE); - pid = new Gtk.Label(_("PID:N/A")); + pid = new Gtk.Label (_ ("PID:N/A")); pid.halign = Gtk.Align.START; pid.get_style_context ().add_class (Granite.STYLE_CLASS_BADGE); - ppid = new Gtk.Label(_("PPID:N/A")); + ppid = new Gtk.Label (_ ("PPID:N/A")); ppid.halign = Gtk.Align.START; ppid.get_style_context ().add_class (Granite.STYLE_CLASS_BADGE); - pgrp = new Gtk.Label(_("PGRP:N/A")); + pgrp = new Gtk.Label (_ ("PGRP:N/A")); pgrp.halign = Gtk.Align.START; pgrp.get_style_context ().add_class (Granite.STYLE_CLASS_BADGE); - var wrapper = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0); + var wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); wrapper.add (status); - wrapper.add (pid); - wrapper.add (pgrp); - wrapper.add (ppid); + wrapper.add ( pid); + wrapper.add ( pgrp); + wrapper.add ( ppid); command = new Gtk.TextView (); command.buffer.text = "N/A"; command.pixels_below_lines = 3; + command.margin = 8; command.set_wrap_mode (Gtk.WrapMode.WORD); + // setting resize mode, so command wraps immediatly when right sidebar changed + command.resize_mode = Gtk.ResizeMode.IMMEDIATE; command.get_style_context ().add_class ("command"); - var command_wrapper = new Gtk.Box(Gtk.Orientation.VERTICAL, 0); + var command_wrapper = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); command_wrapper.get_style_context ().add_class ("command_wrapper"); command_wrapper.margin_top = 24; + command_wrapper.resize_mode = Gtk.ResizeMode.IMMEDIATE; command_wrapper.add (command); grid = new Gtk.Grid (); @@ -65,13 +69,13 @@ public class Monitor.ProcessInfoView : Gtk.Box { grid.column_spacing = 12; - grid.attach (icon, 0, 0, 1, 2); + grid.attach ( icon, 0, 0, 1, 2); grid.attach (application_name, 1, 0, 3, 1); - grid.attach (wrapper, 1, 1, 1, 1); + grid.attach ( wrapper, 1, 1, 1, 1); // attach (grid, 0, 0, 1, 1); // attach (command, 0, 1, 1, 1); - add (grid); + add ( grid); add (command_wrapper); } @@ -80,12 +84,11 @@ public class Monitor.ProcessInfoView : Gtk.Box { pid.set_text (("PID:%d").printf (process.stat.pid)); ppid.set_text (("PPID:%d").printf (process.stat.ppid)); pgrp.set_text (("PGRP:%d").printf (process.stat.pgrp)); - + command.buffer.text = process.command; + show_all (); } public void pid_widget () { - - } } \ No newline at end of file diff --git a/src/Widgets/ProcessView/ProcessView.vala b/src/Widgets/ProcessView/ProcessView.vala index 1f466f24..5c455612 100644 --- a/src/Widgets/ProcessView/ProcessView.vala +++ b/src/Widgets/ProcessView/ProcessView.vala @@ -19,7 +19,7 @@ public class Monitor.ProcessView : Gtk.Box { process_tree_view_scrolled.add (process_tree_view); var paned = new Gtk.Paned (Gtk.Orientation.HORIZONTAL); - paned.pack1 (process_tree_view_scrolled, false, false); + paned.pack1 (process_tree_view_scrolled, true, false); paned.pack2 (process_info_view, false, false); paned.set_position (500); paned.set_hexpand (true); From 70fefaf3e1f52f253255deb4bcbcd389aee702d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= Date: Tue, 14 Jan 2020 16:04:24 +0100 Subject: [PATCH 21/96] display state; better parsing --- src/Managers/Process.vala | 16 +++++++++++++++- src/Managers/ProcessStructs.vala | 2 +- src/Widgets/ProcessView/ProcessInfoView.vala | 12 +++++++----- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index f2c896d4..31019212 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -155,8 +155,22 @@ namespace Monitor { } /* split the contents into an array and parse each value that we care about */ + + // But first we have to extract the command name, since it might include spaces + // First find the command in stat file + Regex regex = /\((.*?)\)/; + MatchInfo match_info; + regex.match (stat_contents, 0, out match_info); + string matched_command = match_info.fetch (0); + + // Remove command from stat_contents + stat_contents = stat_contents.replace (matched_command, ""); + + // split the string var splitted_stat = stat_contents.split (" "); - stat.comm = splitted_stat[1][1 : -1]; + stat.comm = matched_command[1 : -1]; + + stat.state = splitted_stat[2]; stat.ppid = int.parse (splitted_stat[3]); stat.pgrp = int.parse (splitted_stat[4]); diff --git a/src/Managers/ProcessStructs.vala b/src/Managers/ProcessStructs.vala index 4fc2adf6..af76d210 100644 --- a/src/Managers/ProcessStructs.vala +++ b/src/Managers/ProcessStructs.vala @@ -34,7 +34,7 @@ public struct Monitor.ProcessStatus { // swapped out. public string comm; - public char state; + public string state; // The PID of the parent of this process. public int ppid; diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index 7c9a6e6a..eb3eeb38 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -5,7 +5,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { public Gtk.Label pid; public Gtk.Label ppid; public Gtk.Label pgrp; - public Gtk.Label status; + public Gtk.Label state; private Gtk.Grid grid; @@ -26,9 +26,9 @@ public class Monitor.ProcessInfoView : Gtk.Box { application_name.valign = Gtk.Align.START; - status = new Gtk.Label (_ ("S")); - status.halign = Gtk.Align.START; - status.get_style_context ().add_class (Granite.STYLE_CLASS_BADGE); + state = new Gtk.Label (_ ("?")); + state.halign = Gtk.Align.START; + state.get_style_context ().add_class (Granite.STYLE_CLASS_BADGE); pid = new Gtk.Label (_ ("PID:N/A")); pid.halign = Gtk.Align.START; @@ -43,7 +43,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { pgrp.get_style_context ().add_class (Granite.STYLE_CLASS_BADGE); var wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); - wrapper.add (status); + wrapper.add (state); wrapper.add ( pid); wrapper.add ( pgrp); wrapper.add ( ppid); @@ -84,6 +84,8 @@ public class Monitor.ProcessInfoView : Gtk.Box { pid.set_text (("PID:%d").printf (process.stat.pid)); ppid.set_text (("PPID:%d").printf (process.stat.ppid)); pgrp.set_text (("PGRP:%d").printf (process.stat.pgrp)); + state.set_text (process.stat.state); + command.buffer.text = process.command; show_all (); From 94129db7f1c22257797d63d055c2a17235c8d085 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= Date: Wed, 15 Jan 2020 23:26:37 +0100 Subject: [PATCH 22/96] show app icons in ProcessInfoView --- src/Managers/Process.vala | 23 +++++++++++++++++++- src/Managers/ProcessManager.vala | 2 ++ src/Widgets/ProcessView/ProcessInfoView.vala | 20 +++++++++++++++-- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index 31019212..f00439f2 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -14,6 +14,22 @@ namespace Monitor { public string application_name; + Icon _icon; + public Icon icon { + get { return _icon; } + set { + if (value == null) { + try { + _icon = Icon.new_for_string ("application-x-executable"); + } catch (Error e) { + warning (e.message); + } + } else { + _icon = value; + } + } + } + // Contains info about io ProcessIO io; @@ -39,7 +55,12 @@ namespace Monitor { // Construct a new process public Process (int _pid) { - // pid = _pid; + + try { + _icon = Icon.new_for_string ("application-x-executable"); + } catch (Error e) { + warning (e.message); + } last_total = 0; io = {}; diff --git a/src/Managers/ProcessManager.vala b/src/Managers/ProcessManager.vala index 5aeb81c7..708dd680 100644 --- a/src/Managers/ProcessManager.vala +++ b/src/Managers/ProcessManager.vala @@ -224,6 +224,8 @@ namespace Monitor { foreach (var key in apps_info_list.keys) { if (key.contains (process.application_name)) { process.application_name = apps_info_list.get (key).get_name (); + // debug (apps_info_list.get (key).get_icon ().to_string ()); + process.icon = apps_info_list.get (key).get_icon (); } } diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index eb3eeb38..21f2d87e 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -7,6 +7,8 @@ public class Monitor.ProcessInfoView : Gtk.Box { public Gtk.Label pgrp; public Gtk.Label state; + private Gtk.Image icon; + private Regex? regex; private Gtk.Grid grid; public ProcessInfoView () { @@ -14,9 +16,9 @@ public class Monitor.ProcessInfoView : Gtk.Box { margin = 12; orientation = Gtk.Orientation.VERTICAL; hexpand = true; - // row_spacing = 24; + regex = /(?i:^.*\.(xpm|png)$)/; - var icon = new Gtk.Image.from_icon_name ("application-x-executable", Gtk.IconSize.DIALOG); + icon = new Gtk.Image.from_icon_name ("application-x-executable", Gtk.IconSize.DIALOG); icon.set_pixel_size (64); icon.valign = Gtk.Align.END; @@ -80,12 +82,26 @@ public class Monitor.ProcessInfoView : Gtk.Box { } public void update (Process process) { + // probably not ok to update everything application_name.set_text (("%s").printf (process.application_name)); pid.set_text (("PID:%d").printf (process.stat.pid)); ppid.set_text (("PPID:%d").printf (process.stat.ppid)); pgrp.set_text (("PGRP:%d").printf (process.stat.pgrp)); state.set_text (process.stat.state); + var icon_name = process.icon.to_string (); + + if (!regex.match (icon_name)) { + icon.set_from_icon_name (icon_name, Gtk.IconSize.DIALOG); + } else { + try { + var pixbuf = new Gdk.Pixbuf.from_file_at_size (icon_name, 64, -1); + icon.set_from_pixbuf (pixbuf); + } catch (Error e) { + warning (e.message); + } + } + command.buffer.text = process.command; show_all (); From 0c508d765b826b802a8e2fe89c283f72e4ccc56c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= Date: Fri, 17 Jan 2020 23:04:03 +0100 Subject: [PATCH 23/96] command is scrollable --- src/Widgets/ProcessView/ProcessInfoView.vala | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index 21f2d87e..5ac7d888 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -2,6 +2,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { public Gtk.Label application_name; public string ? icon_name; public Gtk.TextView command; + private Gtk.ScrolledWindow command_wrapper; public Gtk.Label pid; public Gtk.Label ppid; public Gtk.Label pgrp; @@ -51,19 +52,21 @@ public class Monitor.ProcessInfoView : Gtk.Box { wrapper.add ( ppid); + // command widget should be one-liner, but expandable on click + // when clicked it should reveal full command command = new Gtk.TextView (); command.buffer.text = "N/A"; - command.pixels_below_lines = 3; + command.pixels_above_lines = 3; command.margin = 8; command.set_wrap_mode (Gtk.WrapMode.WORD); // setting resize mode, so command wraps immediatly when right sidebar changed - command.resize_mode = Gtk.ResizeMode.IMMEDIATE; + // command.resize_mode = Gtk.ResizeMode.IMMEDIATE; command.get_style_context ().add_class ("command"); - var command_wrapper = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); + command_wrapper = new Gtk.ScrolledWindow (null, null); command_wrapper.get_style_context ().add_class ("command_wrapper"); command_wrapper.margin_top = 24; - command_wrapper.resize_mode = Gtk.ResizeMode.IMMEDIATE; + // command_wrapper.resize_mode = Gtk.ResizeMode.IMMEDIATE; command_wrapper.add (command); grid = new Gtk.Grid (); @@ -101,9 +104,12 @@ public class Monitor.ProcessInfoView : Gtk.Box { warning (e.message); } } - + // command.queue_resize (); command.buffer.text = process.command; + // command.queue_resize (); + // command_wrapper.queue_resize (); + show_all (); } From 1e5452bab2a3cd5b1161e6149e24ce2a22d55ec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= Date: Fri, 17 Jan 2020 23:22:33 +0100 Subject: [PATCH 24/96] add ellipsize and tooltip to application_name --- src/Widgets/ProcessView/ProcessInfoView.vala | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index 5ac7d888..7ce492d4 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -25,6 +25,8 @@ public class Monitor.ProcessInfoView : Gtk.Box { application_name = new Gtk.Label (_ ("N/A")); application_name.get_style_context ().add_class ("h2"); + application_name.ellipsize = Pango.EllipsizeMode.END; + application_name.tooltip_text = _("N/A"); application_name.halign = Gtk.Align.START; application_name.valign = Gtk.Align.START; @@ -87,6 +89,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { public void update (Process process) { // probably not ok to update everything application_name.set_text (("%s").printf (process.application_name)); + application_name.tooltip_text = process.application_name; pid.set_text (("PID:%d").printf (process.stat.pid)); ppid.set_text (("PPID:%d").printf (process.stat.ppid)); pgrp.set_text (("PGRP:%d").printf (process.stat.pgrp)); From cb106cead920ef89f1a0182599ced01016fa2463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= Date: Sun, 19 Jan 2020 00:58:03 +0100 Subject: [PATCH 25/96] refactoring: read_file --- src/Managers/Process.vala | 80 ++++---------------- src/Managers/ProcessUtils.vala | 34 ++++++++- src/Widgets/ProcessView/ProcessInfoView.vala | 6 +- 3 files changed, 50 insertions(+), 70 deletions(-) diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index f00439f2..84911c59 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -14,6 +14,9 @@ namespace Monitor { public string application_name; + + public int uid; + Icon _icon; public Icon icon { get { return _icon; } @@ -67,6 +70,11 @@ namespace Monitor { stat = {}; stat.pid = _pid; + // getting uid + GTop.ProcUid proc_uid; + GTop.get_proc_uid (out proc_uid, stat.pid); + uid = proc_uid.uid; + exists = read_stat (0, 1) && read_cmdline (); } @@ -157,23 +165,7 @@ namespace Monitor { // Reads the /proc/%pid%/stat file and updates the process with the information therein. private bool read_stat (uint64 cpu_total, uint64 cpu_last_total) { - /* grab the stat file from /proc/%pid%/stat */ - var stat_file = File.new_for_path ("/proc/%d/stat".printf (stat.pid)); - - /* make sure that it exists, not an error if it doesn't */ - if (!stat_file.query_exists ()) { - return false; - } - - try { - // read the single line from the file - var dis = new DataInputStream (stat_file.read ()); - string? stat_contents = dis.read_line (); - - if (stat_contents == null) { - stderr.printf ("Error reading stat file '%s': couldn't read_line ()\n", stat_file.get_path ()); - return false; - } + string ? stat_contents = ProcessUtils.read_file ("/proc/%d/stat".printf (stat.pid)); /* split the contents into an array and parse each value that we care about */ @@ -195,13 +187,6 @@ namespace Monitor { stat.ppid = int.parse (splitted_stat[3]); stat.pgrp = int.parse (splitted_stat[4]); - // Get process UID - GTop.ProcUid uid; - GTop.get_proc_uid (out uid, stat.pid); - // stat.ppid = uid.ppid; // pid of parent process - // stat.pgrp = uid.pgrp; // process group id - - // Get CPU usage by process GTop.ProcTime proc_time; GTop.get_proc_time (out proc_time, stat.pid); @@ -220,10 +205,6 @@ namespace Monitor { Wnck.ResourceUsage resu = Wnck.ResourceUsage.pid_read (Gdk.Display.get_default(), stat.pid); mem_usage += (resu.total_bytes_estimate / 1024); } - } catch (Error e) { - warning ("Can't read process stat: '%s'", e.message); - return false; - } return true; } @@ -232,48 +213,19 @@ namespace Monitor { * Reads the /proc/%pid%/cmdline file and updates from the information contained therein. */ private bool read_cmdline () { - // grab the cmdline file from /proc/%pid%/cmdline - var cmdline_file = File.new_for_path ("/proc/%d/cmdline".printf (stat.pid)); - // make sure that it exists - if (!cmdline_file.query_exists ()) { - warning ("File '%s' doesn't exist.\n", cmdline_file.get_path ()); - return false; - } - try { - // read the single line from the file - var dis = new DataInputStream (cmdline_file.read ()); - uint8[] cmdline_contents_array = new uint8[4097]; // 4096 is max size with a null terminator - var size = dis.read (cmdline_contents_array); + string ? cmdline = ProcessUtils.read_file ("/proc/%d/cmdline".printf (stat.pid)); - if (size <= 0) { - // was empty, not an error + if (cmdline.length <= 0) { + // was empty, not an error return true; - } - - // cmdline is a single line file with each arg seperated by a null character ('\0') - // convert all \0 and \n to spaces - for (int pos = 0; pos < size; pos++) { - if (cmdline_contents_array[pos] == '\0' || cmdline_contents_array[pos] == '\n') { - cmdline_contents_array[pos] = ' '; - } - } - cmdline_contents_array[size] = '\0'; - string cmdline_contents = (string) cmdline_contents_array; - - //TODO: need to make sure that this works - GTop.ProcState proc_state; - GTop.get_proc_state (out proc_state, stat.pid); - - command = cmdline_contents; - - } - catch (Error e) { - stderr.printf ("Error reading cmdline file '%s': %s\n", cmdline_file.get_path (), e.message); - return false; } + + command = cmdline; return true; } + + } } diff --git a/src/Managers/ProcessUtils.vala b/src/Managers/ProcessUtils.vala index 73698767..e7070a97 100644 --- a/src/Managers/ProcessUtils.vala +++ b/src/Managers/ProcessUtils.vala @@ -1,6 +1,6 @@ public class Monitor.ProcessUtils { - + // checks if it is run by shell private static bool is_shell (string chunk) { if ("sh" == chunk || "bash" == chunk || "zsh" == chunk) { debug (chunk); @@ -9,16 +9,44 @@ public class Monitor.ProcessUtils { return false; } - public static string sanitize_commandline (string commandline) { // splitting command; might include many options var splitted_commandline = commandline.split (" "); // check if started by any shell - if (is_shell(splitted_commandline[0])) { + if (is_shell (splitted_commandline[0])) { return Path.get_basename (splitted_commandline[1]); } return Path.get_basename (splitted_commandline[0]); } + + public static string? read_file (string path) { + var file = File.new_for_path (path); + + /* make sure that it exists, not an error if it doesn't */ + if (!file.query_exists ()) { + return null; + } + var text = new StringBuilder (); + try { + var dis = new DataInputStream (file.read ()); + + // Doing this because of cmdline file. + // cmdline is a single line file with each arg seperated by a null character ('\0') + string line = dis.read_upto ("\0", 1, null); + while (line != null) { + text.append (line); + text.append (" "); + dis.skip (1); + line = dis.read_upto ("\0", 1, null); + } + + return text.str; + } catch (Error e) { + warning ("Error reading cmdline file '%s': %s\n", file.get_path (), e.message); + return null; + } + } + } \ No newline at end of file diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index 7ce492d4..eb4e81bb 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -53,7 +53,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { wrapper.add ( pgrp); wrapper.add ( ppid); - + /* ==========START COMMAND WIDGET============== */ // command widget should be one-liner, but expandable on click // when clicked it should reveal full command command = new Gtk.TextView (); @@ -70,6 +70,8 @@ public class Monitor.ProcessInfoView : Gtk.Box { command_wrapper.margin_top = 24; // command_wrapper.resize_mode = Gtk.ResizeMode.IMMEDIATE; command_wrapper.add (command); + /* ==========END COMMAND WIDGET============== */ + grid = new Gtk.Grid (); grid.get_style_context ().add_class ("horizontal"); @@ -80,8 +82,6 @@ public class Monitor.ProcessInfoView : Gtk.Box { grid.attach (application_name, 1, 0, 3, 1); grid.attach ( wrapper, 1, 1, 1, 1); - // attach (grid, 0, 0, 1, 1); - // attach (command, 0, 1, 1, 1); add ( grid); add (command_wrapper); } From 0c8218cef24927cc6cf6e043d929ada4f083b765 Mon Sep 17 00:00:00 2001 From: stsdc Date: Sun, 19 Jan 2020 15:39:36 +0100 Subject: [PATCH 26/96] refactoring --- src/Managers/Process.vala | 374 ++++++++++--------- src/Widgets/ProcessView/ProcessInfoView.vala | 2 +- 2 files changed, 189 insertions(+), 187 deletions(-) diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index 84911c59..bf0fc359 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -1,231 +1,233 @@ - - -namespace Monitor { - - public class Process : GLib.Object { - // The size of each RSS page, in bytes - // private static long PAGESIZE = Posix.sysconf (Posix._SC_PAGESIZE); - - // Whether or not the PID leads to something - public bool exists { get; private set; } - - // Full command from cmdline file - public string command { get; private set; } - - public string application_name; - - - public int uid; - - Icon _icon; - public Icon icon { - get { return _icon; } - set { - if (value == null) { - try { - _icon = Icon.new_for_string ("application-x-executable"); - } catch (Error e) { - warning (e.message); - } - } else { - _icon = value; +public class Monitor.Process : GLib.Object { + // The size of each RSS page, in bytes + // private static long PAGESIZE = Posix.sysconf (Posix._SC_PAGESIZE); + + // Whether or not the PID leads to something + public bool exists { get; private set; } + + // Full command from cmdline file + public string command { get; private set; } + + // If process is an installed app, this will contain its name, + // otherwise it is just a trimmed command + public string application_name; + + // User id + public int uid; + + Icon _icon; + public Icon icon { + get { return _icon; } + set { + if (value == null) { + try { + _icon = Icon.new_for_string ("application-x-executable"); + } catch (Error e) { + warning (e.message); } + } else { + _icon = value; } } + } - // Contains info about io - ProcessIO io; + // Contains info about io + ProcessIO io; - // Contains status info - public ProcessStatus stat; + // Contains status info + public ProcessStatus stat; - /** - * CPU usage of this process from the last time that it was updated, measured in percent - * - * Will be 0 on first update. - */ - public double cpu_usage { get; private set; } + /** + * CPU usage of this process from the last time that it was updated, measured in percent + * + * Will be 0 on first update. + */ + public double cpu_usage { get; private set; } - private uint64 cpu_last_used; + private uint64 cpu_last_used; - //Memory usage of the process, measured in KiB. + //Memory usage of the process, measured in KiB. - public uint64 mem_usage { get; private set; } + public uint64 mem_usage { get; private set; } - private uint64 last_total; + private uint64 last_total; - // Construct a new process - public Process (int _pid) { + // Construct a new process + public Process (int _pid) { + try { + _icon = Icon.new_for_string ("application-x-executable"); + } catch (Error e) { + warning (e.message); + } + last_total = 0; - try { - _icon = Icon.new_for_string ("application-x-executable"); - } catch (Error e) { - warning (e.message); - } - last_total = 0; + io = { }; + stat = { }; + stat.pid = _pid; - io = {}; - stat = {}; - stat.pid = _pid; + // getting uid + GTop.ProcUid proc_uid; + GTop.get_proc_uid (out proc_uid, stat.pid); + uid = proc_uid.uid; - // getting uid - GTop.ProcUid proc_uid; - GTop.get_proc_uid (out proc_uid, stat.pid); - uid = proc_uid.uid; + exists = parse_stat () && read_cmdline (); + get_usage (0, 1); + } - exists = read_stat (0, 1) && read_cmdline (); - } + // Updates the process to get latest information + // Returns if the update was successful + public bool update (uint64 cpu_total, uint64 cpu_last_total) { + exists = parse_stat (); + if (exists) { + get_usage (cpu_total, cpu_last_total); + parse_io (); + } + return exists; + } - // Updates the process to get latest information - // Returns if the update was successful - public bool update (uint64 cpu_total, uint64 cpu_last_total) { - exists = read_stat (cpu_total, cpu_last_total); - parse_io(); + // Kills the process + // Returns if kill was successful + public bool kill () { + // Sends a kill signal that cannot be ignored + if (Posix.kill (stat.pid, Posix.Signal.KILL) == 0) { + return true; + } + return false; + } - return exists; + // Ends the process + // Returns if end was successful + public bool end () { + // Sends a terminate signal + if (Posix.kill (stat.pid, Posix.Signal.TERM) == 0) { + return true; } + return false; + } - // Kills the process - // Returns if kill was successful - public bool kill () { - // Sends a kill signal that cannot be ignored - if (Posix.kill (stat.pid, Posix.Signal.KILL) == 0) { - return true; - } + private bool parse_io () { + var io_file = File.new_for_path ("/proc/%d/io".printf (stat.pid)); + + if (!io_file.query_exists ()) { return false; } - // Ends the process - // Returns if end was successful - public bool end () { - // Sends a terminate signal - if (Posix.kill (stat.pid, Posix.Signal.TERM) == 0) { - return true; + try { + var dis = new DataInputStream (io_file.read ()); + string ? line; + + while ((line = dis.read_line ()) != null) { + var splitted_line = line.split (":"); + switch (splitted_line[0]) { + case "wchar" : + io.wchar = (uint64)splitted_line[1]; + break; + case "rchar" : + io.rchar = (uint64)splitted_line[1]; + break; + case "syscr" : + io.syscr = (uint64)splitted_line[1]; + break; + case "syscw" : + io.syscw = (uint64)splitted_line[1]; + break; + case "read_bytes" : + io.read_bytes = (uint64)splitted_line[1]; + break; + case "write_bytes" : + io.write_bytes = (uint64)splitted_line[1]; + break; + case "cancelled_write_bytes" : + io.cancelled_write_bytes = (uint64)splitted_line[1]; + break; + default : + warning ("Unknown value in /proc/%d/io", stat.pid); + break; + } + } + } catch (Error e) { + if (e.code != 14) { + // if the error is not `no access to file`, because regular user + // TODO: remove `magic` number + + warning ("Can't read process io: '%s' %d", e.message, e.code); } return false; } + return true; + } - private bool parse_io () { - var io_file = File.new_for_path ("/proc/%d/io".printf (stat.pid)); + // Reads the /proc/%pid%/stat file and updates the process with the information therein. + private bool parse_stat () { + string ? stat_contents = ProcessUtils.read_file ("/proc/%d/stat".printf (stat.pid)); - if (!io_file.query_exists ()) { - return false; - } + if (stat_contents == null) { + return false; + } - try { - var dis = new DataInputStream (io_file.read ()); - string? line; - - while ((line = dis.read_line ()) != null){ - var splitted_line = line.split (":"); - switch (splitted_line[0]) { - case "wchar": - io.wchar = (uint64)splitted_line[1]; - break; - case "rchar": - io.rchar = (uint64)splitted_line[1]; - break; - case "syscr": - io.syscr = (uint64)splitted_line[1]; - break; - case "syscw": - io.syscw = (uint64)splitted_line[1]; - break; - case "read_bytes": - io.read_bytes = (uint64)splitted_line[1]; - break; - case "write_bytes": - io.write_bytes = (uint64)splitted_line[1]; - break; - case "cancelled_write_bytes": - io.cancelled_write_bytes = (uint64)splitted_line[1]; - break; - default: - warning ("Unknown value in /proc/%d/io", stat.pid); - break; - } + // Split the contents into an array and parse each value that we care about - } + // But first we have to extract the command name, since it might include spaces + // First find the command in stat file. It is inside `(command)` - } catch (Error e) { - if (e.code != 14) { - // if the error is not `no access to file`, because regular user - // TODO: remove `magic` number - - warning ("Can't read process io: '%s' %d", e.message, e.code); - } - return false; - } - return true; - } + Regex regex = /\((.*?)\)/; // <- there should be no spaces; uncrustify adds them - // Reads the /proc/%pid%/stat file and updates the process with the information therein. - private bool read_stat (uint64 cpu_total, uint64 cpu_last_total) { - string ? stat_contents = ProcessUtils.read_file ("/proc/%d/stat".printf (stat.pid)); - - /* split the contents into an array and parse each value that we care about */ - - // But first we have to extract the command name, since it might include spaces - // First find the command in stat file - Regex regex = /\((.*?)\)/; - MatchInfo match_info; - regex.match (stat_contents, 0, out match_info); - string matched_command = match_info.fetch (0); - - // Remove command from stat_contents - stat_contents = stat_contents.replace (matched_command, ""); - - // split the string - var splitted_stat = stat_contents.split (" "); - stat.comm = matched_command[1 : -1]; - - stat.state = splitted_stat[2]; - stat.ppid = int.parse (splitted_stat[3]); - stat.pgrp = int.parse (splitted_stat[4]); - - // Get CPU usage by process - GTop.ProcTime proc_time; - GTop.get_proc_time (out proc_time, stat.pid); - cpu_usage = ((double)(proc_time.rtime - cpu_last_used)) / (cpu_total - cpu_last_total); - cpu_last_used = proc_time.rtime; - - // Get memory usage by process - GTop.Memory mem; - GTop.get_mem (out mem); - - GTop.ProcMem proc_mem; - GTop.get_proc_mem (out proc_mem, stat.pid); - mem_usage = (proc_mem.resident - proc_mem.share) / 1024; // in KiB - - if (Gdk.Display.get_default () is Gdk.X11.Display) { - Wnck.ResourceUsage resu = Wnck.ResourceUsage.pid_read (Gdk.Display.get_default(), stat.pid); - mem_usage += (resu.total_bytes_estimate / 1024); - } + MatchInfo match_info; + regex.match (stat_contents, 0, out match_info); + string matched_command = match_info.fetch (0); - return true; - } + // Remove command from stat_contents + stat_contents = stat_contents.replace (matched_command, ""); - /** - * Reads the /proc/%pid%/cmdline file and updates from the information contained therein. - */ - private bool read_cmdline () { + // split the string and extract some stats + var splitted_stat = stat_contents.split (" "); + stat.comm = matched_command[1 : -1]; - string ? cmdline = ProcessUtils.read_file ("/proc/%d/cmdline".printf (stat.pid)); + stat.state = splitted_stat[2]; + stat.ppid = int.parse (splitted_stat[3]); + stat.pgrp = int.parse (splitted_stat[4]); - if (cmdline.length <= 0) { - // was empty, not an error - return true; - } - - command = cmdline; + return true; + } + + /** + * Reads the /proc/%pid%/cmdline file and updates from the information contained therein. + */ + private bool read_cmdline () { + string ? cmdline = ProcessUtils.read_file ("/proc/%d/cmdline".printf (stat.pid)); + if (cmdline.length <= 0) { + // was empty, not an error return true; } - + command = cmdline; + return true; + } + + private void get_usage (uint64 cpu_total, uint64 cpu_last_total) { + // Get CPU usage by process + GTop.ProcTime proc_time; + GTop.get_proc_time (out proc_time, stat.pid); + cpu_usage = ((double)(proc_time.rtime - cpu_last_used)) / (cpu_total - cpu_last_total); + cpu_last_used = proc_time.rtime; + + // Get memory usage by process + GTop.Memory mem; + GTop.get_mem (out mem); + + GTop.ProcMem proc_mem; + GTop.get_proc_mem (out proc_mem, stat.pid); + mem_usage = (proc_mem.resident - proc_mem.share) / 1024; // in KiB + + // also if it is using X Window Server + if (Gdk.Display.get_default () is Gdk.X11.Display) { + Wnck.ResourceUsage resu = Wnck.ResourceUsage.pid_read (Gdk.Display.get_default (), stat.pid); + mem_usage += (resu.total_bytes_estimate / 1024); + } } } diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index eb4e81bb..3b4e07f7 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -54,7 +54,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { wrapper.add ( ppid); /* ==========START COMMAND WIDGET============== */ - // command widget should be one-liner, but expandable on click + // command widget should be a widget that contains one line, but expands on click // when clicked it should reveal full command command = new Gtk.TextView (); command.buffer.text = "N/A"; From 001b6bf21c9905f3d8cfebc6544bb9fae4675ea1 Mon Sep 17 00:00:00 2001 From: stsdc Date: Sun, 19 Jan 2020 16:09:56 +0100 Subject: [PATCH 27/96] do not update command in ProcessInfoView --- src/Widgets/ProcessView/ProcessInfoView.vala | 9 ++++----- src/Widgets/ProcessView/ProcessView.vala | 3 ++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index 3b4e07f7..e84cc920 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -88,6 +88,10 @@ public class Monitor.ProcessInfoView : Gtk.Box { public void update (Process process) { // probably not ok to update everything + // TODO: find a better way to do this + if (pid.get_text() != ("PID:%d").printf (process.stat.pid)) { + command.buffer.text = process.command; + } application_name.set_text (("%s").printf (process.application_name)); application_name.tooltip_text = process.application_name; pid.set_text (("PID:%d").printf (process.stat.pid)); @@ -108,11 +112,6 @@ public class Monitor.ProcessInfoView : Gtk.Box { } } - // command.queue_resize (); - command.buffer.text = process.command; - // command.queue_resize (); - // command_wrapper.queue_resize (); - show_all (); } diff --git a/src/Widgets/ProcessView/ProcessView.vala b/src/Widgets/ProcessView/ProcessView.vala index 5c455612..27060f9b 100644 --- a/src/Widgets/ProcessView/ProcessView.vala +++ b/src/Widgets/ProcessView/ProcessView.vala @@ -21,7 +21,8 @@ public class Monitor.ProcessView : Gtk.Box { var paned = new Gtk.Paned (Gtk.Orientation.HORIZONTAL); paned.pack1 (process_tree_view_scrolled, true, false); paned.pack2 (process_info_view, false, false); - paned.set_position (500); + // paned.set_min_position (200); + paned.set_position (paned.max_position); paned.set_hexpand (true); add (paned); From 76e592ec28a54a032503404ac91760d2e3ac0239 Mon Sep 17 00:00:00 2001 From: stsdc Date: Sun, 19 Jan 2020 19:04:28 +0100 Subject: [PATCH 28/96] Show ProcessInfoView when process is selected #146 --- src/Widgets/ProcessView/ProcessInfoView.vala | 2 -- src/Widgets/ProcessView/ProcessView.vala | 5 ++++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index e84cc920..495d7b29 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -111,8 +111,6 @@ public class Monitor.ProcessInfoView : Gtk.Box { warning (e.message); } } - - show_all (); } public void pid_widget () { diff --git a/src/Widgets/ProcessView/ProcessView.vala b/src/Widgets/ProcessView/ProcessView.vala index 27060f9b..2d54fad5 100644 --- a/src/Widgets/ProcessView/ProcessView.vala +++ b/src/Widgets/ProcessView/ProcessView.vala @@ -6,7 +6,7 @@ public class Monitor.ProcessView : Gtk.Box { construct { process_info_view = new ProcessInfoView (); - + process_info_view.no_show_all = true; } public ProcessView (Model model) { @@ -26,9 +26,12 @@ public class Monitor.ProcessView : Gtk.Box { paned.set_hexpand (true); add (paned); + show_all (); } public void update (Process process) { process_info_view.update(process); + process_info_view.no_show_all = false; + process_info_view.show_all (); } } \ No newline at end of file From e06c6ceac198b16f30ad0722c341cf3ae7a8cf70 Mon Sep 17 00:00:00 2001 From: stsdc Date: Sun, 19 Jan 2020 20:24:47 +0100 Subject: [PATCH 29/96] display username in ProcessInfoView #148 --- src/Managers/Process.vala | 5 +++++ src/Widgets/ProcessView/ProcessInfoView.vala | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index bf0fc359..078f592e 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -15,6 +15,8 @@ public class Monitor.Process : GLib.Object { // User id public int uid; + public string username; + Icon _icon; public Icon icon { get { return _icon; } @@ -72,6 +74,9 @@ public class Monitor.Process : GLib.Object { GTop.get_proc_uid (out proc_uid, stat.pid); uid = proc_uid.uid; + // getting username + unowned Posix.Passwd passwd = Posix.getpwuid (uid); + username = passwd.pw_name; exists = parse_stat () && read_cmdline (); get_usage (0, 1); diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index 495d7b29..467ffa9f 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -7,6 +7,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { public Gtk.Label ppid; public Gtk.Label pgrp; public Gtk.Label state; + public Gtk.Label username; private Gtk.Image icon; private Regex? regex; @@ -47,11 +48,16 @@ public class Monitor.ProcessInfoView : Gtk.Box { pgrp.halign = Gtk.Align.START; pgrp.get_style_context ().add_class (Granite.STYLE_CLASS_BADGE); + username = new Gtk.Label (_ ("N/A")); + username.halign = Gtk.Align.START; + username.get_style_context ().add_class (Granite.STYLE_CLASS_BADGE); + var wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); wrapper.add (state); wrapper.add ( pid); wrapper.add ( pgrp); wrapper.add ( ppid); + wrapper.add ( username); /* ==========START COMMAND WIDGET============== */ // command widget should be a widget that contains one line, but expands on click @@ -98,6 +104,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { ppid.set_text (("PPID:%d").printf (process.stat.ppid)); pgrp.set_text (("PGRP:%d").printf (process.stat.pgrp)); state.set_text (process.stat.state); + username.set_text (process.username); var icon_name = process.icon.to_string (); From cae1cc1a40c7db70594a08545324f9b7c520c439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= Date: Sat, 22 Feb 2020 18:11:21 +0100 Subject: [PATCH 30/96] add RoundyLabel --- data/Application.css | 22 +++++++++ meson.build | 2 + src/Widgets/ProcessView/ProcessInfoView.vala | 51 +++++++++++--------- src/Widgets/ProcessView/RoundyLabel.vala | 20 ++++++++ 4 files changed, 71 insertions(+), 24 deletions(-) create mode 100644 src/Widgets/ProcessView/RoundyLabel.vala diff --git a/data/Application.css b/data/Application.css index b0188444..90f63e4e 100644 --- a/data/Application.css +++ b/data/Application.css @@ -14,6 +14,22 @@ border-width: 0; } +.state_badge, +.state_badge:hover, +.state_badge:selected, +.state_badge:selected:focus, +.state_badge:hover:selected { + background-image: none; + background-color: #8cd5ff; + box-shadow: none; + color: alpha(#002e99, 0.7); + font-weight: 700; + border-radius: 10px; + padding: 0 6px; + margin: 0 3px; + border-width: 0; +} + .command_wrapper { background-color: #fdf6e3; border-radius: 3px; @@ -27,3 +43,9 @@ .command { font-family: monospace; } + +.pid { + color:grey; +font-weight:bold; +font-size:9px; +} \ No newline at end of file diff --git a/meson.build b/meson.build index 173d9c56..4fe6db8a 100644 --- a/meson.build +++ b/meson.build @@ -64,6 +64,8 @@ executable( 'src/Widgets/Headerbar/Headerbar.vala', 'src/Widgets/Statusbar/Statusbar.vala', 'src/Widgets/ProcessView/ProcessInfoView.vala', + 'src/Widgets/ProcessView/RoundyLabel.vala', + 'src/Widgets/ProcessView/ProcessView.vala', 'src/Managers/ProcessUtils.vala', diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index 467ffa9f..114f2066 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -3,12 +3,11 @@ public class Monitor.ProcessInfoView : Gtk.Box { public string ? icon_name; public Gtk.TextView command; private Gtk.ScrolledWindow command_wrapper; - public Gtk.Label pid; - public Gtk.Label ppid; - public Gtk.Label pgrp; + public RoundyLabel ppid; + public RoundyLabel pgrp; public Gtk.Label state; public Gtk.Label username; - + public RoundyLabel pid; private Gtk.Image icon; private Regex? regex; private Gtk.Grid grid; @@ -20,10 +19,19 @@ public class Monitor.ProcessInfoView : Gtk.Box { hexpand = true; regex = /(?i:^.*\.(xpm|png)$)/; + var icon_container = new Gtk.Fixed (); + icon = new Gtk.Image.from_icon_name ("application-x-executable", Gtk.IconSize.DIALOG); icon.set_pixel_size (64); icon.valign = Gtk.Align.END; + state = new Gtk.Label (_ ("?")); + state.halign = Gtk.Align.START; + state.get_style_context ().add_class ("state_badge"); + + icon_container.put (icon, 0, 0); + icon_container.put (state, -5, 48); + application_name = new Gtk.Label (_ ("N/A")); application_name.get_style_context ().add_class ("h2"); application_name.ellipsize = Pango.EllipsizeMode.END; @@ -32,28 +40,21 @@ public class Monitor.ProcessInfoView : Gtk.Box { application_name.valign = Gtk.Align.START; - state = new Gtk.Label (_ ("?")); - state.halign = Gtk.Align.START; - state.get_style_context ().add_class (Granite.STYLE_CLASS_BADGE); - pid = new Gtk.Label (_ ("PID:N/A")); - pid.halign = Gtk.Align.START; - pid.get_style_context ().add_class (Granite.STYLE_CLASS_BADGE); - ppid = new Gtk.Label (_ ("PPID:N/A")); - ppid.halign = Gtk.Align.START; - ppid.get_style_context ().add_class (Granite.STYLE_CLASS_BADGE); + pid = new RoundyLabel (_("PID")); + ppid = new RoundyLabel (_("PPID")); + pgrp = new RoundyLabel (_("PGRP")); - pgrp = new Gtk.Label (_ ("PGRP:N/A")); - pgrp.halign = Gtk.Align.START; - pgrp.get_style_context ().add_class (Granite.STYLE_CLASS_BADGE); username = new Gtk.Label (_ ("N/A")); username.halign = Gtk.Align.START; username.get_style_context ().add_class (Granite.STYLE_CLASS_BADGE); + + var wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); - wrapper.add (state); + // wrapper.add (state); wrapper.add ( pid); wrapper.add ( pgrp); wrapper.add ( ppid); @@ -84,7 +85,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { grid.column_spacing = 12; - grid.attach ( icon, 0, 0, 1, 2); + grid.attach ( icon_container, 0, 0, 1, 2); grid.attach (application_name, 1, 0, 3, 1); grid.attach ( wrapper, 1, 1, 1, 1); @@ -95,14 +96,14 @@ public class Monitor.ProcessInfoView : Gtk.Box { public void update (Process process) { // probably not ok to update everything // TODO: find a better way to do this - if (pid.get_text() != ("PID:%d").printf (process.stat.pid)) { - command.buffer.text = process.command; - } + // if (pid_number.get_text() != ("%d").printf (process.stat.pid)) { + // command.buffer.text = process.command; + // } application_name.set_text (("%s").printf (process.application_name)); application_name.tooltip_text = process.application_name; - pid.set_text (("PID:%d").printf (process.stat.pid)); - ppid.set_text (("PPID:%d").printf (process.stat.ppid)); - pgrp.set_text (("PGRP:%d").printf (process.stat.pgrp)); + pid.set_text (("%d").printf (process.stat.pid)); + ppid.set_text (("%d").printf (process.stat.ppid)); + pgrp.set_text (("%d").printf (process.stat.pgrp)); state.set_text (process.stat.state); username.set_text (process.username); @@ -121,5 +122,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { } public void pid_widget () { + + } } \ No newline at end of file diff --git a/src/Widgets/ProcessView/RoundyLabel.vala b/src/Widgets/ProcessView/RoundyLabel.vala new file mode 100644 index 00000000..bf904dd6 --- /dev/null +++ b/src/Widgets/ProcessView/RoundyLabel.vala @@ -0,0 +1,20 @@ +public class Monitor.RoundyLabel : Gtk.Fixed { + + public Gtk.Label val; + public Gtk.Label desc; + + public RoundyLabel (string description) { + val = new Gtk.Label (_ ("N/A")); + val.get_style_context ().add_class (Granite.STYLE_CLASS_BADGE); + + desc = new Gtk.Label (description); + desc.get_style_context ().add_class ("pid"); + + put(val, 0, 12); + put(desc, 6, 0); + } + + public void set_text (string text) { + val.set_text (text); + } +} \ No newline at end of file From 7741bb4636faaa7914fc4c81778a4808943ab42d Mon Sep 17 00:00:00 2001 From: stsdc Date: Sat, 22 Feb 2020 19:20:29 +0100 Subject: [PATCH 31/96] display nice, priority and num_threads --- src/Managers/Process.vala | 3 ++ src/Managers/ProcessStructs.vala | 4 +- src/Widgets/ProcessView/ProcessInfoView.vala | 42 ++++++++++++++------ 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index 078f592e..3233792b 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -195,6 +195,9 @@ public class Monitor.Process : GLib.Object { stat.state = splitted_stat[2]; stat.ppid = int.parse (splitted_stat[3]); stat.pgrp = int.parse (splitted_stat[4]); + stat.priority = int.parse (splitted_stat[17]); + stat.nice = int.parse (splitted_stat[18]); + stat.num_threads = int.parse (splitted_stat[19]); return true; } diff --git a/src/Managers/ProcessStructs.vala b/src/Managers/ProcessStructs.vala index af76d210..3cd9e054 100644 --- a/src/Managers/ProcessStructs.vala +++ b/src/Managers/ProcessStructs.vala @@ -59,8 +59,10 @@ public struct Monitor.ProcessStatus { // range 19 (low priority) to -20 (high priority). public int nice; + public int priority; + // Number of threads in this process - public uint num_threads; + public int num_threads; // The time the process started after system boot. public uint64 starttime; diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index 114f2066..672ad580 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -5,13 +5,18 @@ public class Monitor.ProcessInfoView : Gtk.Box { private Gtk.ScrolledWindow command_wrapper; public RoundyLabel ppid; public RoundyLabel pgrp; + public RoundyLabel nice; + public RoundyLabel priority; + public RoundyLabel num_threads; public Gtk.Label state; - public Gtk.Label username; + public RoundyLabel username; public RoundyLabel pid; private Gtk.Image icon; private Regex? regex; private Gtk.Grid grid; + private Gtk.Popover pid_popover; + public ProcessInfoView () { // get_style_context ().add_class ("process_info"); margin = 12; @@ -41,23 +46,31 @@ public class Monitor.ProcessInfoView : Gtk.Box { - pid = new RoundyLabel (_("PID")); - ppid = new RoundyLabel (_("PPID")); - pgrp = new RoundyLabel (_("PGRP")); - + nice = new RoundyLabel (_("NI")); + priority = new RoundyLabel (_("PRI")); + num_threads = new RoundyLabel (_("THR")); + // ppid = new RoundyLabel (_("PPID")); + // pgrp = new RoundyLabel (_("PGRP")); + // pid_popover = new Gtk.Popover (pid); + // pid_popover.add (ppid); + // pid_popover.add (pgrp); - username = new Gtk.Label (_ ("N/A")); - username.halign = Gtk.Align.START; - username.get_style_context ().add_class (Granite.STYLE_CLASS_BADGE); + // pid_popover.show_all (); + // pid_popover.present (); + // pid_popover.run (); + // pid_popover.destroy (); + username = new RoundyLabel (""); var wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); // wrapper.add (state); wrapper.add ( pid); - wrapper.add ( pgrp); - wrapper.add ( ppid); + wrapper.add ( priority); + wrapper.add ( nice); + wrapper.add ( num_threads); + // wrapper.add ( ppid); wrapper.add ( username); /* ==========START COMMAND WIDGET============== */ @@ -100,10 +113,13 @@ public class Monitor.ProcessInfoView : Gtk.Box { // command.buffer.text = process.command; // } application_name.set_text (("%s").printf (process.application_name)); - application_name.tooltip_text = process.application_name; + application_name.tooltip_text = process.command; pid.set_text (("%d").printf (process.stat.pid)); - ppid.set_text (("%d").printf (process.stat.ppid)); - pgrp.set_text (("%d").printf (process.stat.pgrp)); + nice.set_text (("%d").printf (process.stat.nice)); + priority.set_text (("%d").printf (process.stat.priority)); + num_threads.set_text (("%d").printf (process.stat.num_threads)); + // ppid.set_text (("%d").printf (process.stat.ppid)); + // pgrp.set_text (("%d").printf (process.stat.pgrp)); state.set_text (process.stat.state); username.set_text (process.username); From 318a32adab22e0480eb5887142770e3417944ac2 Mon Sep 17 00:00:00 2001 From: stsdc Date: Mon, 24 Feb 2020 21:16:59 +0100 Subject: [PATCH 32/96] compiles with libdazzle --- meson.build | 6 +- src/Models/CPUGraphModel.vala | 59 + src/Widgets/ProcessView/CPUGraph.vala | 35 + .../ProcessView/CPUProcessTreeView.vala | 2 +- src/Widgets/ProcessView/ProcessInfoView.vala | 25 +- src/Widgets/ProcessView/ProcessView.vala | 2 + vapi/qqqq.vapi | 1991 +++++++++++++++++ 7 files changed, 2104 insertions(+), 16 deletions(-) create mode 100644 src/Models/CPUGraphModel.vala create mode 100644 src/Widgets/ProcessView/CPUGraph.vala create mode 100644 vapi/qqqq.vapi diff --git a/meson.build b/meson.build index 4fe6db8a..844730d9 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ -project('com.github.stsdc.monitor', 'vala', 'c', version: '0.6.2') +project('com.github.stsdc.monitor', 'vala', 'c', version: '1.0.0') # these are Meson modules gnome = import('gnome') @@ -23,6 +23,7 @@ gtop = dependency('libgtop-2.0') wnck = dependency('libwnck-3.0') wingpanel = dependency('wingpanel-2.0') gdk_x11 = dependency('gdk-x11-3.0') +dazzle = dependency('libdazzle-1.0') config_data = configuration_data() config_data.set_quoted('GETTEXT_PACKAGE', meson.project_name()) @@ -71,6 +72,8 @@ executable( # 'src/Models/GenericModel.vala', 'src/Models/Model.vala', + 'src/Models/CPUGraphModel.vala', + 'src/Widgets/ProcessView/CPUGraph.vala', # 'src/Models/ModelHelper.vala', 'src/Managers/AppManager.vala', @@ -98,6 +101,7 @@ executable( gtop, wnck, gdk_x11, + dazzle, meson.get_compiler('c').find_library('m', required : false), meson.get_compiler('vala').find_library('posix') ], diff --git a/src/Models/CPUGraphModel.vala b/src/Models/CPUGraphModel.vala new file mode 100644 index 00000000..aa7554c5 --- /dev/null +++ b/src/Models/CPUGraphModel.vala @@ -0,0 +1,59 @@ +// /* cpu-graph-model.vala +// * +// * Copyright (C) 2018 Red Hat, Inc. +// * Copyright (C) 2020 stsdc +// * +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see . +// * +// * Authors: Petr Štětka +// * Authors: Stanisław +// */ +public class CpuGraphModel : Dazzle.GraphModel { + public signal void big_process_usage (int column); + public signal void small_process_usage (int column); + private bool[] change_big_process_usage; + private bool[] change_small_process_usage; + + public CpuGraphModel () { + set_timespan (1000); + set_max_samples (50); + + var column_total = new Dazzle.GraphColumn ("TOTAL CPU", Type.from_name ("gdouble")); + add_column (column_total); + + // change_big_process_usage = new bool[get_num_processors()]; + // change_small_process_usage = new bool[get_num_processors()]; + + // for (int i = 0; i < get_num_processors(); i++) { + // var column_x_cpu = new GraphColumn("CPU: " + i.to_string(), Type.from_name("gdouble")); + // add_column(column_x_cpu); + + // change_big_process_usage[i] = true; + // change_small_process_usage[i] = true; + // } + + // Timeout.add(1000, update_data); + } + + bool update_data (int percentage) { + debug ("Got percentage: %d", percentage); + Dazzle.GraphModelIter iter; + + push (out iter, get_monotonic_time ()); + iter_set_value (iter, 0, percentage); + + return true; + } +} diff --git a/src/Widgets/ProcessView/CPUGraph.vala b/src/Widgets/ProcessView/CPUGraph.vala new file mode 100644 index 00000000..46056cfc --- /dev/null +++ b/src/Widgets/ProcessView/CPUGraph.vala @@ -0,0 +1,35 @@ +public class CpuGraph : Dazzle.GraphView + { + private static CpuGraphModel graph_model; + private Dazzle.GraphLineRenderer renderer; + private Gdk.RGBA line_color_max; + private Gdk.RGBA line_color_normal; + + class construct + { + } + + public CpuGraph(CpuGraphModel graph_model) { + this.graph_model = graph_model; + get_style_context().add_class("line_max"); + line_color_max = get_style_context().get_color(get_style_context().get_state()); + get_style_context().remove_class("line_max"); + get_style_context().add_class("line"); + line_color_normal = get_style_context().get_color(get_style_context().get_state()); + get_style_context().remove_class("line"); + get_style_context().add_class("big"); + + set_model(graph_model); + + Gdk.RGBA linecol = Gdk.RGBA (); + linecol.red = 1.0; linecol.green = 0.0; linecol.blue = 0.0; linecol.alpha = 1.0; + + renderer = new Dazzle.GraphLineRenderer(); + renderer.stroke_color_rgba = linecol; + renderer.line_width = 1; + renderer.column = 0; + + add_renderer (renderer); + + } + } diff --git a/src/Widgets/ProcessView/CPUProcessTreeView.vala b/src/Widgets/ProcessView/CPUProcessTreeView.vala index 8639589a..6a6f1476 100644 --- a/src/Widgets/ProcessView/CPUProcessTreeView.vala +++ b/src/Widgets/ProcessView/CPUProcessTreeView.vala @@ -1,5 +1,5 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { - private new Model model; + private Model model; private Gtk.TreeViewColumn name_column; private Gtk.TreeViewColumn pid_column; private Gtk.TreeViewColumn cpu_column; diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index 672ad580..2fc2c858 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -76,20 +76,20 @@ public class Monitor.ProcessInfoView : Gtk.Box { /* ==========START COMMAND WIDGET============== */ // command widget should be a widget that contains one line, but expands on click // when clicked it should reveal full command - command = new Gtk.TextView (); - command.buffer.text = "N/A"; - command.pixels_above_lines = 3; - command.margin = 8; - command.set_wrap_mode (Gtk.WrapMode.WORD); + // command = new Gtk.TextView (); + // command.buffer.text = "N/A"; + // command.pixels_above_lines = 3; + // command.margin = 8; + // command.set_wrap_mode (Gtk.WrapMode.WORD); // setting resize mode, so command wraps immediatly when right sidebar changed // command.resize_mode = Gtk.ResizeMode.IMMEDIATE; - command.get_style_context ().add_class ("command"); + // command.get_style_context ().add_class ("command"); - command_wrapper = new Gtk.ScrolledWindow (null, null); - command_wrapper.get_style_context ().add_class ("command_wrapper"); - command_wrapper.margin_top = 24; + // command_wrapper = new Gtk.ScrolledWindow (null, null); + // command_wrapper.get_style_context ().add_class ("command_wrapper"); + // command_wrapper.margin_top = 24; // command_wrapper.resize_mode = Gtk.ResizeMode.IMMEDIATE; - command_wrapper.add (command); + // command_wrapper.add (command); /* ==========END COMMAND WIDGET============== */ @@ -103,7 +103,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { grid.attach ( wrapper, 1, 1, 1, 1); add ( grid); - add (command_wrapper); + // add (command_wrapper); } public void update (Process process) { @@ -137,8 +137,5 @@ public class Monitor.ProcessInfoView : Gtk.Box { } } - public void pid_widget () { - - } } \ No newline at end of file diff --git a/src/Widgets/ProcessView/ProcessView.vala b/src/Widgets/ProcessView/ProcessView.vala index 2d54fad5..6d56ef5c 100644 --- a/src/Widgets/ProcessView/ProcessView.vala +++ b/src/Widgets/ProcessView/ProcessView.vala @@ -6,6 +6,8 @@ public class Monitor.ProcessView : Gtk.Box { construct { process_info_view = new ProcessInfoView (); + + // hide on startup process_info_view.no_show_all = true; } diff --git a/vapi/qqqq.vapi b/vapi/qqqq.vapi new file mode 100644 index 00000000..84a748b3 --- /dev/null +++ b/vapi/qqqq.vapi @@ -0,0 +1,1991 @@ +/* libdazzle-1.0.vapi generated by vapigen, do not modify. */ + +[CCode (cprefix = "Dzl", gir_namespace = "Dazzle", gir_version = "1.0", lower_case_cprefix = "dzl_")] +namespace Dazzle { + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_animation_get_type ()")] + public class Animation : GLib.InitiallyUnowned { + [CCode (has_construct_function = false)] + protected Animation (); + public void add_property (GLib.ParamSpec pspec, GLib.Value value); + public static uint calculate_duration (Gdk.Monitor monitor, double from_value, double to_value); + public void start (); + public void stop (); + [NoAccessorMethod] + public uint duration { construct; } + [NoAccessorMethod] + public Gdk.FrameClock frame_clock { construct; } + [NoAccessorMethod] + public Dazzle.AnimationMode mode { construct; } + [NoAccessorMethod] + public GLib.Object target { construct; } + public signal void tick (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_application_get_type ()")] + public class Application : Gtk.Application, GLib.ActionGroup, GLib.ActionMap { + [CCode (has_construct_function = false)] + protected Application (); + public virtual void add_resources (string resource_path); + public unowned GLib.Menu get_menu_by_id (string menu_id); + public unowned Dazzle.MenuManager get_menu_manager (); + public unowned Dazzle.ShortcutManager get_shortcut_manager (); + public unowned Dazzle.ThemeManager get_theme_manager (); + public virtual void remove_resources (string resource_path); + public Dazzle.MenuManager menu_manager { get; } + public Dazzle.ShortcutManager shortcut_manager { get; } + public Dazzle.ThemeManager theme_manager { get; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_application_window_get_type ()")] + public class ApplicationWindow : Gtk.ApplicationWindow, Atk.Implementor, GLib.ActionGroup, GLib.ActionMap, Gtk.Buildable { + [CCode (has_construct_function = false)] + protected ApplicationWindow (); + [Version (since = "3.26")] + public virtual bool get_fullscreen (); + [Version (since = "3.26")] + public unowned Gtk.Widget get_titlebar (); + [Version (since = "3.26")] + public virtual void set_fullscreen (bool fullscreen); + [Version (since = "3.26")] + public void set_titlebar (Gtk.Widget titlebar); + public bool fullscreen { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_bin_get_type ()")] + public class Bin : Gtk.Bin, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public Bin (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_binding_group_get_type ()")] + public class BindingGroup : GLib.Object { + [CCode (has_construct_function = false)] + public BindingGroup (); + public void bind (string source_property, GLib.Object target, string target_property, GLib.BindingFlags flags); + public void bind_full (string source_property, GLib.Object target, string target_property, GLib.BindingFlags flags, GLib.BindingTransformFunc? transform_to, owned GLib.BindingTransformFunc? transform_from); + public void bind_with_closures (string source_property, GLib.Object target, string target_property, GLib.BindingFlags flags, GLib.Closure? transform_to, GLib.Closure? transform_from); + public unowned GLib.Object? get_source (); + public void set_source (GLib.Object? source); + public GLib.Object source { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_bolding_label_get_type ()")] + public class BoldingLabel : Gtk.Label, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false)] + protected BoldingLabel (); + public void set_bold (bool bold); + public void set_weight (Pango.Weight weight); + public bool bold { set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_box_get_type ()")] + public class Box : Gtk.Box, Atk.Implementor, Gtk.Buildable, Gtk.Orientable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public Box (); + public int get_max_width_request (); + public unowned Gtk.Widget? get_nth_child (uint nth); + public void set_max_width_request (int max_width_request); + public int max_width_request { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_box_theatric_get_type ()")] + public class BoxTheatric : GLib.Object { + [CCode (has_construct_function = false)] + protected BoxTheatric (); + [NoAccessorMethod] + public double alpha { get; set; } + [NoAccessorMethod] + public string background { owned get; set; } + [NoAccessorMethod] + public int height { get; set; } + [NoAccessorMethod] + public GLib.Icon icon { owned get; set; } + [NoAccessorMethod] + public void* surface { construct; } + [NoAccessorMethod] + public Gtk.Widget target { owned get; construct; } + [NoAccessorMethod] + public int width { get; set; } + [NoAccessorMethod] + public int x { get; set; } + [NoAccessorMethod] + public int y { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_centering_bin_get_type ()")] + public class CenteringBin : Gtk.Bin, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public CenteringBin (); + [NoAccessorMethod] + public int max_width_request { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_child_property_action_get_type ()")] + public class ChildPropertyAction : GLib.Object, GLib.Action { + [CCode (has_construct_function = false)] + protected ChildPropertyAction (); + public static GLib.Action @new (string name, Gtk.Container container, Gtk.Widget child, string child_property_name); + [NoAccessorMethod] + public Gtk.Widget child { owned get; } + [NoAccessorMethod] + public string child_property_name { owned get; } + [NoAccessorMethod] + public Gtk.Container container { owned get; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_column_layout_get_type ()")] + public class ColumnLayout : Gtk.Container, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public ColumnLayout (); + public int get_column_spacing (); + public int get_column_width (); + public uint get_max_columns (); + public int get_row_spacing (); + public void set_column_spacing (int column_spacing); + public void set_column_width (int column_width); + public void set_max_columns (uint max_columns); + public void set_row_spacing (int row_spacing); + public int column_spacing { get; set; } + public int column_width { get; set; } + public uint max_columns { get; set; } + public int row_spacing { get; set; } + } + [CCode (cheader_filename = "dazzle.h", ref_function = "dzl_counter_arena_ref", type_id = "dzl_counter_arena_get_type ()", unref_function = "dzl_counter_arena_unref")] + [Compact] + public class CounterArena { + [CCode (has_construct_function = false)] + public CounterArena.for_pid (GLib.Pid pid); + public void @foreach (Dazzle.CounterForeachFunc func); + [CCode (cheader_filename = "dazzle.h")] + public static Dazzle.CounterArena get_default (); + public Dazzle.CounterArena @ref (); + public void register (Dazzle.Counter counter); + public void unref (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_counters_window_get_type ()")] + public class CountersWindow : Gtk.Window, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public CountersWindow (); + public unowned Dazzle.CounterArena? get_arena (); + public void set_arena (Dazzle.CounterArena arena); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_cpu_graph_get_type ()")] + public class CpuGraph : Dazzle.GraphView, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false)] + protected CpuGraph (); + [CCode (has_construct_function = false, type = "GtkWidget*")] + public CpuGraph.full (int64 timespan, uint max_samples); + [NoAccessorMethod] + public uint max_samples { get; construct; } + [NoAccessorMethod] + public int64 timespan { get; construct; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_cpu_model_get_type ()")] + public class CpuModel : Dazzle.GraphModel { + [CCode (has_construct_function = false, type = "DzlGraphModel*")] + public CpuModel (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_css_provider_get_type ()")] + public class CssProvider : Gtk.CssProvider, Gtk.StyleProvider { + [CCode (has_construct_function = false, type = "GtkCssProvider*")] + public CssProvider (string base_path); + [NoAccessorMethod] + public string base_path { owned get; construct; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_directory_model_get_type ()")] + public class DirectoryModel : GLib.Object, GLib.ListModel { + [CCode (has_construct_function = false)] + protected DirectoryModel (); + public unowned GLib.File get_directory (); + public static GLib.ListModel @new (GLib.File directory); + public void set_directory (GLib.File directory); + public void set_visible_func (owned Dazzle.DirectoryModelVisibleFunc visible_func); + public GLib.File directory { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_directory_reaper_get_type ()")] + public class DirectoryReaper : GLib.Object { + [CCode (has_construct_function = false)] + public DirectoryReaper (); + public void add_directory (GLib.File directory, GLib.TimeSpan min_age); + public void add_file (GLib.File file, GLib.TimeSpan min_age); + public void add_glob (GLib.File directory, string glob, GLib.TimeSpan min_age); + public bool execute (GLib.Cancellable? cancellable = null) throws GLib.Error; + public async bool execute_async (GLib.Cancellable? cancellable = null) throws GLib.Error; + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_dock_bin_get_type ()")] + public class DockBin : Gtk.Container, Atk.Implementor, Dazzle.Dock, Dazzle.DockItem, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public DockBin (); + public unowned Gtk.Widget get_bottom_edge (); + public unowned Gtk.Widget? get_center_widget (); + public unowned Gtk.Widget get_left_edge (); + public unowned Gtk.Widget get_right_edge (); + public unowned Gtk.Widget get_top_edge (); + [NoAccessorMethod] + public bool bottom_visible { get; set; } + [NoAccessorMethod] + public bool left_visible { get; set; } + [NoAccessorMethod] + public bool right_visible { get; set; } + [NoAccessorMethod] + public bool top_visible { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_dock_bin_edge_get_type ()")] + public class DockBinEdge : Dazzle.DockRevealer, Atk.Implementor, Dazzle.DockItem, Gtk.Buildable { + [CCode (has_construct_function = false)] + protected DockBinEdge (); + public Gtk.PositionType get_edge (); + [NoAccessorMethod] + public Gtk.PositionType edge { get; set; } + public virtual signal void move_to_bin_child (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_dock_manager_get_type ()")] + public class DockManager : GLib.Object { + [CCode (has_construct_function = false)] + public DockManager (); + [Version (since = "3.26")] + public void pause_grabs (); + public void release_transient_grab (); + [Version (since = "3.26")] + public void unpause_grabs (); + [HasEmitter] + public virtual signal void register_dock (Dazzle.Dock dock); + [HasEmitter] + public virtual signal void unregister_dock (Dazzle.Dock dock); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_dock_overlay_get_type ()")] + public class DockOverlay : Gtk.EventBox, Atk.Implementor, Dazzle.Dock, Dazzle.DockItem, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public DockOverlay (); + public unowned Dazzle.DockOverlayEdge get_edge (Gtk.PositionType position); + public unowned Gtk.Adjustment get_edge_adjustment (Gtk.PositionType position); + public virtual signal void hide_edges (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_dock_overlay_edge_get_type ()")] + public class DockOverlayEdge : Dazzle.Bin, Atk.Implementor, Dazzle.DockItem, Gtk.Buildable { + [CCode (has_construct_function = false)] + protected DockOverlayEdge (); + public Gtk.PositionType get_edge (); + public int get_position (); + public void set_edge (Gtk.PositionType edge); + public void set_position (int position); + public Gtk.PositionType edge { get; set; } + public int position { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_dock_paned_get_type ()")] + public class DockPaned : Dazzle.MultiPaned, Atk.Implementor, Dazzle.DockItem, Gtk.Buildable, Gtk.Orientable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public DockPaned (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_dock_revealer_get_type ()")] + public class DockRevealer : Dazzle.Bin, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public DockRevealer (); + public void animate_to_position (int position, uint transition_duration); + public bool get_child_revealed (); + public int get_position (); + public bool get_position_set (); + public bool get_reveal_child (); + public uint get_transition_duration (); + public Dazzle.DockRevealerTransitionType get_transition_type (); + public bool is_animating (); + public void set_position (int position); + public void set_position_set (bool position_set); + public void set_reveal_child (bool reveal_child); + public void set_transition_duration (uint transition_duration); + public void set_transition_type (Dazzle.DockRevealerTransitionType transition_type); + public bool child_revealed { get; } + public int position { get; set; } + public bool position_set { get; set; } + public bool reveal_child { get; set; } + public uint transition_duration { get; set; } + public Dazzle.DockRevealerTransitionType transition_type { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_dock_stack_get_type ()")] + public class DockStack : Gtk.Box, Atk.Implementor, Dazzle.DockItem, Gtk.Buildable, Gtk.Orientable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public DockStack (); + public Gtk.PositionType get_edge (); + public bool get_show_pinned_button (); + public Dazzle.TabStyle get_style (); + public void set_edge (Gtk.PositionType edge); + public void set_show_pinned_button (bool show_pinned_button); + public void set_style (Dazzle.TabStyle style); + public Gtk.PositionType edge { get; set; } + public bool show_pinned_button { get; set; } + public Dazzle.TabStyle style { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_dock_transient_grab_get_type ()")] + public class DockTransientGrab : GLib.Object { + [CCode (has_construct_function = false)] + public DockTransientGrab (); + public void acquire (); + public void add_item (Dazzle.DockItem item); + public void cancel (); + public bool contains (Dazzle.DockItem item); + public uint get_timeout (); + public bool is_descendant (Gtk.Widget widget); + public void release (); + public void remove_item (Dazzle.DockItem item); + public void set_timeout (uint timeout); + public void steal_common_ancestors (Dazzle.DockTransientGrab other); + public uint timeout { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_dock_widget_get_type ()")] + public class DockWidget : Dazzle.Bin, Atk.Implementor, Dazzle.DockItem, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public DockWidget (); + public void set_icon_name (string icon_name); + public void set_title (string title); + [NoAccessorMethod] + public bool can_close { get; set; } + [NoAccessorMethod] + public string icon_name { owned get; set; } + [NoAccessorMethod] + public Dazzle.DockManager manager { owned get; set; } + [NoAccessorMethod] + public string title { owned get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_dock_window_get_type ()")] + public class DockWindow : Gtk.Window, Atk.Implementor, Dazzle.Dock, Dazzle.DockItem, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public DockWindow (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_elastic_bin_get_type ()")] + public class ElasticBin : Gtk.Bin, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public ElasticBin (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_empty_state_get_type ()")] + public class EmptyState : Gtk.Bin, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public EmptyState (); + public unowned string get_icon_name (); + public unowned string get_subtitle (); + public unowned string get_title (); + public void set_icon_name (string icon_name); + public void set_resource (string resource); + public void set_subtitle (string title); + public void set_title (string title); + public string icon_name { get; set; } + [NoAccessorMethod] + public int pixel_size { get; set; } + public string resource { set; } + public string subtitle { get; set; } + public string title { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_entry_box_get_type ()")] + public class EntryBox : Gtk.Box, Atk.Implementor, Gtk.Buildable, Gtk.Orientable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public EntryBox (); + [NoAccessorMethod] + public int max_width_chars { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_file_chooser_entry_get_type ()")] + public class FileChooserEntry : Gtk.Bin, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public FileChooserEntry (string title, Gtk.FileChooserAction action); + public GLib.File? get_file (); + public void set_file (GLib.File file); + [NoAccessorMethod] + public Gtk.FileChooserAction action { get; set; } + [NoAccessorMethod] + public bool create_folders { get; set; } + [NoAccessorMethod] + public bool do_overwrite_confirmation { get; set; } + public GLib.File file { owned get; set; } + [NoAccessorMethod] + public Gtk.FileFilter filter { owned get; set; } + [NoAccessorMethod] + public bool local_only { get; set; } + [NoAccessorMethod] + public int max_width_chars { get; set; } + [NoAccessorMethod] + public bool show_hidden { get; set; } + [NoAccessorMethod] + public string title { owned get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_file_transfer_get_type ()")] + public class FileTransfer : GLib.Object { + [CCode (has_construct_function = false)] + public FileTransfer (); + public void add (GLib.File src, GLib.File dest); + public bool execute (int io_priority = GLib.Priority.LOW, GLib.Cancellable? cancellable = null) throws GLib.Error; + public async bool execute_async (int io_priority = GLib.Priority.LOW, GLib.Cancellable? cancellable = null) throws GLib.Error; + public Dazzle.FileTransferFlags get_flags (); + public double get_progress (); + public void set_flags (Dazzle.FileTransferFlags flags); + [Version (since = "3.28")] + public Dazzle.FileTransferStat stat (); + public Dazzle.FileTransferFlags flags { get; set; } + public double progress { get; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_fuzzy_index_get_type ()")] + public class FuzzyIndex : GLib.Object { + [CCode (has_construct_function = false)] + public FuzzyIndex (); + public GLib.Variant? get_metadata (string key); + public unowned string get_metadata_string (string key); + public uint32 get_metadata_uint32 (string key); + public uint64 get_metadata_uint64 (string key); + public bool load_file (GLib.File file, GLib.Cancellable? cancellable = null) throws GLib.Error; + public async bool load_file_async (GLib.File file, GLib.Cancellable? cancellable = null) throws GLib.Error; + public async GLib.ListModel query_async (string query, uint max_matches, GLib.Cancellable? cancellable = null) throws GLib.Error; + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_fuzzy_index_builder_get_type ()")] + public class FuzzyIndexBuilder : GLib.Object { + [CCode (has_construct_function = false)] + public FuzzyIndexBuilder (); + public bool get_case_sensitive (); + public unowned GLib.Variant get_document (uint64 document_id); + public uint64 insert (string key, GLib.Variant document, uint priority); + public void set_case_sensitive (bool case_sensitive); + public void set_metadata (string key, GLib.Variant value); + public void set_metadata_string (string key, string value); + public void set_metadata_uint32 (string key, uint32 value); + public void set_metadata_uint64 (string key, uint64 value); + public bool write (GLib.File file, int io_priority = GLib.Priority.LOW, GLib.Cancellable? cancellable = null) throws GLib.Error; + public async bool write_async (GLib.File file, int io_priority = GLib.Priority.LOW, GLib.Cancellable? cancellable = null) throws GLib.Error; + public bool case_sensitive { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_fuzzy_index_cursor_get_type ()")] + public class FuzzyIndexCursor : GLib.Object, GLib.AsyncInitable, GLib.ListModel { + [CCode (has_construct_function = false)] + protected FuzzyIndexCursor (); + public unowned Dazzle.FuzzyIndex get_index (); + [NoAccessorMethod] + public bool case_sensitive { get; construct; } + [NoAccessorMethod] + public Dazzle.FuzzyIndex index { construct; } + [NoAccessorMethod] + public uint max_matches { get; construct; } + [NoAccessorMethod] + public string query { owned get; construct; } + [NoAccessorMethod] + public GLib.VariantDict tables { construct; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_fuzzy_index_match_get_type ()")] + public class FuzzyIndexMatch : GLib.Object { + [CCode (has_construct_function = false)] + protected FuzzyIndexMatch (); + public unowned GLib.Variant get_document (); + public unowned string get_key (); + public uint get_priority (); + public float get_score (); + public GLib.Variant document { get; construct; } + public string key { get; construct; } + public uint priority { get; construct; } + public float score { get; construct; } + } + [CCode (cheader_filename = "dazzle.h", ref_function = "dzl_fuzzy_mutable_index_ref", type_id = "dzl_fuzzy_mutable_index_get_type ()", unref_function = "dzl_fuzzy_mutable_index_unref")] + [Compact] + public class FuzzyMutableIndex { + [CCode (has_construct_function = false)] + public FuzzyMutableIndex (bool case_sensitive); + public void begin_bulk_insert (); + public bool contains (string key); + public void end_bulk_insert (); + public void insert (string key, void* value); + public GLib.Array match (string needle, size_t max_matches); + public Dazzle.FuzzyMutableIndex @ref (); + public void remove (string key); + public void set_free_func (GLib.DestroyNotify free_func); + public void unref (); + [CCode (has_construct_function = false)] + public FuzzyMutableIndex.with_free_func (bool case_sensitive, GLib.DestroyNotify free_func); + } + [CCode (cheader_filename = "dazzle.h", lower_case_csuffix = "graph_view_column", type_id = "dzl_graph_view_column_get_type ()")] + public class GraphColumn : GLib.Object { + [CCode (has_construct_function = false)] + public GraphColumn (string name, GLib.Type value_type); + public unowned string get_name (); + public void set_name (string name); + public string name { get; set; } + [NoAccessorMethod] + public GLib.Type value_type { get; construct; } + } + [CCode (cheader_filename = "dazzle.h", lower_case_csuffix = "graph_view_line_renderer", type_id = "dzl_graph_view_line_renderer_get_type ()")] + public class GraphLineRenderer : GLib.Object, Dazzle.GraphRenderer { + [CCode (has_construct_function = false)] + public GraphLineRenderer (); + public unowned Gdk.RGBA? get_stroke_color_rgba (); + public void set_stroke_color (string stroke_color); + public void set_stroke_color_rgba (Gdk.RGBA stroke_color_rgba); + [NoAccessorMethod] + public uint column { get; set; } + [NoAccessorMethod] + public double line_width { get; set; } + [NoAccessorMethod] + public string stroke_color { owned get; set; } + public Gdk.RGBA stroke_color_rgba { get; set; } + } + [CCode (cheader_filename = "dazzle.h", lower_case_csuffix = "graph_view_model", type_id = "dzl_graph_view_model_get_type ()")] + public class GraphModel : GLib.Object { + [CCode (has_construct_function = false)] + public GraphModel (); + public uint add_column (Dazzle.GraphColumn column); + public int64 get_end_time (); + public bool get_iter_first (Dazzle.GraphModelIter iter); + public bool get_iter_last (Dazzle.GraphModelIter iter); + public uint get_max_samples (); + public uint get_n_columns (); + public GLib.TimeSpan get_timespan (); + public static int64 iter_get_timestamp (Dazzle.GraphModelIter iter); + public static void iter_get_value (Dazzle.GraphModelIter iter, uint column, GLib.Value value); + public static bool iter_next (Dazzle.GraphModelIter iter); + [Version (since = "3.30")] + public static void iter_set_value (Dazzle.GraphModelIter iter, uint column, GLib.Value value); + public void push (out Dazzle.GraphModelIter iter, int64 timestamp); + public void set_max_samples (uint n_rows); + public void set_timespan (GLib.TimeSpan timespan); + public uint max_samples { get; set construct; } + public int64 timespan { get; set construct; } + [NoAccessorMethod] + public double value_max { get; set; } + [NoAccessorMethod] + public double value_min { get; set; } + public signal void changed (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_graph_view_get_type ()")] + public class GraphView : Gtk.DrawingArea, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public GraphView (); + public void add_renderer (Dazzle.GraphRenderer renderer); + public unowned Dazzle.GraphModel? get_model (); + public void set_model (Dazzle.GraphModel model); + public Dazzle.GraphModel model { get; set; } + } + [CCode (cheader_filename = "dazzle.h", ref_function = "dzl_heap_ref", type_id = "dzl_heap_get_type ()", unref_function = "dzl_heap_unref")] + [Compact] + public class Heap { + public weak string data; + public size_t len; + [CCode (has_construct_function = false)] + public Heap (uint element_size, [CCode (scope = "async")] GLib.CompareFunc compare_func); + public bool extract (void* result); + public bool extract_index (size_t index_, void* result); + public void insert_vals (void* data, uint len); + public Dazzle.Heap @ref (); + public void unref (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_joined_menu_get_type ()")] + public class JoinedMenu : GLib.MenuModel { + [CCode (has_construct_function = false)] + public JoinedMenu (); + public void append_menu (GLib.MenuModel model); + public uint get_n_joined (); + public void prepend_menu (GLib.MenuModel model); + public void remove_index (uint index); + public void remove_menu (GLib.MenuModel model); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_list_box_get_type ()")] + public class ListBox : Gtk.ListBox, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public ListBox (GLib.Type row_type, string property_name); + public unowned GLib.ListModel? get_model (); + public unowned string get_property_name (); + public GLib.Type get_row_type (); + public void set_model (GLib.ListModel model); + [Version (since = "3.28")] + public void set_recycle_max (uint recycle_max); + public string property_name { get; construct; } + public GLib.Type row_type { get; construct; } + [NoAccessorMethod] + public string row_type_name { construct; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_list_box_row_get_type ()")] + public abstract class ListBoxRow : Gtk.ListBoxRow, Atk.Implementor, Gtk.Actionable, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public ListBoxRow (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_list_model_filter_get_type ()")] + public class ListModelFilter : GLib.Object, GLib.ListModel { + [CCode (has_construct_function = false)] + public ListModelFilter (GLib.ListModel child_model); + public unowned GLib.ListModel get_child_model (); + public void invalidate (); + public void set_filter_func (owned Dazzle.ListModelFilterFunc filter_func); + public GLib.ListModel child_model { get; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_list_store_adapter_get_type ()")] + public class ListStoreAdapter : GLib.Object, Gtk.TreeModel { + [CCode (has_construct_function = false)] + public ListStoreAdapter (GLib.ListModel model); + [Version (since = "3.26")] + public unowned GLib.ListModel get_model (); + public void set_model (GLib.ListModel model); + public GLib.ListModel model { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_menu_button_get_type ()")] + public class MenuButton : Gtk.MenuButton, Atk.Implementor, Gtk.Actionable, Gtk.Activatable, Gtk.Buildable { + [CCode (has_construct_function = false)] + protected MenuButton (); + [Version (since = "3.26")] + public unowned GLib.MenuModel? get_model (); + public bool get_show_accels (); + public bool get_show_arrow (); + public bool get_show_icons (); + public void set_model (GLib.MenuModel model); + [Version (since = "3.26")] + public void set_show_accels (bool show_accels); + [Version (since = "3.26")] + public void set_show_arrow (bool show_arrow); + [Version (since = "3.26")] + public void set_show_icons (bool show_icons); + [CCode (has_construct_function = false, type = "GtkWidget*")] + public MenuButton.with_model (string icon_name, GLib.MenuModel? model); + [NoAccessorMethod] + public string icon_name { set; } + [NoAccessorMethod] + [Version (since = "3.26")] + public string menu_id { set; } + public GLib.MenuModel model { get; set; } + public bool show_accels { get; set; } + public bool show_arrow { get; set; } + public bool show_icons { get; set; } + [NoAccessorMethod] + public bool transitions_enabled { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_menu_manager_get_type ()")] + [Version (since = "3.26")] + public class MenuManager : GLib.Object { + [CCode (has_construct_function = false)] + public MenuManager (); + public uint add_filename (string filename) throws GLib.Error; + public uint add_resource (string resource) throws GLib.Error; + public unowned GLib.Menu get_menu_by_id (string menu_id); + public uint merge (string menu_id, GLib.MenuModel model); + public void remove (uint merge_id); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_multi_paned_get_type ()")] + public class MultiPaned : Gtk.Container, Atk.Implementor, Gtk.Buildable, Gtk.Orientable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public MultiPaned (); + [Version (since = "3.28")] + public unowned Gtk.Widget? get_at_point (int x, int y); + public uint get_n_children (); + public unowned Gtk.Widget get_nth_child (uint nth); + [NoAccessorMethod] + public Gtk.Orientation orientation { get; set; } + public virtual signal void resize_drag_begin (Gtk.Widget child); + public virtual signal void resize_drag_end (Gtk.Widget child); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_path_get_type ()")] + public class Path : GLib.Object { + [CCode (has_construct_function = false)] + public Path (); + public void append (Dazzle.PathElement element); + public unowned Dazzle.PathElement? get_element (uint index); + public unowned GLib.List get_elements (); + public uint get_length (); + public bool has_prefix (Dazzle.Path prefix); + public bool is_empty (); + public void prepend (Dazzle.PathElement element); + public string printf (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_path_bar_get_type ()")] + public class PathBar : Gtk.Box, Atk.Implementor, Gtk.Buildable, Gtk.Orientable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public PathBar (); + public unowned Dazzle.Path get_path (); + public void set_path (Dazzle.Path path); + public void set_selected_index (uint index); + public Dazzle.Path path { get; set; } + public signal void element_selected (Dazzle.Path object, Dazzle.PathElement p0); + public signal void populate_menu (Dazzle.Path object, Dazzle.PathElement p0, GLib.Menu p1); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_path_element_get_type ()")] + public class PathElement : GLib.Object { + [CCode (has_construct_function = false)] + [Version (since = "3.26")] + public PathElement (string? id, string? icon_name, string title); + [Version (since = "3.26")] + public unowned string? get_icon_name (); + [Version (since = "3.26")] + public unowned string get_id (); + [Version (since = "3.26")] + public unowned string? get_title (); + [Version (since = "3.26")] + public string icon_name { get; construct; } + [Version (since = "3.26")] + public string id { get; construct; } + [Version (since = "3.26")] + public string title { get; construct; } + } + [CCode (cheader_filename = "dazzle.h", ref_function = "dzl_pattern_spec_ref", type_id = "dzl_pattern_spec_get_type ()", unref_function = "dzl_pattern_spec_unref")] + [Compact] + public class PatternSpec { + [CCode (has_construct_function = false)] + public PatternSpec (string keywords); + public unowned string get_text (); + public bool match (string haystack); + public Dazzle.PatternSpec @ref (); + public void unref (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_pill_box_get_type ()")] + public class PillBox : Gtk.EventBox, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public PillBox (string label); + public unowned string get_label (); + public void set_label (string label); + public string label { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_preferences_bin_get_type ()")] + public class PreferencesBin : Gtk.Bin, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false)] + protected PreferencesBin (); + [NoWrapper] + public virtual void connect (GLib.Settings settings); + [NoWrapper] + public virtual void disconnect (GLib.Settings settings); + [NoWrapper] + public virtual bool matches (Dazzle.PatternSpec spec); + [NoAccessorMethod] + public string keywords { owned get; construct; } + [NoAccessorMethod] + public string path { owned get; construct; } + [NoAccessorMethod] + public int priority { get; construct; } + [NoAccessorMethod] + public string schema_id { owned get; construct; } + public signal void preference_activated (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_preferences_entry_get_type ()")] + public class PreferencesEntry : Dazzle.PreferencesBin, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false)] + protected PreferencesEntry (); + public unowned Gtk.Widget get_entry_widget (); + public unowned Gtk.Widget get_title_widget (); + [NoAccessorMethod] + public string text { owned get; set; } + [NoAccessorMethod] + public string title { owned get; set; } + public signal void activate (); + public signal void changed (string object); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_preferences_file_chooser_button_get_type ()")] + public class PreferencesFileChooserButton : Dazzle.PreferencesBin, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false)] + protected PreferencesFileChooserButton (); + [NoAccessorMethod] + public Gtk.FileChooserAction action { get; construct; } + [NoAccessorMethod] + public string key { owned get; construct; } + [NoAccessorMethod] + public string subtitle { owned get; construct; } + [NoAccessorMethod] + public string title { owned get; construct; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_preferences_flow_box_get_type ()")] + public class PreferencesFlowBox : Dazzle.ColumnLayout, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public PreferencesFlowBox (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_preferences_font_button_get_type ()")] + public class PreferencesFontButton : Dazzle.PreferencesBin, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false)] + protected PreferencesFontButton (); + [NoAccessorMethod] + public string key { owned get; construct; } + [NoAccessorMethod] + public string title { owned get; construct; } + public signal void activate (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_preferences_group_get_type ()")] + public class PreferencesGroup : Gtk.Bin, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false)] + protected PreferencesGroup (); + public void add (Gtk.Widget widget); + public int get_priority (); + public unowned string get_title (); + public uint refilter (Dazzle.PatternSpec spec); + public void set_map (GLib.HashTable map); + [NoAccessorMethod] + public bool is_list { get; construct; } + [NoAccessorMethod] + public Gtk.SelectionMode mode { get; set; } + public int priority { get; construct; } + public string title { get; construct; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_preferences_page_get_type ()")] + public class PreferencesPage : Gtk.Bin, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false)] + protected PreferencesPage (); + public void add_group (Dazzle.PreferencesGroup group); + public unowned Dazzle.PreferencesGroup? get_group (string group_name); + public void refilter (Dazzle.PatternSpec spec); + public void set_map (GLib.HashTable map); + [NoAccessorMethod] + public int priority { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_preferences_spin_button_get_type ()")] + public class PreferencesSpinButton : Dazzle.PreferencesBin, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false)] + protected PreferencesSpinButton (); + public unowned Gtk.Widget get_spin_button (); + [NoAccessorMethod] + public string key { owned get; construct; } + [NoAccessorMethod] + public string subtitle { owned get; construct; } + [NoAccessorMethod] + public string title { owned get; construct; } + public signal void activate (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_preferences_switch_get_type ()")] + public class PreferencesSwitch : Dazzle.PreferencesBin, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false)] + protected PreferencesSwitch (); + [NoAccessorMethod] + public bool is_radio { get; construct; } + [NoAccessorMethod] + public string key { owned get; construct; } + [NoAccessorMethod] + public string subtitle { owned get; set; } + [NoAccessorMethod] + public GLib.Variant target { owned get; construct; } + [NoAccessorMethod] + public string title { owned get; set; } + public signal void activated (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_preferences_view_get_type ()")] + public class PreferencesView : Gtk.Bin, Atk.Implementor, Dazzle.Preferences, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public PreferencesView (); + public bool get_use_sidebar (); + public void reapply_filter (); + public void set_use_sidebar (bool use_sidebar); + public bool use_sidebar { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_priority_box_get_type ()")] + public class PriorityBox : Gtk.Box, Atk.Implementor, Gtk.Buildable, Gtk.Orientable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public PriorityBox (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_progress_button_get_type ()")] + public class ProgressButton : Gtk.Button, Atk.Implementor, Gtk.Actionable, Gtk.Activatable, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public ProgressButton (); + public uint get_progress (); + public bool get_show_progress (); + public void set_progress (uint percentage); + public void set_show_progress (bool show_progress); + public uint progress { get; set; } + public bool show_progress { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_progress_icon_get_type ()")] + public class ProgressIcon : Gtk.DrawingArea, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public ProgressIcon (); + public double get_progress (); + public void set_progress (double progress); + public double progress { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_progress_menu_button_get_type ()")] + public class ProgressMenuButton : Gtk.MenuButton, Atk.Implementor, Gtk.Actionable, Gtk.Activatable, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public ProgressMenuButton (); + public double get_progress (); + public bool get_show_theatric (); + public void reset_theatrics (); + public void set_progress (double progress); + public void set_show_theatric (bool show_theatic); + public double progress { get; set; } + public bool show_theatric { get; set; } + [NoAccessorMethod] + public string theatric_icon_name { owned get; set; } + [NoAccessorMethod] + public uint transition_duration { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_properties_group_get_type ()")] + public class PropertiesGroup : GLib.Object, GLib.ActionGroup { + [CCode (has_construct_function = false)] + [Version (since = "3.26")] + public PropertiesGroup (GLib.Object object); + [Version (since = "3.26")] + public void add_all_properties (); + [Version (since = "3.26")] + public void add_property (string name, string property_name); + [Version (since = "3.26")] + public void add_property_full (string name, string property_name, Dazzle.PropertiesFlags flags); + [CCode (has_construct_function = false)] + public PropertiesGroup.for_type (GLib.Type object_type); + [Version (since = "3.26")] + public void remove (string name); + [NoAccessorMethod] + public GLib.Object object { owned get; set; } + [NoAccessorMethod] + public GLib.Type object_type { get; construct; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_radio_box_get_type ()")] + public class RadioBox : Gtk.Bin, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public RadioBox (); + public void add_item (string id, string text); + public unowned string get_active_id (); + public void set_active_id (string id); + public string active_id { get; set; } + [NoAccessorMethod] + public bool has_more { get; } + [NoAccessorMethod] + public bool show_more { get; set; } + public signal void changed (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_read_only_list_model_get_type ()")] + public class ReadOnlyListModel : GLib.Object, GLib.ListModel { + [CCode (has_construct_function = false)] + protected ReadOnlyListModel (); + [Version (since = "3.30")] + public static GLib.ListModel @new (GLib.ListModel base_model); + [NoAccessorMethod] + [Version (since = "3.30")] + public GLib.ListModel base_model { construct; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_recursive_file_monitor_get_type ()")] + public class RecursiveFileMonitor : GLib.Object { + [CCode (has_construct_function = false)] + public RecursiveFileMonitor (GLib.File root); + [Version (since = "3.28")] + public void cancel (); + [Version (since = "3.28")] + public unowned GLib.File get_root (); + [Version (since = "3.28")] + public void set_ignore_func (owned Dazzle.RecursiveIgnoreFunc ignore_func); + public async bool start_async (GLib.Cancellable? cancellable = null) throws GLib.Error; + public GLib.File root { get; construct; } + [Version (since = "3.28")] + public signal void changed (GLib.File file, GLib.File? other_file, GLib.FileMonitorEvent event); + } + [CCode (cheader_filename = "dazzle.h", ref_function = "dzl_ring_ref", type_id = "dzl_ring_get_type ()", unref_function = "dzl_ring_unref")] + [Compact] + public class Ring { + public uint8 data; + public uint len; + public uint pos; + public uint append_vals (void* data, uint len); + public void @foreach (GLib.Func func); + public Dazzle.Ring @ref (); + [CCode (cname = "dzl_ring_sized_new", has_construct_function = false)] + public Ring.sized_new (uint element_size, uint reserved_size, GLib.DestroyNotify element_destroy); + public void unref (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_scrolled_window_get_type ()")] + public class ScrolledWindow : Gtk.ScrolledWindow, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false)] + protected ScrolledWindow (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_search_bar_get_type ()")] + public class SearchBar : Gtk.Bin, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public SearchBar (); + public unowned Gtk.SearchEntry get_entry (); + public bool get_search_mode_enabled (); + public bool get_show_close_button (); + public void set_search_mode_enabled (bool search_mode_enabled); + public void set_show_close_button (bool show_close_button); + public bool search_mode_enabled { get; set; } + public bool show_close_button { get; set; } + public signal void activate (); + public signal void reveal (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_settings_flag_action_get_type ()")] + public class SettingsFlagAction : GLib.Object, GLib.Action { + [CCode (has_construct_function = false)] + protected SettingsFlagAction (); + public static GLib.Action @new (string schema_id, string schema_key, string flag_nick); + [NoAccessorMethod] + public string flag_nick { owned get; construct; } + [NoAccessorMethod] + public string schema_id { owned get; construct; } + [NoAccessorMethod] + public string schema_key { owned get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_settings_sandwich_get_type ()")] + public class SettingsSandwich : GLib.Object { + [CCode (has_construct_function = false)] + public SettingsSandwich (string schema_id, string path); + public void append (GLib.Settings settings); + public void bind (string key, void* object, string property, GLib.SettingsBindFlags flags); + public void bind_with_mapping (string key, void* object, string property, GLib.SettingsBindFlags flags, [CCode (delegate_target_pos = 6.1, destroy_notify_pos = 6.2)] owned GLib.SettingsBindGetMapping get_mapping, owned GLib.SettingsBindSetMapping set_mapping); + public bool get_boolean (string key); + public GLib.Variant get_default_value (string key); + public double get_double (string key); + public int get_int (string key); + public string get_string (string key); + public uint get_uint (string key); + public GLib.Variant get_user_value (string key); + public GLib.Variant get_value (string key); + public void set_boolean (string key, bool val); + public void set_double (string key, double val); + public void set_int (string key, int val); + public void set_string (string key, string val); + public void set_uint (string key, uint val); + public void set_value (string key, GLib.Variant value); + public void unbind (string property); + [NoAccessorMethod] + public string path { owned get; construct; } + [NoAccessorMethod] + public string schema_id { owned get; construct; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcut_accel_dialog_get_type ()")] + public class ShortcutAccelDialog : Gtk.Dialog, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public ShortcutAccelDialog (); + public string get_accelerator (); + public unowned Dazzle.ShortcutChord get_chord (); + public unowned string get_shortcut_title (); + public void set_accelerator (string accelerator); + public void set_shortcut_title (string title); + public string accelerator { owned get; set; } + public string shortcut_title { get; set; } + } + [CCode (cheader_filename = "dazzle.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "dzl_shortcut_chord_get_type ()")] + [Compact] + public class ShortcutChord { + public bool append_event (Gdk.EventKey event); + public Dazzle.ShortcutChord copy (); + [CCode (cheader_filename = "dazzle.h")] + public static bool equal (void* data1, void* data2); + public void free (); + [CCode (has_construct_function = false)] + public ShortcutChord.from_event (Gdk.EventKey event); + [CCode (has_construct_function = false)] + public ShortcutChord.from_string (string accelerator); + public string get_label (); + public uint get_length (); + public void get_nth_key (uint nth, uint keyval, Gdk.ModifierType modifier); + public bool has_modifier (); + [CCode (cheader_filename = "dazzle.h")] + public static uint hash (void* data); + public Dazzle.ShortcutMatch match (Dazzle.ShortcutChord other); + public string to_string (); + } + [CCode (cheader_filename = "dazzle.h", has_type_id = false)] + [Compact] + public class ShortcutChordTable { + public void add (Dazzle.ShortcutChord chord, void* data); + public void @foreach (Dazzle.ShortcutChordTableForeach foreach_func); + public void free (); + [CCode (cheader_filename = "dazzle.h")] + public static GLib.Type get_type (); + public Dazzle.ShortcutMatch lookup (Dazzle.ShortcutChord chord, void* data); + public unowned Dazzle.ShortcutChord lookup_data (void* data); + public void printf (); + public bool remove (Dazzle.ShortcutChord chord); + public bool remove_data (void* data); + public void set_free_func (GLib.DestroyNotify notify); + public uint size (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcut_context_get_type ()")] + public class ShortcutContext : GLib.Object { + [CCode (has_construct_function = false)] + public ShortcutContext (string name); + public Dazzle.ShortcutMatch activate (Gtk.Widget widget, Dazzle.ShortcutChord chord); + public void add_action (string accel, string detailed_action_name); + public void add_command (string accel, string command); + public void add_signalv (string accel, string signal_name, GLib.Array? values); + public unowned string get_name (); + public bool load_from_data (string data, ssize_t len) throws GLib.Error; + public bool load_from_resource (string resource_path) throws GLib.Error; + public bool remove (string accel); + public string name { get; construct; } + [NoAccessorMethod] + public bool use_binding_sets { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcut_controller_get_type ()")] + public class ShortcutController : GLib.Object { + [CCode (has_construct_function = false)] + public ShortcutController (Gtk.Widget widget); + public void add_command_action (string command_id, string default_accel, Dazzle.ShortcutPhase phase, string action); + public void add_command_callback (string command_id, string default_accel, Dazzle.ShortcutPhase phase, owned Gtk.Callback callback); + public bool execute_command (string command); + public static unowned Dazzle.ShortcutController find (Gtk.Widget widget); + [Version (since = "3.26")] + public unowned Dazzle.ShortcutContext? get_context (); + [Version (since = "3.26")] + public unowned Dazzle.ShortcutContext? get_context_for_phase (Dazzle.ShortcutPhase phase); + public unowned Dazzle.ShortcutChord? get_current_chord (); + public unowned Dazzle.ShortcutManager get_manager (); + [Version (since = "3.26")] + public void set_context_by_name (string? name); + public void set_manager (Dazzle.ShortcutManager? manager); + public static unowned Dazzle.ShortcutController? try_find (Gtk.Widget widget); + public Dazzle.ShortcutContext context { get; } + public Dazzle.ShortcutChord current_chord { get; } + public Dazzle.ShortcutManager manager { get; set; } + [NoAccessorMethod] + public Gtk.Widget widget { owned get; construct; } + public signal void reset (); + public signal void set_context_named (string name); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcut_label_get_type ()")] + public class ShortcutLabel : Gtk.Box, Atk.Implementor, Gtk.Buildable, Gtk.Orientable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public ShortcutLabel (); + public string get_accelerator (); + public unowned Dazzle.ShortcutChord? get_chord (); + public void set_accelerator (string accelerator); + public void set_chord (Dazzle.ShortcutChord chord); + public string accelerator { owned get; set; } + public Dazzle.ShortcutChord chord { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcut_manager_get_type ()")] + public class ShortcutManager : GLib.Object, GLib.Initable, GLib.ListModel { + [CCode (has_construct_function = false)] + protected ShortcutManager (); + public void add_action (string detailed_action_name, string section, string group, string title, string subtitle); + public void add_command (string command, string section, string group, string title, string subtitle); + public void add_shortcut_entries ([CCode (array_length_cname = "n_shortcuts", array_length_pos = 1.5, array_length_type = "guint")] Dazzle.ShortcutEntry[] shortcuts, string? translation_domain); + public void add_shortcuts_to_window (Dazzle.ShortcutsWindow window); + public void append_search_path (string directory); + public static unowned Dazzle.ShortcutManager get_default (); + public unowned Dazzle.ShortcutTheme get_theme (); + public unowned Dazzle.ShortcutTheme? get_theme_by_name (string? theme_name); + public unowned string get_theme_name (); + public unowned string get_user_dir (); + public bool handle_event (Gdk.EventKey event, Gtk.Widget toplevel); + public void prepend_search_path (string directory); + public void queue_reload (); + public void reload (GLib.Cancellable? cancellable = null); + public void remove_search_path (string directory); + public void set_theme (Dazzle.ShortcutTheme theme); + public void set_theme_name (string theme_name); + public void set_user_dir (string user_dir); + public Dazzle.ShortcutTheme theme { get; set; } + public string theme_name { get; set; } + public string user_dir { get; set; } + public signal void changed (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcut_model_get_type ()")] + public class ShortcutModel : Gtk.TreeStore, Gtk.Buildable, Gtk.TreeDragDest, Gtk.TreeDragSource, Gtk.TreeModel, Gtk.TreeSortable { + [CCode (has_construct_function = false)] + protected ShortcutModel (); + public unowned Dazzle.ShortcutManager get_manager (); + public unowned Dazzle.ShortcutTheme get_theme (); + public static Gtk.TreeModel @new (); + public void rebuild (); + public void set_chord (Gtk.TreeIter iter, Dazzle.ShortcutChord chord); + public void set_manager (Dazzle.ShortcutManager manager); + public void set_theme (Dazzle.ShortcutTheme theme); + public Dazzle.ShortcutManager manager { get; set; } + public Dazzle.ShortcutTheme theme { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcut_simple_label_get_type ()")] + public class ShortcutSimpleLabel : Gtk.Box, Atk.Implementor, Gtk.Buildable, Gtk.Orientable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public ShortcutSimpleLabel (); + public unowned string get_accel (); + public unowned string get_action (); + public unowned string get_command (); + public unowned string get_title (); + public void set_accel (string accel); + public void set_action (string action); + public void set_command (string command); + public void set_title (string title); + public string accel { get; set; } + public string action { get; set; } + public string command { get; set; } + [NoAccessorMethod] + public bool show_accel { get; set; } + public string title { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcut_theme_get_type ()")] + public class ShortcutTheme : GLib.Object { + [CCode (has_construct_function = false)] + public ShortcutTheme (string name); + public void add_command (string accelerator, string command); + public void add_context (Dazzle.ShortcutContext context); + public void add_css_resource (string path); + public unowned Dazzle.ShortcutContext find_context_by_name (string name); + public unowned Dazzle.ShortcutContext? find_default_context (Gtk.Widget widget); + public unowned Dazzle.ShortcutChord get_chord_for_action (string detailed_action_name); + public unowned Dazzle.ShortcutChord get_chord_for_command (string command); + public unowned string get_name (); + public unowned Dazzle.ShortcutTheme? get_parent (); + public unowned string? get_parent_name (); + public unowned string get_subtitle (); + public unowned string get_title (); + public bool load_from_data (string data, ssize_t len) throws GLib.Error; + public bool load_from_file (GLib.File file, GLib.Cancellable? cancellable = null) throws GLib.Error; + public bool load_from_path (string path, GLib.Cancellable? cancellable = null) throws GLib.Error; + public void remove_css_resource (string path); + public bool save_to_file (GLib.File file, GLib.Cancellable? cancellable = null) throws GLib.Error; + public bool save_to_path (string path, GLib.Cancellable? cancellable = null) throws GLib.Error; + public bool save_to_stream (GLib.OutputStream stream, GLib.Cancellable? cancellable = null) throws GLib.Error; + public void set_accel_for_action (string detailed_action_name, string accel, Dazzle.ShortcutPhase phase); + public void set_accel_for_command (string? command, string? accel, Dazzle.ShortcutPhase phase); + public void set_chord_for_action (string detailed_action_name, Dazzle.ShortcutChord chord, Dazzle.ShortcutPhase phase); + public void set_chord_for_command (string? command, Dazzle.ShortcutChord? chord, Dazzle.ShortcutPhase phase); + public void set_parent_name (string parent_name); + public string name { get; construct; } + public string parent_name { get; set; } + [NoAccessorMethod] + public string subtitle { owned get; set; } + [NoAccessorMethod] + public string title { owned get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcut_theme_editor_get_type ()")] + public class ShortcutThemeEditor : Gtk.Bin, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public ShortcutThemeEditor (); + public unowned Dazzle.ShortcutTheme? get_theme (); + public void set_theme (Dazzle.ShortcutTheme theme); + public Dazzle.ShortcutTheme theme { get; set; } + public signal void changed (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcuts_group_get_type ()")] + public class ShortcutsGroup : Gtk.Box, Atk.Implementor, Gtk.Buildable, Gtk.Orientable { + [CCode (has_construct_function = false)] + protected ShortcutsGroup (); + [NoAccessorMethod] + public Gtk.SizeGroup accel_size_group { set; } + [NoAccessorMethod] + public uint height { get; } + [NoAccessorMethod] + public string title { owned get; set; } + [NoAccessorMethod] + public Gtk.SizeGroup title_size_group { set; } + [NoAccessorMethod] + public string view { owned get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcuts_section_get_type ()")] + public class ShortcutsSection : Gtk.Box, Atk.Implementor, Gtk.Buildable, Gtk.Orientable { + [CCode (has_construct_function = false)] + protected ShortcutsSection (); + [NoAccessorMethod] + public uint max_height { get; set; } + [NoAccessorMethod] + public string section_name { owned get; set; } + [NoAccessorMethod] + public string title { owned get; set; } + [NoAccessorMethod] + public string view_name { owned get; set; } + public signal bool change_current_page (int object); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcuts_shortcut_get_type ()")] + public class ShortcutsShortcut : Gtk.Box, Atk.Implementor, Gtk.Buildable, Gtk.Orientable { + [CCode (has_construct_function = false)] + protected ShortcutsShortcut (); + [NoAccessorMethod] + public Gtk.SizeGroup accel_size_group { set; } + [NoAccessorMethod] + public string accelerator { owned get; set; } + [NoAccessorMethod] + [Version (since = "3.22")] + public string action_name { owned get; set; } + [NoAccessorMethod] + public Gtk.TextDirection direction { get; set; } + [NoAccessorMethod] + public GLib.Icon icon { owned get; set; } + [NoAccessorMethod] + public bool icon_set { get; set; } + [NoAccessorMethod] + public Gtk.ShortcutType shortcut_type { get; set; } + [NoAccessorMethod] + public string subtitle { owned get; set; } + [NoAccessorMethod] + public bool subtitle_set { get; set; } + [NoAccessorMethod] + public string title { owned get; set; } + [NoAccessorMethod] + public Gtk.SizeGroup title_size_group { set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcuts_window_get_type ()")] + public class ShortcutsWindow : Gtk.Window, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false)] + protected ShortcutsWindow (); + [NoAccessorMethod] + public string section_name { owned get; set; } + [NoAccessorMethod] + public string view_name { owned get; set; } + public virtual signal void close (); + public virtual signal void search (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_signal_group_get_type ()")] + public class SignalGroup : GLib.Object { + [CCode (has_construct_function = false)] + public SignalGroup (GLib.Type target_type); + public void block (); + public void connect_data (string detailed_signal, [CCode (delegate_target_pos = 2.33333, destroy_notify_pos = 2.66667)] owned GLib.Callback c_handler, GLib.ConnectFlags flags); + public void connect_swapped (string detailed_signal, [CCode (scope = "async")] GLib.Callback c_handler); + public unowned GLib.Object? get_target (); + public void set_target (GLib.Object? target); + public void unblock (); + public GLib.Object target { get; set; } + [NoAccessorMethod] + public GLib.Type target_type { get; construct; } + public signal void bind (GLib.Object instance); + public signal void unbind (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_simple_label_get_type ()")] + public class SimpleLabel : Gtk.Widget, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public SimpleLabel (string label); + public unowned string get_label (); + public int get_width_chars (); + public float get_xalign (); + public void set_label (string label); + public void set_width_chars (int width_chars); + public void set_xalign (float xalign); + public string label { get; set; } + public int width_chars { get; set; } + public float xalign { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_simple_popover_get_type ()")] + public class SimplePopover : Gtk.Popover, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public SimplePopover (); + public unowned string get_button_text (); + public unowned string get_message (); + public bool get_ready (); + public unowned string get_text (); + public unowned string get_title (); + public void set_button_text (string button_text); + public void set_message (string message); + public void set_ready (bool ready); + public void set_text (string text); + public void set_title (string title); + public string button_text { get; set; } + public string message { get; set; } + public bool ready { get; set; } + public string text { get; set; } + public string title { get; set; } + public virtual signal void activate (string text); + public virtual signal void changed (); + public virtual signal bool insert_text (uint position, string chars, uint n_chars); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_slider_get_type ()")] + public class Slider : Gtk.Container, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public Slider (); + public void add_slider (Gtk.Widget widget, Dazzle.SliderPosition position); + public Dazzle.SliderPosition get_position (); + public void set_position (Dazzle.SliderPosition position); + public Dazzle.SliderPosition position { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_stack_list_get_type ()")] + public class StackList : Gtk.Bin, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public StackList (); + public void clear (); + public uint get_depth (); + public unowned GLib.ListModel get_model (); + public void pop (); + public void push (Gtk.Widget header, GLib.ListModel model, owned Dazzle.StackListCreateWidgetFunc? create_widget_func); + public GLib.ListModel model { get; } + public virtual signal void header_activated (Gtk.ListBoxRow row); + public virtual signal void row_activated (Gtk.ListBoxRow row); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_state_machine_get_type ()")] + public class StateMachine : GLib.Object, Gtk.Buildable { + [CCode (has_construct_function = false)] + public StateMachine (); + public void add_binding (string state, void* source_object, string source_property, void* target_object, string target_property, GLib.BindingFlags flags); + public void add_propertyv (string state, void* object, string property, GLib.Value value); + public void add_style (string state, Gtk.Widget widget, string style); + public GLib.Action create_action (string name); + public unowned string get_state (); + [Version (since = "3.28")] + public bool is_state (string? state); + public void set_state (string state); + public string state { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_suggestion_get_type ()")] + public class Suggestion : GLib.Object { + [CCode (has_construct_function = false)] + public Suggestion (); + [Version (since = "3.30")] + public virtual GLib.Icon? get_icon (); + public unowned string get_icon_name (); + [Version (since = "3.30")] + public virtual Cairo.Surface? get_icon_surface (Gtk.Widget widget); + public unowned string get_id (); + public unowned string get_subtitle (); + public unowned string get_title (); + public void set_icon_name (string icon_name); + public void set_id (string id); + public void set_subtitle (string subtitle); + public void set_title (string title); + public GLib.Icon icon { owned get; } + public string icon_name { get; set; } + public string id { get; set; } + public string subtitle { get; set; } + public string title { get; set; } + [HasEmitter] + public virtual signal string replace_typed_text (string typed_text); + [HasEmitter] + public virtual signal string suggest_suffix (string typed_text); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_suggestion_entry_get_type ()")] + public class SuggestionEntry : Gtk.Entry, Atk.Implementor, Gtk.Buildable, Gtk.CellEditable, Gtk.Editable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public SuggestionEntry (); + public void default_position_func (Gdk.Rectangle area, bool is_absolute, void* user_data); + public bool get_activate_on_single_click (); + public unowned GLib.ListModel? get_model (); + public unowned Dazzle.Suggestion? get_suggestion (); + public unowned string get_typed_text (); + public void set_activate_on_single_click (bool activate_on_single_click); + public void set_model (GLib.ListModel model); + [Version (since = "3.26")] + public void set_position_func (owned Dazzle.SuggestionPositionFunc? func); + public void set_suggestion (Dazzle.Suggestion suggestion); + public void window_position_func (Gdk.Rectangle area, bool is_absolute, void* user_data); + [Version (since = "3.30")] + public bool activate_on_single_click { get; set; } + public GLib.ListModel model { get; set; } + [Version (since = "3.30")] + public Dazzle.Suggestion suggestion { get; set; } + public string typed_text { get; } + public signal void activate_suggestion (); + [HasEmitter] + public virtual signal void hide_suggestions (); + public virtual signal void move_suggestion (int amount); + public virtual signal void show_suggestions (); + public virtual signal void suggestion_activated (Dazzle.Suggestion suggestion); + [Version (since = "3.30")] + public virtual signal void suggestion_selected (Dazzle.Suggestion suggestion); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_suggestion_entry_buffer_get_type ()")] + public class SuggestionEntryBuffer : Gtk.EntryBuffer { + [CCode (has_construct_function = false)] + public SuggestionEntryBuffer (); + public void clear (); + public void commit (); + public unowned Dazzle.Suggestion? get_suggestion (); + public uint get_typed_length (); + public unowned string get_typed_text (); + public void set_suggestion (Dazzle.Suggestion? suggestion); + public Dazzle.Suggestion suggestion { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_suggestion_popover_get_type ()")] + public class SuggestionPopover : Gtk.Window, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public SuggestionPopover (); + public void activate_selected (); + public unowned GLib.ListModel? get_model (); + public unowned Gtk.Widget? get_relative_to (); + public unowned Dazzle.Suggestion? get_selected (); + public void move_by (int amount); + public void popdown (); + public void popup (); + public void set_model (GLib.ListModel model); + public void set_relative_to (Gtk.Widget widget); + public void set_selected (Dazzle.Suggestion suggestion); + public Dazzle.Suggestion model { get; set; } + public Gtk.Widget relative_to { get; set; } + public Dazzle.Suggestion selected { get; set; } + [NoAccessorMethod] + public Pango.EllipsizeMode subtitle_ellipsize { get; set; } + [NoAccessorMethod] + public Pango.EllipsizeMode title_ellipsize { get; set; } + public signal void suggestion_activated (Dazzle.Suggestion object); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_suggestion_row_get_type ()")] + public class SuggestionRow : Dazzle.ListBoxRow, Atk.Implementor, Gtk.Actionable, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public SuggestionRow (); + public unowned Dazzle.Suggestion get_suggestion (); + public void set_suggestion (Dazzle.Suggestion suggestion); + public Dazzle.Suggestion suggestion { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_tab_get_type ()")] + public class Tab : Dazzle.Bin, Atk.Implementor, Gtk.Actionable, Gtk.Buildable { + [CCode (has_construct_function = false)] + protected Tab (); + public bool get_active (); + public bool get_can_close (); + public Gtk.PositionType get_edge (); + public unowned string get_icon_name (); + public Dazzle.TabStyle get_style (); + public unowned string get_title (); + public unowned Gtk.Widget? get_widget (); + public void set_active (bool active); + public void set_can_close (bool can_close); + public void set_edge (Gtk.PositionType edge); + public void set_icon_name (string icon_name); + public void set_style (Dazzle.TabStyle style); + public void set_title (string title); + public void set_widget (Gtk.Widget widget); + public bool active { get; set; } + public bool can_close { get; set; } + public Gtk.PositionType edge { get; set; } + public Dazzle.TabStyle style { get; set; } + public string title { get; set; } + public Gtk.Widget widget { get; set; } + public signal void clicked (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_tab_strip_get_type ()")] + public class TabStrip : Gtk.Box, Atk.Implementor, Gtk.Buildable, Gtk.Orientable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public TabStrip (); + public void add_control (Gtk.Widget widget); + public Gtk.PositionType get_edge (); + public unowned Gtk.Stack? get_stack (); + public Dazzle.TabStyle get_style (); + public void set_edge (Gtk.PositionType edge); + public void set_stack (Gtk.Stack stack); + public void set_style (Dazzle.TabStyle style); + public Gtk.PositionType edge { get; set; } + public Gtk.Stack stack { get; set; } + public Dazzle.TabStyle style { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_task_cache_get_type ()")] + public class TaskCache : GLib.Object { + [CCode (has_construct_function = false)] + protected TaskCache (); + public bool evict (void* key); + public void evict_all (); + public async void* get_async (void* key, bool force_update, GLib.Cancellable? cancellable = null) throws GLib.Error; + public unowned GLib.Object? peek (void* key); + public void set_name (string name); + [NoAccessorMethod] + public void* key_copy_func { construct; } + [NoAccessorMethod] + public void* key_destroy_func { construct; } + [NoAccessorMethod] + public void* key_equal_func { construct; } + [NoAccessorMethod] + public void* key_hash_func { construct; } + [NoAccessorMethod] + public void* populate_callback { construct; } + [NoAccessorMethod] + public void* populate_callback_data { construct; } + [NoAccessorMethod] + public void* populate_callback_data_destroy { construct; } + [NoAccessorMethod] + public int64 time_to_live { construct; } + [NoAccessorMethod] + public void* value_copy_func { construct; } + [NoAccessorMethod] + public void* value_destroy_func { construct; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_theme_manager_get_type ()")] + public class ThemeManager : GLib.Object { + [CCode (has_construct_function = false)] + public ThemeManager (); + public void add_resources (string resource_path); + public void remove_resources (string resource_path); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_three_grid_get_type ()")] + public class ThreeGrid : Gtk.Container, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public ThreeGrid (); + [NoAccessorMethod] + public uint column_spacing { get; set; } + [NoAccessorMethod] + public uint row_spacing { get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_tree_get_type ()")] + public class Tree : Gtk.TreeView, Atk.Implementor, Gtk.Buildable, Gtk.Scrollable { + [CCode (has_construct_function = false)] + protected Tree (); + public void add_builder (Dazzle.TreeBuilder builder); + public void expand_to_node (Dazzle.TreeNode node); + public unowned Dazzle.TreeNode? find_child_node (Dazzle.TreeNode node, Dazzle.TreeFindFunc find_func); + public unowned Dazzle.TreeNode? find_custom (GLib.EqualFunc equal_func, void* key); + public unowned Dazzle.TreeNode? find_item (GLib.Object? item); + public unowned GLib.MenuModel? get_context_menu (); + public unowned Dazzle.TreeNode? get_root (); + public unowned Dazzle.TreeNode get_selected (); + public bool get_show_icons (); + public void rebuild (); + public void remove_builder (Dazzle.TreeBuilder builder); + public void scroll_to_node (Dazzle.TreeNode node); + public void set_context_menu (GLib.MenuModel context_menu); + public void set_filter (owned Dazzle.TreeFilterFunc filter_func); + public void set_root (Dazzle.TreeNode node); + public void set_show_icons (bool show_icons); + public void unselect_all (); + [NoAccessorMethod] + public bool always_expand { get; construct; } + public GLib.MenuModel context_menu { get; set; } + public Dazzle.TreeNode root { get; set; } + [NoAccessorMethod] + public Dazzle.TreeNode selection { owned get; set; } + public bool show_icons { get; set; } + public virtual signal void action (string action_group, string action_name, string param); + public virtual signal void populate_popup (Gtk.Widget widget); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_tree_builder_get_type ()")] + public class TreeBuilder : GLib.InitiallyUnowned { + [CCode (has_construct_function = false)] + public TreeBuilder (); + [NoWrapper] + public virtual void cell_data_func (Dazzle.TreeNode node, Gtk.CellRenderer cell); + public unowned Dazzle.Tree? get_tree (); + public Dazzle.Tree tree { get; } + public virtual signal void added (Dazzle.Tree tree); + public virtual signal void build_children (Dazzle.TreeNode parent); + public virtual signal void build_node (Dazzle.TreeNode node); + public virtual signal bool drag_data_get (Dazzle.TreeNode node, Gtk.SelectionData data); + public virtual signal bool drag_data_received (Dazzle.TreeNode drop_node, Dazzle.TreeDropPosition position, Gdk.DragAction action, Gtk.SelectionData data); + public virtual signal bool drag_node_delete (Dazzle.TreeNode node); + public virtual signal bool drag_node_received (Dazzle.TreeNode drag_node, Dazzle.TreeNode drop_node, Dazzle.TreeDropPosition position, Gdk.DragAction action, Gtk.SelectionData data); + public virtual signal bool node_activated (Dazzle.TreeNode node); + public virtual signal void node_collapsed (Dazzle.TreeNode node); + public virtual signal bool node_draggable (Dazzle.TreeNode node); + public virtual signal bool node_droppable (Dazzle.TreeNode node, Gtk.SelectionData data); + public virtual signal void node_expanded (Dazzle.TreeNode node); + public virtual signal void node_popup (Dazzle.TreeNode node, GLib.Menu menu); + public virtual signal void node_selected (Dazzle.TreeNode node); + public virtual signal void node_unselected (Dazzle.TreeNode node); + public virtual signal void removed (Dazzle.Tree tree); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_tree_node_get_type ()")] + public class TreeNode : GLib.InitiallyUnowned { + [CCode (has_construct_function = false)] + public TreeNode (); + public void add_emblem (string emblem_name); + public void append (Dazzle.TreeNode child); + public void clear_emblems (); + public void collapse (); + public bool expand (bool expand_ancestors); + public void get_area (Gdk.Rectangle area); + public bool get_children_possible (); + public bool get_expanded (); + [Version (since = "3.28")] + public unowned Gdk.RGBA? get_foreground_rgba (); + public unowned GLib.Icon get_gicon (); + public unowned string get_icon_name (); + public unowned GLib.Object get_item (); + public bool get_iter (Gtk.TreeIter iter); + public unowned Dazzle.TreeNode get_parent (); + public Gtk.TreePath? get_path (); + public bool get_reset_on_collapse (); + public unowned string get_text (); + public unowned Dazzle.Tree get_tree (); + public bool get_use_dim_label (); + public bool get_use_markup (); + public bool has_emblem (string emblem_name); + [Version (since = "3.28")] + public void insert (Dazzle.TreeNode child, uint position); + public void insert_sorted (Dazzle.TreeNode child, Dazzle.TreeNodeCompareFunc compare_func); + public void invalidate (); + public bool is_root (); + public uint n_children (); + public Dazzle.TreeNode? nth_child (uint nth); + public void prepend (Dazzle.TreeNode child); + [Version (since = "3.28")] + public void rebuild (); + public void remove (Dazzle.TreeNode child); + public void remove_emblem (string emblem_name); + public void select (); + public void set_children_possible (bool children_possible); + public void set_emblems (string emblems); + [Version (since = "3.28")] + public void set_foreground_rgba (Gdk.RGBA? foreground_rgba); + public void set_gicon (GLib.Icon icon); + public void set_icon_name (string? icon_name); + public void set_item (GLib.Object item); + public void set_reset_on_collapse (bool reset_on_collapse); + public void set_text (string? text); + public void set_use_dim_label (bool use_dim_label); + public void set_use_markup (bool use_markup); + public void show_popover (Gtk.Popover popover); + public bool children_possible { get; set; } + [NoAccessorMethod] + public string expanded_icon_name { owned get; set; } + public GLib.Icon gicon { get; set; } + public string icon_name { get; set; } + public GLib.Object item { get; set; } + public Dazzle.TreeNode parent { get; } + [Version (since = "3.28")] + public bool reset_on_collapse { get; set; } + public string text { get; set; } + [NoAccessorMethod] + public Dazzle.Tree tree { owned get; set; } + public bool use_dim_label { get; set; } + public bool use_markup { get; set; } + } + [CCode (cheader_filename = "dazzle.h", ref_function = "dzl_trie_ref", type_id = "dzl_trie_get_type ()", unref_function = "dzl_trie_unref")] + [Compact] + public class Trie { + [CCode (has_construct_function = false)] + public Trie (GLib.DestroyNotify value_destroy); + public void destroy (); + public void insert (string key, void* value); + public void* lookup (string key); + public Dazzle.Trie @ref (); + public bool remove (string key); + public void traverse (string key, GLib.TraverseType order, GLib.TraverseFlags flags, int max_depth, Dazzle.TrieTraverseFunc func); + public void unref (); + } + [CCode (cheader_filename = "dazzle.h", type_id = "dzl_widget_action_group_get_type ()")] + public class WidgetActionGroup : GLib.Object, GLib.ActionGroup { + [CCode (has_construct_function = false)] + protected WidgetActionGroup (); + public static void attach (Gtk.Widget widget, string group_name); + public static GLib.ActionGroup @new (Gtk.Widget widget); + public void set_action_enabled (string action_name, bool enabled); + [NoAccessorMethod] + public Gtk.Widget widget { owned get; construct; } + } + [CCode (cheader_filename = "dazzle.h", type_cname = "DzlDockInterface", type_id = "dzl_dock_get_type ()")] + public interface Dock : Gtk.Container { + [NoAccessorMethod] + public abstract Dazzle.DockManager manager { owned get; set; } + } + [CCode (cheader_filename = "dazzle.h", type_cname = "DzlDockItemInterface", type_id = "dzl_dock_item_get_type ()")] + public interface DockItem : Gtk.Widget { + public bool adopt (Dazzle.DockItem child); + public abstract bool close (); + [Version (since = "3.30")] + public void emit_presented (); + public abstract bool get_can_close (); + [CCode (vfunc_name = "can_minimize")] + public abstract bool get_can_minimize (Dazzle.DockItem descendant); + public abstract bool get_child_visible (Dazzle.DockItem child); + public abstract string? get_icon_name (); + public abstract unowned Dazzle.DockManager? get_manager (); + public unowned Dazzle.DockItem? get_parent (); + public abstract string? get_title (); + public bool has_widgets (); + public abstract bool minimize (Dazzle.DockItem child, ref Gtk.PositionType position); + public void present (); + public abstract void present_child (Dazzle.DockItem child); + public abstract void release (Dazzle.DockItem child); + public abstract void set_child_visible (Dazzle.DockItem child, bool child_visible); + public abstract void set_manager (Dazzle.DockManager? manager); + public abstract void update_visibility (); + public virtual signal void manager_set (Dazzle.DockManager old_manager); + public virtual signal void presented (); + } + [CCode (cheader_filename = "dazzle.h", lower_case_csuffix = "graph_view_renderer", type_cname = "DzlGraphRendererInterface", type_id = "dzl_graph_view_renderer_get_type ()")] + public interface GraphRenderer : GLib.Object { + public abstract void render (Dazzle.GraphModel table, int64 x_begin, int64 x_end, double y_begin, double y_end, Cairo.Context cr, Cairo.RectangleInt area); + } + [CCode (cheader_filename = "dazzle.h", type_cname = "DzlPreferencesInterface", type_id = "dzl_preferences_get_type ()")] + public interface Preferences : GLib.Object { + public abstract uint add_custom (string page_name, string group_name, Gtk.Widget widget, string? keywords, int priority); + public abstract uint add_file_chooser (string page_name, string group_name, string schema_id, string key, string path, string title, string subtitle, Gtk.FileChooserAction action, string keywords, int priority); + public abstract uint add_font_button (string page_name, string group_name, string schema_id, string key, string title, string keywords, int priority); + public abstract void add_group (string page_name, string group_name, string title, int priority); + public abstract void add_list_group (string page_name, string group_name, string title, Gtk.SelectionMode mode, int priority); + public abstract void add_page (string page_name, string title, int priority); + public abstract uint add_radio (string page_name, string group_name, string schema_id, string key, string? path, string? variant_string, string? title, string? subtitle, string? keywords, int priority); + public abstract uint add_spin_button (string page_name, string group_name, string schema_id, string key, string path, string title, string subtitle, string keywords, int priority); + public abstract uint add_switch (string page_name, string group_name, string schema_id, string key, string? path, string? variant_string, string? title, string? subtitle, string? keywords, int priority); + public abstract unowned Gtk.Widget? get_widget (uint widget_id); + public abstract bool remove_id (uint widget_id); + public abstract void set_page (string page_name, GLib.HashTable map); + } + [CCode (cheader_filename = "dazzle.h", has_type_id = false)] + public struct Counter { + public Dazzle.CounterValue values; + public weak string category; + public weak string name; + public weak string description; + public int64 @get (); + public void reset (); + } + [CCode (cheader_filename = "dazzle.h", has_type_id = false)] + public struct CounterValue { + public int64 value; + [CCode (array_length = false)] + public weak int64 padding[7]; + } + [CCode (cheader_filename = "dazzle.h", has_type_id = false)] + public struct FileTransferStat { + public int64 n_files_total; + public int64 n_files; + public int64 n_dirs_total; + public int64 n_dirs; + public int64 n_bytes_total; + public int64 n_bytes; + } + [CCode (cheader_filename = "dazzle.h", has_type_id = false)] + public struct FuzzyMutableIndexMatch { + public weak string key; + public void* value; + public float score; + public uint id; + } + [CCode (cheader_filename = "dazzle.h", has_type_id = false)] + public struct GraphModelIter { + [CCode (array_length = false)] + public weak void* data[8]; + } + [CCode (cheader_filename = "dazzle.h", has_type_id = false)] + public struct ShortcutEntry { + public weak string command; + public Dazzle.ShortcutPhase phase; + public weak string default_accel; + public weak string section; + public weak string group; + public weak string title; + public weak string subtitle; + } + [CCode (cheader_filename = "dazzle.h", cname = "_DzlGraphColumnClass", has_type_id = false)] + public struct _GraphColumnClass { + public weak GLib.ObjectClass parent; + } + [CCode (cheader_filename = "dazzle.h", cprefix = "DZL_ANIMATION_", type_id = "dzl_animation_mode_get_type ()")] + public enum AnimationMode { + LINEAR, + EASE_IN_QUAD, + EASE_IN_OUT_QUAD, + EASE_OUT_QUAD, + EASE_IN_CUBIC, + EASE_OUT_CUBIC, + EASE_IN_OUT_CUBIC + } + [CCode (cheader_filename = "dazzle.h", cprefix = "DZL_DOCK_REVEALER_TRANSITION_TYPE_", type_id = "dzl_dock_revealer_transition_type_get_type ()")] + public enum DockRevealerTransitionType { + NONE, + SLIDE_RIGHT, + SLIDE_LEFT, + SLIDE_UP, + SLIDE_DOWN + } + [CCode (cheader_filename = "dazzle.h", cprefix = "DZL_FILE_TRANSFER_FLAGS_", type_id = "dzl_file_transfer_flags_get_type ()")] + [Flags] + public enum FileTransferFlags { + NONE, + MOVE + } + [CCode (cheader_filename = "dazzle.h", cprefix = "DZL_PROPERTIES_FLAGS_", has_type_id = false)] + [Flags] + public enum PropertiesFlags { + NONE, + STATEFUL_BOOLEANS + } + [CCode (cheader_filename = "dazzle.h", cprefix = "DZL_SHORTCUT_MATCH_", type_id = "dzl_shortcut_match_get_type ()")] + public enum ShortcutMatch { + NONE, + EQUAL, + PARTIAL + } + [CCode (cheader_filename = "dazzle.h", cprefix = "DZL_SHORTCUT_PHASE_", type_id = "dzl_shortcut_phase_get_type ()")] + [Flags] + public enum ShortcutPhase { + DISPATCH, + CAPTURE, + BUBBLE, + GLOBAL + } + [CCode (cheader_filename = "dazzle.h", cprefix = "DZL_SHORTCUT_", has_type_id = false)] + [Version (since = "3.20")] + public enum ShortcutType { + ACCELERATOR, + GESTURE_PINCH, + GESTURE_STRETCH, + GESTURE_ROTATE_CLOCKWISE, + GESTURE_ROTATE_COUNTERCLOCKWISE, + GESTURE_TWO_FINGER_SWIPE_LEFT, + GESTURE_TWO_FINGER_SWIPE_RIGHT, + GESTURE + } + [CCode (cheader_filename = "dazzle.h", cprefix = "DZL_SLIDER_", type_id = "dzl_slider_position_get_type ()")] + public enum SliderPosition { + NONE, + TOP, + RIGHT, + BOTTOM, + LEFT + } + [CCode (cheader_filename = "dazzle.h", cprefix = "DZL_TAB_", type_id = "dzl_tab_style_get_type ()")] + [Flags] + public enum TabStyle { + ICONS, + TEXT, + BOTH + } + [CCode (cheader_filename = "dazzle.h", cprefix = "DZL_THREE_GRID_COLUMN_", type_id = "dzl_three_grid_column_get_type ()")] + public enum ThreeGridColumn { + LEFT, + CENTER, + RIGHT + } + [CCode (cheader_filename = "dazzle.h", cprefix = "DZL_TREE_DROP_", type_id = "dzl_tree_drop_position_get_type ()")] + public enum TreeDropPosition { + INTO, + BEFORE, + AFTER + } + [CCode (cheader_filename = "dazzle.h", instance_pos = 1.9)] + public delegate void CounterForeachFunc (Dazzle.Counter counter); + [CCode (cheader_filename = "dazzle.h", instance_pos = 3.9)] + public delegate bool DirectoryModelVisibleFunc (Dazzle.DirectoryModel self, GLib.File directory, GLib.FileInfo file_info); + [CCode (cheader_filename = "dazzle.h", instance_pos = 1.9)] + public delegate bool ListModelFilterFunc (GLib.Object object); + [CCode (cheader_filename = "dazzle.h", instance_pos = 1.9)] + public delegate bool RecursiveIgnoreFunc (GLib.File file); + [CCode (cheader_filename = "dazzle.h", instance_pos = 2.9)] + public delegate void ShortcutChordTableForeach (Dazzle.ShortcutChord chord, void* chord_data); + [CCode (cheader_filename = "dazzle.h", instance_pos = 1.9)] + public delegate Gtk.Widget StackListCreateWidgetFunc ([CCode (type = "gpointer")] GLib.Object item); + [CCode (cheader_filename = "dazzle.h", instance_pos = 3.9)] + [Version (since = "3.26")] + public delegate void SuggestionPositionFunc (Dazzle.SuggestionEntry entry, ref Gdk.Rectangle area, ref bool is_absolute); + [CCode (cheader_filename = "dazzle.h", instance_pos = 3.9)] + public delegate void TaskCacheCallback (Dazzle.TaskCache self, void* key, GLib.Task task); + [CCode (cheader_filename = "dazzle.h", instance_pos = 2.9)] + public delegate bool TreeFilterFunc (Dazzle.Tree tree, Dazzle.TreeNode node); + [CCode (cheader_filename = "dazzle.h", instance_pos = 3.9)] + public delegate bool TreeFindFunc (Dazzle.Tree tree, Dazzle.TreeNode node, Dazzle.TreeNode child); + [CCode (cheader_filename = "dazzle.h", instance_pos = 2.9)] + public delegate int TreeNodeCompareFunc (Dazzle.TreeNode a, Dazzle.TreeNode b); + [CCode (cheader_filename = "dazzle.h", instance_pos = 3.9)] + public delegate bool TrieTraverseFunc (Dazzle.Trie dzl_trie, string key, void* value); + [CCode (cheader_filename = "dazzle.h", cname = "DZL_COUNTER_REQUIRES_ATOMIC")] + public const int COUNTER_REQUIRES_ATOMIC; + [CCode (cheader_filename = "dazzle.h", cname = "DZL_DOCK_BIN_STYLE_CLASS_PINNED")] + public const string DOCK_BIN_STYLE_CLASS_PINNED; + [CCode (cheader_filename = "dazzle.h", cname = "DZL_ENABLE_TRACE")] + public const int ENABLE_TRACE; + [CCode (cheader_filename = "dazzle.h", cname = "DZL_MAJOR_VERSION")] + public const int MAJOR_VERSION; + [CCode (cheader_filename = "dazzle.h", cname = "DZL_MICRO_VERSION")] + public const int MICRO_VERSION; + [CCode (cheader_filename = "dazzle.h", cname = "DZL_MINOR_VERSION")] + public const int MINOR_VERSION; + [CCode (cheader_filename = "dazzle.h", cname = "DZL_VERSION_S")] + public const string VERSION_S; + [CCode (cheader_filename = "dazzle.h")] + public static Cairo.Region cairo_region_create_from_clip_extents (Cairo.Context cr); + [CCode (cheader_filename = "dazzle.h")] + public static void cairo_rounded_rectangle (Cairo.Context cr, Gdk.Rectangle rect, int x_radius, int y_radius); + [CCode (cheader_filename = "dazzle.h")] + [Version (since = "3.28")] + public static unowned GLib.Cancellable? cancellable_chain (GLib.Cancellable? self = null, GLib.Cancellable? other = null); + [CCode (array_length = false, array_null_terminated = true, cheader_filename = "dazzle.h")] + public static string[] dnd_get_uri_list (Gtk.SelectionData selection_data); + [CCode (cheader_filename = "dazzle.h")] + public static bool file_manager_show (GLib.File file) throws GLib.Error; + [CCode (cheader_filename = "dazzle.h")] + public static string fuzzy_highlight (string str, string query, bool case_sensitive); + [CCode (cheader_filename = "dazzle.h")] + public static string g_date_time_format_for_display (GLib.DateTime self); + [CCode (cheader_filename = "dazzle.h")] + public static string g_time_span_to_label (GLib.TimeSpan span); + [CCode (cheader_filename = "dazzle.h")] + public static bool g_time_span_to_label_mapping (GLib.Binding binding, GLib.Value from_value, GLib.Value to_value, void* user_data); + [CCode (cheader_filename = "dazzle.h")] + public static uint g_variant_hash (void* data); + [CCode (cheader_filename = "dazzle.h")] + public static uint get_current_cpu_call (); + [CCode (cheader_filename = "dazzle.h")] + [Version (since = "3.26")] + public static void gtk_list_store_insert_sorted (Gtk.ListStore store, out Gtk.TreeIter iter, void* key, uint compare_column, GLib.CompareDataFunc compare_func); + [CCode (cheader_filename = "dazzle.h")] + public static void gtk_text_buffer_remove_tag (Gtk.TextBuffer buffer, Gtk.TextTag tag, Gtk.TextIter start, Gtk.TextIter end, bool minimal_damage); + [CCode (cheader_filename = "dazzle.h")] + public static bool gtk_widget_action (Gtk.Widget widget, string group, string name, GLib.Variant param); + [CCode (cheader_filename = "dazzle.h")] + public static bool gtk_widget_action_with_string (Gtk.Widget widget, string group, string name, string param); + [CCode (cheader_filename = "dazzle.h")] + public static void gtk_widget_add_style_class (Gtk.Widget widget, string class_name); + [CCode (cheader_filename = "dazzle.h")] + public static unowned Gtk.Widget? gtk_widget_find_child_typed (Gtk.Widget widget, GLib.Type type); + [CCode (cheader_filename = "dazzle.h")] + public static unowned Gtk.Widget? gtk_widget_get_relative (Gtk.Widget widget, GLib.Type relative_type); + [CCode (cheader_filename = "dazzle.h")] + public static void gtk_widget_hide_with_fade (Gtk.Widget widget); + [CCode (cheader_filename = "dazzle.h")] + [Version (since = "3.26")] + public static bool gtk_widget_is_ancestor_or_relative (Gtk.Widget widget, Gtk.Widget ancestor); + [CCode (cheader_filename = "dazzle.h")] + public static void gtk_widget_mux_action_groups (Gtk.Widget widget, Gtk.Widget from_widget, string? mux_key); + [CCode (cheader_filename = "dazzle.h")] + public static void gtk_widget_remove_style_class (Gtk.Widget widget, string class_name); + [CCode (cheader_filename = "dazzle.h")] + public static void gtk_widget_show_with_fade (Gtk.Widget widget); + [CCode (cheader_filename = "dazzle.h")] + public static int levenshtein (string needle, string haystack); + [CCode (cheader_filename = "dazzle.h")] + public static void overlay_add_child (Dazzle.DockOverlay self, Gtk.Widget child, string type); + [CCode (cheader_filename = "dazzle.h")] + public static string pango_font_description_to_css (Pango.FontDescription font_desc); + [CCode (cheader_filename = "dazzle.h")] + public static void rgba_shade (Gdk.RGBA rgba, Gdk.RGBA dst, double k); +} \ No newline at end of file From ad6f42aa50cae6bb83bcac473fe9f987d069c424 Mon Sep 17 00:00:00 2001 From: stsdc Date: Mon, 24 Feb 2020 23:27:00 +0100 Subject: [PATCH 33/96] update ProcessView on intervals --- src/MainWindow.vala | 15 ++-- .../ProcessView/CPUProcessTreeView.vala | 2 +- src/Widgets/ProcessView/ProcessInfoView.vala | 74 +++++++++++-------- src/Widgets/ProcessView/ProcessView.vala | 16 ++-- 4 files changed, 65 insertions(+), 42 deletions(-) diff --git a/src/MainWindow.vala b/src/MainWindow.vala index a472674f..03c734eb 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -7,14 +7,10 @@ // private Gtk.Button process_info_button; public ProcessView process_view; - + // public ProcessManager process_manager; private Statusbar statusbar; - public Model generic_model; - // public Model generic_model; - public Gtk.TreeModelSort sort_model; - public Gtk.TreeModelFilter filter; public DBusServer dbusserver; @@ -43,8 +39,8 @@ // TODO: Granite.Widgets.ModeButton to switch between view modes - generic_model = new Model (); - process_view = new ProcessView (generic_model); + // process_manager = new ProcessManager(); + process_view = new ProcessView (); headerbar = new Headerbar (this); set_titlebar (headerbar); @@ -65,6 +61,11 @@ dbusserver.indicator_state (MonitorApp.settings.get_boolean ("indicator-state")); }); + Timeout.add_seconds (2, () => { + process_view.update(); + return true; + }); + dbusserver.quit.connect (() => app.quit()); dbusserver.show.connect (() => { this.deiconify(); diff --git a/src/Widgets/ProcessView/CPUProcessTreeView.vala b/src/Widgets/ProcessView/CPUProcessTreeView.vala index 6a6f1476..8639589a 100644 --- a/src/Widgets/ProcessView/CPUProcessTreeView.vala +++ b/src/Widgets/ProcessView/CPUProcessTreeView.vala @@ -1,5 +1,5 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { - private Model model; + private new Model model; private Gtk.TreeViewColumn name_column; private Gtk.TreeViewColumn pid_column; private Gtk.TreeViewColumn cpu_column; diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index 2fc2c858..dce30a4d 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -1,4 +1,20 @@ public class Monitor.ProcessInfoView : Gtk.Box { + private Process _process; + public Process process { + get { return _process; } + set { + _process = value; + application_name.set_text (_process.application_name); + pid.set_text (("%d").printf (_process.stat.pid)); + nice.set_text (("%d").printf (_process.stat.nice)); + priority.set_text (("%d").printf (_process.stat.priority)); + username.set_text (_process.username); + num_threads.set_text (("%d").printf (_process.stat.num_threads)); + state.set_text (_process.stat.state); + + set_icon (_process); + } + } public Gtk.Label application_name; public string ? icon_name; public Gtk.TextView command; @@ -12,7 +28,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { public RoundyLabel username; public RoundyLabel pid; private Gtk.Image icon; - private Regex? regex; + private Regex ? regex; private Gtk.Grid grid; private Gtk.Popover pid_popover; @@ -22,7 +38,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { margin = 12; orientation = Gtk.Orientation.VERTICAL; hexpand = true; - regex = /(?i:^.*\.(xpm|png)$)/; + regex = /( ? i : ^.*\.(xpm|png)$)/; var icon_container = new Gtk.Fixed (); @@ -34,22 +50,22 @@ public class Monitor.ProcessInfoView : Gtk.Box { state.halign = Gtk.Align.START; state.get_style_context ().add_class ("state_badge"); - icon_container.put (icon, 0, 0); + icon_container.put (icon, 0, 0); icon_container.put (state, -5, 48); application_name = new Gtk.Label (_ ("N/A")); application_name.get_style_context ().add_class ("h2"); application_name.ellipsize = Pango.EllipsizeMode.END; - application_name.tooltip_text = _("N/A"); + application_name.tooltip_text = _ ("N/A"); application_name.halign = Gtk.Align.START; application_name.valign = Gtk.Align.START; - pid = new RoundyLabel (_("PID")); - nice = new RoundyLabel (_("NI")); - priority = new RoundyLabel (_("PRI")); - num_threads = new RoundyLabel (_("THR")); + pid = new RoundyLabel (_ ("PID")); + nice = new RoundyLabel (_ ("NI")); + priority = new RoundyLabel (_ ("PRI")); + num_threads = new RoundyLabel (_ ("THR")); // ppid = new RoundyLabel (_("PPID")); // pgrp = new RoundyLabel (_("PGRP")); // pid_popover = new Gtk.Popover (pid); @@ -66,12 +82,12 @@ public class Monitor.ProcessInfoView : Gtk.Box { var wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); // wrapper.add (state); - wrapper.add ( pid); - wrapper.add ( priority); - wrapper.add ( nice); - wrapper.add ( num_threads); + wrapper.add (pid); + wrapper.add (priority); + wrapper.add (nice); + wrapper.add (num_threads); // wrapper.add ( ppid); - wrapper.add ( username); + wrapper.add (username); /* ==========START COMMAND WIDGET============== */ // command widget should be a widget that contains one line, but expands on click @@ -98,31 +114,33 @@ public class Monitor.ProcessInfoView : Gtk.Box { grid.column_spacing = 12; - grid.attach ( icon_container, 0, 0, 1, 2); + grid.attach (icon_container, 0, 0, 1, 2); grid.attach (application_name, 1, 0, 3, 1); - grid.attach ( wrapper, 1, 1, 1, 1); + grid.attach (wrapper, 1, 1, 1, 1); - add ( grid); + add (grid); // add (command_wrapper); } - public void update (Process process) { + public void update () { // probably not ok to update everything // TODO: find a better way to do this // if (pid_number.get_text() != ("%d").printf (process.stat.pid)) { // command.buffer.text = process.command; // } - application_name.set_text (("%s").printf (process.application_name)); - application_name.tooltip_text = process.command; - pid.set_text (("%d").printf (process.stat.pid)); - nice.set_text (("%d").printf (process.stat.nice)); - priority.set_text (("%d").printf (process.stat.priority)); - num_threads.set_text (("%d").printf (process.stat.num_threads)); - // ppid.set_text (("%d").printf (process.stat.ppid)); - // pgrp.set_text (("%d").printf (process.stat.pgrp)); - state.set_text (process.stat.state); - username.set_text (process.username); + // this.process = process; + if (process != null) { + num_threads.set_text (("%d").printf (process.stat.num_threads)); + // ppid.set_text (("%d").printf (process.stat.ppid)); + // pgrp.set_text (("%d").printf (process.stat.pgrp)); + state.set_text (process.stat.state); + + set_icon (process); + } + } + private void set_icon (Process process) { + // this construction should be somewhere else var icon_name = process.icon.to_string (); if (!regex.match (icon_name)) { @@ -136,6 +154,4 @@ public class Monitor.ProcessInfoView : Gtk.Box { } } } - - } \ No newline at end of file diff --git a/src/Widgets/ProcessView/ProcessView.vala b/src/Widgets/ProcessView/ProcessView.vala index 6d56ef5c..4b1d8172 100644 --- a/src/Widgets/ProcessView/ProcessView.vala +++ b/src/Widgets/ProcessView/ProcessView.vala @@ -1,4 +1,5 @@ public class Monitor.ProcessView : Gtk.Box { + public new Model treeview_model; public CPUProcessTreeView process_tree_view; public ProcessInfoView process_info_view; @@ -11,10 +12,11 @@ public class Monitor.ProcessView : Gtk.Box { process_info_view.no_show_all = true; } - public ProcessView (Model model) { + public ProcessView () { + treeview_model = new Model (); - process_tree_view = new CPUProcessTreeView (model); - process_tree_view.update_selected_process.connect ((process) => update (process)); + process_tree_view = new CPUProcessTreeView (treeview_model); + process_tree_view.update_selected_process.connect ((process) => on_update_selected_process (process)); // making tree view scrollable var process_tree_view_scrolled = new Gtk.ScrolledWindow (null, null); @@ -31,9 +33,13 @@ public class Monitor.ProcessView : Gtk.Box { show_all (); } - public void update (Process process) { - process_info_view.update(process); + public void on_update_selected_process (Process process) { + process_info_view.process = process; process_info_view.no_show_all = false; process_info_view.show_all (); } + + public void update () { + process_info_view.update (); + } } \ No newline at end of file From 5efbdff6195510d723ef97629798090995c5d4ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= Date: Tue, 25 Feb 2020 12:12:12 +0100 Subject: [PATCH 34/96] fix treeview_model in Search widget --- src/Widgets/Headerbar/Search.vala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Widgets/Headerbar/Search.vala b/src/Widgets/Headerbar/Search.vala index e1bb4574..3e440e8d 100644 --- a/src/Widgets/Headerbar/Search.vala +++ b/src/Widgets/Headerbar/Search.vala @@ -14,10 +14,10 @@ namespace Monitor { this.placeholder_text = _("Search Process"); this.tooltip_markup = Granite.markup_accel_tooltip ({"F"}, _("Type process name or PID to search")); - filter_model = new Gtk.TreeModelFilter (window.generic_model, null); + filter_model = new Gtk.TreeModelFilter (window.process_view.treeview_model, null); connect_signal (); filter_model.set_visible_func(filter_func); - process_tree_view.set_model (filter_model); + // process_tree_view.set_model (filter_model); var sort_model = new Gtk.TreeModelSort.with_model (filter_model); process_tree_view.set_model (sort_model); From 2173e5bcfecf7bff2b9384d296d42e28a43fb437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= Date: Tue, 25 Feb 2020 12:12:35 +0100 Subject: [PATCH 35/96] show tooltip with a full command in ProcessInfoView --- src/Widgets/ProcessView/ProcessInfoView.vala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index dce30a4d..7e06eb0e 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -5,6 +5,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { set { _process = value; application_name.set_text (_process.application_name); + application_name.tooltip_text = _process.command; pid.set_text (("%d").printf (_process.stat.pid)); nice.set_text (("%d").printf (_process.stat.nice)); priority.set_text (("%d").printf (_process.stat.priority)); From 5f4056fb71d387e39a49dc14572005af16b720de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= Date: Tue, 25 Feb 2020 12:33:58 +0100 Subject: [PATCH 36/96] cleanup --- src/Managers/ProcessManager.vala | 14 +- .../ProcessView/CPUProcessTreeView.vala | 365 +++++++++--------- src/Widgets/ProcessView/ProcessView.vala | 5 +- 3 files changed, 187 insertions(+), 197 deletions(-) diff --git a/src/Managers/ProcessManager.vala b/src/Managers/ProcessManager.vala index 708dd680..7fc6b9a0 100644 --- a/src/Managers/ProcessManager.vala +++ b/src/Managers/ProcessManager.vala @@ -33,8 +33,6 @@ namespace Monitor { update_processes.begin (); - // move timeout outside - Timeout.add (2000, handle_timeout); } public void populate_apps_info() { @@ -142,18 +140,10 @@ namespace Monitor { return process_list.read_only_view; } - /** - * Handle updating the process list - */ - private bool handle_timeout () { - update_processes.begin (); - return true; - } - /** * Gets all new process and adds them */ - private async void update_processes () { + public async void update_processes () { /* CPU */ GTop.Cpu cpu_data; GTop.get_cpu (out cpu_data); @@ -204,7 +194,7 @@ namespace Monitor { cpu_last_useds = useds; cpu_last_totals = cpu_data.xcpu_total; - /* call the updated signal so that subscribers can update */ + /* emit the updated signal so that subscribers can update */ updated (); } diff --git a/src/Widgets/ProcessView/CPUProcessTreeView.vala b/src/Widgets/ProcessView/CPUProcessTreeView.vala index 8639589a..523b2abb 100644 --- a/src/Widgets/ProcessView/CPUProcessTreeView.vala +++ b/src/Widgets/ProcessView/CPUProcessTreeView.vala @@ -1,206 +1,205 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { - private new Model model; - private Gtk.TreeViewColumn name_column; - private Gtk.TreeViewColumn pid_column; - private Gtk.TreeViewColumn cpu_column; - private Gtk.TreeViewColumn memory_column; - private Regex? regex; - - const string NO_DATA = "\u2014"; - - public signal void update_selected_process (Process process); - - public CPUProcessTreeView (Model model) { - this.model = model; - regex = /(?i:^.*\.(xpm|png)$)/; - - // setup name column - name_column = new Gtk.TreeViewColumn (); - name_column.title = _("Process Name"); - name_column.expand = true; - name_column.min_width = 250; - name_column.set_sort_column_id (Column.NAME); - - var icon_cell = new Gtk.CellRendererPixbuf (); - name_column.pack_start (icon_cell, false); - // name_column.add_attribute (icon_cell, "icon_name", Column.ICON); - name_column.set_cell_data_func (icon_cell, icon_cell_layout); - - var name_cell = new Gtk.CellRendererText (); - name_cell.ellipsize = Pango.EllipsizeMode.END; - name_cell.set_fixed_height_from_font (1); - name_column.pack_start (name_cell, false); - name_column.add_attribute (name_cell, "text", Column.NAME); - insert_column (name_column, -1); - - // setup cpu column - var cpu_cell = new Gtk.CellRendererText (); - cpu_cell.xalign = 0.5f; - - cpu_column = new Gtk.TreeViewColumn.with_attributes (_("CPU"), cpu_cell); - cpu_column.expand = false; - cpu_column.set_cell_data_func (cpu_cell, cpu_usage_cell_layout); - cpu_column.alignment = 0.5f; - cpu_column.set_sort_column_id (Column.CPU); - insert_column (cpu_column, -1); - - // setup memory column - var memory_cell = new Gtk.CellRendererText (); - memory_cell.xalign = 0.5f; - - memory_column = new Gtk.TreeViewColumn.with_attributes (_("Memory"), memory_cell); - memory_column.expand = false; - memory_column.set_cell_data_func (memory_cell, memory_usage_cell_layout); - memory_column.alignment = 0.5f; - memory_column.set_sort_column_id (Column.MEMORY); - insert_column (memory_column, -1); - - // setup PID column - var pid_cell = new Gtk.CellRendererText (); - pid_cell.xalign = 0.5f; - pid_column = new Gtk.TreeViewColumn.with_attributes (_("PID"), pid_cell); - pid_column.set_cell_data_func (pid_cell, pid_cell_layout); - pid_column.expand = false; - pid_column.alignment = 0.5f; - pid_column.set_sort_column_id (Column.PID); - pid_column.add_attribute (pid_cell, "text", Column.PID); - insert_column (pid_column, -1); - - // resize all of the columns - columns_autosize (); - - set_model (model); - - - cursor_changed.connect (_cursor_changed); - model.process_manager.updated.connect (_cursor_changed); - } - public void icon_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer icon_cell, Gtk.TreeModel model, Gtk.TreeIter iter) { - Value icon_name; - model.get_value (iter, Column.ICON, out icon_name); - if (regex.match ((string) icon_name)) { - string path = ((string) icon_name); - - try { - Gdk.Pixbuf icon = new Gdk.Pixbuf.from_file_at_size (path, 16, -1); - (icon_cell as Gtk.CellRendererPixbuf).pixbuf = icon; - } catch (Error e) { - warning (e.message); - } - } else { - (icon_cell as Gtk.CellRendererPixbuf).icon_name = (string) icon_name; + private new Model model; + private Gtk.TreeViewColumn name_column; + private Gtk.TreeViewColumn pid_column; + private Gtk.TreeViewColumn cpu_column; + private Gtk.TreeViewColumn memory_column; + private Regex ? regex; + + const string NO_DATA = "\u2014"; + + public signal void process_selected (Process process); + + public CPUProcessTreeView (Model model) { + this.model = model; + regex = /(?i:^.*\.(xpm|png)$)/; + + // setup name column + name_column = new Gtk.TreeViewColumn (); + name_column.title = _ ("Process Name"); + name_column.expand = true; + name_column.min_width = 250; + name_column.set_sort_column_id (Column.NAME); + + var icon_cell = new Gtk.CellRendererPixbuf (); + name_column.pack_start (icon_cell, false); + // name_column.add_attribute (icon_cell, "icon_name", Column.ICON); + name_column.set_cell_data_func (icon_cell, icon_cell_layout); + + var name_cell = new Gtk.CellRendererText (); + name_cell.ellipsize = Pango.EllipsizeMode.END; + name_cell.set_fixed_height_from_font (1); + name_column.pack_start (name_cell, false); + name_column.add_attribute (name_cell, "text", Column.NAME); + insert_column (name_column, -1); + + // setup cpu column + var cpu_cell = new Gtk.CellRendererText (); + cpu_cell.xalign = 0.5f; + + cpu_column = new Gtk.TreeViewColumn.with_attributes (_ ("CPU"), cpu_cell); + cpu_column.expand = false; + cpu_column.set_cell_data_func (cpu_cell, cpu_usage_cell_layout); + cpu_column.alignment = 0.5f; + cpu_column.set_sort_column_id (Column.CPU); + insert_column (cpu_column, -1); + + // setup memory column + var memory_cell = new Gtk.CellRendererText (); + memory_cell.xalign = 0.5f; + + memory_column = new Gtk.TreeViewColumn.with_attributes (_ ("Memory"), memory_cell); + memory_column.expand = false; + memory_column.set_cell_data_func (memory_cell, memory_usage_cell_layout); + memory_column.alignment = 0.5f; + memory_column.set_sort_column_id (Column.MEMORY); + insert_column (memory_column, -1); + + // setup PID column + var pid_cell = new Gtk.CellRendererText (); + pid_cell.xalign = 0.5f; + pid_column = new Gtk.TreeViewColumn.with_attributes (_ ("PID"), pid_cell); + pid_column.set_cell_data_func (pid_cell, pid_cell_layout); + pid_column.expand = false; + pid_column.alignment = 0.5f; + pid_column.set_sort_column_id (Column.PID); + pid_column.add_attribute (pid_cell, "text", Column.PID); + insert_column (pid_column, -1); + + // resize all of the columns + columns_autosize (); + + set_model (model); + + + cursor_changed.connect (_cursor_changed); + model.process_manager.updated.connect (_cursor_changed); + } + public void icon_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer icon_cell, Gtk.TreeModel model, Gtk.TreeIter iter) { + Value icon_name; + model.get_value (iter, Column.ICON, out icon_name); + if (regex.match ((string)icon_name)) { + string path = ((string)icon_name); + + try { + Gdk.Pixbuf icon = new Gdk.Pixbuf.from_file_at_size (path, 16, -1); + (icon_cell as Gtk.CellRendererPixbuf).pixbuf = icon; + } catch (Error e) { + warning (e.message); } + } else { + (icon_cell as Gtk.CellRendererPixbuf).icon_name = (string)icon_name; } + } - public void cpu_usage_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter) { - // grab the value that was store in the model and convert it down to a usable format - Value cpu_usage_value; - model.get_value (iter, Column.CPU, out cpu_usage_value); - double cpu_usage = cpu_usage_value.get_double (); - - // format the double into a string - if (cpu_usage < 0.0) - (cell as Gtk.CellRendererText).text = NO_DATA; - else - (cell as Gtk.CellRendererText).text = "%.0f%%".printf (cpu_usage * 100.0); - } - - public void memory_usage_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter) { - // grab the value that was store in the model and convert it down to a usable format - Value memory_usage_value; - model.get_value (iter, Column.MEMORY, out memory_usage_value); - int64 memory_usage = memory_usage_value.get_int64 (); - double memory_usage_double = (double) memory_usage; - string units = _("KiB"); - - // convert to MiB if needed - if (memory_usage_double > 1024.0) { - memory_usage_double /= 1024.0; - units = _("MiB"); - } - - // convert to GiB if needed - if (memory_usage_double > 1024.0) { - memory_usage_double /= 1024.0; - units = _("GiB"); - } + public void cpu_usage_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter) { + // grab the value that was store in the model and convert it down to a usable format + Value cpu_usage_value; + model.get_value (iter, Column.CPU, out cpu_usage_value); + double cpu_usage = cpu_usage_value.get_double (); + + // format the double into a string + if (cpu_usage < 0.0) + (cell as Gtk.CellRendererText).text = NO_DATA; + else + (cell as Gtk.CellRendererText).text = "%.0f%%".printf (cpu_usage * 100.0); + } - // format the double into a string - if (memory_usage == 0) - (cell as Gtk.CellRendererText).text = NO_DATA; - else - (cell as Gtk.CellRendererText).text = "%.1f %s".printf (memory_usage_double, units); + public void memory_usage_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter) { + // grab the value that was store in the model and convert it down to a usable format + Value memory_usage_value; + model.get_value (iter, Column.MEMORY, out memory_usage_value); + int64 memory_usage = memory_usage_value.get_int64 (); + double memory_usage_double = (double)memory_usage; + string units = _ ("KiB"); + + // convert to MiB if needed + if (memory_usage_double > 1024.0) { + memory_usage_double /= 1024.0; + units = _ ("MiB"); } - private void pid_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter) { - Value pid_value; - model.get_value (iter, Column.PID, out pid_value); - int pid = pid_value.get_int (); - // format the double into a string - if (pid == 0) { - (cell as Gtk.CellRendererText).text = NO_DATA; - } + // convert to GiB if needed + if (memory_usage_double > 1024.0) { + memory_usage_double /= 1024.0; + units = _ ("GiB"); } - public void focus_on_first_row () { - Gtk.TreePath tree_path = new Gtk.TreePath.from_indices (0); - this.set_cursor (tree_path, null, false); - grab_focus (); - } + // format the double into a string + if (memory_usage == 0) + (cell as Gtk.CellRendererText).text = NO_DATA; + else + (cell as Gtk.CellRendererText).text = "%.1f %s".printf (memory_usage_double, units); + } - public void focus_on_child_row () { - Gtk.TreePath tree_path = new Gtk.TreePath.from_indices (0, 0); - this.set_cursor (tree_path, null, false); - grab_focus (); + private void pid_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter) { + Value pid_value; + model.get_value (iter, Column.PID, out pid_value); + int pid = pid_value.get_int (); + // format the double into a string + if (pid == 0) { + (cell as Gtk.CellRendererText).text = NO_DATA; } + } - public int get_pid_of_selected () { - Gtk.TreeIter iter; - Gtk.TreeModel model; - int pid = 0; - var selection = this.get_selection ().get_selected_rows(out model).nth_data(0); - model.get_iter (out iter, selection); - model.get (iter, Column.PID, out pid); - return pid; - } + public void focus_on_first_row () { + Gtk.TreePath tree_path = new Gtk.TreePath.from_indices (0); + this.set_cursor (tree_path, null, false); + grab_focus (); + } - // How about GtkTreeSelection ? + public void focus_on_child_row () { + Gtk.TreePath tree_path = new Gtk.TreePath.from_indices (0, 0); + this.set_cursor (tree_path, null, false); + grab_focus (); + } - public void expanded () { - Gtk.TreeModel model; - var selection = this.get_selection ().get_selected_rows(out model).nth_data(0); - this.expand_row (selection, false); - } + public int get_pid_of_selected () { + Gtk.TreeIter iter; + Gtk.TreeModel model; + int pid = 0; + var selection = this.get_selection ().get_selected_rows (out model).nth_data (0); + model.get_iter (out iter, selection); + model.get (iter, Column.PID, out pid); + return pid; + } - public void collapse () { - Gtk.TreeModel model; - var selection = this.get_selection ().get_selected_rows(out model).nth_data(0); - this.collapse_row (selection); - } + // How about GtkTreeSelection ? - public void kill_process () { - int pid = get_pid_of_selected (); - model.kill_process (pid); - } + public void expanded () { + Gtk.TreeModel model; + var selection = this.get_selection ().get_selected_rows (out model).nth_data (0); + this.expand_row (selection, false); + } - public void end_process () { - int pid = get_pid_of_selected (); - model.end_process (pid); + public void collapse () { + Gtk.TreeModel model; + var selection = this.get_selection ().get_selected_rows (out model).nth_data (0); + this.collapse_row (selection); + } + + public void kill_process () { + int pid = get_pid_of_selected (); + model.kill_process (pid); + } + + public void end_process () { + int pid = get_pid_of_selected (); + model.end_process (pid); } // when row is selected send signal to update process_info_view public void _cursor_changed () { - Gtk.TreeModel tree_model; - Gtk.TreeIter iter; - int pid = 0; - var selection = get_selection ().get_selected_rows(out tree_model).nth_data(0); - - if (selection != null) { - tree_model.get_iter (out iter, selection); - tree_model.get (iter, Column.PID, out pid); - Process process = model.process_manager.get_process(pid); - update_selected_process (process); - } - + Gtk.TreeModel tree_model; + Gtk.TreeIter iter; + int pid = 0; + var selection = get_selection ().get_selected_rows (out tree_model).nth_data (0); + + if (selection != null) { + tree_model.get_iter (out iter, selection); + tree_model.get (iter, Column.PID, out pid); + Process process = model.process_manager.get_process (pid); + process_selected (process); } + } } diff --git a/src/Widgets/ProcessView/ProcessView.vala b/src/Widgets/ProcessView/ProcessView.vala index 4b1d8172..f68e6fc6 100644 --- a/src/Widgets/ProcessView/ProcessView.vala +++ b/src/Widgets/ProcessView/ProcessView.vala @@ -16,7 +16,7 @@ public class Monitor.ProcessView : Gtk.Box { treeview_model = new Model (); process_tree_view = new CPUProcessTreeView (treeview_model); - process_tree_view.update_selected_process.connect ((process) => on_update_selected_process (process)); + process_tree_view.process_selected.connect ((process) => on_process_selected (process)); // making tree view scrollable var process_tree_view_scrolled = new Gtk.ScrolledWindow (null, null); @@ -33,7 +33,7 @@ public class Monitor.ProcessView : Gtk.Box { show_all (); } - public void on_update_selected_process (Process process) { + public void on_process_selected (Process process) { process_info_view.process = process; process_info_view.no_show_all = false; process_info_view.show_all (); @@ -41,5 +41,6 @@ public class Monitor.ProcessView : Gtk.Box { public void update () { process_info_view.update (); + treeview_model.process_manager.update_processes.begin(); } } \ No newline at end of file From 4269e6885e5c5581ab3607ce2ae6e1688b0fcd93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= Date: Tue, 25 Feb 2020 15:11:42 +0100 Subject: [PATCH 37/96] graphs showing the thing --- src/Models/CPUGraphModel.vala | 10 ++-- src/Widgets/ProcessView/CPUGraph.vala | 3 + src/Widgets/ProcessView/ProcessInfoView.vala | 63 +++++++------------- 3 files changed, 29 insertions(+), 47 deletions(-) diff --git a/src/Models/CPUGraphModel.vala b/src/Models/CPUGraphModel.vala index aa7554c5..e8f4894a 100644 --- a/src/Models/CPUGraphModel.vala +++ b/src/Models/CPUGraphModel.vala @@ -27,10 +27,10 @@ public class CpuGraphModel : Dazzle.GraphModel { private bool[] change_small_process_usage; public CpuGraphModel () { - set_timespan (1000); - set_max_samples (50); + set_timespan (TimeSpan.MINUTE); + set_max_samples (100); - var column_total = new Dazzle.GraphColumn ("TOTAL CPU", Type.from_name ("gdouble")); + var column_total = new Dazzle.GraphColumn ("TOTAL CPU", Type.DOUBLE); add_column (column_total); // change_big_process_usage = new bool[get_num_processors()]; @@ -47,8 +47,8 @@ public class CpuGraphModel : Dazzle.GraphModel { // Timeout.add(1000, update_data); } - bool update_data (int percentage) { - debug ("Got percentage: %d", percentage); + public bool update (double percentage) { + debug ("Got percentage: %f", percentage); Dazzle.GraphModelIter iter; push (out iter, get_monotonic_time ()); diff --git a/src/Widgets/ProcessView/CPUGraph.vala b/src/Widgets/ProcessView/CPUGraph.vala index 46056cfc..f1e7f370 100644 --- a/src/Widgets/ProcessView/CPUGraph.vala +++ b/src/Widgets/ProcessView/CPUGraph.vala @@ -19,6 +19,9 @@ public class CpuGraph : Dazzle.GraphView get_style_context().remove_class("line"); get_style_context().add_class("big"); + expand = true; + margin = 6; + set_model(graph_model); Gdk.RGBA linecol = Gdk.RGBA (); diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index 7e06eb0e..2c65158a 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -18,7 +18,6 @@ public class Monitor.ProcessInfoView : Gtk.Box { } public Gtk.Label application_name; public string ? icon_name; - public Gtk.TextView command; private Gtk.ScrolledWindow command_wrapper; public RoundyLabel ppid; public RoundyLabel pgrp; @@ -32,14 +31,18 @@ public class Monitor.ProcessInfoView : Gtk.Box { private Regex ? regex; private Gtk.Grid grid; - private Gtk.Popover pid_popover; + private CpuGraph cpu_graph; + private CpuGraphModel cpu_graph_model; + + private CpuGraph mem_graph; + private CpuGraphModel mem_graph_model; public ProcessInfoView () { // get_style_context ().add_class ("process_info"); margin = 12; orientation = Gtk.Orientation.VERTICAL; hexpand = true; - regex = /( ? i : ^.*\.(xpm|png)$)/; + regex = /(?i:^.*\.(xpm|png)$)/; var icon_container = new Gtk.Fixed (); @@ -69,72 +72,48 @@ public class Monitor.ProcessInfoView : Gtk.Box { num_threads = new RoundyLabel (_ ("THR")); // ppid = new RoundyLabel (_("PPID")); // pgrp = new RoundyLabel (_("PGRP")); - // pid_popover = new Gtk.Popover (pid); - // pid_popover.add (ppid); - // pid_popover.add (pgrp); + username = new RoundyLabel (""); - // pid_popover.show_all (); - // pid_popover.present (); - // pid_popover.run (); - // pid_popover.destroy (); + cpu_graph_model = new CpuGraphModel(); + cpu_graph = new CpuGraph(cpu_graph_model); + mem_graph_model = new CpuGraphModel(); + mem_graph = new CpuGraph(mem_graph_model); - username = new RoundyLabel (""); + var graph_wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); + graph_wrapper.valign = Gtk.Align.START; + graph_wrapper.height_request = 60; + + + graph_wrapper.add (cpu_graph); + graph_wrapper.add (mem_graph); var wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); - // wrapper.add (state); wrapper.add (pid); wrapper.add (priority); wrapper.add (nice); wrapper.add (num_threads); - // wrapper.add ( ppid); wrapper.add (username); - /* ==========START COMMAND WIDGET============== */ - // command widget should be a widget that contains one line, but expands on click - // when clicked it should reveal full command - // command = new Gtk.TextView (); - // command.buffer.text = "N/A"; - // command.pixels_above_lines = 3; - // command.margin = 8; - // command.set_wrap_mode (Gtk.WrapMode.WORD); - // setting resize mode, so command wraps immediatly when right sidebar changed - // command.resize_mode = Gtk.ResizeMode.IMMEDIATE; - // command.get_style_context ().add_class ("command"); - - // command_wrapper = new Gtk.ScrolledWindow (null, null); - // command_wrapper.get_style_context ().add_class ("command_wrapper"); - // command_wrapper.margin_top = 24; - // command_wrapper.resize_mode = Gtk.ResizeMode.IMMEDIATE; - // command_wrapper.add (command); - /* ==========END COMMAND WIDGET============== */ - - grid = new Gtk.Grid (); grid.get_style_context ().add_class ("horizontal"); grid.column_spacing = 12; - - grid.attach (icon_container, 0, 0, 1, 2); grid.attach (application_name, 1, 0, 3, 1); grid.attach (wrapper, 1, 1, 1, 1); add (grid); - // add (command_wrapper); + add (graph_wrapper); } public void update () { - // probably not ok to update everything - // TODO: find a better way to do this - // if (pid_number.get_text() != ("%d").printf (process.stat.pid)) { - // command.buffer.text = process.command; - // } - // this.process = process; if (process != null) { num_threads.set_text (("%d").printf (process.stat.num_threads)); // ppid.set_text (("%d").printf (process.stat.ppid)); // pgrp.set_text (("%d").printf (process.stat.pgrp)); state.set_text (process.stat.state); + cpu_graph_model.update (process.cpu_usage * 100); + mem_graph_model.update (process.cpu_usage * 100 + 30); set_icon (process); } From ab74670937e59789d31dc69381a7d6c3bd202295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= Date: Tue, 25 Feb 2020 16:13:20 +0100 Subject: [PATCH 38/96] display graphs of memory usage & cpu usage of particular process --- meson.build | 5 +- src/Managers/Process.vala | 4 ++ src/Models/CPUGraphModel.vala | 59 ------------------- src/Models/GraphModel.vala | 20 +++++++ .../ProcessView/{CPUGraph.vala => Graph.vala} | 6 +- src/Widgets/ProcessView/ProcessInfoView.vala | 21 ++++--- 6 files changed, 41 insertions(+), 74 deletions(-) delete mode 100644 src/Models/CPUGraphModel.vala create mode 100644 src/Models/GraphModel.vala rename src/Widgets/ProcessView/{CPUGraph.vala => Graph.vala} (88%) diff --git a/meson.build b/meson.build index 844730d9..2d3ec743 100644 --- a/meson.build +++ b/meson.build @@ -66,14 +66,13 @@ executable( 'src/Widgets/Statusbar/Statusbar.vala', 'src/Widgets/ProcessView/ProcessInfoView.vala', 'src/Widgets/ProcessView/RoundyLabel.vala', + 'src/Widgets/ProcessView/Graph.vala', 'src/Widgets/ProcessView/ProcessView.vala', 'src/Managers/ProcessUtils.vala', - # 'src/Models/GenericModel.vala', 'src/Models/Model.vala', - 'src/Models/CPUGraphModel.vala', - 'src/Widgets/ProcessView/CPUGraph.vala', + 'src/Models/GraphModel.vala', # 'src/Models/ModelHelper.vala', 'src/Managers/AppManager.vala', diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index 3233792b..5129bbe1 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -52,6 +52,7 @@ public class Monitor.Process : GLib.Object { //Memory usage of the process, measured in KiB. public uint64 mem_usage { get; private set; } + public double mem_percentage { get; private set; } private uint64 last_total; @@ -237,5 +238,8 @@ public class Monitor.Process : GLib.Object { Wnck.ResourceUsage resu = Wnck.ResourceUsage.pid_read (Gdk.Display.get_default (), stat.pid); mem_usage += (resu.total_bytes_estimate / 1024); } + + var total_installed_memory = (double)mem.total / 1024; + mem_percentage = (mem_usage / total_installed_memory) * 100; } } diff --git a/src/Models/CPUGraphModel.vala b/src/Models/CPUGraphModel.vala deleted file mode 100644 index e8f4894a..00000000 --- a/src/Models/CPUGraphModel.vala +++ /dev/null @@ -1,59 +0,0 @@ -// /* cpu-graph-model.vala -// * -// * Copyright (C) 2018 Red Hat, Inc. -// * Copyright (C) 2020 stsdc -// * -// * -// * This program is free software: you can redistribute it and/or modify -// * it under the terms of the GNU General Public License as published by -// * the Free Software Foundation, either version 3 of the License, or -// * (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have received a copy of the GNU General Public License -// * along with this program. If not, see . -// * -// * Authors: Petr Štětka -// * Authors: Stanisław -// */ -public class CpuGraphModel : Dazzle.GraphModel { - public signal void big_process_usage (int column); - public signal void small_process_usage (int column); - private bool[] change_big_process_usage; - private bool[] change_small_process_usage; - - public CpuGraphModel () { - set_timespan (TimeSpan.MINUTE); - set_max_samples (100); - - var column_total = new Dazzle.GraphColumn ("TOTAL CPU", Type.DOUBLE); - add_column (column_total); - - // change_big_process_usage = new bool[get_num_processors()]; - // change_small_process_usage = new bool[get_num_processors()]; - - // for (int i = 0; i < get_num_processors(); i++) { - // var column_x_cpu = new GraphColumn("CPU: " + i.to_string(), Type.from_name("gdouble")); - // add_column(column_x_cpu); - - // change_big_process_usage[i] = true; - // change_small_process_usage[i] = true; - // } - - // Timeout.add(1000, update_data); - } - - public bool update (double percentage) { - debug ("Got percentage: %f", percentage); - Dazzle.GraphModelIter iter; - - push (out iter, get_monotonic_time ()); - iter_set_value (iter, 0, percentage); - - return true; - } -} diff --git a/src/Models/GraphModel.vala b/src/Models/GraphModel.vala new file mode 100644 index 00000000..2951b8ff --- /dev/null +++ b/src/Models/GraphModel.vala @@ -0,0 +1,20 @@ +public class Monitor.GraphModel : Dazzle.GraphModel { + + public GraphModel () { + set_timespan (TimeSpan.MINUTE); + set_max_samples (100); + + var column_total = new Dazzle.GraphColumn ("CPU USAGE", Type.DOUBLE); + add_column (column_total); + } + + public bool update (double percentage) { + debug ("Got percentage: %f", percentage); + Dazzle.GraphModelIter iter; + + push (out iter, get_monotonic_time ()); + iter_set_value (iter, 0, percentage); + + return true; + } +} diff --git a/src/Widgets/ProcessView/CPUGraph.vala b/src/Widgets/ProcessView/Graph.vala similarity index 88% rename from src/Widgets/ProcessView/CPUGraph.vala rename to src/Widgets/ProcessView/Graph.vala index f1e7f370..3adc74aa 100644 --- a/src/Widgets/ProcessView/CPUGraph.vala +++ b/src/Widgets/ProcessView/Graph.vala @@ -1,6 +1,6 @@ -public class CpuGraph : Dazzle.GraphView +public class Monitor.Graph : Dazzle.GraphView { - private static CpuGraphModel graph_model; + private static GraphModel graph_model; private Dazzle.GraphLineRenderer renderer; private Gdk.RGBA line_color_max; private Gdk.RGBA line_color_normal; @@ -9,7 +9,7 @@ public class CpuGraph : Dazzle.GraphView { } - public CpuGraph(CpuGraphModel graph_model) { + public Graph(GraphModel graph_model) { this.graph_model = graph_model; get_style_context().add_class("line_max"); line_color_max = get_style_context().get_color(get_style_context().get_state()); diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index 2c65158a..9aaa93e6 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -31,11 +31,11 @@ public class Monitor.ProcessInfoView : Gtk.Box { private Regex ? regex; private Gtk.Grid grid; - private CpuGraph cpu_graph; - private CpuGraphModel cpu_graph_model; + private Graph cpu_graph; + private GraphModel cpu_graph_model; - private CpuGraph mem_graph; - private CpuGraphModel mem_graph_model; + private Graph mem_graph; + private GraphModel mem_graph_model; public ProcessInfoView () { // get_style_context ().add_class ("process_info"); @@ -74,11 +74,11 @@ public class Monitor.ProcessInfoView : Gtk.Box { // pgrp = new RoundyLabel (_("PGRP")); username = new RoundyLabel (""); - cpu_graph_model = new CpuGraphModel(); - cpu_graph = new CpuGraph(cpu_graph_model); + cpu_graph_model = new GraphModel(); + cpu_graph = new Graph(cpu_graph_model); - mem_graph_model = new CpuGraphModel(); - mem_graph = new CpuGraph(mem_graph_model); + mem_graph_model = new GraphModel(); + mem_graph = new Graph(mem_graph_model); var graph_wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); graph_wrapper.valign = Gtk.Align.START; @@ -113,7 +113,10 @@ public class Monitor.ProcessInfoView : Gtk.Box { // pgrp.set_text (("%d").printf (process.stat.pgrp)); state.set_text (process.stat.state); cpu_graph_model.update (process.cpu_usage * 100); - mem_graph_model.update (process.cpu_usage * 100 + 30); + cpu_graph.tooltip_text = ("%.1f%%").printf (process.cpu_usage * 100); + + mem_graph_model.update (process.mem_percentage); + mem_graph.tooltip_text = ("%.1f%%").printf (process.mem_percentage); set_icon (process); } From ce3b86861e55786ba0c95a8b95c423c61d819cb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= Date: Wed, 26 Feb 2020 20:36:48 +0100 Subject: [PATCH 39/96] lil bit of cleanup --- src/Models/GraphModel.vala | 2 +- src/Widgets/ProcessView/Graph.vala | 28 ++++++++++------------------ 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/Models/GraphModel.vala b/src/Models/GraphModel.vala index 2951b8ff..d0957360 100644 --- a/src/Models/GraphModel.vala +++ b/src/Models/GraphModel.vala @@ -2,7 +2,7 @@ public class Monitor.GraphModel : Dazzle.GraphModel { public GraphModel () { set_timespan (TimeSpan.MINUTE); - set_max_samples (100); + set_max_samples (60); var column_total = new Dazzle.GraphColumn ("CPU USAGE", Type.DOUBLE); add_column (column_total); diff --git a/src/Widgets/ProcessView/Graph.vala b/src/Widgets/ProcessView/Graph.vala index 3adc74aa..f4f79ef8 100644 --- a/src/Widgets/ProcessView/Graph.vala +++ b/src/Widgets/ProcessView/Graph.vala @@ -2,30 +2,17 @@ public class Monitor.Graph : Dazzle.GraphView { private static GraphModel graph_model; private Dazzle.GraphLineRenderer renderer; - private Gdk.RGBA line_color_max; - private Gdk.RGBA line_color_normal; - class construct - { - } - - public Graph(GraphModel graph_model) { - this.graph_model = graph_model; - get_style_context().add_class("line_max"); - line_color_max = get_style_context().get_color(get_style_context().get_state()); - get_style_context().remove_class("line_max"); - get_style_context().add_class("line"); - line_color_normal = get_style_context().get_color(get_style_context().get_state()); - get_style_context().remove_class("line"); - get_style_context().add_class("big"); + construct { expand = true; margin = 6; - set_model(graph_model); - Gdk.RGBA linecol = Gdk.RGBA (); - linecol.red = 1.0; linecol.green = 0.0; linecol.blue = 0.0; linecol.alpha = 1.0; + linecol.red = 1.0; + linecol.green = 0.0; + linecol.blue = 0.0; + linecol.alpha = 1.0; renderer = new Dazzle.GraphLineRenderer(); renderer.stroke_color_rgba = linecol; @@ -33,6 +20,11 @@ public class Monitor.Graph : Dazzle.GraphView renderer.column = 0; add_renderer (renderer); + } + public Graph(GraphModel graph_model) { + this.graph_model = graph_model; + + set_model(graph_model); } } From b1cc0f4b0192ec9aa52c82a7bfb5e7645fd4224a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= Date: Wed, 26 Feb 2020 20:55:35 +0100 Subject: [PATCH 40/96] move default icon creation to ProcessUtils --- src/Managers/Process.vala | 13 +++---------- src/Managers/ProcessUtils.vala | 9 +++++++++ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index 5129bbe1..59d27843 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -22,11 +22,7 @@ public class Monitor.Process : GLib.Object { get { return _icon; } set { if (value == null) { - try { - _icon = Icon.new_for_string ("application-x-executable"); - } catch (Error e) { - warning (e.message); - } + _icon = ProcessUtils.get_default_icon (); } else { _icon = value; } @@ -59,11 +55,8 @@ public class Monitor.Process : GLib.Object { // Construct a new process public Process (int _pid) { - try { - _icon = Icon.new_for_string ("application-x-executable"); - } catch (Error e) { - warning (e.message); - } + _icon = ProcessUtils.get_default_icon (); + last_total = 0; io = { }; diff --git a/src/Managers/ProcessUtils.vala b/src/Managers/ProcessUtils.vala index e7070a97..82736de4 100644 --- a/src/Managers/ProcessUtils.vala +++ b/src/Managers/ProcessUtils.vala @@ -48,5 +48,14 @@ public class Monitor.ProcessUtils { return null; } } + + public static Icon get_default_icon () { + try { + return Icon.new_for_string ("application-x-executable"); + } catch (Error e) { + warning (e.message); + return null; + } + } } \ No newline at end of file From 48866a76ba95452bb7599edd1f7e57b95bb17c69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= Date: Wed, 26 Feb 2020 21:06:13 +0100 Subject: [PATCH 41/96] lil bit of refactoring --- src/MainWindow.vala | 4 +--- src/Managers/Process.vala | 6 +++--- src/Managers/ProcessUtils.vala | 2 +- src/Models/Model.vala | 4 ++-- src/Widgets/ProcessView/CPUProcessTreeView.vala | 2 +- src/Widgets/ProcessView/Graph.vala | 1 - src/Widgets/ProcessView/ProcessInfoView.vala | 4 ++-- 7 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 03c734eb..09a9be4a 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -7,12 +7,9 @@ // private Gtk.Button process_info_button; public ProcessView process_view; - // public ProcessManager process_manager; private Statusbar statusbar; - public Gtk.TreeModelFilter filter; - public DBusServer dbusserver; private Updater updater; @@ -61,6 +58,7 @@ dbusserver.indicator_state (MonitorApp.settings.get_boolean ("indicator-state")); }); + // updating processes every 2 seconds Timeout.add_seconds (2, () => { process_view.update(); return true; diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index 59d27843..b9547ef4 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -41,7 +41,7 @@ public class Monitor.Process : GLib.Object { * * Will be 0 on first update. */ - public double cpu_usage { get; private set; } + public double cpu_percentage { get; private set; } private uint64 cpu_last_used; @@ -56,7 +56,7 @@ public class Monitor.Process : GLib.Object { // Construct a new process public Process (int _pid) { _icon = ProcessUtils.get_default_icon (); - + last_total = 0; io = { }; @@ -215,7 +215,7 @@ public class Monitor.Process : GLib.Object { // Get CPU usage by process GTop.ProcTime proc_time; GTop.get_proc_time (out proc_time, stat.pid); - cpu_usage = ((double)(proc_time.rtime - cpu_last_used)) / (cpu_total - cpu_last_total); + cpu_percentage = 100 * ((double)(proc_time.rtime - cpu_last_used)) / (cpu_total - cpu_last_total); cpu_last_used = proc_time.rtime; // Get memory usage by process diff --git a/src/Managers/ProcessUtils.vala b/src/Managers/ProcessUtils.vala index 82736de4..f766461f 100644 --- a/src/Managers/ProcessUtils.vala +++ b/src/Managers/ProcessUtils.vala @@ -49,7 +49,7 @@ public class Monitor.ProcessUtils { } } - public static Icon get_default_icon () { + public static Icon? get_default_icon () { try { return Icon.new_for_string ("application-x-executable"); } catch (Error e) { diff --git a/src/Models/Model.vala b/src/Models/Model.vala index 6d80824a..b0bbb510 100644 --- a/src/Models/Model.vala +++ b/src/Models/Model.vala @@ -50,7 +50,7 @@ public class Monitor.Model : Gtk.TreeStore { Column.NAME, process.command, Column.ICON, "application-x-executable", Column.PID, process.stat.pid, - Column.CPU, process.cpu_usage, + Column.CPU, process.cpu_percentage, Column.MEMORY, process.mem_usage, -1); @@ -69,7 +69,7 @@ public class Monitor.Model : Gtk.TreeStore { Column.NAME, process.command, Column.ICON, "application-x-executable", Column.PID, process.stat.pid, - Column.CPU, process.cpu_usage, + Column.CPU, process.cpu_percentage, Column.MEMORY, process.mem_usage, -1); } diff --git a/src/Widgets/ProcessView/CPUProcessTreeView.vala b/src/Widgets/ProcessView/CPUProcessTreeView.vala index 523b2abb..5c7bae78 100644 --- a/src/Widgets/ProcessView/CPUProcessTreeView.vala +++ b/src/Widgets/ProcessView/CPUProcessTreeView.vala @@ -102,7 +102,7 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { if (cpu_usage < 0.0) (cell as Gtk.CellRendererText).text = NO_DATA; else - (cell as Gtk.CellRendererText).text = "%.0f%%".printf (cpu_usage * 100.0); + (cell as Gtk.CellRendererText).text = "%.0f%%".printf (cpu_usage); } public void memory_usage_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter) { diff --git a/src/Widgets/ProcessView/Graph.vala b/src/Widgets/ProcessView/Graph.vala index f4f79ef8..3b3afe3f 100644 --- a/src/Widgets/ProcessView/Graph.vala +++ b/src/Widgets/ProcessView/Graph.vala @@ -3,7 +3,6 @@ public class Monitor.Graph : Dazzle.GraphView private static GraphModel graph_model; private Dazzle.GraphLineRenderer renderer; - construct { expand = true; margin = 6; diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index 9aaa93e6..e8040e99 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -112,8 +112,8 @@ public class Monitor.ProcessInfoView : Gtk.Box { // ppid.set_text (("%d").printf (process.stat.ppid)); // pgrp.set_text (("%d").printf (process.stat.pgrp)); state.set_text (process.stat.state); - cpu_graph_model.update (process.cpu_usage * 100); - cpu_graph.tooltip_text = ("%.1f%%").printf (process.cpu_usage * 100); + cpu_graph_model.update (process.cpu_percentage); + cpu_graph.tooltip_text = ("%.1f%%").printf (process.cpu_percentage); mem_graph_model.update (process.mem_percentage); mem_graph.tooltip_text = ("%.1f%%").printf (process.mem_percentage); From f0dea98fac48e87f4fca5e6c3620e42cf53658d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= Date: Wed, 26 Feb 2020 21:10:09 +0100 Subject: [PATCH 42/96] rename: Model -> TreeViewModel --- meson.build | 2 +- src/Models/{Model.vala => TreeViewModel.vala} | 2 +- src/Widgets/ProcessView/CPUProcessTreeView.vala | 4 ++-- src/Widgets/ProcessView/ProcessView.vala | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) rename src/Models/{Model.vala => TreeViewModel.vala} (98%) diff --git a/meson.build b/meson.build index 2d3ec743..86fa770c 100644 --- a/meson.build +++ b/meson.build @@ -71,7 +71,7 @@ executable( 'src/Widgets/ProcessView/ProcessView.vala', 'src/Managers/ProcessUtils.vala', - 'src/Models/Model.vala', + 'src/Models/TreeViewModel.vala', 'src/Models/GraphModel.vala', # 'src/Models/ModelHelper.vala', diff --git a/src/Models/Model.vala b/src/Models/TreeViewModel.vala similarity index 98% rename from src/Models/Model.vala rename to src/Models/TreeViewModel.vala index b0bbb510..862cc49a 100644 --- a/src/Models/Model.vala +++ b/src/Models/TreeViewModel.vala @@ -6,7 +6,7 @@ public enum Monitor.Column { PID, } -public class Monitor.Model : Gtk.TreeStore { +public class Monitor.TreeViewModel : Gtk.TreeStore { public ProcessManager process_manager; private Gee.Map process_rows; diff --git a/src/Widgets/ProcessView/CPUProcessTreeView.vala b/src/Widgets/ProcessView/CPUProcessTreeView.vala index 5c7bae78..0f2f1441 100644 --- a/src/Widgets/ProcessView/CPUProcessTreeView.vala +++ b/src/Widgets/ProcessView/CPUProcessTreeView.vala @@ -1,5 +1,5 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { - private new Model model; + private TreeViewModel model; private Gtk.TreeViewColumn name_column; private Gtk.TreeViewColumn pid_column; private Gtk.TreeViewColumn cpu_column; @@ -10,7 +10,7 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { public signal void process_selected (Process process); - public CPUProcessTreeView (Model model) { + public CPUProcessTreeView (TreeViewModel model) { this.model = model; regex = /(?i:^.*\.(xpm|png)$)/; diff --git a/src/Widgets/ProcessView/ProcessView.vala b/src/Widgets/ProcessView/ProcessView.vala index f68e6fc6..4e3a55aa 100644 --- a/src/Widgets/ProcessView/ProcessView.vala +++ b/src/Widgets/ProcessView/ProcessView.vala @@ -1,5 +1,5 @@ public class Monitor.ProcessView : Gtk.Box { - public new Model treeview_model; + public TreeViewModel treeview_model; public CPUProcessTreeView process_tree_view; public ProcessInfoView process_info_view; @@ -13,7 +13,7 @@ public class Monitor.ProcessView : Gtk.Box { } public ProcessView () { - treeview_model = new Model (); + treeview_model = new TreeViewModel (); process_tree_view = new CPUProcessTreeView (treeview_model); process_tree_view.process_selected.connect ((process) => on_process_selected (process)); From fee4edeec5e849e7e9a4baef484b850054aa9508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= Date: Wed, 26 Feb 2020 21:25:42 +0100 Subject: [PATCH 43/96] show icons in treeview --- src/Models/TreeViewModel.vala | 4 ++-- src/Widgets/ProcessView/CPUProcessTreeView.vala | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Models/TreeViewModel.vala b/src/Models/TreeViewModel.vala index 862cc49a..9c411952 100644 --- a/src/Models/TreeViewModel.vala +++ b/src/Models/TreeViewModel.vala @@ -48,7 +48,7 @@ public class Monitor.TreeViewModel : Gtk.TreeStore { set (iter, Column.NAME, process.command, - Column.ICON, "application-x-executable", + Column.ICON, process.icon.to_string (), Column.PID, process.stat.pid, Column.CPU, process.cpu_percentage, Column.MEMORY, process.mem_usage, @@ -67,7 +67,7 @@ public class Monitor.TreeViewModel : Gtk.TreeStore { Gtk.TreeIter iter = process_rows[pid]; set (iter, Column.NAME, process.command, - Column.ICON, "application-x-executable", + Column.ICON, process.icon.to_string (), Column.PID, process.stat.pid, Column.CPU, process.cpu_percentage, Column.MEMORY, process.mem_usage, diff --git a/src/Widgets/ProcessView/CPUProcessTreeView.vala b/src/Widgets/ProcessView/CPUProcessTreeView.vala index 0f2f1441..6af7a67a 100644 --- a/src/Widgets/ProcessView/CPUProcessTreeView.vala +++ b/src/Widgets/ProcessView/CPUProcessTreeView.vala @@ -1,5 +1,5 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { - private TreeViewModel model; + private new TreeViewModel model; private Gtk.TreeViewColumn name_column; private Gtk.TreeViewColumn pid_column; private Gtk.TreeViewColumn cpu_column; From 9eb017d5dda8b5627000ae5f6a27a4b84e296060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= Date: Wed, 26 Feb 2020 21:53:38 +0100 Subject: [PATCH 44/96] rm debug --- src/Models/GraphModel.vala | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Models/GraphModel.vala b/src/Models/GraphModel.vala index d0957360..b1a58652 100644 --- a/src/Models/GraphModel.vala +++ b/src/Models/GraphModel.vala @@ -9,7 +9,6 @@ public class Monitor.GraphModel : Dazzle.GraphModel { } public bool update (double percentage) { - debug ("Got percentage: %f", percentage); Dazzle.GraphModelIter iter; push (out iter, get_monotonic_time ()); From 2f0273dc7f47e832b919f496a82339420e9c3c8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= Date: Wed, 26 Feb 2020 21:54:32 +0100 Subject: [PATCH 45/96] lil refactoring --- src/Models/TreeViewModel.vala | 9 ++++----- src/Widgets/ProcessView/CPUProcessTreeView.vala | 7 ++++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Models/TreeViewModel.vala b/src/Models/TreeViewModel.vala index 9c411952..5de73663 100644 --- a/src/Models/TreeViewModel.vala +++ b/src/Models/TreeViewModel.vala @@ -46,12 +46,14 @@ public class Monitor.TreeViewModel : Gtk.TreeStore { Gtk.TreeIter iter; append (out iter, null); // null means top-level + // donno what is going on, but maybe just use a string insteead of Icon ?? + // coz it lagz + // string icon_name = process.icon.to_string (); + set (iter, Column.NAME, process.command, Column.ICON, process.icon.to_string (), Column.PID, process.stat.pid, - Column.CPU, process.cpu_percentage, - Column.MEMORY, process.mem_usage, -1); // add the process to our cache of process_rows @@ -66,9 +68,6 @@ public class Monitor.TreeViewModel : Gtk.TreeStore { Process process = process_manager.get_process (pid); Gtk.TreeIter iter = process_rows[pid]; set (iter, - Column.NAME, process.command, - Column.ICON, process.icon.to_string (), - Column.PID, process.stat.pid, Column.CPU, process.cpu_percentage, Column.MEMORY, process.mem_usage, -1); diff --git a/src/Widgets/ProcessView/CPUProcessTreeView.vala b/src/Widgets/ProcessView/CPUProcessTreeView.vala index 6af7a67a..d8dfb7e6 100644 --- a/src/Widgets/ProcessView/CPUProcessTreeView.vala +++ b/src/Widgets/ProcessView/CPUProcessTreeView.vala @@ -78,8 +78,9 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { public void icon_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer icon_cell, Gtk.TreeModel model, Gtk.TreeIter iter) { Value icon_name; model.get_value (iter, Column.ICON, out icon_name); - if (regex.match ((string)icon_name)) { - string path = ((string)icon_name); + string path = ((string)icon_name); + + if (regex.match (path)) { try { Gdk.Pixbuf icon = new Gdk.Pixbuf.from_file_at_size (path, 16, -1); @@ -88,7 +89,7 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { warning (e.message); } } else { - (icon_cell as Gtk.CellRendererPixbuf).icon_name = (string)icon_name; + (icon_cell as Gtk.CellRendererPixbuf).icon_name = path; } } From 4695a2ad0ed4645332dded033367572f6631c623 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw?= Date: Fri, 28 Feb 2020 20:36:18 +0100 Subject: [PATCH 46/96] trying to clear graphs, when process row clicked --- src/Models/GraphModel.vala | 1 + src/Widgets/ProcessView/Graph.vala | 7 ------- src/Widgets/ProcessView/ProcessInfoView.vala | 22 +++++++++++++++----- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/Models/GraphModel.vala b/src/Models/GraphModel.vala index b1a58652..d0957360 100644 --- a/src/Models/GraphModel.vala +++ b/src/Models/GraphModel.vala @@ -9,6 +9,7 @@ public class Monitor.GraphModel : Dazzle.GraphModel { } public bool update (double percentage) { + debug ("Got percentage: %f", percentage); Dazzle.GraphModelIter iter; push (out iter, get_monotonic_time ()); diff --git a/src/Widgets/ProcessView/Graph.vala b/src/Widgets/ProcessView/Graph.vala index 3b3afe3f..431b0fc9 100644 --- a/src/Widgets/ProcessView/Graph.vala +++ b/src/Widgets/ProcessView/Graph.vala @@ -1,6 +1,5 @@ public class Monitor.Graph : Dazzle.GraphView { - private static GraphModel graph_model; private Dazzle.GraphLineRenderer renderer; construct { @@ -20,10 +19,4 @@ public class Monitor.Graph : Dazzle.GraphView add_renderer (renderer); } - - public Graph(GraphModel graph_model) { - this.graph_model = graph_model; - - set_model(graph_model); - } } diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index e8040e99..f9ab0f49 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -1,8 +1,8 @@ public class Monitor.ProcessInfoView : Gtk.Box { private Process _process; - public Process process { + public Process ? process { get { return _process; } - set { + set { _process = value; application_name.set_text (_process.application_name); application_name.tooltip_text = _process.command; @@ -13,6 +13,9 @@ public class Monitor.ProcessInfoView : Gtk.Box { num_threads.set_text (("%d").printf (_process.stat.num_threads)); state.set_text (_process.stat.state); + cpu_graph_model = new GraphModel(); + cpu_graph.set_model(cpu_graph_model); + set_icon (_process); } } @@ -37,6 +40,10 @@ public class Monitor.ProcessInfoView : Gtk.Box { private Graph mem_graph; private GraphModel mem_graph_model; + construct { + cpu_graph_model = new GraphModel(); + } + public ProcessInfoView () { // get_style_context ().add_class ("process_info"); margin = 12; @@ -74,11 +81,13 @@ public class Monitor.ProcessInfoView : Gtk.Box { // pgrp = new RoundyLabel (_("PGRP")); username = new RoundyLabel (""); - cpu_graph_model = new GraphModel(); - cpu_graph = new Graph(cpu_graph_model); + // cpu_graph_model = new GraphModel(); + cpu_graph = new Graph(); + // cpu_graph.set_model(cpu_graph_model); mem_graph_model = new GraphModel(); - mem_graph = new Graph(mem_graph_model); + mem_graph = new Graph(); + mem_graph.model = mem_graph_model; var graph_wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); graph_wrapper.valign = Gtk.Align.START; @@ -136,5 +145,8 @@ public class Monitor.ProcessInfoView : Gtk.Box { warning (e.message); } } + + + } } \ No newline at end of file From 0a1307f321e06221535a1e0855404054ebb8dfab Mon Sep 17 00:00:00 2001 From: stsdc Date: Sun, 8 Mar 2020 21:54:47 +0100 Subject: [PATCH 47/96] clearing graphs when choosing different process --- src/Widgets/ProcessView/CPUProcessTreeView.vala | 3 ++- src/Widgets/ProcessView/ProcessInfoView.vala | 9 ++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Widgets/ProcessView/CPUProcessTreeView.vala b/src/Widgets/ProcessView/CPUProcessTreeView.vala index d8dfb7e6..385cd9c8 100644 --- a/src/Widgets/ProcessView/CPUProcessTreeView.vala +++ b/src/Widgets/ProcessView/CPUProcessTreeView.vala @@ -73,7 +73,7 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { cursor_changed.connect (_cursor_changed); - model.process_manager.updated.connect (_cursor_changed); + // model.process_manager.updated.connect (_cursor_changed); } public void icon_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer icon_cell, Gtk.TreeModel model, Gtk.TreeIter iter) { Value icon_name; @@ -201,6 +201,7 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { tree_model.get (iter, Column.PID, out pid); Process process = model.process_manager.get_process (pid); process_selected (process); + debug ("cursor changed"); } } } diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index f9ab0f49..2775345f 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -13,9 +13,13 @@ public class Monitor.ProcessInfoView : Gtk.Box { num_threads.set_text (("%d").printf (_process.stat.num_threads)); state.set_text (_process.stat.state); + // Clearing graphs when new process is set cpu_graph_model = new GraphModel(); cpu_graph.set_model(cpu_graph_model); + mem_graph_model = new GraphModel(); + mem_graph.set_model(mem_graph_model); + set_icon (_process); } } @@ -81,13 +85,8 @@ public class Monitor.ProcessInfoView : Gtk.Box { // pgrp = new RoundyLabel (_("PGRP")); username = new RoundyLabel (""); - // cpu_graph_model = new GraphModel(); cpu_graph = new Graph(); - // cpu_graph.set_model(cpu_graph_model); - - mem_graph_model = new GraphModel(); mem_graph = new Graph(); - mem_graph.model = mem_graph_model; var graph_wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); graph_wrapper.valign = Gtk.Align.START; From 02fa28943f9091ded441a7c7c8dacd6dc2fe983d Mon Sep 17 00:00:00 2001 From: stsdc Date: Sun, 8 Mar 2020 23:07:51 +0100 Subject: [PATCH 48/96] add kill/end process button do ProcessInfoView --- src/Widgets/ProcessView/ProcessInfoView.vala | 62 +++++++++++++++----- 1 file changed, 47 insertions(+), 15 deletions(-) diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index 2775345f..cd1b99f4 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -44,6 +44,9 @@ public class Monitor.ProcessInfoView : Gtk.Box { private Graph mem_graph; private GraphModel mem_graph_model; + private Gtk.Button end_process_button; + private Gtk.Button kill_process_button; + construct { cpu_graph_model = new GraphModel(); } @@ -75,8 +78,6 @@ public class Monitor.ProcessInfoView : Gtk.Box { application_name.halign = Gtk.Align.START; application_name.valign = Gtk.Align.START; - - pid = new RoundyLabel (_ ("PID")); nice = new RoundyLabel (_ ("NI")); priority = new RoundyLabel (_ ("PRI")); @@ -85,17 +86,6 @@ public class Monitor.ProcessInfoView : Gtk.Box { // pgrp = new RoundyLabel (_("PGRP")); username = new RoundyLabel (""); - cpu_graph = new Graph(); - mem_graph = new Graph(); - - var graph_wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); - graph_wrapper.valign = Gtk.Align.START; - graph_wrapper.height_request = 60; - - - graph_wrapper.add (cpu_graph); - graph_wrapper.add (mem_graph); - var wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); wrapper.add (pid); wrapper.add (priority); @@ -111,7 +101,48 @@ public class Monitor.ProcessInfoView : Gtk.Box { grid.attach (wrapper, 1, 1, 1, 1); add (grid); + + var sep = new Gtk.Separator(Gtk.Orientation.HORIZONTAL); + sep.margin = 12; + add (sep); + + + cpu_graph = new Graph(); + mem_graph = new Graph(); + + var graph_wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); + graph_wrapper.valign = Gtk.Align.START; + graph_wrapper.height_request = 60; + + graph_wrapper.add (cpu_graph); + graph_wrapper.add (mem_graph); + add (graph_wrapper); + + + + var process_action_bar = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); + process_action_bar.valign = Gtk.Align.START; + process_action_bar.halign = Gtk.Align.END; + + end_process_button = new Gtk.Button.with_label (_("End Process")); + end_process_button.margin_end = 10; + end_process_button.clicked.connect (end_process_button_clicked); + end_process_button.tooltip_markup = Granite.markup_accel_tooltip ({"E"}, _("End selected process")); + var end_process_button_context = end_process_button.get_style_context (); + end_process_button_context.add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); + + kill_process_button = new Gtk.Button.with_label (_("Kill Process")); + // kill_process_button.clicked.connect (window.process_view.process_tree_view.kill_process); + kill_process_button.tooltip_markup = Granite.markup_accel_tooltip ({"K"}, _("Kill selected process")); + var kill_process_button_context = kill_process_button.get_style_context (); + kill_process_button_context.add_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION); + + process_action_bar.add (end_process_button); + process_action_bar.add (kill_process_button); + + add (process_action_bar); + } public void update () { @@ -144,8 +175,9 @@ public class Monitor.ProcessInfoView : Gtk.Box { warning (e.message); } } + } - - + private void end_process_button_clicked () { + debug ("click"); } } \ No newline at end of file From b2cea33ff889fee39d54f2fb9b8d1e587e9558a9 Mon Sep 17 00:00:00 2001 From: Ryo Nakano <26003928+ryonakano@users.noreply.github.com> Date: Tue, 10 Mar 2020 06:43:29 +0900 Subject: [PATCH 49/96] Require libdazzle 3.30 or later --- README.md | 1 + debian/control | 1 + meson.build | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7d8ab0f2..2b34813d 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ * libgtk-3-dev * libgranite-dev (>= 5.2.0) * libbamf3-dev +* libdazzle-1.0 (>= 3.30) * libwnck-3-dev * libgtop2-dev * libwingpanel-2.0-dev diff --git a/debian/control b/debian/control index ed40651f..5bc8d42f 100644 --- a/debian/control +++ b/debian/control @@ -10,6 +10,7 @@ Build-Depends: meson, valac (>= 0.26), libgranite-dev (>= 5.2.0), libbamf3-dev, + libdazzle-1.0 (>= 3.30), libwnck-3-dev, libgtop2-dev, libwingpanel-2.0-dev diff --git a/meson.build b/meson.build index 86fa770c..c874a1fc 100644 --- a/meson.build +++ b/meson.build @@ -23,7 +23,7 @@ gtop = dependency('libgtop-2.0') wnck = dependency('libwnck-3.0') wingpanel = dependency('wingpanel-2.0') gdk_x11 = dependency('gdk-x11-3.0') -dazzle = dependency('libdazzle-1.0') +dazzle = dependency('libdazzle-1.0', version: '>= 3.30') config_data = configuration_data() config_data.set_quoted('GETTEXT_PACKAGE', meson.project_name()) From ffb26540108a86d312a8dfd00108ee2821179c82 Mon Sep 17 00:00:00 2001 From: stsdc Date: Sun, 22 Mar 2020 01:26:08 +0100 Subject: [PATCH 50/96] two-step process ending #149 --- meson.build | 1 + src/Widgets/ProcessView/Preventor.vala | 56 ++++++++++++++++++++ src/Widgets/ProcessView/ProcessInfoView.vala | 21 +++++++- 3 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 src/Widgets/ProcessView/Preventor.vala diff --git a/meson.build b/meson.build index 86fa770c..29b611b5 100644 --- a/meson.build +++ b/meson.build @@ -65,6 +65,7 @@ executable( 'src/Widgets/Headerbar/Headerbar.vala', 'src/Widgets/Statusbar/Statusbar.vala', 'src/Widgets/ProcessView/ProcessInfoView.vala', + 'src/Widgets/ProcessView/Preventor.vala', 'src/Widgets/ProcessView/RoundyLabel.vala', 'src/Widgets/ProcessView/Graph.vala', diff --git a/src/Widgets/ProcessView/Preventor.vala b/src/Widgets/ProcessView/Preventor.vala new file mode 100644 index 00000000..f0702cad --- /dev/null +++ b/src/Widgets/ProcessView/Preventor.vala @@ -0,0 +1,56 @@ +public class Monitor.Preventor : Gtk.Stack { + + private Gtk.Box preventive_action_bar; + private Gtk.Label confirmation_label; + private Gtk.Button confirm_button; + private Gtk.Button deny_button; + + private Gtk.Widget child; + + public signal void confirmed (bool is_confirmed); + + construct { + preventive_action_bar = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); + preventive_action_bar.valign = Gtk.Align.START; + preventive_action_bar.halign = Gtk.Align.END; + + + confirmation_label = new Gtk.Label (_ ("Are You sure You want to do this?")); + confirmation_label.margin_end = 10; + + confirm_button = new Gtk.Button.with_label (_("Yes")); + confirm_button.margin_end = 10; + confirm_button.get_style_context ().add_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION); + + deny_button = new Gtk.Button.with_label (_("No")); + + preventive_action_bar.add (confirmation_label); + preventive_action_bar.add (confirm_button); + preventive_action_bar.add (deny_button); + } + + public Preventor (Gtk.Widget _child, string name) { + child = _child; + add_named (child, name); + add_named (preventive_action_bar, "preventive_action_bar"); + + deny_button.clicked.connect (() => { + set_transition_type(Gtk.StackTransitionType.SLIDE_UP); + set_visible_child (child); + confirmed(false); + }); + + confirm_button.clicked.connect(() => { + set_transition_type(Gtk.StackTransitionType.SLIDE_UP); + set_visible_child (child); + confirmed(true); + }); + } + + public void set_prevention (string confirmation_text) { + set_transition_type(Gtk.StackTransitionType.SLIDE_DOWN); + confirmation_label.set_text (_(confirmation_text)); + set_visible_child (preventive_action_bar); + } + +} \ No newline at end of file diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index cd1b99f4..87b364d6 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -47,6 +47,8 @@ public class Monitor.ProcessInfoView : Gtk.Box { private Gtk.Button end_process_button; private Gtk.Button kill_process_button; + private Preventor preventor; + construct { cpu_graph_model = new GraphModel(); } @@ -141,8 +143,25 @@ public class Monitor.ProcessInfoView : Gtk.Box { process_action_bar.add (end_process_button); process_action_bar.add (kill_process_button); - add (process_action_bar); + Preventor preventor = new Preventor (process_action_bar, "process_action_bar"); + + kill_process_button.clicked.connect(() => { + preventor.set_prevention (_("Confirm kill of the process?")); + preventor.confirmed.connect((is_confirmed) => { + if (is_confirmed) process.kill(); // maybe add a toast that process killed + }); + }); + + end_process_button.clicked.connect(() => { + preventor.set_prevention (_("Confirm end of the process?")); + preventor.confirmed.connect((is_confirmed) => { + if (is_confirmed) process.end(); // maybe add a toast that process ended + }); + }); + + add (preventor); + show(); } public void update () { From dc1e47dd91fad7bb43371c8b17d3a202931b8b4c Mon Sep 17 00:00:00 2001 From: stsdc Date: Sun, 22 Mar 2020 01:58:52 +0100 Subject: [PATCH 51/96] remove kill/end buttons from headerbar --- src/Widgets/Headerbar/Headerbar.vala | 28 +--------------------------- src/Widgets/Headerbar/Search.vala | 3 --- 2 files changed, 1 insertion(+), 30 deletions(-) diff --git a/src/Widgets/Headerbar/Headerbar.vala b/src/Widgets/Headerbar/Headerbar.vala index e7fece06..5befb993 100644 --- a/src/Widgets/Headerbar/Headerbar.vala +++ b/src/Widgets/Headerbar/Headerbar.vala @@ -2,8 +2,6 @@ namespace Monitor { public class Headerbar : Gtk.HeaderBar { private MainWindow window; - private Gtk.Button end_process_button; - private Gtk.Button kill_process_button; private Gtk.Switch show_indicator_switch; private Gtk.Switch background_switch; @@ -17,25 +15,6 @@ namespace Monitor { public Headerbar (MainWindow window) { this.window = window; - var button_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); - button_box.valign = Gtk.Align.CENTER; - - end_process_button = new Gtk.Button.with_label (_("End Process")); - end_process_button.margin_end = 10; - end_process_button.clicked.connect (window.process_view.process_tree_view.end_process); - end_process_button.tooltip_markup = Granite.markup_accel_tooltip ({"E"}, _("End selected process")); - var end_process_button_context = end_process_button.get_style_context (); - end_process_button_context.add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); - - kill_process_button = new Gtk.Button.with_label (_("Kill Process")); - kill_process_button.clicked.connect (window.process_view.process_tree_view.kill_process); - kill_process_button.tooltip_markup = Granite.markup_accel_tooltip ({"K"}, _("Kill selected process")); - var kill_process_button_context = kill_process_button.get_style_context (); - kill_process_button_context.add_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION); - - button_box.pack_start (end_process_button); - button_box.pack_end (kill_process_button); - pack_start (button_box); var preferences_button = new Gtk.MenuButton (); preferences_button.has_tooltip = true; @@ -75,7 +54,7 @@ namespace Monitor { search = new Search (window); search.valign = Gtk.Align.CENTER; - pack_end (search); + pack_start (search); show_indicator_switch.notify["active"].connect (() => { MonitorApp.settings.set_boolean ("indicator-state", show_indicator_switch.state); @@ -95,10 +74,5 @@ namespace Monitor { background_switch.state = false; } } - - public void set_header_buttons_sensitivity (bool sensitivity) { - end_process_button.sensitive = sensitivity; - kill_process_button.sensitive = sensitivity; - } } } diff --git a/src/Widgets/Headerbar/Search.vala b/src/Widgets/Headerbar/Search.vala index 3e440e8d..f698e338 100644 --- a/src/Widgets/Headerbar/Search.vala +++ b/src/Widgets/Headerbar/Search.vala @@ -32,9 +32,6 @@ namespace Monitor { filter_model.refilter (); - // if there's no search result, make "Kill/End Process" buttons in headerbar insensitive to avoid the app crashes - window.headerbar.set_header_buttons_sensitivity (filter_model.iter_n_children (null) != 0); - // focus on child row to avoid the app crashes by clicking "Kill/End Process" buttons in headerbar process_tree_view.focus_on_child_row (); this.grab_focus (); From 4365b04ecfbbb939873048a37a47c458e7d4809d Mon Sep 17 00:00:00 2001 From: stsdc Date: Sun, 22 Mar 2020 12:15:41 +0100 Subject: [PATCH 52/96] fix do not show process info on start up --- src/Widgets/ProcessView/ProcessInfoView.vala | 1 - src/Widgets/ProcessView/ProcessView.vala | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Widgets/ProcessView/ProcessInfoView.vala index 87b364d6..7ca91f8c 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Widgets/ProcessView/ProcessInfoView.vala @@ -161,7 +161,6 @@ public class Monitor.ProcessInfoView : Gtk.Box { add (preventor); - show(); } public void update () { diff --git a/src/Widgets/ProcessView/ProcessView.vala b/src/Widgets/ProcessView/ProcessView.vala index 4e3a55aa..8e37bb92 100644 --- a/src/Widgets/ProcessView/ProcessView.vala +++ b/src/Widgets/ProcessView/ProcessView.vala @@ -30,7 +30,6 @@ public class Monitor.ProcessView : Gtk.Box { paned.set_hexpand (true); add (paned); - show_all (); } public void on_process_selected (Process process) { From cce4cf4d0199d35e98e26880481647a5ff86710e Mon Sep 17 00:00:00 2001 From: stsdc Date: Sun, 22 Mar 2020 12:21:35 +0100 Subject: [PATCH 53/96] display application name or trimmed command in tree view --- src/Models/TreeViewModel.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Models/TreeViewModel.vala b/src/Models/TreeViewModel.vala index 5de73663..665211b4 100644 --- a/src/Models/TreeViewModel.vala +++ b/src/Models/TreeViewModel.vala @@ -51,7 +51,7 @@ public class Monitor.TreeViewModel : Gtk.TreeStore { // string icon_name = process.icon.to_string (); set (iter, - Column.NAME, process.command, + Column.NAME, process.application_name, Column.ICON, process.icon.to_string (), Column.PID, process.stat.pid, -1); From b72a8a91d94ff0f99447a48cd20aa371eb492c7c Mon Sep 17 00:00:00 2001 From: stsdc Date: Sun, 22 Mar 2020 13:11:38 +0100 Subject: [PATCH 54/96] changing project structure --- meson.build | 27 +++++++++++-------- .../ProcessView/ProcessInfoView}/Graph.vala | 0 .../ProcessInfoView}/Preventor.vala | 0 .../ProcessInfoView}/ProcessInfoView.vala | 22 ++++++++++----- .../ProcessInfoView}/RoundyLabel.vala | 0 .../ProcessTreeView}/CPUProcessTreeView.vala | 0 .../ProcessView/ProcessView.vala | 0 7 files changed, 31 insertions(+), 18 deletions(-) rename src/{Widgets/ProcessView => Views/ProcessView/ProcessInfoView}/Graph.vala (100%) rename src/{Widgets/ProcessView => Views/ProcessView/ProcessInfoView}/Preventor.vala (100%) rename src/{Widgets/ProcessView => Views/ProcessView/ProcessInfoView}/ProcessInfoView.vala (93%) rename src/{Widgets/ProcessView => Views/ProcessView/ProcessInfoView}/RoundyLabel.vala (100%) rename src/{Widgets/ProcessView => Views/ProcessView/ProcessTreeView}/CPUProcessTreeView.vala (100%) rename src/{Widgets => Views}/ProcessView/ProcessView.vala (100%) diff --git a/meson.build b/meson.build index 58d9956e..e19a2f52 100644 --- a/meson.build +++ b/meson.build @@ -59,27 +59,32 @@ executable( 'src/MainWindow.vala', 'src/Utils.vala', - # 'src/Widgets/OverallView.vala', - 'src/Widgets/ProcessView/CPUProcessTreeView.vala', - 'src/Widgets/Headerbar/Search.vala', + # Views + 'src/Views/ProcessView/ProcessView.vala', + 'src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala', + 'src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala', + + # Widgets related only to ProcessInfoView + 'src/Views/ProcessView/ProcessInfoView/Preventor.vala', + 'src/Views/ProcessView/ProcessInfoView/RoundyLabel.vala', + 'src/Views/ProcessView/ProcessInfoView/Graph.vala', + + # Widgets 'src/Widgets/Headerbar/Headerbar.vala', + 'src/Widgets/Headerbar/Search.vala', 'src/Widgets/Statusbar/Statusbar.vala', - 'src/Widgets/ProcessView/ProcessInfoView.vala', - 'src/Widgets/ProcessView/Preventor.vala', - 'src/Widgets/ProcessView/RoundyLabel.vala', - 'src/Widgets/ProcessView/Graph.vala', - - 'src/Widgets/ProcessView/ProcessView.vala', - 'src/Managers/ProcessUtils.vala', + + # Models 'src/Models/TreeViewModel.vala', 'src/Models/GraphModel.vala', - # 'src/Models/ModelHelper.vala', + # Other 'src/Managers/AppManager.vala', 'src/Managers/ProcessManager.vala', 'src/Managers/Process.vala', 'src/Managers/ProcessStructs.vala', + 'src/Managers/ProcessUtils.vala', 'src/Services/Shortcuts.vala', 'src/Services/DBusServer.vala', diff --git a/src/Widgets/ProcessView/Graph.vala b/src/Views/ProcessView/ProcessInfoView/Graph.vala similarity index 100% rename from src/Widgets/ProcessView/Graph.vala rename to src/Views/ProcessView/ProcessInfoView/Graph.vala diff --git a/src/Widgets/ProcessView/Preventor.vala b/src/Views/ProcessView/ProcessInfoView/Preventor.vala similarity index 100% rename from src/Widgets/ProcessView/Preventor.vala rename to src/Views/ProcessView/ProcessInfoView/Preventor.vala diff --git a/src/Widgets/ProcessView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala similarity index 93% rename from src/Widgets/ProcessView/ProcessInfoView.vala rename to src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index 7ca91f8c..c48d370f 100644 --- a/src/Widgets/ProcessView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -96,7 +96,6 @@ public class Monitor.ProcessInfoView : Gtk.Box { wrapper.add (username); grid = new Gtk.Grid (); - grid.get_style_context ().add_class ("horizontal"); grid.column_spacing = 12; grid.attach (icon_container, 0, 0, 1, 2); grid.attach (application_name, 1, 0, 3, 1); @@ -121,7 +120,19 @@ public class Monitor.ProcessInfoView : Gtk.Box { add (graph_wrapper); + var other_info_grid = new Gtk.Grid(); + other_info_grid.column_spacing = 12; + var io_label = new Gtk.Label (_("IO")); + io_label.get_style_context ().add_class (Granite.STYLE_CLASS_H3_LABEL); + var net_label = new Gtk.Label ( _("NET")); + net_label.get_style_context ().add_class (Granite.STYLE_CLASS_H3_LABEL); + + + other_info_grid.attach (io_label, 0, 0, 1, 2); + other_info_grid.attach (net_label, 1, 0, 1, 2); + + add (other_info_grid); var process_action_bar = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); process_action_bar.valign = Gtk.Align.START; @@ -129,13 +140,11 @@ public class Monitor.ProcessInfoView : Gtk.Box { end_process_button = new Gtk.Button.with_label (_("End Process")); end_process_button.margin_end = 10; - end_process_button.clicked.connect (end_process_button_clicked); end_process_button.tooltip_markup = Granite.markup_accel_tooltip ({"E"}, _("End selected process")); var end_process_button_context = end_process_button.get_style_context (); end_process_button_context.add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); kill_process_button = new Gtk.Button.with_label (_("Kill Process")); - // kill_process_button.clicked.connect (window.process_view.process_tree_view.kill_process); kill_process_button.tooltip_markup = Granite.markup_accel_tooltip ({"K"}, _("Kill selected process")); var kill_process_button_context = kill_process_button.get_style_context (); kill_process_button_context.add_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION); @@ -159,8 +168,10 @@ public class Monitor.ProcessInfoView : Gtk.Box { }); }); - add (preventor); + + + } public void update () { @@ -195,7 +206,4 @@ public class Monitor.ProcessInfoView : Gtk.Box { } } - private void end_process_button_clicked () { - debug ("click"); - } } \ No newline at end of file diff --git a/src/Widgets/ProcessView/RoundyLabel.vala b/src/Views/ProcessView/ProcessInfoView/RoundyLabel.vala similarity index 100% rename from src/Widgets/ProcessView/RoundyLabel.vala rename to src/Views/ProcessView/ProcessInfoView/RoundyLabel.vala diff --git a/src/Widgets/ProcessView/CPUProcessTreeView.vala b/src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala similarity index 100% rename from src/Widgets/ProcessView/CPUProcessTreeView.vala rename to src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala diff --git a/src/Widgets/ProcessView/ProcessView.vala b/src/Views/ProcessView/ProcessView.vala similarity index 100% rename from src/Widgets/ProcessView/ProcessView.vala rename to src/Views/ProcessView/ProcessView.vala From 17658c7a4adf1389edbefed256c246caaaa59700 Mon Sep 17 00:00:00 2001 From: stsdc Date: Sun, 22 Mar 2020 13:28:46 +0100 Subject: [PATCH 55/96] refactor --- meson.build | 7 +- .../ProcessInfoView/ProcessInfoHeader.vala | 88 +++++++++++++++++ .../ProcessInfoView/ProcessInfoView.vala | 94 ++----------------- 3 files changed, 102 insertions(+), 87 deletions(-) create mode 100644 src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala diff --git a/meson.build b/meson.build index e19a2f52..394382d0 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ -project('com.github.stsdc.monitor', 'vala', 'c', version: '1.0.0') +project('com.github.stsdc.monitor', 'vala', 'c', version: '0.7.0') # these are Meson modules gnome = import('gnome') @@ -18,7 +18,7 @@ gtk = dependency('gtk+-3.0') gee = dependency('gee-0.8') gio = dependency('gio-2.0') gobject = dependency('gobject-2.0') -bamf = dependency('libbamf3') +bamf = dependency('libbamf3') # to remove gtop = dependency('libgtop-2.0') wnck = dependency('libwnck-3.0') wingpanel = dependency('wingpanel-2.0') @@ -68,6 +68,7 @@ executable( 'src/Views/ProcessView/ProcessInfoView/Preventor.vala', 'src/Views/ProcessView/ProcessInfoView/RoundyLabel.vala', 'src/Views/ProcessView/ProcessInfoView/Graph.vala', + 'src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala', # Widgets 'src/Widgets/Headerbar/Headerbar.vala', @@ -102,7 +103,7 @@ executable( gee, gio, gobject, - bamf, + bamf, # to remove gtop, wnck, gdk_x11, diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala new file mode 100644 index 00000000..f4bc03f6 --- /dev/null +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala @@ -0,0 +1,88 @@ +public class Monitor.ProcessInfoHeader : Gtk.Grid { + private Gtk.Image icon; + public Gtk.Label state; + public Gtk.Label application_name; + public RoundyLabel pid; + public RoundyLabel ppid; + public RoundyLabel pgrp; + public RoundyLabel nice; + public RoundyLabel priority; + public RoundyLabel num_threads; + public RoundyLabel username; + + private Regex ? regex; + + construct { + column_spacing = 12; + + regex = /(?i:^.*\.(xpm|png)$)/; + + icon = new Gtk.Image.from_icon_name ("application-x-executable", Gtk.IconSize.DIALOG); + icon.set_pixel_size (64); + icon.valign = Gtk.Align.END; + + state = new Gtk.Label ("?"); + state.halign = Gtk.Align.START; + state.get_style_context ().add_class ("state_badge"); + + var icon_container = new Gtk.Fixed (); + icon_container.put (icon, 0, 0); + icon_container.put (state, -5, 48); + + application_name = new Gtk.Label (_ ("N/A")); + application_name.get_style_context ().add_class ("h2"); + application_name.ellipsize = Pango.EllipsizeMode.END; + application_name.tooltip_text = _ ("N/A"); + application_name.halign = Gtk.Align.START; + application_name.valign = Gtk.Align.START; + + pid = new RoundyLabel (_ ("PID")); + nice = new RoundyLabel (_ ("NI")); + priority = new RoundyLabel (_ ("PRI")); + num_threads = new RoundyLabel (_ ("THR")); + // ppid = new RoundyLabel (_("PPID")); + // pgrp = new RoundyLabel (_("PGRP")); + username = new RoundyLabel (""); + + var wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); + wrapper.add (pid); + wrapper.add (priority); + wrapper.add (nice); + wrapper.add (num_threads); + wrapper.add (username); + + attach (icon_container, 0, 0, 1, 2); + attach (application_name, 1, 0, 3, 1); + attach (wrapper, 1, 1, 1, 1); + + } + + public void update (Process process) { + application_name.set_text (process.application_name); + application_name.tooltip_text = process.command; + pid.set_text (("%d").printf (process.stat.pid)); + nice.set_text (("%d").printf (process.stat.nice)); + priority.set_text (("%d").printf (process.stat.priority)); + username.set_text (process.username); + num_threads.set_text (("%d").printf (process.stat.num_threads)); + state.set_text (process.stat.state); + num_threads.set_text (("%d").printf (process.stat.num_threads)); + set_icon (process); + } + + private void set_icon (Process process) { + // this construction should be somewhere else + var icon_name = process.icon.to_string (); + + if (!regex.match (icon_name)) { + icon.set_from_icon_name (icon_name, Gtk.IconSize.DIALOG); + } else { + try { + var pixbuf = new Gdk.Pixbuf.from_file_at_size (icon_name, 64, -1); + icon.set_from_pixbuf (pixbuf); + } catch (Error e) { + warning (e.message); + } + } + } +} \ No newline at end of file diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index c48d370f..e05d2246 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -4,37 +4,21 @@ public class Monitor.ProcessInfoView : Gtk.Box { get { return _process; } set { _process = value; - application_name.set_text (_process.application_name); - application_name.tooltip_text = _process.command; - pid.set_text (("%d").printf (_process.stat.pid)); - nice.set_text (("%d").printf (_process.stat.nice)); - priority.set_text (("%d").printf (_process.stat.priority)); - username.set_text (_process.username); - num_threads.set_text (("%d").printf (_process.stat.num_threads)); - state.set_text (_process.stat.state); + process_info_header.update (_process); // Clearing graphs when new process is set cpu_graph_model = new GraphModel(); cpu_graph.set_model(cpu_graph_model); mem_graph_model = new GraphModel(); mem_graph.set_model(mem_graph_model); - - set_icon (_process); } } - public Gtk.Label application_name; public string ? icon_name; private Gtk.ScrolledWindow command_wrapper; - public RoundyLabel ppid; - public RoundyLabel pgrp; - public RoundyLabel nice; - public RoundyLabel priority; - public RoundyLabel num_threads; - public Gtk.Label state; - public RoundyLabel username; - public RoundyLabel pid; - private Gtk.Image icon; + + private ProcessInfoHeader process_info_header; + private Regex ? regex; private Gtk.Grid grid; @@ -58,50 +42,9 @@ public class Monitor.ProcessInfoView : Gtk.Box { margin = 12; orientation = Gtk.Orientation.VERTICAL; hexpand = true; - regex = /(?i:^.*\.(xpm|png)$)/; - - var icon_container = new Gtk.Fixed (); - - icon = new Gtk.Image.from_icon_name ("application-x-executable", Gtk.IconSize.DIALOG); - icon.set_pixel_size (64); - icon.valign = Gtk.Align.END; - - state = new Gtk.Label (_ ("?")); - state.halign = Gtk.Align.START; - state.get_style_context ().add_class ("state_badge"); - - icon_container.put (icon, 0, 0); - icon_container.put (state, -5, 48); - - application_name = new Gtk.Label (_ ("N/A")); - application_name.get_style_context ().add_class ("h2"); - application_name.ellipsize = Pango.EllipsizeMode.END; - application_name.tooltip_text = _ ("N/A"); - application_name.halign = Gtk.Align.START; - application_name.valign = Gtk.Align.START; - - pid = new RoundyLabel (_ ("PID")); - nice = new RoundyLabel (_ ("NI")); - priority = new RoundyLabel (_ ("PRI")); - num_threads = new RoundyLabel (_ ("THR")); - // ppid = new RoundyLabel (_("PPID")); - // pgrp = new RoundyLabel (_("PGRP")); - username = new RoundyLabel (""); - - var wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); - wrapper.add (pid); - wrapper.add (priority); - wrapper.add (nice); - wrapper.add (num_threads); - wrapper.add (username); - - grid = new Gtk.Grid (); - grid.column_spacing = 12; - grid.attach (icon_container, 0, 0, 1, 2); - grid.attach (application_name, 1, 0, 3, 1); - grid.attach (wrapper, 1, 1, 1, 1); - - add (grid); + + process_info_header = new ProcessInfoHeader(); + add (process_info_header); var sep = new Gtk.Separator(Gtk.Orientation.HORIZONTAL); sep.margin = 12; @@ -176,34 +119,17 @@ public class Monitor.ProcessInfoView : Gtk.Box { public void update () { if (process != null) { - num_threads.set_text (("%d").printf (process.stat.num_threads)); - // ppid.set_text (("%d").printf (process.stat.ppid)); - // pgrp.set_text (("%d").printf (process.stat.pgrp)); - state.set_text (process.stat.state); + process_info_header.update (process); + cpu_graph_model.update (process.cpu_percentage); cpu_graph.tooltip_text = ("%.1f%%").printf (process.cpu_percentage); mem_graph_model.update (process.mem_percentage); mem_graph.tooltip_text = ("%.1f%%").printf (process.mem_percentage); - set_icon (process); } } - private void set_icon (Process process) { - // this construction should be somewhere else - var icon_name = process.icon.to_string (); - - if (!regex.match (icon_name)) { - icon.set_from_icon_name (icon_name, Gtk.IconSize.DIALOG); - } else { - try { - var pixbuf = new Gdk.Pixbuf.from_file_at_size (icon_name, 64, -1); - icon.set_from_pixbuf (pixbuf); - } catch (Error e) { - warning (e.message); - } - } - } + } \ No newline at end of file From 6d32e43cc031b0620fb33310c79e4b7e8b858290 Mon Sep 17 00:00:00 2001 From: stsdc Date: Sun, 22 Mar 2020 23:29:25 +0100 Subject: [PATCH 56/96] display io statistic of a process --- meson.build | 1 + src/Managers/Process.vala | 16 ++-- src/Managers/ProcessStructs.vala | 2 +- .../ProcessInfoView/ProcessInfoOther.vala | 82 +++++++++++++++++++ .../ProcessInfoView/ProcessInfoView.vala | 29 +++---- 5 files changed, 103 insertions(+), 27 deletions(-) create mode 100644 src/Views/ProcessView/ProcessInfoView/ProcessInfoOther.vala diff --git a/meson.build b/meson.build index 394382d0..803001ef 100644 --- a/meson.build +++ b/meson.build @@ -69,6 +69,7 @@ executable( 'src/Views/ProcessView/ProcessInfoView/RoundyLabel.vala', 'src/Views/ProcessView/ProcessInfoView/Graph.vala', 'src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala', + 'src/Views/ProcessView/ProcessInfoView/ProcessInfoOther.vala', # Widgets 'src/Widgets/Headerbar/Headerbar.vala', diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index b9547ef4..37ae047f 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -30,7 +30,7 @@ public class Monitor.Process : GLib.Object { } // Contains info about io - ProcessIO io; + public ProcessIO io; // Contains status info public ProcessStatus stat; @@ -123,25 +123,25 @@ public class Monitor.Process : GLib.Object { var splitted_line = line.split (":"); switch (splitted_line[0]) { case "wchar" : - io.wchar = (uint64)splitted_line[1]; + io.wchar = uint64.parse(splitted_line[1]); break; case "rchar" : - io.rchar = (uint64)splitted_line[1]; + io.rchar = uint64.parse(splitted_line[1]); break; case "syscr" : - io.syscr = (uint64)splitted_line[1]; + io.syscr = uint64.parse(splitted_line[1]); break; case "syscw" : - io.syscw = (uint64)splitted_line[1]; + io.syscw = uint64.parse(splitted_line[1]); break; case "read_bytes" : - io.read_bytes = (uint64)splitted_line[1]; + io.read_bytes = uint64.parse(splitted_line[1]); break; case "write_bytes" : - io.write_bytes = (uint64)splitted_line[1]; + io.write_bytes = uint64.parse(splitted_line[1]); break; case "cancelled_write_bytes" : - io.cancelled_write_bytes = (uint64)splitted_line[1]; + io.cancelled_write_bytes = uint64.parse(splitted_line[1]); break; default : warning ("Unknown value in /proc/%d/io", stat.pid); diff --git a/src/Managers/ProcessStructs.vala b/src/Managers/ProcessStructs.vala index 3cd9e054..872753fb 100644 --- a/src/Managers/ProcessStructs.vala +++ b/src/Managers/ProcessStructs.vala @@ -1,6 +1,6 @@ // For more info look at: http://man7.org/linux/man-pages/man5/proc.5.html -struct Monitor.ProcessIO { +public struct Monitor.ProcessIO { // characters read public uint64 rchar; diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoOther.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoOther.vala new file mode 100644 index 00000000..f89341f7 --- /dev/null +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoOther.vala @@ -0,0 +1,82 @@ +public class Monitor.ProcessInfoOther : Gtk.Grid { + private Gtk.Label rchar_label; + private Gtk.Label wchar_label; + private Gtk.Label syscr_label; + private Gtk.Label syscw_label; + private Gtk.Label write_bytes_label; + private Gtk.Label read_bytes_label; + private Gtk.Label cancelled_write_bytes_label; + + + construct { + column_spacing = 12; + row_spacing = 12; + column_homogeneous = true; + row_homogeneous = true; + + var io_label = new Gtk.Label (_("IO")); + io_label.get_style_context ().add_class (Granite.STYLE_CLASS_H3_LABEL); + + var net_label = new Gtk.Label ( _("NET")); + net_label.get_style_context ().add_class (Granite.STYLE_CLASS_H3_LABEL); + + var rchar_desc_label = create_label (_("characters read")); + rchar_label = create_label (_("N/A")); + + var wchar_desc_label = create_label (_("characters written")); + wchar_label = create_label (_("N/A")); + + var syscr_desc_label = create_label (_("read syscalls")); + syscr_label = create_label (_("N/A")); + + var syscw_desc_label = create_label (_("write syscalls")); + syscw_label = create_label (_("N/A")); + + var write_bytes_desc_label = create_label (_("Read bytes")); + write_bytes_label = create_label (_("N/A")); + + var read_bytes_desc_label = create_label (_("Written bytes")); + read_bytes_label = create_label (_("N/A")); + + var cancelled_write_bytes_desc_label = create_label (_("Cancelled write_bytes")); + cancelled_write_bytes_label = create_label (_("N/A")); + + attach (io_label, 0, 0, 1, 2); + attach (rchar_desc_label, 0, 1, 1, 2); + attach (wchar_desc_label, 0, 2, 1, 2); + attach (syscr_desc_label, 0, 3, 1, 2); + attach (syscw_desc_label, 0, 4, 1, 2); + attach (write_bytes_desc_label, 0, 5, 1, 2); + attach (read_bytes_desc_label, 0, 6, 1, 2); + attach (cancelled_write_bytes_desc_label, 0, 7, 1, 2); + + attach (rchar_label, 1, 1, 1, 2); + attach (wchar_label, 1, 2, 1, 2); + attach (syscr_label, 1, 3, 1, 2); + attach (syscw_label, 1, 4, 1, 2); + attach (write_bytes_label, 1, 5, 1, 2); + attach (read_bytes_label, 1, 6, 1, 2); + attach (cancelled_write_bytes_label, 1, 7, 1, 2); + + + attach (net_label, 2, 0, 1, 2); + } + + private Gtk.Label create_label (string text) { + var label = new Gtk.Label (text); + label.halign = Gtk.Align.START; + return label; + } + + public void update (Process process) { + rchar_label.set_text (process.io.rchar.to_string()); + wchar_label.set_text (process.io.wchar.to_string()); + syscr_label.set_text (process.io.syscr.to_string()); + syscw_label.set_text (process.io.syscw.to_string()); + write_bytes_label.set_text (process.io.write_bytes.to_string()); + read_bytes_label.set_text (process.io.read_bytes.to_string()); + cancelled_write_bytes_label.set_text (process.io.cancelled_write_bytes.to_string()); + + } + +} \ No newline at end of file diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index e05d2246..03318b03 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -1,4 +1,4 @@ -public class Monitor.ProcessInfoView : Gtk.Box { +public class Monitor.ProcessInfoView : Gtk.Grid { private Process _process; public Process ? process { get { return _process; } @@ -6,6 +6,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { _process = value; process_info_header.update (_process); + process_info_other.update (_process); // Clearing graphs when new process is set cpu_graph_model = new GraphModel(); cpu_graph.set_model(cpu_graph_model); @@ -18,6 +19,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { private Gtk.ScrolledWindow command_wrapper; private ProcessInfoHeader process_info_header; + private ProcessInfoOther process_info_other; private Regex ? regex; private Gtk.Grid grid; @@ -42,13 +44,14 @@ public class Monitor.ProcessInfoView : Gtk.Box { margin = 12; orientation = Gtk.Orientation.VERTICAL; hexpand = true; + column_spacing = 12; process_info_header = new ProcessInfoHeader(); - add (process_info_header); + attach (process_info_header, 0, 0, 1, 1); var sep = new Gtk.Separator(Gtk.Orientation.HORIZONTAL); sep.margin = 12; - add (sep); + attach (sep, 0, 1, 1, 1); cpu_graph = new Graph(); @@ -61,21 +64,10 @@ public class Monitor.ProcessInfoView : Gtk.Box { graph_wrapper.add (cpu_graph); graph_wrapper.add (mem_graph); - add (graph_wrapper); + attach (graph_wrapper, 0, 2, 1, 1); - var other_info_grid = new Gtk.Grid(); - other_info_grid.column_spacing = 12; - - var io_label = new Gtk.Label (_("IO")); - io_label.get_style_context ().add_class (Granite.STYLE_CLASS_H3_LABEL); - var net_label = new Gtk.Label ( _("NET")); - net_label.get_style_context ().add_class (Granite.STYLE_CLASS_H3_LABEL); - - - other_info_grid.attach (io_label, 0, 0, 1, 2); - other_info_grid.attach (net_label, 1, 0, 1, 2); - - add (other_info_grid); + process_info_other = new ProcessInfoOther (); + attach (process_info_other, 0, 3, 1, 1); var process_action_bar = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); process_action_bar.valign = Gtk.Align.START; @@ -111,7 +103,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { }); }); - add (preventor); + attach (preventor, 0, 4, 1, 1); @@ -120,6 +112,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { public void update () { if (process != null) { process_info_header.update (process); + process_info_other.update (process); cpu_graph_model.update (process.cpu_percentage); cpu_graph.tooltip_text = ("%.1f%%").printf (process.cpu_percentage); From ccdf4603a95330c2304377cbd7aae9611fb56eb1 Mon Sep 17 00:00:00 2001 From: Ryo Nakano <26003928+ryonakano@users.noreply.github.com> Date: Mon, 23 Mar 2020 09:49:54 +0900 Subject: [PATCH 57/96] Set Node.js version to 10.17.0 to fix CI --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e93f9575..01511385 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ language: node_js node_js: - - 10/* + - 10.17.0 sudo: required From 69f59d5c04eb0f26d64d49d6129e14138dbb2e70 Mon Sep 17 00:00:00 2001 From: Ryo Nakano <26003928+ryonakano@users.noreply.github.com> Date: Mon, 23 Mar 2020 09:56:25 +0900 Subject: [PATCH 58/96] process_info_other at the bottom of graph_wrapper --- src/Views/ProcessView/ProcessInfoView/Preventor.vala | 2 ++ src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Views/ProcessView/ProcessInfoView/Preventor.vala b/src/Views/ProcessView/ProcessInfoView/Preventor.vala index f0702cad..7a2d75bc 100644 --- a/src/Views/ProcessView/ProcessInfoView/Preventor.vala +++ b/src/Views/ProcessView/ProcessInfoView/Preventor.vala @@ -10,6 +10,8 @@ public class Monitor.Preventor : Gtk.Stack { public signal void confirmed (bool is_confirmed); construct { + vexpand = true; + preventive_action_bar = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); preventive_action_bar.valign = Gtk.Align.START; preventive_action_bar.halign = Gtk.Align.END; diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index 03318b03..c1202fc2 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -58,7 +58,7 @@ public class Monitor.ProcessInfoView : Gtk.Grid { mem_graph = new Graph(); var graph_wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); - graph_wrapper.valign = Gtk.Align.START; + graph_wrapper.vexpand = false; graph_wrapper.height_request = 60; graph_wrapper.add (cpu_graph); @@ -70,7 +70,7 @@ public class Monitor.ProcessInfoView : Gtk.Grid { attach (process_info_other, 0, 3, 1, 1); var process_action_bar = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); - process_action_bar.valign = Gtk.Align.START; + process_action_bar.valign = Gtk.Align.END; process_action_bar.halign = Gtk.Align.END; end_process_button = new Gtk.Button.with_label (_("End Process")); From a42f21cb7db9b5a9a6e30df7d2f8853a505ff484 Mon Sep 17 00:00:00 2001 From: stsdc Date: Tue, 24 Mar 2020 01:45:51 +0100 Subject: [PATCH 59/96] refactor --- .../ProcessView/ProcessInfoView/ProcessInfoHeader.vala | 10 +++++----- .../ProcessView/ProcessInfoView/ProcessInfoOther.vala | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala index f4bc03f6..129e834f 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala @@ -60,13 +60,13 @@ public class Monitor.ProcessInfoHeader : Gtk.Grid { public void update (Process process) { application_name.set_text (process.application_name); application_name.tooltip_text = process.command; - pid.set_text (("%d").printf (process.stat.pid)); - nice.set_text (("%d").printf (process.stat.nice)); - priority.set_text (("%d").printf (process.stat.priority)); + pid.set_text (process.stat.pid.to_string()); + nice.set_text (process.stat.nice.to_string()); + priority.set_text (process.stat.priority.to_string()); username.set_text (process.username); - num_threads.set_text (("%d").printf (process.stat.num_threads)); + num_threads.set_text (process.stat.num_threads.to_string()); state.set_text (process.stat.state); - num_threads.set_text (("%d").printf (process.stat.num_threads)); + num_threads.set_text (process.stat.num_threads.to_string()); set_icon (process); } diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoOther.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoOther.vala index f89341f7..96594e3b 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoOther.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoOther.vala @@ -20,16 +20,16 @@ public class Monitor.ProcessInfoOther : Gtk.Grid { var net_label = new Gtk.Label ( _("NET")); net_label.get_style_context ().add_class (Granite.STYLE_CLASS_H3_LABEL); - var rchar_desc_label = create_label (_("characters read")); + var rchar_desc_label = create_label (_("Characters read")); rchar_label = create_label (_("N/A")); - var wchar_desc_label = create_label (_("characters written")); + var wchar_desc_label = create_label (_("Characters written")); wchar_label = create_label (_("N/A")); - var syscr_desc_label = create_label (_("read syscalls")); + var syscr_desc_label = create_label (_("Read syscalls")); syscr_label = create_label (_("N/A")); - var syscw_desc_label = create_label (_("write syscalls")); + var syscw_desc_label = create_label (_("Write syscalls")); syscw_label = create_label (_("N/A")); var write_bytes_desc_label = create_label (_("Read bytes")); @@ -38,7 +38,7 @@ public class Monitor.ProcessInfoOther : Gtk.Grid { var read_bytes_desc_label = create_label (_("Written bytes")); read_bytes_label = create_label (_("N/A")); - var cancelled_write_bytes_desc_label = create_label (_("Cancelled write_bytes")); + var cancelled_write_bytes_desc_label = create_label (_("Cancelled write bytes")); cancelled_write_bytes_label = create_label (_("N/A")); attach (io_label, 0, 0, 1, 2); From 1942b30a77989699cfa055d180ca8ddcf135fb2e Mon Sep 17 00:00:00 2001 From: stsdc Date: Tue, 24 Mar 2020 01:46:29 +0100 Subject: [PATCH 60/96] parse statm and get open files per process --- src/Managers/Process.vala | 45 ++++++++++++++++++++++++++++++++ src/Managers/ProcessStructs.vala | 27 +++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index 37ae047f..044133c3 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -35,6 +35,9 @@ public class Monitor.Process : GLib.Object { // Contains status info public ProcessStatus stat; + public ProcessStatusMemory statm; + + public Gee.HashSet open_files_paths; /** * CPU usage of this process from the last time that it was updated, measured in percent @@ -57,6 +60,8 @@ public class Monitor.Process : GLib.Object { public Process (int _pid) { _icon = ProcessUtils.get_default_icon (); + open_files_paths = new Gee.HashSet (); + last_total = 0; io = { }; @@ -84,6 +89,8 @@ public class Monitor.Process : GLib.Object { if (exists) { get_usage (cpu_total, cpu_last_total); parse_io (); + parse_statm (); + get_open_files (); } return exists; } @@ -196,6 +203,44 @@ public class Monitor.Process : GLib.Object { return true; } + private bool parse_statm () { + string ? statm_contents = ProcessUtils.read_file ("/proc/%d/statm".printf (stat.pid)); + + if (statm_contents == null) return false; + + var splitted_statm = statm_contents.split (" "); + statm.size = int.parse (splitted_statm[0]); + statm.resident = int.parse (splitted_statm[1]); + statm.shared = int.parse (splitted_statm[2]); + statm.trs = int.parse (splitted_statm[3]); + statm.lrs = int.parse (splitted_statm[4]); + statm.drs = int.parse (splitted_statm[5]); + statm.dt = int.parse (splitted_statm[6]); + + return true; + } + + private bool get_open_files () { + try { + string directory = "/proc/%d/fd".printf (stat.pid); + Dir dir = Dir.open (directory, 0); + string? name = null; + while ((name = dir.read_name ()) != null) { + string path = Path.build_filename (directory, name); + + if (FileUtils.test (path, FileTest.IS_SYMLINK)) { + string real_path = FileUtils.read_link(path); + // debug(content); + open_files_paths.add (real_path); + } + + } + } catch (FileError err) { + warning (err.message); + } + return true; + } + /** * Reads the /proc/%pid%/cmdline file and updates from the information contained therein. */ diff --git a/src/Managers/ProcessStructs.vala b/src/Managers/ProcessStructs.vala index 872753fb..335085fb 100644 --- a/src/Managers/ProcessStructs.vala +++ b/src/Managers/ProcessStructs.vala @@ -25,6 +25,33 @@ public struct Monitor.ProcessIO { public uint64 cancelled_write_bytes; } +public struct Monitor.ProcessStatusMemory { + + // total program size (pages) (same as VmSize in status) + public uint64 size; + + // size of memory portions (pages) (same as VmRSS in status) + public uint64 resident; + + // number of pages that are shared + // (i.e. backed by a file, same as RssFile+RssShmem in status) + public uint64 shared; + + // number of pages that are 'code' (not including libs; broken, + // includes data segment) + public uint64 trs; + + // number of pages of library (always 0 on 2.6) + public uint64 lrs; + + // number of pages of data/stack (including libs; broken, + // includes library text) + public uint64 drs; + + // number of dirty pages (always 0 on 2.6) + public uint64 dt; +} + public struct Monitor.ProcessStatus { // process ID public int pid; From d88cfdfe02bf63db0d825f7feaaf70679bfae048 Mon Sep 17 00:00:00 2001 From: stsdc Date: Tue, 24 Mar 2020 01:47:34 +0100 Subject: [PATCH 61/96] display opened files by process, but listbox needs clearing --- meson.build | 1 + .../ProcessInfoView/OpenFilesListBox.vala | 18 ++++++++++++++++++ .../ProcessInfoView/ProcessInfoView.vala | 8 +++++++- 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala diff --git a/meson.build b/meson.build index 803001ef..2e42f9b2 100644 --- a/meson.build +++ b/meson.build @@ -70,6 +70,7 @@ executable( 'src/Views/ProcessView/ProcessInfoView/Graph.vala', 'src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala', 'src/Views/ProcessView/ProcessInfoView/ProcessInfoOther.vala', + 'src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala', # Widgets 'src/Widgets/Headerbar/Headerbar.vala', diff --git a/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala b/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala new file mode 100644 index 00000000..dcd2b69b --- /dev/null +++ b/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala @@ -0,0 +1,18 @@ +public class Monitor.OpenFilesListBox : Gtk.ListBox { + public OpenFilesListBox () { + set_selection_mode (Gtk.SelectionMode.NONE); + vexpand = true; + + } + + public void update (Process process) { + foreach (var path in process.open_files_paths) { + // Gtk.ListBoxRow row = new Gtk.ListBoxRow (); + var path_label = new Gtk.Label (path); + debug (path); + // row.add (path_label); + add (path_label); + } + show_all(); + } +} \ No newline at end of file diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index c1202fc2..79833bf1 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -20,6 +20,7 @@ public class Monitor.ProcessInfoView : Gtk.Grid { private ProcessInfoHeader process_info_header; private ProcessInfoOther process_info_other; + private OpenFilesListBox open_files_list_box; private Regex ? regex; private Gtk.Grid grid; @@ -69,6 +70,9 @@ public class Monitor.ProcessInfoView : Gtk.Grid { process_info_other = new ProcessInfoOther (); attach (process_info_other, 0, 3, 1, 1); + open_files_list_box = new OpenFilesListBox (); + attach (open_files_list_box, 0, 4, 1, 1); + var process_action_bar = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); process_action_bar.valign = Gtk.Align.END; process_action_bar.halign = Gtk.Align.END; @@ -103,7 +107,7 @@ public class Monitor.ProcessInfoView : Gtk.Grid { }); }); - attach (preventor, 0, 4, 1, 1); + attach (preventor, 0, 5, 1, 1); @@ -120,6 +124,8 @@ public class Monitor.ProcessInfoView : Gtk.Grid { mem_graph_model.update (process.mem_percentage); mem_graph.tooltip_text = ("%.1f%%").printf (process.mem_percentage); + open_files_list_box.update (process); + } } From 0912c6cab49a155e18b5c0cb8c2d92ce6e2aa556 Mon Sep 17 00:00:00 2001 From: stsdc Date: Wed, 25 Mar 2020 02:05:23 +0100 Subject: [PATCH 62/96] clear list of opened files before adding new ones --- src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala | 6 +++++- src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala b/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala index dcd2b69b..bbbdbc04 100644 --- a/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala +++ b/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala @@ -6,8 +6,12 @@ public class Monitor.OpenFilesListBox : Gtk.ListBox { } public void update (Process process) { + // removeing all "rows" + // probably should be done with model + foreach (Gtk.Widget element in get_children ()) + remove (element); + foreach (var path in process.open_files_paths) { - // Gtk.ListBoxRow row = new Gtk.ListBoxRow (); var path_label = new Gtk.Label (path); debug (path); // row.add (path_label); diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index 79833bf1..5d29e9df 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -7,6 +7,8 @@ public class Monitor.ProcessInfoView : Gtk.Grid { process_info_header.update (_process); process_info_other.update (_process); + open_files_list_box.update (_process); + // Clearing graphs when new process is set cpu_graph_model = new GraphModel(); cpu_graph.set_model(cpu_graph_model); From d0d757a167e685e76596c38b9483ef13038a3cf8 Mon Sep 17 00:00:00 2001 From: stsdc Date: Wed, 25 Mar 2020 02:23:27 +0100 Subject: [PATCH 63/96] make listbox scrollable --- src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala | 2 +- src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala b/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala index bbbdbc04..22aee5c7 100644 --- a/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala +++ b/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala @@ -13,7 +13,7 @@ public class Monitor.OpenFilesListBox : Gtk.ListBox { foreach (var path in process.open_files_paths) { var path_label = new Gtk.Label (path); - debug (path); + // debug (path); // row.add (path_label); add (path_label); } diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index 5d29e9df..9d05cf84 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -73,7 +73,9 @@ public class Monitor.ProcessInfoView : Gtk.Grid { attach (process_info_other, 0, 3, 1, 1); open_files_list_box = new OpenFilesListBox (); - attach (open_files_list_box, 0, 4, 1, 1); + var open_files_list_box_scrolled = new Gtk.ScrolledWindow (null, null); + open_files_list_box_scrolled.add (open_files_list_box); + attach (open_files_list_box_scrolled, 0, 4, 1, 1); var process_action_bar = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); process_action_bar.valign = Gtk.Align.END; From 2dc0adc0960f7da7a5c39c8e1a4d00e373b1c31d Mon Sep 17 00:00:00 2001 From: stsdc Date: Wed, 25 Mar 2020 20:05:56 +0100 Subject: [PATCH 64/96] open files listbox improvement --- data/Application.css | 4 ++ .../ProcessInfoView/OpenFilesListBox.vala | 43 +++++++++++++------ .../ProcessInfoView/ProcessInfoView.vala | 6 +-- 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/data/Application.css b/data/Application.css index 90f63e4e..142c6339 100644 --- a/data/Application.css +++ b/data/Application.css @@ -48,4 +48,8 @@ color:grey; font-weight:bold; font-size:9px; +} + +.open_files_list_box_wrapper { + border: 1px @SILVER_300 solid; } \ No newline at end of file diff --git a/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala b/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala index 22aee5c7..b8624016 100644 --- a/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala +++ b/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala @@ -1,22 +1,41 @@ -public class Monitor.OpenFilesListBox : Gtk.ListBox { - public OpenFilesListBox () { - set_selection_mode (Gtk.SelectionMode.NONE); - vexpand = true; - +public class Monitor.OpenFilesListBox : Gtk.ScrolledWindow { + Gtk.ListBox listbox; + construct { + get_style_context ().add_class ("open_files_list_box_wrapper"); + hadjustment = null; + vadjustment = null; + + listbox = new Gtk.ListBox (); + listbox.set_selection_mode (Gtk.SelectionMode.NONE); + listbox.get_style_context ().add_class ("open_files_list_box"); + listbox.vexpand = true; + + add (listbox); } public void update (Process process) { // removeing all "rows" // probably should be done with model - foreach (Gtk.Widget element in get_children ()) - remove (element); + foreach (Gtk.Widget element in listbox.get_children ()) + listbox.remove (element); foreach (var path in process.open_files_paths) { - var path_label = new Gtk.Label (path); - // debug (path); - // row.add (path_label); - add (path_label); + var row = new OpenFilesListBoxRow (path); + listbox.add (row); } - show_all(); + show_all (); + } +} + + +public class Monitor.OpenFilesListBoxRow : Gtk.ListBoxRow { + construct { + margin = 6; + } + public OpenFilesListBoxRow (string text) { + Gtk.Label label = new Gtk.Label (text); + label.halign = Gtk.Align.START; + + add (label); } } \ No newline at end of file diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index 9d05cf84..ddfd7bc7 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -73,9 +73,7 @@ public class Monitor.ProcessInfoView : Gtk.Grid { attach (process_info_other, 0, 3, 1, 1); open_files_list_box = new OpenFilesListBox (); - var open_files_list_box_scrolled = new Gtk.ScrolledWindow (null, null); - open_files_list_box_scrolled.add (open_files_list_box); - attach (open_files_list_box_scrolled, 0, 4, 1, 1); + attach (open_files_list_box, 0, 4, 1, 1); var process_action_bar = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); process_action_bar.valign = Gtk.Align.END; @@ -128,7 +126,7 @@ public class Monitor.ProcessInfoView : Gtk.Grid { mem_graph_model.update (process.mem_percentage); mem_graph.tooltip_text = ("%.1f%%").printf (process.mem_percentage); - open_files_list_box.update (process); + // open_files_list_box.update (process); } } From 7ff898564a3c06f37b386427df0a8d5e4c0e8aa9 Mon Sep 17 00:00:00 2001 From: stsdc Date: Thu, 26 Mar 2020 00:40:44 +0100 Subject: [PATCH 65/96] better looking layout for IO and opened files list --- meson.build | 2 +- src/Utils.vala | 49 +++++++++++ .../ProcessInfoView/ProcessInfoIOStats.vala | 88 +++++++++++++++++++ .../ProcessInfoView/ProcessInfoOther.vala | 67 -------------- .../ProcessInfoView/ProcessInfoView.vala | 15 ++-- .../ProcessTreeView/CPUProcessTreeView.vala | 8 +- 6 files changed, 147 insertions(+), 82 deletions(-) create mode 100644 src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala diff --git a/meson.build b/meson.build index 2e42f9b2..ac76a1bc 100644 --- a/meson.build +++ b/meson.build @@ -69,7 +69,7 @@ executable( 'src/Views/ProcessView/ProcessInfoView/RoundyLabel.vala', 'src/Views/ProcessView/ProcessInfoView/Graph.vala', 'src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala', - 'src/Views/ProcessView/ProcessInfoView/ProcessInfoOther.vala', + 'src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala', 'src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala', # Widgets diff --git a/src/Utils.vala b/src/Utils.vala index dbf1939b..7a0afbe7 100644 --- a/src/Utils.vala +++ b/src/Utils.vala @@ -8,4 +8,53 @@ namespace Monitor.Utils { public double swap_used; public double swap_total; } + + const string NOT_AVAILABLE = (_("N/A")); + const string NO_DATA = "\u2014"; } + + /** + * Static helper class for unit formatting + * Author: Laurent Callarec @lcallarec + */ + public class Monitor.Utils.HumanUnitFormatter { + + const string[] SIZE_UNITS = {"B", "KiB", "MiB", "GiB", "TiB"}; + const double KFACTOR = 1024; + + /** + * format a string of bytes to an human readable format with units + */ + public static string string_bytes_to_human(string bytes) { + double current_size = double.parse(bytes); + string current_size_formatted = bytes.to_string() + HumanUnitFormatter.SIZE_UNITS[0]; + + for (int i = 0; i<= HumanUnitFormatter.SIZE_UNITS.length; i++) { + if (current_size < HumanUnitFormatter.KFACTOR) { + return GLib.Math.round(current_size).to_string() + HumanUnitFormatter.SIZE_UNITS[i]; + } + current_size = current_size / HumanUnitFormatter.KFACTOR; + } + + return current_size_formatted; + } + + public static string int_bytes_to_human(int bytes) { + double bytes_double = (double)bytes; + string units = _ ("B"); + + // convert to MiB if needed + if (bytes_double > 1024.0) { + bytes_double /= 1024.0; + units = _ ("KiB"); + } + + // convert to GiB if needed + if (bytes_double > 1024.0) { + bytes_double /= 1024.0; + units = _ ("MiB"); + } + + return "%.1f %s".printf (bytes_double, units); + } + } diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala new file mode 100644 index 00000000..fb5905ba --- /dev/null +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala @@ -0,0 +1,88 @@ +public class Monitor.ProcessInfoIOStats : Gtk.Grid { + private Gtk.Label rchar_label; + private Gtk.Label wchar_label; + private Gtk.Label syscr_label; + private Gtk.Label syscw_label; + private Gtk.Label write_bytes_label; + private Gtk.Label read_bytes_label; + private Gtk.Label cancelled_write_bytes_label; + + private OpenFilesListBox open_files_listbox; + + construct { + column_spacing = 6; + row_spacing = 6; + column_homogeneous = true; + row_homogeneous = false; + + var opened_files_label = create_label (_("Opened files")); + opened_files_label.get_style_context ().add_class (Granite.STYLE_CLASS_H4_LABEL); + opened_files_label.margin_top = 24; + + var characters_label = create_label (_("Characters")); + characters_label.get_style_context ().add_class (Granite.STYLE_CLASS_H4_LABEL); + rchar_label = create_label (_("N/A")); + wchar_label = create_label (_("N/A")); + + var system_calls_label = create_label (_("System calls")); + system_calls_label.get_style_context ().add_class (Granite.STYLE_CLASS_H4_LABEL); + syscr_label = create_label (_("N/A")); + syscw_label = create_label (_("N/A")); + + var io_label = create_label (_("Read/Written")); + io_label.get_style_context ().add_class (Granite.STYLE_CLASS_H4_LABEL); + write_bytes_label = create_label (_("N/A")); + read_bytes_label = create_label (_("N/A")); + + var cancelled_write_label = create_label (_("Cancelled write")); + cancelled_write_label.get_style_context ().add_class (Granite.STYLE_CLASS_H4_LABEL); + + cancelled_write_bytes_label = create_label (Utils.NO_DATA); + + attach (io_label, 0, 1, 1, 1); + attach (create_label_with_icon(read_bytes_label, "go-up-symbolic"), 0, 2, 1, 1); + attach (create_label_with_icon(write_bytes_label, "go-down-symbolic"), 0, 3, 1, 1); + + attach (cancelled_write_label, 1, 1, 1, 1); + attach (cancelled_write_bytes_label, 1, 2, 1, 1); + + attach (opened_files_label, 0, 3, 3, 1); + + open_files_listbox = new OpenFilesListBox (); + attach (open_files_listbox, 0, 4, 3, 1); + } + + public ProcessInfoIOStats() { + + } + + public void update (Process process) { + write_bytes_label.set_text (Utils.HumanUnitFormatter.int_bytes_to_human((int)process.io.write_bytes)); + read_bytes_label.set_text (Utils.HumanUnitFormatter.int_bytes_to_human((int)process.io.read_bytes)); + cancelled_write_bytes_label.set_text (Utils.HumanUnitFormatter.int_bytes_to_human((int)process.io.cancelled_write_bytes)); + + open_files_listbox.update (process); + } + + private Gtk.Label create_label (string text) { + var label = new Gtk.Label (text); + label.halign = Gtk.Align.START; + return label; + } + + private Gtk.Image create_icon (string icon_name) { + var icon = new Gtk.Image (); + icon.gicon = new ThemedIcon (icon_name); + icon.halign = Gtk.Align.START; + icon.pixel_size = 16; + return icon; + } + + private Gtk.Grid create_label_with_icon (Gtk.Label label, string icon_name) { + var grid = new Gtk.Grid (); + grid.column_spacing = 2; + grid.attach (create_icon (icon_name), 0, 0, 1, 1); + grid.attach (label, 1, 0, 1, 1); + return grid; + } +} \ No newline at end of file diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoOther.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoOther.vala index 96594e3b..8c0a2d06 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoOther.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoOther.vala @@ -1,66 +1,8 @@ public class Monitor.ProcessInfoOther : Gtk.Grid { - private Gtk.Label rchar_label; - private Gtk.Label wchar_label; - private Gtk.Label syscr_label; - private Gtk.Label syscw_label; - private Gtk.Label write_bytes_label; - private Gtk.Label read_bytes_label; - private Gtk.Label cancelled_write_bytes_label; - construct { - column_spacing = 12; - row_spacing = 12; - column_homogeneous = true; - row_homogeneous = true; - var io_label = new Gtk.Label (_("IO")); - io_label.get_style_context ().add_class (Granite.STYLE_CLASS_H3_LABEL); - - var net_label = new Gtk.Label ( _("NET")); - net_label.get_style_context ().add_class (Granite.STYLE_CLASS_H3_LABEL); - var rchar_desc_label = create_label (_("Characters read")); - rchar_label = create_label (_("N/A")); - - var wchar_desc_label = create_label (_("Characters written")); - wchar_label = create_label (_("N/A")); - - var syscr_desc_label = create_label (_("Read syscalls")); - syscr_label = create_label (_("N/A")); - - var syscw_desc_label = create_label (_("Write syscalls")); - syscw_label = create_label (_("N/A")); - - var write_bytes_desc_label = create_label (_("Read bytes")); - write_bytes_label = create_label (_("N/A")); - - var read_bytes_desc_label = create_label (_("Written bytes")); - read_bytes_label = create_label (_("N/A")); - - var cancelled_write_bytes_desc_label = create_label (_("Cancelled write bytes")); - cancelled_write_bytes_label = create_label (_("N/A")); - - attach (io_label, 0, 0, 1, 2); - attach (rchar_desc_label, 0, 1, 1, 2); - attach (wchar_desc_label, 0, 2, 1, 2); - attach (syscr_desc_label, 0, 3, 1, 2); - attach (syscw_desc_label, 0, 4, 1, 2); - attach (write_bytes_desc_label, 0, 5, 1, 2); - attach (read_bytes_desc_label, 0, 6, 1, 2); - attach (cancelled_write_bytes_desc_label, 0, 7, 1, 2); - - attach (rchar_label, 1, 1, 1, 2); - attach (wchar_label, 1, 2, 1, 2); - attach (syscr_label, 1, 3, 1, 2); - attach (syscw_label, 1, 4, 1, 2); - attach (write_bytes_label, 1, 5, 1, 2); - attach (read_bytes_label, 1, 6, 1, 2); - attach (cancelled_write_bytes_label, 1, 7, 1, 2); - - - attach (net_label, 2, 0, 1, 2); - } private Gtk.Label create_label (string text) { var label = new Gtk.Label (text); @@ -68,15 +10,6 @@ public class Monitor.ProcessInfoOther : Gtk.Grid { return label; } - public void update (Process process) { - rchar_label.set_text (process.io.rchar.to_string()); - wchar_label.set_text (process.io.wchar.to_string()); - syscr_label.set_text (process.io.syscr.to_string()); - syscw_label.set_text (process.io.syscw.to_string()); - write_bytes_label.set_text (process.io.write_bytes.to_string()); - read_bytes_label.set_text (process.io.read_bytes.to_string()); - cancelled_write_bytes_label.set_text (process.io.cancelled_write_bytes.to_string()); - } } \ No newline at end of file diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index ddfd7bc7..d362424e 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -6,8 +6,8 @@ public class Monitor.ProcessInfoView : Gtk.Grid { _process = value; process_info_header.update (_process); - process_info_other.update (_process); - open_files_list_box.update (_process); + process_info_io_stats.update (_process); + // Clearing graphs when new process is set cpu_graph_model = new GraphModel(); @@ -21,8 +21,7 @@ public class Monitor.ProcessInfoView : Gtk.Grid { private Gtk.ScrolledWindow command_wrapper; private ProcessInfoHeader process_info_header; - private ProcessInfoOther process_info_other; - private OpenFilesListBox open_files_list_box; + private ProcessInfoIOStats process_info_io_stats; private Regex ? regex; private Gtk.Grid grid; @@ -69,11 +68,9 @@ public class Monitor.ProcessInfoView : Gtk.Grid { attach (graph_wrapper, 0, 2, 1, 1); - process_info_other = new ProcessInfoOther (); - attach (process_info_other, 0, 3, 1, 1); + process_info_io_stats = new ProcessInfoIOStats (); + attach (process_info_io_stats, 0, 3, 1, 1); - open_files_list_box = new OpenFilesListBox (); - attach (open_files_list_box, 0, 4, 1, 1); var process_action_bar = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); process_action_bar.valign = Gtk.Align.END; @@ -118,7 +115,7 @@ public class Monitor.ProcessInfoView : Gtk.Grid { public void update () { if (process != null) { process_info_header.update (process); - process_info_other.update (process); + // process_info_other.update (process); cpu_graph_model.update (process.cpu_percentage); cpu_graph.tooltip_text = ("%.1f%%").printf (process.cpu_percentage); diff --git a/src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala b/src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala index 385cd9c8..28351928 100644 --- a/src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala +++ b/src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala @@ -6,8 +6,6 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { private Gtk.TreeViewColumn memory_column; private Regex ? regex; - const string NO_DATA = "\u2014"; - public signal void process_selected (Process process); public CPUProcessTreeView (TreeViewModel model) { @@ -101,7 +99,7 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { // format the double into a string if (cpu_usage < 0.0) - (cell as Gtk.CellRendererText).text = NO_DATA; + (cell as Gtk.CellRendererText).text = Utils.NO_DATA; else (cell as Gtk.CellRendererText).text = "%.0f%%".printf (cpu_usage); } @@ -128,7 +126,7 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { // format the double into a string if (memory_usage == 0) - (cell as Gtk.CellRendererText).text = NO_DATA; + (cell as Gtk.CellRendererText).text = Utils.NO_DATA; else (cell as Gtk.CellRendererText).text = "%.1f %s".printf (memory_usage_double, units); } @@ -139,7 +137,7 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { int pid = pid_value.get_int (); // format the double into a string if (pid == 0) { - (cell as Gtk.CellRendererText).text = NO_DATA; + (cell as Gtk.CellRendererText).text = Utils.NO_DATA; } } From 945d506da87aec4335ddc5894233e137fd5f6cd2 Mon Sep 17 00:00:00 2001 From: stsdc Date: Thu, 26 Mar 2020 21:15:12 +0100 Subject: [PATCH 66/96] display only files --- data/Application.css | 15 +++++++++++++++ .../ProcessInfoView/OpenFilesListBox.vala | 12 +++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/data/Application.css b/data/Application.css index 142c6339..918e9212 100644 --- a/data/Application.css +++ b/data/Application.css @@ -52,4 +52,19 @@ font-size:9px; .open_files_list_box_wrapper { border: 1px @SILVER_300 solid; +} + +.open_files_list_box { + +} +.open_files_list_box_row { + border-bottom: 1px @SILVER_100 solid; +} + +.open_files_list_box_row label { + font-family: monospace; + /* background-color: @SILVER_300; */ + padding: 4px 6; + margin: 6px 4px; + border-radius: 4px; } \ No newline at end of file diff --git a/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala b/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala index b8624016..e4d2e8d0 100644 --- a/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala +++ b/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala @@ -6,6 +6,7 @@ public class Monitor.OpenFilesListBox : Gtk.ScrolledWindow { vadjustment = null; listbox = new Gtk.ListBox (); + listbox.get_style_context ().add_class ("open_files_list_box"); listbox.set_selection_mode (Gtk.SelectionMode.NONE); listbox.get_style_context ().add_class ("open_files_list_box"); listbox.vexpand = true; @@ -20,8 +21,12 @@ public class Monitor.OpenFilesListBox : Gtk.ScrolledWindow { listbox.remove (element); foreach (var path in process.open_files_paths) { - var row = new OpenFilesListBoxRow (path); - listbox.add (row); + // display only real paths + // probably should be done in process class + if (path.substring(0, 1) == "/") { + var row = new OpenFilesListBoxRow (path); + listbox.add (row); + } } show_all (); } @@ -30,7 +35,8 @@ public class Monitor.OpenFilesListBox : Gtk.ScrolledWindow { public class Monitor.OpenFilesListBoxRow : Gtk.ListBoxRow { construct { - margin = 6; + + get_style_context ().add_class ("open_files_list_box_row"); } public OpenFilesListBoxRow (string text) { Gtk.Label label = new Gtk.Label (text); From 4200ec9f0bc3f7a762a63c0672268e87bc4a1e0c Mon Sep 17 00:00:00 2001 From: stsdc Date: Thu, 26 Mar 2020 21:15:28 +0100 Subject: [PATCH 67/96] fix preventor valign --- src/Views/ProcessView/ProcessInfoView/Preventor.vala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Views/ProcessView/ProcessInfoView/Preventor.vala b/src/Views/ProcessView/ProcessInfoView/Preventor.vala index 7a2d75bc..61d5ffed 100644 --- a/src/Views/ProcessView/ProcessInfoView/Preventor.vala +++ b/src/Views/ProcessView/ProcessInfoView/Preventor.vala @@ -11,6 +11,7 @@ public class Monitor.Preventor : Gtk.Stack { construct { vexpand = true; + valign = Gtk.Align.END; preventive_action_bar = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); preventive_action_bar.valign = Gtk.Align.START; From da6119d6a373de42d3bfce2f99de34213da07f0d Mon Sep 17 00:00:00 2001 From: stsdc Date: Thu, 26 Mar 2020 21:15:37 +0100 Subject: [PATCH 68/96] remove unused --- .../ProcessInfoView/ProcessInfoOther.vala | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 src/Views/ProcessView/ProcessInfoView/ProcessInfoOther.vala diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoOther.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoOther.vala deleted file mode 100644 index 8c0a2d06..00000000 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoOther.vala +++ /dev/null @@ -1,15 +0,0 @@ -public class Monitor.ProcessInfoOther : Gtk.Grid { - - - - - - private Gtk.Label create_label (string text) { - var label = new Gtk.Label (text); - label.halign = Gtk.Align.START; - return label; - } - - - -} \ No newline at end of file From f0c65d347c31f0764b9f3e0223fdd30464e940c4 Mon Sep 17 00:00:00 2001 From: stsdc Date: Thu, 26 Mar 2020 21:59:48 +0100 Subject: [PATCH 69/96] show icon if file is deleted in OpenFileListBox --- data/Application.css | 10 +++++--- .../ProcessInfoView/OpenFilesListBox.vala | 24 ++++++++++++++++--- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/data/Application.css b/data/Application.css index 918e9212..2ca73b1b 100644 --- a/data/Application.css +++ b/data/Application.css @@ -64,7 +64,11 @@ font-size:9px; .open_files_list_box_row label { font-family: monospace; /* background-color: @SILVER_300; */ - padding: 4px 6; - margin: 6px 4px; + padding: 6px 2px 2px; border-radius: 4px; -} \ No newline at end of file +} + +.open_files_list_box_row image { + color: @SILVER_700; + margin: 6px; +} diff --git a/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala b/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala index e4d2e8d0..581e31d5 100644 --- a/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala +++ b/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala @@ -24,7 +24,9 @@ public class Monitor.OpenFilesListBox : Gtk.ScrolledWindow { // display only real paths // probably should be done in process class if (path.substring(0, 1) == "/") { - var row = new OpenFilesListBoxRow (path); + + // TODO: remove `(deleted)` at the end of the path if deleted ofc + var row = new OpenFilesListBoxRow (path, path.contains("(deleted)")); listbox.add (row); } } @@ -38,10 +40,26 @@ public class Monitor.OpenFilesListBoxRow : Gtk.ListBoxRow { get_style_context ().add_class ("open_files_list_box_row"); } - public OpenFilesListBoxRow (string text) { + public OpenFilesListBoxRow (string text, bool is_deleted) { + var grid = new Gtk.Grid (); + grid.column_spacing = 2; + + var icon = new Gtk.Image (); + icon.halign = Gtk.Align.START; + icon.pixel_size = 16; + icon.gicon = new ThemedIcon ("emblem-documents-symbolic"); + + if (is_deleted) { + icon.gicon = new ThemedIcon ("edit-delete-symbolic"); + icon.tooltip_text = _("Deleted"); + } + + grid.attach (icon, 0, 0, 1, 1); + Gtk.Label label = new Gtk.Label (text); label.halign = Gtk.Align.START; + grid.attach (label, 1, 0, 1, 1); - add (label); + add (grid); } } \ No newline at end of file From 0f3a2cfa7aed4ee1acdf254a87ba454242b55494 Mon Sep 17 00:00:00 2001 From: stsdc Date: Sat, 28 Mar 2020 16:04:26 +0100 Subject: [PATCH 70/96] better layout for graphs --- data/Application.css | 6 ++ meson.build | 1 + .../ProcessView/ProcessInfoView/Graph.vala | 3 +- .../ProcessInfoView/ProcessInfoCPURAM.vala | 62 +++++++++++++++++++ .../ProcessInfoView/ProcessInfoView.vala | 42 ++----------- 5 files changed, 77 insertions(+), 37 deletions(-) create mode 100644 src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala diff --git a/data/Application.css b/data/Application.css index 2ca73b1b..90cbecf9 100644 --- a/data/Application.css +++ b/data/Application.css @@ -50,6 +50,12 @@ font-weight:bold; font-size:9px; } +.graph { + border: 1px @SILVER_300 solid; + border-radius: 6px + +} + .open_files_list_box_wrapper { border: 1px @SILVER_300 solid; } diff --git a/meson.build b/meson.build index ac76a1bc..98d71b58 100644 --- a/meson.build +++ b/meson.build @@ -69,6 +69,7 @@ executable( 'src/Views/ProcessView/ProcessInfoView/RoundyLabel.vala', 'src/Views/ProcessView/ProcessInfoView/Graph.vala', 'src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala', + 'src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala', 'src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala', 'src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala', diff --git a/src/Views/ProcessView/ProcessInfoView/Graph.vala b/src/Views/ProcessView/ProcessInfoView/Graph.vala index 431b0fc9..544fb209 100644 --- a/src/Views/ProcessView/ProcessInfoView/Graph.vala +++ b/src/Views/ProcessView/ProcessInfoView/Graph.vala @@ -4,7 +4,8 @@ public class Monitor.Graph : Dazzle.GraphView construct { expand = true; - margin = 6; + valign = Gtk.Align.START; + height_request = 60; Gdk.RGBA linecol = Gdk.RGBA (); linecol.red = 1.0; diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala new file mode 100644 index 00000000..95f86490 --- /dev/null +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala @@ -0,0 +1,62 @@ +public class Monitor.ProcessInfoCPURAM : Gtk.Grid { + private Gtk.Label cpu_label; + private Gtk.Label ram_label; + + private Graph cpu_graph; + private GraphModel cpu_graph_model; + + private Graph mem_graph; + private GraphModel mem_graph_model; + + construct { + column_spacing = 6; + row_spacing = 6; + vexpand = false; + column_homogeneous = true; + row_homogeneous = false; + + cpu_graph = new Graph (); + mem_graph = new Graph (); + + var cpu_graph_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); + cpu_graph_box.get_style_context ().add_class ("graph"); + cpu_graph_box.add (cpu_graph); + + var mem_graph_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); + mem_graph_box.get_style_context ().add_class ("graph"); + mem_graph_box.add (mem_graph); + + cpu_label = new Gtk.Label ("CPU: " + Utils.NO_DATA); + cpu_label.get_style_context ().add_class (Granite.STYLE_CLASS_H4_LABEL); + cpu_label.halign = Gtk.Align.START; + + ram_label = new Gtk.Label ("RAM: " + Utils.NO_DATA); + ram_label.get_style_context ().add_class (Granite.STYLE_CLASS_H4_LABEL); + ram_label.halign = Gtk.Align.START; + + attach (cpu_label, 0, 0, 1, 1); + attach (ram_label, 1, 0, 1, 1); + + attach (cpu_graph_box, 0, 1, 1, 1); + attach (mem_graph_box, 1, 1, 1, 1); + } + + public void update (Process process) { + cpu_label.set_text (("CPU: %.1f%%").printf (process.cpu_percentage)); + ram_label.set_text (("RAM: %.1f%%").printf (process.mem_percentage)); + + cpu_graph_model.update (process.cpu_percentage); + cpu_graph.tooltip_text = ("%.1f%%").printf (process.cpu_percentage); + + mem_graph_model.update (process.mem_percentage); + mem_graph.tooltip_text = ("%.1f%%").printf (process.mem_percentage); + } + + public void clear_graphs () { + cpu_graph_model = new GraphModel (); + cpu_graph.set_model (cpu_graph_model); + + mem_graph_model = new GraphModel (); + mem_graph.set_model (mem_graph_model); + } +} \ No newline at end of file diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index d362424e..c379f5a2 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -8,13 +8,8 @@ public class Monitor.ProcessInfoView : Gtk.Grid { process_info_header.update (_process); process_info_io_stats.update (_process); + process_info_cpu_ram.clear_graphs (); - // Clearing graphs when new process is set - cpu_graph_model = new GraphModel(); - cpu_graph.set_model(cpu_graph_model); - - mem_graph_model = new GraphModel(); - mem_graph.set_model(mem_graph_model); } } public string ? icon_name; @@ -22,25 +17,18 @@ public class Monitor.ProcessInfoView : Gtk.Grid { private ProcessInfoHeader process_info_header; private ProcessInfoIOStats process_info_io_stats; + private ProcessInfoCPURAM process_info_cpu_ram; private Regex ? regex; private Gtk.Grid grid; - private Graph cpu_graph; - private GraphModel cpu_graph_model; - private Graph mem_graph; - private GraphModel mem_graph_model; private Gtk.Button end_process_button; private Gtk.Button kill_process_button; private Preventor preventor; - construct { - cpu_graph_model = new GraphModel(); - } - public ProcessInfoView () { // get_style_context ().add_class ("process_info"); margin = 12; @@ -55,21 +43,12 @@ public class Monitor.ProcessInfoView : Gtk.Grid { sep.margin = 12; attach (sep, 0, 1, 1, 1); + process_info_cpu_ram = new ProcessInfoCPURAM (); - cpu_graph = new Graph(); - mem_graph = new Graph(); - - var graph_wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); - graph_wrapper.vexpand = false; - graph_wrapper.height_request = 60; - - graph_wrapper.add (cpu_graph); - graph_wrapper.add (mem_graph); - - attach (graph_wrapper, 0, 2, 1, 1); + attach (process_info_cpu_ram, 0, 2, 1, 1); process_info_io_stats = new ProcessInfoIOStats (); - attach (process_info_io_stats, 0, 3, 1, 1); + attach (process_info_io_stats, 0, 4, 1, 1); var process_action_bar = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); @@ -115,16 +94,7 @@ public class Monitor.ProcessInfoView : Gtk.Grid { public void update () { if (process != null) { process_info_header.update (process); - // process_info_other.update (process); - - cpu_graph_model.update (process.cpu_percentage); - cpu_graph.tooltip_text = ("%.1f%%").printf (process.cpu_percentage); - - mem_graph_model.update (process.mem_percentage); - mem_graph.tooltip_text = ("%.1f%%").printf (process.mem_percentage); - - // open_files_list_box.update (process); - + process_info_cpu_ram.update (process); } } From 37a24b61e0561fe831dc84acdf3d62bd3b3edaa7 Mon Sep 17 00:00:00 2001 From: stsdc Date: Sun, 29 Mar 2020 16:24:56 +0200 Subject: [PATCH 71/96] closes #148 change badge color --- data/Application.css | 27 ++++++++++++++----- src/Managers/ProcessManager.vala | 2 +- .../ProcessInfoView/ProcessInfoHeader.vala | 19 +++++++++++++ .../ProcessInfoView/RoundyLabel.vala | 4 +-- 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/data/Application.css b/data/Application.css index 90cbecf9..8c7fe6e1 100644 --- a/data/Application.css +++ b/data/Application.css @@ -1,10 +1,10 @@ -.badge, -.badge:hover, -.badge:selected, -.badge:selected:focus, -.badge:hover:selected { +.roundy-label, +.roundy-label:hover, +.roundy-label:selected, +.roundy-label:selected:focus, +.roundy-label:hover:selected { background-image: none; - background-color: alpha(@text_color, 0.1); + background-color: @SILVER_300; box-shadow: none; color: alpha(@text_color, 0.7); font-weight: 700; @@ -14,6 +14,21 @@ border-width: 0; } +.username-current { + background-color: @SILVER_300; + color: @SILVER_900; +} + +.username-other { + background-color: @BANANA_300; + color: @BANANA_900; +} + +.username-root { + background-color: @STRAWBERRY_300; + color: @SILVER_100; +} + .state_badge, .state_badge:hover, .state_badge:selected, diff --git a/src/Managers/ProcessManager.vala b/src/Managers/ProcessManager.vala index 7fc6b9a0..9a0e95a3 100644 --- a/src/Managers/ProcessManager.vala +++ b/src/Managers/ProcessManager.vala @@ -179,7 +179,7 @@ namespace Monitor { var uid = Posix.getuid (); GTop.ProcList proclist; var pids = GTop.get_proclist (out proclist, GTop.GLIBTOP_KERN_PROC_UID, uid); - // var pids = GTop.get_proclist (out proclist, GTop.GLIBTOP_KERN_PROC_ALL, 0); + // var pids = GTop.get_proclist (out proclist, GTop.GLIBTOP_KERN_PROC_ALL, uid); for (int i = 0; i < proclist.number; i++) { int pid = pids[i]; diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala index 129e834f..3ec0055d 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala @@ -42,6 +42,8 @@ public class Monitor.ProcessInfoHeader : Gtk.Grid { num_threads = new RoundyLabel (_ ("THR")); // ppid = new RoundyLabel (_("PPID")); // pgrp = new RoundyLabel (_("PGRP")); + + // TODO: tooltip_text UID username = new RoundyLabel (""); var wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); @@ -63,6 +65,23 @@ public class Monitor.ProcessInfoHeader : Gtk.Grid { pid.set_text (process.stat.pid.to_string()); nice.set_text (process.stat.nice.to_string()); priority.set_text (process.stat.priority.to_string()); + + if (process.uid == 0) { + username.val.get_style_context ().add_class ("username-root"); + username.val.get_style_context ().remove_class ("username-other"); + username.val.get_style_context ().remove_class ("username-current"); + + + } else if (process.uid == (int)Posix.getuid ()) { + username.val.get_style_context ().add_class ("username-current"); + username.val.get_style_context ().remove_class ("username-other"); + username.val.get_style_context ().remove_class ("username-root"); + } else { + username.val.get_style_context ().add_class ("username-other"); + username.val.get_style_context ().remove_class ("username-root"); + username.val.get_style_context ().remove_class ("username-current"); + } + username.set_text (process.username); num_threads.set_text (process.stat.num_threads.to_string()); state.set_text (process.stat.state); diff --git a/src/Views/ProcessView/ProcessInfoView/RoundyLabel.vala b/src/Views/ProcessView/ProcessInfoView/RoundyLabel.vala index bf904dd6..7a8964d4 100644 --- a/src/Views/ProcessView/ProcessInfoView/RoundyLabel.vala +++ b/src/Views/ProcessView/ProcessInfoView/RoundyLabel.vala @@ -4,8 +4,8 @@ public class Monitor.RoundyLabel : Gtk.Fixed { public Gtk.Label desc; public RoundyLabel (string description) { - val = new Gtk.Label (_ ("N/A")); - val.get_style_context ().add_class (Granite.STYLE_CLASS_BADGE); + val = new Gtk.Label (Utils.NO_DATA); + val.get_style_context ().add_class ("roundy-label"); desc = new Gtk.Label (description); desc.get_style_context ().add_class ("pid"); From ac68cfdf048350ee8432bda46401a09e0adf66e3 Mon Sep 17 00:00:00 2001 From: stsdc Date: Sun, 29 Mar 2020 16:25:32 +0200 Subject: [PATCH 72/96] fix color for text in roundylabel for class 'username-other' --- data/Application.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/Application.css b/data/Application.css index 8c7fe6e1..e10e873c 100644 --- a/data/Application.css +++ b/data/Application.css @@ -21,7 +21,7 @@ .username-other { background-color: @BANANA_300; - color: @BANANA_900; + color: #381F00; } .username-root { From 2833c0597f2a533ee45e990298a5ad84b504111c Mon Sep 17 00:00:00 2001 From: stsdc Date: Sun, 29 Mar 2020 16:25:45 +0200 Subject: [PATCH 73/96] update OpenFilesList regularly --- src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index c379f5a2..87641300 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -95,6 +95,8 @@ public class Monitor.ProcessInfoView : Gtk.Grid { if (process != null) { process_info_header.update (process); process_info_cpu_ram.update (process); + process_info_io_stats.update (process); + } } From 69b5e15fdce25be30ebce83971ba73be5e536227 Mon Sep 17 00:00:00 2001 From: Ryo Nakano <26003928+ryonakano@users.noreply.github.com> Date: Mon, 30 Mar 2020 08:55:55 +0900 Subject: [PATCH 74/96] Show the current CPU frequency when hovering the CPU usage rate text --- src/Resources/CPU.vala | 37 ++++++++++++++++++++++++++-- src/Services/Updater.vala | 1 + src/Utils.vala | 1 + src/Widgets/Statusbar/Statusbar.vala | 3 +++ 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/Resources/CPU.vala b/src/Resources/CPU.vala index f65bfb5b..e54d8284 100644 --- a/src/Resources/CPU.vala +++ b/src/Resources/CPU.vala @@ -7,10 +7,20 @@ public int percentage { get { - update (); + update_percentage (); return (int) (Math.round(load * 100)); } } + + private double _frequency; + public double frequency { + get { + update_frequency (); + // Convert kH to GHz + return (double) (_frequency / 1000000); + } + } + construct { last_used = 0; last_total = 0; @@ -18,7 +28,7 @@ public CPU () { } - private void update () { + private void update_percentage () { GTop.get_cpu (out cpu); var used = (float) (cpu.user + cpu.sys + cpu.nice + cpu.irq + cpu.softirq); @@ -33,4 +43,27 @@ last_used = used; last_total = total; } + + private void update_frequency () { + double maxcur = 0; + for (uint cpu_id = 0, isize = (int) get_num_processors (); cpu_id < isize; ++cpu_id) { + string cur_content; + try { + FileUtils.get_contents ("/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq".printf (cpu_id), out cur_content); + } catch (Error e) { + warning (e.message); + cur_content = "0"; + } + + var cur = double.parse (cur_content); + + if (cpu_id == 0) { + maxcur = cur; + } else { + maxcur = double.max (cur, maxcur); + } + } + + _frequency = (double) maxcur; + } } diff --git a/src/Services/Updater.vala b/src/Services/Updater.vala index 01fcde90..9825644c 100644 --- a/src/Services/Updater.vala +++ b/src/Services/Updater.vala @@ -26,6 +26,7 @@ namespace Monitor { private bool update_resources () { sysres = Utils.SystemResources () { cpu_percentage = cpu.percentage, + cpu_frequency = cpu.frequency, memory_percentage = memory.percentage, memory_used = memory.used, memory_total = memory.total, diff --git a/src/Utils.vala b/src/Utils.vala index 7a0afbe7..40df65e5 100644 --- a/src/Utils.vala +++ b/src/Utils.vala @@ -1,6 +1,7 @@ namespace Monitor.Utils { public struct SystemResources { public int cpu_percentage; + public double cpu_frequency; public int memory_percentage; public double memory_used; public double memory_total; diff --git a/src/Widgets/Statusbar/Statusbar.vala b/src/Widgets/Statusbar/Statusbar.vala index 1f35151d..2b7bd05f 100644 --- a/src/Widgets/Statusbar/Statusbar.vala +++ b/src/Widgets/Statusbar/Statusbar.vala @@ -35,6 +35,9 @@ public class Monitor.Statusbar : Gtk.ActionBar { cpu_usage_label.set_text (("%d%%").printf (sysres.cpu_percentage)); memory_usage_label.set_text (("%d%%").printf (sysres.memory_percentage)); + string cpu_tooltip_text = ("%.2f %s").printf (sysres.cpu_frequency, _ ("GHz")); + cpu_usage_label.tooltip_text = cpu_tooltip_text; + string memory_tooltip_text = ("%.1f %s / %.1f %s").printf (sysres.memory_used, _ ("GiB"), sysres.memory_total, _ ("GiB")); memory_usage_label.tooltip_text = memory_tooltip_text; From 77377e11f2f45778d0f37608faaadd419fedff3f Mon Sep 17 00:00:00 2001 From: Ryo Nakano <26003928+ryonakano@users.noreply.github.com> Date: Mon, 30 Mar 2020 20:57:20 +0900 Subject: [PATCH 75/96] Add reference as comment --- src/Resources/CPU.vala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Resources/CPU.vala b/src/Resources/CPU.vala index e54d8284..b31e88d7 100644 --- a/src/Resources/CPU.vala +++ b/src/Resources/CPU.vala @@ -44,6 +44,7 @@ last_total = total; } + // From https://github.com/PlugaruT/wingpanel-monitor/blob/edcfea6a31f794aa44da6d8b997378ea1a8d8fa3/src/Services/Cpu.vala#L61-L85 private void update_frequency () { double maxcur = 0; for (uint cpu_id = 0, isize = (int) get_num_processors (); cpu_id < isize; ++cpu_id) { From 0904c586d108d05ee64be37b2ddeab0280bc38bd Mon Sep 17 00:00:00 2001 From: stsdc Date: Mon, 30 Mar 2020 20:56:58 +0200 Subject: [PATCH 76/96] do not show warning #154 --- src/Managers/Process.vala | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index 044133c3..989278fc 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -236,7 +236,12 @@ public class Monitor.Process : GLib.Object { } } catch (FileError err) { - warning (err.message); + if (err is FileError.ACCES) { + // TODO make signal that emits error info + // No permission + } else { + warning (err.message); + } } return true; } From 6ca2f859996640d528a0fad80376f0ee5f1f4658 Mon Sep 17 00:00:00 2001 From: stsdc Date: Mon, 30 Mar 2020 20:57:16 +0200 Subject: [PATCH 77/96] use blueberry color for status badge --- data/Application.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/Application.css b/data/Application.css index e10e873c..4a728fba 100644 --- a/data/Application.css +++ b/data/Application.css @@ -35,9 +35,9 @@ .state_badge:selected:focus, .state_badge:hover:selected { background-image: none; - background-color: #8cd5ff; + background-color: @BLUEBERRY_500; box-shadow: none; - color: alpha(#002e99, 0.7); + color: white; font-weight: 700; border-radius: 10px; padding: 0 6px; From 7c6c7e1e64878b79e9d37c95a12c998832dc4bd1 Mon Sep 17 00:00:00 2001 From: stsdc Date: Mon, 30 Mar 2020 20:59:33 +0200 Subject: [PATCH 78/96] error should be an error --- src/Managers/Process.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index 989278fc..ba856802 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -240,7 +240,7 @@ public class Monitor.Process : GLib.Object { // TODO make signal that emits error info // No permission } else { - warning (err.message); + error (err.message); } } return true; From cb54ea10079351eb3b47d3a4a817f6eb8a0adf5d Mon Sep 17 00:00:00 2001 From: stsdc Date: Wed, 1 Apr 2020 22:55:46 +0200 Subject: [PATCH 79/96] display error infobar if insufficient permissions to read a directory --- src/Managers/Process.vala | 6 ++- src/Managers/ProcessManager.vala | 2 +- .../ProcessInfoView/OpenFilesListBox.vala | 19 ++++--- .../ProcessInfoView/ProcessInfoView.vala | 53 ++++++++++++------- 4 files changed, 52 insertions(+), 28 deletions(-) diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index ba856802..2ffd61a5 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -2,6 +2,9 @@ public class Monitor.Process : GLib.Object { // The size of each RSS page, in bytes // private static long PAGESIZE = Posix.sysconf (Posix._SC_PAGESIZE); + public signal void fd_permission_error (string error); + + // Whether or not the PID leads to something public bool exists { get; private set; } @@ -237,8 +240,7 @@ public class Monitor.Process : GLib.Object { } } catch (FileError err) { if (err is FileError.ACCES) { - // TODO make signal that emits error info - // No permission + fd_permission_error ( err.message); } else { error (err.message); } diff --git a/src/Managers/ProcessManager.vala b/src/Managers/ProcessManager.vala index 9a0e95a3..a730f78c 100644 --- a/src/Managers/ProcessManager.vala +++ b/src/Managers/ProcessManager.vala @@ -179,7 +179,7 @@ namespace Monitor { var uid = Posix.getuid (); GTop.ProcList proclist; var pids = GTop.get_proclist (out proclist, GTop.GLIBTOP_KERN_PROC_UID, uid); - // var pids = GTop.get_proclist (out proclist, GTop.GLIBTOP_KERN_PROC_ALL, uid); + // var pids = GTop.get_proclist (out proclist, GTop.GLIBTOP_KERN_PROC_ALLfla, uid); for (int i = 0; i < proclist.number; i++) { int pid = pids[i]; diff --git a/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala b/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala index 581e31d5..99d4e8ca 100644 --- a/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala +++ b/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala @@ -20,14 +20,17 @@ public class Monitor.OpenFilesListBox : Gtk.ScrolledWindow { foreach (Gtk.Widget element in listbox.get_children ()) listbox.remove (element); - foreach (var path in process.open_files_paths) { - // display only real paths - // probably should be done in process class - if (path.substring(0, 1) == "/") { - // TODO: remove `(deleted)` at the end of the path if deleted ofc - var row = new OpenFilesListBoxRow (path, path.contains("(deleted)")); - listbox.add (row); + if (process.open_files_paths.size > 0) { + foreach (var path in process.open_files_paths) { + // display only real paths + // probably should be done in process class + if (path.substring(0, 1) == "/") { + + // TODO: remove `(deleted)` at the end of the path if deleted ofc + var row = new OpenFilesListBoxRow (path, path.contains("(deleted)")); + listbox.add (row); + } } } show_all (); @@ -56,6 +59,8 @@ public class Monitor.OpenFilesListBoxRow : Gtk.ListBoxRow { grid.attach (icon, 0, 0, 1, 1); + debug (text); + Gtk.Label label = new Gtk.Label (text); label.halign = Gtk.Align.START; grid.attach (label, 1, 0, 1, 1); diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index 87641300..0d34dcee 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -1,8 +1,11 @@ -public class Monitor.ProcessInfoView : Gtk.Grid { +public class Monitor.ProcessInfoView : Gtk.Box { private Process _process; public Process ? process { get { return _process; } set { + + // remember to disconnect before assigning a new value + _process.fd_permission_error.disconnect (show_permission_error_infobar); _process = value; process_info_header.update (_process); @@ -10,11 +13,17 @@ public class Monitor.ProcessInfoView : Gtk.Grid { process_info_cpu_ram.clear_graphs (); + permission_error_infobar.revealed = false; + _process.fd_permission_error.connect (show_permission_error_infobar); + } } public string ? icon_name; private Gtk.ScrolledWindow command_wrapper; + private Gtk.InfoBar permission_error_infobar; + private Gtk.Label permission_error_label; + private ProcessInfoHeader process_info_header; private ProcessInfoIOStats process_info_io_stats; private ProcessInfoCPURAM process_info_cpu_ram; @@ -22,33 +31,41 @@ public class Monitor.ProcessInfoView : Gtk.Grid { private Regex ? regex; private Gtk.Grid grid; - - private Gtk.Button end_process_button; private Gtk.Button kill_process_button; private Preventor preventor; public ProcessInfoView () { - // get_style_context ().add_class ("process_info"); - margin = 12; orientation = Gtk.Orientation.VERTICAL; hexpand = true; - column_spacing = 12; + + permission_error_infobar = new Gtk.InfoBar (); + permission_error_infobar.message_type = Gtk.MessageType.ERROR; + permission_error_infobar.revealed = false; + permission_error_label = new Gtk.Label (Utils.NO_DATA); + permission_error_infobar.get_content_area ().add (permission_error_label); + add (permission_error_infobar); + + var grid = new Gtk.Grid (); + grid.margin = 12; + grid.hexpand = true; + grid.column_spacing = 12; + add (grid); + process_info_header = new ProcessInfoHeader(); - attach (process_info_header, 0, 0, 1, 1); + grid.attach (process_info_header, 0, 0, 1, 1); var sep = new Gtk.Separator(Gtk.Orientation.HORIZONTAL); sep.margin = 12; - attach (sep, 0, 1, 1, 1); + grid.attach (sep, 0, 1, 1, 1); process_info_cpu_ram = new ProcessInfoCPURAM (); - - attach (process_info_cpu_ram, 0, 2, 1, 1); + grid.attach (process_info_cpu_ram, 0, 2, 1, 1); process_info_io_stats = new ProcessInfoIOStats (); - attach (process_info_io_stats, 0, 4, 1, 1); + grid.attach (process_info_io_stats, 0, 4, 1, 1); var process_action_bar = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); @@ -85,10 +102,14 @@ public class Monitor.ProcessInfoView : Gtk.Grid { }); }); - attach (preventor, 0, 5, 1, 1); - - + grid.attach (preventor, 0, 5, 1, 1); + } + private void show_permission_error_infobar (string error) { + if (permission_error_infobar.revealed == false) { + permission_error_label.set_text (error); + permission_error_infobar.revealed = true; + } } public void update () { @@ -96,10 +117,6 @@ public class Monitor.ProcessInfoView : Gtk.Grid { process_info_header.update (process); process_info_cpu_ram.update (process); process_info_io_stats.update (process); - } } - - - } \ No newline at end of file From 4f803dfdafdfc0f46f618e9239fd1dd96317cfe1 Mon Sep 17 00:00:00 2001 From: stsdc Date: Wed, 1 Apr 2020 23:12:14 +0200 Subject: [PATCH 80/96] remove `deleted` from file path --- .../ProcessView/ProcessInfoView/OpenFilesListBox.vala | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala b/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala index 99d4e8ca..e84eb101 100644 --- a/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala +++ b/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala @@ -26,8 +26,6 @@ public class Monitor.OpenFilesListBox : Gtk.ScrolledWindow { // display only real paths // probably should be done in process class if (path.substring(0, 1) == "/") { - - // TODO: remove `(deleted)` at the end of the path if deleted ofc var row = new OpenFilesListBoxRow (path, path.contains("(deleted)")); listbox.add (row); } @@ -43,7 +41,8 @@ public class Monitor.OpenFilesListBoxRow : Gtk.ListBoxRow { get_style_context ().add_class ("open_files_list_box_row"); } - public OpenFilesListBoxRow (string text, bool is_deleted) { + public OpenFilesListBoxRow (string _text, bool is_deleted) { + var text = _text; var grid = new Gtk.Grid (); grid.column_spacing = 2; @@ -55,12 +54,12 @@ public class Monitor.OpenFilesListBoxRow : Gtk.ListBoxRow { if (is_deleted) { icon.gicon = new ThemedIcon ("edit-delete-symbolic"); icon.tooltip_text = _("Deleted"); + text = text.replace ("(deleted)", ""); } + grid.attach (icon, 0, 0, 1, 1); - debug (text); - Gtk.Label label = new Gtk.Label (text); label.halign = Gtk.Align.START; grid.attach (label, 1, 0, 1, 1); From 307fd5f691419035b539d43df542ab5dd6d2e276 Mon Sep 17 00:00:00 2001 From: stsdc Date: Fri, 3 Apr 2020 00:57:40 +0200 Subject: [PATCH 81/96] add live-chart as dependency --- meson.build | 5 +++++ subprojects/live-chart | 1 + subprojects/live-chart.wrap | 3 +++ 3 files changed, 9 insertions(+) create mode 160000 subprojects/live-chart create mode 100644 subprojects/live-chart.wrap diff --git a/meson.build b/meson.build index 98d71b58..738e8d3a 100644 --- a/meson.build +++ b/meson.build @@ -5,12 +5,16 @@ project('com.github.stsdc.monitor', 'vala', 'c', version: '0.7.0') gnome = import('gnome') i18n = import('i18n') + # common dirs prefix = get_option('prefix') datadir = join_paths(prefix, get_option('datadir')) libdir = join_paths(prefix, get_option('libdir')) icondir = join_paths(datadir, 'icons', 'hicolor') +livechart_proj = subproject('live-chart') +livechart_dep = livechart_proj.get_variable('livechart_dep') + # and these are project dependencies glib = dependency('glib-2.0') granite = dependency('granite', version: '>= 5.2.0') @@ -111,6 +115,7 @@ executable( wnck, gdk_x11, dazzle, + livechart_dep, meson.get_compiler('c').find_library('m', required : false), meson.get_compiler('vala').find_library('posix') ], diff --git a/subprojects/live-chart b/subprojects/live-chart new file mode 160000 index 00000000..c25ccd54 --- /dev/null +++ b/subprojects/live-chart @@ -0,0 +1 @@ +Subproject commit c25ccd5405df2e458b1260012212f48a705d1648 diff --git a/subprojects/live-chart.wrap b/subprojects/live-chart.wrap new file mode 100644 index 00000000..aa29f7e5 --- /dev/null +++ b/subprojects/live-chart.wrap @@ -0,0 +1,3 @@ +[wrap-git] +url = https://github.com/lcallarec/live-chart.git +revision = head From dbec150957aececad98cbf6b022d34278e9b63e8 Mon Sep 17 00:00:00 2001 From: stsdc Date: Fri, 3 Apr 2020 01:13:37 +0200 Subject: [PATCH 82/96] add test chart; display process cpu usage --- .../ProcessInfoView/ProcessInfoView.vala | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index 0d34dcee..55f68e31 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -27,6 +27,9 @@ public class Monitor.ProcessInfoView : Gtk.Box { private ProcessInfoHeader process_info_header; private ProcessInfoIOStats process_info_io_stats; private ProcessInfoCPURAM process_info_cpu_ram; + + private LiveChart.Chart cpu_chart; + private LiveChart.Serie cpu_serie; private Regex ? regex; private Gtk.Grid grid; @@ -103,6 +106,23 @@ public class Monitor.ProcessInfoView : Gtk.Box { }); grid.attach (preventor, 0, 5, 1, 1); + + + cpu_serie = new LiveChart.Serie("CPU 1 usage", new LiveChart.SmoothLineArea()); + cpu_serie.set_main_color({ 0.35, 0.8, 0.1, 1.0}); + + var config = new LiveChart.Config(); + config.y_axis.unit = "%"; + config.y_axis.tick_interval = 25; + config.y_axis.fixed_max = LiveChart.cap(96); + + cpu_chart = new LiveChart.Chart(config); + cpu_chart.vexpand = true; + + add (cpu_chart); + + cpu_chart.add_serie(cpu_serie); + } private void show_permission_error_infobar (string error) { @@ -117,6 +137,9 @@ public class Monitor.ProcessInfoView : Gtk.Box { process_info_header.update (process); process_info_cpu_ram.update (process); process_info_io_stats.update (process); + + cpu_chart.add_value(cpu_serie, process.cpu_percentage); + } } } \ No newline at end of file From 26f662350123664d652e4f07c1cf6eeaa13e1187 Mon Sep 17 00:00:00 2001 From: stsdc Date: Sun, 5 Apr 2020 00:52:35 +0200 Subject: [PATCH 83/96] move live chart to deparate class --- meson.build | 1 + .../ProcessView/ProcessInfoView/Chart.vala | 31 +++++++++++++++++++ .../ProcessInfoView/ProcessInfoView.vala | 19 ++---------- 3 files changed, 35 insertions(+), 16 deletions(-) create mode 100644 src/Views/ProcessView/ProcessInfoView/Chart.vala diff --git a/meson.build b/meson.build index 738e8d3a..1bc90452 100644 --- a/meson.build +++ b/meson.build @@ -72,6 +72,7 @@ executable( 'src/Views/ProcessView/ProcessInfoView/Preventor.vala', 'src/Views/ProcessView/ProcessInfoView/RoundyLabel.vala', 'src/Views/ProcessView/ProcessInfoView/Graph.vala', + 'src/Views/ProcessView/ProcessInfoView/Chart.vala', 'src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala', 'src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala', 'src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala', diff --git a/src/Views/ProcessView/ProcessInfoView/Chart.vala b/src/Views/ProcessView/ProcessInfoView/Chart.vala new file mode 100644 index 00000000..18f73a9d --- /dev/null +++ b/src/Views/ProcessView/ProcessInfoView/Chart.vala @@ -0,0 +1,31 @@ +public class Monitor.Chart : Gtk.Box + { + private LiveChart.Serie serie; + private LiveChart.Chart chart; + private LiveChart.Config config; + + + construct { + vexpand = true; + + config = new LiveChart.Config(); + config.y_axis.unit = "%"; + config.y_axis.tick_interval = 25; + config.y_axis.fixed_max = 100.0; + + chart = new LiveChart.Chart (config); + chart.expand = true; + chart.background.main_color = Gdk.RGBA() {red= 1, green= 1, blue= 1, alpha= 1}; //White background + + serie = new LiveChart.Serie("CPU 1 usage", new LiveChart.SmoothLineArea()); + serie.set_main_color({ 0.35, 0.8, 0.1, 1.0}); + + chart.add_serie(serie); + + add (chart); + } + + public void update (double value) { + chart.add_value(serie, value); + } + } diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index 55f68e31..d01f84f5 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -28,8 +28,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { private ProcessInfoIOStats process_info_io_stats; private ProcessInfoCPURAM process_info_cpu_ram; - private LiveChart.Chart cpu_chart; - private LiveChart.Serie cpu_serie; + private Chart cpu_chart; private Regex ? regex; private Gtk.Grid grid; @@ -108,21 +107,9 @@ public class Monitor.ProcessInfoView : Gtk.Box { grid.attach (preventor, 0, 5, 1, 1); - cpu_serie = new LiveChart.Serie("CPU 1 usage", new LiveChart.SmoothLineArea()); - cpu_serie.set_main_color({ 0.35, 0.8, 0.1, 1.0}); - - var config = new LiveChart.Config(); - config.y_axis.unit = "%"; - config.y_axis.tick_interval = 25; - config.y_axis.fixed_max = LiveChart.cap(96); - - cpu_chart = new LiveChart.Chart(config); - cpu_chart.vexpand = true; + cpu_chart = new Chart (); add (cpu_chart); - - cpu_chart.add_serie(cpu_serie); - } private void show_permission_error_infobar (string error) { @@ -138,7 +125,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { process_info_cpu_ram.update (process); process_info_io_stats.update (process); - cpu_chart.add_value(cpu_serie, process.cpu_percentage); + cpu_chart.update(process.cpu_percentage); } } From 7315b9d9309122107f45f6e1dc690b7047e92791 Mon Sep 17 00:00:00 2001 From: stsdc Date: Tue, 7 Apr 2020 00:32:32 +0200 Subject: [PATCH 84/96] replace libdazzle with live-chart --- meson.build | 4 -- src/Models/GraphModel.vala | 20 ------ .../ProcessView/ProcessInfoView/Chart.vala | 72 +++++++++++-------- .../ProcessView/ProcessInfoView/Graph.vala | 23 ------ .../ProcessInfoView/ProcessInfoCPURAM.vala | 30 ++++---- .../ProcessInfoView/ProcessInfoView.vala | 4 -- subprojects/live-chart | 2 +- 7 files changed, 57 insertions(+), 98 deletions(-) delete mode 100644 src/Models/GraphModel.vala delete mode 100644 src/Views/ProcessView/ProcessInfoView/Graph.vala diff --git a/meson.build b/meson.build index 1bc90452..6c9f6690 100644 --- a/meson.build +++ b/meson.build @@ -27,7 +27,6 @@ gtop = dependency('libgtop-2.0') wnck = dependency('libwnck-3.0') wingpanel = dependency('wingpanel-2.0') gdk_x11 = dependency('gdk-x11-3.0') -dazzle = dependency('libdazzle-1.0', version: '>= 3.30') config_data = configuration_data() config_data.set_quoted('GETTEXT_PACKAGE', meson.project_name()) @@ -71,7 +70,6 @@ executable( # Widgets related only to ProcessInfoView 'src/Views/ProcessView/ProcessInfoView/Preventor.vala', 'src/Views/ProcessView/ProcessInfoView/RoundyLabel.vala', - 'src/Views/ProcessView/ProcessInfoView/Graph.vala', 'src/Views/ProcessView/ProcessInfoView/Chart.vala', 'src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala', 'src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala', @@ -86,7 +84,6 @@ executable( # Models 'src/Models/TreeViewModel.vala', - 'src/Models/GraphModel.vala', # Other 'src/Managers/AppManager.vala', @@ -115,7 +112,6 @@ executable( gtop, wnck, gdk_x11, - dazzle, livechart_dep, meson.get_compiler('c').find_library('m', required : false), meson.get_compiler('vala').find_library('posix') diff --git a/src/Models/GraphModel.vala b/src/Models/GraphModel.vala deleted file mode 100644 index d0957360..00000000 --- a/src/Models/GraphModel.vala +++ /dev/null @@ -1,20 +0,0 @@ -public class Monitor.GraphModel : Dazzle.GraphModel { - - public GraphModel () { - set_timespan (TimeSpan.MINUTE); - set_max_samples (60); - - var column_total = new Dazzle.GraphColumn ("CPU USAGE", Type.DOUBLE); - add_column (column_total); - } - - public bool update (double percentage) { - debug ("Got percentage: %f", percentage); - Dazzle.GraphModelIter iter; - - push (out iter, get_monotonic_time ()); - iter_set_value (iter, 0, percentage); - - return true; - } -} diff --git a/src/Views/ProcessView/ProcessInfoView/Chart.vala b/src/Views/ProcessView/ProcessInfoView/Chart.vala index 18f73a9d..9fabbb2b 100644 --- a/src/Views/ProcessView/ProcessInfoView/Chart.vala +++ b/src/Views/ProcessView/ProcessInfoView/Chart.vala @@ -1,31 +1,45 @@ -public class Monitor.Chart : Gtk.Box - { - private LiveChart.Serie serie; - private LiveChart.Chart chart; - private LiveChart.Config config; - - - construct { - vexpand = true; - - config = new LiveChart.Config(); - config.y_axis.unit = "%"; - config.y_axis.tick_interval = 25; - config.y_axis.fixed_max = 100.0; - - chart = new LiveChart.Chart (config); - chart.expand = true; - chart.background.main_color = Gdk.RGBA() {red= 1, green= 1, blue= 1, alpha= 1}; //White background - - serie = new LiveChart.Serie("CPU 1 usage", new LiveChart.SmoothLineArea()); - serie.set_main_color({ 0.35, 0.8, 0.1, 1.0}); - - chart.add_serie(serie); - - add (chart); - } +public class Monitor.Chart : Gtk.Box { + private LiveChart.Serie serie; + private LiveChart.Chart chart; + private LiveChart.Config config; + + + construct { + vexpand = true; + height_request = 60; + + config = new LiveChart.Config (); + config.y_axis.unit = "%"; + config.y_axis.tick_interval = 25; + config.y_axis.fixed_max = 100.0; + config.y_axis.labels.visible = false; + config.x_axis.labels.visible = false; + + config.padding = LiveChart.Padding () { + smart = LiveChart.AutoPadding.NONE, + top = 0, + right = 0, + bottom = 0, + left = 0 + }; + + chart = new LiveChart.Chart (config); + chart.expand = true; + chart.legend.visible = false; + chart.grid.visible = false; + chart.background.main_color = Gdk.RGBA () { + red= 1, green= 1, blue= 1, alpha= 1 + }; //White background + + serie = new LiveChart.Serie ("CPU 1 usage", new LiveChart.SmoothLineArea ()); + serie.set_main_color ({ 0.35, 0.8, 0.1, 1.0}); + + chart.add_serie (serie); + + add (chart); + } - public void update (double value) { - chart.add_value(serie, value); - } + public void update (double value) { + chart.add_value (serie, value); } +} diff --git a/src/Views/ProcessView/ProcessInfoView/Graph.vala b/src/Views/ProcessView/ProcessInfoView/Graph.vala deleted file mode 100644 index 544fb209..00000000 --- a/src/Views/ProcessView/ProcessInfoView/Graph.vala +++ /dev/null @@ -1,23 +0,0 @@ -public class Monitor.Graph : Dazzle.GraphView - { - private Dazzle.GraphLineRenderer renderer; - - construct { - expand = true; - valign = Gtk.Align.START; - height_request = 60; - - Gdk.RGBA linecol = Gdk.RGBA (); - linecol.red = 1.0; - linecol.green = 0.0; - linecol.blue = 0.0; - linecol.alpha = 1.0; - - renderer = new Dazzle.GraphLineRenderer(); - renderer.stroke_color_rgba = linecol; - renderer.line_width = 1; - renderer.column = 0; - - add_renderer (renderer); - } - } diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala index 95f86490..32bb4ddb 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala @@ -2,11 +2,8 @@ public class Monitor.ProcessInfoCPURAM : Gtk.Grid { private Gtk.Label cpu_label; private Gtk.Label ram_label; - private Graph cpu_graph; - private GraphModel cpu_graph_model; - - private Graph mem_graph; - private GraphModel mem_graph_model; + private Chart cpu_chart; + private Chart ram_chart; construct { column_spacing = 6; @@ -14,17 +11,18 @@ public class Monitor.ProcessInfoCPURAM : Gtk.Grid { vexpand = false; column_homogeneous = true; row_homogeneous = false; + + cpu_chart = new Chart (); + ram_chart = new Chart (); - cpu_graph = new Graph (); - mem_graph = new Graph (); var cpu_graph_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); cpu_graph_box.get_style_context ().add_class ("graph"); - cpu_graph_box.add (cpu_graph); + cpu_graph_box.add (cpu_chart); var mem_graph_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); mem_graph_box.get_style_context ().add_class ("graph"); - mem_graph_box.add (mem_graph); + mem_graph_box.add (ram_chart); cpu_label = new Gtk.Label ("CPU: " + Utils.NO_DATA); cpu_label.get_style_context ().add_class (Granite.STYLE_CLASS_H4_LABEL); @@ -45,18 +43,16 @@ public class Monitor.ProcessInfoCPURAM : Gtk.Grid { cpu_label.set_text (("CPU: %.1f%%").printf (process.cpu_percentage)); ram_label.set_text (("RAM: %.1f%%").printf (process.mem_percentage)); - cpu_graph_model.update (process.cpu_percentage); - cpu_graph.tooltip_text = ("%.1f%%").printf (process.cpu_percentage); + cpu_chart.update(process.cpu_percentage); + ram_chart.update(process.mem_percentage); - mem_graph_model.update (process.mem_percentage); - mem_graph.tooltip_text = ("%.1f%%").printf (process.mem_percentage); } public void clear_graphs () { - cpu_graph_model = new GraphModel (); - cpu_graph.set_model (cpu_graph_model); + // cpu_graph_model = new GraphModel (); + // cpu_graph.set_model (cpu_graph_model); - mem_graph_model = new GraphModel (); - mem_graph.set_model (mem_graph_model); + // mem_graph_model = new GraphModel (); + // mem_graph.set_model (mem_graph_model); } } \ No newline at end of file diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index d01f84f5..e39faa38 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -28,7 +28,6 @@ public class Monitor.ProcessInfoView : Gtk.Box { private ProcessInfoIOStats process_info_io_stats; private ProcessInfoCPURAM process_info_cpu_ram; - private Chart cpu_chart; private Regex ? regex; private Gtk.Grid grid; @@ -107,9 +106,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { grid.attach (preventor, 0, 5, 1, 1); - cpu_chart = new Chart (); - add (cpu_chart); } private void show_permission_error_infobar (string error) { @@ -125,7 +122,6 @@ public class Monitor.ProcessInfoView : Gtk.Box { process_info_cpu_ram.update (process); process_info_io_stats.update (process); - cpu_chart.update(process.cpu_percentage); } } diff --git a/subprojects/live-chart b/subprojects/live-chart index c25ccd54..4bfb0588 160000 --- a/subprojects/live-chart +++ b/subprojects/live-chart @@ -1 +1 @@ -Subproject commit c25ccd5405df2e458b1260012212f48a705d1648 +Subproject commit 4bfb0588157f9bfa8ad660db361b5ab5e9aeff1b From 5bd4e77f4355197f7334f06ffd4b5e030634c08e Mon Sep 17 00:00:00 2001 From: stsdc Date: Wed, 8 Apr 2020 17:31:52 +0200 Subject: [PATCH 85/96] remove libdazzle from debian control file --- debian/control | 1 - 1 file changed, 1 deletion(-) diff --git a/debian/control b/debian/control index 5bc8d42f..ed40651f 100644 --- a/debian/control +++ b/debian/control @@ -10,7 +10,6 @@ Build-Depends: meson, valac (>= 0.26), libgranite-dev (>= 5.2.0), libbamf3-dev, - libdazzle-1.0 (>= 3.30), libwnck-3-dev, libgtop2-dev, libwingpanel-2.0-dev From d6c0bf611186d3c45b10d5a6ddc4ed7166a4b71f Mon Sep 17 00:00:00 2001 From: stsdc Date: Thu, 9 Apr 2020 16:48:24 +0200 Subject: [PATCH 86/96] rm libdazzle from readme --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 2b34813d..7d8ab0f2 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,6 @@ * libgtk-3-dev * libgranite-dev (>= 5.2.0) * libbamf3-dev -* libdazzle-1.0 (>= 3.30) * libwnck-3-dev * libgtop2-dev * libwingpanel-2.0-dev From 44c53194ec1d06d07eb0c96aa2358e1913bea51c Mon Sep 17 00:00:00 2001 From: stsdc Date: Thu, 9 Apr 2020 22:52:26 +0200 Subject: [PATCH 87/96] clear chart values --- src/Views/ProcessView/ProcessInfoView/Chart.vala | 15 +++++++++++++-- .../ProcessInfoView/ProcessInfoCPURAM.vala | 10 ++++++++++ .../ProcessInfoView/ProcessInfoView.vala | 1 + 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/Views/ProcessView/ProcessInfoView/Chart.vala b/src/Views/ProcessView/ProcessInfoView/Chart.vala index 9fabbb2b..19e62bb3 100644 --- a/src/Views/ProcessView/ProcessInfoView/Chart.vala +++ b/src/Views/ProcessView/ProcessInfoView/Chart.vala @@ -1,5 +1,6 @@ public class Monitor.Chart : Gtk.Box { private LiveChart.Serie serie; + private LiveChart.SmoothLineArea renderer; private LiveChart.Chart chart; private LiveChart.Config config; @@ -7,7 +8,7 @@ public class Monitor.Chart : Gtk.Box { construct { vexpand = true; height_request = 60; - + config = new LiveChart.Config (); config.y_axis.unit = "%"; config.y_axis.tick_interval = 25; @@ -31,7 +32,9 @@ public class Monitor.Chart : Gtk.Box { red= 1, green= 1, blue= 1, alpha= 1 }; //White background - serie = new LiveChart.Serie ("CPU 1 usage", new LiveChart.SmoothLineArea ()); + renderer = new LiveChart.SmoothLineArea (new LiveChart.Values(30)); + + serie = new LiveChart.Serie ("CPU 1 usage", renderer); serie.set_main_color ({ 0.35, 0.8, 0.1, 1.0}); chart.add_serie (serie); @@ -42,4 +45,12 @@ public class Monitor.Chart : Gtk.Box { public void update (double value) { chart.add_value (serie, value); } + + private void set_serie () { + + } + + public void clear () { + renderer.get_values ().clear (); + } } diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala index 32bb4ddb..fc903f98 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala @@ -20,6 +20,8 @@ public class Monitor.ProcessInfoCPURAM : Gtk.Grid { cpu_graph_box.get_style_context ().add_class ("graph"); cpu_graph_box.add (cpu_chart); + + var mem_graph_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); mem_graph_box.get_style_context ().add_class ("graph"); mem_graph_box.add (ram_chart); @@ -39,6 +41,12 @@ public class Monitor.ProcessInfoCPURAM : Gtk.Grid { attach (mem_graph_box, 1, 1, 1, 1); } + public void set_charts_data (Process process) { + foreach (var item in process.cpu_percentage_history) { + cpu_chart.update(item); + } + } + public void update (Process process) { cpu_label.set_text (("CPU: %.1f%%").printf (process.cpu_percentage)); ram_label.set_text (("RAM: %.1f%%").printf (process.mem_percentage)); @@ -49,6 +57,8 @@ public class Monitor.ProcessInfoCPURAM : Gtk.Grid { } public void clear_graphs () { + cpu_chart.clear (); + ram_chart.clear (); // cpu_graph_model = new GraphModel (); // cpu_graph.set_model (cpu_graph_model); diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index e39faa38..4f0b844f 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -12,6 +12,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { process_info_io_stats.update (_process); process_info_cpu_ram.clear_graphs (); + // process_info_cpu_ram.set_charts_data (_process); permission_error_infobar.revealed = false; _process.fd_permission_error.connect (show_permission_error_infobar); From 0c99cb4c9b15ed279001f418fe28a3f28577b5a7 Mon Sep 17 00:00:00 2001 From: stsdc Date: Thu, 9 Apr 2020 23:12:05 +0200 Subject: [PATCH 88/96] load the usage history when new process is selected --- src/Managers/Process.vala | 38 +++++++++++++------ .../ProcessView/ProcessInfoView/Chart.vala | 14 ++++++- .../ProcessInfoView/ProcessInfoCPURAM.vala | 10 +---- .../ProcessInfoView/ProcessInfoView.vala | 2 +- 4 files changed, 43 insertions(+), 21 deletions(-) diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index 2ffd61a5..9edff12c 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -58,6 +58,11 @@ public class Monitor.Process : GLib.Object { private uint64 last_total; + const int history_buffer_size = 30; + public Gee.ArrayList cpu_percentage_history = new Gee.ArrayList(); + public Gee.ArrayList mem_percentage_history = new Gee.ArrayList(); + + // Construct a new process public Process (int _pid) { @@ -133,25 +138,25 @@ public class Monitor.Process : GLib.Object { var splitted_line = line.split (":"); switch (splitted_line[0]) { case "wchar" : - io.wchar = uint64.parse(splitted_line[1]); + io.wchar = uint64.parse (splitted_line[1]); break; case "rchar" : - io.rchar = uint64.parse(splitted_line[1]); + io.rchar = uint64.parse (splitted_line[1]); break; case "syscr" : - io.syscr = uint64.parse(splitted_line[1]); + io.syscr = uint64.parse (splitted_line[1]); break; case "syscw" : - io.syscw = uint64.parse(splitted_line[1]); + io.syscw = uint64.parse (splitted_line[1]); break; case "read_bytes" : - io.read_bytes = uint64.parse(splitted_line[1]); + io.read_bytes = uint64.parse (splitted_line[1]); break; case "write_bytes" : - io.write_bytes = uint64.parse(splitted_line[1]); + io.write_bytes = uint64.parse (splitted_line[1]); break; case "cancelled_write_bytes" : - io.cancelled_write_bytes = uint64.parse(splitted_line[1]); + io.cancelled_write_bytes = uint64.parse (splitted_line[1]); break; default : warning ("Unknown value in /proc/%d/io", stat.pid); @@ -227,20 +232,19 @@ public class Monitor.Process : GLib.Object { try { string directory = "/proc/%d/fd".printf (stat.pid); Dir dir = Dir.open (directory, 0); - string? name = null; + string ? name = null; while ((name = dir.read_name ()) != null) { string path = Path.build_filename (directory, name); if (FileUtils.test (path, FileTest.IS_SYMLINK)) { - string real_path = FileUtils.read_link(path); + string real_path = FileUtils.read_link (path); // debug(content); open_files_paths.add (real_path); } - } } catch (FileError err) { if (err is FileError.ACCES) { - fd_permission_error ( err.message); + fd_permission_error (err.message); } else { error (err.message); } @@ -270,6 +274,12 @@ public class Monitor.Process : GLib.Object { cpu_percentage = 100 * ((double)(proc_time.rtime - cpu_last_used)) / (cpu_total - cpu_last_total); cpu_last_used = proc_time.rtime; + // Making CPU history + if (cpu_percentage_history.size == history_buffer_size) { + cpu_percentage_history.remove_at (0); + } + cpu_percentage_history.add (cpu_percentage); + // Get memory usage by process GTop.Memory mem; GTop.get_mem (out mem); @@ -286,5 +296,11 @@ public class Monitor.Process : GLib.Object { var total_installed_memory = (double)mem.total / 1024; mem_percentage = (mem_usage / total_installed_memory) * 100; + + // Making RAM history + if (mem_percentage_history.size == history_buffer_size) { + mem_percentage_history.remove_at (0); + } + mem_percentage_history.add (mem_percentage); } } diff --git a/src/Views/ProcessView/ProcessInfoView/Chart.vala b/src/Views/ProcessView/ProcessInfoView/Chart.vala index 19e62bb3..5e025988 100644 --- a/src/Views/ProcessView/ProcessInfoView/Chart.vala +++ b/src/Views/ProcessView/ProcessInfoView/Chart.vala @@ -46,8 +46,20 @@ public class Monitor.Chart : Gtk.Box { chart.add_value (serie, value); } - private void set_serie () { + public void set_data (Gee.ArrayList history) { + var refresh_rate_is_ms = 2000; //your own refresh rate in milliseconds + var now = GLib.get_real_time() / 1000; //now in milliseconds + + //the timestamp of the first point + //we are considering that it is "now", but because of your data structure + //it can be between now and now - 2secs), we can't guess + var ts = now - (history.size * refresh_rate_is_ms); + history.foreach((value) => { + renderer.get_values ().add({ts, value}); + ts += refresh_rate_is_ms; + return true; + }); } public void clear () { diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala index fc903f98..2e46157a 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala @@ -42,9 +42,8 @@ public class Monitor.ProcessInfoCPURAM : Gtk.Grid { } public void set_charts_data (Process process) { - foreach (var item in process.cpu_percentage_history) { - cpu_chart.update(item); - } + cpu_chart.set_data (process.cpu_percentage_history); + ram_chart.set_data (process.mem_percentage_history); } public void update (Process process) { @@ -59,10 +58,5 @@ public class Monitor.ProcessInfoCPURAM : Gtk.Grid { public void clear_graphs () { cpu_chart.clear (); ram_chart.clear (); - // cpu_graph_model = new GraphModel (); - // cpu_graph.set_model (cpu_graph_model); - - // mem_graph_model = new GraphModel (); - // mem_graph.set_model (mem_graph_model); } } \ No newline at end of file diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index 4f0b844f..f4a9d3fa 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -12,7 +12,7 @@ public class Monitor.ProcessInfoView : Gtk.Box { process_info_io_stats.update (_process); process_info_cpu_ram.clear_graphs (); - // process_info_cpu_ram.set_charts_data (_process); + process_info_cpu_ram.set_charts_data (_process); permission_error_infobar.revealed = false; _process.fd_permission_error.connect (show_permission_error_infobar); From 41ed1607c3e0853dcd909dfad7165e6fc20112f5 Mon Sep 17 00:00:00 2001 From: stsdc Date: Fri, 10 Apr 2020 16:39:16 +0200 Subject: [PATCH 89/96] fix disconnect signal from null process --- src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index f4a9d3fa..26929c1f 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -5,7 +5,9 @@ public class Monitor.ProcessInfoView : Gtk.Box { set { // remember to disconnect before assigning a new value - _process.fd_permission_error.disconnect (show_permission_error_infobar); + if (_process != null) { + _process.fd_permission_error.disconnect (show_permission_error_infobar); + } _process = value; process_info_header.update (_process); From 7d5ff11c5d771f48f4e081734a02192f1c3dffd2 Mon Sep 17 00:00:00 2001 From: stsdc Date: Sat, 11 Apr 2020 16:24:27 +0200 Subject: [PATCH 90/96] replaces trash bin with file-deleted icon #156 --- data/icons/file-deleted-symbolic.svg | 97 +++++++++++++++++++ data/icons/icons.indicator.gresource.xml | 1 + .../ProcessInfoView/OpenFilesListBox.vala | 2 +- 3 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 data/icons/file-deleted-symbolic.svg diff --git a/data/icons/file-deleted-symbolic.svg b/data/icons/file-deleted-symbolic.svg new file mode 100644 index 00000000..44b787bd --- /dev/null +++ b/data/icons/file-deleted-symbolic.svg @@ -0,0 +1,97 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/data/icons/icons.indicator.gresource.xml b/data/icons/icons.indicator.gresource.xml index 981a39a9..8f863b06 100644 --- a/data/icons/icons.indicator.gresource.xml +++ b/data/icons/icons.indicator.gresource.xml @@ -4,5 +4,6 @@ cpu-symbolic.svg ram-symbolic.svg swap-symbolic.svg + file-deleted-symbolic.svg \ No newline at end of file diff --git a/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala b/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala index e84eb101..03b17bfd 100644 --- a/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala +++ b/src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala @@ -52,7 +52,7 @@ public class Monitor.OpenFilesListBoxRow : Gtk.ListBoxRow { icon.gicon = new ThemedIcon ("emblem-documents-symbolic"); if (is_deleted) { - icon.gicon = new ThemedIcon ("edit-delete-symbolic"); + icon = new Gtk.Image.from_icon_name ("file-deleted-symbolic", Gtk.IconSize.SMALL_TOOLBAR); icon.tooltip_text = _("Deleted"); text = text.replace ("(deleted)", ""); } From dc4df3ea4b1db07da14874acc00f4caa2f089931 Mon Sep 17 00:00:00 2001 From: stsdc Date: Sat, 11 Apr 2020 19:08:01 +0200 Subject: [PATCH 91/96] rm dazzle vapi --- vapi/qqqq.vapi | 1991 ------------------------------------------------ 1 file changed, 1991 deletions(-) delete mode 100644 vapi/qqqq.vapi diff --git a/vapi/qqqq.vapi b/vapi/qqqq.vapi deleted file mode 100644 index 84a748b3..00000000 --- a/vapi/qqqq.vapi +++ /dev/null @@ -1,1991 +0,0 @@ -/* libdazzle-1.0.vapi generated by vapigen, do not modify. */ - -[CCode (cprefix = "Dzl", gir_namespace = "Dazzle", gir_version = "1.0", lower_case_cprefix = "dzl_")] -namespace Dazzle { - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_animation_get_type ()")] - public class Animation : GLib.InitiallyUnowned { - [CCode (has_construct_function = false)] - protected Animation (); - public void add_property (GLib.ParamSpec pspec, GLib.Value value); - public static uint calculate_duration (Gdk.Monitor monitor, double from_value, double to_value); - public void start (); - public void stop (); - [NoAccessorMethod] - public uint duration { construct; } - [NoAccessorMethod] - public Gdk.FrameClock frame_clock { construct; } - [NoAccessorMethod] - public Dazzle.AnimationMode mode { construct; } - [NoAccessorMethod] - public GLib.Object target { construct; } - public signal void tick (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_application_get_type ()")] - public class Application : Gtk.Application, GLib.ActionGroup, GLib.ActionMap { - [CCode (has_construct_function = false)] - protected Application (); - public virtual void add_resources (string resource_path); - public unowned GLib.Menu get_menu_by_id (string menu_id); - public unowned Dazzle.MenuManager get_menu_manager (); - public unowned Dazzle.ShortcutManager get_shortcut_manager (); - public unowned Dazzle.ThemeManager get_theme_manager (); - public virtual void remove_resources (string resource_path); - public Dazzle.MenuManager menu_manager { get; } - public Dazzle.ShortcutManager shortcut_manager { get; } - public Dazzle.ThemeManager theme_manager { get; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_application_window_get_type ()")] - public class ApplicationWindow : Gtk.ApplicationWindow, Atk.Implementor, GLib.ActionGroup, GLib.ActionMap, Gtk.Buildable { - [CCode (has_construct_function = false)] - protected ApplicationWindow (); - [Version (since = "3.26")] - public virtual bool get_fullscreen (); - [Version (since = "3.26")] - public unowned Gtk.Widget get_titlebar (); - [Version (since = "3.26")] - public virtual void set_fullscreen (bool fullscreen); - [Version (since = "3.26")] - public void set_titlebar (Gtk.Widget titlebar); - public bool fullscreen { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_bin_get_type ()")] - public class Bin : Gtk.Bin, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public Bin (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_binding_group_get_type ()")] - public class BindingGroup : GLib.Object { - [CCode (has_construct_function = false)] - public BindingGroup (); - public void bind (string source_property, GLib.Object target, string target_property, GLib.BindingFlags flags); - public void bind_full (string source_property, GLib.Object target, string target_property, GLib.BindingFlags flags, GLib.BindingTransformFunc? transform_to, owned GLib.BindingTransformFunc? transform_from); - public void bind_with_closures (string source_property, GLib.Object target, string target_property, GLib.BindingFlags flags, GLib.Closure? transform_to, GLib.Closure? transform_from); - public unowned GLib.Object? get_source (); - public void set_source (GLib.Object? source); - public GLib.Object source { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_bolding_label_get_type ()")] - public class BoldingLabel : Gtk.Label, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false)] - protected BoldingLabel (); - public void set_bold (bool bold); - public void set_weight (Pango.Weight weight); - public bool bold { set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_box_get_type ()")] - public class Box : Gtk.Box, Atk.Implementor, Gtk.Buildable, Gtk.Orientable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public Box (); - public int get_max_width_request (); - public unowned Gtk.Widget? get_nth_child (uint nth); - public void set_max_width_request (int max_width_request); - public int max_width_request { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_box_theatric_get_type ()")] - public class BoxTheatric : GLib.Object { - [CCode (has_construct_function = false)] - protected BoxTheatric (); - [NoAccessorMethod] - public double alpha { get; set; } - [NoAccessorMethod] - public string background { owned get; set; } - [NoAccessorMethod] - public int height { get; set; } - [NoAccessorMethod] - public GLib.Icon icon { owned get; set; } - [NoAccessorMethod] - public void* surface { construct; } - [NoAccessorMethod] - public Gtk.Widget target { owned get; construct; } - [NoAccessorMethod] - public int width { get; set; } - [NoAccessorMethod] - public int x { get; set; } - [NoAccessorMethod] - public int y { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_centering_bin_get_type ()")] - public class CenteringBin : Gtk.Bin, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public CenteringBin (); - [NoAccessorMethod] - public int max_width_request { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_child_property_action_get_type ()")] - public class ChildPropertyAction : GLib.Object, GLib.Action { - [CCode (has_construct_function = false)] - protected ChildPropertyAction (); - public static GLib.Action @new (string name, Gtk.Container container, Gtk.Widget child, string child_property_name); - [NoAccessorMethod] - public Gtk.Widget child { owned get; } - [NoAccessorMethod] - public string child_property_name { owned get; } - [NoAccessorMethod] - public Gtk.Container container { owned get; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_column_layout_get_type ()")] - public class ColumnLayout : Gtk.Container, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public ColumnLayout (); - public int get_column_spacing (); - public int get_column_width (); - public uint get_max_columns (); - public int get_row_spacing (); - public void set_column_spacing (int column_spacing); - public void set_column_width (int column_width); - public void set_max_columns (uint max_columns); - public void set_row_spacing (int row_spacing); - public int column_spacing { get; set; } - public int column_width { get; set; } - public uint max_columns { get; set; } - public int row_spacing { get; set; } - } - [CCode (cheader_filename = "dazzle.h", ref_function = "dzl_counter_arena_ref", type_id = "dzl_counter_arena_get_type ()", unref_function = "dzl_counter_arena_unref")] - [Compact] - public class CounterArena { - [CCode (has_construct_function = false)] - public CounterArena.for_pid (GLib.Pid pid); - public void @foreach (Dazzle.CounterForeachFunc func); - [CCode (cheader_filename = "dazzle.h")] - public static Dazzle.CounterArena get_default (); - public Dazzle.CounterArena @ref (); - public void register (Dazzle.Counter counter); - public void unref (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_counters_window_get_type ()")] - public class CountersWindow : Gtk.Window, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public CountersWindow (); - public unowned Dazzle.CounterArena? get_arena (); - public void set_arena (Dazzle.CounterArena arena); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_cpu_graph_get_type ()")] - public class CpuGraph : Dazzle.GraphView, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false)] - protected CpuGraph (); - [CCode (has_construct_function = false, type = "GtkWidget*")] - public CpuGraph.full (int64 timespan, uint max_samples); - [NoAccessorMethod] - public uint max_samples { get; construct; } - [NoAccessorMethod] - public int64 timespan { get; construct; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_cpu_model_get_type ()")] - public class CpuModel : Dazzle.GraphModel { - [CCode (has_construct_function = false, type = "DzlGraphModel*")] - public CpuModel (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_css_provider_get_type ()")] - public class CssProvider : Gtk.CssProvider, Gtk.StyleProvider { - [CCode (has_construct_function = false, type = "GtkCssProvider*")] - public CssProvider (string base_path); - [NoAccessorMethod] - public string base_path { owned get; construct; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_directory_model_get_type ()")] - public class DirectoryModel : GLib.Object, GLib.ListModel { - [CCode (has_construct_function = false)] - protected DirectoryModel (); - public unowned GLib.File get_directory (); - public static GLib.ListModel @new (GLib.File directory); - public void set_directory (GLib.File directory); - public void set_visible_func (owned Dazzle.DirectoryModelVisibleFunc visible_func); - public GLib.File directory { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_directory_reaper_get_type ()")] - public class DirectoryReaper : GLib.Object { - [CCode (has_construct_function = false)] - public DirectoryReaper (); - public void add_directory (GLib.File directory, GLib.TimeSpan min_age); - public void add_file (GLib.File file, GLib.TimeSpan min_age); - public void add_glob (GLib.File directory, string glob, GLib.TimeSpan min_age); - public bool execute (GLib.Cancellable? cancellable = null) throws GLib.Error; - public async bool execute_async (GLib.Cancellable? cancellable = null) throws GLib.Error; - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_dock_bin_get_type ()")] - public class DockBin : Gtk.Container, Atk.Implementor, Dazzle.Dock, Dazzle.DockItem, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public DockBin (); - public unowned Gtk.Widget get_bottom_edge (); - public unowned Gtk.Widget? get_center_widget (); - public unowned Gtk.Widget get_left_edge (); - public unowned Gtk.Widget get_right_edge (); - public unowned Gtk.Widget get_top_edge (); - [NoAccessorMethod] - public bool bottom_visible { get; set; } - [NoAccessorMethod] - public bool left_visible { get; set; } - [NoAccessorMethod] - public bool right_visible { get; set; } - [NoAccessorMethod] - public bool top_visible { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_dock_bin_edge_get_type ()")] - public class DockBinEdge : Dazzle.DockRevealer, Atk.Implementor, Dazzle.DockItem, Gtk.Buildable { - [CCode (has_construct_function = false)] - protected DockBinEdge (); - public Gtk.PositionType get_edge (); - [NoAccessorMethod] - public Gtk.PositionType edge { get; set; } - public virtual signal void move_to_bin_child (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_dock_manager_get_type ()")] - public class DockManager : GLib.Object { - [CCode (has_construct_function = false)] - public DockManager (); - [Version (since = "3.26")] - public void pause_grabs (); - public void release_transient_grab (); - [Version (since = "3.26")] - public void unpause_grabs (); - [HasEmitter] - public virtual signal void register_dock (Dazzle.Dock dock); - [HasEmitter] - public virtual signal void unregister_dock (Dazzle.Dock dock); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_dock_overlay_get_type ()")] - public class DockOverlay : Gtk.EventBox, Atk.Implementor, Dazzle.Dock, Dazzle.DockItem, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public DockOverlay (); - public unowned Dazzle.DockOverlayEdge get_edge (Gtk.PositionType position); - public unowned Gtk.Adjustment get_edge_adjustment (Gtk.PositionType position); - public virtual signal void hide_edges (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_dock_overlay_edge_get_type ()")] - public class DockOverlayEdge : Dazzle.Bin, Atk.Implementor, Dazzle.DockItem, Gtk.Buildable { - [CCode (has_construct_function = false)] - protected DockOverlayEdge (); - public Gtk.PositionType get_edge (); - public int get_position (); - public void set_edge (Gtk.PositionType edge); - public void set_position (int position); - public Gtk.PositionType edge { get; set; } - public int position { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_dock_paned_get_type ()")] - public class DockPaned : Dazzle.MultiPaned, Atk.Implementor, Dazzle.DockItem, Gtk.Buildable, Gtk.Orientable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public DockPaned (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_dock_revealer_get_type ()")] - public class DockRevealer : Dazzle.Bin, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public DockRevealer (); - public void animate_to_position (int position, uint transition_duration); - public bool get_child_revealed (); - public int get_position (); - public bool get_position_set (); - public bool get_reveal_child (); - public uint get_transition_duration (); - public Dazzle.DockRevealerTransitionType get_transition_type (); - public bool is_animating (); - public void set_position (int position); - public void set_position_set (bool position_set); - public void set_reveal_child (bool reveal_child); - public void set_transition_duration (uint transition_duration); - public void set_transition_type (Dazzle.DockRevealerTransitionType transition_type); - public bool child_revealed { get; } - public int position { get; set; } - public bool position_set { get; set; } - public bool reveal_child { get; set; } - public uint transition_duration { get; set; } - public Dazzle.DockRevealerTransitionType transition_type { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_dock_stack_get_type ()")] - public class DockStack : Gtk.Box, Atk.Implementor, Dazzle.DockItem, Gtk.Buildable, Gtk.Orientable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public DockStack (); - public Gtk.PositionType get_edge (); - public bool get_show_pinned_button (); - public Dazzle.TabStyle get_style (); - public void set_edge (Gtk.PositionType edge); - public void set_show_pinned_button (bool show_pinned_button); - public void set_style (Dazzle.TabStyle style); - public Gtk.PositionType edge { get; set; } - public bool show_pinned_button { get; set; } - public Dazzle.TabStyle style { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_dock_transient_grab_get_type ()")] - public class DockTransientGrab : GLib.Object { - [CCode (has_construct_function = false)] - public DockTransientGrab (); - public void acquire (); - public void add_item (Dazzle.DockItem item); - public void cancel (); - public bool contains (Dazzle.DockItem item); - public uint get_timeout (); - public bool is_descendant (Gtk.Widget widget); - public void release (); - public void remove_item (Dazzle.DockItem item); - public void set_timeout (uint timeout); - public void steal_common_ancestors (Dazzle.DockTransientGrab other); - public uint timeout { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_dock_widget_get_type ()")] - public class DockWidget : Dazzle.Bin, Atk.Implementor, Dazzle.DockItem, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public DockWidget (); - public void set_icon_name (string icon_name); - public void set_title (string title); - [NoAccessorMethod] - public bool can_close { get; set; } - [NoAccessorMethod] - public string icon_name { owned get; set; } - [NoAccessorMethod] - public Dazzle.DockManager manager { owned get; set; } - [NoAccessorMethod] - public string title { owned get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_dock_window_get_type ()")] - public class DockWindow : Gtk.Window, Atk.Implementor, Dazzle.Dock, Dazzle.DockItem, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public DockWindow (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_elastic_bin_get_type ()")] - public class ElasticBin : Gtk.Bin, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public ElasticBin (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_empty_state_get_type ()")] - public class EmptyState : Gtk.Bin, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public EmptyState (); - public unowned string get_icon_name (); - public unowned string get_subtitle (); - public unowned string get_title (); - public void set_icon_name (string icon_name); - public void set_resource (string resource); - public void set_subtitle (string title); - public void set_title (string title); - public string icon_name { get; set; } - [NoAccessorMethod] - public int pixel_size { get; set; } - public string resource { set; } - public string subtitle { get; set; } - public string title { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_entry_box_get_type ()")] - public class EntryBox : Gtk.Box, Atk.Implementor, Gtk.Buildable, Gtk.Orientable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public EntryBox (); - [NoAccessorMethod] - public int max_width_chars { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_file_chooser_entry_get_type ()")] - public class FileChooserEntry : Gtk.Bin, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public FileChooserEntry (string title, Gtk.FileChooserAction action); - public GLib.File? get_file (); - public void set_file (GLib.File file); - [NoAccessorMethod] - public Gtk.FileChooserAction action { get; set; } - [NoAccessorMethod] - public bool create_folders { get; set; } - [NoAccessorMethod] - public bool do_overwrite_confirmation { get; set; } - public GLib.File file { owned get; set; } - [NoAccessorMethod] - public Gtk.FileFilter filter { owned get; set; } - [NoAccessorMethod] - public bool local_only { get; set; } - [NoAccessorMethod] - public int max_width_chars { get; set; } - [NoAccessorMethod] - public bool show_hidden { get; set; } - [NoAccessorMethod] - public string title { owned get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_file_transfer_get_type ()")] - public class FileTransfer : GLib.Object { - [CCode (has_construct_function = false)] - public FileTransfer (); - public void add (GLib.File src, GLib.File dest); - public bool execute (int io_priority = GLib.Priority.LOW, GLib.Cancellable? cancellable = null) throws GLib.Error; - public async bool execute_async (int io_priority = GLib.Priority.LOW, GLib.Cancellable? cancellable = null) throws GLib.Error; - public Dazzle.FileTransferFlags get_flags (); - public double get_progress (); - public void set_flags (Dazzle.FileTransferFlags flags); - [Version (since = "3.28")] - public Dazzle.FileTransferStat stat (); - public Dazzle.FileTransferFlags flags { get; set; } - public double progress { get; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_fuzzy_index_get_type ()")] - public class FuzzyIndex : GLib.Object { - [CCode (has_construct_function = false)] - public FuzzyIndex (); - public GLib.Variant? get_metadata (string key); - public unowned string get_metadata_string (string key); - public uint32 get_metadata_uint32 (string key); - public uint64 get_metadata_uint64 (string key); - public bool load_file (GLib.File file, GLib.Cancellable? cancellable = null) throws GLib.Error; - public async bool load_file_async (GLib.File file, GLib.Cancellable? cancellable = null) throws GLib.Error; - public async GLib.ListModel query_async (string query, uint max_matches, GLib.Cancellable? cancellable = null) throws GLib.Error; - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_fuzzy_index_builder_get_type ()")] - public class FuzzyIndexBuilder : GLib.Object { - [CCode (has_construct_function = false)] - public FuzzyIndexBuilder (); - public bool get_case_sensitive (); - public unowned GLib.Variant get_document (uint64 document_id); - public uint64 insert (string key, GLib.Variant document, uint priority); - public void set_case_sensitive (bool case_sensitive); - public void set_metadata (string key, GLib.Variant value); - public void set_metadata_string (string key, string value); - public void set_metadata_uint32 (string key, uint32 value); - public void set_metadata_uint64 (string key, uint64 value); - public bool write (GLib.File file, int io_priority = GLib.Priority.LOW, GLib.Cancellable? cancellable = null) throws GLib.Error; - public async bool write_async (GLib.File file, int io_priority = GLib.Priority.LOW, GLib.Cancellable? cancellable = null) throws GLib.Error; - public bool case_sensitive { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_fuzzy_index_cursor_get_type ()")] - public class FuzzyIndexCursor : GLib.Object, GLib.AsyncInitable, GLib.ListModel { - [CCode (has_construct_function = false)] - protected FuzzyIndexCursor (); - public unowned Dazzle.FuzzyIndex get_index (); - [NoAccessorMethod] - public bool case_sensitive { get; construct; } - [NoAccessorMethod] - public Dazzle.FuzzyIndex index { construct; } - [NoAccessorMethod] - public uint max_matches { get; construct; } - [NoAccessorMethod] - public string query { owned get; construct; } - [NoAccessorMethod] - public GLib.VariantDict tables { construct; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_fuzzy_index_match_get_type ()")] - public class FuzzyIndexMatch : GLib.Object { - [CCode (has_construct_function = false)] - protected FuzzyIndexMatch (); - public unowned GLib.Variant get_document (); - public unowned string get_key (); - public uint get_priority (); - public float get_score (); - public GLib.Variant document { get; construct; } - public string key { get; construct; } - public uint priority { get; construct; } - public float score { get; construct; } - } - [CCode (cheader_filename = "dazzle.h", ref_function = "dzl_fuzzy_mutable_index_ref", type_id = "dzl_fuzzy_mutable_index_get_type ()", unref_function = "dzl_fuzzy_mutable_index_unref")] - [Compact] - public class FuzzyMutableIndex { - [CCode (has_construct_function = false)] - public FuzzyMutableIndex (bool case_sensitive); - public void begin_bulk_insert (); - public bool contains (string key); - public void end_bulk_insert (); - public void insert (string key, void* value); - public GLib.Array match (string needle, size_t max_matches); - public Dazzle.FuzzyMutableIndex @ref (); - public void remove (string key); - public void set_free_func (GLib.DestroyNotify free_func); - public void unref (); - [CCode (has_construct_function = false)] - public FuzzyMutableIndex.with_free_func (bool case_sensitive, GLib.DestroyNotify free_func); - } - [CCode (cheader_filename = "dazzle.h", lower_case_csuffix = "graph_view_column", type_id = "dzl_graph_view_column_get_type ()")] - public class GraphColumn : GLib.Object { - [CCode (has_construct_function = false)] - public GraphColumn (string name, GLib.Type value_type); - public unowned string get_name (); - public void set_name (string name); - public string name { get; set; } - [NoAccessorMethod] - public GLib.Type value_type { get; construct; } - } - [CCode (cheader_filename = "dazzle.h", lower_case_csuffix = "graph_view_line_renderer", type_id = "dzl_graph_view_line_renderer_get_type ()")] - public class GraphLineRenderer : GLib.Object, Dazzle.GraphRenderer { - [CCode (has_construct_function = false)] - public GraphLineRenderer (); - public unowned Gdk.RGBA? get_stroke_color_rgba (); - public void set_stroke_color (string stroke_color); - public void set_stroke_color_rgba (Gdk.RGBA stroke_color_rgba); - [NoAccessorMethod] - public uint column { get; set; } - [NoAccessorMethod] - public double line_width { get; set; } - [NoAccessorMethod] - public string stroke_color { owned get; set; } - public Gdk.RGBA stroke_color_rgba { get; set; } - } - [CCode (cheader_filename = "dazzle.h", lower_case_csuffix = "graph_view_model", type_id = "dzl_graph_view_model_get_type ()")] - public class GraphModel : GLib.Object { - [CCode (has_construct_function = false)] - public GraphModel (); - public uint add_column (Dazzle.GraphColumn column); - public int64 get_end_time (); - public bool get_iter_first (Dazzle.GraphModelIter iter); - public bool get_iter_last (Dazzle.GraphModelIter iter); - public uint get_max_samples (); - public uint get_n_columns (); - public GLib.TimeSpan get_timespan (); - public static int64 iter_get_timestamp (Dazzle.GraphModelIter iter); - public static void iter_get_value (Dazzle.GraphModelIter iter, uint column, GLib.Value value); - public static bool iter_next (Dazzle.GraphModelIter iter); - [Version (since = "3.30")] - public static void iter_set_value (Dazzle.GraphModelIter iter, uint column, GLib.Value value); - public void push (out Dazzle.GraphModelIter iter, int64 timestamp); - public void set_max_samples (uint n_rows); - public void set_timespan (GLib.TimeSpan timespan); - public uint max_samples { get; set construct; } - public int64 timespan { get; set construct; } - [NoAccessorMethod] - public double value_max { get; set; } - [NoAccessorMethod] - public double value_min { get; set; } - public signal void changed (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_graph_view_get_type ()")] - public class GraphView : Gtk.DrawingArea, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public GraphView (); - public void add_renderer (Dazzle.GraphRenderer renderer); - public unowned Dazzle.GraphModel? get_model (); - public void set_model (Dazzle.GraphModel model); - public Dazzle.GraphModel model { get; set; } - } - [CCode (cheader_filename = "dazzle.h", ref_function = "dzl_heap_ref", type_id = "dzl_heap_get_type ()", unref_function = "dzl_heap_unref")] - [Compact] - public class Heap { - public weak string data; - public size_t len; - [CCode (has_construct_function = false)] - public Heap (uint element_size, [CCode (scope = "async")] GLib.CompareFunc compare_func); - public bool extract (void* result); - public bool extract_index (size_t index_, void* result); - public void insert_vals (void* data, uint len); - public Dazzle.Heap @ref (); - public void unref (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_joined_menu_get_type ()")] - public class JoinedMenu : GLib.MenuModel { - [CCode (has_construct_function = false)] - public JoinedMenu (); - public void append_menu (GLib.MenuModel model); - public uint get_n_joined (); - public void prepend_menu (GLib.MenuModel model); - public void remove_index (uint index); - public void remove_menu (GLib.MenuModel model); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_list_box_get_type ()")] - public class ListBox : Gtk.ListBox, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public ListBox (GLib.Type row_type, string property_name); - public unowned GLib.ListModel? get_model (); - public unowned string get_property_name (); - public GLib.Type get_row_type (); - public void set_model (GLib.ListModel model); - [Version (since = "3.28")] - public void set_recycle_max (uint recycle_max); - public string property_name { get; construct; } - public GLib.Type row_type { get; construct; } - [NoAccessorMethod] - public string row_type_name { construct; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_list_box_row_get_type ()")] - public abstract class ListBoxRow : Gtk.ListBoxRow, Atk.Implementor, Gtk.Actionable, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public ListBoxRow (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_list_model_filter_get_type ()")] - public class ListModelFilter : GLib.Object, GLib.ListModel { - [CCode (has_construct_function = false)] - public ListModelFilter (GLib.ListModel child_model); - public unowned GLib.ListModel get_child_model (); - public void invalidate (); - public void set_filter_func (owned Dazzle.ListModelFilterFunc filter_func); - public GLib.ListModel child_model { get; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_list_store_adapter_get_type ()")] - public class ListStoreAdapter : GLib.Object, Gtk.TreeModel { - [CCode (has_construct_function = false)] - public ListStoreAdapter (GLib.ListModel model); - [Version (since = "3.26")] - public unowned GLib.ListModel get_model (); - public void set_model (GLib.ListModel model); - public GLib.ListModel model { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_menu_button_get_type ()")] - public class MenuButton : Gtk.MenuButton, Atk.Implementor, Gtk.Actionable, Gtk.Activatable, Gtk.Buildable { - [CCode (has_construct_function = false)] - protected MenuButton (); - [Version (since = "3.26")] - public unowned GLib.MenuModel? get_model (); - public bool get_show_accels (); - public bool get_show_arrow (); - public bool get_show_icons (); - public void set_model (GLib.MenuModel model); - [Version (since = "3.26")] - public void set_show_accels (bool show_accels); - [Version (since = "3.26")] - public void set_show_arrow (bool show_arrow); - [Version (since = "3.26")] - public void set_show_icons (bool show_icons); - [CCode (has_construct_function = false, type = "GtkWidget*")] - public MenuButton.with_model (string icon_name, GLib.MenuModel? model); - [NoAccessorMethod] - public string icon_name { set; } - [NoAccessorMethod] - [Version (since = "3.26")] - public string menu_id { set; } - public GLib.MenuModel model { get; set; } - public bool show_accels { get; set; } - public bool show_arrow { get; set; } - public bool show_icons { get; set; } - [NoAccessorMethod] - public bool transitions_enabled { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_menu_manager_get_type ()")] - [Version (since = "3.26")] - public class MenuManager : GLib.Object { - [CCode (has_construct_function = false)] - public MenuManager (); - public uint add_filename (string filename) throws GLib.Error; - public uint add_resource (string resource) throws GLib.Error; - public unowned GLib.Menu get_menu_by_id (string menu_id); - public uint merge (string menu_id, GLib.MenuModel model); - public void remove (uint merge_id); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_multi_paned_get_type ()")] - public class MultiPaned : Gtk.Container, Atk.Implementor, Gtk.Buildable, Gtk.Orientable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public MultiPaned (); - [Version (since = "3.28")] - public unowned Gtk.Widget? get_at_point (int x, int y); - public uint get_n_children (); - public unowned Gtk.Widget get_nth_child (uint nth); - [NoAccessorMethod] - public Gtk.Orientation orientation { get; set; } - public virtual signal void resize_drag_begin (Gtk.Widget child); - public virtual signal void resize_drag_end (Gtk.Widget child); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_path_get_type ()")] - public class Path : GLib.Object { - [CCode (has_construct_function = false)] - public Path (); - public void append (Dazzle.PathElement element); - public unowned Dazzle.PathElement? get_element (uint index); - public unowned GLib.List get_elements (); - public uint get_length (); - public bool has_prefix (Dazzle.Path prefix); - public bool is_empty (); - public void prepend (Dazzle.PathElement element); - public string printf (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_path_bar_get_type ()")] - public class PathBar : Gtk.Box, Atk.Implementor, Gtk.Buildable, Gtk.Orientable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public PathBar (); - public unowned Dazzle.Path get_path (); - public void set_path (Dazzle.Path path); - public void set_selected_index (uint index); - public Dazzle.Path path { get; set; } - public signal void element_selected (Dazzle.Path object, Dazzle.PathElement p0); - public signal void populate_menu (Dazzle.Path object, Dazzle.PathElement p0, GLib.Menu p1); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_path_element_get_type ()")] - public class PathElement : GLib.Object { - [CCode (has_construct_function = false)] - [Version (since = "3.26")] - public PathElement (string? id, string? icon_name, string title); - [Version (since = "3.26")] - public unowned string? get_icon_name (); - [Version (since = "3.26")] - public unowned string get_id (); - [Version (since = "3.26")] - public unowned string? get_title (); - [Version (since = "3.26")] - public string icon_name { get; construct; } - [Version (since = "3.26")] - public string id { get; construct; } - [Version (since = "3.26")] - public string title { get; construct; } - } - [CCode (cheader_filename = "dazzle.h", ref_function = "dzl_pattern_spec_ref", type_id = "dzl_pattern_spec_get_type ()", unref_function = "dzl_pattern_spec_unref")] - [Compact] - public class PatternSpec { - [CCode (has_construct_function = false)] - public PatternSpec (string keywords); - public unowned string get_text (); - public bool match (string haystack); - public Dazzle.PatternSpec @ref (); - public void unref (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_pill_box_get_type ()")] - public class PillBox : Gtk.EventBox, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public PillBox (string label); - public unowned string get_label (); - public void set_label (string label); - public string label { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_preferences_bin_get_type ()")] - public class PreferencesBin : Gtk.Bin, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false)] - protected PreferencesBin (); - [NoWrapper] - public virtual void connect (GLib.Settings settings); - [NoWrapper] - public virtual void disconnect (GLib.Settings settings); - [NoWrapper] - public virtual bool matches (Dazzle.PatternSpec spec); - [NoAccessorMethod] - public string keywords { owned get; construct; } - [NoAccessorMethod] - public string path { owned get; construct; } - [NoAccessorMethod] - public int priority { get; construct; } - [NoAccessorMethod] - public string schema_id { owned get; construct; } - public signal void preference_activated (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_preferences_entry_get_type ()")] - public class PreferencesEntry : Dazzle.PreferencesBin, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false)] - protected PreferencesEntry (); - public unowned Gtk.Widget get_entry_widget (); - public unowned Gtk.Widget get_title_widget (); - [NoAccessorMethod] - public string text { owned get; set; } - [NoAccessorMethod] - public string title { owned get; set; } - public signal void activate (); - public signal void changed (string object); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_preferences_file_chooser_button_get_type ()")] - public class PreferencesFileChooserButton : Dazzle.PreferencesBin, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false)] - protected PreferencesFileChooserButton (); - [NoAccessorMethod] - public Gtk.FileChooserAction action { get; construct; } - [NoAccessorMethod] - public string key { owned get; construct; } - [NoAccessorMethod] - public string subtitle { owned get; construct; } - [NoAccessorMethod] - public string title { owned get; construct; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_preferences_flow_box_get_type ()")] - public class PreferencesFlowBox : Dazzle.ColumnLayout, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public PreferencesFlowBox (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_preferences_font_button_get_type ()")] - public class PreferencesFontButton : Dazzle.PreferencesBin, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false)] - protected PreferencesFontButton (); - [NoAccessorMethod] - public string key { owned get; construct; } - [NoAccessorMethod] - public string title { owned get; construct; } - public signal void activate (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_preferences_group_get_type ()")] - public class PreferencesGroup : Gtk.Bin, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false)] - protected PreferencesGroup (); - public void add (Gtk.Widget widget); - public int get_priority (); - public unowned string get_title (); - public uint refilter (Dazzle.PatternSpec spec); - public void set_map (GLib.HashTable map); - [NoAccessorMethod] - public bool is_list { get; construct; } - [NoAccessorMethod] - public Gtk.SelectionMode mode { get; set; } - public int priority { get; construct; } - public string title { get; construct; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_preferences_page_get_type ()")] - public class PreferencesPage : Gtk.Bin, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false)] - protected PreferencesPage (); - public void add_group (Dazzle.PreferencesGroup group); - public unowned Dazzle.PreferencesGroup? get_group (string group_name); - public void refilter (Dazzle.PatternSpec spec); - public void set_map (GLib.HashTable map); - [NoAccessorMethod] - public int priority { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_preferences_spin_button_get_type ()")] - public class PreferencesSpinButton : Dazzle.PreferencesBin, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false)] - protected PreferencesSpinButton (); - public unowned Gtk.Widget get_spin_button (); - [NoAccessorMethod] - public string key { owned get; construct; } - [NoAccessorMethod] - public string subtitle { owned get; construct; } - [NoAccessorMethod] - public string title { owned get; construct; } - public signal void activate (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_preferences_switch_get_type ()")] - public class PreferencesSwitch : Dazzle.PreferencesBin, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false)] - protected PreferencesSwitch (); - [NoAccessorMethod] - public bool is_radio { get; construct; } - [NoAccessorMethod] - public string key { owned get; construct; } - [NoAccessorMethod] - public string subtitle { owned get; set; } - [NoAccessorMethod] - public GLib.Variant target { owned get; construct; } - [NoAccessorMethod] - public string title { owned get; set; } - public signal void activated (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_preferences_view_get_type ()")] - public class PreferencesView : Gtk.Bin, Atk.Implementor, Dazzle.Preferences, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public PreferencesView (); - public bool get_use_sidebar (); - public void reapply_filter (); - public void set_use_sidebar (bool use_sidebar); - public bool use_sidebar { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_priority_box_get_type ()")] - public class PriorityBox : Gtk.Box, Atk.Implementor, Gtk.Buildable, Gtk.Orientable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public PriorityBox (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_progress_button_get_type ()")] - public class ProgressButton : Gtk.Button, Atk.Implementor, Gtk.Actionable, Gtk.Activatable, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public ProgressButton (); - public uint get_progress (); - public bool get_show_progress (); - public void set_progress (uint percentage); - public void set_show_progress (bool show_progress); - public uint progress { get; set; } - public bool show_progress { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_progress_icon_get_type ()")] - public class ProgressIcon : Gtk.DrawingArea, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public ProgressIcon (); - public double get_progress (); - public void set_progress (double progress); - public double progress { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_progress_menu_button_get_type ()")] - public class ProgressMenuButton : Gtk.MenuButton, Atk.Implementor, Gtk.Actionable, Gtk.Activatable, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public ProgressMenuButton (); - public double get_progress (); - public bool get_show_theatric (); - public void reset_theatrics (); - public void set_progress (double progress); - public void set_show_theatric (bool show_theatic); - public double progress { get; set; } - public bool show_theatric { get; set; } - [NoAccessorMethod] - public string theatric_icon_name { owned get; set; } - [NoAccessorMethod] - public uint transition_duration { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_properties_group_get_type ()")] - public class PropertiesGroup : GLib.Object, GLib.ActionGroup { - [CCode (has_construct_function = false)] - [Version (since = "3.26")] - public PropertiesGroup (GLib.Object object); - [Version (since = "3.26")] - public void add_all_properties (); - [Version (since = "3.26")] - public void add_property (string name, string property_name); - [Version (since = "3.26")] - public void add_property_full (string name, string property_name, Dazzle.PropertiesFlags flags); - [CCode (has_construct_function = false)] - public PropertiesGroup.for_type (GLib.Type object_type); - [Version (since = "3.26")] - public void remove (string name); - [NoAccessorMethod] - public GLib.Object object { owned get; set; } - [NoAccessorMethod] - public GLib.Type object_type { get; construct; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_radio_box_get_type ()")] - public class RadioBox : Gtk.Bin, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public RadioBox (); - public void add_item (string id, string text); - public unowned string get_active_id (); - public void set_active_id (string id); - public string active_id { get; set; } - [NoAccessorMethod] - public bool has_more { get; } - [NoAccessorMethod] - public bool show_more { get; set; } - public signal void changed (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_read_only_list_model_get_type ()")] - public class ReadOnlyListModel : GLib.Object, GLib.ListModel { - [CCode (has_construct_function = false)] - protected ReadOnlyListModel (); - [Version (since = "3.30")] - public static GLib.ListModel @new (GLib.ListModel base_model); - [NoAccessorMethod] - [Version (since = "3.30")] - public GLib.ListModel base_model { construct; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_recursive_file_monitor_get_type ()")] - public class RecursiveFileMonitor : GLib.Object { - [CCode (has_construct_function = false)] - public RecursiveFileMonitor (GLib.File root); - [Version (since = "3.28")] - public void cancel (); - [Version (since = "3.28")] - public unowned GLib.File get_root (); - [Version (since = "3.28")] - public void set_ignore_func (owned Dazzle.RecursiveIgnoreFunc ignore_func); - public async bool start_async (GLib.Cancellable? cancellable = null) throws GLib.Error; - public GLib.File root { get; construct; } - [Version (since = "3.28")] - public signal void changed (GLib.File file, GLib.File? other_file, GLib.FileMonitorEvent event); - } - [CCode (cheader_filename = "dazzle.h", ref_function = "dzl_ring_ref", type_id = "dzl_ring_get_type ()", unref_function = "dzl_ring_unref")] - [Compact] - public class Ring { - public uint8 data; - public uint len; - public uint pos; - public uint append_vals (void* data, uint len); - public void @foreach (GLib.Func func); - public Dazzle.Ring @ref (); - [CCode (cname = "dzl_ring_sized_new", has_construct_function = false)] - public Ring.sized_new (uint element_size, uint reserved_size, GLib.DestroyNotify element_destroy); - public void unref (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_scrolled_window_get_type ()")] - public class ScrolledWindow : Gtk.ScrolledWindow, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false)] - protected ScrolledWindow (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_search_bar_get_type ()")] - public class SearchBar : Gtk.Bin, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public SearchBar (); - public unowned Gtk.SearchEntry get_entry (); - public bool get_search_mode_enabled (); - public bool get_show_close_button (); - public void set_search_mode_enabled (bool search_mode_enabled); - public void set_show_close_button (bool show_close_button); - public bool search_mode_enabled { get; set; } - public bool show_close_button { get; set; } - public signal void activate (); - public signal void reveal (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_settings_flag_action_get_type ()")] - public class SettingsFlagAction : GLib.Object, GLib.Action { - [CCode (has_construct_function = false)] - protected SettingsFlagAction (); - public static GLib.Action @new (string schema_id, string schema_key, string flag_nick); - [NoAccessorMethod] - public string flag_nick { owned get; construct; } - [NoAccessorMethod] - public string schema_id { owned get; construct; } - [NoAccessorMethod] - public string schema_key { owned get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_settings_sandwich_get_type ()")] - public class SettingsSandwich : GLib.Object { - [CCode (has_construct_function = false)] - public SettingsSandwich (string schema_id, string path); - public void append (GLib.Settings settings); - public void bind (string key, void* object, string property, GLib.SettingsBindFlags flags); - public void bind_with_mapping (string key, void* object, string property, GLib.SettingsBindFlags flags, [CCode (delegate_target_pos = 6.1, destroy_notify_pos = 6.2)] owned GLib.SettingsBindGetMapping get_mapping, owned GLib.SettingsBindSetMapping set_mapping); - public bool get_boolean (string key); - public GLib.Variant get_default_value (string key); - public double get_double (string key); - public int get_int (string key); - public string get_string (string key); - public uint get_uint (string key); - public GLib.Variant get_user_value (string key); - public GLib.Variant get_value (string key); - public void set_boolean (string key, bool val); - public void set_double (string key, double val); - public void set_int (string key, int val); - public void set_string (string key, string val); - public void set_uint (string key, uint val); - public void set_value (string key, GLib.Variant value); - public void unbind (string property); - [NoAccessorMethod] - public string path { owned get; construct; } - [NoAccessorMethod] - public string schema_id { owned get; construct; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcut_accel_dialog_get_type ()")] - public class ShortcutAccelDialog : Gtk.Dialog, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public ShortcutAccelDialog (); - public string get_accelerator (); - public unowned Dazzle.ShortcutChord get_chord (); - public unowned string get_shortcut_title (); - public void set_accelerator (string accelerator); - public void set_shortcut_title (string title); - public string accelerator { owned get; set; } - public string shortcut_title { get; set; } - } - [CCode (cheader_filename = "dazzle.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "dzl_shortcut_chord_get_type ()")] - [Compact] - public class ShortcutChord { - public bool append_event (Gdk.EventKey event); - public Dazzle.ShortcutChord copy (); - [CCode (cheader_filename = "dazzle.h")] - public static bool equal (void* data1, void* data2); - public void free (); - [CCode (has_construct_function = false)] - public ShortcutChord.from_event (Gdk.EventKey event); - [CCode (has_construct_function = false)] - public ShortcutChord.from_string (string accelerator); - public string get_label (); - public uint get_length (); - public void get_nth_key (uint nth, uint keyval, Gdk.ModifierType modifier); - public bool has_modifier (); - [CCode (cheader_filename = "dazzle.h")] - public static uint hash (void* data); - public Dazzle.ShortcutMatch match (Dazzle.ShortcutChord other); - public string to_string (); - } - [CCode (cheader_filename = "dazzle.h", has_type_id = false)] - [Compact] - public class ShortcutChordTable { - public void add (Dazzle.ShortcutChord chord, void* data); - public void @foreach (Dazzle.ShortcutChordTableForeach foreach_func); - public void free (); - [CCode (cheader_filename = "dazzle.h")] - public static GLib.Type get_type (); - public Dazzle.ShortcutMatch lookup (Dazzle.ShortcutChord chord, void* data); - public unowned Dazzle.ShortcutChord lookup_data (void* data); - public void printf (); - public bool remove (Dazzle.ShortcutChord chord); - public bool remove_data (void* data); - public void set_free_func (GLib.DestroyNotify notify); - public uint size (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcut_context_get_type ()")] - public class ShortcutContext : GLib.Object { - [CCode (has_construct_function = false)] - public ShortcutContext (string name); - public Dazzle.ShortcutMatch activate (Gtk.Widget widget, Dazzle.ShortcutChord chord); - public void add_action (string accel, string detailed_action_name); - public void add_command (string accel, string command); - public void add_signalv (string accel, string signal_name, GLib.Array? values); - public unowned string get_name (); - public bool load_from_data (string data, ssize_t len) throws GLib.Error; - public bool load_from_resource (string resource_path) throws GLib.Error; - public bool remove (string accel); - public string name { get; construct; } - [NoAccessorMethod] - public bool use_binding_sets { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcut_controller_get_type ()")] - public class ShortcutController : GLib.Object { - [CCode (has_construct_function = false)] - public ShortcutController (Gtk.Widget widget); - public void add_command_action (string command_id, string default_accel, Dazzle.ShortcutPhase phase, string action); - public void add_command_callback (string command_id, string default_accel, Dazzle.ShortcutPhase phase, owned Gtk.Callback callback); - public bool execute_command (string command); - public static unowned Dazzle.ShortcutController find (Gtk.Widget widget); - [Version (since = "3.26")] - public unowned Dazzle.ShortcutContext? get_context (); - [Version (since = "3.26")] - public unowned Dazzle.ShortcutContext? get_context_for_phase (Dazzle.ShortcutPhase phase); - public unowned Dazzle.ShortcutChord? get_current_chord (); - public unowned Dazzle.ShortcutManager get_manager (); - [Version (since = "3.26")] - public void set_context_by_name (string? name); - public void set_manager (Dazzle.ShortcutManager? manager); - public static unowned Dazzle.ShortcutController? try_find (Gtk.Widget widget); - public Dazzle.ShortcutContext context { get; } - public Dazzle.ShortcutChord current_chord { get; } - public Dazzle.ShortcutManager manager { get; set; } - [NoAccessorMethod] - public Gtk.Widget widget { owned get; construct; } - public signal void reset (); - public signal void set_context_named (string name); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcut_label_get_type ()")] - public class ShortcutLabel : Gtk.Box, Atk.Implementor, Gtk.Buildable, Gtk.Orientable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public ShortcutLabel (); - public string get_accelerator (); - public unowned Dazzle.ShortcutChord? get_chord (); - public void set_accelerator (string accelerator); - public void set_chord (Dazzle.ShortcutChord chord); - public string accelerator { owned get; set; } - public Dazzle.ShortcutChord chord { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcut_manager_get_type ()")] - public class ShortcutManager : GLib.Object, GLib.Initable, GLib.ListModel { - [CCode (has_construct_function = false)] - protected ShortcutManager (); - public void add_action (string detailed_action_name, string section, string group, string title, string subtitle); - public void add_command (string command, string section, string group, string title, string subtitle); - public void add_shortcut_entries ([CCode (array_length_cname = "n_shortcuts", array_length_pos = 1.5, array_length_type = "guint")] Dazzle.ShortcutEntry[] shortcuts, string? translation_domain); - public void add_shortcuts_to_window (Dazzle.ShortcutsWindow window); - public void append_search_path (string directory); - public static unowned Dazzle.ShortcutManager get_default (); - public unowned Dazzle.ShortcutTheme get_theme (); - public unowned Dazzle.ShortcutTheme? get_theme_by_name (string? theme_name); - public unowned string get_theme_name (); - public unowned string get_user_dir (); - public bool handle_event (Gdk.EventKey event, Gtk.Widget toplevel); - public void prepend_search_path (string directory); - public void queue_reload (); - public void reload (GLib.Cancellable? cancellable = null); - public void remove_search_path (string directory); - public void set_theme (Dazzle.ShortcutTheme theme); - public void set_theme_name (string theme_name); - public void set_user_dir (string user_dir); - public Dazzle.ShortcutTheme theme { get; set; } - public string theme_name { get; set; } - public string user_dir { get; set; } - public signal void changed (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcut_model_get_type ()")] - public class ShortcutModel : Gtk.TreeStore, Gtk.Buildable, Gtk.TreeDragDest, Gtk.TreeDragSource, Gtk.TreeModel, Gtk.TreeSortable { - [CCode (has_construct_function = false)] - protected ShortcutModel (); - public unowned Dazzle.ShortcutManager get_manager (); - public unowned Dazzle.ShortcutTheme get_theme (); - public static Gtk.TreeModel @new (); - public void rebuild (); - public void set_chord (Gtk.TreeIter iter, Dazzle.ShortcutChord chord); - public void set_manager (Dazzle.ShortcutManager manager); - public void set_theme (Dazzle.ShortcutTheme theme); - public Dazzle.ShortcutManager manager { get; set; } - public Dazzle.ShortcutTheme theme { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcut_simple_label_get_type ()")] - public class ShortcutSimpleLabel : Gtk.Box, Atk.Implementor, Gtk.Buildable, Gtk.Orientable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public ShortcutSimpleLabel (); - public unowned string get_accel (); - public unowned string get_action (); - public unowned string get_command (); - public unowned string get_title (); - public void set_accel (string accel); - public void set_action (string action); - public void set_command (string command); - public void set_title (string title); - public string accel { get; set; } - public string action { get; set; } - public string command { get; set; } - [NoAccessorMethod] - public bool show_accel { get; set; } - public string title { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcut_theme_get_type ()")] - public class ShortcutTheme : GLib.Object { - [CCode (has_construct_function = false)] - public ShortcutTheme (string name); - public void add_command (string accelerator, string command); - public void add_context (Dazzle.ShortcutContext context); - public void add_css_resource (string path); - public unowned Dazzle.ShortcutContext find_context_by_name (string name); - public unowned Dazzle.ShortcutContext? find_default_context (Gtk.Widget widget); - public unowned Dazzle.ShortcutChord get_chord_for_action (string detailed_action_name); - public unowned Dazzle.ShortcutChord get_chord_for_command (string command); - public unowned string get_name (); - public unowned Dazzle.ShortcutTheme? get_parent (); - public unowned string? get_parent_name (); - public unowned string get_subtitle (); - public unowned string get_title (); - public bool load_from_data (string data, ssize_t len) throws GLib.Error; - public bool load_from_file (GLib.File file, GLib.Cancellable? cancellable = null) throws GLib.Error; - public bool load_from_path (string path, GLib.Cancellable? cancellable = null) throws GLib.Error; - public void remove_css_resource (string path); - public bool save_to_file (GLib.File file, GLib.Cancellable? cancellable = null) throws GLib.Error; - public bool save_to_path (string path, GLib.Cancellable? cancellable = null) throws GLib.Error; - public bool save_to_stream (GLib.OutputStream stream, GLib.Cancellable? cancellable = null) throws GLib.Error; - public void set_accel_for_action (string detailed_action_name, string accel, Dazzle.ShortcutPhase phase); - public void set_accel_for_command (string? command, string? accel, Dazzle.ShortcutPhase phase); - public void set_chord_for_action (string detailed_action_name, Dazzle.ShortcutChord chord, Dazzle.ShortcutPhase phase); - public void set_chord_for_command (string? command, Dazzle.ShortcutChord? chord, Dazzle.ShortcutPhase phase); - public void set_parent_name (string parent_name); - public string name { get; construct; } - public string parent_name { get; set; } - [NoAccessorMethod] - public string subtitle { owned get; set; } - [NoAccessorMethod] - public string title { owned get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcut_theme_editor_get_type ()")] - public class ShortcutThemeEditor : Gtk.Bin, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public ShortcutThemeEditor (); - public unowned Dazzle.ShortcutTheme? get_theme (); - public void set_theme (Dazzle.ShortcutTheme theme); - public Dazzle.ShortcutTheme theme { get; set; } - public signal void changed (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcuts_group_get_type ()")] - public class ShortcutsGroup : Gtk.Box, Atk.Implementor, Gtk.Buildable, Gtk.Orientable { - [CCode (has_construct_function = false)] - protected ShortcutsGroup (); - [NoAccessorMethod] - public Gtk.SizeGroup accel_size_group { set; } - [NoAccessorMethod] - public uint height { get; } - [NoAccessorMethod] - public string title { owned get; set; } - [NoAccessorMethod] - public Gtk.SizeGroup title_size_group { set; } - [NoAccessorMethod] - public string view { owned get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcuts_section_get_type ()")] - public class ShortcutsSection : Gtk.Box, Atk.Implementor, Gtk.Buildable, Gtk.Orientable { - [CCode (has_construct_function = false)] - protected ShortcutsSection (); - [NoAccessorMethod] - public uint max_height { get; set; } - [NoAccessorMethod] - public string section_name { owned get; set; } - [NoAccessorMethod] - public string title { owned get; set; } - [NoAccessorMethod] - public string view_name { owned get; set; } - public signal bool change_current_page (int object); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcuts_shortcut_get_type ()")] - public class ShortcutsShortcut : Gtk.Box, Atk.Implementor, Gtk.Buildable, Gtk.Orientable { - [CCode (has_construct_function = false)] - protected ShortcutsShortcut (); - [NoAccessorMethod] - public Gtk.SizeGroup accel_size_group { set; } - [NoAccessorMethod] - public string accelerator { owned get; set; } - [NoAccessorMethod] - [Version (since = "3.22")] - public string action_name { owned get; set; } - [NoAccessorMethod] - public Gtk.TextDirection direction { get; set; } - [NoAccessorMethod] - public GLib.Icon icon { owned get; set; } - [NoAccessorMethod] - public bool icon_set { get; set; } - [NoAccessorMethod] - public Gtk.ShortcutType shortcut_type { get; set; } - [NoAccessorMethod] - public string subtitle { owned get; set; } - [NoAccessorMethod] - public bool subtitle_set { get; set; } - [NoAccessorMethod] - public string title { owned get; set; } - [NoAccessorMethod] - public Gtk.SizeGroup title_size_group { set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_shortcuts_window_get_type ()")] - public class ShortcutsWindow : Gtk.Window, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false)] - protected ShortcutsWindow (); - [NoAccessorMethod] - public string section_name { owned get; set; } - [NoAccessorMethod] - public string view_name { owned get; set; } - public virtual signal void close (); - public virtual signal void search (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_signal_group_get_type ()")] - public class SignalGroup : GLib.Object { - [CCode (has_construct_function = false)] - public SignalGroup (GLib.Type target_type); - public void block (); - public void connect_data (string detailed_signal, [CCode (delegate_target_pos = 2.33333, destroy_notify_pos = 2.66667)] owned GLib.Callback c_handler, GLib.ConnectFlags flags); - public void connect_swapped (string detailed_signal, [CCode (scope = "async")] GLib.Callback c_handler); - public unowned GLib.Object? get_target (); - public void set_target (GLib.Object? target); - public void unblock (); - public GLib.Object target { get; set; } - [NoAccessorMethod] - public GLib.Type target_type { get; construct; } - public signal void bind (GLib.Object instance); - public signal void unbind (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_simple_label_get_type ()")] - public class SimpleLabel : Gtk.Widget, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public SimpleLabel (string label); - public unowned string get_label (); - public int get_width_chars (); - public float get_xalign (); - public void set_label (string label); - public void set_width_chars (int width_chars); - public void set_xalign (float xalign); - public string label { get; set; } - public int width_chars { get; set; } - public float xalign { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_simple_popover_get_type ()")] - public class SimplePopover : Gtk.Popover, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public SimplePopover (); - public unowned string get_button_text (); - public unowned string get_message (); - public bool get_ready (); - public unowned string get_text (); - public unowned string get_title (); - public void set_button_text (string button_text); - public void set_message (string message); - public void set_ready (bool ready); - public void set_text (string text); - public void set_title (string title); - public string button_text { get; set; } - public string message { get; set; } - public bool ready { get; set; } - public string text { get; set; } - public string title { get; set; } - public virtual signal void activate (string text); - public virtual signal void changed (); - public virtual signal bool insert_text (uint position, string chars, uint n_chars); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_slider_get_type ()")] - public class Slider : Gtk.Container, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public Slider (); - public void add_slider (Gtk.Widget widget, Dazzle.SliderPosition position); - public Dazzle.SliderPosition get_position (); - public void set_position (Dazzle.SliderPosition position); - public Dazzle.SliderPosition position { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_stack_list_get_type ()")] - public class StackList : Gtk.Bin, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public StackList (); - public void clear (); - public uint get_depth (); - public unowned GLib.ListModel get_model (); - public void pop (); - public void push (Gtk.Widget header, GLib.ListModel model, owned Dazzle.StackListCreateWidgetFunc? create_widget_func); - public GLib.ListModel model { get; } - public virtual signal void header_activated (Gtk.ListBoxRow row); - public virtual signal void row_activated (Gtk.ListBoxRow row); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_state_machine_get_type ()")] - public class StateMachine : GLib.Object, Gtk.Buildable { - [CCode (has_construct_function = false)] - public StateMachine (); - public void add_binding (string state, void* source_object, string source_property, void* target_object, string target_property, GLib.BindingFlags flags); - public void add_propertyv (string state, void* object, string property, GLib.Value value); - public void add_style (string state, Gtk.Widget widget, string style); - public GLib.Action create_action (string name); - public unowned string get_state (); - [Version (since = "3.28")] - public bool is_state (string? state); - public void set_state (string state); - public string state { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_suggestion_get_type ()")] - public class Suggestion : GLib.Object { - [CCode (has_construct_function = false)] - public Suggestion (); - [Version (since = "3.30")] - public virtual GLib.Icon? get_icon (); - public unowned string get_icon_name (); - [Version (since = "3.30")] - public virtual Cairo.Surface? get_icon_surface (Gtk.Widget widget); - public unowned string get_id (); - public unowned string get_subtitle (); - public unowned string get_title (); - public void set_icon_name (string icon_name); - public void set_id (string id); - public void set_subtitle (string subtitle); - public void set_title (string title); - public GLib.Icon icon { owned get; } - public string icon_name { get; set; } - public string id { get; set; } - public string subtitle { get; set; } - public string title { get; set; } - [HasEmitter] - public virtual signal string replace_typed_text (string typed_text); - [HasEmitter] - public virtual signal string suggest_suffix (string typed_text); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_suggestion_entry_get_type ()")] - public class SuggestionEntry : Gtk.Entry, Atk.Implementor, Gtk.Buildable, Gtk.CellEditable, Gtk.Editable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public SuggestionEntry (); - public void default_position_func (Gdk.Rectangle area, bool is_absolute, void* user_data); - public bool get_activate_on_single_click (); - public unowned GLib.ListModel? get_model (); - public unowned Dazzle.Suggestion? get_suggestion (); - public unowned string get_typed_text (); - public void set_activate_on_single_click (bool activate_on_single_click); - public void set_model (GLib.ListModel model); - [Version (since = "3.26")] - public void set_position_func (owned Dazzle.SuggestionPositionFunc? func); - public void set_suggestion (Dazzle.Suggestion suggestion); - public void window_position_func (Gdk.Rectangle area, bool is_absolute, void* user_data); - [Version (since = "3.30")] - public bool activate_on_single_click { get; set; } - public GLib.ListModel model { get; set; } - [Version (since = "3.30")] - public Dazzle.Suggestion suggestion { get; set; } - public string typed_text { get; } - public signal void activate_suggestion (); - [HasEmitter] - public virtual signal void hide_suggestions (); - public virtual signal void move_suggestion (int amount); - public virtual signal void show_suggestions (); - public virtual signal void suggestion_activated (Dazzle.Suggestion suggestion); - [Version (since = "3.30")] - public virtual signal void suggestion_selected (Dazzle.Suggestion suggestion); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_suggestion_entry_buffer_get_type ()")] - public class SuggestionEntryBuffer : Gtk.EntryBuffer { - [CCode (has_construct_function = false)] - public SuggestionEntryBuffer (); - public void clear (); - public void commit (); - public unowned Dazzle.Suggestion? get_suggestion (); - public uint get_typed_length (); - public unowned string get_typed_text (); - public void set_suggestion (Dazzle.Suggestion? suggestion); - public Dazzle.Suggestion suggestion { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_suggestion_popover_get_type ()")] - public class SuggestionPopover : Gtk.Window, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public SuggestionPopover (); - public void activate_selected (); - public unowned GLib.ListModel? get_model (); - public unowned Gtk.Widget? get_relative_to (); - public unowned Dazzle.Suggestion? get_selected (); - public void move_by (int amount); - public void popdown (); - public void popup (); - public void set_model (GLib.ListModel model); - public void set_relative_to (Gtk.Widget widget); - public void set_selected (Dazzle.Suggestion suggestion); - public Dazzle.Suggestion model { get; set; } - public Gtk.Widget relative_to { get; set; } - public Dazzle.Suggestion selected { get; set; } - [NoAccessorMethod] - public Pango.EllipsizeMode subtitle_ellipsize { get; set; } - [NoAccessorMethod] - public Pango.EllipsizeMode title_ellipsize { get; set; } - public signal void suggestion_activated (Dazzle.Suggestion object); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_suggestion_row_get_type ()")] - public class SuggestionRow : Dazzle.ListBoxRow, Atk.Implementor, Gtk.Actionable, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public SuggestionRow (); - public unowned Dazzle.Suggestion get_suggestion (); - public void set_suggestion (Dazzle.Suggestion suggestion); - public Dazzle.Suggestion suggestion { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_tab_get_type ()")] - public class Tab : Dazzle.Bin, Atk.Implementor, Gtk.Actionable, Gtk.Buildable { - [CCode (has_construct_function = false)] - protected Tab (); - public bool get_active (); - public bool get_can_close (); - public Gtk.PositionType get_edge (); - public unowned string get_icon_name (); - public Dazzle.TabStyle get_style (); - public unowned string get_title (); - public unowned Gtk.Widget? get_widget (); - public void set_active (bool active); - public void set_can_close (bool can_close); - public void set_edge (Gtk.PositionType edge); - public void set_icon_name (string icon_name); - public void set_style (Dazzle.TabStyle style); - public void set_title (string title); - public void set_widget (Gtk.Widget widget); - public bool active { get; set; } - public bool can_close { get; set; } - public Gtk.PositionType edge { get; set; } - public Dazzle.TabStyle style { get; set; } - public string title { get; set; } - public Gtk.Widget widget { get; set; } - public signal void clicked (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_tab_strip_get_type ()")] - public class TabStrip : Gtk.Box, Atk.Implementor, Gtk.Buildable, Gtk.Orientable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public TabStrip (); - public void add_control (Gtk.Widget widget); - public Gtk.PositionType get_edge (); - public unowned Gtk.Stack? get_stack (); - public Dazzle.TabStyle get_style (); - public void set_edge (Gtk.PositionType edge); - public void set_stack (Gtk.Stack stack); - public void set_style (Dazzle.TabStyle style); - public Gtk.PositionType edge { get; set; } - public Gtk.Stack stack { get; set; } - public Dazzle.TabStyle style { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_task_cache_get_type ()")] - public class TaskCache : GLib.Object { - [CCode (has_construct_function = false)] - protected TaskCache (); - public bool evict (void* key); - public void evict_all (); - public async void* get_async (void* key, bool force_update, GLib.Cancellable? cancellable = null) throws GLib.Error; - public unowned GLib.Object? peek (void* key); - public void set_name (string name); - [NoAccessorMethod] - public void* key_copy_func { construct; } - [NoAccessorMethod] - public void* key_destroy_func { construct; } - [NoAccessorMethod] - public void* key_equal_func { construct; } - [NoAccessorMethod] - public void* key_hash_func { construct; } - [NoAccessorMethod] - public void* populate_callback { construct; } - [NoAccessorMethod] - public void* populate_callback_data { construct; } - [NoAccessorMethod] - public void* populate_callback_data_destroy { construct; } - [NoAccessorMethod] - public int64 time_to_live { construct; } - [NoAccessorMethod] - public void* value_copy_func { construct; } - [NoAccessorMethod] - public void* value_destroy_func { construct; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_theme_manager_get_type ()")] - public class ThemeManager : GLib.Object { - [CCode (has_construct_function = false)] - public ThemeManager (); - public void add_resources (string resource_path); - public void remove_resources (string resource_path); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_three_grid_get_type ()")] - public class ThreeGrid : Gtk.Container, Atk.Implementor, Gtk.Buildable { - [CCode (has_construct_function = false, type = "GtkWidget*")] - public ThreeGrid (); - [NoAccessorMethod] - public uint column_spacing { get; set; } - [NoAccessorMethod] - public uint row_spacing { get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_tree_get_type ()")] - public class Tree : Gtk.TreeView, Atk.Implementor, Gtk.Buildable, Gtk.Scrollable { - [CCode (has_construct_function = false)] - protected Tree (); - public void add_builder (Dazzle.TreeBuilder builder); - public void expand_to_node (Dazzle.TreeNode node); - public unowned Dazzle.TreeNode? find_child_node (Dazzle.TreeNode node, Dazzle.TreeFindFunc find_func); - public unowned Dazzle.TreeNode? find_custom (GLib.EqualFunc equal_func, void* key); - public unowned Dazzle.TreeNode? find_item (GLib.Object? item); - public unowned GLib.MenuModel? get_context_menu (); - public unowned Dazzle.TreeNode? get_root (); - public unowned Dazzle.TreeNode get_selected (); - public bool get_show_icons (); - public void rebuild (); - public void remove_builder (Dazzle.TreeBuilder builder); - public void scroll_to_node (Dazzle.TreeNode node); - public void set_context_menu (GLib.MenuModel context_menu); - public void set_filter (owned Dazzle.TreeFilterFunc filter_func); - public void set_root (Dazzle.TreeNode node); - public void set_show_icons (bool show_icons); - public void unselect_all (); - [NoAccessorMethod] - public bool always_expand { get; construct; } - public GLib.MenuModel context_menu { get; set; } - public Dazzle.TreeNode root { get; set; } - [NoAccessorMethod] - public Dazzle.TreeNode selection { owned get; set; } - public bool show_icons { get; set; } - public virtual signal void action (string action_group, string action_name, string param); - public virtual signal void populate_popup (Gtk.Widget widget); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_tree_builder_get_type ()")] - public class TreeBuilder : GLib.InitiallyUnowned { - [CCode (has_construct_function = false)] - public TreeBuilder (); - [NoWrapper] - public virtual void cell_data_func (Dazzle.TreeNode node, Gtk.CellRenderer cell); - public unowned Dazzle.Tree? get_tree (); - public Dazzle.Tree tree { get; } - public virtual signal void added (Dazzle.Tree tree); - public virtual signal void build_children (Dazzle.TreeNode parent); - public virtual signal void build_node (Dazzle.TreeNode node); - public virtual signal bool drag_data_get (Dazzle.TreeNode node, Gtk.SelectionData data); - public virtual signal bool drag_data_received (Dazzle.TreeNode drop_node, Dazzle.TreeDropPosition position, Gdk.DragAction action, Gtk.SelectionData data); - public virtual signal bool drag_node_delete (Dazzle.TreeNode node); - public virtual signal bool drag_node_received (Dazzle.TreeNode drag_node, Dazzle.TreeNode drop_node, Dazzle.TreeDropPosition position, Gdk.DragAction action, Gtk.SelectionData data); - public virtual signal bool node_activated (Dazzle.TreeNode node); - public virtual signal void node_collapsed (Dazzle.TreeNode node); - public virtual signal bool node_draggable (Dazzle.TreeNode node); - public virtual signal bool node_droppable (Dazzle.TreeNode node, Gtk.SelectionData data); - public virtual signal void node_expanded (Dazzle.TreeNode node); - public virtual signal void node_popup (Dazzle.TreeNode node, GLib.Menu menu); - public virtual signal void node_selected (Dazzle.TreeNode node); - public virtual signal void node_unselected (Dazzle.TreeNode node); - public virtual signal void removed (Dazzle.Tree tree); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_tree_node_get_type ()")] - public class TreeNode : GLib.InitiallyUnowned { - [CCode (has_construct_function = false)] - public TreeNode (); - public void add_emblem (string emblem_name); - public void append (Dazzle.TreeNode child); - public void clear_emblems (); - public void collapse (); - public bool expand (bool expand_ancestors); - public void get_area (Gdk.Rectangle area); - public bool get_children_possible (); - public bool get_expanded (); - [Version (since = "3.28")] - public unowned Gdk.RGBA? get_foreground_rgba (); - public unowned GLib.Icon get_gicon (); - public unowned string get_icon_name (); - public unowned GLib.Object get_item (); - public bool get_iter (Gtk.TreeIter iter); - public unowned Dazzle.TreeNode get_parent (); - public Gtk.TreePath? get_path (); - public bool get_reset_on_collapse (); - public unowned string get_text (); - public unowned Dazzle.Tree get_tree (); - public bool get_use_dim_label (); - public bool get_use_markup (); - public bool has_emblem (string emblem_name); - [Version (since = "3.28")] - public void insert (Dazzle.TreeNode child, uint position); - public void insert_sorted (Dazzle.TreeNode child, Dazzle.TreeNodeCompareFunc compare_func); - public void invalidate (); - public bool is_root (); - public uint n_children (); - public Dazzle.TreeNode? nth_child (uint nth); - public void prepend (Dazzle.TreeNode child); - [Version (since = "3.28")] - public void rebuild (); - public void remove (Dazzle.TreeNode child); - public void remove_emblem (string emblem_name); - public void select (); - public void set_children_possible (bool children_possible); - public void set_emblems (string emblems); - [Version (since = "3.28")] - public void set_foreground_rgba (Gdk.RGBA? foreground_rgba); - public void set_gicon (GLib.Icon icon); - public void set_icon_name (string? icon_name); - public void set_item (GLib.Object item); - public void set_reset_on_collapse (bool reset_on_collapse); - public void set_text (string? text); - public void set_use_dim_label (bool use_dim_label); - public void set_use_markup (bool use_markup); - public void show_popover (Gtk.Popover popover); - public bool children_possible { get; set; } - [NoAccessorMethod] - public string expanded_icon_name { owned get; set; } - public GLib.Icon gicon { get; set; } - public string icon_name { get; set; } - public GLib.Object item { get; set; } - public Dazzle.TreeNode parent { get; } - [Version (since = "3.28")] - public bool reset_on_collapse { get; set; } - public string text { get; set; } - [NoAccessorMethod] - public Dazzle.Tree tree { owned get; set; } - public bool use_dim_label { get; set; } - public bool use_markup { get; set; } - } - [CCode (cheader_filename = "dazzle.h", ref_function = "dzl_trie_ref", type_id = "dzl_trie_get_type ()", unref_function = "dzl_trie_unref")] - [Compact] - public class Trie { - [CCode (has_construct_function = false)] - public Trie (GLib.DestroyNotify value_destroy); - public void destroy (); - public void insert (string key, void* value); - public void* lookup (string key); - public Dazzle.Trie @ref (); - public bool remove (string key); - public void traverse (string key, GLib.TraverseType order, GLib.TraverseFlags flags, int max_depth, Dazzle.TrieTraverseFunc func); - public void unref (); - } - [CCode (cheader_filename = "dazzle.h", type_id = "dzl_widget_action_group_get_type ()")] - public class WidgetActionGroup : GLib.Object, GLib.ActionGroup { - [CCode (has_construct_function = false)] - protected WidgetActionGroup (); - public static void attach (Gtk.Widget widget, string group_name); - public static GLib.ActionGroup @new (Gtk.Widget widget); - public void set_action_enabled (string action_name, bool enabled); - [NoAccessorMethod] - public Gtk.Widget widget { owned get; construct; } - } - [CCode (cheader_filename = "dazzle.h", type_cname = "DzlDockInterface", type_id = "dzl_dock_get_type ()")] - public interface Dock : Gtk.Container { - [NoAccessorMethod] - public abstract Dazzle.DockManager manager { owned get; set; } - } - [CCode (cheader_filename = "dazzle.h", type_cname = "DzlDockItemInterface", type_id = "dzl_dock_item_get_type ()")] - public interface DockItem : Gtk.Widget { - public bool adopt (Dazzle.DockItem child); - public abstract bool close (); - [Version (since = "3.30")] - public void emit_presented (); - public abstract bool get_can_close (); - [CCode (vfunc_name = "can_minimize")] - public abstract bool get_can_minimize (Dazzle.DockItem descendant); - public abstract bool get_child_visible (Dazzle.DockItem child); - public abstract string? get_icon_name (); - public abstract unowned Dazzle.DockManager? get_manager (); - public unowned Dazzle.DockItem? get_parent (); - public abstract string? get_title (); - public bool has_widgets (); - public abstract bool minimize (Dazzle.DockItem child, ref Gtk.PositionType position); - public void present (); - public abstract void present_child (Dazzle.DockItem child); - public abstract void release (Dazzle.DockItem child); - public abstract void set_child_visible (Dazzle.DockItem child, bool child_visible); - public abstract void set_manager (Dazzle.DockManager? manager); - public abstract void update_visibility (); - public virtual signal void manager_set (Dazzle.DockManager old_manager); - public virtual signal void presented (); - } - [CCode (cheader_filename = "dazzle.h", lower_case_csuffix = "graph_view_renderer", type_cname = "DzlGraphRendererInterface", type_id = "dzl_graph_view_renderer_get_type ()")] - public interface GraphRenderer : GLib.Object { - public abstract void render (Dazzle.GraphModel table, int64 x_begin, int64 x_end, double y_begin, double y_end, Cairo.Context cr, Cairo.RectangleInt area); - } - [CCode (cheader_filename = "dazzle.h", type_cname = "DzlPreferencesInterface", type_id = "dzl_preferences_get_type ()")] - public interface Preferences : GLib.Object { - public abstract uint add_custom (string page_name, string group_name, Gtk.Widget widget, string? keywords, int priority); - public abstract uint add_file_chooser (string page_name, string group_name, string schema_id, string key, string path, string title, string subtitle, Gtk.FileChooserAction action, string keywords, int priority); - public abstract uint add_font_button (string page_name, string group_name, string schema_id, string key, string title, string keywords, int priority); - public abstract void add_group (string page_name, string group_name, string title, int priority); - public abstract void add_list_group (string page_name, string group_name, string title, Gtk.SelectionMode mode, int priority); - public abstract void add_page (string page_name, string title, int priority); - public abstract uint add_radio (string page_name, string group_name, string schema_id, string key, string? path, string? variant_string, string? title, string? subtitle, string? keywords, int priority); - public abstract uint add_spin_button (string page_name, string group_name, string schema_id, string key, string path, string title, string subtitle, string keywords, int priority); - public abstract uint add_switch (string page_name, string group_name, string schema_id, string key, string? path, string? variant_string, string? title, string? subtitle, string? keywords, int priority); - public abstract unowned Gtk.Widget? get_widget (uint widget_id); - public abstract bool remove_id (uint widget_id); - public abstract void set_page (string page_name, GLib.HashTable map); - } - [CCode (cheader_filename = "dazzle.h", has_type_id = false)] - public struct Counter { - public Dazzle.CounterValue values; - public weak string category; - public weak string name; - public weak string description; - public int64 @get (); - public void reset (); - } - [CCode (cheader_filename = "dazzle.h", has_type_id = false)] - public struct CounterValue { - public int64 value; - [CCode (array_length = false)] - public weak int64 padding[7]; - } - [CCode (cheader_filename = "dazzle.h", has_type_id = false)] - public struct FileTransferStat { - public int64 n_files_total; - public int64 n_files; - public int64 n_dirs_total; - public int64 n_dirs; - public int64 n_bytes_total; - public int64 n_bytes; - } - [CCode (cheader_filename = "dazzle.h", has_type_id = false)] - public struct FuzzyMutableIndexMatch { - public weak string key; - public void* value; - public float score; - public uint id; - } - [CCode (cheader_filename = "dazzle.h", has_type_id = false)] - public struct GraphModelIter { - [CCode (array_length = false)] - public weak void* data[8]; - } - [CCode (cheader_filename = "dazzle.h", has_type_id = false)] - public struct ShortcutEntry { - public weak string command; - public Dazzle.ShortcutPhase phase; - public weak string default_accel; - public weak string section; - public weak string group; - public weak string title; - public weak string subtitle; - } - [CCode (cheader_filename = "dazzle.h", cname = "_DzlGraphColumnClass", has_type_id = false)] - public struct _GraphColumnClass { - public weak GLib.ObjectClass parent; - } - [CCode (cheader_filename = "dazzle.h", cprefix = "DZL_ANIMATION_", type_id = "dzl_animation_mode_get_type ()")] - public enum AnimationMode { - LINEAR, - EASE_IN_QUAD, - EASE_IN_OUT_QUAD, - EASE_OUT_QUAD, - EASE_IN_CUBIC, - EASE_OUT_CUBIC, - EASE_IN_OUT_CUBIC - } - [CCode (cheader_filename = "dazzle.h", cprefix = "DZL_DOCK_REVEALER_TRANSITION_TYPE_", type_id = "dzl_dock_revealer_transition_type_get_type ()")] - public enum DockRevealerTransitionType { - NONE, - SLIDE_RIGHT, - SLIDE_LEFT, - SLIDE_UP, - SLIDE_DOWN - } - [CCode (cheader_filename = "dazzle.h", cprefix = "DZL_FILE_TRANSFER_FLAGS_", type_id = "dzl_file_transfer_flags_get_type ()")] - [Flags] - public enum FileTransferFlags { - NONE, - MOVE - } - [CCode (cheader_filename = "dazzle.h", cprefix = "DZL_PROPERTIES_FLAGS_", has_type_id = false)] - [Flags] - public enum PropertiesFlags { - NONE, - STATEFUL_BOOLEANS - } - [CCode (cheader_filename = "dazzle.h", cprefix = "DZL_SHORTCUT_MATCH_", type_id = "dzl_shortcut_match_get_type ()")] - public enum ShortcutMatch { - NONE, - EQUAL, - PARTIAL - } - [CCode (cheader_filename = "dazzle.h", cprefix = "DZL_SHORTCUT_PHASE_", type_id = "dzl_shortcut_phase_get_type ()")] - [Flags] - public enum ShortcutPhase { - DISPATCH, - CAPTURE, - BUBBLE, - GLOBAL - } - [CCode (cheader_filename = "dazzle.h", cprefix = "DZL_SHORTCUT_", has_type_id = false)] - [Version (since = "3.20")] - public enum ShortcutType { - ACCELERATOR, - GESTURE_PINCH, - GESTURE_STRETCH, - GESTURE_ROTATE_CLOCKWISE, - GESTURE_ROTATE_COUNTERCLOCKWISE, - GESTURE_TWO_FINGER_SWIPE_LEFT, - GESTURE_TWO_FINGER_SWIPE_RIGHT, - GESTURE - } - [CCode (cheader_filename = "dazzle.h", cprefix = "DZL_SLIDER_", type_id = "dzl_slider_position_get_type ()")] - public enum SliderPosition { - NONE, - TOP, - RIGHT, - BOTTOM, - LEFT - } - [CCode (cheader_filename = "dazzle.h", cprefix = "DZL_TAB_", type_id = "dzl_tab_style_get_type ()")] - [Flags] - public enum TabStyle { - ICONS, - TEXT, - BOTH - } - [CCode (cheader_filename = "dazzle.h", cprefix = "DZL_THREE_GRID_COLUMN_", type_id = "dzl_three_grid_column_get_type ()")] - public enum ThreeGridColumn { - LEFT, - CENTER, - RIGHT - } - [CCode (cheader_filename = "dazzle.h", cprefix = "DZL_TREE_DROP_", type_id = "dzl_tree_drop_position_get_type ()")] - public enum TreeDropPosition { - INTO, - BEFORE, - AFTER - } - [CCode (cheader_filename = "dazzle.h", instance_pos = 1.9)] - public delegate void CounterForeachFunc (Dazzle.Counter counter); - [CCode (cheader_filename = "dazzle.h", instance_pos = 3.9)] - public delegate bool DirectoryModelVisibleFunc (Dazzle.DirectoryModel self, GLib.File directory, GLib.FileInfo file_info); - [CCode (cheader_filename = "dazzle.h", instance_pos = 1.9)] - public delegate bool ListModelFilterFunc (GLib.Object object); - [CCode (cheader_filename = "dazzle.h", instance_pos = 1.9)] - public delegate bool RecursiveIgnoreFunc (GLib.File file); - [CCode (cheader_filename = "dazzle.h", instance_pos = 2.9)] - public delegate void ShortcutChordTableForeach (Dazzle.ShortcutChord chord, void* chord_data); - [CCode (cheader_filename = "dazzle.h", instance_pos = 1.9)] - public delegate Gtk.Widget StackListCreateWidgetFunc ([CCode (type = "gpointer")] GLib.Object item); - [CCode (cheader_filename = "dazzle.h", instance_pos = 3.9)] - [Version (since = "3.26")] - public delegate void SuggestionPositionFunc (Dazzle.SuggestionEntry entry, ref Gdk.Rectangle area, ref bool is_absolute); - [CCode (cheader_filename = "dazzle.h", instance_pos = 3.9)] - public delegate void TaskCacheCallback (Dazzle.TaskCache self, void* key, GLib.Task task); - [CCode (cheader_filename = "dazzle.h", instance_pos = 2.9)] - public delegate bool TreeFilterFunc (Dazzle.Tree tree, Dazzle.TreeNode node); - [CCode (cheader_filename = "dazzle.h", instance_pos = 3.9)] - public delegate bool TreeFindFunc (Dazzle.Tree tree, Dazzle.TreeNode node, Dazzle.TreeNode child); - [CCode (cheader_filename = "dazzle.h", instance_pos = 2.9)] - public delegate int TreeNodeCompareFunc (Dazzle.TreeNode a, Dazzle.TreeNode b); - [CCode (cheader_filename = "dazzle.h", instance_pos = 3.9)] - public delegate bool TrieTraverseFunc (Dazzle.Trie dzl_trie, string key, void* value); - [CCode (cheader_filename = "dazzle.h", cname = "DZL_COUNTER_REQUIRES_ATOMIC")] - public const int COUNTER_REQUIRES_ATOMIC; - [CCode (cheader_filename = "dazzle.h", cname = "DZL_DOCK_BIN_STYLE_CLASS_PINNED")] - public const string DOCK_BIN_STYLE_CLASS_PINNED; - [CCode (cheader_filename = "dazzle.h", cname = "DZL_ENABLE_TRACE")] - public const int ENABLE_TRACE; - [CCode (cheader_filename = "dazzle.h", cname = "DZL_MAJOR_VERSION")] - public const int MAJOR_VERSION; - [CCode (cheader_filename = "dazzle.h", cname = "DZL_MICRO_VERSION")] - public const int MICRO_VERSION; - [CCode (cheader_filename = "dazzle.h", cname = "DZL_MINOR_VERSION")] - public const int MINOR_VERSION; - [CCode (cheader_filename = "dazzle.h", cname = "DZL_VERSION_S")] - public const string VERSION_S; - [CCode (cheader_filename = "dazzle.h")] - public static Cairo.Region cairo_region_create_from_clip_extents (Cairo.Context cr); - [CCode (cheader_filename = "dazzle.h")] - public static void cairo_rounded_rectangle (Cairo.Context cr, Gdk.Rectangle rect, int x_radius, int y_radius); - [CCode (cheader_filename = "dazzle.h")] - [Version (since = "3.28")] - public static unowned GLib.Cancellable? cancellable_chain (GLib.Cancellable? self = null, GLib.Cancellable? other = null); - [CCode (array_length = false, array_null_terminated = true, cheader_filename = "dazzle.h")] - public static string[] dnd_get_uri_list (Gtk.SelectionData selection_data); - [CCode (cheader_filename = "dazzle.h")] - public static bool file_manager_show (GLib.File file) throws GLib.Error; - [CCode (cheader_filename = "dazzle.h")] - public static string fuzzy_highlight (string str, string query, bool case_sensitive); - [CCode (cheader_filename = "dazzle.h")] - public static string g_date_time_format_for_display (GLib.DateTime self); - [CCode (cheader_filename = "dazzle.h")] - public static string g_time_span_to_label (GLib.TimeSpan span); - [CCode (cheader_filename = "dazzle.h")] - public static bool g_time_span_to_label_mapping (GLib.Binding binding, GLib.Value from_value, GLib.Value to_value, void* user_data); - [CCode (cheader_filename = "dazzle.h")] - public static uint g_variant_hash (void* data); - [CCode (cheader_filename = "dazzle.h")] - public static uint get_current_cpu_call (); - [CCode (cheader_filename = "dazzle.h")] - [Version (since = "3.26")] - public static void gtk_list_store_insert_sorted (Gtk.ListStore store, out Gtk.TreeIter iter, void* key, uint compare_column, GLib.CompareDataFunc compare_func); - [CCode (cheader_filename = "dazzle.h")] - public static void gtk_text_buffer_remove_tag (Gtk.TextBuffer buffer, Gtk.TextTag tag, Gtk.TextIter start, Gtk.TextIter end, bool minimal_damage); - [CCode (cheader_filename = "dazzle.h")] - public static bool gtk_widget_action (Gtk.Widget widget, string group, string name, GLib.Variant param); - [CCode (cheader_filename = "dazzle.h")] - public static bool gtk_widget_action_with_string (Gtk.Widget widget, string group, string name, string param); - [CCode (cheader_filename = "dazzle.h")] - public static void gtk_widget_add_style_class (Gtk.Widget widget, string class_name); - [CCode (cheader_filename = "dazzle.h")] - public static unowned Gtk.Widget? gtk_widget_find_child_typed (Gtk.Widget widget, GLib.Type type); - [CCode (cheader_filename = "dazzle.h")] - public static unowned Gtk.Widget? gtk_widget_get_relative (Gtk.Widget widget, GLib.Type relative_type); - [CCode (cheader_filename = "dazzle.h")] - public static void gtk_widget_hide_with_fade (Gtk.Widget widget); - [CCode (cheader_filename = "dazzle.h")] - [Version (since = "3.26")] - public static bool gtk_widget_is_ancestor_or_relative (Gtk.Widget widget, Gtk.Widget ancestor); - [CCode (cheader_filename = "dazzle.h")] - public static void gtk_widget_mux_action_groups (Gtk.Widget widget, Gtk.Widget from_widget, string? mux_key); - [CCode (cheader_filename = "dazzle.h")] - public static void gtk_widget_remove_style_class (Gtk.Widget widget, string class_name); - [CCode (cheader_filename = "dazzle.h")] - public static void gtk_widget_show_with_fade (Gtk.Widget widget); - [CCode (cheader_filename = "dazzle.h")] - public static int levenshtein (string needle, string haystack); - [CCode (cheader_filename = "dazzle.h")] - public static void overlay_add_child (Dazzle.DockOverlay self, Gtk.Widget child, string type); - [CCode (cheader_filename = "dazzle.h")] - public static string pango_font_description_to_css (Pango.FontDescription font_desc); - [CCode (cheader_filename = "dazzle.h")] - public static void rgba_shade (Gdk.RGBA rgba, Gdk.RGBA dst, double k); -} \ No newline at end of file From a2ca47a8134e2a968a307b2ca5f543f4132e4ae6 Mon Sep 17 00:00:00 2001 From: stsdc Date: Sat, 11 Apr 2020 20:55:54 +0200 Subject: [PATCH 92/96] fixes #161 --- src/Managers/Process.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index 9edff12c..7f0a094e 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -246,7 +246,7 @@ public class Monitor.Process : GLib.Object { if (err is FileError.ACCES) { fd_permission_error (err.message); } else { - error (err.message); + warning (err.message); } } return true; From 1aa5fa562a480142d7d5a5c5dea5814d3f46b546 Mon Sep 17 00:00:00 2001 From: stsdc Date: Sat, 11 Apr 2020 21:15:20 +0200 Subject: [PATCH 93/96] changelogs and screenshot --- data/com.github.stsdc.monitor.appdata.xml.in | 8 +++++--- data/com.github.stsdc.monitor.screenshot.png | Bin 56942 -> 131158 bytes debian/changelog | 7 +++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/data/com.github.stsdc.monitor.appdata.xml.in b/data/com.github.stsdc.monitor.appdata.xml.in index 82e4ce5b..2a191d2c 100644 --- a/data/com.github.stsdc.monitor.appdata.xml.in +++ b/data/com.github.stsdc.monitor.appdata.xml.in @@ -25,11 +25,13 @@ https://github.com/stsdc/monitor/issues - +
    -
  • Bugfix (potential) of crushes and high CPU usage
  • -
  • Update German translation (Carsten Dietrich)
  • +
  • Detailed process info in sidebar
  • +
  • CPU frequency in tooltip (Ryo Nakano)
  • +
  • Removed tree view . This fixes high CPU usage, indicator hangs, and app crashes
  • +
  • Special thanks to gavr, Ryo Nakano, Adam Bieńkowski and Daniele Cocca
diff --git a/data/com.github.stsdc.monitor.screenshot.png b/data/com.github.stsdc.monitor.screenshot.png index 428bd264bf1df63aa8f287731008dea0680b4731..92336770c4328bc0ef0b3febd8492c706e54a9bf 100644 GIT binary patch literal 131158 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 Tb?=av@H+E{gKgDGzm)$2Ao#^T literal 56942 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 Sat, 11 Apr 2020 21:01:15 +0200 + com.github.stsdc.monitor (0.6.2) bionic; urgency=low * Bugfix (potential) of crushes and high CPU usage From ff7372a18a67fc240d2016371edd4e1cd953529f Mon Sep 17 00:00:00 2001 From: stsdc Date: Sat, 11 Apr 2020 21:21:01 +0200 Subject: [PATCH 94/96] update gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3c571fa7..b9d6950c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ build .vscode *~ .goutputstream-* +./subprojects/*/ \ No newline at end of file From 53211d6304ba5ed661a4b8af36ccc426518e5f88 Mon Sep 17 00:00:00 2001 From: stsdc Date: Sat, 11 Apr 2020 21:21:58 +0200 Subject: [PATCH 95/96] remove live-chart dir --- subprojects/live-chart | 1 - 1 file changed, 1 deletion(-) delete mode 160000 subprojects/live-chart diff --git a/subprojects/live-chart b/subprojects/live-chart deleted file mode 160000 index 4bfb0588..00000000 --- a/subprojects/live-chart +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4bfb0588157f9bfa8ad660db361b5ab5e9aeff1b From 96236c31a73356ce19d2eb89dbeb23e5a56c5fc5 Mon Sep 17 00:00:00 2001 From: stsdc Date: Sat, 11 Apr 2020 21:25:05 +0200 Subject: [PATCH 96/96] exclude subdirectories in subproject directory in .gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b9d6950c..633af797 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ build .vscode *~ .goutputstream-* -./subprojects/*/ \ No newline at end of file +subprojects/*/ \ No newline at end of file