1 /*
2  * Copyright (C) 2002-2012 Edscott Wilson Garcia
3  * EMail: edscott@users.sf.net
4  *
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program;
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23 
24 #include "rfm.h"
25 #include "rfm_modules.h"
26 
27 #include "primary-pixbuf-cairo.i"
28 #include "primary-icons-hash.i"
29 #include "primary-icons.i"
30 
31 static void
add_theme_list(GSList ** list_p,const gchar * path)32 add_theme_list(GSList **list_p, const gchar *path){
33     if (!g_file_test(path, G_FILE_TEST_IS_DIR)) return;
34     DIR *directory = opendir(path);
35     if (!directory) return;
36     struct dirent *d;
37 
38     while ((d=readdir(directory)) != NULL){
39 	gboolean unknown=TRUE;
40 #ifdef HAVE_STRUCT_DIRENT_D_TYPE
41 	if (d->d_type != DT_DIR && d->d_type != DT_UNKNOWN) continue;
42 	if (d->d_type == DT_DIR) unknown = FALSE;
43 #endif
44 	if (unknown) {
45 	    gchar *file =  g_strconcat(path, G_DIR_SEPARATOR_S, d->d_name, NULL);
46 	    struct stat st;
47 	    if (stat(file,&st) < 0){
48 		g_free(file);
49 		continue;
50 	    }
51 	    g_free(file);
52 	    if (!S_ISDIR(st.st_mode)) continue;
53 	}
54 	gchar *test_file = g_strconcat(path, G_DIR_SEPARATOR_S, d->d_name, G_DIR_SEPARATOR_S,"index.theme", NULL);
55 	if (g_file_test(test_file, G_FILE_TEST_EXISTS)){
56 	    NOOP(stderr, "%s exists...\n", test_file);
57 	    *list_p = g_slist_append(*list_p, g_strdup(d->d_name));
58 	}
59 	g_free(test_file);
60     }
61     closedir (directory);
62 
63 
64 }
65 
66 
extend_icon_theme_path(gchar ** pathv,int * l)67 static gchar **extend_icon_theme_path(gchar **pathv, int *l){
68     gchar * s_p[]={"/usr/share/icons", "/usr/local/share/icons", "/usr/share/pixmaps", "usr/local/share/pixmaps", NULL};
69 
70     gint length = 0;
71     gchar **p;
72     for (p=pathv;p && *p;p++) {
73         length++;
74     }
75 
76     gchar **q;
77     for(q = s_p;q && *q; q++){
78         gboolean found = FALSE;
79         for (p=pathv;p && *p;p++) {
80             if (strcmp(*q, *p)==0) {
81                 found = TRUE;
82                 break;
83             }
84         }
85         if (!found) length++;
86     }
87 
88     gchar **new_pathv = (gchar **)malloc((length+1)*sizeof(gchar *));
89     if (!new_pathv) g_error("malloc: %s\n", strerror(errno));
90     gchar **r = new_pathv;
91     memset(r, 0, (length+1)*sizeof(gchar *));
92 
93     for (p=pathv;p && *p;p++,r++) *r = g_strdup(*p);
94 
95     for(q = s_p;q && *q; q++){
96         gboolean found = FALSE;
97         for (p=pathv;p && *p;p++) {
98             if (strcmp(*q, *p)==0) {
99                 found = TRUE;
100                 break;
101             }
102         }
103         if (!found) {
104              *r = g_strdup(*q);
105              r++;
106         }
107     }
108     *l = length;
109     return new_pathv;
110 }
111 
rfm_get_iconthemes(void)112 gchar **rfm_get_iconthemes(void){
113     gchar **pathv=NULL;
114     GtkIconTheme *icon_theme = gtk_icon_theme_get_default ();
115     gtk_icon_theme_get_search_path (icon_theme, &pathv, NULL);
116 
117     gint length;
118     gchar **epathv = extend_icon_theme_path(pathv, &length);
119     g_strfreev(pathv);
120 
121 
122     gtk_icon_theme_set_search_path(icon_theme, (const gchar **)epathv, length);
123     gtk_icon_theme_get_search_path (icon_theme, &pathv, NULL);
124     g_strfreev(epathv);
125 
126     GSList *list=NULL;
127     gchar **p;
128     for (p=pathv;p && *p;p++){
129 	DBG("icontheme path=%s\n", *p);
130 	if (g_file_test(*p, G_FILE_TEST_EXISTS)) add_theme_list(&list, *p);
131     }
132     gchar **th_options = (gchar **)malloc((g_slist_length(list)+1)*sizeof(gchar *));
133     if (!th_options) g_error("malloc: %s\n", strerror(errno));
134     memset(th_options, 0, (g_slist_length(list)+1)*sizeof(gchar *));
135     GSList *tmp=list;
136     gint j;
137     for (j=0; tmp && tmp->data ; tmp=tmp->next){
138 	DBG("theme: %s\n", (gchar *)tmp->data);
139 	th_options[j++] = tmp->data;
140     }
141     g_slist_free(list);
142     g_strfreev(pathv);
143     return th_options;
144 }
145 
146 Pixmap
rfm_create_background_pixmap(char * file)147 rfm_create_background_pixmap (char *file) {
148     /* create Pixmap */
149 
150     gint root_x;
151     gint root_y;
152     gint root_w;
153     gint root_h;
154     gint root_d;
155 
156       Display 	*Xdisplay;
157       Drawable 	root_Xwindow;
158       Visual 	*Xvisual;
159     rfm_global_t *rfm_global_p = rfm_global();
160     if (rfm_global_p) {
161 	Xdisplay = rfm_global_p->Xdisplay;
162 	root_Xwindow = rfm_global_p->root_Xwindow;
163 	Xvisual = rfm_global_p->Xvisual;
164     } else {
165 	root_Xwindow = gdk_x11_get_default_root_xwindow ();
166 	Xdisplay = gdk_x11_display_get_xdisplay(gdk_display_get_default());
167 	Xvisual = gdk_x11_visual_get_xvisual(gdk_visual_get_system());
168 
169     }
170 
171     rfm_get_drawable_geometry(root_Xwindow,
172 	    &root_x, &root_y, &root_w, &root_h, &root_d);
173     Pixmap xpixmap = XCreatePixmap (Xdisplay, GDK_ROOT_WINDOW (), root_w, root_h, root_d);
174 
175     // The X way
176     // create a graphic context for the pixmap
177     GC graphic_context = XCreateGC(Xdisplay, xpixmap, 0, 0);;
178     // get default colormap
179     static Colormap colormap = None;
180     if (colormap == None){
181 	colormap = DefaultColormap(Xdisplay, 0);
182     }
183 
184     // parse the color specification
185     XColor background_color;
186     const gchar *background=NULL;
187     if(getenv ("RFM_DESKTOP_COLOR") && strlen (getenv ("RFM_DESKTOP_COLOR"))) {
188 	background=getenv ("RFM_DESKTOP_COLOR");
189         if (!XParseColor(Xdisplay,
190 	    colormap, background, &background_color)) {
191 	    DBG("cannot parse background color: %s\n", background);
192 	    background=NULL;
193 	}
194     }
195     if (!background) {
196 	background="#000000";
197         if (!XParseColor(Xdisplay,
198 	    colormap, background, &background_color)) {
199 	    g_error("cannot parse default background color: %s", background);
200 	}
201     }
202     XAllocColor(Xdisplay, colormap, &background_color);
203     XSetForeground(Xdisplay, graphic_context, background_color.pixel);
204     XFillRectangle (Xdisplay, xpixmap, graphic_context, 0, 0, root_w, root_h);
205 
206 
207 // cairo way
208 #ifndef CAIRO_HAS_XLIB_SURFACE
209  DBG ("CAIRO_HAS_XLIB_SURFACE is not defined!\n");
210 #else
211     GdkPixbuf *pixbuf = NULL;
212     if (file) {
213 	pixbuf = rfm_create_background_pixbuf (file, root_w, root_h);
214 	if(!GDK_IS_PIXBUF(pixbuf)) {
215 	    DBG("cannot create pixbuf from %s\n", file);
216 	}
217     }
218 
219     if (pixbuf && GDK_IS_PIXBUF(pixbuf)) {
220 	cairo_surface_t *pixmap_surface =
221 	    cairo_xlib_surface_create (
222 		    Xdisplay, // Display *
223 		    xpixmap, // Drawable
224 		    Xvisual, // Visual *
225 		    root_w, root_h);
226 	if(cairo_surface_status (pixmap_surface) != CAIRO_STATUS_SUCCESS) {
227 	    g_error ("cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS");
228 	}
229 	cairo_surface_reference(pixmap_surface);
230 	cairo_t *pixmap_context = cairo_create (pixmap_surface);
231 	cairo_reference(pixmap_context);
232 
233 	gdk_cairo_set_source_pixbuf(pixmap_context, pixbuf,
234 		       (root_w - gdk_pixbuf_get_width (pixbuf)) / 2,
235 		       (root_h - gdk_pixbuf_get_height (pixbuf)) / 2);
236 	cairo_paint (pixmap_context);
237 	cairo_surface_destroy(pixmap_surface);
238 	cairo_destroy(pixmap_context);
239 	g_object_unref(pixbuf);
240     }
241 #endif
242     XFreeGC(Xdisplay, graphic_context);
243     return xpixmap;
244 }
245 /******************************************************************/
246 
247 gboolean
rfm_is_dark_background(view_t * view_p)248 rfm_is_dark_background(view_t *view_p){
249     gboolean is_dark = FALSE; // default is light
250     // Get background color
251     const gchar *bkg_var=(view_p->flags.type == DESKVIEW_TYPE)?
252 	"RFM_DESKTOP_COLOR": "RFM_ICONVIEW_COLOR";
253     // figure out if light or dark background to use
254     // dark or light color set
255     if(getenv (bkg_var) && strlen (getenv (bkg_var))) {
256 #if GTK_MAJOR_VERSION==3
257         GdkRGBA gdk_color;
258 	if (!gdk_rgba_parse (&gdk_color, getenv (bkg_var))){
259 	    DBG("cannot parse background color %s", getenv (bkg_var));
260 	} else {
261 	    gint sum = (gdk_color.red) +
262 		      (gdk_color.green) +
263 		      (gdk_color.blue);
264 	    is_dark = (sum < 1.5);
265 	}
266 #else
267         GdkColor gdk_color;
268 	if (!gdk_color_parse (getenv (bkg_var), &gdk_color)){
269 	    DBG("cannot parse background color %s", getenv (bkg_var));
270 	} else {
271 	    gint sum = (gdk_color.red) +
272 		      (gdk_color.green) +
273 		      (gdk_color.blue);
274 	    is_dark = (sum < 0xffff * 3 / 2);
275 	}
276 #endif
277     }
278     return is_dark;
279 }
280 
281 #define NUM_COLORS 8
282 #if GTK_MAJOR_VERSION==3
283 GdkRGBA *
rfm_get_gdk_color(view_t * view_p,int p)284 rfm_get_gdk_color (view_t *view_p, int p) {
285     if(p < 0 || p >= NUM_COLORS) {
286         DBG ("rodent_select_pen: pen %d out of range.\n", p);
287         return NULL;
288     }
289     GdkRGBA pen_colors[] = {
290 /* light background */
291         {1.0, 1.0, 1.0, 1.0},       /*white */
292         { 0.0, 0.0, 0.0, 1.0},           /*black */
293         { 1.0, 0.0, 0.0, 1.0},       /*red */
294         { 0.0, 0.4577, 0.0, 1.0},       /*green */
295         { 0.0, 0.0, 0.4882, 1.0},       /*blue */
296         { 0.4882, 0.4882, 0.0, 1.0},   /*brown */
297         { 1.0, 0.0, 1.0, 1.0},   /*magenta */
298         { 0.7324, 0.7324, 0.7324, 1.0},       /*grey */
299 /* dark background */
300         { 0.0, 0.0, 0.0, 1.0},           /*black */
301         { 1.0, 1.0, 1.0, 1.0},       /*white */
302         { 1.0, 0.3052, 0.3052, 1.0},      /*red */
303         { 0.3052, 0.9155, 0.3052, 1.0},      /*green */
304         { 0.6104, 0.6104, 1.0, 1.0},      /*blue */
305         { 0.4882, 0.4882, 0.0, 1.0},  /*brown */
306         { 1.0, 0.0, 1.0, 1.0},  /*magenta */
307         { 0.7324, 0.7324, 0.7324, 1.0}       /*grey */
308     };
309 
310     GdkRGBA *gdk_color = (GdkRGBA *) malloc(sizeof(GdkRGBA));
311     if (!gdk_color) return NULL;
312     memset(gdk_color, 0, sizeof(GdkRGBA));
313 
314     // if background color requested, return now
315     const gchar *bkg_var=(view_p->flags.type == DESKVIEW_TYPE)?
316 	"RFM_DESKTOP_COLOR": "RFM_ICONVIEW_COLOR";
317     const gchar *bg_color = getenv (bkg_var);
318     if (p == BACKGROUND_COLOR && bg_color && strlen (bg_color)) {
319 	if (!gdk_rgba_parse (gdk_color, bg_color)){
320 	    DBG("cannot parse background color %s\n", bg_color);
321 	} else {
322 	    NOOP ("DESK: selecting BACKGROUND_COLOR %s\n", bg_color);
323 	    return gdk_color;
324 	}
325     }
326 
327     gint offset = (rfm_is_dark_background(view_p))? NUM_COLORS : 0;
328     // return color entry
329     memcpy(gdk_color,  pen_colors + p + offset, sizeof(GdkRGBA));
330     return gdk_color;
331 }
332 
333 #else
334 GdkColor *
rfm_get_gdk_color(view_t * view_p,int p)335 rfm_get_gdk_color (view_t *view_p, int p) {
336     if(p < 0 || p >= NUM_COLORS) {
337         DBG ("rodent_select_pen: pen %d out of range.\n", p);
338         return NULL;
339     }
340     GdkColor pen_colors[] = {
341 /* light background */
342         {0, 65535, 65535, 65535},       /*white */
343         {1, 0, 0, 0},           /*black */
344         {2, 65535, 0, 0},       /*red */
345         {3, 0, 30000, 0},       /*green */
346         {4, 0, 0, 32000},       /*blue */
347         {5, 32000, 32000, 0},   /*brown */
348         {6, 65535, 0, 65535},   /*magenta */
349         {7, 48000, 48000, 48000},       /*grey */
350 /* dark background */
351         {1, 0, 0, 0},           /*black */
352         {0, 65535, 65535, 65535},       /*white */
353         {12, 65535, 20000, 20000},      /*red */
354         {13, 20000, 60000, 20000},      /*green */
355         {14, 40000, 40000, 65535},      /*blue */
356         {15, 32000, 32000, 0},  /*brown */
357         {16, 65535, 0, 65535},  /*magenta */
358         {17, 48000, 48000, 48000}       /*grey */
359     };
360 
361     GdkColor *gdk_color = (GdkColor *) malloc(sizeof(GdkColor));
362     memset(gdk_color, 0, sizeof(GdkColor));
363 
364     // if background color requested, return now
365     const gchar *bkg_var=(view_p->flags.type == DESKVIEW_TYPE)?
366 	"RFM_DESKTOP_COLOR": "RFM_ICONVIEW_COLOR";
367     if (p == BACKGROUND_COLOR && getenv (bkg_var) && strlen (getenv (bkg_var))) {
368 	if (!gdk_color_parse (getenv (bkg_var), gdk_color)){
369 	    DBG("cannot parse background color %s\n", getenv (bkg_var));
370 	} else {
371 	    NOOP ("DESK: selecting BACKGROUND_COLOR %s\n", getenv (bkg_var));
372 	    return gdk_color;
373 	}
374     }
375 
376     gint offset = (rfm_is_dark_background(view_p))? NUM_COLORS : 0;
377     // return color entry
378     memcpy(gdk_color,  pen_colors + p + offset, sizeof(GdkColor));
379     return gdk_color;
380 }
381 #endif
382 
383 GdkPixbuf *
rfm_create_background_pixbuf(const char * file,int width,int height)384 rfm_create_background_pixbuf (const char *file, int width, int height) {
385 
386       Drawable root_Xwindow;
387       //Display *Xdisplay;
388       //Visual *Xvisual;
389     rfm_global_t *rfm_global_p = rfm_global();
390     if (rfm_global_p) {
391 	root_Xwindow = rfm_global_p->root_Xwindow;
392 	//Xdisplay = rfm_global_p->Xdisplay;
393 	//Xvisual = rfm_global_p->Xvisual;
394     } else {
395 	root_Xwindow = gdk_x11_get_default_root_xwindow ();
396 	//Xdisplay = gdk_x11_display_get_xdisplay(gdk_display_get_default());
397 	//Xvisual = gdk_x11_visual_get_xvisual(gdk_visual_get_system());
398 
399     }
400     if (width < 0 || height < 0) {
401         rfm_get_drawable_geometry (root_Xwindow,
402 	    NULL, NULL, &width, &height, NULL);
403     }
404 
405     GdkPixbuf *tgt;
406     gdouble factor, x_factor, y_factor;
407     gint w, h;
408     if(!file) return NULL;
409     NOOP ("getting pixbuf %s", file);
410     GdkPixbuf *src = NULL;
411 
412     if (g_file_test(file, G_FILE_TEST_EXISTS)){
413       src = rfm_pixbuf_new_from_file(file, -1, -1);
414       if(!src) return NULL;
415     }
416 
417     if(!src) return NULL;
418 
419     w = gdk_pixbuf_get_width (src);
420     h = gdk_pixbuf_get_height (src);
421     NOOP (stderr, " pixbuf is %d,%d width,height is %d,%d\n", w, h, width, height);
422     x_factor = (double)width / w;
423     y_factor = (double)height / h;
424     factor = (x_factor < y_factor) ? x_factor : y_factor;
425     NOOP (stderr, "factors %lf,%lf --> %lf, distorsion=%lf\n", x_factor, y_factor, factor, fabs (x_factor - y_factor) / factor);
426     if(fabs (x_factor - y_factor) / factor < 0.20) {
427     //if (1){
428 	NOOP (stderr, "scaling pixbuf %s to %d,%d\n", file, width, height);
429 	tgt = rfm_pixbuf_scale_stretch(src, width, height, GDK_INTERP_BILINEAR);
430     } else {
431 	NOOP (stderr, "factor=%lf scaling pixbuf %s to %lf,%lf\n", factor, file, factor * w, factor * h);
432 	if (x_factor > y_factor) {
433 	    tgt = rfm_pixbuf_scale_stretch(src, 1.2*factor * w, factor * h,
434 		    GDK_INTERP_BILINEAR);
435 	} else {
436 	    tgt = rfm_pixbuf_scale_stretch(src, factor * w, 1.2*factor * h,
437 		    GDK_INTERP_BILINEAR);
438 	}
439     }
440     g_object_unref (G_OBJECT (src));
441     NOOP ("got pixbuf %s\n", file);
442     return tgt;
443 }
444 
445 
446 gchar *
rfm_get_thumbnail_path(const gchar * file,gint size)447 rfm_get_thumbnail_path (const gchar * file, gint size) {
448     gchar *cache_dir;
449     gchar *thumbnail_path = NULL;
450     GString *gs;
451     gchar key[11];
452 
453     cache_dir = g_build_filename (RFM_THUMBNAIL_DIR, NULL);
454     if(g_mkdir_with_parents (cache_dir, 0700) < 0) {
455         g_free (cache_dir);
456         return NULL;
457     }
458 
459     /* thumbnails are not subject to thumbnailization: */
460     gchar *dirname = g_path_get_dirname (file);
461     if(strncmp (cache_dir, dirname, strlen (cache_dir)) == 0) {
462         NOOP ("thumbnails cannot be thumbnailed:%s\n", file);
463         g_free (cache_dir);
464         g_free (dirname);
465         return NULL;
466     }
467 
468     gs = g_string_new (dirname);
469     sprintf (key, "%10u", g_string_hash (gs));
470     g_strstrip (key);
471     g_string_free (gs, TRUE);
472     g_free (dirname);
473 
474     gchar *thumbnail_dir = g_build_filename (cache_dir, key, NULL);
475     if(g_mkdir_with_parents (thumbnail_dir, 0700) < 0) {
476         g_free (thumbnail_dir);
477         return NULL;
478     }
479 
480     gchar *filename = g_path_get_basename (file);
481 
482     gs = g_string_new (file);
483     sprintf (key, "%10u", g_string_hash (gs));
484     g_strstrip (key);
485     g_string_free (gs, TRUE);
486     g_free (filename);
487 
488     filename = g_strdup_printf ("%s-%d.png", key, size);
489     thumbnail_path = g_build_filename (thumbnail_dir, filename, NULL);
490     g_free (filename);
491     g_free (cache_dir);
492     g_free (thumbnail_dir);
493     NOOP ("thread: %s ->thumbnail_path=%s\n", file, thumbnail_path);
494 
495     return thumbnail_path;
496 }
497 /*
498 static void *
499     replace_pixbuf_hash(void *data){
500     GHashTable *new_pixbuf_hash = data;
501     GHashTable *old_pixbuf_hash = pixbuf_hash;
502     pixbuf_hash = new_pixbuf_hash;
503     g_hash_table_destroy(old_pixbuf_hash);
504     return NULL;
505 }
506 */
507 /*
508 static gboolean
509 pixbuf_scale(GdkPixbuf *in_pixbuf, pixbuf_t *pixbuf_p){
510     if (!in_pixbuf || !pixbuf_p || !pixbuf_p->pixbuf) return FALSE;
511     gint width = gdk_pixbuf_get_width(pixbuf_p->pixbuf);
512     gint height = gdk_pixbuf_get_height(pixbuf_p->pixbuf);
513     gdk_pixbuf_scale  (in_pixbuf, pixbuf_p->pixbuf,
514 			    0, 0,
515                           width, height,
516 			  0, 0,
517 			  1.0, 1.0,
518 			  GDK_INTERP_NEAREST);
519     g_object_unref(in_pixbuf);
520     return FALSE;
521 }
522 */
523 /*
524 static void
525 update_pixbuf_f (gpointer key, gpointer value, gpointer data){
526     pixbuf_t *pixbuf_p = value;
527     if (g_path_is_absolute(pixbuf_p->path)){
528 	// don't touch thumbnails.
529 	return;
530     }
531     gboolean replace_pixbuf = TRUE;
532     GdkPixbuf *pixbuf =
533 	get_pixbuf(pixbuf_p->mime_id, pixbuf_p->size, replace_pixbuf);
534     if (pixbuf && GDK_IS_PIXBUF(pixbuf)) {
535 	NOOP("updating pixbuf: %s (%d)\n", pixbuf_p->mime_id, pixbuf_p->size);
536         pixbuf_scale(pixbuf, pixbuf_p);
537 	// in function... g_object_unref(pixbuf);
538     }
539 }
540 */
541 /*
542 static void *
543 rfm_change_icontheme_f(void *data){
544     NOOP(stderr, "-----> rfm_change_icontheme_f\n");
545     if (rfm_get_gtk_thread() != g_thread_self()){
546 	DBG("update_pixbuf_f(): rfm_get_gtk_thread() != g_thread_self()\n");
547         return NULL;
548     }
549     g_hash_table_foreach (pixbuf_hash, update_pixbuf_f, NULL);
550     return NULL;
551 }
552 */
553 static void *
change_pixbuf_hash(void * data)554 change_pixbuf_hash(void *data){
555     GHashTable *old_pixbuf_hash = pixbuf_hash;
556     pixbuf_hash = g_hash_table_new_full (g_str_hash, g_str_equal,g_free, free_pixbuf_t);
557     g_hash_table_destroy(old_pixbuf_hash);
558     return NULL;
559 }
560 #if 0
561 void
rfm_change_icontheme(void)562 rfm_change_icontheme(void){
563     if(!pixbuf_hash) return;
564 
565     if (rfm_get_gtk_thread()==g_thread_self()){
566 	rfm_change_icontheme_f(NULL);
567     } else {
568 	rfm_context_function(rfm_change_icontheme_f, NULL);
569     }
570 }
571 #else
572 // XXX here's the rub... We are using gtk icon theme to get icon search path,
573 //     we should not do this when icontheme not selected, but we should not alter
574 //     the gtk search path either. (Dont use gtk search path when no icontheme selected...)
575 void
rfm_change_icontheme(void)576 rfm_change_icontheme(void){
577     widgets_t *widgets_p = rfm_get_widget("widgets_p");
578     const gchar *icontheme_name = getenv("RFM_USE_GTK_ICON_THEME");
579     if (icontheme_name && strlen(icontheme_name)) {
580 	GtkSettings *settings = gtk_settings_get_default();
581 	g_object_set( G_OBJECT(settings),
582 		"gtk-icon-theme-name", icontheme_name,
583 		NULL);
584     }
585 
586     gchar *text = g_strdup_printf("%s %s (%s)\n",
587 	    _("Icon theme:"), (icontheme_name && strlen(icontheme_name))?icontheme_name:_("None"),
588 	    _("Note: Some changes will not take effect until restart"));
589 
590     if (rfm_get_gtk_thread() != g_thread_self()){
591 	rfm_threaded_show_text(widgets_p);
592 	rfm_threaded_diagnostics(widgets_p, "xffm/stock_dialog-warning", NULL);
593 	rfm_threaded_diagnostics(widgets_p, "xffm_tag/red", text);
594     } else {
595 	rfm_show_text(widgets_p);
596 	rfm_diagnostics(widgets_p, "xffm/stock_dialog-warning", NULL);
597 	rfm_diagnostics(widgets_p, "xffm_tag/red", text, NULL);
598 	g_free(text);
599     }
600     // Recreate pixbuf hash.
601     rfm_context_function(change_pixbuf_hash, NULL);
602     //rfm_context_function(rfm_change_icontheme_f, NULL);
603 }
604 
605 #endif
606 
607 static gboolean
pixbuf_save_f(void * data)608 pixbuf_save_f(void *data){
609     void **arg = data;
610     GdkPixbuf *tgt = arg[0];
611     gchar *path = arg[1];
612     g_free(arg);
613     gint status = 0;
614     rfm_global_t *rfm_global_p = rfm_global();
615     if (rfm_global_p){
616 	g_mutex_lock(rfm_global_p->status_mutex);
617 	status = rfm_global_p->status;
618 	g_mutex_unlock(rfm_global_p->status_mutex);
619     }
620     if (tgt && GDK_IS_PIXBUF(tgt) && status != STATUS_EXIT) {
621 	GError *error = NULL;
622 	gdk_pixbuf_save (tgt, path, "png", &error,
623 			 "tEXt::Software", "Rodent", NULL);
624 	if (error){
625 	    DBG("pixbuf_save_f(%s): %s\n", path, error->message);
626 	    g_error_free(error);
627 	}
628     }
629     g_free(path);
630     return FALSE;
631 }
632 
633 static void *
pixbuf_scale_simple_f(void * data)634 pixbuf_scale_simple_f(void *data){
635     void **arg = data;
636     GdkPixbuf *in_src = arg[0];
637     gint width = GPOINTER_TO_INT(arg[1]);
638     gint height = GPOINTER_TO_INT(arg[2]);
639     gint type = GPOINTER_TO_INT(arg[3]);
640     g_free(arg);
641     return gdk_pixbuf_scale_simple (in_src, width, height, type);
642 
643     // XXX Where is this hack necessary?
644 #if 0
645     GdkPixbuf *src = NULL;
646     gint ph = gdk_pixbuf_get_height (in_src);
647     gint pw = gdk_pixbuf_get_width (in_src);
648 
649 
650     if (ph > pw) {
651 	    gint w = height * pw / ph;
652 	    src = gdk_pixbuf_scale_simple (in_src, w, height, type);
653     } else {
654 	    gint h = width * ph / pw;
655 	    src = gdk_pixbuf_scale_simple (in_src, width, h, type);
656     }
657     return src;
658 #endif
659 }
660 
661 
662 GdkPixbuf *
rfm_pixbuf_scale_simple(GdkPixbuf * in_pixbuf,gint size,gint type)663 rfm_pixbuf_scale_simple (GdkPixbuf *in_pixbuf,  gint size, gint type){
664     //g_object_ref(in_pixbuf); return (in_pixbuf);
665 
666     void **arg = (void **)malloc(4*sizeof(void *));
667     if (!arg) g_error("malloc: %s\n", strerror(errno));
668     arg[0] = in_pixbuf;
669     arg[1] = GINT_TO_POINTER(size);
670     arg[2] = GINT_TO_POINTER(size);
671     arg[3] = GINT_TO_POINTER(type);
672     GdkPixbuf *pixbuf;
673     if (rfm_get_gtk_thread() != g_thread_self()){
674 	pixbuf = rfm_context_function(pixbuf_scale_simple_f, arg);
675     } else {
676 	pixbuf = pixbuf_scale_simple_f(arg);
677     }
678     return pixbuf;
679 }
680 
681 GdkPixbuf *
rfm_pixbuf_scale_stretch(GdkPixbuf * in_pixbuf,gint width,gint height,gint type)682 rfm_pixbuf_scale_stretch (GdkPixbuf *in_pixbuf,  gint width, gint height, gint type){
683     void **arg = (void **)malloc(4*sizeof(void *));
684     if (!arg) g_error("malloc: %s\n", strerror(errno));
685     arg[0] = in_pixbuf;
686     arg[1] = GINT_TO_POINTER(width);
687     arg[2] = GINT_TO_POINTER(height);
688     arg[3] = GINT_TO_POINTER(type);
689     GdkPixbuf *pixbuf;
690     if (rfm_get_gtk_thread() != g_thread_self()){
691 	pixbuf = rfm_context_function(pixbuf_scale_simple_f, arg);
692     } else {
693 	pixbuf = pixbuf_scale_simple_f(arg);
694     }
695     return pixbuf;
696 }
697 
698 
699 
700 void
rfm_pixbuf_save(GdkPixbuf * tgt,const gchar * path)701 rfm_pixbuf_save(GdkPixbuf *tgt, const gchar *path){
702     if (!tgt || !path || !GDK_IS_PIXBUF(tgt)) return ;
703     void **arg =(void **)malloc(2*sizeof(void *));
704     if (!arg) g_error("malloc: %s\n", strerror(errno));
705     arg[0] = tgt;
706     arg[1] = g_strdup(path);
707     // Additional reference to pixbuf to be removed
708     // by save function.
709     if (rfm_get_gtk_thread() != g_thread_self()){
710 	// don't wait here
711 	g_main_context_invoke(NULL, pixbuf_save_f, arg);
712     } else {
713 	pixbuf_save_f(arg);
714     }
715     return;
716 }
717 
718 
719 static void *
pixbuf_from_file_f(void * data)720 pixbuf_from_file_f(void *data){
721     void **arg = data;
722     gchar *path = arg[0];
723     gint width = GPOINTER_TO_INT(arg[1]);
724     gint height = GPOINTER_TO_INT(arg[2]);
725     GError *error = NULL;
726     GdkPixbuf *pixbuf = NULL;
727     if (width < 0) {
728 	pixbuf = gdk_pixbuf_new_from_file (path, &error);
729     } else {
730 	pixbuf = gdk_pixbuf_new_from_file_at_size (path, width, height, &error);
731     }
732     // hmmm... from the scale_simple line below, it seems that the above two
733     //         functions will do a g_object_ref on the returned pixbuf...
734 
735 
736     // Gdkpixbuf Bug workaround
737     // (necessary for GTK-2, still necessary in GTK-3.8)
738     // xpm icons not resized. Need the extra scale_simple.
739 
740 
741     //if (pixbuf && width > 0 && gdk_pixbuf_get_width(pixbuf) != width){
742     //if (pixbuf && strstr(path, ".xpm")){
743     if (pixbuf && width > 0 && strstr(path, ".xpm")) {
744 	NOOP(stderr, "** resizing %s\n", path);
745 	GdkPixbuf *pix = gdk_pixbuf_scale_simple (pixbuf, width, height, GDK_INTERP_HYPER);
746 	g_object_unref(pixbuf);
747 	pixbuf = pix;
748 
749     }
750 
751     if(error && !strstr(path, ".cache/rfm/thumbnails")) {
752 	    DBG ("pixbuf_from_file() %s:%s\n", error->message, path);
753 	    g_error_free (error);
754     }
755     return pixbuf;
756 }
757 
758 static pthread_mutex_t pixbuf_mutex = PTHREAD_MUTEX_INITIALIZER;
759 
760 GdkPixbuf *
rfm_pixbuf_new_from_file(const gchar * path,gint width,gint height)761 rfm_pixbuf_new_from_file (const gchar *path, gint width, gint height){
762     if (!path) return NULL;
763     if (!g_file_test(path, G_FILE_TEST_EXISTS)) return NULL;
764     GdkPixbuf *pixbuf;
765     void *arg[3];
766     arg[0] = (void *)path;
767     arg[1] = GINT_TO_POINTER(width);
768     arg[2] = GINT_TO_POINTER(height);
769 #if 1
770     // This gives priority to gtk thread...
771     static gboolean gtk_thread_wants_lock = FALSE;
772     if (rfm_get_gtk_thread() == g_thread_self()) {
773         gtk_thread_wants_lock = TRUE;
774     } else {
775         // hold your horses...
776         while (gtk_thread_wants_lock) rfm_threadwait();
777     }
778     pthread_mutex_lock(&pixbuf_mutex);
779 
780     //  g_warning("pthread_mutex_trylock(&pixbuf_mutex) on gtk thread failed for %s\n",
781 
782     pixbuf = pixbuf_from_file_f(arg);
783     pthread_mutex_unlock(&pixbuf_mutex);
784     if (rfm_get_gtk_thread() == g_thread_self()) gtk_thread_wants_lock = FALSE;
785 
786 #else
787     // This sends everything to the gtk thread...
788 	pixbuf = rfm_context_function(pixbuf_from_file_f, arg);
789 #endif
790 
791     return pixbuf;
792 }
793 
794 #if 10
795 // Bug workaround in opensuse 12.3.
796 // Something with their gdk/cairo construction
797 // is broken... See workaround below...
798 //
799 static void *
insert_pixbuf_tag_f(void * data)800 insert_pixbuf_tag_f (void *data){
801     void **arg = data;
802     const GdkPixbuf *tag = arg[0];
803     GdkPixbuf *composite_pixbuf = arg[1];
804     gchar *where = arg[2];
805     double *scale_factor = arg[3];
806     gint overall_alpha = GPOINTER_TO_INT(arg[4]);
807     g_free(arg);
808 
809     gdouble scale_x = 1.0 / (*scale_factor);
810     gdouble scale_y = 1.0 / (*scale_factor);
811     gint width = gdk_pixbuf_get_width(tag);
812     gint height = gdk_pixbuf_get_height(tag);
813 
814     GdkPixbuf *tag_s = gdk_pixbuf_scale_simple(tag,
815 	    floor(scale_x*width), floor(scale_y*height),
816 	    GDK_INTERP_BILINEAR);
817 
818 
819     gint dest_width = gdk_pixbuf_get_width (composite_pixbuf);
820     gint dest_height = gdk_pixbuf_get_height (composite_pixbuf);
821     gint s_width = gdk_pixbuf_get_width (tag);
822     gint s_height = gdk_pixbuf_get_height (tag);
823     // "SW"
824     //gint dest_x = 0;
825     //gint dest_y = 0;
826     s_width = ((gdouble) s_width) * scale_x;
827     s_height = ((gdouble) s_height) * scale_y;
828 
829     // default SW
830     gdouble offset_x = 0.0;
831     gdouble offset_y = dest_height - s_height;
832 
833     if(strcmp (where, "SW") == 0) {
834         offset_x = dest_width - s_width;
835     } else if(strcmp (where, "SE") == 0) {
836         offset_x = dest_width - s_width;
837     } else if(strcmp (where, "NW") == 0) {
838         offset_y = 0.0;
839     } else if(strcmp (where, "NE") == 0) {
840         offset_x = dest_width - s_width;
841         offset_y = 0.0;
842     } else if(strcmp (where, "C") == 0) {
843         offset_x = (dest_width - s_width) / 2;
844         offset_y = (dest_height - s_height) / 2;
845     } else if(strcmp (where, "SC") == 0) {
846         offset_x = (dest_width - s_width) / 2;
847     } else if (strcmp (where, "NC") == 0) {
848         offset_y = 0.0;
849         offset_x = (dest_width - s_width) / 2;
850     }
851 
852 
853 
854     cairo_t   *pixbuf_context = pixbuf_cairo_create(composite_pixbuf);
855 
856     // This proved necessary in opensuse-12.3,
857     // but not in gentoo nor ubuntu. Go figure...
858 	gdk_cairo_set_source_pixbuf(pixbuf_context, composite_pixbuf,0,0);
859 	cairo_paint_with_alpha(pixbuf_context, 1.0);
860 
861     gdk_cairo_set_source_pixbuf(pixbuf_context, tag_s, offset_x,offset_y);
862     cairo_paint_with_alpha(pixbuf_context, (double)overall_alpha/255.0);
863     pixbuf_cairo_destroy(pixbuf_context, composite_pixbuf);
864     g_object_unref(tag_s);
865 
866     g_free(scale_factor);
867     g_free(where);
868     return NULL;
869 }
870 
871 
872 #else
873 // This is the old method. Using cairo is a bit less bug prone:
874 // not really bug free. Does not work right in opensuse12.3
875 // without a slight workaround...
876 <snip>
877 }
878 #endif
879 gboolean
880 rfm_insert_pixbuf_tag (GdkPixbuf *tag, GdkPixbuf *composite_pixbuf,
881 	const gchar *where, gdouble scale_factor, gint overall_alpha){
882     if (!tag || !composite_pixbuf || !GDK_IS_PIXBUF(composite_pixbuf) || !where) {
883 	return FALSE;
884     }
885     void **arg = (void **)malloc(5*sizeof(void *));
886     if (!arg) g_error("malloc: %s\n", strerror(errno));
887     arg[0] = tag;
888     arg[1] = composite_pixbuf;
889     arg[2] = g_strdup(where);
890     arg[3] = (gdouble *)malloc(sizeof(gdouble));
891     if (!arg[3]) g_error("malloc: %s\n", strerror(errno));
892     memcpy(arg[3], &scale_factor, sizeof(gdouble));
893     arg[4] = GINT_TO_POINTER(overall_alpha);
894 
895     if (rfm_get_gtk_thread() != g_thread_self()){
896 	rfm_context_function(insert_pixbuf_tag_f, arg);
897     } else {
898 	insert_pixbuf_tag_f(arg);
899     }
900     return TRUE;
901 }
902 
903 
904 static void *
905 duplicate_pixbuf(void *data){
906     GdkPixbuf *pixbuf = data;
907     if (!pixbuf || !G_IS_OBJECT(pixbuf)) {
908 	return NULL;
909     }
910     GdkPixbuf *new_pixbuf = gdk_pixbuf_copy (pixbuf);
911     return new_pixbuf;
912 }
913 
914 GdkPixbuf *
915 rfm_pixbuf_duplicate(GdkPixbuf *pixbuf){
916     if (!pixbuf) return NULL;
917     GdkPixbuf *new_pixbuf = NULL;
918     if (rfm_get_gtk_thread() != g_thread_self()){
919 	//g_mutex_lock (pixbuf_hash_mutex);
920 	new_pixbuf = rfm_context_function(duplicate_pixbuf, pixbuf);
921     } else {
922 	//while (!g_mutex_trylock (pixbuf_hash_mutex)) gtk_main_iteration();
923 	new_pixbuf = duplicate_pixbuf(pixbuf);
924     }
925     //g_mutex_unlock (pixbuf_hash_mutex);
926     return new_pixbuf;
927 }
928 
929 
930 
931 ////////////////   module wraparounds:
932 //
933 
934 gint
935 rfm_svg_supported (void) {
936     void *value = rfm_void (RFM_MODULE_DIR, "icons", "svg_supported");
937     return GPOINTER_TO_INT (value);
938 }
939 
940 ///////////////////////  primary_icon_resolve.i   /////////////////////
941 
942 
943 static const gchar *
944 get_type_icon_id(record_entry_t *en){
945     if(IS_BROKEN_LNK (en->type)) return ("xffm/stock_missing-image");
946     if(IS_UP_TYPE (en->type)) {
947 	// When up item is not a directory.
948         return "xffm/stock_go-up";
949     }
950     if (IS_SDIR (en->type)){
951 	// No access directory_:
952         if(IS_NOACCESS_TYPE (en->type)) {
953 	    return "xffm/stock_directory/compositeC/emblem_unreadable";
954         }
955 	// Invariant under write or no write flag:
956 	if(strcmp (en->path, g_get_home_dir ()) == 0) {
957 	    return "xffm/stock_home";
958 	} else if(strcmp (en->path, "/") == 0){
959 		return "xffm/stock_directory";
960 	} else if(
961 		(strstr (en->path, "cdrom") ||
962 		 strstr (en->path, "cdrw") ||
963 		 strstr (en->path, "dvd"))
964 		 &&  FSTAB_is_in_fstab(en->path))
965 	{
966 	    return "xffm/emblem_disk";
967 	}
968 	else if(IS_NOWRITE_TYPE (en->type)) {
969 	    // No write directory
970 	    return "xffm/stock_directory";
971         } else if(strcmp (en->path, "/") == 0){
972 		return "xffm/stock_directory";
973 	} else if (getenv("RFM_DESKTOP_DIR") && strcmp(en->path, getenv("RFM_DESKTOP_DIR"))==0){
974 		return "xffm/emblem_desktop";
975 	} else if(strcmp (en->path, "/") == 0){
976 		return "xffm/stock_directory";
977 	}
978 
979 	//write ok
980 	return "xffm/stock_directory/compositeSE/emblem_write-ok";
981     }
982     if (IS_SCHR(en->type)) return ("xffm/emblem_chardevice");
983     if (IS_SBLK(en->type)) return ("xffm/emblem_blockdevice");
984     if (IS_SFIFO(en->type)) return ("xffm/emblem_fifo");
985     if (IS_SSOCK(en->type)) return ("xffm/emblem_network/compositeSE/emblem_fifo");
986     if (IS_PARTITION_TYPE(en->type)) return ("xffm/emblem_harddisk");
987 //    if (IS_SLNK(en->type)) return g_strdup("inode/symlink");
988 //    if ((en->type)) return g_strdup("inode/virtual-disk");
989     return NULL;
990 
991 }
992 
993 
994 // Partition greenball resolution is now set in fstab module.
995 static gchar *greenball_id(view_t *view_p, record_entry_t *en, gchar *icon_id){
996     if (!icon_id || !en) return NULL;
997     /* block controlled in fstab plugin: */
998     gboolean valid_mount_view =
999 	(view_p && (!view_p->en || view_p->en->module ||  IS_LOCAL_TYPE(view_p->en->type)));
1000     gboolean valid_mount_point =
1001 	(en->path && IS_SDIR(en->type));
1002 //	(en->path && (IS_SDIR(en->type) || IS_PARTITION_TYPE (en->type)));
1003     if (valid_mount_point && valid_mount_view){
1004 	gint mounted = GPOINTER_TO_INT(rfm_natural(PLUGIN_DIR, "fstab", en, "entry_is_mounted"));
1005 	if (mounted<0) {
1006 	    gchar *g = g_strconcat (icon_id, "/compositeNW/emblem_unreadable", NULL);
1007 	    g_free(icon_id);
1008 	    icon_id = g;
1009 	} else	if (mounted>0) {
1010 	    gchar *g = g_strconcat (icon_id, "/compositeNW/emblem_greenball", NULL);
1011 	    g_free(icon_id);
1012 	    icon_id = g;
1013 	} else if (rfm_natural(PLUGIN_DIR, "fstab", en->path, "is_in_fstab")){
1014 	    gchar *g = g_strconcat (icon_id, "/compositeNW/emblem_redball", NULL);
1015 	    g_free(icon_id);
1016 	    icon_id = g;
1017 	}
1018     }
1019     return icon_id;
1020 }
1021 
1022 gboolean
1023 rfm_save_icon_id_to_cache(record_entry_t *en, const gchar *id){
1024     if (en && (IS_UP_TYPE(en->type) || IS_DUMMY_TYPE(en->type))) return FALSE;
1025     const gchar *path;
1026     if (en) path = en->path;
1027     else path = "RODENT_ROOT";
1028 
1029     DBHashTable *icon_id_cache;
1030     gchar *g;
1031     if(getenv("RFM_CONTENT_FOLDER_ICONS") && strlen(getenv("RFM_CONTENT_FOLDER_ICONS"))){
1032 	g = g_build_filename (ICON_ID_DBH_FILE, NULL);
1033     } else {
1034 	g = g_build_filename (ICON_ID_PLAIN_DBH_FILE, NULL);
1035     }
1036     TRACE("opening %s...\n",g);
1037     if (!g_file_test(g, G_FILE_TEST_EXISTS)){
1038 	unsigned char key_length=11;
1039         gchar *directory = g_path_get_dirname(g);
1040         if (!g_file_test(directory, G_FILE_TEST_IS_DIR)){
1041             g_mkdir_with_parents(directory, 0700);
1042         }
1043         g_free(directory);
1044         icon_id_cache = dbh_new (g, &key_length, DBH_CREATE|DBH_PARALLEL_SAFE|DBH_THREAD_SAFE);
1045     } else {
1046 	icon_id_cache = dbh_new (g, NULL, DBH_PARALLEL_SAFE|DBH_THREAD_SAFE);
1047     }
1048     TRACE("open %s.\n",g);
1049     if (!icon_id_cache){
1050 	DBG("cannot open %s for write.\n", g);
1051 	g_free(g);
1052 	return FALSE;
1053     }
1054     dbh_set_parallel_lock_timeout(icon_id_cache, 3);
1055     GString *gs = g_string_new (path);
1056     gchar *key = g_strdup_printf ("%10u", g_string_hash (gs));
1057     dbh_set_key  (icon_id_cache,  (unsigned char *)key);
1058     dbh_set_data (icon_id_cache, (void *)id, strlen(id)+1);
1059     g_string_free (gs, TRUE);
1060     g_free(key);
1061     gboolean retval = TRUE;
1062     if (dbh_update (icon_id_cache) == 0){
1063 	DBG("cannot write record %s to cache: %s.\n", path, g);
1064 	retval = FALSE;
1065     }
1066     dbh_close(icon_id_cache);
1067     g_free(g);
1068     return retval;
1069 }
1070 
1071 gchar *
1072 rfm_get_icon_id_from_cache(record_entry_t *en){
1073     //return NULL;
1074     if (en && (IS_UP_TYPE(en->type) || IS_DUMMY_TYPE(en->type))) return NULL;
1075     const gchar *path;
1076     if (en) path = en->path;
1077     else path = "RODENT_ROOT";
1078 
1079     DBHashTable *icon_id_cache;
1080     gchar *cache_value=NULL;
1081     gchar *g;
1082     if(getenv("RFM_CONTENT_FOLDER_ICONS") && strlen(getenv("RFM_CONTENT_FOLDER_ICONS"))){
1083 	g = g_build_filename (ICON_ID_DBH_FILE, NULL);
1084     } else {
1085 	g = g_build_filename (ICON_ID_PLAIN_DBH_FILE, NULL);
1086     }
1087     if (!g_file_test(g, G_FILE_TEST_EXISTS)){
1088 	g_free(g);
1089 	return FALSE;
1090     }
1091     TRACE("opening %s...\n",g);
1092     if((icon_id_cache = dbh_new (g, NULL, DBH_READ_ONLY|DBH_PARALLEL_SAFE|DBH_THREAD_SAFE)) != NULL) {
1093 	dbh_set_parallel_lock_timeout(icon_id_cache, 3);
1094 	GString *gs = g_string_new (path);
1095 	sprintf ((char *)DBH_KEY (icon_id_cache), "%10u", g_string_hash (gs));
1096 	g_string_free (gs, TRUE);
1097         TRACE("open load %s...\n",g);
1098 	if (dbh_load (icon_id_cache) != 0){
1099 	    cache_value = g_strdup((gchar *)icon_id_cache->data);
1100 	}
1101 	dbh_close(icon_id_cache);
1102     }
1103     TRACE("open and close %s.\n",g);
1104     g_free(g);
1105     if (cache_value && strlen(cache_value)==0) {
1106 	g_free(cache_value);
1107 	return NULL;
1108     }
1109     return cache_value;
1110 }
1111 
1112 gchar *
1113 rfm_get_entry_icon_id(view_t *view_p, record_entry_t *en, gboolean magic_icon){
1114     if (!en) return g_strdup("xffm/emblem_computer");
1115     const gchar *id = NULL;
1116 
1117     // Modules may override icon resolution.
1118     if (en->module){
1119 	id = rfm_natural (PLUGIN_DIR, en->module, en, "item_icon_id");
1120         // if module does not resolve icon, proceed as normal.
1121         if(id) {
1122 	    NOOP("rfm_get_entry_icon_id(): %s: %s\n", en->path, id);
1123 	    return greenball_id(view_p, en, g_strdup(id));
1124         }
1125 	NOOP("module: %s does not resolve icon for %s\n", en->module, en->path);
1126     }
1127 
1128 #if 0
1129     if (!IS_LOCAL_TYPE(en->type) || en->module)
1130     {
1131 	// Remote files or module items will never be done magic.
1132 	magic_icon = FALSE;
1133     }
1134     if (!magic_icon ) {
1135 	// valid view? directory type icon?
1136 	if (view_p->en && IS_LOCAL_TYPE(view_p->en->type) && IS_SDIR(en->type)){
1137 	    id = get_plain_icon_id(en);
1138 	    return greenball_id(view_p, en, g_strdup(id));
1139 	}
1140 	gchar *cache_value=get_icon_id_from_cache(en);
1141 	if (cache_value) return cache_value;
1142 	id = get_plain_icon_id (en);
1143 	// remote file but valid view entry?
1144 	// (this does not do the trick...)
1145 	//if (IS_SDIR(en->type)) return greenball_id(view_p, en, g_strdup(id));
1146 	return g_strdup(id);
1147     }
1148 #endif
1149 
1150     // Try to resolve from readdir type information first.
1151     id = get_type_icon_id(en);
1152     if (id) {
1153 	// greenball resolution
1154 	//save_icon_id_to_cache(en, id);
1155 	return  greenball_id(view_p, en, g_strdup(id));
1156     }
1157 
1158     // We need the stat record now.
1159     if (!en->st){
1160         DBG("rfm_get_entry_icon_id(): no stat record for %s\n", en->path);
1161         return (g_strdup("xffm/stock_dialog-warning"));
1162     }
1163 
1164     if (!en->st->st_blksize && !en->st->st_mtime){
1165 	DBG("mime magic will not work if stat record is not initialized.\n");
1166 	return g_strdup("xffm/stock_file/compositeC/stock_dialog-question");
1167     }
1168 
1169     // Try to get a valid extension mimetype first.
1170     g_free(en->mimetype);
1171     en->mimetype = MIME_type(en->path, en->st);
1172     if (!en->mimetype) {
1173 	    en->mimetype = g_strdup(_("unknown"));
1174     }
1175 
1176     // Only in the event that a valid mime type is not found,
1177     // and magic option is set, do magic.
1178     if (magic_icon && strcmp(en->mimetype, _("unknown"))==0) {
1179 	// Does the user have read permission for the file?
1180 	// Mime magic will not work otherwise...
1181 	// We need a valid stat record for this.
1182 	g_free(en->mimemagic);
1183 	if (rfm_read_ok_path(en->path)) {
1184 	    // Magic at this step as a last resort
1185 	    en->mimemagic = rfm_rational(RFM_MODULE_DIR, "mime", en, "mime_magic", "mime_function");
1186 	    if (!en->mimemagic) en->mimemagic = g_strdup(_("unknown"));
1187 	} else {
1188 	    en->mimemagic = g_strdup(_("No Read Permission"));
1189 	}
1190     }
1191 
1192     // Resolve icon id from mimetype or mimemagic.
1193     if (en->mimetype && strcmp(en->mimetype, _("unknown"))){
1194 	id = en->mimetype;
1195     }
1196     if (!id) {
1197 	id = en->mimemagic;
1198     }
1199     // Override of particular mimetypes
1200     if (!id || strcmp(id, _("unknown"))==0) {
1201 	return g_strdup("xffm/stock_file");
1202     }
1203     if (strcmp(id, _("No Read Permission"))==0){
1204 	return g_strdup("xffm/stock_file/compositeC/emblem_unreadable");
1205     }
1206     // Override dotdesktop icons with module icon determination.
1207     if (strcmp("application/x-desktop", id)==0) {
1208 	const gchar *icon_name=rfm_natural(PLUGIN_DIR, "dotdesktop", en, "item_icon_id");
1209 	if (icon_name) {
1210 	    //save_icon_id_to_cache(en, icon_name);
1211 	    return g_strdup(icon_name);
1212 	}
1213     }
1214     //save_icon_id_to_cache(en, id);
1215 
1216 #if 0
1217     // This would need fine tuning...
1218     if (!IS_LOCAL_TYPE(en->type)){
1219 	gchar *g = g_strconcat(icon_id, "/compositeC/emblem_shared", NULL);
1220 	g_free(icon_id);
1221 	icon_id = g;
1222     }
1223 #endif
1224     // Greenball resolution
1225     return greenball_id(view_p, en, g_strdup(id));
1226 }
1227 
1228 
1229 void rfm_free_lite_hash(void){
1230     pthread_mutex_lock (&lite_hash_mutex);
1231     if(lite_hash) g_hash_table_destroy(lite_hash);
1232     pthread_mutex_unlock (&lite_hash_mutex);
1233 
1234     if(lite_type_hash) g_hash_table_destroy(lite_type_hash);
1235     if(lite_key_hash) g_hash_table_destroy(lite_key_hash);
1236 }
1237 
1238 
1239 // hmmmmmm serialized....
1240 static void *
1241 get_pixbuf_f(void *data){
1242     void **arg=data;
1243     const gchar *key = (const gchar *)arg[0];
1244     gint size = GPOINTER_TO_INT(arg[1]);
1245     GdkPixbuf *pixbuf = get_pixbuf(key, size, FALSE); //refs
1246     return pixbuf;
1247 }
1248 
1249 GdkPixbuf *
1250 rfm_get_pixbuf (const gchar * key, gint size) {
1251     void *arg[2];
1252     arg[0] = (void *)key;
1253     arg[1] = GINT_TO_POINTER(size);
1254     GdkPixbuf *pixbuf = rfm_context_function(get_pixbuf_f, arg);
1255     return pixbuf;
1256 }
1257 
1258 // find in hash : refs
1259 // put in hash: refs not
1260 // get: refs
1261 // create: refs
1262