[gnome-shell] ShellAppMonitor now always assocates windows with desktop files
- From: Colin Walters <walters src gnome org>
- To: svn-commits-list gnome org
- Subject: [gnome-shell] ShellAppMonitor now always assocates windows with desktop files
- Date: Tue, 30 Jun 2009 20:50:36 +0000 (UTC)
commit 94f92072c2e39f43dfbc281cccc46cfc89c63fc0
Author: Colin Walters <walters verbum org>
Date: Thu Jun 25 17:42:46 2009 -0400
ShellAppMonitor now always assocates windows with desktop files
Track all windows; at the time of opening (and shell startup)
we call into ShellAppSystem to take the WM_CLASS property and
try to find an associated .desktop file.
Add mozilla-firefox to the list of our WM_CLASS workarounds.
Add shell_global_get_screen, since it's often used.
src/shell-app-monitor.c | 317 +++++++++++++++++++++++++++++++++++++++--------
src/shell-app-monitor.h | 5 +-
src/shell-global.c | 13 ++-
src/shell-global.h | 2 +
4 files changed, 282 insertions(+), 55 deletions(-)
---
diff --git a/src/shell-app-monitor.c b/src/shell-app-monitor.c
index 34afc3c..ce10908 100644
--- a/src/shell-app-monitor.c
+++ b/src/shell-app-monitor.c
@@ -13,9 +13,11 @@
#include "shell-app-monitor.h"
+#include "shell-app-system.h"
#include "shell-global.h"
#include "display.h"
+#include "window.h"
/* This file includes modified code from
* desktop-data-engine/engine-dbus/hippo-application-monitor.c
@@ -63,6 +65,7 @@ static struct
const char *pattern;
GRegex *regex;
} title_patterns[] = {
+ {"mozilla-firefox", ".* - Mozilla Firefox", NULL}, \
{"openoffice.org-writer", ".* - OpenOffice.org Writer$", NULL}, \
{"openoffice.org-calc", ".* - OpenOffice.org Calc$", NULL}, \
{"openoffice.org-impress", ".* - OpenOffice.org Impress$", NULL}, \
@@ -93,6 +96,12 @@ struct _ShellAppMonitor
gboolean currently_idle;
gboolean enable_monitoring;
+ /* <char * appid, guint window_count> */
+ GHashTable *running_appids;
+
+ /* <MetaWindow * window, char * appid> */
+ GHashTable *window_to_appid;
+
GHashTable *apps_by_wm_class; /* Seen apps by wm_class */
GHashTable *popularities; /* One AppPopularity struct list per activity */
int upload_apps_burst_count;
@@ -191,6 +200,232 @@ destroy_popularity (gpointer key,
g_slist_free (list);
}
+static char *
+get_wmclass_for_window (MetaWindow *window)
+{
+ static gboolean patterns_initialized = FALSE;
+ const char *wm_class;
+ char *title;
+ int i;
+
+ wm_class = meta_window_get_wm_class (window);
+ g_object_get (window, "title", &title, NULL);
+
+ if (!patterns_initialized) /* Generate match patterns once for all */
+ {
+ patterns_initialized = TRUE;
+ for (i = 0; title_patterns[i].app_id; i++)
+ {
+ title_patterns[i].regex = g_regex_new (title_patterns[i].pattern,
+ 0, 0, NULL);
+ }
+ }
+
+ /* Match window title patterns to identifiers for non-standard apps */
+ if (title)
+ {
+ for (i = 0; title_patterns[i].app_id; i++)
+ {
+ if (g_regex_match (title_patterns[i].regex, title, 0, NULL))
+ {
+ /* Set a pseudo WM class, handled like true ones */
+ wm_class = title_patterns[i].app_id;
+ break;
+ }
+ }
+ }
+
+ g_free (title);
+ return g_strdup (wm_class);
+}
+
+/**
+ * get_cleaned_wmclass_for_window:
+ *
+ * A "cleaned" wmclass is the WM_CLASS property of a window,
+ * after some transformations to turn it into a form
+ * somewhat more resilient to changes, such as lowercasing.
+ */
+static char *
+get_cleaned_wmclass_for_window (MetaWindow *window)
+{
+ char *wmclass;
+ char *cleaned_wmclass;
+
+ if (meta_window_get_window_type (window) != META_WINDOW_NORMAL)
+ return NULL;
+
+ wmclass = get_wmclass_for_window (window);
+ if (!wmclass)
+ return NULL;
+
+ cleaned_wmclass = g_utf8_strdown (wmclass, -1);
+ g_free (wmclass);
+ /* This handles "Fedora Eclipse", probably others */
+ g_strdelimit (cleaned_wmclass, " ", '-');
+ wmclass = g_strdup (cleaned_wmclass);
+ g_free (cleaned_wmclass);
+ return wmclass;
+}
+
+/**
+ * get_appid_for_window:
+ *
+ * Returns a desktop file ID for an application, or %NULL if
+ * we're unable to determine one.
+ */
+static char *
+get_appid_for_window (MetaWindow *window)
+{
+ char *wmclass;
+ char *with_desktop;
+ char *fullpath;
+ ShellAppSystem *appsys;
+
+ wmclass = get_cleaned_wmclass_for_window (window);
+
+ if (!wmclass)
+ return NULL;
+
+ with_desktop = g_strjoin (NULL, wmclass, ".desktop", NULL);
+ g_free (wmclass);
+
+ appsys = shell_app_system_get_default ();
+
+ fullpath = shell_app_system_lookup_basename (appsys, with_desktop);
+
+ return fullpath;
+}
+
+static void
+track_window (ShellAppMonitor *self,
+ MetaWindow *window)
+{
+ char *appid;
+ guint window_count;
+
+ appid = get_appid_for_window (window);
+ if (!appid)
+ return;
+
+ g_hash_table_insert (self->window_to_appid, window, g_strdup (appid));
+
+ window_count = GPOINTER_TO_UINT (g_hash_table_lookup (self->running_appids, appid));
+
+ window_count += 1;
+ g_hash_table_insert (self->running_appids, g_strdup (appid), GUINT_TO_POINTER (window_count));
+ if (window_count == 1)
+ g_signal_emit (self, signals[CHANGED], 0);
+}
+
+static void
+shell_app_monitor_on_window_added (MetaWorkspace *workspace,
+ MetaWindow *window,
+ gpointer user_data)
+{
+ ShellAppMonitor *self = SHELL_APP_MONITOR (user_data);
+
+ track_window (self, window);
+}
+
+static void
+shell_app_monitor_on_window_removed (MetaWorkspace *workspace,
+ MetaWindow *window,
+ gpointer user_data)
+{
+ ShellAppMonitor *self = SHELL_APP_MONITOR (user_data);
+ char *appid;
+ guint window_count;
+
+ appid = g_hash_table_lookup (self->window_to_appid, window);
+ if (!appid)
+ return;
+
+ window_count = GPOINTER_TO_UINT (g_hash_table_lookup (self->running_appids, appid));
+
+ window_count -= 1;
+ if (window_count == 0)
+ {
+ g_hash_table_remove (self->running_appids, appid);
+ g_free (appid);
+ g_signal_emit (self, signals[CHANGED], 0);
+ }
+ else
+ {
+ g_hash_table_insert (self->running_appids, appid, GUINT_TO_POINTER (window_count));
+ }
+ g_hash_table_remove (self->window_to_appid, window);
+}
+
+static void
+load_initial_windows (ShellAppMonitor *monitor)
+{
+ GList *workspaces, *iter;
+ MetaScreen *screen = shell_global_get_screen (shell_global_get ());
+ workspaces = meta_screen_get_workspaces (screen);
+
+ for (iter = workspaces; iter; iter = iter->next)
+ {
+ MetaWorkspace *workspace = iter->data;
+ GList *windows = meta_workspace_list_windows (workspace);
+ GList *window_iter;
+
+ for (window_iter = windows; window_iter; window_iter = window_iter->next)
+ track_window (monitor, (MetaWindow*)window_iter->data);
+
+ g_list_free (windows);
+ }
+}
+
+guint
+shell_app_monitor_get_window_count (ShellAppMonitor *self,
+ const char *appid)
+{
+ return GPOINTER_TO_UINT (g_hash_table_lookup (self->running_appids, appid));
+}
+
+static void
+shell_app_monitor_on_n_workspaces_changed (MetaScreen *screen,
+ gpointer user_data)
+{
+ ShellAppMonitor *self = SHELL_APP_MONITOR (user_data);
+ GList *workspaces, *iter;
+
+ workspaces = meta_screen_get_workspaces (screen);
+
+ for (iter = workspaces; iter; iter = iter->next)
+ {
+ MetaWorkspace *workspace = iter->data;
+
+ /* This pair of disconnect/connect is idempotent if we were
+ * already connected, while ensuring we get connected for
+ * new workspaces.
+ */
+ g_signal_handlers_disconnect_by_func (workspace,
+ shell_app_monitor_on_window_added,
+ self);
+ g_signal_handlers_disconnect_by_func (workspace,
+ shell_app_monitor_on_window_removed,
+ self);
+
+ g_signal_connect (workspace, "window-added",
+ G_CALLBACK (shell_app_monitor_on_window_added), self);
+ g_signal_connect (workspace, "window-removed",
+ G_CALLBACK (shell_app_monitor_on_window_removed), self);
+ }
+}
+
+static void
+init_window_monitoring (ShellAppMonitor *self)
+{
+ MetaScreen *screen = shell_global_get_screen (shell_global_get ());
+
+ g_signal_connect (screen, "notify::n-workspaces",
+ G_CALLBACK (shell_app_monitor_on_n_workspaces_changed), self);
+
+ shell_app_monitor_on_n_workspaces_changed (screen, self);
+}
+
static void
shell_app_monitor_init (ShellAppMonitor *self)
{
@@ -223,6 +458,15 @@ shell_app_monitor_init (ShellAppMonitor *self)
(GDestroyNotify) g_free,
(GDestroyNotify) g_free);
+ self->running_appids = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+
+ self->window_to_appid = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify) g_free);
+
+ load_initial_windows (self);
+ init_window_monitoring (self);
+
g_object_get (shell_global_get(), "configdir", &shell_config_dir, NULL),
path = g_build_filename (shell_config_dir, DATA_FILENAME, NULL);
g_free (shell_config_dir);
@@ -299,16 +543,31 @@ shell_app_monitor_get_most_used_apps (ShellAppMonitor *monitor,
return list;
}
-/* Find the active window in order to collect stats */
+/**
+ * shell_app_monitor_get_running_app_ids:
+ *
+ * @monitor: An app monitor instance
+ *
+ * Returns: (element-type utf8) (transfer container): List of application desktop
+ * identifiers
+ */
+GList *
+shell_app_monitor_get_running_app_ids (ShellAppMonitor *monitor)
+{
+ return g_hash_table_get_keys (monitor->running_appids);
+}
+
void
-get_active_app_properties (ShellAppMonitor *monitor,
- char **wm_class,
- char **title)
+update_app_info (ShellAppMonitor *monitor)
{
+ char *wm_class;
ShellGlobal *global;
+ GHashTable *app_active_times = NULL; /* last active time for an application */
MetaScreen *screen;
MetaDisplay *display;
MetaWindow *active;
+ int activity;
+ guint32 timestamp;
global = shell_global_get ();
g_object_get (global, "screen", &screen, NULL);
@@ -317,60 +576,14 @@ get_active_app_properties (ShellAppMonitor *monitor,
active = meta_display_get_focus_window (display);
- if (wm_class)
- *wm_class = NULL;
- if (title)
- *title = NULL;
-
if (active == NULL)
return;
- *wm_class = g_strdup (meta_window_get_wm_class (active));
- g_object_get (active, "title", title, NULL);
-}
+ wm_class = get_cleaned_wmclass_for_window (active);
-void
-update_app_info (ShellAppMonitor *monitor)
-{
- char *wm_class;
- char *title;
- GHashTable *app_active_times = NULL; /* GTime spent per activity */
- static gboolean first_time = TRUE;
- int activity;
- guint32 timestamp;
- int i;
-
- if (first_time) /* Generate match patterns once for all */
- {
- first_time = FALSE;
- for (i = 0; title_patterns[i].app_id; i++)
- {
- title_patterns[i].regex = g_regex_new (title_patterns[i].pattern,
- 0, 0, NULL);
- }
- }
-
- get_active_app_properties (monitor, &wm_class, &title);
-
- /* Match window title patterns to identifiers for non-standard apps */
- if (title)
- {
- for (i = 0; title_patterns[i].app_id; i++)
- {
- if ( g_regex_match (title_patterns[i].regex, title, 0, NULL) )
- {
- /* Set a pseudo WM class, handled like true ones */
- g_free (wm_class);
- wm_class = g_strdup(title_patterns[i].app_id);
- break;
- }
- }
- g_free (title);
- }
-
if (!wm_class)
return;
-
+
app_active_times = g_hash_table_lookup (monitor->apps_by_wm_class, wm_class);
if (!app_active_times)
{
diff --git a/src/shell-app-monitor.h b/src/shell-app-monitor.h
index f0cf891..65bf8b0 100644
--- a/src/shell-app-monitor.h
+++ b/src/shell-app-monitor.h
@@ -40,9 +40,10 @@ GSList *shell_app_monitor_get_most_used_apps (ShellAppMonitor *monitor,
int activity,
gint number);
+guint shell_app_monitor_get_window_count (ShellAppMonitor *monitor, const char *appid);
+
/* Get whatever's running right now */
-GSList *shell_app_monitor_get_running_apps (ShellAppMonitor *monitor,
- int activity);
+GList *shell_app_monitor_get_running_app_ids (ShellAppMonitor *monitor);
G_END_DECLS
diff --git a/src/shell-global.c b/src/shell-global.c
index 46d6052..a197aa2 100644
--- a/src/shell-global.c
+++ b/src/shell-global.c
@@ -101,7 +101,7 @@ shell_global_get_property(GObject *object,
g_value_set_object (value, mutter_plugin_get_overlay_group (global->plugin));
break;
case PROP_SCREEN:
- g_value_set_object (value, mutter_plugin_get_screen (global->plugin));
+ g_value_set_object (value, shell_global_get_screen (global));
break;
case PROP_SCREEN_WIDTH:
{
@@ -609,6 +609,17 @@ shell_global_set_stage_input_region (ShellGlobal *global,
}
/**
+ * shell_global_get_screen:
+ *
+ * Return value: (transfer none): The default #MetaScreen
+ */
+MetaScreen *
+shell_global_get_screen (ShellGlobal *global)
+{
+ return mutter_plugin_get_screen (global->plugin);
+}
+
+/**
* shell_global_get_windows:
*
* Gets the list of MutterWindows for the plugin's screen
diff --git a/src/shell-global.h b/src/shell-global.h
index 2192b75..0b641a5 100644
--- a/src/shell-global.h
+++ b/src/shell-global.h
@@ -48,6 +48,8 @@ ClutterActor *shell_get_event_related(ClutterEvent *event);
ShellGlobal *shell_global_get (void);
+MetaScreen *shell_global_get_screen (ShellGlobal *global);
+
void shell_global_grab_dbus_service (ShellGlobal *global);
void shell_global_start_task_panel (ShellGlobal *global);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]