Blame libwnck/util.c

Packit 4e910c
/* util header */
Packit 4e910c
/* vim: set sw=2 et: */
Packit 4e910c
Packit 4e910c
/*
Packit 4e910c
 * Copyright (C) 2001 Havoc Pennington
Packit 4e910c
 * Copyright (C) 2006-2007 Vincent Untz
Packit 4e910c
 *
Packit 4e910c
 * This library is free software; you can redistribute it and/or
Packit 4e910c
 * modify it under the terms of the GNU Library General Public
Packit 4e910c
 * License as published by the Free Software Foundation; either
Packit 4e910c
 * version 2 of the License, or (at your option) any later version.
Packit 4e910c
 *
Packit 4e910c
 * This library is distributed in the hope that it will be useful,
Packit 4e910c
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 4e910c
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 4e910c
 * Library General Public License for more details.
Packit 4e910c
 *
Packit 4e910c
 * You should have received a copy of the GNU Library General Public
Packit 4e910c
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit 4e910c
 */
Packit 4e910c
Packit 4e910c
#include <config.h>
Packit 4e910c
Packit 4e910c
#include <glib/gi18n-lib.h>
Packit 4e910c
#include "util.h"
Packit 4e910c
#include "xutils.h"
Packit 4e910c
#include "private.h"
Packit 4e910c
#include <gdk/gdkx.h>
Packit 4e910c
#include <string.h>
Packit 4e910c
#ifdef HAVE_XRES
Packit 4e910c
#include <X11/extensions/XRes.h>
Packit 4e910c
#endif
Packit 4e910c
Packit 4e910c
/**
Packit 4e910c
 * SECTION:resource
Packit 4e910c
 * @short_description: reading resource usage of X clients.
Packit 4e910c
 * @see_also: wnck_window_get_xid(), wnck_application_get_xid(), wnck_window_get_pid(), wnck_application_get_pid()
Packit 4e910c
 * @stability: Unstable
Packit 4e910c
 *
Packit 4e910c
 * libwnck provides an easy-to-use interface to the XRes X server extension to
Packit 4e910c
 * read resource usage of X clients, which can be defined either by the X
Packit 4e910c
 * window ID of one of their windows or by the process ID of their process.
Packit 4e910c
 */
Packit 4e910c
Packit 4e910c
/**
Packit 4e910c
 * SECTION:misc
Packit 4e910c
 * @short_description: other additional features.
Packit 4e910c
 * @stability: Unstable
Packit 4e910c
 *
Packit 4e910c
 * These functions are utility functions providing some additional features to
Packit 4e910c
 * libwnck users.
Packit 4e910c
 */
Packit 4e910c
Packit 4e910c
/**
Packit 4e910c
 * SECTION:icons
Packit 4e910c
 * @short_description: icons related functions.
Packit 4e910c
 * @stability: Unstable
Packit 4e910c
 *
Packit 4e910c
 * These functions are utility functions to manage icons for #WnckWindow and
Packit 4e910c
 * #WnckApplication.
Packit 4e910c
 */
Packit 4e910c
Packit 4e910c
typedef enum
Packit 4e910c
{
Packit 4e910c
  WNCK_EXT_UNKNOWN = 0,
Packit 4e910c
  WNCK_EXT_FOUND = 1,
Packit 4e910c
  WNCK_EXT_MISSING = 2
Packit 4e910c
} WnckExtStatus;
Packit 4e910c
Packit 4e910c
Packit 4e910c
#if 0
Packit 4e910c
/* useful for debugging */
Packit 4e910c
static void
Packit 4e910c
_wnck_print_resource_usage (WnckResourceUsage *usage)
Packit 4e910c
{
Packit 4e910c
  if (!usage)
Packit 4e910c
    return;
Packit 4e910c
Packit 4e910c
  g_print ("\twindows       : %d\n"
Packit 4e910c
           "\tGCs           : %d\n"
Packit 4e910c
           "\tfonts         : %d\n"
Packit 4e910c
           "\tpixmaps       : %d\n"
Packit 4e910c
           "\tpictures      : %d\n"
Packit 4e910c
           "\tglyphsets     : %d\n"
Packit 4e910c
           "\tcolormaps     : %d\n"
Packit 4e910c
           "\tpassive grabs : %d\n"
Packit 4e910c
           "\tcursors       : %d\n"
Packit 4e910c
           "\tunknowns      : %d\n"
Packit 4e910c
           "\tpixmap bytes  : %ld\n"
Packit 4e910c
           "\ttotal bytes   : ~%ld\n",
Packit 4e910c
           usage->n_windows,
Packit 4e910c
           usage->n_gcs,
Packit 4e910c
           usage->n_fonts,
Packit 4e910c
           usage->n_pixmaps,
Packit 4e910c
           usage->n_pictures,
Packit 4e910c
           usage->n_glyphsets,
Packit 4e910c
           usage->n_colormap_entries,
Packit 4e910c
           usage->n_passive_grabs,
Packit 4e910c
           usage->n_cursors,
Packit 4e910c
           usage->n_other,
Packit 4e910c
           usage->pixmap_bytes,
Packit 4e910c
           usage->total_bytes_estimate);
Packit 4e910c
}
Packit 4e910c
#endif
Packit 4e910c
Packit 4e910c
static WnckExtStatus
Packit 4e910c
wnck_init_resource_usage (GdkDisplay *gdisplay)
Packit 4e910c
{
Packit 4e910c
  WnckExtStatus status;
Packit 4e910c
Packit 4e910c
  status = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (gdisplay),
Packit 4e910c
                                               "wnck-xres-status"));
