/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */ /* gtkpathbar.c * Copyright (C) 2004 Red Hat, Inc., Jonathan Blandford * * 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, see . */ #include "config.h" #include "gtkpathbar.h" #include #include "gtkarrow.h" #include "gtkbox.h" #include "gtkdnd.h" #include "gtkicontheme.h" #include "gtkimage.h" #include "gtkintl.h" #include "gtklabel.h" #include "gtkmain.h" #include "gtkmarshalers.h" #include "gtksettings.h" #include "gtktogglebutton.h" #include "gtkwidgetpath.h" #include "gtkwidgetprivate.h" struct _GtkPathBarPrivate { GtkFileSystem *file_system; GFile *root_file; GFile *home_file; GFile *desktop_file; GCancellable *get_info_cancellable; cairo_surface_t *root_icon; cairo_surface_t *home_icon; cairo_surface_t *desktop_icon; GdkWindow *event_window; 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; guint scrolling_up : 1; guint scrolling_down : 1; }; enum { PATH_CLICKED, LAST_SIGNAL }; typedef enum { NORMAL_BUTTON, ROOT_BUTTON, HOME_BUTTON, DESKTOP_BUTTON } ButtonType; #define BUTTON_DATA(x) ((ButtonData *)(x)) #define SCROLL_DELAY_FACTOR 5 #define TIMEOUT_INITIAL 500 #define TIMEOUT_REPEAT 50 static guint path_bar_signals [LAST_SIGNAL] = { 0 }; /* Icon size for if we can't get it from the theme */ #define FALLBACK_ICON_SIZE 16 typedef struct _ButtonData ButtonData; struct _ButtonData { GtkWidget *button; ButtonType type; char *dir_name; GFile *file; GtkWidget *image; GtkWidget *label; GCancellable *cancellable; 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) G_DEFINE_TYPE_WITH_PRIVATE (GtkPathBar, gtk_path_bar, GTK_TYPE_CONTAINER) static void gtk_path_bar_finalize (GObject *object); static void gtk_path_bar_dispose (GObject *object); static void gtk_path_bar_realize (GtkWidget *widget); static void gtk_path_bar_unrealize (GtkWidget *widget); static void gtk_path_bar_get_preferred_width (GtkWidget *widget, gint *minimum, gint *natural); static void gtk_path_bar_get_preferred_height (GtkWidget *widget, gint *minimum, gint *natural); static void gtk_path_bar_map (GtkWidget *widget); static void gtk_path_bar_unmap (GtkWidget *widget); static void gtk_path_bar_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static void gtk_path_bar_add (GtkContainer *container, GtkWidget *widget); static void gtk_path_bar_remove (GtkContainer *container, GtkWidget *widget); static void gtk_path_bar_forall (GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data); static GtkWidgetPath *gtk_path_bar_get_path_for_child (GtkContainer *container, GtkWidget *child); static gboolean gtk_path_bar_scroll (GtkWidget *widget, GdkEventScroll *event); static void gtk_path_bar_scroll_up (GtkPathBar *path_bar); static void gtk_path_bar_scroll_down (GtkPathBar *path_bar); static void gtk_path_bar_stop_scrolling (GtkPathBar *path_bar); static gboolean gtk_path_bar_slider_up_defocus (GtkWidget *widget, GdkEventButton *event, GtkPathBar *path_bar); static gboolean gtk_path_bar_slider_down_defocus (GtkWidget *widget, GdkEventButton *event, GtkPathBar *path_bar); static gboolean gtk_path_bar_slider_button_press (GtkWidget *widget, GdkEventButton *event, GtkPathBar *path_bar); static gboolean gtk_path_bar_slider_button_release(GtkWidget *widget, GdkEventButton *event, GtkPathBar *path_bar); static void gtk_path_bar_grab_notify (GtkWidget *widget, gboolean was_grabbed); static void gtk_path_bar_state_changed (GtkWidget *widget, GtkStateType previous_state); static void gtk_path_bar_style_updated (GtkWidget *widget); static void gtk_path_bar_screen_changed (GtkWidget *widget, GdkScreen *previous_screen); static void gtk_path_bar_check_icon_theme (GtkPathBar *path_bar); static void gtk_path_bar_update_button_appearance (GtkPathBar *path_bar, ButtonData *button_data, gboolean current_dir); static void on_slider_unmap (GtkWidget *widget, GtkPathBar *path_bar) { if (path_bar->priv->timer && ((widget == path_bar->priv->up_slider_button && path_bar->priv->scrolling_up) || (widget == path_bar->priv->down_slider_button && path_bar->priv->scrolling_down))) gtk_path_bar_stop_scrolling (path_bar); } static void gtk_path_bar_init (GtkPathBar *path_bar) { GtkStyleContext *context; path_bar->priv = gtk_path_bar_get_instance_private (path_bar); gtk_widget_init_template (GTK_WIDGET (path_bar)); /* Add the children manually because GtkPathBar derives from an abstract class, * Glade cannot edit a