* Carsten Haitzler <raster@rasterman.com>
*/
+#include <string.h>
+
#include "pixbuf.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
-GCache *pixbuf_cache = NULL;
+static GCache *pixbuf_cache = NULL;
+
+static GdkPixbuf *
+bilinear_gradient (GdkPixbuf *src,
+ gint src_x,
+ gint src_y,
+ gint width,
+ gint height)
+{
+ guint n_channels = gdk_pixbuf_get_n_channels (src);
+ guint src_rowstride = gdk_pixbuf_get_rowstride (src);
+ guchar *src_pixels = gdk_pixbuf_get_pixels (src);
+ guchar *p1, *p2, *p3, *p4;
+ guint dest_rowstride;
+ guchar *dest_pixels;
+ GdkPixbuf *result;
+ int i, j, k;
+
+ if (src_x == 0 || src_y == 0)
+ {
+ g_warning ("invalid source position for bilinear gradient");
+ return NULL;
+ }
+
+ p1 = src_pixels + (src_y - 1) * src_rowstride + (src_x - 1) * n_channels;
+ p2 = p1 + n_channels;
+ p3 = src_pixels + src_y * src_rowstride + (src_x - 1) * n_channels;
+ p4 = p3 + n_channels;
+
+ result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
+ width, height);
+
+ if (result == NULL)
+ {
+ g_warning ("failed to create a %dx%d pixbuf", width, height);
+ return NULL;
+ }
+
+ dest_rowstride = gdk_pixbuf_get_rowstride (result);
+ dest_pixels = gdk_pixbuf_get_pixels (result);
+
+ for (i = 0; i < height; i++)
+ {
+ guchar *p = dest_pixels + dest_rowstride *i;
+ guint v[4];
+ gint dv[4];
+
+ for (k = 0; k < n_channels; k++)
+ {
+ guint start = ((height - i) * p1[k] + (1 + i) * p3[k]) / (height + 1);
+ guint end = ((height - i) * p2[k] + (1 + i) * p4[k]) / (height + 1);
+
+ dv[k] = (((gint)end - (gint)start) << 16) / (width + 1);
+ v[k] = (start << 16) + dv[k] + 0x8000;
+ }
+
+ for (j = width; j; j--)
+ {
+ for (k = 0; k < n_channels; k++)
+ {
+ *(p++) = v[k] >> 16;
+ v[k] += dv[k];
+ }
+ }
+ }
+
+ return result;
+}
+
+static GdkPixbuf *
+horizontal_gradient (GdkPixbuf *src,
+ gint src_x,
+ gint src_y,
+ gint width,
+ gint height)
+{
+ guint n_channels = gdk_pixbuf_get_n_channels (src);
+ guint src_rowstride = gdk_pixbuf_get_rowstride (src);
+ guchar *src_pixels = gdk_pixbuf_get_pixels (src);
+ guint dest_rowstride;
+ guchar *dest_pixels;
+ GdkPixbuf *result;
+ int i, j, k;
+
+ if (src_x == 0)
+ {
+ g_warning ("invalid source position for horizontal gradient");
+ return NULL;
+ }
+
+ result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
+ width, height);
+
+ if (result == NULL)
+ {
+ g_warning ("failed to create a %dx%d pixbuf", width, height);
+ return NULL;
+ }
+
+ dest_rowstride = gdk_pixbuf_get_rowstride (result);
+ dest_pixels = gdk_pixbuf_get_pixels (result);
+
+ for (i = 0; i < height; i++)
+ {
+ guchar *p = dest_pixels + dest_rowstride *i;
+ guchar *p1 = src_pixels + (src_y + i) * src_rowstride + (src_x - 1) * n_channels;
+ guchar *p2 = p1 + n_channels;
+
+ guint v[4];
+ gint dv[4];
+
+ for (k = 0; k < n_channels; k++)
+ {
+ dv[k] = (((gint)p2[k] - (gint)p1[k]) << 16) / (width + 1);
+ v[k] = (p1[k] << 16) + dv[k] + 0x8000;
+ }
+
+ for (j = width; j; j--)
+ {
+ for (k = 0; k < n_channels; k++)
+ {
+ *(p++) = v[k] >> 16;
+ v[k] += dv[k];
+ }
+ }
+ }
+
+ return result;
+}
+
+static GdkPixbuf *
+vertical_gradient (GdkPixbuf *src,
+ gint src_x,
+ gint src_y,
+ gint width,
+ gint height)
+{
+ guint n_channels = gdk_pixbuf_get_n_channels (src);
+ guint src_rowstride = gdk_pixbuf_get_rowstride (src);
+ guchar *src_pixels = gdk_pixbuf_get_pixels (src);
+ guchar *top_pixels, *bottom_pixels;
+ guint dest_rowstride;
+ guchar *dest_pixels;
+ GdkPixbuf *result;
+ int i, j;
+
+ if (src_y == 0)
+ {
+ g_warning ("invalid source position for vertical gradient");
+ return NULL;
+ }
+
+ top_pixels = src_pixels + (src_y - 1) * src_rowstride + (src_x) * n_channels;
+ bottom_pixels = top_pixels + src_rowstride;
+
+ result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
+ width, height);
+
+ if (result == NULL)
+ {
+ g_warning ("failed to create a %dx%d pixbuf", width, height);
+ return NULL;
+ }
+
+ dest_rowstride = gdk_pixbuf_get_rowstride (result);
+ dest_pixels = gdk_pixbuf_get_pixels (result);
+
+ for (i = 0; i < height; i++)
+ {
+ guchar *p = dest_pixels + dest_rowstride *i;
+ guchar *p1 = top_pixels;
+ guchar *p2 = bottom_pixels;
+
+ for (j = width * n_channels; j; j--)
+ *(p++) = ((height - i) * *(p1++) + (1 + i) * *(p2++)) / (height + 1);
+ }
+
+ return result;
+}
+
+static GdkPixbuf *
+replicate_single (GdkPixbuf *src,
+ gint src_x,
+ gint src_y,
+ gint width,
+ gint height)
+{
+ guint n_channels = gdk_pixbuf_get_n_channels (src);
+ guchar *pixels = (gdk_pixbuf_get_pixels (src) +
+ src_y * gdk_pixbuf_get_rowstride (src) +
+ src_x * n_channels);
+ guchar r = *(pixels++);
+ guchar g = *(pixels++);
+ guchar b = *(pixels++);
+ guint dest_rowstride;
+ guchar *dest_pixels;
+ guchar a = 0;
+ GdkPixbuf *result;
+ int i, j;
+
+ if (n_channels == 4)
+ a = *(pixels++);
+
+ result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
+ width, height);
+
+ if (result == NULL)
+ {
+ g_warning ("failed to create a %dx%d pixbuf", width, height);
+ return NULL;
+ }
+ dest_rowstride = gdk_pixbuf_get_rowstride (result);
+ dest_pixels = gdk_pixbuf_get_pixels (result);
+
+ for (i = 0; i < height; i++)
+ {
+ guchar *p = dest_pixels + dest_rowstride *i;
+
+ for (j = 0; j < width; j++)
+ {
+ *(p++) = r;
+ *(p++) = g;
+ *(p++) = b;
+
+ if (n_channels == 4)
+ *(p++) = a;
+ }
+ }
+
+ return result;
+}
+
+static GdkPixbuf *
+replicate_rows (GdkPixbuf *src,
+ gint src_x,
+ gint src_y,
+ gint width,
+ gint height)
+{
+ guint n_channels = gdk_pixbuf_get_n_channels (src);
+ guint src_rowstride = gdk_pixbuf_get_rowstride (src);
+ guchar *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x * n_channels);
+ guchar *dest_pixels;
+ GdkPixbuf *result;
+ guint dest_rowstride;
+ int i;
+
+ result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
+ width, height);
+
+ if (result == NULL)
+ {
+ g_warning ("failed to create a %dx%d pixbuf", width, height);
+ return NULL;
+ }
+
+ dest_rowstride = gdk_pixbuf_get_rowstride (result);
+ dest_pixels = gdk_pixbuf_get_pixels (result);
+
+ for (i = 0; i < height; i++)
+ memcpy (dest_pixels + dest_rowstride * i, pixels, n_channels * width);
+
+ return result;
+}
+
+static GdkPixbuf *
+replicate_cols (GdkPixbuf *src,
+ gint src_x,
+ gint src_y,
+ gint width,
+ gint height)
+{
+ guint n_channels = gdk_pixbuf_get_n_channels (src);
+ guint src_rowstride = gdk_pixbuf_get_rowstride (src);
+ guchar *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x * n_channels);
+ guchar *dest_pixels;
+ GdkPixbuf *result;
+ guint dest_rowstride;
+ int i, j;
+
+ result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
+ width, height);
+
+ if (result == NULL)
+ {
+ g_warning ("failed to create a %dx%d pixbuf", width, height);
+ return NULL;
+ }
+
+ dest_rowstride = gdk_pixbuf_get_rowstride (result);
+ dest_pixels = gdk_pixbuf_get_pixels (result);
+
+ for (i = 0; i < height; i++)
+ {
+ guchar *p = dest_pixels + dest_rowstride * i;
+ guchar *q = pixels + src_rowstride * i;
+
+ guchar r = *(q++);
+ guchar g = *(q++);
+ guchar b = *(q++);
+ guchar a = 0;
+
+ if (n_channels == 4)
+ a = *(q++);
+
+ for (j = 0; j < width; j++)
+ {
+ *(p++) = r;
+ *(p++) = g;
+ *(p++) = b;
+
+ if (n_channels == 4)
+ *(p++) = a;
+ }
+ }
+
+ return result;
+}
+
+/* Scale the rectangle (src_x, src_y, src_width, src_height)
+ * onto the rectangle (dest_x, dest_y, dest_width, dest_height)
+ * of the destination, clip by clip_rect and render
+ */
static void
pixbuf_render (GdkPixbuf *src,
+ guint hints,
GdkWindow *window,
GdkBitmap *mask,
GdkRectangle *clip_rect,
gint dest_width,
gint dest_height)
{
- GdkPixbuf *tmp_pixbuf;
+ GdkPixbuf *tmp_pixbuf = NULL;
GdkRectangle rect;
int x_offset, y_offset;
+ gboolean has_alpha = gdk_pixbuf_get_has_alpha (src);
+ gint src_rowstride = gdk_pixbuf_get_rowstride (src);
+ gint src_n_channels = gdk_pixbuf_get_n_channels (src);
if (dest_width <= 0 || dest_height <= 0)
return;
rect.width = dest_width;
rect.height = dest_height;
- /* FIXME: we need the full mask, not a partial mask; the following is, however,
- * horribly expensive
- */
- if (!mask && clip_rect && !gdk_rectangle_intersect (clip_rect, &rect, &rect))
+ if (hints & THEME_MISSING)
return;
-
- if (dest_width != src->art_pixbuf->width ||
- dest_height != src->art_pixbuf->height)
+
+ /* FIXME: Because we use the mask to shape windows, we don't use
+ * clip_rect to clip what we draw to the mask, only to clip
+ * what we actually draw. But this leads to the horrible ineffiency
+ * of scale the whole image to get a little bit of it.
+ */
+ if (!mask && clip_rect)
{
- ArtPixBuf *partial_src_art;
- GdkPixbuf *partial_src_gdk;
+ if (!gdk_rectangle_intersect (clip_rect, &rect, &rect))
+ return;
+ }
- if (src->art_pixbuf->n_channels == 3)
- {
- partial_src_art =
- art_pixbuf_new_const_rgb (src->art_pixbuf->pixels + src_y * src->art_pixbuf->rowstride + src_x * src->art_pixbuf->n_channels,
- src_width,
- src_height,
- src->art_pixbuf->rowstride);
- }
- else
- {
- partial_src_art =
- art_pixbuf_new_const_rgba (src->art_pixbuf->pixels + src_y * src->art_pixbuf->rowstride + src_x * src->art_pixbuf->n_channels,
- src_width,
- src_height,
- src->art_pixbuf->rowstride);
- }
+ if (dest_width == src_width && dest_height == src_height)
+ {
+ tmp_pixbuf = g_object_ref (src);
- partial_src_gdk = gdk_pixbuf_new_from_art_pixbuf (partial_src_art);
- tmp_pixbuf = gdk_pixbuf_new (ART_PIX_RGB, src->art_pixbuf->has_alpha, 8, rect.width, rect.height);
+ x_offset = src_x + rect.x - dest_x;
+ y_offset = src_y + rect.y - dest_y;
+ }
+ else if (src_width == 0 && src_height == 0)
+ {
+ tmp_pixbuf = bilinear_gradient (src, src_x, src_y, dest_width, dest_height);
+
+ x_offset = rect.x - dest_x;
+ y_offset = rect.y - dest_y;
+ }
+ else if (src_width == 0 && dest_height == src_height)
+ {
+ tmp_pixbuf = horizontal_gradient (src, src_x, src_y, dest_width, dest_height);
+
+ x_offset = rect.x - dest_x;
+ y_offset = rect.y - dest_y;
+ }
+ else if (src_height == 0 && dest_width == src_width)
+ {
+ tmp_pixbuf = vertical_gradient (src, src_x, src_y, dest_width, dest_height);
+
+ x_offset = rect.x - dest_x;
+ y_offset = rect.y - dest_y;
+ }
+ else if ((hints & THEME_CONSTANT_COLS) && (hints & THEME_CONSTANT_ROWS))
+ {
+ tmp_pixbuf = replicate_single (src, src_x, src_y, dest_width, dest_height);
- gdk_pixbuf_scale (partial_src_gdk, tmp_pixbuf, 0, 0, rect.width, rect.height,
- dest_x - rect.x, dest_y - rect.y,
- (double)dest_width / src_width, (double)dest_height / src_height,
- ART_FILTER_BILINEAR);
+ x_offset = rect.x - dest_x;
+ y_offset = rect.y - dest_y;
+ }
+ else if (dest_width == src_width && (hints & THEME_CONSTANT_COLS))
+ {
+ tmp_pixbuf = replicate_rows (src, src_x, src_y, dest_width, dest_height);
- gdk_pixbuf_unref (partial_src_gdk);
-
- x_offset = 0;
- y_offset = 0;
+ x_offset = rect.x - dest_x;
+ y_offset = rect.y - dest_y;
}
- else
+ else if (dest_height == src_height && (hints & THEME_CONSTANT_ROWS))
{
- tmp_pixbuf = src;
- gdk_pixbuf_ref (tmp_pixbuf);
+ tmp_pixbuf = replicate_cols (src, src_x, src_y, dest_width, dest_height);
- x_offset = src_x + rect.x - dest_x;
- y_offset = src_y + rect.y - dest_y;
+ x_offset = rect.x - dest_x;
+ y_offset = rect.y - dest_y;
+ }
+ else if (src_width > 0 && src_height > 0)
+ {
+ double x_scale = (double)dest_width / src_width;
+ double y_scale = (double)dest_height / src_height;
+ guchar *pixels;
+ GdkPixbuf *partial_src;
+
+ pixels = (gdk_pixbuf_get_pixels (src)
+ + src_y * src_rowstride
+ + src_x * src_n_channels);
+
+ partial_src = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB,
+ has_alpha,
+ 8, src_width, src_height,
+ src_rowstride,
+ NULL, NULL);
+
+ tmp_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+ has_alpha, 8,
+ rect.width, rect.height);
+
+ gdk_pixbuf_scale (partial_src, tmp_pixbuf,
+ 0, 0, rect.width, rect.height,
+ dest_x - rect.x, dest_y - rect.y,
+ x_scale, y_scale,
+ GDK_INTERP_BILINEAR);
+
+ g_object_unref (partial_src);
+
+ x_offset = 0;
+ y_offset = 0;
}
- if (mask)
+ if (tmp_pixbuf)
{
- GdkGC *tmp_gc;
+ cairo_t *cr;
+
+ cr = gdk_cairo_create (window);
+ if (mask)
+ {
+ gdk_pixbuf_render_threshold_alpha (tmp_pixbuf, mask,
+ x_offset, y_offset,
+ rect.x, rect.y,
+ rect.width, rect.height,
+ 128);
+ }
- gdk_pixbuf_render_threshold_alpha (tmp_pixbuf, mask,
- x_offset, y_offset,
- rect.x, rect.y,
- rect.width, rect.height,
- 128);
+ gdk_cairo_set_source_pixbuf (cr,
+ tmp_pixbuf,
+ -x_offset + rect.x,
+ -y_offset + rect.y);
+ gdk_cairo_rectangle (cr, &rect);
+ cairo_fill (cr);
- tmp_gc = gdk_gc_new (window);
- gdk_pixbuf_render_to_drawable (tmp_pixbuf, window, tmp_gc,
- x_offset, y_offset,
- rect.x, rect.y,
- rect.width, rect.height,
- GDK_RGB_DITHER_NORMAL,
- 0, 0);
- gdk_gc_unref (tmp_gc);
+ cairo_destroy (cr);
+ g_object_unref (tmp_pixbuf);
}
- else
- gdk_pixbuf_render_to_drawable_alpha (tmp_pixbuf, window,
- x_offset, y_offset,
- rect.x, rect.y,
- rect.width, rect.height,
- GDK_PIXBUF_ALPHA_BILEVEL, 128,
- GDK_RGB_DITHER_NORMAL,
- 0, 0);
- gdk_pixbuf_unref (tmp_pixbuf);
}
ThemePixbuf *
theme_pixbuf_new (void)
{
- ThemePixbuf *result = g_new (ThemePixbuf, 1);
+ ThemePixbuf *result = g_new0 (ThemePixbuf, 1);
result->filename = NULL;
result->pixbuf = NULL;
void
theme_pixbuf_destroy (ThemePixbuf *theme_pb)
{
- if (theme_pb->pixbuf)
- g_cache_remove (pixbuf_cache, theme_pb->pixbuf);
+ theme_pixbuf_set_filename (theme_pb, NULL);
+ g_free (theme_pb);
}
void
theme_pb->pixbuf = NULL;
}
- if (theme_pb->filename)
- g_free (theme_pb->filename);
+ g_free (theme_pb->filename);
- theme_pb->filename = g_strdup (filename);
+ if (filename)
+ theme_pb->filename = g_strdup (filename);
+ else
+ theme_pb->filename = NULL;
+}
+
+static guint
+compute_hint (GdkPixbuf *pixbuf,
+ gint x0,
+ gint x1,
+ gint y0,
+ gint y1)
+{
+ int i, j;
+ int hints = THEME_CONSTANT_ROWS | THEME_CONSTANT_COLS | THEME_MISSING;
+ int n_channels = gdk_pixbuf_get_n_channels (pixbuf);
+
+ guchar *data = gdk_pixbuf_get_pixels (pixbuf);
+ int rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+
+ if (x0 == x1 || y0 == y1)
+ return 0;
+
+ for (i = y0; i < y1; i++)
+ {
+ guchar *p = data + i * rowstride + x0 * n_channels;
+ guchar r = p[0];
+ guchar g = p[1];
+ guchar b = p[2];
+ guchar a = 0;
+
+ if (n_channels == 4)
+ a = p[3];
+
+ for (j = x0; j < x1 ; j++)
+ {
+ if (n_channels != 4 || p[3] != 0)
+ {
+ hints &= ~THEME_MISSING;
+ if (!(hints & THEME_CONSTANT_ROWS))
+ goto cols;
+ }
+
+ if (r != *(p++) ||
+ g != *(p++) ||
+ b != *(p++) ||
+ (n_channels != 4 && a != *(p++)))
+ {
+ hints &= ~THEME_CONSTANT_ROWS;
+ if (!(hints & THEME_MISSING))
+ goto cols;
+ }
+ }
+ }
+
+ cols:
+ for (i = y0 + 1; i < y1; i++)
+ {
+ guchar *base = data + y0 * rowstride + x0 * n_channels;
+ guchar *p = data + i * rowstride + x0 * n_channels;
+
+ if (memcmp (p, base, n_channels * (x1 - x0)) != 0)
+ {
+ hints &= ~THEME_CONSTANT_COLS;
+ return hints;
+ }
+ }
+
+ return hints;
+}
+
+static void
+theme_pixbuf_compute_hints (ThemePixbuf *theme_pb)
+{
+ int i, j;
+ gint width = gdk_pixbuf_get_width (theme_pb->pixbuf);
+ gint height = gdk_pixbuf_get_height (theme_pb->pixbuf);
+
+ if (theme_pb->border_left + theme_pb->border_right > width ||
+ theme_pb->border_top + theme_pb->border_bottom > height)
+ {
+ g_warning ("Invalid borders specified for theme pixmap:\n"
+ " %s,\n"
+ "borders don't fit within the image", theme_pb->filename);
+ if (theme_pb->border_left + theme_pb->border_right > width)
+ {
+ theme_pb->border_left = width / 2;
+ theme_pb->border_right = (width + 1) / 2;
+ }
+ if (theme_pb->border_bottom + theme_pb->border_top > height)
+ {
+ theme_pb->border_top = height / 2;
+ theme_pb->border_bottom = (height + 1) / 2;
+ }
+ }
+
+ for (i = 0; i < 3; i++)
+ {
+ gint y0, y1;
+
+ switch (i)
+ {
+ case 0:
+ y0 = 0;
+ y1 = theme_pb->border_top;
+ break;
+ case 1:
+ y0 = theme_pb->border_top;
+ y1 = height - theme_pb->border_bottom;
+ break;
+ default:
+ y0 = height - theme_pb->border_bottom;
+ y1 = height;
+ break;
+ }
+
+ for (j = 0; j < 3; j++)
+ {
+ gint x0, x1;
+
+ switch (j)
+ {
+ case 0:
+ x0 = 0;
+ x1 = theme_pb->border_left;
+ break;
+ case 1:
+ x0 = theme_pb->border_left;
+ x1 = width - theme_pb->border_right;
+ break;
+ default:
+ x0 = width - theme_pb->border_right;
+ x1 = width;
+ break;
+ }
+
+ theme_pb->hints[i][j] = compute_hint (theme_pb->pixbuf, x0, x1, y0, y1);
+ }
+ }
+
}
void
theme_pb->border_right = right;
theme_pb->border_top = top;
theme_pb->border_bottom = bottom;
+
+ if (theme_pb->pixbuf)
+ theme_pixbuf_compute_hints (theme_pb);
}
void
gboolean stretch)
{
theme_pb->stretch = stretch;
+
+ if (theme_pb->pixbuf)
+ theme_pixbuf_compute_hints (theme_pb);
}
-GdkPixbuf *
+static GdkPixbuf *
pixbuf_cache_value_new (gchar *filename)
{
- GdkPixbuf *result = gdk_pixbuf_new_from_file (filename);
+ GError *err = NULL;
+
+ GdkPixbuf *result = gdk_pixbuf_new_from_file (filename, &err);
if (!result)
- g_warning("Pixbuf theme: Cannot load pixmap file %s\n", filename);
+ {
+ g_warning ("Pixbuf theme: Cannot load pixmap file %s: %s\n",
+ filename, err->message);
+ g_error_free (err);
+ }
return result;
}
{
if (!pixbuf_cache)
pixbuf_cache = g_cache_new ((GCacheNewFunc)pixbuf_cache_value_new,
- (GCacheDestroyFunc)gdk_pixbuf_unref,
+ (GCacheDestroyFunc)g_object_unref,
(GCacheDupFunc)g_strdup,
(GCacheDestroyFunc)g_free,
g_str_hash, g_direct_hash, g_str_equal);
theme_pb->pixbuf = g_cache_insert (pixbuf_cache, theme_pb->filename);
+
+ if (theme_pb->stretch)
+ theme_pixbuf_compute_hints (theme_pb);
}
return theme_pb->pixbuf;
{
GdkPixbuf *pixbuf = theme_pixbuf_get_pixbuf (theme_pb);
gint src_x[4], src_y[4], dest_x[4], dest_y[4];
+ gint pixbuf_width = gdk_pixbuf_get_width (pixbuf);
+ gint pixbuf_height = gdk_pixbuf_get_height (pixbuf);
if (!pixbuf)
return;
if (theme_pb->stretch)
{
+ if (component_mask & COMPONENT_ALL)
+ component_mask = (COMPONENT_ALL - 1) & ~component_mask;
+
src_x[0] = 0;
src_x[1] = theme_pb->border_left;
- src_x[2] = pixbuf->art_pixbuf->width - theme_pb->border_right;
- src_x[3] = pixbuf->art_pixbuf->width;
+ src_x[2] = pixbuf_width - theme_pb->border_right;
+ src_x[3] = pixbuf_width;
src_y[0] = 0;
src_y[1] = theme_pb->border_top;
- src_y[2] = pixbuf->art_pixbuf->height - theme_pb->border_bottom;
- src_y[3] = pixbuf->art_pixbuf->height;
+ src_y[2] = pixbuf_height - theme_pb->border_bottom;
+ src_y[3] = pixbuf_height;
dest_x[0] = x;
dest_x[1] = x + theme_pb->border_left;
dest_x[2] = x + width - theme_pb->border_right;
dest_x[3] = x + width;
+ if (dest_x[1] > dest_x[2])
+ {
+ component_mask &= ~(COMPONENT_NORTH | COMPONENT_SOUTH | COMPONENT_CENTER);
+ dest_x[1] = dest_x[2] = (dest_x[1] + dest_x[2]) / 2;
+ }
+
dest_y[0] = y;
dest_y[1] = y + theme_pb->border_top;
dest_y[2] = y + height - theme_pb->border_bottom;
dest_y[3] = y + height;
- if (component_mask & COMPONENT_ALL)
- component_mask = (COMPONENT_ALL - 1) & ~component_mask;
+ if (dest_y[1] > dest_y[2])
+ {
+ component_mask &= ~(COMPONENT_EAST | COMPONENT_WEST | COMPONENT_CENTER);
+ dest_y[1] = dest_y[2] = (dest_y[1] + dest_y[2]) / 2;
+ }
+
+
-#define RENDER_COMPONENT(X1,X2,Y1,Y2) \
- pixbuf_render (pixbuf, window, mask, clip_rect, \
- src_x[X1], src_y[Y1], \
- src_x[X2] - src_x[X1], src_y[Y2] - src_y[Y1], \
- dest_x[X1], dest_y[Y1], \
+#define RENDER_COMPONENT(X1,X2,Y1,Y2) \
+ pixbuf_render (pixbuf, theme_pb->hints[Y1][X1], window, mask, clip_rect, \
+ src_x[X1], src_y[Y1], \
+ src_x[X2] - src_x[X1], src_y[Y2] - src_y[Y1], \
+ dest_x[X1], dest_y[Y1], \
dest_x[X2] - dest_x[X1], dest_y[Y2] - dest_y[Y1]);
if (component_mask & COMPONENT_NORTH_WEST)
{
if (center)
{
- x += (width - pixbuf->art_pixbuf->width) / 2;
- y += (height - pixbuf->art_pixbuf->height) / 2;
+ x += (width - pixbuf_width) / 2;
+ y += (height - pixbuf_height) / 2;
- pixbuf_render (pixbuf, window, NULL, clip_rect,
+ pixbuf_render (pixbuf, 0, window, NULL, clip_rect,
0, 0,
- pixbuf->art_pixbuf->width, pixbuf->art_pixbuf->height,
+ pixbuf_width, pixbuf_height,
x, y,
- pixbuf->art_pixbuf->width, pixbuf->art_pixbuf->height);
+ pixbuf_width, pixbuf_height);
}
else
{
- GdkPixmap *tmp_pixmap;
- GdkGC *tmp_gc;
- GdkGCValues gc_values;
-
- tmp_pixmap = gdk_pixmap_new (window,
- pixbuf->art_pixbuf->width,
- pixbuf->art_pixbuf->height,
- -1);
- tmp_gc = gdk_gc_new (tmp_pixmap);
- gdk_pixbuf_render_to_drawable (pixbuf, tmp_pixmap, tmp_gc,
- 0, 0,
- 0, 0,
- pixbuf->art_pixbuf->width, pixbuf->art_pixbuf->height,
- GDK_RGB_DITHER_NORMAL,
- 0, 0);
- gdk_gc_unref (tmp_gc);
-
- gc_values.fill = GDK_TILED;
- gc_values.tile = tmp_pixmap;
- tmp_gc = gdk_gc_new_with_values (window,
- &gc_values, GDK_GC_FILL | GDK_GC_TILE);
+ cairo_t *cr = gdk_cairo_create (window);
+
+ gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
+ cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
+
if (clip_rect)
- gdk_draw_rectangle (window, tmp_gc, TRUE,
- clip_rect->x, clip_rect->y, clip_rect->width, clip_rect->height);
+ gdk_cairo_rectangle (cr, clip_rect);
else
- gdk_draw_rectangle (window, tmp_gc, TRUE, x, y, width, height);
+ cairo_rectangle (cr, x, y, width, height);
- gdk_gc_unref (tmp_gc);
- gdk_pixmap_unref (tmp_pixmap);
+ cairo_fill (cr);
+
+ cairo_destroy (cr);
}
}
}