11 static gint filelist_click_row = -1;
13 static void update_progressbar(gfloat val);
15 static gint file_is_hidden(gchar *name);
16 static gint file_is_in_filter(gchar *name);
17 static void add_to_filter(gchar *text, gint add);
19 static gint sort_list_cb(void *a, void *b);
20 static void filelist_read(gchar *path);
22 static gint file_find_closest_unaccounted(gint row, gint count, GList *ignore_list);
24 static void history_menu_select_cb(GtkWidget *widget, gpointer data);
25 static gchar *truncate_hist_text(gchar *t, gint l);
26 static void filelist_set_history(gchar *path);
29 *-----------------------------------------------------------------------------
30 * file status information (private)
31 *-----------------------------------------------------------------------------
34 static void update_progressbar(gfloat val)
36 gtk_progress_bar_update (GTK_PROGRESS_BAR(info_progress_bar), val);
39 void update_status_label(gchar *text)
47 gtk_label_set(GTK_LABEL(info_status), text);
51 if (slideshow_is_running()) ss = _(" Slideshow");
53 count = file_selection_count();
55 buf = g_strdup_printf(_("%d files (%d)%s"), file_count(), count, ss);
57 buf = g_strdup_printf(_("%d files%s"), file_count(), ss);
59 gtk_label_set(GTK_LABEL(info_status), buf);
64 *-----------------------------------------------------------------------------
66 *-----------------------------------------------------------------------------
69 static gint file_is_hidden(gchar *name)
71 if (name[0] != '.') return FALSE;
72 if (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')) return FALSE;
76 static gint file_is_in_filter(gchar *name)
79 if (!filename_filter || file_filter_disable) return TRUE;
81 work = filename_filter;
84 gchar *filter = work->data;
85 gint lf = strlen(filter);
86 gint ln = strlen(name);
89 if (strncasecmp(name + ln - lf, filter, lf) == 0) return TRUE;
97 static void add_to_filter(gchar *text, gint add)
99 if (add) filename_filter = g_list_append(filename_filter, g_strdup(text));
102 void rebuild_file_filter()
106 g_list_foreach(filename_filter,(GFunc)g_free,NULL);
107 g_list_free(filename_filter);
108 filename_filter = NULL;
111 add_to_filter(".jpg", filter_include_jpg);
112 add_to_filter(".jpeg", filter_include_jpg);
113 add_to_filter(".xpm", filter_include_xpm);
114 add_to_filter(".tif", filter_include_tif);
115 add_to_filter(".tiff", filter_include_tif);
116 add_to_filter(".gif", filter_include_gif);
117 add_to_filter(".png", filter_include_png);
118 add_to_filter(".ppm", filter_include_ppm);
119 add_to_filter(".pgm", filter_include_pgm);
120 add_to_filter(".pcx", filter_include_pcx);
121 add_to_filter(".bmp", filter_include_bmp);
125 gchar *buf = g_strdup(custom_filter);
127 gchar *pos_ptr_e = buf;
128 while(pos_ptr_e[0] != '\0')
130 pos_ptr_b = pos_ptr_e;
131 while (pos_ptr_e[0] != ';' && pos_ptr_e[0] != '\0') pos_ptr_e++;
132 if (pos_ptr_e[0] == ';')
137 add_to_filter(pos_ptr_b, TRUE);
144 *-----------------------------------------------------------------------------
145 * load file list (private)
146 *-----------------------------------------------------------------------------
149 static gint sort_list_cb(void *a, void *b)
151 return strcmp((gchar *)a, (gchar *)b);
154 static void filelist_read(gchar *path)
158 struct stat ent_sbuf;
160 if((dp = opendir(path))==NULL)
166 g_list_foreach(dir_list,(GFunc)g_free,NULL);
167 g_list_free(dir_list);
170 g_list_foreach(file_list,(GFunc)g_free,NULL);
171 g_list_free(file_list);
174 while ((dir = readdir(dp)) != NULL)
176 /* skips removed files */
179 gchar *name = dir->d_name;
180 if (show_dot_files || !file_is_hidden(name))
182 gchar *filepath = g_strconcat(path, "/", name, NULL);
183 if (stat(filepath,&ent_sbuf) >= 0 && S_ISDIR(ent_sbuf.st_mode))
185 dir_list = g_list_prepend(dir_list, g_strdup(name));
189 if (file_is_in_filter(name))
190 file_list = g_list_prepend(file_list, g_strdup(name));
199 dir_list = g_list_sort(dir_list, (GCompareFunc) sort_list_cb);
200 file_list = g_list_sort(file_list, (GCompareFunc) sort_list_cb);
204 *-----------------------------------------------------------------------------
205 * file list utilities to retrieve information (public)
206 *-----------------------------------------------------------------------------
211 return g_list_length(file_list);
214 gint file_selection_count()
217 GList *work = GTK_CLIST(file_clist)->selection;
221 if (debug) printf("s = %d\n", GPOINTER_TO_INT(work->data));
225 if (debug) printf("files selected = %d\n", count);
230 gint find_file_in_list(gchar *path)
232 GList *work = file_list;
237 if (!path) return -1;
239 buf = remove_level_from_path(path);
240 if (strcmp(buf, current_path) != 0)
247 name = filename_from_path(path);
251 if (strcmp(name, work->data) == 0) return count;
258 gchar *file_get_path(gint row)
261 gchar *name = gtk_clist_get_row_data(GTK_CLIST(file_clist), row);
263 if (name) path = g_strconcat(current_path, "/", name, NULL);
268 gint file_is_selected(gint row)
270 GList *work = GTK_CLIST(file_clist)->selection;
274 if (GPOINTER_TO_INT(work->data) == row) return TRUE;
282 *-----------------------------------------------------------------------------
283 * utilities to retrieve list of selected files (public)
284 *-----------------------------------------------------------------------------
287 GList *file_get_selected_list()
290 GList *work = GTK_CLIST(file_clist)->selection;
294 gchar *name = gtk_clist_get_row_data(GTK_CLIST(file_clist),
295 GPOINTER_TO_INT(work->data));
296 list = g_list_prepend(list, g_strconcat(current_path, "/", name, NULL));
300 list = g_list_reverse(list);
305 void free_selected_list(GList *list)
307 g_list_foreach(list, (GFunc)g_free, NULL);
311 gint file_clicked_is_selected()
313 return file_is_selected(filelist_click_row);
316 gchar *file_clicked_get_path()
318 return file_get_path(filelist_click_row);
322 *-----------------------------------------------------------------------------
323 * image change routines
324 *-----------------------------------------------------------------------------
327 void file_image_change_to(gint row)
329 gtk_clist_unselect_all(GTK_CLIST(file_clist));
330 gtk_clist_select_row(GTK_CLIST(file_clist), row, -1);
331 if (gtk_clist_row_is_visible(GTK_CLIST(file_clist), row) != GTK_VISIBILITY_FULL)
333 gtk_clist_moveto(GTK_CLIST(file_clist), row, -1, 0.5, 0.0);
337 void file_next_image()
342 if (slideshow_is_running())
348 current = find_file_in_list(image_get_path());
349 total = file_count();
353 if (current < total - 1)
355 file_image_change_to(current + 1);
360 file_image_change_to(0);
364 void file_prev_image()
368 if (slideshow_is_running())
374 current = find_file_in_list(image_get_path());
380 file_image_change_to(current - 1);
385 file_image_change_to(file_count() - 1);
389 void file_first_image()
391 gint current = find_file_in_list(image_get_path());
392 if (current != 0 && file_count() > 0)
394 file_image_change_to(0);
398 void file_last_image()
400 gint current = find_file_in_list(image_get_path());
401 gint count = file_count();
402 if (current != count - 1 && count > 0)
404 file_image_change_to(count - 1);
409 *-----------------------------------------------------------------------------
410 * file delete/rename update routines
411 *-----------------------------------------------------------------------------
414 static gint file_find_closest_unaccounted(gint row, gint count, GList *ignore_list)
424 gint f = find_file_in_list(work->data);
425 if (f >= 0) list = g_list_append(list, GINT_TO_POINTER(f));
435 gpointer p = work->data;
437 if (row == GPOINTER_TO_INT(p))
442 if (rev == GPOINTER_TO_INT(p))
447 if (!c) list = g_list_remove(list, p);
468 void file_is_gone(gchar *path, GList *ignore_list)
474 row = find_file_in_list(path);
477 if (file_is_selected(row) /* && file_selection_count() == 1 */)
479 gint n = file_count();
482 new_row = file_find_closest_unaccounted(row, n, ignore_list);
483 if (debug) printf("row = %d, closest is %d\n", row, new_row);
496 gtk_clist_unselect_all(GTK_CLIST(file_clist));
499 gtk_clist_select_row(GTK_CLIST(file_clist), new_row, -1);
500 file_image_change_to(new_row);
504 image_change_to(NULL);
508 gtk_clist_remove(GTK_CLIST(file_clist), row);
509 list = g_list_nth(file_list, row);
511 file_list = g_list_remove(file_list, name);
513 update_status_label(NULL);
516 void file_is_renamed(gchar *source, gchar *dest)
522 if (image_get_path() && !strcmp(source, image_get_path()))
524 image_set_path(dest);
527 row = find_file_in_list(source);
530 source_base = remove_level_from_path(source);
531 dest_base = remove_level_from_path(dest);
533 if (strcmp(source_base, dest_base) == 0)
537 GList *work = g_list_nth(file_list, row);
539 file_list = g_list_remove(file_list, name);
541 name = g_strdup(filename_from_path(dest));
542 file_list = g_list_insert_sorted(file_list, name, (GCompareFunc) sort_list_cb);
543 n = g_list_index(file_list, name);
545 if (gtk_clist_get_cell_type(GTK_CLIST(file_clist), row, 0) != GTK_CELL_PIXTEXT)
547 gtk_clist_set_text (GTK_CLIST(file_clist), row, 0, name);
552 GdkPixmap *pixmap = NULL;
553 GdkBitmap *mask = NULL;
554 gtk_clist_get_pixtext(GTK_CLIST(file_clist), row, 0,
555 NULL, &spacing, &pixmap, &mask);
556 gtk_clist_set_pixtext(GTK_CLIST(file_clist), row, 0,
557 name, spacing, pixmap, mask);
560 gtk_clist_set_row_data(GTK_CLIST(file_clist), row, name);
561 gtk_clist_row_move(GTK_CLIST(file_clist), row, n);
565 GList *work = g_list_nth(file_list, row);
566 gchar *name = work->data;
567 file_list = g_list_remove(file_list, name);
568 gtk_clist_remove(GTK_CLIST(file_clist), row);
570 update_status_label(NULL);
579 *-----------------------------------------------------------------------------
580 * directory list callbacks
581 *-----------------------------------------------------------------------------
584 void dir_select_cb(GtkWidget *widget, gint row, gint col,
585 GdkEvent *event, gpointer data)
589 name = gtk_clist_get_row_data (GTK_CLIST(dir_clist), row);
590 if (strcmp(name, ".") == 0)
592 new_path = g_strdup(current_path);
594 else if (strcmp(name, "..") == 0)
596 new_path = remove_level_from_path(current_path);
600 if (strcmp(current_path, "/") == 0)
601 new_path = g_strconcat(current_path, name, NULL);
603 new_path = g_strconcat(current_path, "/", name, NULL);
605 filelist_change_to(new_path);
609 void dir_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
614 gtk_clist_get_selection_info (GTK_CLIST (widget), bevent->x, bevent->y, &row, &col);
616 if (bevent->button == 2)
618 gtk_object_set_user_data(GTK_OBJECT(dir_clist), GINT_TO_POINTER(row));
623 *-----------------------------------------------------------------------------
624 * file list callbacks
625 *-----------------------------------------------------------------------------
628 void file_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
633 gtk_clist_get_selection_info (GTK_CLIST (widget), bevent->x, bevent->y, &row, &col);
634 if (row == -1 || col == -1)
636 filelist_click_row = -1;
640 filelist_click_row = row;
642 if (bevent->button == 3)
644 file_clist_highlight_set();
645 gtk_menu_popup (GTK_MENU(menu_file_popup), NULL, NULL, NULL, NULL,
646 bevent->button, bevent->time);
650 void file_select_cb(GtkWidget *widget, gint row, gint col,
651 GdkEvent *event, gpointer data)
656 if (file_selection_count() != 1)
658 update_status_label(NULL);
662 name = gtk_clist_get_row_data(GTK_CLIST(file_clist), row);
663 path = g_strconcat(current_path, "/", name, NULL);
664 image_change_to(path);
665 update_status_label(NULL);
669 void file_unselect_cb(GtkWidget *widget, gint row, gint col,
670 GdkEvent *event, gpointer data)
676 name = gtk_clist_get_row_data(GTK_CLIST(file_clist), row);
677 path = g_strconcat(current_path, "/", name, NULL);
679 if (strcmp(path, image_get_path()) == 0)
681 if (file_selection_count() > 0 && !file_is_selected(find_file_in_list(image_get_path())) )
683 gint new_row = GPOINTER_TO_INT(GTK_CLIST(file_clist)->selection->data);
684 gchar *new_name = gtk_clist_get_row_data(GTK_CLIST(file_clist), new_row);
685 gchar *new_path = g_strconcat(current_path, "/", new_name, NULL);
686 image_change_to(new_path);
692 update_status_label(NULL);
696 *-----------------------------------------------------------------------------
697 * file list highlight utils
698 *-----------------------------------------------------------------------------
701 void file_clist_highlight_set()
703 if (file_clicked_is_selected()) return;
705 gtk_clist_set_background(GTK_CLIST(file_clist), filelist_click_row,
706 >K_WIDGET (file_clist)->style->bg[GTK_STATE_PRELIGHT]);
707 gtk_clist_set_foreground(GTK_CLIST(file_clist), filelist_click_row,
708 >K_WIDGET (file_clist)->style->fg[GTK_STATE_PRELIGHT]);
711 void file_clist_highlight_unset()
713 if (file_clicked_is_selected()) return;
715 gtk_clist_set_background(GTK_CLIST(file_clist), filelist_click_row, NULL);
716 gtk_clist_set_foreground(GTK_CLIST(file_clist), filelist_click_row, NULL);
720 *-----------------------------------------------------------------------------
721 * path entry and history menu
722 *-----------------------------------------------------------------------------
725 void path_entry_tab_cb(gchar *newdir, gpointer data)
731 new_path = g_strdup(newdir);
732 parse_out_relatives(new_path);
733 buf = remove_level_from_path(new_path);
735 if (buf && current_path && strcmp(buf, current_path) == 0)
740 part = filename_from_path(new_path);
745 gchar *name = work->data;
748 if (strncmp(part, name, strlen(part)) == 0)
750 gint row = g_list_index(file_list, name);
751 if (!gtk_clist_row_is_visible(GTK_CLIST(file_clist), row) != GTK_VISIBILITY_FULL)
753 gtk_clist_moveto(GTK_CLIST(file_clist), row, -1, 0.5, 0.0);
761 if (!found && new_path && current_path &&
762 strcmp(new_path, current_path) != 0 && isdir(new_path))
764 filelist_change_to(new_path);
765 /* we are doing tab completion, add '/' back */
766 gtk_entry_append_text(GTK_ENTRY(path_entry), "/");
773 void path_entry_cb(gchar *newdir, gpointer data)
775 gchar *new_path = g_strdup(newdir);
776 parse_out_relatives(new_path);
778 filelist_change_to(new_path);
779 else if (isfile(new_path))
781 gchar *path = remove_level_from_path(new_path);
782 filelist_change_to(path);
784 image_change_to(new_path);
789 static void history_menu_select_cb(GtkWidget *widget, gpointer data)
791 gchar *new_path = data;
792 filelist_change_to(new_path);
795 static gchar *truncate_hist_text(gchar *t, gint l)
799 if (l >= strlen(t)) return g_strdup(t);
800 tp = t + strlen(t) - l;
801 while (tp[0] != '/' && tp < t + strlen(t)) tp++;
802 /* this checks to see if directory name is longer than l, if so
803 * reset the length of name to l, it's better to have a partial
804 * name than no name at all.
806 if (tp >= t + strlen(t)) tp = t + strlen(t) - l;
807 tbuf = g_strconcat("/...", tp, NULL);
811 static void filelist_set_history(gchar *path)
813 static GList *history_list = NULL;
821 gtk_entry_set_text(GTK_ENTRY(path_entry), current_path);
825 g_list_foreach(history_list, (GFunc)g_free, NULL);
826 g_list_free(history_list);
830 menu = gtk_menu_new();
832 buf = g_strdup(path);
833 buf_ptr = buf + strlen(buf) - 1 ;
834 while (buf_ptr > buf)
838 truncated = truncate_hist_text(buf, 32);
840 full_path = g_strdup(buf);
841 history_list = g_list_append(history_list, full_path);
843 item = gtk_menu_item_new_with_label (truncated);
844 gtk_signal_connect (GTK_OBJECT (item), "activate",
845 (GtkSignalFunc) history_menu_select_cb, full_path);
847 gtk_menu_append (GTK_MENU (menu), item);
848 gtk_widget_show (item);
852 while (buf_ptr[0] != '/' && buf_ptr > buf) buf_ptr--;
857 item = gtk_menu_item_new_with_label ("/");
859 gtk_signal_connect (GTK_OBJECT (item), "activate",
860 (GtkSignalFunc) history_menu_select_cb, "/");
862 gtk_menu_append (GTK_MENU (menu), item);
863 gtk_widget_show (item);
865 gtk_option_menu_set_menu(GTK_OPTION_MENU(history_menu), menu);
869 *-----------------------------------------------------------------------------
870 * list update routines (public)
871 *-----------------------------------------------------------------------------
874 static gint thumbs_running = 0;
876 void interrupt_thumbs()
878 if (thumbs_running > 0) thumbs_running ++;
881 void filelist_populate_clist()
887 gchar *image_name = NULL;
898 filelist_set_history(current_path);
900 gtk_clist_freeze (GTK_CLIST (dir_clist));
901 gtk_clist_clear (GTK_CLIST (dir_clist));
910 row = gtk_clist_append(GTK_CLIST(dir_clist), buf);
911 gtk_clist_set_row_data (GTK_CLIST(dir_clist), row, work->data);
912 tmp_width = gdk_string_width(dir_clist->style->font, buf[0]);
913 if (tmp_width > width) width = tmp_width;
917 gtk_clist_set_column_width(GTK_CLIST(dir_clist), 0, width);
918 gtk_clist_thaw(GTK_CLIST (dir_clist));
920 buf = remove_level_from_path(image_get_path());
921 if (buf && strcmp(buf, current_path) == 0)
923 image_name = image_get_name();
927 gtk_clist_freeze (GTK_CLIST (file_clist));
929 if (!thumbnails_enabled)
931 gtk_clist_set_row_height (GTK_CLIST(file_clist),
932 GTK_WIDGET(file_clist)->style->font->ascent +
933 GTK_WIDGET(file_clist)->style->font->descent + 1);
937 gtk_clist_set_row_height (GTK_CLIST(file_clist), thumb_max_height + 2);
938 maintain_thumbnail_dir(current_path, FALSE);
948 gchar *name = work->data;
953 if (GTK_CLIST(file_clist)->rows > row_p)
955 if (gtk_clist_get_cell_type(GTK_CLIST(file_clist),row_p, 0) == GTK_CELL_PIXTEXT)
957 gtk_clist_get_pixtext(GTK_CLIST(file_clist), row_p, 0, &text, &spacing, &nopixmap, &nomask);
962 gtk_clist_get_text(GTK_CLIST(file_clist), row_p, 0, &text);
965 match = strcmp(name, text);
977 row = gtk_clist_insert(GTK_CLIST(file_clist), row_p, buf);
978 gtk_clist_set_row_data (GTK_CLIST(file_clist), row, name);
979 if (thumbnails_enabled)
980 gtk_clist_set_shift(GTK_CLIST(file_clist), row, 0, 0, 5 + thumb_max_width);
982 if (image_name && strcmp(name, image_name) == 0)
983 gtk_clist_select_row(GTK_CLIST(file_clist), row, 0);
987 gtk_clist_remove(GTK_CLIST(file_clist), row_p);
991 if (thumbnails_enabled && !has_pixmap)
992 gtk_clist_set_shift(GTK_CLIST(file_clist), row_p, 0, 0, 5 + thumb_max_width);
993 if (!thumbnails_enabled/* && has_pixmap*/)
995 gtk_clist_set_text(GTK_CLIST(file_clist), row_p, 0, name);
996 gtk_clist_set_shift(GTK_CLIST(file_clist), row_p, 0, 0, 0);
998 gtk_clist_set_row_data (GTK_CLIST(file_clist), row_p, name);
1004 if (thumbnails_enabled)
1005 tmp_width = gdk_string_width(file_clist->style->font, name) + thumb_max_width + 5;
1007 tmp_width = gdk_string_width(file_clist->style->font, name);
1008 if (tmp_width > width) width = tmp_width;
1012 while (GTK_CLIST(file_clist)->rows > row_p)
1013 gtk_clist_remove(GTK_CLIST(file_clist), row_p);
1015 gtk_clist_set_column_width(GTK_CLIST(file_clist), 0, width);
1016 gtk_clist_thaw(GTK_CLIST (file_clist));
1018 if (thumbnails_enabled)
1020 GList *done_list = NULL;
1022 gint finished = FALSE;
1025 update_status_label(_("Loading thumbs..."));
1027 for (j = 0; j < GTK_CLIST(file_clist)->rows; j++)
1029 done_list = g_list_prepend(done_list, GINT_TO_POINTER(FALSE));
1034 while (!finished && done_list)
1039 gtk_clist_get_selection_info (GTK_CLIST(file_clist), 1, 1, &r, &c);
1042 work = g_list_nth(done_list, r);
1045 if (gtk_clist_row_is_visible(GTK_CLIST(file_clist), r))
1047 if (!GPOINTER_TO_INT(work->data))
1049 work->data = GINT_TO_POINTER(TRUE);
1069 while(work && p == -1)
1071 if (!GPOINTER_TO_INT(work->data))
1074 work->data = GINT_TO_POINTER(TRUE);
1080 if (!work) finished = TRUE;
1087 if (!finished && gtk_clist_get_cell_type(GTK_CLIST(file_clist), p, 0) != GTK_CELL_PIXTEXT)
1089 GdkPixmap *pixmap = NULL;
1090 GdkBitmap *mask = NULL;
1095 past_run = thumbs_running;
1096 while(gtk_events_pending()) gtk_main_iteration();
1097 if (thumbs_running > past_run)
1099 thumbs_running -= 2;
1100 update_progressbar(0.0);
1101 update_status_label(NULL);
1102 g_list_free(done_list);
1107 name = gtk_clist_get_row_data(GTK_CLIST(file_clist), p);
1108 path = g_strconcat (current_path, "/", name, NULL);
1109 spacing = create_thumbnail(path, &pixmap, &mask);
1111 gtk_clist_set_pixtext (GTK_CLIST(file_clist), p, 0, name, spacing + 5, pixmap, mask);
1112 gtk_clist_set_shift(GTK_CLIST(file_clist), p, 0, 0, 0);
1114 update_progressbar((gfloat)(count) / GTK_CLIST(file_clist)->rows);
1117 update_progressbar(0.0);
1118 g_list_free(done_list);
1121 update_status_label(NULL);
1124 void filelist_refresh()
1126 filelist_read(current_path);
1127 filelist_populate_clist();
1128 filelist_click_row = -1;
1131 void filelist_change_to(gchar *path)
1133 if (!isdir(path)) return;
1135 g_free(current_path);
1136 current_path = g_strdup(path);