/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Procman - main window * Copyright (C) 2001 Kevin Vandersloot * * 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 2 * 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 Library General Public * License along with this program; if not, see . * */ #include #include #include #include #include #include #include #include #include #include #include #include "interface.h" #include "proctable.h" #include "procactions.h" #include "procdialogs.h" #include "setaffinity.h" #include "memmaps.h" #include "openfiles.h" #include "procproperties.h" #include "load-graph.h" #include "util.h" #include "disks.h" #include "settings-keys.h" #include "legacy/gsm_color_button.h" static const char* LOAD_GRAPH_CSS = "\ .loadgraph {\ background: linear-gradient(to bottom,\ @theme_bg_color,\ @theme_base_color\ );\ color: mix (@theme_fg_color, @theme_bg_color, 0.5);\ }\ "; static gboolean cb_window_key_press_event (GtkWidget *widget, GdkEvent *event, gpointer user_data) { const char *current_page = gtk_stack_get_visible_child_name (GTK_STACK (GsmApplication::get()->stack)); if (strcmp (current_page, "processes") == 0) return gtk_search_bar_handle_event (GTK_SEARCH_BAR (user_data), event); return FALSE; } static void search_text_changed (GtkEditable *entry, gpointer data) { GsmApplication * const app = static_cast(data); gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (gtk_tree_model_sort_get_model ( GTK_TREE_MODEL_SORT (gtk_tree_view_get_model( GTK_TREE_VIEW (app->tree)))))); } static void set_affinity_visiblity (GtkWidget *widget, gpointer user_data) { #ifndef __linux__ GtkMenuItem *item = GTK_MENU_ITEM (widget); const gchar *name = gtk_menu_item_get_label (item); if (strcmp (name, "Set _Affinity") == 0) { gtk_widget_set_visible (widget, false); } #endif } static void create_proc_view(GsmApplication *app, GtkBuilder * builder) { GsmTreeView *proctree; GtkScrolledWindow *scrolled; proctree = proctable_new (app); scrolled = GTK_SCROLLED_WINDOW (gtk_builder_get_object (builder, "processes_scrolled")); gtk_container_add (GTK_CONTAINER (scrolled), GTK_WIDGET (proctree)); app->proc_actionbar_revealer = GTK_REVEALER (gtk_builder_get_object (builder, "proc_actionbar_revealer")); /* create popup_menu for the processes tab */ GMenuModel *menu_model = G_MENU_MODEL (gtk_builder_get_object (builder, "process-popup-menu")); app->popup_menu = GTK_MENU (gtk_menu_new_from_model (menu_model)); gtk_menu_attach_to_widget (app->popup_menu, GTK_WIDGET (app->main_window), NULL); gtk_container_foreach (GTK_CONTAINER (app->popup_menu), set_affinity_visiblity, NULL); app->search_bar = GTK_SEARCH_BAR (gtk_builder_get_object (builder, "proc_searchbar")); app->search_entry = GTK_SEARCH_ENTRY (gtk_builder_get_object (builder, "proc_searchentry")); gtk_search_bar_connect_entry (app->search_bar, GTK_ENTRY (app->search_entry)); g_signal_connect (app->main_window, "key-press-event", G_CALLBACK (cb_window_key_press_event), app->search_bar); g_signal_connect (app->search_entry, "changed", G_CALLBACK (search_text_changed), app); g_object_bind_property (app->search_bar, "search-mode-enabled", app->search_button, "active", (GBindingFlags)(G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE)); } static void cb_cpu_color_changed (GsmColorButton *cp, gpointer data) { guint cpu_i = GPOINTER_TO_UINT (data); auto settings = Gio::Settings::create (GSM_GSETTINGS_SCHEMA); /* Get current values */ GVariant *cpu_colors_var = g_settings_get_value (settings->gobj(), GSM_SETTING_CPU_COLORS); gsize children_n = g_variant_n_children(cpu_colors_var); /* Create builder to construct new setting with updated value for cpu i */ GVariantBuilder builder; g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY); for (guint i = 0; i < children_n; i++) { if(cpu_i == i) { gchar *color; GdkRGBA button_color; gsm_color_button_get_color(cp, &button_color); color = gdk_rgba_to_string (&button_color); g_variant_builder_add(&builder, "(us)", i, color); g_free (color); } else { g_variant_builder_add_value(&builder, g_variant_get_child_value(cpu_colors_var, i)); } } /* Just set the value and let the changed::cpu-colors signal callback do the rest. */ settings->set_value (GSM_SETTING_CPU_COLORS, Glib::wrap (g_variant_builder_end(&builder))); } static void change_settings_color(Gio::Settings& settings, const char *key, GsmColorButton *cp) { GdkRGBA c; char *color; gsm_color_button_get_color(cp, &c); color = gdk_rgba_to_string (&c); settings.set_string (key, color); g_free (color); } static void cb_mem_color_changed (GsmColorButton *cp, gpointer data) { GsmApplication *app = (GsmApplication *) data; change_settings_color (*app->settings.operator->(), GSM_SETTING_MEM_COLOR, cp); } static void cb_swap_color_changed (GsmColorButton *cp, gpointer data) { GsmApplication *app = (GsmApplication *) data; change_settings_color (*app->settings.operator->(), GSM_SETTING_SWAP_COLOR, cp); } static void cb_net_in_color_changed (GsmColorButton *cp, gpointer data) { GsmApplication *app = (GsmApplication *) data; change_settings_color (*app->settings.operator->(), GSM_SETTING_NET_IN_COLOR, cp); } static void cb_net_out_color_changed (GsmColorButton *cp, gpointer data) { GsmApplication *app = (GsmApplication *) data; change_settings_color(*app->settings.operator->(), GSM_SETTING_NET_OUT_COLOR, cp); } static void create_sys_view (GsmApplication *app, GtkBuilder * builder) { GtkBox *cpu_graph_box, *mem_graph_box, *net_graph_box; GtkExpander *cpu_expander, *mem_expander, *net_expander; GtkLabel *label,*cpu_label; GtkGrid *table; GsmColorButton *color_picker; GtkCssProvider *provider; LoadGraph *cpu_graph, *mem_graph, *net_graph; gint i; gchar *title_text; gchar *label_text; gchar *title_template; provider = gtk_css_provider_new (); gtk_css_provider_load_from_data (provider, LOAD_GRAPH_CSS, -1, NULL); gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); // Translators: color picker title, %s is CPU, Memory, Swap, Receiving, Sending title_template = g_strdup(_("Pick a Color for “%s”")); /* The CPU BOX */ cpu_graph_box = GTK_BOX (gtk_builder_get_object (builder, "cpu_graph_box")); cpu_expander = GTK_EXPANDER (gtk_builder_get_object (builder, "cpu_expander")); g_object_bind_property (cpu_expander, "expanded", cpu_expander, "vexpand", G_BINDING_DEFAULT); cpu_graph = new LoadGraph(LOAD_GRAPH_CPU); gtk_widget_set_size_request (GTK_WIDGET(load_graph_get_widget(cpu_graph)), -1, 70); gtk_box_pack_start (cpu_graph_box, GTK_WIDGET (load_graph_get_widget(cpu_graph)), TRUE, TRUE, 0); GtkGrid* cpu_table = GTK_GRID (gtk_builder_get_object (builder, "cpu_table")); gint cols = 4; for (i=0;iconfig.num_cpus; i++) { GtkBox *temp_hbox; temp_hbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0)); gtk_widget_show (GTK_WIDGET (temp_hbox)); if (i < cols) { gtk_grid_insert_column(cpu_table, i%cols); } if ((i+1)%cols ==cols) { gtk_grid_insert_row(cpu_table, (i+1)/cols); } gtk_grid_attach(cpu_table, GTK_WIDGET (temp_hbox), i%cols, i/cols, 1, 1); color_picker = gsm_color_button_new (&cpu_graph->colors.at(i), GSMCP_TYPE_CPU); g_signal_connect (G_OBJECT (color_picker), "color-set", G_CALLBACK (cb_cpu_color_changed), GINT_TO_POINTER (i)); gtk_box_pack_start (temp_hbox, GTK_WIDGET (color_picker), FALSE, TRUE, 0); gtk_widget_set_size_request(GTK_WIDGET(color_picker), 32, -1); if(app->config.num_cpus == 1) { label_text = g_strdup (_("CPU")); } else { label_text = g_strdup_printf (_("CPU%d"), i+1); } title_text = g_strdup_printf(title_template, label_text); label = GTK_LABEL (gtk_label_new (label_text)); gtk_label_set_xalign(label, 0.0); if(app->config.num_cpus >=10) { gtk_label_set_width_chars(label, log10(app->config.num_cpus)+1+4); } gsm_color_button_set_title(color_picker, title_text); g_free(title_text); gtk_box_pack_start (temp_hbox, GTK_WIDGET (label), FALSE, FALSE, 6); gtk_widget_show (GTK_WIDGET (label)); g_free (label_text); cpu_label = make_tnum_label (); /* Reserve some space to avoid the layout changing with the values. */ gtk_label_set_width_chars(cpu_label, 6); gtk_label_set_xalign(cpu_label, 1.0); gtk_widget_set_valign (GTK_WIDGET (cpu_label), GTK_ALIGN_CENTER); gtk_widget_set_halign (GTK_WIDGET (cpu_label), GTK_ALIGN_START); gtk_box_pack_start (temp_hbox, GTK_WIDGET (cpu_label), FALSE, FALSE, 0); gtk_widget_show (GTK_WIDGET (cpu_label)); load_graph_get_labels(cpu_graph)->cpu[i] = cpu_label; } app->cpu_graph = cpu_graph; /** The memory box */ mem_graph_box = GTK_BOX (gtk_builder_get_object (builder, "mem_graph_box")); mem_expander = GTK_EXPANDER (gtk_builder_get_object (builder, "mem_expander")); g_object_bind_property (mem_expander, "expanded", mem_expander, "vexpand", G_BINDING_DEFAULT); mem_graph = new LoadGraph(LOAD_GRAPH_MEM); gtk_widget_set_size_request (GTK_WIDGET(load_graph_get_widget(mem_graph)), -1, 70); gtk_box_pack_start (mem_graph_box, GTK_WIDGET (load_graph_get_widget(mem_graph)), TRUE, TRUE, 0); table = GTK_GRID (gtk_builder_get_object (builder, "mem_table")); color_picker = load_graph_get_mem_color_picker(mem_graph); g_signal_connect (G_OBJECT (color_picker), "color-set", G_CALLBACK (cb_mem_color_changed), app); title_text = g_strdup_printf(title_template, _("Memory")); gsm_color_button_set_title(color_picker, title_text); g_free(title_text); label = GTK_LABEL (gtk_builder_get_object(builder, "memory_label")); gtk_grid_attach_next_to (table, GTK_WIDGET (color_picker), GTK_WIDGET (label), GTK_POS_LEFT, 1, 3); gtk_grid_attach_next_to (table, GTK_WIDGET (load_graph_get_labels(mem_graph)->memory), GTK_WIDGET (label), GTK_POS_BOTTOM, 1, 2); color_picker = load_graph_get_swap_color_picker(mem_graph); g_signal_connect (G_OBJECT (color_picker), "color-set", G_CALLBACK (cb_swap_color_changed), app); title_text = g_strdup_printf(title_template, _("Swap")); gsm_color_button_set_title(GSM_COLOR_BUTTON(color_picker), title_text); g_free(title_text); label = GTK_LABEL (gtk_builder_get_object(builder, "swap_label")); gtk_grid_attach_next_to (table, GTK_WIDGET (color_picker), GTK_WIDGET (label), GTK_POS_LEFT, 1, 3); gtk_grid_attach_next_to (table, GTK_WIDGET (load_graph_get_labels(mem_graph)->swap), GTK_WIDGET (label), GTK_POS_BOTTOM, 1, 2); app->mem_graph = mem_graph; /* The net box */ net_graph_box = GTK_BOX (gtk_builder_get_object (builder, "net_graph_box")); net_expander = GTK_EXPANDER (gtk_builder_get_object (builder, "net_expander")); g_object_bind_property (net_expander, "expanded", net_expander, "vexpand", G_BINDING_DEFAULT); net_graph = new LoadGraph(LOAD_GRAPH_NET); gtk_widget_set_size_request (GTK_WIDGET(load_graph_get_widget(net_graph)), -1, 70); gtk_box_pack_start (net_graph_box, GTK_WIDGET (load_graph_get_widget(net_graph)), TRUE, TRUE, 0); table = GTK_GRID (gtk_builder_get_object (builder, "net_table")); color_picker = gsm_color_button_new ( &net_graph->colors.at(0), GSMCP_TYPE_NETWORK_IN); gtk_widget_set_valign (GTK_WIDGET(color_picker), GTK_ALIGN_CENTER); g_signal_connect (G_OBJECT (color_picker), "color-set", G_CALLBACK (cb_net_in_color_changed), app); title_text = g_strdup_printf(title_template, _("Receiving")); gsm_color_button_set_title(color_picker, title_text); g_free(title_text); label = GTK_LABEL (gtk_builder_get_object(builder, "receiving_label")); gtk_grid_attach_next_to (table, GTK_WIDGET (color_picker), GTK_WIDGET (label), GTK_POS_LEFT, 1, 2); gtk_grid_attach_next_to (table, GTK_WIDGET (load_graph_get_labels(net_graph)->net_in), GTK_WIDGET (label), GTK_POS_RIGHT, 1, 1); label = GTK_LABEL (gtk_builder_get_object(builder, "total_received_label")); gtk_grid_attach_next_to (table, GTK_WIDGET (load_graph_get_labels(net_graph)->net_in_total), GTK_WIDGET (label), GTK_POS_RIGHT, 1, 1); color_picker = gsm_color_button_new ( &net_graph->colors.at(1), GSMCP_TYPE_NETWORK_OUT); gtk_widget_set_valign (GTK_WIDGET(color_picker), GTK_ALIGN_CENTER); gtk_widget_set_hexpand (GTK_WIDGET(color_picker), true); gtk_widget_set_halign (GTK_WIDGET(color_picker), GTK_ALIGN_END); g_signal_connect (G_OBJECT (color_picker), "color-set", G_CALLBACK (cb_net_out_color_changed), app); title_text = g_strdup_printf(title_template, _("Sending")); gsm_color_button_set_title(color_picker, title_text); g_free(title_text); label = GTK_LABEL (gtk_builder_get_object(builder, "sending_label")); gtk_grid_attach_next_to (table, GTK_WIDGET (color_picker), GTK_WIDGET (label), GTK_POS_LEFT, 1, 2); gtk_grid_attach_next_to (table, GTK_WIDGET (load_graph_get_labels(net_graph)->net_out), GTK_WIDGET (label), GTK_POS_RIGHT, 1, 1); label = GTK_LABEL (gtk_builder_get_object(builder, "total_sent_label")); gtk_grid_attach_next_to (table, GTK_WIDGET (load_graph_get_labels(net_graph)->net_out_total), GTK_WIDGET (label), GTK_POS_RIGHT, 1, 1); gtk_widget_set_hexpand (GTK_WIDGET(load_graph_get_labels(net_graph)->net_out_total), true); gtk_widget_set_halign (GTK_WIDGET(load_graph_get_labels(net_graph)->net_out_total), GTK_ALIGN_START); gtk_widget_set_hexpand (GTK_WIDGET(load_graph_get_labels(net_graph)->net_out), true); gtk_widget_set_halign (GTK_WIDGET(load_graph_get_labels(net_graph)->net_out), GTK_ALIGN_START); app->net_graph = net_graph; g_free (title_template); } static void on_activate_about (GSimpleAction *, GVariant *, gpointer data) { GsmApplication *app = (GsmApplication *) data; const gchar * const authors[] = { "Kevin Vandersloot", "Erik Johnsson", "Jorgen Scheibengruber", "Benoît Dejean", "Paolo Borelli", "Karl Lattimer", "Chris Kühl", "Robert Roth", "Stefano Facchini", "Jacob Barkdull", NULL }; const gchar * const documenters[] = { "Bill Day", "Sun Microsystems", NULL }; const gchar * const artists[] = { "Baptiste Mille-Mathias", NULL }; gtk_show_about_dialog ( GTK_WINDOW (app->main_window), "name", _("System Monitor"), "comments", _("View current processes and monitor " "system state"), "version", VERSION, "website", "https://wiki.gnome.org/Apps/SystemMonitor", "copyright", "Copyright \xc2\xa9 2001-2004 Kevin Vandersloot\n" "Copyright \xc2\xa9 2005-2007 Benoît Dejean\n" "Copyright \xc2\xa9 2011 Chris Kühl", "logo-icon-name", "org.gnome.SystemMonitor", "authors", authors, "artists", artists, "documenters", documenters, "translator-credits", _("translator-credits"), "license-type", GTK_LICENSE_GPL_2_0, NULL ); } static void on_activate_keyboard_shortcuts (GSimpleAction *, GVariant *, gpointer data) { GsmApplication *app = (GsmApplication *) data; gtk_widget_show (GTK_WIDGET (gtk_application_window_get_help_overlay (GTK_APPLICATION_WINDOW (app->main_window)))); } static void on_activate_refresh (GSimpleAction *, GVariant *, gpointer data) { GsmApplication *app = (GsmApplication *) data; proctable_update (app); } static void kill_process_with_confirmation (GsmApplication *app, int signal) { gboolean kill_dialog = app->settings->get_boolean(GSM_SETTING_SHOW_KILL_DIALOG); if (kill_dialog) procdialog_create_kill_dialog (app, signal); else kill_process (app, signal); } static void on_activate_send_signal (GSimpleAction *, GVariant *parameter, gpointer data) { GsmApplication *app = (GsmApplication *) data; /* no confirmation */ gint32 signal = g_variant_get_int32(parameter); switch (signal) { case SIGCONT: kill_process (app, signal); break; case SIGSTOP: case SIGTERM: case SIGKILL: kill_process_with_confirmation (app, signal); break; } } static void on_activate_set_affinity (GSimpleAction *, GVariant *, gpointer data) { GsmApplication *app = (GsmApplication *) data; create_set_affinity_dialog (app); } static void on_activate_memory_maps (GSimpleAction *, GVariant *, gpointer data) { GsmApplication *app = (GsmApplication *) data; create_memmaps_dialog (app); } static void on_activate_open_files (GSimpleAction *, GVariant *, gpointer data) { GsmApplication *app = (GsmApplication *) data; create_openfiles_dialog (app); } static void on_activate_process_properties (GSimpleAction *, GVariant *, gpointer data) { GsmApplication *app = (GsmApplication *) data; create_procproperties_dialog (app); } static void on_activate_radio (GSimpleAction *action, GVariant *parameter, gpointer data) { g_action_change_state (G_ACTION (action), parameter); } static void on_activate_toggle (GSimpleAction *action, GVariant *parameter, gpointer data) { GVariant *state = g_action_get_state (G_ACTION (action)); g_action_change_state (G_ACTION (action), g_variant_new_boolean (!g_variant_get_boolean (state))); g_variant_unref (state); } static void on_activate_search (GSimpleAction *action, GVariant *parameter, gpointer data) { GsmApplication *app = (GsmApplication *) data; GVariant *state = g_action_get_state (G_ACTION (action)); gboolean is_search_shortcut = g_variant_get_boolean (parameter); gboolean is_search_bar = gtk_search_bar_get_search_mode (app->search_bar); gtk_widget_set_visible (GTK_WIDGET (app->search_bar), is_search_bar || is_search_shortcut); if (is_search_shortcut && is_search_bar) { gtk_widget_grab_focus (GTK_WIDGET (app->search_entry)); } else { g_action_change_state (G_ACTION (action), g_variant_new_boolean (!g_variant_get_boolean (state))); } g_variant_unref (state); } static void change_show_page_state (GSimpleAction *action, GVariant *state, gpointer data) { GsmApplication *app = (GsmApplication *) data; auto state_var = Glib::wrap(state, true); g_simple_action_set_state (action, state); app->settings->set_value (GSM_SETTING_CURRENT_TAB, state_var); } static void change_show_processes_state (GSimpleAction *action, GVariant *state, gpointer data) { GsmApplication *app = (GsmApplication *) data; auto state_var = Glib::wrap(state, true); g_simple_action_set_state (action, state); app->settings->set_value (GSM_SETTING_SHOW_WHOSE_PROCESSES, state_var); } static void change_show_dependencies_state (GSimpleAction *action, GVariant *state, gpointer data) { GsmApplication *app = (GsmApplication *) data; auto state_var = Glib::wrap(state, true); g_simple_action_set_state (action, state); app->settings->set_value (GSM_SETTING_SHOW_DEPENDENCIES, state_var); } static void on_activate_priority (GSimpleAction *action, GVariant *parameter, gpointer data) { GsmApplication *app = (GsmApplication *) data; g_action_change_state (G_ACTION (action), parameter); const gint32 priority = g_variant_get_int32 (parameter); switch (priority) { case 32: procdialog_create_renice_dialog (app); break; default: renice (app, priority); break; } } static void change_priority_state (GSimpleAction *action, GVariant *state, gpointer data) { g_simple_action_set_state (action, state); } static void update_page_activities (GsmApplication *app) { const char *current_page = gtk_stack_get_visible_child_name (app->stack); if (strcmp (current_page, "processes") == 0) { GAction *search_action = g_action_map_lookup_action (G_ACTION_MAP (app->main_window), "search"); proctable_update (app); proctable_thaw (app); gtk_widget_show (GTK_WIDGET (app->end_process_button)); gtk_widget_show (GTK_WIDGET (app->search_button)); gtk_widget_show (GTK_WIDGET (app->process_menu_button)); gtk_widget_hide (GTK_WIDGET (app->window_menu_button)); update_sensitivity (app); if (g_variant_get_boolean (g_action_get_state (search_action))) gtk_widget_grab_focus (GTK_WIDGET (app->search_entry)); else gtk_widget_grab_focus (GTK_WIDGET (app->tree)); } else { proctable_freeze (app); gtk_widget_hide (GTK_WIDGET (app->end_process_button)); gtk_widget_hide (GTK_WIDGET (app->search_button)); gtk_widget_hide (GTK_WIDGET (app->process_menu_button)); gtk_widget_show (GTK_WIDGET (app->window_menu_button)); update_sensitivity (app); } if (strcmp (current_page, "resources") == 0) { load_graph_start (app->cpu_graph); load_graph_start (app->mem_graph); load_graph_start (app->net_graph); } else { load_graph_stop (app->cpu_graph); load_graph_stop (app->mem_graph); load_graph_stop (app->net_graph); } if (strcmp (current_page, "disks") == 0) { disks_update (app); disks_thaw (app); } else { disks_freeze (app); } } static void cb_change_current_page (GtkStack *stack, GParamSpec *pspec, gpointer data) { update_page_activities ((GsmApplication *)data); } static gboolean cb_main_window_delete (GtkWidget *window, GdkEvent *event, gpointer data) { GsmApplication *app = (GsmApplication *) data; app->shutdown (); return TRUE; } static gboolean cb_main_window_state_changed (GtkWidget *window, GdkEventWindowState *event, gpointer data) { GsmApplication *app = (GsmApplication *) data; auto current_page = app->settings->get_string (GSM_SETTING_CURRENT_TAB); if (event->new_window_state & GDK_WINDOW_STATE_BELOW || event->new_window_state & GDK_WINDOW_STATE_ICONIFIED || event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN) { if (current_page == "processes") { proctable_freeze (app); } else if (current_page == "resources") { load_graph_stop (app->cpu_graph); load_graph_stop (app->mem_graph); load_graph_stop (app->net_graph); } else if (current_page == "disks") { disks_freeze (app); } } else { if (current_page == "processes") { proctable_update (app); proctable_thaw (app); } else if (current_page == "resources") { load_graph_start (app->cpu_graph); load_graph_start (app->mem_graph); load_graph_start (app->net_graph); } else if (current_page == "disks") { disks_update (app); disks_thaw (app); } } return FALSE; } void create_main_window (GsmApplication *app) { HdyApplicationWindow *main_window; GtkStack *stack; GMenuModel *window_menu_model; GMenuModel *process_menu_model; GdkDisplay *display; GdkMonitor *monitor; GdkRectangle monitor_geometry; int width, height, xpos, ypos; GtkBuilder *builder = gtk_builder_new(); gtk_builder_add_from_resource (builder, "/org/gnome/gnome-system-monitor/data/interface.ui", NULL); gtk_builder_add_from_resource (builder, "/org/gnome/gnome-system-monitor/data/menus.ui", NULL); gtk_builder_add_from_resource (builder, "/org/gnome/gnome-system-monitor/gtk/help-overlay.ui", NULL); main_window = HDY_APPLICATION_WINDOW (gtk_builder_get_object (builder, "main_window")); gtk_window_set_application (GTK_WINDOW (main_window), app->gobj()); gtk_widget_set_name (GTK_WIDGET (main_window), "gnome-system-monitor"); app->main_window = main_window; gtk_application_window_set_help_overlay (GTK_APPLICATION_WINDOW (app->main_window), GTK_SHORTCUTS_WINDOW (gtk_builder_get_object (builder, "help_overlay"))); g_settings_get (app->settings->gobj(), GSM_SETTING_WINDOW_STATE, "(iiii)", &width, &height, &xpos, &ypos); display = gdk_display_get_default (); monitor = gdk_display_get_monitor_at_point (display, xpos, ypos); if (monitor == NULL) { monitor = gdk_display_get_monitor (display, 0); } gdk_monitor_get_geometry (monitor, &monitor_geometry); width = CLAMP (width, 50, monitor_geometry.width); height = CLAMP (height, 50, monitor_geometry.height); xpos = CLAMP (xpos, 0, monitor_geometry.width - width); ypos = CLAMP (ypos, 0, monitor_geometry.height - height); gtk_window_set_default_size (GTK_WINDOW (main_window), width, height); gtk_window_move (GTK_WINDOW (main_window), xpos, ypos); if (app->settings->get_boolean (GSM_SETTING_MAXIMIZED)) gtk_window_maximize (GTK_WINDOW (main_window)); app->process_menu_button = GTK_MENU_BUTTON (gtk_builder_get_object (builder, "process_menu_button")); process_menu_model = G_MENU_MODEL (gtk_builder_get_object (builder, "process-window-menu")); gtk_menu_button_set_menu_model (app->process_menu_button, process_menu_model); app->window_menu_button = GTK_MENU_BUTTON (gtk_builder_get_object (builder, "window_menu_button")); window_menu_model = G_MENU_MODEL (gtk_builder_get_object (builder, "generic-window-menu")); gtk_menu_button_set_menu_model (app->window_menu_button, window_menu_model); app->end_process_button = GTK_BUTTON (gtk_builder_get_object (builder, "end_process_button")); app->search_button = GTK_BUTTON (gtk_builder_get_object (builder, "search_button")); GActionEntry win_action_entries[] = { { "about", on_activate_about, NULL, NULL, NULL }, { "show-help-overlay", on_activate_keyboard_shortcuts, NULL, NULL, NULL}, { "search", on_activate_search, "b", "false", NULL }, { "send-signal-stop", on_activate_send_signal, "i", NULL, NULL }, { "send-signal-cont", on_activate_send_signal, "i", NULL, NULL }, { "send-signal-end", on_activate_send_signal, "i", NULL, NULL }, { "send-signal-kill", on_activate_send_signal, "i", NULL, NULL }, { "priority", on_activate_priority, "i", "@i 0", change_priority_state }, { "set-affinity", on_activate_set_affinity, NULL, NULL, NULL }, { "memory-maps", on_activate_memory_maps, NULL, NULL, NULL }, { "open-files", on_activate_open_files, NULL, NULL, NULL }, { "process-properties", on_activate_process_properties, NULL, NULL, NULL }, { "refresh", on_activate_refresh, NULL, NULL, NULL }, { "show-page", on_activate_radio, "s", "'resources'", change_show_page_state }, { "show-whose-processes", on_activate_radio, "s", "'all'", change_show_processes_state }, { "show-dependencies", on_activate_toggle, NULL, "false", change_show_dependencies_state } }; g_action_map_add_action_entries (G_ACTION_MAP (main_window), win_action_entries, G_N_ELEMENTS (win_action_entries), app); GdkScreen* screen = gtk_widget_get_screen(GTK_WIDGET (main_window)); GdkVisual* visual = gdk_screen_get_rgba_visual(screen); /* use visual, if available */ if (visual) gtk_widget_set_visual(GTK_WIDGET (main_window), visual); /* create the main stack */ app->stack = stack = GTK_STACK (gtk_builder_get_object (builder, "stack")); create_proc_view(app, builder); create_sys_view (app, builder); create_disk_view (app, builder); g_settings_bind (app->settings->gobj (), GSM_SETTING_CURRENT_TAB, stack, "visible-child-name", G_SETTINGS_BIND_DEFAULT); g_signal_connect (G_OBJECT (stack), "notify::visible-child", G_CALLBACK (cb_change_current_page), app); g_signal_connect (G_OBJECT (main_window), "delete_event", G_CALLBACK (cb_main_window_delete), app); g_signal_connect (G_OBJECT (main_window), "window-state-event", G_CALLBACK (cb_main_window_state_changed), app); GAction *action; action = g_action_map_lookup_action (G_ACTION_MAP (main_window), "show-dependencies"); g_action_change_state (action, g_settings_get_value (app->settings->gobj (), GSM_SETTING_SHOW_DEPENDENCIES)); action = g_action_map_lookup_action (G_ACTION_MAP (main_window), "show-whose-processes"); g_action_change_state (action, g_settings_get_value (app->settings->gobj (), GSM_SETTING_SHOW_WHOSE_PROCESSES)); gtk_widget_show (GTK_WIDGET (main_window)); update_page_activities (app); g_object_unref (G_OBJECT (builder)); } static gboolean scroll_to_selection (gpointer data) { GsmApplication *app = (GsmApplication *) data; GList* paths = gtk_tree_selection_get_selected_rows (app->selection, NULL); guint length = g_list_length(paths); if (length > 0) { GtkTreePath* last_path = (GtkTreePath*) g_list_nth_data(paths, length - 1); gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (app->tree), last_path, NULL, FALSE, 0.0, 0.0); } g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free); return FALSE; } void update_sensitivity(GsmApplication *app) { const char * const selected_actions[] = { "send-signal-stop", "send-signal-cont", "send-signal-end", "send-signal-kill", "priority", "set-affinity", "memory-maps", "open-files", "process-properties" }; const char * const processes_actions[] = { "refresh", "search", "show-whose-processes", "show-dependencies" }; size_t i; gboolean processes_sensitivity, selected_sensitivity; GAction *action; processes_sensitivity = (strcmp (gtk_stack_get_visible_child_name (GTK_STACK (app->stack)), "processes") == 0); selected_sensitivity = gtk_tree_selection_count_selected_rows (app->selection) > 0; for (i = 0; i != G_N_ELEMENTS (processes_actions); ++i) { action = g_action_map_lookup_action (G_ACTION_MAP (app->main_window), processes_actions[i]); g_simple_action_set_enabled (G_SIMPLE_ACTION (action), processes_sensitivity); } for (i = 0; i != G_N_ELEMENTS (selected_actions); ++i) { action = g_action_map_lookup_action (G_ACTION_MAP (app->main_window), selected_actions[i]); g_simple_action_set_enabled (G_SIMPLE_ACTION (action), processes_sensitivity & selected_sensitivity); } gtk_revealer_set_reveal_child (GTK_REVEALER (app->proc_actionbar_revealer), selected_sensitivity); // Scrolls the table to selected row. Useful when the last row is obstructed by the revealer guint duration_ms = gtk_revealer_get_transition_duration (GTK_REVEALER (app->proc_actionbar_revealer)); g_timeout_add (duration_ms, scroll_to_selection, app); }