Re: [PATCH] Add Pathbar to Nautilus Browser



Alexander Larsson wrote:

First a bit on the general UI. I don't want to have the pathbar in
addition to the location bar, I want it to replace the location bar. For
a long time a major goal of nautilus has been to avoid displaying
pathnames (as in absolute pathnames or uris) in the UI. Going from
location bar will help with this. It will also help us look less like a
web browser, which is nice, as that can confuse people at times.

Of course, we can't totally remove the location bar, as its needed for
typing in addresses, and some people still might want it. What we'll do
is put the path bar and the location bar in the same place, but only
show one at a time. Normally we show the pathbar, but on "go ->
Location" in the menu (or ctrl+l) we temporarily show the location bar,
similarly to how this is handled when the location bar is not visible.


okay done.


Lets also add a preference (hidden for the moment) to allow people to
always have the location bar instead of the pathbar.

done.


Comments about the code:

strings are not translated

done


It doesn't handle the desktop-is-home preference

done (might need to open new window to get full effect)


file_path_exists does synchronous i/o, which is a no-no in nautilus. Why
do you have to check for the file existance here?


removed

The root icon for non file:/// uris is always a folder (I think). It
should use the real icon that nautilus uses for it, i.e. gotten from
nautilus_icon_factory_get_icon_for_file(). See for instance the location
menu in spatial mode that uses this and what icon it uses for
"computer:///".

done


We should really re-root for all volumes too, not only the homedir. This
means you won't see /mnt/media/cdrom, but only
  [{cdicon} cdrom name][folder1][folder2]
Maybe we can wait a bit with implementing this so that we can get
something in first, but this would be really nice.


done. Also no arrows to the left as its display name is the volume name.


The gtk+ pathbar code you used isn't the latest version. Gtk+ HEAD has a
different behaviour, primary wrt rerooting. It:
* only re-roots to the desktop
* allows you to scroll left when things are re-rooted
We should update the code to this version.

Done. Found a bug in size_allocate which prevented it from applying the scroll arrows when you resize properly. (added on line 425 of nautilus_pathbar.c).


Why did you add folder icons to normal folders? That seems to use a lot
of space for something that isn't really needed.

removed.

Patch attached for above - hope its acceptable as we are on the brink of feature freeze.

jamie.

--
Mr Jamie McCracken
http://www.advogato.org/person/jamiemcc/
/* nautllus-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)

/* checks if button represents a mounted volume. 
 * unlike fake root above, hidden buttons are not shown or 
 * accessible via the "<" arrow button. 
 * The button label is aliased to the volume display name
 */
#define BUTTON_IS_VOLUME_ROOT(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 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
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 = gnome_vfs_get_uri_from_local_path (nautilus_get_desktop_directory ());
	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);
	
}

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 = gnome_vfs_get_uri_from_local_path (nautilus_get_desktop_directory ());
	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);
	}
	if (path_bar->home_path) {
		g_free (path_bar->home_path);
	}
	if (path_bar->desktop_path) {
		g_free (path_bar->desktop_path);
	}

	if (path_bar->root_icon) {
		g_object_unref (path_bar->root_icon);
	}
	if (path_bar->home_icon) {
                g_object_unref (path_bar->home_icon);
	}
	if (path_bar->desktop_icon) {
		g_object_unref (path_bar->desktop_icon);
	}

        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 (!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);
			break;
		}
		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;
}


gboolean
nautilus_path_bar_set_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;

        /* 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;
	}

        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);

		/* mounted volumes must be a fixed root as they are aliased namewise */
		if (BUTTON_IS_VOLUME_ROOT (button_data)) {
			if (parent_path) {
				g_free (parent_path);
			}
			break;
		}


		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;
}


/**
 * _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;
		}
        }
}
/* 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.
 *
 * 
 */


#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);


Index: src/nautilus-navigation-window.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-navigation-window.c,v
retrieving revision 1.432
diff -u -r1.432 nautilus-navigation-window.c
--- src/nautilus-navigation-window.c	28 Jun 2005 12:54:45 -0000	1.432
+++ src/nautilus-navigation-window.c	7 Jul 2005 18:45:19 -0000
@@ -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,7 +112,9 @@
 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);
 
 GNOME_CLASS_BOILERPLATE (NautilusNavigationWindow, nautilus_navigation_window,
 			 NautilusWindow, NAUTILUS_TYPE_WINDOW)
