]> Pileus Git - ~andy/gtk/blob - gtk/gtkpathbar.c
Modified patch from muppet <scott@asofyet.org> to keep child directories
[~andy/gtk] / gtk / gtkpathbar.c
1 /* gtkpathbar.h
2  * Copyright (C) 2004  Red Hat, Inc.,  Jonathan Blandford <jrb@gnome.org>
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 #include <string.h>
21 #include "gtkpathbar.h"
22 #include "gtktogglebutton.h"
23 #include "gtkarrow.h"
24 #include "gtklabel.h"
25 #include "gtkmain.h"
26 #include "gtkmarshalers.h"
27
28 enum {
29   PATH_CLICKED,
30   LAST_SIGNAL
31 };
32
33 static guint path_bar_signals [LAST_SIGNAL] = { 0 };
34
35
36 G_DEFINE_TYPE (GtkPathBar,
37                gtk_path_bar,
38                GTK_TYPE_CONTAINER);
39
40
41 static void gtk_path_bar_finalize (GObject *object);
42 static void gtk_path_bar_size_request  (GtkWidget      *widget,
43                                         GtkRequisition *requisition);
44 static void gtk_path_bar_size_allocate (GtkWidget      *widget,
45                                         GtkAllocation  *allocation);
46 static void gtk_path_bar_direction_changed (GtkWidget *widget,
47                                             GtkTextDirection direction);
48 static void gtk_path_bar_add (GtkContainer *container,
49                               GtkWidget    *widget);
50 static void gtk_path_bar_remove (GtkContainer *container,
51                                  GtkWidget    *widget);
52 static void gtk_path_bar_forall (GtkContainer *container,
53                                  gboolean      include_internals,
54                                  GtkCallback   callback,
55                                  gpointer      callback_data);
56 static void gtk_path_bar_scroll_up (GtkWidget *button, GtkPathBar *path_bar);
57 static void gtk_path_bar_scroll_down (GtkWidget *button, GtkPathBar *path_bar);
58
59 static GtkWidget *
60 get_slider_button (GtkPathBar *path_bar)
61 {
62   GtkWidget *button;
63
64   gtk_widget_push_composite_child ();
65
66   button = gtk_button_new ();
67   gtk_container_add (GTK_CONTAINER (button), gtk_arrow_new (GTK_ARROW_RIGHT, GTK_SHADOW_OUT));
68   gtk_container_add (GTK_CONTAINER (path_bar), button);
69   gtk_widget_show_all (button);
70
71   gtk_widget_pop_composite_child ();
72
73   return button;
74 }
75
76 static void
77 gtk_path_bar_init (GtkPathBar *path_bar)
78 {
79   GTK_WIDGET_SET_FLAGS (path_bar, GTK_NO_WINDOW);
80   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (path_bar), FALSE);
81
82   path_bar->spacing = 3;
83   path_bar->up_slider_button = get_slider_button (path_bar);
84   path_bar->down_slider_button = get_slider_button (path_bar);
85
86   g_signal_connect (path_bar->up_slider_button, "clicked", G_CALLBACK (gtk_path_bar_scroll_up), path_bar);
87   g_signal_connect (path_bar->down_slider_button, "clicked", G_CALLBACK (gtk_path_bar_scroll_down), path_bar);
88 }
89
90 static void
91 gtk_path_bar_class_init (GtkPathBarClass *path_bar_class)
92 {
93   GObjectClass *gobject_class;
94   GtkObjectClass *object_class;
95   GtkWidgetClass *widget_class;
96   GtkContainerClass *container_class;
97
98   gobject_class = (GObjectClass *) path_bar_class;
99   object_class = (GtkObjectClass *) path_bar_class;
100   widget_class = (GtkWidgetClass *) path_bar_class;
101   container_class = (GtkContainerClass *) path_bar_class;
102
103   gobject_class->finalize = gtk_path_bar_finalize;
104
105   widget_class->size_request = gtk_path_bar_size_request;
106   widget_class->size_allocate = gtk_path_bar_size_allocate;
107   widget_class->direction_changed = gtk_path_bar_direction_changed;
108
109   container_class->add = gtk_path_bar_add;
110   container_class->forall = gtk_path_bar_forall;
111   container_class->remove = gtk_path_bar_remove;
112   /* FIXME: */
113   /*  container_class->child_type = gtk_path_bar_child_type;*/
114
115   path_bar_signals [PATH_CLICKED] =
116     g_signal_new ("path_clicked",
117                   G_OBJECT_CLASS_TYPE (object_class),
118                   G_SIGNAL_RUN_FIRST,
119                   G_STRUCT_OFFSET (GtkPathBarClass, path_clicked),
120                   NULL, NULL,
121                   _gtk_marshal_VOID__POINTER,
122                   G_TYPE_NONE, 1,
123                   G_TYPE_POINTER);
124 }
125
126
127 static void
128 gtk_path_bar_finalize (GObject *object)
129 {
130   GtkPathBar *path_bar;
131
132   path_bar = GTK_PATH_BAR (object);
133   g_list_free (path_bar->button_list);
134   if (path_bar->home_directory)
135     gtk_file_path_free (path_bar->home_directory);
136   if (path_bar->home_icon)
137     g_object_unref (path_bar->home_icon);
138   if (path_bar->root_icon)
139     g_object_unref (path_bar->home_icon);
140
141   G_OBJECT_CLASS (gtk_path_bar_parent_class)->finalize (object);
142 }
143
144 /* Size requisition:
145  * 
146  * Ideally, our size is determined by another widget, and we are just filling
147  * available space.
148  */
149 static void
150 gtk_path_bar_size_request (GtkWidget      *widget,
151                            GtkRequisition *requisition)
152 {
153   GtkPathBar *path_bar;
154   GtkRequisition child_requisition;
155   GList *list;
156
157   path_bar = GTK_PATH_BAR (widget);
158
159   requisition->width = 0;
160   requisition->height = 0;
161
162   for (list = path_bar->button_list; list; list = list->next)
163     {
164       gtk_widget_size_request (GTK_WIDGET (list->data),
165                                &child_requisition);
166       requisition->width = MAX (child_requisition.width, requisition->width);
167       requisition->height = MAX (child_requisition.height, requisition->height);
168     }
169
170   /* Add space for slider, if we have more than one path */
171   /* Theoretically, the slider could be bigger than the other button.  But we're
172    * not going to worry about that now.
173    */
174   path_bar->slider_width = requisition->height / 2 + 5;
175   if (path_bar->button_list && path_bar->button_list->next != NULL)
176     requisition->width += (path_bar->spacing + path_bar->slider_width) * 2;
177
178   gtk_widget_size_request (path_bar->up_slider_button, &child_requisition);
179   gtk_widget_size_request (path_bar->down_slider_button, &child_requisition);
180
181   requisition->width += GTK_CONTAINER (widget)->border_width * 2;
182   requisition->height += GTK_CONTAINER (widget)->border_width * 2;
183
184   widget->requisition = *requisition;
185 }
186
187 static void
188 gtk_path_bar_update_slider_buttons (GtkPathBar *path_bar)
189 {
190   GtkTextDirection direction;
191
192   direction = gtk_widget_get_direction (GTK_WIDGET (path_bar));
193   if (direction == GTK_TEXT_DIR_RTL)
194     {
195       GtkWidget *arrow;
196
197       arrow = gtk_bin_get_child (GTK_BIN (path_bar->up_slider_button));
198       g_object_set (arrow, "arrow_type", GTK_ARROW_RIGHT, NULL);
199
200       arrow = gtk_bin_get_child (GTK_BIN (path_bar->down_slider_button));
201       g_object_set (arrow, "arrow_type", GTK_ARROW_LEFT, NULL);
202     }
203   else
204     {
205       GtkWidget *arrow;
206
207       arrow = gtk_bin_get_child (GTK_BIN (path_bar->up_slider_button));
208       g_object_set (arrow, "arrow_type", GTK_ARROW_LEFT, NULL);
209
210       arrow = gtk_bin_get_child (GTK_BIN (path_bar->down_slider_button));
211       g_object_set (arrow, "arrow_type", GTK_ARROW_RIGHT, NULL);
212     }
213
214   if (path_bar->button_list)
215     {
216       GtkWidget *button;
217
218       button = path_bar->button_list->data;
219       if (gtk_widget_get_child_visible (button))
220         gtk_widget_set_sensitive (path_bar->down_slider_button, FALSE);
221       else
222         gtk_widget_set_sensitive (path_bar->down_slider_button, TRUE);
223
224       button = g_list_last (path_bar->button_list)->data;
225       if (gtk_widget_get_child_visible (button))
226         gtk_widget_set_sensitive (path_bar->up_slider_button, FALSE);
227       else
228         gtk_widget_set_sensitive (path_bar->up_slider_button, TRUE);
229     }
230 }
231
232 /* This is a tad complicated
233  */
234 static void
235 gtk_path_bar_size_allocate (GtkWidget     *widget,
236                             GtkAllocation *allocation)
237 {
238   GtkWidget *child;
239   GtkPathBar *path_bar = GTK_PATH_BAR (widget);
240   GtkTextDirection direction;
241   GtkAllocation child_allocation;
242   GList *list, *first_button;
243   gint width;
244   gint allocation_width;
245   gint border_width;
246   gboolean need_sliders = FALSE;
247   gint up_slider_offset = 0;
248   gint down_slider_offset = 0;
249
250   widget->allocation = *allocation;
251
252   /* No path is set; we don't have to allocate anything. */
253   if (path_bar->button_list == NULL)
254     return;
255
256   direction = gtk_widget_get_direction (widget);
257   border_width = (gint) GTK_CONTAINER (path_bar)->border_width;
258   allocation_width = allocation->width - 2 * border_width;
259
260   /* First, we check to see if we need the scrollbars. */
261   width = GTK_WIDGET (path_bar->button_list->data)->requisition.width;
262   for (list = path_bar->button_list->next; list; list = list->next)
263     {
264       child = GTK_WIDGET (list->data);
265
266       width += child->requisition.width + path_bar->spacing;
267     }
268
269   if (width <= allocation_width)
270     {
271       first_button = g_list_last (path_bar->button_list);
272     }
273   else
274     {
275       gboolean reached_end = FALSE;
276       gint slider_space = 2 * (path_bar->spacing + path_bar->slider_width);
277
278       if (path_bar->first_scrolled_button)
279         first_button = path_bar->first_scrolled_button;
280       else
281         first_button = path_bar->button_list;
282       need_sliders = TRUE;
283       
284       /* To see how much space we have, and how many buttons we can display.
285        * We start at the first button, count forward until hit the new
286        * button, then count backwards.
287        */
288       /* Count down the path chain towards the end. */
289       width = GTK_WIDGET (first_button->data)->requisition.width;
290       list = first_button->prev;
291       while (list && !reached_end)
292         {
293           child = GTK_WIDGET (list->data);
294
295           if (width + child->requisition.width +
296               path_bar->spacing + slider_space > allocation_width)
297             reached_end = TRUE;
298           else
299             width += child->requisition.width + path_bar->spacing;
300
301           list = list->prev;
302         }
303
304       /* Finally, we walk up, seeing how many of the previous buttons we can
305        * add */
306       while (first_button->next && ! reached_end)
307         {
308           child = GTK_WIDGET (first_button->next->data);
309
310           if (width + child->requisition.width + path_bar->spacing + slider_space > allocation_width)
311             {
312               reached_end = TRUE;
313             }
314           else
315             {
316               width += child->requisition.width + path_bar->spacing;
317               first_button = first_button->next;
318             }
319         }
320     }
321
322   /* Now, we allocate space to the buttons */
323   child_allocation.y = allocation->y + border_width;
324   child_allocation.height = MAX (1, (gint) allocation->height - border_width * 2);
325
326   if (direction == GTK_TEXT_DIR_RTL)
327     {
328       child_allocation.x = allocation->x + allocation->width - border_width;
329       if (need_sliders)
330         {
331           child_allocation.x -= (path_bar->spacing + path_bar->slider_width);
332           up_slider_offset = allocation->width - border_width - path_bar->slider_width;
333         }
334     }
335   else
336     {
337       child_allocation.x = allocation->x + border_width;
338       if (need_sliders)
339         {
340           up_slider_offset = border_width;
341           child_allocation.x += (path_bar->spacing + path_bar->slider_width);
342         }
343     }
344
345   for (list = first_button; list; list = list->prev)
346     {
347       child = GTK_WIDGET (list->data);
348
349       child_allocation.width = child->requisition.width;
350       if (direction == GTK_TEXT_DIR_RTL)
351         child_allocation.x -= child_allocation.width;
352
353       /* Check to see if we've don't have any more space to allocate buttons */
354       if (need_sliders && direction == GTK_TEXT_DIR_RTL)
355         {
356           if (child_allocation.x - path_bar->spacing - path_bar->slider_width < widget->allocation.x + border_width)
357             break;
358         }
359       else if (need_sliders && direction == GTK_TEXT_DIR_LTR)
360         {
361           if (child_allocation.x + child_allocation.width + path_bar->spacing + path_bar->slider_width >
362               widget->allocation.x + border_width + allocation_width)
363             break;
364         }
365
366       gtk_widget_set_child_visible (list->data, TRUE);
367       gtk_widget_size_allocate (child, &child_allocation);
368
369       if (direction == GTK_TEXT_DIR_RTL)
370         {
371           child_allocation.x -= path_bar->spacing;
372           down_slider_offset = child_allocation.x - widget->allocation.x - path_bar->slider_width;
373         }
374       else
375         {
376           child_allocation.x += child_allocation.width + path_bar->spacing;
377           down_slider_offset = child_allocation.x - widget->allocation.x;
378         }
379     }
380   /* Now we go hide all the widgets that don't fit */
381   while (list)
382     {
383       gtk_widget_set_child_visible (list->data, FALSE);
384       list = list->prev;
385     }
386   for (list = first_button->next; list; list = list->next)
387     {
388       gtk_widget_set_child_visible (list->data, FALSE);
389     }
390
391   if (need_sliders)
392     {
393       child_allocation.width = path_bar->slider_width;
394       
395       child_allocation.x = up_slider_offset + allocation->x;
396       gtk_widget_size_allocate (path_bar->up_slider_button, &child_allocation);
397
398       child_allocation.x = down_slider_offset + allocation->x;
399       gtk_widget_size_allocate (path_bar->down_slider_button, &child_allocation);
400
401       gtk_widget_set_child_visible (path_bar->up_slider_button, TRUE);
402       gtk_widget_set_child_visible (path_bar->down_slider_button, TRUE);
403       gtk_widget_show_all (path_bar->up_slider_button);
404       gtk_widget_show_all (path_bar->down_slider_button);
405       gtk_path_bar_update_slider_buttons (path_bar);
406     }
407   else
408     {
409       gtk_widget_set_child_visible (path_bar->up_slider_button, FALSE);
410       gtk_widget_set_child_visible (path_bar->down_slider_button, FALSE);
411     }
412 }
413
414 static void
415  gtk_path_bar_direction_changed (GtkWidget *widget,
416                                  GtkTextDirection direction)
417 {
418   gtk_path_bar_update_slider_buttons (GTK_PATH_BAR (widget));
419
420   (* GTK_WIDGET_CLASS (gtk_path_bar_parent_class)->direction_changed) (widget, direction);
421 }
422
423 static void
424 gtk_path_bar_add (GtkContainer *container,
425                   GtkWidget    *widget)
426 {
427   gtk_widget_set_parent (widget, GTK_WIDGET (container));
428 }
429
430 static void
431 gtk_path_bar_remove (GtkContainer *container,
432                      GtkWidget    *widget)
433 {
434   GtkPathBar *path_bar;
435   GList *children;
436
437   path_bar = GTK_PATH_BAR (container);
438
439   children = path_bar->button_list;
440
441   while (children)
442     {
443       if (widget == children->data)
444         {
445           gboolean was_visible;
446
447           was_visible = GTK_WIDGET_VISIBLE (widget);
448           gtk_widget_unparent (widget);
449
450           path_bar->button_list = g_list_remove_link (path_bar->button_list, children);
451           g_list_free (children);
452
453           if (was_visible)
454             gtk_widget_queue_resize (GTK_WIDGET (container));
455           break;
456         }
457       
458       children = children->next;
459     }
460 }
461
462 static void
463 gtk_path_bar_forall (GtkContainer *container,
464                      gboolean      include_internals,
465                      GtkCallback   callback,
466                      gpointer      callback_data)
467 {
468   GtkPathBar *path_bar;
469   GList *children;
470
471   g_return_if_fail (callback != NULL);
472   path_bar = GTK_PATH_BAR (container);
473
474   children = path_bar->button_list;
475   while (children)
476     {
477       GtkWidget *child;
478       child = children->data;
479       children = children->next;
480
481       (* callback) (child, callback_data);
482     }
483
484   (* callback) (path_bar->up_slider_button, callback_data);
485   (* callback) (path_bar->down_slider_button, callback_data);
486 }
487
488 static void
489  gtk_path_bar_scroll_down (GtkWidget *button, GtkPathBar *path_bar)
490 {
491   GList *list;
492   GList *down_button = NULL;
493   GList *up_button = NULL;
494   gint space_available;
495   gint space_needed;
496   gint border_width;
497   GtkTextDirection direction;
498   
499   border_width = GTK_CONTAINER (path_bar)->border_width;
500   direction = gtk_widget_get_direction (GTK_WIDGET (path_bar));
501   
502   /* We find the button at the 'down' end that we have to make
503    * visible */
504   for (list = path_bar->button_list; list; list = list->next)
505     {
506       if (list->next && gtk_widget_get_child_visible (GTK_WIDGET (list->next->data)))
507         {
508           down_button = list;
509           break;
510         }
511     }
512   
513   /* Find the last visible button on the 'up' end
514    */
515   for (list = g_list_last (path_bar->button_list); list; list = list->prev)
516     {
517       if (gtk_widget_get_child_visible (GTK_WIDGET (list->data)))
518         {
519           up_button = list;
520           break;
521         }
522     }
523
524   space_needed = GTK_WIDGET (down_button->data)->allocation.width + path_bar->spacing;
525   if (direction == GTK_TEXT_DIR_RTL)
526     space_available = GTK_WIDGET (path_bar)->allocation.x + GTK_WIDGET (path_bar)->allocation.width;
527   else
528     space_available = (GTK_WIDGET (path_bar)->allocation.x + GTK_WIDGET (path_bar)->allocation.width - border_width) -
529       (path_bar->down_slider_button->allocation.x + path_bar->down_slider_button->allocation.width);
530
531   /* We have space_available extra space that's not being used.  We
532    * need space_needed space to make the button fit.  So we walk down
533    * from the end, removing buttons until we get all the space we
534    * need. */
535   while (space_available < space_needed)
536     {
537       space_available += GTK_WIDGET (up_button->data)->allocation.width + path_bar->spacing;
538       up_button = up_button->prev;
539       path_bar->first_scrolled_button = up_button;
540     }
541 }
542
543 static void
544  gtk_path_bar_scroll_up (GtkWidget *button, GtkPathBar *path_bar)
545 {
546   GList *list;
547
548   for (list = g_list_last (path_bar->button_list); list; list = list->prev)
549     {
550       if (list->prev && gtk_widget_get_child_visible (GTK_WIDGET (list->prev->data)))
551         {
552           path_bar->first_scrolled_button = list;
553           return;
554         }
555     }
556 }
557
558
559
560 /* Public functions. */
561 static void
562 gtk_path_bar_clear_buttons (GtkPathBar *path_bar)
563 {
564   while (path_bar->button_list != NULL)
565     {
566       gtk_container_remove (GTK_CONTAINER (path_bar), path_bar->button_list->data);
567     }
568   path_bar->first_scrolled_button = NULL;
569 }
570
571 static void
572 button_clicked_cb (GtkWidget *button,
573                    gpointer   data)
574 {
575   GtkWidget *path_bar;
576   GtkFilePath *file_path;
577
578   path_bar = button->parent;
579   g_assert (GTK_IS_PATH_BAR (path_bar));
580
581   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
582
583   file_path = g_object_get_data (G_OBJECT (button), "gtk-path-bar-button-path");
584   g_signal_emit (path_bar, path_bar_signals [PATH_CLICKED], 0, file_path);
585 }
586
587 static void
588 update_button_appearance (GtkWidget *button,
589                           gboolean   current_dir)
590 {
591   GtkWidget *label;
592   const gchar *dir_name;
593
594   dir_name = (const gchar *) g_object_get_data (G_OBJECT (button),
595                                                 "gtk-path-bar-button-dir-name");
596   label = gtk_bin_get_child (GTK_BIN (button));
597
598   if (current_dir)
599     {
600       char *markup;
601
602       markup = g_markup_printf_escaped ("<b>%s</b>", dir_name);
603       gtk_label_set_markup (GTK_LABEL (label), markup);
604       g_free (markup);
605     }
606   else
607     {
608       gtk_label_set_text (GTK_LABEL (label), dir_name);
609     }
610
611   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) != current_dir)
612     {
613       g_signal_handlers_block_by_func (G_OBJECT (button), button_clicked_cb, NULL);
614       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), current_dir);
615       g_signal_handlers_unblock_by_func (G_OBJECT (button), button_clicked_cb, NULL);
616     }
617 }
618
619 /* Since gtk_file_path_free() can be a macro, we provide a real function that
620  * can be used as a callback.
621  */
622 static void
623 file_path_destroy (GtkFilePath *path)
624 {
625   gtk_file_path_free (path);
626 }
627
628 static GtkWidget *
629 make_directory_button (const char  *dir_name,
630                        GtkFilePath *path,
631                        gboolean     current_dir)
632 {
633   GtkWidget *button, *label;
634       
635   button = gtk_toggle_button_new ();
636   label = gtk_label_new (NULL);
637
638   g_signal_connect (button, "clicked",
639                     G_CALLBACK (button_clicked_cb),
640                     NULL);
641
642   g_object_set_data_full (G_OBJECT (button), "gtk-path-bar-button-dir-name",
643                           g_strdup (dir_name),
644                           (GDestroyNotify) g_free);
645   g_object_set_data_full (G_OBJECT (button), "gtk-path-bar-button-path",
646                           gtk_file_path_new_dup (gtk_file_path_get_string (path)),
647                           (GDestroyNotify) file_path_destroy);
648
649   gtk_container_add (GTK_CONTAINER (button), label);
650   gtk_widget_show_all (button);
651
652   update_button_appearance (button, current_dir);
653
654   return button;
655 }
656
657 static gboolean
658 gtk_path_bar_check_parent_path (GtkPathBar         *path_bar,
659                                 const GtkFilePath  *file_path,
660                                 GtkFileSystem      *file_system)
661 {
662   GList *list;
663   GList *current_path = NULL;
664
665   for (list = path_bar->button_list; list; list = list->next)
666     {
667       GtkFilePath *tmp_path;
668
669       tmp_path = (GtkFilePath *) g_object_get_data (G_OBJECT (list->data),
670                                                     "gtk-path-bar-button-path");
671       if (! gtk_file_path_compare (file_path, tmp_path))
672         {
673           current_path = list;
674           break;
675         }
676
677     }
678
679   if (current_path)
680     {
681       for (list = path_bar->button_list; list; list = list->next)
682         {
683           update_button_appearance (GTK_WIDGET (list->data),
684                                     (list == current_path) ? TRUE : FALSE);
685         }
686       return TRUE;
687     }
688   return FALSE;
689 }
690
691 gboolean
692 _gtk_path_bar_set_path (GtkPathBar         *path_bar,
693                         const GtkFilePath  *file_path,
694                         GtkFileSystem      *file_system,
695                         GError            **error)
696 {
697   GtkFilePath *path;
698   gboolean first_directory = TRUE;
699   gboolean result;
700
701   g_return_val_if_fail (GTK_IS_PATH_BAR (path_bar), FALSE);
702   g_return_val_if_fail (file_path != NULL, FALSE);
703   g_return_val_if_fail (file_system != NULL, FALSE);
704
705   result = TRUE;
706
707   if (gtk_path_bar_check_parent_path (path_bar, file_path, file_system))
708     return TRUE;
709       
710   gtk_path_bar_clear_buttons (path_bar);
711   path = gtk_file_path_copy (file_path);
712
713   gtk_widget_push_composite_child ();
714
715   while (path != NULL)
716     {
717       GtkFilePath *parent_path = NULL;
718       GtkWidget *button;
719       const gchar *display_name;
720       GError *err = NULL;
721       GtkFileFolder *file_folder;
722       GtkFileInfo *file_info;
723       gboolean valid;
724
725       valid = gtk_file_system_get_parent (file_system,
726                                           path,
727                                           &parent_path,
728                                           &err);
729       if (!valid)
730         {
731           result = FALSE;
732           g_propagate_error (error, err);
733           gtk_file_path_free (path);
734           break;
735         }
736
737       if (parent_path)
738         file_folder = gtk_file_system_get_folder (file_system, parent_path,
739                                                   GTK_FILE_INFO_DISPLAY_NAME, NULL);
740       else
741         file_folder = gtk_file_system_get_folder (file_system, path,
742                                                   GTK_FILE_INFO_DISPLAY_NAME, NULL);
743
744       file_info = gtk_file_folder_get_info (file_folder, path, &err);
745       if (!file_info)
746         {
747           result = FALSE;
748           g_propagate_error (error, err);
749           g_object_unref (file_folder);
750           gtk_file_path_free (parent_path);
751           gtk_file_path_free (path);
752           break;
753         }
754
755       display_name = gtk_file_info_get_display_name (file_info);
756       /* FIXME: Do this better */
757       if (! strcmp ("/", display_name))
758         display_name = " / ";
759       button = make_directory_button (display_name, path, first_directory);
760       gtk_file_info_free (file_info);
761       gtk_file_path_free (path);
762       g_object_unref (file_folder);
763
764       gtk_container_add (GTK_CONTAINER (path_bar), button);
765       path_bar->button_list = g_list_prepend (path_bar->button_list, button);
766
767       path = parent_path;
768       first_directory = FALSE;
769     }
770
771   gtk_widget_pop_composite_child ();
772
773   path_bar->button_list = g_list_reverse (path_bar->button_list);
774
775   return result;
776 }
777
778 void
779 gtk_path_bar_set_root_icon (GtkPathBar *path_bar,
780                             GdkPixbuf  *root_icon)
781 {
782   g_return_if_fail (GTK_IS_PATH_BAR (path_bar));
783
784   if (root_icon)
785     path_bar->home_icon = g_object_ref (root_icon);
786
787   if (path_bar->root_icon)
788     g_object_unref (root_icon);
789
790   path_bar->root_icon = root_icon;
791 }
792
793 void
794 gtk_path_bar_set_home_icon (GtkPathBar        *path_bar,
795                             const GtkFilePath *home_directory,
796                             GdkPixbuf         *home_icon)
797 {
798   g_return_if_fail (GTK_IS_PATH_BAR (path_bar));
799
800   if (home_icon)
801     g_object_ref (home_icon);
802
803   if (path_bar->home_directory != NULL)
804     gtk_file_path_free (path_bar->home_directory);
805   if (path_bar->home_icon)
806     g_object_unref (home_icon);
807
808   if (home_directory)
809     path_bar->home_directory = gtk_file_path_new_dup (gtk_file_path_get_string (home_directory));
810   else
811     path_bar->home_directory = NULL;
812   path_bar->home_icon = home_icon;
813 }
814