2 * Copyright (C) 1998-2000 Red Hat, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
19 * Written by Owen Taylor <otaylor@redhat.com>, based on code by
20 * Carsten Haitzler <raster@rasterman.com>
23 #include "pixmap_theme.h"
24 #include <gdk-pixbuf/gdk-pixbuf.h>
26 GCache *pixbuf_cache = NULL;
29 pixbuf_render (GdkPixbuf *src,
32 GdkRectangle *clip_rect,
42 GdkPixbuf *tmp_pixbuf;
44 int x_offset, y_offset;
46 if (dest_width <= 0 || dest_height <= 0)
51 rect.width = dest_width;
52 rect.height = dest_height;
54 /* FIXME: we need the full mask, not a partial mask; the following is, however,
57 if (!mask && clip_rect && !gdk_rectangle_intersect (clip_rect, &rect, &rect))
60 if (dest_width != src->art_pixbuf->width ||
61 dest_height != src->art_pixbuf->height)
63 ArtPixBuf *partial_src_art;
64 GdkPixbuf *partial_src_gdk;
66 if (src->art_pixbuf->n_channels == 3)
69 art_pixbuf_new_const_rgb (src->art_pixbuf->pixels + src_y * src->art_pixbuf->rowstride + src_x * src->art_pixbuf->n_channels,
72 src->art_pixbuf->rowstride);
77 art_pixbuf_new_const_rgba (src->art_pixbuf->pixels + src_y * src->art_pixbuf->rowstride + src_x * src->art_pixbuf->n_channels,
80 src->art_pixbuf->rowstride);
83 partial_src_gdk = gdk_pixbuf_new_from_art_pixbuf (partial_src_art);
84 tmp_pixbuf = gdk_pixbuf_new (ART_PIX_RGB, src->art_pixbuf->has_alpha, 8, rect.width, rect.height);
86 gdk_pixbuf_scale (partial_src_gdk, tmp_pixbuf, 0, 0, rect.width, rect.height,
87 dest_x - rect.x, dest_y - rect.y,
88 (double)dest_width / src_width, (double)dest_height / src_height,
91 gdk_pixbuf_unref (partial_src_gdk);
99 gdk_pixbuf_ref (tmp_pixbuf);
101 x_offset = src_x + rect.x - dest_x;
102 y_offset = src_y + rect.y - dest_y;
109 gdk_pixbuf_render_threshold_alpha (tmp_pixbuf, mask,
112 rect.width, rect.height,
115 tmp_gc = gdk_gc_new (window);
116 gdk_pixbuf_render_to_drawable (tmp_pixbuf, window, tmp_gc,
119 rect.width, rect.height,
120 GDK_RGB_DITHER_NORMAL,
122 gdk_gc_unref (tmp_gc);
125 gdk_pixbuf_render_to_drawable_alpha (tmp_pixbuf, window,
128 rect.width, rect.height,
129 GDK_PIXBUF_ALPHA_BILEVEL, 128,
130 GDK_RGB_DITHER_NORMAL,
132 gdk_pixbuf_unref (tmp_pixbuf);
136 theme_pixbuf_new (void)
138 ThemePixbuf *result = g_new (ThemePixbuf, 1);
139 result->filename = NULL;
140 result->pixbuf = NULL;
142 result->stretch = TRUE;
143 result->border_left = 0;
144 result->border_right = 0;
145 result->border_bottom = 0;
146 result->border_top = 0;
152 theme_pixbuf_destroy (ThemePixbuf *theme_pb)
154 if (theme_pb->pixbuf)
155 g_cache_remove (pixbuf_cache, theme_pb->pixbuf);
159 theme_pixbuf_set_filename (ThemePixbuf *theme_pb,
160 const char *filename)
162 if (theme_pb->pixbuf)
164 g_cache_remove (pixbuf_cache, theme_pb->pixbuf);
165 theme_pb->pixbuf = NULL;
168 if (theme_pb->filename)
169 g_free (theme_pb->filename);
171 theme_pb->filename = g_strdup (filename);
175 theme_pixbuf_set_border (ThemePixbuf *theme_pb,
181 theme_pb->border_left = left;
182 theme_pb->border_right = right;
183 theme_pb->border_top = top;
184 theme_pb->border_bottom = bottom;
188 theme_pixbuf_set_stretch (ThemePixbuf *theme_pb,
191 theme_pb->stretch = stretch;
195 pixbuf_cache_value_new (gchar *filename)
197 GdkPixbuf *result = gdk_pixbuf_new_from_file (filename);
199 g_warning("Pixbuf theme: Cannot load pixmap file %s\n", filename);
205 theme_pixbuf_get_pixbuf (ThemePixbuf *theme_pb)
207 if (!theme_pb->pixbuf)
210 pixbuf_cache = g_cache_new ((GCacheNewFunc)pixbuf_cache_value_new,
211 (GCacheDestroyFunc)gdk_pixbuf_unref,
212 (GCacheDupFunc)g_strdup,
213 (GCacheDestroyFunc)g_free,
214 g_str_hash, g_direct_hash, g_str_equal);
216 theme_pb->pixbuf = g_cache_insert (pixbuf_cache, theme_pb->filename);
219 return theme_pb->pixbuf;
223 theme_pixbuf_render (ThemePixbuf *theme_pb,
226 GdkRectangle *clip_rect,
227 guint component_mask,
234 GdkPixbuf *pixbuf = theme_pixbuf_get_pixbuf (theme_pb);
235 gint src_x[4], src_y[4], dest_x[4], dest_y[4];
240 if (theme_pb->stretch)
243 src_x[1] = theme_pb->border_left;
244 src_x[2] = pixbuf->art_pixbuf->width - theme_pb->border_right;
245 src_x[3] = pixbuf->art_pixbuf->width;
248 src_y[1] = theme_pb->border_top;
249 src_y[2] = pixbuf->art_pixbuf->height - theme_pb->border_bottom;
250 src_y[3] = pixbuf->art_pixbuf->height;
253 dest_x[1] = x + theme_pb->border_left;
254 dest_x[2] = x + width - theme_pb->border_right;
255 dest_x[3] = x + width;
258 dest_y[1] = y + theme_pb->border_top;
259 dest_y[2] = y + height - theme_pb->border_bottom;
260 dest_y[3] = y + height;
262 if (component_mask & COMPONENT_ALL)
263 component_mask = (COMPONENT_ALL - 1) & ~component_mask;
265 #define RENDER_COMPONENT(X1,X2,Y1,Y2) \
266 pixbuf_render (pixbuf, window, mask, clip_rect, \
267 src_x[X1], src_y[Y1], \
268 src_x[X2] - src_x[X1], src_y[Y2] - src_y[Y1], \
269 dest_x[X1], dest_y[Y1], \
270 dest_x[X2] - dest_x[X1], dest_y[Y2] - dest_y[Y1]);
272 if (component_mask & COMPONENT_NORTH_WEST)
273 RENDER_COMPONENT (0, 1, 0, 1);
275 if (component_mask & COMPONENT_NORTH)
276 RENDER_COMPONENT (1, 2, 0, 1);
278 if (component_mask & COMPONENT_NORTH_EAST)
279 RENDER_COMPONENT (2, 3, 0, 1);
281 if (component_mask & COMPONENT_WEST)
282 RENDER_COMPONENT (0, 1, 1, 2);
284 if (component_mask & COMPONENT_CENTER)
285 RENDER_COMPONENT (1, 2, 1, 2);
287 if (component_mask & COMPONENT_EAST)
288 RENDER_COMPONENT (2, 3, 1, 2);
290 if (component_mask & COMPONENT_SOUTH_WEST)
291 RENDER_COMPONENT (0, 1, 2, 3);
293 if (component_mask & COMPONENT_SOUTH)
294 RENDER_COMPONENT (1, 2, 2, 3);
296 if (component_mask & COMPONENT_SOUTH_EAST)
297 RENDER_COMPONENT (2, 3, 2, 3);
303 x += (width - pixbuf->art_pixbuf->width) / 2;
304 y += (height - pixbuf->art_pixbuf->height) / 2;
306 pixbuf_render (pixbuf, window, NULL, clip_rect,
308 pixbuf->art_pixbuf->width, pixbuf->art_pixbuf->height,
310 pixbuf->art_pixbuf->width, pixbuf->art_pixbuf->height);
314 GdkPixmap *tmp_pixmap;
316 GdkGCValues gc_values;
318 tmp_pixmap = gdk_pixmap_new (window,
319 pixbuf->art_pixbuf->width,
320 pixbuf->art_pixbuf->height,
322 tmp_gc = gdk_gc_new (tmp_pixmap);
323 gdk_pixbuf_render_to_drawable (pixbuf, tmp_pixmap, tmp_gc,
326 pixbuf->art_pixbuf->width, pixbuf->art_pixbuf->height,
327 GDK_RGB_DITHER_NORMAL,
329 gdk_gc_unref (tmp_gc);
331 gc_values.fill = GDK_TILED;
332 gc_values.tile = tmp_pixmap;
333 tmp_gc = gdk_gc_new_with_values (window,
334 &gc_values, GDK_GC_FILL | GDK_GC_TILE);
336 gdk_draw_rectangle (window, tmp_gc, TRUE,
337 clip_rect->x, clip_rect->y, clip_rect->width, clip_rect->height);
339 gdk_draw_rectangle (window, tmp_gc, TRUE, x, y, width, height);
341 gdk_gc_unref (tmp_gc);
342 gdk_pixmap_unref (tmp_pixmap);