@@ -123,26 +127,49 @@
 	GtkWidget *location_bar;
 	GtkWidget *view_as_menu_vbox;
 	GtkToolItem *item;
-	
+
 	window->details = g_new0 (NautilusNavigationWindowDetails, 1);
 
 	window->details->tooltips = gtk_tooltips_new ();
-	g_object_ref (G_OBJECT (window->details->tooltips));
+	g_object_ref (G_OBJECT (window->details->tooltips)); 
 	gtk_object_sink (GTK_OBJECT (window->details->tooltips));
 	
 	window->details->content_paned = nautilus_horizontal_splitter_new ();
-	gtk_table_attach (GTK_TABLE (NAUTILUS_WINDOW (window)->details->table),
-			  window->details->content_paned,
-			  /* X direction */       /* Y direction */
-			  0, 1,                   3, 4,
-			  GTK_EXPAND | GTK_FILL,  GTK_EXPAND | GTK_FILL,
-			  0,                      0);
+	window->details->content_table = gtk_vbox_new (FALSE,0);
+
+	gtk_widget_show (window->details->content_table);
 	gtk_widget_show (window->details->content_paned);
 
+	nautilus_horizontal_splitter_pack2 (
+		NAUTILUS_HORIZONTAL_SPLITTER (window->details->content_paned),
+		window->details->content_table);
+
+	window->details->pathbar_tool_bar = gtk_toolbar_new ();
+	gtk_widget_show (GTK_WIDGET (window->details->pathbar_tool_bar));
+
+	gtk_box_pack_start (GTK_BOX (window->details->content_table),window->details->pathbar_tool_bar, FALSE, TRUE,0);  
+
+	item = gtk_tool_item_new ();
+	gtk_container_set_border_width (GTK_CONTAINER (item),1);
+	gtk_widget_show (GTK_WIDGET (item));
+	gtk_tool_item_set_expand (item, TRUE);
+	
+	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_container_add (GTK_CONTAINER (item), window->path_bar );
+
+	gtk_toolbar_insert (GTK_TOOLBAR (window->details->pathbar_tool_bar),
+			    item, -1);
+
 	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;
 	gtk_table_attach (GTK_TABLE (NAUTILUS_WINDOW (window)->details->table),
@@ -223,17 +250,27 @@
 
 	gtk_widget_show (location_bar);
 
+	gtk_box_pack_start (GTK_BOX (window->details->content_table),location_bar, FALSE, TRUE,0); 
+
 	gtk_table_attach (GTK_TABLE (NAUTILUS_WINDOW (window)->details->table),
-			  location_bar,
+			  window->details->content_paned,
 			  /* X direction */       /* Y direction */
-			  0, 1,                   2, 3,
-			  GTK_EXPAND | GTK_FILL,  0,
+			  0, 1,                   3, 4,
+			  GTK_EXPAND | GTK_FILL,  GTK_EXPAND | GTK_FILL,
 			  0,                      0);
-	
-	
 }
 
 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,
 					  NautilusNavigationWindow *window)
@@ -245,6 +282,9 @@
 			nautilus_navigation_window_hide_location_bar (window, FALSE);
 		}
 		window->details->temporary_navigation_bar = FALSE;
+		if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_START_WITH_LOCATION_BAR)) {
+			nautilus_navigation_window_show_path_bar (window, FALSE);
+		}
 	}
 
 	nautilus_window_go_to (NAUTILUS_WINDOW (window), uri);
@@ -418,10 +458,12 @@
 
 	window->view_as_option_menu = NULL;
 	window->navigation_bar = NULL;
+	window->path_bar = NULL;
 	window->zoom_control = NULL;
 
 	window->details->content_paned = NULL;
