diff options
Diffstat (limited to 'render')
| -rw-r--r-- | render/image.c | 314 | ||||
| -rw-r--r-- | render/image.h | 9 | ||||
| -rw-r--r-- | render/imagecache.c | 149 | ||||
| -rw-r--r-- | render/imagecache.h | 37 | ||||
| -rw-r--r-- | render/render.c | 49 | ||||
| -rw-r--r-- | render/render.h | 64 | ||||
| -rw-r--r-- | render/theme.c | 3 | ||||
| -rw-r--r-- | render/theme.h | 4 |
8 files changed, 571 insertions, 58 deletions
diff --git a/render/image.c b/render/image.c index fa630b74..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,53 +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 (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; @@ -160,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) | @@ -177,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 b81e80a6..fd442d26 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; @@ -405,6 +416,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 - l - r, a->texture[i].data.lineart.x2 - l - r)); @@ -457,6 +471,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 - t - b, a->texture[i].data.lineart.y2 - t - b)); diff --git a/render/render.h b/render/render.h index 10eafc6e..e79727df 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 b1b15ff2..cd2352c3 100644 --- a/render/theme.c +++ b/render/theme.c @@ -547,6 +547,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 3f87ce93..1940970a 100644 --- a/render/theme.h +++ b/render/theme.h @@ -107,7 +107,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; |
