Bug Summary

File:ctk/ctkicontheme.c
Warning:line 2849, column 7
This statement is never executed

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 ctkicontheme.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/ctk -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I .. -D G_LOG_DOMAIN="Ctk" -D G_LOG_USE_STRUCTURED=1 -D CTK_VERSION="3.25.5" -D CTK_BINARY_VERSION="3.0.0" -D CTK_COMPILATION -D CTK_PRINT_BACKEND_ENABLE_UNSUPPORTED -D CTK_LIBDIR="/usr/lib" -D CTK_LOCALEDIR="/usr/share/locale" -D CTK_DATADIR="/usr/share" -D CTK_DATA_PREFIX="/usr" -D CTK_SYSCONFDIR="/usr/etc" -D CTK_HOST="x86_64-pc-linux-gnu" -D CTK_PRINT_BACKENDS="file,cups" -D X11_DATA_PREFIX="/usr" -D ISO_CODES_PREFIX="" -I .. -I ../ctk -I .. -I ../cdk -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -D G_ENABLE_DEBUG -D G_ENABLE_CONSISTENCY_CHECKS -D GLIB_MIN_REQUIRED_VERSION=GLIB_VERSION_2_66 -D GLIB_MAX_ALLOWED_VERSION=GLIB_VERSION_2_66 -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/atk-1.0 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -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/gio-unix-2.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -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/pango-1.0 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -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/14/../../../../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/ctk -ferror-limit 19 -fvisibility=hidden -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-09-19-171836-43636-1 -x c ctkicontheme.c
1/* CtkIconTheme - a loader for icon themes
2 * ctk-icon-theme.c Copyright (C) 2002, 2003 Red Hat, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser 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.
8 *
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 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "config.h"
19
20#include <sys/types.h>
21#include <sys/stat.h>
22#ifdef HAVE_UNISTD_H1
23#include <unistd.h>
24#endif
25#include <string.h>
26#include <stdlib.h>
27#include <math.h>
28#include <glib.h>
29#include <glib/gstdio.h>
30
31#ifdef G_OS_WIN32
32#ifndef S_ISDIR
33#define S_ISDIR(mode)((((mode)) & 0170000) == (0040000)) ((mode)&_S_IFDIR)
34#endif
35#define WIN32_LEAN_AND_MEAN
36#include <windows.h>
37#include <shellapi.h>
38#include "win32/cdkwin32.h"
39#endif /* G_OS_WIN32 */
40
41#include "ctkiconthemeprivate.h"
42#include "ctkcsspalettevalueprivate.h"
43#include "ctkcssrgbavalueprivate.h"
44#include "ctkdebug.h"
45#include "ctkiconfactory.h"
46#include "ctkiconcache.h"
47#include "ctkintl.h"
48#include "ctkmain.h"
49#include "deprecated/ctknumerableiconprivate.h"
50#include "ctksettingsprivate.h"
51#include "ctkstylecontextprivate.h"
52#include "ctkprivate.h"
53#include "gdkpixbufutilsprivate.h"
54
55#undef CDK_DEPRECATED
56#undef CDK_DEPRECATED_FOR
57#define CDK_DEPRECATED
58#define CDK_DEPRECATED_FOR(f)
59
60#include "ctkstyle.h"
61
62/* this is in case round() is not provided by the compiler,
63 * such as in the case of C89 compilers, like MSVC
64 */
65#include "fallback-c89.c"
66
67/**
68 * SECTION:ctkicontheme
69 * @Short_description: Looking up icons by name
70 * @Title: CtkIconTheme
71 *
72 * #CtkIconTheme provides a facility for looking up icons by name
73 * and size. The main reason for using a name rather than simply
74 * providing a filename is to allow different icons to be used
75 * depending on what “icon theme” is selected
76 * by the user. The operation of icon themes on Linux and Unix
77 * follows the [Icon Theme Specification](http://www.freedesktop.org/Standards/icon-theme-spec)
78 * There is a fallback icon theme, named `hicolor`, where applications
79 * should install their icons, but additional icon themes can be installed
80 * as operating system vendors and users choose.
81 *
82 * Named icons are similar to the deprecated [Stock Items][ctkstock],
83 * and the distinction between the two may be a bit confusing.
84 * A few things to keep in mind:
85 *
86 * - Stock images usually are used in conjunction with
87 * [Stock Items][ctkstock], such as %CTK_STOCK_OK or
88 * %CTK_STOCK_OPEN. Named icons are easier to set up and therefore
89 * are more useful for new icons that an application wants to
90 * add, such as application icons or window icons.
91 *
92 * - Stock images can only be loaded at the symbolic sizes defined
93 * by the #CtkIconSize enumeration, or by custom sizes defined
94 * by ctk_icon_size_register(), while named icons are more flexible
95 * and any pixel size can be specified.
96 *
97 * - Because stock images are closely tied to stock items, and thus
98 * to actions in the user interface, stock images may come in
99 * multiple variants for different widget states or writing
100 * directions.
101 *
102 * A good rule of thumb is that if there is a stock image for what
103 * you want to use, use it, otherwise use a named icon. It turns
104 * out that internally stock images are generally defined in
105 * terms of one or more named icons. (An example of the
106 * more than one case is icons that depend on writing direction;
107 * %CTK_STOCK_GO_FORWARD uses the two themed icons
108 * “ctk-stock-go-forward-ltr” and “ctk-stock-go-forward-rtl”.)
109 *
110 * In many cases, named themes are used indirectly, via #CtkImage
111 * or stock items, rather than directly, but looking up icons
112 * directly is also simple. The #CtkIconTheme object acts
113 * as a database of all the icons in the current theme. You
114 * can create new #CtkIconTheme objects, but it’s much more
115 * efficient to use the standard icon theme for the #CdkScreen
116 * so that the icon information is shared with other people
117 * looking up icons.
118 * |[<!-- language="C" -->
119 * GError *error = NULL;
120 * CtkIconTheme *icon_theme;
121 * GdkPixbuf *pixbuf;
122 *
123 * icon_theme = ctk_icon_theme_get_default ();
124 * pixbuf = ctk_icon_theme_load_icon (icon_theme,
125 * "my-icon-name", // icon name
126 * 48, // icon size
127 * 0, // flags
128 * &error);
129 * if (!pixbuf)
130 * {
131 * g_warning ("Couldn’t load icon: %s", error->message);
132 * g_error_free (error);
133 * }
134 * else
135 * {
136 * // Use the pixbuf
137 * g_object_unref (pixbuf);
138 * }
139 * ]|
140 */
141
142#define FALLBACK_ICON_THEME"hicolor" "hicolor"
143
144typedef enum
145{
146 ICON_THEME_DIR_FIXED,
147 ICON_THEME_DIR_SCALABLE,
148 ICON_THEME_DIR_THRESHOLD,
149 ICON_THEME_DIR_UNTHEMED
150} IconThemeDirType;
151
152/* In reverse search order: */
153typedef enum
154{
155 ICON_SUFFIX_NONE = 0,
156 ICON_SUFFIX_XPM = 1 << 0,
157 ICON_SUFFIX_SVG = 1 << 1,
158 ICON_SUFFIX_PNG = 1 << 2,
159 HAS_ICON_FILE = 1 << 3,
160 ICON_SUFFIX_SYMBOLIC_PNG = 1 << 4
161} IconSuffix;
162
163#define INFO_CACHE_LRU_SIZE32 32
164#if 0
165#define DEBUG_CACHE(args) g_print args
166#else
167#define DEBUG_CACHE(args)
168#endif
169
170struct _CtkIconThemePrivate
171{
172 GHashTable *info_cache;
173 GList *info_cache_lru;
174
175 gchar *current_theme;
176 gchar **search_path;
177 gint search_path_len;
178 GList *resource_paths;
179
180 guint custom_theme : 1;
181 guint is_screen_singleton : 1;
182 guint pixbuf_supports_svg : 1;
183 guint themes_valid : 1;
184 guint loading_themes : 1;
185
186 /* A list of all the themes needed to look up icons.
187 * In search order, without duplicates
188 */
189 GList *themes;
190 GHashTable *unthemed_icons;
191
192 /* CdkScreen for the icon theme (may be NULL) */
193 CdkScreen *screen;
194
195 /* time when we last stat:ed for theme changes */
196 gint64 last_stat_time;
197 GList *dir_mtimes;
198
199 gulong theme_changed_idle;
200};
201
202typedef struct {
203 gchar **icon_names;
204 gint size;
205 gint scale;
206 CtkIconLookupFlags flags;
207} IconInfoKey;
208
209typedef struct _SymbolicPixbufCache SymbolicPixbufCache;
210
211struct _SymbolicPixbufCache {
212 GdkPixbuf *pixbuf;
213 GdkPixbuf *proxy_pixbuf;
214 CdkRGBA fg;
215 CdkRGBA success_color;
216 CdkRGBA warning_color;
217 CdkRGBA error_color;
218 SymbolicPixbufCache *next;
219};
220
221struct _CtkIconInfoClass
222{
223 GObjectClass parent_class;
224};
225
226struct _CtkIconInfo
227{
228 GObject parent_instance;
229
230 /* Information about the source
231 */
232 IconInfoKey key;
233 CtkIconTheme *in_cache;
234
235 gchar *filename;
236 GFile *icon_file;
237 GLoadableIcon *loadable;
238 GSList *emblem_infos;
239
240 /* Cache pixbuf (if there is any) */
241 GdkPixbuf *cache_pixbuf;
242
243 /* Information about the directory where
244 * the source was found
245 */
246 IconThemeDirType dir_type;
247 gint dir_size;
248 gint dir_scale;
249 gint min_size;
250 gint max_size;
251
252 /* Parameters influencing the scaled icon
253 */
254 gint desired_size;
255 gint desired_scale;
256 guint forced_size : 1;
257 guint emblems_applied : 1;
258 guint is_svg : 1;
259 guint is_resource : 1;
260
261 /* Cached information if we go ahead and try to load
262 * the icon.
263 */
264 GdkPixbuf *pixbuf;
265 GdkPixbuf *proxy_pixbuf;
266 GError *load_error;
267 gdouble unscaled_scale;
268 gdouble scale;
269
270 SymbolicPixbufCache *symbolic_pixbuf_cache;
271
272 gint symbolic_width;
273 gint symbolic_height;
274};
275
276typedef struct
277{
278 gchar *name;
279 gchar *display_name;
280 gchar *comment;
281 gchar *example;
282
283 /* In search order */
284 GList *dirs;
285} IconTheme;
286
287typedef struct
288{
289 IconThemeDirType type;
290 GQuark context;
291
292 gint size;
293 gint min_size;
294 gint max_size;
295 gint threshold;
296 gint scale;
297 gboolean is_resource;
298
299 gchar *dir;
300 gchar *subdir;
301 gint subdir_index;
302
303 CtkIconCache *cache;
304
305 GHashTable *icons;
306} IconThemeDir;
307
308typedef struct
309{
310 gchar *svg_filename;
311 gchar *no_svg_filename;
312 gboolean is_resource;
313} UnthemedIcon;
314
315typedef struct
316{
317 gint size;
318 GdkPixbuf *pixbuf;
319} BuiltinIcon;
320
321typedef struct
322{
323 gchar *dir;
324 time_t mtime;
325 CtkIconCache *cache;
326 gboolean exists;
327} IconThemeDirMtime;
328
329static void ctk_icon_theme_finalize (GObject *object);
330static void theme_dir_destroy (IconThemeDir *dir);
331static void theme_destroy (IconTheme *theme);
332static CtkIconInfo *theme_lookup_icon (IconTheme *theme,
333 const gchar *icon_name,
334 gint size,
335 gint scale,
336 gboolean allow_svg,
337 gboolean use_default_icons);
338static void theme_list_icons (IconTheme *theme,
339 GHashTable *icons,
340 GQuark context);
341static gboolean theme_has_icon (IconTheme *theme,
342 const gchar *icon_name);
343static void theme_list_contexts (IconTheme *theme,
344 GHashTable *contexts);
345static void theme_subdir_load (CtkIconTheme *icon_theme,
346 IconTheme *theme,
347 GKeyFile *theme_file,
348 gchar *subdir);
349static void do_theme_change (CtkIconTheme *icon_theme);
350static void blow_themes (CtkIconTheme *icon_themes);
351static gboolean rescan_themes (CtkIconTheme *icon_themes);
352static IconSuffix theme_dir_get_icon_suffix (IconThemeDir *dir,
353 const gchar *icon_name,
354 gboolean *has_icon_file);
355static CtkIconInfo *icon_info_new (IconThemeDirType type,
356 gint dir_size,
357 gint dir_scale);
358static CtkIconInfo *icon_info_new_builtin (BuiltinIcon *icon);
359static IconSuffix suffix_from_name (const gchar *name);
360static BuiltinIcon *find_builtin_icon (const gchar *icon_name,
361 gint size,
362 gint scale,
363 gint *min_difference_p);
364static void remove_from_lru_cache (CtkIconTheme *icon_theme,
365 CtkIconInfo *icon_info);
366static gboolean icon_info_ensure_scale_and_pixbuf (CtkIconInfo* icon_info);
367
368static guint signal_changed = 0;
369
370static GHashTable *icon_theme_builtin_icons;
371
372static guint
373icon_info_key_hash (gconstpointer _key)
374{
375 const IconInfoKey *key = _key;
376 guint h = 0;
377 int i;
378 for (i = 0; key->icon_names[i] != NULL((void*)0); i++)
379 h ^= g_str_hash (key->icon_names[i]);
380
381 h ^= key->size * 0x10001;
382 h ^= key->scale * 0x1000010;
383 h ^= key->flags * 0x100000100;
384
385 return h;
386}
387
388static gboolean
389icon_info_key_equal (gconstpointer _a,
390 gconstpointer _b)
391{
392 const IconInfoKey *a = _a;
393 const IconInfoKey *b = _b;
394 int i;
395
396 if (a->size != b->size)
397 return FALSE(0);
398
399 if (a->scale != b->scale)
400 return FALSE(0);
401
402 if (a->flags != b->flags)
403 return FALSE(0);
404
405 for (i = 0;
406 a->icon_names[i] != NULL((void*)0) &&
407 b->icon_names[i] != NULL((void*)0); i++)
408 {
409 if (strcmp (a->icon_names[i], b->icon_names[i]) != 0)
410 return FALSE(0);
411 }
412
413 return a->icon_names[i] == NULL((void*)0) && b->icon_names[i] == NULL((void*)0);
414}
415
416G_DEFINE_TYPE_WITH_PRIVATE (CtkIconTheme, ctk_icon_theme, G_TYPE_OBJECT)static void ctk_icon_theme_init (CtkIconTheme *self); static void
ctk_icon_theme_class_init (CtkIconThemeClass *klass); static
GType ctk_icon_theme_get_type_once (void); static gpointer ctk_icon_theme_parent_class
= ((void*)0); static gint CtkIconTheme_private_offset; static
void ctk_icon_theme_class_intern_init (gpointer klass) { ctk_icon_theme_parent_class
= g_type_class_peek_parent (klass); if (CtkIconTheme_private_offset
!= 0) g_type_class_adjust_private_offset (klass, &CtkIconTheme_private_offset
); ctk_icon_theme_class_init ((CtkIconThemeClass*) klass); } __attribute__
((__unused__)) static inline gpointer ctk_icon_theme_get_instance_private
(CtkIconTheme *self) { return (((gpointer) ((guint8*) (self)
+ (glong) (CtkIconTheme_private_offset)))); } GType ctk_icon_theme_get_type
(void) { static GType static_g_define_type_id = 0; if ((__extension__
({ _Static_assert (sizeof *(&static_g_define_type_id) ==
sizeof (gpointer), "Expression evaluates to false"); (void) (
0 ? (gpointer) * (&static_g_define_type_id) : ((void*)0))
; (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter_pointer (
&static_g_define_type_id)); })) ) { GType g_define_type_id
= ctk_icon_theme_get_type_once (); (__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id
) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer
((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id
)); })) ; } return static_g_define_type_id; } __attribute__ (
(__noinline__)) static GType ctk_icon_theme_get_type_once (void
) { GType g_define_type_id = g_type_register_static_simple ((
(GType) ((20) << (2))), g_intern_static_string ("CtkIconTheme"
), sizeof (CtkIconThemeClass), (GClassInitFunc)(void (*)(void
)) ctk_icon_theme_class_intern_init, sizeof (CtkIconTheme), (
GInstanceInitFunc)(void (*)(void)) ctk_icon_theme_init, (GTypeFlags
) 0); { {{ CtkIconTheme_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (CtkIconThemePrivate)); };} } return
g_define_type_id; }
417
418/**
419 * ctk_icon_theme_new:
420 *
421 * Creates a new icon theme object. Icon theme objects are used
422 * to lookup up an icon by name in a particular icon theme.
423 * Usually, you’ll want to use ctk_icon_theme_get_default()
424 * or ctk_icon_theme_get_for_screen() rather than creating
425 * a new icon theme object for scratch.
426 *
427 * Returns: the newly created #CtkIconTheme object.
428 *
429 * Since: 2.4
430 */
431CtkIconTheme *
432ctk_icon_theme_new (void)
433{
434 return g_object_new (CTK_TYPE_ICON_THEME(ctk_icon_theme_get_type ()), NULL((void*)0));
435}
436
437/**
438 * ctk_icon_theme_get_default:
439 *
440 * Gets the icon theme for the default screen. See
441 * ctk_icon_theme_get_for_screen().
442 *
443 * Returns: (transfer none): A unique #CtkIconTheme associated with
444 * the default screen. This icon theme is associated with
445 * the screen and can be used as long as the screen
446 * is open. Do not ref or unref it.
447 *
448 * Since: 2.4
449 */
450CtkIconTheme *
451ctk_icon_theme_get_default (void)
452{
453 return ctk_icon_theme_get_for_screen (cdk_screen_get_default ());
454}
455
456/**
457 * ctk_icon_theme_get_for_screen:
458 * @screen: a #CdkScreen
459 *
460 * Gets the icon theme object associated with @screen; if this
461 * function has not previously been called for the given
462 * screen, a new icon theme object will be created and
463 * associated with the screen. Icon theme objects are
464 * fairly expensive to create, so using this function
465 * is usually a better choice than calling than ctk_icon_theme_new()
466 * and setting the screen yourself; by using this function
467 * a single icon theme object will be shared between users.
468 *
469 * Returns: (transfer none): A unique #CtkIconTheme associated with
470 * the given screen. This icon theme is associated with
471 * the screen and can be used as long as the screen
472 * is open. Do not ref or unref it.
473 *
474 * Since: 2.4
475 */
476CtkIconTheme *
477ctk_icon_theme_get_for_screen (CdkScreen *screen)
478{
479 CtkIconTheme *icon_theme;
480
481 g_return_val_if_fail (CDK_IS_SCREEN (screen), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((screen)); GType __t = ((cdk_screen_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CDK_IS_SCREEN (screen)"); return (((void*)0)); } } while
(0)
;
482
483 icon_theme = g_object_get_data (G_OBJECT (screen)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((screen)), (((GType) ((20) << (2))))))))
, "ctk-icon-theme");
484 if (!icon_theme)
485 {
486 CtkIconThemePrivate *priv;
487
488 icon_theme = ctk_icon_theme_new ();
489 ctk_icon_theme_set_screen (icon_theme, screen);
490
491 priv = icon_theme->priv;
492 priv->is_screen_singleton = TRUE(!(0));
493
494 g_object_set_data (G_OBJECT (screen)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((screen)), (((GType) ((20) << (2))))))))
, I_("ctk-icon-theme")g_intern_static_string ("ctk-icon-theme"), icon_theme);
495 }
496
497 return icon_theme;
498}
499
500static void
501ctk_icon_theme_class_init (CtkIconThemeClass *klass)
502{
503 GObjectClass *gobject_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), (((GType) ((20) << (2))))))))
;
504
505 gobject_class->finalize = ctk_icon_theme_finalize;
506
507 /**
508 * CtkIconTheme::changed:
509 * @icon_theme: the icon theme
510 *
511 * Emitted when the current icon theme is switched or CTK+ detects
512 * that a change has occurred in the contents of the current
513 * icon theme.
514 */
515 signal_changed = g_signal_new (I_("changed")g_intern_static_string ("changed"),
516 G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type),
517 G_SIGNAL_RUN_LAST,
518 G_STRUCT_OFFSET (CtkIconThemeClass, changed)((glong) __builtin_offsetof(CtkIconThemeClass, changed)),
519 NULL((void*)0), NULL((void*)0),
520 NULL((void*)0),
521 G_TYPE_NONE((GType) ((1) << (2))), 0);
522}
523
524
525/* Callback when the display that the icon theme is attached
526 * to is closed; unset the screen, and if it’s the unique theme
527 * for the screen, drop the reference
528 */
529static void
530display_closed (CdkDisplay *display G_GNUC_UNUSED__attribute__ ((__unused__)),
531 gboolean is_error G_GNUC_UNUSED__attribute__ ((__unused__)),
532 CtkIconTheme *icon_theme)
533{
534 CtkIconThemePrivate *priv = icon_theme->priv;
535 CdkScreen *screen = priv->screen;
536 gboolean was_screen_singleton = priv->is_screen_singleton;
537
538 if (was_screen_singleton)
539 {
540 g_object_set_data (G_OBJECT (screen)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((screen)), (((GType) ((20) << (2))))))))
, I_("ctk-icon-theme")g_intern_static_string ("ctk-icon-theme"), NULL((void*)0));
541 priv->is_screen_singleton = FALSE(0);
542 }
543
544 ctk_icon_theme_set_screen (icon_theme, NULL((void*)0));
545
546 if (was_screen_singleton)
547 {
548 g_object_unref (icon_theme);
549 }
550}
551
552static void
553update_current_theme (CtkIconTheme *icon_theme)
554{
555#define theme_changed(_old, _new) \
556 ((_old && !_new) || (!_old && _new) || \
557 (_old && _new && strcmp (_old, _new) != 0))
558 CtkIconThemePrivate *priv = icon_theme->priv;
559
560 if (!priv->custom_theme)
561 {
562 gchar *theme = NULL((void*)0);
563 gboolean changed = FALSE(0);
564
565 if (priv->screen)
566 {
567 CtkSettings *settings = ctk_settings_get_for_screen (priv->screen);
568 g_object_get (settings, "ctk-icon-theme-name", &theme, NULL((void*)0));
569 }
570
571 if (theme_changed (priv->current_theme, theme))
572 {
573 g_free (priv->current_theme);
574 priv->current_theme = theme;
575 changed = TRUE(!(0));
576 }
577 else
578 g_free (theme);
579
580 if (changed)
581 do_theme_change (icon_theme);
582 }
583#undef theme_changed
584}
585
586/* Callback when the icon theme CtkSetting changes
587 */
588static void
589theme_changed (CtkSettings *settings G_GNUC_UNUSED__attribute__ ((__unused__)),
590 GParamSpec *pspec G_GNUC_UNUSED__attribute__ ((__unused__)),
591 CtkIconTheme *icon_theme)
592{
593 update_current_theme (icon_theme);
594}
595
596static void
597unset_screen (CtkIconTheme *icon_theme)
598{
599 CtkIconThemePrivate *priv = icon_theme->priv;
600 CtkSettings *settings;
601 CdkDisplay *display;
602
603 if (priv->screen)
604 {
605 settings = ctk_settings_get_for_screen (priv->screen);
606 display = cdk_screen_get_display (priv->screen);
607
608 g_signal_handlers_disconnect_by_func (display,g_signal_handlers_disconnect_matched ((display), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), ((gpointer) display_closed), (icon_theme))
609 (gpointer) display_closed,g_signal_handlers_disconnect_matched ((display), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), ((gpointer) display_closed), (icon_theme))
610 icon_theme)g_signal_handlers_disconnect_matched ((display), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), ((gpointer) display_closed), (icon_theme))
;
611 if (settings)
612 g_signal_handlers_disconnect_by_func (settings,g_signal_handlers_disconnect_matched ((settings), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), ((gpointer) theme_changed), (icon_theme))
613 (gpointer) theme_changed,g_signal_handlers_disconnect_matched ((settings), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), ((gpointer) theme_changed), (icon_theme))
614 icon_theme)g_signal_handlers_disconnect_matched ((settings), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), ((gpointer) theme_changed), (icon_theme))
;
615
616 priv->screen = NULL((void*)0);
617 }
618}
619
620/**
621 * ctk_icon_theme_set_screen:
622 * @icon_theme: a #CtkIconTheme
623 * @screen: a #CdkScreen
624 *
625 * Sets the screen for an icon theme; the screen is used
626 * to track the user’s currently configured icon theme,
627 * which might be different for different screens.
628 *
629 * Since: 2.4
630 */
631void
632ctk_icon_theme_set_screen (CtkIconTheme *icon_theme,
633 CdkScreen *screen)
634{
635 CtkIconThemePrivate *priv;
636 CtkSettings *settings;
637 CdkDisplay *display;
638
639 g_return_if_fail (CTK_ICON_THEME (icon_theme))do { if ((((((CtkIconTheme*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((icon_theme)), ((ctk_icon_theme_get_type (
))))))))) { } else { g_return_if_fail_warning ("Ctk", ((const
char*) (__func__)), "CTK_ICON_THEME (icon_theme)"); return; }
} while (0)
;
640 g_return_if_fail (screen == NULL || CDK_IS_SCREEN (screen))do { if ((screen == ((void*)0) || (((__extension__ ({ GTypeInstance
*__inst = (GTypeInstance*) ((screen)); GType __t = ((cdk_screen_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("Ctk", ((const
char*) (__func__)), "screen == NULL || CDK_IS_SCREEN (screen)"
); return; } } while (0)
;
641
642 priv = icon_theme->priv;
643
644 unset_screen (icon_theme);
645
646 if (screen)
647 {
648 display = cdk_screen_get_display (screen);
649 settings = ctk_settings_get_for_screen (screen);
650
651 priv->screen = screen;
652
653 g_signal_connect (display, "closed",g_signal_connect_data ((display), ("closed"), (((GCallback) (
display_closed))), (icon_theme), ((void*)0), (GConnectFlags) 0
)
654 G_CALLBACK (display_closed), icon_theme)g_signal_connect_data ((display), ("closed"), (((GCallback) (
display_closed))), (icon_theme), ((void*)0), (GConnectFlags) 0
)
;
655 g_signal_connect (settings, "notify::ctk-icon-theme-name",g_signal_connect_data ((settings), ("notify::ctk-icon-theme-name"
), (((GCallback) (theme_changed))), (icon_theme), ((void*)0),
(GConnectFlags) 0)
656 G_CALLBACK (theme_changed), icon_theme)g_signal_connect_data ((settings), ("notify::ctk-icon-theme-name"
), (((GCallback) (theme_changed))), (icon_theme), ((void*)0),
(GConnectFlags) 0)
;
657 }
658
659 update_current_theme (icon_theme);
660}
661
662/* Checks whether a loader for SVG files has been registered
663 * with GdkPixbuf.
664 */
665static gboolean
666pixbuf_supports_svg (void)
667{
668 GSList *formats;
669 GSList *tmp_list;
670 static gint found_svg = -1;
671
672 if (found_svg != -1)
673 return found_svg;
674
675 formats = gdk_pixbuf_get_formats ();
676
677 found_svg = FALSE(0);
678 for (tmp_list = formats; tmp_list && !found_svg; tmp_list = tmp_list->next)
679 {
680 gchar **mime_types = gdk_pixbuf_format_get_mime_types (tmp_list->data);
681 gchar **mime_type;
682
683 for (mime_type = mime_types; *mime_type && !found_svg; mime_type++)
684 {
685 if (strcmp (*mime_type, "image/svg") == 0)
686 found_svg = TRUE(!(0));
687 }
688
689 g_strfreev (mime_types);
690 }
691
692 g_slist_free (formats);
693
694 return found_svg;
695}
696
697/* The icon info was removed from the icon_info_hash hash table */
698static void
699icon_info_uncached (CtkIconInfo *icon_info)
700{
701 CtkIconTheme *icon_theme = icon_info->in_cache;
702
703 DEBUG_CACHE (("removing %p (%s %d 0x%x) from cache (icon_them: %p) (cache size %d)\n",
704 icon_info,
705 g_strjoinv (",", icon_info->key.icon_names),
706 icon_info->key.size, icon_info->key.flags,
707 icon_theme,
708 icon_theme != NULL ? g_hash_table_size (icon_theme->priv->info_cache) : 0));
709
710 icon_info->in_cache = NULL((void*)0);
711
712 if (icon_theme != NULL((void*)0))
713 remove_from_lru_cache (icon_theme, icon_info);
714}
715
716static void
717ctk_icon_theme_init (CtkIconTheme *icon_theme)
718{
719 CtkIconThemePrivate *priv;
720 const gchar * const *xdg_data_dirs;
721 int i, j;
722
723 priv = ctk_icon_theme_get_instance_private (icon_theme);
724 icon_theme->priv = priv;
725
726 priv->info_cache = g_hash_table_new_full (icon_info_key_hash, icon_info_key_equal, NULL((void*)0),
727 (GDestroyNotify)icon_info_uncached);
728
729 priv->custom_theme = FALSE(0);
730
731 xdg_data_dirs = g_get_system_data_dirs ();
732 for (i = 0; xdg_data_dirs[i]; i++) ;
733
734 priv->search_path_len = 2 * i + 2;
735
736 priv->search_path = g_new (char *, priv->search_path_len)((char * *) g_malloc_n ((priv->search_path_len), sizeof (char
*)))
;
737
738 i = 0;
739 priv->search_path[i++] = g_build_filename (g_get_user_data_dir (), "icons", NULL((void*)0));
740 priv->search_path[i++] = g_build_filename (g_get_home_dir (), ".icons", NULL((void*)0));
741
742 for (j = 0; xdg_data_dirs[j]; j++)
743 priv->search_path[i++] = g_build_filename (xdg_data_dirs[j], "icons", NULL((void*)0));
744
745 for (j = 0; xdg_data_dirs[j]; j++)
746 priv->search_path[i++] = g_build_filename (xdg_data_dirs[j], "pixmaps", NULL((void*)0));
747
748 priv->resource_paths = g_list_append (NULL((void*)0), g_strdup ("/org/ctk/libctk/icons/")g_strdup_inline ("/org/ctk/libctk/icons/"));
749
750 priv->themes_valid = FALSE(0);
751 priv->themes = NULL((void*)0);
752 priv->unthemed_icons = NULL((void*)0);
753
754 priv->pixbuf_supports_svg = pixbuf_supports_svg ();
755}
756
757static void
758free_dir_mtime (IconThemeDirMtime *dir_mtime)
759{
760 if (dir_mtime->cache)
761 _ctk_icon_cache_unref (dir_mtime->cache);
762
763 g_free (dir_mtime->dir);
764 g_slice_free (IconThemeDirMtime, dir_mtime)do { if (1) g_slice_free1 (sizeof (IconThemeDirMtime), (dir_mtime
)); else (void) ((IconThemeDirMtime*) 0 == (dir_mtime)); } while
(0)
;
765}
766
767static gboolean
768theme_changed_idle (gpointer user_data)
769{
770 CtkIconTheme *icon_theme;
771 CtkIconThemePrivate *priv;
772
773 icon_theme = CTK_ICON_THEME (user_data)((((CtkIconTheme*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((user_data)), ((ctk_icon_theme_get_type ()))))))
;
774 priv = icon_theme->priv;
775
776 g_signal_emit (icon_theme, signal_changed, 0);
777
778 if (priv->screen && priv->is_screen_singleton)
779 ctk_style_context_reset_widgets (priv->screen);
780
781 priv->theme_changed_idle = 0;
782
783 return FALSE(0);
784}
785
786static void
787queue_theme_changed (CtkIconTheme *icon_theme)
788{
789 CtkIconThemePrivate *priv = icon_theme->priv;
790
791 if (!priv->theme_changed_idle)
792 {
793 priv->theme_changed_idle =
794 cdk_threads_add_idle_full (CTK_PRIORITY_RESIZE(100 + 10) - 2,
795 theme_changed_idle, icon_theme, NULL((void*)0));
796 g_source_set_name_by_id (priv->theme_changed_idle, "[ctk+] theme_changed_idle");
797 }
798}
799
800static void
801do_theme_change (CtkIconTheme *icon_theme)
802{
803 CtkIconThemePrivate *priv = icon_theme->priv;
804
805 g_hash_table_remove_all (priv->info_cache);
806
807 if (!priv->themes_valid)
808 return;
809
810 CTK_NOTE (ICONTHEME,do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
g_message ("change to icon theme \"%s\"", priv->current_theme
); }; } while (0)
811 g_message ("change to icon theme \"%s\"", priv->current_theme))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
g_message ("change to icon theme \"%s\"", priv->current_theme
); }; } while (0)
;
812 blow_themes (icon_theme);
813
814 queue_theme_changed (icon_theme);
815
816}
817
818static void
819blow_themes (CtkIconTheme *icon_theme)
820{
821 CtkIconThemePrivate *priv = icon_theme->priv;
822
823 if (priv->themes_valid)
824 {
825 g_list_free_full (priv->themes, (GDestroyNotify) theme_destroy);
826 g_list_free_full (priv->dir_mtimes, (GDestroyNotify) free_dir_mtime);
827 g_hash_table_destroy (priv->unthemed_icons);
828 }
829 priv->themes = NULL((void*)0);
830 priv->unthemed_icons = NULL((void*)0);
831 priv->dir_mtimes = NULL((void*)0);
832 priv->themes_valid = FALSE(0);
833}
834
835static void
836ctk_icon_theme_finalize (GObject *object)
837{
838 CtkIconTheme *icon_theme;
839 CtkIconThemePrivate *priv;
840 int i;
841
842 icon_theme = CTK_ICON_THEME (object)((((CtkIconTheme*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((ctk_icon_theme_get_type ()))))))
;
843 priv = icon_theme->priv;
844
845 g_hash_table_destroy (priv->info_cache);
846 g_assert (priv->info_cache_lru == NULL)do { if (priv->info_cache_lru == ((void*)0)) ; else g_assertion_message_expr
("Ctk", "ctkicontheme.c", 846, ((const char*) (__func__)), "priv->info_cache_lru == NULL"
); } while (0)
;
847
848 if (priv->theme_changed_idle)
849 g_source_remove (priv->theme_changed_idle);
850
851 unset_screen (icon_theme);
852
853 g_free (priv->current_theme);
854
855 for (i = 0; i < priv->search_path_len; i++)
856 g_free (priv->search_path[i]);
857 g_free (priv->search_path);
858
859 g_list_free_full (priv->resource_paths, g_free);
860
861 blow_themes (icon_theme);
862
863 G_OBJECT_CLASS (ctk_icon_theme_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_icon_theme_parent_class)), (((GType) ((20) << (
2))))))))
->finalize (object);
864}
865
866/**
867 * ctk_icon_theme_set_search_path:
868 * @icon_theme: a #CtkIconTheme
869 * @path: (array length=n_elements) (element-type filename): array of
870 * directories that are searched for icon themes
871 * @n_elements: number of elements in @path.
872 *
873 * Sets the search path for the icon theme object. When looking
874 * for an icon theme, CTK+ will search for a subdirectory of
875 * one or more of the directories in @path with the same name
876 * as the icon theme containing an index.theme file. (Themes from
877 * multiple of the path elements are combined to allow themes to be
878 * extended by adding icons in the user’s home directory.)
879 *
880 * In addition if an icon found isn’t found either in the current
881 * icon theme or the default icon theme, and an image file with
882 * the right name is found directly in one of the elements of
883 * @path, then that image will be used for the icon name.
884 * (This is legacy feature, and new icons should be put
885 * into the fallback icon theme, which is called hicolor,
886 * rather than directly on the icon path.)
887 *
888 * Since: 2.4
889 */
890void
891ctk_icon_theme_set_search_path (CtkIconTheme *icon_theme,
892 const gchar *path[],
893 gint n_elements)
894{
895 CtkIconThemePrivate *priv;
896 gint i;
897
898 g_return_if_fail (CTK_IS_ICON_THEME (icon_theme))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((icon_theme)); GType __t = ((ctk_icon_theme_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ICON_THEME (icon_theme)"); return; } }
while (0)
;
899
900 priv = icon_theme->priv;
901 for (i = 0; i < priv->search_path_len; i++)
902 g_free (priv->search_path[i]);
903
904 g_free (priv->search_path);
905
906 priv->search_path = g_new (gchar *, n_elements)((gchar * *) g_malloc_n ((n_elements), sizeof (gchar *)));
907 priv->search_path_len = n_elements;
908
909 for (i = 0; i < priv->search_path_len; i++)
910 priv->search_path[i] = g_strdup (path[i])g_strdup_inline (path[i]);
911
912 do_theme_change (icon_theme);
913}
914
915/**
916 * ctk_icon_theme_get_search_path:
917 * @icon_theme: a #CtkIconTheme
918 * @path: (allow-none) (array length=n_elements) (element-type filename) (out):
919 * location to store a list of icon theme path directories or %NULL.
920 * The stored value should be freed with g_strfreev().
921 * @n_elements: location to store number of elements in @path, or %NULL
922 *
923 * Gets the current search path. See ctk_icon_theme_set_search_path().
924 *
925 * Since: 2.4
926 */
927void
928ctk_icon_theme_get_search_path (CtkIconTheme *icon_theme,
929 gchar **path[],
930 gint *n_elements)
931{
932 CtkIconThemePrivate *priv;
933 gint i;
934
935 g_return_if_fail (CTK_IS_ICON_THEME (icon_theme))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((icon_theme)); GType __t = ((ctk_icon_theme_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ICON_THEME (icon_theme)"); return; } }
while (0)
;
936
937 priv = icon_theme->priv;
938
939 if (n_elements)
940 *n_elements = priv->search_path_len;
941
942 if (path)
943 {
944 *path = g_new (gchar *, priv->search_path_len + 1)((gchar * *) g_malloc_n ((priv->search_path_len + 1), sizeof
(gchar *)))
;
945 for (i = 0; i < priv->search_path_len; i++)
946 (*path)[i] = g_strdup (priv->search_path[i])g_strdup_inline (priv->search_path[i]);
947 (*path)[i] = NULL((void*)0);
948 }
949}
950
951/**
952 * ctk_icon_theme_append_search_path:
953 * @icon_theme: a #CtkIconTheme
954 * @path: (type filename): directory name to append to the icon path
955 *
956 * Appends a directory to the search path.
957 * See ctk_icon_theme_set_search_path().
958 *
959 * Since: 2.4
960 */
961void
962ctk_icon_theme_append_search_path (CtkIconTheme *icon_theme,
963 const gchar *path)
964{
965 CtkIconThemePrivate *priv;
966
967 g_return_if_fail (CTK_IS_ICON_THEME (icon_theme))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((icon_theme)); GType __t = ((ctk_icon_theme_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ICON_THEME (icon_theme)"); return; } }
while (0)
;
968 g_return_if_fail (path != NULL)do { if ((path != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "path != NULL"); return;
} } while (0)
;
969
970 priv = icon_theme->priv;
971
972 priv->search_path_len++;
973
974 priv->search_path = g_renew (gchar *, priv->search_path, priv->search_path_len)((gchar * *) g_realloc_n (priv->search_path, (priv->search_path_len
), sizeof (gchar *)))
;
975 priv->search_path[priv->search_path_len-1] = g_strdup (path)g_strdup_inline (path);
976
977 do_theme_change (icon_theme);
978}
979
980/**
981 * ctk_icon_theme_prepend_search_path:
982 * @icon_theme: a #CtkIconTheme
983 * @path: (type filename): directory name to prepend to the icon path
984 *
985 * Prepends a directory to the search path.
986 * See ctk_icon_theme_set_search_path().
987 *
988 * Since: 2.4
989 */
990void
991ctk_icon_theme_prepend_search_path (CtkIconTheme *icon_theme,
992 const gchar *path)
993{
994 CtkIconThemePrivate *priv;
995 gint i;
996
997 g_return_if_fail (CTK_IS_ICON_THEME (icon_theme))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((icon_theme)); GType __t = ((ctk_icon_theme_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ICON_THEME (icon_theme)"); return; } }
while (0)
;
998 g_return_if_fail (path != NULL)do { if ((path != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "path != NULL"); return;
} } while (0)
;
999
1000 priv = icon_theme->priv;
1001
1002 priv->search_path_len++;
1003 priv->search_path = g_renew (gchar *, priv->search_path, priv->search_path_len)((gchar * *) g_realloc_n (priv->search_path, (priv->search_path_len
), sizeof (gchar *)))
;
1004
1005 for (i = priv->search_path_len - 1; i > 0; i--)
1006 priv->search_path[i] = priv->search_path[i - 1];
1007
1008 priv->search_path[0] = g_strdup (path)g_strdup_inline (path);
1009
1010 do_theme_change (icon_theme);
1011}
1012
1013/**
1014 * ctk_icon_theme_add_resource_path:
1015 * @icon_theme: a #CtkIconTheme
1016 * @path: a resource path
1017 *
1018 * Adds a resource path that will be looked at when looking
1019 * for icons, similar to search paths.
1020 *
1021 * This function should be used to make application-specific icons
1022 * available as part of the icon theme.
1023 *
1024 * The resources are considered as part of the hicolor icon theme
1025 * and must be located in subdirectories that are defined in the
1026 * hicolor icon theme, such as `@path/16x16/actions/run.png`.
1027 * Icons that are directly placed in the resource path instead
1028 * of a subdirectory are also considered as ultimate fallback.
1029 *
1030 * Since: 3.14
1031 */
1032void
1033ctk_icon_theme_add_resource_path (CtkIconTheme *icon_theme,
1034 const gchar *path)
1035{
1036 CtkIconThemePrivate *priv = NULL((void*)0);
1037
1038 g_return_if_fail (CTK_IS_ICON_THEME (icon_theme))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((icon_theme)); GType __t = ((ctk_icon_theme_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ICON_THEME (icon_theme)"); return; } }
while (0)
;
1039 g_return_if_fail (path != NULL)do { if ((path != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "path != NULL"); return;
} } while (0)
;
1040
1041 priv = icon_theme->priv;
1042 priv->resource_paths = g_list_append (priv->resource_paths, g_strdup (path)g_strdup_inline (path));
1043
1044 do_theme_change (icon_theme);
1045}
1046
1047/**
1048 * ctk_icon_theme_set_custom_theme:
1049 * @icon_theme: a #CtkIconTheme
1050 * @theme_name: (allow-none): name of icon theme to use instead of
1051 * configured theme, or %NULL to unset a previously set custom theme
1052 *
1053 * Sets the name of the icon theme that the #CtkIconTheme object uses
1054 * overriding system configuration. This function cannot be called
1055 * on the icon theme objects returned from ctk_icon_theme_get_default()
1056 * and ctk_icon_theme_get_for_screen().
1057 *
1058 * Since: 2.4
1059 */
1060void
1061ctk_icon_theme_set_custom_theme (CtkIconTheme *icon_theme,
1062 const gchar *theme_name)
1063{
1064 CtkIconThemePrivate *priv;
1065
1066 g_return_if_fail (CTK_IS_ICON_THEME (icon_theme))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((icon_theme)); GType __t = ((ctk_icon_theme_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ICON_THEME (icon_theme)"); return; } }
while (0)
;
1067
1068 priv = icon_theme->priv;
1069
1070 g_return_if_fail (!priv->is_screen_singleton)do { if ((!priv->is_screen_singleton)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "!priv->is_screen_singleton"
); return; } } while (0)
;
1071
1072 if (theme_name != NULL((void*)0))
1073 {
1074 priv->custom_theme = TRUE(!(0));
1075 if (!priv->current_theme || strcmp (theme_name, priv->current_theme) != 0)
1076 {
1077 g_free (priv->current_theme);
1078 priv->current_theme = g_strdup (theme_name)g_strdup_inline (theme_name);
1079
1080 do_theme_change (icon_theme);
1081 }
1082 }
1083 else
1084 {
1085 if (priv->custom_theme)
1086 {
1087 priv->custom_theme = FALSE(0);
1088 update_current_theme (icon_theme);
1089 }
1090 }
1091}
1092
1093static const gchar builtin_hicolor_index[] =
1094"[Icon Theme]\n"
1095"Name=Hicolor\n"
1096"Hidden=True\n"
1097"Directories=16x16/actions,16x16/status,22x22/actions,24x24/actions,24x24/status,32x32/actions,32x32/status,48x48/status,64x64/actions\n"
1098"[16x16/actions]\n"
1099"Size=16\n"
1100"Type=Threshold\n"
1101"[16x16/status]\n"
1102"Size=16\n"
1103"Type=Threshold\n"
1104"[22x22/actions]\n"
1105"Size=22\n"
1106"Type=Threshold\n"
1107"[24x24/actions]\n"
1108"Size=24\n"
1109"Type=Threshold\n"
1110"[24x24/status]\n"
1111"Size=24\n"
1112"Type=Threshold\n"
1113"[32x32/actions]\n"
1114"Size=32\n"
1115"Type=Threshold\n"
1116"[32x32/status]\n"
1117"Size=32\n"
1118"Type=Threshold\n"
1119"[48x48/status]\n"
1120"Size=48\n"
1121"Type=Threshold\n"
1122"[64x64/actions]\n"
1123"Size=64\n"
1124"Type=Threshold\n";
1125
1126static void
1127insert_theme (CtkIconTheme *icon_theme,
1128 const gchar *theme_name)
1129{
1130 gint i;
1131 GList *l;
1132 gchar **dirs;
1133 gchar **scaled_dirs;
1134 gchar **themes;
1135 CtkIconThemePrivate *priv;
1136 IconTheme *theme = NULL((void*)0);
1137 gchar *path;
1138 GKeyFile *theme_file;
1139 GError *error = NULL((void*)0);
1140 IconThemeDirMtime *dir_mtime;
1141 GStatBuf stat_buf;
1142
1143 priv = icon_theme->priv;
1144
1145 for (l = priv->themes; l != NULL((void*)0); l = l->next)
1146 {
1147 theme = l->data;
1148 if (strcmp (theme->name, theme_name) == 0)
1149 return;
1150 }
1151
1152 for (i = 0; i < priv->search_path_len; i++)
1153 {
1154 path = g_build_filename (priv->search_path[i],
1155 theme_name,
1156 NULL((void*)0));
1157 dir_mtime = g_slice_new (IconThemeDirMtime)((IconThemeDirMtime*) g_slice_alloc (sizeof (IconThemeDirMtime
)))
;
1158 dir_mtime->cache = NULL((void*)0);
1159 dir_mtime->dir = path;
1160 if (g_statstat (path, &stat_buf) == 0 && S_ISDIR (stat_buf.st_mode)((((stat_buf.st_mode)) & 0170000) == (0040000))) {
1161 dir_mtime->mtime = stat_buf.st_mtimest_mtim.tv_sec;
1162 dir_mtime->exists = TRUE(!(0));
1163 } else {
1164 dir_mtime->mtime = 0;
1165 dir_mtime->exists = FALSE(0);
1166 }
1167
1168 priv->dir_mtimes = g_list_prepend (priv->dir_mtimes, dir_mtime);
1169 }
1170
1171 theme_file = NULL((void*)0);
1172 for (i = 0; i < priv->search_path_len && !theme_file; i++)
1173 {
1174 path = g_build_filename (priv->search_path[i],
1175 theme_name,
1176 "index.theme",
1177 NULL((void*)0));
1178 if (g_file_test (path, G_FILE_TEST_IS_REGULAR))
1179 {
1180 theme_file = g_key_file_new ();
1181 g_key_file_set_list_separator (theme_file, ',');
1182 if (!g_key_file_load_from_file (theme_file, path, 0, &error))
1183 {
1184 g_key_file_free (theme_file);
1185 theme_file = NULL((void*)0);
1186 g_error_free (error);
1187 error = NULL((void*)0);
1188 }
1189 }
1190 g_free (path);
1191 }
1192
1193 if (theme_file || strcmp (theme_name, FALLBACK_ICON_THEME"hicolor") == 0)
1194 {
1195 theme = g_new0 (IconTheme, 1)((IconTheme *) g_malloc0_n ((1), sizeof (IconTheme)));
1196 theme->name = g_strdup (theme_name)g_strdup_inline (theme_name);
1197 priv->themes = g_list_prepend (priv->themes, theme);
1198 if (!theme_file)
1199 {
1200 theme_file = g_key_file_new ();
1201 g_key_file_set_list_separator (theme_file, ',');
1202 g_key_file_load_from_data (theme_file, builtin_hicolor_index, -1, 0, NULL((void*)0));
1203 }
1204 }
1205
1206 if (theme_file == NULL((void*)0))
1207 return;
1208
1209 theme->display_name =
1210 g_key_file_get_locale_string (theme_file, "Icon Theme", "Name", NULL((void*)0), NULL((void*)0));
1211 if (!theme->display_name)
1212 g_warning ("Theme file for %s has no name", theme_name);
1213
1214 dirs = g_key_file_get_string_list (theme_file, "Icon Theme", "Directories", NULL((void*)0), NULL((void*)0));
1215 if (!dirs)
1216 {
1217 g_warning ("Theme file for %s has no directories", theme_name);
1218 priv->themes = g_list_remove (priv->themes, theme);
1219 g_free (theme->name);
1220 g_free (theme->display_name);
1221 g_free (theme);
1222 g_key_file_free (theme_file);
1223 return;
1224 }
1225
1226 scaled_dirs = g_key_file_get_string_list (theme_file, "Icon Theme", "ScaledDirectories", NULL((void*)0), NULL((void*)0));
1227
1228 theme->comment =
1229 g_key_file_get_locale_string (theme_file,
1230 "Icon Theme", "Comment",
1231 NULL((void*)0), NULL((void*)0));
1232 theme->example =
1233 g_key_file_get_string (theme_file,
1234 "Icon Theme", "Example",
1235 NULL((void*)0));
1236
1237 theme->dirs = NULL((void*)0);
1238 for (i = 0; dirs[i] != NULL((void*)0); i++)
1239 theme_subdir_load (icon_theme, theme, theme_file, dirs[i]);
1240
1241 if (scaled_dirs)
1242 {
1243 for (i = 0; scaled_dirs[i] != NULL((void*)0); i++)
1244 theme_subdir_load (icon_theme, theme, theme_file, scaled_dirs[i]);
1245 }
1246 g_strfreev (dirs);
1247 g_strfreev (scaled_dirs);
1248
1249 theme->dirs = g_list_reverse (theme->dirs);
1250
1251 themes = g_key_file_get_string_list (theme_file,
1252 "Icon Theme",
1253 "Inherits",
1254 NULL((void*)0),
1255 NULL((void*)0));
1256 if (themes)
1257 {
1258 for (i = 0; themes[i] != NULL((void*)0); i++)
1259 insert_theme (icon_theme, themes[i]);
1260
1261 g_strfreev (themes);
1262 }
1263
1264 g_key_file_free (theme_file);
1265}
1266
1267static void
1268free_unthemed_icon (UnthemedIcon *unthemed_icon)
1269{
1270 g_free (unthemed_icon->svg_filename);
1271 g_free (unthemed_icon->no_svg_filename);
1272 g_slice_free (UnthemedIcon, unthemed_icon)do { if (1) g_slice_free1 (sizeof (UnthemedIcon), (unthemed_icon
)); else (void) ((UnthemedIcon*) 0 == (unthemed_icon)); } while
(0)
;
1273}
1274
1275static gchar *
1276strip_suffix (const gchar *filename)
1277{
1278 const gchar *dot;
1279
1280 if (g_str_has_suffix (filename, ".symbolic.png")(__builtin_constant_p (".symbolic.png")? __extension__ ({ const
char * const __str = (filename); const char * const __suffix
= (".symbolic.png"); gboolean __result = (0); if (__str == (
(void*)0) || __suffix == ((void*)0)) __result = (g_str_has_suffix
) (__str, __suffix); else { const size_t __str_len = strlen (
((__str) + !(__str))); const size_t __suffix_len = strlen (((
__suffix) + !(__suffix))); if (__str_len >= __suffix_len) __result
= memcmp (__str + __str_len - __suffix_len, ((__suffix) + !(
__suffix)), __suffix_len) == 0; } __result; }) : (g_str_has_suffix
) (filename, ".symbolic.png") )
)
1281 return g_strndup (filename, strlen(filename)-13);
1282
1283 dot = strrchr (filename, '.');
1284
1285 if (dot == NULL((void*)0))
1286 return g_strdup (filename)g_strdup_inline (filename);
1287
1288 return g_strndup (filename, dot - filename);
1289}
1290
1291static void
1292add_unthemed_icon (CtkIconTheme *icon_theme,
1293 const gchar *dir,
1294 const gchar *file,
1295 gboolean is_resource)
1296{
1297 CtkIconThemePrivate *priv = icon_theme->priv;
1298 IconSuffix new_suffix, old_suffix;
1299 gchar *abs_file;
1300 gchar *base_name;
1301 UnthemedIcon *unthemed_icon;
1302
1303 new_suffix = suffix_from_name (file);
1304
1305 if (new_suffix == ICON_SUFFIX_NONE)
1306 return;
1307
1308 abs_file = g_build_filename (dir, file, NULL((void*)0));
1309 base_name = strip_suffix (file);
1310
1311 unthemed_icon = g_hash_table_lookup (priv->unthemed_icons, base_name);
1312
1313 if (unthemed_icon)
1314 {
1315 if (new_suffix == ICON_SUFFIX_SVG)
1316 {
1317 if (unthemed_icon->svg_filename)
1318 g_free (abs_file);
1319 else
1320 unthemed_icon->svg_filename = abs_file;
1321 }
1322 else
1323 {
1324 if (unthemed_icon->no_svg_filename)
1325 {
1326 old_suffix = suffix_from_name (unthemed_icon->no_svg_filename);
1327 if (new_suffix > old_suffix)
1328 {
1329 g_free (unthemed_icon->no_svg_filename);
1330 unthemed_icon->no_svg_filename = abs_file;
1331 }
1332 else
1333 g_free (abs_file);
1334 }
1335 else
1336 unthemed_icon->no_svg_filename = abs_file;
1337 }
1338
1339 g_free (base_name);
1340 }
1341 else
1342 {
1343 unthemed_icon = g_slice_new0 (UnthemedIcon)((UnthemedIcon*) g_slice_alloc0 (sizeof (UnthemedIcon)));
1344
1345 unthemed_icon->is_resource = is_resource;
1346
1347 if (new_suffix == ICON_SUFFIX_SVG)
1348 unthemed_icon->svg_filename = abs_file;
1349 else
1350 unthemed_icon->no_svg_filename = abs_file;
1351
1352 /* takes ownership of base_name */
1353 g_hash_table_replace (priv->unthemed_icons, base_name, unthemed_icon);
1354 }
1355}
1356
1357static void
1358load_themes (CtkIconTheme *icon_theme)
1359{
1360 CtkIconThemePrivate *priv;
1361 GDir *gdir;
1362 gint base;
1363 gchar *dir;
1364 const gchar *file;
1365 IconThemeDirMtime *dir_mtime;
1366 GStatBuf stat_buf;
1367 GList *d;
1368
1369 priv = icon_theme->priv;
1370
1371 if (priv->current_theme)
1372 insert_theme (icon_theme, priv->current_theme);
1373
1374 /* Always look in the Advaita, gnome and hicolor icon themes.
1375 * Looking in hicolor is mandated by the spec, looking in Advaita
1376 * and gnome is a pragmatic solution to prevent missing icons in
1377 * CTK+ applications when run under, e.g. KDE.
1378 */
1379 insert_theme (icon_theme, DEFAULT_ICON_THEME"Advaita");
1380 insert_theme (icon_theme, "gnome");
1381 insert_theme (icon_theme, FALLBACK_ICON_THEME"hicolor");
1382 priv->themes = g_list_reverse (priv->themes);
1383
1384
1385 priv->unthemed_icons = g_hash_table_new_full (g_str_hash, g_str_equal,
1386 g_free, (GDestroyNotify)free_unthemed_icon);
1387
1388 for (base = 0; base < icon_theme->priv->search_path_len; base++)
1389 {
1390 dir = icon_theme->priv->search_path[base];
1391
1392 dir_mtime = g_slice_new (IconThemeDirMtime)((IconThemeDirMtime*) g_slice_alloc (sizeof (IconThemeDirMtime
)))
;
1393 priv->dir_mtimes = g_list_prepend (priv->dir_mtimes, dir_mtime);
1394
1395 dir_mtime->dir = g_strdup (dir)g_strdup_inline (dir);
1396 dir_mtime->mtime = 0;
1397 dir_mtime->exists = FALSE(0);
1398 dir_mtime->cache = NULL((void*)0);
1399
1400 if (g_statstat (dir, &stat_buf) != 0 || !S_ISDIR (stat_buf.st_mode)((((stat_buf.st_mode)) & 0170000) == (0040000)))
1401 continue;
1402 dir_mtime->mtime = stat_buf.st_mtimest_mtim.tv_sec;
1403 dir_mtime->exists = TRUE(!(0));
1404
1405 dir_mtime->cache = _ctk_icon_cache_new_for_path (dir);
1406 if (dir_mtime->cache != NULL((void*)0))
1407 continue;
1408
1409 gdir = g_dir_open (dir, 0, NULL((void*)0));
1410 if (gdir == NULL((void*)0))
1411 continue;
1412
1413 while ((file = g_dir_read_name (gdir)))
1414 add_unthemed_icon (icon_theme, dir, file, FALSE(0));
1415
1416 g_dir_close (gdir);
1417 }
1418 priv->dir_mtimes = g_list_reverse (priv->dir_mtimes);
1419
1420 for (d = priv->resource_paths; d; d = d->next)
1421 {
1422 gchar **children;
1423 gint i;
1424
1425 dir = d->data;
1426 children = g_resources_enumerate_children (dir, 0, NULL((void*)0));
1427 if (!children)
1428 continue;
1429
1430 for (i = 0; children[i]; i++)
1431 add_unthemed_icon (icon_theme, dir, children[i], TRUE(!(0)));
1432
1433 g_strfreev (children);
1434 }
1435
1436 priv->themes_valid = TRUE(!(0));
1437
1438 priv->last_stat_time = g_get_monotonic_time ();
1439
1440 CTK_NOTE (ICONTHEME, {do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
{ GList *l; GString *s; s = g_string_new ("Current icon themes "
); for (l = icon_theme->priv->themes; l; l = l->next
) { IconTheme *theme = l->data; (__builtin_constant_p (theme
->name) ? __extension__ ({ const char * const __val = (theme
->name); g_string_append_len_inline (s, __val, (__val != (
(void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (s, theme->name, (gssize
) -1)); g_string_append_c_inline (s, ' '); } g_message ("%s",
s->str); (__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free
) ((s), ((!(0)))) : g_string_free_and_steal (s)) : (g_string_free
) ((s), ((!(0))))); }; }; } while (0)
1441 GList *l;do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
{ GList *l; GString *s; s = g_string_new ("Current icon themes "
); for (l = icon_theme->priv->themes; l; l = l->next
) { IconTheme *theme = l->data; (__builtin_constant_p (theme
->name) ? __extension__ ({ const char * const __val = (theme
->name); g_string_append_len_inline (s, __val, (__val != (
(void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (s, theme->name, (gssize
) -1)); g_string_append_c_inline (s, ' '); } g_message ("%s",
s->str); (__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free
) ((s), ((!(0)))) : g_string_free_and_steal (s)) : (g_string_free
) ((s), ((!(0))))); }; }; } while (0)
1442 GString *s;do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
{ GList *l; GString *s; s = g_string_new ("Current icon themes "
); for (l = icon_theme->priv->themes; l; l = l->next
) { IconTheme *theme = l->data; (__builtin_constant_p (theme
->name) ? __extension__ ({ const char * const __val = (theme
->name); g_string_append_len_inline (s, __val, (__val != (
(void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (s, theme->name, (gssize
) -1)); g_string_append_c_inline (s, ' '); } g_message ("%s",
s->str); (__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free
) ((s), ((!(0)))) : g_string_free_and_steal (s)) : (g_string_free
) ((s), ((!(0))))); }; }; } while (0)
1443 s = g_string_new ("Current icon themes ");do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
{ GList *l; GString *s; s = g_string_new ("Current icon themes "
); for (l = icon_theme->priv->themes; l; l = l->next
) { IconTheme *theme = l->data; (__builtin_constant_p (theme
->name) ? __extension__ ({ const char * const __val = (theme
->name); g_string_append_len_inline (s, __val, (__val != (
(void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (s, theme->name, (gssize
) -1)); g_string_append_c_inline (s, ' '); } g_message ("%s",
s->str); (__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free
) ((s), ((!(0)))) : g_string_free_and_steal (s)) : (g_string_free
) ((s), ((!(0))))); }; }; } while (0)
1444 for (l = icon_theme->priv->themes; l; l = l->next)do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
{ GList *l; GString *s; s = g_string_new ("Current icon themes "
); for (l = icon_theme->priv->themes; l; l = l->next
) { IconTheme *theme = l->data; (__builtin_constant_p (theme
->name) ? __extension__ ({ const char * const __val = (theme
->name); g_string_append_len_inline (s, __val, (__val != (
(void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (s, theme->name, (gssize
) -1)); g_string_append_c_inline (s, ' '); } g_message ("%s",
s->str); (__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free
) ((s), ((!(0)))) : g_string_free_and_steal (s)) : (g_string_free
) ((s), ((!(0))))); }; }; } while (0)
1445 {do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
{ GList *l; GString *s; s = g_string_new ("Current icon themes "
); for (l = icon_theme->priv->themes; l; l = l->next
) { IconTheme *theme = l->data; (__builtin_constant_p (theme
->name) ? __extension__ ({ const char * const __val = (theme
->name); g_string_append_len_inline (s, __val, (__val != (
(void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (s, theme->name, (gssize
) -1)); g_string_append_c_inline (s, ' '); } g_message ("%s",
s->str); (__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free
) ((s), ((!(0)))) : g_string_free_and_steal (s)) : (g_string_free
) ((s), ((!(0))))); }; }; } while (0)
1446 IconTheme *theme = l->data;do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
{ GList *l; GString *s; s = g_string_new ("Current icon themes "
); for (l = icon_theme->priv->themes; l; l = l->next
) { IconTheme *theme = l->data; (__builtin_constant_p (theme
->name) ? __extension__ ({ const char * const __val = (theme
->name); g_string_append_len_inline (s, __val, (__val != (
(void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (s, theme->name, (gssize
) -1)); g_string_append_c_inline (s, ' '); } g_message ("%s",
s->str); (__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free
) ((s), ((!(0)))) : g_string_free_and_steal (s)) : (g_string_free
) ((s), ((!(0))))); }; }; } while (0)
1447 g_string_append (s, theme->name);do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
{ GList *l; GString *s; s = g_string_new ("Current icon themes "
); for (l = icon_theme->priv->themes; l; l = l->next
) { IconTheme *theme = l->data; (__builtin_constant_p (theme
->name) ? __extension__ ({ const char * const __val = (theme
->name); g_string_append_len_inline (s, __val, (__val != (
(void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (s, theme->name, (gssize
) -1)); g_string_append_c_inline (s, ' '); } g_message ("%s",
s->str); (__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free
) ((s), ((!(0)))) : g_string_free_and_steal (s)) : (g_string_free
) ((s), ((!(0))))); }; }; } while (0)
1448 g_string_append_c (s, ' ');do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
{ GList *l; GString *s; s = g_string_new ("Current icon themes "
); for (l = icon_theme->priv->themes; l; l = l->next
) { IconTheme *theme = l->data; (__builtin_constant_p (theme
->name) ? __extension__ ({ const char * const __val = (theme
->name); g_string_append_len_inline (s, __val, (__val != (
(void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (s, theme->name, (gssize
) -1)); g_string_append_c_inline (s, ' '); } g_message ("%s",
s->str); (__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free
) ((s), ((!(0)))) : g_string_free_and_steal (s)) : (g_string_free
) ((s), ((!(0))))); }; }; } while (0)
1449 }do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
{ GList *l; GString *s; s = g_string_new ("Current icon themes "
); for (l = icon_theme->priv->themes; l; l = l->next
) { IconTheme *theme = l->data; (__builtin_constant_p (theme
->name) ? __extension__ ({ const char * const __val = (theme
->name); g_string_append_len_inline (s, __val, (__val != (
(void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (s, theme->name, (gssize
) -1)); g_string_append_c_inline (s, ' '); } g_message ("%s",
s->str); (__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free
) ((s), ((!(0)))) : g_string_free_and_steal (s)) : (g_string_free
) ((s), ((!(0))))); }; }; } while (0)
1450 g_message ("%s", s->str);do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
{ GList *l; GString *s; s = g_string_new ("Current icon themes "
); for (l = icon_theme->priv->themes; l; l = l->next
) { IconTheme *theme = l->data; (__builtin_constant_p (theme
->name) ? __extension__ ({ const char * const __val = (theme
->name); g_string_append_len_inline (s, __val, (__val != (
(void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (s, theme->name, (gssize
) -1)); g_string_append_c_inline (s, ' '); } g_message ("%s",
s->str); (__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free
) ((s), ((!(0)))) : g_string_free_and_steal (s)) : (g_string_free
) ((s), ((!(0))))); }; }; } while (0)
1451 g_string_free (s, TRUE);do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
{ GList *l; GString *s; s = g_string_new ("Current icon themes "
); for (l = icon_theme->priv->themes; l; l = l->next
) { IconTheme *theme = l->data; (__builtin_constant_p (theme
->name) ? __extension__ ({ const char * const __val = (theme
->name); g_string_append_len_inline (s, __val, (__val != (
(void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (s, theme->name, (gssize
) -1)); g_string_append_c_inline (s, ' '); } g_message ("%s",
s->str); (__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free
) ((s), ((!(0)))) : g_string_free_and_steal (s)) : (g_string_free
) ((s), ((!(0))))); }; }; } while (0)
1452 })do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
{ GList *l; GString *s; s = g_string_new ("Current icon themes "
); for (l = icon_theme->priv->themes; l; l = l->next
) { IconTheme *theme = l->data; (__builtin_constant_p (theme
->name) ? __extension__ ({ const char * const __val = (theme
->name); g_string_append_len_inline (s, __val, (__val != (
(void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (s, theme->name, (gssize
) -1)); g_string_append_c_inline (s, ' '); } g_message ("%s",
s->str); (__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free
) ((s), ((!(0)))) : g_string_free_and_steal (s)) : (g_string_free
) ((s), ((!(0))))); }; }; } while (0)
;
1453}
1454
1455static void
1456ensure_valid_themes (CtkIconTheme *icon_theme)
1457{
1458 CtkIconThemePrivate *priv = icon_theme->priv;
1459 gboolean was_valid = priv->themes_valid;
1460
1461 if (priv->loading_themes)
1462 return;
1463 priv->loading_themes = TRUE(!(0));
1464
1465 if (priv->themes_valid)
1466 {
1467 gint64 now = g_get_monotonic_time ();
1468
1469 if ((now - priv->last_stat_time) / G_USEC_PER_SEC1000000 > 5 &&
1470 rescan_themes (icon_theme))
1471 {
1472 g_hash_table_remove_all (priv->info_cache);
1473 blow_themes (icon_theme);
1474 }
1475 }
1476
1477 if (!priv->themes_valid)
1478 {
1479 load_themes (icon_theme);
1480
1481 if (was_valid)
1482 queue_theme_changed (icon_theme);
1483 }
1484
1485 priv->loading_themes = FALSE(0);
1486}
1487
1488/* The LRU cache is a short list of IconInfos that are kept
1489 * alive even though their IconInfo would otherwise have
1490 * been freed, so that we can avoid reloading these
1491 * constantly.
1492 * We put infos on the lru list when nothing otherwise
1493 * references the info. So, when we get a cache hit
1494 * we remove it from the list, and when the proxy
1495 * pixmap is released we put it on the list.
1496 */
1497static void
1498ensure_lru_cache_space (CtkIconTheme *icon_theme)
1499{
1500 CtkIconThemePrivate *priv = icon_theme->priv;
1501 GList *l;
1502
1503 /* Remove last item if LRU full */
1504 l = g_list_nth (priv->info_cache_lru, INFO_CACHE_LRU_SIZE32 - 1);
1505 if (l)
1506 {
1507 CtkIconInfo *icon_info = l->data;
1508
1509 DEBUG_CACHE (("removing (due to out of space) %p (%s %d 0x%x) from LRU cache (cache size %d)\n",
1510 icon_info,
1511 g_strjoinv (",", icon_info->key.icon_names),
1512 icon_info->key.size, icon_info->key.flags,
1513 g_list_length (priv->info_cache_lru)));
1514
1515 priv->info_cache_lru = g_list_delete_link (priv->info_cache_lru, l);
1516 g_object_unref (icon_info);
1517 }
1518}
1519
1520static void
1521add_to_lru_cache (CtkIconTheme *icon_theme,
1522 CtkIconInfo *icon_info)
1523{
1524 CtkIconThemePrivate *priv = icon_theme->priv;
1525
1526 DEBUG_CACHE (("adding %p (%s %d 0x%x) to LRU cache (cache size %d)\n",
1527 icon_info,
1528 g_strjoinv (",", icon_info->key.icon_names),
1529 icon_info->key.size, icon_info->key.flags,
1530 g_list_length (priv->info_cache_lru)));
1531
1532 g_assert (g_list_find (priv->info_cache_lru, icon_info) == NULL)do { if (g_list_find (priv->info_cache_lru, icon_info) == (
(void*)0)) ; else g_assertion_message_expr ("Ctk", "ctkicontheme.c"
, 1532, ((const char*) (__func__)), "g_list_find (priv->info_cache_lru, icon_info) == NULL"
); } while (0)
;
1533
1534 ensure_lru_cache_space (icon_theme);
1535 /* prepend new info to LRU */
1536 priv->info_cache_lru = g_list_prepend (priv->info_cache_lru,
1537 g_object_ref (icon_info)((__typeof__ (icon_info)) (g_object_ref) (icon_info)));
1538}
1539
1540static void
1541ensure_in_lru_cache (CtkIconTheme *icon_theme,
1542 CtkIconInfo *icon_info)
1543{
1544 CtkIconThemePrivate *priv = icon_theme->priv;
1545 GList *l;
1546
1547 l = g_list_find (priv->info_cache_lru, icon_info);
1548 if (l)
1549 {
1550 /* Move to front of LRU if already in it */
1551 priv->info_cache_lru = g_list_remove_link (priv->info_cache_lru, l);
1552 priv->info_cache_lru = g_list_concat (l, priv->info_cache_lru);
1553 }
1554 else
1555 add_to_lru_cache (icon_theme, icon_info);
1556}
1557
1558static void
1559remove_from_lru_cache (CtkIconTheme *icon_theme,
1560 CtkIconInfo *icon_info)
1561{
1562 CtkIconThemePrivate *priv = icon_theme->priv;
1563 if (g_list_find (priv->info_cache_lru, icon_info))
1564 {
1565 DEBUG_CACHE (("removing %p (%s %d 0x%x) from LRU cache (cache size %d)\n",
1566 icon_info,
1567 g_strjoinv (",", icon_info->key.icon_names),
1568 icon_info->key.size, icon_info->key.flags,
1569 g_list_length (priv->info_cache_lru)));
1570
1571 priv->info_cache_lru = g_list_remove (priv->info_cache_lru, icon_info);
1572 g_object_unref (icon_info);
1573 }
1574}
1575
1576static SymbolicPixbufCache *
1577symbolic_pixbuf_cache_new (GdkPixbuf *pixbuf,
1578 const CdkRGBA *fg,
1579 const CdkRGBA *success_color,
1580 const CdkRGBA *warning_color,
1581 const CdkRGBA *error_color,
1582 SymbolicPixbufCache *next)
1583{
1584 SymbolicPixbufCache *cache;
1585
1586 cache = g_new0 (SymbolicPixbufCache, 1)((SymbolicPixbufCache *) g_malloc0_n ((1), sizeof (SymbolicPixbufCache
)))
;
1587 cache->pixbuf = g_object_ref (pixbuf)((__typeof__ (pixbuf)) (g_object_ref) (pixbuf));
1588 if (fg)
1589 cache->fg = *fg;
1590 if (success_color)
1591 cache->success_color = *success_color;
1592 if (warning_color)
1593 cache->warning_color = *warning_color;
1594 if (error_color)
1595 cache->error_color = *error_color;
1596 cache->next = next;
1597 return cache;
1598}
1599
1600static gboolean
1601rgba_matches (const CdkRGBA *a,
1602 const CdkRGBA *b)
1603{
1604 CdkRGBA transparent = { 0 };
1605
1606 /* For matching we treat unset colors as transparent rather
1607 than default, which works as well, because transparent
1608 will never be used for real symbolic icon colors */
1609 if (a == NULL((void*)0))
1610 a = &transparent;
1611
1612 return
1613 fabs(a->red - b->red) < 0.0001 &&
1614 fabs(a->green - b->green) < 0.0001 &&
1615 fabs(a->blue - b->blue) < 0.0001 &&
1616 fabs(a->alpha - b->alpha) < 0.0001;
1617}
1618
1619static SymbolicPixbufCache *
1620symbolic_pixbuf_cache_matches (SymbolicPixbufCache *cache,
1621 const CdkRGBA *fg,
1622 const CdkRGBA *success_color,
1623 const CdkRGBA *warning_color,
1624 const CdkRGBA *error_color)
1625{
1626 while (cache != NULL((void*)0))
1627 {
1628 if (rgba_matches (fg, &cache->fg) &&
1629 rgba_matches (success_color, &cache->success_color) &&
1630 rgba_matches (warning_color, &cache->warning_color) &&
1631 rgba_matches (error_color, &cache->error_color))
1632 return cache;
1633
1634 cache = cache->next;
1635 }
1636
1637 return NULL((void*)0);
1638}
1639
1640static void
1641symbolic_pixbuf_cache_free (SymbolicPixbufCache *cache)
1642{
1643 SymbolicPixbufCache *next;
1644
1645 while (cache != NULL((void*)0))
1646 {
1647 next = cache->next;
1648 g_object_unref (cache->pixbuf);
1649 g_free (cache);
1650
1651 cache = next;
1652 }
1653}
1654
1655static gboolean
1656icon_name_is_symbolic (const gchar *icon_name)
1657{
1658 return g_str_has_suffix (icon_name, "-symbolic")(__builtin_constant_p ("-symbolic")? __extension__ ({ const char
* const __str = (icon_name); const char * const __suffix = (
"-symbolic"); gboolean __result = (0); if (__str == ((void*)0
) || __suffix == ((void*)0)) __result = (g_str_has_suffix) (__str
, __suffix); else { const size_t __str_len = strlen (((__str)
+ !(__str))); const size_t __suffix_len = strlen (((__suffix
) + !(__suffix))); if (__str_len >= __suffix_len) __result
= memcmp (__str + __str_len - __suffix_len, ((__suffix) + !(
__suffix)), __suffix_len) == 0; } __result; }) : (g_str_has_suffix
) (icon_name, "-symbolic") )
1659 || g_str_has_suffix (icon_name, "-symbolic-ltr")(__builtin_constant_p ("-symbolic-ltr")? __extension__ ({ const
char * const __str = (icon_name); const char * const __suffix
= ("-symbolic-ltr"); gboolean __result = (0); if (__str == (
(void*)0) || __suffix == ((void*)0)) __result = (g_str_has_suffix
) (__str, __suffix); else { const size_t __str_len = strlen (
((__str) + !(__str))); const size_t __suffix_len = strlen (((
__suffix) + !(__suffix))); if (__str_len >= __suffix_len) __result
= memcmp (__str + __str_len - __suffix_len, ((__suffix) + !(
__suffix)), __suffix_len) == 0; } __result; }) : (g_str_has_suffix
) (icon_name, "-symbolic-ltr") )
1660 || g_str_has_suffix (icon_name, "-symbolic-rtl")(__builtin_constant_p ("-symbolic-rtl")? __extension__ ({ const
char * const __str = (icon_name); const char * const __suffix
= ("-symbolic-rtl"); gboolean __result = (0); if (__str == (
(void*)0) || __suffix == ((void*)0)) __result = (g_str_has_suffix
) (__str, __suffix); else { const size_t __str_len = strlen (
((__str) + !(__str))); const size_t __suffix_len = strlen (((
__suffix) + !(__suffix))); if (__str_len >= __suffix_len) __result
= memcmp (__str + __str_len - __suffix_len, ((__suffix) + !(
__suffix)), __suffix_len) == 0; } __result; }) : (g_str_has_suffix
) (icon_name, "-symbolic-rtl") )
;
1661}
1662
1663static gboolean
1664icon_uri_is_symbolic (const gchar *icon_name)
1665{
1666 return g_str_has_suffix (icon_name, "-symbolic.svg")(__builtin_constant_p ("-symbolic.svg")? __extension__ ({ const
char * const __str = (icon_name); const char * const __suffix
= ("-symbolic.svg"); gboolean __result = (0); if (__str == (
(void*)0) || __suffix == ((void*)0)) __result = (g_str_has_suffix
) (__str, __suffix); else { const size_t __str_len = strlen (
((__str) + !(__str))); const size_t __suffix_len = strlen (((
__suffix) + !(__suffix))); if (__str_len >= __suffix_len) __result
= memcmp (__str + __str_len - __suffix_len, ((__suffix) + !(
__suffix)), __suffix_len) == 0; } __result; }) : (g_str_has_suffix
) (icon_name, "-symbolic.svg") )
1667 || g_str_has_suffix (icon_name, "-symbolic-ltr.svg")(__builtin_constant_p ("-symbolic-ltr.svg")? __extension__ ({
const char * const __str = (icon_name); const char * const __suffix
= ("-symbolic-ltr.svg"); gboolean __result = (0); if (__str ==
((void*)0) || __suffix == ((void*)0)) __result = (g_str_has_suffix
) (__str, __suffix); else { const size_t __str_len = strlen (
((__str) + !(__str))); const size_t __suffix_len = strlen (((
__suffix) + !(__suffix))); if (__str_len >= __suffix_len) __result
= memcmp (__str + __str_len - __suffix_len, ((__suffix) + !(
__suffix)), __suffix_len) == 0; } __result; }) : (g_str_has_suffix
) (icon_name, "-symbolic-ltr.svg") )
1668 || g_str_has_suffix (icon_name, "-symbolic-rtl.svg")(__builtin_constant_p ("-symbolic-rtl.svg")? __extension__ ({
const char * const __str = (icon_name); const char * const __suffix
= ("-symbolic-rtl.svg"); gboolean __result = (0); if (__str ==
((void*)0) || __suffix == ((void*)0)) __result = (g_str_has_suffix
) (__str, __suffix); else { const size_t __str_len = strlen (
((__str) + !(__str))); const size_t __suffix_len = strlen (((
__suffix) + !(__suffix))); if (__str_len >= __suffix_len) __result
= memcmp (__str + __str_len - __suffix_len, ((__suffix) + !(
__suffix)), __suffix_len) == 0; } __result; }) : (g_str_has_suffix
) (icon_name, "-symbolic-rtl.svg") )
1669 || g_str_has_suffix (icon_name, ".symbolic.png")(__builtin_constant_p (".symbolic.png")? __extension__ ({ const
char * const __str = (icon_name); const char * const __suffix
= (".symbolic.png"); gboolean __result = (0); if (__str == (
(void*)0) || __suffix == ((void*)0)) __result = (g_str_has_suffix
) (__str, __suffix); else { const size_t __str_len = strlen (
((__str) + !(__str))); const size_t __suffix_len = strlen (((
__suffix) + !(__suffix))); if (__str_len >= __suffix_len) __result
= memcmp (__str + __str_len - __suffix_len, ((__suffix) + !(
__suffix)), __suffix_len) == 0; } __result; }) : (g_str_has_suffix
) (icon_name, ".symbolic.png") )
;
1670}
1671
1672static CtkIconInfo *
1673real_choose_icon (CtkIconTheme *icon_theme,
1674 const gchar *icon_names[],
1675 gint size,
1676 gint scale,
1677 CtkIconLookupFlags flags)
1678{
1679 CtkIconThemePrivate *priv;
1680 GList *l;
1681 CtkIconInfo *icon_info = NULL((void*)0);
1682 CtkIconInfo *unscaled_icon_info;
1683 UnthemedIcon *unthemed_icon = NULL((void*)0);
1684 const gchar *icon_name = NULL((void*)0);
1685 gboolean allow_svg;
1686 gboolean use_builtin;
1687 IconTheme *theme = NULL((void*)0);
1688 gint i;
1689 IconInfoKey key;
1690
1691 priv = icon_theme->priv;
1692
1693 ensure_valid_themes (icon_theme);
1694
1695 key.icon_names = (gchar **)icon_names;
1696 key.size = size;
1697 key.scale = scale;
1698 key.flags = flags;
1699
1700 icon_info = g_hash_table_lookup (priv->info_cache, &key);
1701 if (icon_info != NULL((void*)0))
1702 {
1703 DEBUG_CACHE (("cache hit %p (%s %d 0x%x) (cache size %d)\n",
1704 icon_info,
1705 g_strjoinv (",", icon_info->key.icon_names),
1706 icon_info->key.size, icon_info->key.flags,
1707 g_hash_table_size (priv->info_cache)));
1708
1709 icon_info = g_object_ref (icon_info)((__typeof__ (icon_info)) (g_object_ref) (icon_info));
1710 remove_from_lru_cache (icon_theme, icon_info);
1711
1712 return icon_info;
1713 }
1714
1715 if (flags & CTK_ICON_LOOKUP_NO_SVG)
1716 allow_svg = FALSE(0);
1717 else if (flags & CTK_ICON_LOOKUP_FORCE_SVG)
1718 allow_svg = TRUE(!(0));
1719 else
1720 allow_svg = priv->pixbuf_supports_svg;
1721
1722 use_builtin = flags & CTK_ICON_LOOKUP_USE_BUILTIN;
1723
1724 /* This is used in the icontheme unit test */
1725 CTK_NOTE (ICONTHEME,do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
for (i = 0; icon_names[i]; i++) g_message ("\tlookup name: %s"
, icon_names[i]); }; } while (0)
1726 for (i = 0; icon_names[i]; i++)do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
for (i = 0; icon_names[i]; i++) g_message ("\tlookup name: %s"
, icon_names[i]); }; } while (0)
1727 g_message ("\tlookup name: %s", icon_names[i]))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
for (i = 0; icon_names[i]; i++) g_message ("\tlookup name: %s"
, icon_names[i]); }; } while (0)
;
1728
1729 /* For symbolic icons, do a search in all registered themes first;
1730 * a theme that inherits them from a parent theme might provide
1731 * an alternative full-color version, but still expect the symbolic icon
1732 * to show up instead.
1733 *
1734 * In other words: We prefer symbolic icons in inherited themes over
1735 * generic icons in the theme.
1736 */
1737 for (l = priv->themes; l; l = l->next)
1738 {
1739 theme = l->data;
1740 for (i = 0; icon_names[i] && icon_name_is_symbolic (icon_names[i]); i++)
1741 {
1742 icon_name = icon_names[i];
1743 icon_info = theme_lookup_icon (theme, icon_name, size, scale, allow_svg, use_builtin);
1744 if (icon_info)
1745 goto out;
1746 }
1747 }
1748
1749 for (l = priv->themes; l; l = l->next)
1750 {
1751 theme = l->data;
1752
1753 for (i = 0; icon_names[i]; i++)
1754 {
1755 icon_name = icon_names[i];
1756 icon_info = theme_lookup_icon (theme, icon_name, size, scale, allow_svg, use_builtin);
1757 if (icon_info)
1758 goto out;
1759 }
1760 }
1761
1762 theme = NULL((void*)0);
1763
1764 for (i = 0; icon_names[i]; i++)
1765 {
1766 unthemed_icon = g_hash_table_lookup (priv->unthemed_icons, icon_names[i]);
1767 if (unthemed_icon)
1768 break;
1769 }
1770#ifdef G_OS_WIN32
1771 /* Still not found an icon, check if reference to a Win32 resource */
1772 if (!unthemed_icon)
1773 {
1774 gchar **resources;
1775 HICON hIcon = NULL((void*)0);
1776
1777 resources = g_strsplit (icon_names[0], ",", 0);
1778 if (resources[0])
1779 {
1780 wchar_t *wfile = g_utf8_to_utf16 (resources[0], -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
1781 ExtractIconExW (wfile, resources[1] ? atoi (resources[1]) : 0, &hIcon, NULL((void*)0), 1);
1782 g_free (wfile);
1783 }
1784
1785 if (hIcon)
1786 {
1787 icon_info = icon_info_new (ICON_THEME_DIR_UNTHEMED, size, 1);
1788 icon_info->cache_pixbuf = cdk_win32_icon_to_pixbuf_libctk_only (hIcon, NULL((void*)0), NULL((void*)0));
1789 DestroyIcon (hIcon);
1790 }
1791 g_strfreev (resources);
1792 }
1793#endif
1794
1795 if (unthemed_icon)
1796 {
1797 icon_info = icon_info_new (ICON_THEME_DIR_UNTHEMED, size, 1);
1798
1799 /* A SVG icon, when allowed, beats out a XPM icon, but not a PNG icon */
1800 if (allow_svg &&
1801 unthemed_icon->svg_filename &&
1802 (!unthemed_icon->no_svg_filename ||
1803 suffix_from_name (unthemed_icon->no_svg_filename) < ICON_SUFFIX_PNG))
1804 icon_info->filename = g_strdup (unthemed_icon->svg_filename)g_strdup_inline (unthemed_icon->svg_filename);
1805 else if (unthemed_icon->no_svg_filename)
1806 icon_info->filename = g_strdup (unthemed_icon->no_svg_filename)g_strdup_inline (unthemed_icon->no_svg_filename);
1807 else
1808 {
1809 static gboolean warned_once = FALSE(0);
1810
1811 if (!warned_once)
1812 {
1813 g_warning ("Found an icon but could not load it. "
1814 "Most likely gdk-pixbuf does not provide SVG support.");
1815 warned_once = TRUE(!(0));
1816 }
1817
1818 g_clear_object (&icon_info)do { _Static_assert (sizeof *((&icon_info)) == sizeof (gpointer
), "Expression evaluates to false"); __typeof__ (((&icon_info
))) _pp = ((&icon_info)); __typeof__ (*((&icon_info))
) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref) (
_ptr); } while (0)
;
1819 goto out;
1820 }
1821
1822 if (unthemed_icon->is_resource)
1823 {
1824 gchar *uri;
1825 uri = g_strconcat ("resource://", icon_info->filename, NULL((void*)0));
1826 icon_info->icon_file = g_file_new_for_uri (uri);
1827 g_free (uri);
1828 }
1829 else
1830 icon_info->icon_file = g_file_new_for_path (icon_info->filename);
1831
1832 icon_info->is_svg = suffix_from_name (icon_info->filename) == ICON_SUFFIX_SVG;
1833 icon_info->is_resource = unthemed_icon->is_resource;
1834 }
1835
1836 out:
1837 if (icon_info)
1838 {
1839 icon_info->desired_size = size;
1840 icon_info->desired_scale = scale;
1841 icon_info->forced_size = (flags & CTK_ICON_LOOKUP_FORCE_SIZE) != 0;
1842
1843 /* In case we're not scaling the icon we want to reuse the exact same
1844 * size as a scale==1 lookup would be, rather than not scaling at all
1845 * and causing a different layout
1846 */
1847 icon_info->unscaled_scale = 1.0;
1848 if (scale != 1 && !icon_info->forced_size && theme != NULL((void*)0))
1849 {
1850 unscaled_icon_info = theme_lookup_icon (theme, icon_name, size, 1, allow_svg, use_builtin);
1851 if (unscaled_icon_info)
1852 {
1853 icon_info->unscaled_scale =
1854 (gdouble) unscaled_icon_info->dir_size * scale / (icon_info->dir_size * icon_info->dir_scale);
1855 g_object_unref (unscaled_icon_info);
1856 }
1857 }
1858
1859 icon_info->key.icon_names = g_strdupv ((char **)icon_names);
1860 icon_info->key.size = size;
1861 icon_info->key.scale = scale;
1862 icon_info->key.flags = flags;
1863 icon_info->in_cache = icon_theme;
1864 DEBUG_CACHE (("adding %p (%s %d 0x%x) to cache (cache size %d)\n",
1865 icon_info,
1866 g_strjoinv (",", icon_info->key.icon_names),
1867 icon_info->key.size, icon_info->key.flags,
1868 g_hash_table_size (priv->info_cache)));
1869 g_hash_table_insert (priv->info_cache, &icon_info->key, icon_info);
1870 }
1871 else
1872 {
1873 static gboolean check_for_default_theme = TRUE(!(0));
1874 gchar *default_theme_path;
1875 gboolean found = FALSE(0);
1876
1877 if (check_for_default_theme)
1878 {
1879 check_for_default_theme = FALSE(0);
1880
1881 for (i = 0; !found && i < priv->search_path_len; i++)
1882 {
1883 default_theme_path = g_build_filename (priv->search_path[i],
1884 FALLBACK_ICON_THEME"hicolor",
1885 "index.theme",
1886 NULL((void*)0));
1887 found = g_file_test (default_theme_path, G_FILE_TEST_IS_REGULAR);
1888 g_free (default_theme_path);
1889 }
1890
1891 if (!found)
1892 {
1893 g_warning ("Could not find the icon '%s'. The '%s' theme\n"
1894 "was not found either, perhaps you need to install it.\n"
1895 "You can get a copy from:\n"
1896 "\t%s",
1897 icon_names[0], FALLBACK_ICON_THEME"hicolor", "http://icon-theme.freedesktop.org/releases");
1898 }
1899 }
1900 }
1901
1902 return icon_info;
1903}
1904
1905static void
1906icon_name_list_add_icon (GPtrArray *icons,
1907 const gchar *dir_suffix,
1908 gchar *icon_name)
1909{
1910 if (dir_suffix)
1911 g_ptr_array_add (icons, g_strconcat (icon_name, dir_suffix, NULL((void*)0)));
1912 g_ptr_array_add (icons, icon_name);
1913}
1914
1915static CtkIconInfo *
1916choose_icon (CtkIconTheme *icon_theme,
1917 const gchar *icon_names[],
1918 gint size,
1919 gint scale,
1920 CtkIconLookupFlags flags)
1921{
1922 gboolean has_regular = FALSE(0), has_symbolic = FALSE(0);
1923 CtkIconInfo *icon_info;
1924 GPtrArray *new_names;
1925 const gchar *dir_suffix;
1926 guint i;
1927
1928 if (flags & CTK_ICON_LOOKUP_DIR_LTR)
1929 dir_suffix = "-ltr";
1930 else if (flags & CTK_ICON_LOOKUP_DIR_RTL)
1931 dir_suffix = "-rtl";
1932 else
1933 dir_suffix = NULL((void*)0);
1934
1935 for (i = 0; icon_names[i]; i++)
1936 {
1937 if (icon_name_is_symbolic (icon_names[i]))
1938 has_symbolic = TRUE(!(0));
1939 else
1940 has_regular = TRUE(!(0));
1941 }
1942
1943 if ((flags & CTK_ICON_LOOKUP_FORCE_REGULAR) && has_symbolic)
1944 {
1945 new_names = g_ptr_array_new_with_free_func (g_free);
1946 for (i = 0; icon_names[i]; i++)
1947 {
1948 if (icon_name_is_symbolic (icon_names[i]))
1949 icon_name_list_add_icon (new_names, dir_suffix, g_strndup (icon_names[i], strlen (icon_names[i]) - strlen ("-symbolic")));
1950 else
1951 icon_name_list_add_icon (new_names, dir_suffix, g_strdup (icon_names[i])g_strdup_inline (icon_names[i]));
1952 }
1953 for (i = 0; icon_names[i]; i++)
1954 {
1955 if (icon_name_is_symbolic (icon_names[i]))
1956 icon_name_list_add_icon (new_names, dir_suffix, g_strdup (icon_names[i])g_strdup_inline (icon_names[i]));
1957 }
1958 g_ptr_array_add (new_names, NULL((void*)0));
1959
1960 icon_info = real_choose_icon (icon_theme,
1961 (const gchar **) new_names->pdata,
1962 size,
1963 scale,
1964 flags & ~(CTK_ICON_LOOKUP_FORCE_REGULAR | CTK_ICON_LOOKUP_FORCE_SYMBOLIC));
1965
1966 g_ptr_array_free (new_names, TRUE(!(0)));
1967 }
1968 else if ((flags & CTK_ICON_LOOKUP_FORCE_SYMBOLIC) && has_regular)
1969 {
1970 new_names = g_ptr_array_new_with_free_func (g_free);
1971 for (i = 0; icon_names[i]; i++)
1972 {
1973 if (!icon_name_is_symbolic (icon_names[i]))
1974 icon_name_list_add_icon (new_names, dir_suffix, g_strconcat (icon_names[i], "-symbolic", NULL((void*)0)));
1975 else
1976 icon_name_list_add_icon (new_names, dir_suffix, g_strdup (icon_names[i])g_strdup_inline (icon_names[i]));
1977 }
1978 for (i = 0; icon_names[i]; i++)
1979 {
1980 if (!icon_name_is_symbolic (icon_names[i]))
1981 icon_name_list_add_icon (new_names, dir_suffix, g_strdup (icon_names[i])g_strdup_inline (icon_names[i]));
1982 }
1983 g_ptr_array_add (new_names, NULL((void*)0));
1984
1985 icon_info = real_choose_icon (icon_theme,
1986 (const gchar **) new_names->pdata,
1987 size,
1988 scale,
1989 flags & ~(CTK_ICON_LOOKUP_FORCE_REGULAR | CTK_ICON_LOOKUP_FORCE_SYMBOLIC));
1990
1991 g_ptr_array_free (new_names, TRUE(!(0)));
1992 }
1993 else if (dir_suffix)
1994 {
1995 new_names = g_ptr_array_new_with_free_func (g_free);
1996 for (i = 0; icon_names[i]; i++)
1997 {
1998 icon_name_list_add_icon (new_names, dir_suffix, g_strdup (icon_names[i])g_strdup_inline (icon_names[i]));
1999 }
2000 g_ptr_array_add (new_names, NULL((void*)0));
2001
2002 icon_info = real_choose_icon (icon_theme,
2003 (const gchar **) new_names->pdata,
2004 size,
2005 scale,
2006 flags & ~(CTK_ICON_LOOKUP_FORCE_REGULAR | CTK_ICON_LOOKUP_FORCE_SYMBOLIC));
2007
2008 g_ptr_array_free (new_names, TRUE(!(0)));
2009 }
2010 else
2011 {
2012 icon_info = real_choose_icon (icon_theme,
2013 icon_names,
2014 size,
2015 scale,
2016 flags & ~(CTK_ICON_LOOKUP_FORCE_REGULAR | CTK_ICON_LOOKUP_FORCE_SYMBOLIC));
2017 }
2018
2019 return icon_info;
2020}
2021
2022/**
2023 * ctk_icon_theme_lookup_icon:
2024 * @icon_theme: a #CtkIconTheme
2025 * @icon_name: the name of the icon to lookup
2026 * @size: desired icon size
2027 * @flags: flags modifying the behavior of the icon lookup
2028 *
2029 * Looks up a named icon and returns a #CtkIconInfo containing
2030 * information such as the filename of the icon. The icon
2031 * can then be rendered into a pixbuf using
2032 * ctk_icon_info_load_icon(). (ctk_icon_theme_load_icon()
2033 * combines these two steps if all you need is the pixbuf.)
2034 *
2035 * When rendering on displays with high pixel densities you should not
2036 * use a @size multiplied by the scaling factor returned by functions
2037 * like cdk_window_get_scale_factor(). Instead, you should use
2038 * ctk_icon_theme_lookup_icon_for_scale(), as the assets loaded
2039 * for a given scaling factor may be different.
2040 *
2041 * Returns: (nullable) (transfer full): a #CtkIconInfo object
2042 * containing information about the icon, or %NULL if the
2043 * icon wasn’t found.
2044 *
2045 * Since: 2.4
2046 */
2047CtkIconInfo *
2048ctk_icon_theme_lookup_icon (CtkIconTheme *icon_theme,
2049 const gchar *icon_name,
2050 gint size,
2051 CtkIconLookupFlags flags)
2052{
2053 g_return_val_if_fail (CTK_IS_ICON_THEME (icon_theme), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((icon_theme)); GType __t = ((ctk_icon_theme_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ICON_THEME (icon_theme)"); return (((
void*)0)); } } while (0)
;
2054 g_return_val_if_fail (icon_name != NULL, NULL)do { if ((icon_name != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "icon_name != NULL"); return
(((void*)0)); } } while (0)
;
2055 g_return_val_if_fail ((flags & CTK_ICON_LOOKUP_NO_SVG) == 0 ||do { if (((flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags
& CTK_ICON_LOOKUP_FORCE_SVG) == 0)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "(flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags & CTK_ICON_LOOKUP_FORCE_SVG) == 0"
); return (((void*)0)); } } while (0)
2056 (flags & CTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL)do { if (((flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags
& CTK_ICON_LOOKUP_FORCE_SVG) == 0)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "(flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags & CTK_ICON_LOOKUP_FORCE_SVG) == 0"
); return (((void*)0)); } } while (0)
;
2057
2058 CTK_NOTE (ICONTHEME, g_message ("looking up icon %s", icon_name))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
g_message ("looking up icon %s", icon_name); }; } while (0)
;
2059
2060 return ctk_icon_theme_lookup_icon_for_scale (icon_theme, icon_name,
2061 size, 1, flags);
2062}
2063
2064/**
2065 * ctk_icon_theme_lookup_icon_for_scale:
2066 * @icon_theme: a #CtkIconTheme
2067 * @icon_name: the name of the icon to lookup
2068 * @size: desired icon size
2069 * @scale: the desired scale
2070 * @flags: flags modifying the behavior of the icon lookup
2071 *
2072 * Looks up a named icon for a particular window scale and returns a
2073 * #CtkIconInfo containing information such as the filename of the
2074 * icon. The icon can then be rendered into a pixbuf using
2075 * ctk_icon_info_load_icon(). (ctk_icon_theme_load_icon() combines
2076 * these two steps if all you need is the pixbuf.)
2077 *
2078 * Returns: (nullable) (transfer full): a #CtkIconInfo object
2079 * containing information about the icon, or %NULL if the
2080 * icon wasn’t found.
2081 *
2082 * Since: 3.10
2083 */
2084CtkIconInfo *
2085ctk_icon_theme_lookup_icon_for_scale (CtkIconTheme *icon_theme,
2086 const gchar *icon_name,
2087 gint size,
2088 gint scale,
2089 CtkIconLookupFlags flags)
2090{
2091 CtkIconInfo *info;
2092
2093 g_return_val_if_fail (CTK_IS_ICON_THEME (icon_theme), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((icon_theme)); GType __t = ((ctk_icon_theme_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ICON_THEME (icon_theme)"); return (((
void*)0)); } } while (0)
;
2094 g_return_val_if_fail (icon_name != NULL, NULL)do { if ((icon_name != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "icon_name != NULL"); return
(((void*)0)); } } while (0)
;
2095 g_return_val_if_fail ((flags & CTK_ICON_LOOKUP_NO_SVG) == 0 ||do { if (((flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags
& CTK_ICON_LOOKUP_FORCE_SVG) == 0)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "(flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags & CTK_ICON_LOOKUP_FORCE_SVG) == 0"
); return (((void*)0)); } } while (0)
2096 (flags & CTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL)do { if (((flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags
& CTK_ICON_LOOKUP_FORCE_SVG) == 0)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "(flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags & CTK_ICON_LOOKUP_FORCE_SVG) == 0"
); return (((void*)0)); } } while (0)
;
2097 g_return_val_if_fail (scale >= 1, NULL)do { if ((scale >= 1)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "scale >= 1"); return
(((void*)0)); } } while (0)
;
2098
2099 CTK_NOTE (ICONTHEME, g_message ("looking up icon %s for scale %d", icon_name, scale))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
g_message ("looking up icon %s for scale %d", icon_name, scale
); }; } while (0)
;
2100
2101 if (flags & CTK_ICON_LOOKUP_GENERIC_FALLBACK)
2102 {
2103 gchar **names, **nonsymbolic_names;
2104 gint dashes, i;
2105 gchar *p, *nonsymbolic_icon_name;
2106 gboolean is_symbolic;
2107
2108 is_symbolic = icon_name_is_symbolic (icon_name);
2109 if (is_symbolic)
2110 nonsymbolic_icon_name = g_strndup (icon_name, strlen (icon_name) - strlen ("-symbolic"));
2111 else
2112 nonsymbolic_icon_name = g_strdup (icon_name)g_strdup_inline (icon_name);
2113
2114 dashes = 0;
2115 for (p = (gchar *) nonsymbolic_icon_name; *p; p++)
2116 if (*p == '-')
2117 dashes++;
2118
2119 nonsymbolic_names = g_new (gchar *, dashes + 2)((gchar * *) g_malloc_n ((dashes + 2), sizeof (gchar *)));
2120 nonsymbolic_names[0] = nonsymbolic_icon_name;
2121
2122 for (i = 1; i <= dashes; i++)
2123 {
2124 nonsymbolic_names[i] = g_strdup (nonsymbolic_names[i - 1])g_strdup_inline (nonsymbolic_names[i - 1]);
2125 p = strrchr (nonsymbolic_names[i], '-');
2126 *p = '\0';
2127 }
2128 nonsymbolic_names[dashes + 1] = NULL((void*)0);
2129
2130 if (is_symbolic)
2131 {
2132 names = g_new (gchar *, 2 * dashes + 3)((gchar * *) g_malloc_n ((2 * dashes + 3), sizeof (gchar *)));
2133 for (i = 0; nonsymbolic_names[i] != NULL((void*)0); i++)
2134 {
2135 names[i] = g_strconcat (nonsymbolic_names[i], "-symbolic", NULL((void*)0));
2136 names[dashes + 1 + i] = nonsymbolic_names[i];
2137 }
2138
2139 names[dashes + 1 + i] = NULL((void*)0);
2140 g_free (nonsymbolic_names);
2141 }
2142 else
2143 {
2144 names = nonsymbolic_names;
2145 }
2146
2147 info = choose_icon (icon_theme, (const gchar **) names, size, scale, flags);
2148
2149 g_strfreev (names);
2150 }
2151 else
2152 {
2153 const gchar *names[2];
2154
2155 names[0] = icon_name;
2156 names[1] = NULL((void*)0);
2157
2158 info = choose_icon (icon_theme, names, size, scale, flags);
2159 }
2160
2161 return info;
2162}
2163
2164/**
2165 * ctk_icon_theme_choose_icon:
2166 * @icon_theme: a #CtkIconTheme
2167 * @icon_names: (array zero-terminated=1): %NULL-terminated array of
2168 * icon names to lookup
2169 * @size: desired icon size
2170 * @flags: flags modifying the behavior of the icon lookup
2171 *
2172 * Looks up a named icon and returns a #CtkIconInfo containing
2173 * information such as the filename of the icon. The icon
2174 * can then be rendered into a pixbuf using
2175 * ctk_icon_info_load_icon(). (ctk_icon_theme_load_icon()
2176 * combines these two steps if all you need is the pixbuf.)
2177 *
2178 * If @icon_names contains more than one name, this function
2179 * tries them all in the given order before falling back to
2180 * inherited icon themes.
2181 *
2182 * Returns: (nullable) (transfer full): a #CtkIconInfo object
2183 * containing information about the icon, or %NULL if the icon wasn’t
2184 * found.
2185 *
2186 * Since: 2.12
2187 */
2188CtkIconInfo *
2189ctk_icon_theme_choose_icon (CtkIconTheme *icon_theme,
2190 const gchar *icon_names[],
2191 gint size,
2192 CtkIconLookupFlags flags)
2193{
2194 g_return_val_if_fail (CTK_IS_ICON_THEME (icon_theme), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((icon_theme)); GType __t = ((ctk_icon_theme_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ICON_THEME (icon_theme)"); return (((
void*)0)); } } while (0)
;
2195 g_return_val_if_fail (icon_names != NULL, NULL)do { if ((icon_names != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "icon_names != NULL"); return
(((void*)0)); } } while (0)
;
2196 g_return_val_if_fail ((flags & CTK_ICON_LOOKUP_NO_SVG) == 0 ||do { if (((flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags
& CTK_ICON_LOOKUP_FORCE_SVG) == 0)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "(flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags & CTK_ICON_LOOKUP_FORCE_SVG) == 0"
); return (((void*)0)); } } while (0)
2197 (flags & CTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL)do { if (((flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags
& CTK_ICON_LOOKUP_FORCE_SVG) == 0)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "(flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags & CTK_ICON_LOOKUP_FORCE_SVG) == 0"
); return (((void*)0)); } } while (0)
;
2198 g_warn_if_fail ((flags & CTK_ICON_LOOKUP_GENERIC_FALLBACK) == 0)do { if ((flags & CTK_ICON_LOOKUP_GENERIC_FALLBACK) == 0)
; else g_warn_message ("Ctk", "ctkicontheme.c", 2198, ((const
char*) (__func__)), "(flags & CTK_ICON_LOOKUP_GENERIC_FALLBACK) == 0"
); } while (0)
;
2199
2200 return choose_icon (icon_theme, icon_names, size, 1, flags);
2201}
2202
2203/**
2204 * ctk_icon_theme_choose_icon_for_scale:
2205 * @icon_theme: a #CtkIconTheme
2206 * @icon_names: (array zero-terminated=1): %NULL-terminated
2207 * array of icon names to lookup
2208 * @size: desired icon size
2209 * @scale: desired scale
2210 * @flags: flags modifying the behavior of the icon lookup
2211 *
2212 * Looks up a named icon for a particular window scale and returns
2213 * a #CtkIconInfo containing information such as the filename of the
2214 * icon. The icon can then be rendered into a pixbuf using
2215 * ctk_icon_info_load_icon(). (ctk_icon_theme_load_icon()
2216 * combines these two steps if all you need is the pixbuf.)
2217 *
2218 * If @icon_names contains more than one name, this function
2219 * tries them all in the given order before falling back to
2220 * inherited icon themes.
2221 *
2222 * Returns: (nullable) (transfer full): a #CtkIconInfo object
2223 * containing information about the icon, or %NULL if the
2224 * icon wasn’t found.
2225 *
2226 * Since: 3.10
2227 */
2228CtkIconInfo *
2229ctk_icon_theme_choose_icon_for_scale (CtkIconTheme *icon_theme,
2230 const gchar *icon_names[],
2231 gint size,
2232 gint scale,
2233 CtkIconLookupFlags flags)
2234{
2235 g_return_val_if_fail (CTK_IS_ICON_THEME (icon_theme), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((icon_theme)); GType __t = ((ctk_icon_theme_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ICON_THEME (icon_theme)"); return (((
void*)0)); } } while (0)
;
2236 g_return_val_if_fail (icon_names != NULL, NULL)do { if ((icon_names != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "icon_names != NULL"); return
(((void*)0)); } } while (0)
;
2237 g_return_val_if_fail ((flags & CTK_ICON_LOOKUP_NO_SVG) == 0 ||do { if (((flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags
& CTK_ICON_LOOKUP_FORCE_SVG) == 0)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "(flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags & CTK_ICON_LOOKUP_FORCE_SVG) == 0"
); return (((void*)0)); } } while (0)
2238 (flags & CTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL)do { if (((flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags
& CTK_ICON_LOOKUP_FORCE_SVG) == 0)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "(flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags & CTK_ICON_LOOKUP_FORCE_SVG) == 0"
); return (((void*)0)); } } while (0)
;
2239 g_return_val_if_fail (scale >= 1, NULL)do { if ((scale >= 1)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "scale >= 1"); return
(((void*)0)); } } while (0)
;
2240 g_warn_if_fail ((flags & CTK_ICON_LOOKUP_GENERIC_FALLBACK) == 0)do { if ((flags & CTK_ICON_LOOKUP_GENERIC_FALLBACK) == 0)
; else g_warn_message ("Ctk", "ctkicontheme.c", 2240, ((const
char*) (__func__)), "(flags & CTK_ICON_LOOKUP_GENERIC_FALLBACK) == 0"
); } while (0)
;
2241
2242 return choose_icon (icon_theme, icon_names, size, scale, flags);
2243}
2244
2245
2246/* Error quark */
2247GQuark
2248ctk_icon_theme_error_quark (void)
2249{
2250 return g_quark_from_static_string ("ctk-icon-theme-error-quark");
2251}
2252
2253/**
2254 * ctk_icon_theme_load_icon:
2255 * @icon_theme: a #CtkIconTheme
2256 * @icon_name: the name of the icon to lookup
2257 * @size: the desired icon size. The resulting icon may not be
2258 * exactly this size; see ctk_icon_info_load_icon().
2259 * @flags: flags modifying the behavior of the icon lookup
2260 * @error: (allow-none): Location to store error information on failure,
2261 * or %NULL.
2262 *
2263 * Looks up an icon in an icon theme, scales it to the given size
2264 * and renders it into a pixbuf. This is a convenience function;
2265 * if more details about the icon are needed, use
2266 * ctk_icon_theme_lookup_icon() followed by ctk_icon_info_load_icon().
2267 *
2268 * Note that you probably want to listen for icon theme changes and
2269 * update the icon. This is usually done by connecting to the
2270 * CtkWidget::style-set signal. If for some reason you do not want to
2271 * update the icon when the icon theme changes, you should consider
2272 * using gdk_pixbuf_copy() to make a private copy of the pixbuf
2273 * returned by this function. Otherwise CTK+ may need to keep the old
2274 * icon theme loaded, which would be a waste of memory.
2275 *
2276 * Returns: (nullable) (transfer full): the rendered icon; this may be
2277 * a newly created icon or a new reference to an internal icon, so
2278 * you must not modify the icon. Use g_object_unref() to release
2279 * your reference to the icon. %NULL if the icon isn’t found.
2280 *
2281 * Since: 2.4
2282 */
2283GdkPixbuf *
2284ctk_icon_theme_load_icon (CtkIconTheme *icon_theme,
2285 const gchar *icon_name,
2286 gint size,
2287 CtkIconLookupFlags flags,
2288 GError **error)
2289{
2290 g_return_val_if_fail (CTK_IS_ICON_THEME (icon_theme), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((icon_theme)); GType __t = ((ctk_icon_theme_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ICON_THEME (icon_theme)"); return (((
void*)0)); } } while (0)
;
2291 g_return_val_if_fail (icon_name != NULL, NULL)do { if ((icon_name != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "icon_name != NULL"); return
(((void*)0)); } } while (0)
;
2292 g_return_val_if_fail ((flags & CTK_ICON_LOOKUP_NO_SVG) == 0 ||do { if (((flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags
& CTK_ICON_LOOKUP_FORCE_SVG) == 0)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "(flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags & CTK_ICON_LOOKUP_FORCE_SVG) == 0"
); return (((void*)0)); } } while (0)
2293 (flags & CTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL)do { if (((flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags
& CTK_ICON_LOOKUP_FORCE_SVG) == 0)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "(flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags & CTK_ICON_LOOKUP_FORCE_SVG) == 0"
); return (((void*)0)); } } while (0)
;
2294 g_return_val_if_fail (error == NULL || *error == NULL, NULL)do { if ((error == ((void*)0) || *error == ((void*)0))) { } else
{ g_return_if_fail_warning ("Ctk", ((const char*) (__func__)
), "error == NULL || *error == NULL"); return (((void*)0)); }
} while (0)
;
2295
2296 return ctk_icon_theme_load_icon_for_scale (icon_theme, icon_name,
2297 size, 1, flags, error);
2298}
2299
2300/**
2301 * ctk_icon_theme_load_icon_for_scale:
2302 * @icon_theme: a #CtkIconTheme
2303 * @icon_name: the name of the icon to lookup
2304 * @size: the desired icon size. The resulting icon may not be
2305 * exactly this size; see ctk_icon_info_load_icon().
2306 * @scale: desired scale
2307 * @flags: flags modifying the behavior of the icon lookup
2308 * @error: (allow-none): Location to store error information on failure,
2309 * or %NULL.
2310 *
2311 * Looks up an icon in an icon theme for a particular window scale,
2312 * scales it to the given size and renders it into a pixbuf. This is a
2313 * convenience function; if more details about the icon are needed,
2314 * use ctk_icon_theme_lookup_icon() followed by
2315 * ctk_icon_info_load_icon().
2316 *
2317 * Note that you probably want to listen for icon theme changes and
2318 * update the icon. This is usually done by connecting to the
2319 * CtkWidget::style-set signal. If for some reason you do not want to
2320 * update the icon when the icon theme changes, you should consider
2321 * using gdk_pixbuf_copy() to make a private copy of the pixbuf
2322 * returned by this function. Otherwise CTK+ may need to keep the old
2323 * icon theme loaded, which would be a waste of memory.
2324 *
2325 * Returns: (nullable) (transfer full): the rendered icon; this may be
2326 * a newly created icon or a new reference to an internal icon, so
2327 * you must not modify the icon. Use g_object_unref() to release
2328 * your reference to the icon. %NULL if the icon isn’t found.
2329 *
2330 * Since: 3.10
2331 */
2332GdkPixbuf *
2333ctk_icon_theme_load_icon_for_scale (CtkIconTheme *icon_theme,
2334 const gchar *icon_name,
2335 gint size,
2336 gint scale,
2337 CtkIconLookupFlags flags,
2338 GError **error)
2339{
2340 CtkIconInfo *icon_info;
2341 GdkPixbuf *pixbuf = NULL((void*)0);
2342
2343 g_return_val_if_fail (CTK_IS_ICON_THEME (icon_theme), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((icon_theme)); GType __t = ((ctk_icon_theme_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ICON_THEME (icon_theme)"); return (((
void*)0)); } } while (0)
;
2344 g_return_val_if_fail (icon_name != NULL, NULL)do { if ((icon_name != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "icon_name != NULL"); return
(((void*)0)); } } while (0)
;
2345 g_return_val_if_fail ((flags & CTK_ICON_LOOKUP_NO_SVG) == 0 ||do { if (((flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags
& CTK_ICON_LOOKUP_FORCE_SVG) == 0)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "(flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags & CTK_ICON_LOOKUP_FORCE_SVG) == 0"
); return (((void*)0)); } } while (0)
2346 (flags & CTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL)do { if (((flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags
& CTK_ICON_LOOKUP_FORCE_SVG) == 0)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "(flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags & CTK_ICON_LOOKUP_FORCE_SVG) == 0"
); return (((void*)0)); } } while (0)
;
2347 g_return_val_if_fail (error == NULL || *error == NULL, NULL)do { if ((error == ((void*)0) || *error == ((void*)0))) { } else
{ g_return_if_fail_warning ("Ctk", ((const char*) (__func__)
), "error == NULL || *error == NULL"); return (((void*)0)); }
} while (0)
;
2348 g_return_val_if_fail (scale >= 1, NULL)do { if ((scale >= 1)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "scale >= 1"); return
(((void*)0)); } } while (0)
;
2349
2350 icon_info = ctk_icon_theme_lookup_icon_for_scale (icon_theme, icon_name, size, scale,
2351 flags | CTK_ICON_LOOKUP_USE_BUILTIN);
2352 if (!icon_info)
2353 {
2354 g_set_error (error, CTK_ICON_THEME_ERRORctk_icon_theme_error_quark (), CTK_ICON_THEME_NOT_FOUND,
2355 _("Icon '%s' not present in theme %s")((char *) g_dgettext ("ctk30", "Icon '%s' not present in theme %s"
))
, icon_name, icon_theme->priv->current_theme);
2356 return NULL((void*)0);
2357 }
2358
2359 pixbuf = ctk_icon_info_load_icon (icon_info, error);
2360 g_prefix_error (error, "Failed to load %s: ", icon_info->filename);
2361 g_object_unref (icon_info);
2362
2363 return pixbuf;
2364}
2365
2366/**
2367 * ctk_icon_theme_load_surface:
2368 * @icon_theme: a #CtkIconTheme
2369 * @icon_name: the name of the icon to lookup
2370 * @size: the desired icon size. The resulting icon may not be
2371 * exactly this size; see ctk_icon_info_load_icon().
2372 * @scale: desired scale
2373 * @for_window: (allow-none): #CdkWindow to optimize drawing for, or %NULL
2374 * @flags: flags modifying the behavior of the icon lookup
2375 * @error: (allow-none): Location to store error information on failure,
2376 * or %NULL.
2377 *
2378 * Looks up an icon in an icon theme for a particular window scale,
2379 * scales it to the given size and renders it into a cairo surface. This is a
2380 * convenience function; if more details about the icon are needed,
2381 * use ctk_icon_theme_lookup_icon() followed by
2382 * ctk_icon_info_load_surface().
2383 *
2384 * Note that you probably want to listen for icon theme changes and
2385 * update the icon. This is usually done by connecting to the
2386 * CtkWidget::style-set signal.
2387 *
2388 * Returns: (nullable) (transfer full): the rendered icon; this may be
2389 * a newly created icon or a new reference to an internal icon, so
2390 * you must not modify the icon. Use cairo_surface_destroy() to
2391 * release your reference to the icon. %NULL if the icon isn’t
2392 * found.
2393 *
2394 * Since: 3.10
2395 */
2396cairo_surface_t *
2397ctk_icon_theme_load_surface (CtkIconTheme *icon_theme,
2398 const gchar *icon_name,
2399 gint size,
2400 gint scale,
2401 CdkWindow *for_window,
2402 CtkIconLookupFlags flags,
2403 GError **error)
2404{
2405 CtkIconInfo *icon_info;
2406 cairo_surface_t *surface = NULL((void*)0);
2407
2408 g_return_val_if_fail (CTK_IS_ICON_THEME (icon_theme), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((icon_theme)); GType __t = ((ctk_icon_theme_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ICON_THEME (icon_theme)"); return (((
void*)0)); } } while (0)
;
2409 g_return_val_if_fail (icon_name != NULL, NULL)do { if ((icon_name != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "icon_name != NULL"); return
(((void*)0)); } } while (0)
;
2410 g_return_val_if_fail ((flags & CTK_ICON_LOOKUP_NO_SVG) == 0 ||do { if (((flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags
& CTK_ICON_LOOKUP_FORCE_SVG) == 0)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "(flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags & CTK_ICON_LOOKUP_FORCE_SVG) == 0"
); return (((void*)0)); } } while (0)
2411 (flags & CTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL)do { if (((flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags
& CTK_ICON_LOOKUP_FORCE_SVG) == 0)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "(flags & CTK_ICON_LOOKUP_NO_SVG) == 0 || (flags & CTK_ICON_LOOKUP_FORCE_SVG) == 0"
); return (((void*)0)); } } while (0)
;
2412 g_return_val_if_fail (error == NULL || *error == NULL, NULL)do { if ((error == ((void*)0) || *error == ((void*)0))) { } else
{ g_return_if_fail_warning ("Ctk", ((const char*) (__func__)
), "error == NULL || *error == NULL"); return (((void*)0)); }
} while (0)
;
2413 g_return_val_if_fail (scale >= 1, NULL)do { if ((scale >= 1)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "scale >= 1"); return
(((void*)0)); } } while (0)
;
2414
2415 icon_info = ctk_icon_theme_lookup_icon_for_scale (icon_theme, icon_name, size, scale,
2416 flags | CTK_ICON_LOOKUP_USE_BUILTIN);
2417 if (!icon_info)
2418 {
2419 g_set_error (error, CTK_ICON_THEME_ERRORctk_icon_theme_error_quark (), CTK_ICON_THEME_NOT_FOUND,
2420 _("Icon '%s' not present in theme %s")((char *) g_dgettext ("ctk30", "Icon '%s' not present in theme %s"
))
, icon_name, icon_theme->priv->current_theme);
2421 return NULL((void*)0);
2422 }
2423
2424 surface = ctk_icon_info_load_surface (icon_info, for_window, error);
2425 g_object_unref (icon_info);
2426
2427 return surface;
2428}
2429
2430/**
2431 * ctk_icon_theme_has_icon:
2432 * @icon_theme: a #CtkIconTheme
2433 * @icon_name: the name of an icon
2434 *
2435 * Checks whether an icon theme includes an icon
2436 * for a particular name.
2437 *
2438 * Returns: %TRUE if @icon_theme includes an
2439 * icon for @icon_name.
2440 *
2441 * Since: 2.4
2442 */
2443gboolean
2444ctk_icon_theme_has_icon (CtkIconTheme *icon_theme,
2445 const gchar *icon_name)
2446{
2447 CtkIconThemePrivate *priv;
2448 GList *l;
2449
2450 g_return_val_if_fail (CTK_IS_ICON_THEME (icon_theme), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((icon_theme)); GType __t = ((ctk_icon_theme_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ICON_THEME (icon_theme)"); return ((0
)); } } while (0)
;
2451 g_return_val_if_fail (icon_name != NULL, FALSE)do { if ((icon_name != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "icon_name != NULL"); return
((0)); } } while (0)
;
2452
2453 priv = icon_theme->priv;
2454
2455 ensure_valid_themes (icon_theme);
2456
2457 for (l = priv->dir_mtimes; l; l = l->next)
2458 {
2459 IconThemeDirMtime *dir_mtime = l->data;
2460 CtkIconCache *cache = dir_mtime->cache;
2461
2462 if (cache && _ctk_icon_cache_has_icon (cache, icon_name))
2463 return TRUE(!(0));
2464 }
2465
2466 for (l = priv->themes; l; l = l->next)
2467 {
2468 if (theme_has_icon (l->data, icon_name))
2469 return TRUE(!(0));
2470 }
2471
2472 if (icon_theme_builtin_icons &&
2473 g_hash_table_lookup_extended (icon_theme_builtin_icons,
2474 icon_name, NULL((void*)0), NULL((void*)0)))
2475 return TRUE(!(0));
2476
2477 return FALSE(0);
2478}
2479
2480static void
2481add_size (gpointer key,
2482 gpointer value G_GNUC_UNUSED__attribute__ ((__unused__)),
2483 gpointer user_data)
2484{
2485 gint **res_p = user_data;
2486
2487 **res_p = GPOINTER_TO_INT (key)((gint) (glong) (key));
2488
2489 (*res_p)++;
2490}
2491
2492/**
2493 * ctk_icon_theme_get_icon_sizes:
2494 * @icon_theme: a #CtkIconTheme
2495 * @icon_name: the name of an icon
2496 *
2497 * Returns an array of integers describing the sizes at which
2498 * the icon is available without scaling. A size of -1 means
2499 * that the icon is available in a scalable format. The array
2500 * is zero-terminated.
2501 *
2502 * Returns: (array zero-terminated=1) (transfer full): An newly
2503 * allocated array describing the sizes at which the icon is
2504 * available. The array should be freed with g_free() when it is no
2505 * longer needed.
2506 *
2507 * Since: 2.6
2508 */
2509gint *
2510ctk_icon_theme_get_icon_sizes (CtkIconTheme *icon_theme,
2511 const gchar *icon_name)
2512{
2513 GList *l, *d, *icons;
2514 GHashTable *sizes;
2515 gint *result, *r;
2516 guint suffix;
2517 CtkIconThemePrivate *priv;
2518
2519 g_return_val_if_fail (CTK_IS_ICON_THEME (icon_theme), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((icon_theme)); GType __t = ((ctk_icon_theme_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ICON_THEME (icon_theme)"); return (((
void*)0)); } } while (0)
;
2520
2521 priv = icon_theme->priv;
2522
2523 ensure_valid_themes (icon_theme);
2524
2525 sizes = g_hash_table_new (g_direct_hash, g_direct_equal);
2526
2527 for (l = priv->themes; l; l = l->next)
2528 {
2529 IconTheme *theme = l->data;
2530 for (d = theme->dirs; d; d = d->next)
2531 {
2532 IconThemeDir *dir = d->data;
2533
2534 if (dir->type != ICON_THEME_DIR_SCALABLE && g_hash_table_lookup_extended (sizes, GINT_TO_POINTER (dir->size)((gpointer) (glong) (dir->size)), NULL((void*)0), NULL((void*)0)))
2535 continue;
2536
2537 suffix = theme_dir_get_icon_suffix (dir, icon_name, NULL((void*)0));
2538 if (suffix != ICON_SUFFIX_NONE)
2539 {
2540 if (suffix == ICON_SUFFIX_SVG)
2541 g_hash_table_insert (sizes, GINT_TO_POINTER (-1)((gpointer) (glong) (-1)), NULL((void*)0));
2542 else
2543 g_hash_table_insert (sizes, GINT_TO_POINTER (dir->size)((gpointer) (glong) (dir->size)), NULL((void*)0));
2544 }
2545 }
2546 }
2547
2548 if (icon_theme_builtin_icons)
2549 {
2550 icons = g_hash_table_lookup (icon_theme_builtin_icons, icon_name);
2551
2552 while (icons)
2553 {
2554 BuiltinIcon *icon = icons->data;
2555
2556 g_hash_table_insert (sizes, GINT_TO_POINTER (icon->size)((gpointer) (glong) (icon->size)), NULL((void*)0));
2557 icons = icons->next;
2558 }
2559 }
2560
2561 r = result = g_new0 (gint, g_hash_table_size (sizes) + 1)((gint *) g_malloc0_n ((g_hash_table_size (sizes) + 1), sizeof
(gint)))
;
2562
2563 g_hash_table_foreach (sizes, add_size, &r);
2564 g_hash_table_destroy (sizes);
2565
2566 return result;
2567}
2568
2569static void
2570add_key_to_hash (gpointer key,
2571 gpointer value G_GNUC_UNUSED__attribute__ ((__unused__)),
2572 gpointer user_data)
2573{
2574 GHashTable *hash = user_data;
2575
2576 g_hash_table_insert (hash, key, NULL((void*)0));
2577}
2578
2579static void
2580add_key_to_list (gpointer key,
2581 gpointer value G_GNUC_UNUSED__attribute__ ((__unused__)),
2582 gpointer user_data)
2583{
2584 GList **list = user_data;
2585
2586 *list = g_list_prepend (*list, g_strdup (key)g_strdup_inline (key));
2587}
2588
2589/**
2590 * ctk_icon_theme_list_icons:
2591 * @icon_theme: a #CtkIconTheme
2592 * @context: (allow-none): a string identifying a particular type of
2593 * icon, or %NULL to list all icons.
2594 *
2595 * Lists the icons in the current icon theme. Only a subset
2596 * of the icons can be listed by providing a context string.
2597 * The set of values for the context string is system dependent,
2598 * but will typically include such values as “Applications” and
2599 * “MimeTypes”. Contexts are explained in the
2600 * [Icon Theme Specification](http://www.freedesktop.org/wiki/Specifications/icon-theme-spec).
2601 * The standard contexts are listed in the
2602 * [Icon Naming Specification](http://www.freedesktop.org/wiki/Specifications/icon-naming-spec).
2603 * Also see ctk_icon_theme_list_contexts().
2604 *
2605 * Returns: (element-type utf8) (transfer full): a #GList list
2606 * holding the names of all the icons in the theme. You must
2607 * first free each element in the list with g_free(), then
2608 * free the list itself with g_list_free().
2609 *
2610 * Since: 2.4
2611 */
2612GList *
2613ctk_icon_theme_list_icons (CtkIconTheme *icon_theme,
2614 const gchar *context)
2615{
2616 CtkIconThemePrivate *priv;
2617 GHashTable *icons;
2618 GList *list, *l;
2619 GQuark context_quark;
2620
2621 priv = icon_theme->priv;
2622
2623 ensure_valid_themes (icon_theme);
2624
2625 if (context)
2626 {
2627 context_quark = g_quark_try_string (context);
2628
2629 if (!context_quark)
2630 return NULL((void*)0);
2631 }
2632 else
2633 context_quark = 0;
2634
2635 icons = g_hash_table_new (g_str_hash, g_str_equal);
2636
2637 l = priv->themes;
2638 while (l != NULL((void*)0))
2639 {
2640 theme_list_icons (l->data, icons, context_quark);
2641 l = l->next;
2642 }
2643
2644 if (context_quark == 0)
2645 g_hash_table_foreach (priv->unthemed_icons,
2646 add_key_to_hash,
2647 icons);
2648
2649 list = NULL((void*)0);
2650
2651 g_hash_table_foreach (icons,
2652 add_key_to_list,
2653 &list);
2654
2655 g_hash_table_destroy (icons);
2656
2657 return list;
2658}
2659
2660/**
2661 * ctk_icon_theme_list_contexts:
2662 * @icon_theme: a #CtkIconTheme
2663 *
2664 * Gets the list of contexts available within the current
2665 * hierarchy of icon themes.
2666 * See ctk_icon_theme_list_icons() for details about contexts.
2667 *
2668 * Returns: (element-type utf8) (transfer full): a #GList list
2669 * holding the names of all the contexts in the theme. You must first
2670 * free each element in the list with g_free(), then free the list
2671 * itself with g_list_free().
2672 *
2673 * Since: 2.12
2674 */
2675GList *
2676ctk_icon_theme_list_contexts (CtkIconTheme *icon_theme)
2677{
2678 CtkIconThemePrivate *priv;
2679 GHashTable *contexts;
2680 GList *list, *l;
2681
2682 priv = icon_theme->priv;
2683
2684 ensure_valid_themes (icon_theme);
2685
2686 contexts = g_hash_table_new (g_str_hash, g_str_equal);
2687
2688 l = priv->themes;
2689 while (l != NULL((void*)0))
2690 {
2691 theme_list_contexts (l->data, contexts);
2692 l = l->next;
2693 }
2694
2695 list = NULL((void*)0);
2696
2697 g_hash_table_foreach (contexts,
2698 add_key_to_list,
2699 &list);
2700
2701 g_hash_table_destroy (contexts);
2702
2703 return list;
2704}
2705
2706/**
2707 * ctk_icon_theme_get_example_icon_name:
2708 * @icon_theme: a #CtkIconTheme
2709 *
2710 * Gets the name of an icon that is representative of the
2711 * current theme (for instance, to use when presenting
2712 * a list of themes to the user.)
2713 *
2714 * Returns: (nullable): the name of an example icon or %NULL.
2715 * Free with g_free().
2716 *
2717 * Since: 2.4
2718 */
2719gchar *
2720ctk_icon_theme_get_example_icon_name (CtkIconTheme *icon_theme)
2721{
2722 CtkIconThemePrivate *priv;
2723 GList *l;
2724 IconTheme *theme;
2725
2726 g_return_val_if_fail (CTK_IS_ICON_THEME (icon_theme), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((icon_theme)); GType __t = ((ctk_icon_theme_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ICON_THEME (icon_theme)"); return (((
void*)0)); } } while (0)
;
2727
2728 priv = icon_theme->priv;
2729
2730 ensure_valid_themes (icon_theme);
2731
2732 l = priv->themes;
2733 while (l != NULL((void*)0))
2734 {
2735 theme = l->data;
2736 if (theme->example)
2737 return g_strdup (theme->example)g_strdup_inline (theme->example);
2738
2739 l = l->next;
2740 }
2741
2742 return NULL((void*)0);
2743}
2744
2745
2746static gboolean
2747rescan_themes (CtkIconTheme *icon_theme)
2748{
2749 CtkIconThemePrivate *priv;
2750 IconThemeDirMtime *dir_mtime;
2751 GList *d;
2752 gint stat_res;
2753 GStatBuf stat_buf;
2754
2755 priv = icon_theme->priv;
2756
2757 for (d = priv->dir_mtimes; d != NULL((void*)0); d = d->next)
2758 {
2759 dir_mtime = d->data;
2760
2761 stat_res = g_statstat (dir_mtime->dir, &stat_buf);
2762
2763 /* dir mtime didn't change */
2764 if (stat_res == 0 && dir_mtime->exists &&
2765 S_ISDIR (stat_buf.st_mode)((((stat_buf.st_mode)) & 0170000) == (0040000)) &&
2766 dir_mtime->mtime == stat_buf.st_mtimest_mtim.tv_sec)
2767 continue;
2768 /* didn't exist before, and still doesn't */
2769 if (!dir_mtime->exists &&
2770 (stat_res != 0 || !S_ISDIR (stat_buf.st_mode)((((stat_buf.st_mode)) & 0170000) == (0040000))))
2771 continue;
2772
2773 return TRUE(!(0));
2774 }
2775
2776 priv->last_stat_time = g_get_monotonic_time ();
2777
2778 return FALSE(0);
2779}
2780
2781/**
2782 * ctk_icon_theme_rescan_if_needed:
2783 * @icon_theme: a #CtkIconTheme
2784 *
2785 * Checks to see if the icon theme has changed; if it has, any
2786 * currently cached information is discarded and will be reloaded
2787 * next time @icon_theme is accessed.
2788 *
2789 * Returns: %TRUE if the icon theme has changed and needed
2790 * to be reloaded.
2791 *
2792 * Since: 2.4
2793 */
2794gboolean
2795ctk_icon_theme_rescan_if_needed (CtkIconTheme *icon_theme)
2796{
2797 gboolean retval;
2798
2799 g_return_val_if_fail (CTK_IS_ICON_THEME (icon_theme), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((icon_theme)); GType __t = ((ctk_icon_theme_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ICON_THEME (icon_theme)"); return ((0
)); } } while (0)
;
2800
2801 retval = rescan_themes (icon_theme);
2802 if (retval)
2803 do_theme_change (icon_theme);
2804
2805 return retval;
2806}
2807
2808static void
2809theme_destroy (IconTheme *theme)
2810{
2811 g_free (theme->display_name);
2812 g_free (theme->comment);
2813 g_free (theme->name);
2814 g_free (theme->example);
2815
2816 g_list_free_full (theme->dirs, (GDestroyNotify) theme_dir_destroy);
2817
2818 g_free (theme);
2819}
2820
2821static void
2822theme_dir_destroy (IconThemeDir *dir)
2823{
2824 if (dir->cache)
2825 _ctk_icon_cache_unref (dir->cache);
2826 if (dir->icons)
2827 g_hash_table_destroy (dir->icons);
2828
2829 g_free (dir->dir);
2830 g_free (dir->subdir);
2831 g_free (dir);
2832}
2833
2834static int
2835theme_dir_size_difference (IconThemeDir *dir,
2836 gint size,
2837 gint scale)
2838{
2839 gint scaled_size, scaled_dir_size;
2840 gint min, max;
2841
2842 scaled_size = size * scale;
2843 scaled_dir_size = dir->size * dir->scale;
2844
2845 switch (dir->type)
2846 {
2847 case ICON_THEME_DIR_FIXED:
2848 return abs (scaled_size - scaled_dir_size);
2849 break;
This statement is never executed
2850 case ICON_THEME_DIR_SCALABLE:
2851 if (scaled_size < (dir->min_size * dir->scale))
2852 return (dir->min_size * dir->scale) - scaled_size;
2853 if (size > (dir->max_size * dir->scale))
2854 return scaled_size - (dir->max_size * dir->scale);
2855 return 0;
2856 break;
2857 case ICON_THEME_DIR_THRESHOLD:
2858 min = (dir->size - dir->threshold) * dir->scale;
2859 max = (dir->size + dir->threshold) * dir->scale;
2860 if (scaled_size < min)
2861 return min - scaled_size;
2862 if (scaled_size > max)
2863 return scaled_size - max;
2864 return 0;
2865 break;
2866 case ICON_THEME_DIR_UNTHEMED:
2867 g_assert_not_reached ()do { g_assertion_message_expr ("Ctk", "ctkicontheme.c", 2867,
((const char*) (__func__)), ((void*)0)); } while (0)
;
2868 break;
2869 }
2870 g_assert_not_reached ()do { g_assertion_message_expr ("Ctk", "ctkicontheme.c", 2870,
((const char*) (__func__)), ((void*)0)); } while (0)
;
2871 return 1000;
2872}
2873
2874static const gchar *
2875string_from_suffix (IconSuffix suffix)
2876{
2877 switch (suffix)
2878 {
2879 case ICON_SUFFIX_XPM:
2880 return ".xpm";
2881 case ICON_SUFFIX_SVG:
2882 return ".svg";
2883 case ICON_SUFFIX_PNG:
2884 return ".png";
2885 case ICON_SUFFIX_SYMBOLIC_PNG:
2886 return ".symbolic.png";
2887 default:
2888 g_assert_not_reached()do { g_assertion_message_expr ("Ctk", "ctkicontheme.c", 2888,
((const char*) (__func__)), ((void*)0)); } while (0)
;
2889 }
2890 return NULL((void*)0);
2891}
2892
2893static IconSuffix
2894suffix_from_name (const gchar *name)
2895{
2896 IconSuffix retval = ICON_SUFFIX_NONE;
2897
2898 if (name != NULL((void*)0))
2899 {
2900 if (g_str_has_suffix (name, ".symbolic.png")(__builtin_constant_p (".symbolic.png")? __extension__ ({ const
char * const __str = (name); const char * const __suffix = (
".symbolic.png"); gboolean __result = (0); if (__str == ((void
*)0) || __suffix == ((void*)0)) __result = (g_str_has_suffix)
(__str, __suffix); else { const size_t __str_len = strlen ((
(__str) + !(__str))); const size_t __suffix_len = strlen (((__suffix
) + !(__suffix))); if (__str_len >= __suffix_len) __result
= memcmp (__str + __str_len - __suffix_len, ((__suffix) + !(
__suffix)), __suffix_len) == 0; } __result; }) : (g_str_has_suffix
) (name, ".symbolic.png") )
)
2901 retval = ICON_SUFFIX_SYMBOLIC_PNG;
2902 else if (g_str_has_suffix (name, ".png")(__builtin_constant_p (".png")? __extension__ ({ const char *
const __str = (name); const char * const __suffix = (".png")
; gboolean __result = (0); if (__str == ((void*)0) || __suffix
== ((void*)0)) __result = (g_str_has_suffix) (__str, __suffix
); else { const size_t __str_len = strlen (((__str) + !(__str
))); const size_t __suffix_len = strlen (((__suffix) + !(__suffix
))); if (__str_len >= __suffix_len) __result = memcmp (__str
+ __str_len - __suffix_len, ((__suffix) + !(__suffix)), __suffix_len
) == 0; } __result; }) : (g_str_has_suffix) (name, ".png") )
)
2903 retval = ICON_SUFFIX_PNG;
2904 else if (g_str_has_suffix (name, ".svg")(__builtin_constant_p (".svg")? __extension__ ({ const char *
const __str = (name); const char * const __suffix = (".svg")
; gboolean __result = (0); if (__str == ((void*)0) || __suffix
== ((void*)0)) __result = (g_str_has_suffix) (__str, __suffix
); else { const size_t __str_len = strlen (((__str) + !(__str
))); const size_t __suffix_len = strlen (((__suffix) + !(__suffix
))); if (__str_len >= __suffix_len) __result = memcmp (__str
+ __str_len - __suffix_len, ((__suffix) + !(__suffix)), __suffix_len
) == 0; } __result; }) : (g_str_has_suffix) (name, ".svg") )
)
2905 retval = ICON_SUFFIX_SVG;
2906 else if (g_str_has_suffix (name, ".xpm")(__builtin_constant_p (".xpm")? __extension__ ({ const char *
const __str = (name); const char * const __suffix = (".xpm")
; gboolean __result = (0); if (__str == ((void*)0) || __suffix
== ((void*)0)) __result = (g_str_has_suffix) (__str, __suffix
); else { const size_t __str_len = strlen (((__str) + !(__str
))); const size_t __suffix_len = strlen (((__suffix) + !(__suffix
))); if (__str_len >= __suffix_len) __result = memcmp (__str
+ __str_len - __suffix_len, ((__suffix) + !(__suffix)), __suffix_len
) == 0; } __result; }) : (g_str_has_suffix) (name, ".xpm") )
)
2907 retval = ICON_SUFFIX_XPM;
2908 }
2909
2910 return retval;
2911}
2912
2913static IconSuffix
2914best_suffix (IconSuffix suffix,
2915 gboolean allow_svg)
2916{
2917 if ((suffix & ICON_SUFFIX_SYMBOLIC_PNG) != 0)
2918 return ICON_SUFFIX_SYMBOLIC_PNG;
2919 else if ((suffix & ICON_SUFFIX_PNG) != 0)
2920 return ICON_SUFFIX_PNG;
2921 else if (allow_svg && ((suffix & ICON_SUFFIX_SVG) != 0))
2922 return ICON_SUFFIX_SVG;
2923 else if ((suffix & ICON_SUFFIX_XPM) != 0)
2924 return ICON_SUFFIX_XPM;
2925 else
2926 return ICON_SUFFIX_NONE;
2927}
2928
2929static IconSuffix
2930theme_dir_get_icon_suffix (IconThemeDir *dir,
2931 const gchar *icon_name,
2932 gboolean *has_icon_file)
2933{
2934 IconSuffix suffix, symbolic_suffix;
2935
2936 if (dir->cache)
2937 {
2938 suffix = (IconSuffix)_ctk_icon_cache_get_icon_flags (dir->cache,
2939 icon_name,
2940 dir->subdir_index);
2941
2942 if (icon_name_is_symbolic (icon_name))
2943 {
2944 /* Look for foo-symbolic.symbolic.png, as the cache only stores the ".png" suffix */
2945 char *icon_name_with_prefix = g_strconcat (icon_name, ".symbolic", NULL((void*)0));
2946 symbolic_suffix = (IconSuffix)_ctk_icon_cache_get_icon_flags (dir->cache,
2947 icon_name_with_prefix,
2948 dir->subdir_index);
2949 g_free (icon_name_with_prefix);
2950
2951 if (symbolic_suffix & ICON_SUFFIX_PNG)
2952 suffix = ICON_SUFFIX_SYMBOLIC_PNG;
2953 }
2954
2955 if (has_icon_file)
2956 *has_icon_file = suffix & HAS_ICON_FILE;
2957
2958 suffix = suffix & ~HAS_ICON_FILE;
2959 }
2960 else
2961 suffix = GPOINTER_TO_UINT (g_hash_table_lookup (dir->icons, icon_name))((guint) (gulong) (g_hash_table_lookup (dir->icons, icon_name
)))
;
2962
2963 CTK_NOTE (ICONTHEME, g_message ("get icon suffix%s: %u", dir->cache ? " (cached)" : "", suffix))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
g_message ("get icon suffix%s: %u", dir->cache ? " (cached)"
: "", suffix); }; } while (0)
;
2964
2965 return suffix;
2966}
2967
2968/* returns TRUE if dir_a is a better match */
2969static gboolean
2970compare_dir_matches (IconThemeDir *dir_a, gint difference_a,
2971 IconThemeDir *dir_b, gint difference_b,
2972 gint requested_size,
2973 gint requested_scale)
2974{
2975 gint diff_a;
2976 gint diff_b;
2977
2978 if (difference_a == 0)
2979 {
2980 if (difference_b != 0)
2981 return TRUE(!(0));
2982
2983 /* a and b both exact matches */
2984 }
2985 else
2986 {
2987 /* If scaling, *always* prefer downscaling */
2988 if (dir_a->size >= requested_size &&
2989 dir_b->size < requested_size)
2990 return TRUE(!(0));
2991
2992 if (dir_a->size < requested_size &&
2993 dir_b->size >= requested_size)
2994 return FALSE(0);
2995
2996 /* Otherwise prefer the closest match */
2997
2998 if (difference_a < difference_b)
2999 return TRUE(!(0));
3000
3001 if (difference_a > difference_b)
3002 return FALSE(0);
3003
3004 /* same pixel difference */
3005 }
3006
3007 if (dir_a->scale == requested_scale &&
3008 dir_b->scale != requested_scale)
3009 return TRUE(!(0));
3010
3011 if (dir_a->scale != requested_scale &&
3012 dir_b->scale == requested_scale)
3013 return FALSE(0);
3014
3015 /* a and b both match the scale */
3016
3017 if (dir_a->type != ICON_THEME_DIR_SCALABLE &&
3018 dir_b->type == ICON_THEME_DIR_SCALABLE)
3019 return TRUE(!(0));
3020
3021 if (dir_a->type == ICON_THEME_DIR_SCALABLE &&
3022 dir_b->type != ICON_THEME_DIR_SCALABLE)
3023 return FALSE(0);
3024
3025 /* a and b both are scalable */
3026
3027 diff_a = abs (requested_size * requested_scale - dir_a->size * dir_a->scale);
3028 diff_b = abs (requested_size * requested_scale - dir_b->size * dir_b->scale);
3029
3030 return diff_a <= diff_b;
3031}
3032
3033static CtkIconInfo *
3034theme_lookup_icon (IconTheme *theme,
3035 const gchar *icon_name,
3036 gint size,
3037 gint scale,
3038 gboolean allow_svg,
3039 gboolean use_builtin)
3040{
3041 GList *dirs, *l;
3042 IconThemeDir *dir, *min_dir;
3043 gchar *file;
3044 gint min_difference, difference;
3045 BuiltinIcon *closest_builtin = NULL((void*)0);
3046 IconSuffix suffix;
3047
3048 min_difference = G_MAXINT2147483647;
3049 min_dir = NULL((void*)0);
3050
3051 /* Builtin icons are logically part of the default theme and
3052 * are searched before other subdirectories of the default theme.
3053 */
3054 if (use_builtin && strcmp (theme->name, FALLBACK_ICON_THEME"hicolor") == 0)
3055 {
3056 closest_builtin = find_builtin_icon (icon_name,
3057 size, scale,
3058 &min_difference);
3059
3060 if (min_difference == 0)
3061 return icon_info_new_builtin (closest_builtin);
3062 }
3063
3064 dirs = theme->dirs;
3065
3066 l = dirs;
3067 while (l != NULL((void*)0))
3068 {
3069 dir = l->data;
3070
3071 CTK_NOTE (ICONTHEME, g_message ("look up icon dir %s", dir->dir))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
g_message ("look up icon dir %s", dir->dir); }; } while (
0)
;
3072 suffix = theme_dir_get_icon_suffix (dir, icon_name, NULL((void*)0));
3073 if (best_suffix (suffix, allow_svg) != ICON_SUFFIX_NONE)
3074 {
3075 difference = theme_dir_size_difference (dir, size, scale);
3076 if (min_dir == NULL((void*)0) ||
3077 compare_dir_matches (dir, difference,
3078 min_dir, min_difference,
3079 size, scale))
3080 {
3081 min_dir = dir;
3082 min_difference = difference;
3083 }
3084 }
3085
3086 l = l->next;
3087 }
3088
3089 if (min_dir)
3090 {
3091 CtkIconInfo *icon_info;
3092 gboolean has_icon_file = FALSE(0);
3093
3094 icon_info = icon_info_new (min_dir->type, min_dir->size, min_dir->scale);
3095 icon_info->min_size = min_dir->min_size;
3096 icon_info->max_size = min_dir->max_size;
3097
3098 suffix = theme_dir_get_icon_suffix (min_dir, icon_name, &has_icon_file);
3099 suffix = best_suffix (suffix, allow_svg);
3100 g_assert (suffix != ICON_SUFFIX_NONE)do { if (suffix != ICON_SUFFIX_NONE) ; else g_assertion_message_expr
("Ctk", "ctkicontheme.c", 3100, ((const char*) (__func__)), "suffix != ICON_SUFFIX_NONE"
); } while (0)
;
3101
3102 if (min_dir->dir)
3103 {
3104 file = g_strconcat (icon_name, string_from_suffix (suffix), NULL((void*)0));
3105 icon_info->filename = g_build_filename (min_dir->dir, file, NULL((void*)0));
3106
3107 if (min_dir->is_resource)
3108 {
3109 gchar *uri;
3110 uri = g_strconcat ("resource://", icon_info->filename, NULL((void*)0));
3111 icon_info->icon_file = g_file_new_for_uri (uri);
3112 g_free (uri);
3113 }
3114 else
3115 icon_info->icon_file = g_file_new_for_path (icon_info->filename);
3116
3117 icon_info->is_svg = suffix == ICON_SUFFIX_SVG;
3118 icon_info->is_resource = min_dir->is_resource;
3119 g_free (file);
3120 }
3121 else
3122 {
3123 icon_info->filename = NULL((void*)0);
3124 icon_info->icon_file = NULL((void*)0);
3125 }
3126
3127 if (min_dir->cache)
3128 {
3129 icon_info->cache_pixbuf = _ctk_icon_cache_get_icon (min_dir->cache, icon_name,
3130 min_dir->subdir_index);
3131 }
3132
3133 return icon_info;
3134 }
3135
3136 if (closest_builtin)
3137 return icon_info_new_builtin (closest_builtin);
3138
3139 return NULL((void*)0);
3140}
3141
3142static void
3143theme_list_icons (IconTheme *theme,
3144 GHashTable *icons,
3145 GQuark context)
3146{
3147 GList *l = theme->dirs;
3148 IconThemeDir *dir;
3149
3150 while (l != NULL((void*)0))
3151 {
3152 dir = l->data;
3153
3154 if (context == dir->context ||
3155 context == 0)
3156 {
3157 if (dir->cache)
3158 _ctk_icon_cache_add_icons (dir->cache, dir->subdir, icons);
3159 else
3160 g_hash_table_foreach (dir->icons, add_key_to_hash, icons);
3161 }
3162 l = l->next;
3163 }
3164}
3165
3166static gboolean
3167theme_has_icon (IconTheme *theme,
3168 const gchar *icon_name)
3169{
3170 GList *l;
3171
3172 for (l = theme->dirs; l; l = l->next)
3173 {
3174 IconThemeDir *dir = l->data;
3175
3176 if (dir->cache)
3177 {
3178 if (_ctk_icon_cache_has_icon (dir->cache, icon_name))
3179 return TRUE(!(0));
3180 }
3181 else
3182 {
3183 if (g_hash_table_lookup (dir->icons, icon_name) != NULL((void*)0))
3184 return TRUE(!(0));
3185 }
3186 }
3187
3188 return FALSE(0);
3189}
3190
3191static void
3192theme_list_contexts (IconTheme *theme,
3193 GHashTable *contexts)
3194{
3195 GList *l = theme->dirs;
3196 IconThemeDir *dir;
3197 const gchar *context;
3198
3199 while (l != NULL((void*)0))
3200 {
3201 dir = l->data;
3202
3203 /* The "Context" key can be unset */
3204 if (dir->context != 0)
3205 {
3206 context = g_quark_to_string (dir->context);
3207 g_hash_table_replace (contexts, (gpointer) context, NULL((void*)0));
3208 }
3209
3210 l = l->next;
3211 }
3212}
3213
3214static gboolean
3215scan_directory (CtkIconThemePrivate *icon_theme G_GNUC_UNUSED__attribute__ ((__unused__)),
3216 IconThemeDir *dir,
3217 gchar *full_dir)
3218{
3219 GDir *gdir;
3220 const gchar *name;
3221
3222 CTK_NOTE (ICONTHEME, g_message ("scanning directory %s", full_dir))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
g_message ("scanning directory %s", full_dir); }; } while (0
)
;
3223
3224 gdir = g_dir_open (full_dir, 0, NULL((void*)0));
3225
3226 if (gdir == NULL((void*)0))
3227 return FALSE(0);
3228
3229 dir->icons = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL((void*)0));
3230
3231 while ((name = g_dir_read_name (gdir)))
3232 {
3233 gchar *base_name;
3234 IconSuffix suffix, hash_suffix;
3235
3236 suffix = suffix_from_name (name);
3237 if (suffix == ICON_SUFFIX_NONE)
3238 continue;
3239
3240 base_name = strip_suffix (name);
3241
3242 hash_suffix = GPOINTER_TO_INT (g_hash_table_lookup (dir->icons, base_name))((gint) (glong) (g_hash_table_lookup (dir->icons, base_name
)))
;
3243 /* takes ownership of base_name */
3244 g_hash_table_replace (dir->icons, base_name, GUINT_TO_POINTER (hash_suffix|suffix)((gpointer) (gulong) (hash_suffix|suffix)));
3245 }
3246
3247 g_dir_close (gdir);
3248
3249 return g_hash_table_size (dir->icons) > 0;
3250}
3251
3252static gboolean
3253scan_resources (CtkIconThemePrivate *icon_theme G_GNUC_UNUSED__attribute__ ((__unused__)),
3254 IconThemeDir *dir,
3255 gchar *full_dir)
3256{
3257 gint i;
3258 gchar **children;
3259
3260 CTK_NOTE (ICONTHEME, g_message ("scanning resources %s", full_dir))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
g_message ("scanning resources %s", full_dir); }; } while (0
)
;
3261
3262 children = g_resources_enumerate_children (full_dir, 0, NULL((void*)0));
3263 if (!children)
3264 return FALSE(0);
3265
3266 dir->icons = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL((void*)0));
3267
3268 for (i = 0; children[i]; i++)
3269 {
3270 gchar *base_name;
3271 IconSuffix suffix, hash_suffix;
3272
3273 suffix = suffix_from_name (children[i]);
3274 if (suffix == ICON_SUFFIX_NONE)
3275 continue;
3276
3277 base_name = strip_suffix (children[i]);
3278
3279 hash_suffix = GPOINTER_TO_INT (g_hash_table_lookup (dir->icons, base_name))((gint) (glong) (g_hash_table_lookup (dir->icons, base_name
)))
;
3280 /* takes ownership of base_name */
3281 g_hash_table_replace (dir->icons, base_name, GUINT_TO_POINTER (hash_suffix|suffix)((gpointer) (gulong) (hash_suffix|suffix)));
3282 }
3283 g_strfreev (children);
3284
3285 return g_hash_table_size (dir->icons) > 0;
3286}
3287
3288static void
3289theme_subdir_load (CtkIconTheme *icon_theme,
3290 IconTheme *theme,
3291 GKeyFile *theme_file,
3292 gchar *subdir)
3293{
3294 GList *d;
3295 gchar *type_string;
3296 IconThemeDir *dir;
3297 IconThemeDirType type;
3298 gchar *context_string;
3299 GQuark context;
3300 gint size;
3301 gint min_size;
3302 gint max_size;
3303 gint threshold;
3304 gchar *full_dir;
3305 GError *error = NULL((void*)0);
3306 IconThemeDirMtime *dir_mtime;
3307 gint scale;
3308 gboolean has_icons;
3309
3310 size = g_key_file_get_integer (theme_file, subdir, "Size", &error);
3311 if (error)
3312 {
3313 g_error_free (error);
3314 g_warning ("Theme directory %s of theme %s has no size field\n",
3315 subdir, theme->name);
3316 return;
3317 }
3318
3319 type = ICON_THEME_DIR_THRESHOLD;
3320 type_string = g_key_file_get_string (theme_file, subdir, "Type", NULL((void*)0));
3321 if (type_string)
3322 {
3323 if (strcmp (type_string, "Fixed") == 0)
3324 type = ICON_THEME_DIR_FIXED;
3325 else if (strcmp (type_string, "Scalable") == 0)
3326 type = ICON_THEME_DIR_SCALABLE;
3327 else if (strcmp (type_string, "Threshold") == 0)
3328 type = ICON_THEME_DIR_THRESHOLD;
3329
3330 g_free (type_string);
3331 }
3332
3333 context = 0;
3334 context_string = g_key_file_get_string (theme_file, subdir, "Context", NULL((void*)0));
3335 if (context_string)
3336 {
3337 context = g_quark_from_string (context_string);
3338 g_free (context_string);
3339 }
3340
3341 if (g_key_file_has_key (theme_file, subdir, "MaxSize", NULL((void*)0)))
3342 max_size = g_key_file_get_integer (theme_file, subdir, "MaxSize", NULL((void*)0));
3343 else
3344 max_size = size;
3345
3346 if (g_key_file_has_key (theme_file, subdir, "MinSize", NULL((void*)0)))
3347 min_size = g_key_file_get_integer (theme_file, subdir, "MinSize", NULL((void*)0));
3348 else
3349 min_size = size;
3350
3351 if (g_key_file_has_key (theme_file, subdir, "Threshold", NULL((void*)0)))
3352 threshold = g_key_file_get_integer (theme_file, subdir, "Threshold", NULL((void*)0));
3353 else
3354 threshold = 2;
3355
3356 if (g_key_file_has_key (theme_file, subdir, "Scale", NULL((void*)0)))
3357 scale = g_key_file_get_integer (theme_file, subdir, "Scale", NULL((void*)0));
3358 else
3359 scale = 1;
3360
3361 for (d = icon_theme->priv->dir_mtimes; d; d = d->next)
3362 {
3363 dir_mtime = (IconThemeDirMtime *)d->data;
3364
3365 if (!dir_mtime->exists)
3366 continue; /* directory doesn't exist */
3367
3368 full_dir = g_build_filename (dir_mtime->dir, subdir, NULL((void*)0));
3369
3370 /* First, see if we have a cache for the directory */
3371 if (dir_mtime->cache != NULL((void*)0) || g_file_test (full_dir, G_FILE_TEST_IS_DIR))
3372 {
3373 if (dir_mtime->cache == NULL((void*)0))
3374 {
3375 /* This will return NULL if the cache doesn't exist or is outdated */
3376 dir_mtime->cache = _ctk_icon_cache_new_for_path (dir_mtime->dir);
3377 }
3378
3379 dir = g_new0 (IconThemeDir, 1)((IconThemeDir *) g_malloc0_n ((1), sizeof (IconThemeDir)));
3380 dir->type = type;
3381 dir->is_resource = FALSE(0);
3382 dir->context = context;
3383 dir->size = size;
3384 dir->min_size = min_size;
3385 dir->max_size = max_size;
3386 dir->threshold = threshold;
3387 dir->dir = full_dir;
3388 dir->subdir = g_strdup (subdir)g_strdup_inline (subdir);
3389 dir->scale = scale;
3390
3391 if (dir_mtime->cache != NULL((void*)0))
3392 {
3393 dir->cache = _ctk_icon_cache_ref (dir_mtime->cache);
3394 dir->subdir_index = _ctk_icon_cache_get_directory_index (dir->cache, dir->subdir);
3395 has_icons = _ctk_icon_cache_has_icons (dir->cache, dir->subdir);
3396 }
3397 else
3398 {
3399 dir->cache = NULL((void*)0);
3400 dir->subdir_index = -1;
3401 has_icons = scan_directory (icon_theme->priv, dir, full_dir);
3402 }
3403
3404 if (has_icons)
3405 theme->dirs = g_list_prepend (theme->dirs, dir);
3406 else
3407 theme_dir_destroy (dir);
3408 }
3409 else
3410 g_free (full_dir);
3411 }
3412
3413 if (strcmp (theme->name, FALLBACK_ICON_THEME"hicolor") == 0)
3414 {
3415 for (d = icon_theme->priv->resource_paths; d; d = d->next)
3416 {
3417 /* Force a trailing / here, to avoid extra copies in GResource */
3418 full_dir = g_build_filename ((const gchar *)d->data, subdir, " ", NULL((void*)0));
3419 full_dir[strlen (full_dir) - 1] = '\0';
3420 dir = g_new0 (IconThemeDir, 1)((IconThemeDir *) g_malloc0_n ((1), sizeof (IconThemeDir)));
3421 dir->type = type;
3422 dir->is_resource = TRUE(!(0));
3423 dir->context = context;
3424 dir->size = size;
3425 dir->min_size = min_size;
3426 dir->max_size = max_size;
3427 dir->threshold = threshold;
3428 dir->dir = full_dir;
3429 dir->subdir = g_strdup (subdir)g_strdup_inline (subdir);
3430 dir->scale = scale;
3431 dir->cache = NULL((void*)0);
3432 dir->subdir_index = -1;
3433
3434 if (scan_resources (icon_theme->priv, dir, full_dir))
3435 theme->dirs = g_list_prepend (theme->dirs, dir);
3436 else
3437 theme_dir_destroy (dir);
3438 }
3439 }
3440}
3441
3442/*
3443 * CtkIconInfo
3444 */
3445
3446static void ctk_icon_info_class_init (CtkIconInfoClass *klass);
3447
3448G_DEFINE_TYPE (CtkIconInfo, ctk_icon_info, G_TYPE_OBJECT)static void ctk_icon_info_init (CtkIconInfo *self); static void
ctk_icon_info_class_init (CtkIconInfoClass *klass); static GType
ctk_icon_info_get_type_once (void); static gpointer ctk_icon_info_parent_class
= ((void*)0); static gint CtkIconInfo_private_offset; static
void ctk_icon_info_class_intern_init (gpointer klass) { ctk_icon_info_parent_class
= g_type_class_peek_parent (klass); if (CtkIconInfo_private_offset
!= 0) g_type_class_adjust_private_offset (klass, &CtkIconInfo_private_offset
); ctk_icon_info_class_init ((CtkIconInfoClass*) klass); } __attribute__
((__unused__)) static inline gpointer ctk_icon_info_get_instance_private
(CtkIconInfo *self) { return (((gpointer) ((guint8*) (self) +
(glong) (CtkIconInfo_private_offset)))); } GType ctk_icon_info_get_type
(void) { static GType static_g_define_type_id = 0; if ((__extension__
({ _Static_assert (sizeof *(&static_g_define_type_id) ==
sizeof (gpointer), "Expression evaluates to false"); (void) (
0 ? (gpointer) * (&static_g_define_type_id) : ((void*)0))
; (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter_pointer (
&static_g_define_type_id)); })) ) { GType g_define_type_id
= ctk_icon_info_get_type_once (); (__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id
) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer
((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id
)); })) ; } return static_g_define_type_id; } __attribute__ (
(__noinline__)) static GType ctk_icon_info_get_type_once (void
) { GType g_define_type_id = g_type_register_static_simple ((
(GType) ((20) << (2))), g_intern_static_string ("CtkIconInfo"
), sizeof (CtkIconInfoClass), (GClassInitFunc)(void (*)(void)
) ctk_icon_info_class_intern_init, sizeof (CtkIconInfo), (GInstanceInitFunc
)(void (*)(void)) ctk_icon_info_init, (GTypeFlags) 0); { {{};
} } return g_define_type_id; }
3449
3450static void
3451ctk_icon_info_init (CtkIconInfo *icon_info)
3452{
3453 icon_info->scale = -1.;
3454}
3455
3456static CtkIconInfo *
3457icon_info_new (IconThemeDirType type,
3458 gint dir_size,
3459 gint dir_scale)
3460{
3461 CtkIconInfo *icon_info;
3462
3463 icon_info = g_object_new (CTK_TYPE_ICON_INFO(ctk_icon_info_get_type ()), NULL((void*)0));
3464
3465 icon_info->dir_type = type;
3466 icon_info->dir_size = dir_size;
3467 icon_info->dir_scale = dir_scale;
3468 icon_info->unscaled_scale = 1.0;
3469 icon_info->is_svg = FALSE(0);
3470 icon_info->is_resource = FALSE(0);
3471
3472 return icon_info;
3473}
3474
3475/* This only copies whatever is needed to load the pixbuf,
3476 * so that we can do a load in a thread without affecting
3477 * the original IconInfo from the thread.
3478 */
3479static CtkIconInfo *
3480icon_info_dup (CtkIconInfo *icon_info)
3481{
3482 CtkIconInfo *dup;
3483 GSList *l;
3484
3485 dup = icon_info_new (icon_info->dir_type, icon_info->dir_size, icon_info->dir_scale);
3486
3487 dup->filename = g_strdup (icon_info->filename)g_strdup_inline (icon_info->filename);
3488 dup->is_svg = icon_info->is_svg;
3489
3490 if (icon_info->icon_file)
3491 dup->icon_file = g_object_ref (icon_info->icon_file)((__typeof__ (icon_info->icon_file)) (g_object_ref) (icon_info
->icon_file))
;
3492 if (icon_info->loadable)
3493 dup->loadable = g_object_ref (icon_info->loadable)((__typeof__ (icon_info->loadable)) (g_object_ref) (icon_info
->loadable))
;
3494 if (icon_info->pixbuf)
3495 dup->pixbuf = g_object_ref (icon_info->pixbuf)((__typeof__ (icon_info->pixbuf)) (g_object_ref) (icon_info
->pixbuf))
;
3496
3497 for (l = icon_info->emblem_infos; l != NULL((void*)0); l = l->next)
3498 {
3499 dup->emblem_infos =
3500 g_slist_append (dup->emblem_infos,
3501 icon_info_dup (l->data));
3502 }
3503
3504 if (icon_info->cache_pixbuf)
3505 dup->cache_pixbuf = g_object_ref (icon_info->cache_pixbuf)((__typeof__ (icon_info->cache_pixbuf)) (g_object_ref) (icon_info
->cache_pixbuf))
;
3506
3507 dup->scale = icon_info->scale;
3508 dup->unscaled_scale = icon_info->unscaled_scale;
3509 dup->desired_size = icon_info->desired_size;
3510 dup->desired_scale = icon_info->desired_scale;
3511 dup->forced_size = icon_info->forced_size;
3512 dup->emblems_applied = icon_info->emblems_applied;
3513 dup->is_resource = icon_info->is_resource;
3514 dup->min_size = icon_info->min_size;
3515 dup->max_size = icon_info->max_size;
3516 dup->symbolic_width = icon_info->symbolic_width;
3517 dup->symbolic_height = icon_info->symbolic_height;
3518
3519 return dup;
3520}
3521
3522static CtkIconInfo *
3523icon_info_new_builtin (BuiltinIcon *icon)
3524{
3525 CtkIconInfo *icon_info = icon_info_new (ICON_THEME_DIR_THRESHOLD, icon->size, 1);
3526
3527 icon_info->cache_pixbuf = g_object_ref (icon->pixbuf)((__typeof__ (icon->pixbuf)) (g_object_ref) (icon->pixbuf
))
;
3528
3529 return icon_info;
3530}
3531
3532/**
3533 * ctk_icon_info_copy: (skip)
3534 * @icon_info: a #CtkIconInfo
3535 *
3536 * Make a copy of a #CtkIconInfo.
3537 *
3538 * Returns: (transfer full): the new CtkIconInfo
3539 *
3540 * Since: 2.4
3541 *
3542 * Deprecated: 3.8: Use g_object_ref()
3543 */
3544CtkIconInfo *
3545ctk_icon_info_copy (CtkIconInfo *icon_info)
3546{
3547 g_return_val_if_fail (icon_info != NULL, NULL)do { if ((icon_info != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "icon_info != NULL"); return
(((void*)0)); } } while (0)
;
3548 return g_object_ref (icon_info)((__typeof__ (icon_info)) (g_object_ref) (icon_info));
3549}
3550
3551/**
3552 * ctk_icon_info_free: (skip)
3553 * @icon_info: a #CtkIconInfo
3554 *
3555 * Free a #CtkIconInfo and associated information
3556 *
3557 * Since: 2.4
3558 *
3559 * Deprecated: 3.8: Use g_object_unref()
3560 */
3561void
3562ctk_icon_info_free (CtkIconInfo *icon_info)
3563{
3564 g_return_if_fail (icon_info != NULL)do { if ((icon_info != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "icon_info != NULL"); return
; } } while (0)
;
3565 g_object_unref (icon_info);
3566}
3567
3568static void
3569ctk_icon_info_finalize (GObject *object)
3570{
3571 CtkIconInfo *icon_info = (CtkIconInfo *) object;
3572
3573 if (icon_info->in_cache)
3574 g_hash_table_remove (icon_info->in_cache->priv->info_cache, &icon_info->key);
3575
3576 g_strfreev (icon_info->key.icon_names);
3577
3578 g_free (icon_info->filename);
3579 g_clear_object (&icon_info->icon_file)do { _Static_assert (sizeof *((&icon_info->icon_file))
== sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&icon_info->icon_file))) _pp = ((&icon_info->
icon_file)); __typeof__ (*((&icon_info->icon_file))) _ptr
= *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr)
; } while (0)
;
3580
3581 g_clear_object (&icon_info->loadable)do { _Static_assert (sizeof *((&icon_info->loadable)) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&icon_info->loadable))) _pp = ((&icon_info->
loadable)); __typeof__ (*((&icon_info->loadable))) _ptr
= *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr)
; } while (0)
;
3582 g_slist_free_full (icon_info->emblem_infos, (GDestroyNotify) g_object_unref);
3583 g_clear_object (&icon_info->pixbuf)do { _Static_assert (sizeof *((&icon_info->pixbuf)) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&icon_info->pixbuf))) _pp = ((&icon_info->pixbuf
)); __typeof__ (*((&icon_info->pixbuf))) _ptr = *_pp; *
_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while (
0)
;
3584 g_clear_object (&icon_info->proxy_pixbuf)do { _Static_assert (sizeof *((&icon_info->proxy_pixbuf
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&icon_info->proxy_pixbuf))) _pp = ((&icon_info
->proxy_pixbuf)); __typeof__ (*((&icon_info->proxy_pixbuf
))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref
) (_ptr); } while (0)
;
3585 g_clear_object (&icon_info->cache_pixbuf)do { _Static_assert (sizeof *((&icon_info->cache_pixbuf
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&icon_info->cache_pixbuf))) _pp = ((&icon_info
->cache_pixbuf)); __typeof__ (*((&icon_info->cache_pixbuf
))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref
) (_ptr); } while (0)
;
3586 g_clear_error (&icon_info->load_error);
3587
3588 symbolic_pixbuf_cache_free (icon_info->symbolic_pixbuf_cache);
3589
3590 G_OBJECT_CLASS (ctk_icon_info_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_icon_info_parent_class)), (((GType) ((20) << (
2))))))))
->finalize (object);
3591}
3592
3593static void
3594ctk_icon_info_class_init (CtkIconInfoClass *klass)
3595{
3596 GObjectClass *gobject_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), (((GType) ((20) << (2))))))))
;
3597
3598 gobject_class->finalize = ctk_icon_info_finalize;
3599}
3600
3601/**
3602 * ctk_icon_info_get_base_size:
3603 * @icon_info: a #CtkIconInfo
3604 *
3605 * Gets the base size for the icon. The base size
3606 * is a size for the icon that was specified by
3607 * the icon theme creator. This may be different
3608 * than the actual size of image; an example of
3609 * this is small emblem icons that can be attached
3610 * to a larger icon. These icons will be given
3611 * the same base size as the larger icons to which
3612 * they are attached.
3613 *
3614 * Note that for scaled icons the base size does
3615 * not include the base scale.
3616 *
3617 * Returns: the base size, or 0, if no base
3618 * size is known for the icon.
3619 *
3620 * Since: 2.4
3621 */
3622gint
3623ctk_icon_info_get_base_size (CtkIconInfo *icon_info)
3624{
3625 g_return_val_if_fail (icon_info != NULL, 0)do { if ((icon_info != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "icon_info != NULL"); return
(0); } } while (0)
;
3626
3627 return icon_info->dir_size;
3628}
3629
3630/**
3631 * ctk_icon_info_get_base_scale:
3632 * @icon_info: a #CtkIconInfo
3633 *
3634 * Gets the base scale for the icon. The base scale is a scale
3635 * for the icon that was specified by the icon theme creator.
3636 * For instance an icon drawn for a high-dpi screen with window
3637 * scale 2 for a base size of 32 will be 64 pixels tall and have
3638 * a base scale of 2.
3639 *
3640 * Returns: the base scale
3641 *
3642 * Since: 3.10
3643 */
3644gint
3645ctk_icon_info_get_base_scale (CtkIconInfo *icon_info)
3646{
3647 g_return_val_if_fail (icon_info != NULL, 0)do { if ((icon_info != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "icon_info != NULL"); return
(0); } } while (0)
;
3648
3649 return icon_info->dir_scale;
3650}
3651
3652/**
3653 * ctk_icon_info_get_filename:
3654 * @icon_info: a #CtkIconInfo
3655 *
3656 * Gets the filename for the icon. If the %CTK_ICON_LOOKUP_USE_BUILTIN
3657 * flag was passed to ctk_icon_theme_lookup_icon(), there may be no
3658 * filename if a builtin icon is returned; in this case, you should
3659 * use ctk_icon_info_get_builtin_pixbuf().
3660 *
3661 * Returns: (nullable) (type filename): the filename for the icon, or %NULL
3662 * if ctk_icon_info_get_builtin_pixbuf() should be used instead.
3663 * The return value is owned by CTK+ and should not be modified
3664 * or freed.
3665 *
3666 * Since: 2.4
3667 */
3668const gchar *
3669ctk_icon_info_get_filename (CtkIconInfo *icon_info)
3670{
3671 g_return_val_if_fail (icon_info != NULL, NULL)do { if ((icon_info != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "icon_info != NULL"); return
(((void*)0)); } } while (0)
;
3672
3673 return icon_info->filename;
3674}
3675
3676/**
3677 * ctk_icon_info_get_builtin_pixbuf:
3678 * @icon_info: a #CtkIconInfo
3679 *
3680 * Gets the built-in image for this icon, if any. To allow CTK+ to use
3681 * built in icon images, you must pass the %CTK_ICON_LOOKUP_USE_BUILTIN
3682 * to ctk_icon_theme_lookup_icon().
3683 *
3684 * Returns: (nullable) (transfer none): the built-in image pixbuf, or %NULL.
3685 * No extra reference is added to the returned pixbuf, so if
3686 * you want to keep it around, you must use g_object_ref().
3687 * The returned image must not be modified.
3688 *
3689 * Since: 2.4
3690 *
3691 * Deprecated: 3.14: This function is deprecated, use
3692 * ctk_icon_theme_add_resource_path() instead of builtin icons.
3693 */
3694GdkPixbuf *
3695ctk_icon_info_get_builtin_pixbuf (CtkIconInfo *icon_info)
3696{
3697 g_return_val_if_fail (icon_info != NULL, NULL)do { if ((icon_info != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "icon_info != NULL"); return
(((void*)0)); } } while (0)
;
3698
3699 if (icon_info->filename)
3700 return NULL((void*)0);
3701
3702 return icon_info->cache_pixbuf;
3703}
3704
3705/**
3706 * ctk_icon_info_is_symbolic:
3707 * @icon_info: a #CtkIconInfo
3708 *
3709 * Checks if the icon is symbolic or not. This currently uses only
3710 * the file name and not the file contents for determining this.
3711 * This behaviour may change in the future.
3712 *
3713 * Returns: %TRUE if the icon is symbolic, %FALSE otherwise
3714 *
3715 * Since: 3.12
3716 */
3717gboolean
3718ctk_icon_info_is_symbolic (CtkIconInfo *icon_info)
3719{
3720 gchar *icon_uri;
3721 gboolean is_symbolic;
3722
3723 g_return_val_if_fail (CTK_IS_ICON_INFO (icon_info), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((icon_info)); GType __t = ((ctk_icon_info_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_ICON_INFO (icon_info)"); return ((0)); } } while (
0)
;
3724
3725 icon_uri = NULL((void*)0);
3726 if (icon_info->icon_file)
3727 icon_uri = g_file_get_uri (icon_info->icon_file);
3728
3729 is_symbolic = (icon_uri != NULL((void*)0)) && (icon_uri_is_symbolic (icon_uri));
3730 g_free (icon_uri);
3731
3732 return is_symbolic;
3733}
3734
3735static GdkPixbuf *
3736apply_emblems_to_pixbuf (GdkPixbuf *pixbuf,
3737 CtkIconInfo *info)
3738{
3739 GdkPixbuf *icon = NULL((void*)0);
3740 gint w, h, pos;
3741 GSList *l;
3742
3743 if (info->emblem_infos == NULL((void*)0))
3744 return NULL((void*)0);
3745
3746 w = gdk_pixbuf_get_width (pixbuf);
3747 h = gdk_pixbuf_get_height (pixbuf);
3748
3749 for (l = info->emblem_infos, pos = 0; l; l = l->next, pos++)
3750 {
3751 CtkIconInfo *emblem_info = l->data;
3752
3753 if (icon_info_ensure_scale_and_pixbuf (emblem_info))
3754 {
3755 GdkPixbuf *emblem = emblem_info->pixbuf;
3756 gint ew, eh;
3757 gint x = 0, y = 0; /* silence compiler */
3758 gdouble scale;
3759
3760 ew = gdk_pixbuf_get_width (emblem);
3761 eh = gdk_pixbuf_get_height (emblem);
3762 if (ew >= w)
3763 {
3764 scale = 0.75;
3765 ew = ew * 0.75;
3766 eh = eh * 0.75;
3767 }
3768 else
3769 scale = 1.0;
3770
3771 switch (pos % 4)
3772 {
3773 case 0:
3774 x = w - ew;
3775 y = h - eh;
3776 break;
3777 case 1:
3778 x = w - ew;
3779 y = 0;
3780 break;
3781 case 2:
3782 x = 0;
3783 y = h - eh;
3784 break;
3785 case 3:
3786 x = 0;
3787 y = 0;
3788 break;
3789 }
3790
3791 if (icon == NULL((void*)0))
3792 {
3793 icon = gdk_pixbuf_copy (pixbuf);
3794 if (icon == NULL((void*)0))
3795 break;
3796 }
3797
3798 gdk_pixbuf_composite (emblem, icon, x, y, ew, eh, x, y,
3799 scale, scale, GDK_INTERP_BILINEAR, 255);
3800 }
3801 }
3802
3803 return icon;
3804}
3805
3806/* Combine the icon with all emblems, the first emblem is placed
3807 * in the southeast corner. Scale emblems to be at most 3/4 of the
3808 * size of the icon itself.
3809 */
3810static void
3811apply_emblems (CtkIconInfo *info)
3812{
3813 GdkPixbuf *icon;
3814
3815 if (info->emblems_applied)
3816 return;
3817
3818 icon = apply_emblems_to_pixbuf (info->pixbuf, info);
3819
3820 if (icon)
3821 {
3822 g_object_unref (info->pixbuf);
3823 info->pixbuf = icon;
3824 info->emblems_applied = TRUE(!(0));
3825 }
3826}
3827
3828/* If this returns TRUE, its safe to call icon_info_ensure_scale_and_pixbuf
3829 * without blocking
3830 */
3831static gboolean
3832icon_info_get_pixbuf_ready (CtkIconInfo *icon_info)
3833{
3834 if (icon_info->pixbuf &&
3835 (icon_info->emblem_infos == NULL((void*)0) || icon_info->emblems_applied))
3836 return TRUE(!(0));
3837
3838 if (icon_info->load_error)
3839 return TRUE(!(0));
3840
3841 return FALSE(0);
3842}
3843
3844/* This function contains the complicated logic for deciding
3845 * on the size at which to load the icon and loading it at
3846 * that size.
3847 */
3848static gboolean
3849icon_info_ensure_scale_and_pixbuf (CtkIconInfo *icon_info)
3850{
3851 gint image_width, image_height, image_size;
3852 gint scaled_desired_size;
3853 GdkPixbuf *source_pixbuf;
3854 gdouble dir_scale;
3855
3856 if (icon_info->pixbuf)
3857 {
3858 apply_emblems (icon_info);
3859 return TRUE(!(0));
3860 }
3861
3862 if (icon_info->load_error)
3863 return FALSE(0);
3864
3865 if (icon_info->icon_file && !icon_info->loadable)
3866 icon_info->loadable = G_LOADABLE_ICON (g_file_icon_new (icon_info->icon_file))((((GLoadableIcon*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((g_file_icon_new (icon_info->icon_file))), ((g_loadable_icon_get_type
()))))))
;
3867
3868 scaled_desired_size = icon_info->desired_size * icon_info->desired_scale;
3869
3870 dir_scale = icon_info->dir_scale;
3871
3872 /* In many cases, the scale can be determined without actual access
3873 * to the icon file. This is generally true when we have a size
3874 * for the directory where the icon is; the image size doesn't
3875 * matter in that case.
3876 */
3877 if (icon_info->forced_size ||
3878 icon_info->dir_type == ICON_THEME_DIR_UNTHEMED)
3879 icon_info->scale = -1;
3880 else if (icon_info->dir_type == ICON_THEME_DIR_FIXED ||
3881 icon_info->dir_type == ICON_THEME_DIR_THRESHOLD)
3882 icon_info->scale = icon_info->unscaled_scale;
3883 else if (icon_info->dir_type == ICON_THEME_DIR_SCALABLE)
3884 {
3885 /* For svg icons, treat scalable directories as if they had
3886 * a Scale=<desired_scale> entry. In particular, this means
3887 * spinners that are restriced to size 32 will loaded at size
3888 * up to 64 with Scale=2.
3889 */
3890 if (icon_info->is_svg)
3891 dir_scale = icon_info->desired_scale;
3892
3893 if (scaled_desired_size < icon_info->min_size * dir_scale)
3894 icon_info->scale = (gdouble) icon_info->min_size / (gdouble) icon_info->dir_size;
3895 else if (scaled_desired_size > icon_info->max_size * dir_scale)
3896 icon_info->scale = (gdouble) icon_info->max_size / (gdouble) icon_info->dir_size;
3897 else
3898 icon_info->scale = (gdouble) scaled_desired_size / (icon_info->dir_size * dir_scale);
3899 }
3900
3901 /* At this point, we need to actually get the icon; either from the
3902 * builtin image or by loading the file
3903 */
3904 source_pixbuf = NULL((void*)0);
3905 if (icon_info->cache_pixbuf)
3906 source_pixbuf = g_object_ref (icon_info->cache_pixbuf)((__typeof__ (icon_info->cache_pixbuf)) (g_object_ref) (icon_info
->cache_pixbuf))
;
3907 else if (icon_info->is_resource)
3908 {
3909 if (icon_info->is_svg)
3910 {
3911 gint size;
3912
3913 if (icon_info->forced_size || icon_info->dir_type == ICON_THEME_DIR_UNTHEMED)
3914 size = scaled_desired_size;
3915 else
3916 size = icon_info->dir_size * dir_scale * icon_info->scale;
3917
3918 if (size == 0)
3919 source_pixbuf = _gdk_pixbuf_new_from_resource_scaled (icon_info->filename,
3920 icon_info->desired_scale,
3921 &icon_info->load_error);
3922 else
3923 source_pixbuf = gdk_pixbuf_new_from_resource_at_scale (icon_info->filename,
3924 size, size, TRUE(!(0)),
3925 &icon_info->load_error);
3926 }
3927 else
3928 source_pixbuf = gdk_pixbuf_new_from_resource (icon_info->filename,
3929 &icon_info->load_error);
3930 }
3931 else
3932 {
3933 GInputStream *stream;
3934
3935 /* TODO: We should have a load_at_scale */
3936 stream = g_loadable_icon_load (icon_info->loadable,
3937 scaled_desired_size,
3938 NULL((void*)0), NULL((void*)0),
3939 &icon_info->load_error);
3940 if (stream)
3941 {
3942 /* SVG icons are a special case - we just immediately scale them
3943 * to the desired size
3944 */
3945 if (icon_info->is_svg)
3946 {
3947 gint size;
3948
3949 if (icon_info->forced_size || icon_info->dir_type == ICON_THEME_DIR_UNTHEMED)
3950 size = scaled_desired_size;
3951 else
3952 size = icon_info->dir_size * dir_scale * icon_info->scale;
3953 if (size == 0)
3954 source_pixbuf = _gdk_pixbuf_new_from_stream_scaled (stream,
3955 icon_info->desired_scale,
3956 NULL((void*)0),
3957 &icon_info->load_error);
3958 else
3959 source_pixbuf = gdk_pixbuf_new_from_stream_at_scale (stream,
3960 size, size,
3961 TRUE(!(0)), NULL((void*)0),
3962 &icon_info->load_error);
3963 }
3964 else
3965 source_pixbuf = gdk_pixbuf_new_from_stream (stream,
3966 NULL((void*)0),
3967 &icon_info->load_error);
3968 g_object_unref (stream);
3969 }
3970 }
3971
3972 if (!source_pixbuf)
3973 {
3974 static gboolean warn_about_load_failure = TRUE(!(0));
3975
3976 if (warn_about_load_failure)
3977 {
3978 gchar *path;
3979
3980 if (icon_info->is_resource)
3981 path = g_strdup (icon_info->filename)g_strdup_inline (icon_info->filename);
3982 else if (G_IS_FILE (icon_info->loadable)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(icon_info->loadable)); GType __t = ((g_file_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
))))
)
3983 path = g_file_get_path (G_FILE (icon_info->loadable)((((GFile*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((icon_info->loadable)), ((g_file_get_type ()))))))
);
3984 else
3985 path = g_strdup ("icon theme")g_strdup_inline ("icon theme");
3986
3987 g_warning ("Could not load a pixbuf from %s.\n"
3988 "This may indicate that pixbuf loaders or the mime database could not be found.",
3989 path);
3990 g_free (path);
3991
3992 warn_about_load_failure = FALSE(0);
3993 }
3994
3995 return FALSE(0);
3996 }
3997
3998 /* Do scale calculations that depend on the image size
3999 */
4000 image_width = gdk_pixbuf_get_width (source_pixbuf);
4001 image_height = gdk_pixbuf_get_height (source_pixbuf);
4002 image_size = MAX (image_width, image_height)(((image_width) > (image_height)) ? (image_width) : (image_height
))
;
4003
4004 if (icon_info->is_svg)
4005 icon_info->scale = image_size / 1000.;
4006 else if (icon_info->scale < 0.0)
4007 {
4008 if (image_size > 0 && scaled_desired_size > 0)
4009 icon_info->scale = (gdouble)scaled_desired_size / (gdouble)image_size;
4010 else
4011 icon_info->scale = 1.0;
4012
4013 if (icon_info->dir_type == ICON_THEME_DIR_UNTHEMED &&
4014 !icon_info->forced_size)
4015 icon_info->scale = MIN (icon_info->scale, 1.0)(((icon_info->scale) < (1.0)) ? (icon_info->scale) :
(1.0))
;
4016 }
4017
4018 if (icon_info->is_svg)
4019 icon_info->pixbuf = source_pixbuf;
4020 else if (icon_info->scale == 1.0)
4021 icon_info->pixbuf = source_pixbuf;
4022 else
4023 {
4024 icon_info->pixbuf = gdk_pixbuf_scale_simple (source_pixbuf,
4025 MAX (1, 0.5 + image_width * icon_info->scale)(((1) > (0.5 + image_width * icon_info->scale)) ? (1) :
(0.5 + image_width * icon_info->scale))
,
4026 MAX (1, 0.5 + image_height * icon_info->scale)(((1) > (0.5 + image_height * icon_info->scale)) ? (1) :
(0.5 + image_height * icon_info->scale))
,
4027 GDK_INTERP_BILINEAR);
4028 g_object_unref (source_pixbuf);
4029 }
4030
4031 apply_emblems (icon_info);
4032
4033 return TRUE(!(0));
4034}
4035
4036static void
4037proxy_pixbuf_destroy (guchar *pixels G_GNUC_UNUSED__attribute__ ((__unused__)),
4038 gpointer data)
4039{
4040 CtkIconInfo *icon_info = data;
4041 CtkIconTheme *icon_theme = icon_info->in_cache;
4042
4043 g_assert (icon_info->proxy_pixbuf != NULL)do { if (icon_info->proxy_pixbuf != ((void*)0)) ; else g_assertion_message_expr
("Ctk", "ctkicontheme.c", 4043, ((const char*) (__func__)), "icon_info->proxy_pixbuf != NULL"
); } while (0)
;
4044 icon_info->proxy_pixbuf = NULL((void*)0);
4045
4046 /* Keep it alive a bit longer */
4047 if (icon_theme != NULL((void*)0))
4048 ensure_in_lru_cache (icon_theme, icon_info);
4049
4050 g_object_unref (icon_info);
4051}
4052
4053/**
4054 * ctk_icon_info_load_icon:
4055 * @icon_info: a #CtkIconInfo from ctk_icon_theme_lookup_icon()
4056 * @error: (allow-none): location to store error information on failure,
4057 * or %NULL.
4058 *
4059 * Renders an icon previously looked up in an icon theme using
4060 * ctk_icon_theme_lookup_icon(); the size will be based on the size
4061 * passed to ctk_icon_theme_lookup_icon(). Note that the resulting
4062 * pixbuf may not be exactly this size; an icon theme may have icons
4063 * that differ slightly from their nominal sizes, and in addition CTK+
4064 * will avoid scaling icons that it considers sufficiently close to the
4065 * requested size or for which the source image would have to be scaled
4066 * up too far. (This maintains sharpness.). This behaviour can be changed
4067 * by passing the %CTK_ICON_LOOKUP_FORCE_SIZE flag when obtaining
4068 * the #CtkIconInfo. If this flag has been specified, the pixbuf
4069 * returned by this function will be scaled to the exact size.
4070 *
4071 * Returns: (transfer full): the rendered icon; this may be a newly
4072 * created icon or a new reference to an internal icon, so you must
4073 * not modify the icon. Use g_object_unref() to release your reference
4074 * to the icon.
4075 *
4076 * Since: 2.4
4077 */
4078GdkPixbuf *
4079ctk_icon_info_load_icon (CtkIconInfo *icon_info,
4080 GError **error)
4081{
4082 g_return_val_if_fail (icon_info != NULL, NULL)do { if ((icon_info != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "icon_info != NULL"); return
(((void*)0)); } } while (0)
;
4083 g_return_val_if_fail (error == NULL || *error == NULL, NULL)do { if ((error == ((void*)0) || *error == ((void*)0))) { } else
{ g_return_if_fail_warning ("Ctk", ((const char*) (__func__)
), "error == NULL || *error == NULL"); return (((void*)0)); }
} while (0)
;
4084
4085 if (!icon_info_ensure_scale_and_pixbuf (icon_info))
4086 {
4087 if (icon_info->load_error)
4088 {
4089 if (error)
4090 *error = g_error_copy (icon_info->load_error);
4091 }
4092 else
4093 {
4094 g_set_error_literal (error,
4095 CTK_ICON_THEME_ERRORctk_icon_theme_error_quark (),
4096 CTK_ICON_THEME_NOT_FOUND,
4097 _("Failed to load icon")((char *) g_dgettext ("ctk30", "Failed to load icon")));
4098 }
4099
4100 return NULL((void*)0);
4101 }
4102
4103 /* Instead of returning the pixbuf directly we return a proxy
4104 * to it that we don't own (but that shares the data with the
4105 * one we own). This way we can know when it is freed and ensure
4106 * the IconInfo is alive (and thus cached) while the pixbuf is
4107 * still alive.
4108 */
4109 if (icon_info->proxy_pixbuf != NULL((void*)0))
4110 return g_object_ref (icon_info->proxy_pixbuf)((__typeof__ (icon_info->proxy_pixbuf)) (g_object_ref) (icon_info
->proxy_pixbuf))
;
4111
4112 icon_info->proxy_pixbuf =
4113 gdk_pixbuf_new_from_data (gdk_pixbuf_get_pixels (icon_info->pixbuf),
4114 gdk_pixbuf_get_colorspace (icon_info->pixbuf),
4115 gdk_pixbuf_get_has_alpha (icon_info->pixbuf),
4116 gdk_pixbuf_get_bits_per_sample (icon_info->pixbuf),
4117 gdk_pixbuf_get_width (icon_info->pixbuf),
4118 gdk_pixbuf_get_height (icon_info->pixbuf),
4119 gdk_pixbuf_get_rowstride (icon_info->pixbuf),
4120 proxy_pixbuf_destroy,
4121 g_object_ref (icon_info)((__typeof__ (icon_info)) (g_object_ref) (icon_info)));
4122
4123 return icon_info->proxy_pixbuf;
4124}
4125
4126/**
4127 * ctk_icon_info_load_surface:
4128 * @icon_info: a #CtkIconInfo from ctk_icon_theme_lookup_icon()
4129 * @for_window: (allow-none): #CdkWindow to optimize drawing for, or %NULL
4130 * @error: (allow-none): location for error information on failure, or %NULL
4131 *
4132 * Renders an icon previously looked up in an icon theme using
4133 * ctk_icon_theme_lookup_icon(); the size will be based on the size
4134 * passed to ctk_icon_theme_lookup_icon(). Note that the resulting
4135 * surface may not be exactly this size; an icon theme may have icons
4136 * that differ slightly from their nominal sizes, and in addition CTK+
4137 * will avoid scaling icons that it considers sufficiently close to the
4138 * requested size or for which the source image would have to be scaled
4139 * up too far. (This maintains sharpness.). This behaviour can be changed
4140 * by passing the %CTK_ICON_LOOKUP_FORCE_SIZE flag when obtaining
4141 * the #CtkIconInfo. If this flag has been specified, the pixbuf
4142 * returned by this function will be scaled to the exact size.
4143 *
4144 * Returns: (transfer full): the rendered icon; this may be a newly
4145 * created icon or a new reference to an internal icon, so you must
4146 * not modify the icon. Use cairo_surface_destroy() to release your
4147 * reference to the icon.
4148 *
4149 * Since: 3.10
4150 */
4151cairo_surface_t *
4152ctk_icon_info_load_surface (CtkIconInfo *icon_info,
4153 CdkWindow *for_window,
4154 GError **error)
4155{
4156 GdkPixbuf *pixbuf;
4157 cairo_surface_t *surface;
4158
4159 g_return_val_if_fail (icon_info != NULL, NULL)do { if ((icon_info != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "icon_info != NULL"); return
(((void*)0)); } } while (0)
;
4160 g_return_val_if_fail (error == NULL || *error == NULL, NULL)do { if ((error == ((void*)0) || *error == ((void*)0))) { } else
{ g_return_if_fail_warning ("Ctk", ((const char*) (__func__)
), "error == NULL || *error == NULL"); return (((void*)0)); }
} while (0)
;
4161
4162 pixbuf = ctk_icon_info_load_icon (icon_info, error);
4163
4164 if (pixbuf == NULL((void*)0))
4165 return NULL((void*)0);
4166
4167 surface = cdk_cairo_surface_create_from_pixbuf (pixbuf, icon_info->desired_scale, for_window);
4168 g_object_unref (pixbuf);
4169
4170 return surface;
4171}
4172
4173static void
4174load_icon_thread (GTask *task,
4175 gpointer source_object G_GNUC_UNUSED__attribute__ ((__unused__)),
4176 gpointer task_data,
4177 GCancellable *cancellable G_GNUC_UNUSED__attribute__ ((__unused__)))
4178{
4179 CtkIconInfo *dup = task_data;
4180
4181 (void)icon_info_ensure_scale_and_pixbuf (dup);
4182 g_task_return_pointer (task, NULL((void*)0), NULL((void*)0));
4183}
4184
4185/**
4186 * ctk_icon_info_load_icon_async:
4187 * @icon_info: a #CtkIconInfo from ctk_icon_theme_lookup_icon()
4188 * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore
4189 * @callback: (scope async): a #GAsyncReadyCallback to call when the
4190 * request is satisfied
4191 * @user_data: (closure): the data to pass to callback function
4192 *
4193 * Asynchronously load, render and scale an icon previously looked up
4194 * from the icon theme using ctk_icon_theme_lookup_icon().
4195 *
4196 * For more details, see ctk_icon_info_load_icon() which is the synchronous
4197 * version of this call.
4198 *
4199 * Since: 3.8
4200 */
4201void
4202ctk_icon_info_load_icon_async (CtkIconInfo *icon_info,
4203 GCancellable *cancellable,
4204 GAsyncReadyCallback callback,
4205 gpointer user_data)
4206{
4207 GTask *task;
4208 GdkPixbuf *pixbuf;
4209 CtkIconInfo *dup;
4210 GError *error = NULL((void*)0);
4211
4212 task = g_task_new (icon_info, cancellable, callback, user_data);
4213
4214 if (icon_info_get_pixbuf_ready (icon_info))
4215 {
4216 pixbuf = ctk_icon_info_load_icon (icon_info, &error);
4217 if (pixbuf == NULL((void*)0))
4218 g_task_return_error (task, error);
4219 else
4220 g_task_return_pointer (task, pixbuf, g_object_unref);
4221 g_object_unref (task);
4222 }
4223 else
4224 {
4225 dup = icon_info_dup (icon_info);
4226 g_task_set_task_data (task, dup, g_object_unref);
4227 g_task_run_in_thread (task, load_icon_thread);
4228 g_object_unref (task);
4229 }
4230}
4231
4232/**
4233 * ctk_icon_info_load_icon_finish:
4234 * @icon_info: a #CtkIconInfo from ctk_icon_theme_lookup_icon()
4235 * @res: a #GAsyncResult
4236 * @error: (allow-none): location to store error information on failure,
4237 * or %NULL.
4238 *
4239 * Finishes an async icon load, see ctk_icon_info_load_icon_async().
4240 *
4241 * Returns: (transfer full): the rendered icon; this may be a newly
4242 * created icon or a new reference to an internal icon, so you must
4243 * not modify the icon. Use g_object_unref() to release your reference
4244 * to the icon.
4245 *
4246 * Since: 3.8
4247 */
4248GdkPixbuf *
4249ctk_icon_info_load_icon_finish (CtkIconInfo *icon_info,
4250 GAsyncResult *result,
4251 GError **error)
4252{
4253 GTask *task = G_TASK (result)((((GTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((result)), ((g_task_get_type ()))))))
;
4254 CtkIconInfo *dup;
4255
4256 g_return_val_if_fail (g_task_is_valid (result, icon_info), NULL)do { if ((g_task_is_valid (result, icon_info))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "g_task_is_valid (result, icon_info)"
); return (((void*)0)); } } while (0)
;
4257
4258 dup = g_task_get_task_data (task);
4259 if (dup == NULL((void*)0) || g_task_had_error (task))
4260 return g_task_propagate_pointer (task, error);
4261
4262 /* We ran the thread and it was not cancelled */
4263
4264 /* Check if someone else updated the icon_info in between */
4265 if (!icon_info_get_pixbuf_ready (icon_info))
4266 {
4267 /* If not, copy results from dup back to icon_info */
4268 icon_info->emblems_applied = dup->emblems_applied;
4269 icon_info->scale = dup->scale;
4270 g_clear_object (&icon_info->pixbuf)do { _Static_assert (sizeof *((&icon_info->pixbuf)) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&icon_info->pixbuf))) _pp = ((&icon_info->pixbuf
)); __typeof__ (*((&icon_info->pixbuf))) _ptr = *_pp; *
_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while (
0)
;
4271 if (dup->pixbuf)
4272 icon_info->pixbuf = g_object_ref (dup->pixbuf)((__typeof__ (dup->pixbuf)) (g_object_ref) (dup->pixbuf
))
;
4273 g_clear_error (&icon_info->load_error);
4274 if (dup->load_error)
4275 icon_info->load_error = g_error_copy (dup->load_error);
4276 }
4277
4278 g_assert (icon_info_get_pixbuf_ready (icon_info))do { if (icon_info_get_pixbuf_ready (icon_info)) ; else g_assertion_message_expr
("Ctk", "ctkicontheme.c", 4278, ((const char*) (__func__)), "icon_info_get_pixbuf_ready (icon_info)"
); } while (0)
;
4279
4280 /* This is now guaranteed to not block */
4281 return ctk_icon_info_load_icon (icon_info, error);
4282}
4283
4284static void
4285proxy_symbolic_pixbuf_destroy (guchar *pixels,
4286 gpointer data)
4287{
4288 CtkIconInfo *icon_info = data;
4289 CtkIconTheme *icon_theme = icon_info->in_cache;
4290 SymbolicPixbufCache *symbolic_cache;
4291
4292 for (symbolic_cache = icon_info->symbolic_pixbuf_cache;
4293 symbolic_cache != NULL((void*)0);
4294 symbolic_cache = symbolic_cache->next)
4295 {
4296 if (symbolic_cache->proxy_pixbuf != NULL((void*)0) &&
4297 gdk_pixbuf_get_pixels (symbolic_cache->proxy_pixbuf) == pixels)
4298 break;
4299 }
4300
4301 g_assert (symbolic_cache != NULL)do { if (symbolic_cache != ((void*)0)) ; else g_assertion_message_expr
("Ctk", "ctkicontheme.c", 4301, ((const char*) (__func__)), "symbolic_cache != NULL"
); } while (0)
;
4302 g_assert (symbolic_cache->proxy_pixbuf != NULL)do { if (symbolic_cache->proxy_pixbuf != ((void*)0)) ; else
g_assertion_message_expr ("Ctk", "ctkicontheme.c", 4302, ((const
char*) (__func__)), "symbolic_cache->proxy_pixbuf != NULL"
); } while (0)
;
4303
4304 symbolic_cache->proxy_pixbuf = NULL((void*)0);
4305
4306 /* Keep it alive a bit longer */
4307 if (icon_theme != NULL((void*)0))
4308 ensure_in_lru_cache (icon_theme, icon_info);
4309
4310 g_object_unref (icon_info);
4311}
4312
4313static GdkPixbuf *
4314symbolic_cache_get_proxy (SymbolicPixbufCache *symbolic_cache,
4315 CtkIconInfo *icon_info)
4316{
4317 if (symbolic_cache->proxy_pixbuf)
4318 return g_object_ref (symbolic_cache->proxy_pixbuf)((__typeof__ (symbolic_cache->proxy_pixbuf)) (g_object_ref
) (symbolic_cache->proxy_pixbuf))
;
4319
4320 symbolic_cache->proxy_pixbuf =
4321 gdk_pixbuf_new_from_data (gdk_pixbuf_get_pixels (symbolic_cache->pixbuf),
4322 gdk_pixbuf_get_colorspace (symbolic_cache->pixbuf),
4323 gdk_pixbuf_get_has_alpha (symbolic_cache->pixbuf),
4324 gdk_pixbuf_get_bits_per_sample (symbolic_cache->pixbuf),
4325 gdk_pixbuf_get_width (symbolic_cache->pixbuf),
4326 gdk_pixbuf_get_height (symbolic_cache->pixbuf),
4327 gdk_pixbuf_get_rowstride (symbolic_cache->pixbuf),
4328 proxy_symbolic_pixbuf_destroy,
4329 g_object_ref (icon_info)((__typeof__ (icon_info)) (g_object_ref) (icon_info)));
4330
4331 return symbolic_cache->proxy_pixbuf;
4332}
4333
4334static gchar *
4335rgba_to_string_noalpha (const CdkRGBA *rgba)
4336{
4337 CdkRGBA color;
4338
4339 color = *rgba;
4340 color.alpha = 1.0;
4341
4342 return cdk_rgba_to_string (&color);
4343}
4344
4345static void
4346rgba_to_pixel(const CdkRGBA *rgba,
4347 guint8 pixel[4])
4348{
4349 pixel[0] = rgba->red * 255;
4350 pixel[1] = rgba->green * 255;
4351 pixel[2] = rgba->blue * 255;
4352 pixel[3] = 255;
4353}
4354
4355GdkPixbuf *
4356ctk_icon_theme_color_symbolic_pixbuf (GdkPixbuf *symbolic,
4357 const CdkRGBA *fg_color,
4358 const CdkRGBA *success_color,
4359 const CdkRGBA *warning_color,
4360 const CdkRGBA *error_color)
4361{
4362 int width, height, x, y, src_stride, dst_stride;
4363 guchar *src_data, *dst_data;
4364 guchar *src_row, *dst_row;
4365 int alpha;
4366 GdkPixbuf *colored;
4367 guint8 fg_pixel[4], success_pixel[4], warning_pixel[4], error_pixel[4];
4368
4369 alpha = fg_color->alpha * 255;
4370
4371 rgba_to_pixel (fg_color, fg_pixel);
4372 rgba_to_pixel (success_color, success_pixel);
4373 rgba_to_pixel (warning_color, warning_pixel);
4374 rgba_to_pixel (error_color, error_pixel);
4375
4376 width = gdk_pixbuf_get_width (symbolic);
4377 height = gdk_pixbuf_get_height (symbolic);
4378
4379 colored = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE(!(0)), 8, width, height);
4380
4381 src_stride = gdk_pixbuf_get_rowstride (symbolic);
4382 src_data = gdk_pixbuf_get_pixels (symbolic);
4383
4384 dst_data = gdk_pixbuf_get_pixels (colored);
4385 dst_stride = gdk_pixbuf_get_rowstride (colored);
4386
4387 for (y = 0; y < height; y++)
4388 {
4389 src_row = src_data + src_stride * y;
4390 dst_row = dst_data + dst_stride * y;
4391 for (x = 0; x < width; x++)
4392 {
4393 guint r, g, b, a;
4394 int c1, c2, c3, c4;
4395
4396 a = src_row[3];
4397 dst_row[3] = a * alpha / 255;
4398
4399 if (a == 0)
4400 {
4401 dst_row[0] = 0;
4402 dst_row[1] = 0;
4403 dst_row[2] = 0;
4404 }
4405 else
4406 {
4407 c2 = src_row[0];
4408 c3 = src_row[1];
4409 c4 = src_row[2];
4410
4411 if (c2 == 0 && c3 == 0 && c4 == 0)
4412 {
4413 dst_row[0] = fg_pixel[0];
4414 dst_row[1] = fg_pixel[1];
4415 dst_row[2] = fg_pixel[2];
4416 }
4417 else
4418 {
4419 c1 = 255 - c2 - c3 - c4;
4420
4421 r = fg_pixel[0] * c1 + success_pixel[0] * c2 + warning_pixel[0] * c3 + error_pixel[0] * c4;
4422 g = fg_pixel[1] * c1 + success_pixel[1] * c2 + warning_pixel[1] * c3 + error_pixel[1] * c4;
4423 b = fg_pixel[2] * c1 + success_pixel[2] * c2 + warning_pixel[2] * c3 + error_pixel[2] * c4;
4424
4425 dst_row[0] = r / 255;
4426 dst_row[1] = g / 255;
4427 dst_row[2] = b / 255;
4428 }
4429 }
4430
4431 src_row += 4;
4432 dst_row += 4;
4433 }
4434 }
4435
4436 return colored;
4437}
4438
4439static GdkPixbuf *
4440ctk_icon_info_load_symbolic_png (CtkIconInfo *icon_info,
4441 const CdkRGBA *fg,
4442 const CdkRGBA *success_color,
4443 const CdkRGBA *warning_color,
4444 const CdkRGBA *error_color,
4445 GError **error)
4446{
4447 CdkRGBA fg_default = { 0.7450980392156863, 0.7450980392156863, 0.7450980392156863, 1.0};
4448 CdkRGBA success_default = { 0.3046921492332342,0.6015716792553597, 0.023437857633325704, 1.0};
4449 CdkRGBA warning_default = {0.9570458533607996, 0.47266346227206835, 0.2421911955443656, 1.0 };
4450 CdkRGBA error_default = { 0.796887159533074, 0 ,0, 1.0 };
4451
4452 if (!icon_info_ensure_scale_and_pixbuf (icon_info))
4453 {
4454 if (icon_info->load_error)
4455 {
4456 if (error)
4457 *error = g_error_copy (icon_info->load_error);
4458 }
4459 else
4460 {
4461 g_set_error_literal (error,
4462 CTK_ICON_THEME_ERRORctk_icon_theme_error_quark (),
4463 CTK_ICON_THEME_NOT_FOUND,
4464 _("Failed to load icon")((char *) g_dgettext ("ctk30", "Failed to load icon")));
4465 }
4466
4467 return NULL((void*)0);
4468 }
4469
4470 return ctk_icon_theme_color_symbolic_pixbuf (icon_info->pixbuf,
4471 fg ? fg : &fg_default,
4472 success_color ? success_color : &success_default,
4473 warning_color ? warning_color : &warning_default,
4474 error_color ? error_color : &error_default);
4475}
4476
4477static GdkPixbuf *
4478ctk_icon_info_load_symbolic_svg (CtkIconInfo *icon_info,
4479 const CdkRGBA *fg,
4480 const CdkRGBA *success_color,
4481 const CdkRGBA *warning_color,
4482 const CdkRGBA *error_color,
4483 GError **error)
4484{
4485 GInputStream *stream;
4486 GdkPixbuf *pixbuf;
4487 gchar *css_fg;
4488 gchar *css_success;
4489 gchar *css_warning;
4490 gchar *css_error;
4491 gchar *data;
4492 gchar *width;
4493 gchar *height;
4494 gchar *file_data, *escaped_file_data;
4495 gsize file_len;
4496 gint symbolic_size;
4497 double alpha;
4498 gchar alphastr[G_ASCII_DTOSTR_BUF_SIZE(29 + 10)];
4499
4500 alpha = fg->alpha;
4501
4502 css_fg = rgba_to_string_noalpha (fg);
4503
4504 css_success = css_warning = css_error = NULL((void*)0);
4505
4506 if (warning_color)
4507 css_warning = rgba_to_string_noalpha (warning_color);
4508 else
4509 css_warning = g_strdup ("rgb(245,121,62)")g_strdup_inline ("rgb(245,121,62)");
4510
4511 if (error_color)
4512 css_error = rgba_to_string_noalpha (error_color);
4513 else
4514 css_error = g_strdup ("rgb(204,0,0)")g_strdup_inline ("rgb(204,0,0)");
4515
4516 if (success_color)
4517 css_success = rgba_to_string_noalpha (success_color);
4518 else
4519 css_success = g_strdup ("rgb(78,154,6)")g_strdup_inline ("rgb(78,154,6)");
4520
4521 if (!g_file_load_contents (icon_info->icon_file, NULL((void*)0), &file_data, &file_len, NULL((void*)0), error))
4522 return NULL((void*)0);
4523
4524 if (!icon_info_ensure_scale_and_pixbuf (icon_info))
4525 {
4526 g_propagate_error (error, icon_info->load_error);
4527 icon_info->load_error = NULL((void*)0);
4528 g_free (css_fg);
4529 g_free (css_warning);
4530 g_free (css_error);
4531 g_free (css_success);
4532 g_free (file_data);
4533 return NULL((void*)0);
4534 }
4535
4536 if (icon_info->symbolic_width == 0 ||
4537 icon_info->symbolic_height == 0)
4538 {
4539 /* Fetch size from the original icon */
4540 stream = g_memory_input_stream_new_from_data (file_data, file_len, NULL((void*)0));
4541 pixbuf = gdk_pixbuf_new_from_stream (stream, NULL((void*)0), error);
4542 g_object_unref (stream);
4543
4544 if (!pixbuf)
4545 {
4546 g_free (css_fg);
4547 g_free (css_warning);
4548 g_free (css_error);
4549 g_free (css_success);
4550 g_free (file_data);
4551 return NULL((void*)0);
4552 }
4553
4554 icon_info->symbolic_width = gdk_pixbuf_get_width (pixbuf);
4555 icon_info->symbolic_height = gdk_pixbuf_get_height (pixbuf);
4556 g_object_unref (pixbuf);
4557 }
4558
4559 symbolic_size = MAX (icon_info->symbolic_width, icon_info->symbolic_height)(((icon_info->symbolic_width) > (icon_info->symbolic_height
)) ? (icon_info->symbolic_width) : (icon_info->symbolic_height
))
;
4560
4561 CTK_NOTE (ICONTHEME,do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
if (icon_info->dir_type == ICON_THEME_DIR_UNTHEMED) g_message
("Symbolic icon %s is not in an icon theme directory", icon_info
->key.icon_names ? icon_info->key.icon_names[0] : icon_info
->filename); else if (icon_info->dir_size * icon_info->
dir_scale != symbolic_size) g_message ("Symbolic icon %s of size %d is in an icon theme directory of size %d"
, icon_info->key.icon_names ? icon_info->key.icon_names
[0] : icon_info->filename, symbolic_size, icon_info->dir_size
* icon_info->dir_scale); }; } while (0)
4562 if (icon_info->dir_type == ICON_THEME_DIR_UNTHEMED)do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
if (icon_info->dir_type == ICON_THEME_DIR_UNTHEMED) g_message
("Symbolic icon %s is not in an icon theme directory", icon_info
->key.icon_names ? icon_info->key.icon_names[0] : icon_info
->filename); else if (icon_info->dir_size * icon_info->
dir_scale != symbolic_size) g_message ("Symbolic icon %s of size %d is in an icon theme directory of size %d"
, icon_info->key.icon_names ? icon_info->key.icon_names
[0] : icon_info->filename, symbolic_size, icon_info->dir_size
* icon_info->dir_scale); }; } while (0)
4563 g_message ("Symbolic icon %s is not in an icon theme directory",do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
if (icon_info->dir_type == ICON_THEME_DIR_UNTHEMED) g_message
("Symbolic icon %s is not in an icon theme directory", icon_info
->key.icon_names ? icon_info->key.icon_names[0] : icon_info
->filename); else if (icon_info->dir_size * icon_info->
dir_scale != symbolic_size) g_message ("Symbolic icon %s of size %d is in an icon theme directory of size %d"
, icon_info->key.icon_names ? icon_info->key.icon_names
[0] : icon_info->filename, symbolic_size, icon_info->dir_size
* icon_info->dir_scale); }; } while (0)
4564 icon_info->key.icon_names ? icon_info->key.icon_names[0] : icon_info->filename);do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
if (icon_info->dir_type == ICON_THEME_DIR_UNTHEMED) g_message
("Symbolic icon %s is not in an icon theme directory", icon_info
->key.icon_names ? icon_info->key.icon_names[0] : icon_info
->filename); else if (icon_info->dir_size * icon_info->
dir_scale != symbolic_size) g_message ("Symbolic icon %s of size %d is in an icon theme directory of size %d"
, icon_info->key.icon_names ? icon_info->key.icon_names
[0] : icon_info->filename, symbolic_size, icon_info->dir_size
* icon_info->dir_scale); }; } while (0)
4565 else if (icon_info->dir_size * icon_info->dir_scale != symbolic_size)do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
if (icon_info->dir_type == ICON_THEME_DIR_UNTHEMED) g_message
("Symbolic icon %s is not in an icon theme directory", icon_info
->key.icon_names ? icon_info->key.icon_names[0] : icon_info
->filename); else if (icon_info->dir_size * icon_info->
dir_scale != symbolic_size) g_message ("Symbolic icon %s of size %d is in an icon theme directory of size %d"
, icon_info->key.icon_names ? icon_info->key.icon_names
[0] : icon_info->filename, symbolic_size, icon_info->dir_size
* icon_info->dir_scale); }; } while (0)
4566 g_message ("Symbolic icon %s of size %d is in an icon theme directory of size %d",do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
if (icon_info->dir_type == ICON_THEME_DIR_UNTHEMED) g_message
("Symbolic icon %s is not in an icon theme directory", icon_info
->key.icon_names ? icon_info->key.icon_names[0] : icon_info
->filename); else if (icon_info->dir_size * icon_info->
dir_scale != symbolic_size) g_message ("Symbolic icon %s of size %d is in an icon theme directory of size %d"
, icon_info->key.icon_names ? icon_info->key.icon_names
[0] : icon_info->filename, symbolic_size, icon_info->dir_size
* icon_info->dir_scale); }; } while (0)
4567 icon_info->key.icon_names ? icon_info->key.icon_names[0] : icon_info->filename,do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
if (icon_info->dir_type == ICON_THEME_DIR_UNTHEMED) g_message
("Symbolic icon %s is not in an icon theme directory", icon_info
->key.icon_names ? icon_info->key.icon_names[0] : icon_info
->filename); else if (icon_info->dir_size * icon_info->
dir_scale != symbolic_size) g_message ("Symbolic icon %s of size %d is in an icon theme directory of size %d"
, icon_info->key.icon_names ? icon_info->key.icon_names
[0] : icon_info->filename, symbolic_size, icon_info->dir_size
* icon_info->dir_scale); }; } while (0)
4568 symbolic_size,do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
if (icon_info->dir_type == ICON_THEME_DIR_UNTHEMED) g_message
("Symbolic icon %s is not in an icon theme directory", icon_info
->key.icon_names ? icon_info->key.icon_names[0] : icon_info
->filename); else if (icon_info->dir_size * icon_info->
dir_scale != symbolic_size) g_message ("Symbolic icon %s of size %d is in an icon theme directory of size %d"
, icon_info->key.icon_names ? icon_info->key.icon_names
[0] : icon_info->filename, symbolic_size, icon_info->dir_size
* icon_info->dir_scale); }; } while (0)
4569 icon_info->dir_size * icon_info->dir_scale)do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
if (icon_info->dir_type == ICON_THEME_DIR_UNTHEMED) g_message
("Symbolic icon %s is not in an icon theme directory", icon_info
->key.icon_names ? icon_info->key.icon_names[0] : icon_info
->filename); else if (icon_info->dir_size * icon_info->
dir_scale != symbolic_size) g_message ("Symbolic icon %s of size %d is in an icon theme directory of size %d"
, icon_info->key.icon_names ? icon_info->key.icon_names
[0] : icon_info->filename, symbolic_size, icon_info->dir_size
* icon_info->dir_scale); }; } while (0)
4570 )do { if ((ctk_get_debug_flags () & CTK_DEBUG_ICONTHEME)) {
if (icon_info->dir_type == ICON_THEME_DIR_UNTHEMED) g_message
("Symbolic icon %s is not in an icon theme directory", icon_info
->key.icon_names ? icon_info->key.icon_names[0] : icon_info
->filename); else if (icon_info->dir_size * icon_info->
dir_scale != symbolic_size) g_message ("Symbolic icon %s of size %d is in an icon theme directory of size %d"
, icon_info->key.icon_names ? icon_info->key.icon_names
[0] : icon_info->filename, symbolic_size, icon_info->dir_size
* icon_info->dir_scale); }; } while (0)
;
4571
4572 width = g_strdup_printf ("%d", icon_info->symbolic_width);
4573 height = g_strdup_printf ("%d", icon_info->symbolic_height);
4574
4575 escaped_file_data = g_base64_encode ((guchar *) file_data, file_len);
4576 g_free (file_data);
4577
4578 g_ascii_dtostr (alphastr, G_ASCII_DTOSTR_BUF_SIZE(29 + 10), CLAMP (alpha, 0, 1)(((alpha) > (1)) ? (1) : (((alpha) < (0)) ? (0) : (alpha
)))
);
4579
4580 data = g_strconcat ("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
4581 "<svg version=\"1.1\"\n"
4582 " xmlns=\"http://www.w3.org/2000/svg\"\n"
4583 " xmlns:xi=\"http://www.w3.org/2001/XInclude\"\n"
4584 " width=\"", width, "\"\n"
4585 " height=\"", height, "\">\n"
4586 " <style type=\"text/css\">\n"
4587 " rect,path,ellipse,circle,polygon {\n"
4588 " fill: ", css_fg," !important;\n"
4589 " }\n"
4590 " .warning {\n"
4591 " fill: ", css_warning, " !important;\n"
4592 " }\n"
4593 " .error {\n"
4594 " fill: ", css_error ," !important;\n"
4595 " }\n"
4596 " .success {\n"
4597 " fill: ", css_success, " !important;\n"
4598 " }\n"
4599 " </style>\n"
4600 " <g opacity=\"", alphastr, "\" ><xi:include href=\"data:text/xml;base64,", escaped_file_data, "\"/></g>\n"
4601 "</svg>",
4602 NULL((void*)0));
4603 g_free (escaped_file_data);
4604 g_free (css_fg);
4605 g_free (css_warning);
4606 g_free (css_error);
4607 g_free (css_success);
4608 g_free (width);
4609 g_free (height);
4610
4611 stream = g_memory_input_stream_new_from_data (data, -1, g_free);
4612 pixbuf = gdk_pixbuf_new_from_stream_at_scale (stream,
4613 gdk_pixbuf_get_width (icon_info->pixbuf),
4614 gdk_pixbuf_get_height (icon_info->pixbuf),
4615 TRUE(!(0)),
4616 NULL((void*)0),
4617 error);
4618 g_object_unref (stream);
4619
4620 return pixbuf;
4621}
4622
4623
4624static GdkPixbuf *
4625ctk_icon_info_load_symbolic_internal (CtkIconInfo *icon_info,
4626 const CdkRGBA *fg,
4627 const CdkRGBA *success_color,
4628 const CdkRGBA *warning_color,
4629 const CdkRGBA *error_color,
4630 gboolean use_cache,
4631 GError **error)
4632{
4633 GdkPixbuf *pixbuf;
4634 SymbolicPixbufCache *symbolic_cache;
4635 char *icon_uri;
4636
4637 if (use_cache)
4638 {
4639 symbolic_cache = symbolic_pixbuf_cache_matches (icon_info->symbolic_pixbuf_cache,
4640 fg, success_color, warning_color, error_color);
4641 if (symbolic_cache)
4642 return symbolic_cache_get_proxy (symbolic_cache, icon_info);
4643 }
4644
4645 /* css_fg can't possibly have failed, otherwise
4646 * that would mean we have a broken style
4647 */
4648 g_return_val_if_fail (fg != NULL, NULL)do { if ((fg != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "fg != NULL"); return ((
(void*)0)); } } while (0)
;
4649
4650 icon_uri = g_file_get_uri (icon_info->icon_file);
4651 if (g_str_has_suffix (icon_uri, ".symbolic.png")(__builtin_constant_p (".symbolic.png")? __extension__ ({ const
char * const __str = (icon_uri); const char * const __suffix
= (".symbolic.png"); gboolean __result = (0); if (__str == (
(void*)0) || __suffix == ((void*)0)) __result = (g_str_has_suffix
) (__str, __suffix); else { const size_t __str_len = strlen (
((__str) + !(__str))); const size_t __suffix_len = strlen (((
__suffix) + !(__suffix))); if (__str_len >= __suffix_len) __result
= memcmp (__str + __str_len - __suffix_len, ((__suffix) + !(
__suffix)), __suffix_len) == 0; } __result; }) : (g_str_has_suffix
) (icon_uri, ".symbolic.png") )
)
4652 pixbuf = ctk_icon_info_load_symbolic_png (icon_info, fg, success_color, warning_color, error_color, error);
4653 else
4654 pixbuf = ctk_icon_info_load_symbolic_svg (icon_info, fg, success_color, warning_color, error_color, error);
4655
4656 g_free (icon_uri);
4657
4658 if (pixbuf != NULL((void*)0))
4659 {
4660 GdkPixbuf *icon;
4661
4662 icon = apply_emblems_to_pixbuf (pixbuf, icon_info);
4663 if (icon != NULL((void*)0))
4664 {
4665 g_object_unref (pixbuf);
4666 pixbuf = icon;
4667 }
4668
4669 if (use_cache)
4670 {
4671 icon_info->symbolic_pixbuf_cache =
4672 symbolic_pixbuf_cache_new (pixbuf, fg, success_color, warning_color, error_color,
4673 icon_info->symbolic_pixbuf_cache);
4674 g_object_unref (pixbuf);
4675 return symbolic_cache_get_proxy (icon_info->symbolic_pixbuf_cache, icon_info);
4676 }
4677 else
4678 return pixbuf;
4679 }
4680
4681 return NULL((void*)0);
4682}
4683
4684/**
4685 * ctk_icon_info_load_symbolic:
4686 * @icon_info: a #CtkIconInfo
4687 * @fg: a #CdkRGBA representing the foreground color of the icon
4688 * @success_color: (allow-none): a #CdkRGBA representing the warning color
4689 * of the icon or %NULL to use the default color
4690 * @warning_color: (allow-none): a #CdkRGBA representing the warning color
4691 * of the icon or %NULL to use the default color
4692 * @error_color: (allow-none): a #CdkRGBA representing the error color
4693 * of the icon or %NULL to use the default color (allow-none)
4694 * @was_symbolic: (out) (allow-none): a #gboolean, returns whether the
4695 * loaded icon was a symbolic one and whether the @fg color was
4696 * applied to it.
4697 * @error: (allow-none): location to store error information on failure,
4698 * or %NULL.
4699 *
4700 * Loads an icon, modifying it to match the system colours for the foreground,
4701 * success, warning and error colors provided. If the icon is not a symbolic
4702 * one, the function will return the result from ctk_icon_info_load_icon().
4703 *
4704 * This allows loading symbolic icons that will match the system theme.
4705 *
4706 * Unless you are implementing a widget, you will want to use
4707 * g_themed_icon_new_with_default_fallbacks() to load the icon.
4708 *
4709 * As implementation details, the icon loaded needs to be of SVG type,
4710 * contain the “symbolic” term as the last component of the icon name,
4711 * and use the “fg”, “success”, “warning” and “error” CSS styles in the
4712 * SVG file itself.
4713 *
4714 * See the [Symbolic Icons Specification](http://www.freedesktop.org/wiki/SymbolicIcons)
4715 * for more information about symbolic icons.
4716 *
4717 * Returns: (transfer full): a #GdkPixbuf representing the loaded icon
4718 *
4719 * Since: 3.0
4720 */
4721GdkPixbuf *
4722ctk_icon_info_load_symbolic (CtkIconInfo *icon_info,
4723 const CdkRGBA *fg,
4724 const CdkRGBA *success_color,
4725 const CdkRGBA *warning_color,
4726 const CdkRGBA *error_color,
4727 gboolean *was_symbolic,
4728 GError **error)
4729{
4730 gboolean is_symbolic;
4731
4732 g_return_val_if_fail (icon_info != NULL, NULL)do { if ((icon_info != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "icon_info != NULL"); return
(((void*)0)); } } while (0)
;
4733 g_return_val_if_fail (fg != NULL, NULL)do { if ((fg != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "fg != NULL"); return ((
(void*)0)); } } while (0)
;
4734
4735 is_symbolic = ctk_icon_info_is_symbolic (icon_info);
4736
4737 if (was_symbolic)
4738 *was_symbolic = is_symbolic;
4739
4740 if (!is_symbolic)
4741 return ctk_icon_info_load_icon (icon_info, error);
4742
4743 return ctk_icon_info_load_symbolic_internal (icon_info,
4744 fg, success_color,
4745 warning_color, error_color,
4746 TRUE(!(0)),
4747 error);
4748}
4749
4750void
4751ctk_icon_theme_lookup_symbolic_colors (CtkCssStyle *style,
4752 CdkRGBA *color_out,
4753 CdkRGBA *success_out,
4754 CdkRGBA *warning_out,
4755 CdkRGBA *error_out)
4756{
4757 CtkCssValue *palette, *color;
4758 const CdkRGBA *lookup;
4759
4760 color = ctk_css_style_get_value (style, CTK_CSS_PROPERTY_COLOR);
4761 palette = ctk_css_style_get_value (style, CTK_CSS_PROPERTY_ICON_PALETTE);
4762 *color_out = *_ctk_css_rgba_value_get_rgba (color);
4763
4764 lookup = ctk_css_palette_value_get_color (palette, "success");
4765 if (lookup)
4766 *success_out = *lookup;
4767 else
4768 *success_out = *color_out;
4769
4770 lookup = ctk_css_palette_value_get_color (palette, "warning");
4771 if (lookup)
4772 *warning_out = *lookup;
4773 else
4774 *warning_out = *color_out;
4775
4776 lookup = ctk_css_palette_value_get_color (palette, "error");
4777 if (lookup)
4778 *error_out = *lookup;
4779 else
4780 *error_out = *color_out;
4781}
4782
4783/**
4784 * ctk_icon_info_load_symbolic_for_context:
4785 * @icon_info: a #CtkIconInfo
4786 * @context: a #CtkStyleContext
4787 * @was_symbolic: (out) (allow-none): a #gboolean, returns whether the
4788 * loaded icon was a symbolic one and whether the @fg color was
4789 * applied to it.
4790 * @error: (allow-none): location to store error information on failure,
4791 * or %NULL.
4792 *
4793 * Loads an icon, modifying it to match the system colors for the foreground,
4794 * success, warning and error colors provided. If the icon is not a symbolic
4795 * one, the function will return the result from ctk_icon_info_load_icon().
4796 * This function uses the regular foreground color and the symbolic colors
4797 * with the names “success_color”, “warning_color” and “error_color” from
4798 * the context.
4799 *
4800 * This allows loading symbolic icons that will match the system theme.
4801 *
4802 * See ctk_icon_info_load_symbolic() for more details.
4803 *
4804 * Returns: (transfer full): a #GdkPixbuf representing the loaded icon
4805 *
4806 * Since: 3.0
4807 */
4808GdkPixbuf *
4809ctk_icon_info_load_symbolic_for_context (CtkIconInfo *icon_info,
4810 CtkStyleContext *context,
4811 gboolean *was_symbolic,
4812 GError **error)
4813{
4814 CdkRGBA fg;
4815 CdkRGBA success_color;
4816 CdkRGBA warning_color;
4817 CdkRGBA error_color;
4818 gboolean is_symbolic;
4819
4820 g_return_val_if_fail (icon_info != NULL, NULL)do { if ((icon_info != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "icon_info != NULL"); return
(((void*)0)); } } while (0)
;
4821 g_return_val_if_fail (context != NULL, NULL)do { if ((context != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "context != NULL"); return
(((void*)0)); } } while (0)
;
4822
4823 is_symbolic = ctk_icon_info_is_symbolic (icon_info);
4824
4825 if (was_symbolic)
4826 *was_symbolic = is_symbolic;
4827
4828 if (!is_symbolic)
4829 return ctk_icon_info_load_icon (icon_info, error);
4830
4831 ctk_icon_theme_lookup_symbolic_colors (ctk_style_context_lookup_style (context),
4832 &fg, &success_color,
4833 &warning_color, &error_color);
4834
4835 return ctk_icon_info_load_symbolic_internal (icon_info,
4836 &fg, &success_color,
4837 &warning_color, &error_color,
4838 TRUE(!(0)),
4839 error);
4840}
4841
4842typedef struct {
4843 gboolean is_symbolic;
4844 CtkIconInfo *dup;
4845 CdkRGBA fg;
4846 gboolean fg_set;
4847 CdkRGBA success_color;
4848 gboolean success_color_set;
4849 CdkRGBA warning_color;
4850 gboolean warning_color_set;
4851 CdkRGBA error_color;
4852 gboolean error_color_set;
4853} AsyncSymbolicData;
4854
4855static void
4856async_symbolic_data_free (AsyncSymbolicData *data)
4857{
4858 if (data->dup)
4859 g_object_unref (data->dup);
4860 g_slice_free (AsyncSymbolicData, data)do { if (1) g_slice_free1 (sizeof (AsyncSymbolicData), (data)
); else (void) ((AsyncSymbolicData*) 0 == (data)); } while (0
)
;
4861}
4862
4863static void
4864async_load_no_symbolic_cb (GObject *source_object,
4865 GAsyncResult *res,
4866 gpointer user_data)
4867{
4868 CtkIconInfo *icon_info = CTK_ICON_INFO (source_object)((((CtkIconInfo*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((source_object)), ((ctk_icon_info_get_type ()))))))
;
4869 GTask *task = user_data;
4870 GError *error = NULL((void*)0);
4871 GdkPixbuf *pixbuf;
4872
4873 pixbuf = ctk_icon_info_load_icon_finish (icon_info, res, &error);
4874 if (pixbuf == NULL((void*)0))
4875 g_task_return_error (task, error);
4876 else
4877 g_task_return_pointer (task, pixbuf, g_object_unref);
4878 g_object_unref (task);
4879}
4880
4881static void
4882load_symbolic_icon_thread (GTask *task,
4883 gpointer source_object G_GNUC_UNUSED__attribute__ ((__unused__)),
4884 gpointer task_data,
4885 GCancellable *cancellable G_GNUC_UNUSED__attribute__ ((__unused__)))
4886{
4887 AsyncSymbolicData *data = task_data;
4888 GError *error;
4889 GdkPixbuf *pixbuf;
4890
4891 error = NULL((void*)0);
4892 pixbuf = ctk_icon_info_load_symbolic_internal (data->dup,
4893 data->fg_set ? &data->fg : NULL((void*)0),
4894 data->success_color_set ? &data->success_color : NULL((void*)0),
4895 data->warning_color_set ? &data->warning_color : NULL((void*)0),
4896 data->error_color_set ? &data->error_color : NULL((void*)0),
4897 FALSE(0),
4898 &error);
4899 if (pixbuf == NULL((void*)0))
4900 g_task_return_error (task, error);
4901 else
4902 g_task_return_pointer (task, pixbuf, g_object_unref);
4903}
4904
4905/**
4906 * ctk_icon_info_load_symbolic_async:
4907 * @icon_info: a #CtkIconInfo from ctk_icon_theme_lookup_icon()
4908 * @fg: a #CdkRGBA representing the foreground color of the icon
4909 * @success_color: (allow-none): a #CdkRGBA representing the warning color
4910 * of the icon or %NULL to use the default color
4911 * @warning_color: (allow-none): a #CdkRGBA representing the warning color
4912 * of the icon or %NULL to use the default color
4913 * @error_color: (allow-none): a #CdkRGBA representing the error color
4914 * of the icon or %NULL to use the default color (allow-none)
4915 * @cancellable: (allow-none): optional #GCancellable object,
4916 * %NULL to ignore
4917 * @callback: (scope async): a #GAsyncReadyCallback to call when the
4918 * request is satisfied
4919 * @user_data: (closure): the data to pass to callback function
4920 *
4921 * Asynchronously load, render and scale a symbolic icon previously looked up
4922 * from the icon theme using ctk_icon_theme_lookup_icon().
4923 *
4924 * For more details, see ctk_icon_info_load_symbolic() which is the synchronous
4925 * version of this call.
4926 *
4927 * Since: 3.8
4928 */
4929void
4930ctk_icon_info_load_symbolic_async (CtkIconInfo *icon_info,
4931 const CdkRGBA *fg,
4932 const CdkRGBA *success_color,
4933 const CdkRGBA *warning_color,
4934 const CdkRGBA *error_color,
4935 GCancellable *cancellable,
4936 GAsyncReadyCallback callback,
4937 gpointer user_data)
4938{
4939 GTask *task;
4940 AsyncSymbolicData *data;
4941 SymbolicPixbufCache *symbolic_cache;
4942 GdkPixbuf *pixbuf;
4943
4944 g_return_if_fail (icon_info != NULL)do { if ((icon_info != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "icon_info != NULL"); return
; } } while (0)
;
4945 g_return_if_fail (fg != NULL)do { if ((fg != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "fg != NULL"); return; }
} while (0)
;
4946
4947 task = g_task_new (icon_info, cancellable, callback, user_data);
4948
4949 data = g_slice_new0 (AsyncSymbolicData)((AsyncSymbolicData*) g_slice_alloc0 (sizeof (AsyncSymbolicData
)))
;
4950 g_task_set_task_data (task, data, (GDestroyNotify) async_symbolic_data_free);
4951
4952 data->is_symbolic = ctk_icon_info_is_symbolic (icon_info);
4953
4954 if (!data->is_symbolic)
4955 {
4956 ctk_icon_info_load_icon_async (icon_info, cancellable, async_load_no_symbolic_cb, g_object_ref (task)((__typeof__ (task)) (g_object_ref) (task)));
4957 }
4958 else
4959 {
4960 symbolic_cache = symbolic_pixbuf_cache_matches (icon_info->symbolic_pixbuf_cache,
4961 fg, success_color, warning_color, error_color);
4962 if (symbolic_cache)
4963 {
4964 pixbuf = symbolic_cache_get_proxy (symbolic_cache, icon_info);
4965 g_task_return_pointer (task, pixbuf, g_object_unref);
4966 }
4967 else
4968 {
4969 if (fg)
4970 {
4971 data->fg = *fg;
4972 data->fg_set = TRUE(!(0));
4973 }
4974
4975 if (success_color)
4976 {
4977 data->success_color = *success_color;
4978 data->success_color_set = TRUE(!(0));
4979 }
4980
4981 if (warning_color)
4982 {
4983 data->warning_color = *warning_color;
4984 data->warning_color_set = TRUE(!(0));
4985 }
4986
4987 if (error_color)
4988 {
4989 data->error_color = *error_color;
4990 data->error_color_set = TRUE(!(0));
4991 }
4992
4993 data->dup = icon_info_dup (icon_info);
4994 g_task_run_in_thread (task, load_symbolic_icon_thread);
4995 }
4996 }
4997 g_object_unref (task);
4998}
4999
5000/**
5001 * ctk_icon_info_load_symbolic_finish:
5002 * @icon_info: a #CtkIconInfo from ctk_icon_theme_lookup_icon()
5003 * @res: a #GAsyncResult
5004 * @was_symbolic: (out) (allow-none): a #gboolean, returns whether the
5005 * loaded icon was a symbolic one and whether the @fg color was
5006 * applied to it.
5007 * @error: (allow-none): location to store error information on failure,
5008 * or %NULL.
5009 *
5010 * Finishes an async icon load, see ctk_icon_info_load_symbolic_async().
5011 *
5012 * Returns: (transfer full): the rendered icon; this may be a newly
5013 * created icon or a new reference to an internal icon, so you must
5014 * not modify the icon. Use g_object_unref() to release your reference
5015 * to the icon.
5016 *
5017 * Since: 3.8
5018 */
5019GdkPixbuf *
5020ctk_icon_info_load_symbolic_finish (CtkIconInfo *icon_info,
5021 GAsyncResult *result,
5022 gboolean *was_symbolic,
5023 GError **error)
5024{
5025 GTask *task = G_TASK (result)((((GTask*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((result)), ((g_task_get_type ()))))))
;
5026 AsyncSymbolicData *data = g_task_get_task_data (task);
5027 SymbolicPixbufCache *symbolic_cache;
5028 GdkPixbuf *pixbuf;
5029
5030 if (was_symbolic)
5031 *was_symbolic = data->is_symbolic;
5032
5033 if (data->dup && !g_task_had_error (task))
5034 {
5035 pixbuf = g_task_propagate_pointer (task, NULL((void*)0));
5036
5037 g_assert (pixbuf != NULL)do { if (pixbuf != ((void*)0)) ; else g_assertion_message_expr
("Ctk", "ctkicontheme.c", 5037, ((const char*) (__func__)), "pixbuf != NULL"
); } while (0)
; /* we checked for !had_error above */
5038
5039 symbolic_cache = symbolic_pixbuf_cache_matches (icon_info->symbolic_pixbuf_cache,
5040 data->fg_set ? &data->fg : NULL((void*)0),
5041 data->success_color_set ? &data->success_color : NULL((void*)0),
5042 data->warning_color_set ? &data->warning_color : NULL((void*)0),
5043 data->error_color_set ? &data->error_color : NULL((void*)0));
5044
5045 if (symbolic_cache == NULL((void*)0))
5046 {
5047 symbolic_cache = icon_info->symbolic_pixbuf_cache =
5048 symbolic_pixbuf_cache_new (pixbuf,
5049 data->fg_set ? &data->fg : NULL((void*)0),
5050 data->success_color_set ? &data->success_color : NULL((void*)0),
5051 data->warning_color_set ? &data->warning_color : NULL((void*)0),
5052 data->error_color_set ? &data->error_color : NULL((void*)0),
5053 icon_info->symbolic_pixbuf_cache);
5054 }
5055
5056 g_object_unref (pixbuf);
5057
5058 return symbolic_cache_get_proxy (symbolic_cache, icon_info);
5059 }
5060
5061 return g_task_propagate_pointer (task, error);
5062}
5063
5064/**
5065 * ctk_icon_info_load_symbolic_for_context_async:
5066 * @icon_info: a #CtkIconInfo from ctk_icon_theme_lookup_icon()
5067 * @context: a #CtkStyleContext
5068 * @cancellable: (allow-none): optional #GCancellable object,
5069 * %NULL to ignore
5070 * @callback: (scope async): a #GAsyncReadyCallback to call when the
5071 * request is satisfied
5072 * @user_data: (closure): the data to pass to callback function
5073 *
5074 * Asynchronously load, render and scale a symbolic icon previously
5075 * looked up from the icon theme using ctk_icon_theme_lookup_icon().
5076 *
5077 * For more details, see ctk_icon_info_load_symbolic_for_context()
5078 * which is the synchronous version of this call.
5079 *
5080 * Since: 3.8
5081 */
5082void
5083ctk_icon_info_load_symbolic_for_context_async (CtkIconInfo *icon_info,
5084 CtkStyleContext *context,
5085 GCancellable *cancellable,
5086 GAsyncReadyCallback callback,
5087 gpointer user_data)
5088{
5089 CdkRGBA fg;
5090 CdkRGBA success_color;
5091 CdkRGBA warning_color;
5092 CdkRGBA error_color;
5093
5094 g_return_if_fail (icon_info != NULL)do { if ((icon_info != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "icon_info != NULL"); return
; } } while (0)
;
5095 g_return_if_fail (context != NULL)do { if ((context != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "context != NULL"); return
; } } while (0)
;
5096
5097 ctk_icon_theme_lookup_symbolic_colors (ctk_style_context_lookup_style (context),
5098 &fg, &success_color,
5099 &warning_color, &error_color);
5100
5101 ctk_icon_info_load_symbolic_async (icon_info,
5102 &fg, &success_color,
5103 &warning_color, &error_color,
5104 cancellable, callback, user_data);
5105}
5106
5107/**
5108 * ctk_icon_info_load_symbolic_for_context_finish:
5109 * @icon_info: a #CtkIconInfo from ctk_icon_theme_lookup_icon()
5110 * @res: a #GAsyncResult
5111 * @was_symbolic: (out) (allow-none): a #gboolean, returns whether the
5112 * loaded icon was a symbolic one and whether the @fg color was
5113 * applied to it.
5114 * @error: (allow-none): location to store error information on failure,
5115 * or %NULL.
5116 *
5117 * Finishes an async icon load, see ctk_icon_info_load_symbolic_for_context_async().
5118 *
5119 * Returns: (transfer full): the rendered icon; this may be a newly
5120 * created icon or a new reference to an internal icon, so you must
5121 * not modify the icon. Use g_object_unref() to release your reference
5122 * to the icon.
5123 *
5124 * Since: 3.8
5125 */
5126GdkPixbuf *
5127ctk_icon_info_load_symbolic_for_context_finish (CtkIconInfo *icon_info,
5128 GAsyncResult *result,
5129 gboolean *was_symbolic,
5130 GError **error)
5131{
5132 return ctk_icon_info_load_symbolic_finish (icon_info, result, was_symbolic, error);
5133}
5134
5135static CdkRGBA *
5136color_to_rgba (CdkColor *color,
5137 CdkRGBA *rgba)
5138{
5139 rgba->red = color->red / 65535.0;
5140 rgba->green = color->green / 65535.0;
5141 rgba->blue = color->blue / 65535.0;
5142 rgba->alpha = 1.0;
5143 return rgba;
5144}
5145
5146/**
5147 * ctk_icon_info_load_symbolic_for_style:
5148 * @icon_info: a #CtkIconInfo
5149 * @style: a #CtkStyle to take the colors from
5150 * @state: the widget state to use for colors
5151 * @was_symbolic: (out) (allow-none): a #gboolean, returns whether the
5152 * loaded icon was a symbolic one and whether the @fg color was
5153 * applied to it.
5154 * @error: (allow-none): location to store error information on failure,
5155 * or %NULL.
5156 *
5157 * Loads an icon, modifying it to match the system colours for the foreground,
5158 * success, warning and error colors provided. If the icon is not a symbolic
5159 * one, the function will return the result from ctk_icon_info_load_icon().
5160 *
5161 * This allows loading symbolic icons that will match the system theme.
5162 *
5163 * See ctk_icon_info_load_symbolic() for more details.
5164 *
5165 * Returns: (transfer full): a #GdkPixbuf representing the loaded icon
5166 *
5167 * Since: 3.0
5168 *
5169 * Deprecated: 3.0: Use ctk_icon_info_load_symbolic_for_context() instead
5170 */
5171GdkPixbuf *
5172ctk_icon_info_load_symbolic_for_style (CtkIconInfo *icon_info,
5173 CtkStyle *style,
5174 CtkStateType state,
5175 gboolean *was_symbolic,
5176 GError **error)
5177{
5178 CdkColor color;
5179 CdkRGBA fg;
5180 CdkRGBA success_color;
5181 CdkRGBA *success_colorp;
5182 CdkRGBA warning_color;
5183 CdkRGBA *warning_colorp;
5184 CdkRGBA error_color;
5185 CdkRGBA *error_colorp;
5186 gboolean is_symbolic;
5187
5188 g_return_val_if_fail (icon_info != NULL, NULL)do { if ((icon_info != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "icon_info != NULL"); return
(((void*)0)); } } while (0)
;
5189 g_return_val_if_fail (style != NULL, NULL)do { if ((style != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "style != NULL"); return
(((void*)0)); } } while (0)
;
5190
5191 is_symbolic = ctk_icon_info_is_symbolic (icon_info);
5192
5193 if (was_symbolic)
5194 *was_symbolic = is_symbolic;
5195
5196 if (!is_symbolic)
5197 return ctk_icon_info_load_icon (icon_info, error);
5198
5199 color_to_rgba (&style->fg[state], &fg);
5200
5201 success_colorp = warning_colorp = error_colorp = NULL((void*)0);
5202
5203 if (ctk_style_lookup_color (style, "success_color", &color))
5204 success_colorp = color_to_rgba (&color, &success_color);
5205
5206 if (ctk_style_lookup_color (style, "warning_color", &color))
5207 warning_colorp = color_to_rgba (&color, &warning_color);
5208
5209 if (ctk_style_lookup_color (style, "error_color", &color))
5210 error_colorp = color_to_rgba (&color, &error_color);
5211
5212 return ctk_icon_info_load_symbolic_internal (icon_info,
5213 &fg, success_colorp,
5214 warning_colorp, error_colorp,
5215 TRUE(!(0)),
5216 error);
5217}
5218
5219/**
5220 * ctk_icon_info_set_raw_coordinates:
5221 * @icon_info: a #CtkIconInfo
5222 * @raw_coordinates: whether the coordinates of embedded rectangles
5223 * and attached points should be returned in their original
5224 * (unscaled) form.
5225 *
5226 * Sets whether the coordinates returned by ctk_icon_info_get_embedded_rect()
5227 * and ctk_icon_info_get_attach_points() should be returned in their
5228 * original form as specified in the icon theme, instead of scaled
5229 * appropriately for the pixbuf returned by ctk_icon_info_load_icon().
5230 *
5231 * Raw coordinates are somewhat strange; they are specified to be with
5232 * respect to the unscaled pixmap for PNG and XPM icons, but for SVG
5233 * icons, they are in a 1000x1000 coordinate space that is scaled
5234 * to the final size of the icon. You can determine if the icon is an SVG
5235 * icon by using ctk_icon_info_get_filename(), and seeing if it is non-%NULL
5236 * and ends in “.svg”.
5237 *
5238 * This function is provided primarily to allow compatibility wrappers
5239 * for older API's, and is not expected to be useful for applications.
5240 *
5241 * Since: 2.4
5242 *
5243 * Deprecated: 3.14: Embedded rectangles and attachment points are deprecated
5244 */
5245void
5246ctk_icon_info_set_raw_coordinates (CtkIconInfo *icon_info G_GNUC_UNUSED__attribute__ ((__unused__)),
5247 gboolean raw_coordinates G_GNUC_UNUSED__attribute__ ((__unused__)))
5248{
5249}
5250
5251/**
5252 * ctk_icon_info_get_embedded_rect:
5253 * @icon_info: a #CtkIconInfo
5254 * @rectangle: (out): #CdkRectangle in which to store embedded
5255 * rectangle coordinates; coordinates are only stored
5256 * when this function returns %TRUE.
5257 *
5258 * This function is deprecated and always returns %FALSE.
5259 *
5260 * Returns: %FALSE
5261 *
5262 * Since: 2.4
5263 *
5264 * Deprecated: 3.14: Embedded rectangles are deprecated
5265 */
5266gboolean
5267ctk_icon_info_get_embedded_rect (CtkIconInfo *icon_info G_GNUC_UNUSED__attribute__ ((__unused__)),
5268 CdkRectangle *rectangle G_GNUC_UNUSED__attribute__ ((__unused__)))
5269{
5270 return FALSE(0);
5271}
5272
5273/**
5274 * ctk_icon_info_get_attach_points:
5275 * @icon_info: a #CtkIconInfo
5276 * @points: (allow-none) (array length=n_points) (out): location to store pointer
5277 * to an array of points, or %NULL free the array of points with g_free().
5278 * @n_points: (allow-none): location to store the number of points in @points,
5279 * or %NULL
5280 *
5281 * This function is deprecated and always returns %FALSE.
5282 *
5283 * Returns: %FALSE
5284 *
5285 * Since: 2.4
5286 *
5287 * Deprecated: 3.14: Attachment points are deprecated
5288 */
5289gboolean
5290ctk_icon_info_get_attach_points (CtkIconInfo *icon_info G_GNUC_UNUSED__attribute__ ((__unused__)),
5291 CdkPoint **points G_GNUC_UNUSED__attribute__ ((__unused__)),
5292 gint *n_points G_GNUC_UNUSED__attribute__ ((__unused__)))
5293{
5294 return FALSE(0);
5295}
5296
5297/**
5298 * ctk_icon_info_get_display_name:
5299 * @icon_info: a #CtkIconInfo
5300 *
5301 * This function is deprecated and always returns %NULL.
5302 *
5303 * Returns: %NULL
5304 *
5305 * Since: 2.4
5306 *
5307 * Deprecated: 3.14: Display names are deprecated
5308 */
5309const gchar *
5310ctk_icon_info_get_display_name (CtkIconInfo *icon_info G_GNUC_UNUSED__attribute__ ((__unused__)))
5311{
5312 return NULL((void*)0);
5313}
5314
5315/*
5316 * Builtin icons
5317 */
5318
5319
5320/**
5321 * ctk_icon_theme_add_builtin_icon:
5322 * @icon_name: the name of the icon to register
5323 * @size: the size in pixels at which to register the icon (different
5324 * images can be registered for the same icon name at different sizes.)
5325 * @pixbuf: #GdkPixbuf that contains the image to use for @icon_name
5326 *
5327 * Registers a built-in icon for icon theme lookups. The idea
5328 * of built-in icons is to allow an application or library
5329 * that uses themed icons to function requiring files to
5330 * be present in the file system. For instance, the default
5331 * images for all of CTK+’s stock icons are registered
5332 * as built-icons.
5333 *
5334 * In general, if you use ctk_icon_theme_add_builtin_icon()
5335 * you should also install the icon in the icon theme, so
5336 * that the icon is generally available.
5337 *
5338 * This function will generally be used with pixbufs loaded
5339 * via gdk_pixbuf_new_from_inline().
5340 *
5341 * Since: 2.4
5342 *
5343 * Deprecated: 3.14: Use ctk_icon_theme_add_resource_path()
5344 * to add application-specific icons to the icon theme.
5345 */
5346void
5347ctk_icon_theme_add_builtin_icon (const gchar *icon_name,
5348 gint size,
5349 GdkPixbuf *pixbuf)
5350{
5351 BuiltinIcon *default_icon;
5352 GSList *icons;
5353 gpointer key;
5354
5355 g_return_if_fail (icon_name != NULL)do { if ((icon_name != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "icon_name != NULL"); return
; } } while (0)
;
5356 g_return_if_fail (GDK_IS_PIXBUF (pixbuf))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((pixbuf)); GType __t = ((gdk_pixbuf_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "GDK_IS_PIXBUF (pixbuf)"); return; } } while (0)
;
5357
5358 if (!icon_theme_builtin_icons)
5359 icon_theme_builtin_icons = g_hash_table_new (g_str_hash, g_str_equal);
5360
5361 icons = g_hash_table_lookup (icon_theme_builtin_icons, icon_name);
5362 if (!icons)
5363 key = g_strdup (icon_name)g_strdup_inline (icon_name);
5364 else
5365 key = (gpointer)icon_name; /* Won't get stored */
5366
5367 default_icon = g_new (BuiltinIcon, 1)((BuiltinIcon *) g_malloc_n ((1), sizeof (BuiltinIcon)));
5368 default_icon->size = size;
5369 default_icon->pixbuf = g_object_ref (pixbuf)((__typeof__ (pixbuf)) (g_object_ref) (pixbuf));
5370 icons = g_slist_prepend (icons, default_icon);
5371
5372 /* Replaces value, leaves key untouched
5373 */
5374 g_hash_table_insert (icon_theme_builtin_icons, key, icons);
5375}
5376
5377/* Look up a builtin icon; the min_difference_p and
5378 * has_larger_p out parameters allow us to combine
5379 * this lookup with searching through the actual directories
5380 * of the “hicolor” icon theme. See theme_lookup_icon()
5381 * for how they are used.
5382 */
5383static BuiltinIcon *
5384find_builtin_icon (const gchar *icon_name,
5385 gint size,
5386 gint scale,
5387 gint *min_difference_p)
5388{
5389 GSList *icons = NULL((void*)0);
5390 gint min_difference = G_MAXINT2147483647;
5391 gboolean has_larger = FALSE(0);
5392 BuiltinIcon *min_icon = NULL((void*)0);
5393
5394 if (!icon_theme_builtin_icons)
5395 return NULL((void*)0);
5396
5397 size *= scale;
5398
5399 icons = g_hash_table_lookup (icon_theme_builtin_icons, icon_name);
5400
5401 while (icons)
5402 {
5403 BuiltinIcon *default_icon = icons->data;
5404 int min, max, difference;
5405 gboolean smaller;
5406
5407 min = default_icon->size - 2;
5408 max = default_icon->size + 2;
5409 smaller = size < min;
5410 if (size < min)
5411 difference = min - size;
5412 else if (size > max)
5413 difference = size - max;
5414 else
5415 difference = 0;
5416
5417 if (difference == 0)
5418 {
5419 min_difference = 0;
5420 min_icon = default_icon;
5421 break;
5422 }
5423
5424 if (!has_larger)
5425 {
5426 if (difference < min_difference || smaller)
5427 {
5428 min_difference = difference;
5429 min_icon = default_icon;
5430 has_larger = smaller;
5431 }
5432 }
5433 else
5434 {
5435 if (difference < min_difference && smaller)
5436 {
5437 min_difference = difference;
5438 min_icon = default_icon;
5439 }
5440 }
5441
5442 icons = icons->next;
5443 }
5444
5445 if (min_difference_p)
5446 *min_difference_p = min_difference;
5447
5448 return min_icon;
5449}
5450
5451/**
5452 * ctk_icon_theme_lookup_by_gicon:
5453 * @icon_theme: a #CtkIconTheme
5454 * @icon: the #GIcon to look up
5455 * @size: desired icon size
5456 * @flags: flags modifying the behavior of the icon lookup
5457 *
5458 * Looks up an icon and returns a #CtkIconInfo containing information
5459 * such as the filename of the icon. The icon can then be rendered
5460 * into a pixbuf using ctk_icon_info_load_icon().
5461 *
5462 * When rendering on displays with high pixel densities you should not
5463 * use a @size multiplied by the scaling factor returned by functions
5464 * like cdk_window_get_scale_factor(). Instead, you should use
5465 * ctk_icon_theme_lookup_by_gicon_for_scale(), as the assets loaded
5466 * for a given scaling factor may be different.
5467 *
5468 * Returns: (nullable) (transfer full): a #CtkIconInfo containing
5469 * information about the icon, or %NULL if the icon wasn’t
5470 * found. Unref with g_object_unref()
5471 *
5472 * Since: 2.14
5473 */
5474CtkIconInfo *
5475ctk_icon_theme_lookup_by_gicon (CtkIconTheme *icon_theme,
5476 GIcon *icon,
5477 gint size,
5478 CtkIconLookupFlags flags)
5479{
5480 return ctk_icon_theme_lookup_by_gicon_for_scale (icon_theme, icon,
5481 size, 1, flags);
5482}
5483
5484
5485/**
5486 * ctk_icon_theme_lookup_by_gicon_for_scale:
5487 * @icon_theme: a #CtkIconTheme
5488 * @icon: the #GIcon to look up
5489 * @size: desired icon size
5490 * @scale: the desired scale
5491 * @flags: flags modifying the behavior of the icon lookup
5492 *
5493 * Looks up an icon and returns a #CtkIconInfo containing information
5494 * such as the filename of the icon. The icon can then be rendered into
5495 * a pixbuf using ctk_icon_info_load_icon().
5496 *
5497 * Returns: (nullable) (transfer full): a #CtkIconInfo containing
5498 * information about the icon, or %NULL if the icon wasn’t
5499 * found. Unref with g_object_unref()
5500 *
5501 * Since: 3.10
5502 */
5503CtkIconInfo *
5504ctk_icon_theme_lookup_by_gicon_for_scale (CtkIconTheme *icon_theme,
5505 GIcon *icon,
5506 gint size,
5507 gint scale,
5508 CtkIconLookupFlags flags)
5509{
5510 CtkIconInfo *info;
5511
5512 g_return_val_if_fail (CTK_IS_ICON_THEME (icon_theme), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((icon_theme)); GType __t = ((ctk_icon_theme_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ICON_THEME (icon_theme)"); return (((
void*)0)); } } while (0)
;
5513 g_return_val_if_fail (G_IS_ICON (icon), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((icon)); GType __t = ((g_icon_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "G_IS_ICON (icon)"); return (((void*)0)); } } while (0)
;
5514 g_warn_if_fail ((flags & CTK_ICON_LOOKUP_GENERIC_FALLBACK) == 0)do { if ((flags & CTK_ICON_LOOKUP_GENERIC_FALLBACK) == 0)
; else g_warn_message ("Ctk", "ctkicontheme.c", 5514, ((const
char*) (__func__)), "(flags & CTK_ICON_LOOKUP_GENERIC_FALLBACK) == 0"
); } while (0)
;
5515
5516 if (GDK_IS_PIXBUF (icon)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(icon)); GType __t = ((gdk_pixbuf_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
5517 {
5518 GdkPixbuf *pixbuf;
5519
5520 pixbuf = GDK_PIXBUF (icon)((((GdkPixbuf*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((icon)), ((gdk_pixbuf_get_type ()))))))
;
5521
5522 if ((flags & CTK_ICON_LOOKUP_FORCE_SIZE) != 0)
5523 {
5524 gint width, height, max;
5525 gdouble pixbuf_scale;
5526 GdkPixbuf *scaled;
5527
5528 width = gdk_pixbuf_get_width (pixbuf);
5529 height = gdk_pixbuf_get_height (pixbuf);
5530 max = MAX (width, height)(((width) > (height)) ? (width) : (height));
5531 pixbuf_scale = (gdouble) size * scale / (gdouble) max;
5532
5533 scaled = gdk_pixbuf_scale_simple (pixbuf,
5534 0.5 + width * pixbuf_scale,
5535 0.5 + height * pixbuf_scale,
5536 GDK_INTERP_BILINEAR);
5537
5538 info = ctk_icon_info_new_for_pixbuf (icon_theme, scaled);
5539
5540 g_object_unref (scaled);
5541 }
5542 else
5543 {
5544 info = ctk_icon_info_new_for_pixbuf (icon_theme, pixbuf);
5545 }
5546
5547 return info;
5548 }
5549 else if (G_IS_FILE_ICON (icon)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(icon)); GType __t = ((g_file_icon_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
5550 {
5551 GFile *file = g_file_icon_get_file (G_FILE_ICON (icon)((((GFileIcon*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((icon)), ((g_file_icon_get_type ()))))))
);
5552
5553 info = ctk_icon_info_new_for_file (file, size, scale);
5554 info->forced_size = (flags & CTK_ICON_LOOKUP_FORCE_SIZE) != 0;
5555
5556 return info;
5557 }
5558 else if (G_IS_LOADABLE_ICON (icon)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(icon)); GType __t = ((g_loadable_icon_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
5559 {
5560 info = icon_info_new (ICON_THEME_DIR_UNTHEMED, size, 1);
5561 info->loadable = G_LOADABLE_ICON (g_object_ref (icon))((((GLoadableIcon*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((((__typeof__ (icon)) (g_object_ref) (icon)))), ((g_loadable_icon_get_type
()))))))
;
5562 info->is_svg = FALSE(0);
5563 info->desired_size = size;
5564 info->desired_scale = scale;
5565 info->forced_size = (flags & CTK_ICON_LOOKUP_FORCE_SIZE) != 0;
5566
5567 return info;
5568 }
5569 else if (G_IS_THEMED_ICON (icon)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(icon)); GType __t = ((g_themed_icon_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
5570 {
5571 const gchar **names;
5572
5573 names = (const gchar **)g_themed_icon_get_names (G_THEMED_ICON (icon)((((GThemedIcon*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((icon)), ((g_themed_icon_get_type ()))))))
);
5574 info = ctk_icon_theme_choose_icon_for_scale (icon_theme, names, size, scale, flags);
5575
5576 return info;
5577 }
5578 else if (G_IS_EMBLEMED_ICON (icon)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(icon)); GType __t = ((g_emblemed_icon_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
5579 {
5580 GIcon *base, *emblem;
5581 GList *list, *l;
5582 CtkIconInfo *base_info, *emblem_info;
5583
5584G_GNUC_BEGIN_IGNORE_DEPRECATIONSclang diagnostic push clang diagnostic ignored "-Wdeprecated-declarations"
5585 if (CTK_IS_NUMERABLE_ICON (icon)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(icon)); GType __t = ((ctk_numerable_icon_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
5586 _ctk_numerable_icon_set_background_icon_size (CTK_NUMERABLE_ICON (icon)((((CtkNumerableIcon*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((icon)), ((ctk_numerable_icon_get_type ())))
)))
, size / 2);
5587G_GNUC_END_IGNORE_DEPRECATIONSclang diagnostic pop
5588
5589 base = g_emblemed_icon_get_icon (G_EMBLEMED_ICON (icon)((((GEmblemedIcon*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((icon)), ((g_emblemed_icon_get_type ()))))))
);
5590 base_info = ctk_icon_theme_lookup_by_gicon_for_scale (icon_theme, base, size, scale, flags);
5591 if (base_info)
5592 {
5593 info = icon_info_dup (base_info);
5594 g_object_unref (base_info);
5595
5596 list = g_emblemed_icon_get_emblems (G_EMBLEMED_ICON (icon)((((GEmblemedIcon*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((icon)), ((g_emblemed_icon_get_type ()))))))
);
5597 for (l = list; l; l = l->next)
5598 {
5599 emblem = g_emblem_get_icon (G_EMBLEM (l->data)((((GEmblem*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((g_emblem_get_type ()))))))
);
5600 /* always force size for emblems */
5601 emblem_info = ctk_icon_theme_lookup_by_gicon_for_scale (icon_theme, emblem, size / 2, scale, flags | CTK_ICON_LOOKUP_FORCE_SIZE);
5602 if (emblem_info)
5603 info->emblem_infos = g_slist_prepend (info->emblem_infos, emblem_info);
5604 }
5605
5606 return info;
5607 }
5608 else
5609 return NULL((void*)0);
5610 }
5611
5612 return NULL((void*)0);
5613}
5614
5615/**
5616 * ctk_icon_info_new_for_pixbuf:
5617 * @icon_theme: a #CtkIconTheme
5618 * @pixbuf: the pixbuf to wrap in a #CtkIconInfo
5619 *
5620 * Creates a #CtkIconInfo for a #GdkPixbuf.
5621 *
5622 * Returns: (transfer full): a #CtkIconInfo
5623 *
5624 * Since: 2.14
5625 */
5626CtkIconInfo *
5627ctk_icon_info_new_for_pixbuf (CtkIconTheme *icon_theme,
5628 GdkPixbuf *pixbuf)
5629{
5630 CtkIconInfo *info;
5631
5632 g_return_val_if_fail (CTK_IS_ICON_THEME (icon_theme), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((icon_theme)); GType __t = ((ctk_icon_theme_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ICON_THEME (icon_theme)"); return (((
void*)0)); } } while (0)
;
5633 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((pixbuf)); GType __t = ((gdk_pixbuf_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "GDK_IS_PIXBUF (pixbuf)"); return (((void*)0)); } } while
(0)
;
5634
5635 info = icon_info_new (ICON_THEME_DIR_UNTHEMED, 0, 1);
5636 info->pixbuf = g_object_ref (pixbuf)((__typeof__ (pixbuf)) (g_object_ref) (pixbuf));
5637 info->scale = 1.0;
5638
5639 return info;
5640}
5641
5642CtkIconInfo *
5643ctk_icon_info_new_for_file (GFile *file,
5644 gint size,
5645 gint scale)
5646{
5647 CtkIconInfo *info;
5648
5649 info = icon_info_new (ICON_THEME_DIR_UNTHEMED, size, 1);
5650 info->loadable = G_LOADABLE_ICON (g_file_icon_new (file))((((GLoadableIcon*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((g_file_icon_new (file))), ((g_loadable_icon_get_type ())
)))))
;
5651 info->icon_file = g_object_ref (file)((__typeof__ (file)) (g_object_ref) (file));
5652 info->is_resource = g_file_has_uri_scheme (file, "resource");
5653
5654 if (info->is_resource)
5655 {
5656 gchar *uri;
5657
5658 uri = g_file_get_uri (file);
5659 info->filename = g_strdup (uri + 11)g_strdup_inline (uri + 11); /* resource:// */
5660 g_free (uri);
5661 }
5662 else
5663 {
5664 info->filename = g_file_get_path (file);
5665 }
5666
5667 info->is_svg = suffix_from_name (info->filename) == ICON_SUFFIX_SVG;
5668
5669 info->desired_size = size;
5670 info->desired_scale = scale;
5671 info->forced_size = FALSE(0);
5672
5673 return info;
5674}