1 /*
2 * ROX-Filer, filer for the ROX desktop project
3 * Copyright (C) 2006, Thomas Leonard and others (see changelog for details).
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 /* display.c - code for arranging and displaying file items */
21
22 #include "config.h"
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <math.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <sys/param.h>
30 #include <unistd.h>
31 #include <time.h>
32 #include <ctype.h>
33
34 #include <gtk/gtk.h>
35 #include <gdk/gdkx.h>
36 #include <gdk/gdkkeysyms.h>
37
38 #include "global.h"
39
40 #include "main.h"
41 #include "filer.h"
42 #include "display.h"
43 #include "support.h"
44 #include "gui_support.h"
45 #include "pixmaps.h"
46 #include "menu.h"
47 #include "dnd.h"
48 #include "run.h"
49 #include "mount.h"
50 #include "type.h"
51 #include "options.h"
52 #include "action.h"
53 #include "minibuffer.h"
54 #include "dir.h"
55 #include "diritem.h"
56 #include "fscache.h"
57 #include "view_iface.h"
58 #include "xtypes.h"
59
60 #define HUGE_WRAP (1.5 * o_large_width.int_value)
61
62 /* Options bits */
63 static Option o_display_caps_first;
64 static Option o_display_dirs_first;
65 Option o_display_size;
66 Option o_display_details;
67 Option o_display_sort_by;
68 static Option o_large_width;
69 Option o_small_width;
70 Option o_display_show_hidden;
71 Option o_display_show_thumbs;
72 Option o_display_show_headers;
73 Option o_display_show_full_type;
74 Option o_display_inherit_options;
75 static Option o_filer_change_size_num;
76 Option o_vertical_order_small, o_vertical_order_large;
77 Option o_xattr_show;
78
79 /* Static prototypes */
80 static void display_details_set(FilerWindow *filer_window, DetailsType details);
81 static void display_style_set(FilerWindow *filer_window, DisplayStyle style);
82 static void options_changed(void);
83 static char *details(FilerWindow *filer_window, DirItem *item);
84 static void display_set_actual_size_real(FilerWindow *filer_window);
85
86 /****************************************************************
87 * EXTERNAL INTERFACE *
88 ****************************************************************/
89
display_init()90 void display_init()
91 {
92 option_add_int(&o_display_caps_first, "display_caps_first", FALSE);
93 option_add_int(&o_display_dirs_first, "display_dirs_first", FALSE);
94 option_add_int(&o_display_size, "display_icon_size", AUTO_SIZE_ICONS);
95 option_add_int(&o_display_details, "display_details", DETAILS_NONE);
96 option_add_int(&o_display_sort_by, "display_sort_by", SORT_NAME);
97 option_add_int(&o_large_width, "display_large_width", 155);
98 option_add_int(&o_small_width, "display_small_width", 250);
99 option_add_int(&o_display_show_hidden, "display_show_hidden", FALSE);
100 option_add_int(&o_display_show_thumbs, "display_show_thumbs", FALSE);
101 option_add_int(&o_display_show_headers, "display_show_headers", TRUE);
102 option_add_int(&o_display_show_full_type, "display_show_full_type", FALSE);
103 option_add_int(&o_display_inherit_options,
104 "display_inherit_options", FALSE);
105 option_add_int(&o_filer_change_size_num, "filer_change_size_num", 30);
106 option_add_int(&o_vertical_order_small, "vertical_order_small", FALSE);
107 option_add_int(&o_vertical_order_large, "vertical_order_large", FALSE);
108 option_add_int(&o_xattr_show, "xattr_show", TRUE);
109
110 option_add_notify(options_changed);
111 }
112
draw_emblem_on_icon(GdkWindow * window,GtkStyle * style,const char * stock_id,int * x,int y)113 void draw_emblem_on_icon(GdkWindow *window, GtkStyle *style,
114 const char *stock_id,
115 int *x, int y)
116 {
117 GtkIconSet *icon_set;
118 GdkPixbuf *pixbuf;
119
120 icon_set = gtk_style_lookup_icon_set(style,
121 stock_id);
122 if (icon_set)
123 {
124 pixbuf = gtk_icon_set_render_icon(icon_set,
125 style,
126 GTK_TEXT_DIR_LTR,
127 GTK_STATE_NORMAL,
128 mount_icon_size,
129 NULL,
130 NULL);
131 }
132 else
133 {
134 pixbuf=im_unknown->pixbuf;
135 g_object_ref(pixbuf);
136 }
137
138 gdk_pixbuf_render_to_drawable_alpha(pixbuf,
139 window,
140 0, 0, /* src */
141 *x, y, /* dest */
142 -1, -1,
143 GDK_PIXBUF_ALPHA_FULL, 128, /* (unused) */
144 GDK_RGB_DITHER_NORMAL, 0, 0);
145
146 *x+=gdk_pixbuf_get_width(pixbuf)+1;
147 g_object_unref(pixbuf);
148 }
149
150 /* Draw this icon (including any symlink or mount symbol) inside the
151 * given rectangle.
152 */
draw_huge_icon(GdkWindow * window,GtkStyle * style,GdkRectangle * area,DirItem * item,MaskedPixmap * image,gboolean selected,GdkColor * color)153 void draw_huge_icon(GdkWindow *window, GtkStyle *style, GdkRectangle *area,
154 DirItem *item, MaskedPixmap *image, gboolean selected,
155 GdkColor *color)
156 {
157 int width, height;
158 int image_x;
159 int image_y;
160 GdkPixbuf *pixbuf;
161
162 if (!image)
163 return;
164
165 width = image->huge_width;
166 height = image->huge_height;
167 image_x = area->x + ((area->width - width) >> 1);
168 image_y = MAX(0, area->height - height - 6);
169
170 pixbuf = selected
171 ? create_spotlight_pixbuf(image->huge_pixbuf, color)
172 : image->huge_pixbuf;
173
174 gdk_pixbuf_render_to_drawable_alpha(
175 pixbuf,
176 window,
177 0, 0, /* src */
178 image_x, area->y + image_y, /* dest */
179 width, height,
180 GDK_PIXBUF_ALPHA_FULL, 128, /* (unused) */
181 GDK_RGB_DITHER_NORMAL, 0, 0);
182
183 if (selected)
184 g_object_unref(pixbuf);
185
186 if (item->flags & ITEM_FLAG_MOUNT_POINT)
187 {
188 const char *mp = item->flags & ITEM_FLAG_MOUNTED
189 ? ROX_STOCK_MOUNTED
190 : ROX_STOCK_MOUNT;
191 draw_emblem_on_icon(window, style, mp, &image_x, area->y + 2);
192 }
193 if (item->flags & ITEM_FLAG_SYMLINK)
194 {
195 draw_emblem_on_icon(window, style, ROX_STOCK_SYMLINK,
196 &image_x, area->y + 2);
197 }
198 if ((item->flags & ITEM_FLAG_HAS_XATTR) && o_xattr_show.int_value)
199 {
200 draw_emblem_on_icon(window, style, ROX_STOCK_XATTR,
201 &image_x, area->y + 2);
202 }
203 }
204
205 /* Draw this icon (including any symlink or mount symbol) inside the
206 * given rectangle.
207 */
draw_large_icon(GdkWindow * window,GtkStyle * style,GdkRectangle * area,DirItem * item,MaskedPixmap * image,gboolean selected,GdkColor * color)208 void draw_large_icon(GdkWindow *window,
209 GtkStyle *style,
210 GdkRectangle *area,
211 DirItem *item,
212 MaskedPixmap *image,
213 gboolean selected,
214 GdkColor *color)
215 {
216 int width;
217 int height;
218 int image_x;
219 int image_y;
220 GdkPixbuf *pixbuf;
221
222 if (!image)
223 return;
224
225 width = MIN(image->width, ICON_WIDTH);
226 height = MIN(image->height, ICON_HEIGHT);
227 image_x = area->x + ((area->width - width) >> 1);
228 image_y = MAX(0, area->height - height - 6);
229
230 pixbuf = selected
231 ? create_spotlight_pixbuf(image->pixbuf, color)
232 : image->pixbuf;
233
234 gdk_pixbuf_render_to_drawable_alpha(
235 pixbuf,
236 window,
237 0, 0, /* src */
238 image_x, area->y + image_y, /* dest */
239 width, height,
240 GDK_PIXBUF_ALPHA_FULL, 128, /* (unused) */
241 GDK_RGB_DITHER_NORMAL, 0, 0);
242
243 if (selected)
244 g_object_unref(pixbuf);
245
246 if (item->flags & ITEM_FLAG_MOUNT_POINT)
247 {
248 const char *mp = item->flags & ITEM_FLAG_MOUNTED
249 ? ROX_STOCK_MOUNTED
250 : ROX_STOCK_MOUNT;
251 draw_emblem_on_icon(window, style, mp, &image_x, area->y + 2);
252 }
253 if (item->flags & ITEM_FLAG_SYMLINK)
254 {
255 draw_emblem_on_icon(window, style, ROX_STOCK_SYMLINK,
256 &image_x, area->y + 2);
257 }
258 if ((item->flags & ITEM_FLAG_HAS_XATTR) && o_xattr_show.int_value)
259 {
260 draw_emblem_on_icon(window, style, ROX_STOCK_XATTR,
261 &image_x, area->y + 2);
262 }
263 }
264
draw_small_icon(GdkWindow * window,GtkStyle * style,GdkRectangle * area,DirItem * item,MaskedPixmap * image,gboolean selected,GdkColor * color)265 void draw_small_icon(GdkWindow *window, GtkStyle *style, GdkRectangle *area,
266 DirItem *item, MaskedPixmap *image, gboolean selected,
267 GdkColor *color)
268 {
269 int width, height, image_x, image_y;
270 GdkPixbuf *pixbuf;
271
272 if (!image)
273 return;
274
275 if (!image->sm_pixbuf)
276 pixmap_make_small(image);
277
278 width = MIN(image->sm_width, SMALL_WIDTH);
279 height = MIN(image->sm_height, SMALL_HEIGHT);
280 image_x = area->x + ((area->width - width) >> 1);
281 image_y = MAX(0, SMALL_HEIGHT - image->sm_height);
282
283 pixbuf = selected
284 ? create_spotlight_pixbuf(image->sm_pixbuf, color)
285 : image->sm_pixbuf;
286
287 gdk_pixbuf_render_to_drawable_alpha(
288 pixbuf,
289 window,
290 0, 0, /* src */
291 image_x, area->y + image_y, /* dest */
292 width, height,
293 GDK_PIXBUF_ALPHA_FULL, 128, /* (unused) */
294 GDK_RGB_DITHER_NORMAL, 0, 0);
295
296 if (selected)
297 g_object_unref(pixbuf);
298
299 if (item->flags & ITEM_FLAG_MOUNT_POINT)
300 {
301 const char *mp = item->flags & ITEM_FLAG_MOUNTED
302 ? ROX_STOCK_MOUNTED
303 : ROX_STOCK_MOUNT;
304 draw_emblem_on_icon(window, style, mp, &image_x, area->y + 2);
305 }
306 if (item->flags & ITEM_FLAG_SYMLINK)
307 {
308 draw_emblem_on_icon(window, style, ROX_STOCK_SYMLINK,
309 &image_x, area->y + 8);
310 }
311 if ((item->flags & ITEM_FLAG_HAS_XATTR) && o_xattr_show.int_value)
312 {
313 draw_emblem_on_icon(window, style, ROX_STOCK_XATTR,
314 &image_x, area->y + 8);
315 }
316 }
317
318 /* The sort functions aren't called from outside, but they are
319 * passed as arguments to display_set_sort_fn().
320 */
321
322 #define IS_A_DIR(item) (item->base_type == TYPE_DIRECTORY && \
323 !(item->flags & ITEM_FLAG_APPDIR))
324
325 #define SORT_DIRS \
326 if (o_display_dirs_first.int_value) { \
327 gboolean id1 = IS_A_DIR(i1); \
328 gboolean id2 = IS_A_DIR(i2); \
329 if (id1 && !id2) return -1; \
330 if (id2 && !id1) return 1; \
331 }
332
sort_by_name(const void * item1,const void * item2)333 int sort_by_name(const void *item1, const void *item2)
334 {
335 const DirItem *i1 = (DirItem *) item1;
336 const DirItem *i2 = (DirItem *) item2;
337 CollateKey *n1 = i1->leafname_collate;
338 CollateKey *n2 = i2->leafname_collate;
339 int retval;
340
341 SORT_DIRS;
342
343 retval = collate_key_cmp(n1, n2, o_display_caps_first.int_value);
344
345 return retval ? retval : strcmp(i1->leafname, i2->leafname);
346 }
347
sort_by_type(const void * item1,const void * item2)348 int sort_by_type(const void *item1, const void *item2)
349 {
350 const DirItem *i1 = (DirItem *) item1;
351 const DirItem *i2 = (DirItem *) item2;
352 MIME_type *m1, *m2;
353
354 int diff = i1->base_type - i2->base_type;
355
356 if (!diff)
357 diff = (i1->flags & ITEM_FLAG_APPDIR)
358 - (i2->flags & ITEM_FLAG_APPDIR);
359 if (diff)
360 return diff > 0 ? 1 : -1;
361
362 m1 = i1->mime_type;
363 m2 = i2->mime_type;
364
365 if (m1 && m2)
366 {
367 diff = strcmp(m1->media_type, m2->media_type);
368 if (!diff)
369 diff = strcmp(m1->subtype, m2->subtype);
370 }
371 else if (m1 || m2)
372 diff = m1 ? 1 : -1;
373 else
374 diff = 0;
375
376 if (diff)
377 return diff > 0 ? 1 : -1;
378
379 return sort_by_name(item1, item2);
380 }
381
sort_by_owner(const void * item1,const void * item2)382 int sort_by_owner(const void *item1, const void *item2)
383 {
384 const DirItem *i1 = (DirItem *) item1;
385 const DirItem *i2 = (DirItem *) item2;
386 const gchar *name1;
387 const gchar *name2;
388
389 if(i1->uid==i2->uid)
390 return sort_by_name(item1, item2);
391
392 name1=user_name(i1->uid);
393 name2=user_name(i2->uid);
394
395 return strcmp(name1, name2);
396 }
397
sort_by_group(const void * item1,const void * item2)398 int sort_by_group(const void *item1, const void *item2)
399 {
400 const DirItem *i1 = (DirItem *) item1;
401 const DirItem *i2 = (DirItem *) item2;
402 const gchar *name1;
403 const gchar *name2;
404
405 if(i1->gid==i2->gid)
406 return sort_by_name(item1, item2);
407
408 name1=group_name(i1->gid);
409 name2=group_name(i2->gid);
410
411 return strcmp(name1, name2);
412 }
413
sort_by_date(const void * item1,const void * item2)414 int sort_by_date(const void *item1, const void *item2)
415 {
416 const DirItem *i1 = (DirItem *) item1;
417 const DirItem *i2 = (DirItem *) item2;
418
419 /* SORT_DIRS; -- too confusing! */
420
421 return i1->mtime < i2->mtime ? -1 :
422 i1->mtime > i2->mtime ? 1 :
423 sort_by_name(item1, item2);
424 }
425
sort_by_size(const void * item1,const void * item2)426 int sort_by_size(const void *item1, const void *item2)
427 {
428 const DirItem *i1 = (DirItem *) item1;
429 const DirItem *i2 = (DirItem *) item2;
430
431 SORT_DIRS;
432
433 return i1->size < i2->size ? -1 :
434 i1->size > i2->size ? 1 :
435 sort_by_name(item1, item2);
436 }
437
display_set_sort_type(FilerWindow * filer_window,SortType sort_type,GtkSortType order)438 void display_set_sort_type(FilerWindow *filer_window, SortType sort_type,
439 GtkSortType order)
440 {
441 if (filer_window->sort_type == sort_type &&
442 filer_window->sort_order == order)
443 return;
444
445 filer_window->sort_type = sort_type;
446 filer_window->sort_order = order;
447
448 view_sort(filer_window->view);
449 }
450
451 /* Change the icon size and style.
452 * force_resize should only be TRUE for new windows.
453 */
display_set_layout(FilerWindow * filer_window,DisplayStyle style,DetailsType details,gboolean force_resize)454 void display_set_layout(FilerWindow *filer_window,
455 DisplayStyle style,
456 DetailsType details,
457 gboolean force_resize)
458 {
459 gboolean style_changed = FALSE;
460
461 g_return_if_fail(filer_window != NULL);
462
463 if (filer_window->display_style_wanted != style
464 || filer_window->details_type != details)
465 {
466 style_changed = TRUE;
467 }
468
469 display_style_set(filer_window, style);
470 display_details_set(filer_window, details);
471
472 /* Recreate layouts because wrapping may have changed */
473 view_style_changed(filer_window->view, VIEW_UPDATE_NAME);
474
475 if (force_resize || o_filer_auto_resize.int_value == RESIZE_ALWAYS
476 || (o_filer_auto_resize.int_value == RESIZE_STYLE && style_changed))
477 {
478 view_autosize(filer_window->view);
479 }
480 }
481
482 /* Set the 'Show Thumbnails' flag for this window */
display_set_thumbs(FilerWindow * filer_window,gboolean thumbs)483 void display_set_thumbs(FilerWindow *filer_window, gboolean thumbs)
484 {
485 if (filer_window->show_thumbs == thumbs)
486 return;
487
488 filer_window->show_thumbs = thumbs;
489
490 view_style_changed(filer_window->view, VIEW_UPDATE_VIEWDATA);
491
492 if (!thumbs)
493 filer_cancel_thumbnails(filer_window);
494
495 filer_set_title(filer_window);
496
497 filer_create_thumbs(filer_window);
498 }
499
display_update_hidden(FilerWindow * filer_window)500 void display_update_hidden(FilerWindow *filer_window)
501 {
502 filer_detach_rescan(filer_window); /* (updates titlebar) */
503
504 display_set_actual_size(filer_window, FALSE);
505 }
506
507 /* Set the 'Show Hidden' flag for this window */
display_set_hidden(FilerWindow * filer_window,gboolean hidden)508 void display_set_hidden(FilerWindow *filer_window, gboolean hidden)
509 {
510 if (filer_window->show_hidden == hidden)
511 return;
512
513 /*
514 filer_window->show_hidden = hidden;
515 */
516 filer_set_hidden(filer_window, hidden);
517
518 display_update_hidden(filer_window);
519 }
520
521 /* Set the 'Filter Directories' flag for this window */
display_set_filter_directories(FilerWindow * filer_window,gboolean filter_directories)522 void display_set_filter_directories(FilerWindow *filer_window, gboolean filter_directories)
523 {
524 if (filer_window->filter_directories == filter_directories)
525 return;
526
527 /*
528 filer_window->show_hidden = hidden;
529 */
530 filer_set_filter_directories(filer_window, filter_directories);
531
532 display_update_hidden(filer_window);
533 }
534
display_set_filter(FilerWindow * filer_window,FilterType type,const gchar * filter_string)535 void display_set_filter(FilerWindow *filer_window, FilterType type,
536 const gchar *filter_string)
537 {
538 if (filer_set_filter(filer_window, type, filter_string))
539 display_update_hidden(filer_window);
540 }
541
542
543 /* Highlight (wink or cursor) this item in the filer window. If the item
544 * isn't already there but we're scanning then highlight it if it
545 * appears later.
546 */
display_set_autoselect(FilerWindow * filer_window,const gchar * leaf)547 void display_set_autoselect(FilerWindow *filer_window, const gchar *leaf)
548 {
549 gchar *new;
550
551 g_return_if_fail(filer_window != NULL);
552 g_return_if_fail(leaf != NULL);
553
554 new = g_strdup(leaf); /* leaf == old value sometimes */
555
556 null_g_free(&filer_window->auto_select);
557
558 if (view_autoselect(filer_window->view, new))
559 g_free(new);
560 else
561 filer_window->auto_select = new;
562 }
563
564 /* Change the icon size (wraps) */
display_change_size(FilerWindow * filer_window,gboolean bigger)565 void display_change_size(FilerWindow *filer_window, gboolean bigger)
566 {
567 DisplayStyle new;
568
569 g_return_if_fail(filer_window != NULL);
570
571 switch (filer_window->display_style)
572 {
573 case LARGE_ICONS:
574 new = bigger ? HUGE_ICONS : SMALL_ICONS;
575 break;
576 case HUGE_ICONS:
577 if (bigger)
578 return;
579 new = LARGE_ICONS;
580 break;
581 default:
582 if (!bigger)
583 return;
584 new = LARGE_ICONS;
585 break;
586 }
587
588 display_set_layout(filer_window, new, filer_window->details_type,
589 FALSE);
590 }
591
display_create_viewdata(FilerWindow * filer_window,DirItem * item)592 ViewData *display_create_viewdata(FilerWindow *filer_window, DirItem *item)
593 {
594 ViewData *view;
595
596 view = g_new(ViewData, 1);
597
598 view->layout = NULL;
599 view->details = NULL;
600 view->image = NULL;
601
602 display_update_view(filer_window, item, view, TRUE);
603
604 return view;
605 }
606
607 /* Set the display style to the desired style. If the desired style
608 * is AUTO_SIZE_ICONS, choose an appropriate size. Also resizes filer
609 * window, if requested.
610 */
display_set_actual_size(FilerWindow * filer_window,gboolean force_resize)611 void display_set_actual_size(FilerWindow *filer_window, gboolean force_resize)
612 {
613 display_set_layout(filer_window, filer_window->display_style_wanted,
614 filer_window->details_type, force_resize);
615 }
616
617
618 /****************************************************************
619 * INTERNAL FUNCTIONS *
620 ****************************************************************/
621
options_changed(void)622 static void options_changed(void)
623 {
624 GList *next;
625
626 for (next = all_filer_windows; next; next = next->next)
627 {
628 FilerWindow *filer_window = (FilerWindow *) next->data;
629 int flags = 0;
630
631 if (o_display_dirs_first.has_changed ||
632 o_display_caps_first.has_changed)
633 view_sort(VIEW(filer_window->view));
634
635 if (o_display_show_headers.has_changed)
636 flags |= VIEW_UPDATE_HEADERS;
637
638 if (o_large_width.has_changed || o_small_width.has_changed)
639 flags |= VIEW_UPDATE_NAME; /* Recreate PangoLayout */
640
641 view_style_changed(filer_window->view, flags);
642 }
643 }
644
645 /* Return a new string giving details of this item, or NULL if details
646 * are not being displayed. If details are not yet available, return
647 * a string of the right length.
648 */
details(FilerWindow * filer_window,DirItem * item)649 static char *details(FilerWindow *filer_window, DirItem *item)
650 {
651 mode_t m = item->mode;
652 guchar *buf = NULL;
653 gboolean scanned = item->base_type != TYPE_UNKNOWN;
654
655 if (filer_window->details_type == DETAILS_NONE)
656 return NULL;
657
658 if (scanned && item->lstat_errno)
659 buf = g_strdup_printf(_("lstat(2) failed: %s"),
660 g_strerror(item->lstat_errno));
661 else if (filer_window->details_type == DETAILS_TYPE)
662 {
663 MIME_type *type = item->mime_type;
664
665 if (!scanned)
666 return g_strdup("application/octet-stream");
667
668 buf = g_strdup_printf("%s/%s",
669 type->media_type, type->subtype);
670 }
671 else if (filer_window->details_type == DETAILS_TIMES)
672 {
673 guchar *ctime, *mtime, *atime;
674
675 ctime = pretty_time(&item->ctime);
676 mtime = pretty_time(&item->mtime);
677 atime = pretty_time(&item->atime);
678
679 buf = g_strdup_printf("a[%s] c[%s] m[%s]", atime, ctime, mtime);
680 g_free(ctime);
681 g_free(mtime);
682 g_free(atime);
683 }
684 else if (filer_window->details_type == DETAILS_PERMISSIONS)
685 {
686 if (!scanned)
687 return g_strdup("---,---,---/--"
688 #ifdef S_ISVTX
689 "-"
690 #endif
691 " 12345678 12345678");
692
693 buf = g_strdup_printf("%s %-8.8s %-8.8s",
694 pretty_permissions(m),
695 user_name(item->uid),
696 group_name(item->gid));
697 }
698 else
699 {
700 if (!scanned)
701 {
702 if (filer_window->display_style == SMALL_ICONS)
703 return g_strdup("1234M");
704 else
705 return g_strdup("1234 bytes");
706 }
707
708 if (item->base_type != TYPE_DIRECTORY)
709 {
710 if (filer_window->display_style == SMALL_ICONS)
711 buf = g_strdup(format_size_aligned(item->size));
712 else
713 buf = g_strdup(format_size(item->size));
714 }
715 else
716 buf = g_strdup("-");
717 }
718
719 return buf;
720 }
721
722 /* Note: Call style_changed after this */
display_details_set(FilerWindow * filer_window,DetailsType details)723 static void display_details_set(FilerWindow *filer_window, DetailsType details)
724 {
725 filer_window->details_type = details;
726 }
727
728 /* Note: Call style_changed after this */
display_style_set(FilerWindow * filer_window,DisplayStyle style)729 static void display_style_set(FilerWindow *filer_window, DisplayStyle style)
730 {
731 filer_window->display_style_wanted = style;
732 display_set_actual_size_real(filer_window);
733 }
734
735 /* Each displayed item has a ViewData structure with some cached information
736 * to help quickly draw the item (eg, the PangoLayout). This function updates
737 * this information.
738 */
display_update_view(FilerWindow * filer_window,DirItem * item,ViewData * view,gboolean update_name_layout)739 void display_update_view(FilerWindow *filer_window,
740 DirItem *item,
741 ViewData *view,
742 gboolean update_name_layout)
743 {
744 DisplayStyle style = filer_window->display_style;
745 int w, h;
746 int wrap_width = -1;
747 char *str;
748 static PangoFontDescription *monospace = NULL;
749 PangoAttrList *list = NULL;
750
751 if (!monospace)
752 monospace = pango_font_description_from_string("monospace");
753
754 if (view->details)
755 {
756 g_object_unref(G_OBJECT(view->details));
757 view->details = NULL;
758 }
759
760 str = details(filer_window, item);
761 if (str)
762 {
763 PangoAttrList *details_list;
764 int perm_offset = -1;
765
766 view->details = gtk_widget_create_pango_layout(
767 filer_window->window, str);
768 g_free(str);
769
770 pango_layout_set_font_description(view->details, monospace);
771 pango_layout_get_size(view->details, &w, &h);
772 view->details_width = w / PANGO_SCALE;
773 view->details_height = h / PANGO_SCALE;
774
775 if (filer_window->details_type == DETAILS_PERMISSIONS)
776 perm_offset = 0;
777 if (perm_offset > -1)
778 {
779 PangoAttribute *attr;
780
781 attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
782
783 perm_offset += 4 * applicable(item->uid, item->gid);
784 attr->start_index = perm_offset;
785 attr->end_index = perm_offset + 3;
786
787 details_list = pango_attr_list_new();
788 pango_attr_list_insert(details_list, attr);
789 pango_layout_set_attributes(view->details,
790 details_list);
791 }
792 }
793
794 if (view->image)
795 {
796 g_object_unref(view->image);
797 view->image = NULL;
798 }
799
800 if (filer_window->show_thumbs && item->base_type == TYPE_FILE /*&&
801 strcmp(item->mime_type->media_type, "image") == 0*/)
802 {
803 const guchar *path;
804
805 path = make_path(filer_window->real_path, item->leafname);
806
807 view->image = g_fscache_lookup_full(pixmap_cache, path,
808 FSCACHE_LOOKUP_ONLY_NEW, NULL);
809 }
810
811 if (!view->image)
812 {
813 view->image = di_image(item);
814 if (view->image)
815 g_object_ref(view->image);
816 }
817
818 if (view->layout && update_name_layout)
819 {
820 g_object_unref(G_OBJECT(view->layout));
821 view->layout = NULL;
822 }
823
824 if (view->layout)
825 {
826 /* Do nothing */
827 }
828 else if (g_utf8_validate(item->leafname, -1, NULL))
829 {
830 view->layout = gtk_widget_create_pango_layout(
831 filer_window->window, item->leafname);
832 pango_layout_set_auto_dir(view->layout, FALSE);
833 }
834 else
835 {
836 PangoAttribute *attr;
837 gchar *utf8;
838
839 utf8 = to_utf8(item->leafname);
840 view->layout = gtk_widget_create_pango_layout(
841 filer_window->window, utf8);
842 g_free(utf8);
843
844 attr = pango_attr_foreground_new(0xffff, 0, 0);
845 attr->start_index = 0;
846 attr->end_index = -1;
847 if (!list)
848 list = pango_attr_list_new();
849 pango_attr_list_insert(list, attr);
850 }
851
852 if (item->flags & ITEM_FLAG_RECENT)
853 {
854 PangoAttribute *attr;
855
856 attr = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
857 attr->start_index = 0;
858 attr->end_index = -1;
859 if (!list)
860 list = pango_attr_list_new();
861 pango_attr_list_insert(list, attr);
862 }
863
864 if (list)
865 pango_layout_set_attributes(view->layout, list);
866
867 if (filer_window->details_type == DETAILS_NONE)
868 {
869 if (style == HUGE_ICONS)
870 wrap_width = HUGE_WRAP * PANGO_SCALE;
871 else if (style == LARGE_ICONS)
872 wrap_width = o_large_width.int_value * PANGO_SCALE;
873 }
874
875 #ifdef USE_PANGO_WRAP_WORD_CHAR
876 pango_layout_set_wrap(view->layout, PANGO_WRAP_WORD_CHAR);
877 #endif
878 if (wrap_width != -1)
879 pango_layout_set_width(view->layout, wrap_width);
880
881 pango_layout_get_size(view->layout, &w, &h);
882 view->name_width = w / PANGO_SCALE;
883 view->name_height = h / PANGO_SCALE;
884 }
885
886 /* Sets display_style from display_style_wanted.
887 * See also display_set_actual_size().
888 */
display_set_actual_size_real(FilerWindow * filer_window)889 static void display_set_actual_size_real(FilerWindow *filer_window)
890 {
891 DisplayStyle size = filer_window->display_style_wanted;
892 int n;
893
894 g_return_if_fail(filer_window != NULL);
895
896 if (size == AUTO_SIZE_ICONS)
897 {
898 n = view_count_items(filer_window->view);
899
900 if (n >= o_filer_change_size_num.int_value)
901 size = SMALL_ICONS;
902 else
903 size = LARGE_ICONS;
904 }
905
906 filer_window->display_style = size;
907 }
908