Packit 4e910c
Packit 4e910c
  if (status == WNCK_EXT_UNKNOWN)
Packit 4e910c
    {
Packit 4e910c
#ifdef HAVE_XRES
Packit 4e910c
      Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdisplay);
Packit 4e910c
      int event, error;
Packit 4e910c
Packit 4e910c
      if (!XResQueryExtension (xdisplay, &event, &error))
Packit 4e910c
        status = WNCK_EXT_MISSING;
Packit 4e910c
      else
Packit 4e910c
        status = WNCK_EXT_FOUND;
Packit 4e910c
#else
Packit 4e910c
      status = WNCK_EXT_MISSING;
Packit 4e910c
#endif
Packit 4e910c
Packit 4e910c
      g_object_set_data (G_OBJECT (gdisplay),
Packit 4e910c
                         "wnck-xres-status",
Packit 4e910c
                         GINT_TO_POINTER (status));
Packit 4e910c
    }
Packit 4e910c
Packit 4e910c
  g_assert (status != WNCK_EXT_UNKNOWN);
Packit 4e910c
Packit 4e910c
  return status;
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
/**
Packit 4e910c
 * wnck_xid_read_resource_usage:
Packit 4e910c
 * @gdk_display: a <classname>GdkDisplay</classname>.
Packit 4e910c
 * @xid: an X window ID.
Packit 4e910c
 * @usage: return location for the X resource usage of the application owning
Packit 4e910c
 * the X window ID @xid.
Packit 4e910c
 *
Packit 4e910c
 * Looks for the X resource usage of the application owning the X window ID
Packit 4e910c
 * @xid on display @gdisplay. If no resource usage can be found, then all
Packit 4e910c
 * fields of @usage are set to 0.
Packit 4e910c
 *
Packit 4e910c
 * To properly work, this function requires the XRes extension on the X server.
Packit 4e910c
 *
Packit 4e910c
 * Since: 2.6
Packit 4e910c
 */
Packit 4e910c
void
Packit 4e910c
wnck_xid_read_resource_usage (GdkDisplay        *gdisplay,
Packit 4e910c
                              gulong             xid,
Packit 4e910c
                              WnckResourceUsage *usage)
