1 /* gtkiconfileselection - gtkiconfileselection dialog widget for gtk+
2  * Copyright 1999-2001  Adrian E. Feiguin <feiguin@ifir.edu.ar>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 
20 /**
21  * SECTION: gtkiconfilesel
22  * @short_description: A file selection dialog widget for GTK.
23  *
24  * It is a nice looking file selection dialog using icons.
25  * It combines GtkDirTree and GtkFileList to navigate the file system and select files.
26  * It has also two entries to select the file and filter.
27  */
28 
29 /**
30  * GtkIconFileSelection:
31  *
32  * The GtkIconFileSelection structure contains only private data.
33  * It should only be accessed through the functions described below.
34  */
35 
36 #include "config.h"
37 #include <gtk/gtk.h>
38 #include <gdk/gdkkeysyms.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 
42 #ifdef HAVE_UNISTD_H
43 #  include <unistd.h>
44 #endif
45 
46 #ifdef HAVE_DIRENT_H
47 #  include <dirent.h>
48 #endif
49 
50 #include <string.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 
54 #include "gtkextra-compat.h"
55 #include "gtkiconfilesel.h"
56 #include "gtkextraicons.h"
57 
58 #ifndef MAXHOSTNAMELEN
59 #  define MAXHOSTNAMELEN 64
60 #endif
61 
62 #ifndef MAXPATHLEN
63 #  define MAXPATHLEN 1024
64 #endif
65 
66 static void gtk_icon_file_selection_class_init          (GtkIconFileSelClass *klass);
67 static void gtk_icon_file_selection_init                (GtkIconFileSel *filesel);
68 static void gtk_icon_file_selection_destroy             (GtkObject *object);
69 static void open_dir					(GtkWidget *widget,
70 							 GtkCTreeNode *node,
71 							 gint n,
72                                                          gpointer data);
73 static gboolean entry_set_file				(GtkWidget *widget,
74 							 GdkEventKey *key,
75 							 gpointer data);
76 static void real_set_file				(GtkWidget *widget,
77 							 gpointer data);
78 static gboolean set_filter				(GtkWidget *widget,
79                                                          GdkEventKey *key,
80 							 gpointer data);
81 static gboolean select_icon				(GtkIconList *iconlist,
82             						 GtkIconListItem *icon,
83             						 GdkEvent *event,
84 							 gpointer data);
85 static gboolean insert_text                             (GtkEditable *editable,
86                                                          const gchar *new_text,
87                                                          gint  new_text_length,
88                                                          gint  *position,
89                                                          gpointer data);
90 static void init_history_combo				(GtkIconFileSel *filesel,
91 							 const gchar *curr_dir);
92 static void update_history_combo			(GtkIconFileSel *filesel,
93 							 const gchar *curr_dir);
94 static void go_to_history				(const gchar *path,
95 							 gpointer data);
96 static gboolean combo_changed				(GtkWidget *widget,
97 							 gpointer data);
98 static gboolean entry_key_press				(GtkWidget *widget,
99 							 GdkEventKey *event,
100 							 gpointer data);
101 static gchar *get_real_path				(const gchar *full_path);
102 
103 static GtkWindowClass *parent_class = NULL;
104 
105 
106 GType
gtk_icon_file_selection_get_type(void)107 gtk_icon_file_selection_get_type (void)
108 {
109   static GType filesel_type = 0;
110 
111   if (!filesel_type)
112     {
113       filesel_type = g_type_register_static_simple (
114 		gtk_window_get_type(),
115 		"GtkIconFileSel",
116 		sizeof (GtkIconFileSelClass),
117 		(GClassInitFunc) gtk_icon_file_selection_class_init,
118 		sizeof (GtkIconFileSel),
119 		(GInstanceInitFunc) gtk_icon_file_selection_init,
120 		0);
121     }
122 
123   return filesel_type;
124 }
125 
126 GtkWidget*
gtk_icon_file_selection_new(const gchar * title)127 gtk_icon_file_selection_new (const gchar *title)
128 {
129   GtkWidget *widget;
130 
131   widget = gtk_widget_new (gtk_icon_file_selection_get_type(), NULL);
132 
133   gtk_icon_file_selection_construct(GTK_ICON_FILESEL(widget), title);
134 
135   return widget;
136 }
137 
138 /**
139  * gtk_icon_file_selection_construct:
140  * @filesel: the #GtkIconFileSelection widget.
141  * @title: window title.
142  *
143  * Sets the window title for #GtkIconFileSelection widget.
144  */
145 void
gtk_icon_file_selection_construct(GtkIconFileSel * filesel,const gchar * title)146 gtk_icon_file_selection_construct (GtkIconFileSel *filesel, const gchar *title)
147 {
148 /*  GTK_ICON_FILESEL(widget)->title = g_strdup(title);
149 */
150   gtk_window_set_title(GTK_WINDOW(filesel),title);
151 }
152 
153 static void
gtk_icon_file_selection_class_init(GtkIconFileSelClass * klass)154 gtk_icon_file_selection_class_init (GtkIconFileSelClass *klass)
155 {
156   GtkWidgetClass *widget_class;
157   GtkObjectClass *object_class;
158 
159   widget_class = (GtkWidgetClass*) klass;
160   object_class = (GtkObjectClass*) klass;
161   parent_class = g_type_class_ref (gtk_window_get_type ());
162 
163   object_class->destroy = gtk_icon_file_selection_destroy;
164 }
165 
166 static void
up_clicked(GtkWidget * widget,gpointer data)167 up_clicked(GtkWidget *widget, gpointer data)
168 {
169   GtkIconFileSel *filesel = GTK_ICON_FILESEL(widget);
170   gchar *current_dir;
171   gint dir_len;
172   gint i;
173 
174   current_dir = g_strdup (GTK_FILE_LIST(filesel->file_list)->path);
175   dir_len = strlen (current_dir);
176 
177   for (i = dir_len - 1; i >= 0; i--){
178 
179     /* the i == dir_len is to catch the full path for the first
180      * entry. */
181     if ( current_dir[i] == G_DIR_SEPARATOR ) {
182           current_dir[i + 1] = '\0';
183           gtk_icon_file_selection_open_dir(filesel, current_dir);
184           break;
185      }
186   }
187 
188   g_free(current_dir);
189 }
190 
191 static void
refresh_clicked(GtkWidget * widget,gpointer data)192 refresh_clicked(GtkWidget *widget, gpointer data)
193 {
194   GtkIconFileSel *filesel = GTK_ICON_FILESEL(widget);
195   gtk_icon_file_selection_open_dir(filesel, GTK_FILE_LIST(filesel->file_list)->path);
196 }
197 
198 static void
home_clicked(GtkWidget * widget,gpointer data)199 home_clicked(GtkWidget *widget, gpointer data)
200 {
201   GtkIconFileSel *filesel = GTK_ICON_FILESEL(widget);
202 
203   gtk_icon_file_selection_open_dir(filesel, g_get_home_dir());
204 }
205 
206 
207 static void
gtk_icon_file_selection_init(GtkIconFileSel * filesel)208 gtk_icon_file_selection_init (GtkIconFileSel *filesel)
209 {
210   GtkWidget *main_vbox;
211   GtkWidget *hbox, *box;
212   GtkWidget *table;
213   GtkWidget *label;
214   GtkWidget *scrolled_window;
215   GtkWidget *wpixmap;
216   GtkTooltips *tp;
217   GdkPixmap *pixmap;
218   GdkBitmap *mask;
219   gchar cwd_path[2*MAXPATHLEN] = "";
220   gchar path[2*MAXPATHLEN] = "";
221   GdkColormap *colormap = gtk_widget_get_colormap(GTK_WIDGET(filesel));
222 
223   filesel->show_tree = FALSE;
224 
225   /* We don't use getcwd() on SUNOS, because, it does a popen("pwd")
226    * and, if that wasn't bad enough, hangs in doing so.
227    */
228 #if defined(sun) && !defined(__SVR4)
229   getwd (cwd_path);
230 #else
231   getcwd (cwd_path, MAXPATHLEN);
232 #endif
233   g_snprintf(path, MAXPATHLEN, "%s%s", cwd_path, G_DIR_SEPARATOR_S);
234 
235   gtk_window_set_resizable(GTK_WINDOW(filesel), FALSE);
236   gtk_container_set_border_width (GTK_CONTAINER (filesel), 10);
237 
238   main_vbox=gtk_vbox_new(FALSE,1);
239   gtk_container_set_border_width(GTK_CONTAINER(main_vbox),0);
240   gtk_container_add(GTK_CONTAINER(filesel), main_vbox);
241   gtk_widget_show(main_vbox);
242 
243   hbox = gtk_hbox_new(FALSE, 1);
244   gtk_box_pack_start(GTK_BOX(main_vbox), hbox, FALSE, TRUE, 0);
245   gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new ("Go to:  "), FALSE, FALSE, 0);
246   filesel->history_combo = gtk_combo_box_entry_new_text();
247   gtk_box_pack_start(GTK_BOX(hbox), filesel->history_combo, TRUE, TRUE, 0);
248   init_history_combo(filesel, path);
249   gtk_widget_show_all(hbox);
250 
251 /* RRR */
252   g_signal_connect(GTK_OBJECT(GTK_COMBO_BOX(filesel->history_combo)),
253 		     "key_press_event",
254                      (void *)entry_key_press, filesel);
255 
256   g_signal_connect(GTK_OBJECT(GTK_COMBO_BOX(filesel->history_combo)),
257 		     "changed",
258                      (void *)combo_changed, filesel);
259 
260   filesel->up_button = gtk_button_new();
261   pixmap = gdk_pixmap_colormap_create_from_xpm_d(NULL, colormap, &mask, NULL,
262                                                  up_xpm);
263   wpixmap = gtk_image_new_from_pixmap(pixmap, mask);
264   gdk_pixmap_unref(pixmap);
265   gdk_bitmap_unref(mask);
266 
267   gtk_container_add(GTK_CONTAINER(filesel->up_button), wpixmap);
268   gtk_box_pack_start(GTK_BOX(hbox), filesel->up_button, FALSE, FALSE, 0);
269   gtk_widget_show_all(filesel->up_button);
270   g_signal_connect_swapped(GTK_OBJECT(filesel->up_button), "clicked",
271 		            (void *)up_clicked,
272 			    GTK_OBJECT(filesel));
273   tp = gtk_tooltips_new();
274   gtk_tooltips_set_tip(GTK_TOOLTIPS(tp), filesel->up_button, "Parent directory", "Parent directory");
275   gtk_tooltips_enable(GTK_TOOLTIPS(tp));
276 
277   filesel->home_button = gtk_button_new();
278   pixmap = gdk_pixmap_colormap_create_from_xpm_d(NULL, colormap, &mask, NULL,
279                                                  home_xpm);
280   wpixmap = gtk_image_new_from_pixmap(pixmap, mask);
281   gdk_pixmap_unref(pixmap);
282   gdk_bitmap_unref(mask);
283 
284   gtk_container_add(GTK_CONTAINER(filesel->home_button), wpixmap);
285   gtk_box_pack_start(GTK_BOX(hbox), filesel->home_button, FALSE, FALSE, 0);
286   gtk_widget_show_all(filesel->home_button);
287   g_signal_connect_swapped(GTK_OBJECT(filesel->home_button), "clicked",
288 		            (void *)home_clicked,
289 			    GTK_OBJECT(filesel));
290   tp = gtk_tooltips_new();
291   gtk_tooltips_set_tip(GTK_TOOLTIPS(tp), filesel->home_button, "Home", "Home");
292   gtk_tooltips_enable(GTK_TOOLTIPS(tp));
293 
294   filesel->refresh_button = gtk_button_new();
295   pixmap = gdk_pixmap_colormap_create_from_xpm_d(NULL, colormap, &mask, NULL,
296                                                  refresh_xpm);
297   wpixmap = gtk_image_new_from_pixmap(pixmap, mask);
298   gdk_pixmap_unref(pixmap);
299   gdk_bitmap_unref(mask);
300 
301   gtk_container_add(GTK_CONTAINER(filesel->refresh_button), wpixmap);
302   gtk_box_pack_start(GTK_BOX(hbox), filesel->refresh_button, FALSE, FALSE, 0);
303   gtk_widget_show_all(filesel->refresh_button);
304   g_signal_connect_swapped(GTK_OBJECT(filesel->refresh_button), "clicked",
305 		            (void *)refresh_clicked,
306 			    GTK_OBJECT(filesel));
307   tp = gtk_tooltips_new();
308   gtk_tooltips_set_tip(GTK_TOOLTIPS(tp), filesel->refresh_button, "Refresh", "Refresh");
309   gtk_tooltips_enable(GTK_TOOLTIPS(tp));
310 
311   filesel->path_label = gtk_label_new(path);
312   gtk_misc_set_alignment(GTK_MISC(filesel->path_label), 0., .5);
313   gtk_box_pack_start(GTK_BOX(main_vbox), filesel->path_label, FALSE, TRUE, 0);
314   gtk_widget_show(filesel->path_label);
315 
316   hbox=gtk_hbox_new(FALSE,1);
317   gtk_box_pack_start(GTK_BOX(main_vbox), hbox, TRUE, TRUE, 0);
318   gtk_widget_show(hbox);
319 
320   filesel->tree_window = scrolled_window=gtk_scrolled_window_new(NULL, NULL);
321   gtk_widget_set_size_request(scrolled_window, 200, 250);
322   gtk_box_pack_start(GTK_BOX(hbox), scrolled_window, TRUE, TRUE, 0);
323   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
324                                  GTK_POLICY_AUTOMATIC,
325                                  GTK_POLICY_AUTOMATIC);
326 
327 /* FIXME
328   filesel->dir_tree = gtk_dir_tree_new();
329   GTK_DIR_TREE(filesel->dir_tree)->show_hidden = TRUE;
330   gtk_container_add(GTK_CONTAINER(scrolled_window), filesel->dir_tree);
331   gtk_widget_show(filesel->dir_tree);
332 
333   gtk_box_pack_start(GTK_BOX(hbox), gtk_vseparator_new(), TRUE, TRUE, 0);
334 */
335 
336   filesel->list_window = scrolled_window=gtk_scrolled_window_new(NULL, NULL);
337   gtk_box_pack_start(GTK_BOX(hbox), scrolled_window, TRUE, TRUE, 0);
338   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
339                                  GTK_POLICY_ALWAYS,
340                                  GTK_POLICY_AUTOMATIC);
341 
342   filesel->file_list = gtk_file_list_new(20, GTK_ICON_LIST_TEXT_RIGHT, G_DIR_SEPARATOR_S);
343   GTK_ICON_LIST(filesel->file_list)->is_editable = FALSE;
344   GTK_FILE_LIST(filesel->file_list)->show_folders = TRUE;
345   GTK_FILE_LIST(filesel->file_list)->show_hidden = TRUE;
346   gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window),
347                                         filesel->file_list);
348   gtk_widget_show(filesel->file_list);
349 
350   if(filesel->show_tree){
351      gtk_icon_file_selection_show_tree(filesel, TRUE);
352      gtk_widget_set_size_request(filesel->list_window, 380, 250);
353   }else{
354      gtk_widget_set_size_request(filesel->list_window, 550, 250);
355   }
356 
357   gtk_widget_show(scrolled_window);
358 
359   g_signal_connect(GTK_OBJECT(filesel->file_list), "select_icon",
360                      (void *)select_icon, filesel);
361 
362   filesel->action_area = table = gtk_table_new(TRUE, 2, 4);
363   gtk_box_pack_start(GTK_BOX(main_vbox), table, TRUE, TRUE, 3);
364   gtk_widget_show(table);
365 
366   label = gtk_label_new("File:        ");
367   gtk_misc_set_alignment(GTK_MISC(label), 1., 0.5);
368   gtk_table_attach_defaults(GTK_TABLE(table),
369                             label,
370                             0, 1, 0, 1);
371   gtk_widget_show(label);
372 
373   label = gtk_label_new("Filter:        ");
374   gtk_misc_set_alignment(GTK_MISC(label), 1., 0.5);
375   gtk_table_attach_defaults(GTK_TABLE(table),
376                             label,
377                             0, 1, 1, 2);
378   gtk_widget_show(label);
379 
380   filesel->file_entry = gtk_entry_new();
381   gtk_table_attach_defaults(GTK_TABLE(table), filesel->file_entry, 1, 3, 0, 1);
382   gtk_widget_show(filesel->file_entry);
383 
384   g_signal_connect(GTK_OBJECT(filesel->file_entry), "key_press_event",
385                      (void *)entry_set_file, filesel);
386 
387   filesel->filter_entry = gtk_entry_new();
388   gtk_table_attach_defaults(GTK_TABLE(table), filesel->filter_entry, 1, 3, 1, 2);
389   gtk_widget_show(filesel->filter_entry);
390 
391   g_signal_connect(GTK_OBJECT(filesel->filter_entry), "key_press_event",
392                      (void *)set_filter, filesel);
393 
394 /* FIXME
395   g_signal_connect(GTK_OBJECT(filesel->filter_entry), "insert_text",
396                      (void *)insert_text, NULL);
397 */
398 
399   box = gtk_vbutton_box_new();
400   gtk_table_attach_defaults(GTK_TABLE(table), box, 3, 4, 0, 2);
401   gtk_widget_show(box);
402 
403   pixmap = gdk_pixmap_colormap_create_from_xpm_d(NULL, colormap, &mask, NULL,
404                                                  ok_xpm);
405   wpixmap = gtk_image_new_from_pixmap(pixmap, mask);
406   gdk_pixmap_unref(pixmap);
407   gdk_bitmap_unref(mask);
408 
409   filesel->ok_button = gtk_button_new_from_stock(GTK_STOCK_OK);
410   gtk_box_pack_end (GTK_BOX (box), filesel->ok_button, TRUE, TRUE, 0);
411   gtk_widget_show(filesel->ok_button);
412 
413   g_signal_connect(GTK_OBJECT(filesel->ok_button), "clicked",
414                      (void *)real_set_file, filesel);
415 
416   pixmap = gdk_pixmap_colormap_create_from_xpm_d(NULL, colormap, &mask, NULL,
417                                                  cancel_xpm);
418   wpixmap = gtk_image_new_from_pixmap(pixmap, mask);
419   gdk_pixmap_unref(pixmap);
420   gdk_bitmap_unref(mask);
421 
422   filesel->cancel_button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
423   gtk_box_pack_end (GTK_BOX (box), filesel->cancel_button, TRUE, TRUE, 0);
424   gtk_widget_show(filesel->cancel_button);
425 
426   gtk_icon_file_selection_open_dir(filesel, path);
427 
428   filesel->selection = NULL;
429 }
430 
431 static void
gtk_icon_file_selection_destroy(GtkObject * object)432 gtk_icon_file_selection_destroy(GtkObject *object)
433 {
434   if(GTK_ICON_FILESEL(object)->selection)
435     g_free(GTK_ICON_FILESEL(object)->selection);
436   GTK_ICON_FILESEL(object)->selection = NULL;
437 
438   if (GTK_OBJECT_CLASS (parent_class)->destroy)
439     (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
440 }
441 
442 /**
443  * gtk_icon_file_selection_show_tree:
444  * @filesel: the #GtkIconFileSelection widget.
445  * @show: TRUE(show) or FALSE(don't show).
446  *
447  * Show icon file selection tree in filesel widget.
448  */
449 void
gtk_icon_file_selection_show_tree(GtkIconFileSel * filesel,gboolean show)450 gtk_icon_file_selection_show_tree(GtkIconFileSel *filesel, gboolean show)
451 {
452 /* FIXME
453   if(show == filesel->show_tree) return;
454 
455   filesel->show_tree = show;
456 
457   if(show){
458     const gchar *path;
459 
460     filesel->tree_signal_id = g_signal_connect(GTK_OBJECT(filesel->dir_tree),
461                                                  "tree_select_row",
462                                                  (void *)open_dir,
463                                                  filesel);
464 
465     path = gtk_file_list_get_path(GTK_FILE_LIST(filesel->file_list));
466     gtk_dir_tree_open_dir(GTK_DIR_TREE(filesel->dir_tree), path);
467 
468     gtk_widget_set_size_request(filesel->list_window, 380, 250);
469     gtk_widget_show(filesel->tree_window);
470   } else {
471     g_signal_disconnect(GTK_OBJECT(filesel->dir_tree),
472                           filesel->tree_signal_id);
473     gtk_widget_hide(filesel->tree_window);
474     gtk_widget_set_size_request(filesel->list_window, 550, 250);
475   }
476 */
477 }
478 
479 static gboolean
insert_text(GtkEditable * editable,const gchar * new_text,gint new_text_length,gint * position,gpointer data)480 insert_text     (GtkEditable *editable,
481                  const gchar *new_text,
482                  gint         new_text_length,
483                  gint        *position,
484                  gpointer data)
485 {
486   g_object_ref(editable);
487   g_signal_stop_emission_by_name (GTK_OBJECT(editable), "insert_text");
488   if(new_text[0] != ' '){
489      GTK_EDITABLE_CLASS (g_type_class_ref(gtk_editable_get_type ()))->insert_text(editable,
490                                                               new_text,
491                                                               new_text_length,
492                                                               position);
493 
494 
495   }
496   g_object_unref(editable);
497   return TRUE;
498 }
499 
500 static gboolean
select_icon(GtkIconList * iconlist,GtkIconListItem * icon,GdkEvent * event,gpointer data)501 select_icon(GtkIconList *iconlist,
502             GtkIconListItem *icon,
503             GdkEvent *event, gpointer data)
504 {
505   GtkIconFileSel *filesel;
506   GdkModifierType mods;
507   const gchar *path = NULL;
508   gchar *real_path = NULL;
509   gchar *full_path = NULL;
510   const gchar *file = NULL;
511   GtkFileListItem *item;
512   gboolean return_val = FALSE;
513 
514   item = (GtkFileListItem *)icon->link;
515 
516   filesel = GTK_ICON_FILESEL(data);
517 
518   if(item->type != GTK_FILE_LIST_FOLDER){
519     GList *list = iconlist->selection;
520     if(iconlist->selection_mode == GTK_SELECTION_MULTIPLE && list != NULL){
521       gchar *text = g_strdup(((GtkIconListItem *)list->data)->label);
522       list = list->next;
523       while(list){
524         text = g_strconcat(text,";",((GtkIconListItem *)list->data)->label,NULL);
525         list = list->next;
526       }
527       text = g_strconcat(text,";",icon->label,NULL);
528       gtk_entry_set_text(GTK_ENTRY(filesel->file_entry), text);
529       g_free(text);
530     } else {
531       gtk_entry_set_text(GTK_ENTRY(filesel->file_entry), icon->label);
532     }
533     return TRUE;
534   }else{
535     gtk_entry_set_text(GTK_ENTRY(filesel->file_entry), "");
536   }
537 
538   if(!event) return FALSE;
539 
540   if(event->type == GDK_BUTTON_PRESS || event->type == GDK_2BUTTON_PRESS)
541     gdk_window_get_pointer(event->button.window, NULL, NULL, &mods);
542   else
543     return FALSE;
544 
545   path = gtk_file_list_get_path(GTK_FILE_LIST(filesel->file_list));
546   file = gtk_file_list_get_filename(GTK_FILE_LIST(filesel->file_list));
547   file = icon->label;
548 
549   if(strlen(path) == 1)
550     full_path = g_strconcat(G_DIR_SEPARATOR_S,file,G_DIR_SEPARATOR_S,NULL);
551   else
552     full_path = g_strconcat(path,G_DIR_SEPARATOR_S,file,G_DIR_SEPARATOR_S,NULL);
553   real_path = get_real_path((const gchar *)full_path);
554 
555   if(filesel->selection) g_free(filesel->selection);
556   filesel->selection = NULL;
557   if(item->type != GTK_FILE_LIST_FOLDER){
558     filesel->selection = g_strdup(real_path);
559   }
560 
561   if((mods & GDK_BUTTON1_MASK) && event->type == GDK_2BUTTON_PRESS){
562     gtk_label_set_text(GTK_LABEL(filesel->path_label), "Scanning...");
563     if(filesel->show_tree){
564 /* FIXME
565       return_val = gtk_dir_tree_open_dir(GTK_DIR_TREE(filesel->dir_tree), real_path);
566 */
567     } else
568       return_val = gtk_file_list_open_dir(GTK_FILE_LIST(filesel->file_list), real_path);
569 
570     update_history_combo(filesel, real_path);
571 
572     gtk_label_set_text(GTK_LABEL(filesel->path_label), real_path);
573   }
574 
575   g_free(full_path);
576   g_free(real_path);
577   return (!return_val);
578 }
579 
580 static gboolean
entry_set_file(GtkWidget * widget,GdkEventKey * key,gpointer data)581 entry_set_file(GtkWidget *widget, GdkEventKey *key, gpointer data)
582 {
583 	GtkIconFileSel *filesel = GTK_ICON_FILESEL(data);
584 
585 	if (key->keyval != GDK_KEY_Return && key->keyval != GDK_KEY_KP_Enter)
586 		return FALSE;
587 
588     /*  real_set_file(widget, data); */
589 
590 	g_signal_emit_by_name(GTK_OBJECT(filesel->ok_button), "clicked", filesel);
591 
592 	return FALSE;
593 }
594 
595 static void
real_set_file(GtkWidget * widget,gpointer data)596 real_set_file(GtkWidget *widget, gpointer data)
597 {
598   GtkIconFileSel *filesel;
599   GtkIconListItem *item;
600   GList *list;
601   const gchar *c;
602   gchar *last, *text;
603   gchar *folder;
604   gchar *file;
605   gint nlen, file_len;
606 
607   filesel = (GtkIconFileSel *)data;
608 
609   c = gtk_entry_get_text(GTK_ENTRY(filesel->file_entry));
610   folder = NULL;
611   file = NULL;
612   last = NULL;
613   file_len = nlen = 0;
614 
615   while(*c != '\0' && *c != '\n' && c != NULL){
616    nlen++;
617    file_len++;
618    folder = (char *)g_realloc(folder, (nlen+1)*sizeof(char));
619    folder[nlen-1] = *c;
620    folder[nlen]='\0';
621    file = (char *)g_realloc(file, (file_len+1)*sizeof(char));
622    file[file_len-1] = *c;
623    file[file_len]='\0';
624    if(*c == G_DIR_SEPARATOR){
625        g_free(file);
626        g_free(last);
627        last = g_strdup(folder);
628        file_len = 0;
629        file = NULL;
630    }
631    c++;
632   }
633 
634   if(last) gtk_icon_file_selection_open_dir(filesel, last);
635 
636   if(file){
637     list = GTK_ICON_LIST(filesel->file_list)->icons;
638     while(list){
639       item = (GtkIconListItem *)list->data;
640       text = ((GtkFileListItem *)item->link)->file_name;
641       if(strcmp(text, file) == 0){
642          item->state = GTK_STATE_SELECTED;
643 /*
644          gtk_icon_list_select_icon(GTK_ICON_LIST(filesel->file_list), item);
645 */
646          break;
647       }
648       list = list->next;
649     }
650   }
651 
652 
653   g_free(folder);
654   g_free(file);
655   g_free(last);
656 }
657 
658 static gboolean
set_filter(GtkWidget * widget,GdkEventKey * key,gpointer data)659 set_filter(GtkWidget *widget, GdkEventKey *key, gpointer data)
660 {
661 	GtkIconFileSel *filesel;
662 
663 	if (key->keyval != GDK_KEY_Return && key->keyval != GDK_KEY_KP_Enter)
664 		return FALSE;
665 
666 	filesel = (GtkIconFileSel *)data;
667 
668 	gtk_file_list_set_filter(GTK_FILE_LIST(filesel->file_list),
669 							 gtk_entry_get_text(GTK_ENTRY(widget)));
670 
671 	return TRUE;
672 }
673 
674 static void
open_dir(GtkWidget * widget,GtkCTreeNode * node,gint n,gpointer data)675 open_dir(GtkWidget *widget, GtkCTreeNode *node, gint n, gpointer data)
676 {
677   DIR *dir;
678   GtkDirTreeNode *dirnode;
679   gchar *path;
680   const gchar *last_path;
681   GtkIconFileSel *filesel;
682 
683   filesel = GTK_ICON_FILESEL(data);
684 
685 
686   dirnode=gtk_ctree_node_get_row_data(GTK_CTREE(widget),node);
687 
688   path = dirnode->path;
689 
690   last_path = gtk_file_list_get_path(GTK_FILE_LIST(filesel->file_list));
691 
692   if(strcmp(last_path, G_DIR_SEPARATOR_S) !=0 && strcmp(last_path, path) == 0) return;
693 
694   gtk_widget_unmap(filesel->file_list);
695 
696   if((dir = opendir(path)) == NULL){
697     return;
698   }
699   closedir(dir);
700 
701   gtk_label_set_text(GTK_LABEL(filesel->path_label), "Scanning...");
702 
703   gtk_file_list_open_dir(GTK_FILE_LIST(filesel->file_list), path);
704 
705   update_history_combo(filesel, path);
706 
707   gtk_widget_map(filesel->file_list);
708 
709   gtk_label_set_text(GTK_LABEL(filesel->path_label), path);
710 }
711 
712 /**
713  * gtk_icon_file_selection_open_dir:
714  * @filesel: the #GtkIconFileSelection widget.
715  * @path: directory path.
716  *
717  * Show the file from path directory in filesel widget.
718  *
719  * Returns: TRUE or FALSE depending on success
720  */
721 gint
gtk_icon_file_selection_open_dir(GtkIconFileSel * filesel,const gchar * path)722 gtk_icon_file_selection_open_dir(GtkIconFileSel *filesel, const gchar *path)
723 {
724   DIR *dir;
725   gint return_val = TRUE;
726   gchar *real_path = NULL;
727 
728   if(!path) return FALSE;
729   real_path = get_real_path(path);
730 
731   if((dir = opendir(real_path)) == NULL){
732     g_warning("Can not open folder: %s",real_path);
733     g_free(real_path);
734     return FALSE;
735   }
736 
737   gtk_label_set_text(GTK_LABEL(filesel->path_label), "Scanning...");
738 
739   if(filesel->show_tree){
740 /* FIXME
741     return_val = gtk_dir_tree_open_dir(GTK_DIR_TREE(filesel->dir_tree), real_path);
742 */
743   } else
744     return_val = gtk_file_list_open_dir(GTK_FILE_LIST(filesel->file_list), real_path);
745 
746   gtk_label_set_text(GTK_LABEL(filesel->path_label), real_path);
747 
748   update_history_combo(filesel, (const gchar *)real_path);
749 
750   g_free(real_path);
751 
752   return return_val;
753 }
754 
755 /**
756  * gtk_icon_file_selection_show_hidden:
757  * @filesel: the #GtkIconFileSelection widget.
758  * @visible: TRUE(show hidden files) or FALSE(don't show hidden files).
759  *
760  * Set the visibility of hidden files.
761  */
762 void
gtk_icon_file_selection_show_hidden(GtkIconFileSel * filesel,gboolean visible)763 gtk_icon_file_selection_show_hidden(GtkIconFileSel *filesel, gboolean visible)
764 {
765 /* FIXME
766     GTK_DIR_TREE(filesel->dir_tree)->show_hidden = visible;
767 */
768     GTK_FILE_LIST(filesel->file_list)->show_hidden = visible;
769 }
770 
771 /**
772  * gtk_icon_file_selection_set_filter:
773  * @filesel: the #GtkIconFileSelection widget.
774  * @filter: filter to be applied on files.
775  *
776  * Set a filter for the files show in filelist.
777  */
778 void
gtk_icon_file_selection_set_filter(GtkIconFileSel * filesel,const gchar * filter)779 gtk_icon_file_selection_set_filter(GtkIconFileSel *filesel, const gchar *filter)
780 {
781   GTK_FILE_LIST(filesel->file_list)->filter = g_strdup(filter);
782   gtk_file_list_open_dir(GTK_FILE_LIST(filesel->file_list), GTK_FILE_LIST(filesel->file_list)->path);
783   update_history_combo(filesel, GTK_FILE_LIST(filesel->file_list)->path);
784   if(filter != NULL)
785     gtk_entry_set_text(GTK_ENTRY(filesel->filter_entry),filter);
786 }
787 
788 static gchar *
get_real_path(const gchar * full_path)789 get_real_path(const gchar *full_path)
790 {
791   gchar root[5], root1[5], root2[5], root3[5], root4[5];
792   gchar *aux_path;
793   gint length;
794 
795   /* GET ABSOLUTE PATH */
796 
797   sprintf(root,"%s",G_DIR_SEPARATOR_S);
798   sprintf(root1,"%s.",G_DIR_SEPARATOR_S);
799   sprintf(root2,"%s..",G_DIR_SEPARATOR_S);
800   sprintf(root3,"%s..%s",G_DIR_SEPARATOR_S,G_DIR_SEPARATOR_S);
801   sprintf(root4,"%s.%s",G_DIR_SEPARATOR_S,G_DIR_SEPARATOR_S);
802 
803   aux_path = g_strdup(full_path);
804   length = strlen(aux_path);
805 
806   if(strcmp(aux_path + length - 2, root1) == 0){
807      if(length == 2) {
808         g_free(aux_path);
809         aux_path = g_strdup(root);
810      } else {
811         aux_path[length - 2] = '\0';
812      }
813   } else if(strcmp(aux_path + length - 3, root2) == 0){
814      if(length == 3) {
815         g_free(aux_path);
816         aux_path = g_strdup(root);
817      } else {
818         gint i = length - 4;
819         while(i >= 0){
820            if(aux_path[i] == root[0]){
821                 aux_path[i] = '\0';
822                 break;
823            }
824            i--;
825         }
826      }
827   } else if(strcmp(aux_path + length - 4, root3) == 0){
828      if(length == 4) {
829         g_free(aux_path);
830         aux_path = g_strdup(root);
831      } else {
832         gint i = length - 5;
833         while(i >= 0){
834            if(aux_path[i] == root[0]){
835                 aux_path[i] = '\0';
836                 break;
837            }
838            i--;
839         }
840      }
841   } else if(strcmp(aux_path + length - 3, root4) == 0){
842      if(length == 3) {
843         g_free(aux_path);
844         aux_path = g_strdup(root);
845      } else {
846         aux_path[length - 3] = '\0';
847      }
848   } else if(strcmp(aux_path + length - 1, root) == 0 && length > 1){
849      aux_path[length - 1] = '\0';
850   }
851 
852   if(strlen(aux_path) == 0)
853   {
854     g_free(aux_path);
855     aux_path = g_strdup(G_DIR_SEPARATOR_S);
856   }
857 
858   return(aux_path);
859 }
860 
861 static void
init_history_combo(GtkIconFileSel * filesel,const gchar * current_directory)862 init_history_combo(GtkIconFileSel *filesel, const gchar *current_directory)
863 {
864   gchar *current_dir;
865   gint dir_len;
866   gint i;
867 
868   current_dir = g_strdup (current_directory);
869   dir_len = strlen (current_dir);
870 
871   for (i = dir_len - 1; i >= 0; i--){
872 
873     /* the i == dir_len is to catch the full path for the first
874      * entry. */
875     if ( current_dir[i] == G_DIR_SEPARATOR )
876     {
877 
878           current_dir[i + 1] = '\0';
879 	gtk_combo_box_append_text(GTK_COMBO_BOX(filesel->history_combo),
880 				current_dir);
881      }
882   }
883   gtk_combo_box_set_active (GTK_COMBO_BOX(filesel->history_combo), 0);
884   g_free(current_dir);
885 }
886 
887 
888 static void
update_history_combo(GtkIconFileSel * filesel,const gchar * current_directory)889 update_history_combo(GtkIconFileSel *filesel, const gchar *current_directory)
890 {
891   GtkComboBox *combo;
892   gchar *sel_dir;
893 
894   combo = GTK_COMBO_BOX(filesel->history_combo);
895   sel_dir = gtk_combo_box_get_active_text(GTK_COMBO_BOX(filesel->history_combo));
896   if (strcmp(current_directory, sel_dir) == 0)
897       return;
898   gtk_combo_box_prepend_text(combo, current_directory);
899   gtk_combo_box_set_active(combo, 0);
900   return;
901 }
902 
903 static void
go_to_history(const gchar * path,gpointer data)904 go_to_history(const gchar *path, gpointer data)
905 {
906   gchar *real_path;
907 
908   if(path[strlen(path)-1] != G_DIR_SEPARATOR)
909     real_path = g_strconcat(path, G_DIR_SEPARATOR_S, NULL);
910   else
911     real_path = g_strdup(path);
912   gtk_icon_file_selection_open_dir(GTK_ICON_FILESEL(data), real_path);
913   g_free(real_path);
914 }
915 
916 static gboolean
combo_changed(GtkWidget * widget,gpointer data)917 combo_changed(GtkWidget *widget, gpointer data)
918 {
919   GtkComboBox *comboBox;
920   GtkIconFileSel *filesel;
921   gchar *dir_selected;
922 
923   filesel = GTK_ICON_FILESEL(data);
924   comboBox = GTK_COMBO_BOX(filesel->history_combo);
925 
926   dir_selected = gtk_combo_box_get_active_text(comboBox);
927   go_to_history(dir_selected, filesel);
928   return TRUE;
929 
930 }
931 
932 static gboolean
entry_key_press(GtkWidget * widget,GdkEventKey * event,gpointer data)933 entry_key_press(GtkWidget *widget,
934 				GdkEventKey *event,
935 				gpointer data)
936 {
937 	GtkEntry *entry = GTK_ENTRY (widget);
938 
939 	if (event->keyval == GDK_KEY_Return)
940 	{
941 		g_signal_stop_emission_by_name( GTK_OBJECT(entry), "key_press_event");
942 		//RRRgo_to_history(entry, data);
943 		return TRUE;
944 	}
945 	return FALSE;
946 }
947 
948 /**
949  * gtk_icon_file_selection_get_selection:
950  * @filesel: the #GtkIconFileSelection widget.
951  *
952  * Gets the current selection applied on #GtkIconFileSelection.
953  *
954  * Returns: the current selection.
955  */
956 const gchar *
gtk_icon_file_selection_get_selection(GtkIconFileSel * filesel)957 gtk_icon_file_selection_get_selection(GtkIconFileSel *filesel)
958 {
959   return filesel->selection;
960 }
961