[PATCH] Add Pathbar to Nautilus Browser



Having integrated the GtkFileChooser places into Nautilus, I have now done a patch to add the pathbar too. Screenshots can be found on my blog (see link in footer)

I have left the location bar as is (its handy for those that wanna CTRL+L occasionally or those that want a persistent type in interface). The new pathbar, unlike the other toolbars, is to the right of the sidebar so as to make it much neater and more consistent with the file chooser whilst keeping the window more compact. It can also be toggled with Ctrl+P.

I have used a modfied version of the GTK pathbar and have done the bare minimum to it to get it to work in Nautilus. The following changes have been implemented:

1) All gtk private stuff is removed
2) Replaced GtkFilePath with char *
3) Replaced GtkFileSystem and related functions with equivalent Gnome-VFS ones
4) Added folder icon to ordinary button folders
5) Namespaced it all.
6) Made the code consistent with Nauitlus' coding standards

Other than that it is identical to the file chooser's.

(note I haven't tested on HEAD because its not available on anon CVS - latest on there is 23rd June. I expect the Makefile to fail on patching on HEAD so simply add nautilus-pathbar.c and .h to it manually)

jamie.

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

	GList *button_list;
	GList *first_scrolled_button;
	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);


/* 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 <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 <libgnomevfs/gnome-vfs-utils.h>
#include <libnautilus-private/nautilus-icon-factory.h>
#include <libnautilus-private/nautilus-file-utilities.h>
#include "nautilus-pathbar.h"

enum {
        PATH_CLICKED,
        LAST_SIGNAL
};

typedef enum {
        NORMAL_BUTTON,
        ROOT_BUTTON,
        HOME_BUTTON,
        DESKTOP_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 };

/* Icon size for if we can't get it from the theme */
#define FALLBACK_ICON_SIZE 20
#define NAUTILUS_PATH_BAR_ICON_SIZE 18

typedef struct _ButtonData ButtonData;

struct _ButtonData
{
        GtkWidget *button;
        ButtonType type;
        char *dir_name;
        char *path;
        GtkWidget *image;
        GtkWidget *label;
        guint ignore_changes : 1;
        guint file_is_hidden : 1;
};

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_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 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
nautilus_path_bar_init (NautilusPathBar *path_bar)
{
	const char *home;
	char *desktop;

        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 = FALLBACK_ICON_SIZE;
	
	home = gnome_vfs_get_uri_from_local_path (g_get_home_dir ());
 	desktop = g_build_filename (home, "Desktop", NULL);
        path_bar->desktop_path = desktop;
	path_bar->home_path = g_strdup (home);
	path_bar->root_path = g_strdup ("file:///");

        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->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);
        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);
	}
	if (path_bar->normal_icon) {
		g_object_unref (path_bar->normal_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);
		}
	}
}

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

        widget->allocation = *allocation;
	need_sliders = FALSE;
	up_slider_offset = 0;
	down_slider_offset = 0;
	path_bar = NAUTILUS_PATH_BAR (widget);

        /* 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. */
        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 (width <= allocation_width) {
                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 {
	    			width += child->requisition.width + path_bar->spacing;
			}

	  		list = list->prev;
		}

                /* Finally, we walk up, seeing how many of the previous buttons we can */

                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;
	      			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) {
	  		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) {
	  		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) {
                child_allocation.width = path_bar->slider_width;
                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);

                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->up_slider_button, TRUE);
                gtk_widget_set_child_visible (path_bar->down_slider_button, TRUE);
                gtk_widget_show_all (path_bar->up_slider_button);
                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->up_slider_button, FALSE);
                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;
		}
                if (widget == BUTTON_DATA (children->data)->button) {
                        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)) {
			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;
        }
        if (path_bar->normal_icon) {
                g_object_unref (path_bar->normal_icon);
                path_bar->normal_icon = NULL;
        }

        for (list = path_bar->button_list; list; list = list->next) {
                ButtonData *button_data;
                gboolean current_dir;

                button_data = BUTTON_DATA (list->data);
                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)
{
        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;
}

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 GdkPixbuf *
get_button_image (NautilusPathBar *path_bar,
		  ButtonType  button_type)
{


	switch (button_type)
        {
		case ROOT_BUTTON:
			if (path_bar->root_icon != NULL) {
				return path_bar->root_icon;
                       	}
		        path_bar->root_icon = nautilus_icon_factory_get_pixbuf_from_name ("gnome-fs-blockdev",
											  NULL, NAUTILUS_PATH_BAR_ICON_SIZE,
											  TRUE, NULL);
			return path_bar->root_icon;

		case HOME_BUTTON:
		      	if (path_bar->home_icon != NULL) {
		      		return path_bar->home_icon;
			}

		        path_bar->home_icon = nautilus_icon_factory_get_pixbuf_from_name ("gnome-fs-home",
											  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;
			}
		      	path_bar->desktop_icon = nautilus_icon_factory_get_pixbuf_from_name ("gnome-fs-desktop",
											     NULL, NAUTILUS_PATH_BAR_ICON_SIZE,
											     TRUE, NULL);
      			return path_bar->desktop_icon;

	    	default:
                        if (path_bar->normal_icon != NULL) {
				return path_bar->normal_icon;
			}
		      	path_bar->normal_icon = nautilus_icon_factory_get_pixbuf_from_name ("gnome-fs-directory",
											    NULL, NAUTILUS_PATH_BAR_ICON_SIZE,
											    TRUE, NULL);
                        return path_bar->normal_icon;
        }
  
       	return NULL;
}