-
+	window->details->pathbar_tool_bar = NULL;
+	
 	if (window->details->tooltips) {
 		g_object_unref (G_OBJECT (window->details->tooltips));
 		window->details->tooltips = NULL;
@@ -733,10 +775,11 @@
 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, 
@@ -750,9 +793,7 @@
 
 	connect_view (window, new_view);
 
-	nautilus_horizontal_splitter_pack2 (
-		NAUTILUS_HORIZONTAL_SPLITTER (window->details->content_paned),
-		GTK_WIDGET (new_view));
+	gtk_box_pack_end (GTK_BOX (window->details->content_table),GTK_WIDGET (new_view), TRUE, TRUE,0); 
 
 	if (new_view != NULL && nautilus_view_supports_zooming (new_view)) {
 		gtk_widget_show (window->zoom_control);
@@ -783,6 +824,9 @@
 {
 	if (!nautilus_navigation_window_location_bar_showing (window)) {
 		nautilus_navigation_window_show_location_bar (window, FALSE);
+		if (nautilus_navigation_window_path_bar_showing (window)) {		
+			nautilus_navigation_window_hide_path_bar (window, FALSE);
+		}
 		window->details->temporary_navigation_bar = TRUE;
 	}
 	nautilus_navigation_bar_activate 
@@ -873,6 +917,9 @@
 {
 	window->details->temporary_navigation_bar = FALSE;
 	gtk_widget_hide (window->details->location_bar);
+	if (!eel_preferences_get_boolean (NAUTILUS_PREFERENCES_ALWAYS_USE_LOCATION_ENTRY)) {
+		return;
+	}
 	nautilus_navigation_window_update_show_hide_menu_items (window);
 	if (save_preference &&
 	    eel_preferences_key_is_writable (NAUTILUS_PREFERENCES_START_WITH_LOCATION_BAR)) {
@@ -884,6 +931,9 @@
 nautilus_navigation_window_show_location_bar (NautilusNavigationWindow *window, gboolean save_preference)
 {
 	gtk_widget_show (window->details->location_bar);
+	if (!eel_preferences_get_boolean (NAUTILUS_PREFERENCES_ALWAYS_USE_LOCATION_ENTRY)) {
+		return;
+	}
 	nautilus_navigation_window_update_show_hide_menu_items (window);
 	if (save_preference &&
 	    eel_preferences_key_is_writable (NAUTILUS_PREFERENCES_START_WITH_LOCATION_BAR)) {
@@ -891,6 +941,43 @@
 	}
 }
 
+void 
+nautilus_navigation_window_hide_path_bar (NautilusNavigationWindow *window, gboolean save_preference)
+{
+
+	gtk_widget_hide (window->details->pathbar_tool_bar);
+	if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_ALWAYS_USE_LOCATION_ENTRY)) {
+		return;
+	}
+	nautilus_navigation_window_update_show_hide_menu_items (window);
+	if (save_preference && eel_preferences_key_is_writable (NAUTILUS_PREFERENCES_START_WITH_LOCATION_BAR)) {
+		eel_preferences_set_boolean (NAUTILUS_PREFERENCES_START_WITH_LOCATION_BAR, FALSE);
+	}
+}
+
+void 
+nautilus_navigation_window_show_path_bar (NautilusNavigationWindow *window, gboolean save_preference)
+{
+	gtk_widget_show (window->details->pathbar_tool_bar);
+	if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_ALWAYS_USE_LOCATION_ENTRY)) {
+		return;
+	}
+	nautilus_navigation_window_update_show_hide_menu_items (window);
+	if (save_preference && eel_preferences_key_is_writable (NAUTILUS_PREFERENCES_START_WITH_LOCATION_BAR)) {
+		eel_preferences_set_boolean (NAUTILUS_PREFERENCES_START_WITH_LOCATION_BAR, TRUE);
+	}
+}
+
+gboolean
+nautilus_navigation_window_path_bar_showing (NautilusNavigationWindow *window)
+{
+	if (window->details->pathbar_tool_bar != NULL) {
+		return GTK_WIDGET_VISIBLE (window->details->pathbar_tool_bar);
+	}
+	/* If we're not visible yet we haven't changed visibility, so its TRUE */
+	return TRUE;
+}
+
 gboolean
 nautilus_navigation_window_location_bar_showing (NautilusNavigationWindow *window)
 {
@@ -901,6 +988,47 @@
 	return TRUE;
 }
 
+void 
+nautilus_navigation_window_hide_location_tool_bars (NautilusNavigationWindow *window, gboolean save_preference)
+{
+ 	if (nautilus_navigation_window_path_bar_showing) {
+		nautilus_navigation_window_hide_path_bar (window, TRUE);
+	}
+	if (nautilus_navigation_window_location_bar_showing) {
+		nautilus_navigation_window_hide_location_bar (window, FALSE);
+	}
+}
+
+void 
+nautilus_navigation_window_show_location_tool_bars (NautilusNavigationWindow *window, gboolean save_preference)
+{
+	if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_ALWAYS_USE_LOCATION_ENTRY)) {
+		nautilus_navigation_window_show_location_bar (window, save_preference);	
+		if (nautilus_navigation_window_path_bar_showing) {
+			nautilus_navigation_window_hide_path_bar (window, FALSE);
+		}
+	} else {
+		nautilus_navigation_window_show_path_bar (window, save_preference);
+		if (nautilus_navigation_window_location_bar_showing) {
+			nautilus_navigation_window_hide_location_bar (window, FALSE);
+		}
+	}
+}
+
+/* returns true if either location/path bar is showing */
+gboolean
+nautilus_navigation_window_location_tool_bars_showing (NautilusNavigationWindow *window)
+{
+	gboolean result;
+	
+	result = nautilus_navigation_window_path_bar_showing (window);
+	if (!result) {
+		return nautilus_navigation_window_location_bar_showing (window);
+	}
+	return result;
+}
+
+
 gboolean
 nautilus_navigation_window_toolbar_showing (NautilusNavigationWindow *window)
 {
@@ -1012,6 +1140,8 @@
 	return forward_count;
 }
 
