1 #ifdef COPYRIGHT_INFORMATION
2 #include "gplv3.h"
3 #endif
4 
5 
6 static
7 GdkPixbuf *
8 get_pixbuf (const gchar * key, gint size, gboolean replace_pixbuf);
9 
10 static pthread_mutex_t lite_hash_mutex = PTHREAD_MUTEX_INITIALIZER;
11 
12 // internal hash record structure
13 static GHashTable *lite_hash = NULL;
14 static GHashTable *lite_type_hash = NULL;
15 static GHashTable *lite_key_hash = NULL;
16 
17 typedef struct composite_t{
18     const gchar *sub_id;
19     const gchar *where;
20     double scale_factor;
21     gint overall_alpha;
22 }composite_t;
23 
24 
25 
26 static void
free_pixbuf(void * data)27 free_pixbuf(void *data){
28     GdkPixbuf *pixbuf = data;
29     if (pixbuf && !G_IS_OBJECT (pixbuf)) {
30 	DBG("This should not happen: pixbuf is not a pixbuf\n");
31     } else {
32 	g_object_unref (pixbuf);
33     }
34 }
35 
36 
37 typedef struct lite_t {
38     gchar *id;
39     gchar *type;
40     gchar *icon;
41     guchar red;
42     guchar green;
43     guchar blue;
44 } lite_t;
45 
46 // We could read these from an xml file...
47 // To add a new ad hoc icon, first define the lite key to use to associate
48 // the mimetype to the litetype. Then define the lite type (lite_t) with
49 // the values you wish. The type (translated item) should be the same as
50 // whatever is after the / or - in the lite type. This will be the tag
51 // that shows up (translated).
52 lite_t lite_v[]={
53     {"lite/regular", NULL, NULL, 0xff, 0xff, 0xff},
54     {"lite/image", N_("image"), "xffm/emblem_image", 0xff, 0xcc, 0xff},
55     {"lite/Audio", N_("Audio"), "xffm/emblem_music", 0, 0xff, 0xff},
56     {"lite/Video", N_("Video"), "xffm/emblem_video", 0xff, 0xff, 0},
57     {"lite/office", N_("office"), "xffm/emblem_oo", 0xff, 0xff, 0xff},
58     {"lite/chemical", N_("chemical"), "xffm/emblem_science", 0xff, 0xff, 0xff},
59     {"lite/lyx", N_("lyx"), "xffm/emblem_math", 0xaa, 0xaa, 0xff},
60     {"lite/tex", N_("tex"), "xffm/emblem_math", 0xff, 0xff, 0xff},
61     {"lite/text", N_("text"), "xffm/emblem_text", 0xff, 0xff, 0xff},
62     {"lite/text-log", N_("log"), "xffm/emblem_bookmark", 0xff, 0xff, 0xff},
63     {"lite/text-readme", N_("readme"), "xffm/emblem_star", 0xff, 0xff, 0xff},
64     {"lite/text-credits", N_("credits"), "xffm/emblem_star", 0xff, 0xff, 0xff},
65     {"lite/text-authors", N_("authors"), "xffm/emblem_user", 0xff, 0xff, 0xff},
66     {"lite/text-install", N_("install"), "xffm/emblem_important", 0xff, 0xff, 0xff},
67     {"lite/text-info", N_("info"), "xffm/emblem_important", 0xff, 0xff, 0xff},
68     {"lite/text-html", N_("html"), "xffm/emblem_www", 0xff, 0xff, 0xff},
69     {"lite/text-chdr", N_("chdr"), "xffm/emblem_text", 0xee, 0xd6, 0x80},
70     {"lite/text-c++hdr", N_("c++hdr"), "xffm/emblem_text", 0xee, 0xd6, 0x80},
71     {"lite/text-csrc", N_("csrc"), "xffm/emblem_text", 0x88, 0x7f, 0xa3},
72     {"lite/text-c++", N_("c++"), "xffm/emblem_text", 0x88, 0x7f, 0xa3},
73     {"lite/application", N_("App"), "xffm/emblem_application", 0xdd, 0xdd, 0xff},
74     {"lite/graphics", N_("graphics"), "xffm/emblem_graphics", 0xff, 0xff, 0xff},
75     {"lite/pgp", N_("pgp"), "xffm/emblem_lock", 0x88, 0x88, 0x88},
76     {"lite/trash", N_("trash"), "xffm/emblem_bak", 0x22, 0x22, 0x22},
77     {"lite/pdf", N_("pdf"), "xffm/emblem_pdf", 0xaa, 0xdd, 0xcc},
78     {"lite/ps", N_("ps"), "xffm/emblem_print", 0xaa, 0xdd, 0xcc},
79     {"lite/msoffice", N_("msoffice"), "xffm/emblem_msoffice", 0x44, 0x44, 0x44},
80     {"lite/package", N_("package"), "xffm/emblem_package", 0xaa, 0, 0},
81     {"lite/executable", N_("executable"), "xffm/emblem_exec", 0xaa, 0xff, 0xaa},
82     {"lite/script", N_("script"), "xffm/emblem_script", 0xaa, 0xff, 0xaa},
83     {"lite/core", N_("core"), "xffm/emblem_core", 0xaa, 0xaa, 0xaa},
84     {NULL,NULL,NULL, 0,0,0}
85 };
86 
87 gchar *lite_keys[] = {
88     //"image/jpeg", "lite/image",
89 
90     "text/x-tex", "lite/tex",
91     "text/x-log", "lite/text-log",
92     "text/x-readme", "lite/text-readme",
93     "text/x-chdr", "lite/text-chdr",
94     "text/x-c++hdr", "lite/text-c++hdr",
95     "text/x-c", "lite/text-csrc",
96     "text/x-c++", "lite/text-c++",
97     "text/x-c++src", "lite/text-c++",
98     "text/x-csrc", "lite/text-csrc",
99     "text/x-credits", "lite/text-credits",
100     "text/x-authors", "lite/text-authors",
101     "text/x-install", "lite/text-install",
102     "text/x-info", "lite/text-info",
103     "text/html", "lite/text-html",
104     "application/x-lyx", "lite/lyx",
105     "application/x-trash", "lite/trash",
106     "application/pdf", "lite/pdf",
107     "application/x-bzpdf", "lite/pdf",
108     "application/x-gzpdf", "lite/pdf",
109 
110     "application/x-dia-diagram", "lite/graphics",
111     "application/pgp", "lite/pgp",
112     "application/pgp-encrypted", "lite/pgp",
113 
114     "application/x-core", "lite/core",
115     "application/x-coredump", "lite/core",
116 
117     "application/postscript", "lite/ps",
118     "application/x-bzpostscript", "lite/ps",
119     "application/x-gzpostscript", "lite/ps",
120 
121     "application/msword", "lite/msoffice",
122     "application/ms-powerpoint", "lite/msoffice",
123     "application/ms-excel", "lite/msoffice",
124     "application/ms-project", "lite/msoffice",
125     "application/msword-template", "lite/msoffice",
126     "application/vnd.ms-powerpoint", "lite/msoffice",
127     "application/vnd.ms-excel", "lite/msoffice",
128     "application/vnd.ms-project", "lite/msoffice",
129     "application/msword-template", "lite/msoffice",
130     "application/vnd.msword", "lite/msoffice",
131 
132     "application/x-tar", "lite/package",
133     "application/x-compress", "lite/package",
134     "application/x-compressed-tar", "lite/package",
135     "application/x-arj", "lite/package",
136     "application/x-lha", "lite/package",
137     "application/x-lzma", "lite/package",
138     "application/zip", "lite/package",
139     "application/x-gzip", "lite/package",
140     "application/x-lzip", "lite/package",
141     "application/x-cbz", "lite/package",
142     "application/x-cbr", "lite/package",
143     "application/x-xz", "lite/package",
144     "application/x-xz-compressed-tar", "lite/package",
145     "application/x-bzip", "lite/package",
146     "application/x-bzip2", "lite/package",
147     "application/x-bzip-compressed-tar", "lite/package",
148     "application/x-deb", "lite/package",
149     "application/x-rpm", "lite/package",
150     "application/x-java-archive", "lite/package",
151     "application/x-rar", "lite/package",
152     "application/x-ace", "lite/package",
153     "application/x-zoo", "lite/package",
154     "application/x-cpio", "lite/package",
155     "application/x-cpio-compressed", "lite/package",
156     "application/x-7z-compressed", "lite/package",
157 
158     "application/x-shellscript", "lite/script",
159     "application/x-csh", "lite/script",
160     "text/x-csh", "lite/script",
161     "text/x-sh", "lite/script",
162     "text/x-shellscript", "lite/script",
163     "text/x-python", "lite/script",
164     "application/javascript", "lite/script",
165     "application/sieve", "lite/script",
166     "application/x-awk", "lite/script",
167     "application/x-m4", "lite/script",
168     "application/x-markaby", "lite/script",
169     "application/x-perl", "lite/script",
170     "application/x-php", "lite/script",
171     "application/x-ruby", "lite/script",
172     "application/x-setupscript", "lite/script",
173     "text/javascript", "lite/script",
174     "text/scriptlet", "lite/script",
175     "text/x-dcl", "lite/script",
176     "text/x-lua", "lite/script",
177     "text/x-matlab", "lite/script",
178     "text/x-tcl", "lite/script",
179     NULL, NULL
180 };
181 
182 
183 static void
init_lite_hash()184 init_lite_hash () {
185     // g_once init
186     static gsize initialized = 0;
187     if (g_once_init_enter (&initialized)){
188         lite_hash = g_hash_table_new_full (g_str_hash, g_str_equal,g_free, free_pixbuf);
189         lite_type_hash = g_hash_table_new (g_str_hash, g_str_equal);
190         lite_key_hash = g_hash_table_new (g_str_hash, g_str_equal);
191 	lite_t *lite_type_p = lite_v;
192 	for (;lite_type_p && lite_type_p->id; lite_type_p++){
193 	    g_hash_table_insert(lite_type_hash, lite_type_p->id, lite_type_p);
194 	}
195 	gchar **cp = lite_keys;
196 	for (;cp && *cp; cp+=2){
197 	    g_hash_table_insert(lite_key_hash, cp[0], cp[1]);
198 	}
199 	g_once_init_leave (&initialized, 1);
200     }
201     return;
202 }
203 
204 
205 
206 
207 static void *
pixbuf_from_gtkid_f(void * data)208 pixbuf_from_gtkid_f(void *data){
209     void **arg = data;
210     gchar *id = arg[0];
211     gint size = GPOINTER_TO_INT(arg[1]);
212     GdkPixbuf *pixbuf = NULL;
213 
214     gchar *file = g_strdup_printf("%s/icons/rfm/scalable/stock/%s.svg",
215                 PACKAGE_DATA_DIR, id);
216     NOOP(stderr, "trying: \"%s\"\n", file);
217     if (!g_file_test(file, G_FILE_TEST_EXISTS)) {
218         fprintf(stderr, "Failed to get pixbuf from %s-->%s\n", id, file);
219         g_free(file);
220         file = g_strdup_printf("%s/icons/rfm/scalable/emblems/emblem-%s.svg",
221         PACKAGE_DATA_DIR, id);
222         NOOP(stderr, "now trying: \"%s\"\n", file);
223         if (!g_file_test(file, G_FILE_TEST_EXISTS)){
224             g_free(file);
225             file = NULL;
226         }
227     }
228     if (file){
229        pixbuf = rfm_pixbuf_new_from_file(file, size, size);
230     }
231 
232 
233     g_free(file);
234     return pixbuf;
235 }
236 
237 GdkPixbuf *
pixbuf_from_gtkid(const gchar * id,gint size)238 pixbuf_from_gtkid(const gchar * id, gint size){
239     if (!id) return NULL;
240     GdkPixbuf *pixbuf = NULL;
241     void *arg[] = {(void *)id, GINT_TO_POINTER(size)};
242     arg[0] = g_strdup(id);
243     arg[1] = GINT_TO_POINTER(size);
244 
245     pixbuf = pixbuf_from_gtkid_f(arg);
246 
247     if (pixbuf) g_object_ref(pixbuf);
248     return pixbuf;
249 }
250 
251 static const gchar *
get_mask_color(const gchar * id,guchar * red,guchar * green,guchar * blue,gchar ** tpath)252 get_mask_color(const gchar *id, guchar *red, guchar *green, guchar *blue, gchar **tpath){
253     // 30 black:
254     // 31 red: bright red, tar files
255     // 32 green: document files; bright: executables;
256     // 33 yellow:
257     // 34 blue: directories;
258     // 35 magenta: bright: images;
259     // 36 cyan: audio; bright: symlinks;
260     // 37 white
261 
262     lite_t *lite_type_p = NULL;
263 
264     const gchar *key = "lite/regular";
265 
266     if (strncmp(id,"image/", strlen("image/"))==0)
267 	key = "lite/image";
268     else if (strncmp(id,"audio/", strlen("audio/"))==0)
269 	key = "lite/Audio";
270     else if (strncmp(id,"video/", strlen("video/"))==0)
271 	key = "lite/Video";
272     else if (strstr(id,"opendocument") || strstr(id,"officedocument") || strstr(id,"application/rtf")
273 	    ||strstr(id,"vnd.sun.xml"))
274 	key = "lite/office";
275     else if (strstr(id,"abobe"))
276 	key = "lite/graphics";
277     else if (strncmp(id,"text/", strlen("text/"))==0){
278 	key = g_hash_table_lookup(lite_key_hash, id);
279 	if (!key) key = "lite/text";
280 
281     } else if (strncmp(id,"application/", strlen("application/"))==0){
282 	key = g_hash_table_lookup(lite_key_hash, id);
283 	if (!key) key = "lite/application";
284     }
285     NOOP (stderr, "+++ getting lite id for %s: %s\n", id, key);
286 
287     lite_type_p = g_hash_table_lookup(lite_type_hash, key);
288 
289     if (!lite_type_p) {
290 	lite_type_p = g_hash_table_lookup(lite_type_hash, "lite/regular");
291     }
292 
293 
294     if (tpath && lite_type_p->icon) {
295 	if (!strstr(lite_type_p->icon, "xffm/emblem_")){
296 	    DBG("get_mask_color(): incorrect lite icon specification: %s\n", lite_type_p->icon);
297 	} else {
298 	gboolean gtk_theme = (getenv("RFM_USE_GTK_ICON_THEME") &&
299 			    strlen(getenv("RFM_USE_GTK_ICON_THEME")));
300 	    if (gtk_theme) {
301 		*tpath = ICON_get_filename_from_id(lite_type_p->icon);
302 	    } else {
303 		gchar *icon = g_strdup(lite_type_p->icon + strlen("xffm/emblem_"));
304 		*tpath = g_strdup_printf("%s/icons/rfm/scalable/emblems/emblem-%s.svg",
305 			PACKAGE_DATA_DIR, icon);
306 		NOOP(stderr, "%s->%s\n", icon, file);
307 		g_free(icon);
308 	    }
309 	}
310     }
311     if (red) *red = lite_type_p->red;
312     if (green) *green = lite_type_p->green;
313     if (blue) *blue = lite_type_p->blue;
314 
315     return lite_type_p->id;
316 }
317 
318 static void
add_label_pixbuf(cairo_t * pixbuf_context,GdkPixbuf * pixbuf,const gchar * lite_id,gint size)319 add_label_pixbuf(cairo_t   *pixbuf_context,
320 	GdkPixbuf *pixbuf,
321 	const gchar *lite_id,
322 	gint size){
323     rfm_global_t *rfm_global_p = rfm_global();
324     if (!rfm_global_p) return;
325     // Skip regular icons
326     if (strcmp(lite_id, "lite/regular")==0) return;
327     // Insert text into pixbuf
328     gint x = 0;
329     gint y = 0;
330     const gchar *text_size = NULL;
331     switch(size) {
332 	case SMALL_ICON_SIZE: text_size="xx-small"; break;
333 	case MEDIUM_ICON_SIZE: text_size="x-small"; break;
334 	case BIG_ICON_SIZE: text_size="medium"; break;
335     }
336     if (!text_size) return ;
337     GdkPixbuf   *t_pixbuf = NULL;
338     const gchar *icon_text;
339     if (strchr(lite_id,'.')) icon_text = strrchr(lite_id,'.')+1;
340     else if (strchr(lite_id,'-')) icon_text = strrchr(lite_id,'-')+1;
341     else  icon_text = strrchr(lite_id,'/')+1;
342     const gchar *color = "white";
343     gchar *layout_text = g_strdup_printf("<span foreground=\"black\" background=\"%s\" size=\"%s\">%s </span>", color, text_size, _(icon_text));
344     PangoLayout *layout =
345 	gtk_widget_create_pango_layout (rfm_global_p->window, NULL);
346     pango_layout_set_markup(layout, layout_text, -1);
347     g_free(layout_text);
348     PangoRectangle logical_rect;
349     pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
350     x = gdk_pixbuf_get_width(pixbuf) - logical_rect.width-2;
351     y = gdk_pixbuf_get_height(pixbuf) - logical_rect.height-2;
352     if (x < 0) x = 0;
353     if (y < 0) y = 0;
354     if (logical_rect.width > gdk_pixbuf_get_width(pixbuf)-1)
355 	logical_rect.width = gdk_pixbuf_get_width(pixbuf)-1;
356     if (logical_rect.height > gdk_pixbuf_get_height(pixbuf)-1)
357 	logical_rect.height = gdk_pixbuf_get_height(pixbuf)-1;
358 
359     //cairo_set_source_rgba(pixbuf_context, 1.0, 0.0, 0.0, 0.75);
360     //
361     t_pixbuf =
362 	gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, logical_rect.width+2, logical_rect.height+2);
363     cairo_t   *t_pixbuf_context = pixbuf_cairo_create(t_pixbuf);
364 
365     //cairo_set_source_rgba(t_pixbuf_context, 1.0, 1.0, 1.0, 1.0);
366 
367     cairo_rectangle(t_pixbuf_context, 0, 0, logical_rect.width+2, logical_rect.height+2);
368     //cairo_fill(t_pixbuf_context);
369     cairo_clip(t_pixbuf_context);
370 
371 
372     cairo_move_to (t_pixbuf_context, 1, 1);
373 
374     cairo_set_source_rgba(t_pixbuf_context, 0, 0, 0, 1.0);
375     //cairo_set_source_rgba(t_pixbuf_context, 0, 0, 0, 0.5);
376     if (PANGO_IS_LAYOUT (layout)) {
377         pango_cairo_show_layout (t_pixbuf_context, layout);
378         g_object_unref(layout);
379     }
380     pixbuf_cairo_destroy(t_pixbuf_context, t_pixbuf);
381 
382     if (t_pixbuf) {
383 	gdk_cairo_set_source_pixbuf(pixbuf_context, t_pixbuf,x,y);
384 	cairo_paint_with_alpha(pixbuf_context, 0.650);
385 	g_object_unref(t_pixbuf);
386     }
387 
388     return ;
389 }
390 
391 static void
add_color_pixbuf(cairo_t * pixbuf_context,GdkPixbuf * pixbuf,guchar red,guchar green,guchar blue)392 add_color_pixbuf(cairo_t   *pixbuf_context, GdkPixbuf *pixbuf,
393 	guchar red, guchar green, guchar blue){
394     GdkPixbuf *pixbuf_mask = create_pixbuf_mask(pixbuf, red, green, blue);
395     gdk_cairo_set_source_pixbuf(pixbuf_context, pixbuf_mask, 0,0);
396     cairo_paint_with_alpha(pixbuf_context, 0.450);
397     g_object_unref(pixbuf_mask);
398 }
399 
400 static void
add_emblem_pixbuf(cairo_t * pixbuf_context,GdkPixbuf * pixbuf,gchar * tpath,gint size)401 add_emblem_pixbuf(cairo_t   *pixbuf_context, GdkPixbuf *pixbuf, gchar *tpath, gint size){
402 
403     if (tpath && g_file_test(tpath, G_FILE_TEST_EXISTS)){
404 	gdouble b = (double) size / 1.618;
405 	gint ia = size - floor(b);
406 	//gint ia = size/4;
407 	GdkPixbuf *tag = rfm_pixbuf_new_from_file(tpath, size/2, size/2);
408 	gdk_cairo_set_source_pixbuf(pixbuf_context, tag,ia,size/4);
409 	cairo_paint_with_alpha(pixbuf_context, 1.0);
410 	//cairo_paint_with_alpha(pixbuf_context, 0.650);
411 
412 	g_object_unref(tag);
413     }
414 }
415 
416 static GdkPixbuf *
ad_hoc_pixbuf(GdkPixbuf * pixbuf,const gchar * id,gint size)417 ad_hoc_pixbuf(GdkPixbuf *pixbuf, const gchar *id, gint size){
418     GdkPixbuf *old_p = pixbuf;
419     pixbuf = rfm_pixbuf_duplicate(old_p);
420     g_object_unref(old_p);
421     g_object_ref(pixbuf);
422     rfm_global_t *rfm_global_p = rfm_global();
423     if (!rfm_global_p) return pixbuf;
424 
425 
426 #if 10
427 
428 
429     guchar red, green, blue;
430     gchar *tpath = NULL;
431     const gchar *lite_id = get_mask_color(id, &red, &green, &blue, &tpath);
432 
433 
434 
435 #endif
436     cairo_t   *pixbuf_context = pixbuf_cairo_create(pixbuf);
437 
438     // This proved necessary in opensuse-12.3,
439     // but not in gentoo nor ubuntu. Go figure...
440 	gdk_cairo_set_source_pixbuf(pixbuf_context, pixbuf,0,0);
441 	cairo_paint_with_alpha(pixbuf_context, 1.0);
442 
443     // Color:
444     add_color_pixbuf(pixbuf_context, pixbuf, red, green, blue);
445 
446     // Emblem:
447     add_emblem_pixbuf(pixbuf_context, pixbuf,tpath, size);
448     g_free(tpath);
449 
450     // Text:
451     add_label_pixbuf(pixbuf_context, pixbuf, lite_id, size);
452 
453 
454     // Using the same hash is not correct.
455     // rfm_put_in_pixbuf_hash(lite_id, size, pixbuf);
456     pixbuf_cairo_destroy(pixbuf_context, pixbuf);
457 
458     gchar *hash_key = rfm_get_hash_key (lite_id, size);
459     pthread_mutex_lock(&lite_hash_mutex);
460     g_hash_table_replace(lite_hash, hash_key, pixbuf);
461     pthread_mutex_unlock(&lite_hash_mutex);
462 
463     return pixbuf;
464 }
465 
466 static GdkPixbuf *
try_app_icon(const gchar * id,gint size)467 try_app_icon(const gchar *id, gint size){
468     GdkPixbuf *pixbuf = NULL;
469     // try svg application icons?
470     if (!pixbuf){
471 	gchar *fullpath = g_strdup_printf("%s/pixmaps/%s.svg", PACKAGE_DATA_DIR, id);
472 	pixbuf = rfm_pixbuf_new_from_file(fullpath, size, size);
473         if (!pixbuf) {
474             DBG("svg application icon not found %s -> %s\n", id, fullpath);
475             g_free(fullpath);
476 	    fullpath = g_strdup_printf("%s/icons/hicolor/scalable/apps/%s.svg",
477                     PACKAGE_DATA_DIR, id);
478 	    pixbuf = rfm_pixbuf_new_from_file(fullpath, size, size);
479         }
480         if (!pixbuf) DBG("svg application icon not found %s -> %s\n", id, fullpath);
481         g_free(fullpath);
482     }
483     // try png application icons?
484     if (!pixbuf){
485 	gchar *fullpath = g_strdup_printf("%s/pixmaps/%s.png", PACKAGE_DATA_DIR, id);
486 	pixbuf = rfm_pixbuf_new_from_file(fullpath, size, size);
487         if (!pixbuf) {
488             DBG("png application icon not found %s -> %s\n", id, fullpath);
489             g_free(fullpath);
490 	    fullpath = g_strdup_printf("%s/icons/hicolor/48x48/apps/%s.png",
491                     PACKAGE_DATA_DIR, id);
492 	    pixbuf = rfm_pixbuf_new_from_file(fullpath, size, size);
493         }
494         if (!pixbuf) DBG("svg application icon not found %s -> %s\n", id, fullpath);
495 	g_free(fullpath);
496     }
497     // try xpm application icons?
498     if (!pixbuf){
499 	gchar *fullpath = g_strdup_printf("%s/pixmaps/%s.xpm", PACKAGE_DATA_DIR, id);
500 	pixbuf = rfm_pixbuf_new_from_file(fullpath, size, size);
501         if (!pixbuf) DBG("png application icon not found %s -> %s\n", id, fullpath);
502 	g_free(fullpath);
503     }
504     return pixbuf;
505 }
506 
507 static GdkPixbuf *
last_resort_pixbuf(gint size,const gchar * id)508 last_resort_pixbuf(gint size, const gchar *id){
509     NOOP("last_resort_pixbuf: %s\n", id);
510     init_lite_hash();
511     GdkPixbuf *pixbuf = NULL;
512     gchar *tpath = NULL;
513     guchar red, green, blue;
514     const gchar *lite_id = get_mask_color(id, &red, &green, &blue, &tpath);
515     g_free(tpath); // No used... really now?
516     tpath = NULL;
517     if (!lite_id) {
518 	DBG("Could not retrieve lite_id\n");
519 	return NULL;
520     }
521 
522     gchar *hash_key = rfm_get_hash_key (lite_id, size);
523     pthread_mutex_lock(&lite_hash_mutex);
524     pixbuf = g_hash_table_lookup(lite_hash, hash_key);
525     pthread_mutex_unlock(&lite_hash_mutex);
526     g_free(hash_key);
527 
528     if (pixbuf){
529 	g_object_ref(pixbuf);
530 	return pixbuf;
531     }
532 
533     hash_key = rfm_get_hash_key ("lite/regular", size);
534     pthread_mutex_lock(&lite_hash_mutex);
535     pixbuf = g_hash_table_lookup(lite_hash, hash_key);
536     pthread_mutex_unlock(&lite_hash_mutex);
537     g_free(hash_key);
538 
539     if (pixbuf) g_object_ref(pixbuf);
540 
541     if ( !pixbuf) pixbuf = try_app_icon(id, size);
542 
543 
544     if (!pixbuf) {
545 	gchar *fullpath = g_strdup_printf("%s/icons/rfm/scalable/emblems/emblem-file.svg", PACKAGE_DATA_DIR);
546 	pixbuf = rfm_pixbuf_new_from_file(fullpath, size, size);
547 	g_free(fullpath);
548 	if (pixbuf) {
549 	    g_object_ref(pixbuf); // refs.
550 	    hash_key = rfm_get_hash_key ("lite/regular", size);
551 	    pthread_mutex_lock(&lite_hash_mutex);
552 	    g_hash_table_replace(lite_hash, hash_key, pixbuf);
553 	    pthread_mutex_unlock(&lite_hash_mutex);
554 	}
555     }
556 
557     gboolean gtk_icontheme = (getenv("RFM_USE_GTK_ICON_THEME") && strlen(getenv("RFM_USE_GTK_ICON_THEME")));
558 
559     if (gtk_icontheme && !pixbuf) {
560 	pixbuf = pixbuf_from_gtkid("file", size); // refs.
561 	if (pixbuf) {
562 	    hash_key = rfm_get_hash_key ("lite/regular", size);
563 	    pthread_mutex_lock(&lite_hash_mutex);
564 	    g_hash_table_replace(lite_hash, hash_key, pixbuf);
565 	    pthread_mutex_unlock(&lite_hash_mutex);
566 	}
567     }
568 
569     if (!pixbuf){
570 	DBG("unable to get lite/regular pixbuf\n");
571 	return NULL;
572     }
573 
574     if (strcmp(lite_id, "lite/regular")==0)
575     {
576 	return pixbuf;
577     }
578 
579     // Create ad hoc pixbuf
580     return ad_hoc_pixbuf(pixbuf, id, size);
581 
582 }
583 
584 
585 static
586 gchar *
fallback_icon_path(const gchar * id)587 fallback_icon_path(const gchar * id){
588     gchar *fullpath=NULL;
589     if (strstr(id, "xffm/emblem_")){
590 	fullpath = g_strdup_printf("%s/icons/rfm/scalable/emblems/emblem-%s.svg",
591 		PACKAGE_DATA_DIR, id+strlen("xffm/emblem_"));
592     }
593     return fullpath;
594 }
595 
596 
597 
598 static GdkPixbuf *
make_pixbuf_from_id(const gchar * id,int size)599 make_pixbuf_from_id (const gchar * id, int size) {
600     GdkPixbuf *pixbuf=NULL;
601     // Short circuit to items in pixmaps directory... (ghack)
602     pixbuf = try_app_icon(id, size);
603     if(pixbuf){
604         g_object_ref(pixbuf);
605         return pixbuf;
606     }
607 
608 
609     NOOP (stderr, "ICONx:make_pixbuf_from_id: %s\n", id);
610     if(!id || !strlen (id)) return NULL;
611     const gchar *c_key="/compositeC";
612     const gchar *cc_key="/compositeC/";
613     const gchar *ccc_key="compositeC/";
614     const gchar *position="C";
615     gdouble scale_f=1.8;
616     gint overall_alpha=180;
617 
618     if (strstr(id, "/compositeC/")){
619 	c_key="/compositeC";
620 	cc_key="/compositeC/";
621 	ccc_key="compositeC/";
622 	scale_f=2.2;
623 	position="C";
624 	overall_alpha=225;
625     }
626     else if (strstr(id, "/compositeX/")){
627 	c_key="/compositeX";
628 	cc_key="/compositeX/";
629 	ccc_key="compositeX/";
630 	scale_f=1.0;
631 	position="C";
632         overall_alpha=150;
633     }
634     else if (strstr(id, "/compositeNE/")){
635 	c_key="/compositeNE";
636 	cc_key="/compositeNE/";
637 	ccc_key="compositeNE/";
638 	scale_f=3.0;
639 	position="NE";
640     }
641     else if (strstr(id, "/compositeNW/")){
642 	c_key="/compositeNW";
643 	cc_key="/compositeNW/";
644 	ccc_key="compositeNW/";
645 	position="NW";
646 	scale_f=3.0;
647     }
648     else if (strstr(id, "/compositeNC/")){
649 	c_key="/compositeNC";
650 	cc_key="/compositeNC/";
651 	ccc_key="compositeNC/";
652 	position="NC";
653 	scale_f=3.0;
654     }
655     else if (strstr(id, "/compositeSC/")){
656 	c_key="/compositeSC";
657 	cc_key="/compositeSC/";
658 	ccc_key="compositeSC/";
659 	position="SC";
660     }
661     else if (strstr(id, "/compositeSW/")){
662 	c_key="/compositeSW";
663 	cc_key="/compositeSW/";
664 	ccc_key="compositeSW/";
665 	position="SW";
666 	scale_f=1.5;
667 	overall_alpha=210;
668     }
669     /*else if (strstr(id, "/compositeHSW/")){
670 	c_key="/compositeSW";
671 	cc_key="/compositeSW/";
672 	ccc_key="compositeSW/";
673 	position="SW";
674         scale_f=1.4;
675 	overall_alpha=255;
676     }*/
677     else if (strstr(id, "/compositeSE/")){
678 	c_key="/compositeSE";
679 	cc_key="/compositeSE/";
680 	ccc_key="compositeSE/";
681 	position="SE";
682     }
683 
684     if(strstr (id, c_key)) {
685         gchar *basic_type = g_strdup (id);
686         NOOP (stderr, "composite type = %s\n", id);
687 
688         GdkPixbuf *basic_pixbuf;
689         if (strstr (basic_type, c_key)) *(strstr (basic_type, c_key)) = 0;
690         else DBG("make_pixbuf_from_id(): strstr (basic_type, c_key) returns NULL.");
691 
692         basic_pixbuf = get_pixbuf (basic_type, size, FALSE); //refs
693         if(!basic_pixbuf){
694 	    g_free (basic_type);
695 	    return NULL;
696 	}
697         if(strstr (id, cc_key) == NULL) {
698 	    DBG("incomplete composite specification: %s\n", id);
699 	    g_object_unref(basic_pixbuf);
700 	    g_free (basic_type);
701 	    return NULL;
702         }
703 	NOOP(stderr, "duplicating pixbuf for %s: %s\n", basic_type, id);
704         g_free (basic_type);
705 
706         GdkPixbuf *composite_pixbuf = rfm_pixbuf_duplicate(basic_pixbuf);
707 
708 	if (!composite_pixbuf) {
709 	    g_error("cannot duplicate basic pixbuf for %s\n", id);
710 	    return  basic_pixbuf;
711 	}
712 	g_object_unref(basic_pixbuf);
713 	g_object_ref(composite_pixbuf);
714 
715 
716         gchar *composite_id = g_strdup(strstr(id, cc_key) + strlen(cc_key));
717 
718 	// split
719 	gint count=0;
720 	gchar *p;
721 	gchar *comp_id[10];
722 	p=comp_id[count]=composite_id;
723 	count++;
724 	while (strchr(p,'/')){
725 	    *strchr(p,'/')=0;
726 	    p += (strlen(p)+1);
727 	    if (strncmp(p,ccc_key,strlen(ccc_key)!=0)){
728 		NOOP(" composite type= %s\n", p);
729 		comp_id[count]=p;
730 		count++;
731 	    }
732 	}
733 	gint j;
734 	const gchar *group="xffm";
735 	for (j=0; j<count; j++){
736 	    // Determine the group to which the icon belongs to
737 	    gchar *groups[]={
738 		"application", "audio",
739 		"chemical", "image",
740 		"inode", "message",
741 		"model", "multipart",
742 		"text", "video",
743 		"x-conference",	"x-content",
744 		"x-epoc", "x-world",
745 		NULL};
746 	    gchar **pp=groups;
747 	    for(; pp && *pp; pp++){
748 		if (strcmp(comp_id[j],*pp)==0){
749 		    group=*pp;
750 		    continue;
751 		}
752 	    }
753 	    // Don't composite with group names (only with xffm group).
754 	    if (strcmp(group, comp_id[j])==0) continue;
755 	    gchar *c_id = NULL;
756 	    if (!c_id) {
757 		// no special position found
758 		c_id = g_strdup_printf ("%s/%s", group, comp_id[j]);
759 	    }
760 	    NOOP(stderr, "id = %s composite tag=%s\n", id, c_id);
761 
762 	    GdkPixbuf *tag = get_pixbuf (c_id, size, FALSE); //refs
763 	    if(!tag) {
764 		NOOP ("cannot get pixbuf for id: %s\n", c_id);
765 		g_free(c_id);
766 		g_free(composite_id);
767 		return composite_pixbuf;
768 	    }
769 	    rfm_insert_pixbuf_tag (tag, composite_pixbuf, position, scale_f, overall_alpha);
770 	    g_free(c_id);
771 	    g_object_unref(tag);
772 	}
773 	g_free(composite_id);
774 
775         return composite_pixbuf;
776     }
777 
778     gboolean gtk_icontheme = (getenv("RFM_USE_GTK_ICON_THEME") && strlen(getenv("RFM_USE_GTK_ICON_THEME")));
779 
780 // hack...
781     if (strcmp(id, "image/png")==0) id = "xffm/emblem_image";
782     if (strcmp(id, "xffm/")==0) id = "xffm/stock_file";
783 
784 
785 
786 
787     gchar *file = NULL;
788     if (strcmp(id, _("unknown"))==0) {
789 	if (gtk_icontheme) file = ICON_get_filename_from_id ("xffm/stock_file");
790 	else file = ICON_get_filename_from_id ("xffm/emblem_file");
791 
792     } else {
793 	file = ICON_get_filename_from_id (id);
794     }
795 
796     // Fallback icons
797     if (!file) {
798 	gboolean is_stock_icon = (strncmp(id, "xffm/stock_", strlen("xffm/stock_")) == 0);
799 	gboolean is_dir_icon = (strncmp(id, "xffm/stock_directory", strlen("xffm/stock_directory")) == 0);
800 	gboolean is_file_icon = (strncmp(id, "xffm/stock_file", strlen("xffm/stock_file")) == 0);
801 	if (is_dir_icon || is_file_icon || !is_stock_icon){
802 	    gchar *new_id=NULL;
803 	    if (strcmp(id, "inode/directory")==0) id = "xffm/stock_directory";
804 
805 	    if (!gtk_icontheme && is_dir_icon ) {
806 		new_id = g_strdup_printf("xffm/emblem_folder%s", id + strlen("xffm/stock_directory"));
807 	    } else if (!gtk_icontheme && is_file_icon) {
808 		new_id = g_strdup_printf("xffm/emblem_file%s", id + strlen("xffm/stock_file"));
809 	    } else {
810 		new_id = g_strdup(id);
811 	    }
812 	    file = fallback_icon_path(new_id);
813 	    g_free(new_id);
814 	}
815     }
816     // Create pixbuf from path to image file
817     if (file){
818 	pixbuf = rfm_pixbuf_new_from_file(file, size, size); // refs
819         // This is wrong. Pixbuf already has a reference returned from gdk_pixbuf function.
820 	/*if (pixbuf) g_object_ref(pixbuf);
821 	else DBG("make_pixbuf_from_id(%s, %d): returns NULL!\n", id, size);*/
822 #ifdef DEBUG
823 	if (pixbuf==NULL) DBG("make_pixbuf_from_id(%s, %d): returns NULL!\n", id, size);
824 #endif
825 	g_free(file);
826 	NOOP(stderr, "id=%s\n", id);
827 	if (!strstr(id, "xffm/stock_directory")
828 		&& !strstr(id, "xffm/emblem")
829 		&& !strstr(id, "xffm/stock_home")
830 		&& !strstr(id, "inode/directory")
831 		&& !strstr(id, "xffm/stock_go-up")){
832             if (pixbuf && GDK_IS_PIXBUF(pixbuf)){
833 	    guchar red, green, blue;
834 	    init_lite_hash();
835 	        gchar *tpath = NULL;
836 	        const gchar *lite_id = get_mask_color(id, &red, &green, &blue, &tpath);
837 	        cairo_t   *pixbuf_context = pixbuf_cairo_create(pixbuf);
838                 // This proved necessary in opensuse-12.3,
839                 // but not in gentoo nor ubuntu. Go figure...
840 		gdk_cairo_set_source_pixbuf(pixbuf_context, pixbuf,0,0);
841 		cairo_paint_with_alpha(pixbuf_context, 1.0);
842 
843                 // Color:
844                 if (red != 0xff || green != 0xff || blue != 0xff)
845                     add_color_pixbuf(pixbuf_context, pixbuf, red, green, blue);
846                 // Emblem:
847                 add_emblem_pixbuf(pixbuf_context, pixbuf,tpath, size);
848                 g_free(tpath);
849                 // Text:
850                 add_label_pixbuf(pixbuf_context, pixbuf, lite_id, size);
851                 pixbuf_cairo_destroy(pixbuf_context, pixbuf);
852             }
853 	}
854 
855 
856     } else {
857 	if (strncmp(id, "xffm/stock_", strlen("xffm/stock_"))==0) {
858 	    gchar *gtk_id = g_strdup_printf("%s", id+strlen("xffm/stock_"));
859 	    pixbuf = pixbuf_from_gtkid(gtk_id, size); // refs
860             NOOP(stderr, "cannot get icon path from \"%s\", trying \"%s\" --> %d\n",
861                     id, gtk_id, GPOINTER_TO_INT(pixbuf));
862 	    g_free(gtk_id);
863 	}
864 
865 	if (!pixbuf) {
866             if (strstr(id, "rodent")) DBG("Unknown pixbuf id: %s\n", id);
867 	}
868     }
869     if (!pixbuf) {
870 	pixbuf = last_resort_pixbuf(size, id); //refs belongs to litehash
871 	if(pixbuf) g_object_ref(pixbuf);
872     }
873     return pixbuf;
874 }
875 
876 static
877 GdkPixbuf *
get_pixbuf(const gchar * key,gint size,gboolean replace_pixbuf)878 get_pixbuf (const gchar * key, gint size, gboolean replace_pixbuf) {
879 #if GTK_MAJOR_VERSION==3
880     //Bug workaround for non icontheme gtk-3.14, still present at time of test in gtk-3.16
881     static gsize initialized = 0;
882         if (g_once_init_enter (&initialized)) {
883         // gtk 3.14 non deprecated method...
884         // add emblems and stock
885 
886         gchar *resource_path = g_build_filename(PREFIX, "share", "icons", "rfm", NULL);
887         gtk_icon_theme_add_resource_path (gtk_icon_theme_get_default (),resource_path);
888 
889         // this works, but icons should be fixed size. scalable vector graphics dont work...
890         // icons should be in the "symbolic" internal gtk name format (hack...)
891         // This is for non icon-themed boxes, like mine.
892         gchar *path = g_build_filename(resource_path, "24x24", NULL);
893         gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (), path);
894         g_free(path);
895         g_free(resource_path);
896 	g_once_init_leave (&initialized, 1);
897     }
898 #endif
899 
900 
901 
902     NOOP ("get_pixbuf(%s, %d)\n", key, size);
903     if(!key) {
904         NOOP ("get_pixbuf(): key is NULL!\n");
905 	return NULL;
906     }
907     GdkPixbuf *pixbuf = NULL;
908     // find in pixbuf hash
909     if (!replace_pixbuf){
910 	pixbuf = rfm_find_in_pixbuf_hash (key, size); // refs
911         if(pixbuf) {
912 	    NOOP ("HASH-primary-icons.c: %s found in pixbuf hash\n", key);
913 	    return pixbuf;
914 	}
915     }
916 
917 
918     // Pixbuf does not exist or will be replaced in the pixbuf hash table.
919     const gchar *path = key;
920     if(g_path_is_absolute (path)) {
921 	NOOP ("Direct access to source pixbuf file.\n");
922 	if (!g_file_test (path, G_FILE_TEST_EXISTS) || g_file_test (path, G_FILE_TEST_IS_DIR)){
923 	    NOOP ("get_pixbuf(%s): is not a pixbuf source file", path);
924 	    return NULL;
925 	}
926         pixbuf = rfm_create_preview (path, size); // refs
927         if(!pixbuf) {
928             NOOP ("create_preview(%s, %d): returns NULL!\n", path, size);
929             return NULL;
930         }
931     } else {
932 	NOOP (stderr, "Pixbuf creation from pixbuf id: make_pixbuf_from_id\n");
933         pixbuf = make_pixbuf_from_id (path, size); // refs
934 
935         if(!pixbuf) {
936             NOOP ("get_pixbuf(%s, %d): returns NULL!\n", path, size);
937             return NULL;
938         }
939     }
940     if (pixbuf && GDK_IS_PIXBUF(pixbuf)){
941         rfm_put_in_pixbuf_hash(path, size, pixbuf); // no ref
942     }
943     return pixbuf;
944 }
945 
946 
947