2 * Copyright (C) 2004 Red Hat, Inc., Jonathan Blandford <jrb@gnome.org>
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.
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.
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.
22 #include <eel/eel-debug.h>
23 #include <eel/eel-gtk-extensions.h>
24 #include <eel/eel-glib-extensions.h>
25 #include <eel/eel-preferences.h>
26 #include <eel/eel-string.h>
27 #include <gtk/gtktogglebutton.h>
28 #include <gtk/gtkalignment.h>
29 #include <gtk/gtkarrow.h>
30 #include <gtk/gtkdnd.h>
31 #include <gtk/gtkimage.h>
32 #include <gtk/gtklabel.h>
33 #include <gtk/gtkhbox.h>
34 #include <gtk/gtkmain.h>
35 #include <glib/gi18n.h>
37 #include <libnautilus-private/nautilus-file.h>
38 #include <libnautilus-private/nautilus-file-utilities.h>
39 #include <libnautilus-private/nautilus-global-preferences.h>
40 #include <libnautilus-private/nautilus-icon-names.h>
41 #include <libnautilus-private/nautilus-trash-monitor.h>
42 #include "nautilus-pathbar.h"
57 #define BUTTON_DATA(x) ((ButtonData *)(x))
59 #define SCROLL_TIMEOUT 150
60 #define INITIAL_SCROLL_TIMEOUT 300
62 static guint path_bar_signals
[LAST_SIGNAL
] = { 0 };
64 static gboolean desktop_is_home
;
66 #define NAUTILUS_PATH_BAR_ICON_SIZE 16
68 typedef struct _ButtonData ButtonData
;
78 GdkPixbuf
*custom_icon
;
80 /* flag to indicate its the base folder in the URI */
85 guint ignore_changes
: 1;
86 guint file_is_hidden
: 1;
89 /* This macro is used to check if a button can be used as a fake root.
90 * All buttons in front of a fake root are automatically hidden when in a
91 * directory below a fake root and replaced with the "<" arrow button.
93 #define BUTTON_IS_FAKE_ROOT(button) ((button)->type == HOME_BUTTON || (button)->type == MOUNT_BUTTON)
95 G_DEFINE_TYPE (NautilusPathBar
,
99 static void nautilus_path_bar_finalize (GObject
*object
);
100 static void nautilus_path_bar_dispose (GObject
*object
);
101 static void nautilus_path_bar_size_request (GtkWidget
*widget
,
102 GtkRequisition
*requisition
);
103 static void nautilus_path_bar_unmap (GtkWidget
*widget
);
104 static void nautilus_path_bar_size_allocate (GtkWidget
*widget
,
105 GtkAllocation
*allocation
);
106 static void nautilus_path_bar_add (GtkContainer
*container
,
108 static void nautilus_path_bar_remove (GtkContainer
*container
,
110 static void nautilus_path_bar_forall (GtkContainer
*container
,
111 gboolean include_internals
,
112 GtkCallback callback
,
113 gpointer callback_data
);
114 static void nautilus_path_bar_scroll_up (GtkWidget
*button
,
115 NautilusPathBar
*path_bar
);
116 static void nautilus_path_bar_scroll_down (GtkWidget
*button
,
117 NautilusPathBar
*path_bar
);
118 static void nautilus_path_bar_stop_scrolling (NautilusPathBar
*path_bar
);
119 static gboolean
nautilus_path_bar_slider_button_press (GtkWidget
*widget
,
120 GdkEventButton
*event
,
121 NautilusPathBar
*path_bar
);
122 static gboolean
nautilus_path_bar_slider_button_release (GtkWidget
*widget
,
123 GdkEventButton
*event
,
124 NautilusPathBar
*path_bar
);
125 static void nautilus_path_bar_grab_notify (GtkWidget
*widget
,
126 gboolean was_grabbed
);
127 static void nautilus_path_bar_state_changed (GtkWidget
*widget
,
128 GtkStateType previous_state
);
129 static void nautilus_path_bar_style_set (GtkWidget
*widget
,
130 GtkStyle
*previous_style
);
131 static void nautilus_path_bar_screen_changed (GtkWidget
*widget
,
132 GdkScreen
*previous_screen
);
133 static void nautilus_path_bar_check_icon_theme (NautilusPathBar
*path_bar
);
134 static void nautilus_path_bar_update_button_appearance (NautilusPathBar
*path_bar
,
135 ButtonData
*button_data
,
136 gboolean current_dir
);
137 static gboolean
nautilus_path_bar_update_path (NautilusPathBar
*path_bar
,
141 get_slider_button (NautilusPathBar
*path_bar
,
142 GtkArrowType arrow_type
)
146 gtk_widget_push_composite_child ();
148 button
= gtk_button_new ();
149 gtk_button_set_focus_on_click (GTK_BUTTON (button
), FALSE
);
150 gtk_container_add (GTK_CONTAINER (button
), gtk_arrow_new (arrow_type
, GTK_SHADOW_OUT
));
151 gtk_container_add (GTK_CONTAINER (path_bar
), button
);
152 gtk_widget_show_all (button
);
154 gtk_widget_pop_composite_child ();
160 update_button_types (NautilusPathBar
*path_bar
)
165 for (list
= path_bar
->button_list
; list
; list
= list
->next
) {
166 ButtonData
*button_data
;
167 button_data
= BUTTON_DATA (list
->data
);
168 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_data
->button
))) {
169 path
= button_data
->path
;
174 nautilus_path_bar_update_path (path_bar
, path
);
180 desktop_location_changed_callback (gpointer user_data
)
182 NautilusPathBar
*path_bar
;
184 path_bar
= NAUTILUS_PATH_BAR (user_data
);
186 g_object_unref (path_bar
->desktop_path
);
187 g_object_unref (path_bar
->home_path
);
188 path_bar
->desktop_path
= nautilus_get_desktop_location ();
189 path_bar
->home_path
= g_file_new_for_path (g_get_home_dir ());
190 desktop_is_home
= g_file_equal (path_bar
->home_path
, path_bar
->desktop_path
);
192 if (path_bar
->home_icon
) {
193 g_object_unref (path_bar
->home_icon
);
194 path_bar
->home_icon
= NULL
;
197 update_button_types (path_bar
);
201 trash_state_changed_cb (NautilusTrashMonitor
*monitor
,
203 NautilusPathBar
*path_bar
)
208 file
= g_file_new_for_uri ("trash:///");
209 for (list
= path_bar
->button_list
; list
; list
= list
->next
) {
210 ButtonData
*button_data
;
211 button_data
= BUTTON_DATA (list
->data
);
212 if (g_file_equal (file
, button_data
->path
)) {
214 NautilusIconInfo
*icon_info
;
217 icon
= nautilus_trash_monitor_get_icon ();
218 icon_info
= nautilus_icon_info_lookup (icon
, NAUTILUS_PATH_BAR_ICON_SIZE
);
219 pixbuf
= nautilus_icon_info_get_pixbuf_at_size (icon_info
, NAUTILUS_PATH_BAR_ICON_SIZE
);
220 gtk_image_set_from_pixbuf (GTK_IMAGE (button_data
->image
), pixbuf
);
223 g_object_unref (file
);
227 nautilus_path_bar_init (NautilusPathBar
*path_bar
)
231 GTK_WIDGET_SET_FLAGS (path_bar
, GTK_NO_WINDOW
);
232 gtk_widget_set_redraw_on_allocate (GTK_WIDGET (path_bar
), FALSE
);
234 path_bar
->spacing
= 3;
235 path_bar
->up_slider_button
= get_slider_button (path_bar
, GTK_ARROW_LEFT
);
236 path_bar
->down_slider_button
= get_slider_button (path_bar
, GTK_ARROW_RIGHT
);
237 path_bar
->icon_size
= NAUTILUS_PATH_BAR_ICON_SIZE
;
239 p
= nautilus_get_desktop_directory ();
240 path_bar
->desktop_path
= g_file_new_for_path (p
);
242 path_bar
->home_path
= g_file_new_for_path (g_get_home_dir ());
243 path_bar
->root_path
= g_file_new_for_path ("/");
244 desktop_is_home
= g_file_equal (path_bar
->home_path
, path_bar
->desktop_path
);
246 eel_preferences_add_callback_while_alive (NAUTILUS_PREFERENCES_DESKTOP_IS_HOME_DIR
,
247 desktop_location_changed_callback
,
249 G_OBJECT (path_bar
));
251 g_signal_connect (path_bar
->up_slider_button
, "clicked", G_CALLBACK (nautilus_path_bar_scroll_up
), path_bar
);
252 g_signal_connect (path_bar
->down_slider_button
, "clicked", G_CALLBACK (nautilus_path_bar_scroll_down
), path_bar
);
254 g_signal_connect (path_bar
->up_slider_button
, "button_press_event", G_CALLBACK (nautilus_path_bar_slider_button_press
), path_bar
);
255 g_signal_connect (path_bar
->up_slider_button
, "button_release_event", G_CALLBACK (nautilus_path_bar_slider_button_release
), path_bar
);
256 g_signal_connect (path_bar
->down_slider_button
, "button_press_event", G_CALLBACK (nautilus_path_bar_slider_button_press
), path_bar
);
257 g_signal_connect (path_bar
->down_slider_button
, "button_release_event", G_CALLBACK (nautilus_path_bar_slider_button_release
), path_bar
);
259 g_signal_connect (nautilus_trash_monitor_get (),
260 "trash_state_changed",
261 G_CALLBACK (trash_state_changed_cb
),
266 nautilus_path_bar_class_init (NautilusPathBarClass
*path_bar_class
)
268 GObjectClass
*gobject_class
;
269 GtkObjectClass
*object_class
;
270 GtkWidgetClass
*widget_class
;
271 GtkContainerClass
*container_class
;
273 gobject_class
= (GObjectClass
*) path_bar_class
;
274 object_class
= (GtkObjectClass
*) path_bar_class
;
275 widget_class
= (GtkWidgetClass
*) path_bar_class
;
276 container_class
= (GtkContainerClass
*) path_bar_class
;
278 gobject_class
->finalize
= nautilus_path_bar_finalize
;
279 gobject_class
->dispose
= nautilus_path_bar_dispose
;
281 widget_class
->size_request
= nautilus_path_bar_size_request
;
282 widget_class
->unmap
= nautilus_path_bar_unmap
;
283 widget_class
->size_allocate
= nautilus_path_bar_size_allocate
;
284 widget_class
->style_set
= nautilus_path_bar_style_set
;
285 widget_class
->screen_changed
= nautilus_path_bar_screen_changed
;
286 widget_class
->grab_notify
= nautilus_path_bar_grab_notify
;
287 widget_class
->state_changed
= nautilus_path_bar_state_changed
;
289 container_class
->add
= nautilus_path_bar_add
;
290 container_class
->forall
= nautilus_path_bar_forall
;
291 container_class
->remove
= nautilus_path_bar_remove
;
293 path_bar_signals
[PATH_CLICKED
] =
294 g_signal_new ("path-clicked",
295 G_OBJECT_CLASS_TYPE (object_class
),
297 G_STRUCT_OFFSET (NautilusPathBarClass
, path_clicked
),
299 g_cclosure_marshal_VOID__OBJECT
,
306 nautilus_path_bar_finalize (GObject
*object
)
308 NautilusPathBar
*path_bar
;
310 path_bar
= NAUTILUS_PATH_BAR (object
);
312 nautilus_path_bar_stop_scrolling (path_bar
);
314 g_list_free (path_bar
->button_list
);
315 if (path_bar
->root_path
) {
316 g_object_unref (path_bar
->root_path
);
317 path_bar
->root_path
= NULL
;
319 if (path_bar
->home_path
) {
320 g_object_unref (path_bar
->home_path
);
321 path_bar
->home_path
= NULL
;
323 if (path_bar
->desktop_path
) {
324 g_object_unref (path_bar
->desktop_path
);
325 path_bar
->desktop_path
= NULL
;
328 if (path_bar
->root_icon
) {
329 g_object_unref (path_bar
->root_icon
);
330 path_bar
->root_icon
= NULL
;
332 if (path_bar
->home_icon
) {
333 g_object_unref (path_bar
->home_icon
);
334 path_bar
->home_icon
= NULL
;
336 if (path_bar
->desktop_icon
) {
337 g_object_unref (path_bar
->desktop_icon
);
338 path_bar
->desktop_icon
= NULL
;
341 g_signal_handlers_disconnect_by_func (nautilus_trash_monitor_get (),
342 trash_state_changed_cb
, path_bar
);
344 G_OBJECT_CLASS (nautilus_path_bar_parent_class
)->finalize (object
);
347 /* Removes the settings signal handler. It's safe to call multiple times */
349 remove_settings_signal (NautilusPathBar
*path_bar
,
352 if (path_bar
->settings_signal_id
) {
353 GtkSettings
*settings
;
355 settings
= gtk_settings_get_for_screen (screen
);
356 g_signal_handler_disconnect (settings
,
357 path_bar
->settings_signal_id
);
358 path_bar
->settings_signal_id
= 0;
363 nautilus_path_bar_dispose (GObject
*object
)
365 remove_settings_signal (NAUTILUS_PATH_BAR (object
), gtk_widget_get_screen (GTK_WIDGET (object
)));
367 G_OBJECT_CLASS (nautilus_path_bar_parent_class
)->dispose (object
);
372 * Ideally, our size is determined by another widget, and we are just filling
376 nautilus_path_bar_size_request (GtkWidget
*widget
,
377 GtkRequisition
*requisition
)
379 ButtonData
*button_data
;
380 NautilusPathBar
*path_bar
;
381 GtkRequisition child_requisition
;
384 path_bar
= NAUTILUS_PATH_BAR (widget
);
386 requisition
->width
= 0;
387 requisition
->height
= 0;
389 for (list
= path_bar
->button_list
; list
; list
= list
->next
) {
390 button_data
= BUTTON_DATA (list
->data
);
391 gtk_widget_size_request (button_data
->button
, &child_requisition
);
392 requisition
->width
= MAX (child_requisition
.width
, requisition
->width
);
393 requisition
->height
= MAX (child_requisition
.height
, requisition
->height
);
396 /* Add space for slider, if we have more than one path */
397 /* Theoretically, the slider could be bigger than the other button. But we're */
398 /* not going to worry about that now.*/
400 path_bar
->slider_width
= MIN(requisition
->height
* 2 / 3 + 5, requisition
->height
);
401 if (path_bar
->button_list
&& path_bar
->button_list
->next
!= NULL
) {
402 requisition
->width
+= (path_bar
->spacing
+ path_bar
->slider_width
) * 2;
405 gtk_widget_size_request (path_bar
->up_slider_button
, &child_requisition
);
406 gtk_widget_size_request (path_bar
->down_slider_button
, &child_requisition
);
408 requisition
->width
+= GTK_CONTAINER (widget
)->border_width
* 2;
409 requisition
->height
+= GTK_CONTAINER (widget
)->border_width
* 2;
411 widget
->requisition
= *requisition
;
415 nautilus_path_bar_update_slider_buttons (NautilusPathBar
*path_bar
)
417 if (path_bar
->button_list
) {
421 button
= BUTTON_DATA (path_bar
->button_list
->data
)->button
;
422 if (gtk_widget_get_child_visible (button
)) {
423 gtk_widget_set_sensitive (path_bar
->down_slider_button
, FALSE
);
425 gtk_widget_set_sensitive (path_bar
->down_slider_button
, TRUE
);
427 button
= BUTTON_DATA (g_list_last (path_bar
->button_list
)->data
)->button
;
428 if (gtk_widget_get_child_visible (button
)) {
429 gtk_widget_set_sensitive (path_bar
->up_slider_button
, FALSE
);
431 gtk_widget_set_sensitive (path_bar
->up_slider_button
, TRUE
);
437 nautilus_path_bar_unmap (GtkWidget
*widget
)
439 nautilus_path_bar_stop_scrolling (NAUTILUS_PATH_BAR (widget
));
441 GTK_WIDGET_CLASS (nautilus_path_bar_parent_class
)->unmap (widget
);
444 /* This is a tad complicated */
446 nautilus_path_bar_size_allocate (GtkWidget
*widget
,
447 GtkAllocation
*allocation
)
450 NautilusPathBar
*path_bar
;
451 GtkTextDirection direction
;
452 GtkAllocation child_allocation
;
453 GList
*list
, *first_button
;
455 gint allocation_width
;
457 gboolean need_sliders
;
458 gint up_slider_offset
;
459 gint down_slider_offset
;
461 need_sliders
= FALSE
;
462 up_slider_offset
= 0;
463 down_slider_offset
= 0;
464 path_bar
= NAUTILUS_PATH_BAR (widget
);
466 widget
->allocation
= *allocation
;
469 /* No path is set so we don't have to allocate anything. */
470 if (path_bar
->button_list
== NULL
) {
473 direction
= gtk_widget_get_direction (widget
);
474 border_width
= (gint
) GTK_CONTAINER (path_bar
)->border_width
;
475 allocation_width
= allocation
->width
- 2 * border_width
;
477 /* First, we check to see if we need the scrollbars. */
478 if (path_bar
->fake_root
) {
479 width
= path_bar
->spacing
+ path_bar
->slider_width
;
484 width
+= BUTTON_DATA (path_bar
->button_list
->data
)->button
->requisition
.width
;
486 for (list
= path_bar
->button_list
->next
; list
; list
= list
->next
) {
487 child
= BUTTON_DATA (list
->data
)->button
;
488 width
+= child
->requisition
.width
+ path_bar
->spacing
;
490 if (list
== path_bar
->fake_root
) {
495 if (width
<= allocation_width
) {
496 if (path_bar
->fake_root
) {
497 first_button
= path_bar
->fake_root
;
499 first_button
= g_list_last (path_bar
->button_list
);
502 gboolean reached_end
;
505 slider_space
= 2 * (path_bar
->spacing
+ path_bar
->slider_width
);
507 if (path_bar
->first_scrolled_button
) {
508 first_button
= path_bar
->first_scrolled_button
;
510 first_button
= path_bar
->button_list
;
514 /* To see how much space we have, and how many buttons we can display.
515 * We start at the first button, count forward until hit the new
516 * button, then count backwards.
518 /* Count down the path chain towards the end. */
519 width
= BUTTON_DATA (first_button
->data
)->button
->requisition
.width
;
520 list
= first_button
->prev
;
521 while (list
&& !reached_end
) {
522 child
= BUTTON_DATA (list
->data
)->button
;
524 if (width
+ child
->requisition
.width
+ path_bar
->spacing
+ slider_space
> allocation_width
) {
527 if (list
== path_bar
->fake_root
) {
530 width
+= child
->requisition
.width
+ path_bar
->spacing
;
537 /* Finally, we walk up, seeing how many of the previous buttons we can add*/
539 while (first_button
->next
&& ! reached_end
) {
540 child
= BUTTON_DATA (first_button
->next
->data
)->button
;
541 if (width
+ child
->requisition
.width
+ path_bar
->spacing
+ slider_space
> allocation_width
) {
544 width
+= child
->requisition
.width
+ path_bar
->spacing
;
545 if (first_button
== path_bar
->fake_root
) {
548 first_button
= first_button
->next
;
553 /* Now, we allocate space to the buttons */
554 child_allocation
.y
= allocation
->y
+ border_width
;
555 child_allocation
.height
= MAX (1, (gint
) allocation
->height
- border_width
* 2);
557 if (direction
== GTK_TEXT_DIR_RTL
) {
558 child_allocation
.x
= allocation
->x
+ allocation
->width
- border_width
;
559 if (need_sliders
|| path_bar
->fake_root
) {
560 child_allocation
.x
-= (path_bar
->spacing
+ path_bar
->slider_width
);
561 up_slider_offset
= allocation
->width
- border_width
- path_bar
->slider_width
;
564 child_allocation
.x
= allocation
->x
+ border_width
;
565 if (need_sliders
|| path_bar
->fake_root
) {
566 up_slider_offset
= border_width
;
567 child_allocation
.x
+= (path_bar
->spacing
+ path_bar
->slider_width
);
571 for (list
= first_button
; list
; list
= list
->prev
) {
572 child
= BUTTON_DATA (list
->data
)->button
;
574 child_allocation
.width
= child
->requisition
.width
;
575 if (direction
== GTK_TEXT_DIR_RTL
) {
576 child_allocation
.x
-= child_allocation
.width
;
578 /* Check to see if we've don't have any more space to allocate buttons */
579 if (need_sliders
&& direction
== GTK_TEXT_DIR_RTL
) {
580 if (child_allocation
.x
- path_bar
->spacing
- path_bar
->slider_width
< widget
->allocation
.x
+ border_width
) {
584 if (need_sliders
&& direction
== GTK_TEXT_DIR_LTR
) {
585 if (child_allocation
.x
+ child_allocation
.width
+ path_bar
->spacing
+ path_bar
->slider_width
> widget
->allocation
.x
+ border_width
+ allocation_width
) {
591 gtk_widget_set_child_visible (BUTTON_DATA (list
->data
)->button
, TRUE
);
592 gtk_widget_size_allocate (child
, &child_allocation
);
594 if (direction
== GTK_TEXT_DIR_RTL
) {
595 child_allocation
.x
-= path_bar
->spacing
;
596 down_slider_offset
= child_allocation
.x
- widget
->allocation
.x
- path_bar
->slider_width
;
597 down_slider_offset
= border_width
;
599 down_slider_offset
= child_allocation
.x
- widget
->allocation
.x
;
600 down_slider_offset
= allocation
->width
- border_width
- path_bar
->slider_width
;
601 child_allocation
.x
+= child_allocation
.width
+ path_bar
->spacing
;
604 /* Now we go hide all the widgets that don't fit */
606 gtk_widget_set_child_visible (BUTTON_DATA (list
->data
)->button
, FALSE
);
609 for (list
= first_button
->next
; list
; list
= list
->next
) {
610 gtk_widget_set_child_visible (BUTTON_DATA (list
->data
)->button
, FALSE
);
613 if (need_sliders
|| path_bar
->fake_root
) {
614 child_allocation
.width
= path_bar
->slider_width
;
615 child_allocation
.x
= up_slider_offset
+ allocation
->x
;
616 gtk_widget_size_allocate (path_bar
->up_slider_button
, &child_allocation
);
618 gtk_widget_set_child_visible (path_bar
->up_slider_button
, TRUE
);
619 gtk_widget_show_all (path_bar
->up_slider_button
);
622 gtk_widget_set_child_visible (path_bar
->up_slider_button
, FALSE
);
626 child_allocation
.width
= path_bar
->slider_width
;
627 child_allocation
.x
= down_slider_offset
+ allocation
->x
;
628 gtk_widget_size_allocate (path_bar
->down_slider_button
, &child_allocation
);
630 gtk_widget_set_child_visible (path_bar
->down_slider_button
, TRUE
);
631 gtk_widget_show_all (path_bar
->down_slider_button
);
632 nautilus_path_bar_update_slider_buttons (path_bar
);
634 gtk_widget_set_child_visible (path_bar
->down_slider_button
, FALSE
);
639 nautilus_path_bar_style_set (GtkWidget
*widget
, GtkStyle
*previous_style
)
641 if (GTK_WIDGET_CLASS (nautilus_path_bar_parent_class
)->style_set
) {
642 GTK_WIDGET_CLASS (nautilus_path_bar_parent_class
)->style_set (widget
, previous_style
);
645 nautilus_path_bar_check_icon_theme (NAUTILUS_PATH_BAR (widget
));
649 nautilus_path_bar_screen_changed (GtkWidget
*widget
,
650 GdkScreen
*previous_screen
)
652 if (GTK_WIDGET_CLASS (nautilus_path_bar_parent_class
)->screen_changed
) {
653 GTK_WIDGET_CLASS (nautilus_path_bar_parent_class
)->screen_changed (widget
, previous_screen
);
655 /* We might nave a new settings, so we remove the old one */
656 if (previous_screen
) {
657 remove_settings_signal (NAUTILUS_PATH_BAR (widget
), previous_screen
);
659 nautilus_path_bar_check_icon_theme (NAUTILUS_PATH_BAR (widget
));
663 nautilus_path_bar_add (GtkContainer
*container
,
666 gtk_widget_set_parent (widget
, GTK_WIDGET (container
));
670 nautilus_path_bar_remove_1 (GtkContainer
*container
,
673 gboolean was_visible
= GTK_WIDGET_VISIBLE (widget
);
674 gtk_widget_unparent (widget
);
676 gtk_widget_queue_resize (GTK_WIDGET (container
));
681 nautilus_path_bar_remove (GtkContainer
*container
,
684 NautilusPathBar
*path_bar
;
687 path_bar
= NAUTILUS_PATH_BAR (container
);
689 if (widget
== path_bar
->up_slider_button
) {
690 nautilus_path_bar_remove_1 (container
, widget
);
691 path_bar
->up_slider_button
= NULL
;
695 if (widget
== path_bar
->down_slider_button
) {
696 nautilus_path_bar_remove_1 (container
, widget
);
697 path_bar
->down_slider_button
= NULL
;
701 children
= path_bar
->button_list
;
703 if (widget
== BUTTON_DATA (children
->data
)->button
) {
704 nautilus_path_bar_remove_1 (container
, widget
);
705 path_bar
->button_list
= g_list_remove_link (path_bar
->button_list
, children
);
706 g_list_free (children
);
709 children
= children
->next
;
714 nautilus_path_bar_forall (GtkContainer
*container
,
715 gboolean include_internals
,
716 GtkCallback callback
,
717 gpointer callback_data
)
719 NautilusPathBar
*path_bar
;
722 g_return_if_fail (callback
!= NULL
);
723 path_bar
= NAUTILUS_PATH_BAR (container
);
725 children
= path_bar
->button_list
;
728 child
= BUTTON_DATA (children
->data
)->button
;
729 children
= children
->next
;
730 (* callback
) (child
, callback_data
);
733 if (path_bar
->up_slider_button
) {
734 (* callback
) (path_bar
->up_slider_button
, callback_data
);
737 if (path_bar
->down_slider_button
) {
738 (* callback
) (path_bar
->down_slider_button
, callback_data
);
743 nautilus_path_bar_scroll_down (GtkWidget
*button
, NautilusPathBar
*path_bar
)
748 gint space_available
;
751 GtkTextDirection direction
;
756 if (path_bar
->ignore_click
) {
757 path_bar
->ignore_click
= FALSE
;
761 gtk_widget_queue_resize (GTK_WIDGET (path_bar
));
763 border_width
= GTK_CONTAINER (path_bar
)->border_width
;
764 direction
= gtk_widget_get_direction (GTK_WIDGET (path_bar
));
766 /* We find the button at the 'down' end that we have to make */
768 for (list
= path_bar
->button_list
; list
; list
= list
->next
) {
769 if (list
->next
&& gtk_widget_get_child_visible (BUTTON_DATA (list
->next
->data
)->button
)) {
775 /* Find the last visible button on the 'up' end */
776 for (list
= g_list_last (path_bar
->button_list
); list
; list
= list
->prev
) {
777 if (gtk_widget_get_child_visible (BUTTON_DATA (list
->data
)->button
)) {
783 space_needed
= BUTTON_DATA (down_button
->data
)->button
->allocation
.width
+ path_bar
->spacing
;
784 if (direction
== GTK_TEXT_DIR_RTL
) {
785 space_available
= path_bar
->down_slider_button
->allocation
.x
- GTK_WIDGET (path_bar
)->allocation
.x
;
787 space_available
= (GTK_WIDGET (path_bar
)->allocation
.x
+ GTK_WIDGET (path_bar
)->allocation
.width
- border_width
) -
788 (path_bar
->down_slider_button
->allocation
.x
+ path_bar
->down_slider_button
->allocation
.width
);
791 /* We have space_available extra space that's not being used. We
792 * need space_needed space to make the button fit. So we walk down
793 * from the end, removing buttons until we get all the space we
795 while (space_available
< space_needed
) {
796 space_available
+= BUTTON_DATA (up_button
->data
)->button
->allocation
.width
+ path_bar
->spacing
;
797 up_button
= up_button
->prev
;
798 path_bar
->first_scrolled_button
= up_button
;
803 nautilus_path_bar_scroll_up (GtkWidget
*button
, NautilusPathBar
*path_bar
)
807 if (path_bar
->ignore_click
) {
808 path_bar
->ignore_click
= FALSE
;
812 gtk_widget_queue_resize (GTK_WIDGET (path_bar
));
814 for (list
= g_list_last (path_bar
->button_list
); list
; list
= list
->prev
) {
815 if (list
->prev
&& gtk_widget_get_child_visible (BUTTON_DATA (list
->prev
->data
)->button
)) {
816 if (list
->prev
== path_bar
->fake_root
) {
817 path_bar
->fake_root
= NULL
;
819 path_bar
->first_scrolled_button
= list
;
826 nautilus_path_bar_scroll_timeout (NautilusPathBar
*path_bar
)
828 gboolean retval
= FALSE
;
830 GDK_THREADS_ENTER ();
832 if (path_bar
->timer
) {
833 if (GTK_WIDGET_HAS_FOCUS (path_bar
->up_slider_button
)) {
834 nautilus_path_bar_scroll_up (path_bar
->up_slider_button
, path_bar
);
836 if (GTK_WIDGET_HAS_FOCUS (path_bar
->down_slider_button
)) {
837 nautilus_path_bar_scroll_down (path_bar
->down_slider_button
, path_bar
);
840 if (path_bar
->need_timer
) {
841 path_bar
->need_timer
= FALSE
;
843 path_bar
->timer
= g_timeout_add (SCROLL_TIMEOUT
,
844 (GSourceFunc
)nautilus_path_bar_scroll_timeout
,
853 GDK_THREADS_LEAVE ();
859 nautilus_path_bar_stop_scrolling (NautilusPathBar
*path_bar
)
861 if (path_bar
->timer
) {
862 g_source_remove (path_bar
->timer
);
864 path_bar
->need_timer
= FALSE
;
869 nautilus_path_bar_slider_button_press (GtkWidget
*widget
,
870 GdkEventButton
*event
,
871 NautilusPathBar
*path_bar
)
873 if (!GTK_WIDGET_HAS_FOCUS (widget
)) {
874 gtk_widget_grab_focus (widget
);
877 if (event
->type
!= GDK_BUTTON_PRESS
|| event
->button
!= 1) {
881 path_bar
->ignore_click
= FALSE
;
883 if (widget
== path_bar
->up_slider_button
) {
884 nautilus_path_bar_scroll_up (path_bar
->up_slider_button
, path_bar
);
886 if (widget
== path_bar
->down_slider_button
) {
887 nautilus_path_bar_scroll_down (path_bar
->down_slider_button
, path_bar
);
891 if (!path_bar
->timer
) {
892 path_bar
->need_timer
= TRUE
;
893 path_bar
->timer
= g_timeout_add (INITIAL_SCROLL_TIMEOUT
,
894 (GSourceFunc
)nautilus_path_bar_scroll_timeout
,
902 nautilus_path_bar_slider_button_release (GtkWidget
*widget
,
903 GdkEventButton
*event
,
904 NautilusPathBar
*path_bar
)
906 if (event
->type
!= GDK_BUTTON_RELEASE
) {
910 path_bar
->ignore_click
= TRUE
;
911 nautilus_path_bar_stop_scrolling (path_bar
);
917 nautilus_path_bar_grab_notify (GtkWidget
*widget
,
918 gboolean was_grabbed
)
921 nautilus_path_bar_stop_scrolling (NAUTILUS_PATH_BAR (widget
));
926 nautilus_path_bar_state_changed (GtkWidget
*widget
,
927 GtkStateType previous_state
)
929 if (!GTK_WIDGET_IS_SENSITIVE (widget
)) {
930 nautilus_path_bar_stop_scrolling (NAUTILUS_PATH_BAR (widget
));
936 /* Changes the icons wherever it is needed */
938 reload_icons (NautilusPathBar
*path_bar
)
942 if (path_bar
->root_icon
) {
943 g_object_unref (path_bar
->root_icon
);
944 path_bar
->root_icon
= NULL
;
946 if (path_bar
->home_icon
) {
947 g_object_unref (path_bar
->home_icon
);
948 path_bar
->home_icon
= NULL
;
950 if (path_bar
->desktop_icon
) {
951 g_object_unref (path_bar
->desktop_icon
);
952 path_bar
->desktop_icon
= NULL
;
956 for (list
= path_bar
->button_list
; list
; list
= list
->next
) {
957 ButtonData
*button_data
;
958 gboolean current_dir
;
960 button_data
= BUTTON_DATA (list
->data
);
961 if (button_data
->type
!= NORMAL_BUTTON
) {
962 current_dir
= gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_data
->button
));
963 nautilus_path_bar_update_button_appearance (path_bar
, button_data
, current_dir
);
970 change_icon_theme (NautilusPathBar
*path_bar
)
972 path_bar
->icon_size
= NAUTILUS_PATH_BAR_ICON_SIZE
;
973 reload_icons (path_bar
);
976 /* Callback used when a GtkSettings value changes */
978 settings_notify_cb (GObject
*object
,
980 NautilusPathBar
*path_bar
)
984 name
= g_param_spec_get_name (pspec
);
986 if (! strcmp (name
, "gtk-icon-theme-name") || ! strcmp (name
, "gtk-icon-sizes")) {
987 change_icon_theme (path_bar
);
992 nautilus_path_bar_check_icon_theme (NautilusPathBar
*path_bar
)
994 GtkSettings
*settings
;
996 if (path_bar
->settings_signal_id
) {
1000 settings
= gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (path_bar
)));
1001 path_bar
->settings_signal_id
= g_signal_connect (settings
, "notify", G_CALLBACK (settings_notify_cb
), path_bar
);
1003 change_icon_theme (path_bar
);
1006 /* Public functions and their helpers */
1008 nautilus_path_bar_clear_buttons (NautilusPathBar
*path_bar
)
1010 while (path_bar
->button_list
!= NULL
) {
1011 gtk_container_remove (GTK_CONTAINER (path_bar
), BUTTON_DATA (path_bar
->button_list
->data
)->button
);
1013 path_bar
->first_scrolled_button
= NULL
;
1014 path_bar
->fake_root
= NULL
;
1018 button_clicked_cb (GtkWidget
*button
,
1021 ButtonData
*button_data
;
1022 NautilusPathBar
*path_bar
;
1024 gboolean child_is_hidden
;
1026 button_data
= BUTTON_DATA (data
);
1027 if (button_data
->ignore_changes
) {
1031 path_bar
= NAUTILUS_PATH_BAR (button
->parent
);
1033 button_list
= g_list_find (path_bar
->button_list
, button_data
);
1034 g_assert (button_list
!= NULL
);
1036 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button
), TRUE
);
1038 if (button_list
->prev
) {
1039 ButtonData
*child_data
;
1041 child_data
= BUTTON_DATA (button_list
->prev
->data
);
1042 child_is_hidden
= child_data
->file_is_hidden
;
1044 child_is_hidden
= FALSE
;
1046 g_signal_emit (path_bar
, path_bar_signals
[PATH_CLICKED
], 0, button_data
->path
);
1050 get_icon_for_file_path (GFile
*location
, const char *NAUTILUS_ICON_FOLDER_name
)
1053 NautilusIconInfo
*info
;
1056 file
= nautilus_file_get (location
);
1059 nautilus_file_check_if_ready (file
,
1060 NAUTILUS_FILE_ATTRIBUTES_FOR_ICON
)) {
1061 info
= nautilus_file_get_icon (file
, NAUTILUS_PATH_BAR_ICON_SIZE
, 0);
1062 pixbuf
= nautilus_icon_info_get_pixbuf_at_size (info
, NAUTILUS_PATH_BAR_ICON_SIZE
);
1063 g_object_unref (info
);
1067 nautilus_file_unref (file
);
1069 info
= nautilus_icon_info_lookup_from_name (NAUTILUS_ICON_FOLDER_name
, NAUTILUS_PATH_BAR_ICON_SIZE
);
1070 pixbuf
= nautilus_icon_info_get_pixbuf_at_size (info
, NAUTILUS_PATH_BAR_ICON_SIZE
);
1071 g_object_unref (info
);
1077 get_button_image (NautilusPathBar
*path_bar
,
1078 ButtonType button_type
)
1080 switch (button_type
)
1083 if (path_bar
->root_icon
!= NULL
) {
1084 return path_bar
->root_icon
;
1087 path_bar
->root_icon
= get_icon_for_file_path (path_bar
->root_path
, NAUTILUS_ICON_FILESYSTEM
);
1088 return path_bar
->root_icon
;
1091 if (path_bar
->home_icon
!= NULL
) {
1092 return path_bar
->home_icon
;
1095 path_bar
->home_icon
= get_icon_for_file_path (path_bar
->root_path
, NAUTILUS_ICON_HOME
);
1096 return path_bar
->home_icon
;
1098 case DESKTOP_BUTTON
:
1099 if (path_bar
->desktop_icon
!= NULL
) {
1100 return path_bar
->desktop_icon
;
1102 path_bar
->desktop_icon
= get_icon_for_file_path (path_bar
->root_path
, NAUTILUS_ICON_DESKTOP
);
1103 return path_bar
->desktop_icon
;
1113 button_data_free (ButtonData
*button_data
)
1115 g_object_unref (button_data
->path
);
1116 g_free (button_data
->dir_name
);
1117 if (button_data
->custom_icon
) {
1118 g_object_unref (button_data
->custom_icon
);
1120 g_free (button_data
);
1124 get_dir_name (ButtonData
*button_data
)
1126 if (button_data
->type
== DESKTOP_BUTTON
) {
1127 return _("Desktop");
1129 return button_data
->dir_name
;
1133 /* We always want to request the same size for the label, whether
1134 * or not the contents are bold
1137 label_size_request_cb (GtkWidget
*widget
,
1138 GtkRequisition
*requisition
,
1139 ButtonData
*button_data
)
1141 const gchar
*dir_name
= get_dir_name (button_data
);
1142 PangoLayout
*layout
;
1143 gint bold_width
, bold_height
;
1146 layout
= gtk_widget_create_pango_layout (button_data
->label
, dir_name
);
1147 pango_layout_get_pixel_size (layout
, &requisition
->width
, &requisition
->height
);
1149 markup
= g_markup_printf_escaped ("<b>%s</b>", dir_name
);
1150 pango_layout_set_markup (layout
, markup
, -1);
1153 pango_layout_get_pixel_size (layout
, &bold_width
, &bold_height
);
1154 requisition
->width
= MAX (requisition
->width
, bold_width
);
1155 requisition
->height
= MAX (requisition
->height
, bold_height
);
1157 g_object_unref (layout
);
1161 nautilus_path_bar_update_button_appearance (NautilusPathBar
*path_bar
,
1162 ButtonData
*button_data
,
1163 gboolean current_dir
)
1165 const gchar
*dir_name
= get_dir_name (button_data
);
1168 if (button_data
->label
!= NULL
) {
1172 markup
= g_markup_printf_escaped ("<b>%s</b>", dir_name
);
1173 gtk_label_set_markup (GTK_LABEL (button_data
->label
), markup
);
1176 gtk_label_set_text (GTK_LABEL (button_data
->label
), dir_name
);
1180 if (button_data
->image
!= NULL
) {
1181 if (button_data
->type
== MOUNT_BUTTON
|| (button_data
->type
== NORMAL_BUTTON
&& button_data
->is_base_dir
) ) {
1183 /* set custom icon for roots */
1184 if (button_data
->custom_icon
) {
1185 gtk_image_set_from_pixbuf (GTK_IMAGE (button_data
->image
), button_data
->custom_icon
);
1189 pixbuf
= get_button_image (path_bar
, button_data
->type
);
1190 gtk_image_set_from_pixbuf (GTK_IMAGE (button_data
->image
), pixbuf
);
1194 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_data
->button
)) != current_dir
) {
1195 button_data
->ignore_changes
= TRUE
;
1196 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button_data
->button
), current_dir
);
1197 button_data
->ignore_changes
= FALSE
;
1202 is_file_path_mounted_mount (GFile
*location
, ButtonData
*button_data
)
1204 GVolumeMonitor
*volume_monitor
;
1209 NautilusIconInfo
*info
;
1213 volume_monitor
= g_volume_monitor_get ();
1214 mounts
= g_volume_monitor_get_mounts (volume_monitor
);
1215 for (l
= mounts
; l
!= NULL
; l
= l
->next
) {
1218 g_object_unref (mount
);
1221 root
= g_mount_get_root (mount
);
1222 if (g_file_equal (location
, root
)) {
1224 /* set mount specific details in button_data */
1226 icon
= g_mount_get_icon (mount
);
1228 icon
= g_themed_icon_new (NAUTILUS_ICON_FOLDER
);
1230 info
= nautilus_icon_info_lookup (icon
, NAUTILUS_PATH_BAR_ICON_SIZE
);
1231 g_object_unref (icon
);
1232 button_data
->custom_icon
= nautilus_icon_info_get_pixbuf_at_size (info
, NAUTILUS_PATH_BAR_ICON_SIZE
);
1233 g_object_unref (info
);
1234 button_data
->path
= g_object_ref (location
);
1235 button_data
->dir_name
= g_mount_get_name (mount
);
1237 g_object_unref (mount
);
1238 g_object_unref (root
);
1241 g_object_unref (mount
);
1242 g_object_unref (root
);
1244 g_list_free (mounts
);
1249 find_button_type (NautilusPathBar
*path_bar
,
1251 ButtonData
*button_data
)
1255 if (path_bar
->root_path
!= NULL
&& g_file_equal (location
, path_bar
->root_path
)) {
1258 if (path_bar
->home_path
!= NULL
&& g_file_equal (location
, path_bar
->home_path
)) {
1261 if (path_bar
->desktop_path
!= NULL
&& g_file_equal (location
, path_bar
->desktop_path
)) {
1262 if (!desktop_is_home
) {
1263 return DESKTOP_BUTTON
;
1265 return NORMAL_BUTTON
;
1268 if (is_file_path_mounted_mount (location
, button_data
)) {
1269 return MOUNT_BUTTON
;
1272 return NORMAL_BUTTON
;
1276 button_drag_data_get_cb (GtkWidget
*widget
,
1277 GdkDragContext
*context
,
1278 GtkSelectionData
*selection_data
,
1283 ButtonData
*button_data
;
1288 uri
= g_file_get_uri (button_data
->path
);
1289 uri_list
= g_strconcat (uri
, "\r\n", NULL
);
1291 gtk_selection_data_set (selection_data
,
1292 selection_data
->target
,
1300 make_directory_button (NautilusPathBar
*path_bar
,
1301 const char *dir_name
,
1303 gboolean current_dir
,
1305 gboolean file_is_hidden
)
1307 const GtkTargetEntry targets
[] = {
1308 { "text/uri-list", 0, 0 }
1312 GtkWidget
*label_alignment
;
1313 ButtonData
*button_data
;
1316 label_alignment
= NULL
;
1318 file_is_hidden
= !! file_is_hidden
;
1319 /* Is it a special button? */
1320 button_data
= g_new0 (ButtonData
, 1);
1322 button_data
->type
= find_button_type (path_bar
, path
, button_data
);
1323 button_data
->button
= gtk_toggle_button_new ();
1324 gtk_button_set_focus_on_click (GTK_BUTTON (button_data
->button
), FALSE
);
1326 switch (button_data
->type
) {
1328 button_data
->image
= gtk_image_new ();
1329 child
= button_data
->image
;
1330 button_data
->label
= NULL
;
1333 case DESKTOP_BUTTON
:
1335 button_data
->image
= gtk_image_new ();
1336 button_data
->label
= gtk_label_new (NULL
);
1337 label_alignment
= gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
1338 gtk_container_add (GTK_CONTAINER (label_alignment
), button_data
->label
);
1339 child
= gtk_hbox_new (FALSE
, 2);
1340 gtk_box_pack_start (GTK_BOX (child
), button_data
->image
, FALSE
, FALSE
, 0);
1341 gtk_box_pack_start (GTK_BOX (child
), label_alignment
, FALSE
, FALSE
, 0);
1346 button_data
->image
= gtk_image_new ();
1347 button_data
->label
= gtk_label_new (NULL
);
1348 label_alignment
= gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
1349 gtk_container_add (GTK_CONTAINER (label_alignment
), button_data
->label
);
1350 child
= gtk_hbox_new (FALSE
, 2);
1351 gtk_box_pack_start (GTK_BOX (child
), button_data
->image
, FALSE
, FALSE
, 0);
1352 gtk_box_pack_start (GTK_BOX (child
), label_alignment
, FALSE
, FALSE
, 0);
1353 button_data
->is_base_dir
= TRUE
;
1354 button_data
->custom_icon
= get_icon_for_file_path (path
, NAUTILUS_ICON_FOLDER
);
1356 button_data
->is_base_dir
= FALSE
;
1357 button_data
->label
= gtk_label_new (NULL
);
1358 label_alignment
= gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
1359 gtk_container_add (GTK_CONTAINER (label_alignment
), button_data
->label
);
1360 child
= label_alignment
;
1361 button_data
->image
= NULL
;
1365 /* label_alignment is created because we can't override size-request
1366 * on label itself and still have the contents of the label centered
1367 * properly in the label's requisition
1370 if (label_alignment
) {
1371 g_signal_connect (label_alignment
, "size-request",
1372 G_CALLBACK (label_size_request_cb
), button_data
);
1375 /* do not set these for mounts */
1376 if (button_data
->type
!= MOUNT_BUTTON
) {
1377 button_data
->dir_name
= g_strdup (dir_name
);
1378 button_data
->path
= g_object_ref (path
);
1381 button_data
->file_is_hidden
= file_is_hidden
;
1383 gtk_container_add (GTK_CONTAINER (button_data
->button
), child
);
1384 gtk_widget_show_all (button_data
->button
);
1386 nautilus_path_bar_update_button_appearance (path_bar
, button_data
, current_dir
);
1388 g_signal_connect (button_data
->button
, "clicked", G_CALLBACK (button_clicked_cb
), button_data
);
1389 g_object_weak_ref (G_OBJECT (button_data
->button
), (GWeakNotify
) button_data_free
, button_data
);
1391 gtk_drag_source_set (button_data
->button
,
1394 G_N_ELEMENTS (targets
),
1396 g_signal_connect (button_data
->button
, "drag-data-get",G_CALLBACK (button_drag_data_get_cb
), button_data
);
1402 nautilus_path_bar_check_parent_path (NautilusPathBar
*path_bar
,
1406 GList
*current_path
;
1407 gboolean need_new_fake_root
;
1409 current_path
= NULL
;
1410 need_new_fake_root
= FALSE
;
1412 for (list
= path_bar
->button_list
; list
; list
= list
->next
) {
1413 ButtonData
*button_data
;
1415 button_data
= list
->data
;
1416 if (g_file_equal (location
, button_data
->path
)) {
1417 current_path
= list
;
1420 if (list
== path_bar
->fake_root
) {
1421 need_new_fake_root
= TRUE
;
1427 if (need_new_fake_root
) {
1428 path_bar
->fake_root
= NULL
;
1429 for (list
= current_path
; list
; list
= list
->next
) {
1430 ButtonData
*button_data
;
1432 button_data
= list
->data
;
1433 if (BUTTON_IS_FAKE_ROOT (button_data
)) {
1434 path_bar
->fake_root
= list
;
1440 for (list
= path_bar
->button_list
; list
; list
= list
->next
) {
1442 nautilus_path_bar_update_button_appearance (path_bar
,
1443 BUTTON_DATA (list
->data
),
1444 (list
== current_path
) ? TRUE
: FALSE
);
1447 if (!gtk_widget_get_child_visible (BUTTON_DATA (current_path
->data
)->button
)) {
1448 path_bar
->first_scrolled_button
= current_path
;
1449 gtk_widget_queue_resize (GTK_WIDGET (path_bar
));
1457 get_display_name_for_folder (GFile
*location
)
1462 /* This does sync i/o, which isn't ideal.
1463 * It should probably use the NautilusFile machinery
1467 info
= g_file_query_info (location
,
1468 G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME
,
1471 name
= g_strdup (g_file_info_get_display_name (info
));
1472 g_object_unref (info
);
1476 name
= g_file_get_basename (location
);
1483 nautilus_path_bar_update_path (NautilusPathBar
*path_bar
, GFile
*file_path
)
1485 GFile
*path
, *parent_path
;
1487 gboolean first_directory
, last_directory
;
1489 GList
*new_buttons
, *l
, *fake_root
;
1490 ButtonData
*button_data
;
1492 g_return_val_if_fail (NAUTILUS_IS_PATH_BAR (path_bar
), FALSE
);
1493 g_return_val_if_fail (file_path
!= NULL
, FALSE
);
1499 first_directory
= TRUE
;
1500 last_directory
= FALSE
;
1503 path
= g_object_ref (file_path
);
1505 gtk_widget_push_composite_child ();
1507 while (path
!= NULL
) {
1509 parent_path
= g_file_get_parent (path
);
1510 name
= get_display_name_for_folder (path
);
1511 last_directory
= !parent_path
;
1512 button_data
= make_directory_button (path_bar
, name
, path
, first_directory
, last_directory
, FALSE
);
1513 g_object_unref (path
);
1516 new_buttons
= g_list_prepend (new_buttons
, button_data
);
1518 if (BUTTON_IS_FAKE_ROOT (button_data
)) {
1519 fake_root
= new_buttons
;
1523 first_directory
= FALSE
;
1526 nautilus_path_bar_clear_buttons (path_bar
);
1527 path_bar
->button_list
= g_list_reverse (new_buttons
);
1528 path_bar
->fake_root
= fake_root
;
1530 for (l
= path_bar
->button_list
; l
; l
= l
->next
) {
1532 button
= BUTTON_DATA (l
->data
)->button
;
1533 gtk_container_add (GTK_CONTAINER (path_bar
), button
);
1536 gtk_widget_pop_composite_child ();
1542 nautilus_path_bar_set_path (NautilusPathBar
*path_bar
, GFile
*file_path
)
1544 g_return_val_if_fail (NAUTILUS_IS_PATH_BAR (path_bar
), FALSE
);
1545 g_return_val_if_fail (file_path
!= NULL
, FALSE
);
1547 /* Check whether the new path is already present in the pathbar as buttons.
1548 * This could be a parent directory or a previous selected subdirectory. */
1549 if (nautilus_path_bar_check_parent_path (path_bar
, file_path
)) {
1553 return nautilus_path_bar_update_path (path_bar
, file_path
);
1559 * _nautilus_path_bar_up:
1560 * @path_bar: a #NautilusPathBar
1562 * If the selected button in the pathbar is not the furthest button "up" (in the
1563 * root direction), act as if the user clicked on the next button up.
1566 nautilus_path_bar_up (NautilusPathBar
*path_bar
)
1570 for (l
= path_bar
->button_list
; l
; l
= l
->next
) {
1571 GtkWidget
*button
= BUTTON_DATA (l
->data
)->button
;
1572 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button
))) {
1574 GtkWidget
*next_button
= BUTTON_DATA (l
->next
->data
)->button
;
1575 button_clicked_cb (next_button
, l
->next
->data
);
1583 * _nautilus_path_bar_down:
1584 * @path_bar: a #NautilusPathBar
1586 * If the selected button in the pathbar is not the furthest button "down" (in the
1587 * leaf direction), act as if the user clicked on the next button down.
1590 nautilus_path_bar_down (NautilusPathBar
*path_bar
)
1594 for (l
= path_bar
->button_list
; l
; l
= l
->next
) {
1595 GtkWidget
*button
= BUTTON_DATA (l
->data
)->button
;
1596 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button
))) {
1598 GtkWidget
*prev_button
= BUTTON_DATA (l
->prev
->data
)->button
;
1599 button_clicked_cb (prev_button
, l
->prev
->data
);