diff --git a/configure.ac.in b/configure.ac.in index 98ca9d6..666d6bc 100644 --- a/configure.ac.in +++ b/configure.ac.in @@ -65,6 +65,12 @@ dnl *** Check for required packages *** dnl *********************************** XDT_CHECK_PACKAGE([GTK], [gtk+-2.0], [2.12.0]) +dnl ****************************************** +dnl *** Check for optional package libwnck *** +dnl ****************************************** +XDT_CHECK_OPTIONAL_PACKAGE([WNCK], [libwnck-1.0], [2.0], [wnck], [building with libwnck for window icons/names], [yes]) +AM_CONDITIONAL([HAVE_WNCK], [test x"$WNCK_FOUND" = x"yes"]) + dnl *********************************** dnl ********** Check for skel ********* dnl *********************************** @@ -137,6 +143,7 @@ dnl *************************** echo echo "Build Configuration:" echo +echo "* Wnck: ${WNCK_FOUND:-no} ${WNCK_VERSION:+(libwnck $WNCK_VERSION)}" echo "* Target OS: $target_os ($ac_os_implementation)" echo "* Debug Support: $enable_debug" echo diff --git a/src/Makefile.am b/src/Makefile.am index 386adee..9fc671a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,10 +9,14 @@ bin_PROGRAMS = \ xfce4-taskmanager xfce4_taskmanager_CFLAGS = \ - $(GTK_CFLAGS) - + $(GTK_CFLAGS) \ + $(WNCK_CFLAGS) \ + $(NULL) + xfce4_taskmanager_LDADD = \ - $(GTK_LIBS) + $(GTK_LIBS) \ + $(WNCK_LIBS) \ + $(NULL) xfce4_taskmanager_SOURCES = \ main.c \ @@ -24,6 +28,10 @@ xfce4_taskmanager_SOURCES = \ settings.c settings.h \ $(NULL) +if HAVE_WNCK +xfce4_taskmanager_SOURCES += app-manager.c app-manager.h +endif + if OS_FREEBSD xfce4_taskmanager_SOURCES += task-manager-freebsd.c endif diff --git a/src/app-manager.c b/src/app-manager.c new file mode 100644 index 0000000..07bbf82 --- /dev/null +++ b/src/app-manager.c @@ -0,0 +1,196 @@ +/* + * 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 +#define WNCK_I_KNOW_THIS_IS_UNSTABLE +#include + +#include "app-manager.h" + + + +typedef struct _XtmAppManagerClass XtmAppManagerClass; +struct _XtmAppManagerClass +{ + GObjectClass parent_class; +}; +struct _XtmAppManager +{ + GObject parent; + /**/ + GArray * apps; +}; +G_DEFINE_TYPE (XtmAppManager, xtm_app_manager, G_TYPE_OBJECT) + +static void xtm_app_manager_finalize (GObject *object); + +static void apps_add_application (GArray *apps, WnckApplication *application); +static void apps_remove_application (GArray *apps, WnckApplication *application); +static App * apps_lookup_pid (GArray *apps, gint pid); +static void application_opened (WnckScreen *screen, WnckApplication *application, XtmAppManager *manager); +static void application_closed (WnckScreen *screen, WnckApplication *application, XtmAppManager *manager); + + + +static void +xtm_app_manager_class_init (XtmAppManagerClass *klass) +{ + GObjectClass *class = G_OBJECT_CLASS (klass); + xtm_app_manager_parent_class = g_type_class_peek_parent (klass); + class->finalize = xtm_app_manager_finalize; +} + +static void +xtm_app_manager_init (XtmAppManager *manager) +{ + WnckScreen *screen = wnck_screen_get_default (); + GList *windows, *l; + gint i; + App app; + + /* Retrieve initial applications */ + while (gtk_events_pending ()) + gtk_main_iteration (); + + manager->apps = g_array_new (FALSE, FALSE, sizeof (App)); + windows = wnck_screen_get_windows (screen); + for (l = windows; l != NULL; l = l->next) + { + WnckWindow *window = WNCK_WINDOW (l->data); + WnckApplication *application = wnck_window_get_application (window); + gint pid = wnck_application_get_pid (application); + + if (wnck_window_get_window_type (window) != WNCK_WINDOW_NORMAL) + continue; + + if (apps_lookup_pid (manager->apps, pid) != NULL) + continue; + + apps_add_application (manager->apps, application); + } + +#if DEBUG + g_debug ("Initial applications: %d", manager->apps->len); +#endif + + /* Connect signals */ + g_signal_connect (screen, "application-opened", G_CALLBACK (application_opened), manager); + g_signal_connect (screen, "application-closed", G_CALLBACK (application_closed), manager); +} + +static void +xtm_app_manager_finalize (GObject *object) +{ + g_array_free (XTM_APP_MANAGER (object)->apps, TRUE); +} + +static void +apps_add_application (GArray *apps, WnckApplication *application) +{ + App app; + gint pid; + + pid = wnck_application_get_pid (application); + if (pid == 0) + { + WnckWindow *window = WNCK_WINDOW (wnck_application_get_windows (application)->data); + pid = wnck_window_get_pid (window); + } + + if (apps_lookup_pid (apps, pid)) + return; + + app.application = application; + app.pid = pid; + g_snprintf (app.name, 1024, "%s", wnck_application_get_name (application)); + app.icon = wnck_application_get_mini_icon (application); + g_object_ref (app.icon); + + g_array_append_val (apps, app); +} + +static void +apps_remove_application (GArray *apps, WnckApplication *application) +{ + App *app; + gint pid; + gint i; + + for (i = 0; i < apps->len; i++) + { + app = &g_array_index (apps, App, i); + if (app->application == application) + break; + } + + g_object_unref (app->icon); + g_array_remove_index (apps, i); +} + +static App * +apps_lookup_pid (GArray *apps, gint pid) +{ + App *app; + gint i; + + for (app = NULL, i = 0; i < apps->len; i++) + { + app = &g_array_index (apps, App, i); + if (app->pid == pid) + break; + app = NULL; + } + + return app; +} + +static void +application_opened (WnckScreen *screen, WnckApplication *application, XtmAppManager *manager) +{ +#if DEBUG + g_debug ("Application opened %p %d", application, wnck_application_get_pid (application)); +#endif + apps_add_application (manager->apps, application); +} + +static void +application_closed (WnckScreen *screen, WnckApplication *application, XtmAppManager *manager) +{ +#if DEBUG + g_debug ("Application closed %p", application); +#endif + apps_remove_application (manager->apps, application); +} + + + +XtmAppManager * +xtm_app_manager_new () +{ + return g_object_new (XTM_TYPE_APP_MANAGER, NULL); +} + +const GArray * +xtm_app_manager_get_app_list (XtmAppManager *manager) +{ + g_return_val_if_fail (XTM_IS_APP_MANAGER (manager), NULL); + return manager->apps; +} + +App * +xtm_app_manager_get_app_from_pid (XtmAppManager *manager, gint pid) +{ + return apps_lookup_pid (manager->apps, pid); +} + diff --git a/src/app-manager.h b/src/app-manager.h new file mode 100644 index 0000000..ebded9a --- /dev/null +++ b/src/app-manager.h @@ -0,0 +1,45 @@ +/* + * 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 APP_MANAGER_H +#define APP_MANAGER_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#define WNCK_I_KNOW_THIS_IS_UNSTABLE +#include + +typedef struct _App App; +struct _App +{ + WnckApplication * application; + guint pid; + gchar name[1024]; + GdkPixbuf * icon; +}; + +#define XTM_TYPE_APP_MANAGER (xtm_app_manager_get_type ()) +#define XTM_APP_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XTM_TYPE_APP_MANAGER, XtmAppManager)) +#define XTM_APP_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XTM_TYPE_APP_MANAGER, XtmAppManagerClass)) +#define XTM_IS_APP_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XTM_TYPE_APP_MANAGER)) +#define XTM_IS_APP_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XTM_TYPE_APP_MANAGER)) +#define XTM_APP_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XTM_TYPE_APP_MANAGER, XtmAppManagerClass)) + +typedef struct _XtmAppManager XtmAppManager; + +GType xtm_app_manager_get_type (void); +XtmAppManager * xtm_app_manager_new (); +const GArray * xtm_app_manager_get_app_list (XtmAppManager *manager); +App * xtm_app_manager_get_app_from_pid (XtmAppManager *manager, gint pid); + +#endif /* !APP_MANAGER_H */ diff --git a/src/process-tree-view.c b/src/process-tree-view.c index 480fc68..d7ee2f7 100644 --- a/src/process-tree-view.c +++ b/src/process-tree-view.c @@ -79,7 +79,11 @@ xtm_process_tree_view_class_init (XtmProcessTreeViewClass *klass) static void xtm_process_tree_view_init (XtmProcessTreeView *treeview) { +#ifdef HAVE_WNCK + GtkCellRenderer *cell_text, *cell_right_aligned, *cell_icon, *cell_cmdline; +#else GtkCellRenderer *cell_text, *cell_right_aligned, *cell_cmdline; +#endif GtkTreeViewColumn *column; gboolean visible; @@ -94,7 +98,11 @@ xtm_process_tree_view_init (XtmProcessTreeView *treeview) } /* Create tree view model */ +#ifdef HAVE_WNCK + treeview->model = gtk_list_store_new (XTM_PTV_N_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_UINT64, +#else treeview->model = gtk_list_store_new (XTM_PTV_N_COLUMNS, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_UINT64, +#endif G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_FLOAT, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_LONG); @@ -117,7 +125,15 @@ xtm_process_tree_view_init (XtmProcessTreeView *treeview) /* Create tree view columns */ #define COLUMN_PROPERTIES "expand", TRUE, "clickable", TRUE, "reorderable", TRUE, "resizable", TRUE, "visible", TRUE - column = gtk_tree_view_column_new_with_attributes (_("Task"), cell_cmdline, "text", XTM_PTV_COLUMN_COMMAND, "cell-background", XTM_PTV_COLUMN_BACKGROUND, "foreground", XTM_PTV_COLUMN_FOREGROUND, NULL); + column = gtk_tree_view_column_new (); + gtk_tree_view_column_set_title (GTK_TREE_VIEW_COLUMN (column), _("Task")); +#ifdef HAVE_WNCK + cell_icon = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (GTK_TREE_VIEW_COLUMN (column), cell_icon, FALSE); + gtk_tree_view_column_set_attributes (GTK_TREE_VIEW_COLUMN (column), cell_icon, "pixbuf", XTM_PTV_COLUMN_ICON, "cell-background", XTM_PTV_COLUMN_BACKGROUND, NULL); +#endif + gtk_tree_view_column_pack_start (GTK_TREE_VIEW_COLUMN (column), cell_cmdline, TRUE); + gtk_tree_view_column_set_attributes (GTK_TREE_VIEW_COLUMN (column), cell_cmdline, "text", XTM_PTV_COLUMN_COMMAND, "cell-background", XTM_PTV_COLUMN_BACKGROUND, "foreground", XTM_PTV_COLUMN_FOREGROUND, NULL); g_object_set (column, COLUMN_PROPERTIES, NULL); g_object_set_data (G_OBJECT (column), "sort-column-id", GINT_TO_POINTER (XTM_PTV_COLUMN_COMMAND)); g_object_set_data (G_OBJECT (column), "column-id", GINT_TO_POINTER (COLUMN_COMMAND)); diff --git a/src/process-tree-view.h b/src/process-tree-view.h index 2ab6da5..3082806 100644 --- a/src/process-tree-view.h +++ b/src/process-tree-view.h @@ -18,6 +18,9 @@ enum { +#ifdef HAVE_WNCK + XTM_PTV_COLUMN_ICON, +#endif XTM_PTV_COLUMN_COMMAND, XTM_PTV_COLUMN_PID, XTM_PTV_COLUMN_PPID, diff --git a/src/task-manager.c b/src/task-manager.c index cba8a73..5b13ebf 100644 --- a/src/task-manager.c +++ b/src/task-manager.c @@ -22,6 +22,9 @@ #include #include "task-manager.h" +#ifdef HAVE_WNCK +#include "app-manager.h" +#endif #include "process-tree-view.h" /* for the columns of the model */ #include "settings.h" @@ -45,6 +48,9 @@ struct _XtmTaskManager { GObject parent; /**/ +#ifdef HAVE_WNCK + XtmAppManager * app_manager; +#endif GtkTreeModel * model; GArray * tasks; guint owner_uid; @@ -65,11 +71,17 @@ G_DEFINE_TYPE (XtmTaskManager, xtm_task_manager, G_TYPE_OBJECT) static void xtm_task_manager_finalize (GObject *object); static void setting_changed (GObject *object, GParamSpec *pspec, XtmTaskManager *manager); +#ifdef HAVE_WNCK +static void model_add_task (GtkTreeModel *model, Task *task, App *app, glong timestamp); +static void model_update_tree_iter (GtkTreeModel *model, GtkTreeIter *iter, Task *task, App *app); +static void model_update_task (GtkTreeModel *model, Task *task, App *app); +#else static void model_add_task (GtkTreeModel *model, Task *task, glong timestamp); -static void model_mark_tree_iter_as_removed (GtkTreeModel *model, GtkTreeIter *iter); -static void model_remove_tree_iter (GtkTreeModel *model, GtkTreeIter *iter); static void model_update_tree_iter (GtkTreeModel *model, GtkTreeIter *iter, Task *task); static void model_update_task (GtkTreeModel *model, Task *task); +#endif +static void model_mark_tree_iter_as_removed (GtkTreeModel *model, GtkTreeIter *iter); +static void model_remove_tree_iter (GtkTreeModel *model, GtkTreeIter *iter); static void model_find_tree_iter_for_pid (GtkTreeModel *model, guint pid, GtkTreeIter *iter); static glong __current_timestamp (); @@ -86,6 +98,9 @@ xtm_task_manager_class_init (XtmTaskManagerClass *klass) static void xtm_task_manager_init (XtmTaskManager *manager) { +#ifdef HAVE_WNCK + manager->app_manager = xtm_app_manager_new (); +#endif manager->tasks = g_array_new (FALSE, FALSE, sizeof (Task)); get_owner_uid (&(manager->owner_uid), &(manager->owner_uid_name)); manager->hostname = get_hostname (); @@ -105,6 +120,10 @@ xtm_task_manager_finalize (GObject *object) g_array_free (manager->tasks, TRUE); g_free (manager->owner_uid_name); g_free (manager->hostname); +#ifdef HAVE_WNCK + g_object_unref (manager->app_manager); +#endif + g_object_unref (settings); } static void @@ -143,10 +162,24 @@ _xtm_task_manager_set_model (XtmTaskManager *manager, GtkTreeModel *model) } static void +#ifdef HAVE_WNCK +model_add_task (GtkTreeModel *model, Task *task, App *app, glong timestamp) +#else model_add_task (GtkTreeModel *model, Task *task, glong timestamp) +#endif { GtkTreeIter iter; - gchar *cmdline = pretty_cmdline (task->cmdline, task->name); + gchar *cmdline; + +#ifdef HAVE_WNCK + if (app != NULL && full_cmdline == FALSE) + cmdline = g_strdup (app->name); + else + cmdline = pretty_cmdline (task->cmdline, task->name); +#else + cmdline = pretty_cmdline (task->cmdline, task->name); +#endif + gtk_list_store_append (GTK_LIST_STORE (model), &iter); gtk_list_store_set (GTK_LIST_STORE (model), &iter, XTM_PTV_COLUMN_COMMAND, cmdline, @@ -158,7 +191,12 @@ model_add_task (GtkTreeModel *model, Task *task, glong timestamp) XTM_PTV_COLUMN_FOREGROUND, NULL, XTM_PTV_COLUMN_TIMESTAMP, timestamp, -1); +#ifdef HAVE_WNCK + model_update_tree_iter (model, &iter, task, app); +#else model_update_tree_iter (model, &iter, task); +#endif + g_free (cmdline); } @@ -203,13 +241,20 @@ memory_human_size (guint64 mem, gchar *mem_str) } static void +#ifdef HAVE_WNCK +model_update_tree_iter (GtkTreeModel *model, GtkTreeIter *iter, Task *task, App *app) +#else model_update_tree_iter (GtkTreeModel *model, GtkTreeIter *iter, Task *task) +#endif { gchar vsz[64], rss[64], cpu[16]; gchar value[14]; glong old_timestamp; gchar *old_state; gchar *background, *foreground; +#ifdef HAVE_WNCK + GdkPixbuf *icon; +#endif memory_human_size (task->vsz, vsz); memory_human_size (task->rss, rss); @@ -217,17 +262,34 @@ model_update_tree_iter (GtkTreeModel *model, GtkTreeIter *iter, Task *task) g_snprintf (value, 14, (more_precision) ? "%.2f" : "%.0f", task->cpu_user + task->cpu_system); g_snprintf (cpu, 16, _("%s%%"), value); + /* Retrieve values for tweaking background/foreground color and updating content as needed */ + gtk_tree_model_get (model, iter, XTM_PTV_COLUMN_TIMESTAMP, &old_timestamp, XTM_PTV_COLUMN_STATE, &old_state, + XTM_PTV_COLUMN_BACKGROUND, &background, XTM_PTV_COLUMN_FOREGROUND, &foreground, +#ifdef HAVE_WNCK + XTM_PTV_COLUMN_ICON, &icon, +#endif + -1); + +#ifdef HAVE_WNCK + if (app != NULL && icon == NULL) + gtk_list_store_set (GTK_LIST_STORE (model), iter, XTM_PTV_COLUMN_ICON, app->icon, -1); + + if (app != NULL && full_cmdline == FALSE) + { + gchar *cmdline = g_strdup (app->name); + gtk_list_store_set (GTK_LIST_STORE (model), iter, XTM_PTV_COLUMN_COMMAND, cmdline, -1); + g_free (cmdline); + } + else if (model_update_forced) +#else if (model_update_forced) +#endif { gchar *cmdline = pretty_cmdline (task->cmdline, task->name); gtk_list_store_set (GTK_LIST_STORE (model), iter, XTM_PTV_COLUMN_COMMAND, cmdline, -1); g_free (cmdline); } - /* Retrieve values for tweaking background/foreground color */ - gtk_tree_model_get (model, iter, XTM_PTV_COLUMN_TIMESTAMP, &old_timestamp, XTM_PTV_COLUMN_STATE, &old_state, - XTM_PTV_COLUMN_BACKGROUND, &background, XTM_PTV_COLUMN_FOREGROUND, &foreground, -1); - if (g_strcmp0 (task->state, old_state) != 0 && background == NULL) { /* Set yellow color for changing state */ @@ -270,11 +332,19 @@ model_update_tree_iter (GtkTreeModel *model, GtkTreeIter *iter, Task *task) } static void +#ifdef HAVE_WNCK +model_update_task (GtkTreeModel *model, Task *task, App *app) +#else model_update_task (GtkTreeModel *model, Task *task) +#endif { GtkTreeIter iter; model_find_tree_iter_for_pid (model, task->pid, &iter); +#ifdef HAVE_WNCK + model_update_tree_iter (model, &iter, task, app); +#else model_update_tree_iter (model, &iter, task); +#endif } static void @@ -385,7 +455,12 @@ xtm_task_manager_update_model (XtmTaskManager *manager) for (i = 0; i < manager->tasks->len; i++) { Task *task = &g_array_index (manager->tasks, Task, i); +#ifdef HAVE_WNCK + App *app = xtm_app_manager_get_app_from_pid (manager->app_manager, task->pid); + model_add_task (manager->model, task, app, 0); +#else model_add_task (manager->model, task, 0); +#endif #if DEBUG g_print ("%5d %5s %15s %.50s\n", task->pid, task->uid_name, task->name, task->cmdline); #endif @@ -454,11 +529,17 @@ xtm_task_manager_update_model (XtmTaskManager *manager) for (j = 0; j < manager->tasks->len; j++) { Task *task = &g_array_index (manager->tasks, Task, j); +#ifdef HAVE_WNCK + App *app; +#endif gboolean updated = FALSE; if (task->pid != tasktmp->pid) continue; +#ifdef HAVE_WNCK + app = xtm_app_manager_get_app_from_pid (manager->app_manager, task->pid); +#endif found = TRUE; /* Update the model (with the rest) only if needed, this keeps the CPU cool */ @@ -479,7 +560,11 @@ xtm_task_manager_update_model (XtmTaskManager *manager) task->rss = tasktmp->rss; task->vsz = tasktmp->vsz; task->prio = tasktmp->prio; +#ifdef HAVE_WNCK + model_update_task (manager->model, tasktmp, app); +#else model_update_task (manager->model, tasktmp); +#endif } /* Update command name if needed (can happen) */ @@ -509,7 +594,11 @@ xtm_task_manager_update_model (XtmTaskManager *manager) #if DEBUG g_debug ("Remove color from running PID %d", task->pid); #endif +#ifdef HAVE_WNCK + model_update_task (manager->model, tasktmp, app); +#else model_update_task (manager->model, tasktmp); +#endif } g_free (color); @@ -523,7 +612,12 @@ xtm_task_manager_update_model (XtmTaskManager *manager) #if DEBUG g_debug ("Add new task %d %s", tasktmp->pid, tasktmp->name); #endif +#ifdef HAVE_WNCK + App *app = xtm_app_manager_get_app_from_pid (manager->app_manager, tasktmp->pid); + model_add_task (manager->model, tasktmp, app, __current_timestamp ()); +#else model_add_task (manager->model, tasktmp, __current_timestamp ()); +#endif g_array_append_val (manager->tasks, *tasktmp); } }