summaryrefslogtreecommitdiff
path: root/render
diff options
context:
space:
mode:
Diffstat (limited to 'render')
-rw-r--r--render/image.c317
-rw-r--r--render/image.h9
-rw-r--r--render/imagecache.c149
-rw-r--r--render/imagecache.h37
-rw-r--r--render/render.c49
-rw-r--r--render/render.h64
-rw-r--r--render/theme.c3
-rw-r--r--render/theme.h4
8 files changed, 571 insertions, 61 deletions
diff --git a/render/image.c b/render/image.c
index 2eb043a2..d22ef9e3 100644
--- a/render/image.c
+++ b/render/image.c
@@ -20,6 +20,7 @@
#include "geom.h"
#include "image.h"
#include "color.h"
+#include "imagecache.h"
#include <glib.h>
@@ -27,13 +28,91 @@
#define FLOOR(i) ((i) & (~0UL << FRACTION))
#define AVERAGE(a, b) (((((a) ^ (b)) & 0xfefefefeL) >> 1) + ((a) & (b)))
-static void ImageCopyResampled(RrPixel32 *dst, RrPixel32 *src,
- gulong dstW, gulong dstH,
- gulong srcW, gulong srcH)
+static void AddPicture(RrImage *self, RrImagePic ***list, gint *len,
+ RrImagePic *pic)
{
+ gint i;
+
+ g_assert(pic->width > 0 && pic->height > 0);
+
+ g_assert(g_hash_table_lookup(self->cache->table, pic) == NULL);
+
+ /* grow the list */
+ *list = g_renew(RrImagePic*, *list, ++*len);
+
+ /* move everything else down one */
+ for (i = *len-1; i > 0; --i)
+ (*list)[i] = (*list)[i-1];
+
+ /* set the new picture up at the front of the list */
+ (*list)[0] = pic;
+
+ /* add the picture as a key to point to this image in the cache */
+ g_hash_table_insert(self->cache->table, (*list)[0], self);
+
+#ifdef DEBUG
+ g_print("Adding %s picture to the cache: "
+ "Image 0x%x, w %d h %d Hash %u\n",
+ (*list == self->original ? "ORIGINAL" : "RESIZED"),
+ (guint)self, pic->width, pic->height, RrImagePicHash(pic));
+#endif
+}
+
+static void RemovePicture(RrImage *self, RrImagePic ***list,
+ gint i, gint *len)
+{
+ gint j;
+
+#ifdef DEBUG
+ g_print("Removing %s picture from the cache: "
+ "Image 0x%x, w %d h %d Hash %u\n",
+ (*list == self->original ? "ORIGINAL" : "RESIZED"),
+ (guint)self, (*list)[i]->width, (*list)[i]->height,
+ RrImagePicHash((*list)[i]));
+#endif
+
+ /* remove the picture as a key in the cache */
+ g_hash_table_remove(self->cache->table, (*list)[i]);
+
+ /* free the picture (and its rgba data) */
+ g_free((*list)[i]);
+ g_free((*list)[i]->data);
+ /* shift everything down one */
+ for (j = i; j < *len-1; ++j)
+ (*list)[j] = (*list)[j+1];
+ /* shrink the list */
+ *list = g_renew(RrImagePic*, *list, --*len);
+}
+
+static RrImagePic* ResizeImage(RrPixel32 *src,
+ gulong srcW, gulong srcH,
+ gulong dstW, gulong dstH)
+{
+ RrPixel32 *dst;
+ RrImagePic *pic;
gulong dstX, dstY, srcX, srcY;
gulong srcX1, srcX2, srcY1, srcY2;
gulong ratioX, ratioY;
+ gulong aspectW, aspectH;
+
+ /* keep the aspect ratio */
+ aspectW = dstW;
+ aspectH = (gint)(dstW * ((gdouble)srcH / srcW));
+ if (aspectH > dstH) {
+ aspectH = dstH;
+ aspectW = (gint)(dstH * ((gdouble)srcW / srcH));
+ }
+ dstW = aspectW;
+ dstH = aspectH;
+
+ if (srcW == dstW && srcH == dstH)
+ return NULL; /* no scaling needed ! */
+
+ pic = g_new(RrImagePic, 1);
+ dst = g_new(RrPixel32, dstW * dstH);
+ pic->width = dstW;
+ pic->height = dstH;
+ pic->data = dst;
ratioX = (srcW << FRACTION) / dstW;
ratioY = (srcH << FRACTION) / dstH;
@@ -104,56 +183,42 @@ static void ImageCopyResampled(RrPixel32 *dst, RrPixel32 *src,
(alpha << RrDefaultAlphaOffset);
}
}
+
+ return pic;
}
-void RrImageDraw(RrPixel32 *target, RrTextureRGBA *rgba,
- gint target_w, gint target_h,
- RrRect *area)
+/*! This drawns an RGBA picture into the target, within the rectangle specified
+ by the area parameter. If the area's size differs from the source's then it
+ will be centered within the rectangle */
+void DrawRGBA(RrPixel32 *target, gint target_w, gint target_h,
+ RrPixel32 *source, gint source_w, gint source_h,
+ gint alpha, RrRect *area)
{
RrPixel32 *dest;
- RrPixel32 *source;
- gint sw, sh, dw, dh;
gint col, num_pixels;
+ gint dw, dh;
- sw = rgba->width;
- sh = rgba->height;
+ g_assert(source_w <= area->width && source_h <= area->height);
- /* keep the ratio */
+ /* keep the aspect ratio */
dw = area->width;
- dh = (gint)(dw * ((gdouble)sh / sw));
+ dh = (gint)(dw * ((gdouble)source_h / source_w));
if (dh > area->height) {
dh = area->height;
- dw = (gint)(dh * ((gdouble)sw / sh));
- }
-
- if (!(dw && dh))
- return; /* XXX sanity check */
-
- if (sw != dw || sh != dh) {
- /*if (!(rgba->cache && dw == rgba->cwidth && dh == rgba->cheight))*/ {
- g_free(rgba->cache);
- rgba->cache = g_new(RrPixel32, dw * dh);
- ImageCopyResampled(rgba->cache, rgba->data, dw, dh, sw, sh);
- rgba->cwidth = dw;
- rgba->cheight = dh;
- }
- source = rgba->cache;
- } else {
- source = rgba->data;
+ dw = (gint)(dh * ((gdouble)source_w / source_h));
}
/* copy source -> dest, and apply the alpha channel.
-
center the image if it is smaller than the area */
col = 0;
num_pixels = dw * dh;
dest = target + area->x + (area->width - dw) / 2 +
(target_w * (area->y + (area->height - dh) / 2));
while (num_pixels-- > 0) {
- guchar alpha, r, g, b, bgr, bgg, bgb;
+ guchar a, r, g, b, bgr, bgg, bgb;
/* apply the rgba's opacity as well */
- alpha = ((*source >> RrDefaultAlphaOffset) * rgba->alpha) >> 8;
+ a = ((*source >> RrDefaultAlphaOffset) * alpha) >> 8;
r = *source >> RrDefaultRedOffset;
g = *source >> RrDefaultGreenOffset;
b = *source >> RrDefaultBlueOffset;
@@ -163,9 +228,9 @@ void RrImageDraw(RrPixel32 *target, RrTextureRGBA *rgba,
bgg = *dest >> RrDefaultGreenOffset;
bgb = *dest >> RrDefaultBlueOffset;
- r = bgr + (((r - bgr) * alpha) >> 8);
- g = bgg + (((g - bgg) * alpha) >> 8);
- b = bgb + (((b - bgb) * alpha) >> 8);
+ r = bgr + (((r - bgr) * a) >> 8);
+ g = bgg + (((g - bgg) * a) >> 8);
+ b = bgb + (((b - bgb) * a) >> 8);
*dest = ((r << RrDefaultRedOffset) |
(g << RrDefaultGreenOffset) |
@@ -180,3 +245,185 @@ void RrImageDraw(RrPixel32 *target, RrTextureRGBA *rgba,
}
}
}
+
+void RrImageDrawRGBA(RrPixel32 *target, RrTextureRGBA *rgba,
+ gint target_w, gint target_h,
+ RrRect *area)
+{
+ RrImagePic *scaled;
+
+ scaled = ResizeImage(rgba->data, rgba->width, rgba->height,
+ area->width, area->height);
+
+ if (scaled) {
+#ifdef DEBUG
+ g_warning("Scaling an RGBA! You should avoid this and just make "
+ "it the right size yourself!");
+#endif
+ DrawRGBA(target, target_w, target_h,
+ scaled->data, scaled->width, scaled->height,
+ rgba->alpha, area);
+ }
+ else
+ DrawRGBA(target, target_w, target_h,
+ rgba->data, rgba->width, rgba->height,
+ rgba->alpha, area);
+}
+
+RrImage* RrImageNew(RrImageCache *cache)
+{
+ RrImage *self;
+
+ self = g_new0(RrImage, 1);
+ self->ref = 1;
+ self->cache = cache;
+ return self;
+}
+
+void RrImageRef(RrImage *self)
+{
+ ++self->ref;
+}
+
+void RrImageUnref(RrImage *self)
+{
+ if (self && --self->ref == 0) {
+#ifdef DEBUG
+ g_print("Refcount to 0, removing ALL pictures from the cache: "
+ "Image 0x%x\n", (guint)self);
+#endif
+ while (self->n_original > 0)
+ RemovePicture(self, &self->original, 0, &self->n_original);
+ while (self->n_resized > 0)
+ RemovePicture(self, &self->resized, 0, &self->n_resized);
+ g_free(self);
+ }
+}
+
+void RrImageAddPicture(RrImage *self, RrPixel32 *data, gint w, gint h)
+{
+ gint i;
+ RrImagePic *pic;
+
+ /* make sure we don't already have this size.. */
+ for (i = 0; i < self->n_original; ++i)
+ if (self->original[i]->width == w && self->original[i]->height == h) {
+#ifdef DEBUG
+ g_print("Found duplicate ORIGINAL image: "
+ "Image 0x%x, w %d h %d\n", (guint)self, w, h);
+#endif
+ return;
+ }
+
+ /* remove any resized pictures of this same size */
+ for (i = 0; i < self->n_resized; ++i)
+ if (self->resized[i]->width == w || self->resized[i]->height == h) {
+ RemovePicture(self, &self->resized, i, &self->n_resized);
+ break;
+ }
+
+ /* add the new picture */
+ pic = g_new(RrImagePic, 1);
+ pic->width = w;
+ pic->height = h;
+ pic->data = g_memdup(data, w*h*sizeof(RrPixel32));
+ AddPicture(self, &self->original, &self->n_original, pic);
+}
+
+void RrImageRemovePicture(RrImage *self, gint w, gint h)
+{
+ gint i;
+
+ /* remove any resized pictures of this same size */
+ for (i = 0; i < self->n_original; ++i)
+ if (self->original[i]->width == w && self->original[i]->height == h) {
+ RemovePicture(self, &self->original, i, &self->n_original);
+ break;
+ }
+}
+
+void RrImageDrawImage(RrPixel32 *target, RrTextureImage *img,
+ gint target_w, gint target_h,
+ RrRect *area)
+{
+ gint i, min_diff, min_i;
+ RrImage *self;
+ RrImagePic *pic;
+
+ self = img->image;
+ pic = NULL;
+
+ /* is there an original of this size? (only w or h has to be right cuz
+ we maintain aspect ratios) */
+ for (i = 0; i < self->n_original; ++i)
+ if (self->original[i]->width == area->width ||
+ self->original[i]->height == area->height)
+ {
+ pic = self->original[i];
+ break;
+ }
+
+ /* is there a resize of this size? */
+ for (i = 0; i < self->n_resized; ++i)
+ if (self->resized[i]->width == area->width ||
+ self->resized[i]->height == area->height)
+ {
+ gint j;
+ RrImagePic *saved;
+
+ /* save the selected one */
+ saved = self->resized[i];
+
+ /* shift all the others down */
+ for (j = i; j > 0; --j)
+ self->resized[j] = self->resized[j-1];
+
+ /* and move the selected one to the top of the list */
+ self->resized[0] = saved;
+
+ pic = self->resized[0];
+ break;
+ }
+
+ if (!pic) {
+ /* find an original with a close size */
+ min_diff = -1;
+ min_i = 0;
+ for (i = 0; i < self->n_original; ++i) {
+ gint diff;
+ gint wdiff, hdiff;
+
+ /* our size difference metric.. */
+ wdiff = self->original[i]->width - area->width;
+ hdiff = self->original[i]->height - area->height;
+ diff = (wdiff * wdiff) + (hdiff * hdiff);
+
+ if (min_diff < 0 || diff < min_diff) {
+ min_diff = diff;
+ min_i = i;
+ }
+ }
+
+ /* resize the original to the given area */
+ pic = ResizeImage(self->original[min_i]->data,
+ self->original[min_i]->width,
+ self->original[min_i]->height,
+ area->width, area->height);
+
+ /* add the resized image to the image, as the first in the resized
+ list */
+ if (self->n_resized >= MAX_CACHE_RESIZED) {
+ /* remove the last one (last used one) */
+ RemovePicture(self, &self->resized, self->n_resized - 1,
+ &self->n_resized);
+ }
+ /* add it to the top of the resized list */
+ AddPicture(self, &self->resized, &self->n_resized, pic);
+ }
+
+ g_assert(pic != NULL);
+
+ DrawRGBA(target, target_w, target_h,
+ pic->data, pic->width, pic->height,
+ img->alpha, area);
+}
diff --git a/render/image.h b/render/image.h
index 1c535960..28f29c2c 100644
--- a/render/image.h
+++ b/render/image.h
@@ -22,8 +22,11 @@
#include "render.h"
#include "geom.h"
-void RrImageDraw(RrPixel32 *target, RrTextureRGBA *rgba,
- gint target_w, gint target_h,
- RrRect *area);
+void RrImageDrawImage(RrPixel32 *target, RrTextureImage *img,
+ gint target_w, gint target_h,
+ RrRect *area);
+void RrImageDrawRGBA(RrPixel32 *target, RrTextureRGBA *rgba,
+ gint target_w, gint target_h,
+ RrRect *area);
#endif
diff --git a/render/imagecache.c b/render/imagecache.c
new file mode 100644
index 00000000..ec2ff4d0
--- /dev/null
+++ b/render/imagecache.c
@@ -0,0 +1,149 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ imagecache.c for the Openbox window manager
+ Copyright (c) 2008 Dana Jansens
+
+ 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#include "render.h"
+#include "imagecache.h"
+
+static gboolean RrImagePicEqual(const RrImagePic *p1,
+ const RrImagePic *p2);
+
+RrImageCache* RrImageCacheNew()
+{
+ RrImageCache *self;
+
+ self = g_new(RrImageCache, 1);
+ self->ref = 1;
+ self->table = g_hash_table_new((GHashFunc)RrImagePicHash,
+ (GEqualFunc)RrImagePicEqual);
+ return self;
+}
+
+void RrImageCacheRef(RrImageCache *self)
+{
+ ++self->ref;
+}
+
+void RrImageCacheUnref(RrImageCache *self)
+{
+ if (self && --self->ref == 0) {
+ g_assert(g_hash_table_size(self->table) == 0);
+ g_hash_table_unref(self->table);
+
+ g_free(self);
+ }
+}
+
+/*! Finds an image in the cache, if it is already in there */
+RrImage* RrImageCacheFind(RrImageCache *self,
+ RrPixel32 *data, gint w, gint h)
+{
+ RrImagePic pic;
+ pic.width = w;
+ pic.height = h;
+ pic.data = data;
+ return g_hash_table_lookup(self->table, &pic);
+}
+
+/* This is a fast, reversable hash function called "lookup3", found here:
+ http://burtleburtle.net/bob/c/lookup3.c
+*/
+#define hashsize(n) ((RrPixel32)1<<(n))
+#define hashmask(n) (hashsize(n)-1)
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+/* mix -- mix 3 32-bit values reversibly. */
+#define mix(a,b,c) \
+{ \
+ a -= c; a ^= rot(c, 4); c += b; \
+ b -= a; b ^= rot(a, 6); a += c; \
+ c -= b; c ^= rot(b, 8); b += a; \
+ a -= c; a ^= rot(c,16); c += b; \
+ b -= a; b ^= rot(a,19); a += c; \
+ c -= b; c ^= rot(b, 4); b += a; \
+}
+/* final -- final mixing of 3 32-bit values (a,b,c) into c */
+#define final(a,b,c) \
+{ \
+ c ^= b; c -= rot(b,14); \
+ a ^= c; a -= rot(c,11); \
+ b ^= a; b -= rot(a,25); \
+ c ^= b; c -= rot(b,16); \
+ a ^= c; a -= rot(c,4); \
+ b ^= a; b -= rot(a,14); \
+ c ^= b; c -= rot(b,24); \
+}
+
+guint32 hashword(const guint32 *key, gint length, guint32 initval)
+{
+ guint32 a,b,c;
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + (((guint32)length)<<2) + initval;
+
+ /* handle most of the key */
+ while (length > 3)
+ {
+ a += key[0];
+ b += key[1];
+ c += key[2];
+ mix(a,b,c);
+ length -= 3;
+ key += 3;
+ }
+
+ /* handle the last 3 guint32's */
+ switch(length) /* all the case statements fall through */
+ {
+ case 3: c+=key[2];
+ case 2: b+=key[1];
+ case 1: a+=key[0];
+ final(a,b,c);
+ case 0: /* case 0: nothing left to add */
+ break;
+ }
+ /* report the result */
+ return c;
+}
+
+#define HASH_INITVAL 0xf00d
+
+guint RrImagePicHash(const RrImagePic *p)
+{
+ return hashword(p->data, p->width * p->height, HASH_INITVAL);
+}
+
+static gboolean RrImagePicEqual(const RrImagePic *p1,
+ const RrImagePic *p2)
+{
+ guint s1, s2;
+ RrPixel32 *data1, *data2;
+ gint i;
+
+ if (p1->width != p2->width || p1->height != p2->height) return FALSE;
+
+ /* strcmp() would probably suck on 4k of data.. sum all their values and
+ see if they get the same thing. they already matched on their hashes
+ at this point. */
+ s1 = s2 = 0;
+ data1 = p1->data;
+ data2 = p2->data;
+ for (i = 0; i < p1->width * p1->height; ++i, ++data1)
+ s1 += *data1;
+ for (i = 0; i < p2->width * p2->height; ++i, ++data2)
+ s2 += *data2;
+ return s1 == s2;
+}
diff --git a/render/imagecache.h b/render/imagecache.h
new file mode 100644
index 00000000..8c96caf0
--- /dev/null
+++ b/render/imagecache.h
@@ -0,0 +1,37 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ imagecache.h for the Openbox window manager
+ Copyright (c) 2008 Dana Jansens
+
+ 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#ifndef __imagecache_h
+#define __imagecache_h
+
+#include <glib.h>
+
+/* the number of resized pictures to cache for an image */
+#define MAX_CACHE_RESIZED 3
+
+struct _RrImagePic;
+
+guint RrImagePicHash(const struct _RrImagePic *p);
+
+struct _RrImageCache {
+ gint ref;
+
+ GHashTable *table;
+};
+
+#endif
diff --git a/render/render.c b/render/render.c
index 49485c8a..304148de 100644
--- a/render/render.c
+++ b/render/render.c
@@ -130,6 +130,24 @@ Pixmap RrPaintPixmap(RrAppearance *a, gint w, gint h)
}
RrPixmapMaskDraw(a->pixmap, &a->texture[i].data.mask, &tarea);
break;
+ case RR_TEXTURE_IMAGE:
+ g_assert(!transferred);
+ {
+ RrRect narea = tarea;
+ RrTextureImage *img = &a->texture[i].data.image;
+ if (img->twidth)
+ narea.width = MIN(tarea.width, img->twidth);
+ if (img->theight)
+ narea.height = MIN(tarea.height, img->theight);
+ narea.x += img->tx;
+ narea.y += img->ty;
+ RrImageDrawImage(a->surface.pixel_data,
+ &a->texture[i].data.image,
+ a->w, a->h,
+ &narea);
+ }
+ force_transfer = 1;
+ break;
case RR_TEXTURE_RGBA:
g_assert(!transferred);
{
@@ -141,10 +159,10 @@ Pixmap RrPaintPixmap(RrAppearance *a, gint w, gint h)
narea.height = MIN(tarea.height, rgb->theight);
narea.x += rgb->tx;
narea.y += rgb->ty;
- RrImageDraw(a->surface.pixel_data,
- &a->texture[i].data.rgba,
- a->w, a->h,
- &narea);
+ RrImageDrawRGBA(a->surface.pixel_data,
+ &a->texture[i].data.rgba,
+ a->w, a->h,
+ &narea);
}
force_transfer = 1;
break;
@@ -202,11 +220,15 @@ void RrAppearanceAddTextures(RrAppearance *a, gint numtex)
if (numtex) a->texture = g_new0(RrTexture, numtex);
}
+void RrAppearanceClearTextures(RrAppearance *a)
+{
+ memset(a->texture, 0, a->textures * sizeof(RrTexture));
+}
+
RrAppearance *RrAppearanceCopy(RrAppearance *orig)
{
RrSurface *spo, *spc;
RrAppearance *copy = g_new(RrAppearance, 1);
- gint i;
copy->inst = orig->inst;
@@ -282,10 +304,6 @@ RrAppearance *RrAppearanceCopy(RrAppearance *orig)
copy->textures = orig->textures;
copy->texture = g_memdup(orig->texture,
orig->textures * sizeof(RrTexture));
- for (i = 0; i < copy->textures; ++i)
- if (copy->texture[i].type == RR_TEXTURE_RGBA) {
- copy->texture[i].data.rgba.cache = NULL;
- }
copy->pixmap = None;
copy->xftdraw = NULL;
copy->w = copy->h = 0;
@@ -294,17 +312,10 @@ RrAppearance *RrAppearanceCopy(RrAppearance *orig)
void RrAppearanceFree(RrAppearance *a)
{
- gint i;
-
if (a) {
RrSurface *p;
if (a->pixmap != None) XFreePixmap(RrDisplay(a->inst), a->pixmap);
if (a->xftdraw != NULL) XftDrawDestroy(a->xftdraw);
- for (i = 0; i < a->textures; ++i)
- if (a->texture[i].type == RR_TEXTURE_RGBA) {
- g_free(a->texture[i].data.rgba.cache);
- a->texture[i].data.rgba.cache = NULL;
- }
if (a->textures)
g_free(a->texture);
p = &a->surface;
@@ -403,6 +414,9 @@ gint RrMinWidth(RrAppearance *a)
case RR_TEXTURE_RGBA:
w += MAX(w, a->texture[i].data.rgba.width);
break;
+ case RR_TEXTURE_IMAGE:
+ /* images resize so they don't contribute anything to the min */
+ break;
case RR_TEXTURE_LINE_ART:
w += MAX(w, MAX(a->texture[i].data.lineart.x1,
a->texture[i].data.lineart.x2));
@@ -455,6 +469,9 @@ gint RrMinHeight(RrAppearance *a)
case RR_TEXTURE_RGBA:
h += MAX(h, a->texture[i].data.rgba.height);
break;
+ case RR_TEXTURE_IMAGE:
+ /* images resize so they don't contribute anything to the min */
+ break;
case RR_TEXTURE_LINE_ART:
h += MAX(h, MAX(a->texture[i].data.lineart.y1,
a->texture[i].data.lineart.y2));
diff --git a/render/render.h b/render/render.h
index 260ebeb0..5d1d1552 100644
--- a/render/render.h
+++ b/render/render.h
@@ -37,11 +37,15 @@ typedef struct _RrFont RrFont;
typedef struct _RrTexture RrTexture;
typedef struct _RrTextureMask RrTextureMask;
typedef struct _RrTextureRGBA RrTextureRGBA;
+typedef struct _RrTextureImage RrTextureImage;
typedef struct _RrTextureText RrTextureText;
typedef struct _RrTextureLineArt RrTextureLineArt;
typedef struct _RrPixmapMask RrPixmapMask;
typedef struct _RrInstance RrInstance;
typedef struct _RrColor RrColor;
+typedef struct _RrImage RrImage;
+typedef struct _RrImagePic RrImagePic;
+typedef struct _RrImageCache RrImageCache;
typedef guint32 RrPixel32;
typedef guint16 RrPixel16;
@@ -76,7 +80,8 @@ typedef enum {
RR_TEXTURE_MASK,
RR_TEXTURE_TEXT,
RR_TEXTURE_LINE_ART,
- RR_TEXTURE_RGBA
+ RR_TEXTURE_RGBA,
+ RR_TEXTURE_IMAGE
} RrTextureType;
typedef enum {
@@ -163,11 +168,19 @@ struct _RrTextureRGBA {
gint height;
gint alpha;
RrPixel32 *data;
-/* cached scaled so we don't have to scale often */
- gint cwidth;
- gint cheight;
- RrPixel32 *cache;
-/* size and position to draw at */
+ /* size and position to draw at (if these are zero, then it will be
+ drawn to fill the entire texture */
+ gint tx;
+ gint ty;
+ gint twidth;
+ gint theight;
+};
+
+struct _RrTextureImage {
+ RrImage *image;
+ gint alpha;
+ /* size and position to draw at (if these are zero, then it will be
+ drawn to fill the entire texture */
gint tx;
gint ty;
gint twidth;
@@ -184,12 +197,15 @@ struct _RrTextureLineArt {
union _RrTextureData {
RrTextureRGBA rgba;
+ RrTextureImage image;
RrTextureText text;
RrTextureMask mask;
RrTextureLineArt lineart;
};
struct _RrTexture {
+ /* If changing the type of a texture, you should DEFINITELY call
+ RrAppearanceClearTextures() first! */
RrTextureType type;
RrTextureData data;
};
@@ -207,6 +223,25 @@ struct _RrAppearance {
gint w, h;
};
+/*! Holds a RGBA image picture */
+struct _RrImagePic {
+ gint width, height;
+ RrPixel32 *data;
+};
+
+/*! An RrImage is a sort of meta-image. It can contain multiple versions of
+ an image at different sizes, which may or may not be completely different
+ pictures */
+struct _RrImage {
+ gint ref;
+ struct _RrImageCache *cache;
+
+ struct _RrImagePic **original;
+ gint n_original;
+ struct _RrImagePic **resized;
+ gint n_resized;
+};
+
/* these are the same on all endian machines because it seems to be dependant
on the endianness of the gfx card, not the cpu. */
#define RrDefaultAlphaOffset 24
@@ -253,6 +288,8 @@ RrAppearance *RrAppearanceCopy (RrAppearance *a);
void RrAppearanceFree (RrAppearance *a);
void RrAppearanceRemoveTextures(RrAppearance *a);
void RrAppearanceAddTextures(RrAppearance *a, gint numtex);
+/*! Always call this when changing the type of a texture in an appearance */
+void RrAppearanceClearTextures(RrAppearance *a);
RrFont *RrFontOpen (const RrInstance *inst, const gchar *name,
gint size, RrFontWeight weight, RrFontSlant slant);
@@ -280,6 +317,21 @@ gboolean RrPixmapToRGBA(const RrInstance *inst,
Pixmap pmap, Pixmap mask,
gint *w, gint *h, RrPixel32 **data);
+RrImageCache* RrImageCacheNew();
+void RrImageCacheRef(RrImageCache *self);
+void RrImageCacheUnref(RrImageCache *self);
+
+/*! Finds an image in the cache, if it is already in there */
+RrImage* RrImageCacheFind(RrImageCache *self,
+ RrPixel32 *data, gint w, gint h);
+
+RrImage* RrImageNew(RrImageCache *cache);
+void RrImageRef(RrImage *im);
+void RrImageUnref(RrImage *im);
+
+void RrImageAddPicture(RrImage *im, RrPixel32 *data, gint w, gint h);
+void RrImageRemovePicture(RrImage *im, gint w, gint h);
+
G_END_DECLS
#endif /*__render_h*/
diff --git a/render/theme.c b/render/theme.c
index a6931be6..e1cff0cd 100644
--- a/render/theme.c
+++ b/render/theme.c
@@ -552,6 +552,9 @@ RrTheme* RrThemeNew(const RrInstance *inst, const gchar *name,
theme->def_win_icon = read_c_image(OB_DEFAULT_ICON_WIDTH,
OB_DEFAULT_ICON_HEIGHT,
OB_DEFAULT_ICON_pixel_data);
+ theme->def_win_icon_w = OB_DEFAULT_ICON_WIDTH;
+ theme->def_win_icon_h = OB_DEFAULT_ICON_HEIGHT;
+
/* read the decoration textures */
if (!read_appearance(db, inst,
diff --git a/render/theme.h b/render/theme.h
index 9f51fabd..5b4e785e 100644
--- a/render/theme.h
+++ b/render/theme.h
@@ -106,7 +106,9 @@ struct _RrTheme {
gchar menu_text_disabled_selected_shadow_alpha;
/* style settings - pics */
- RrPixel32 *def_win_icon; /* 48x48 RGBA */
+ RrPixel32 *def_win_icon; /* RGBA */
+ gint def_win_icon_w;
+ gint def_win_icon_h;
/* style settings - masks */
RrPixmapMask *max_mask;