Packit 4e910c
{
Packit 4e910c
  g_return_if_fail (usage != NULL);
Packit 4e910c
Packit 4e910c
  memset (usage, '\0', sizeof (*usage));
Packit 4e910c
Packit 4e910c
  if (wnck_init_resource_usage (gdisplay) == WNCK_EXT_MISSING)
Packit 4e910c
    return;
Packit 4e910c
Packit 4e910c
#ifdef HAVE_XRES
Packit 4e910c
 {
Packit 4e910c
   Display *xdisplay;
Packit 4e910c
   XResType *types;
Packit 4e910c
   int n_types;
Packit 4e910c
   unsigned long pixmap_bytes;
Packit 4e910c
   int i;
Packit 4e910c
   Atom pixmap_atom;
Packit 4e910c
   Atom window_atom;
Packit 4e910c
   Atom gc_atom;
Packit 4e910c
   Atom picture_atom;
Packit 4e910c
   Atom glyphset_atom;
Packit 4e910c
   Atom font_atom;
Packit 4e910c
   Atom colormap_entry_atom;
Packit 4e910c
   Atom passive_grab_atom;
Packit 4e910c
   Atom cursor_atom;
Packit 4e910c
Packit 4e910c
   types = NULL;
Packit 4e910c
   n_types = 0;
Packit 4e910c
   pixmap_bytes = 0;
Packit 4e910c
Packit 4e910c
  xdisplay = GDK_DISPLAY_XDISPLAY (gdisplay);
Packit 4e910c
Packit 4e910c
  _wnck_error_trap_push (xdisplay);
Packit 4e910c
Packit 4e910c
  XResQueryClientResources (xdisplay,
Packit 4e910c
                             xid, &n_types,
Packit 4e910c
                             &types);
Packit 4e910c
Packit 4e910c
   XResQueryClientPixmapBytes (xdisplay,
Packit 4e910c
                               xid, &pixmap_bytes);
Packit 4e910c
   _wnck_error_trap_pop (xdisplay);
Packit 4e910c
Packit 4e910c
   usage->pixmap_bytes = pixmap_bytes;
Packit 4e910c
Packit 4e910c
   pixmap_atom = _wnck_atom_get ("PIXMAP");
Packit 4e910c
   window_atom = _wnck_atom_get ("WINDOW");
Packit 4e910c
   gc_atom = _wnck_atom_get ("GC");
Packit 4e910c
   font_atom = _wnck_atom_get ("FONT");
Packit 4e910c
   glyphset_atom = _wnck_atom_get ("GLYPHSET");
Packit 4e910c
   picture_atom = _wnck_atom_get ("PICTURE");
Packit 4e910c
   colormap_entry_atom = _wnck_atom_get ("COLORMAP ENTRY");
Packit 4e910c
   passive_grab_atom = _wnck_atom_get ("PASSIVE GRAB");
Packit 4e910c
   cursor_atom = _wnck_atom_get ("CURSOR");
Packit 4e910c
Packit 4e910c
   i = 0;
Packit 4e910c
   while (i < n_types)
Packit 4e910c
     {
Packit 4e910c
       guint t = types[i].resource_type;
Packit 4e910c
Packit 4e910c
       if (t == pixmap_atom)
Packit 4e910c
         usage->n_pixmaps += types[i].count;
Packit 4e910c
       else if (t == window_atom)
Packit 4e910c
         usage->n_windows += types[i].count;
Packit 4e910c
       else if (t == gc_atom)
Packit 4e910c
         usage->n_gcs += types[i].count;
Packit 4e910c
       else if (t == picture_atom)
Packit 4e910c
         usage->n_pictures += types[i].count;
Packit 4e910c
       else if (t == glyphset_atom)
Packit 4e910c
         usage->n_glyphsets += types[i].count;
Packit 4e910c
       else if (t == font_atom)
Packit 4e910c
         usage->n_fonts += types[i].count;
Packit 4e910c
       else if (t == colormap_entry_atom)
Packit 4e910c
         usage->n_colormap_entries += types[i].count;
Packit 4e910c
       else if (t == passive_grab_atom)
Packit 4e910c
         usage->n_passive_grabs += types[i].count;
Packit 4e910c
       else if (t == cursor_atom)
Packit 4e910c
         usage->n_cursors += types[i].count;
Packit 4e910c
       else
Packit 4e910c
         usage->n_other += types[i].count;
Packit 4e910c
Packit 4e910c
       ++i;
Packit 4e910c
     }
Packit 4e910c
Packit 4e910c
   XFree(types);
Packit 4e910c
Packit 4e910c
   usage->total_bytes_estimate = usage->pixmap_bytes;
Packit 4e910c
Packit 4e910c
   /* FIXME look in the X server source and come up with better
Packit 4e910c
    * answers here. Ideally we change XRes to return a number
Packit 4e910c
    * like this since it can do things like divide the cost of
Packit 4e910c
    * a shared resource among those sharing it.
Packit 4e910c
    */
Packit 4e910c
   usage->total_bytes_estimate += usage->n_windows * 24;
Packit 4e910c
   usage->total_bytes_estimate += usage->n_gcs * 24;
Packit 4e910c
   usage->total_bytes_estimate += usage->n_pictures * 24;
Packit 4e910c
   usage->total_bytes_estimate += usage->n_glyphsets * 24;
Packit 4e910c
   usage->total_bytes_estimate += usage->n_fonts * 1024;
Packit 4e910c
   usage->total_bytes_estimate += usage->n_colormap_entries * 24;
Packit 4e910c
   usage->total_bytes_estimate += usage->n_passive_grabs * 24;
Packit 4e910c
   usage->total_bytes_estimate += usage->n_cursors * 24;
Packit 4e910c
   usage->total_bytes_estimate += usage->n_other * 24;
Packit 4e910c
 }
Packit 4e910c
#else /* HAVE_XRES */
Packit 4e910c
  g_assert_not_reached ();
Packit 4e910c
#endif /* HAVE_XRES */
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
#ifdef HAVE_XRES
Packit 4e910c
static void
Packit 4e910c
wnck_pid_read_resource_usage_free_hash (gpointer data)
Packit 4e910c
{
Packit 4e910c
  g_slice_free (gulong, data);
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
static guint
Packit 4e910c
wnck_gulong_hash (gconstpointer v)
Packit 4e910c
{
Packit 4e910c
  /* FIXME: this is obvioulsy wrong, but nearly 100% of the time, the gulong
Packit 4e910c
   * only contains guint values */
Packit 4e910c
  return *(const guint *) v;
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
static gboolean
Packit 4e910c
wnck_gulong_equal (gconstpointer a,
Packit 4e910c
                   gconstpointer b)
Packit 4e910c
{
Packit 4e910c
  return *((const gulong *) a) == *((const gulong *) b);
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
static gulong
Packit 4e910c
wnck_check_window_for_pid (Screen *screen,
Packit 4e910c
                           Window  win,
Packit 4e910c
                           XID     match_xid,
Packit 4e910c
                           XID     mask)
Packit 4e910c
{
Packit 4e910c
  if ((win & ~mask) == match_xid) {
Packit 4e910c
    return _wnck_get_pid (screen, win);
Packit 4e910c
  }
Packit 4e910c
Packit 4e910c
  return 0;
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
static void
Packit 4e910c
wnck_find_pid_for_resource_r (Display *xdisplay,
Packit 4e910c
                              Screen  *screen,
Packit 4e910c
                              Window   win_top,
Packit 4e910c
                              XID      match_xid,
Packit 4e910c
                              XID      mask,
Packit 4e910c
                              gulong  *xid,
Packit 4e910c
                              gulong  *pid)
Packit 4e910c
{
Packit 4e910c
  Status   qtres;
Packit 4e910c
  int      err;
Packit 4e910c
  Window   dummy;
Packit 4e910c
  Window  *children;
Packit 4e910c
  guint    n_children;
Packit 4e910c
  guint    i;
Packit 4e910c
  gulong   found_pid = 0;
Packit 4e910c
Packit 4e910c
  while (gtk_events_pending ())
Packit 4e910c
    gtk_main_iteration ();
Packit 4e910c
Packit 4e910c
  found_pid = wnck_check_window_for_pid (screen, win_top, match_xid, mask);
Packit 4e910c
  if (found_pid != 0)
Packit 4e910c
    {
Packit 4e910c
      *xid = win_top;
Packit 4e910c
      *pid = found_pid;
Packit 4e910c
    }
Packit 4e910c
Packit 4e910c
  _wnck_error_trap_push (xdisplay);
Packit 4e910c
  qtres = XQueryTree (xdisplay, win_top, &dummy, &dummy,
Packit 4e910c
                      &children, &n_children);
Packit 4e910c
  err = _wnck_error_trap_pop (xdisplay);
Packit 4e910c
Packit 4e910c
  if (!qtres || err != Success)
Packit 4e910c
    return;
Packit 4e910c
Packit 4e910c
  for (i = 0; i < n_children; i++)
Packit 4e910c
    {
Packit 4e910c
      wnck_find_pid_for_resource_r (xdisplay, screen, children[i],
Packit 4e910c
                                    match_xid, mask, xid, pid);
Packit 4e910c
Packit 4e910c
      if (*pid != 0)
Packit 4e910c
	break;
Packit 4e910c
    }
Packit 4e910c
Packit 4e910c
  if (children)
Packit 4e910c
    XFree ((char *)children);
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
struct xresclient_state
Packit 4e910c
{
Packit 4e910c
  XResClient *clients;
Packit 4e910c
  int         n_clients;
Packit 4e910c
  int         next;
Packit 4e910c
  Display    *xdisplay;
Packit 4e910c
  GHashTable *hashtable_pid;
Packit 4e910c
};
Packit 4e910c
Packit 4e910c
static struct xresclient_state xres_state = { NULL, 0, -1, NULL, NULL };
Packit 4e910c
static guint       xres_idleid = 0;
Packit 4e910c
static GHashTable *xres_hashtable = NULL;
Packit 4e910c
static time_t      start_update = 0;
Packit 4e910c
static time_t      end_update = 0;
Packit 4e910c
static guint       xres_removeid = 0;
Packit 4e910c
Packit 4e910c
static void
Packit 4e910c
wnck_pid_read_resource_usage_xres_state_free (gpointer data)
Packit 4e910c
{
Packit 4e910c
  struct xresclient_state *state;
Packit 4e910c
Packit 4e910c
  state = (struct xresclient_state *) data;
Packit 4e910c
Packit 4e910c
  if (state->clients)
Packit 4e910c
    XFree (state->clients);
Packit 4e910c
  state->clients = NULL;
Packit 4e910c
Packit 4e910c
  state->n_clients = 0;
Packit 4e910c
  state->next = -1;
Packit 4e910c
  state->xdisplay = NULL;
Packit 4e910c
Packit 4e910c
  if (state->hashtable_pid)
Packit 4e910c
    g_hash_table_destroy (state->hashtable_pid);
Packit 4e910c
  state->hashtable_pid = NULL;
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
static gboolean
Packit 4e910c
wnck_pid_read_resource_usage_fill_cache (struct xresclient_state *state)
Packit 4e910c
{
Packit 4e910c
  int    i;
Packit 4e910c
  gulong pid;
Packit 4e910c
  gulong xid;
Packit 4e910c
  XID    match_xid;
Packit 4e910c
Packit 4e910c
  if (state->next >= state->n_clients)
Packit 4e910c
    {
Packit 4e910c
      if (xres_hashtable)
Packit 4e910c
        g_hash_table_destroy (xres_hashtable);
Packit 4e910c
      xres_hashtable = state->hashtable_pid;
Packit 4e910c
      state->hashtable_pid = NULL;
Packit 4e910c
Packit 4e910c
      time (&end_update);
Packit 4e910c
Packit 4e910c
      xres_idleid = 0;
Packit 4e910c
      return FALSE;
Packit 4e910c
    }
Packit 4e910c
Packit 4e910c
  match_xid = (state->clients[state->next].resource_base &
Packit 4e910c
               ~state->clients[state->next].resource_mask);
Packit 4e910c
Packit 4e910c
  pid = 0;
Packit 4e910c
  xid = 0;
Packit 4e910c
Packit 4e910c
  for (i = 0; i < ScreenCount (state->xdisplay); i++)
Packit 4e910c
    {
Packit 4e910c
      Screen *screen;
Packit 4e910c
      Window  root;
Packit 4e910c
Packit 4e910c
      screen = ScreenOfDisplay (state->xdisplay, i);
Packit 4e910c
      root = RootWindow (state->xdisplay, i);
Packit 4e910c
Packit 4e910c
      if (root == None)
Packit 4e910c
        continue;
Packit 4e910c
Packit 4e910c
      wnck_find_pid_for_resource_r (state->xdisplay, screen, root, match_xid,
Packit 4e910c
                                    state->clients[state->next].resource_mask,
Packit 4e910c
                                    &xid, &pid;;
Packit 4e910c
Packit 4e910c
      if (pid != 0 && xid != 0)
Packit 4e910c
        break;
Packit 4e910c
    }
Packit 4e910c
Packit 4e910c
  if (pid != 0 && xid != 0)
Packit 4e910c
    {
Packit 4e910c
      gulong *key;
Packit 4e910c
      gulong *value;
Packit 4e910c
Packit 4e910c
      key = g_slice_new (gulong);
Packit 4e910c
      value = g_slice_new (gulong);
Packit 4e910c
      *key = pid;
Packit 4e910c
      *value = xid;
Packit 4e910c
      g_hash_table_insert (state->hashtable_pid, key, value);
Packit 4e910c
    }
Packit 4e910c
Packit 4e910c
  state->next++;
Packit 4e910c
Packit 4e910c
  return TRUE;
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
static void
Packit 4e910c
wnck_pid_read_resource_usage_start_build_cache (GdkDisplay *gdisplay)
Packit 4e910c
{
Packit 4e910c
  Display *xdisplay;
Packit 4e910c
  int      err;
Packit 4e910c
Packit 4e910c
  if (xres_idleid != 0)
Packit 4e910c
    return;
Packit 4e910c
Packit 4e910c
  time (&start_update);
Packit 4e910c
Packit 4e910c
  xdisplay = GDK_DISPLAY_XDISPLAY (gdisplay);
Packit 4e910c
Packit 4e910c
  _wnck_error_trap_push (xdisplay);
Packit 4e910c
  XResQueryClients (xdisplay, &xres_state.n_clients, &xres_state.clients);
Packit 4e910c
  err = _wnck_error_trap_pop (xdisplay);
Packit 4e910c
Packit 4e910c
  if (err != Success)
Packit 4e910c
    return;
Packit 4e910c
Packit 4e910c
  xres_state.next = (xres_state.n_clients > 0) ? 0 : -1;
Packit 4e910c
  xres_state.xdisplay = xdisplay;
Packit 4e910c
  xres_state.hashtable_pid = g_hash_table_new_full (
Packit 4e910c
                                     wnck_gulong_hash,
Packit 4e910c
                                     wnck_gulong_equal,
Packit 4e910c
                                     wnck_pid_read_resource_usage_free_hash,
Packit 4e910c
                                     wnck_pid_read_resource_usage_free_hash);
Packit 4e910c
Packit 4e910c
  xres_idleid = g_idle_add_full (
Packit 4e910c
                        G_PRIORITY_HIGH_IDLE,
Packit 4e910c
                        (GSourceFunc) wnck_pid_read_resource_usage_fill_cache,
Packit 4e910c
                        &xres_state, wnck_pid_read_resource_usage_xres_state_free);
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
static gboolean
Packit 4e910c
wnck_pid_read_resource_usage_destroy_hash_table (gpointer data)
Packit 4e910c
{
Packit 4e910c
  xres_removeid = 0;
Packit 4e910c
Packit 4e910c
  if (xres_hashtable)
Packit 4e910c
    g_hash_table_destroy (xres_hashtable);
Packit 4e910c
Packit 4e910c
  xres_hashtable = NULL;
Packit 4e910c
Packit 4e910c
  return FALSE;
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
#define XRES_UPDATE_RATE_SEC 30
Packit 4e910c
static gboolean
Packit 4e910c
wnck_pid_read_resource_usage_from_cache (GdkDisplay        *gdisplay,
Packit 4e910c
                                         gulong             pid,
Packit 4e910c
                                         WnckResourceUsage *usage)
Packit 4e910c
{
Packit 4e910c
  gboolean  need_rebuild;
Packit 4e910c
  gulong   *xid_p;
Packit 4e910c
  int       cache_validity;
Packit 4e910c
Packit 4e910c
  if (end_update == 0)
Packit 4e910c
    time (&end_update);
Packit 4e910c
Packit 4e910c
  cache_validity = MAX (XRES_UPDATE_RATE_SEC, (end_update - start_update) * 2);
Packit 4e910c
Packit 4e910c
  /* we rebuild the cache if it was never built or if it's old */
Packit 4e910c
  need_rebuild = (xres_hashtable == NULL ||
Packit 4e910c
                  (end_update < time (NULL) - cache_validity));
Packit 4e910c
Packit 4e910c
  if (xres_hashtable)
Packit 4e910c
    {
Packit 4e910c
      /* clear the cache after quite some time, because it might not be used
Packit 4e910c
       * anymore */
Packit 4e910c
      if (xres_removeid != 0)
Packit 4e910c
        g_source_remove (xres_removeid);
Packit 4e910c
      xres_removeid = g_timeout_add_seconds (cache_validity * 2,
Packit 4e910c
                                             wnck_pid_read_resource_usage_destroy_hash_table,
Packit 4e910c
                                             NULL);
Packit 4e910c
    }
Packit 4e910c
Packit 4e910c
  if (need_rebuild)
Packit 4e910c
    wnck_pid_read_resource_usage_start_build_cache (gdisplay);
Packit 4e910c
Packit 4e910c
  if (xres_hashtable)
Packit 4e910c
    xid_p = g_hash_table_lookup (xres_hashtable, &pid;;
Packit 4e910c
  else
Packit 4e910c
    xid_p = NULL;
Packit 4e910c
Packit 4e910c
  if (xid_p)
Packit 4e910c
    {
Packit 4e910c
      wnck_xid_read_resource_usage (gdisplay, *xid_p, usage);
Packit 4e910c
      return TRUE;
Packit 4e910c
    }
Packit 4e910c
Packit 4e910c
  return FALSE;
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
static void
Packit 4e910c
wnck_pid_read_resource_usage_no_cache (GdkDisplay        *gdisplay,
Packit 4e910c
                                       gulong             pid,
Packit 4e910c
                                       WnckResourceUsage *usage)
Packit 4e910c
{
Packit 4e910c
  Display *xdisplay;
Packit 4e910c
  int i;
Packit 4e910c
Packit 4e910c
  xdisplay = GDK_DISPLAY_XDISPLAY (gdisplay);
Packit 4e910c
Packit 4e910c
  i = 0;
Packit 4e910c
  while (i < ScreenCount (xdisplay))
Packit 4e910c
    {
Packit 4e910c
      WnckScreen *screen;
Packit 4e910c
      GList *windows;
Packit 4e910c
      GList *tmp;
Packit 4e910c
Packit 4e910c
      screen = wnck_screen_get (i);
Packit 4e910c
Packit 4e910c
      g_assert (screen != NULL);
Packit 4e910c
Packit 4e910c
      windows = wnck_screen_get_windows (screen);
Packit 4e910c
      tmp = windows;
Packit 4e910c
      while (tmp != NULL)
Packit 4e910c
        {
Packit 4e910c
          if (wnck_window_get_pid (tmp->data) == (int) pid)
Packit 4e910c
            {
Packit 4e910c
              wnck_xid_read_resource_usage (gdisplay,
Packit 4e910c
                                            wnck_window_get_xid (tmp->data),
Packit 4e910c
                                            usage);
Packit 4e910c
Packit 4e910c
              /* stop on first window found */
Packit 4e910c
              return;
Packit 4e910c
            }
Packit 4e910c
Packit 4e910c
          tmp = tmp->next;
Packit 4e910c
        }
Packit 4e910c
Packit 4e910c
      ++i;
Packit 4e910c
    }
Packit 4e910c
}
Packit 4e910c
#endif /* HAVE_XRES */
Packit 4e910c
Packit 4e910c
/**
Packit 4e910c
 * wnck_pid_read_resource_usage:
Packit 4e910c
 * @gdk_display: a <classname>GdkDisplay</classname>.
Packit 4e910c
 * @pid: a process ID.
Packit 4e910c
 * @usage: return location for the X resource usage of the application with
Packit 4e910c
 * process ID @pid.
Packit 4e910c
 *
Packit 4e910c
 * Looks for the X resource usage of the application with process ID @pid on
Packit 4e910c
 * display @gdisplay. If no resource usage can be found, then all fields of
Packit 4e910c
 * @usage are set to 0.
Packit 4e910c
 *
Packit 4e910c
 * In order to find the resource usage of an application that does not have an
Packit 4e910c
 * X window visible to libwnck (panel applets do not have any toplevel windows,
Packit 4e910c
 * for example), wnck_pid_read_resource_usage() walks through the whole tree of
Packit 4e910c
 * X windows. Since this walk is expensive in CPU, a cache is created. This
Packit 4e910c
 * cache is updated in the background. This means there is a non-null
Packit 4e910c
 * probability that no resource usage will be found for an application, even if
Packit 4e910c
 * it is an X client. If this happens, calling wnck_pid_read_resource_usage()
Packit 4e910c
 * again after a few seconds should work.
Packit 4e910c
 *
Packit 4e910c
 * To properly work, this function requires the XRes extension on the X server.
Packit 4e910c
 *
Packit 4e910c
 * Since: 2.6
Packit 4e910c
 */
Packit 4e910c
void
Packit 4e910c
wnck_pid_read_resource_usage (GdkDisplay        *gdisplay,
Packit 4e910c
                              gulong             pid,
Packit 4e910c
                              WnckResourceUsage *usage)
Packit 4e910c
{
Packit 4e910c
  g_return_if_fail (usage != NULL);
Packit 4e910c
Packit 4e910c
  memset (usage, '\0', sizeof (*usage));
Packit 4e910c
Packit 4e910c
  if (wnck_init_resource_usage (gdisplay) == WNCK_EXT_MISSING)
Packit 4e910c
    return;
Packit 4e910c
Packit 4e910c
#ifdef HAVE_XRES
Packit 4e910c
  if (!wnck_pid_read_resource_usage_from_cache (gdisplay, pid, usage))
Packit 4e910c
    /* the cache might not be built, might be outdated or might not contain
Packit 4e910c
     * data for a new X client, so try to fallback to something else */
Packit 4e910c
    wnck_pid_read_resource_usage_no_cache (gdisplay, pid, usage);
Packit 4e910c
#endif /* HAVE_XRES */
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
static WnckClientType client_type = 0;
Packit 4e910c
Packit 4e910c
/**
Packit 4e910c
 * wnck_set_client_type:
Packit 4e910c
 * @ewmh_sourceindication_client_type: a role for the client.
Packit 4e910c
 *
Packit 4e910c
 * Sets the role of the libwnck user.
Packit 4e910c
 *
Packit 4e910c
 * The default role is %WNCK_CLIENT_TYPE_APPLICATION. Therefore, for
Packit 4e910c
 * applications providing some window management features, like pagers or
Packit 4e910c
 * tasklists, it is important to set the role to %WNCK_CLIENT_TYPE_PAGER for
Packit 4e910c
 * libwnck to properly work.
Packit 4e910c
 *
Packit 4e910c
 * Since: 2.14
Packit 4e910c
 */
Packit 4e910c
void
Packit 4e910c
wnck_set_client_type (WnckClientType ewmh_sourceindication_client_type)
Packit 4e910c
{
Packit 4e910c
  /* Clients constantly switching types makes no sense; this should only be
Packit 4e910c
   * set once.
Packit 4e910c
   */
Packit 4e910c
  if (client_type != 0)
Packit 4e910c
    g_critical ("wnck_set_client_type got called multiple times.\n");
Packit 4e910c
  else
Packit 4e910c
    client_type = ewmh_sourceindication_client_type;
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
WnckClientType
Packit 4e910c
_wnck_get_client_type (void)
Packit 4e910c
{
Packit 4e910c
  /* If the type hasn't been set yet, use the default--treat it as a
Packit 4e910c
   * normal application.
Packit 4e910c
   */
Packit 4e910c
  if (client_type == 0)
Packit 4e910c
    client_type = WNCK_CLIENT_TYPE_APPLICATION;
Packit 4e910c
Packit 4e910c
  return client_type;
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
static gsize default_icon_size = WNCK_DEFAULT_ICON_SIZE;
Packit 4e910c
Packit 4e910c
/**
Packit 4e910c
 * wnck_set_default_icon_size:
Packit 4e910c
 * @size: the default size for windows and application standard icons.
Packit 4e910c
 *
Packit 4e910c
 * The default main icon size is %WNCK_DEFAULT_ICON_SIZE. This function allows
Packit 4e910c
 * to change this value.
Packit 4e910c
 *
Packit 4e910c
 * Since: 2.4.6
Packit 4e910c
 */
Packit 4e910c
void
Packit 4e910c
wnck_set_default_icon_size (gsize size)
Packit 4e910c
{
Packit 4e910c
  default_icon_size = size;
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
gsize
Packit 4e910c
_wnck_get_default_icon_size (void)
Packit 4e910c
{
Packit 4e910c
  return default_icon_size;
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
static gsize default_mini_icon_size = WNCK_DEFAULT_MINI_ICON_SIZE;
Packit 4e910c
Packit 4e910c
/**
Packit 4e910c
 * wnck_set_default_mini_icon_size:
Packit 4e910c
 * @size: the default size for windows and application mini icons.
Packit 4e910c
 *
Packit 4e910c
 * The default main icon size is %WNCK_DEFAULT_MINI_ICON_SIZE. This function
Packit 4e910c
 * allows to change this value.
Packit 4e910c
 *
Packit 4e910c
 * Since: 2.4.6
Packit 4e910c
 */
Packit 4e910c
void
Packit 4e910c
wnck_set_default_mini_icon_size (gsize size)
Packit 4e910c
{
Packit 4e910c
  int default_screen;
Packit 4e910c
  WnckScreen *screen;
Packit 4e910c
  GList *l;
Packit 4e910c
Packit 4e910c
  default_mini_icon_size = size;
Packit 4e910c
Packit 4e910c
  default_screen = DefaultScreen (_wnck_get_default_display ());
Packit 4e910c
  screen = _wnck_screen_get_existing (default_screen);
Packit 4e910c
Packit 4e910c
  if (WNCK_IS_SCREEN (screen))
Packit 4e910c
    {
Packit 4e910c
      /* Make applications and icons to reload their icons */
Packit 4e910c
      for (l = wnck_screen_get_windows (screen); l; l = l->next)
Packit 4e910c
        {
Packit 4e910c
          WnckWindow *window = WNCK_WINDOW (l->data);
Packit 4e910c
          WnckApplication *application = wnck_window_get_application (window);
Packit 4e910c
Packit 4e910c
          _wnck_window_load_icons (window);
Packit 4e910c
Packit 4e910c
          if (WNCK_IS_APPLICATION (application))
Packit 4e910c
            _wnck_application_load_icons (application);
Packit 4e910c
        }
Packit 4e910c
    }
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
gsize
Packit 4e910c
_wnck_get_default_mini_icon_size (void)
Packit 4e910c
{
Packit 4e910c
  return default_mini_icon_size;
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
/**
Packit 4e910c
 * _make_gtk_label_bold:
Packit 4e910c
 * @label: The label.
Packit 4e910c
 *
Packit 4e910c
 * Switches the font of label to a bold equivalent.
Packit 4e910c
 **/
Packit 4e910c
void
Packit 4e910c
_make_gtk_label_bold (GtkLabel *label)
Packit 4e910c
{
Packit 4e910c
  GtkStyleContext *context;
Packit 4e910c
Packit 4e910c
  _wnck_ensure_fallback_style ();
Packit 4e910c
Packit 4e910c
  context = gtk_widget_get_style_context (GTK_WIDGET (label));
Packit 4e910c
  gtk_style_context_add_class (context, "wnck-needs-attention");
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
void
Packit 4e910c
_make_gtk_label_normal (GtkLabel *label)
Packit 4e910c
{
Packit 4e910c
  GtkStyleContext *context;
Packit 4e910c
Packit 4e910c
  context = gtk_widget_get_style_context (GTK_WIDGET (label));
Packit 4e910c
  gtk_style_context_remove_class (context, "wnck-needs-attention");
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
#ifdef HAVE_STARTUP_NOTIFICATION
Packit 4e910c
static gboolean
Packit 4e910c
_wnck_util_sn_utf8_validator (const char *str,
Packit 4e910c
                              int         max_len)
Packit 4e910c
{
Packit 4e910c
  return g_utf8_validate (str, max_len, NULL);
Packit 4e910c
}
Packit 4e910c
#endif /* HAVE_STARTUP_NOTIFICATION */
Packit 4e910c
Packit 4e910c
void
Packit 4e910c
_wnck_init (void)
Packit 4e910c
{
Packit 4e910c
  static gboolean done = FALSE;
Packit 4e910c
Packit 4e910c
  if (!done)
Packit 4e910c
    {
Packit 4e910c
      bindtextdomain (GETTEXT_PACKAGE, WNCK_LOCALEDIR);
Packit 4e910c
      bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
Packit 4e910c
Packit 4e910c
#ifdef HAVE_STARTUP_NOTIFICATION
Packit 4e910c
      sn_set_utf8_validator (_wnck_util_sn_utf8_validator);
Packit 4e910c
#endif /* HAVE_STARTUP_NOTIFICATION */
Packit 4e910c
Packit 4e910c
      done = TRUE;
Packit 4e910c
    }
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
Display *
Packit 4e910c
_wnck_get_default_display (void)
Packit 4e910c
{
Packit 4e910c
  GdkDisplay *display = gdk_display_get_default ();
Packit 4e910c
  /* FIXME: when we fix libwnck to not use the GDK default display, we will
Packit 4e910c
   * need to fix wnckprop accordingly. */
Packit 4e910c
  if (!GDK_IS_X11_DISPLAY (display))
Packit 4e910c
    {
Packit 4e910c
      g_warning ("libwnck is designed to work in X11 only, no valid display found");
Packit 4e910c
      return NULL;
Packit 4e910c
    }
Packit 4e910c
Packit 4e910c
  return GDK_DISPLAY_XDISPLAY (display);
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
/**
Packit 4e910c
 * wnck_shutdown:
Packit 4e910c
 *
Packit 4e910c
 * Makes libwnck stop listening to events and tear down all resources from
Packit 4e910c
 * libwnck. This should be done if you are not going to need the state change
Packit 4e910c
 * notifications for an extended period of time, to avoid wakeups with every
Packit 4e910c
 * key and focus event.
Packit 4e910c
 *
Packit 4e910c
 * After this, all pointers to Wnck object you might still hold are invalid.
Packit 4e910c
 *
Packit 4e910c
 * Due to the fact that 
Packit 4e910c
 * linkend="getting-started.pitfalls.memory-management">Wnck objects are all
Packit 4e910c
 * owned by libwnck</link>, users of this API through introspection should be
Packit 4e910c
 * extremely careful: they must explicitly clear variables referencing objects
Packit 4e910c
 * before this call. Failure to do so might result in crashes.
Packit 4e910c
 *
Packit 4e910c
 * Since: 3.4
Packit 4e910c
 */
Packit 4e910c
void
Packit 4e910c
wnck_shutdown (void)
Packit 4e910c
{
Packit 4e910c
  _wnck_event_filter_shutdown ();
Packit 4e910c
Packit 4e910c
  /* Warning: this is hacky :-)
Packit 4e910c
   *
Packit 4e910c
   * Shutting down all WnckScreen objects will automatically unreference (and
Packit 4e910c
   * finalize) all WnckWindow objects, but not the WnckClassGroup and
Packit 4e910c
   * WnckApplication objects.
Packit 4e910c
   * Therefore we need to manually shut down all WnckClassGroup and
Packit 4e910c
   * WnckApplication objects first, since they reference the WnckScreen they're
Packit 4e910c
   * on.
Packit 4e910c
   * On the other side, shutting down the WnckScreen objects will results in
Packit 4e910c
   * all WnckWindow objects getting unreferenced and finalized, and must
Packit 4e910c
   * actually be done before shutting down global WnckWindow structures
Packit 4e910c
   * (because the WnckScreen has a list of WnckWindow that will get mis-used
Packit 4e910c
   * otherwise). */
Packit 4e910c
  _wnck_class_group_shutdown_all ();
Packit 4e910c
  _wnck_application_shutdown_all ();
Packit 4e910c
  _wnck_screen_shutdown_all ();
Packit 4e910c
  _wnck_window_shutdown_all ();
Packit 4e910c
Packit 4e910c
#ifdef HAVE_XRES
Packit 4e910c
  if (xres_removeid != 0)
Packit 4e910c
    g_source_remove (xres_removeid);
Packit 4e910c
  xres_removeid = 0;
Packit 4e910c
  wnck_pid_read_resource_usage_destroy_hash_table (NULL);
Packit 4e910c
#endif
Packit 4e910c
}
Packit 4e910c
Packit 4e910c
void
Packit 4e910c
_wnck_ensure_fallback_style (void)
Packit 4e910c
{
Packit 4e910c
  static gboolean css_loaded = FALSE;
Packit 4e910c
  GtkCssProvider *provider;
Packit 4e910c
  guint priority;
Packit 4e910c
Packit 4e910c
  if (css_loaded)
Packit 4e910c
    return;
Packit 4e910c
Packit 4e910c
  provider = gtk_css_provider_new ();
Packit 4e910c
  gtk_css_provider_load_from_resource (provider, "/org/gnome/libwnck/wnck.css");
Packit 4e910c
Packit 4e910c
  priority = GTK_STYLE_PROVIDER_PRIORITY_FALLBACK;
Packit 4e910c
  gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
Packit 4e910c
                                             GTK_STYLE_PROVIDER (provider),
Packit 4e910c
                                             priority);
Packit 4e910c
Packit 4e910c
  g_object_unref (provider);
Packit 4e910c
Packit 4e910c
  css_loaded = TRUE;
Packit 4e910c
}