Display window icons/names

Add optional link on libwnck (default=yes) and build a new object from
app-manager.c to keep an up to date list of applications with their name
and icon. Use it inside the task manager object to display inside the
tree view.
This commit is contained in:
Mike Massonnet
2010-06-04 14:41:28 +02:00
parent d4b63cac19
commit 2f995e8226
7 changed files with 380 additions and 11 deletions

View File

@@ -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

View File

@@ -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

196
src/app-manager.c Normal file
View File

@@ -0,0 +1,196 @@
/*
* Copyright (c) 2010 Mike Massonnet, <mmassonnet@xfce.org>
*
* 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 <config.h>
#endif
#include <glib-object.h>
#include <gtk/gtk.h>
#define WNCK_I_KNOW_THIS_IS_UNSTABLE
#include <libwnck/libwnck.h>
#include "app-manager.h"
typedef struct _XtmAppManagerClass XtmAppManagerClass;
struct _XtmAppManagerClass
{
GObjectClass parent_class;
};
struct _XtmAppManager
{
GObject parent;
/*<private>*/
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);
}

45
src/app-manager.h Normal file
View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2010 Mike Massonnet, <mmassonnet@xfce.org>
*
* 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 <config.h>
#endif
#include <glib-object.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#define WNCK_I_KNOW_THIS_IS_UNSTABLE
#include <libwnck/libwnck.h>
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 */

View File

@@ -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));

View File

@@ -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,

View File

@@ -22,6 +22,9 @@
#include <gtk/gtk.h>
#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;
/*<private>*/
#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);
}
}