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