+
+
 /**
  * nautilus_navigation_window_show:
  * @widget:	GtkWidget
@@ -1029,10 +1159,28 @@
 	/* Initially show or hide views based on preferences; once the window is displayed
 	 * these can be controlled on a per-window basis from View menu items. 
 	 */
+
+	/* toggle location bar entry and pathbar toolbars so they are mutually exclusive */
 	if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_START_WITH_LOCATION_BAR)) {
-		nautilus_navigation_window_show_location_bar (window, FALSE);
+		if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_ALWAYS_USE_LOCATION_ENTRY)) {
+			nautilus_navigation_window_show_location_bar (window, FALSE);
+			if (nautilus_navigation_window_path_bar_showing (window)) {
+				nautilus_navigation_window_hide_path_bar (window, FALSE);
+			}
+		} else {
+			if (nautilus_navigation_window_location_bar_showing (window)) {
+				nautilus_navigation_window_hide_location_bar (window, FALSE);
+			}
+			nautilus_navigation_window_show_path_bar (window, FALSE);
+		}
 	} else {
-		nautilus_navigation_window_hide_location_bar (window, FALSE);
+		
+		if (nautilus_navigation_window_location_bar_showing (window)) {
+			nautilus_navigation_window_hide_location_bar (window, FALSE);
+		}
+		if (nautilus_navigation_window_path_bar_showing (window)) {
+			nautilus_navigation_window_hide_path_bar (window, FALSE);
+		}
 	}
 
 	if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_START_WITH_SIDEBAR)) {
Index: src/nautilus-navigation-window.h
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-navigation-window.h,v
retrieving revision 1.111
diff -u -r1.111 nautilus-navigation-window.h
--- src/nautilus-navigation-window.h	23 Jun 2005 14:16:58 -0000	1.111
+++ src/nautilus-navigation-window.h	7 Jul 2005 18:45:19 -0000
@@ -47,7 +47,7 @@
 
 typedef struct _NautilusNavigationWindow        NautilusNavigationWindow;
 typedef struct _NautilusNavigationWindowClass   NautilusNavigationWindowClass;
-typedef struct _NautilusNavigationWindowDetails NautilusNavigationWindowDetails;
+typedef struct _NautilusNavigationWindowDetails NautilusNavigationWindowDetails; 
 
 struct _NautilusNavigationWindow {
         NautilusWindow parent_object;
@@ -58,7 +58,9 @@
         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,19 @@
                                                           gboolean                  save_preference);
 void     nautilus_navigation_window_show_location_bar    (NautilusNavigationWindow *window,
                                                           gboolean                  save_preference);
+
+void     nautilus_navigation_window_hide_path_bar        (NautilusNavigationWindow *window,
+                                                          gboolean                  save_preference);
+void     nautilus_navigation_window_show_path_bar        (NautilusNavigationWindow *window,
+                                                          gboolean                  save_preference);
+gboolean nautilus_navigation_window_path_bar_showing 	 (NautilusNavigationWindow *window);
+
+void     nautilus_navigation_window_show_location_tool_bars    (NautilusNavigationWindow *window,
+								gboolean save_preference);
+void     nautilus_navigation_window_hide_location_tool_bars    (NautilusNavigationWindow *window,
+							        gboolean save_preference);
+gboolean nautilus_navigation_window_location_tool_bars_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);
Index: src/nautilus-window-private.h
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-window-private.h,v
retrieving revision 1.108
diff -u -r1.108 nautilus-window-private.h
--- src/nautilus-window-private.h	23 Jun 2005 14:16:59 -0000	1.108
+++ src/nautilus-window-private.h	7 Jul 2005 18:45:20 -0000
@@ -97,6 +97,7 @@
 
 struct _NautilusNavigationWindowDetails {
         GtkWidget *content_paned;
+        GtkWidget *content_table;
         GtkActionGroup *navigation_action_group; /* owned by ui_manager */
         
         /* Location bar */
@@ -115,6 +116,7 @@
         GtkWidget *toolbar;
         GtkTooltips *tooltips;
         GtkWidget *location_bar;
+	GtkWidget *pathbar_tool_bar;
 
         guint extensions_toolbar_merge_id;
         GtkActionGroup *extensions_toolbar_action_group;
Index: src/nautilus-window-manage-views.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-window-manage-views.c,v
retrieving revision 1.352
diff -u -r1.352 nautilus-window-manage-views.c
--- src/nautilus-window-manage-views.c	4 Jun 2005 16:23:15 -0000	1.352
+++ src/nautilus-window-manage-views.c	7 Jul 2005 18:45:24 -0000
@@ -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 @@
                         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 andpath 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 @@
                 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));
         }
         
