diff --git a/ChangeLog b/ChangeLog index 90e5fe0193..0346f51a52 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,42 @@ +2004-03-19 Federico Mena Quintero + + Fix #137520. + + * gtk/gtkfilesystem.h (struct _GtkFileFolderIface): Added slots + for an ::is_finished_loading() method and a ::finished_loading() + signal at the end of the struct. + + * gtk/gtkfilesystem.c (gtk_file_folder_base_init): Create the + "finished-loading" signal. + (gtk_file_folder_is_finished_loading): New function. + + * gtk/gtkfilesystemunix.c + (gtk_file_folder_unix_is_finished_loading): Implement. + + * gtk/gtkfilesystemmodel.c (struct _GtkFileSystemModelClass): New + slot for a "finished-loading" signal. + (gtk_file_system_model_class_init): Create the "finished-loading" + signal. + (struct _GtkFileSystemModel): New field + idle_finished_loading_source. We emit the "finished-loading" + signal in an idle if the root folder was done loading right in + _gtk_file_system_model_new(), so that the caller has a chance to + connect to the signal. + (_gtk_file_system_model_new): Connect to the normal signals of the + folder even if the initial _list_children() fails. Also, see if + the folder is finished loading; connect to the "finished-loading" + signal otherwise. + (gtk_file_system_model_finalize): Remove the idle handler. + + * gtk/gtkfilechooserdefault.c (set_list_model): Set a busy cursor + and connect to the model's "finished-loading" signal. + (get_toplevel): New helper function. + (error_message): Use get_toplevel(). + (trap_activate_cb): Likewise. + (location_popup_handler): Likewise. + (set_busy_cursor): New function. + (browse_files_model_finished_loading_cb): New callback. + Thu Mar 18 12:10:45 2004 Owen Taylor * gtk/gtktreeitem.c (gtk_tree_item_forall): Include diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 90e5fe0193..0346f51a52 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,42 @@ +2004-03-19 Federico Mena Quintero + + Fix #137520. + + * gtk/gtkfilesystem.h (struct _GtkFileFolderIface): Added slots + for an ::is_finished_loading() method and a ::finished_loading() + signal at the end of the struct. + + * gtk/gtkfilesystem.c (gtk_file_folder_base_init): Create the + "finished-loading" signal. + (gtk_file_folder_is_finished_loading): New function. + + * gtk/gtkfilesystemunix.c + (gtk_file_folder_unix_is_finished_loading): Implement. + + * gtk/gtkfilesystemmodel.c (struct _GtkFileSystemModelClass): New + slot for a "finished-loading" signal. + (gtk_file_system_model_class_init): Create the "finished-loading" + signal. + (struct _GtkFileSystemModel): New field + idle_finished_loading_source. We emit the "finished-loading" + signal in an idle if the root folder was done loading right in + _gtk_file_system_model_new(), so that the caller has a chance to + connect to the signal. + (_gtk_file_system_model_new): Connect to the normal signals of the + folder even if the initial _list_children() fails. Also, see if + the folder is finished loading; connect to the "finished-loading" + signal otherwise. + (gtk_file_system_model_finalize): Remove the idle handler. + + * gtk/gtkfilechooserdefault.c (set_list_model): Set a busy cursor + and connect to the model's "finished-loading" signal. + (get_toplevel): New helper function. + (error_message): Use get_toplevel(). + (trap_activate_cb): Likewise. + (location_popup_handler): Likewise. + (set_busy_cursor): New function. + (browse_files_model_finished_loading_cb): New callback. + Thu Mar 18 12:10:45 2004 Owen Taylor * gtk/gtktreeitem.c (gtk_tree_item_forall): Include diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 90e5fe0193..0346f51a52 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,42 @@ +2004-03-19 Federico Mena Quintero + + Fix #137520. + + * gtk/gtkfilesystem.h (struct _GtkFileFolderIface): Added slots + for an ::is_finished_loading() method and a ::finished_loading() + signal at the end of the struct. + + * gtk/gtkfilesystem.c (gtk_file_folder_base_init): Create the + "finished-loading" signal. + (gtk_file_folder_is_finished_loading): New function. + + * gtk/gtkfilesystemunix.c + (gtk_file_folder_unix_is_finished_loading): Implement. + + * gtk/gtkfilesystemmodel.c (struct _GtkFileSystemModelClass): New + slot for a "finished-loading" signal. + (gtk_file_system_model_class_init): Create the "finished-loading" + signal. + (struct _GtkFileSystemModel): New field + idle_finished_loading_source. We emit the "finished-loading" + signal in an idle if the root folder was done loading right in + _gtk_file_system_model_new(), so that the caller has a chance to + connect to the signal. + (_gtk_file_system_model_new): Connect to the normal signals of the + folder even if the initial _list_children() fails. Also, see if + the folder is finished loading; connect to the "finished-loading" + signal otherwise. + (gtk_file_system_model_finalize): Remove the idle handler. + + * gtk/gtkfilechooserdefault.c (set_list_model): Set a busy cursor + and connect to the model's "finished-loading" signal. + (get_toplevel): New helper function. + (error_message): Use get_toplevel(). + (trap_activate_cb): Likewise. + (location_popup_handler): Likewise. + (set_busy_cursor): New function. + (browse_files_model_finished_loading_cb): New callback. + Thu Mar 18 12:10:45 2004 Owen Taylor * gtk/gtktreeitem.c (gtk_tree_item_forall): Include diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 90e5fe0193..0346f51a52 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,42 @@ +2004-03-19 Federico Mena Quintero + + Fix #137520. + + * gtk/gtkfilesystem.h (struct _GtkFileFolderIface): Added slots + for an ::is_finished_loading() method and a ::finished_loading() + signal at the end of the struct. + + * gtk/gtkfilesystem.c (gtk_file_folder_base_init): Create the + "finished-loading" signal. + (gtk_file_folder_is_finished_loading): New function. + + * gtk/gtkfilesystemunix.c + (gtk_file_folder_unix_is_finished_loading): Implement. + + * gtk/gtkfilesystemmodel.c (struct _GtkFileSystemModelClass): New + slot for a "finished-loading" signal. + (gtk_file_system_model_class_init): Create the "finished-loading" + signal. + (struct _GtkFileSystemModel): New field + idle_finished_loading_source. We emit the "finished-loading" + signal in an idle if the root folder was done loading right in + _gtk_file_system_model_new(), so that the caller has a chance to + connect to the signal. + (_gtk_file_system_model_new): Connect to the normal signals of the + folder even if the initial _list_children() fails. Also, see if + the folder is finished loading; connect to the "finished-loading" + signal otherwise. + (gtk_file_system_model_finalize): Remove the idle handler. + + * gtk/gtkfilechooserdefault.c (set_list_model): Set a busy cursor + and connect to the model's "finished-loading" signal. + (get_toplevel): New helper function. + (error_message): Use get_toplevel(). + (trap_activate_cb): Likewise. + (location_popup_handler): Likewise. + (set_busy_cursor): New function. + (browse_files_model_finished_loading_cb): New callback. + Thu Mar 18 12:10:45 2004 Owen Taylor * gtk/gtktreeitem.c (gtk_tree_item_forall): Include diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 90e5fe0193..0346f51a52 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,42 @@ +2004-03-19 Federico Mena Quintero + + Fix #137520. + + * gtk/gtkfilesystem.h (struct _GtkFileFolderIface): Added slots + for an ::is_finished_loading() method and a ::finished_loading() + signal at the end of the struct. + + * gtk/gtkfilesystem.c (gtk_file_folder_base_init): Create the + "finished-loading" signal. + (gtk_file_folder_is_finished_loading): New function. + + * gtk/gtkfilesystemunix.c + (gtk_file_folder_unix_is_finished_loading): Implement. + + * gtk/gtkfilesystemmodel.c (struct _GtkFileSystemModelClass): New + slot for a "finished-loading" signal. + (gtk_file_system_model_class_init): Create the "finished-loading" + signal. + (struct _GtkFileSystemModel): New field + idle_finished_loading_source. We emit the "finished-loading" + signal in an idle if the root folder was done loading right in + _gtk_file_system_model_new(), so that the caller has a chance to + connect to the signal. + (_gtk_file_system_model_new): Connect to the normal signals of the + folder even if the initial _list_children() fails. Also, see if + the folder is finished loading; connect to the "finished-loading" + signal otherwise. + (gtk_file_system_model_finalize): Remove the idle handler. + + * gtk/gtkfilechooserdefault.c (set_list_model): Set a busy cursor + and connect to the model's "finished-loading" signal. + (get_toplevel): New helper function. + (error_message): Use get_toplevel(). + (trap_activate_cb): Likewise. + (location_popup_handler): Likewise. + (set_busy_cursor): New function. + (browse_files_model_finished_loading_cb): New callback. + Thu Mar 18 12:10:45 2004 Owen Taylor * gtk/gtktreeitem.c (gtk_tree_item_forall): Include diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c index 8987297667..456c7d5e31 100644 --- a/gtk/gtkfilechooserdefault.c +++ b/gtk/gtkfilechooserdefault.c @@ -664,19 +664,25 @@ error_message_with_parent (GtkWindow *parent, gtk_widget_destroy (dialog); } +/* Returns a toplevel GtkWindow, or NULL if none */ +static GtkWindow * +get_toplevel (GtkWidget *widget) +{ + GtkWidget *toplevel; + + toplevel = gtk_widget_get_toplevel (widget); + if (!GTK_WIDGET_TOPLEVEL (toplevel)) + return NULL; + else + return GTK_WINDOW (toplevel); +} + /* Shows an error dialog for the file chooser */ static void error_message (GtkFileChooserDefault *impl, const char *msg) { - GtkWidget *toplevel; - - toplevel = gtk_widget_get_toplevel (GTK_WIDGET (impl)); - if (!GTK_WIDGET_TOPLEVEL (toplevel)) - toplevel = NULL; - - error_message_with_parent (toplevel ? GTK_WINDOW (toplevel) : NULL, - msg); + error_message_with_parent (get_toplevel (GTK_WIDGET (impl)), msg); } /* Shows a simple error dialog relative to a path. Frees the GError as well. */ @@ -2556,21 +2562,15 @@ trap_activate_cb (GtkWidget *widget, || event->keyval == GDK_KP_Enter || event->keyval == GDK_space) { - GtkWidget *toplevel; + GtkWindow *window; - toplevel = gtk_widget_get_toplevel (widget); - if (GTK_IS_WINDOW (toplevel)) - { - GtkWindow *window; + window = get_toplevel (widget); + if (window + && widget != window->default_widget + && !(widget == window->focus_widget && + (!window->default_widget || !GTK_WIDGET_SENSITIVE (window->default_widget)))) + gtk_window_activate_default (window); - window = GTK_WINDOW (toplevel); - - if (window && - widget != window->default_widget && - !(widget == window->focus_widget && - (!window->default_widget || !GTK_WIDGET_SENSITIVE (window->default_widget)))) - gtk_window_activate_default (window); - } return TRUE; } return FALSE; @@ -3602,6 +3602,40 @@ list_sort_column_changed_cb (GtkTreeSortable *sortable, impl->list_sort_ascending = (sort_type == GTK_SORT_ASCENDING); } +static void +set_busy_cursor (GtkFileChooserDefault *impl, + gboolean busy) +{ + GtkWindow *toplevel; + GdkDisplay *display; + GdkCursor *cursor; + + toplevel = get_toplevel (GTK_WIDGET (impl)); + if (!toplevel || !GTK_WIDGET_REALIZED (toplevel)) + return; + + display = gtk_widget_get_display (GTK_WIDGET (toplevel)); + + if (busy) + cursor = gdk_cursor_new_for_display (display, GDK_WATCH); + else + cursor = NULL; + + gdk_window_set_cursor (GTK_WIDGET (toplevel)->window, cursor); + gdk_display_flush (display); + + if (cursor) + gdk_cursor_unref (cursor); +} + +/* Callback used when the file system model finishes loading */ +static void +browse_files_model_finished_loading_cb (GtkFileSystemModel *model, + GtkFileChooserDefault *impl) +{ + set_busy_cursor (impl, FALSE); +} + /* Gets rid of the old list model and creates a new one for the current folder */ static void set_list_model (GtkFileChooserDefault *impl) @@ -3612,9 +3646,14 @@ set_list_model (GtkFileChooserDefault *impl) g_object_unref (impl->sort_model); } + set_busy_cursor (impl, TRUE); + impl->browse_files_model = _gtk_file_system_model_new (impl->file_system, impl->current_folder, 0, GTK_FILE_INFO_ALL); + g_signal_connect (impl->browse_files_model, "finished-loading", + G_CALLBACK (browse_files_model_finished_loading_cb), impl); + _gtk_file_system_model_set_show_hidden (impl->browse_files_model, impl->show_hidden); switch (impl->action) { @@ -4997,7 +5036,7 @@ static void location_popup_handler (GtkFileChooserDefault *impl) { GtkWidget *dialog; - GtkWidget *toplevel; + GtkWindow *toplevel; GtkWidget *hbox; GtkWidget *label; GtkWidget *entry; @@ -5006,9 +5045,7 @@ location_popup_handler (GtkFileChooserDefault *impl) /* Create dialog */ - toplevel = gtk_widget_get_toplevel (GTK_WIDGET (impl)); - if (!GTK_WIDGET_TOPLEVEL (toplevel)) - toplevel = NULL; + toplevel = get_toplevel (GTK_WIDGET (impl)); if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) @@ -5023,7 +5060,7 @@ location_popup_handler (GtkFileChooserDefault *impl) } dialog = gtk_dialog_new_with_buttons (title, - GTK_WINDOW (toplevel), + toplevel, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, @@ -5071,11 +5108,11 @@ location_popup_handler (GtkFileChooserDefault *impl) if (refocus) { - GtkWidget *toplevel; + GtkWindow *toplevel; - toplevel = gtk_widget_get_toplevel (GTK_WIDGET (impl)); - if (GTK_WIDGET_TOPLEVEL (toplevel) && GTK_WINDOW (toplevel)->focus_widget) - gtk_widget_grab_focus (GTK_WINDOW (toplevel)->focus_widget); + toplevel = get_toplevel (GTK_WIDGET (impl)); + if (toplevel && toplevel->focus_widget) + gtk_widget_grab_focus (toplevel->focus_widget); } gtk_widget_destroy (dialog); diff --git a/gtk/gtkfilesystem.c b/gtk/gtkfilesystem.c index 4f176f6fe2..af5f537e6a 100644 --- a/gtk/gtkfilesystem.c +++ b/gtk/gtkfilesystem.c @@ -838,6 +838,13 @@ gtk_file_folder_base_init (gpointer g_class) g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); + g_signal_new ("finished-loading", + iface_type, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkFileFolderIface, finished_loading), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); initialized = TRUE; } @@ -876,6 +883,17 @@ gtk_file_folder_get_info (GtkFileFolder *folder, return GTK_FILE_FOLDER_GET_IFACE (folder)->get_info (folder, path, error); } +gboolean +gtk_file_folder_is_finished_loading (GtkFileFolder *folder) +{ + g_return_val_if_fail (GTK_IS_FILE_FOLDER (folder), TRUE); + + if (!GTK_FILE_FOLDER_GET_IFACE (folder)->is_finished_loading) + return TRUE; + else + return GTK_FILE_FOLDER_GET_IFACE (folder)->is_finished_loading (folder); +} + /***************************************** * GtkFilePath modules * diff --git a/gtk/gtkfilesystem.h b/gtk/gtkfilesystem.h index 1124fc9f52..d7a570024f 100644 --- a/gtk/gtkfilesystem.h +++ b/gtk/gtkfilesystem.h @@ -307,6 +307,10 @@ struct _GtkFileFolderIface GSList *paths); void (*files_removed) (GtkFileFolder *monitor, GSList *paths); + + /* Method / signal */ + gboolean (*is_finished_loading) (GtkFileFolder *folder); + void (*finished_loading) (GtkFileFolder *folder); }; GType gtk_file_folder_get_type (void); @@ -317,6 +321,8 @@ GtkFileInfo *gtk_file_folder_get_info (GtkFileFolder *folder, const GtkFilePath *path, GError **error); +gboolean gtk_file_folder_is_finished_loading (GtkFileFolder *folder); + /* GtkFilePath */ #define GTK_TYPE_FILE_PATH (gtk_file_path_get_type ()) diff --git a/gtk/gtkfilesystemmodel.c b/gtk/gtkfilesystemmodel.c index 79e08674cc..4032f7a09d 100644 --- a/gtk/gtkfilesystemmodel.c +++ b/gtk/gtkfilesystemmodel.c @@ -24,6 +24,7 @@ #include "gtkfilesystemmodel.h" #include "gtkfilesystem.h" #include "gtkintl.h" +#include "gtkmarshalers.h" #include "gtktreednd.h" #include "gtktreemodel.h" @@ -37,6 +38,10 @@ typedef struct _FileModelNode FileModelNode; struct _GtkFileSystemModelClass { GObjectClass parent_class; + + /* Signals */ + + void (*finished_loading) (GtkFileSystemModel *model); }; struct _GtkFileSystemModel @@ -54,6 +59,7 @@ struct _GtkFileSystemModel GSList *idle_clears; GSource *idle_clear_source; + GSource *idle_finished_loading_source; gushort max_depth; @@ -186,6 +192,16 @@ static void root_files_removed_callback (GtkFileFolder *folder, static GObjectClass *parent_class = NULL; +/* Signal IDs */ +enum { + FINISHED_LOADING, + LAST_SIGNAL +}; + +static guint file_system_model_signals[LAST_SIGNAL] = { 0 }; + + + GType _gtk_file_system_model_get_type (void) { @@ -242,6 +258,15 @@ gtk_file_system_model_class_init (GtkFileSystemModelClass *class) parent_class = g_type_class_peek_parent (class); gobject_class->finalize = gtk_file_system_model_finalize; + + file_system_model_signals[FINISHED_LOADING] = + g_signal_new ("finished-loading", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkFileSystemModelClass, finished_loading), + NULL, NULL, + _gtk_marshal_VOID__VOID, + G_TYPE_NONE, 0); } static void @@ -286,6 +311,9 @@ gtk_file_system_model_finalize (GObject *object) if (model->file_system) g_object_unref (model->file_system); + if (model->idle_finished_loading_source) + g_source_destroy (model->idle_finished_loading_source); + children = model->roots; while (children) { @@ -647,6 +675,39 @@ drag_source_drag_data_get (GtkTreeDragSource *drag_source, return TRUE; } +/* Callback used when the root folder finished loading */ +static void +root_folder_finished_loading_cb (GtkFileFolder *folder, + GtkFileSystemModel *model) +{ + g_signal_emit (model, file_system_model_signals[FINISHED_LOADING], 0); +} + +/* Emits the "finished-loading" signal as an idle handler; see the comment in + * _gtk_file_system_model_new() + */ +static gboolean +idle_finished_loading_cb (GtkFileSystemModel *model) +{ + g_signal_emit (model, file_system_model_signals[FINISHED_LOADING], 0); + + g_source_destroy (model->idle_finished_loading_source); + model->idle_finished_loading_source = NULL; + + return FALSE; +} + +/* Queues an idle handler to emit the "finished-loading" signal */ +static void +queue_finished_loading (GtkFileSystemModel *model) +{ + model->idle_finished_loading_source = g_idle_source_new (); + g_source_set_closure (model->idle_finished_loading_source, + g_cclosure_new_object (G_CALLBACK (idle_finished_loading_cb), + G_OBJECT (model))); + g_source_attach (model->idle_finished_loading_source, NULL); +} + /** * _gtk_file_system_model_new: * @file_system: an object implementing #GtkFileSystem @@ -699,13 +760,19 @@ _gtk_file_system_model_new (GtkFileSystem *file_system, model->types, NULL); /* NULL-GError */ - if (model->root_folder && - gtk_file_folder_list_children (model->root_folder, - &child_paths, - NULL)) /* NULL-GError */ + if (model->root_folder) { - roots = child_paths; - + if (gtk_file_folder_list_children (model->root_folder, + &child_paths, + NULL)) /* NULL-GError */ + roots = child_paths; + + if (gtk_file_folder_is_finished_loading (model->root_folder)) + queue_finished_loading (model); /* done in an idle because we are being created */ + else + g_signal_connect (model->root_folder, "finished-loading", + G_CALLBACK (root_folder_finished_loading_cb), model); + g_signal_connect_object (model->root_folder, "deleted", G_CALLBACK (root_deleted_callback), model, 0); g_signal_connect_object (model->root_folder, "files-added", diff --git a/gtk/gtkfilesystemunix.c b/gtk/gtkfilesystemunix.c index 01528ce533..c71a643e00 100644 --- a/gtk/gtkfilesystemunix.c +++ b/gtk/gtkfilesystemunix.c @@ -203,6 +203,8 @@ static gboolean gtk_file_folder_unix_list_children (GtkFileFolder *folder, GSList **children, GError **error); +static gboolean gtk_file_folder_unix_is_finished_loading (GtkFileFolder *folder); + static GtkFilePath *filename_to_path (const gchar *filename); static gboolean filename_is_root (const char *filename); @@ -1464,6 +1466,7 @@ gtk_file_folder_unix_iface_init (GtkFileFolderIface *iface) { iface->get_info = gtk_file_folder_unix_get_info; iface->list_children = gtk_file_folder_unix_list_children; + iface->is_finished_loading = gtk_file_folder_unix_is_finished_loading; } static void @@ -1623,6 +1626,12 @@ gtk_file_folder_unix_list_children (GtkFileFolder *folder, return TRUE; } +static gboolean +gtk_file_folder_unix_is_finished_loading (GtkFileFolder *folder) +{ + /* Since we don't do asynchronous loads, we are always finished loading */ + return TRUE; +} static void free_stat_info_entry (struct stat_info_entry *entry)