static void
button_data_free (ButtonData *button_data)
{
        g_free (button_data->path);
        g_free (button_data->dir_name);
        g_free (button_data);
}

static const char *
get_dir_name (ButtonData *button_data)
{
        if (button_data->type == HOME_BUTTON) {
                return "Home";
	} 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 = gtk_widget_create_pango_layout (button_data->label, dir_name);
        gint bold_width, bold_height;
        gchar *markup;

        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) {
                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 ButtonType
find_button_type (NautilusPathBar  *path_bar,
		  char *path)
{
        if (path_bar->root_path != NULL && ! strcmp (path, path_bar->root_path)) {
                return ROOT_BUTTON;
	}
        if (path_bar->home_path != NULL && ! strcmp (path, path_bar->home_path)) {
                return HOME_BUTTON;
	}
        if (path_bar->desktop_path != NULL && ! strcmp (path, path_bar->desktop_path)) {
                return DESKTOP_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,
		       char *path,
		       gboolean     current_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 = 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 NORMAL_BUTTON:
                default:
                        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;
        }

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

        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;

	current_path = NULL;

        for (list = path_bar->button_list; list; list = list->next) {
                ButtonData *button_data;

                button_data = list->data;
                if (! strcmp (file_path, button_data->path)) {
			current_path = list;
		  	break;
		}
        }

        if (current_path) {
                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;
        gboolean result;
        GList *new_buttons, *l;
        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;
        result = TRUE;
	first_directory = TRUE;
	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);		
                button_data = make_directory_button (path_bar, name, path, first_directory, FALSE);
                g_free (path);
		g_free (name);
                g_object_ref (button_data->button);
                gtk_object_sink (GTK_OBJECT (button_data->button));

                new_buttons = g_list_prepend (new_buttons, button_data);

                if (button_data->type != NORMAL_BUTTON) {
	  		g_free (parent_path);
	  		break;
		}

                path = parent_path;
                first_directory = FALSE;
        }

        nautilus_path_bar_clear_buttons (path_bar);
        path_bar->button_list = g_list_reverse (new_buttons);

        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;
		}
        }
}
Index: src/nautilus-navigation-window.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-navigation-window.c,v
retrieving revision 1.431
diff -u -r1.431 nautilus-navigation-window.c
--- src/nautilus-navigation-window.c	23 Jun 2005 14:16:58 -0000	1.431
+++ src/nautilus-navigation-window.c	4 Jul 2005 18:18:32 -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,50 @@
 	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),
@@ -229,11 +257,26 @@
 			  0, 1,                   2, 3,
 			  GTK_EXPAND | GTK_FILL,  0,
 			  0,                      0);
-	
-	
+
+	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);
 }
 
 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)
@@ -418,10 +461,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;
@@ -729,10 +774,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, 
@@ -746,9 +792,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);
@@ -887,6 +931,37 @@
 	}
 }
 
+void 
+nautilus_navigation_window_hide_path_bar (NautilusNavigationWindow *window)
+{
+
+	gtk_widget_hide (window->details->pathbar_tool_bar);
+	nautilus_navigation_window_update_show_hide_menu_items (window);
+	if (eel_preferences_key_is_writable (NAUTILUS_PREFERENCES_START_WITH_PATH_BAR)) {
+		eel_preferences_set_boolean (NAUTILUS_PREFERENCES_START_WITH_PATH_BAR, FALSE);
+	}
+}
+
+void 
+nautilus_navigation_window_show_path_bar (NautilusNavigationWindow *window)
+{
+	gtk_widget_show (window->details->pathbar_tool_bar);
+	nautilus_navigation_window_update_show_hide_menu_items (window);
+	if (eel_preferences_key_is_writable (NAUTILUS_PREFERENCES_START_WITH_PATH_BAR)) {
+		eel_preferences_set_boolean (NAUTILUS_PREFERENCES_START_WITH_PATH_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)
 {
@@ -1031,6 +1106,12 @@
 		nautilus_navigation_window_hide_location_bar (window, FALSE);
 	}
 
+	if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_START_WITH_PATH_BAR)) {
+		nautilus_navigation_window_show_path_bar (window);
+	} else {
+		nautilus_navigation_window_hide_path_bar (window);
+	}
+
 	if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_START_WITH_SIDEBAR)) {
 		nautilus_navigation_window_show_sidebar (window);
 	} else {
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	4 Jul 2005 18:18:32 -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,11 @@
                                                           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);
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	4 Jul 2005 18:18:33 -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	4 Jul 2005 18:18:37 -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	4 Jul 2005 18:18:38 -0000
@@ -174,6 +174,22 @@
 }
 
 static void
