Bug Summary

File:capplets/common/cafe-theme-info.c
Warning:line 1235, column 12
Potential leak of memory pointed to by 'tuple'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name cafe-theme-info.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/capplets/common -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I ../.. -D CAFECC_DATA_DIR="/usr/share/cafe-control-center" -D CAFELOCALEDIR="/usr/share/locale" -D CTK_ENGINE_DIR="/usr/lib/x86_64-linux-gnu/ctk-3.0/3.0.0/theming-engines" -D G_LOG_DOMAIN="capplet-common" -D INSTALL_PREFIX="/usr" -I ../.. -I ../../libwindow-settings -D PIXMAP_DIR="/usr/share/cafe-control-center/pixmaps" -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/libxml2 -I /usr/include/cafe-desktop-2.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dconf -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/cafe-desktop-2.0 -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/startup-notification-1.0 -I /usr/include/dconf -I /usr/include/croma-1 -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/cafe-settings-daemon -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/dconf -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/libmount -I /usr/include/blkid -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/capplets/common -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-08-06-111517-113088-1 -x c cafe-theme-info.c
1/* cafe-theme-info.c - CAFE Theme information
2 *
3 * Copyright (C) 2002 Jonathan Blandford <jrb@gnome.org>
4 * Copyright (C) 2011 Perberos
5 * All rights reserved.
6 *
7 * This file is part of the Cafe Library.
8 *
9 * The Cafe Library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * The Cafe Library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with the Cafe Library; see the file COPYING.LIB. If not,
21 * write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 */
24
25#ifdef HAVE_CONFIG_H1
26 #include <config.h>
27#endif
28
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <dirent.h>
32#include <glib/gi18n.h>
33#include <gmodule.h>
34#include <ctk/ctk.h>
35#include <cdk/cdkx.h>
36#include <gio/gio.h>
37#include <string.h>
38#include <libcafe-desktop/cafe-desktop-item.h>
39#include "cafe-theme-info.h"
40#include "ctkrc-utils.h"
41
42#include <X11/Xcursor/Xcursor.h>
43
44#define THEME_NAME"X-GNOME-Metatheme/Name" "X-GNOME-Metatheme/Name"
45#define THEME_COMMENT"X-GNOME-Metatheme/Comment" "X-GNOME-Metatheme/Comment"
46#define CTK_THEME_KEY"X-GNOME-Metatheme/CtkTheme" "X-GNOME-Metatheme/CtkTheme"
47#define CTK_COLOR_SCHEME_KEY"X-GNOME-Metatheme/CtkColorScheme" "X-GNOME-Metatheme/CtkColorScheme"
48#define CROMA_THEME_KEY"X-GNOME-Metatheme/MetacityTheme" "X-GNOME-Metatheme/MetacityTheme"
49#define ICON_THEME_KEY"X-GNOME-Metatheme/IconTheme" "X-GNOME-Metatheme/IconTheme"
50#define CURSOR_THEME_KEY"X-GNOME-Metatheme/CursorTheme" "X-GNOME-Metatheme/CursorTheme"
51#define NOTIFICATION_THEME_KEY"X-GNOME-Metatheme/NotificationTheme" "X-GNOME-Metatheme/NotificationTheme"
52#define CURSOR_SIZE_KEY"X-GNOME-Metatheme/CursorSize" "X-GNOME-Metatheme/CursorSize"
53#define SOUND_THEME_KEY"X-GNOME-Metatheme/SoundTheme" "X-GNOME-Metatheme/SoundTheme"
54#define APPLICATION_FONT_KEY"X-GNOME-Metatheme/ApplicationFont" "X-GNOME-Metatheme/ApplicationFont"
55#define DOCUMENTS_FONT_KEY"X-GNOME-Metatheme/DocumentsFont" "X-GNOME-Metatheme/DocumentsFont"
56#define DESKTOP_FONT_KEY"X-GNOME-Metatheme/DesktopFont" "X-GNOME-Metatheme/DesktopFont"
57#define WINDOWTITLE_FONT_KEY"X-GNOME-Metatheme/WindowTitleFont" "X-GNOME-Metatheme/WindowTitleFont"
58#define MONOSPACE_FONT_KEY"X-GNOME-Metatheme/MonospaceFont" "X-GNOME-Metatheme/MonospaceFont"
59#define BACKGROUND_IMAGE_KEY"X-GNOME-Metatheme/BackgroundImage" "X-GNOME-Metatheme/BackgroundImage"
60#define HIDDEN_KEY"X-GNOME-Metatheme/Hidden" "X-GNOME-Metatheme/Hidden"
61
62/* Terminology used in this lib:
63 *
64 * /usr/share/themes, ~/.themes -- top_theme_dir
65 * top_theme_dir/theme_name/ -- common_theme_dir
66 * /usr/share/icons, ~/.icons -- top_icon_theme_dir
67 * top_icon_theme_dir/theme_name/ -- icon_common_theme_dir
68 *
69 */
70
71typedef struct _ThemeCallbackData {
72 ThemeChangedCallback func;
73 gpointer data;
74} ThemeCallbackData;
75
76typedef struct {
77 GFileMonitor* common_theme_dir_handle;
78 GFileMonitor* ctk2_dir_handle;
79 GFileMonitor* keybinding_dir_handle;
80 GFileMonitor* croma_dir_handle;
81 gint priority;
82} CommonThemeDirMonitorData;
83
84typedef struct {
85 GFileMonitor* common_icon_theme_dir_handle;
86 gint priority;
87} CommonIconThemeDirMonitorData;
88
89typedef struct {
90 GHashTable* handle_hash;
91 gint priority;
92} CallbackTuple;
93
94
95/* Hash tables */
96
97/* The hashes_by_dir are indexed by an escaped uri of the common_theme_dir that
98 * that particular theme is part of. The data pointed to by them is a
99 * CafeTheme{Meta,Icon,}Info struct. Note that the uri is of the form
100 * "file:///home/username/.themes/foo", and not "/home/username/.themes/foo"
101 */
102
103/* The hashes_by_name are hashed by the index of the theme. The data pointed to
104 * by them is a GList whose data elements are CafeTheme{Meta,Icon,}Info
105 * structs. This is because a theme can be found both in the users ~/.theme as
106 * well as globally in $prefix. All access to them must be done via helper
107 * functions.
108 */
109static GList* callbacks = NULL((void*)0);
110
111static GHashTable* meta_theme_hash_by_uri;
112static GHashTable* meta_theme_hash_by_name;
113static GHashTable* icon_theme_hash_by_uri;
114static GHashTable* icon_theme_hash_by_name;
115static GHashTable* cursor_theme_hash_by_uri;
116static GHashTable* cursor_theme_hash_by_name;
117static GHashTable* theme_hash_by_uri;
118static GHashTable* theme_hash_by_name;
119static gboolean initting = FALSE(0);
120
121/* private functions */
122static gint safe_strcmp(const gchar* a_str, const gchar* b_str)
123{
124 if (a_str && b_str)
125 {
126 return strcmp(a_str, b_str);
127 }
128 else
129 {
130 return a_str - b_str;
131 }
132}
133
134static GFileType
135get_file_type (GFile *file)
136{
137 GFileType file_type = G_FILE_TYPE_UNKNOWN;
138 GFileInfo *file_info;
139
140 file_info = g_file_query_info (file,
141 G_FILE_ATTRIBUTE_STANDARD_TYPE"standard::type",
142 G_FILE_QUERY_INFO_NONE,
143 NULL((void*)0), NULL((void*)0));
144 if (file_info != NULL((void*)0)) {
145 file_type = g_file_info_get_file_type (file_info);
146 g_object_unref (file_info);
147 }
148
149 return file_type;
150}
151
152static void
153add_theme_to_hash_by_name (GHashTable *hash_table,
154 gpointer data)
155{
156 CafeThemeCommonInfo *info = data;
157 GList *list;
158
159 list = g_hash_table_lookup (hash_table, info->name);
160 if (list == NULL((void*)0)) {
161 list = g_list_append (list, info);
162 } else {
163 GList *list_ptr = list;
164 gboolean added = FALSE(0);
165
166 while (list_ptr) {
167 gint theme_priority;
168
169 theme_priority = ((CafeThemeCommonInfo *) list_ptr->data)->priority;
170
171 if (theme_priority == info->priority) {
172 /* Swap it in */
173 list_ptr->data = info;
174 added = TRUE(!(0));
175 break;
176 } else if (theme_priority > info->priority) {
177 list = g_list_insert_before (list, list_ptr, info);
178 added = TRUE(!(0));
179 break;
180 }
181 list_ptr = list_ptr->next;
182 }
183 if (!added)
184 list = g_list_append (list, info);
185 }
186 g_hash_table_insert (hash_table, g_strdup (info->name)g_strdup_inline (info->name), list);
187}
188
189static void
190remove_theme_from_hash_by_name (GHashTable *hash_table,
191 gpointer data)
192{
193 CafeThemeCommonInfo *info = data;
194 GList *list;
195
196 list = g_hash_table_lookup (hash_table, info->name);
197
198 list = g_list_remove (list, info);
199 if (list == NULL((void*)0))
200 g_hash_table_remove (hash_table, info->name);
201 else
202 g_hash_table_insert (hash_table, g_strdup (info->name)g_strdup_inline (info->name), list);
203}
204
205static CafeThemeCommonInfo *
206get_theme_from_hash_by_name (GHashTable *hash_table,
207 const gchar *name,
208 gint priority)
209{
210 GList *list;
211
212 list = g_hash_table_lookup (hash_table, name);
213
214 /* -1 implies return the first one */
215 if (priority == -1) {
216 return list ? list->data : NULL((void*)0);
217 }
218
219 while (list) {
220 CafeThemeCommonInfo *info = (CafeThemeCommonInfo *) list->data;
221
222 if (info->priority == priority)
223 return info;
224
225 list = list->next;
226 }
227 return NULL((void*)0);
228}
229
230static gint
231theme_compare (CafeThemeCommonInfo *a,
232 CafeThemeCommonInfo *b)
233{
234 gint cmp;
235
236 g_return_val_if_fail (a->type == b->type, a->type - b->type)do { if ((a->type == b->type)) { } else { g_return_if_fail_warning
("capplet-common", ((const char*) (__func__)), "a->type == b->type"
); return (a->type - b->type); } } while (0)
;
237
238 switch (a->type) {
239 case CAFE_THEME_TYPE_METATHEME:
240 cmp = cafe_theme_meta_info_compare (
241 (CafeThemeMetaInfo *) a, (CafeThemeMetaInfo *) b);
242 break;
243 case CAFE_THEME_TYPE_ICON:
244 cmp = cafe_theme_icon_info_compare (
245 (CafeThemeIconInfo *) a, (CafeThemeIconInfo *) b);
246 break;
247 case CAFE_THEME_TYPE_CURSOR:
248 cmp = cafe_theme_cursor_info_compare (
249 (CafeThemeCursorInfo *) a, (CafeThemeCursorInfo *) b);
250 break;
251 default:
252 /* not supported at this time */
253 g_assert_not_reached ()do { g_assertion_message_expr ("capplet-common", "cafe-theme-info.c"
, 253, ((const char*) (__func__)), ((void*)0)); } while (0)
;
254 }
255
256 return cmp;
257}
258
259static void
260theme_free (CafeThemeCommonInfo *info)
261{
262 switch (info->type) {
263 case CAFE_THEME_TYPE_METATHEME:
264 cafe_theme_meta_info_free ((CafeThemeMetaInfo *) info);
265 break;
266 case CAFE_THEME_TYPE_ICON:
267 cafe_theme_icon_info_free ((CafeThemeIconInfo *) info);
268 break;
269 case CAFE_THEME_TYPE_REGULAR:
270 cafe_theme_info_free ((CafeThemeInfo *) info);
271 break;
272 case CAFE_THEME_TYPE_CURSOR:
273 cafe_theme_cursor_info_free ((CafeThemeCursorInfo *) info);
274 break;
275 default:
276 g_assert_not_reached ()do { g_assertion_message_expr ("capplet-common", "cafe-theme-info.c"
, 276, ((const char*) (__func__)), ((void*)0)); } while (0)
;
277 }
278}
279
280GQuark cafe_theme_info_error_quark(void)
281{
282 return g_quark_from_static_string("cafe-theme-info-error-quark");
283}
284
285CafeThemeMetaInfo* cafe_theme_read_meta_theme(GFile* meta_theme_uri)
286{
287 CafeThemeMetaInfo* meta_theme_info;
288 GFile* common_theme_dir_uri;
289 CafeDesktopItem* meta_theme_ditem;
290 gchar* meta_theme_file;
291 const gchar* str;
292 gchar* scheme;
293
294 meta_theme_file = g_file_get_uri(meta_theme_uri);
295 meta_theme_ditem = cafe_desktop_item_new_from_uri(meta_theme_file, 0, NULL((void*)0));
296 g_free(meta_theme_file);
297
298 if (meta_theme_ditem == NULL((void*)0))
299 return NULL((void*)0);
300
301 common_theme_dir_uri = g_file_get_parent(meta_theme_uri);
302 meta_theme_info = cafe_theme_meta_info_new();
303 meta_theme_info->path = g_file_get_path(meta_theme_uri);
304 meta_theme_info->name = g_file_get_basename(common_theme_dir_uri);
305 g_object_unref(common_theme_dir_uri);
306
307 str = cafe_desktop_item_get_localestring(meta_theme_ditem, THEME_NAME"X-GNOME-Metatheme/Name");
308
309 if (!str)
310 {
311 str = cafe_desktop_item_get_localestring(meta_theme_ditem, CAFE_DESKTOP_ITEM_NAME"Name");
312 if (!str)
313 { /* shouldn't reach */
314 cafe_theme_meta_info_free(meta_theme_info);
315 return NULL((void*)0);
316 }
317 }
318
319 meta_theme_info->readable_name = g_strdup(str)g_strdup_inline (str);
320
321 str = cafe_desktop_item_get_localestring(meta_theme_ditem, THEME_COMMENT"X-GNOME-Metatheme/Comment");
322
323 if (str == NULL((void*)0))
324 str = cafe_desktop_item_get_localestring(meta_theme_ditem, CAFE_DESKTOP_ITEM_COMMENT"Comment");
325
326 if (str != NULL((void*)0))
327 meta_theme_info->comment = g_strdup(str)g_strdup_inline (str);
328
329 str = cafe_desktop_item_get_string(meta_theme_ditem, CAFE_DESKTOP_ITEM_ICON"Icon");
330
331 if (str != NULL((void*)0))
332 meta_theme_info->icon_file = g_strdup(str)g_strdup_inline (str);
333
334 str = cafe_desktop_item_get_string(meta_theme_ditem, CTK_THEME_KEY"X-GNOME-Metatheme/CtkTheme");
335
336 if (str == NULL((void*)0))
337 {
338 cafe_theme_meta_info_free(meta_theme_info);
339 return NULL((void*)0);
340 }
341 meta_theme_info->ctk_theme_name = g_strdup(str)g_strdup_inline (str);
342
343 str = cafe_desktop_item_get_string(meta_theme_ditem, CTK_COLOR_SCHEME_KEY"X-GNOME-Metatheme/CtkColorScheme");
344
345 if (str == NULL((void*)0) || str[0] == '\0')
346 scheme = ctkrc_get_color_scheme_for_theme(meta_theme_info->ctk_theme_name);
347 else
348 scheme = g_strdup(str)g_strdup_inline (str);
349
350 if (scheme != NULL((void*)0))
351 {
352 meta_theme_info->ctk_color_scheme = scheme;
353
354 for (; *scheme != '\0'; scheme++)
355 if (*scheme == ',')
356 *scheme = '\n';
357 }
358
359 str = cafe_desktop_item_get_string (meta_theme_ditem, CROMA_THEME_KEY"X-GNOME-Metatheme/MetacityTheme");
360
361 if (str == NULL((void*)0))
362 {
363 cafe_theme_meta_info_free (meta_theme_info);
364 return NULL((void*)0);
365 }
366
367 meta_theme_info->croma_theme_name = g_strdup (str)g_strdup_inline (str);
368
369 str = cafe_desktop_item_get_string(meta_theme_ditem, ICON_THEME_KEY"X-GNOME-Metatheme/IconTheme");
370
371 if (str == NULL((void*)0))
372 {
373 cafe_theme_meta_info_free(meta_theme_info);
374 return NULL((void*)0);
375 }
376
377 meta_theme_info->icon_theme_name = g_strdup(str)g_strdup_inline (str);
378
379 str = cafe_desktop_item_get_string(meta_theme_ditem, NOTIFICATION_THEME_KEY"X-GNOME-Metatheme/NotificationTheme");
380
381 if (str != NULL((void*)0))
382 meta_theme_info->notification_theme_name = g_strdup(str)g_strdup_inline (str);
383
384 str = cafe_desktop_item_get_string(meta_theme_ditem, CURSOR_THEME_KEY"X-GNOME-Metatheme/CursorTheme");
385
386 if (str != NULL((void*)0))
387 {
388 meta_theme_info->cursor_theme_name = g_strdup(str)g_strdup_inline (str);
389
390 str = cafe_desktop_item_get_string(meta_theme_ditem, CURSOR_SIZE_KEY"X-GNOME-Metatheme/CursorSize");
391
392 if (str)
393 meta_theme_info->cursor_size = (int) g_ascii_strtoll(str, NULL((void*)0), 10);
394 else
395 meta_theme_info->cursor_size = 24;
396 }
397 else
398 {
399 meta_theme_info->cursor_theme_name = g_strdup("default")g_strdup_inline ("default");
400 meta_theme_info->cursor_size = 24;
401 }
402
403 str = cafe_desktop_item_get_string(meta_theme_ditem, APPLICATION_FONT_KEY"X-GNOME-Metatheme/ApplicationFont");
404
405 if (str != NULL((void*)0))
406 meta_theme_info->application_font = g_strdup(str)g_strdup_inline (str);
407
408 str = cafe_desktop_item_get_string(meta_theme_ditem, DOCUMENTS_FONT_KEY"X-GNOME-Metatheme/DocumentsFont");
409
410 if (str != NULL((void*)0))
411 meta_theme_info->documents_font = g_strdup(str)g_strdup_inline (str);
412
413 str = cafe_desktop_item_get_string(meta_theme_ditem, DESKTOP_FONT_KEY"X-GNOME-Metatheme/DesktopFont");
414
415 if (str != NULL((void*)0))
416 meta_theme_info->desktop_font = g_strdup(str)g_strdup_inline (str);
417
418 str = cafe_desktop_item_get_string(meta_theme_ditem, WINDOWTITLE_FONT_KEY"X-GNOME-Metatheme/WindowTitleFont");
419
420 if (str != NULL((void*)0))
421 meta_theme_info->windowtitle_font = g_strdup(str)g_strdup_inline (str);
422
423 str = cafe_desktop_item_get_string(meta_theme_ditem, MONOSPACE_FONT_KEY"X-GNOME-Metatheme/MonospaceFont");
424
425 if (str != NULL((void*)0))
426 meta_theme_info->monospace_font = g_strdup(str)g_strdup_inline (str);
427
428 str = cafe_desktop_item_get_string(meta_theme_ditem, BACKGROUND_IMAGE_KEY"X-GNOME-Metatheme/BackgroundImage");
429
430 if (str != NULL((void*)0))
431 meta_theme_info->background_image = g_strdup(str)g_strdup_inline (str);
432
433 meta_theme_info->hidden = cafe_desktop_item_get_boolean(meta_theme_ditem, HIDDEN_KEY"X-GNOME-Metatheme/Hidden");
434
435 cafe_desktop_item_unref(meta_theme_ditem);
436
437 return meta_theme_info;
438}
439
440static CafeThemeIconInfo *
441read_icon_theme (GFile *icon_theme_uri)
442{
443 CafeThemeIconInfo *icon_theme_info;
444 CafeDesktopItem *icon_theme_ditem;
445 gchar *icon_theme_file;
446 gchar *dir_name;
447 const gchar *name;
448 const gchar *directories;
449
450 icon_theme_file = g_file_get_uri (icon_theme_uri);
451 icon_theme_ditem = cafe_desktop_item_new_from_uri (icon_theme_file, 0, NULL((void*)0));
452 g_free (icon_theme_file);
453
454 if (icon_theme_ditem == NULL((void*)0))
455 return NULL((void*)0);
456
457 name = cafe_desktop_item_get_localestring (icon_theme_ditem, "Icon Theme/Name");
458 if (!name) {
459 name = cafe_desktop_item_get_localestring (icon_theme_ditem, CAFE_DESKTOP_ITEM_NAME"Name");
460 if (!name) {
461 cafe_desktop_item_unref (icon_theme_ditem);
462 return NULL((void*)0);
463 }
464 }
465
466 /* If index.theme has no Directories entry, it is only a cursor theme */
467 directories = cafe_desktop_item_get_string (icon_theme_ditem, "Icon Theme/Directories");
468 if (directories == NULL((void*)0)) {
469 cafe_desktop_item_unref (icon_theme_ditem);
470 return NULL((void*)0);
471 }
472
473 icon_theme_info = cafe_theme_icon_info_new ();
474 icon_theme_info->readable_name = g_strdup (name)g_strdup_inline (name);
475 icon_theme_info->path = g_file_get_path (icon_theme_uri);
476 icon_theme_info->hidden = cafe_desktop_item_get_boolean (icon_theme_ditem, "Icon Theme/Hidden");
477 dir_name = g_path_get_dirname (icon_theme_info->path);
478 icon_theme_info->name = g_path_get_basename (dir_name);
479 g_free (dir_name);
480
481 cafe_desktop_item_unref (icon_theme_ditem);
482
483 return icon_theme_info;
484}
485
486static void
487add_default_cursor_theme ()
488{
489 CafeThemeCursorInfo *theme_info;
490
491 theme_info = cafe_theme_cursor_info_new ();
492 theme_info->path = g_strdup ("builtin")g_strdup_inline ("builtin");
493 theme_info->name = g_strdup ("default")g_strdup_inline ("default");
494 theme_info->readable_name = g_strdup (_("Default Pointer"))g_strdup_inline (gettext ("Default Pointer"));
495 theme_info->sizes = g_array_sized_new (FALSE(0), FALSE(0), sizeof (gint), 0);
496
497 g_hash_table_insert (cursor_theme_hash_by_uri, theme_info->path, theme_info);
498 add_theme_to_hash_by_name (cursor_theme_hash_by_name, theme_info);
499}
500
501static GdkPixbuf *
502gdk_pixbuf_from_xcursor_image (XcursorImage *cursor)
503{
504 GdkPixbuf *pixbuf;
505#define BUF_SIZEsizeof(guint32) * cursor->width * cursor->height sizeof(guint32) * cursor->width * cursor->height
506 guchar *buf = g_malloc0 (BUF_SIZEsizeof(guint32) * cursor->width * cursor->height);
507 guchar *it;
508
509 for (it = buf; it < (buf + BUF_SIZEsizeof(guint32) * cursor->width * cursor->height); it += 4) {
510#if G_BYTE_ORDER1234 == G_LITTLE_ENDIAN1234
511 /* on little endianess it's BGRA to RGBA */
512 it[0] = ((guchar *) (cursor->pixels))[it - buf + 2];
513 it[1] = ((guchar *) (cursor->pixels))[it - buf + 1];
514 it[2] = ((guchar *) (cursor->pixels))[it - buf + 0];
515 it[3] = ((guchar *) (cursor->pixels))[it - buf + 3];
516#else
517 /* on big endianess it's ARGB to RGBA */
518 it[0] = ((guchar *) cursor->pixels)[it - buf + 1];
519 it[1] = ((guchar *) cursor->pixels)[it - buf + 2];
520 it[2] = ((guchar *) cursor->pixels)[it - buf + 3];
521 it[3] = ((guchar *) cursor->pixels)[it - buf + 0];
522#endif
523 }
524
525 pixbuf = gdk_pixbuf_new_from_data ((const guchar *) buf,
526 GDK_COLORSPACE_RGB, TRUE(!(0)), 8,
527 cursor->width, cursor->height,
528 cursor->width * 4,
529 (GdkPixbufDestroyNotify) g_free,
530 NULL((void*)0));
531
532 if (!pixbuf)
533 g_free (buf);
534
535 return pixbuf;
536}
537
538static CafeThemeCursorInfo *
539read_cursor_theme (GFile *cursor_theme_uri)
540{
541 CafeThemeCursorInfo *cursor_theme_info = NULL((void*)0);
542 GFile *parent_uri, *cursors_uri;
543
544 const gint filter_sizes[] = { 12, 16, 18, 24, 32, 36, 40, 48, 64, 96, 128 };
545 const gint num_sizes = G_N_ELEMENTS (filter_sizes)(sizeof (filter_sizes) / sizeof ((filter_sizes)[0]));
546
547 parent_uri = g_file_get_parent (cursor_theme_uri);
548 cursors_uri = g_file_get_child (parent_uri, "cursors");
549
550 if (get_file_type (cursors_uri) == G_FILE_TYPE_DIRECTORY) {
551 GArray *sizes;
552 XcursorImage *cursor;
553 GdkPixbuf *thumbnail = NULL((void*)0);
554 gchar *name;
555 gint i;
556
557 name = g_file_get_basename (parent_uri);
558
559 sizes = g_array_sized_new (FALSE(0), FALSE(0), sizeof (gint), num_sizes);
560
561 for (i = 0; i < num_sizes; ++i) {
562 cursor = XcursorLibraryLoadImage ("left_ptr", name, filter_sizes[i]);
563
564 if (cursor) {
565 if (cursor->size == filter_sizes[i]) {
566 g_array_append_val (sizes, filter_sizes[i])g_array_append_vals (sizes, &(filter_sizes[i]), 1);
567
568 if (thumbnail == NULL((void*)0) && i >= 1)
569 thumbnail = gdk_pixbuf_from_xcursor_image (cursor);
570 }
571
572 XcursorImageDestroy (cursor);
573 }
574 }
575
576 if (sizes->len == 0) {
577 g_array_free (sizes, TRUE(!(0)));
578 g_free (name);
579 } else {
580 CafeDesktopItem *cursor_theme_ditem;
581 gchar *cursor_theme_file;
582
583 if (!thumbnail) {
584 cursor = XcursorLibraryLoadImage ("left_ptr", name,
585 g_array_index (sizes, gint, 0)(((gint*) (void *) (sizes)->data) [(0)]));
586 if (cursor) {
587 thumbnail = gdk_pixbuf_from_xcursor_image (cursor);
588 XcursorImageDestroy (cursor);
589 }
590 }
591
592 cursor_theme_info = cafe_theme_cursor_info_new ();
593 cursor_theme_info->path = g_file_get_path (parent_uri);
594 cursor_theme_info->name = name;
595 cursor_theme_info->sizes = sizes;
596 cursor_theme_info->thumbnail = thumbnail;
597
598 cursor_theme_file = g_file_get_path (cursor_theme_uri);
599 cursor_theme_ditem = cafe_desktop_item_new_from_file (cursor_theme_file, 0, NULL((void*)0));
600 g_free (cursor_theme_file);
601
602 if (cursor_theme_ditem != NULL((void*)0)) {
603 const gchar *readable_name;
604
605 readable_name = cafe_desktop_item_get_string (cursor_theme_ditem,
606 "Icon Theme/Name");
607 if (readable_name)
608 cursor_theme_info->readable_name = g_strdup (readable_name)g_strdup_inline (readable_name);
609 else
610 cursor_theme_info->readable_name = g_strdup (name)g_strdup_inline (name);
611
612 cursor_theme_info->hidden = cafe_desktop_item_get_boolean (cursor_theme_ditem,
613 "Icon Theme/Hidden");
614
615 cafe_desktop_item_unref (cursor_theme_ditem);
616 } else {
617 cursor_theme_info->readable_name = g_strdup (name)g_strdup_inline (name);
618 }
619 }
620 }
621
622 g_object_unref (cursors_uri);
623 g_object_unref (parent_uri);
624
625 return cursor_theme_info;
626}
627
628static void
629handle_change_signal (gpointer data,
630 CafeThemeChangeType change_type,
631 CafeThemeElement element_type)
632{
633#ifdef DEBUG
634 gchar *type_str = NULL((void*)0);
635 gchar *change_str = NULL((void*)0);
636 gchar *element_str = NULL((void*)0);
637#endif
638 CafeThemeCommonInfo *theme = data;
639 GList *list;
640
641 if (initting)
642 return;
643
644 for (list = callbacks; list; list = list->next) {
645 ThemeCallbackData *callback_data = list->data;
646 (* callback_data->func) (theme, change_type, element_type, callback_data->data);
647 }
648
649#ifdef DEBUG
650 if (theme->type == CAFE_THEME_TYPE_METATHEME)
651 type_str = "meta";
652 else if (theme->type == CAFE_THEME_TYPE_ICON)
653 type_str = "icon";
654 else if (theme->type == CAFE_THEME_TYPE_CURSOR)
655 type_str = "cursor";
656 else if (theme->type == CAFE_THEME_TYPE_REGULAR) {
657 if (element_type & CAFE_THEME_CTK_2)
658 element_str = "ctk-2";
659 else if (element_type & CAFE_THEME_CTK_2_KEYBINDING)
660 element_str = "keybinding";
661 else if (element_type & CAFE_THEME_CROMA)
662 element_str = "croma";
663 }
664
665 if (change_type == CAFE_THEME_CHANGE_CREATED)
666 change_str = "created";
667 else if (change_type == CAFE_THEME_CHANGE_CHANGED)
668 change_str = "changed";
669 else if (change_type == CAFE_THEME_CHANGE_DELETED)
670 change_str = "deleted";
671
672 if (type == CAFE_THEME_TYPE_REGULAR) {
673 g_print ("theme \"%s\" has a theme of type %s (priority %d) has been %s\n",
674 theme->name,
675 element_str,
676 theme->priority,
677 type_str);
678 } else if (type_str != NULL((void*)0)) {
679 g_print ("%s theme \"%s\" (priority %d) has been %s\n",
680 type_str,
681 theme->name,
682 theme->priority,
683 type_str);
684 }
685#endif
686}
687
688/* index_uri should point to the ctkrc file that was modified */
689static void
690update_theme_index (GFile *index_uri,
691 CafeThemeElement key_element,
692 gint priority)
693{
694 gboolean theme_exists;
695 CafeThemeInfo *theme_info;
696 GFile *parent;
697 GFile *common_theme_dir_uri;
698 gchar *common_theme_dir;
699
700 /* First, we determine the new state of the file. We do no more
701 * sophisticated a test than "files exists and is a file" */
702 theme_exists = (get_file_type (index_uri) == G_FILE_TYPE_REGULAR);
703
704 /* Next, we see what currently exists */
705 parent = g_file_get_parent (index_uri);
706 common_theme_dir_uri = g_file_get_parent (parent);
707 common_theme_dir = g_file_get_path (common_theme_dir_uri);
708
709 theme_info = g_hash_table_lookup (theme_hash_by_uri, common_theme_dir);
710 if (theme_info == NULL((void*)0)) {
711 if (theme_exists) {
712 theme_info = cafe_theme_info_new ();
713 theme_info->path = g_strdup (common_theme_dir)g_strdup_inline (common_theme_dir);
714 theme_info->name = g_file_get_basename (common_theme_dir_uri);
715 theme_info->readable_name = g_strdup (theme_info->name)g_strdup_inline (theme_info->name);
716 theme_info->priority = priority;
717 if (key_element & CAFE_THEME_CTK_2)
718 theme_info->has_ctk = TRUE(!(0));
719 else if (key_element & CAFE_THEME_CTK_2_KEYBINDING)
720 theme_info->has_keybinding = TRUE(!(0));
721 else if (key_element & CAFE_THEME_CROMA)
722 theme_info->has_croma = TRUE(!(0));
723
724 g_hash_table_insert (theme_hash_by_uri, g_strdup (common_theme_dir)g_strdup_inline (common_theme_dir), theme_info);
725 add_theme_to_hash_by_name (theme_hash_by_name, theme_info);
726 handle_change_signal (theme_info, CAFE_THEME_CHANGE_CREATED, key_element);
727 }
728 } else {
729 gboolean theme_used_to_exist = FALSE(0);
730
731 if (key_element & CAFE_THEME_CTK_2) {
732 theme_used_to_exist = theme_info->has_ctk;
733 theme_info->has_ctk = theme_exists;
734 } else if (key_element & CAFE_THEME_CTK_2_KEYBINDING) {
735 theme_used_to_exist = theme_info->has_keybinding;
736 theme_info->has_keybinding = theme_exists;
737 } else if (key_element & CAFE_THEME_CROMA) {
738 theme_used_to_exist = theme_info->has_croma;
739 theme_info->has_croma = theme_exists;
740 }
741
742 if (!theme_info->has_croma && !theme_info->has_keybinding && !theme_info->has_ctk) {
743 g_hash_table_remove (theme_hash_by_uri, common_theme_dir);
744 remove_theme_from_hash_by_name (theme_hash_by_name, theme_info);
745 }
746
747 if (theme_exists && theme_used_to_exist) {
748 handle_change_signal (theme_info, CAFE_THEME_CHANGE_CHANGED, key_element);
749 } else if (theme_exists && !theme_used_to_exist) {
750 handle_change_signal (theme_info, CAFE_THEME_CHANGE_CREATED, key_element);
751 } else if (!theme_exists && theme_used_to_exist) {
752 handle_change_signal (theme_info, CAFE_THEME_CHANGE_DELETED, key_element);
753 }
754
755 if (!theme_info->has_croma && !theme_info->has_keybinding && !theme_info->has_ctk) {
756 cafe_theme_info_free (theme_info);
757 }
758 }
759
760 g_free (common_theme_dir);
761 g_object_unref (parent);
762 g_object_unref (common_theme_dir_uri);
763}
764
765static void
766update_ctk2_index (GFile *ctk2_index_uri,
767 gint priority)
768{
769 update_theme_index (ctk2_index_uri, CAFE_THEME_CTK_2, priority);
770}
771
772static void
773update_keybinding_index (GFile *keybinding_index_uri,
774 gint priority)
775{
776 update_theme_index (keybinding_index_uri, CAFE_THEME_CTK_2_KEYBINDING, priority);
777}
778
779static void
780update_croma_index (GFile *croma_index_uri,
781 gint priority)
782{
783 update_theme_index (croma_index_uri, CAFE_THEME_CROMA, priority);
784}
785
786static void
787update_common_theme_dir_index (GFile *theme_index_uri,
788 CafeThemeType type,
789 gint priority)
790{
791 gboolean theme_exists;
792 CafeThemeCommonInfo *theme_info = NULL((void*)0);
793 CafeThemeCommonInfo *old_theme_info;
794 GFile *common_theme_dir_uri;
795 gchar *common_theme_dir;
796 GHashTable *hash_by_uri;
797 GHashTable *hash_by_name;
798
799 if (type == CAFE_THEME_TYPE_ICON) {
800 hash_by_uri = icon_theme_hash_by_uri;
801 hash_by_name = icon_theme_hash_by_name;
802 } else if (type == CAFE_THEME_TYPE_CURSOR) {
803 hash_by_uri = cursor_theme_hash_by_uri;
804 hash_by_name = cursor_theme_hash_by_name;
805 } else {
806 hash_by_uri = meta_theme_hash_by_uri;
807 hash_by_name = meta_theme_hash_by_name;
808 }
809
810 if (type != CAFE_THEME_TYPE_CURSOR) {
811 /* First, we determine the new state of the file. */
812 if (get_file_type (theme_index_uri) == G_FILE_TYPE_REGULAR) {
813 /* It's an interesting file. Let's try to load it. */
814 if (type == CAFE_THEME_TYPE_ICON)
815 theme_info = (CafeThemeCommonInfo *) read_icon_theme (theme_index_uri);
816 else
817 theme_info = (CafeThemeCommonInfo *) cafe_theme_read_meta_theme (theme_index_uri);
818 } else {
819 theme_info = NULL((void*)0);
820 }
821
822 }
823 /* cursor themes don't necessarily have an index file, so try those in any case */
824 else {
825 theme_info = (CafeThemeCommonInfo *) read_cursor_theme (theme_index_uri);
826 }
827
828 if (theme_info) {
829 theme_info->priority = priority;
830 theme_exists = TRUE(!(0));
831 } else {
832 theme_exists = FALSE(0);
833 }
834
835 /* Next, we see what currently exists */
836 common_theme_dir_uri = g_file_get_parent (theme_index_uri);
837 common_theme_dir = g_file_get_path (common_theme_dir_uri);
838 g_object_unref (common_theme_dir_uri);
839
840 old_theme_info = (CafeThemeCommonInfo *) g_hash_table_lookup (hash_by_uri, common_theme_dir);
841
842 if (old_theme_info == NULL((void*)0)) {
843 if (theme_exists) {
844 g_hash_table_insert (hash_by_uri, g_strdup (common_theme_dir)g_strdup_inline (common_theme_dir), theme_info);
845 add_theme_to_hash_by_name (hash_by_name, theme_info);
846 handle_change_signal (theme_info, CAFE_THEME_CHANGE_CREATED, 0);
847 }
848 } else {
849 if (theme_exists) {
850 if (theme_compare (theme_info, old_theme_info) != 0) {
851 /* Remove old theme */
852 g_hash_table_remove (hash_by_uri, common_theme_dir);
853 remove_theme_from_hash_by_name (hash_by_name, old_theme_info);
854 g_hash_table_insert (hash_by_uri, g_strdup (common_theme_dir)g_strdup_inline (common_theme_dir), theme_info);
855 add_theme_to_hash_by_name (hash_by_name, theme_info);
856 handle_change_signal (theme_info, CAFE_THEME_CHANGE_CHANGED, 0);
857 theme_free (old_theme_info);
858 } else {
859 theme_free (theme_info);
860 }
861 } else {
862 g_hash_table_remove (hash_by_uri, common_theme_dir);
863 remove_theme_from_hash_by_name (hash_by_name, old_theme_info);
864
865 handle_change_signal (old_theme_info, CAFE_THEME_CHANGE_DELETED, 0);
866 theme_free (old_theme_info);
867 }
868 }
869
870 g_free (common_theme_dir);
871}
872
873static void
874update_meta_theme_index (GFile *meta_theme_index_uri,
875 gint priority)
876{
877 update_common_theme_dir_index (meta_theme_index_uri, CAFE_THEME_TYPE_METATHEME, priority);
878}
879
880static void
881update_icon_theme_index (GFile *icon_theme_index_uri,
882 gint priority)
883{
884 update_common_theme_dir_index (icon_theme_index_uri, CAFE_THEME_TYPE_ICON, priority);
885}
886
887static void
888update_cursor_theme_index (GFile *cursor_theme_index_uri,
889 gint priority)
890{
891 update_common_theme_dir_index (cursor_theme_index_uri, CAFE_THEME_TYPE_CURSOR, priority);
892}
893
894static void
895ctk2_dir_changed (GFileMonitor *monitor,
896 GFile *file,
897 GFile *other_file,
898 GFileMonitorEvent event_type,
899 CommonThemeDirMonitorData *monitor_data)
900{
901 gchar *affected_file;
902
903 affected_file = g_file_get_basename (file);
904
905 /* The only file we care about is ctkrc */
906 if (!strcmp (affected_file, "ctkrc")) {
907 update_ctk2_index (file, monitor_data->priority);
908 }
909
910 g_free (affected_file);
911}
912
913static void
914keybinding_dir_changed (GFileMonitor *monitor,
915 GFile *file,
916 GFile *other_file,
917 GFileMonitorEvent event_type,
918 CommonThemeDirMonitorData *monitor_data)
919{
920 gchar *affected_file;
921
922 affected_file = g_file_get_basename (file);
923
924 /* The only file we care about is ctkrc */
925 if (!strcmp (affected_file, "ctkrc")) {
926 update_keybinding_index (file, monitor_data->priority);
927 }
928
929 g_free (affected_file);
930}
931
932static void
933croma_dir_changed (GFileMonitor *monitor,
934 GFile *file,
935 GFile *other_file,
936 GFileMonitorEvent event_type,
937 CommonThemeDirMonitorData *monitor_data)
938{
939 gchar *affected_file;
940
941 affected_file = g_file_get_basename (file);
942
943 /* The only file we care about is metacity-theme-(1|2).xml */
944 if (!strcmp (affected_file, "metacity-theme-1.xml") || !strcmp (affected_file, "metacity-theme-2.xml")) {
945 update_croma_index (file, monitor_data->priority);
946 }
947
948 g_free (affected_file);
949}
950
951static void
952common_theme_dir_changed (GFileMonitor *monitor,
953 GFile *file,
954 GFile *other_file,
955 GFileMonitorEvent event_type,
956 CommonThemeDirMonitorData *monitor_data)
957{
958 gchar *affected_file;
959
960 affected_file = g_file_get_basename (file);
961
962 /* The only file we care about is index.theme */
963 if (!strcmp (affected_file, "index.theme")) {
964 update_meta_theme_index (file, monitor_data->priority);
965 }
966
967 g_free (affected_file);
968}
969
970static void
971common_icon_theme_dir_changed (GFileMonitor *monitor,
972 GFile *file,
973 GFile *other_file,
974 GFileMonitorEvent event_type,
975 CommonIconThemeDirMonitorData *monitor_data)
976{
977 gchar *affected_file;
978
979 affected_file = g_file_get_basename (file);
980
981 /* The only file we care about is index.theme */
982 if (!strcmp (affected_file, "index.theme")) {
983 update_icon_theme_index (file, monitor_data->priority);
984 update_cursor_theme_index (file, monitor_data->priority);
985 }
986 /* and the cursors subdir for cursor themes */
987 else if (!strcmp (affected_file, "cursors")) {
988 /* always call update_cursor_theme_index with the index.theme URI */
989 GFile *parent, *index;
990
991 parent = g_file_get_parent (file);
992 index = g_file_get_child (parent, "index.theme");
993 g_object_unref (parent);
994
995 update_cursor_theme_index (index, monitor_data->priority);
996
997 g_object_unref (index);
998 }
999
1000 g_free (affected_file);
1001}
1002
1003/* Add a monitor to a common_theme_dir. */
1004static gboolean
1005add_common_theme_dir_monitor (GFile *theme_dir_uri,
1006 CommonThemeDirMonitorData *monitor_data,
1007 GError **error)
1008{
1009 GFile *uri, *subdir;
1010 GFileMonitor *monitor;
1011
1012 uri = g_file_get_child (theme_dir_uri, "index.theme");
1013 update_meta_theme_index (uri, monitor_data->priority);
1014 g_object_unref (uri);
1015
1016 /* Add the handle for this directory */
1017 monitor = g_file_monitor_file (theme_dir_uri, G_FILE_MONITOR_NONE, NULL((void*)0), NULL((void*)0));
1018 if (monitor == NULL((void*)0))
1019 return FALSE(0);
1020
1021 g_signal_connect (monitor, "changed",g_signal_connect_data ((monitor), ("changed"), ((GCallback) common_theme_dir_changed
), (monitor_data), ((void*)0), (GConnectFlags) 0)
1022 (GCallback) common_theme_dir_changed, monitor_data)g_signal_connect_data ((monitor), ("changed"), ((GCallback) common_theme_dir_changed
), (monitor_data), ((void*)0), (GConnectFlags) 0)
;
1023
1024 monitor_data->common_theme_dir_handle = monitor;
1025
1026
1027 /* ctk-2 theme subdir */
1028 subdir = g_file_get_child (theme_dir_uri, "ctk-2.0");
1029 uri = g_file_get_child (subdir, "ctkrc");
1030 if (g_file_query_exists (uri, NULL((void*)0))) {
1031 update_ctk2_index (uri, monitor_data->priority);
1032 }
1033 g_object_unref (uri);
1034
1035 monitor = g_file_monitor_directory (subdir, G_FILE_MONITOR_NONE, NULL((void*)0), NULL((void*)0));
1036 if (monitor != NULL((void*)0)) {
1037 g_signal_connect (monitor, "changed",g_signal_connect_data ((monitor), ("changed"), ((GCallback) ctk2_dir_changed
), (monitor_data), ((void*)0), (GConnectFlags) 0)
1038 (GCallback) ctk2_dir_changed, monitor_data)g_signal_connect_data ((monitor), ("changed"), ((GCallback) ctk2_dir_changed
), (monitor_data), ((void*)0), (GConnectFlags) 0)
;
1039 }
1040 monitor_data->ctk2_dir_handle = monitor;
1041 g_object_unref (subdir);
1042
1043 /* keybinding theme subdir */
1044 subdir = g_file_get_child (theme_dir_uri, "ctk-2.0-key");
1045 uri = g_file_get_child (subdir, "ctkrc");
1046 if (g_file_query_exists (uri, NULL((void*)0))) {
1047 update_keybinding_index (uri, monitor_data->priority);
1048 }
1049 g_object_unref (uri);
1050
1051 monitor = g_file_monitor_directory (subdir, G_FILE_MONITOR_NONE, NULL((void*)0), NULL((void*)0));
1052 if (monitor != NULL((void*)0)) {
1053 g_signal_connect (monitor, "changed",g_signal_connect_data ((monitor), ("changed"), ((GCallback) keybinding_dir_changed
), (monitor_data), ((void*)0), (GConnectFlags) 0)
1054 (GCallback) keybinding_dir_changed, monitor_data)g_signal_connect_data ((monitor), ("changed"), ((GCallback) keybinding_dir_changed
), (monitor_data), ((void*)0), (GConnectFlags) 0)
;
1055 }
1056 monitor_data->keybinding_dir_handle = monitor;
1057 g_object_unref (subdir);
1058
1059 /* croma theme subdir */
1060 subdir = g_file_get_child (theme_dir_uri, "metacity-1");
1061 uri = g_file_get_child (subdir, "metacity-theme-2.xml");
1062 if (g_file_query_exists (uri, NULL((void*)0))) {
1063 update_croma_index (uri, monitor_data->priority);
1064 }
1065 else {
1066 g_object_unref (uri);
1067 uri = g_file_get_child (subdir, "metacity-theme-1.xml");
1068 if (g_file_query_exists (uri, NULL((void*)0))) {
1069 update_croma_index (uri, monitor_data->priority);
1070 }
1071 }
1072 g_object_unref (uri);
1073
1074 monitor = g_file_monitor_directory (subdir, G_FILE_MONITOR_NONE, NULL((void*)0), NULL((void*)0));
1075 if (monitor != NULL((void*)0)) {
1076 g_signal_connect (monitor, "changed",g_signal_connect_data ((monitor), ("changed"), ((GCallback) croma_dir_changed
), (monitor_data), ((void*)0), (GConnectFlags) 0)
1077 (GCallback) croma_dir_changed, monitor_data)g_signal_connect_data ((monitor), ("changed"), ((GCallback) croma_dir_changed
), (monitor_data), ((void*)0), (GConnectFlags) 0)
;
1078 }
1079 monitor_data->croma_dir_handle = monitor;
1080 g_object_unref (subdir);
1081
1082 return TRUE(!(0));
1083}
1084
1085static gboolean
1086add_common_icon_theme_dir_monitor (GFile *theme_dir_uri,
1087 CommonIconThemeDirMonitorData *monitor_data,
1088 GError **error)
1089{
1090 GFile *index_uri;
1091 GFileMonitor *monitor;
1092
1093 /* Add the handle for this directory */
1094 index_uri = g_file_get_child (theme_dir_uri, "index.theme");
1095 update_icon_theme_index (index_uri, monitor_data->priority);
1096 update_cursor_theme_index (index_uri, monitor_data->priority);
1097 g_object_unref (index_uri);
1098
1099 monitor = g_file_monitor_file (theme_dir_uri, G_FILE_MONITOR_NONE, NULL((void*)0), NULL((void*)0));
1100 if (monitor == NULL((void*)0))
1101 return FALSE(0);
1102
1103 g_signal_connect (monitor, "changed",g_signal_connect_data ((monitor), ("changed"), ((GCallback) common_icon_theme_dir_changed
), (monitor_data), ((void*)0), (GConnectFlags) 0)
1104 (GCallback) common_icon_theme_dir_changed, monitor_data)g_signal_connect_data ((monitor), ("changed"), ((GCallback) common_icon_theme_dir_changed
), (monitor_data), ((void*)0), (GConnectFlags) 0)
;
1105
1106 monitor_data->common_icon_theme_dir_handle = monitor;
1107 return TRUE(!(0));
1108}
1109
1110static void
1111remove_common_theme_dir_monitor (CommonThemeDirMonitorData *monitor_data)
1112{
1113 g_file_monitor_cancel (monitor_data->common_theme_dir_handle);
1114 g_file_monitor_cancel (monitor_data->ctk2_dir_handle);
1115 g_file_monitor_cancel (monitor_data->keybinding_dir_handle);
1116 g_file_monitor_cancel (monitor_data->croma_dir_handle);
1117}
1118
1119static void
1120remove_common_icon_theme_dir_monitor (CommonIconThemeDirMonitorData *monitor_data)
1121{
1122 g_file_monitor_cancel (monitor_data->common_icon_theme_dir_handle);
1123}
1124
1125static void
1126top_theme_dir_changed (GFileMonitor *monitor,
1127 GFile *file,
1128 GFile *other_file,
1129 GFileMonitorEvent event_type,
1130 CallbackTuple *tuple)
1131{
1132 GHashTable *handle_hash;
1133 CommonThemeDirMonitorData *monitor_data;
1134 gint priority;
1135
1136 handle_hash = tuple->handle_hash;
1137 priority = tuple->priority;
1138
1139 if (event_type == G_FILE_MONITOR_EVENT_CREATED) {
1140 if (get_file_type (file) == G_FILE_TYPE_DIRECTORY) {
1141 monitor_data = g_new0 (CommonThemeDirMonitorData, 1)((CommonThemeDirMonitorData *) g_malloc0_n ((1), sizeof (CommonThemeDirMonitorData
)))
;
1142 monitor_data->priority = priority;
1143 add_common_theme_dir_monitor (file, monitor_data, NULL((void*)0));
1144 g_hash_table_insert (handle_hash, g_file_get_basename (file), monitor_data);
1145 }
1146
1147 } else if (event_type == G_FILE_MONITOR_EVENT_DELETED) {
1148 gchar *name;
1149
1150 name = g_file_get_basename (file);
1151 monitor_data = g_hash_table_lookup (handle_hash, name);
1152 if (monitor_data != NULL((void*)0)) {
1153 remove_common_theme_dir_monitor (monitor_data);
1154 g_hash_table_remove (handle_hash, name);
1155 }
1156 g_free (name);
1157 }
1158}
1159
1160static void
1161top_icon_theme_dir_changed (GFileMonitor *monitor,
1162 GFile *file,
1163 GFile *other_file,
1164 GFileMonitorEvent event_type,
1165 CallbackTuple *tuple)
1166{
1167 GHashTable *handle_hash;
1168 CommonIconThemeDirMonitorData *monitor_data;
1169 gint priority;
1170
1171 handle_hash = tuple->handle_hash;
1172 priority = tuple->priority;
1173
1174 if (event_type == G_FILE_MONITOR_EVENT_CREATED) {
1175 if (get_file_type (file) == G_FILE_TYPE_DIRECTORY) {
1176 monitor_data = g_new0 (CommonIconThemeDirMonitorData, 1)((CommonIconThemeDirMonitorData *) g_malloc0_n ((1), sizeof (
CommonIconThemeDirMonitorData)))
;
1177 monitor_data->priority = priority;
1178 add_common_icon_theme_dir_monitor (file, monitor_data, NULL((void*)0));
1179 g_hash_table_insert (handle_hash, g_file_get_basename (file), monitor_data);
1180 }
1181
1182 } else if (event_type == G_FILE_MONITOR_EVENT_DELETED) {
1183 gchar *name;
1184
1185 name = g_file_get_basename (file);
1186 monitor_data = g_hash_table_lookup (handle_hash, name);
1187 if (monitor_data != NULL((void*)0)) {
1188 remove_common_icon_theme_dir_monitor (monitor_data);
1189 g_hash_table_remove (handle_hash, name);
1190 }
1191 g_free (name);
1192 }
1193}
1194
1195/* Add a monitor to a top dir. These monitors persist for the duration of the
1196 * lib.
1197 */
1198static gboolean
1199real_add_top_theme_dir_monitor (GFile *uri,
1200 gint priority,
1201 gboolean icon_theme,
1202 GError **error)
1203{
1204 GFileInfo *file_info;
1205 GFileMonitor *monitor;
1206 GFileEnumerator *enumerator;
1207 CallbackTuple *tuple;
1208
1209 /* Check the URI */
1210 if (get_file_type (uri) != G_FILE_TYPE_DIRECTORY)
8
Assuming the condition is false
9
Taking false branch
1211 return FALSE(0);
1212
1213 /* handle_hash is a hash of common_theme_dir names to their monitor_data. We
1214 * use it to remove the monitor handles when a dir is removed.
1215 */
1216 tuple = g_new (CallbackTuple, 1)((CallbackTuple *) g_malloc_n ((1), sizeof (CallbackTuple)));
10
Memory is allocated
1217 tuple->handle_hash = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_free);
1218 tuple->priority = priority;
1219
1220 /* Monitor the top directory */
1221 monitor = g_file_monitor_directory (uri, G_FILE_MONITOR_NONE, NULL((void*)0), NULL((void*)0));
1222 if (monitor != NULL((void*)0)) {
11
Assuming 'monitor' is equal to NULL
12
Taking false branch
1223 g_signal_connect (monitor, "changed",g_signal_connect_data ((monitor), ("changed"), ((GCallback) (
icon_theme ? top_icon_theme_dir_changed : top_theme_dir_changed
)), (tuple), ((void*)0), (GConnectFlags) 0)
1224 (GCallback) (icon_theme ? top_icon_theme_dir_changed : top_theme_dir_changed),g_signal_connect_data ((monitor), ("changed"), ((GCallback) (
icon_theme ? top_icon_theme_dir_changed : top_theme_dir_changed
)), (tuple), ((void*)0), (GConnectFlags) 0)
1225 tuple)g_signal_connect_data ((monitor), ("changed"), ((GCallback) (
icon_theme ? top_icon_theme_dir_changed : top_theme_dir_changed
)), (tuple), ((void*)0), (GConnectFlags) 0)
;
1226 }
1227
1228 /* Go through the directory to add monitoring */
1229 enumerator = g_file_enumerate_children (uri,
1230 G_FILE_ATTRIBUTE_STANDARD_TYPE"standard::type" ","
1231 G_FILE_ATTRIBUTE_STANDARD_NAME"standard::name",
1232 G_FILE_QUERY_INFO_NONE,
1233 NULL((void*)0), NULL((void*)0));
1234 if (enumerator == NULL((void*)0))
13
Assuming 'enumerator' is equal to NULL
14
Taking true branch
1235 return FALSE(0);
15
Potential leak of memory pointed to by 'tuple'
1236
1237 while ((file_info = g_file_enumerator_next_file (enumerator, NULL((void*)0), NULL((void*)0)))) {
1238 GFileType type = g_file_info_get_file_type (file_info);
1239
1240 if (type == G_FILE_TYPE_DIRECTORY || type == G_FILE_TYPE_SYMBOLIC_LINK) {
1241 GFile *child;
1242 const gchar *name;
1243 gpointer data;
1244
1245 /* Add the directory */
1246 name = g_file_info_get_name (file_info);
1247 child = g_file_get_child (uri, name);
1248
1249 if (icon_theme) {
1250 CommonIconThemeDirMonitorData *monitor_data;
1251 monitor_data = g_new0 (CommonIconThemeDirMonitorData, 1)((CommonIconThemeDirMonitorData *) g_malloc0_n ((1), sizeof (
CommonIconThemeDirMonitorData)))
;
1252 monitor_data->priority = priority;
1253 add_common_icon_theme_dir_monitor (child, monitor_data, error);
1254 data = monitor_data;
1255 } else {
1256 CommonThemeDirMonitorData *monitor_data;
1257 monitor_data = g_new0 (CommonThemeDirMonitorData, 1)((CommonThemeDirMonitorData *) g_malloc0_n ((1), sizeof (CommonThemeDirMonitorData
)))
;
1258 monitor_data->priority = priority;
1259 add_common_theme_dir_monitor (child, monitor_data, error);
1260 data = monitor_data;
1261 }
1262 g_object_unref (child);
1263
1264 g_hash_table_insert (tuple->handle_hash, g_strdup (name)g_strdup_inline (name), data);
1265 }
1266 g_object_unref (file_info);
1267 }
1268 g_file_enumerator_close (enumerator, NULL((void*)0), NULL((void*)0));
1269
1270 return TRUE(!(0));
1271}
1272
1273static gboolean
1274add_top_theme_dir_monitor (GFile *uri,
1275 gint priority,
1276 GError **error)
1277{
1278 return real_add_top_theme_dir_monitor (uri, priority, FALSE(0), error);
7
Calling 'real_add_top_theme_dir_monitor'
1279}
1280
1281static gboolean
1282add_top_icon_theme_dir_monitor (GFile *uri,
1283 gint priority,
1284 GError **error)
1285{
1286 return real_add_top_theme_dir_monitor (uri, priority, TRUE(!(0)), error);
1287}
1288
1289/* Public functions */
1290
1291/* CTK/Croma/keybinding Themes */
1292CafeThemeInfo *
1293cafe_theme_info_new (void)
1294{
1295 CafeThemeInfo *theme_info;
1296
1297 theme_info = g_new0 (CafeThemeInfo, 1)((CafeThemeInfo *) g_malloc0_n ((1), sizeof (CafeThemeInfo)));
1298 theme_info->type = CAFE_THEME_TYPE_REGULAR;
1299
1300 return theme_info;
1301}
1302
1303void
1304cafe_theme_info_free (CafeThemeInfo *theme_info)
1305{
1306 g_free (theme_info->path);
1307 g_free (theme_info->name);
1308 g_free (theme_info->readable_name);
1309 g_free (theme_info);
1310}
1311
1312CafeThemeInfo *
1313cafe_theme_info_find (const gchar *theme_name)
1314{
1315 return (CafeThemeInfo *)
1316 get_theme_from_hash_by_name (theme_hash_by_name, theme_name, -1);
1317}
1318
1319struct CafeThemeInfoHashData
1320{
1321 gconstpointer user_data;
1322 GList *list;
1323};
1324
1325static void
1326cafe_theme_info_find_by_type_helper (gpointer key,
1327 GList *list,
1328 struct CafeThemeInfoHashData *hash_data)
1329{
1330 guint elements = GPOINTER_TO_INT (hash_data->user_data)((gint) (glong) (hash_data->user_data));
1331
1332 do {
1333 CafeThemeInfo *theme_info = list->data;
1334
1335 if ((elements & CAFE_THEME_CROMA && theme_info->has_croma) ||
1336 (elements & CAFE_THEME_CTK_2 && theme_info->has_ctk) ||
1337 (elements & CAFE_THEME_CTK_2_KEYBINDING && theme_info->has_keybinding)) {
1338 hash_data->list = g_list_prepend (hash_data->list, theme_info);
1339 return;
1340 }
1341
1342 list = list->next;
1343 } while (list);
1344}
1345
1346GList *
1347cafe_theme_info_find_by_type (guint elements)
1348{
1349 struct CafeThemeInfoHashData data;
1350 data.user_data = GINT_TO_POINTER (elements)((gpointer) (glong) (elements));
1351 data.list = NULL((void*)0);
1352
1353 g_hash_table_foreach (theme_hash_by_name,
1354 (GHFunc) cafe_theme_info_find_by_type_helper,
1355 &data);
1356
1357 return data.list;
1358}
1359
1360static void cafe_theme_info_find_all_helper(const gchar* key, GList* list, GList** themes)
1361{
1362 /* only return visible themes */
1363 if (!((CafeThemeCommonInfo*) list->data)->hidden)
1364 {
1365 *themes = g_list_prepend(*themes, list->data);
1366 }
1367}
1368
1369gchar* ctk_theme_info_missing_engine(const gchar* ctk_theme, gboolean name_only)
1370{
1371 gchar* engine = NULL((void*)0);
1372 gchar* ctkrc;
1373
1374 ctkrc = ctkrc_find_named(ctk_theme);
1375
1376 if (ctkrc)
1377 {
1378 GSList* engines = NULL((void*)0);
1379 GSList* l;
1380
1381 ctkrc_get_details(ctkrc, &engines, NULL((void*)0));
1382
1383 g_free(ctkrc);
1384
1385 for (l = engines; l; l = l->next)
1386 {
1387 /* This code do not work on distros with more of one ctk theme
1388 * engine path. Like debian. But yes on others like Archlinux.
1389 * Example, debian use:
1390 * /usr/lib/i386-linux-gnu/2.10.0/engines/
1391 * and /usr/lib/2.10.0/engines/
1392 *
1393 * some links
1394 * http://forums.linuxmint.com/viewtopic.php?f=190&t=85015
1395 */
1396 gchar* full = g_module_build_path(CTK_ENGINE_DIR"/usr/lib/x86_64-linux-gnu/ctk-3.0/3.0.0/theming-engines", l->data);
1397
1398 gboolean found = g_file_test(full, G_FILE_TEST_EXISTS);
1399
1400 if (!found)
1401 {
1402 if (name_only)
1403 {
1404 engine = g_strdup(l->data)g_strdup_inline (l->data);
1405 g_free(full);
1406 }
1407 else
1408 {
1409 engine = full;
1410 }
1411
1412 break;
1413 }
1414
1415 g_free(full);
1416 }
1417
1418 g_slist_foreach(engines, (GFunc) g_free, NULL((void*)0));
1419 g_slist_free(engines);
1420 }
1421
1422 return engine;
1423}
1424
1425/* Icon themes */
1426CafeThemeIconInfo *
1427cafe_theme_icon_info_new (void)
1428{
1429 CafeThemeIconInfo *icon_theme_info;
1430
1431 icon_theme_info = g_new0 (CafeThemeIconInfo, 1)((CafeThemeIconInfo *) g_malloc0_n ((1), sizeof (CafeThemeIconInfo
)))
;
1432 icon_theme_info->type = CAFE_THEME_TYPE_ICON;
1433
1434 return icon_theme_info;
1435}
1436
1437void
1438cafe_theme_icon_info_free (CafeThemeIconInfo *icon_theme_info)
1439{
1440 g_free (icon_theme_info->name);
1441 g_free (icon_theme_info->readable_name);
1442 g_free (icon_theme_info->path);
1443 g_free (icon_theme_info);
1444}
1445
1446CafeThemeIconInfo *
1447cafe_theme_icon_info_find (const gchar *icon_theme_name)
1448{
1449 g_return_val_if_fail (icon_theme_name != NULL, NULL)do { if ((icon_theme_name != ((void*)0))) { } else { g_return_if_fail_warning
("capplet-common", ((const char*) (__func__)), "icon_theme_name != NULL"
); return (((void*)0)); } } while (0)
;
1450
1451 return (CafeThemeIconInfo *)
1452 get_theme_from_hash_by_name (icon_theme_hash_by_name, icon_theme_name, -1);
1453}
1454
1455GList *
1456cafe_theme_icon_info_find_all (void)
1457{
1458 GList *list = NULL((void*)0);
1459
1460 g_hash_table_foreach (icon_theme_hash_by_name,
1461 (GHFunc) cafe_theme_info_find_all_helper,
1462 &list);
1463
1464 return list;
1465}
1466
1467gint
1468cafe_theme_icon_info_compare (CafeThemeIconInfo *a,
1469 CafeThemeIconInfo *b)
1470{
1471 gint cmp;
1472
1473 cmp = safe_strcmp (a->path, b->path);
1474 if (cmp != 0) return cmp;
1475
1476 return safe_strcmp (a->name, b->name);
1477}
1478
1479/* Cursor themes */
1480CafeThemeCursorInfo *
1481cafe_theme_cursor_info_new (void)
1482{
1483 CafeThemeCursorInfo *theme_info;
1484
1485 theme_info = g_new0 (CafeThemeCursorInfo, 1)((CafeThemeCursorInfo *) g_malloc0_n ((1), sizeof (CafeThemeCursorInfo
)))
;
1486 theme_info->type = CAFE_THEME_TYPE_CURSOR;
1487
1488 return theme_info;
1489}
1490
1491void
1492cafe_theme_cursor_info_free (CafeThemeCursorInfo *cursor_theme_info)
1493{
1494 g_free (cursor_theme_info->name);
1495 g_free (cursor_theme_info->readable_name);
1496 g_free (cursor_theme_info->path);
1497 g_array_free (cursor_theme_info->sizes, TRUE(!(0)));
1498 if (cursor_theme_info->thumbnail != NULL((void*)0))
1499 g_object_unref (cursor_theme_info->thumbnail);
1500 g_free (cursor_theme_info);
1501}
1502
1503CafeThemeCursorInfo *
1504cafe_theme_cursor_info_find (const gchar *cursor_theme_name)
1505{
1506 g_return_val_if_fail (cursor_theme_name != NULL, NULL)do { if ((cursor_theme_name != ((void*)0))) { } else { g_return_if_fail_warning
("capplet-common", ((const char*) (__func__)), "cursor_theme_name != NULL"
); return (((void*)0)); } } while (0)
;
1507
1508 return (CafeThemeCursorInfo *)
1509 get_theme_from_hash_by_name (cursor_theme_hash_by_name, cursor_theme_name, -1);
1510}
1511
1512GList *
1513cafe_theme_cursor_info_find_all (void)
1514{
1515 GList *list = NULL((void*)0);
1516
1517 g_hash_table_foreach (cursor_theme_hash_by_name,
1518 (GHFunc) cafe_theme_info_find_all_helper,
1519 &list);
1520
1521 return list;
1522}
1523
1524gint
1525cafe_theme_cursor_info_compare (CafeThemeCursorInfo *a,
1526 CafeThemeCursorInfo *b)
1527{
1528 gint cmp;
1529
1530 cmp = safe_strcmp (a->path, b->path);
1531 if (cmp != 0) return cmp;
1532
1533 return safe_strcmp (a->name, b->name);
1534}
1535
1536/* Meta themes */
1537CafeThemeMetaInfo* cafe_theme_meta_info_new(void)
1538{
1539 CafeThemeMetaInfo* theme_info;
1540
1541 theme_info = g_new0(CafeThemeMetaInfo, 1)((CafeThemeMetaInfo *) g_malloc0_n ((1), sizeof (CafeThemeMetaInfo
)))
;
1542 theme_info->type = CAFE_THEME_TYPE_METATHEME;
1543
1544 return theme_info;
1545}
1546
1547void cafe_theme_meta_info_free(CafeThemeMetaInfo* meta_theme_info)
1548{
1549 g_free (meta_theme_info->application_font);
1550 g_free (meta_theme_info->background_image);
1551 g_free (meta_theme_info->comment);
1552 g_free (meta_theme_info->cursor_theme_name);
1553 g_free (meta_theme_info->desktop_font);
1554 g_free (meta_theme_info->documents_font);
1555 g_free (meta_theme_info->ctk_color_scheme);
1556 g_free (meta_theme_info->ctk_theme_name);
1557 g_free (meta_theme_info->icon_file);
1558 g_free (meta_theme_info->icon_theme_name);
1559 g_free (meta_theme_info->croma_theme_name);
1560 g_free (meta_theme_info->monospace_font);
1561 g_free (meta_theme_info->name);
1562 g_free (meta_theme_info->notification_theme_name);
1563 g_free (meta_theme_info->path);
1564 g_free (meta_theme_info->sound_theme_name);
1565 g_free (meta_theme_info->windowtitle_font);
1566 g_free (meta_theme_info);
1567}
1568
1569gboolean cafe_theme_meta_info_validate(const CafeThemeMetaInfo* info, GError** error)
1570{
1571 CafeThemeInfo* theme;
1572
1573 g_return_val_if_fail (error == NULL || *error == NULL, FALSE)do { if ((error == ((void*)0) || *error == ((void*)0))) { } else
{ g_return_if_fail_warning ("capplet-common", ((const char*)
(__func__)), "error == NULL || *error == NULL"); return ((0)
); } } while (0)
;
1574
1575 theme = cafe_theme_info_find (info->ctk_theme_name);
1576
1577 if (!theme || !theme->has_ctk)
1578 {
1579 g_set_error (error, CAFE_THEME_ERRORcafe_theme_info_error_quark(), CAFE_THEME_ERROR_CTK_THEME_NOT_AVAILABLE,
1580 _("This theme will not look as intended because the required CTK+ theme '%s' is not installed.")gettext ("This theme will not look as intended because the required CTK+ theme '%s' is not installed."
)
,
1581 info->ctk_theme_name);
1582 return FALSE(0);
1583 }
1584
1585 theme = cafe_theme_info_find (info->croma_theme_name);
1586
1587 if (!theme || !theme->has_croma)
1588 {
1589 g_set_error (error, CAFE_THEME_ERRORcafe_theme_info_error_quark(), CAFE_THEME_ERROR_WM_THEME_NOT_AVAILABLE,
1590 _("This theme will not look as intended because the required window manager theme '%s' is not installed.")gettext ("This theme will not look as intended because the required window manager theme '%s' is not installed."
)
,
1591 info->croma_theme_name);
1592 return FALSE(0);
1593 }
1594
1595 if (!cafe_theme_icon_info_find (info->icon_theme_name))
1596 {
1597 g_set_error (error, CAFE_THEME_ERRORcafe_theme_info_error_quark(), CAFE_THEME_ERROR_ICON_THEME_NOT_AVAILABLE,
1598 _("This theme will not look as intended because the required icon theme '%s' is not installed.")gettext ("This theme will not look as intended because the required icon theme '%s' is not installed."
)
,
1599 info->icon_theme_name);
1600 return FALSE(0);
1601 }
1602
1603 return TRUE(!(0));
1604}
1605
1606CafeThemeMetaInfo* cafe_theme_meta_info_find(const char* meta_theme_name)
1607{
1608 g_return_val_if_fail(meta_theme_name != NULL, NULL)do { if ((meta_theme_name != ((void*)0))) { } else { g_return_if_fail_warning
("capplet-common", ((const char*) (__func__)), "meta_theme_name != NULL"
); return (((void*)0)); } } while (0)
;
1609
1610 return (CafeThemeMetaInfo*) get_theme_from_hash_by_name (meta_theme_hash_by_name, meta_theme_name, -1);
1611}
1612
1613GList* cafe_theme_meta_info_find_all(void)
1614{
1615 GList* list = NULL((void*)0);
1616
1617 g_hash_table_foreach (meta_theme_hash_by_name, (GHFunc) cafe_theme_info_find_all_helper, &list);
1618
1619 return list;
1620}
1621
1622gint
1623cafe_theme_meta_info_compare (CafeThemeMetaInfo *a,
1624 CafeThemeMetaInfo *b)
1625{
1626 gint cmp;
1627
1628 cmp = safe_strcmp (a->path, b->path);
1629 if (cmp != 0) return cmp;
1630
1631 cmp = safe_strcmp (a->readable_name, b->readable_name);
1632 if (cmp != 0) return cmp;
1633
1634 cmp = safe_strcmp (a->name, b->name);
1635 if (cmp != 0) return cmp;
1636
1637 cmp = safe_strcmp (a->comment, b->comment);
1638 if (cmp != 0) return cmp;
1639
1640 cmp = safe_strcmp (a->icon_file, b->icon_file);
1641 if (cmp != 0) return cmp;
1642
1643 cmp = safe_strcmp (a->ctk_theme_name, b->ctk_theme_name);
1644 if (cmp != 0) return cmp;
1645
1646 cmp = safe_strcmp (a->ctk_color_scheme, b->ctk_color_scheme);
1647 if (cmp != 0) return cmp;
1648
1649 cmp = safe_strcmp (a->croma_theme_name, b->croma_theme_name);
1650 if (cmp != 0) return cmp;
1651
1652 cmp = safe_strcmp (a->icon_theme_name, b->icon_theme_name);
1653 if (cmp != 0) return cmp;
1654
1655 cmp = safe_strcmp (a->notification_theme_name, b->notification_theme_name);
1656 if (cmp != 0) return cmp;
1657
1658 cmp = safe_strcmp (a->sound_theme_name, b->sound_theme_name);
1659 if (cmp != 0) return cmp;
1660
1661 cmp = safe_strcmp (a->application_font, b->application_font);
1662 if (cmp != 0) return cmp;
1663
1664 cmp = safe_strcmp (a->documents_font, b->documents_font);
1665 if (cmp != 0) return cmp;
1666
1667 cmp = safe_strcmp (a->desktop_font, b->desktop_font);
1668 if (cmp != 0) return cmp;
1669
1670 cmp = safe_strcmp (a->windowtitle_font, b->windowtitle_font);
1671 if (cmp != 0) return cmp;
1672
1673 cmp = safe_strcmp (a->monospace_font, b->monospace_font);
1674 if (cmp != 0) return cmp;
1675
1676 return safe_strcmp (a->background_image, b->background_image);
1677}
1678
1679void
1680cafe_theme_info_register_theme_change (ThemeChangedCallback func,
1681 gpointer data)
1682{
1683 ThemeCallbackData *callback_data;
1684
1685 g_return_if_fail (func != NULL)do { if ((func != ((void*)0))) { } else { g_return_if_fail_warning
("capplet-common", ((const char*) (__func__)), "func != NULL"
); return; } } while (0)
;
1686
1687 callback_data = g_new (ThemeCallbackData, 1)((ThemeCallbackData *) g_malloc_n ((1), sizeof (ThemeCallbackData
)))
;
1688 callback_data->func = func;
1689 callback_data->data = data;
1690
1691 callbacks = g_list_prepend (callbacks, callback_data);
1692}
1693
1694gboolean
1695cafe_theme_color_scheme_parse (const gchar *scheme, CdkRGBA *colors)
1696{
1697 gchar **color_scheme_strings, **color_scheme_pair, *current_string;
1698 gint i;
1699
1700 if (!scheme || !strcmp (scheme, ""))
1701 return FALSE(0);
1702
1703 /* initialise the array */
1704 for (i = 0; i < NUM_SYMBOLIC_COLORS; i++)
1705 colors[i].red = colors[i].green = colors[i].blue = 0;
1706
1707 /* The color scheme string consists of name:color pairs, separated by
1708 * newlines, so first we split the string up by new line */
1709
1710 color_scheme_strings = g_strsplit (scheme, "\n", 0);
1711
1712 /* loop through the name:color pairs, and save the color if we recognise the name */
1713 i = 0;
1714 while ((current_string = color_scheme_strings[i++])) {
1715 color_scheme_pair = g_strsplit (current_string, ":", 0);
1716
1717 if (color_scheme_pair[0] != NULL((void*)0) && color_scheme_pair[1] != NULL((void*)0)) {
1718 g_strstrip (color_scheme_pair[0])g_strchomp (g_strchug (color_scheme_pair[0]));
1719 g_strstrip (color_scheme_pair[1])g_strchomp (g_strchug (color_scheme_pair[1]));
1720
1721 if (!strcmp ("fg_color", color_scheme_pair[0]))
1722 cdk_rgba_parse (&colors[COLOR_FG], color_scheme_pair[1]);
1723 else if (!strcmp ("bg_color", color_scheme_pair[0]))
1724 cdk_rgba_parse (&colors[COLOR_BG], color_scheme_pair[1]);
1725 else if (!strcmp ("text_color", color_scheme_pair[0]))
1726 cdk_rgba_parse (&colors[COLOR_TEXT], color_scheme_pair[1]);
1727 else if (!strcmp ("base_color", color_scheme_pair[0]))
1728 cdk_rgba_parse (&colors[COLOR_BASE], color_scheme_pair[1]);
1729 else if (!strcmp ("selected_fg_color", color_scheme_pair[0]))
1730 cdk_rgba_parse (&colors[COLOR_SELECTED_FG], color_scheme_pair[1]);
1731 else if (!strcmp ("selected_bg_color", color_scheme_pair[0]))
1732 cdk_rgba_parse ( &colors[COLOR_SELECTED_BG], color_scheme_pair[1]);
1733 else if (!strcmp ("tooltip_fg_color", color_scheme_pair[0]))
1734 cdk_rgba_parse (&colors[COLOR_TOOLTIP_FG], color_scheme_pair[1]);
1735 else if (!strcmp ("tooltip_bg_color", color_scheme_pair[0]))
1736 cdk_rgba_parse (&colors[COLOR_TOOLTIP_BG], color_scheme_pair[1]);
1737 }
1738
1739 g_strfreev (color_scheme_pair);
1740 }
1741
1742 g_strfreev (color_scheme_strings);
1743
1744 return TRUE(!(0));
1745}
1746
1747gboolean
1748cafe_theme_color_scheme_equal (const gchar *s1, const gchar *s2)
1749{
1750 CdkRGBA c1[NUM_SYMBOLIC_COLORS], c2[NUM_SYMBOLIC_COLORS];
1751 int i;
1752
1753 if (!cafe_theme_color_scheme_parse (s1, c1) ||
1754 !cafe_theme_color_scheme_parse (s2, c2))
1755 return FALSE(0);
1756
1757 for (i = 0; i < NUM_SYMBOLIC_COLORS; ++i) {
1758 if (!cdk_rgba_equal (&c1[i], &c2[i]))
1759 return FALSE(0);
1760 }
1761
1762 return TRUE(!(0));
1763}
1764
1765void
1766cafe_theme_init ()
1767{
1768 const gchar * const * dirs;
1769 GFile *top_theme_dir;
1770 gchar *top_theme_dir_string;
1771 static gboolean initted = FALSE(0);
1772 gchar **search_path;
1773 gint i, n;
1774
1775 if (initted
0.1
'initted' is 0
)
1
Taking false branch
1776 return;
1777
1778 initting = TRUE(!(0));
1779
1780 meta_theme_hash_by_uri = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL((void*)0));
1781 meta_theme_hash_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL((void*)0));
1782 icon_theme_hash_by_uri = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL((void*)0));
1783 icon_theme_hash_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL((void*)0));
1784 cursor_theme_hash_by_uri = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL((void*)0));
1785 cursor_theme_hash_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL((void*)0));
1786 theme_hash_by_uri = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL((void*)0));
1787 theme_hash_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL((void*)0));
1788
1789 /* Add all the toplevel theme dirs following the XDG Base Directory Specification */
1790 dirs = g_get_system_data_dirs ();
1791 if (dirs != NULL((void*)0))
2
Assuming 'dirs' is not equal to NULL
3
Taking true branch
1792 for (; *dirs != NULL((void*)0); ++dirs) {
4
Assuming the condition is true
5
Loop condition is true. Entering loop body
1793 top_theme_dir_string = g_build_filename (*dirs, "themes", NULL((void*)0));
1794 top_theme_dir = g_file_new_for_path (top_theme_dir_string);
1795 g_free (top_theme_dir_string);
1796 add_top_theme_dir_monitor (top_theme_dir, 1, NULL((void*)0));
6
Calling 'add_top_theme_dir_monitor'
1797 g_object_unref (top_theme_dir);
1798 }
1799
1800 /* ~/.themes */
1801 top_theme_dir_string = g_build_filename (g_get_home_dir (), ".themes", NULL((void*)0));
1802 top_theme_dir = g_file_new_for_path (top_theme_dir_string);
1803 g_free (top_theme_dir_string);
1804 if (!g_file_query_exists (top_theme_dir, NULL((void*)0)))
1805 g_file_make_directory (top_theme_dir, NULL((void*)0), NULL((void*)0));
1806 add_top_theme_dir_monitor (top_theme_dir, 0, NULL((void*)0));
1807 g_object_unref (top_theme_dir);
1808
1809 /* ~/.icons */
1810 top_theme_dir_string = g_build_filename (g_get_home_dir (), ".icons", NULL((void*)0));
1811 top_theme_dir = g_file_new_for_path (top_theme_dir_string);
1812 g_free (top_theme_dir_string);
1813 if (!g_file_query_exists (top_theme_dir, NULL((void*)0)))
1814 g_file_make_directory (top_theme_dir, NULL((void*)0), NULL((void*)0));
1815 g_object_unref (top_theme_dir);
1816
1817 /* icon theme search path */
1818 ctk_icon_theme_get_search_path (ctk_icon_theme_get_default (), &search_path, &n);
1819 for (i = 0; i < n; ++i) {
1820 top_theme_dir = g_file_new_for_path (search_path[i]);
1821 add_top_icon_theme_dir_monitor (top_theme_dir, i, NULL((void*)0));
1822 g_object_unref (top_theme_dir);
1823 }
1824 g_strfreev (search_path);
1825
1826 /* if there's a separate xcursors dir, add that as well */
1827 if (strcmp (XCURSOR_ICONDIR"/usr/share/icons", "/usr/share/icons")) {
1828 top_theme_dir = g_file_new_for_path (XCURSOR_ICONDIR"/usr/share/icons");
1829 add_top_icon_theme_dir_monitor (top_theme_dir, 1, NULL((void*)0));
1830 g_object_unref (top_theme_dir);
1831 }
1832
1833 /* make sure we have the default theme */
1834 if (!cafe_theme_cursor_info_find ("default"))
1835 add_default_cursor_theme ();
1836
1837 /* done */
1838 initted = TRUE(!(0));
1839 initting = FALSE(0);
1840}