diff options
-rw-r--r-- | ChangeLog | 32 | ||||
-rw-r--r-- | libnautilus-private/nautilus-bonobo-extensions.c | 44 | ||||
-rw-r--r-- | libnautilus-private/nautilus-bonobo-extensions.h | 2 | ||||
-rw-r--r-- | libnautilus-private/nautilus-file-private.h | 4 | ||||
-rw-r--r-- | libnautilus-private/nautilus-file.c | 82 | ||||
-rw-r--r-- | libnautilus-private/nautilus-file.h | 7 | ||||
-rw-r--r-- | libnautilus-private/nautilus-mime-actions.c | 122 | ||||
-rw-r--r-- | libnautilus-private/nautilus-mime-actions.h | 1 | ||||
-rw-r--r-- | src/file-manager/fm-directory-view.c | 172 |
9 files changed, 414 insertions, 52 deletions
@@ -1,3 +1,35 @@ +2004-02-23 Dave Camp <dave@ximian.com> + + * libnautilus-private/nautilus-file-private.h: + * libnautilus-private/nautilus-file.h: + * libnautilus-private/nautilus-file.c: (finalize), + (update_info_internal), (nautilus_file_get_guessed_mime_type): + Save the guessed mime type when the sniffed mime type is read. + + (file_list_file_ready_callback): + (nautilus_file_list_call_when_ready): New function. + + * libnautilus-private/nautilus-bonobo-extensions.c: + (nautilus_bonobo_get_extension_item_command_xml), + (nautilus_bonobo_add_extension_item_command): + * libnautilus-private/nautilus-bonobo-extensions.h: + * libnautilus-private/nautilus-mime-actions.c: + (get_open_with_mime_applications), + (nautilus_mime_get_open_with_applications_for_file), + (nautilus_mime_actions_get_popup_file_attributes), + (nautilus_mime_actions_check_if_popup_attributes_ready), + (nautilus_mime_get_popup_components_for_file): + * libnautilus-private/nautilus-mime-actions.h: + * src/file-manager/fm-directory-view.c: + (reset_bonobo_open_with_menu), (get_all_extension_menu_items), + (extension_action_callback_data_free), + (extension_action_slow_mime_types_ready_callback), + (extension_action_callback), (add_extension_command_for_files), + (add_extension_menu_items), + (activate_activation_uri_ready_callback): Don't invoke + extension menu items that don't apply to the sniffed mime + type. + 2004-02-22 Christian Rose <menthos@menthos.com> * configure.in: Added "en_CA" to ALL_LINGUAS. diff --git a/libnautilus-private/nautilus-bonobo-extensions.c b/libnautilus-private/nautilus-bonobo-extensions.c index c9d1946a4..32a665217 100644 --- a/libnautilus-private/nautilus-bonobo-extensions.c +++ b/libnautilus-private/nautilus-bonobo-extensions.c @@ -534,33 +534,45 @@ extension_action_callback (BonoboUIComponent *component, nautilus_menu_item_activate (NAUTILUS_MENU_ITEM (callback_data)); } -void -nautilus_bonobo_add_extension_item_command (BonoboUIComponent *ui, - NautilusMenuItem *item) +char * +nautilus_bonobo_get_extension_item_command_xml (NautilusMenuItem *item) { - GString *ui_xml; - GClosure *closure; char *name; char *label; char *tip; - char *sensitive; - - ui_xml = g_string_new ("<Root><commands>"); + gboolean sensitive; + char *xml; g_object_get (G_OBJECT (item), "name", &name, "label", &label, "tip", &tip, "sensitive", &sensitive, NULL); - g_string_append_printf (ui_xml, - "<cmd name=\"%s\" label=\"%s\" tip=\"%s\" sensitive=\"%s\"/>", - name, label, tip, sensitive ? "1" : "0"); + xml = g_strdup_printf ("<cmd name=\"%s\" label=\"%s\" tip=\"%s\" sensitive=\"%s\"/>", + name, label, tip, sensitive ? "1" : "0"); - ui_xml = g_string_append (ui_xml, "</commands></Root>"); - - bonobo_ui_component_set (ui, "/", ui_xml->str, NULL); - g_string_free (ui_xml, TRUE); + g_free (name); + g_free (label); + g_free (tip); + return xml; +} + +void +nautilus_bonobo_add_extension_item_command (BonoboUIComponent *ui, + NautilusMenuItem *item) +{ + char *xml; + char *name; + GClosure *closure; + + xml = nautilus_bonobo_get_extension_item_command_xml (item); + + bonobo_ui_component_set (ui, "/commands", xml, NULL); + + g_free (xml); + + g_object_get (G_OBJECT (item), "name", &name, NULL); closure = g_cclosure_new (G_CALLBACK (extension_action_callback), @@ -570,8 +582,6 @@ nautilus_bonobo_add_extension_item_command (BonoboUIComponent *ui, bonobo_ui_component_add_verb_full (ui, name, closure); g_free (name); - g_free (label); - g_free (tip); } void diff --git a/libnautilus-private/nautilus-bonobo-extensions.h b/libnautilus-private/nautilus-bonobo-extensions.h index f780761d6..46c985150 100644 --- a/libnautilus-private/nautilus-bonobo-extensions.h +++ b/libnautilus-private/nautilus-bonobo-extensions.h @@ -107,6 +107,8 @@ void nautilus_bonobo_set_icon const char *icon_relative_path); void nautilus_bonobo_add_extension_item_command (BonoboUIComponent *ui, NautilusMenuItem *item); +char *nautilus_bonobo_get_extension_item_command_xml (NautilusMenuItem *item); + void nautilus_bonobo_add_extension_item (BonoboUIComponent *ui, const char *path, NautilusMenuItem *item); diff --git a/libnautilus-private/nautilus-file-private.h b/libnautilus-private/nautilus-file-private.h index f37ad0c0f..b3aba8da5 100644 --- a/libnautilus-private/nautilus-file-private.h +++ b/libnautilus-private/nautilus-file-private.h @@ -83,6 +83,10 @@ struct NautilusFileDetails char *custom_icon; char *activation_uri; + /* The guessed (extension-based) mime type. This is saved for + * comparison vs. the slow mime type upon activation */ + char *guessed_mime_type; + /* The following is for file operations in progress. Since * there are normally only a few of these, we can move them to * a separate hash table or something if required to keep the diff --git a/libnautilus-private/nautilus-file.c b/libnautilus-private/nautilus-file.c index 7bf61fb3e..c1229e35a 100644 --- a/libnautilus-private/nautilus-file.c +++ b/libnautilus-private/nautilus-file.c @@ -490,6 +490,7 @@ finalize (GObject *object) g_free (file->details->relative_uri); g_free (file->details->cached_display_name); g_free (file->details->display_name_collation_key); + g_free (file->details->guessed_mime_type); if (file->details->info != NULL) { gnome_vfs_file_info_unref (file->details->info); } @@ -1421,6 +1422,12 @@ update_info_internal (NautilusFile *file, file->details->file_info_is_up_to_date = TRUE; file->details->got_slow_mime_type = info_has_slow_mime; + + if (!info_has_slow_mime || file->details->guessed_mime_type == NULL) { + g_free (file->details->guessed_mime_type); + file->details->guessed_mime_type = g_strdup (info->mime_type); + } + if (file->details->info != NULL && gnome_vfs_file_info_matches (file->details->info, info)) { return FALSE; @@ -4468,7 +4475,7 @@ nautilus_file_get_deep_directory_count_as_string (NautilusFile *file) * set includes "name", "type", "mime_type", "size", "deep_size", "deep_directory_count", * "deep_file_count", "deep_total_count", "date_modified", "date_changed", "date_accessed", * "date_permissions", "owner", "group", "permissions", "octal_permissions", "uri", "where", - * "link_target", "volume", "free_space". + * "link_target", "volume", "free_space" * * Returns: Newly allocated string ready to display to the user, or NULL * if the value is unknown or @attribute_name is not supported. @@ -4775,6 +4782,27 @@ nautilus_file_get_mime_type (NautilusFile *file) } /** + * nautilus_file_get_guessed_mime_type + * + * Return the mime type that was guessed based on the extension. + * @file: NautilusFile representing the file in question. + * + * Returns: The mime type. + * + **/ +char * +nautilus_file_get_guessed_mime_type (NautilusFile *file) +{ + if (file != NULL) { + g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL); + if (file->details->guessed_mime_type != NULL) { + return g_strdup (file->details->guessed_mime_type); + } + } + return g_strdup (GNOME_VFS_MIME_TYPE_UNKNOWN); +} + +/** * nautilus_file_is_mime_type * * Check whether a file is of a particular MIME type. @@ -5771,6 +5799,58 @@ nautilus_file_list_sort_by_display_name (GList *list) return g_list_sort (list, compare_by_display_name_cover); } +typedef struct +{ + GList *file_list; + GList *remaining_files; + NautilusFileListCallback callback; + gpointer callback_data; +} FileListReadyData; + +static void +file_list_file_ready_callback (NautilusFile *file, + gpointer user_data) +{ + FileListReadyData *data; + + data = user_data; + data->remaining_files = g_list_remove (data->remaining_files, file); + + if (data->remaining_files == NULL) { + if (data->callback) { + (*data->callback) (data->file_list, data->callback_data); + } + + nautilus_file_list_free (data->file_list); + g_free (data); + } +} + +void +nautilus_file_list_call_when_ready (GList *file_list, + NautilusFileAttributes attributes, + NautilusFileListCallback callback, + gpointer callback_data) +{ + GList *l; + FileListReadyData *data; + + g_return_if_fail (file_list != NULL); + + data = g_new0 (FileListReadyData, 1); + data->file_list = nautilus_file_list_copy (file_list); + data->remaining_files = g_list_copy (file_list); + data->callback = callback; + data->callback_data = callback_data; + + for (l = file_list; l != NULL; l = l->next) { + nautilus_file_call_when_ready (NAUTILUS_FILE (l->data), + attributes, + file_list_file_ready_callback, + data); + } +} + static char * try_to_make_utf8 (const char *text, int *length) { diff --git a/libnautilus-private/nautilus-file.h b/libnautilus-private/nautilus-file.h index 14ec51d07..116101580 100644 --- a/libnautilus-private/nautilus-file.h +++ b/libnautilus-private/nautilus-file.h @@ -78,6 +78,8 @@ typedef enum { typedef void (*NautilusFileCallback) (NautilusFile *file, gpointer callback_data); +typedef void (*NautilusFileListCallback) (GList *file_list, + gpointer callback_data); typedef void (*NautilusFileOperationCallback) (NautilusFile *file, GnomeVFSResult result, gpointer callback_data); @@ -135,6 +137,7 @@ char * nautilus_file_get_parent_uri (Nautilu char * nautilus_file_get_parent_uri_for_display (NautilusFile *file); GnomeVFSFileSize nautilus_file_get_size (NautilusFile *file); GnomeVFSFileType nautilus_file_get_file_type (NautilusFile *file); +char * nautilus_file_get_guessed_mime_type (NautilusFile *file); char * nautilus_file_get_mime_type (NautilusFile *file); gboolean nautilus_file_is_mime_type (NautilusFile *file, const char *mime_type); @@ -332,6 +335,10 @@ void nautilus_file_list_unref (GList void nautilus_file_list_free (GList *file_list); GList * nautilus_file_list_copy (GList *file_list); GList * nautilus_file_list_sort_by_display_name (GList *file_list); +void nautilus_file_list_call_when_ready (GList *file_list, + NautilusFileAttributes attributes, + NautilusFileListCallback callback, + gpointer callback_data); /* Debugging */ void nautilus_file_dump (NautilusFile *file); diff --git a/libnautilus-private/nautilus-mime-actions.c b/libnautilus-private/nautilus-mime-actions.c index 30951f14f..1bac22872 100644 --- a/libnautilus-private/nautilus-mime-actions.c +++ b/libnautilus-private/nautilus-mime-actions.c @@ -447,7 +447,6 @@ nautilus_mime_is_default_component_for_file_user_chosen (NautilusFile *file return user_chosen; } - GList * nautilus_mime_get_short_list_applications_for_file (NautilusFile *file) { @@ -513,6 +512,105 @@ nautilus_mime_get_short_list_applications_for_file (NautilusFile *file) return result; } +static GList * +get_open_with_mime_applications (NautilusFile *file) +{ + char *guessed_mime_type; + char *mime_type; + GList *result; + + guessed_mime_type = nautilus_file_get_guessed_mime_type (file); + mime_type = nautilus_file_get_mime_type (file); + + result = gnome_vfs_mime_get_short_list_applications (mime_type); + + if (strcmp (guessed_mime_type, mime_type) != 0) { + GList *result_2; + GList *l; + + result_2 = gnome_vfs_mime_get_short_list_applications (guessed_mime_type); + for (l = result_2; l != NULL; l = l->next) { + if (!g_list_find_custom (result, + ((GnomeVFSMimeApplication*)l->data)->id, + (GCompareFunc) gnome_vfs_mime_application_has_id)) { + result = g_list_prepend (result, l->data); + } + } + g_list_free (result_2); + } + + g_free (mime_type); + g_free (guessed_mime_type); + + return result; +} + +/* Get a list of applications for the Open With menu. This is + * different than nautilus_mime_get_short_list_applications_for_file() + * because this function will merge the lists of the fast and slow + * mime types for the file */ +GList * +nautilus_mime_get_open_with_applications_for_file (NautilusFile *file) +{ + char *uri_scheme; + GList *result; + GList *removed; + GList *metadata_application_add_ids; + GList *metadata_application_remove_ids; + GList *p; + GnomeVFSMimeApplication *application; + + if (!nautilus_mime_actions_check_if_minimum_attributes_ready (file)) { + return NULL; + } + + result = get_open_with_mime_applications (file); + + /* First remove applications that cannot support this location */ + uri_scheme = nautilus_file_get_uri_scheme (file); + g_assert (uri_scheme != NULL); + result = eel_g_list_partition (result, application_supports_uri_scheme, + uri_scheme, &removed); + gnome_vfs_mime_application_list_free (removed); + g_free (uri_scheme); + + metadata_application_add_ids = nautilus_file_get_metadata_list + (file, + NAUTILUS_METADATA_KEY_SHORT_LIST_APPLICATION_ADD, + NAUTILUS_METADATA_SUBKEY_APPLICATION_ID); + metadata_application_remove_ids = nautilus_file_get_metadata_list + (file, + NAUTILUS_METADATA_KEY_SHORT_LIST_APPLICATION_REMOVE, + NAUTILUS_METADATA_SUBKEY_APPLICATION_ID); + + + result = eel_g_list_partition (result, (EelPredicateFunction) gnome_vfs_mime_application_has_id_not_in_list, + metadata_application_remove_ids, &removed); + + gnome_vfs_mime_application_list_free (removed); + + result = g_list_reverse (result); + for (p = metadata_application_add_ids; p != NULL; p = p->next) { + if (g_list_find_custom (result, + p->data, + (GCompareFunc) gnome_vfs_mime_application_has_id) == NULL && + g_list_find_custom (metadata_application_remove_ids, + p->data, + (GCompareFunc) strcmp) == NULL) { + application = gnome_vfs_application_registry_get_mime_application (p->data); + if (application != NULL) { + result = g_list_prepend (result, application); + } + } + } + result = g_list_reverse (result); + + eel_g_list_free_deep (metadata_application_add_ids); + eel_g_list_free_deep (metadata_application_remove_ids); + + return result; +} + static char * build_joined_string (GList *list, const char *prefix, const char *separator, const char *suffix) { @@ -796,6 +894,26 @@ nautilus_mime_get_all_components_for_file_extended (NautilusFile *file, return info_list; } +static NautilusFileAttributes +nautilus_mime_actions_get_popup_file_attributes (void) +{ + return NAUTILUS_FILE_ATTRIBUTE_VOLUMES | + NAUTILUS_FILE_ATTRIBUTE_ACTIVATION_URI | + NAUTILUS_FILE_ATTRIBUTE_MIME_TYPE; +} + +static gboolean +nautilus_mime_actions_check_if_popup_attributes_ready (NautilusFile *file) +{ + NautilusFileAttributes attributes; + gboolean ready; + + attributes = nautilus_mime_actions_get_popup_file_attributes (); + ready = nautilus_file_check_if_ready (file, attributes); + + return ready; +} + GList * nautilus_mime_get_popup_components_for_file (NautilusFile *file) { @@ -805,7 +923,7 @@ nautilus_mime_get_popup_components_for_file (NautilusFile *file) GList *item_mime_types; GList *info_list; - if (!nautilus_mime_actions_check_if_minimum_attributes_ready (file)) { + if (!nautilus_mime_actions_check_if_popup_attributes_ready (file)) { return NULL; } diff --git a/libnautilus-private/nautilus-mime-actions.h b/libnautilus-private/nautilus-mime-actions.h index b4736cf40..685534f4f 100644 --- a/libnautilus-private/nautilus-mime-actions.h +++ b/libnautilus-private/nautilus-mime-actions.h @@ -40,6 +40,7 @@ gboolean nautilus_mime_is_default_application_for_file_user_chos Bonobo_ServerInfo * nautilus_mime_get_default_component_for_file (NautilusFile *file); gboolean nautilus_mime_is_default_component_for_file_user_chosen (NautilusFile *file); GList * nautilus_mime_get_short_list_applications_for_file (NautilusFile *file); +GList * nautilus_mime_get_open_with_applications_for_file (NautilusFile *file); GList * nautilus_mime_get_short_list_components_for_file (NautilusFile *file); GList * nautilus_mime_get_all_applications_for_file (NautilusFile *file); GList * nautilus_mime_get_all_components_for_file (NautilusFile *file); diff --git a/src/file-manager/fm-directory-view.c b/src/file-manager/fm-directory-view.c index aacae0a39..3fd1a6649 100644 --- a/src/file-manager/fm-directory-view.c +++ b/src/file-manager/fm-directory-view.c @@ -3718,7 +3718,7 @@ reset_bonobo_open_with_menu (FMDirectoryView *view, GList *selection) uri = nautilus_file_get_uri (file); - applications = nautilus_mime_get_short_list_applications_for_file (NAUTILUS_FILE (selection->data)); + applications = nautilus_mime_get_open_with_applications_for_file (NAUTILUS_FILE (selection->data)); for (node = applications, index = 0; node != NULL; node = node->next, index++) { any_applications = TRUE; add_application_to_bonobo_menu (view, node->data, file, index); @@ -3744,6 +3744,141 @@ reset_bonobo_open_with_menu (FMDirectoryView *view, GList *selection) sensitive); } +static GList * +get_all_extension_menu_items (GtkWidget *window, + GList *selection) +{ + GList *items; + GList *providers; + GList *l; + + providers = nautilus_module_get_extensions_for_type (NAUTILUS_TYPE_MENU_PROVIDER); + items = NULL; + + for (l = providers; l != NULL; l = l->next) { + NautilusMenuProvider *provider; + GList *file_items; + + provider = NAUTILUS_MENU_PROVIDER (l->data); + file_items = nautilus_menu_provider_get_file_items (provider, + window, + selection); + items = g_list_concat (items, file_items); + } + + nautilus_module_extension_list_free (providers); + + return items; +} + +typedef struct +{ + NautilusMenuItem *item; + FMDirectoryView *view; + GList *selection; +} ExtensionActionCallbackData; + +static void +extension_action_callback_data_free (ExtensionActionCallbackData *data) +{ + g_object_unref (data->item); + nautilus_file_list_free (data->selection); + + g_free (data); +} + +static void +extension_action_slow_mime_types_ready_callback (GList *selection, + gpointer callback_data) +{ + ExtensionActionCallbackData *data; + char *item_name; + gboolean is_valid; + GList *l; + GList *items; + + data = callback_data; + + /* Make sure the selected menu item is valid for the final sniffed + * mime type */ + g_object_get (data->item, "name", &item_name, NULL); + items = get_all_extension_menu_items (gtk_widget_get_toplevel (GTK_WIDGET (data->view)), + data->selection); + + is_valid = FALSE; + for (l = items; l != NULL; l = l->next) { + char *name; + + g_object_get (l->data, "name", &name, NULL); + + if (strcmp (name, item_name)) { + is_valid = TRUE; + g_free (name); + break; + } + g_free (name); + } + + for (l = items; l != NULL; l = l->next) { + g_object_unref (l->data); + } + g_list_free (items); + + g_free (item_name); + + if (is_valid) { + nautilus_menu_item_activate (data->item); + } +} + +static void +extension_action_callback (BonoboUIComponent *component, + gpointer callback_data, const char *path) +{ + ExtensionActionCallbackData *data; + + data = callback_data; + + nautilus_file_list_call_when_ready + (data->selection, + NAUTILUS_FILE_ATTRIBUTE_SLOW_MIME_TYPE, + extension_action_slow_mime_types_ready_callback, + callback_data); +} + +static void +add_extension_command_for_files (FMDirectoryView *view, + NautilusMenuItem *item, + GList *files) +{ + char *xml; + char *name; + ExtensionActionCallbackData *data; + GClosure *closure; + + xml = nautilus_bonobo_get_extension_item_command_xml (item); + + bonobo_ui_component_set (view->details->ui, "/commands", xml, NULL); + + g_free (xml); + + g_object_get (G_OBJECT (item), "name", &name, NULL); + + data = g_new0 (ExtensionActionCallbackData, 1); + data->item = g_object_ref (item); + data->view = view; + data->selection = nautilus_file_list_copy (files); + + closure = g_cclosure_new + (G_CALLBACK (extension_action_callback), + data, + (GClosureNotify)extension_action_callback_data_free); + + bonobo_ui_component_add_verb_full (view->details->ui, name, closure); + + g_free (name); +} + static void add_extension_menu_items (FMDirectoryView *view, GList *files, @@ -3755,8 +3890,7 @@ add_extension_menu_items (FMDirectoryView *view, item = NAUTILUS_MENU_ITEM (l->data); - nautilus_bonobo_add_extension_item_command (view->details->ui, - item); + add_extension_command_for_files (view, item, files); nautilus_bonobo_add_extension_item (view->details->ui, FM_DIRECTORY_VIEW_POPUP_PATH_EXTENSION_ACTIONS, @@ -3808,32 +3942,6 @@ get_unique_files (GList *selection) return g_list_reverse (result); } -static GList * -get_all_extension_menu_items (GtkWidget *window, - GList *selection) -{ - GList *items; - GList *providers; - GList *l; - - providers = nautilus_module_get_extensions_for_type (NAUTILUS_TYPE_MENU_PROVIDER); - items = NULL; - - for (l = providers; l != NULL; l = l->next) { - NautilusMenuProvider *provider; - GList *file_items; - - provider = NAUTILUS_MENU_PROVIDER (l->data); - file_items = nautilus_menu_provider_get_file_items (provider, - window, - selection); - items = g_list_concat (items, file_items); - } - - nautilus_module_extension_list_free (providers); - - return items; -} static void reset_extension_actions_menu (FMDirectoryView *view, GList *selection) @@ -5769,7 +5877,6 @@ can_use_component_for_file (FMDirectoryView *view, nautilus_view_get_window_type (view->details->nautilus_view) == Nautilus_WINDOW_NAVIGATION); } - static void activate_callback (NautilusFile *file, gpointer callback_data) { @@ -5940,8 +6047,9 @@ activate_activation_uri_ready_callback (NautilusFile *file, gpointer callback_da /* get the parameters for the actual file */ attributes = nautilus_mime_actions_get_minimum_file_attributes () | - NAUTILUS_FILE_ATTRIBUTE_FILE_TYPE | - NAUTILUS_FILE_ATTRIBUTE_ACTIVATION_URI; + NAUTILUS_FILE_ATTRIBUTE_FILE_TYPE | + NAUTILUS_FILE_ATTRIBUTE_SLOW_MIME_TYPE | + NAUTILUS_FILE_ATTRIBUTE_ACTIVATION_URI; parameters->file = actual_file; parameters->callback = activate_callback; |