#define BUTTON_DATA(x) ((ButtonData *)(x))
-#define SCROLL_TIMEOUT 150
-#define INITIAL_SCROLL_TIMEOUT 300
+#define SCROLL_DELAY_FACTOR 5
static guint path_bar_signals [LAST_SIGNAL] = { 0 };
GtkFilePath *path;
GtkWidget *image;
GtkWidget *label;
+ GtkFileSystemHandle *handle;
guint ignore_changes : 1;
guint file_is_hidden : 1;
};
*/
#define BUTTON_IS_FAKE_ROOT(button) ((button)->type == HOME_BUTTON)
-G_DEFINE_TYPE (GtkPathBar, gtk_path_bar, GTK_TYPE_CONTAINER);
+G_DEFINE_TYPE (GtkPathBar, gtk_path_bar, GTK_TYPE_CONTAINER)
static void gtk_path_bar_finalize (GObject *object);
static void gtk_path_bar_dispose (GObject *object);
gtk_widget_push_composite_child ();
button = gtk_button_new ();
- gtk_button_set_focus_on_click (button, FALSE);
+ gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
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_SET_FLAGS (path_bar, GTK_NO_WINDOW);
gtk_widget_set_redraw_on_allocate (GTK_WIDGET (path_bar), FALSE);
- path_bar->spacing = 3;
+ path_bar->set_path_handle = NULL;
+
+ path_bar->spacing = 0;
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;
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GtkPathBarClass, path_clicked),
NULL, NULL,
- _gtk_marshal_VOID__POINTER_BOOLEAN,
- G_TYPE_NONE, 2,
+ _gtk_marshal_VOID__POINTER_POINTER_BOOLEAN,
+ G_TYPE_NONE, 3,
+ G_TYPE_POINTER,
G_TYPE_POINTER,
G_TYPE_BOOLEAN);
}
static void
gtk_path_bar_dispose (GObject *object)
{
- remove_settings_signal (GTK_PATH_BAR (object),
- gtk_widget_get_screen (GTK_WIDGET (object)));
+ GList *list;
+ GtkPathBar *path_bar = GTK_PATH_BAR (object);
+
+ remove_settings_signal (path_bar, gtk_widget_get_screen (GTK_WIDGET (object)));
+
+ if (path_bar->set_path_handle)
+ gtk_file_system_cancel_operation (path_bar->set_path_handle);
+ path_bar->set_path_handle = NULL;
+
+ for (list = path_bar->button_list; list; list = list->next)
+ {
+ ButtonData *button_data = BUTTON_DATA (list->data);
+
+ if (button_data->handle)
+ gtk_file_system_cancel_operation (button_data->handle);
+ button_data->handle = NULL;
+ }
G_OBJECT_CLASS (gtk_path_bar_parent_class)->dispose (object);
}
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);
+ {
+ gtk_path_bar_stop_scrolling (path_bar);
+ 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);
+ {
+ gtk_path_bar_stop_scrolling (path_bar);
+ gtk_widget_set_sensitive (path_bar->up_slider_button, FALSE);
+ }
else
gtk_widget_set_sensitive (path_bar->up_slider_button, TRUE);
}
{
if (path_bar->scrolling_up)
gtk_path_bar_scroll_up (path_bar->up_slider_button, path_bar);
- else
+ else if (path_bar->scrolling_down)
gtk_path_bar_scroll_down (path_bar->down_slider_button, path_bar);
if (path_bar->need_timer)
{
+ GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (path_bar));
+ guint timeout;
+
+ g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
+
path_bar->need_timer = FALSE;
- path_bar->timer = g_timeout_add (SCROLL_TIMEOUT,
+ path_bar->timer = g_timeout_add (timeout * SCROLL_DELAY_FACTOR,
(GSourceFunc)gtk_path_bar_scroll_timeout,
path_bar);
-
}
else
retval = TRUE;
-
}
GDK_THREADS_LEAVE ();
if (widget == path_bar->up_slider_button)
{
+ path_bar->scrolling_down = FALSE;
path_bar->scrolling_up = TRUE;
gtk_path_bar_scroll_up (path_bar->up_slider_button, path_bar);
}
else if (widget == path_bar->down_slider_button)
{
path_bar->scrolling_up = FALSE;
+ path_bar->scrolling_down = TRUE;
gtk_path_bar_scroll_down (path_bar->down_slider_button, path_bar);
}
if (!path_bar->timer)
{
+ GtkSettings *settings = gtk_widget_get_settings (widget);
+ guint timeout;
+
+ g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
+
path_bar->need_timer = TRUE;
- path_bar->timer = g_timeout_add (INITIAL_SCROLL_TIMEOUT,
+ path_bar->timer = g_timeout_add (timeout,
(GSourceFunc)gtk_path_bar_scroll_timeout,
path_bar);
}
GtkPathBar *path_bar;
GList *button_list;
gboolean child_is_hidden;
+ GtkFilePath *child_path;
button_data = BUTTON_DATA (data);
if (button_data->ignore_changes)
button_list = g_list_find (path_bar->button_list, button_data);
g_assert (button_list != NULL);
+ g_signal_handlers_block_by_func (button,
+ G_CALLBACK (button_clicked_cb), data);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
+ g_signal_handlers_unblock_by_func (button,
+ G_CALLBACK (button_clicked_cb), data);
if (button_list->prev)
{
ButtonData *child_data;
child_data = BUTTON_DATA (button_list->prev->data);
+ child_path = child_data->path;
child_is_hidden = child_data->file_is_hidden;
}
else
- child_is_hidden = FALSE;
+ {
+ child_path = NULL;
+ child_is_hidden = FALSE;
+ }
- g_signal_emit (path_bar, path_bar_signals [PATH_CLICKED], 0, button_data->path, child_is_hidden);
+ g_signal_emit (path_bar, path_bar_signals [PATH_CLICKED], 0,
+ button_data->path, child_path, child_is_hidden);
}
-static GdkPixbuf *
-get_button_image (GtkPathBar *path_bar,
- ButtonType button_type)
+struct SetButtonImageData
+{
+ GtkPathBar *path_bar;
+ ButtonData *button_data;
+};
+
+static void
+set_button_image_get_info_cb (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer user_data)
+{
+ gboolean cancelled = handle->cancelled;
+ GdkPixbuf *pixbuf;
+ struct SetButtonImageData *data = user_data;
+
+ if (handle != data->button_data->handle)
+ goto out;
+
+ data->button_data->handle = NULL;
+
+ if (cancelled || error)
+ goto out;
+
+ pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (data->path_bar),
+ data->path_bar->icon_size, NULL);
+ gtk_image_set_from_pixbuf (GTK_IMAGE (data->button_data->image), pixbuf);
+
+ switch (data->button_data->type)
+ {
+ case HOME_BUTTON:
+ if (data->path_bar->home_icon)
+ g_object_unref (pixbuf);
+ else
+ data->path_bar->home_icon = pixbuf;
+ break;
+
+ case DESKTOP_BUTTON:
+ if (data->path_bar->desktop_icon)
+ g_object_unref (pixbuf);
+ else
+ data->path_bar->desktop_icon = pixbuf;
+ break;
+
+ default:
+ break;
+ };
+
+out:
+ g_free (data);
+ g_object_unref (handle);
+}
+
+static void
+set_button_image (GtkPathBar *path_bar,
+ ButtonData *button_data)
{
GtkFileSystemVolume *volume;
+ struct SetButtonImageData *data;
- switch (button_type)
+ switch (button_data->type)
{
case ROOT_BUTTON:
if (path_bar->root_icon != NULL)
- return path_bar->root_icon;
+ {
+ gtk_image_set_from_pixbuf (GTK_IMAGE (button_data->image), path_bar->root_icon);
+ break;
+ }
volume = gtk_file_system_get_volume_for_path (path_bar->file_system, path_bar->root_path);
if (volume == NULL)
- return NULL;
+ return;
path_bar->root_icon = gtk_file_system_volume_render_icon (path_bar->file_system,
volume,
NULL);
gtk_file_system_volume_free (path_bar->file_system, volume);
- return path_bar->root_icon;
+ gtk_image_set_from_pixbuf (GTK_IMAGE (button_data->image), path_bar->root_icon);
+ break;
+
case HOME_BUTTON:
if (path_bar->home_icon != NULL)
- return path_bar->home_icon;
-
- path_bar->home_icon = gtk_file_system_render_icon (path_bar->file_system,
- path_bar->home_path,
- GTK_WIDGET (path_bar),
- path_bar->icon_size,
- NULL);
- return path_bar->home_icon;
+ {
+ gtk_image_set_from_pixbuf (GTK_IMAGE (button_data->image), path_bar->home_icon);
+ break;
+ }
+
+ data = g_new0 (struct SetButtonImageData, 1);
+ data->path_bar = path_bar;
+ data->button_data = button_data;
+
+ if (button_data->handle)
+ gtk_file_system_cancel_operation (button_data->handle);
+
+ button_data->handle =
+ gtk_file_system_get_info (path_bar->file_system,
+ path_bar->home_path,
+ GTK_FILE_INFO_ICON,
+ set_button_image_get_info_cb,
+ data);
+ break;
+
case DESKTOP_BUTTON:
if (path_bar->desktop_icon != NULL)
- return path_bar->desktop_icon;
-
- path_bar->desktop_icon = gtk_file_system_render_icon (path_bar->file_system,
- path_bar->desktop_path,
- GTK_WIDGET (path_bar),
- path_bar->icon_size,
- NULL);
- return path_bar->desktop_icon;
+ {
+ gtk_image_set_from_pixbuf (GTK_IMAGE (button_data->image), path_bar->desktop_icon);
+ break;
+ }
+
+ data = g_new0 (struct SetButtonImageData, 1);
+ data->path_bar = path_bar;
+ data->button_data = button_data;
+
+ if (button_data->handle)
+ gtk_file_system_cancel_operation (button_data->handle);
+
+ button_data->handle =
+ gtk_file_system_get_info (path_bar->file_system,
+ path_bar->desktop_path,
+ GTK_FILE_INFO_ICON,
+ set_button_image_get_info_cb,
+ data);
+ break;
default:
- return NULL;
+ break;
}
-
- return NULL;
}
static void
button_data_free (ButtonData *button_data)
{
+ if (button_data->handle)
+ gtk_file_system_cancel_operation (button_data->handle);
+
gtk_file_path_free (button_data->path);
g_free (button_data->dir_name);
g_free (button_data);
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);
+ set_button_image (path_bar, button_data);
}
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_data->button)) != current_dir)
gtk_selection_data_set (selection_data,
selection_data->target,
8,
- uri_list,
+ (guchar *)uri_list,
strlen (uri_list));
g_free (uri_list);
}
button_data->type = find_button_type (path_bar, path);
button_data->button = gtk_toggle_button_new ();
- gtk_button_set_focus_on_click (button_data->button, FALSE);
+ gtk_button_set_focus_on_click (GTK_BUTTON (button_data->button), FALSE);
switch (button_data->type)
{
return FALSE;
}
-gboolean
-_gtk_path_bar_set_path (GtkPathBar *path_bar,
- const GtkFilePath *file_path,
- const gboolean keep_trail,
- GError **error)
+
+struct SetPathInfo
{
GtkFilePath *path;
- gboolean first_directory = TRUE;
- gboolean result;
- GList *new_buttons = NULL;
- GList *fake_root = NULL;
-
- g_return_val_if_fail (GTK_IS_PATH_BAR (path_bar), FALSE);
- g_return_val_if_fail (file_path != NULL, FALSE);
-
- result = TRUE;
-
- /* 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 (keep_trail &&
- gtk_path_bar_check_parent_path (path_bar, file_path, path_bar->file_system))
- return TRUE;
+ GtkFilePath *parent_path;
+ GtkPathBar *path_bar;
+ GList *new_buttons;
+ GList *fake_root;
+ gboolean first_directory;
+};
- path = gtk_file_path_copy (file_path);
+static void
+gtk_path_bar_set_path_finish (struct SetPathInfo *info,
+ gboolean result)
+{
+ if (result)
+ {
+ GList *l;
- gtk_widget_push_composite_child ();
+ gtk_path_bar_clear_buttons (info->path_bar);
+ info->path_bar->button_list = g_list_reverse (info->new_buttons);
+ info->path_bar->fake_root = info->fake_root;
- while (path != NULL)
- {
- GtkFilePath *parent_path = NULL;
- ButtonData *button_data;
- const gchar *display_name;
- gboolean is_hidden;
- GtkFileFolder *file_folder;
- GtkFileInfo *file_info;
- gboolean valid;
-
- valid = gtk_file_system_get_parent (path_bar->file_system,
- path,
- &parent_path,
- error);
- if (!valid)
+ for (l = info->path_bar->button_list; l; l = l->next)
{
- result = FALSE;
- gtk_file_path_free (path);
- break;
+ GtkWidget *button = BUTTON_DATA (l->data)->button;
+ gtk_container_add (GTK_CONTAINER (info->path_bar), button);
}
+ }
+ else
+ {
+ GList *l;
- file_folder = gtk_file_system_get_folder (path_bar->file_system,
- parent_path ? parent_path : path,
- GTK_FILE_INFO_DISPLAY_NAME | GTK_FILE_INFO_IS_HIDDEN,
- NULL);
- if (!file_folder)
+ for (l = info->new_buttons; l; l = l->next)
{
- result = FALSE;
- gtk_file_path_free (parent_path);
- gtk_file_path_free (path);
- break;
- }
-
- file_info = gtk_file_folder_get_info (file_folder, parent_path ? path : NULL, error);
- g_object_unref (file_folder);
+ ButtonData *button_data;
- if (!file_info)
- {
- result = FALSE;
- gtk_file_path_free (parent_path);
- gtk_file_path_free (path);
- break;
+ button_data = BUTTON_DATA (l->data);
+ gtk_widget_destroy (button_data->button);
}
- display_name = gtk_file_info_get_display_name (file_info);
- is_hidden = gtk_file_info_get_is_hidden (file_info);
-
- button_data = make_directory_button (path_bar, display_name, path, first_directory, is_hidden);
- gtk_file_info_free (file_info);
- gtk_file_path_free (path);
+ g_list_free (info->new_buttons);
+ }
- new_buttons = g_list_prepend (new_buttons, button_data);
+ if (info->path)
+ gtk_file_path_free (info->path);
+ if (info->parent_path)
+ gtk_file_path_free (info->parent_path);
+ g_free (info);
+}
- if (BUTTON_IS_FAKE_ROOT (button_data))
- fake_root = new_buttons;
+static void
+gtk_path_bar_get_info_callback (GtkFileSystemHandle *handle,
+ const GtkFileInfo *file_info,
+ const GError *error,
+ gpointer data)
+{
+ gboolean cancelled = handle->cancelled;
+ struct SetPathInfo *path_info = data;
+ ButtonData *button_data;
+ const gchar *display_name;
+ gboolean is_hidden;
+ gboolean valid;
- path = parent_path;
- first_directory = FALSE;
+ if (handle != path_info->path_bar->set_path_handle)
+ {
+ gtk_path_bar_set_path_finish (path_info, FALSE);
+ g_object_unref (handle);
+ return;
}
- if (result)
+ g_object_unref (handle);
+ path_info->path_bar->set_path_handle = NULL;
+
+ if (cancelled || !file_info)
{
- GList *l;
+ gtk_path_bar_set_path_finish (path_info, FALSE);
+ return;
+ }
- gtk_path_bar_clear_buttons (path_bar);
- path_bar->button_list = g_list_reverse (new_buttons);
- path_bar->fake_root = fake_root;
+ display_name = gtk_file_info_get_display_name (file_info);
+ is_hidden = gtk_file_info_get_is_hidden (file_info);
- for (l = path_bar->button_list; l; l = l->next)
- {
- GtkWidget *button = BUTTON_DATA (l->data)->button;
- gtk_container_add (GTK_CONTAINER (path_bar), button);
- }
+ gtk_widget_push_composite_child ();
+ button_data = make_directory_button (path_info->path_bar, display_name,
+ path_info->path,
+ path_info->first_directory, is_hidden);
+ gtk_widget_pop_composite_child ();
+ gtk_file_path_free (path_info->path);
+
+ path_info->new_buttons = g_list_prepend (path_info->new_buttons, button_data);
+
+ if (BUTTON_IS_FAKE_ROOT (button_data))
+ path_info->fake_root = path_info->new_buttons;
+
+ path_info->path = path_info->parent_path;
+ path_info->first_directory = FALSE;
+
+ if (!path_info->path)
+ {
+ gtk_path_bar_set_path_finish (path_info, TRUE);
+ return;
}
- else
+
+ valid = gtk_file_system_get_parent (path_info->path_bar->file_system,
+ path_info->path,
+ &path_info->parent_path,
+ NULL);
+ if (!valid)
{
- GList *l;
+ gtk_path_bar_set_path_finish (path_info, FALSE);
+ return;
+ }
- for (l = new_buttons; l; l = l->next)
- {
- ButtonData *button_data;
+ path_info->path_bar->set_path_handle =
+ gtk_file_system_get_info (handle->file_system,
+ path_info->path,
+ GTK_FILE_INFO_DISPLAY_NAME | GTK_FILE_INFO_IS_HIDDEN,
+ gtk_path_bar_get_info_callback,
+ path_info);
+}
- button_data = BUTTON_DATA (l->data);
- gtk_widget_destroy (button_data->button);
- }
+gboolean
+_gtk_path_bar_set_path (GtkPathBar *path_bar,
+ const GtkFilePath *file_path,
+ const gboolean keep_trail,
+ GError **error)
+{
+ struct SetPathInfo *info;
+ gboolean result;
+
+ g_return_val_if_fail (GTK_IS_PATH_BAR (path_bar), FALSE);
+ g_return_val_if_fail (file_path != NULL, FALSE);
+
+ result = TRUE;
+
+ /* 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 (keep_trail &&
+ gtk_path_bar_check_parent_path (path_bar, file_path, path_bar->file_system))
+ return TRUE;
+
+ info = g_new0 (struct SetPathInfo, 1);
+ info->path = gtk_file_path_copy (file_path);
+ info->path_bar = path_bar;
+ info->first_directory = TRUE;
- g_list_free (new_buttons);
+ result = gtk_file_system_get_parent (path_bar->file_system,
+ info->path, &info->parent_path, error);
+ if (!result)
+ {
+ gtk_file_path_free (info->path);
+ g_free (info);
+ return result;
}
- gtk_widget_pop_composite_child ();
+ if (path_bar->set_path_handle)
+ gtk_file_system_cancel_operation (path_bar->set_path_handle);
+
+ path_bar->set_path_handle =
+ gtk_file_system_get_info (path_bar->file_system,
+ info->path,
+ GTK_FILE_INFO_DISPLAY_NAME | GTK_FILE_INFO_IS_HIDDEN,
+ gtk_path_bar_get_info_callback,
+ info);
- return result;
+ return TRUE;
}
/* FIXME: This should be a construct-only property */