diff options
Diffstat (limited to 'libwnck/util.c')
-rw-r--r-- | libwnck/util.c | 523 |
1 files changed, 4 insertions, 519 deletions
diff --git a/libwnck/util.c b/libwnck/util.c index 3760bc3..fa06c34 100644 --- a/libwnck/util.c +++ b/libwnck/util.c @@ -25,11 +25,9 @@ #include "util.h" #include "xutils.h" #include "private.h" +#include "wnck-resource-usage-private.h" #include <gdk/gdkx.h> #include <string.h> -#ifdef HAVE_XRES -#include <X11/extensions/XRes.h> -#endif /** * SECTION:resource @@ -60,81 +58,6 @@ * #WnckApplication. */ -typedef enum -{ - WNCK_EXT_UNKNOWN = 0, - WNCK_EXT_FOUND = 1, - WNCK_EXT_MISSING = 2 -} WnckExtStatus; - - -#if 0 -/* useful for debugging */ -static void -_wnck_print_resource_usage (WnckResourceUsage *usage) -{ - if (!usage) - return; - - g_print ("\twindows : %d\n" - "\tGCs : %d\n" - "\tfonts : %d\n" - "\tpixmaps : %d\n" - "\tpictures : %d\n" - "\tglyphsets : %d\n" - "\tcolormaps : %d\n" - "\tpassive grabs : %d\n" - "\tcursors : %d\n" - "\tunknowns : %d\n" - "\tpixmap bytes : %ld\n" - "\ttotal bytes : ~%ld\n", - usage->n_windows, - usage->n_gcs, - usage->n_fonts, - usage->n_pixmaps, - usage->n_pictures, - usage->n_glyphsets, - usage->n_colormap_entries, - usage->n_passive_grabs, - usage->n_cursors, - usage->n_other, - usage->pixmap_bytes, - usage->total_bytes_estimate); -} -#endif - -static WnckExtStatus -wnck_init_resource_usage (GdkDisplay *gdisplay) -{ - WnckExtStatus status; - - status = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (gdisplay), - "wnck-xres-status")); - - if (status == WNCK_EXT_UNKNOWN) - { -#ifdef HAVE_XRES - Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdisplay); - int event, error; - - if (!XResQueryExtension (xdisplay, &event, &error)) - status = WNCK_EXT_MISSING; - else - status = WNCK_EXT_FOUND; -#else - status = WNCK_EXT_MISSING; -#endif - - g_object_set_data (G_OBJECT (gdisplay), - "wnck-xres-status", - GINT_TO_POINTER (status)); - } - - g_assert (status != WNCK_EXT_UNKNOWN); - - return status; -} - /** * wnck_xid_read_resource_usage: * @gdk_display: a <classname>GdkDisplay</classname>. @@ -155,430 +78,9 @@ wnck_xid_read_resource_usage (GdkDisplay *gdisplay, gulong xid, WnckResourceUsage *usage) { - g_return_if_fail (usage != NULL); - - memset (usage, '\0', sizeof (*usage)); - - if (wnck_init_resource_usage (gdisplay) == WNCK_EXT_MISSING) - return; - -#ifdef HAVE_XRES - { - Display *xdisplay; - XResType *types; - int n_types; - unsigned long pixmap_bytes; - int i; - Atom pixmap_atom; - Atom window_atom; - Atom gc_atom; - Atom picture_atom; - Atom glyphset_atom; - Atom font_atom; - Atom colormap_entry_atom; - Atom passive_grab_atom; - Atom cursor_atom; - - types = NULL; - n_types = 0; - pixmap_bytes = 0; - - xdisplay = GDK_DISPLAY_XDISPLAY (gdisplay); - - _wnck_error_trap_push (xdisplay); - - XResQueryClientResources (xdisplay, - xid, &n_types, - &types); - - XResQueryClientPixmapBytes (xdisplay, - xid, &pixmap_bytes); - _wnck_error_trap_pop (xdisplay); - - usage->pixmap_bytes = pixmap_bytes; - - pixmap_atom = _wnck_atom_get ("PIXMAP"); - window_atom = _wnck_atom_get ("WINDOW"); - gc_atom = _wnck_atom_get ("GC"); - font_atom = _wnck_atom_get ("FONT"); - glyphset_atom = _wnck_atom_get ("GLYPHSET"); - picture_atom = _wnck_atom_get ("PICTURE"); - colormap_entry_atom = _wnck_atom_get ("COLORMAP ENTRY"); - passive_grab_atom = _wnck_atom_get ("PASSIVE GRAB"); - cursor_atom = _wnck_atom_get ("CURSOR"); - - i = 0; - while (i < n_types) - { - guint t = types[i].resource_type; - - if (t == pixmap_atom) - usage->n_pixmaps += types[i].count; - else if (t == window_atom) - usage->n_windows += types[i].count; - else if (t == gc_atom) - usage->n_gcs += types[i].count; - else if (t == picture_atom) - usage->n_pictures += types[i].count; - else if (t == glyphset_atom) - usage->n_glyphsets += types[i].count; - else if (t == font_atom) - usage->n_fonts += types[i].count; - else if (t == colormap_entry_atom) - usage->n_colormap_entries += types[i].count; - else if (t == passive_grab_atom) - usage->n_passive_grabs += types[i].count; - else if (t == cursor_atom) - usage->n_cursors += types[i].count; - else - usage->n_other += types[i].count; - - ++i; - } - - XFree(types); - - usage->total_bytes_estimate = usage->pixmap_bytes; - - /* FIXME look in the X server source and come up with better - * answers here. Ideally we change XRes to return a number - * like this since it can do things like divide the cost of - * a shared resource among those sharing it. - */ - usage->total_bytes_estimate += usage->n_windows * 24; - usage->total_bytes_estimate += usage->n_gcs * 24; - usage->total_bytes_estimate += usage->n_pictures * 24; - usage->total_bytes_estimate += usage->n_glyphsets * 24; - usage->total_bytes_estimate += usage->n_fonts * 1024; - usage->total_bytes_estimate += usage->n_colormap_entries * 24; - usage->total_bytes_estimate += usage->n_passive_grabs * 24; - usage->total_bytes_estimate += usage->n_cursors * 24; - usage->total_bytes_estimate += usage->n_other * 24; - } -#else /* HAVE_XRES */ - g_assert_not_reached (); -#endif /* HAVE_XRES */ + _wnck_read_resource_usage_xid (gdisplay, xid, usage); } -#ifdef HAVE_XRES -static void -wnck_pid_read_resource_usage_free_hash (gpointer data) -{ - g_slice_free (gulong, data); -} - -static guint -wnck_gulong_hash (gconstpointer v) -{ - /* FIXME: this is obvioulsy wrong, but nearly 100% of the time, the gulong - * only contains guint values */ - return *(const guint *) v; -} - -static gboolean -wnck_gulong_equal (gconstpointer a, - gconstpointer b) -{ - return *((const gulong *) a) == *((const gulong *) b); -} - -static gulong -wnck_check_window_for_pid (Screen *screen, - Window win, - XID match_xid, - XID mask) -{ - if ((win & ~mask) == match_xid) { - return _wnck_get_pid (screen, win); - } - - return 0; -} - -static void -wnck_find_pid_for_resource_r (Display *xdisplay, - Screen *screen, - Window win_top, - XID match_xid, - XID mask, - gulong *xid, - gulong *pid) -{ - Status qtres; - int err; - Window dummy; - Window *children; - guint n_children; - guint i; - gulong found_pid = 0; - - while (gtk_events_pending ()) - gtk_main_iteration (); - - found_pid = wnck_check_window_for_pid (screen, win_top, match_xid, mask); - if (found_pid != 0) - { - *xid = win_top; - *pid = found_pid; - } - - _wnck_error_trap_push (xdisplay); - qtres = XQueryTree (xdisplay, win_top, &dummy, &dummy, - &children, &n_children); - err = _wnck_error_trap_pop (xdisplay); - - if (!qtres || err != Success) - return; - - for (i = 0; i < n_children; i++) - { - wnck_find_pid_for_resource_r (xdisplay, screen, children[i], - match_xid, mask, xid, pid); - - if (*pid != 0) - break; - } - - if (children) - XFree ((char *)children); -} - -struct xresclient_state -{ - XResClient *clients; - int n_clients; - int next; - Display *xdisplay; - GHashTable *hashtable_pid; -}; - -static struct xresclient_state xres_state = { NULL, 0, -1, NULL, NULL }; -static guint xres_idleid = 0; -static GHashTable *xres_hashtable = NULL; -static time_t start_update = 0; -static time_t end_update = 0; -static guint xres_removeid = 0; - -static void -wnck_pid_read_resource_usage_xres_state_free (gpointer data) -{ - struct xresclient_state *state; - - state = (struct xresclient_state *) data; - - if (state->clients) - XFree (state->clients); - state->clients = NULL; - - state->n_clients = 0; - state->next = -1; - state->xdisplay = NULL; - - if (state->hashtable_pid) - g_hash_table_destroy (state->hashtable_pid); - state->hashtable_pid = NULL; -} - -static gboolean -wnck_pid_read_resource_usage_fill_cache (struct xresclient_state *state) -{ - int i; - gulong pid; - gulong xid; - XID match_xid; - - if (state->next >= state->n_clients) - { - if (xres_hashtable) - g_hash_table_destroy (xres_hashtable); - xres_hashtable = state->hashtable_pid; - state->hashtable_pid = NULL; - - time (&end_update); - - xres_idleid = 0; - return FALSE; - } - - match_xid = (state->clients[state->next].resource_base & - ~state->clients[state->next].resource_mask); - - pid = 0; - xid = 0; - - for (i = 0; i < ScreenCount (state->xdisplay); i++) - { - Screen *screen; - Window root; - - screen = ScreenOfDisplay (state->xdisplay, i); - root = RootWindow (state->xdisplay, i); - - if (root == None) - continue; - - wnck_find_pid_for_resource_r (state->xdisplay, screen, root, match_xid, - state->clients[state->next].resource_mask, - &xid, &pid); - - if (pid != 0 && xid != 0) - break; - } - - if (pid != 0 && xid != 0) - { - gulong *key; - gulong *value; - - key = g_slice_new (gulong); - value = g_slice_new (gulong); - *key = pid; - *value = xid; - g_hash_table_insert (state->hashtable_pid, key, value); - } - - state->next++; - - return TRUE; -} - -static void -wnck_pid_read_resource_usage_start_build_cache (GdkDisplay *gdisplay) -{ - Display *xdisplay; - int err; - - if (xres_idleid != 0) - return; - - time (&start_update); - - xdisplay = GDK_DISPLAY_XDISPLAY (gdisplay); - - _wnck_error_trap_push (xdisplay); - XResQueryClients (xdisplay, &xres_state.n_clients, &xres_state.clients); - err = _wnck_error_trap_pop (xdisplay); - - if (err != Success) - return; - - xres_state.next = (xres_state.n_clients > 0) ? 0 : -1; - xres_state.xdisplay = xdisplay; - xres_state.hashtable_pid = g_hash_table_new_full ( - wnck_gulong_hash, - wnck_gulong_equal, - wnck_pid_read_resource_usage_free_hash, - wnck_pid_read_resource_usage_free_hash); - - xres_idleid = g_idle_add_full ( - G_PRIORITY_HIGH_IDLE, - (GSourceFunc) wnck_pid_read_resource_usage_fill_cache, - &xres_state, wnck_pid_read_resource_usage_xres_state_free); -} - -static gboolean -wnck_pid_read_resource_usage_destroy_hash_table (gpointer data) -{ - xres_removeid = 0; - - if (xres_hashtable) - g_hash_table_destroy (xres_hashtable); - - xres_hashtable = NULL; - - return FALSE; -} - -#define XRES_UPDATE_RATE_SEC 30 -static gboolean -wnck_pid_read_resource_usage_from_cache (GdkDisplay *gdisplay, - gulong pid, - WnckResourceUsage *usage) -{ - gboolean need_rebuild; - gulong *xid_p; - int cache_validity; - - if (end_update == 0) - time (&end_update); - - cache_validity = MAX (XRES_UPDATE_RATE_SEC, (end_update - start_update) * 2); - - /* we rebuild the cache if it was never built or if it's old */ - need_rebuild = (xres_hashtable == NULL || - (end_update < time (NULL) - cache_validity)); - - if (xres_hashtable) - { - /* clear the cache after quite some time, because it might not be used - * anymore */ - if (xres_removeid != 0) - g_source_remove (xres_removeid); - xres_removeid = g_timeout_add_seconds (cache_validity * 2, - wnck_pid_read_resource_usage_destroy_hash_table, - NULL); - } - - if (need_rebuild) - wnck_pid_read_resource_usage_start_build_cache (gdisplay); - - if (xres_hashtable) - xid_p = g_hash_table_lookup (xres_hashtable, &pid); - else - xid_p = NULL; - - if (xid_p) - { - wnck_xid_read_resource_usage (gdisplay, *xid_p, usage); - return TRUE; - } - - return FALSE; -} - -static void -wnck_pid_read_resource_usage_no_cache (GdkDisplay *gdisplay, - gulong pid, - WnckResourceUsage *usage) -{ - Display *xdisplay; - int i; - - xdisplay = GDK_DISPLAY_XDISPLAY (gdisplay); - - i = 0; - while (i < ScreenCount (xdisplay)) - { - WnckScreen *screen; - GList *windows; - GList *tmp; - - screen = wnck_screen_get (i); - - g_assert (screen != NULL); - - windows = wnck_screen_get_windows (screen); - tmp = windows; - while (tmp != NULL) - { - if (wnck_window_get_pid (tmp->data) == (int) pid) - { - wnck_xid_read_resource_usage (gdisplay, - wnck_window_get_xid (tmp->data), - usage); - - /* stop on first window found */ - return; - } - - tmp = tmp->next; - } - - ++i; - } -} -#endif /* HAVE_XRES */ - /** * wnck_pid_read_resource_usage: * @gdk_display: a <classname>GdkDisplay</classname>. @@ -608,19 +110,7 @@ wnck_pid_read_resource_usage (GdkDisplay *gdisplay, gulong pid, WnckResourceUsage *usage) { - g_return_if_fail (usage != NULL); - - memset (usage, '\0', sizeof (*usage)); - - if (wnck_init_resource_usage (gdisplay) == WNCK_EXT_MISSING) - return; - -#ifdef HAVE_XRES - if (!wnck_pid_read_resource_usage_from_cache (gdisplay, pid, usage)) - /* the cache might not be built, might be outdated or might not contain - * data for a new X client, so try to fallback to something else */ - wnck_pid_read_resource_usage_no_cache (gdisplay, pid, usage); -#endif /* HAVE_XRES */ + _wnck_read_resource_usage_pid (gdisplay, pid, usage); } static WnckClientType client_type = 0; @@ -835,12 +325,7 @@ wnck_shutdown (void) { g_clear_object (&wnck_handle); -#ifdef HAVE_XRES - if (xres_removeid != 0) - g_source_remove (xres_removeid); - xres_removeid = 0; - wnck_pid_read_resource_usage_destroy_hash_table (NULL); -#endif + _wnck_read_resources_shutdown_all (); } void |