diff options
author | Alexander Larsson <alexl@redhat.com> | 2005-07-08 11:25:51 +0000 |
---|---|---|
committer | Alexander Larsson <alexl@src.gnome.org> | 2005-07-08 11:25:51 +0000 |
commit | 5d20d56ec4111cd27778c067d838fe8473e70868 (patch) | |
tree | 957e428f3e4accfc5b062dd0f89ff5c0794d1a3c | |
parent | ae70afe44715c69672006b3bd8942db3f4a2c008 (diff) | |
download | nautilus-5d20d56ec4111cd27778c067d838fe8473e70868.tar.gz |
Patch from Jamie McCracken <jamiemcc@blueyonder.co.uk>
2005-07-08 Alexander Larsson <alexl@redhat.com>
Patch from Jamie McCracken <jamiemcc@blueyonder.co.uk>
* src/Makefile.am:
* src/nautilus-pathbar.[ch]:
New pathbar widget. Based on code from gtk.
* src/nautilus-navigation-window.[ch]:
* src/nautilus-window-manage-views.c:
* src/nautilus-window-private.h:
Use pathbar in browser window.
* libnautilus-private/apps_nautilus_preferences.schemas.in:
* libnautilus-private/nautilus-global-preferences.[ch]:
Add always_use_location_entry prefs.
* src/nautilus-navigation-window-menus.c:
Whitespace fixup.
-rw-r--r-- | ChangeLog | 20 | ||||
-rw-r--r-- | libnautilus-private/apps_nautilus_preferences.schemas.in | 15 | ||||
-rw-r--r-- | libnautilus-private/nautilus-global-preferences.c | 4 | ||||
-rw-r--r-- | libnautilus-private/nautilus-global-preferences.h | 1 | ||||
-rw-r--r-- | po/ChangeLog | 5 | ||||
-rw-r--r-- | po/POTFILES.in | 1 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/nautilus-navigation-window-menus.c | 4 | ||||
-rw-r--r-- | src/nautilus-navigation-window.c | 124 | ||||
-rw-r--r-- | src/nautilus-navigation-window.h | 11 | ||||
-rw-r--r-- | src/nautilus-pathbar.c | 1641 | ||||
-rw-r--r-- | src/nautilus-pathbar.h | 80 | ||||
-rw-r--r-- | src/nautilus-window-manage-views.c | 10 | ||||
-rw-r--r-- | src/nautilus-window-private.h | 1 |
14 files changed, 1897 insertions, 22 deletions
@@ -1,3 +1,23 @@ +2005-07-08 Alexander Larsson <alexl@redhat.com> + + Patch from Jamie McCracken <jamiemcc@blueyonder.co.uk> + + * src/Makefile.am: + * src/nautilus-pathbar.[ch]: + New pathbar widget. Based on code from gtk. + + * src/nautilus-navigation-window.[ch]: + * src/nautilus-window-manage-views.c: + * src/nautilus-window-private.h: + Use pathbar in browser window. + + * libnautilus-private/apps_nautilus_preferences.schemas.in: + * libnautilus-private/nautilus-global-preferences.[ch]: + Add always_use_location_entry prefs. + + * src/nautilus-navigation-window-menus.c: + Whitespace fixup. + 2005-07-07 Joe Shaw <joeshaw@novell.com> * configure.in: Bump required gnome-vfs version up to diff --git a/libnautilus-private/apps_nautilus_preferences.schemas.in b/libnautilus-private/apps_nautilus_preferences.schemas.in index 58d75eb83..05b3cb5fe 100644 --- a/libnautilus-private/apps_nautilus_preferences.schemas.in +++ b/libnautilus-private/apps_nautilus_preferences.schemas.in @@ -52,6 +52,21 @@ </long> </locale> </schema> + + <schema> + <key>/schemas/apps/nautilus/preferences/always_use_location_entry</key> + <applyto>/apps/nautilus/preferences/always_use_location_entry</applyto> + <owner>nautilus</owner> + <type>bool</type> + <default>false</default> + <locale name="C"> + <short>Always use the location entry, instead of the pathbar</short> + <long> + If set to true, then Nautilus browser windows will always use a textual + input entry for the location toolbar, instead of the pathbar. + </long> + </locale> + </schema> <schema> <key>/schemas/apps/nautilus/preferences/confirm_trash</key> diff --git a/libnautilus-private/nautilus-global-preferences.c b/libnautilus-private/nautilus-global-preferences.c index 0492dce8e..24f3fc798 100644 --- a/libnautilus-private/nautilus-global-preferences.c +++ b/libnautilus-private/nautilus-global-preferences.c @@ -394,6 +394,10 @@ static const PreferenceDefault preference_defaults[] = { PREFERENCE_BOOLEAN, GINT_TO_POINTER (TRUE) }, + { NAUTILUS_PREFERENCES_ALWAYS_USE_LOCATION_ENTRY, + PREFERENCE_BOOLEAN, + GINT_TO_POINTER (FALSE) + }, { NAUTILUS_PREFERENCES_START_WITH_STATUS_BAR, PREFERENCE_BOOLEAN, GINT_TO_POINTER (TRUE) diff --git a/libnautilus-private/nautilus-global-preferences.h b/libnautilus-private/nautilus-global-preferences.h index 3596681bc..610756c06 100644 --- a/libnautilus-private/nautilus-global-preferences.h +++ b/libnautilus-private/nautilus-global-preferences.h @@ -82,6 +82,7 @@ typedef enum /* Which views should be displayed for new windows */ #define NAUTILUS_PREFERENCES_START_WITH_LOCATION_BAR "preferences/start_with_location_bar" +#define NAUTILUS_PREFERENCES_ALWAYS_USE_LOCATION_ENTRY "preferences/always_use_location_entry" #define NAUTILUS_PREFERENCES_START_WITH_STATUS_BAR "preferences/start_with_status_bar" #define NAUTILUS_PREFERENCES_START_WITH_SIDEBAR "preferences/start_with_sidebar" #define NAUTILUS_PREFERENCES_SIDE_PANE_VIEW "preferences/side_pane_view" diff --git a/po/ChangeLog b/po/ChangeLog index c0ebc7fd0..b161c8db7 100644 --- a/po/ChangeLog +++ b/po/ChangeLog @@ -1,3 +1,8 @@ +2005-07-08 Alexander Larsson <alexl@redhat.com> + + * POTFILES.in: + Added src/nautilus-pathbar.c + 2005-07-08 Priit Laes <plaes@cvs.gnome.org> * et.po: Translation updated by Ivar Smolin. diff --git a/po/POTFILES.in b/po/POTFILES.in index 91147ec70..d6fe0485f 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -73,6 +73,7 @@ src/nautilus-navigation-window-menus.c src/nautilus-navigation-window-ui.xml src/nautilus-navigation-window.c src/nautilus-notes-viewer.c +src/nautilus-pathbar.c src/nautilus-places-sidebar.c src/nautilus-property-browser.c src/nautilus-shell-ui.xml diff --git a/src/Makefile.am b/src/Makefile.am index cd11ecf4c..3e19e7b5a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -93,6 +93,8 @@ nautilus_SOURCES = \ nautilus-navigation-window.h \ nautilus-notes-viewer.c \ nautilus-notes-viewer.h \ + nautilus-pathbar.c \ + nautilus-pathbar.h \ nautilus-places-sidebar.c \ nautilus-places-sidebar.h \ nautilus-property-browser.c \ diff --git a/src/nautilus-navigation-window-menus.c b/src/nautilus-navigation-window-menus.c index 310ca1094..8eed02d71 100644 --- a/src/nautilus-navigation-window-menus.c +++ b/src/nautilus-navigation-window-menus.c @@ -423,12 +423,12 @@ static const GtkToggleActionEntry navigation_toggle_entries[] = { N_("Location _Bar"), NULL, /* label, accelerator */ N_("Change the visibility of this window's location bar"), /* tooltip */ G_CALLBACK (action_show_hide_location_bar_callback), - TRUE }, /* is_active */ + TRUE}, /* is_active */ { "Show Hide Statusbar", NULL, /* name, stock id */ N_("St_atusbar"), NULL, /* label, accelerator */ N_("Change the visibility of this window's statusbar"), /* tooltip */ G_CALLBACK (action_show_hide_statusbar_callback), - TRUE }, /* is_active */ + TRUE}, /* is_active */ }; void diff --git a/src/nautilus-navigation-window.c b/src/nautilus-navigation-window.c index 005ce6981..30d7d0883 100644 --- a/src/nautilus-navigation-window.c +++ b/src/nautilus-navigation-window.c @@ -37,6 +37,7 @@ #include "nautilus-main.h" #include "nautilus-signaller.h" #include "nautilus-location-bar.h" +#include "nautilus-pathbar.h" #include "nautilus-window-manage-views.h" #include "nautilus-zoom-control.h" #include <eel/eel-accessibility.h> @@ -81,6 +82,7 @@ #include <math.h> #include <sys/time.h> + /* FIXME bugzilla.gnome.org 41243: * We should use inheritance instead of these special cases * for the desktop window. @@ -110,6 +112,10 @@ static void side_panel_image_changed_callback (NautilusSidebar * static void navigation_bar_location_changed_callback (GtkWidget *widget, const char *uri, NautilusNavigationWindow *window); +static void path_bar_location_changed_callback (GtkWidget *widget, + const char *uri, + NautilusNavigationWindow *window); +static void always_use_location_entry_changed (gpointer callback_data); GNOME_CLASS_BOILERPLATE (NautilusNavigationWindow, nautilus_navigation_window, @@ -123,6 +129,7 @@ nautilus_navigation_window_instance_init (NautilusNavigationWindow *window) GtkWidget *location_bar; GtkWidget *view_as_menu_vbox; GtkToolItem *item; + GtkWidget *hbox; window->details = g_new0 (NautilusNavigationWindowDetails, 1); @@ -141,7 +148,7 @@ nautilus_navigation_window_instance_init (NautilusNavigationWindow *window) nautilus_navigation_window_initialize_actions (window); nautilus_navigation_window_initialize_menus (window); - + ui_manager = nautilus_window_get_ui_manager (NAUTILUS_WINDOW (window)); toolbar = gtk_ui_manager_get_widget (ui_manager, "/Toolbar"); window->details->toolbar = toolbar; @@ -164,22 +171,36 @@ nautilus_navigation_window_instance_init (NautilusNavigationWindow *window) /* set up location bar */ location_bar = gtk_toolbar_new (); window->details->location_bar = location_bar; - - window->navigation_bar = nautilus_location_bar_new (window); - gtk_widget_show (GTK_WIDGET (window->navigation_bar)); - - g_signal_connect_object (window->navigation_bar, "location_changed", - G_CALLBACK (navigation_bar_location_changed_callback), window, 0); + hbox = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox); item = gtk_tool_item_new (); gtk_container_set_border_width (GTK_CONTAINER (item), GNOME_PAD_SMALL); gtk_widget_show (GTK_WIDGET (item)); gtk_tool_item_set_expand (item, TRUE); - gtk_container_add (GTK_CONTAINER (item), window->navigation_bar); + gtk_container_add (GTK_CONTAINER (item), hbox); gtk_toolbar_insert (GTK_TOOLBAR (location_bar), item, -1); + window->path_bar = g_object_new (NAUTILUS_TYPE_PATH_BAR, NULL); + gtk_widget_show (window->path_bar); + + g_signal_connect_object (window->path_bar, "path_clicked", + G_CALLBACK (path_bar_location_changed_callback), window, 0); + + gtk_box_pack_start (GTK_BOX (hbox), + window->path_bar, + TRUE, TRUE, 0); + + window->navigation_bar = nautilus_location_bar_new (window); + g_signal_connect_object (window->navigation_bar, "location_changed", + G_CALLBACK (navigation_bar_location_changed_callback), window, 0); + + gtk_box_pack_start (GTK_BOX (hbox), + window->navigation_bar, + TRUE, TRUE, 0); + /* Option menu for content view types; it's empty here, filled in when a uri is set. * Pack it into vbox so it doesn't grow vertically when location bar does. */ @@ -229,10 +250,37 @@ nautilus_navigation_window_instance_init (NautilusNavigationWindow *window) 0, 1, 2, 3, GTK_EXPAND | GTK_FILL, 0, 0, 0); - - + + eel_preferences_add_callback_while_alive (NAUTILUS_PREFERENCES_ALWAYS_USE_LOCATION_ENTRY, + always_use_location_entry_changed, + window, G_OBJECT (window)); +} + +static void +always_use_location_entry_changed (gpointer callback_data) +{ + NautilusNavigationWindow *window; + + window = NAUTILUS_NAVIGATION_WINDOW (callback_data); + + if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_ALWAYS_USE_LOCATION_ENTRY)) { + nautilus_navigation_window_hide_path_bar (window); + } else { + nautilus_navigation_window_show_path_bar (window); + } } + +static void +path_bar_location_changed_callback (GtkWidget *widget, + const char *uri, + NautilusNavigationWindow *window) +{ + g_assert (NAUTILUS_IS_NAVIGATION_WINDOW (window)); + nautilus_window_go_to (NAUTILUS_WINDOW (window), uri); +} + + static void navigation_bar_location_changed_callback (GtkWidget *widget, const char *uri, @@ -240,13 +288,20 @@ navigation_bar_location_changed_callback (GtkWidget *widget, { g_assert (NAUTILUS_IS_NAVIGATION_WINDOW (window)); - if (window->details->temporary_navigation_bar) { + if (window->details->temporary_location_bar) { if (nautilus_navigation_window_location_bar_showing (window)) { nautilus_navigation_window_hide_location_bar (window, FALSE); } + window->details->temporary_location_bar = FALSE; + } + if (window->details->temporary_navigation_bar) { + if (!eel_preferences_get_boolean (NAUTILUS_PREFERENCES_ALWAYS_USE_LOCATION_ENTRY)) { + nautilus_navigation_window_show_path_bar (window); + } window->details->temporary_navigation_bar = FALSE; } + nautilus_window_go_to (NAUTILUS_WINDOW (window), uri); } @@ -418,10 +473,11 @@ nautilus_navigation_window_destroy (GtkObject *object) window->view_as_option_menu = NULL; window->navigation_bar = NULL; + window->path_bar = NULL; window->zoom_control = NULL; window->details->content_paned = NULL; - + if (window->details->tooltips) { g_object_unref (G_OBJECT (window->details->tooltips)); window->details->tooltips = NULL; @@ -733,10 +789,11 @@ static void real_set_content_view_widget (NautilusWindow *nautilus_window, NautilusView *new_view) { - NautilusNavigationWindow *window; + NautilusNavigationWindow *window; + window = NAUTILUS_NAVIGATION_WINDOW (nautilus_window); - + disconnect_view (window, nautilus_window->content_view); EEL_CALL_PARENT (NAUTILUS_WINDOW_CLASS, @@ -783,6 +840,10 @@ nautilus_navigation_window_show_location_bar_temporarily (NautilusNavigationWind { if (!nautilus_navigation_window_location_bar_showing (window)) { nautilus_navigation_window_show_location_bar (window, FALSE); + window->details->temporary_location_bar = TRUE; + } + if (nautilus_navigation_window_path_bar_showing (window)) { + nautilus_navigation_window_hide_path_bar (window); window->details->temporary_navigation_bar = TRUE; } nautilus_navigation_bar_activate @@ -871,7 +932,7 @@ add_sidebar_panels (NautilusNavigationWindow *window) void nautilus_navigation_window_hide_location_bar (NautilusNavigationWindow *window, gboolean save_preference) { - window->details->temporary_navigation_bar = FALSE; + window->details->temporary_location_bar = FALSE; gtk_widget_hide (window->details->location_bar); nautilus_navigation_window_update_show_hide_menu_items (window); if (save_preference && @@ -901,6 +962,31 @@ nautilus_navigation_window_location_bar_showing (NautilusNavigationWindow *windo return TRUE; } +void +nautilus_navigation_window_hide_path_bar (NautilusNavigationWindow *window) +{ + window->details->temporary_navigation_bar = FALSE; + gtk_widget_hide (window->path_bar); + gtk_widget_show (window->navigation_bar); +} + +void +nautilus_navigation_window_show_path_bar (NautilusNavigationWindow *window) +{ + gtk_widget_show (window->path_bar); + gtk_widget_hide (window->navigation_bar); +} + +gboolean +nautilus_navigation_window_path_bar_showing (NautilusNavigationWindow *window) +{ + if (window->path_bar != NULL) { + return GTK_WIDGET_VISIBLE (window->path_bar); + } + /* If we're not visible yet we haven't changed visibility, so its TRUE */ + return TRUE; +} + gboolean nautilus_navigation_window_toolbar_showing (NautilusNavigationWindow *window) { @@ -1012,6 +1098,8 @@ nautilus_navigation_window_get_base_page_index (NautilusNavigationWindow *window return forward_count; } + + /** * nautilus_navigation_window_show: * @widget: GtkWidget @@ -1035,6 +1123,12 @@ nautilus_navigation_window_show (GtkWidget *widget) nautilus_navigation_window_hide_location_bar (window, FALSE); } + if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_ALWAYS_USE_LOCATION_ENTRY)) { + nautilus_navigation_window_hide_path_bar (window); + } else { + nautilus_navigation_window_show_path_bar (window); + } + if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_START_WITH_SIDEBAR)) { nautilus_navigation_window_show_sidebar (window); } else { diff --git a/src/nautilus-navigation-window.h b/src/nautilus-navigation-window.h index c6f3ca9d8..4f00e7d0b 100644 --- a/src/nautilus-navigation-window.h +++ b/src/nautilus-navigation-window.h @@ -31,6 +31,7 @@ #define NAUTILUS_NAVIGATION_WINDOW_H #include <bonobo/bonobo-window.h> +#include <gtk/gtktoolitem.h> #include <eel/eel-glib-extensions.h> #include <libnautilus-private/nautilus-bookmark.h> #include <libnautilus-private/nautilus-sidebar.h> @@ -47,7 +48,7 @@ typedef struct _NautilusNavigationWindow NautilusNavigationWindow; typedef struct _NautilusNavigationWindowClass NautilusNavigationWindowClass; -typedef struct _NautilusNavigationWindowDetails NautilusNavigationWindowDetails; +typedef struct _NautilusNavigationWindowDetails NautilusNavigationWindowDetails; struct _NautilusNavigationWindow { NautilusWindow parent_object; @@ -58,7 +59,8 @@ struct _NautilusNavigationWindow { NautilusSidePane *sidebar; GtkWidget *view_as_option_menu; GtkWidget *navigation_bar; - + GtkWidget *path_bar; + /* Back/Forward chain, and history list. * The data in these lists are NautilusBookmark pointers. */ @@ -90,6 +92,11 @@ void nautilus_navigation_window_hide_location_bar (NautilusNavigationWind gboolean save_preference); void nautilus_navigation_window_show_location_bar (NautilusNavigationWindow *window, gboolean save_preference); + +void nautilus_navigation_window_hide_path_bar (NautilusNavigationWindow *window); +void nautilus_navigation_window_show_path_bar (NautilusNavigationWindow *window); +gboolean nautilus_navigation_window_path_bar_showing (NautilusNavigationWindow *window); + gboolean nautilus_navigation_window_location_bar_showing (NautilusNavigationWindow *window); void nautilus_navigation_window_hide_toolbar (NautilusNavigationWindow *window); void nautilus_navigation_window_show_toolbar (NautilusNavigationWindow *window); diff --git a/src/nautilus-pathbar.c b/src/nautilus-pathbar.c new file mode 100644 index 000000000..98df1c96f --- /dev/null +++ b/src/nautilus-pathbar.c @@ -0,0 +1,1641 @@ +/* nautilus-pathbar.c + * Copyright (C) 2004 Red Hat, Inc., Jonathan Blandford <jrb@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <config.h> +#include <string.h> +#include <eel/eel-debug.h> +#include <eel/eel-gtk-extensions.h> +#include <eel/eel-glib-extensions.h> +#include <eel/eel-preferences.h> +#include <eel/eel-string.h> +#include <gtk/gtktogglebutton.h> +#include <gtk/gtkalignment.h> +#include <gtk/gtkarrow.h> +#include <gtk/gtkdnd.h> +#include <gtk/gtkimage.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkhbox.h> +#include <gtk/gtkmain.h> +#include <libgnome/gnome-i18n.h> +#include <libgnomevfs/gnome-vfs-utils.h> +#include <libgnomevfs/gnome-vfs-volume-monitor.h> +#include <libnautilus-private/nautilus-icon-factory.h> +#include <libnautilus-private/nautilus-file-utilities.h> +#include <libnautilus-private/nautilus-global-preferences.h> +#include "nautilus-pathbar.h" + +enum { + PATH_CLICKED, + LAST_SIGNAL +}; + +typedef enum { + NORMAL_BUTTON, + ROOT_BUTTON, + HOME_BUTTON, + DESKTOP_BUTTON, + VOLUME_BUTTON +} ButtonType; + +#define BUTTON_DATA(x) ((ButtonData *)(x)) + +#define SCROLL_TIMEOUT 150 +#define INITIAL_SCROLL_TIMEOUT 300 + +static guint path_bar_signals [LAST_SIGNAL] = { 0 }; + +static gboolean desktop_is_home; + +#define NAUTILUS_PATH_BAR_ICON_SIZE 16 + +#define DEFAULT_ICON "gnome-fs-directory" +#define DEFAULT_DESKTOP_ICON "gnome-fs-desktop" +#define DEFAULT_HOME_ICON "gnome-fs-home" +#define DEFAULT_FILESYSTEM_ICON "gnome-fs-blockdev" + +typedef struct _ButtonData ButtonData; + +struct _ButtonData +{ + GtkWidget *button; + ButtonType type; + char *dir_name; + char *path; + + /* custom icon */ + char *custom_icon_name; + + /* flag to indicate its the base folder in the URI */ + gboolean is_base_dir; + + GtkWidget *image; + GtkWidget *label; + guint ignore_changes : 1; + guint file_is_hidden : 1; +}; + +/* This macro is used to check if a button can be used as a fake root. + * All buttons in front of a fake root are automatically hidden when in a + * directory below a fake root and replaced with the "<" arrow button. + */ +#define BUTTON_IS_FAKE_ROOT(button) ((button)->type == HOME_BUTTON || (button)->type == VOLUME_BUTTON) + +G_DEFINE_TYPE (NautilusPathBar, + nautilus_path_bar, + GTK_TYPE_CONTAINER); + +static void nautilus_path_bar_finalize (GObject *object); +static void nautilus_path_bar_dispose (GObject *object); +static void nautilus_path_bar_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void nautilus_path_bar_unmap (GtkWidget *widget); +static void nautilus_path_bar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void nautilus_path_bar_add (GtkContainer *container, + GtkWidget *widget); +static void nautilus_path_bar_remove (GtkContainer *container, + GtkWidget *widget); +static void nautilus_path_bar_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); +static void nautilus_path_bar_scroll_up (GtkWidget *button, + NautilusPathBar *path_bar); +static void nautilus_path_bar_scroll_down (GtkWidget *button, + NautilusPathBar *path_bar); +static void nautilus_path_bar_stop_scrolling (NautilusPathBar *path_bar); +static gboolean nautilus_path_bar_slider_button_press (GtkWidget *widget, + GdkEventButton *event, + NautilusPathBar *path_bar); +static gboolean nautilus_path_bar_slider_button_release (GtkWidget *widget, + GdkEventButton *event, + NautilusPathBar *path_bar); +static void nautilus_path_bar_grab_notify (GtkWidget *widget, + gboolean was_grabbed); +static void nautilus_path_bar_state_changed (GtkWidget *widget, + GtkStateType previous_state); +static void nautilus_path_bar_style_set (GtkWidget *widget, + GtkStyle *previous_style); +static void nautilus_path_bar_screen_changed (GtkWidget *widget, + GdkScreen *previous_screen); +static void nautilus_path_bar_check_icon_theme (NautilusPathBar *path_bar); +static void nautilus_path_bar_update_button_appearance (NautilusPathBar *path_bar, + ButtonData *button_data, + gboolean current_dir); +static gboolean nautilus_path_bar_update_path (NautilusPathBar *path_bar, + const char *file_path); + +static GtkWidget * +get_slider_button (NautilusPathBar *path_bar, + GtkArrowType arrow_type) +{ + GtkWidget *button; + + gtk_widget_push_composite_child (); + + button = gtk_button_new (); + gtk_container_add (GTK_CONTAINER (button), gtk_arrow_new (arrow_type, GTK_SHADOW_OUT)); + gtk_container_add (GTK_CONTAINER (path_bar), button); + gtk_widget_show_all (button); + + gtk_widget_pop_composite_child (); + + return button; +} + +static void +update_button_types (NautilusPathBar *path_bar) +{ + GList *list; + char *path = NULL; + + for (list = path_bar->button_list; list; list = list->next) { + ButtonData *button_data; + button_data = BUTTON_DATA (list->data); + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_data->button))) { + path = button_data->path; + break; + } + } + if (path != NULL) { + nautilus_path_bar_update_path (path_bar, path); + } +} + + +static void +desktop_location_changed_callback (gpointer user_data) +{ + NautilusPathBar *path_bar; + + path_bar = NAUTILUS_PATH_BAR (user_data); + + g_free (path_bar->desktop_path); + g_free (path_bar->home_path); + path_bar->desktop_path = nautilus_get_desktop_directory_uri (); + path_bar->home_path = gnome_vfs_get_uri_from_local_path (g_get_home_dir ()); + desktop_is_home = (strcmp (path_bar->home_path, path_bar->desktop_path) == 0); + + if (path_bar->home_icon) { + g_object_unref (path_bar->home_icon); + path_bar->home_icon = NULL; + } + + update_button_types (path_bar); +} + +static void +nautilus_path_bar_init (NautilusPathBar *path_bar) +{ + GTK_WIDGET_SET_FLAGS (path_bar, GTK_NO_WINDOW); + gtk_widget_set_redraw_on_allocate (GTK_WIDGET (path_bar), FALSE); + + path_bar->spacing = 3; + path_bar->up_slider_button = get_slider_button (path_bar, GTK_ARROW_LEFT); + path_bar->down_slider_button = get_slider_button (path_bar, GTK_ARROW_RIGHT); + path_bar->icon_size = NAUTILUS_PATH_BAR_ICON_SIZE; + + path_bar->desktop_path = nautilus_get_desktop_directory_uri (); + path_bar->home_path = gnome_vfs_get_uri_from_local_path (g_get_home_dir ()); + path_bar->root_path = g_strdup ("file:///"); + desktop_is_home = (strcmp (path_bar->home_path, path_bar->desktop_path) == 0); + + eel_preferences_add_callback_while_alive (NAUTILUS_PREFERENCES_DESKTOP_IS_HOME_DIR, + desktop_location_changed_callback, + path_bar, + G_OBJECT (path_bar)); + + g_signal_connect (path_bar->up_slider_button, "clicked", G_CALLBACK (nautilus_path_bar_scroll_up), path_bar); + g_signal_connect (path_bar->down_slider_button, "clicked", G_CALLBACK (nautilus_path_bar_scroll_down), path_bar); + + g_signal_connect (path_bar->up_slider_button, "button_press_event", G_CALLBACK (nautilus_path_bar_slider_button_press), path_bar); + g_signal_connect (path_bar->up_slider_button, "button_release_event", G_CALLBACK (nautilus_path_bar_slider_button_release), path_bar); + g_signal_connect (path_bar->down_slider_button, "button_press_event", G_CALLBACK (nautilus_path_bar_slider_button_press), path_bar); + g_signal_connect (path_bar->down_slider_button, "button_release_event", G_CALLBACK (nautilus_path_bar_slider_button_release), path_bar); +} + +static void +nautilus_path_bar_class_init (NautilusPathBarClass *path_bar_class) +{ + GObjectClass *gobject_class; + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + gobject_class = (GObjectClass *) path_bar_class; + object_class = (GtkObjectClass *) path_bar_class; + widget_class = (GtkWidgetClass *) path_bar_class; + container_class = (GtkContainerClass *) path_bar_class; + + gobject_class->finalize = nautilus_path_bar_finalize; + gobject_class->dispose = nautilus_path_bar_dispose; + + widget_class->size_request = nautilus_path_bar_size_request; + widget_class->unmap = nautilus_path_bar_unmap; + widget_class->size_allocate = nautilus_path_bar_size_allocate; + widget_class->style_set = nautilus_path_bar_style_set; + widget_class->screen_changed = nautilus_path_bar_screen_changed; + widget_class->grab_notify = nautilus_path_bar_grab_notify; + widget_class->state_changed = nautilus_path_bar_state_changed; + + container_class->add = nautilus_path_bar_add; + container_class->forall = nautilus_path_bar_forall; + container_class->remove = nautilus_path_bar_remove; + + path_bar_signals [PATH_CLICKED] = + g_signal_new ("path-clicked", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NautilusPathBarClass, path_clicked), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); +} + + +static void +nautilus_path_bar_finalize (GObject *object) +{ + NautilusPathBar *path_bar; + + path_bar = NAUTILUS_PATH_BAR (object); + + nautilus_path_bar_stop_scrolling (path_bar); + + g_list_free (path_bar->button_list); + if (path_bar->root_path) { + g_free (path_bar->root_path); + path_bar->root_path = NULL; + } + if (path_bar->home_path) { + g_free (path_bar->home_path); + path_bar->home_path = NULL; + } + if (path_bar->desktop_path) { + g_free (path_bar->desktop_path); + path_bar->desktop_path = NULL; + } + + if (path_bar->root_icon) { + g_object_unref (path_bar->root_icon); + path_bar->root_icon = NULL; + } + if (path_bar->home_icon) { + g_object_unref (path_bar->home_icon); + path_bar->home_icon = NULL; + } + if (path_bar->desktop_icon) { + g_object_unref (path_bar->desktop_icon); + path_bar->desktop_icon = NULL; + } + + G_OBJECT_CLASS (nautilus_path_bar_parent_class)->finalize (object); +} + +/* Removes the settings signal handler. It's safe to call multiple times */ +static void +remove_settings_signal (NautilusPathBar *path_bar, + GdkScreen *screen) +{ + if (path_bar->settings_signal_id) { + GtkSettings *settings; + + settings = gtk_settings_get_for_screen (screen); + g_signal_handler_disconnect (settings, + path_bar->settings_signal_id); + path_bar->settings_signal_id = 0; + } +} + +static void +nautilus_path_bar_dispose (GObject *object) +{ + remove_settings_signal (NAUTILUS_PATH_BAR (object), gtk_widget_get_screen (GTK_WIDGET (object))); + + G_OBJECT_CLASS (nautilus_path_bar_parent_class)->dispose (object); +} + +/* Size requisition: + * + * Ideally, our size is determined by another widget, and we are just filling + * available space. + */ +static void +nautilus_path_bar_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + ButtonData *button_data; + NautilusPathBar *path_bar; + GtkRequisition child_requisition; + GList *list; + + path_bar = NAUTILUS_PATH_BAR (widget); + + requisition->width = 0; + requisition->height = 0; + + for (list = path_bar->button_list; list; list = list->next) { + button_data = BUTTON_DATA (list->data); + gtk_widget_size_request (button_data->button, &child_requisition); + requisition->width = MAX (child_requisition.width, requisition->width); + requisition->height = MAX (child_requisition.height, requisition->height); + } + + /* Add space for slider, if we have more than one path */ + /* Theoretically, the slider could be bigger than the other button. But we're */ + /* not going to worry about that now.*/ + + path_bar->slider_width = MIN(requisition->height * 2 / 3 + 5, requisition->height); + if (path_bar->button_list && path_bar->button_list->next != NULL) { + requisition->width += (path_bar->spacing + path_bar->slider_width) * 2; + } + + gtk_widget_size_request (path_bar->up_slider_button, &child_requisition); + gtk_widget_size_request (path_bar->down_slider_button, &child_requisition); + + requisition->width += GTK_CONTAINER (widget)->border_width * 2; + requisition->height += GTK_CONTAINER (widget)->border_width * 2; + + widget->requisition = *requisition; +} + +static void +nautilus_path_bar_update_slider_buttons (NautilusPathBar *path_bar) +{ + if (path_bar->button_list) { + + GtkWidget *button; + + button = BUTTON_DATA (path_bar->button_list->data)->button; + if (gtk_widget_get_child_visible (button)) { + gtk_widget_set_sensitive (path_bar->down_slider_button, FALSE); + } else { + gtk_widget_set_sensitive (path_bar->down_slider_button, TRUE); + } + button = BUTTON_DATA (g_list_last (path_bar->button_list)->data)->button; + if (gtk_widget_get_child_visible (button)) { + gtk_widget_set_sensitive (path_bar->up_slider_button, FALSE); + } else { + gtk_widget_set_sensitive (path_bar->up_slider_button, TRUE); + } + } +} + +static void +nautilus_path_bar_unmap (GtkWidget *widget) +{ + nautilus_path_bar_stop_scrolling (NAUTILUS_PATH_BAR (widget)); + + GTK_WIDGET_CLASS (nautilus_path_bar_parent_class)->unmap (widget); +} + +/* This is a tad complicated */ +static void +nautilus_path_bar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkWidget *child; + NautilusPathBar *path_bar; + GtkTextDirection direction; + GtkAllocation child_allocation; + GList *list, *first_button; + gint width; + gint allocation_width; + gint border_width; + gboolean need_sliders; + gint up_slider_offset; + gint down_slider_offset; + + need_sliders = FALSE; + up_slider_offset = 0; + down_slider_offset = 0; + path_bar = NAUTILUS_PATH_BAR (widget); + + widget->allocation = *allocation; + + + /* No path is set so we don't have to allocate anything. */ + if (path_bar->button_list == NULL) { + return; + } + direction = gtk_widget_get_direction (widget); + border_width = (gint) GTK_CONTAINER (path_bar)->border_width; + allocation_width = allocation->width - 2 * border_width; + + /* First, we check to see if we need the scrollbars. */ + if (path_bar->fake_root) { + width = path_bar->spacing + path_bar->slider_width; + } else { + width = 0; + } + + width += BUTTON_DATA (path_bar->button_list->data)->button->requisition.width; + + for (list = path_bar->button_list->next; list; list = list->next) { + child = BUTTON_DATA (list->data)->button; + width += child->requisition.width + path_bar->spacing; + + if (list == path_bar->fake_root) { + break; + } + } + + if (width <= allocation_width) { + if (path_bar->fake_root) { + first_button = path_bar->fake_root; + } else { + first_button = g_list_last (path_bar->button_list); + } + } else { + gboolean reached_end; + gint slider_space; + reached_end = FALSE; + slider_space = 2 * (path_bar->spacing + path_bar->slider_width); + + if (path_bar->first_scrolled_button) { + first_button = path_bar->first_scrolled_button; + } else { + first_button = path_bar->button_list; + } + + need_sliders = TRUE; + /* To see how much space we have, and how many buttons we can display. + * We start at the first button, count forward until hit the new + * button, then count backwards. + */ + /* Count down the path chain towards the end. */ + width = BUTTON_DATA (first_button->data)->button->requisition.width; + list = first_button->prev; + while (list && !reached_end) { + child = BUTTON_DATA (list->data)->button; + + if (width + child->requisition.width + path_bar->spacing + slider_space > allocation_width) { + reached_end = TRUE; + } else { + if (list == path_bar->fake_root) { + break; + } else { + width += child->requisition.width + path_bar->spacing; + } + } + + list = list->prev; + } + + /* Finally, we walk up, seeing how many of the previous buttons we can add*/ + + while (first_button->next && ! reached_end) { + child = BUTTON_DATA (first_button->next->data)->button; + if (width + child->requisition.width + path_bar->spacing + slider_space > allocation_width) { + reached_end = TRUE; + } else { + width += child->requisition.width + path_bar->spacing; + if (first_button == path_bar->fake_root) { + break; + } + first_button = first_button->next; + } + } + } + + /* Now, we allocate space to the buttons */ + child_allocation.y = allocation->y + border_width; + child_allocation.height = MAX (1, (gint) allocation->height - border_width * 2); + + if (direction == GTK_TEXT_DIR_RTL) { + child_allocation.x = allocation->x + allocation->width - border_width; + if (need_sliders || path_bar->fake_root) { + child_allocation.x -= (path_bar->spacing + path_bar->slider_width); + up_slider_offset = allocation->width - border_width - path_bar->slider_width; + } + } else { + child_allocation.x = allocation->x + border_width; + if (need_sliders || path_bar->fake_root) { + up_slider_offset = border_width; + child_allocation.x += (path_bar->spacing + path_bar->slider_width); + } + } + + for (list = first_button; list; list = list->prev) { + child = BUTTON_DATA (list->data)->button; + + child_allocation.width = child->requisition.width; + if (direction == GTK_TEXT_DIR_RTL) { + child_allocation.x -= child_allocation.width; + } + /* Check to see if we've don't have any more space to allocate buttons */ + if (need_sliders && direction == GTK_TEXT_DIR_RTL) { + if (child_allocation.x - path_bar->spacing - path_bar->slider_width < widget->allocation.x + border_width) { + break; + } + } else { + if (need_sliders && direction == GTK_TEXT_DIR_LTR) { + if (child_allocation.x + child_allocation.width + path_bar->spacing + path_bar->slider_width > widget->allocation.x + border_width + allocation_width) { + break; + } + } + } + + gtk_widget_set_child_visible (BUTTON_DATA (list->data)->button, TRUE); + gtk_widget_size_allocate (child, &child_allocation); + + if (direction == GTK_TEXT_DIR_RTL) { + child_allocation.x -= path_bar->spacing; + down_slider_offset = child_allocation.x - widget->allocation.x - path_bar->slider_width; + down_slider_offset = border_width; + } else { + down_slider_offset = child_allocation.x - widget->allocation.x; + down_slider_offset = allocation->width - border_width - path_bar->slider_width; + child_allocation.x += child_allocation.width + path_bar->spacing; + } + } + /* Now we go hide all the widgets that don't fit */ + while (list) { + gtk_widget_set_child_visible (BUTTON_DATA (list->data)->button, FALSE); + list = list->prev; + } + for (list = first_button->next; list; list = list->next) { + gtk_widget_set_child_visible (BUTTON_DATA (list->data)->button, FALSE); + } + + if (need_sliders || path_bar->fake_root) { + child_allocation.width = path_bar->slider_width; + child_allocation.x = up_slider_offset + allocation->x; + gtk_widget_size_allocate (path_bar->up_slider_button, &child_allocation); + + gtk_widget_set_child_visible (path_bar->up_slider_button, TRUE); + gtk_widget_show_all (path_bar->up_slider_button); + + } else { + gtk_widget_set_child_visible (path_bar->up_slider_button, FALSE); + } + + if (need_sliders) { + child_allocation.width = path_bar->slider_width; + child_allocation.x = down_slider_offset + allocation->x; + gtk_widget_size_allocate (path_bar->down_slider_button, &child_allocation); + + gtk_widget_set_child_visible (path_bar->down_slider_button, TRUE); + gtk_widget_show_all (path_bar->down_slider_button); + nautilus_path_bar_update_slider_buttons (path_bar); + } else { + gtk_widget_set_child_visible (path_bar->down_slider_button, FALSE); + } +} + +static void +nautilus_path_bar_style_set (GtkWidget *widget, GtkStyle *previous_style) +{ + if (GTK_WIDGET_CLASS (nautilus_path_bar_parent_class)->style_set) { + GTK_WIDGET_CLASS (nautilus_path_bar_parent_class)->style_set (widget, previous_style); + } + + nautilus_path_bar_check_icon_theme (NAUTILUS_PATH_BAR (widget)); +} + +static void +nautilus_path_bar_screen_changed (GtkWidget *widget, + GdkScreen *previous_screen) +{ + if (GTK_WIDGET_CLASS (nautilus_path_bar_parent_class)->screen_changed) { + GTK_WIDGET_CLASS (nautilus_path_bar_parent_class)->screen_changed (widget, previous_screen); + } + /* We might nave a new settings, so we remove the old one */ + if (previous_screen) { + remove_settings_signal (NAUTILUS_PATH_BAR (widget), previous_screen); + } + nautilus_path_bar_check_icon_theme (NAUTILUS_PATH_BAR (widget)); +} + +static void +nautilus_path_bar_add (GtkContainer *container, + GtkWidget *widget) +{ + gtk_widget_set_parent (widget, GTK_WIDGET (container)); +} + +static void +nautilus_path_bar_remove_1 (GtkContainer *container, + GtkWidget *widget) +{ + gboolean was_visible = GTK_WIDGET_VISIBLE (widget); + gtk_widget_unparent (widget); + if (was_visible) { + gtk_widget_queue_resize (GTK_WIDGET (container)); + } +} + +static void +nautilus_path_bar_remove (GtkContainer *container, + GtkWidget *widget) +{ + NautilusPathBar *path_bar; + GList *children; + + path_bar = NAUTILUS_PATH_BAR (container); + + if (widget == path_bar->up_slider_button) { + nautilus_path_bar_remove_1 (container, widget); + path_bar->up_slider_button = NULL; + return; + } + + if (widget == path_bar->down_slider_button) { + nautilus_path_bar_remove_1 (container, widget); + path_bar->down_slider_button = NULL; + return; + } + + children = path_bar->button_list; + while (children) { + if (widget == BUTTON_DATA (children->data)->button) { + nautilus_path_bar_remove_1 (container, widget); + path_bar->button_list = g_list_remove_link (path_bar->button_list, children); + g_list_free (children); + return; + } + children = children->next; + } +} + +static void +nautilus_path_bar_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) +{ + NautilusPathBar *path_bar; + GList *children; + + g_return_if_fail (callback != NULL); + path_bar = NAUTILUS_PATH_BAR (container); + + children = path_bar->button_list; + while (children) { + GtkWidget *child; + child = BUTTON_DATA (children->data)->button; + children = children->next; + (* callback) (child, callback_data); + } + + if (path_bar->up_slider_button) { + (* callback) (path_bar->up_slider_button, callback_data); + } + + if (path_bar->down_slider_button) { + (* callback) (path_bar->down_slider_button, callback_data); + } +} + +static void +nautilus_path_bar_scroll_down (GtkWidget *button, NautilusPathBar *path_bar) +{ + GList *list; + GList *down_button; + GList *up_button; + gint space_available; + gint space_needed; + gint border_width; + GtkTextDirection direction; + + down_button = NULL; + up_button = NULL; + + if (path_bar->ignore_click) { + path_bar->ignore_click = FALSE; + return; + } + + gtk_widget_queue_resize (GTK_WIDGET (path_bar)); + + border_width = GTK_CONTAINER (path_bar)->border_width; + direction = gtk_widget_get_direction (GTK_WIDGET (path_bar)); + + /* We find the button at the 'down' end that we have to make */ + /* visible */ + for (list = path_bar->button_list; list; list = list->next) { + if (list->next && gtk_widget_get_child_visible (BUTTON_DATA (list->next->data)->button)) { + down_button = list; + break; + } + } + + /* Find the last visible button on the 'up' end */ + for (list = g_list_last (path_bar->button_list); list; list = list->prev) { + if (gtk_widget_get_child_visible (BUTTON_DATA (list->data)->button)) { + up_button = list; + break; + } + } + + space_needed = BUTTON_DATA (down_button->data)->button->allocation.width + path_bar->spacing; + if (direction == GTK_TEXT_DIR_RTL) { + space_available = path_bar->down_slider_button->allocation.x - GTK_WIDGET (path_bar)->allocation.x; + } else { + space_available = (GTK_WIDGET (path_bar)->allocation.x + GTK_WIDGET (path_bar)->allocation.width - border_width) - + (path_bar->down_slider_button->allocation.x + path_bar->down_slider_button->allocation.width); + } + + /* We have space_available extra space that's not being used. We + * need space_needed space to make the button fit. So we walk down + * from the end, removing buttons until we get all the space we + * need. */ + while (space_available < space_needed) { + space_available += BUTTON_DATA (up_button->data)->button->allocation.width + path_bar->spacing; + up_button = up_button->prev; + path_bar->first_scrolled_button = up_button; + } +} + +static void +nautilus_path_bar_scroll_up (GtkWidget *button, NautilusPathBar *path_bar) +{ + GList *list; + + if (path_bar->ignore_click) { + path_bar->ignore_click = FALSE; + return; + } + + gtk_widget_queue_resize (GTK_WIDGET (path_bar)); + + for (list = g_list_last (path_bar->button_list); list; list = list->prev) { + if (list->prev && gtk_widget_get_child_visible (BUTTON_DATA (list->prev->data)->button)) { + if (list->prev == path_bar->fake_root) { + path_bar->fake_root = NULL; + } + path_bar->first_scrolled_button = list; + return; + } + } +} + +static gboolean +nautilus_path_bar_scroll_timeout (NautilusPathBar *path_bar) +{ + gboolean retval = FALSE; + + GDK_THREADS_ENTER (); + + if (path_bar->timer) { + if (GTK_WIDGET_HAS_FOCUS (path_bar->up_slider_button)) { + nautilus_path_bar_scroll_up (path_bar->up_slider_button, path_bar); + } else { + if (GTK_WIDGET_HAS_FOCUS (path_bar->down_slider_button)) { + nautilus_path_bar_scroll_down (path_bar->down_slider_button, path_bar); + } + } + if (path_bar->need_timer) { + path_bar->need_timer = FALSE; + + path_bar->timer = g_timeout_add (SCROLL_TIMEOUT, + (GSourceFunc)nautilus_path_bar_scroll_timeout, + path_bar); + + } else { + retval = TRUE; + } + } + + + GDK_THREADS_LEAVE (); + + return retval; +} + +static void +nautilus_path_bar_stop_scrolling (NautilusPathBar *path_bar) +{ + if (path_bar->timer) { + g_source_remove (path_bar->timer); + path_bar->timer = 0; + path_bar->need_timer = FALSE; + } +} + +static gboolean +nautilus_path_bar_slider_button_press (GtkWidget *widget, + GdkEventButton *event, + NautilusPathBar *path_bar) +{ + if (!GTK_WIDGET_HAS_FOCUS (widget)) { + gtk_widget_grab_focus (widget); + } + + if (event->type != GDK_BUTTON_PRESS || event->button != 1) { + return FALSE; + } + + path_bar->ignore_click = FALSE; + + if (widget == path_bar->up_slider_button) { + nautilus_path_bar_scroll_up (path_bar->up_slider_button, path_bar); + } else { + if (widget == path_bar->down_slider_button) { + nautilus_path_bar_scroll_down (path_bar->down_slider_button, path_bar); + } + } + + if (!path_bar->timer) { + path_bar->need_timer = TRUE; + path_bar->timer = g_timeout_add (INITIAL_SCROLL_TIMEOUT, + (GSourceFunc)nautilus_path_bar_scroll_timeout, + path_bar); + } + + return FALSE; +} + +static gboolean +nautilus_path_bar_slider_button_release (GtkWidget *widget, + GdkEventButton *event, + NautilusPathBar *path_bar) +{ + if (event->type != GDK_BUTTON_RELEASE) { + return FALSE; + } + + path_bar->ignore_click = TRUE; + nautilus_path_bar_stop_scrolling (path_bar); + + return FALSE; +} + +static void +nautilus_path_bar_grab_notify (GtkWidget *widget, + gboolean was_grabbed) +{ + if (!was_grabbed) { + nautilus_path_bar_stop_scrolling (NAUTILUS_PATH_BAR (widget)); + } +} + +static void +nautilus_path_bar_state_changed (GtkWidget *widget, + GtkStateType previous_state) +{ + if (!GTK_WIDGET_IS_SENSITIVE (widget)) { + nautilus_path_bar_stop_scrolling (NAUTILUS_PATH_BAR (widget)); + } +} + + + +/* Changes the icons wherever it is needed */ +static void +reload_icons (NautilusPathBar *path_bar) +{ + GList *list; + + if (path_bar->root_icon) { + g_object_unref (path_bar->root_icon); + path_bar->root_icon = NULL; + } + if (path_bar->home_icon) { + g_object_unref (path_bar->home_icon); + path_bar->home_icon = NULL; + } + if (path_bar->desktop_icon) { + g_object_unref (path_bar->desktop_icon); + path_bar->desktop_icon = NULL; + } + + + for (list = path_bar->button_list; list; list = list->next) { + ButtonData *button_data; + gboolean current_dir; + + button_data = BUTTON_DATA (list->data); + if (button_data->type != NORMAL_BUTTON) { + current_dir = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_data->button)); + nautilus_path_bar_update_button_appearance (path_bar, button_data, current_dir); + } + + } +} + +static void +change_icon_theme (NautilusPathBar *path_bar) +{ + path_bar->icon_size = NAUTILUS_PATH_BAR_ICON_SIZE; + reload_icons (path_bar); +} + +/* Callback used when a GtkSettings value changes */ +static void +settings_notify_cb (GObject *object, + GParamSpec *pspec, + NautilusPathBar *path_bar) +{ + const char *name; + + name = g_param_spec_get_name (pspec); + + if (! strcmp (name, "gtk-icon-theme-name") || ! strcmp (name, "gtk-icon-sizes")) { + change_icon_theme (path_bar); + } +} + +static void +nautilus_path_bar_check_icon_theme (NautilusPathBar *path_bar) +{ + GtkSettings *settings; + + if (path_bar->settings_signal_id) { + return; + } + + settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (path_bar))); + path_bar->settings_signal_id = g_signal_connect (settings, "notify", G_CALLBACK (settings_notify_cb), path_bar); + + change_icon_theme (path_bar); +} + +/* Public functions and their helpers */ +static void +nautilus_path_bar_clear_buttons (NautilusPathBar *path_bar) +{ + while (path_bar->button_list != NULL) { + gtk_container_remove (GTK_CONTAINER (path_bar), BUTTON_DATA (path_bar->button_list->data)->button); + } + path_bar->first_scrolled_button = NULL; + path_bar->fake_root = NULL; +} + +static void +button_clicked_cb (GtkWidget *button, + gpointer data) +{ + ButtonData *button_data; + NautilusPathBar *path_bar; + GList *button_list; + gboolean child_is_hidden; + + button_data = BUTTON_DATA (data); + if (button_data->ignore_changes) { + return; + } + + path_bar = NAUTILUS_PATH_BAR (button->parent); + + button_list = g_list_find (path_bar->button_list, button_data); + g_assert (button_list != NULL); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE); + + if (button_list->prev) { + ButtonData *child_data; + + child_data = BUTTON_DATA (button_list->prev->data); + child_is_hidden = child_data->file_is_hidden; + } else { + child_is_hidden = FALSE; + } + g_signal_emit (path_bar, path_bar_signals [PATH_CLICKED], 0, button_data->path); +} + +static char * +get_icon_name_for_file_path (const char *file_path) +{ + NautilusFile *file; + char *icon_name; + + file = nautilus_file_get (file_path); + if (!file) { + return g_strdup (DEFAULT_ICON); + } + icon_name = NULL; + if (nautilus_icon_factory_is_icon_ready_for_file (file)) { + icon_name = nautilus_icon_factory_get_icon_for_file (file, FALSE); + } + if (!icon_name) { + icon_name = g_strdup (DEFAULT_ICON); + } + nautilus_file_unref (file); + return icon_name; +} + +static GdkPixbuf * +get_button_image (NautilusPathBar *path_bar, + ButtonType button_type) +{ + char *icon_name; + + switch (button_type) + { + case ROOT_BUTTON: + if (path_bar->root_icon != NULL) { + return path_bar->root_icon; + } + + icon_name = get_icon_name_for_file_path (path_bar->root_path); + if (strcmp (icon_name, DEFAULT_ICON) == 0) { + path_bar->root_icon = nautilus_icon_factory_get_pixbuf_from_name (DEFAULT_FILESYSTEM_ICON, + NULL, NAUTILUS_PATH_BAR_ICON_SIZE, + TRUE, NULL); + } else { + path_bar->root_icon = nautilus_icon_factory_get_pixbuf_from_name (icon_name, + NULL, NAUTILUS_PATH_BAR_ICON_SIZE, + TRUE, NULL); + } + + g_free (icon_name); + return path_bar->root_icon; + + case HOME_BUTTON: + if (path_bar->home_icon != NULL) { + return path_bar->home_icon; + } + + if (!desktop_is_home) { + icon_name = get_icon_name_for_file_path (path_bar->home_path); + if (strcmp (icon_name, DEFAULT_ICON) == 0) { + path_bar->home_icon = nautilus_icon_factory_get_pixbuf_from_name (DEFAULT_HOME_ICON, + NULL, NAUTILUS_PATH_BAR_ICON_SIZE, + TRUE, NULL); + } else { + path_bar->home_icon = nautilus_icon_factory_get_pixbuf_from_name (icon_name, + NULL, NAUTILUS_PATH_BAR_ICON_SIZE, + TRUE, NULL); + } + + g_free (icon_name); + } else { + path_bar->home_icon = nautilus_icon_factory_get_pixbuf_from_name (DEFAULT_DESKTOP_ICON, + NULL, NAUTILUS_PATH_BAR_ICON_SIZE, + TRUE, NULL); + } + return path_bar->home_icon; + + case DESKTOP_BUTTON: + if (path_bar->desktop_icon != NULL) { + return path_bar->desktop_icon; + } + icon_name = get_icon_name_for_file_path (path_bar->desktop_path); + if (strcmp (icon_name, DEFAULT_ICON) == 0) { + path_bar->desktop_icon = nautilus_icon_factory_get_pixbuf_from_name (DEFAULT_DESKTOP_ICON, + NULL, NAUTILUS_PATH_BAR_ICON_SIZE, + TRUE, NULL); + } else { + path_bar->desktop_icon = nautilus_icon_factory_get_pixbuf_from_name (icon_name, + NULL, NAUTILUS_PATH_BAR_ICON_SIZE, + TRUE, NULL); + } + + g_free (icon_name); + return path_bar->desktop_icon; + + default: + return NULL; + } + + return NULL; +} + +static void +button_data_free (ButtonData *button_data) +{ + g_free (button_data->path); + g_free (button_data->dir_name); + if (button_data->custom_icon_name) { + g_free (button_data->custom_icon_name); + } + g_free (button_data); +} + +static const char * +get_dir_name (ButtonData *button_data) +{ + if (button_data->type == HOME_BUTTON) { + if (!desktop_is_home) { + return _("Home"); + } else { + return _("Desktop"); + } + } else { + if (button_data->type == DESKTOP_BUTTON) { + return _("Desktop"); + } else { + return button_data->dir_name; + } + } +} + +/* We always want to request the same size for the label, whether + * or not the contents are bold + */ +static void +label_size_request_cb (GtkWidget *widget, + GtkRequisition *requisition, + ButtonData *button_data) +{ + const gchar *dir_name = get_dir_name (button_data); + PangoLayout *layout; + gint bold_width, bold_height; + gchar *markup; + + layout = gtk_widget_create_pango_layout (button_data->label, dir_name); + pango_layout_get_pixel_size (layout, &requisition->width, &requisition->height); + + markup = g_markup_printf_escaped ("<b>%s</b>", dir_name); + pango_layout_set_markup (layout, markup, -1); + g_free (markup); + + pango_layout_get_pixel_size (layout, &bold_width, &bold_height); + requisition->width = MAX (requisition->width, bold_width); + requisition->height = MAX (requisition->height, bold_height); + + g_object_unref (layout); +} + +static void +nautilus_path_bar_update_button_appearance (NautilusPathBar *path_bar, + ButtonData *button_data, + gboolean current_dir) +{ + const gchar *dir_name = get_dir_name (button_data); + + + if (button_data->label != NULL) { + if (current_dir) { + char *markup; + + markup = g_markup_printf_escaped ("<b>%s</b>", dir_name); + gtk_label_set_markup (GTK_LABEL (button_data->label), markup); + g_free (markup); + } else { + gtk_label_set_text (GTK_LABEL (button_data->label), dir_name); + } + } + + if (button_data->image != NULL) { + if (button_data->type == VOLUME_BUTTON || (button_data->type == NORMAL_BUTTON && button_data->is_base_dir) ) { + + /* set custom icon for roots */ + if (button_data->custom_icon_name) { + gtk_image_set_from_icon_name (GTK_IMAGE (button_data->image), button_data->custom_icon_name, GTK_ICON_SIZE_MENU); + } + } else { + GdkPixbuf *pixbuf; + pixbuf = get_button_image (path_bar, button_data->type); + gtk_image_set_from_pixbuf (GTK_IMAGE (button_data->image), pixbuf); + } + } + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_data->button)) != current_dir) { + button_data->ignore_changes = TRUE; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button_data->button), current_dir); + button_data->ignore_changes = FALSE; + } +} + +static gboolean +is_file_path_equal (const char *file_path_1, const char *file_path_2) +{ + GnomeVFSURI *vfs_uri_1, *vfs_uri_2; + gboolean result; + + vfs_uri_1 = gnome_vfs_uri_new (file_path_1); + if (vfs_uri_1 == NULL) { + return FALSE; + } + + vfs_uri_2 = gnome_vfs_uri_new (file_path_2); + if (vfs_uri_2 == NULL) { + gnome_vfs_uri_unref (vfs_uri_1); + return FALSE; + } + + result = gnome_vfs_uri_equal (vfs_uri_1, vfs_uri_2); + + gnome_vfs_uri_unref (vfs_uri_1); + gnome_vfs_uri_unref (vfs_uri_2); + return result; +} + +static gboolean +is_file_path_mounted_volume (const char *file_path, ButtonData *button_data) +{ + GnomeVFSVolumeMonitor *volume_monitor; + GList *volumes, *l; + GnomeVFSVolume *volume; + gboolean result; + char *mount_uri; + + result = FALSE; + volume_monitor = gnome_vfs_get_volume_monitor (); + volumes = gnome_vfs_volume_monitor_get_mounted_volumes (volume_monitor); + for (l = volumes; l != NULL; l = l->next) { + volume = l->data; + if (result || !gnome_vfs_volume_is_user_visible (volume)) { + gnome_vfs_volume_unref (volume); + continue; + } + mount_uri = gnome_vfs_volume_get_activation_uri (volume); + if (is_file_path_equal (file_path, mount_uri)) { + result = TRUE; + /* set volume specific details in button_data */ + if (button_data) { + button_data->custom_icon_name = gnome_vfs_volume_get_icon (volume); + if (!button_data->custom_icon_name) { + button_data->custom_icon_name = g_strdup (DEFAULT_ICON); + } + button_data->path = g_strdup (mount_uri); + button_data->dir_name = gnome_vfs_volume_get_display_name (volume); + } + gnome_vfs_volume_unref (volume); + g_free (mount_uri); + continue; + } + gnome_vfs_volume_unref (volume); + g_free (mount_uri); + } + g_list_free (volumes); + return result; +} + +static ButtonType +find_button_type (NautilusPathBar *path_bar, + const char *path, + ButtonData *button_data) +{ + + + if (path_bar->root_path != NULL && is_file_path_equal (path, path_bar->root_path)) { + return ROOT_BUTTON; + } + if (path_bar->home_path != NULL && is_file_path_equal (path, path_bar->home_path)) { + return HOME_BUTTON; + } + if (path_bar->desktop_path != NULL && is_file_path_equal (path, path_bar->desktop_path)) { + if (!desktop_is_home) { + return DESKTOP_BUTTON; + } else { + return NORMAL_BUTTON; + } + } + if (is_file_path_mounted_volume (path, button_data)) { + return VOLUME_BUTTON; + } + + return NORMAL_BUTTON; +} + +static void +button_drag_data_get_cb (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time_, + gpointer data) +{ + ButtonData *button_data; + char *uri_list; + + button_data = data; + uri_list = g_strconcat (button_data->path, "\r\n", NULL); + gtk_selection_data_set (selection_data, + selection_data->target, + 8, + uri_list, + strlen (uri_list)); + g_free (uri_list); +} + +static ButtonData * +make_directory_button (NautilusPathBar *path_bar, + const char *dir_name, + const char *path, + gboolean current_dir, + gboolean base_dir, + gboolean file_is_hidden) +{ + const GtkTargetEntry targets[] = { + { "text/uri-list", 0, 0 } + }; + + GtkWidget *child; + GtkWidget *label_alignment; + ButtonData *button_data; + + child = NULL; + label_alignment = NULL; + + file_is_hidden = !! file_is_hidden; + /* Is it a special button? */ + button_data = g_new0 (ButtonData, 1); + + button_data->type = find_button_type (path_bar, path, button_data); + button_data->button = gtk_toggle_button_new (); + + switch (button_data->type) { + case ROOT_BUTTON: + button_data->image = gtk_image_new (); + child = button_data->image; + button_data->label = NULL; + break; + case HOME_BUTTON: + case DESKTOP_BUTTON: + case VOLUME_BUTTON: + button_data->image = gtk_image_new (); + button_data->label = gtk_label_new (NULL); + label_alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0); + gtk_container_add (GTK_CONTAINER (label_alignment), button_data->label); + child = gtk_hbox_new (FALSE, 2); + gtk_box_pack_start (GTK_BOX (child), button_data->image, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (child), label_alignment, FALSE, FALSE, 0); + break; + case NORMAL_BUTTON: + default: + if (base_dir) { + button_data->image = gtk_image_new (); + button_data->label = gtk_label_new (NULL); + label_alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0); + gtk_container_add (GTK_CONTAINER (label_alignment), button_data->label); + child = gtk_hbox_new (FALSE, 2); + gtk_box_pack_start (GTK_BOX (child), button_data->image, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (child), label_alignment, FALSE, FALSE, 0); + button_data->is_base_dir = TRUE; + button_data->custom_icon_name = get_icon_name_for_file_path (path); + } else { + button_data->is_base_dir = FALSE; + button_data->label = gtk_label_new (NULL); + label_alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0); + gtk_container_add (GTK_CONTAINER (label_alignment), button_data->label); + child = label_alignment; + button_data->image = NULL; + } + } + + /* label_alignment is created because we can't override size-request + * on label itself and still have the contents of the label centered + * properly in the label's requisition + */ + + if (label_alignment) { + g_signal_connect (label_alignment, "size-request", + G_CALLBACK (label_size_request_cb), button_data); + } + + /* do not set these for volumes */ + if (button_data->type != VOLUME_BUTTON) { + button_data->dir_name = g_strdup (dir_name); + button_data->path = g_strdup (path); + } + + button_data->file_is_hidden = file_is_hidden; + + gtk_container_add (GTK_CONTAINER (button_data->button), child); + gtk_widget_show_all (button_data->button); + + nautilus_path_bar_update_button_appearance (path_bar, button_data, current_dir); + + g_signal_connect (button_data->button, "clicked", G_CALLBACK (button_clicked_cb), button_data); + g_object_weak_ref (G_OBJECT (button_data->button), (GWeakNotify) button_data_free, button_data); + + gtk_drag_source_set (button_data->button, + GDK_BUTTON1_MASK, + targets, + G_N_ELEMENTS (targets), + GDK_ACTION_COPY); + g_signal_connect (button_data->button, "drag-data-get",G_CALLBACK (button_drag_data_get_cb), button_data); + + return button_data; +} + +static gboolean +nautilus_path_bar_check_parent_path (NautilusPathBar *path_bar, + const char *file_path) +{ + GList *list; + GList *current_path; + gboolean need_new_fake_root; + + current_path = NULL; + need_new_fake_root = FALSE; + + for (list = path_bar->button_list; list; list = list->next) { + ButtonData *button_data; + + button_data = list->data; + if (is_file_path_equal (file_path, button_data->path)) { + current_path = list; + break; + } + if (list == path_bar->fake_root) { + need_new_fake_root = TRUE; + } + } + + if (current_path) { + + if (need_new_fake_root) { + path_bar->fake_root = NULL; + for (list = current_path; list; list = list->next) { + ButtonData *button_data; + + button_data = list->data; + if (BUTTON_IS_FAKE_ROOT (button_data)) { + path_bar->fake_root = list; + break; + } + } + } + + for (list = path_bar->button_list; list; list = list->next) { + + nautilus_path_bar_update_button_appearance (path_bar, + BUTTON_DATA (list->data), + (list == current_path) ? TRUE : FALSE); + } + + if (!gtk_widget_get_child_visible (BUTTON_DATA (current_path->data)->button)) { + path_bar->first_scrolled_button = current_path; + gtk_widget_queue_resize (GTK_WIDGET (path_bar)); + } + return TRUE; + } + return FALSE; +} + +static char * +get_parent_directory (const char *file_path) +{ + GnomeVFSURI *vfs_uri, *parent_vfs_uri; + char *parent_directory; + + + vfs_uri = gnome_vfs_uri_new (file_path); + if (vfs_uri == NULL) { + return NULL; + } + + parent_vfs_uri = gnome_vfs_uri_get_parent (vfs_uri); + gnome_vfs_uri_unref (vfs_uri); + if (parent_vfs_uri == NULL) { + return NULL; + } + + parent_directory = gnome_vfs_uri_to_string (parent_vfs_uri, + GNOME_VFS_URI_HIDE_NONE); + gnome_vfs_uri_unref (parent_vfs_uri); + return parent_directory; + +} + + +static char * +get_display_name_for_folder (const char *file_path) +{ + GnomeVFSURI *vfs_uri; + char *name; + + vfs_uri = gnome_vfs_uri_new (file_path); + if (vfs_uri == NULL) { + return NULL; + } + name = nautilus_get_uri_shortname_for_display (vfs_uri); + gnome_vfs_uri_unref (vfs_uri); + return name; +} + + +static gboolean +nautilus_path_bar_update_path (NautilusPathBar *path_bar, const char *file_path) +{ + char *path, *parent_path, *name; + gboolean first_directory, last_directory; + gboolean result; + GList *new_buttons, *l, *fake_root; + ButtonData *button_data; + + g_return_val_if_fail (NAUTILUS_IS_PATH_BAR (path_bar), FALSE); + g_return_val_if_fail (file_path != NULL, FALSE); + + name = NULL; + fake_root = NULL; + result = TRUE; + parent_path = NULL; + first_directory = TRUE; + last_directory = FALSE; + new_buttons = NULL; + + path = g_strdup (file_path); + + gtk_widget_push_composite_child (); + + while (path != NULL) { + + parent_path = get_parent_directory (path); + name = get_display_name_for_folder (path); + last_directory = !parent_path; + button_data = make_directory_button (path_bar, name, path, first_directory, last_directory, FALSE); + g_free (path); + g_free (name); + + new_buttons = g_list_prepend (new_buttons, button_data); + + if (BUTTON_IS_FAKE_ROOT (button_data)) { + fake_root = new_buttons; + } + + path = parent_path; + first_directory = FALSE; + } + + nautilus_path_bar_clear_buttons (path_bar); + path_bar->button_list = g_list_reverse (new_buttons); + path_bar->fake_root = fake_root; + + for (l = path_bar->button_list; l; l = l->next) { + GtkWidget *button; + button = BUTTON_DATA (l->data)->button; + gtk_container_add (GTK_CONTAINER (path_bar), button); + } + + gtk_widget_pop_composite_child (); + + return result; +} + +gboolean +nautilus_path_bar_set_path (NautilusPathBar *path_bar, const char *file_path) +{ + g_return_val_if_fail (NAUTILUS_IS_PATH_BAR (path_bar), FALSE); + g_return_val_if_fail (file_path != NULL, FALSE); + + /* Check whether the new path is already present in the pathbar as buttons. + * This could be a parent directory or a previous selected subdirectory. */ + if (nautilus_path_bar_check_parent_path (path_bar, file_path)) { + return TRUE; + } + + return nautilus_path_bar_update_path (path_bar, file_path); +} + + + +/** + * _nautilus_path_bar_up: + * @path_bar: a #NautilusPathBar + * + * If the selected button in the pathbar is not the furthest button "up" (in the + * root direction), act as if the user clicked on the next button up. + **/ +void +nautilus_path_bar_up (NautilusPathBar *path_bar) +{ + GList *l; + + for (l = path_bar->button_list; l; l = l->next) { + GtkWidget *button = BUTTON_DATA (l->data)->button; + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) { + if (l->next) { + GtkWidget *next_button = BUTTON_DATA (l->next->data)->button; + button_clicked_cb (next_button, l->next->data); + } + break; + } + } +} + +/** + * _nautilus_path_bar_down: + * @path_bar: a #NautilusPathBar + * + * If the selected button in the pathbar is not the furthest button "down" (in the + * leaf direction), act as if the user clicked on the next button down. + **/ +void +nautilus_path_bar_down (NautilusPathBar *path_bar) +{ + GList *l; + + for (l = path_bar->button_list; l; l = l->next) { + GtkWidget *button = BUTTON_DATA (l->data)->button; + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) { + if (l->prev) { + GtkWidget *prev_button = BUTTON_DATA (l->prev->data)->button; + button_clicked_cb (prev_button, l->prev->data); + } + break; + } + } +} diff --git a/src/nautilus-pathbar.h b/src/nautilus-pathbar.h new file mode 100644 index 000000000..5da857e00 --- /dev/null +++ b/src/nautilus-pathbar.h @@ -0,0 +1,80 @@ +/* nautilus-pathbar.h + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * + */ + +#ifndef NAUTILUS_PATHBAR_H +#define NAUTILUS_PATHBAR_H + +#include <gtk/gtkcontainer.h> + +typedef struct _NautilusPathBar NautilusPathBar; +typedef struct _NautilusPathBarClass NautilusPathBarClass; + + +#define NAUTILUS_TYPE_PATH_BAR (nautilus_path_bar_get_type ()) +#define NAUTILUS_PATH_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_PATH_BAR, NautilusPathBar)) +#define NAUTILUS_PATH_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_PATH_BAR, NautilusPathBarClass)) +#define NAUTILUS_IS_PATH_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_PATH_BAR)) +#define NAUTILUS_IS_PATH_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_PATH_BAR)) +#define NAUTILUS_PATH_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NAUTILUS_TYPE_PATH_BAR, NautilusPathBarClass)) + +struct _NautilusPathBar +{ + GtkContainer parent; + + char *root_path; + char *home_path; + char *desktop_path; + + GdkPixbuf *root_icon; + GdkPixbuf *home_icon; + GdkPixbuf *desktop_icon; + + GList *button_list; + GList *first_scrolled_button; + GList *fake_root; + GtkWidget *up_slider_button; + GtkWidget *down_slider_button; + guint settings_signal_id; + gint icon_size; + gint16 slider_width; + gint16 spacing; + gint16 button_offset; + guint timer; + guint slider_visible : 1; + guint need_timer : 1; + guint ignore_click : 1; +}; + +struct _NautilusPathBarClass +{ + GtkContainerClass parent_class; + + void (* path_clicked) (NautilusPathBar *path_bar, + const char *file_path); +}; + +GType nautilus_path_bar_get_type (void) G_GNUC_CONST; + +gboolean nautilus_path_bar_set_path (NautilusPathBar *path_bar, const char *file_path); + +void nautilus_path_bar_up (NautilusPathBar *path_bar); +void nautilus_path_bar_down (NautilusPathBar *path_bar); + +#endif /* NAUTILUS_PATHBAR_H */ diff --git a/src/nautilus-window-manage-views.c b/src/nautilus-window-manage-views.c index e4a4443cd..47cb563f9 100644 --- a/src/nautilus-window-manage-views.c +++ b/src/nautilus-window-manage-views.c @@ -31,6 +31,7 @@ #include "nautilus-actions.h" #include "nautilus-application.h" #include "nautilus-location-bar.h" +#include "nautilus-pathbar.h" #include "nautilus-main.h" #include "nautilus-window-private.h" #include "nautilus-zoom-control.h" @@ -347,10 +348,12 @@ viewed_file_changed_callback (NautilusFile *file, update_up_button (window); #if !NEW_UI_COMPLETE if (NAUTILUS_IS_NAVIGATION_WINDOW (window)) { - /* Change the location bar to match the current location. */ + /* Change the location bar and path bar to match the current location. */ nautilus_navigation_bar_set_location (NAUTILUS_NAVIGATION_BAR (NAUTILUS_NAVIGATION_WINDOW (window)->navigation_bar), window->details->location); + nautilus_path_bar_set_path (NAUTILUS_PATH_BAR (NAUTILUS_NAVIGATION_WINDOW (window)->path_bar), + window->details->location); } if (NAUTILUS_IS_SPATIAL_WINDOW (window)) { /* Change the location button to match the current location. */ @@ -1171,10 +1174,11 @@ update_for_new_location (NautilusWindow *window) nautilus_navigation_window_allow_back (NAUTILUS_NAVIGATION_WINDOW (window), NAUTILUS_NAVIGATION_WINDOW (window)->back_list != NULL); nautilus_navigation_window_allow_forward (NAUTILUS_NAVIGATION_WINDOW (window), NAUTILUS_NAVIGATION_WINDOW (window)->forward_list != NULL); - /* Change the location bar to match the current location. */ + /* Change the location bar and path bar to match the current location. */ nautilus_navigation_bar_set_location (NAUTILUS_NAVIGATION_BAR (NAUTILUS_NAVIGATION_WINDOW (window)->navigation_bar), window->details->location); - + nautilus_path_bar_set_path (NAUTILUS_PATH_BAR (NAUTILUS_NAVIGATION_WINDOW (window)->path_bar), + window->details->location); nautilus_navigation_window_load_extension_toolbar_items (NAUTILUS_NAVIGATION_WINDOW (window)); } diff --git a/src/nautilus-window-private.h b/src/nautilus-window-private.h index ccfde8906..7673e848f 100644 --- a/src/nautilus-window-private.h +++ b/src/nautilus-window-private.h @@ -101,6 +101,7 @@ struct _NautilusNavigationWindowDetails { /* Location bar */ gboolean temporary_navigation_bar; + gboolean temporary_location_bar; /* Side Pane */ int side_pane_width; |