+action_show_hide_path_bar_callback (GtkAction *action, 
+				    gpointer user_data)
+{
+	NautilusNavigationWindow *window;
+
+	window = NAUTILUS_NAVIGATION_WINDOW (user_data);
+
+	if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
+		nautilus_navigation_window_show_path_bar (window);
+	} else {
+		nautilus_navigation_window_hide_path_bar (window);
+	}
+}
+
+
+static void
 action_show_hide_statusbar_callback (GtkAction *action,
 				     gpointer user_data)
 {
@@ -206,6 +222,11 @@
 				      nautilus_navigation_window_location_bar_showing (window));
 
 	action = gtk_action_group_get_action (window->details->navigation_action_group,
+					      NAUTILUS_ACTION_SHOW_HIDE_PATH_BAR);
+	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
+				      nautilus_navigation_window_path_bar_showing (window));
+
+	action = gtk_action_group_get_action (window->details->navigation_action_group,
 					      NAUTILUS_ACTION_SHOW_HIDE_STATUSBAR);
 	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
 				      nautilus_navigation_window_status_bar_showing (window));
@@ -424,6 +445,11 @@
     N_("Change the visibility of this window's location bar"),                    /* tooltip */
     G_CALLBACK (action_show_hide_location_bar_callback),
     TRUE  },                                    /* is_active */
+  { "Show Hide Pathbar", NULL,                 /* name, stock id */
+    N_("_Pathbar"), "<control>P",               /* label, accelerator */     
+    N_("Change the visibility of this window's pathbar"),                    /* tooltip */
+    G_CALLBACK (action_show_hide_path_bar_callback),
+    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 */
Index: src/nautilus-navigation-window-ui.xml
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-navigation-window-ui.xml,v
retrieving revision 1.11
diff -u -r1.11 nautilus-navigation-window-ui.xml
--- src/nautilus-navigation-window-ui.xml	22 Nov 2004 15:24:37 -0000	1.11
+++ src/nautilus-navigation-window-ui.xml	4 Jul 2005 18:18:38 -0000
@@ -13,6 +13,7 @@
 		<placeholder name="Show Hide Placeholder">
 			<menuitem name="Show Hide Sidebar" action="Show Hide Sidebar"/>
 			<menuitem name="Show Hide Location Bar" action="Show Hide Location Bar"/>
+			<menuitem name="Show Hide Pathbar" action="Show Hide Pathbar"/>
 			<menuitem name="Show Hide Statusbar" action="Show Hide Statusbar"/>
 		</placeholder>
 	</menu>
Index: src/nautilus-actions.h
===================================================================
RCS file: /cvs/gnome/nautilus/src/nautilus-actions.h,v
retrieving revision 1.3
diff -u -r1.3 nautilus-actions.h
--- src/nautilus-actions.h	28 Jan 2005 08:49:42 -0000	1.3
+++ src/nautilus-actions.h	4 Jul 2005 18:18:38 -0000
@@ -36,6 +36,7 @@
 #define NAUTILUS_ACTION_SHOW_HIDE_SIDEBAR "Show Hide Sidebar"
 #define NAUTILUS_ACTION_SHOW_HIDE_STATUSBAR "Show Hide Statusbar"
 #define NAUTILUS_ACTION_SHOW_HIDE_LOCATION_BAR "Show Hide Location Bar"
+#define NAUTILUS_ACTION_SHOW_HIDE_PATH_BAR "Show Hide Pathbar"
 #define NAUTILUS_ACTION_GO_TO_BURN_CD "Go to Burn CD"
 #define NAUTILUS_ACTION_ZOOM_IN "Zoom In"
 #define NAUTILUS_ACTION_ZOOM_OUT "Zoom Out"
Index: src/Makefile.am
===================================================================
RCS file: /cvs/gnome/nautilus/src/Makefile.am,v
retrieving revision 1.160
diff -u -r1.160 Makefile.am
--- src/Makefile.am	23 Jun 2005 14:16:58 -0000	1.160
+++ src/Makefile.am	4 Jul 2005 18:18:38 -0000
@@ -93,6 +93,8 @@
 	nautilus-navigation-window.h            \
 	nautilus-notes-viewer.c			\
 	nautilus-notes-viewer.h			\
+	nautilus-pathbar.c			\
+	nautilus-pathbar.h			\
 	nautilus-property-browser.c     	\
 	nautilus-property-browser.h		\
 	nautilus-self-check-functions.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	4 Jul 2005 18:18:39 -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_START_WITH_PATH_BAR		"preferences/start_with_path_bar"
 #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	4 Jul 2005 18:18:41 -0000
@@ -394,6 +394,10 @@
 	  PREFERENCE_BOOLEAN,
 	  GINT_TO_POINTER (TRUE)
 	},
+	{ NAUTILUS_PREFERENCES_START_WITH_PATH_BAR,
+	  PREFERENCE_BOOLEAN,
+	  GINT_TO_POINTER (TRUE)
+	},
 	{ 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]