/* -*- 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 "gtkbox.h" #include "gtkcssnodeprivate.h" #include "gtkdnd.h" #include "gtkdragsource.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" #include "gtkeventcontrollerscroll.h" struct _GtkPathBarPrivate { GtkFileSystem *file_system; GFile *root_file; GFile *home_file; GFile *desktop_file; GCancellable *get_info_cancellable; GIcon *root_icon; GIcon *home_icon; GIcon *desktop_icon; GtkEventController *scroll_controller; GList *button_list; GList *first_scrolled_button; GList *fake_root; GtkWidget *up_slider_button; GtkWidget *down_slider_button; guint settings_signal_id; gint16 slider_width; 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_measure (GtkWidget *widget, GtkOrientation orientation, int for_size, int *minimum, int *natural, int *minimum_baseline, int *natural_baseline); static void gtk_path_bar_unmap (GtkWidget *widget); static void gtk_path_bar_size_allocate (GtkWidget *widget, const GtkAllocation *allocation, int baseline, GtkAllocation *out_clip); 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, GtkCallback callback, gpointer callback_data); 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_flags_changed (GtkWidget *widget, GtkStateFlags 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 gtk_path_bar_scroll_controller_scroll (GtkEventControllerScroll *scroll, gdouble dx, gdouble dy, GtkPathBar *path_bar); 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