summaryrefslogtreecommitdiff
path: root/libwnck/xutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'libwnck/xutils.c')
-rw-r--r--libwnck/xutils.c729
1 files changed, 1 insertions, 728 deletions
diff --git a/libwnck/xutils.c b/libwnck/xutils.c
index 8c14234..58873dc 100644
--- a/libwnck/xutils.c
+++ b/libwnck/xutils.c
@@ -1451,206 +1451,7 @@ _wnck_select_input (Screen *screen,
return old_mask;
}
-static gboolean
-find_best_size (gulong *data,
- gulong nitems,
- int ideal_size,
- int *width,
- int *height,
- gulong **start)
-{
- int best_w;
- int best_h;
- gulong *best_start;
-
- *width = 0;
- *height = 0;
- *start = NULL;
-
- best_w = 0;
- best_h = 0;
- best_start = NULL;
-
- while (nitems > 0)
- {
- int w, h;
- gboolean replace;
-
- replace = FALSE;
-
- if (nitems < 3)
- return FALSE; /* no space for w, h */
-
- w = data[0];
- h = data[1];
-
- if (nitems < ((gulong) (w * h) + 2))
- break; /* not enough data */
-
- if (best_start == NULL)
- {
- replace = TRUE;
- }
- else
- {
- /* work with averages */
- int best_size = (best_w + best_h) / 2;
- int this_size = (w + h) / 2;
-
- /* larger than desired is always better than smaller */
- if (best_size < ideal_size &&
- this_size >= ideal_size)
- replace = TRUE;
- /* if we have too small, pick anything bigger */
- else if (best_size < ideal_size &&
- this_size > best_size)
- replace = TRUE;
- /* if we have too large, pick anything smaller
- * but still >= the ideal
- */
- else if (best_size > ideal_size &&
- this_size >= ideal_size &&
- this_size < best_size)
- replace = TRUE;
- }
-
- if (replace)
- {
- best_start = data + 2;
- best_w = w;
- best_h = h;
- }
-
- data += (w * h) + 2;
- nitems -= (w * h) + 2;
- }
-
- if (best_start)
- {
- *start = best_start;
- *width = best_w;
- *height = best_h;
- return TRUE;
- }
- else
- return FALSE;
-}
-
-static void
-argbdata_to_pixdata (gulong *argb_data, int len, guchar **pixdata)
-{
- guchar *p;
- int i;
-
- *pixdata = g_new (guchar, len * 4);
- p = *pixdata;
-
- /* One could speed this up a lot. */
- i = 0;
- while (i < len)
- {
- guint argb;
- guint rgba;
-
- argb = argb_data[i];
- rgba = (argb << 8) | (argb >> 24);
-
- *p = rgba >> 24;
- ++p;
- *p = (rgba >> 16) & 0xff;
- ++p;
- *p = (rgba >> 8) & 0xff;
- ++p;
- *p = rgba & 0xff;
- ++p;
-
- ++i;
- }
-}
-
-static gboolean
-read_rgb_icon (Screen *screen,
- Window xwindow,
- int ideal_size,
- int ideal_mini_size,
- int *width,
- int *height,
- guchar **pixdata,
- int *mini_width,
- int *mini_height,
- guchar **mini_pixdata)
-{
- Display *display;
- Atom type;
- int format;
- gulong nitems;
- gulong bytes_after;
- int result, err;
- gulong *data;
- gulong *best;
- int w, h;
- gulong *best_mini;
- int mini_w, mini_h;
-
- display = DisplayOfScreen (screen);
-
- _wnck_error_trap_push (display);
- type = None;
- data = NULL;
- result = XGetWindowProperty (display,
- xwindow,
- _wnck_atom_get ("_NET_WM_ICON"),
- 0, G_MAXLONG,
- False, XA_CARDINAL, &type, &format, &nitems,
- &bytes_after, (void*)&data);
-
- err = _wnck_error_trap_pop (display);
-
- if (err != Success ||
- result != Success)
- return FALSE;
-
- if (type != XA_CARDINAL)
- {
- XFree (data);
- return FALSE;
- }
-
- if (!find_best_size (data, nitems, ideal_size, &w, &h, &best))
- {
- XFree (data);
- return FALSE;
- }
-
- if (!find_best_size (data, nitems,
- ideal_mini_size,
- &mini_w, &mini_h, &best_mini))
- {
- XFree (data);
- return FALSE;
- }
-
- *width = w;
- *height = h;
-
- *mini_width = mini_w;
- *mini_height = mini_h;
-
- argbdata_to_pixdata (best, w * h, pixdata);
- argbdata_to_pixdata (best_mini, mini_w * mini_h, mini_pixdata);
-
- XFree (data);
-
- return TRUE;
-}
-
-static void
-free_pixels (guchar *pixels, gpointer data)
-{
- g_free (pixels);
-}
-
-static cairo_surface_t *
+cairo_surface_t *
_wnck_cairo_surface_get_from_pixmap (Screen *screen,
Pixmap xpixmap)
{
@@ -1741,534 +1542,6 @@ _wnck_gdk_pixbuf_get_from_pixmap (Screen *screen,
return retval;
}
-static gboolean
-try_pixmap_and_mask (Screen *screen,
- Pixmap src_pixmap,
- Pixmap src_mask,
- GdkPixbuf **iconp,
- int ideal_size,
- GdkPixbuf **mini_iconp,
- int ideal_mini_size)
-{
- cairo_surface_t *surface, *mask_surface, *image;
- GdkDisplay *gdk_display;
- GdkPixbuf *unscaled;
- int width, height;
- cairo_t *cr;
-
- if (src_pixmap == None)
- return FALSE;
-
- surface = _wnck_cairo_surface_get_from_pixmap (screen, src_pixmap);
-
- if (surface && src_mask != None)
- mask_surface = _wnck_cairo_surface_get_from_pixmap (screen, src_mask);
- else
- mask_surface = NULL;
-
- if (surface == NULL)
- return FALSE;
-
- gdk_display = gdk_x11_lookup_xdisplay (XDisplayOfScreen (screen));
- g_assert (gdk_display != NULL);
-
- gdk_x11_display_error_trap_push (gdk_display);
-
- width = cairo_xlib_surface_get_width (surface);
- height = cairo_xlib_surface_get_height (surface);
-
- image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
- width, height);
- cr = cairo_create (image);
-
- /* Need special code for alpha-only surfaces. We only get those
- * for bitmaps. And in that case, it's a differentiation between
- * foreground (white) and background (black).
- */
- if (cairo_surface_get_content (surface) & CAIRO_CONTENT_ALPHA)
- {
- cairo_push_group (cr);
-
- /* black background */
- cairo_set_source_rgb (cr, 0, 0, 0);
- cairo_paint (cr);
- /* mask with white foreground */
- cairo_set_source_rgb (cr, 1, 1, 1);
- cairo_mask_surface (cr, surface, 0, 0);
-
- cairo_pop_group_to_source (cr);
- }
- else
- cairo_set_source_surface (cr, surface, 0, 0);
-
- if (mask_surface)
- {
- cairo_mask_surface (cr, mask_surface, 0, 0);
- cairo_surface_destroy (mask_surface);
- }
- else
- cairo_paint (cr);
-
- cairo_surface_destroy (surface);
- cairo_destroy (cr);
-
- if (gdk_x11_display_error_trap_pop (gdk_display) != Success)
- {
- cairo_surface_destroy (image);
- return FALSE;
- }
-
- unscaled = gdk_pixbuf_get_from_surface (image,
- 0, 0,
- width, height);
-
- cairo_surface_destroy (image);
-
- if (unscaled)
- {
- *iconp =
- gdk_pixbuf_scale_simple (unscaled,
- ideal_size,
- ideal_size,
- GDK_INTERP_BILINEAR);
- *mini_iconp =
- gdk_pixbuf_scale_simple (unscaled,
- ideal_mini_size,
- ideal_mini_size,
- GDK_INTERP_BILINEAR);
-
- g_object_unref (G_OBJECT (unscaled));
- return TRUE;
- }
- else
- return FALSE;
-}
-
-static void
-get_kwm_win_icon (Screen *screen,
- Window xwindow,
- Pixmap *pixmap,
- Pixmap *mask)
-{
- Display *display;
- Atom type;
- int format;
- gulong nitems;
- gulong bytes_after;
- Pixmap *icons;
- int err, result;
-
- display = DisplayOfScreen (screen);
-
- *pixmap = None;
- *mask = None;
-
- _wnck_error_trap_push (display);
- icons = NULL;
- result = XGetWindowProperty (display, xwindow,
- _wnck_atom_get ("KWM_WIN_ICON"),
- 0, G_MAXLONG,
- False,
- _wnck_atom_get ("KWM_WIN_ICON"),
- &type, &format, &nitems,
- &bytes_after, (void*)&icons);
-
- err = _wnck_error_trap_pop (display);
- if (err != Success ||
- result != Success)
- return;
-
- if (type != _wnck_atom_get ("KWM_WIN_ICON"))
- {
- XFree (icons);
- return;
- }
-
- *pixmap = icons[0];
- *mask = icons[1];
-
- XFree (icons);
-
- return;
-}
-
-typedef enum
-{
- /* These MUST be in ascending order of preference;
- * i.e. if we get _NET_WM_ICON and already have
- * WM_HINTS, we prefer _NET_WM_ICON
- */
- USING_NO_ICON,
- USING_FALLBACK_ICON,
- USING_KWM_WIN_ICON,
- USING_WM_HINTS,
- USING_NET_WM_ICON
-} IconOrigin;
-
-struct _WnckIconCache
-{
- IconOrigin origin;
- Pixmap prev_pixmap;
- Pixmap prev_mask;
- GdkPixbuf *icon;
- GdkPixbuf *mini_icon;
- int ideal_size;
- int ideal_mini_size;
- guint want_fallback : 1;
- /* TRUE if these props have changed */
- guint wm_hints_dirty : 1;
- guint kwm_win_icon_dirty : 1;
- guint net_wm_icon_dirty : 1;
-};
-
-WnckIconCache*
-_wnck_icon_cache_new (void)
-{
- WnckIconCache *icon_cache;
-
- icon_cache = g_slice_new0 (WnckIconCache);
-
- icon_cache->origin = USING_NO_ICON;
- icon_cache->prev_pixmap = None;
- icon_cache->icon = NULL;
- icon_cache->mini_icon = NULL;
- icon_cache->ideal_size = -1; /* won't be a legit size */
- icon_cache->ideal_mini_size = -1;
- icon_cache->want_fallback = TRUE;
- icon_cache->wm_hints_dirty = TRUE;
- icon_cache->kwm_win_icon_dirty = TRUE;
- icon_cache->net_wm_icon_dirty = TRUE;
-
- return icon_cache;
-}
-
-static void
-clear_icon_cache (WnckIconCache *icon_cache,
- gboolean dirty_all)
-{
- if (icon_cache->icon)
- g_object_unref (G_OBJECT (icon_cache->icon));
- icon_cache->icon = NULL;
-
- if (icon_cache->mini_icon)
- g_object_unref (G_OBJECT (icon_cache->mini_icon));
- icon_cache->mini_icon = NULL;
-
- icon_cache->origin = USING_NO_ICON;
-
- if (dirty_all)
- {
- icon_cache->wm_hints_dirty = TRUE;
- icon_cache->kwm_win_icon_dirty = TRUE;
- icon_cache->net_wm_icon_dirty = TRUE;
- }
-}
-
-void
-_wnck_icon_cache_free (WnckIconCache *icon_cache)
-{
- clear_icon_cache (icon_cache, FALSE);
-
- g_slice_free (WnckIconCache, icon_cache);
-}
-
-void
-_wnck_icon_cache_property_changed (WnckIconCache *icon_cache,
- Atom atom)
-{
- if (atom == _wnck_atom_get ("_NET_WM_ICON"))
- icon_cache->net_wm_icon_dirty = TRUE;
- else if (atom == _wnck_atom_get ("KWM_WIN_ICON"))
- icon_cache->kwm_win_icon_dirty = TRUE;
- else if (atom == _wnck_atom_get ("WM_HINTS"))
- icon_cache->wm_hints_dirty = TRUE;
-}
-
-gboolean
-_wnck_icon_cache_get_icon_invalidated (WnckIconCache *icon_cache)
-{
- if (icon_cache->origin <= USING_KWM_WIN_ICON &&
- icon_cache->kwm_win_icon_dirty)
- return TRUE;
- else if (icon_cache->origin <= USING_WM_HINTS &&
- icon_cache->wm_hints_dirty)
- return TRUE;
- else if (icon_cache->origin <= USING_NET_WM_ICON &&
- icon_cache->net_wm_icon_dirty)
- return TRUE;
- else if (icon_cache->origin < USING_FALLBACK_ICON &&
- icon_cache->want_fallback)
- return TRUE;
- else if (icon_cache->origin == USING_NO_ICON)
- return TRUE;
- else if (icon_cache->origin == USING_FALLBACK_ICON &&
- !icon_cache->want_fallback)
- return TRUE;
- else
- return FALSE;
-}
-
-void
-_wnck_icon_cache_set_want_fallback (WnckIconCache *icon_cache,
- gboolean setting)
-{
- icon_cache->want_fallback = setting;
-}
-
-gboolean
-_wnck_icon_cache_get_is_fallback (WnckIconCache *icon_cache)
-{
- return icon_cache->origin == USING_FALLBACK_ICON;
-}
-
-static void
-replace_cache (WnckIconCache *icon_cache,
- IconOrigin origin,
- GdkPixbuf *new_icon,
- GdkPixbuf *new_mini_icon)
-{
- clear_icon_cache (icon_cache, FALSE);
-
- icon_cache->origin = origin;
-
- if (new_icon)
- g_object_ref (G_OBJECT (new_icon));
-
- icon_cache->icon = new_icon;
-
- if (new_mini_icon)
- g_object_ref (G_OBJECT (new_mini_icon));
-
- icon_cache->mini_icon = new_mini_icon;
-}
-
-static GdkPixbuf*
-scaled_from_pixdata (guchar *pixdata,
- int w,
- int h,
- int new_w,
- int new_h)
-{
- GdkPixbuf *src;
- GdkPixbuf *dest;
-
- src = gdk_pixbuf_new_from_data (pixdata,
- GDK_COLORSPACE_RGB,
- TRUE,
- 8,
- w, h, w * 4,
- free_pixels,
- NULL);
-
- if (src == NULL)
- return NULL;
-
- if (w != h)
- {
- GdkPixbuf *tmp;
- int size;
-
- size = MAX (w, h);
-
- tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, size, size);
-
- if (tmp != NULL)
- {
- gdk_pixbuf_fill (tmp, 0);
- gdk_pixbuf_copy_area (src, 0, 0, w, h,
- tmp,
- (size - w) / 2, (size - h) / 2);
-
- g_object_unref (src);
- src = tmp;
- }
- }
-
- if (w != new_w || h != new_h)
- {
- dest = gdk_pixbuf_scale_simple (src, new_w, new_h, GDK_INTERP_BILINEAR);
-
- g_object_unref (G_OBJECT (src));
- }
- else
- {
- dest = src;
- }
-
- return dest;
-}
-
-gboolean
-_wnck_read_icons (WnckScreen *screen,
- Window xwindow,
- WnckIconCache *icon_cache,
- GdkPixbuf **iconp,
- int ideal_size,
- GdkPixbuf **mini_iconp,
- int ideal_mini_size)
-{
- Screen *xscreen;
- Display *display;
- guchar *pixdata;
- int w, h;
- guchar *mini_pixdata;
- int mini_w, mini_h;
- Pixmap pixmap;
- Pixmap mask;
- XWMHints *hints;
-
- /* Return value is whether the icon changed */
-
- g_return_val_if_fail (icon_cache != NULL, FALSE);
-
- xscreen = _wnck_screen_get_xscreen (screen);
- display = DisplayOfScreen (xscreen);
-
- *iconp = NULL;
- *mini_iconp = NULL;
-
- if (ideal_size != icon_cache->ideal_size ||
- ideal_mini_size != icon_cache->ideal_mini_size)
- clear_icon_cache (icon_cache, TRUE);
-
- icon_cache->ideal_size = ideal_size;
- icon_cache->ideal_mini_size = ideal_mini_size;
-
- if (!_wnck_icon_cache_get_icon_invalidated (icon_cache))
- return FALSE; /* we have no new info to use */
-
- pixdata = NULL;
-
- /* Our algorithm here assumes that we can't have for example origin
- * < USING_NET_WM_ICON and icon_cache->net_wm_icon_dirty == FALSE
- * unless we have tried to read NET_WM_ICON.
- *
- * Put another way, if an icon origin is not dirty, then we have
- * tried to read it at the current size. If it is dirty, then
- * we haven't done that since the last change.
- */
-
- if (icon_cache->origin <= USING_NET_WM_ICON &&
- icon_cache->net_wm_icon_dirty)
-
- {
- icon_cache->net_wm_icon_dirty = FALSE;
-
- if (read_rgb_icon (xscreen, xwindow,
- ideal_size,
- ideal_mini_size,
- &w, &h, &pixdata,
- &mini_w, &mini_h, &mini_pixdata))
- {
- *iconp = scaled_from_pixdata (pixdata, w, h, ideal_size, ideal_size);
-
- *mini_iconp = scaled_from_pixdata (mini_pixdata, mini_w, mini_h,
- ideal_mini_size, ideal_mini_size);
-
- replace_cache (icon_cache, USING_NET_WM_ICON,
- *iconp, *mini_iconp);
-
- return TRUE;
- }
- }
-
- if (icon_cache->origin <= USING_WM_HINTS &&
- icon_cache->wm_hints_dirty)
- {
- icon_cache->wm_hints_dirty = FALSE;
-
- _wnck_error_trap_push (display);
- hints = XGetWMHints (display, xwindow);
- _wnck_error_trap_pop (display);
- pixmap = None;
- mask = None;
- if (hints)
- {
- if (hints->flags & IconPixmapHint)
- pixmap = hints->icon_pixmap;
- if (hints->flags & IconMaskHint)
- mask = hints->icon_mask;
-
- XFree (hints);
- hints = NULL;
- }
-
- /* We won't update if pixmap is unchanged;
- * avoids a get_from_drawable() on every geometry
- * hints change
- */
- if ((pixmap != icon_cache->prev_pixmap ||
- mask != icon_cache->prev_mask) &&
- pixmap != None)
- {
- if (try_pixmap_and_mask (xscreen, pixmap, mask,
- iconp, ideal_size,
- mini_iconp, ideal_mini_size))
- {
- icon_cache->prev_pixmap = pixmap;
- icon_cache->prev_mask = mask;
-
- replace_cache (icon_cache, USING_WM_HINTS,
- *iconp, *mini_iconp);
-
- return TRUE;
- }
- }
- }
-
- if (icon_cache->origin <= USING_KWM_WIN_ICON &&
- icon_cache->kwm_win_icon_dirty)
- {
- icon_cache->kwm_win_icon_dirty = FALSE;
-
- get_kwm_win_icon (xscreen, xwindow, &pixmap, &mask);
-
- if ((pixmap != icon_cache->prev_pixmap ||
- mask != icon_cache->prev_mask) &&
- pixmap != None)
- {
- if (try_pixmap_and_mask (xscreen, pixmap, mask,
- iconp, ideal_size,
- mini_iconp, ideal_mini_size))
- {
- icon_cache->prev_pixmap = pixmap;
- icon_cache->prev_mask = mask;
-
- replace_cache (icon_cache, USING_KWM_WIN_ICON,
- *iconp, *mini_iconp);
-
- return TRUE;
- }
- }
- }
-
- if (icon_cache->want_fallback &&
- icon_cache->origin < USING_FALLBACK_ICON)
- {
- _wnck_get_fallback_icons (iconp,
- ideal_size,
- mini_iconp,
- ideal_mini_size);
-
- replace_cache (icon_cache, USING_FALLBACK_ICON,
- *iconp, *mini_iconp);
-
- return TRUE;
- }
-
- if (!icon_cache->want_fallback &&
- icon_cache->origin == USING_FALLBACK_ICON)
- {
- /* Get rid of current icon */
- clear_icon_cache (icon_cache, FALSE);
-
- return TRUE;
- }
-
- /* found nothing new */
- return FALSE;
-}
-
static GdkPixbuf*
default_icon_at_size (int size)
{