From cc6dbd8373a5309f7136c72cd8a28e067dc2f1c2 Mon Sep 17 00:00:00 2001 From: Mike Massonnet Date: Wed, 28 Apr 2010 17:40:54 +0200 Subject: [PATCH] Initial commit of new interface Changes touching the build: - Bumped version to 0.5.0. - Removed dependency on Xfce libs (it only depends on GTK+-2.0.) - Updated Makefile with new source files. - Build ChangeLog through a script (remove it from source tree.) More generally speaking, the interface is build on top of a GtkBuilder UI definition, with a personal GtkTreeView and a Settings GObject to update the information shown on the interface on changes. All the code is being written with GObjects which will make it a lot easier to separate GUI code and system code. --- ChangeLog | 142 --------- Makefile.am | 10 +- configure.in.in => configure.ac.in | 10 +- src/Makefile.am | 43 +-- src/main.c | 46 +-- src/menu-positions.c | 37 --- src/menu-positions.h | 35 --- src/process-tree-view.c | 248 ++++++++++++++++ src/process-tree-view.h | 31 ++ src/process-window.c | 445 +++++++++++++++++++++++++++++ src/process-window.h | 34 +++ src/process-window.ui | 147 ++++++++++ src/settings.c | 311 ++++++++++++++++++++ src/settings.h | 31 ++ 14 files changed, 1280 insertions(+), 290 deletions(-) delete mode 100644 ChangeLog rename configure.in.in => configure.ac.in (92%) delete mode 100644 src/menu-positions.c delete mode 100644 src/menu-positions.h create mode 100644 src/process-tree-view.c create mode 100644 src/process-tree-view.h create mode 100644 src/process-window.c create mode 100644 src/process-window.h create mode 100644 src/process-window.ui create mode 100644 src/settings.c create mode 100644 src/settings.h diff --git a/ChangeLog b/ChangeLog deleted file mode 100644 index 3bdf00b..0000000 --- a/ChangeLog +++ /dev/null @@ -1,142 +0,0 @@ -2009-09-11 Mike Massonnet - - * Small factorize on cmdline reading. - -2009-09-09 Mike Massonnet - - * Show command line arguments in Linux. - -2009-09-08 Mike Massonnet - - * Update Solaris patch from Peter Tribble. - * Check for the lib kstat in the autoconf script. - * Build with the correct file for Solaris in the automake script. - * Fixed the xfce_err messages and switched to g_snprintf for the - command strings. - * Updated the TODO file. - -2009-09-03 Mike Massonnet - - * Add support for Solaris from Peter Tribble - -2008-09-21 Mike Massonnet - - * Fix build for libtool 2.2 (or at least for ArchLinux) - -2008-09-15 Mike Massonnet - -=== Release 0.4.1 === - -2008-08-08 Mike Massonnet - - * Refresh deprecated GtkTooltips against new GtkTooltip code - * Rework the border size between the GtkBox's - -2008-08-03 Mike Massonnet - - * New function to get the full and short cmdline (Linux) - * Fix compare functions (now works with floats and insensitive text) - * Fix cast which makes the CPU usage per process worky for multi-cores - -2008-08-02 Mike Massonnet - - * Display memory less than 1 MB with two decimals like 0.00 MB - * Quick clean up - * Update TODO - -2008-07-31 Mike Massonnet - - * Apply patch for BSD support from Landry Breuil - -2008-05-11 Mike Massonnet - -=== Release 0.4.0 === - -2008-05-11 Mike Massonnet - - * Set window icon to "xfce-system" and modify the about dialog - -2008-05-10 Mike Massonnet - - * Redo what is displayed in More info (PPID, STATE, VM-size), and keep RSS - in normal info - -2008-05-10 Mike Massonnet - - * Set buffer_status to 1024 (fixes issues with 64bit archs) bug#4059 - * Use convenience macro GINT_TO_POINTER to pass to user_data - -2008-05-09 Mike Massonnet - - * Properly refresh the CPU usage of a process - * Properly display the memory usage and fix signal connected on the - show_cached_as_free menu item - -2008-05-09 Mike Massonnet - - * Save sort column/type in config - * Set command column to expand and ellipsize - * Right align numerical columns - -2008-05-09 Mike Massonnet - - * Fix the event of the main menu to display on keyboard and mouse - * Properly position the main menu - * Properly save window size on quit - -2008-05-09 Mike Massonnet - - * Fix strings - -2008-05-08 Mike Massonnet - - * Properly refresh processes on CPU usage - * Correctly display the memory size of the processes - -2008-05-05 Mike Massonnet - - * Delete automated files - * Remove useless gettext() and properly align menu items on the right - -2008-02-10 Johannes Zellner - - * Initial priority setting - * Few bug fixes - -2007-01-12 Nick Schermer - - * Change version number and svn revision support in configure.in.in - -2007-01-12 Nick Schermer - - * Apply patch from Álvaro Lopes to fix CPU usage per task, with - more then 1 CPU. - * Added a THANKS file. - * Remove some svn executable properties and add svn keywords. - * Added LINGUAS support and removed the configure.ac > configure.in.in file. - * Improved the configure.in.in and Makefiles. - -2007-01-12 Nick Schermer - - * Apply patch from bug 2714. - * Fix all typo and compiler warnings. - -2006-06-26 Johannes Zellner - - * rewrite of the taskmanager ;) - * now using seperate files for each os to get the processinfos - -2005-07-05 Johannes Zellner - - * added finnish translation - * fixed a memory leak in functions.c - -2005-06-30 Johannes Zellner - - * bugfix in the sorting function - * name of about-dialog changed - * scrollbars only showed when needed - -2005-06-30 Johannes Zellner - - * started completly new ;) diff --git a/Makefile.am b/Makefile.am index c7890e7..4a3c2d6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,3 @@ -# $Id$ - SUBDIRS = \ po \ src @@ -9,12 +7,8 @@ desktop_in_files = xfce4-taskmanager.desktop.in desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) @INTLTOOL_DESKTOP_RULE@ -distclean-local: - rm -rf *.cache *~ - -rpm: dist - rpmbuild -ta $(PACKAGE)-$(VERSION).tar.gz - @rm -f $(PACKAGE)-$(VERSION).tar.gz +ChangeLog: + ChangeLog-git.sh > $(srcdir)/ChangeLog || touch $(srcdir)/ChangeLog EXTRA_DIST = \ intltool-extract.in \ diff --git a/configure.in.in b/configure.ac.in similarity index 92% rename from configure.in.in rename to configure.ac.in index 35e16cd..c8013a1 100644 --- a/configure.in.in +++ b/configure.ac.in @@ -7,8 +7,8 @@ dnl *************************** dnl *** Version information *** dnl *************************** m4_define([taskmanager_version_major], [0]) -m4_define([taskmanager_version_minor], [4]) -m4_define([taskmanager_version_micro], [1]) +m4_define([taskmanager_version_minor], [5]) +m4_define([taskmanager_version_micro], [0]) m4_define([taskmanager_version_build], [@REVISION@]) m4_define([taskmanager_version_tag], [git]) m4_define([taskmanager_version], [taskmanager_version_major().taskmanager_version_minor().taskmanager_version_micro()ifelse(taskmanager_version_tag(), [git], [taskmanager_version_tag()-taskmanager_version_build()], [taskmanager_version_tag()])]) @@ -30,6 +30,7 @@ dnl *************************** AM_INIT_AUTOMAKE([1.8 dist-bzip2]) AM_CONFIG_HEADER([config.h]) AM_MAINTAINER_MODE() +AM_SILENT_RULES([yes]) dnl ******************************* dnl *** Check for UNIX variants *** @@ -42,6 +43,7 @@ dnl ******************************** dnl *** Check for basic programs *** dnl ******************************** AC_PROG_CC() +AM_PROG_CC_C_O() AC_PROG_LD() AC_PROG_INSTALL() AC_PROG_LIBTOOL() @@ -68,9 +70,7 @@ XDT_I18N([@LINGUAS@]) dnl *********************************** dnl *** Check for required packages *** dnl *********************************** -XDT_CHECK_PACKAGE([LIBXFCEGUI4], [libxfcegui4-1.0], [4.4.0]) -XDT_CHECK_PACKAGE([LIBXFCE4UTIL], [libxfce4util-1.0], [4.4.0]) -XDT_CHECK_PACKAGE([GTK], [gtk+-2.0], [2.2.0]) +XDT_CHECK_PACKAGE([GTK], [gtk+-2.0], [2.12.0]) dnl *********************************** dnl ******* Check for OS family ******* diff --git a/src/Makefile.am b/src/Makefile.am index a1fc0b4..854536f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,3 +1,5 @@ +NULL = + INCLUDES = \ -I$(top_srcdir)/include \ -DG_LOG_DOMAIN=\"xfce4-taskmanager\" \ @@ -6,37 +8,22 @@ INCLUDES = \ bin_PROGRAMS = \ xfce4-taskmanager -xfce4_taskmanager_SOURCES = \ - main.c \ - callbacks.c \ - callbacks.h \ - menu-positions.c \ - menu-positions.h \ - functions.c \ - functions.h \ - interface.c \ - interface.h \ - taskmanager.h \ - types.h - -if OS_BSD_FAMILY -xfce4_taskmanager_SOURCES += taskmanager-bsd.c -endif -if OS_SOLARIS -xfce4_taskmanager_SOURCES += taskmanager-solaris.c -endif -if OS_LINUX -xfce4_taskmanager_SOURCES += taskmanager-linux.c -endif - xfce4_taskmanager_CFLAGS = \ - $(LIBXFCEGUI4_CFLAGS) \ - $(LIBXFCE4UTIL_CFLAGS) \ $(GTK_CFLAGS) xfce4_taskmanager_LDADD = \ - $(LIBXFCEGUI4_LIBS) \ - $(LIBXFCE4UTIL_LIBS) \ $(GTK_LIBS) -# vi:set ts=8 sw=8 noet ai nocindent syntax=automake: +xfce4_taskmanager_SOURCES = \ + main.c \ + process-window.c process-window.h \ + process-tree-view.c process-tree-view.h \ + settings.c settings.h \ + $(NULL) + +if MAINTAINER_MODE +BUILT_SOURCES = process-window_ui.h +process-window_ui.h: process-window.ui + $(AM_V_GEN) exo-csource --static --strip-comments --strip-content --name=process_window_ui $< >$@ +endif + diff --git a/src/main.c b/src/main.c index 4d40ed4..7f86fc6 100644 --- a/src/main.c +++ b/src/main.c @@ -1,38 +1,24 @@ -/* $Id$ - * - * Copyright (c) 2006 Johannes Zellner, +/* + * Copyright (c) 2005-2006 Johannes Zellner, + * Copyright (c) 2010 Mike Massonnet, * * 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 Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H -# include +#include #endif #include -#include -#include -#include - -#include "types.h" -#include "interface.h" -#include "functions.h" +#include "process-window.h" int main (int argc, char *argv[]) { + GtkWidget *window; #ifdef ENABLE_NLS bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); @@ -40,27 +26,17 @@ int main (int argc, char *argv[]) textdomain (GETTEXT_PACKAGE); #endif - gtk_set_locale (); gtk_init (&argc, &argv); - own_uid = getuid(); + window = xtm_process_window_new (); + gtk_widget_show (window); - config_file = xfce_resource_save_location(XFCE_RESOURCE_CONFIG, "xfce4-taskmanager.rc", FALSE); - load_config(); - - task_array = g_array_new (FALSE, FALSE, sizeof (struct task)); - tasks = 0; - - main_window = create_main_window (); - gtk_widget_show (main_window); - - if(!refresh_task_list()) - return 0; - - g_timeout_add(REFRESH_INTERVAL, (gpointer) refresh_task_list, NULL); + g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); gtk_main (); + g_object_unref (window); + return 0; } diff --git a/src/menu-positions.c b/src/menu-positions.c deleted file mode 100644 index 16ae4e8..0000000 --- a/src/menu-positions.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * xfce4-taskmanager - very simple taskmanager - * - * Copyright (c) 2008 Mike Massonnet - * - * 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 Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include "menu-positions.h" - -void position_menu_cover_widget(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, GtkWidget *widget) -{ - GtkRequisition requisition; - - gdk_window_get_origin(widget->window, x, y); - *x += widget->allocation.x; - *y += widget->allocation.y; - - gtk_widget_size_request(GTK_WIDGET(menu), &requisition); - if(*y + requisition.height > gdk_screen_height()) - *y = gdk_screen_height() - requisition.height; - else if(*y < 0) - *y = 0; -} - diff --git a/src/menu-positions.h b/src/menu-positions.h deleted file mode 100644 index 5f8019a..0000000 --- a/src/menu-positions.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * xfce4-taskmanager - very simple taskmanger - * - * Copyright (c) 2008 Mike Massonnet - * - * 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 Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __MENU_POSITIONS_H_ -#define __MENU_POSITIONS_H_ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#include "functions.h" -#include "interface.h" - -void position_menu_cover_widget(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, GtkWidget *widget); - -#endif diff --git a/src/process-tree-view.c b/src/process-tree-view.c new file mode 100644 index 0000000..e649f58 --- /dev/null +++ b/src/process-tree-view.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2010 Mike Massonnet, + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "process-tree-view.h" +#include "settings.h" + + + +typedef struct _XtmProcessTreeViewClass XtmProcessTreeViewClass; +struct _XtmProcessTreeViewClass +{ + GtkTreeViewClass parent_class; +}; +struct _XtmProcessTreeView +{ + GtkTreeView parent; + /**/ + GtkListStore * model; + XtmSettings * settings; +}; +G_DEFINE_TYPE (XtmProcessTreeView, xtm_process_tree_view, GTK_TYPE_TREE_VIEW) + +enum +{ + COLUMN_COMMAND, + COLUMN_PID, + COLUMN_PPID, + COLUMN_STATE, + COLUMN_VSZ, + COLUMN_RSS, + COLUMN_UID, + COLUMN_CPU, + COLUMN_PRIORITY, + N_COLUMNS, +}; + +static gboolean treeview_clicked (XtmProcessTreeView *treeview, GdkEventButton *event); +static void settings_changed (GObject *object, GParamSpec *pspec, XtmProcessTreeView *treeview); +static int sort_by_string (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data); + + + +static void +xtm_process_tree_view_class_init (XtmProcessTreeViewClass *klass) +{ + GObjectClass *class = G_OBJECT_CLASS (klass); + xtm_process_tree_view_parent_class = g_type_class_peek_parent (klass); +} + +static void +xtm_process_tree_view_init (XtmProcessTreeView *treeview) +{ + GtkCellRenderer *cell_text, *cell_right_aligned, *cell_cmdline; + GtkTreeViewColumn *column; + gboolean visible; + guint sort_column_id; + GtkSortType sort_type; + + treeview->settings = xtm_settings_get_default (); + g_object_get (treeview->settings, "sort-column-id", &sort_column_id, "sort-type", &sort_type, NULL); + g_signal_connect (treeview->settings, "notify", G_CALLBACK (settings_changed), treeview); + + treeview->model = gtk_list_store_new (9, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); + + g_object_set (treeview, "search-column", COLUMN_COMMAND, "model", treeview->model, NULL); + + cell_text = gtk_cell_renderer_text_new(); + + cell_right_aligned = gtk_cell_renderer_text_new (); + g_object_set (cell_right_aligned, "xalign", 1.0, NULL); + + cell_cmdline = gtk_cell_renderer_text_new (); + g_object_set (cell_cmdline, "ellipsize", PANGO_ELLIPSIZE_END, NULL); + + column = gtk_tree_view_column_new_with_attributes (_("Task"), cell_cmdline, "text", COLUMN_COMMAND, NULL); + g_object_set (column, "expand", TRUE, "reorderable", FALSE, "resizable", TRUE, "visible", TRUE, NULL); + gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_COMMAND); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + g_object_get (treeview->settings, "column-pid", &visible, NULL); + column = gtk_tree_view_column_new_with_attributes (_("PID"), cell_right_aligned, "text", COLUMN_PID, NULL); + g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL); + gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_PID); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + g_object_get (treeview->settings, "column-ppid", &visible, NULL); + column = gtk_tree_view_column_new_with_attributes (_("PPID"), cell_right_aligned, "text", COLUMN_PPID, NULL); + g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL); + gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_PPID); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + g_object_get (treeview->settings, "column-state", &visible, NULL); + column = gtk_tree_view_column_new_with_attributes (_("State"), cell_text, "text", COLUMN_STATE, NULL); + g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL); + gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_STATE); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + g_object_get (treeview->settings, "column-vsz", &visible, NULL); + column = gtk_tree_view_column_new_with_attributes (_("VSZ"), cell_right_aligned, "text", COLUMN_VSZ, NULL); + g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL); + gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_VSZ); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + g_object_get (treeview->settings, "column-rss", &visible, NULL); + column = gtk_tree_view_column_new_with_attributes (_("RSS"), cell_right_aligned, "text", COLUMN_RSS, NULL); + g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL); + gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_RSS); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + g_object_get (treeview->settings, "column-uid", &visible, NULL); + column = gtk_tree_view_column_new_with_attributes (_("UID"), cell_text, "text", COLUMN_UID, NULL); + g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL); + gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_UID); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + g_object_get (treeview->settings, "column-cpu", &visible, NULL); + column = gtk_tree_view_column_new_with_attributes (_("CPU"), cell_right_aligned, "text", COLUMN_CPU, NULL); + g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL); + gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_CPU); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + g_object_get (treeview->settings, "column-priority", &visible, NULL); + /* TRANSLATORS: “Prio.†is short for Priority, it appears in the tree view header. */ + column = gtk_tree_view_column_new_with_attributes (_("Prio."), cell_right_aligned, "text", COLUMN_PRIORITY, NULL); + g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL); + gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_PRIORITY); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (treeview->model), sort_by_string, NULL, NULL); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (treeview->model), sort_column_id, sort_type); + + g_signal_connect (treeview, "button-press-event", G_CALLBACK (treeview_clicked), NULL); +} + +/** + * Helper functions + */ + +static gboolean +treeview_clicked (XtmProcessTreeView *treeview, GdkEventButton *event) +{ + if (event->button != 3) + return FALSE; + + g_debug ("popup menu"); + + return TRUE; +} + +static void +settings_changed (GObject *object, GParamSpec *pspec, XtmProcessTreeView *treeview) +{ + if (g_strstr_len (pspec->name, -1, "column-") != NULL) + { + gboolean visible; + gushort column_id; + + if (!g_strcmp0 (pspec->name, "column-uid")) + column_id = COLUMN_UID; + else if (!g_strcmp0 (pspec->name, "column-pid")) + column_id = COLUMN_PID; + else if (!g_strcmp0 (pspec->name, "column-ppid")) + column_id = COLUMN_PPID; + else if (!g_strcmp0 (pspec->name, "column-state")) + column_id = COLUMN_STATE; + else if (!g_strcmp0 (pspec->name, "column-vsz")) + column_id = COLUMN_VSZ; + else if (!g_strcmp0 (pspec->name, "column-rss")) + column_id = COLUMN_RSS; + else if (!g_strcmp0 (pspec->name, "column-cpu")) + column_id = COLUMN_CPU; + else if (!g_strcmp0 (pspec->name, "column-priority")) + column_id = COLUMN_PRIORITY; + + g_object_get (object, pspec->name, &visible, NULL); + gtk_tree_view_column_set_visible (gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), column_id), visible); + } + else if (!g_strcmp0 (pspec->name, "show-system-processes")) + { + gboolean visible; + g_object_get (object, pspec->name, &visible, NULL); + // TODO show/hide system processes from treeview + } +} + +static int +sort_by_string (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) +{ + gint sort_column_id; + GtkSortType order; + gchar *str1 = NULL, *str2 = NULL; + gchar *cstr1 = NULL, *cstr2 = NULL; + gint ret = 0; + + g_debug (__func__); + + if (!gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model), &sort_column_id, &order)) + { + g_debug ("sort column default or unsorted: %d", sort_column_id); + return ret; + } + + gtk_tree_model_get(model, a, sort_column_id, &str1, -1); + gtk_tree_model_get(model, b, sort_column_id, &str2, -1); + + cstr1 = g_utf8_collate_key_for_filename (str1, -1); + cstr2 = g_utf8_collate_key_for_filename (str2, -1); + + if (cstr1 != NULL && cstr2 != NULL) + { + ret = g_utf8_collate (cstr1, cstr2); + } + else if ((cstr1 == NULL && cstr2 != NULL) || (cstr1 != NULL && cstr2 == NULL)) + { + ret = (cstr1 == NULL) ? -1 : 1; + } + + g_free (str1); + g_free (str2); + g_free (cstr1); + g_free (cstr2); + + return ret; +} + + + +GtkWidget * +xtm_process_tree_view_new () +{ + return g_object_new (XTM_TYPE_PROCESS_TREE_VIEW, NULL); +} + diff --git a/src/process-tree-view.h b/src/process-tree-view.h new file mode 100644 index 0000000..71db963 --- /dev/null +++ b/src/process-tree-view.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2010 Mike Massonnet, + * + * 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. + */ + +#ifndef PROCESS_TREE_VIEW_H +#define PROCESS_TREE_VIEW_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#define XTM_TYPE_PROCESS_TREE_VIEW (xtm_process_tree_view_get_type ()) +#define XTM_PROCESS_TREE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XTM_TYPE_PROCESS_TREE_VIEW, XtmProcessTreeView)) +#define XTM_PROCESS_TREE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XTM_TYPE_PROCESS_TREE_VIEW, XtmProcessTreeViewClass)) +#define XTM_IS_PROCESS_TREE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XTM_TYPE_PROCESS_TREE_VIEW)) +#define XTM_IS_PROCESS_TREE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XTM_TYPE_PROCESS_TREE_VIEW)) +#define XTM_PROCESS_TREE_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XTM_TYPE_PROCESS_TREE_VIEW, XtmProcessTreeViewClass)) + +typedef struct _XtmProcessTreeView XtmProcessTreeView; + +GType xtm_process_tree_view_get_type (void); +GtkWidget * xtm_process_tree_view_new (); + +#endif /* !PROCESS_TREE_VIEW_H */ diff --git a/src/process-window.c b/src/process-window.c new file mode 100644 index 0000000..5abc152 --- /dev/null +++ b/src/process-window.c @@ -0,0 +1,445 @@ +/* + * Copyright (c) 2010 Mike Massonnet, + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "settings.h" +#include "process-window.h" +#include "process-window_ui.h" +#include "process-tree-view.h" + + + +enum +{ + PROP_CPU = 1, + PROP_MEMORY, + PROP_NUM_PROCESSES, +}; +typedef struct _XtmProcessWindowClass XtmProcessWindowClass; +typedef struct _XtmProcessWindowPriv XtmProcessWindowPriv; +struct _XtmProcessWindowClass +{ + GtkWidgetClass parent_class; +}; +struct _XtmProcessWindow +{ + GtkWidget parent; + /**/ + XtmProcessWindowPriv * priv; +}; +struct _XtmProcessWindowPriv +{ + GtkBuilder * builder; + GtkWidget * window; + GtkWidget * treeview; + GtkWidget * statusbar; + guint statusbar_context_id; + + gushort cpu; + guint64 memory; + guint num_processes; + + XtmSettings * settings; +}; +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), XTM_TYPE_PROCESS_WINDOW, XtmProcessWindowPriv)) +G_DEFINE_TYPE (XtmProcessWindow, xtm_process_window, GTK_TYPE_WIDGET) + +static void xtm_process_window_finalize (GObject *object); +static void xtm_process_window_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec); +static void xtm_process_window_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); +static void xtm_process_window_show (GtkWidget *widget); +static void xtm_process_window_hide (GtkWidget *widget); + +static void emit_destroy_signal (XtmProcessWindow *window); +static void show_menu_execute_task (XtmProcessWindow *window); +static void show_menu_information (XtmProcessWindow *window); +static void show_about_dialog (XtmProcessWindow *window); +static void update_status_bar (XtmProcessWindow *window); + + + +static void +xtm_process_window_class_init (XtmProcessWindowClass *klass) +{ + GObjectClass *class; + GtkWidgetClass *widget_class; + + g_type_class_add_private (klass, sizeof (XtmProcessWindowPriv)); + xtm_process_window_parent_class = g_type_class_peek_parent (klass); + class = G_OBJECT_CLASS (klass); + class->finalize = xtm_process_window_finalize; + widget_class = GTK_WIDGET_CLASS (klass); + widget_class->show = xtm_process_window_show; + widget_class->hide = xtm_process_window_hide; + + class->get_property = xtm_process_window_get_property; + class->set_property = xtm_process_window_set_property; + g_object_class_install_property (class, PROP_CPU, + g_param_spec_uint ("cpu", "CPU", "CPU usage", 0, 100, 0, G_PARAM_CONSTRUCT|G_PARAM_WRITABLE)); + g_object_class_install_property (class, PROP_MEMORY, + g_param_spec_uint64 ("memory", "Memory", "Memory usage", 0, G_MAXUINT64, 0, G_PARAM_CONSTRUCT|G_PARAM_WRITABLE)); + g_object_class_install_property (class, PROP_NUM_PROCESSES, + g_param_spec_uint ("num-processes", "NumProcesses", "Number of processes", 0, G_MAXUINT, 0, G_PARAM_CONSTRUCT|G_PARAM_WRITABLE)); +} + +static void +xtm_process_window_init (XtmProcessWindow *window) +{ + GtkWidget *button; + gint width, height; + + window->priv = GET_PRIV (window); + + window->priv->settings = xtm_settings_get_default (); + + window->priv->builder = gtk_builder_new (); + gtk_builder_add_from_string (window->priv->builder, process_window_ui, process_window_ui_length, NULL); + + window->priv->window = GTK_WIDGET (gtk_builder_get_object (window->priv->builder, "process-window")); + g_object_get (window->priv->settings, "window-width", &width, "window-height", &height, NULL); + if (width >= 1 && height >= 1) + gtk_window_resize (GTK_WINDOW (window->priv->window), width, height); + g_signal_connect_swapped (window->priv->window, "destroy", G_CALLBACK (emit_destroy_signal), window); + + window->priv->treeview = xtm_process_tree_view_new (); + gtk_widget_show (window->priv->treeview); + gtk_container_add (GTK_CONTAINER (gtk_builder_get_object (window->priv->builder, "scrolledwindow")), window->priv->treeview); + + window->priv->statusbar = GTK_WIDGET (gtk_builder_get_object (window->priv->builder, "process-statusbar")); + window->priv->statusbar_context_id = gtk_statusbar_get_context_id (GTK_STATUSBAR (window->priv->statusbar), "System information"); + + button = GTK_WIDGET (gtk_builder_get_object (window->priv->builder, "toolbutton-execute")); + g_signal_connect_swapped (button, "clicked", G_CALLBACK (show_menu_execute_task), window); + + button = GTK_WIDGET (gtk_builder_get_object (window->priv->builder, "toolbutton-information")); + g_signal_connect_swapped (button, "clicked", G_CALLBACK (show_menu_information), window); + + button = GTK_WIDGET (gtk_builder_get_object (window->priv->builder, "toolbutton-about")); + g_signal_connect_swapped (button, "clicked", G_CALLBACK (show_about_dialog), window); + + button = GTK_WIDGET (gtk_builder_get_object (window->priv->builder, "toolbutton-quit")); + g_signal_connect_swapped (button, "clicked", G_CALLBACK (emit_destroy_signal), window); + + g_object_unref (window->priv->builder); + window->priv->builder = NULL; +} + +static void +xtm_process_window_finalize (GObject *object) +{ + XtmProcessWindowPriv *priv = XTM_PROCESS_WINDOW (object)->priv; + + if (GTK_IS_WINDOW (priv->window)) + { + gint width, height; + guint sort_column_id; + GtkSortType sort_type; + + gtk_window_get_size (GTK_WINDOW (priv->window), &width, &height); + gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview))), + &sort_column_id, &sort_type); + + g_object_set (priv->settings, "window-width", width, "window-height", height, + "sort-column-id", sort_column_id, "sort-type", sort_type, NULL); + } + + if (XTM_IS_SETTINGS (priv->settings)) + { + g_object_unref (priv->settings); + } +} + +static void +xtm_process_window_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +{ + XtmProcessWindowPriv *priv = XTM_PROCESS_WINDOW (object)->priv; + + switch (property_id) + { + case PROP_CPU: + g_value_set_uint (value, priv->cpu); + break; + + case PROP_MEMORY: + g_value_set_uint64 (value, priv->memory); + break; + + case PROP_NUM_PROCESSES: + g_value_set_uint (value, priv->num_processes); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +xtm_process_window_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) +{ + XtmProcessWindowPriv *priv = XTM_PROCESS_WINDOW (object)->priv; + + switch (property_id) + { + case PROP_CPU: + priv->cpu = g_value_get_uint (value); + // TODO update_cpu_monitor (); + update_status_bar (XTM_PROCESS_WINDOW (object)); + break; + + case PROP_MEMORY: + priv->memory = g_value_get_uint64 (value); + // TODO update_memory_monitor (); + update_status_bar (XTM_PROCESS_WINDOW (object)); + break; + + case PROP_NUM_PROCESSES: + priv->num_processes = g_value_get_uint (value); + update_status_bar (XTM_PROCESS_WINDOW (object)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +/** + * Helper functions + */ + +static void +emit_destroy_signal (XtmProcessWindow *window) +{ + g_signal_emit_by_name (window, "destroy", G_TYPE_NONE); +} + +static void +execute_command (const gchar *command) +{ + GError *error = NULL; + + gdk_spawn_command_line_on_screen (gdk_screen_get_default (), command, &error); + if (error != NULL) + { + GtkWidget *dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, + _("Execution error")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", error->message); + gtk_window_set_title (GTK_WINDOW (dialog), _("Task Manager")); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + g_error_free (error); + } +} + +static void +menu_execute_append_item (GtkMenu *menu, gchar *title, gchar *command, gchar *icon_name) +{ + GtkWidget *mi; + GtkWidget *image; + + image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU); + mi = gtk_image_menu_item_new_with_label (title); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), image); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi); + g_signal_connect_swapped (mi, "activate", G_CALLBACK (execute_command), command); +} + +static void +show_menu_execute_task (XtmProcessWindow *window) +{ + // TODO check if xfrun4, xfce4-appfinder, etc are installed and pull them in the menu + static GtkWidget *menu = NULL; + GtkWidget *mi; + + if (menu == NULL) + { + menu = gtk_menu_new (); + menu_execute_append_item (GTK_MENU (menu), _("Run Program..."), "xfrun4", "system-run"); + menu_execute_append_item (GTK_MENU (menu), _("Application Finder"), "xfce4-appfinder", "xfce4-appfinder"); + menu_execute_append_item (GTK_MENU (menu), _("Terminal emulator"), "exo-open --launch TerminalEmulator", "terminal"); + menu_execute_append_item (GTK_MENU (menu), _("XTerm"), "xterm -fg grey -bg black", "terminal"); + gtk_widget_show_all (menu); + } + + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time ()); +} + +static void +information_toggled (GtkCheckMenuItem *mi, XtmSettings *settings) +{ + gchar *setting_name; + gboolean active; + + active = gtk_check_menu_item_get_active (mi); + setting_name = g_object_get_data (G_OBJECT (mi), "setting-name"); + g_object_set (settings, setting_name, active, NULL); +} + +static void +menu_information_append_item (GtkMenu *menu, gchar *title, gchar *setting_name, XtmSettings *settings) +{ + GtkWidget *mi; + gboolean active = FALSE; + + g_object_get (settings, setting_name, &active, NULL); + + mi = gtk_check_menu_item_new_with_label (title); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi), active); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi); + g_object_set_data (G_OBJECT (mi), "setting-name", setting_name); + g_signal_connect (mi, "toggled", G_CALLBACK (information_toggled), settings); +} + +static void +show_menu_information (XtmProcessWindow *window) +{ + static GtkWidget *menu = NULL; + GtkWidget *mi; + + if (menu != NULL) + { + gtk_widget_destroy (menu); + } + + menu = gtk_menu_new (); + menu_information_append_item (GTK_MENU (menu), _("Show system processes"), "show-system-processes", window->priv->settings); + + mi = gtk_separator_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi); + + menu_information_append_item (GTK_MENU (menu), _("PID"), "column-pid", window->priv->settings); + menu_information_append_item (GTK_MENU (menu), _("PPID"), "column-ppid", window->priv->settings); + menu_information_append_item (GTK_MENU (menu), _("State"), "column-state", window->priv->settings); + menu_information_append_item (GTK_MENU (menu), _("Virtual Bytes"), "column-vsz", window->priv->settings); + menu_information_append_item (GTK_MENU (menu), _("Private Bytes"), "column-rss", window->priv->settings); + menu_information_append_item (GTK_MENU (menu), _("UID"), "column-uid", window->priv->settings); + menu_information_append_item (GTK_MENU (menu), _("CPU"), "column-cpu", window->priv->settings); + menu_information_append_item (GTK_MENU (menu), _("Priority"), "column-priority", window->priv->settings); + + gtk_widget_show_all (menu); + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time ()); +} + +#if !GTK_CHECK_VERSION(2,18,0) +static void +url_hook_about_dialog (GtkAboutDialog *dialog, const gchar *uri, gpointer user_data) +{ + gchar *command = g_strdup_printf ("exo-open %s", uri); + if (!g_spawn_command_line_async (command, NULL)) + { + g_free (command); + command = g_strdup_printf ("firefox %s", uri); + g_spawn_command_line_async (command, NULL); + } + g_free (command); +} +#endif + +static void +show_about_dialog (XtmProcessWindow *window) +{ + const gchar *authors[] = { + "(c) 2008-2010 Mike Massonnet", + "(c) 2005-2008 Johannes Zellner", + NULL }; + const gchar *license = + "This program is free software; you can redistribute it and/or modify\n" + "it under the terms of the GNU General Public License as published by\n" + "the Free Software Foundation; either version 2 of the License, or\n" + "(at your option) any later version.\n"; + +#if !GTK_CHECK_VERSION(2,18,0) + gtk_about_dialog_set_url_hook (url_hook_about_dialog, NULL, NULL); +#endif + gtk_show_about_dialog (GTK_WINDOW (window->priv->window), + "program-name", _("Task Manager"), + "version", PACKAGE_VERSION, + "copyright", "Copyright \302\251 2005-2010 The Xfce development team", + "logo-icon-name", "utilities-system-monitor", + "icon-name", GTK_STOCK_ABOUT, + "comments", _("Easy to use task manager"), + "license", license, + "authors", authors, + "translator-credits", _("translator-credits"), + "website", "http://goodies.xfce.org/projects/applications/xfce4-taskmanager", + "website-label", "goodies.xfce.org", + NULL); +} + +static void +update_status_bar (XtmProcessWindow *window) +{ + gchar *text = NULL; + + text = g_strdup_printf (_("Processes: %d \t CPU: %d%% \t Memory: %d%%"), + window->priv->num_processes, window->priv->cpu, window->priv->memory); + gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar), window->priv->statusbar_context_id); + gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar), window->priv->statusbar_context_id, text); +} + + + +/** + * Class functions + */ + +GtkWidget * +xtm_process_window_new () +{ + return g_object_new (XTM_TYPE_PROCESS_WINDOW, NULL); +} + +static void +xtm_process_window_show (GtkWidget *widget) +{ + g_return_if_fail (G_LIKELY (GTK_IS_WIDGET (widget))); + g_return_if_fail (G_LIKELY (GTK_IS_WIDGET (XTM_PROCESS_WINDOW (widget)->priv->window))); + gtk_widget_show (XTM_PROCESS_WINDOW (widget)->priv->window); +} + +static void +xtm_process_window_hide (GtkWidget *widget) +{ + g_return_if_fail (G_LIKELY (GTK_IS_WIDGET (widget))); + g_return_if_fail (G_LIKELY (GTK_IS_WIDGET (XTM_PROCESS_WINDOW (widget)->priv->window))); + gtk_widget_hide (XTM_PROCESS_WINDOW (widget)->priv->window); +} + +void +xtm_process_window_set_model (XtmProcessWindow *window, GtkTreeModel *model) +{ + g_return_if_fail (G_LIKELY (XTM_IS_PROCESS_WINDOW (window))); + g_return_if_fail (G_LIKELY (GTK_IS_TREE_VIEW (window->priv->treeview))); + gtk_tree_view_set_model (GTK_TREE_VIEW (window->priv->treeview), model); +} + +GtkTreeModel * +xtm_process_window_get_model (XtmProcessWindow *window) +{ + g_return_val_if_fail (G_LIKELY (XTM_IS_PROCESS_WINDOW (window)), NULL); + g_return_val_if_fail (G_LIKELY (GTK_IS_TREE_VIEW (window->priv->treeview)), NULL); + return gtk_tree_view_get_model (GTK_TREE_VIEW (window->priv->treeview)); +} + +void +xtm_process_window_set_system_info (XtmProcessWindow *window, guint num_processes, gushort cpu, guint64 memory) +{ + g_return_if_fail (G_LIKELY (XTM_IS_PROCESS_WINDOW (window))); + g_return_if_fail (G_LIKELY (GTK_IS_STATUSBAR (window->priv->statusbar))); + g_object_set (window, "num-processes", num_processes, "cpu", cpu, "memory", memory, NULL); +} + diff --git a/src/process-window.h b/src/process-window.h new file mode 100644 index 0000000..8555d92 --- /dev/null +++ b/src/process-window.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2010 Mike Massonnet, + * + * 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. + */ + +#ifndef PROCESS_WINDOW_H +#define PROCESS_WINDOW_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#define XTM_TYPE_PROCESS_WINDOW (xtm_process_window_get_type ()) +#define XTM_PROCESS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XTM_TYPE_PROCESS_WINDOW, XtmProcessWindow)) +#define XTM_PROCESS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XTM_TYPE_PROCESS_WINDOW, XtmProcessWindowClass)) +#define XTM_IS_PROCESS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XTM_TYPE_PROCESS_WINDOW)) +#define XTM_IS_PROCESS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XTM_TYPE_PROCESS_WINDOW)) +#define XTM_PROCESS_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XTM_TYPE_PROCESS_WINDOW, XtmProcessWindowClass)) + +typedef struct _XtmProcessWindow XtmProcessWindow; + +GType xtm_process_window_get_type (void); +GtkWidget * xtm_process_window_new (); +GtkTreeModel * xtm_process_window_get_model (XtmProcessWindow *window); +void xtm_process_window_set_system_info (XtmProcessWindow *window, guint num_processes, gushort cpu, guint64 mem); + +#endif /* !PROCESS_WINDOW_H */ diff --git a/src/process-window.ui b/src/process-window.ui new file mode 100644 index 0000000..10740d7 --- /dev/null +++ b/src/process-window.ui @@ -0,0 +1,147 @@ + + + + + + Task Manager + 490 + 465 + utilities-system-monitor + + + True + vertical + + + True + both + False + 1 + + + True + True + True + gtk-execute + + + False + True + + + + + True + True + True + gtk-info + + + False + True + + + + + True + 2 + + + True + True + CPU + + + + + True + True + + + + + True + 2 + + + True + True + Memory + + + + + True + True + + + + + True + True + gtk-about + + + False + True + + + + + True + True + True + gtk-quit + + + False + True + + + + + False + 0 + + + + + True + 6 + vertical + 6 + + + True + True + automatic + automatic + in + + + + + + 0 + + + + + 1 + + + + + True + 2 + + + False + end + 2 + + + + + + diff --git a/src/settings.c b/src/settings.c new file mode 100644 index 0000000..8591443 --- /dev/null +++ b/src/settings.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2010 Mike Massonnet, + * + * Based on ThunarPreferences: + * Copyright (c) Benedikt Meurer + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "settings.h" + + + +enum +{ + PROP_SHOW_SYSTEM_PROCESSES = 1, + PROP_COLUMN_UID, + PROP_COLUMN_PID, + PROP_COLUMN_PPID, + PROP_COLUMN_STATE, + PROP_COLUMN_VSZ, + PROP_COLUMN_RSS, + PROP_COLUMN_CPU, + PROP_COLUMN_PRIORITY, + PROP_SORT_COLUMN_ID, + PROP_SORT_TYPE, + PROP_WINDOW_WIDTH, + PROP_WINDOW_HEIGHT, + N_PROPS, +}; +typedef struct _XtmSettingsClass XtmSettingsClass; +struct _XtmSettingsClass +{ + GObjectClass parent_class; +}; +struct _XtmSettings +{ + GObject parent; + /**/ + GValue values[N_PROPS]; +}; +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), XTM_TYPE_SETTINGS, XtmSettingsPriv)) +G_DEFINE_TYPE (XtmSettings, xtm_settings, G_TYPE_OBJECT) + +static void xtm_settings_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec); +static void xtm_settings_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); + +static void xtm_settings_load_settings (XtmSettings *settings); +static void xtm_settings_save_settings (XtmSettings *settings); + + + +static void +xtm_settings_class_init (XtmSettingsClass *klass) +{ + GObjectClass *class = G_OBJECT_CLASS (klass); + xtm_settings_parent_class = g_type_class_peek_parent (klass); + class->get_property = xtm_settings_get_property; + class->set_property = xtm_settings_set_property; + g_object_class_install_property (class, PROP_SHOW_SYSTEM_PROCESSES, + g_param_spec_boolean ("show-system-processes", "ShowSystemProcesses", "Show system processes", FALSE, G_PARAM_READWRITE)); + g_object_class_install_property (class, PROP_COLUMN_UID, + g_param_spec_boolean ("column-uid", "ColumnUID", "Show column UID", FALSE, G_PARAM_READWRITE)); + g_object_class_install_property (class, PROP_COLUMN_PID, + g_param_spec_boolean ("column-pid", "ColumnPID", "Show column PID", TRUE, G_PARAM_READWRITE)); + g_object_class_install_property (class, PROP_COLUMN_PPID, + g_param_spec_boolean ("column-ppid", "ColumnPPID", "Show column PPID", FALSE, G_PARAM_READWRITE)); + g_object_class_install_property (class, PROP_COLUMN_STATE, + g_param_spec_boolean ("column-state", "ColumnState", "Show column state", FALSE, G_PARAM_READWRITE)); + g_object_class_install_property (class, PROP_COLUMN_VSZ, + g_param_spec_boolean ("column-vsz", "ColumnVSZ", "Show column VSZ", FALSE, G_PARAM_READWRITE)); + g_object_class_install_property (class, PROP_COLUMN_RSS, + g_param_spec_boolean ("column-rss", "ColumnRSS", "Show column RSS", TRUE, G_PARAM_READWRITE)); + g_object_class_install_property (class, PROP_COLUMN_CPU, + g_param_spec_boolean ("column-cpu", "ColumnCPU", "Show column CPU", TRUE, G_PARAM_READWRITE)); + g_object_class_install_property (class, PROP_COLUMN_PRIORITY, + g_param_spec_boolean ("column-priority", "ColumnPriority", "Show column priority", FALSE, G_PARAM_READWRITE)); + g_object_class_install_property (class, PROP_SORT_COLUMN_ID, + g_param_spec_uint ("sort-column-id", "SortColumn", "Sort by column id", 0, G_MAXUINT, 0, G_PARAM_READWRITE)); + g_object_class_install_property (class, PROP_SORT_TYPE, + g_param_spec_uint ("sort-type", "SortType", "Sort type (asc/dsc)", 0, 1, 0, G_PARAM_READWRITE)); + g_object_class_install_property (class, PROP_WINDOW_WIDTH, + g_param_spec_int ("window-width", "WindowWidth", "Window width", -1, G_MAXINT, -1, G_PARAM_READWRITE)); + g_object_class_install_property (class, PROP_WINDOW_HEIGHT, + g_param_spec_int ("window-height", "WindowHeight", "Window height", -1, G_MAXINT, -1, G_PARAM_READWRITE)); +} + +static void +xtm_settings_init (XtmSettings *settings) +{ + xtm_settings_load_settings (settings); +} + +static void +xtm_settings_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +{ + GValue *src = XTM_SETTINGS (object)->values + property_id; + if (G_LIKELY (G_IS_VALUE (src))) + g_value_copy (src, value); + else + g_param_value_set_default (pspec, value); +} + +static void +xtm_settings_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) +{ + GValue *dest = XTM_SETTINGS (object)->values + property_id; + if (G_UNLIKELY (!G_IS_VALUE(dest))) + { + g_value_init (dest, pspec->value_type); + g_param_value_set_default (pspec, dest); + } + if (G_LIKELY (g_param_values_cmp (pspec, value, dest) != 0)) + { + g_value_copy (value, dest); + xtm_settings_save_settings (XTM_SETTINGS (object)); + } +} + + + +static void +transform_string_to_boolean (const GValue *src, GValue *dst) +{ + g_value_set_boolean (dst, (gboolean)strcmp (g_value_get_string (src), "FALSE") != 0); +} + +static void +transform_string_to_int (const GValue *src, GValue *dst) +{ + g_value_set_int (dst, (gint)strtol (g_value_get_string (src), NULL, 10)); +} + +static void +transform_string_to_uint (const GValue *src, GValue *dst) +{ + g_value_set_uint (dst, (gint)strtoul (g_value_get_string (src), NULL, 10)); +} + +static void +register_transformable () +{ + if (!g_value_type_transformable (G_TYPE_STRING, G_TYPE_BOOLEAN)) + g_value_register_transform_func (G_TYPE_STRING, G_TYPE_BOOLEAN, transform_string_to_boolean); + + if (!g_value_type_transformable (G_TYPE_STRING, G_TYPE_INT)) + g_value_register_transform_func (G_TYPE_STRING, G_TYPE_INT, transform_string_to_int); + + if (!g_value_type_transformable (G_TYPE_STRING, G_TYPE_UINT)) + g_value_register_transform_func (G_TYPE_STRING, G_TYPE_UINT, transform_string_to_uint); +} + +static void +xtm_settings_load_settings (XtmSettings *settings) +{ + GKeyFile *rc; + gchar *filename; + + register_transformable (); + + g_object_freeze_notify (G_OBJECT (settings)); + + rc = g_key_file_new (); + filename = g_strdup_printf ("%s/xfce4/xfce4-taskmanager.rc", g_get_user_config_dir ()); + + if (g_key_file_load_from_file (rc, filename, G_KEY_FILE_NONE, NULL)) + { + const gchar *string; + GValue dst = {0}; + GValue src = {0}; + GParamSpec **specs; + GParamSpec *spec; + guint nspecs; + guint n; + + specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (settings), &nspecs); + for (n = 0; n < nspecs; ++n) + { + spec = specs[n]; + string = g_key_file_get_string (rc, "Settings", g_param_spec_get_nick (spec), NULL); + if (G_UNLIKELY (string == NULL)) + continue; + + g_value_init (&src, G_TYPE_STRING); + g_value_set_static_string (&src, string); + + if (spec->value_type == G_TYPE_STRING) + { + g_object_set_property (G_OBJECT (settings), spec->name, &src); + } + else if (g_value_type_transformable (G_TYPE_STRING, spec->value_type)) + { + g_value_init (&dst, spec->value_type); + if (g_value_transform (&src, &dst)) + g_object_set_property (G_OBJECT (settings), spec->name, &dst); + g_value_unset (&dst); + } + else + { + g_warning ("Failed to load property \"%s\"", spec->name); + } + + g_value_unset (&src); + } + g_free (specs); + } + + g_free (filename); + g_key_file_free (rc); + + g_object_thaw_notify (G_OBJECT (settings)); +} + +static void +xtm_settings_save_settings (XtmSettings *settings) +{ + GKeyFile *rc; + gchar *filename; + + rc = g_key_file_new (); + filename = g_strdup_printf ("%s/xfce4/xfce4-taskmanager.rc", g_get_user_config_dir ()); + + { + const gchar *string; + GValue dst = {0}; + GValue src = {0}; + GParamSpec **specs; + GParamSpec *spec; + guint nspecs; + guint n; + + specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (settings), &nspecs); + for (n = 0; n < nspecs; ++n) + { + spec = specs[n]; + g_value_init (&dst, G_TYPE_STRING); + if (spec->value_type == G_TYPE_STRING) + { + g_object_get_property (G_OBJECT (settings), spec->name, &dst); + } + else + { + g_value_init (&src, spec->value_type); + g_object_get_property (G_OBJECT (settings), spec->name, &src); + g_value_transform (&src, &dst); + g_value_unset (&src); + } + string = g_value_get_string (&dst); + + if (G_LIKELY (string != NULL)) + g_key_file_set_string (rc, "Settings", g_param_spec_get_nick (spec), string); + + g_value_unset (&dst); + } + g_free (specs); + } + + { + GError *error = NULL; + gchar *data; + gsize length; + + if (!g_file_test (filename, G_FILE_TEST_EXISTS)) + { + gchar *path = g_strdup_printf ("%s/xfce4", g_get_user_config_dir ()); + g_mkdir_with_parents (path, 0700); + g_free (path); + } + + data = g_key_file_to_data (rc, &length, NULL); + if (!g_file_set_contents (filename, data, length, &error)) + { + g_warning ("Unable to save settings: %s", error->message); + g_error_free (error); + } + + g_free (data); + } + + g_free (filename); + g_key_file_free (rc); +} + + + +XtmSettings * +xtm_settings_get_default () +{ + static XtmSettings *settings = NULL; + if (G_UNLIKELY (settings == NULL)) + { + settings = g_object_new (XTM_TYPE_SETTINGS, NULL); + g_object_add_weak_pointer (G_OBJECT (settings), (gpointer)&settings); + } + else + { + g_object_ref (settings); + } + return settings; +} + diff --git a/src/settings.h b/src/settings.h new file mode 100644 index 0000000..9e143bb --- /dev/null +++ b/src/settings.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2010 Mike Massonnet, + * + * 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. + */ + +#ifndef SETTINGS_H +#define SETTINGS_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#define XTM_TYPE_SETTINGS (xtm_settings_get_type ()) +#define XTM_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XTM_TYPE_SETTINGS, XtmSettings)) +#define XTM_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XTM_TYPE_SETTINGS, XtmSettingsClass)) +#define XTM_IS_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XTM_TYPE_SETTINGS)) +#define XTM_IS_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XTM_TYPE_SETTINGS)) +#define XTM_SETTINGS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XTM_TYPE_SETTINGS, XtmSettingsClass)) + +typedef struct _XtmSettings XtmSettings; + +GType xtm_settings_get_type (void); +XtmSettings * xtm_settings_get_default (); + +#endif /* !SETTINGS_H */