Index: src/nautilus-navigation-window-menus.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-navigation-window-menus.c,v
retrieving revision 1.278
diff -u -r1.278 nautilus-navigation-window-menus.c
--- src/nautilus-navigation-window-menus.c	23 Jun 2005 14:16:58 -0000	1.278
+++ src/nautilus-navigation-window-menus.c	7 Jul 2005 18:45:25 -0000
@@ -167,9 +167,9 @@
 	window = NAUTILUS_NAVIGATION_WINDOW (user_data);
 
 	if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
-		nautilus_navigation_window_show_location_bar (window, TRUE);
+		nautilus_navigation_window_show_location_tool_bars (window, TRUE);
 	} else {
-		nautilus_navigation_window_hide_location_bar (window, TRUE);
+		nautilus_navigation_window_hide_location_tool_bars (window, TRUE);
 	}
 }
 
@@ -201,14 +201,15 @@
 				      nautilus_navigation_window_sidebar_showing (window));
 	
 	action = gtk_action_group_get_action (window->details->navigation_action_group,
-					      NAUTILUS_ACTION_SHOW_HIDE_LOCATION_BAR);
+					      NAUTILUS_ACTION_SHOW_HIDE_STATUSBAR);
 	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
-				      nautilus_navigation_window_location_bar_showing (window));
+				      nautilus_navigation_window_status_bar_showing (window));
 
 	action = gtk_action_group_get_action (window->details->navigation_action_group,
-					      NAUTILUS_ACTION_SHOW_HIDE_STATUSBAR);
+					      NAUTILUS_ACTION_SHOW_HIDE_LOCATION_BAR);
 	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
-				      nautilus_navigation_window_status_bar_showing (window));
+				      nautilus_navigation_window_location_tool_bars_showing (window));
+
 }
 
 static void
@@ -423,12 +424,12 @@
     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 
Index: src/Makefile.am
===================================================================
RCS file: /cvs/gnome/nautilus/src/Makefile.am,v
retrieving revision 1.161
diff -u -r1.161 Makefile.am
--- src/Makefile.am	1 Jul 2005 14:13:49 -0000	1.161
+++ src/Makefile.am	7 Jul 2005 18:45:26 -0000
@@ -93,6 +93,8 @@
 	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     	\
Index: libnautilus-private/nautilus-global-preferences.h
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-global-preferences.h,v
retrieving revision 1.128
diff -u -r1.128 nautilus-global-preferences.h
--- libnautilus-private/nautilus-global-preferences.h	22 Nov 2004 15:24:36 -0000	1.128
+++ libnautilus-private/nautilus-global-preferences.h	7 Jul 2005 18:45:26 -0000
@@ -82,6 +82,7 @@
 
 /* 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"
Index: libnautilus-private/nautilus-global-preferences.c
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-global-preferences.c,v
retrieving revision 1.221
diff -u -r1.221 nautilus-global-preferences.c
--- libnautilus-private/nautilus-global-preferences.c	22 Nov 2004 15:24:36 -0000	1.221
+++ libnautilus-private/nautilus-global-preferences.c	7 Jul 2005 18:45:28 -0000
@@ -394,6 +394,10 @@
 	  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)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]