1
0
Fork 0
mutter-performance-source/src/theme.c

331 lines
9.2 KiB
C
Raw Normal View History

/* Metacity Theme Rendering */
2001-05-31 16:18:40 +00:00
/*
* Copyright (C) 2001 Havoc Pennington
*
* 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.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include "theme.h"
2001-06-03 21:39:57 +00:00
#include "util.h"
#include "gradient.h"
#include <string.h>
2001-05-31 16:18:40 +00:00
#if 0
/* fill_gradient routine from GNOME background-properties, CVS says
* Michael Fulbright checked it in, Copyright 1998 Red Hat Inc.
*/
2001-06-03 21:39:57 +00:00
static void
fill_gradient (GdkPixbuf *pixbuf,
const GdkColor *c1,
const GdkColor *c2,
int vertical,
int gradient_width,
int gradient_height,
int pixbuf_x,
int pixbuf_y)
2001-06-03 21:39:57 +00:00
{
int i, j;
int dr, dg, db;
int gs1;
int vc = (!vertical || (c1 == c2));
int w = gdk_pixbuf_get_width (pixbuf);
int h = gdk_pixbuf_get_height (pixbuf);
guchar *b, *row;
guchar *d = gdk_pixbuf_get_pixels (pixbuf);
int rowstride = gdk_pixbuf_get_rowstride (pixbuf);
#define R1 c1->red
#define G1 c1->green
#define B1 c1->blue
#define R2 c2->red
#define G2 c2->green
#define B2 c2->blue
dr = R2 - R1;
dg = G2 - G1;
db = B2 - B1;
gs1 = (vertical) ? gradient_height - 1 : gradient_width - 1;
row = g_new (unsigned char, rowstride);
if (vc)
2001-06-03 21:39:57 +00:00
{
b = row;
for (j = 0; j < w; j++)
{
*b++ = (R1 + ((j + pixbuf_x) * dr) / gs1) >> 8;
*b++ = (G1 + ((j + pixbuf_x) * dg) / gs1) >> 8;
*b++ = (B1 + ((j + pixbuf_x) * db) / gs1) >> 8;
}
2001-06-03 21:39:57 +00:00
}
for (i = 0; i < h; i++)
2001-06-03 21:39:57 +00:00
{
if (!vc)
{
unsigned char cr, cg, cb;
cr = (R1 + ((i + pixbuf_y) * dr) / gs1) >> 8;
cg = (G1 + ((i + pixbuf_y) * dg) / gs1) >> 8;
cb = (B1 + ((i + pixbuf_y) * db) / gs1) >> 8;
b = row;
for (j = 0; j < w; j++)
{
*b++ = cr;
*b++ = cg;
*b++ = cb;
}
}
memcpy (d, row, w * 3);
d += rowstride;
2001-06-03 21:39:57 +00:00
}
#undef R1
#undef G1
#undef B1
#undef R2
#undef G2
#undef B2
g_free (row);
}
#endif
2001-06-03 21:39:57 +00:00
typedef struct _CachedGradient CachedGradient;
2001-06-03 21:39:57 +00:00
struct _CachedGradient
{
MetaGradientType type;
GdkColor color_one;
GdkColor color_two;
int width;
int height;
GdkPixbuf *pixbuf;
int access_serial;
};
2001-06-03 21:39:57 +00:00
static GHashTable *gradient_cache = NULL;
static int access_counter = 0;
static int cache_size = 0;
2001-06-03 21:39:57 +00:00
#define GRADIENT_SIZE(g) ((g)->width * (g)->height * 4)
2001-06-03 21:39:57 +00:00
#define MAX_CACHE_SIZE (1024 * 128) /* 128k */
2001-06-03 21:39:57 +00:00
static guint
cached_gradient_hash (gconstpointer value)
2001-05-31 16:18:40 +00:00
{
/* I have no idea how to write a hash function. */
const CachedGradient *gradient = value;
guint colorone_hash = gdk_color_hash (&gradient->color_one);
guint colortwo_hash = gdk_color_hash (&gradient->color_two);
guint hash = (colorone_hash >> 16) | (colortwo_hash << 16);
2001-06-03 21:39:57 +00:00
hash ^= gradient->width << 22;
hash ^= gradient->height;
hash ^= gradient->type << 15;
2001-06-03 21:39:57 +00:00
return hash;
2001-06-03 18:33:59 +00:00
}
static gboolean
cached_gradient_equal (gconstpointer value_a,
gconstpointer value_b)
2001-06-03 18:33:59 +00:00
{
const CachedGradient *gradient_a = value_a;
const CachedGradient *gradient_b = value_b;
2001-06-01 03:00:01 +00:00
return gradient_a->type == gradient_b->type &&
gradient_a->width == gradient_b->width &&
gradient_a->height == gradient_b->height &&
gdk_color_equal (&gradient_a->color_one, &gradient_b->color_one) &&
gdk_color_equal (&gradient_a->color_two, &gradient_b->color_two);
2001-05-31 16:18:40 +00:00
}
2001-06-03 21:39:57 +00:00
static void
hash_listify (gpointer key, gpointer value, gpointer data)
2001-06-03 21:39:57 +00:00
{
GSList **list = data;
2001-06-03 21:39:57 +00:00
if (key != value)
meta_bug ("Gradient cache got munged (value was overwritten)\n");
2001-06-03 21:39:57 +00:00
*list = g_slist_prepend (*list, value);
}
2001-06-03 21:39:57 +00:00
/* sort gradients so that least-recently-used are first */
static int
gradient_lru_compare (gconstpointer a,
gconstpointer b)
{
const CachedGradient *gradient_a = a;
const CachedGradient *gradient_b = b;
2001-06-03 21:39:57 +00:00
if (gradient_a->access_serial < gradient_b->access_serial)
return -1;
else if (gradient_a->access_serial > gradient_b->access_serial)
return 1;
2001-06-03 21:39:57 +00:00
else
return 0;
2001-06-03 21:39:57 +00:00
}
static void
expire_some_old_gradients (void)
2001-06-03 21:39:57 +00:00
{
GSList *all_gradients;
GSList *tmp;
all_gradients = NULL;
2001-06-03 21:39:57 +00:00
g_hash_table_foreach (gradient_cache, hash_listify, &all_gradients);
2001-06-03 21:39:57 +00:00
all_gradients = g_slist_sort (all_gradients, gradient_lru_compare);
2001-06-03 21:39:57 +00:00
tmp = all_gradients;
while (tmp != NULL)
2001-06-06 04:47:37 +00:00
{
CachedGradient *gradient = tmp->data;
if (cache_size < MAX_CACHE_SIZE)
break;
2001-06-06 04:47:37 +00:00
meta_topic (META_DEBUG_GRADIENT_CACHE,
" Removing gradient of size %d from cache of size %d\n",
GRADIENT_SIZE (gradient), cache_size);
cache_size -= GRADIENT_SIZE (gradient);
2001-06-06 04:47:37 +00:00
g_hash_table_remove (gradient_cache, gradient);
2001-06-06 04:47:37 +00:00
g_object_unref (G_OBJECT (gradient->pixbuf));
g_free (gradient);
tmp = tmp->next;
}
2001-06-06 04:47:37 +00:00
g_slist_free (all_gradients);
2001-06-06 04:47:37 +00:00
meta_topic (META_DEBUG_GRADIENT_CACHE,
"Cache reduced to size %d bytes %d gradients after expiring old gradients\n",
cache_size, g_hash_table_size (gradient_cache));
2001-06-06 04:47:37 +00:00
}
GdkPixbuf*
meta_theme_get_gradient (MetaGradientType type,
const GdkColor *color_one,
const GdkColor *color_two,
int width,
int height)
2001-05-31 16:18:40 +00:00
{
CachedGradient gradient;
CachedGradient *cached;
GdkPixbuf *retval;
2001-06-01 03:00:01 +00:00
meta_topic (META_DEBUG_GRADIENT_CACHE,
"Requesting %s gradient one %d/%d/%d two %d/%d/%d "
"%d x %d\n",
type == META_GRADIENT_VERTICAL ? "vertical" : "horizontal",
color_one->red / 256, color_one->green / 256, color_one->blue / 256,
color_two->red / 256, color_two->green / 256, color_two->blue / 256,
width, height);
2001-06-01 03:00:01 +00:00
if (gradient_cache == NULL)
2001-06-04 04:58:22 +00:00
{
gradient_cache = g_hash_table_new (cached_gradient_hash,
cached_gradient_equal);
2001-06-04 04:58:22 +00:00
}
2001-06-06 04:47:37 +00:00
gradient.type = type;
gradient.color_one = *color_one;
gradient.color_two = *color_two;
gradient.width = width;
gradient.height = height;
gradient.pixbuf = NULL;
gradient.access_serial = access_counter;
2001-06-04 04:58:22 +00:00
cached = g_hash_table_lookup (gradient_cache, &gradient);
2001-06-03 21:39:57 +00:00
if (cached)
2001-06-06 04:47:37 +00:00
{
meta_topic (META_DEBUG_GRADIENT_CACHE,
"Found gradient in cache\n");
++access_counter;
cached->access_serial = access_counter;
g_object_ref (G_OBJECT (cached->pixbuf));
return cached->pixbuf;
2001-06-03 21:39:57 +00:00
}
#if 0
gradient.pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
gradient.width, gradient.height);
2001-06-03 21:39:57 +00:00
fill_gradient (gradient.pixbuf,
&gradient.color_one,
&gradient.color_two,
type == META_GRADIENT_VERTICAL ? TRUE : FALSE,
gradient.width,
gradient.height,
0, 0);
#else
gradient.pixbuf = meta_gradient_create_simple (gradient.width,
gradient.height,
&gradient.color_one,
&gradient.color_two,
type);
if (gradient.pixbuf == NULL)
{
meta_topic (META_DEBUG_GRADIENT_CACHE,
"Not enough memory to create gradient of size %d bytes\n",
GRADIENT_SIZE (&gradient));
return NULL;
}
#endif
2001-06-02 04:14:18 +00:00
if (GRADIENT_SIZE (&gradient) > MAX_CACHE_SIZE)
{
cached = g_new (CachedGradient, 1);
*cached = gradient;
g_hash_table_insert (gradient_cache, cached, cached);
2001-05-31 16:18:40 +00:00
meta_topic (META_DEBUG_GRADIENT_CACHE,
"Caching newly-created gradient, size is %d bytes, total cache size %d bytes %d gradients, maximum %d bytes\n",
GRADIENT_SIZE (cached),
cache_size, g_hash_table_size (gradient_cache), MAX_CACHE_SIZE);
2001-06-03 21:39:57 +00:00
cache_size += GRADIENT_SIZE (cached);
g_object_ref (G_OBJECT (cached->pixbuf)); /* to return to caller */
retval = cached->pixbuf;
2001-06-06 04:47:37 +00:00
if (cache_size > MAX_CACHE_SIZE)
expire_some_old_gradients (); /* may unref "cached->pixbuf" and free "cached" */
}
else
{
meta_topic (META_DEBUG_GRADIENT_CACHE,
"Gradient of size %d bytes is too large to cache\n",
GRADIENT_SIZE (&gradient));
retval = gradient.pixbuf;
}
2001-06-02 04:14:18 +00:00
return retval;
2001-05-31 16:18:40 +00:00
}