1 /* Atomix -- a little puzzle game about atoms and molecules.
2 * Copyright (C) 1999-2001 Jens Finke
3 * Copyright (C) 2005 Guilherme de S. Pastore
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 #include "theme.h"
21 #include "theme-private.h"
22
23
24 /*=================================================================
25
26 Declaration of internal functions
27
28 ---------------------------------------------------------------*/
29
30 static void theme_class_init (GObjectClass *class);
31 static void theme_init (Theme *theme);
32 static void theme_finalize (GObject *object);
33 static void destroy_theme_image (gpointer data);
34
35 static GObjectClass *parent_class;
36
theme_get_type(void)37 GType theme_get_type (void)
38 {
39 static GType object_type = 0;
40
41 if (!object_type)
42 {
43 static const GTypeInfo object_info = {
44 sizeof (ThemeClass),
45 (GBaseInitFunc) NULL,
46 (GBaseFinalizeFunc) NULL,
47 (GClassInitFunc) theme_class_init,
48 NULL, /* clas_finalize */
49 NULL, /* class_data */
50 sizeof (Theme),
51 0, /* n_preallocs */
52 (GInstanceInitFunc) theme_init,
53 };
54
55 object_type = g_type_register_static (G_TYPE_OBJECT,
56 "Theme", &object_info, 0);
57 }
58
59 return object_type;
60 }
61
62
63 /*=================================================================
64
65 Theme creation, initialisation and clean up
66
67 ---------------------------------------------------------------*/
68
theme_class_init(GObjectClass * class)69 static void theme_class_init (GObjectClass *class)
70 {
71 parent_class = g_type_class_ref (G_TYPE_OBJECT);
72 class->finalize = theme_finalize;
73 }
74
theme_init(Theme * theme)75 static void theme_init (Theme *theme)
76 {
77 ThemePrivate *priv;
78
79 priv = g_new0 (ThemePrivate, 1);
80
81 priv->name = NULL;
82 priv->path = NULL;
83 priv->tile_width = 0;
84 priv->tile_height = 0;
85 priv->animstep = 0;
86 priv->bg_color.red = 0;
87 priv->bg_color.green = 0;
88 priv->bg_color.blue = 0;
89 g_datalist_init (&priv->images);
90
91 theme->priv = priv;
92 }
93
theme_finalize(GObject * object)94 static void theme_finalize (GObject *object)
95 {
96 ThemePrivate *priv;
97 Theme *theme = THEME (object);
98
99 g_return_if_fail (theme != NULL);
100
101 #ifdef DEBUG
102 g_message ("Finalize theme");
103 #endif
104 priv = theme->priv;
105
106 if (priv->name)
107 g_free (priv->name);
108 priv->name = NULL;
109
110 if (priv->path)
111 g_free (priv->path);
112 priv->path = NULL;
113
114 if (priv->images)
115 g_datalist_clear (&priv->images);
116
117 g_free (theme->priv);
118 theme->priv = NULL;
119 }
120
theme_new(void)121 Theme *theme_new (void)
122 {
123 Theme *theme;
124 theme = THEME (g_object_new (THEME_TYPE, NULL));
125 return theme;
126 }
127
128
129 /*=================================================================
130
131 Theme functions
132
133 ---------------------------------------------------------------*/
134
theme_get_name(Theme * theme)135 gchar *theme_get_name (Theme *theme)
136 {
137 g_return_val_if_fail (IS_THEME (theme), NULL);
138
139 return theme->priv->name;
140 }
141
theme_get_animstep(Theme * theme)142 gint theme_get_animstep (Theme *theme)
143 {
144 g_return_val_if_fail (IS_THEME (theme), 0);
145
146 return theme->priv->animstep;
147 }
148
destroy_theme_image(gpointer data)149 static void destroy_theme_image (gpointer data)
150 {
151 ThemeImage *ti;
152
153 ti = (ThemeImage *) data;
154
155 if (ti == NULL)
156 return;
157
158 if (ti->file)
159 g_free (ti->file);
160
161 if (ti->image)
162 g_object_unref (ti->image);
163
164 if (ti->decorations)
165 g_slist_free (ti->decorations);
166
167 g_free (ti);
168 }
169
get_theme_image_pixbuf(ThemeImage * ti)170 static GdkPixbuf *get_theme_image_pixbuf (ThemeImage *ti)
171 {
172 GdkPixbuf *pixbuf;
173
174 if (ti == NULL)
175 return NULL;
176
177 if (ti->loading_failed)
178 return NULL;
179
180 if (ti->image == NULL)
181 {
182 ti->image = gdk_pixbuf_new_from_file (ti->file, NULL);
183 if (ti->image == NULL)
184 ti->loading_failed = TRUE;
185 else if (ti->alpha < 255)
186 {
187 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
188 gdk_pixbuf_get_width (ti->image),
189 gdk_pixbuf_get_height (ti->image));
190 gdk_pixbuf_fill (pixbuf, 0x00000000);
191 gdk_pixbuf_composite (ti->image,
192 pixbuf,
193 0, 0,
194 gdk_pixbuf_get_width (pixbuf),
195 gdk_pixbuf_get_height (pixbuf),
196 0.0, 0.0, 1.0, 1.0,
197 GDK_INTERP_NEAREST, ti->alpha);
198 g_object_unref (ti->image);
199 ti->image = pixbuf;
200 }
201 }
202
203 if (ti->image != NULL)
204 g_object_ref (ti->image);
205
206 return ti->image;
207 }
208
create_sub_images(Theme * theme,Tile * tile,TileSubType sub_type)209 static GdkPixbuf *create_sub_images (Theme *theme, Tile *tile,
210 TileSubType sub_type)
211 {
212 ThemePrivate *priv;
213 GSList *elem;
214 ThemeImage *ti;
215 GdkPixbuf *pixbuf = NULL;
216 GdkPixbuf *pb;
217
218 g_return_val_if_fail (IS_THEME (theme), NULL);
219 g_return_val_if_fail (IS_TILE (tile), NULL);
220
221 priv = theme->priv;
222
223 elem = tile_get_sub_ids (tile, sub_type);
224
225 for (; elem != NULL; elem = elem->next)
226 {
227 ti = g_datalist_id_get_data (&priv->images, GPOINTER_TO_QUARK (elem->data));
228 if (ti == NULL)
229 continue;
230
231 pb = get_theme_image_pixbuf (ti);
232 if (pb == NULL)
233 {
234 #ifdef DEBUG
235 g_warning ("Couldn't load sub image: %s",
236 g_quark_to_string (GPOINTER_TO_QUARK (elem->data)));
237 #endif
238 continue;
239 }
240
241 if (pixbuf == NULL)
242 {
243 pixbuf = gdk_pixbuf_copy (pb);
244 }
245 else
246 {
247 gdk_pixbuf_composite (pb,
248 pixbuf,
249 0, 0,
250 gdk_pixbuf_get_width (pixbuf),
251 gdk_pixbuf_get_height (pixbuf),
252 0.0, 0.0, 1.0, 1.0, GDK_INTERP_NEAREST, 255);
253 }
254 g_object_unref (pb);
255 }
256
257 return pixbuf;
258 }
259
theme_apply_decoration(Theme * theme,Tile * tile)260 gboolean theme_apply_decoration (Theme *theme, Tile *tile)
261 {
262 static int counter = 0;
263 ThemeImage *ti;
264 gint n_decorations;
265 GQuark decor_id;
266
267 if (tile == NULL)
268 return FALSE;
269
270 g_return_val_if_fail (IS_THEME (theme), FALSE);
271 g_return_val_if_fail (IS_TILE (tile), FALSE);
272
273 ti = g_datalist_id_get_data (&theme->priv->images, tile_get_base_id (tile));
274 if (ti->decorations == NULL)
275 return FALSE;
276
277 n_decorations = g_slist_length (ti->decorations);
278 decor_id = GPOINTER_TO_QUARK (g_slist_nth_data (ti->decorations,
279 counter++ % n_decorations));
280 tile_add_sub_id (tile, decor_id, TILE_SUB_OVERLAY);
281
282 return TRUE;
283 }
284
theme_get_tile_image(Theme * theme,Tile * tile)285 GdkPixbuf *theme_get_tile_image (Theme *theme, Tile *tile)
286 {
287 ThemePrivate *priv;
288 GQuark image_id;
289 ThemeImage *ti = NULL;
290 GdkPixbuf *underlay_pb = NULL;
291 GdkPixbuf *overlay_pb = NULL;
292 GdkPixbuf *base_pb = NULL;
293 GdkPixbuf *result = NULL;
294 gint tw, th;
295
296 g_return_val_if_fail (IS_THEME (theme), NULL);
297 g_return_val_if_fail (IS_TILE (tile), NULL);
298
299 priv = theme->priv;
300
301 image_id = tile_get_base_id (tile);
302
303 underlay_pb = create_sub_images (theme, tile, TILE_SUB_UNDERLAY);
304 overlay_pb = create_sub_images (theme, tile, TILE_SUB_OVERLAY);
305
306 ti = g_datalist_id_get_data (&priv->images, image_id);
307 base_pb = get_theme_image_pixbuf (ti);
308 if (base_pb == NULL)
309 {
310 theme_get_tile_size (theme, &tw, &th);
311 base_pb = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, tw, th);
312 gdk_pixbuf_fill (base_pb, 0);
313 }
314
315 if (underlay_pb && overlay_pb)
316 {
317 result = gdk_pixbuf_copy (underlay_pb);
318 gdk_pixbuf_composite (base_pb,
319 result,
320 0, 0,
321 gdk_pixbuf_get_width (result),
322 gdk_pixbuf_get_height (result),
323 0.0, 0.0, 1.0, 1.0, GDK_INTERP_NEAREST, 255);
324 gdk_pixbuf_composite (overlay_pb,
325 result,
326 0, 0,
327 gdk_pixbuf_get_width (result),
328 gdk_pixbuf_get_height (result),
329 0.0, 0.0, 1.0, 1.0, GDK_INTERP_NEAREST, 255);
330 g_object_unref (overlay_pb);
331 g_object_unref (underlay_pb);
332 }
333 else if (!underlay_pb && overlay_pb)
334 {
335 result = gdk_pixbuf_copy (base_pb);
336 gdk_pixbuf_composite (overlay_pb,
337 result,
338 0, 0,
339 gdk_pixbuf_get_width (result),
340 gdk_pixbuf_get_height (result),
341 0.0, 0.0, 1.0, 1.0, GDK_INTERP_NEAREST, 255);
342 g_object_unref (overlay_pb);
343 }
344 else if (underlay_pb && !overlay_pb)
345 {
346 result = gdk_pixbuf_copy (underlay_pb);
347 gdk_pixbuf_composite (base_pb,
348 result,
349 0, 0,
350 gdk_pixbuf_get_width (result),
351 gdk_pixbuf_get_height (result),
352 0.0, 0.0, 1.0, 1.0, GDK_INTERP_NEAREST, 255);
353 g_object_unref (underlay_pb);
354 }
355 else
356 result = g_object_ref (base_pb);
357
358 g_object_unref (base_pb);
359
360 return result;
361 }
362
theme_get_selector_image(Theme * theme)363 GdkPixbuf *theme_get_selector_image (Theme *theme)
364 {
365 static GQuark cursor_id = 0;
366 ThemeImage *ti;
367
368 if (!cursor_id)
369 cursor_id = g_quark_from_static_string ("cursor");
370
371 g_return_val_if_fail (IS_THEME (theme), NULL);
372
373 ti = g_datalist_id_get_data (&theme->priv->images, cursor_id);
374
375 return get_theme_image_pixbuf (ti);
376 }
377
theme_get_selector_arrow_images(Theme * theme,GdkPixbuf ** arrows)378 void theme_get_selector_arrow_images (Theme *theme, GdkPixbuf **arrows)
379 {
380 gint i;
381 ThemeImage *ti;
382 static GQuark arrow_id[4] = { 0, 0, 0, 0 };
383
384 if (!arrow_id[0])
385 {
386 arrow_id[0] = g_quark_from_static_string ("arrow-top");
387 arrow_id[1] = g_quark_from_static_string ("arrow-right");
388 arrow_id[2] = g_quark_from_static_string ("arrow-bottom");
389 arrow_id[3] = g_quark_from_static_string ("arrow-left");
390 }
391
392 for (i = 0; i < 4; i++)
393 {
394 ti = g_datalist_id_get_data (&theme->priv->images, arrow_id[i]);
395 arrows[i] = get_theme_image_pixbuf (ti);
396 }
397 }
398
theme_get_tile_size(Theme * theme,gint * width,gint * height)399 void theme_get_tile_size (Theme *theme, gint *width, gint *height)
400 {
401 *width = *height = 0;
402
403 g_return_if_fail (IS_THEME (theme));
404
405 *width = theme->priv->tile_width;
406 *height = theme->priv->tile_height;
407 }
408
theme_get_background_color(Theme * theme)409 GdkRGBA *theme_get_background_color (Theme *theme)
410 {
411 return &(theme->priv->bg_color);
412 }
413
414
theme_add_image(Theme * theme,const gchar * src,gint alpha)415 GQuark theme_add_image (Theme *theme, const gchar *src, gint alpha)
416 {
417 ThemeImage *ti;
418 gchar *filename;
419 gchar *suffix;
420
421 g_return_val_if_fail (IS_THEME (theme), 0);
422 g_return_val_if_fail (src != NULL, 0);
423 g_return_val_if_fail (0 <= alpha && alpha <= 255, 0);
424
425 ti = g_new0 (ThemeImage, 1);
426 ti->file = g_strdup (src);
427 ti->loading_failed = FALSE;
428 ti->image = NULL;
429 ti->alpha = alpha;
430 ti->decorations = NULL;
431
432 filename = g_path_get_basename (src);
433 suffix = g_strrstr (filename, ".png");
434 if (suffix != NULL)
435 *suffix = '\0';
436 else
437 {
438 suffix = g_strrstr (filename, ".gif");
439 if (suffix != NULL)
440 *suffix = '\0';
441 }
442
443 ti->id = g_quark_from_string (filename);
444
445 g_datalist_id_set_data_full (&theme->priv->images,
446 ti->id, ti, destroy_theme_image);
447
448 g_free (filename);
449
450 return ti->id;
451 }
452
theme_add_image_decoration(Theme * theme,GQuark base,GQuark decor)453 void theme_add_image_decoration (Theme *theme, GQuark base, GQuark decor)
454 {
455 ThemeImage *ti;
456
457 g_return_if_fail (IS_THEME (theme));
458
459 ti = g_datalist_id_get_data (&theme->priv->images, base);
460 if (ti == NULL)
461 return;
462
463 ti->decorations = g_slist_append (ti->decorations, GQUARK_TO_POINTER (decor));
464 }
465