diff options
Diffstat (limited to 'capplets/file-types')
26 files changed, 1788 insertions, 575 deletions
diff --git a/capplets/file-types/.cvsignore b/capplets/file-types/.cvsignore index 7ef4ea673..5ec9e2d05 100644 --- a/capplets/file-types/.cvsignore +++ b/capplets/file-types/.cvsignore @@ -2,4 +2,5 @@ Makefile Makefile.in .deps .libs -nautilus-mime-type-capplet +file-types-capplet +file-types-capplet.desktop diff --git a/capplets/file-types/Makefile.am b/capplets/file-types/Makefile.am index 8b2afcdcd..14faaa9e1 100644 --- a/capplets/file-types/Makefile.am +++ b/capplets/file-types/Makefile.am @@ -1,6 +1,10 @@ -INCLUDES = -I. \ - -I$(top_srcdir) \ - -I$(srcdir) \ +NULL = + +SUBDIRS = libuuid + +INCLUDES = -I. \ + -I$(top_srcdir) \ + -I$(srcdir) \ -I$(top_srcdir)/intl -I$(top_builddir)/intl \ -I$(top_srcdir)/libgnomevfs \ $(CAPPLET_INCLUDEDIR) \ @@ -9,36 +13,49 @@ INCLUDES = -I. \ $(GTK_CFLAGS) \ -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \ -I$(includedir) \ - $(VFS_CFLAGS) $(WERROR) + $(VFS_CFLAGS) $(WERROR) \ + $(NULL) -bin_PROGRAMS = nautilus-mime-type-capplet -nautilus_mime_type_capplet_SOURCES = \ +bin_PROGRAMS = file-types-capplet + +file_types_capplet_SOURCES = \ nautilus-mime-type-capplet.h \ nautilus-mime-type-capplet-dialogs.h \ nautilus-mime-type-icon-entry.h \ nautilus-mime-type-capplet.c \ nautilus-mime-type-capplet-dialogs.c \ - nautilus-mime-type-icon-entry.c + nautilus-mime-type-icon-entry.c \ + $(NULL) + -nautilus_mime_type_capplet_LDADD = \ +file_types_capplet_LDADD = \ $(CAPPLET_LIBDIR) \ $(CAPPLET_LIBS) \ $(ORBIT_LIBS) \ $(OAF_LIBS) \ $(INTLLIBS) \ $(top_builddir)/libgnomevfs/libgnomevfs.la \ - -lgdk_pixbuf + -lgdk_pixbuf \ + $/libuuid/libuuid.a \ + $(NULL) -sysdir = $(datadir)/control-center -sys_DATA = nautilus-mime-type.desktop +sysdir = $(datadir)/control-center/Documents +sys_in_files = file-types-capplet.desktop.in +sys_DATA = $(sys_in_files:.desktop.in=.desktop) settingsdir = $(datadir)/gnome/apps/Settings -settings_DATA = nautilus-mime-type.desktop +settings_DATA = $(sys_DATA) + +desktop_in_file = file-types-capplet.desktop.in + +desktop_file = $(desktop_in_file:.desktop.in=.desktop) + +@XML_I18N_MERGE_DESKTOP_RULE@ EXTRA_DIST = \ - $(sys_DATA) + $(sys_DATA) $(desktop_in_file) diff --git a/capplets/file-types/file-types-capplet-dialogs.c b/capplets/file-types/file-types-capplet-dialogs.c index 8af403ea7..c554c72b1 100644 --- a/capplets/file-types/file-types-capplet-dialogs.c +++ b/capplets/file-types/file-types-capplet-dialogs.c @@ -35,7 +35,9 @@ #include <libgnomevfs/gnome-vfs-mime-handlers.h> #include <libgnomevfs/gnome-vfs-application-registry.h> #include <libgnomevfs/gnome-vfs-mime-info.h> +#include <libgnomevfs/gnome-vfs-utils.h> +#include "libuuid/uuid.h" #include "nautilus-mime-type-capplet.h" #include "nautilus-mime-type-capplet-dialogs.h" @@ -67,7 +69,8 @@ static edit_dialog_details *edit_component_details = NULL; static void show_new_application_window (GtkWidget *button, GtkWidget *list); static void show_edit_application_window (GtkWidget *button, GtkWidget *list); static void delete_selected_application (GtkWidget *button, GtkWidget *list); -static void add_item_to_application_list (GtkWidget *list, const char *name, const char *mime_type, int position); +static void add_item_to_application_list (GtkWidget *list, const char *id, const char *name, const char *mime_type, + gboolean user_owned, int position); static void find_message_label_callback (GtkWidget *widget, gpointer callback_data); static void find_message_label (GtkWidget *widget, const char *message); @@ -139,12 +142,73 @@ application_button_toggled_callback (GtkToggleButton *button, gpointer user_data } static void +insert_item (GtkList *list_widget, GtkListItem *item, int position) +{ + GList *singleton_list; + + g_assert (GTK_IS_LIST (list_widget)); + g_assert (GTK_IS_LIST_ITEM (item)); + + /* Due to GTK inheritance stupidity, the "Add" signal, which we + * rely on for widget sensitivity updates, is not sent if you + * use the GtkList API to add items. So when we add new items, + * which always go at the end, we must use the GtkContainer API. + */ + if (position < 0) { + gtk_container_add (GTK_CONTAINER (list_widget), GTK_WIDGET (item)); + } else { + singleton_list = g_list_prepend (NULL, item); + gtk_list_insert_items (list_widget, singleton_list, position); + /* This looks like a leak of a singleton_list, but believe it or not + * gtk_list takes ownership of the list of items. + */ + } +} + +static GtkListItem * +create_application_list_item (const char *id, const char *name, const char *mime_type, + gboolean user_owned, GList *short_list) +{ + GtkWidget *list_item; + GtkWidget *hbox, *check_button, *label; + + list_item = gtk_list_item_new (); + + hbox = gtk_hbox_new (FALSE, GNOME_PAD_SMALL); + gtk_container_add (GTK_CONTAINER (list_item), hbox); + + check_button = gtk_check_button_new (); + gtk_box_pack_start (GTK_BOX (hbox), check_button, FALSE, FALSE, 0); + + label = gtk_label_new (name); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + + gtk_widget_show_all (list_item); + + /* Save ID and mime type*/ + gtk_object_set_data_full (GTK_OBJECT (check_button), "application_id", g_strdup (id), g_free); + gtk_object_set_data_full (GTK_OBJECT (check_button), "mime_type", g_strdup (mime_type), g_free); + gtk_object_set_data_full (GTK_OBJECT (list_item), "application_id", g_strdup (id), g_free); + gtk_object_set_data_full (GTK_OBJECT (list_item), "mime_type", g_strdup (mime_type), g_free); + gtk_object_set_data (GTK_OBJECT (list_item), "user_owned", GINT_TO_POINTER(user_owned)); + + /* Check and see if component is in preferred list */ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), + application_is_in_list (id, short_list)); + + /* Connect to toggled signal */ + gtk_signal_connect (GTK_OBJECT (check_button), "toggled", + GTK_SIGNAL_FUNC (application_button_toggled_callback), NULL); + + return GTK_LIST_ITEM (list_item); +} + +static void populate_default_applications_list (GtkWidget *list, const char *mime_type) { GList *short_list, *app_list, *list_element; GnomeVFSMimeApplication *application; - GtkWidget *button, *list_item; - GtkWidget *hbox, *label; + GtkListItem *list_item; /* Get the application short list */ short_list = gnome_vfs_mime_get_short_list_applications (mime_type); @@ -156,43 +220,20 @@ populate_default_applications_list (GtkWidget *list, const char *mime_type) application = list_element->data; /* Create list item */ - list_item = gtk_list_item_new (); - - /* Create check button */ - hbox = gtk_hbox_new (FALSE, GNOME_PAD_SMALL); - gtk_container_add (GTK_CONTAINER (list_item), hbox); - - button = gtk_check_button_new (); - gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); - - label = gtk_label_new (application->name); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - - /* Add list item to list */ - gtk_container_add (GTK_CONTAINER (list), list_item); + list_item = create_application_list_item (application->id, application->name, + mime_type, + gnome_vfs_application_is_user_owned_application (application), + short_list); - /* Save ID and mime type*/ - gtk_object_set_data_full (GTK_OBJECT (button), "application_id", g_strdup (application->id), g_free); - gtk_object_set_data_full (GTK_OBJECT (button), "mime_type", g_strdup (mime_type), g_free); - gtk_object_set_data_full (GTK_OBJECT (list_item), "application_id", g_strdup (application->id), g_free); - gtk_object_set_data_full (GTK_OBJECT (list_item), "mime_type", g_strdup (mime_type), g_free); + insert_item (GTK_LIST (list), list_item, -1); - /* Check and see if component is in preferred list */ - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), - application_is_in_list (application->id, short_list)); - - /* Connect to toggled signal */ - gtk_signal_connect (GTK_OBJECT (button), "toggled", - GTK_SIGNAL_FUNC (application_button_toggled_callback), NULL); - } + } gnome_vfs_mime_application_list_free (app_list); } - if (short_list != NULL) { - gnome_vfs_mime_application_list_free (short_list); - } + gnome_vfs_mime_application_list_free (short_list); } @@ -314,11 +355,17 @@ check_button_status (GtkList *list, GtkWidget *widget, ButtonHolder *button_hold gtk_widget_set_sensitive (button_holder->delete_button, FALSE); gtk_widget_set_sensitive (button_holder->edit_button, FALSE); } else { - gtk_widget_set_sensitive (button_holder->delete_button, TRUE); gtk_widget_set_sensitive (button_holder->edit_button, TRUE); } } +static void +update_delete_button (GtkList *list, GtkWidget *widget, ButtonHolder *button_holder) +{ + gtk_widget_set_sensitive (button_holder->delete_button, + GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (widget), "user_owned"))); +} + /* * initialize_edit_applications_dialog @@ -342,6 +389,8 @@ initialize_edit_applications_dialog (const char *mime_type) NULL, NULL); + /* FIXME: dialog should be parented on Control Center window */ + gtk_container_set_border_width (GTK_CONTAINER (edit_application_details->window), GNOME_PAD); gtk_window_set_policy (GTK_WINDOW (edit_application_details->window), FALSE, TRUE, FALSE); gtk_window_set_default_size (GTK_WINDOW (edit_application_details->window), @@ -357,7 +406,7 @@ initialize_edit_applications_dialog (const char *mime_type) main_vbox = GNOME_DIALOG (edit_application_details->window)->vbox; /* Add label */ - label_text = g_strdup_printf (_("Select applications to appear in menu for mime type \"%s\""), mime_type); + label_text = g_strdup_printf (_("Select applications to appear in menu for MIME type \"%s\""), mime_type); label = gtk_label_new (label_text); g_free (label_text); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); @@ -403,11 +452,12 @@ initialize_edit_applications_dialog (const char *mime_type) /* Watch container so we can update buttons */ gtk_signal_connect (GTK_OBJECT (list), "add", check_button_status, button_holder); gtk_signal_connect_full (GTK_OBJECT (list), "remove", check_button_status, NULL, button_holder, - g_free, FALSE, FALSE); + g_free, FALSE, FALSE); + gtk_signal_connect (GTK_OBJECT (list), "select_child", update_delete_button, button_holder); - populate_default_applications_list (list, mime_type); - gtk_widget_show_all (main_vbox); + + populate_default_applications_list (list, mime_type); } @@ -447,7 +497,7 @@ initialize_edit_components_dialog (const char *mime_type) main_vbox = GNOME_DIALOG (edit_component_details->window)->vbox; /* Add label */ - label_text = g_strdup_printf (_("Select views to appear in menu for mime type \"%s\""), mime_type); + label_text = g_strdup_printf (_("Select views to appear in menu for MIME type \"%s\""), mime_type); label = gtk_label_new (label_text); g_free (label_text); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); @@ -482,19 +532,13 @@ show_edit_applications_dialog (const char *mime_type) if (edit_application_details == NULL) { initialize_edit_applications_dialog (mime_type); } - - switch(gnome_dialog_run (GNOME_DIALOG (edit_application_details->window))) { - case 0: - nautilus_mime_type_capplet_update_application_info (mime_type); - /* Delete the dialog so the lists are repopulated on next lauch */ - gtk_widget_destroy (edit_application_details->window); - break; - - case 1: - /* Delete the dialog so the lists are repopulated on next lauch */ - gtk_widget_destroy (edit_application_details->window); - break; - } + + /* FIXME: This is a modal dialog with no Cancel button, so the close box + * has to do the same thing as the OK button, which is pretty darn confusing. + * It would be better to make it modeless someday. + */ + gnome_dialog_run_and_close (GNOME_DIALOG (edit_application_details->window)); + nautilus_mime_type_capplet_update_application_info (mime_type); } @@ -511,18 +555,13 @@ show_edit_components_dialog (const char *mime_type) initialize_edit_components_dialog (mime_type); } - switch(gnome_dialog_run (GNOME_DIALOG (edit_component_details->window))) { - case 0: - nautilus_mime_type_capplet_update_viewer_info (mime_type); - /* Delete the dialog so the lists are repopulated on next lauch */ - gtk_widget_destroy (edit_component_details->window); - break; - - case 1: - /* Delete the dialog so the lists are repopulated on next lauch */ - gtk_widget_destroy (edit_component_details->window); - break; - } + /* FIXME: This is a modal dialog with no Cancel button, so the close box + * has to do the same thing as the OK button, which is pretty darn confusing. + * It would be better to make it modeless someday. + */ + gnome_dialog_run_and_close (GNOME_DIALOG (edit_component_details->window)); + + nautilus_mime_type_capplet_update_viewer_info (mime_type); } @@ -688,6 +727,30 @@ display_upper_case_dialog (void) gnome_dialog_run_and_close (dialog); } +/* Do some basic validation of the text entry and enable the OK button if the text is + * determined to be a valid string. + */ +static void +validate_text_and_update_button (GtkEntry *entry, gpointer data) +{ + char *text, *token; + gboolean sensitize; + + sensitize = TRUE; + + text = gtk_entry_get_text (entry); + if (text == NULL) { + sensitize = FALSE; + } else { + token = strtok (text, " "); + if (token == NULL || strlen (token) <= 0) { + /* Entered text is invalid as best as we can detect. */ + sensitize = FALSE; + } + } + + gtk_widget_set_sensitive (GTK_WIDGET (data), sensitize); +} char * nautilus_mime_type_capplet_show_new_mime_window (void) @@ -696,8 +759,6 @@ nautilus_mime_type_capplet_show_new_mime_window (void) GtkWidget *mime_entry; GtkWidget *label; GtkWidget *desc_entry; - GtkWidget *hbox; - GtkWidget *vbox; const char *description; char *mime_type, *tmp_str, c; gboolean upper_case_alert; @@ -705,70 +766,62 @@ nautilus_mime_type_capplet_show_new_mime_window (void) mime_type = NULL; upper_case_alert = FALSE; - dialog = gnome_dialog_new (_("Add Mime Type"), GNOME_STOCK_BUTTON_OK, + dialog = gnome_dialog_new (_("Add MIME Type"), GNOME_STOCK_BUTTON_OK, GNOME_STOCK_BUTTON_CANCEL, NULL); gnome_dialog_set_default (GNOME_DIALOG (dialog), 1); - label = gtk_label_new (_("Add a new Mime Type\n" - "For example: image/tiff; text/x-scheme")); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - hbox = gtk_hbox_new (FALSE, GNOME_PAD_SMALL); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox), hbox, FALSE, FALSE, 0); - label = gtk_label_new (_("Mime Type:")); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - hbox = gtk_hbox_new (FALSE, GNOME_PAD_SMALL); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + + label = gtk_label_new (_("New MIME type (e.g. image/x-thumper):")); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox), label, TRUE, TRUE, 0); + mime_entry = gtk_entry_new (); - gtk_box_pack_start (GTK_BOX (hbox), mime_entry, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox), hbox, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox), mime_entry, TRUE, TRUE, 0); - - vbox = gtk_vbox_new (FALSE, GNOME_PAD_SMALL); - gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox), vbox, FALSE, FALSE, 0); - gtk_container_set_border_width (GTK_CONTAINER (vbox), GNOME_PAD_SMALL); - label = gtk_label_new (_("Type in a description for this mime-type.")); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - hbox = gtk_hbox_new (FALSE, GNOME_PAD_SMALL); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); - hbox = gtk_hbox_new (FALSE, GNOME_PAD_SMALL); - gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new (_("Description:")), FALSE, FALSE, 0); + label = gtk_label_new (_("Description (e.g. Thumper image):")); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox), label, TRUE, TRUE, 0); + desc_entry = gtk_entry_new (); - gtk_box_pack_start (GTK_BOX (hbox), desc_entry, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox), desc_entry, TRUE, TRUE, 0); + /* Set up text entry validation signal */ + gtk_signal_connect (GTK_OBJECT (mime_entry), "changed", + GTK_SIGNAL_FUNC (validate_text_and_update_button), GNOME_DIALOG (dialog)->buttons->data); - gnome_dialog_set_close (GNOME_DIALOG (dialog), FALSE); + /* Set initial OK button state to desensitized */ + gtk_widget_set_sensitive (GTK_WIDGET (GNOME_DIALOG (dialog)->buttons->data), FALSE); + + /* Set focus to text entry widget */ + gtk_widget_grab_focus (mime_entry); gtk_widget_show_all (GNOME_DIALOG (dialog)->vbox); - switch (gnome_dialog_run (GNOME_DIALOG (dialog))) { - case 0: - mime_type = g_strdup (gtk_entry_get_text (GTK_ENTRY (mime_entry))); - g_assert (mime_type != NULL); - - /* Handle illegal mime types as best we can */ - for (tmp_str = mime_type; (c = *tmp_str) != '\0'; tmp_str++) { - if (isascii (c) && isupper (c)) { - *tmp_str = tolower (c); - upper_case_alert = TRUE; - } - } - - description = gtk_entry_get_text (GTK_ENTRY (desc_entry)); - - /* Add new mime type here */ - if (strlen (mime_type) > 3) { - gnome_vfs_mime_set_value (mime_type, - "description", - description); + if (gnome_dialog_run (GNOME_DIALOG (dialog)) == GNOME_OK) { + mime_type = g_strdup (gtk_entry_get_text (GTK_ENTRY (mime_entry))); + g_assert (mime_type != NULL); + + /* Handle illegal mime types as best we can */ + for (tmp_str = mime_type; (c = *tmp_str) != '\0'; tmp_str++) { + if (isascii ((guchar) c) && isupper ((guchar) c)) { + *tmp_str = tolower (c); + upper_case_alert = TRUE; } - /* Fall through to close dialog */ - break; - - case 1: - default: - break; + } + + description = gtk_entry_get_text (GTK_ENTRY (desc_entry)); + + /* Add new mime type here */ + if (strlen (mime_type) > 3) { + /* This call creates the key */ + gnome_vfs_mime_set_registered_type_key (mime_type, + "description", + description); + + /* Ths call sets the user information */ + gnome_vfs_mime_set_value (mime_type, + "description", + description); + } } gnome_dialog_close (GNOME_DIALOG (dialog)); @@ -793,6 +846,13 @@ add_extension_clicked (GtkWidget *widget, gpointer data) extension_list = GTK_LIST (data); new_extension = nautilus_mime_type_capplet_show_new_extension_window (); + + /* Filter out bogus extensions */ + if (new_extension == NULL || strlen (new_extension) <= 0 || new_extension[0] == ' ') { + g_free (new_extension); + return; + } + new_list_item = gtk_list_item_new_with_label (new_extension); gtk_widget_show (new_list_item); @@ -874,14 +934,16 @@ get_extensions_from_gtk_list (GtkList *list) } char * -nautilus_mime_type_capplet_show_change_extension_window (const char *mime_type) +nautilus_mime_type_capplet_show_change_extension_window (const char *mime_type, gboolean *new_list) { GtkWidget *dialog; GtkWidget *hbox; GtkWidget *button; GtkWidget *list; - char *extensions_list; + char *extensions_list_str; + *new_list = FALSE; + dialog = gnome_dialog_new (_("File Extensions "), GNOME_STOCK_BUTTON_OK, GNOME_STOCK_BUTTON_CANCEL, @@ -933,7 +995,6 @@ nautilus_mime_type_capplet_show_change_extension_window (const char *mime_type) extensions_list = gnome_vfs_mime_get_extensions_list (mime_type); - if (extensions_list != NULL) { widget_list = NULL; for (temp = extensions_list; temp != NULL; temp = temp->next) { @@ -950,22 +1011,21 @@ nautilus_mime_type_capplet_show_change_extension_window (const char *mime_type) gtk_widget_show_all (GNOME_DIALOG (dialog)->vbox); - switch (gnome_dialog_run (GNOME_DIALOG (dialog))) { - case 0: - extensions_list = get_extensions_from_gtk_list (GTK_LIST (list)); - if (extensions_list == NULL) { - extensions_list = g_strdup (""); - } - break; - case 1: - default: - extensions_list = g_strdup (""); - break; - } + extensions_list_str = NULL; + if (gnome_dialog_run (GNOME_DIALOG (dialog)) == GNOME_OK) { + *new_list = TRUE; + extensions_list_str = get_extensions_from_gtk_list (GTK_LIST (list)); + if (extensions_list_str == NULL) { + extensions_list_str = g_strdup (""); + } + } + if (extensions_list_str == NULL) { + extensions_list_str = g_strdup (""); + } gnome_dialog_close (GNOME_DIALOG (dialog)); - return extensions_list; + return extensions_list_str; } @@ -982,7 +1042,9 @@ nautilus_mime_type_capplet_show_new_extension_window (void) GNOME_STOCK_BUTTON_CANCEL, NULL); gnome_dialog_set_default (GNOME_DIALOG (dialog), 0); gnome_dialog_set_close (GNOME_DIALOG (dialog), FALSE); - label = gtk_label_new (_("Type in the extensions for this mime-type.\nFor example: .html, .htm")); + label = gtk_label_new (_("Type in the extensions for this mime-type (without dot).\n" + "You can enter several extensions seperated by a space,\n" + "for example: html htm")); gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); hbox = gtk_hbox_new (FALSE, GNOME_PAD_SMALL); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); @@ -998,17 +1060,13 @@ nautilus_mime_type_capplet_show_new_extension_window (void) gtk_widget_show_all (GNOME_DIALOG (dialog)->vbox); /* Set focus to text entry widget */ - gtk_window_set_focus (GTK_WINDOW (dialog), mime_entry); + gtk_widget_grab_focus (mime_entry); - new_extension = g_strdup (""); - switch (gnome_dialog_run (GNOME_DIALOG (dialog))) { - case 0: - new_extension = g_strdup (gtk_entry_get_text (GTK_ENTRY (mime_entry))); - case 1: - break; - default: - break; - } + if (gnome_dialog_run (GNOME_DIALOG (dialog)) == GNOME_OK) { + new_extension = g_strdup (gtk_entry_get_text (GTK_ENTRY (mime_entry))); + } else { + new_extension = g_strdup (""); + } gnome_dialog_close (GNOME_DIALOG (dialog)); @@ -1020,17 +1078,19 @@ nautilus_mime_type_capplet_show_new_extension_window (void) * Create or update a GnomeVFSMimeApplication and register * it with the mime database. */ -static void +static char * add_or_update_application (GtkWidget *list, const char *name, const char *command, gboolean multiple, gboolean expects_uris, gboolean update) { GnomeVFSMimeApplication app, *original; const char *mime_type; - + uuid_t app_uuid; + char app_uuid_string[100]; + /* Check for empty strings. Command can be empty. */ if (name[0] == '\0') { - return; + return NULL; } mime_type = nautilus_mime_type_capplet_get_selected_item_mime_type (); @@ -1039,7 +1099,11 @@ add_or_update_application (GtkWidget *list, const char *name, const char *comman /* It's ok to cast, we don't modify the application * structure and thus the name/command, this should really * use the application registry explicitly */ - app.id = (char *)name; + + /* Generate unique application id */ + uuid_generate(app_uuid); + uuid_unparse(app_uuid, app_uuid_string); + app.id = app_uuid_string; app.name = (char *)name; app.command = (char *)command; app.can_open_multiple_files = multiple; @@ -1049,7 +1113,7 @@ add_or_update_application (GtkWidget *list, const char *name, const char *comman app.requires_terminal = FALSE; if (update) { - original = gnome_vfs_mime_application_new_from_id (name); + original = gnome_vfs_mime_application_new_from_id (app.id); if (original == NULL) { const char *original_id; GList *selection; @@ -1059,20 +1123,20 @@ add_or_update_application (GtkWidget *list, const char *name, const char *comman /* If there isn't a selection we cannot allow an edit */ selection = GTK_LIST (list)->selection; if (selection == NULL || g_list_length (selection) <= 0) { - return; + return NULL; } /* Get application id and info */ item = GTK_LIST_ITEM (selection->data); if (item == NULL) { - return; + return NULL; } original_id = gtk_object_get_data (GTK_OBJECT (item), "application_id"); if (original_id == NULL) { - return; + return NULL; } - + /* Remove original application data */ gnome_vfs_application_registry_remove_mime_type (original_id, mime_type); gnome_vfs_application_registry_sync (); @@ -1083,77 +1147,122 @@ add_or_update_application (GtkWidget *list, const char *name, const char *comman gtk_container_remove (GTK_CONTAINER (list), GTK_WIDGET (item)); /* Add new widget and restore position */ - add_item_to_application_list (list, name, mime_type, position); + add_item_to_application_list (list, original_id, name, mime_type, + gnome_vfs_application_is_user_owned_application (original), + position); } } gnome_vfs_application_registry_save_mime_application (&app); - gnome_vfs_application_registry_add_mime_type (name, mime_type); + gnome_vfs_application_registry_add_mime_type (app.id, mime_type); gnome_vfs_application_registry_sync (); gnome_vfs_mime_add_application_to_short_list (mime_type, app.id); + + return g_strdup (app.id); } static void -add_item_to_application_list (GtkWidget *list, const char *name, const char *mime_type, int position) +add_item_to_application_list (GtkWidget *list, const char *id, const char *name, const char *mime_type, + gboolean user_owned, int position) { - GtkWidget *check_button, *list_item, *hbox, *label; - - /* Create list item */ - list_item = gtk_list_item_new (); - - /* Create check button */ - hbox = gtk_hbox_new (FALSE, GNOME_PAD_SMALL); - gtk_container_add (GTK_CONTAINER (list_item), hbox); - - check_button = gtk_check_button_new (); - gtk_box_pack_start (GTK_BOX (hbox), check_button, FALSE, FALSE, 0); + GtkListItem *list_item; + GList *short_list; - label = gtk_label_new (name); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - - /* Add list item to list */ - if (position == -1) { - gtk_container_add (GTK_CONTAINER (list), list_item); - } else { - GList *items; - items = g_list_alloc (); - items->data = list_item; - gtk_list_insert_items (GTK_LIST (list), items, position); - gtk_list_select_child (GTK_LIST (list), list_item); + short_list = gnome_vfs_mime_get_short_list_applications (mime_type); + list_item = create_application_list_item (id, name, mime_type, user_owned, short_list); + gnome_vfs_mime_application_list_free (short_list); + + insert_item (GTK_LIST (list), list_item, position); + gtk_list_select_child (GTK_LIST (list), GTK_WIDGET (list_item)); +} + +static gboolean +handle_invalid_application_input (GtkWindow *parent_window, const char *name, const char *command) +{ + char *message; + char *stripped_name; + GnomeDialog *error_dialog; + gboolean error_in_name; + + message = NULL; + error_in_name = FALSE; + + stripped_name = g_strstrip (g_strdup (name)); + + if (strlen (stripped_name) == 0) { + message = g_strdup (_("You must enter a name.")); + error_in_name = TRUE; + } else if (strlen (command) == 0) { + message = g_strdup (_("You must enter a command.")); + } else if (!gnome_vfs_is_executable_command_string (command)) { + if (command[0] == '/') { + /* FIXME: Should strip parameters off before using in this message. */ + /* FIXME: Should use separate messages for doesn't exist/isn't executable. */ + /* Both of these FIXMEs would need to handle quoting to work correctly, + * since otherwise a space might be part of path or separator before parameters. + */ + /* FIXME: Should use some line-wrapping technology a la nautilus-stock-dialogs.c */ + message = g_strdup_printf + (_("\"%s\" does not exist or is not executable.\n" + "Check your spelling and make sure you have\n" + "the right permissions to execute this file."), command); + } else { + /* FIXME: Should strip parameters off before using in this message */ + message = g_strdup_printf + (_("The command \"%s\" cannot be found.\n" + "You must use a command that can work from any command line."), command); + } } - - gtk_widget_show_all (list); - - /* Save ID and mime type*/ - gtk_object_set_data_full (GTK_OBJECT (check_button), "application_id", g_strdup (name), g_free); - gtk_object_set_data_full (GTK_OBJECT (check_button), "mime_type", g_strdup (mime_type), g_free); - gtk_object_set_data_full (GTK_OBJECT (list_item), "application_id", g_strdup (name), g_free); - gtk_object_set_data_full (GTK_OBJECT (list_item), "mime_type", g_strdup (mime_type), g_free); - /* Check and see if component is in preferred list */ - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), TRUE); + g_free (stripped_name); + + if (message != NULL) { + error_dialog = GNOME_DIALOG (gnome_error_dialog_parented (message, + parent_window)); + gtk_window_set_title (GTK_WINDOW (error_dialog), + error_in_name + ? _("Bad Application Name") + : _("Bad Application Command")); + + gnome_dialog_run (error_dialog); + g_free (message); + + return TRUE; + } - /* Connect to toggled signal */ - gtk_signal_connect (GTK_OBJECT (check_button), "toggled", - GTK_SIGNAL_FUNC (application_button_toggled_callback), NULL); + return FALSE; } + static void -show_new_application_window (GtkWidget *button, GtkWidget *list) +run_edit_or_new_application_dialog (const char *mime_type, GtkWidget *list, GnomeVFSMimeApplication *application) { - GtkWidget *app_entry, *command_entry; GtkWidget *dialog; + GtkWidget *app_entry, *command_entry; GtkWidget *label; GtkWidget *behavior_frame, *frame_vbox; GtkWidget *multiple_check_box, *uri_check_box; GtkWidget *table; - char *name, *command, *mime_type; - gboolean multiple, uri; - - dialog = gnome_dialog_new (_("New Application"), GNOME_STOCK_BUTTON_OK, GNOME_STOCK_BUTTON_CANCEL, NULL); - + gboolean initial_toggle_state; + const char *name; + const char *command; + int dialog_result; + gboolean entry_validated; + char *invalid_entry_message, *app_id; + + g_assert (mime_type != NULL || application != NULL); + g_assert (GTK_IS_WIDGET (list)); + + dialog = gnome_dialog_new ( + application == NULL + ? _("Add Application") + : _("Edit Application"), + GNOME_STOCK_BUTTON_OK, GNOME_STOCK_BUTTON_CANCEL, NULL); + + /* FIXME: Dialog should be parented on Edit Applications dialog */ + /* Create table */ - table = gtk_table_new (3, 2, FALSE); + table = gtk_table_new (4, 2, FALSE); gtk_container_add (GTK_CONTAINER (GNOME_DIALOG (dialog)->vbox), table); gtk_table_set_row_spacings (GTK_TABLE (table), GNOME_PAD_SMALL); gtk_table_set_col_spacings (GTK_TABLE (table), GNOME_PAD_SMALL); @@ -1161,21 +1270,26 @@ show_new_application_window (GtkWidget *button, GtkWidget *list) /* Application Name label and entry */ label = gtk_label_new (_("Application Name:")); gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_table_attach_defaults ( GTK_TABLE (table), label, 0, 1, 0, 1); + gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 0, 1); app_entry = gtk_entry_new (); gtk_table_attach_defaults ( GTK_TABLE (table), app_entry, 1, 2, 0, 1); + if (application != NULL) { + gtk_entry_set_text (GTK_ENTRY (app_entry), application->name); + } /* Application Command label and entry */ label = gtk_label_new (_("Application Command:")); gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_table_attach_defaults ( GTK_TABLE (table), label, 0, 1, 1, 2); + gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 1, 2); command_entry = gtk_entry_new (); - gtk_table_attach_defaults ( GTK_TABLE (table), command_entry, 1, 2, 1, 2); - + gtk_table_attach_defaults (GTK_TABLE (table), command_entry, 1, 2, 1, 2); + if (application != NULL) { + gtk_entry_set_text (GTK_ENTRY (command_entry), application->command); + } + /* Open Behavior frame */ - /* FIXME bugzilla.eazel.com 6066: Need to add expected uri schemes */ behavior_frame = gtk_frame_new (_("Open Behavior")); gtk_table_attach_defaults ( GTK_TABLE (table), behavior_frame, 0, 2, 2, 3); @@ -1184,52 +1298,70 @@ show_new_application_window (GtkWidget *button, GtkWidget *list) multiple_check_box = gtk_check_button_new_with_label (_("Can open multiple files")); gtk_box_pack_start (GTK_BOX (frame_vbox), multiple_check_box, FALSE, FALSE, 0); + initial_toggle_state = application == NULL + ? FALSE + : application->can_open_multiple_files; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (multiple_check_box), initial_toggle_state); - uri_check_box = gtk_check_button_new_with_label (_("Expects URIs as arguments")); + /* FIXME bugzilla.eazel.com 6066: This needs to be three options now: "yes", "no", and "use uris for non-file locations" */ + uri_check_box = gtk_check_button_new_with_label (_("Can open from URI")); gtk_box_pack_start (GTK_BOX (frame_vbox), uri_check_box, FALSE, FALSE, 0); - - + initial_toggle_state = application == NULL + ? FALSE + : application->expects_uris; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (uri_check_box), initial_toggle_state); + + gtk_widget_show_all (GNOME_DIALOG (dialog)->vbox); /* Set focus to text entry widget */ - gtk_window_set_focus (GTK_WINDOW (dialog), app_entry); + gtk_widget_grab_focus (app_entry); + + do { + dialog_result = gnome_dialog_run (GNOME_DIALOG (dialog)); + entry_validated = FALSE; - switch (gnome_dialog_run (GNOME_DIALOG (dialog))) { - case 0: + if (dialog_result == GNOME_OK) { name = gtk_entry_get_text (GTK_ENTRY (app_entry)); command = gtk_entry_get_text (GTK_ENTRY (command_entry)); - multiple = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (multiple_check_box)); - uri = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (uri_check_box)); - - if (strlen (name) > 0 && strlen (command) > 0) { - mime_type = gtk_object_get_data (GTK_OBJECT (button), "mime_type"); - add_or_update_application (list, - gtk_entry_get_text (GTK_ENTRY (app_entry)), - gtk_entry_get_text (GTK_ENTRY (command_entry)), - - gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (multiple_check_box)), - gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (uri_check_box)), - FALSE); - add_item_to_application_list (list, name, mime_type, -1); + + invalid_entry_message = NULL; + + if (!handle_invalid_application_input (GTK_WINDOW (dialog), name, command)) { + entry_validated = TRUE; + app_id = add_or_update_application (list, + name, + command, + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (multiple_check_box)), + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (uri_check_box)), + application != NULL); + if (application == NULL && app_id != NULL) { + add_item_to_application_list (list, app_id, name, mime_type, TRUE, -1); + } + g_free (app_id); } - case 1: - gtk_widget_destroy (dialog); - break; - - default: - break; - } + } + } while (dialog_result == GNOME_OK && !entry_validated); + + /* FIXME: Close box is treated like Cancel, which loses user changes silently. + * Would be better to either do nothing at all (force use of OK or Cancel) or + * even put up a little dialog telling them they have to use OK or Cancel. + * Too bad we can't prevent the close box from appearing. Window Managers suck. + */ + if (dialog_result >= 0) { + gnome_dialog_close (GNOME_DIALOG (dialog)); + } } static void +show_new_application_window (GtkWidget *button, GtkWidget *list) +{ + run_edit_or_new_application_dialog (gtk_object_get_data (GTK_OBJECT (button), "mime_type"), list, NULL); +} + +static void show_edit_application_window (GtkWidget *button, GtkWidget *list) { - GtkWidget *app_entry, *command_entry; - GtkWidget *dialog; - GtkWidget *label; - GtkWidget *behavior_frame, *frame_vbox; - GtkWidget *multiple_check_box, *uri_check_box; - GtkWidget *table; GList *selection; const char *id; GnomeVFSMimeApplication *application; @@ -1257,78 +1389,16 @@ show_edit_application_window (GtkWidget *button, GtkWidget *list) return; } - dialog = gnome_dialog_new (_("Edit Application"), GNOME_STOCK_BUTTON_OK, GNOME_STOCK_BUTTON_CANCEL, NULL); - - /* Create table */ - table = gtk_table_new (4, 2, FALSE); - gtk_container_add (GTK_CONTAINER (GNOME_DIALOG (dialog)->vbox), table); - gtk_table_set_row_spacings (GTK_TABLE (table), GNOME_PAD_SMALL); - gtk_table_set_col_spacings (GTK_TABLE (table), GNOME_PAD_SMALL); - - /* Application Name label and entry */ - label = gtk_label_new (_("Application Name:")); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 0, 1); - - app_entry = gtk_entry_new (); - gtk_table_attach_defaults ( GTK_TABLE (table), app_entry, 1, 2, 0, 1); - gtk_entry_set_text (GTK_ENTRY (app_entry), application->name); + run_edit_or_new_application_dialog (NULL, list, application); - /* Application Command label and entry */ - label = gtk_label_new (_("Application Command:")); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 1, 2); - - command_entry = gtk_entry_new (); - gtk_entry_set_text (GTK_ENTRY (command_entry), application->command); - gtk_table_attach_defaults (GTK_TABLE (table), command_entry, 1, 2, 1, 2); - - /* Open Behavior frame */ - behavior_frame = gtk_frame_new (_("Open Behavior")); - gtk_table_attach_defaults ( GTK_TABLE (table), behavior_frame, 0, 2, 2, 3); - - frame_vbox = gtk_vbox_new (FALSE, GNOME_PAD_SMALL); - gtk_container_add (GTK_CONTAINER (behavior_frame), frame_vbox); - - multiple_check_box = gtk_check_button_new_with_label (_("Can open multiple files")); - gtk_box_pack_start (GTK_BOX (frame_vbox), multiple_check_box, FALSE, FALSE, 0); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (multiple_check_box), application->can_open_multiple_files); - - /* FIXME bugzilla.eazel.com 6066: This needs to be three options now: "yes", "no", and "use uris for non-file locations" */ - uri_check_box = gtk_check_button_new_with_label (_("Can open from URI")); - gtk_box_pack_start (GTK_BOX (frame_vbox), uri_check_box, FALSE, FALSE, 0); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (uri_check_box), application->expects_uris); - - - gtk_widget_show_all (GNOME_DIALOG (dialog)->vbox); - - /* Set focus to text entry widget */ - gtk_window_set_focus (GTK_WINDOW (dialog), app_entry); - - switch (gnome_dialog_run (GNOME_DIALOG (dialog))) { - case 0: - add_or_update_application (list, - gtk_entry_get_text (GTK_ENTRY (app_entry)), - gtk_entry_get_text (GTK_ENTRY (command_entry)), - gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (multiple_check_box)), - gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (uri_check_box)), - TRUE); - - case 1: - gnome_vfs_mime_application_free (application); - gtk_widget_destroy (dialog); - break; - - default: - break; - } + gnome_vfs_mime_application_free (application); } static void delete_selected_application (GtkWidget *button, GtkWidget *list) { GtkListItem *item; - const char *mime_type, *name; + const char *mime_type, *id; GList *selection; /* Get selected list item */ @@ -1342,14 +1412,16 @@ delete_selected_application (GtkWidget *button, GtkWidget *list) return; } - name = gtk_object_get_data (GTK_OBJECT (item), "application_id"); + g_return_if_fail (GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (item), "user_owned"))); + + id = gtk_object_get_data (GTK_OBJECT (item), "application_id"); mime_type = gtk_object_get_data (GTK_OBJECT (item), "mime_type"); - /* Remove mime data */ - if (name != NULL && mime_type != NULL) { - gnome_vfs_application_registry_remove_mime_type (name, mime_type); + /* Remove application if it is user owned */ + if (id != NULL && mime_type != NULL) { + gnome_vfs_application_registry_remove_mime_type (id, mime_type); gnome_vfs_application_registry_sync (); - gnome_vfs_mime_remove_application_from_short_list (mime_type, name); + gnome_vfs_mime_remove_application_from_short_list (mime_type, id); } /* Remove widget from list */ diff --git a/capplets/file-types/file-types-capplet-dialogs.h b/capplets/file-types/file-types-capplet-dialogs.h index d472c95fe..5567b6141 100644 --- a/capplets/file-types/file-types-capplet-dialogs.h +++ b/capplets/file-types/file-types-capplet-dialogs.h @@ -30,6 +30,7 @@ void show_edit_components_dialog (const char *mime_type); char *name_from_oaf_server_info (OAF_ServerInfo *server); char *nautilus_mime_type_capplet_show_new_mime_window (void); char *nautilus_mime_type_capplet_show_new_extension_window (void); -char *nautilus_mime_type_capplet_show_change_extension_window (const char *mime_type); +char *nautilus_mime_type_capplet_show_change_extension_window (const char *mime_type, + gboolean *new_list); #endif /* NAUTILUS_MIME_TYPE_CAPPLET_DIALOGS_H */ diff --git a/capplets/file-types/file-types-capplet.c b/capplets/file-types/file-types-capplet.c index cbbbda318..b40ce7d58 100644 --- a/capplets/file-types/file-types-capplet.c +++ b/capplets/file-types/file-types-capplet.c @@ -48,8 +48,11 @@ #include "nautilus-mime-type-capplet.h" -#define DEFAULT_REGULAR_ICON "/nautilus/i-regular-24.png" -#define DEFAULT_ACTION_ICON "/nautilus/i-executable.png" +#define DEFAULT_REGULAR_ICON "nautilus/i-regular-24.png" +#define DEFAULT_ACTION_ICON "nautilus/i-executable.png" + +#define MAX_ICON_WIDTH_IN_LIST 18 +#define MAX_ICON_HEIGHT_IN_LIST 18 enum { COLUMN_DESCRIPTION = 0, @@ -90,6 +93,8 @@ static void populate_mime_list (GList *type_li static GdkPixbuf *capplet_get_icon_pixbuf (const char *mime_string, gboolean is_executable); + +/* FIXME: Using global variables here is yucky */ GtkWidget *capplet; GtkWidget *delete_button; GtkWidget *remove_button; @@ -99,6 +104,8 @@ GtkWidget *default_menu; GtkWidget *application_button, *viewer_button; GtkLabel *mime_label; GtkWidget *description_entry; +gboolean description_has_changed; +gboolean sort_column_clicked [TOTAL_COLUMNS]; /* * main @@ -261,11 +268,6 @@ nautilus_mime_type_capplet_add_extension (const char *extension) return; } - /* Check for starting space in string */ - if (extension[0] == ' ') { - return; - } - /* Copy only contiguous part of string. No spaces allowed. */ search_string = g_strdup (extension); token = strtok (search_string, " "); @@ -274,7 +276,7 @@ nautilus_mime_type_capplet_add_extension (const char *extension) title[0] = g_strdup (extension); } else if (strlen (token) <= 0) { return; - }else { + } else { title[0] = g_strdup (token); } g_free (search_string); @@ -377,26 +379,34 @@ get_selected_mime_type (void) static void really_change_icon (gpointer user_data) { - + NautilusMimeIconEntry *icon_entry; char *filename; const char *mime_type; + g_assert (NAUTILUS_MIME_IS_ICON_ENTRY (user_data)); + mime_type = get_selected_mime_type (); if (mime_type == NULL) { return; } - - filename = nautilus_mime_type_icon_entry_get_relative_filename (NAUTILUS_MIME_ICON_ENTRY (user_data)); + + icon_entry = NAUTILUS_MIME_ICON_ENTRY (user_data); + + filename = nautilus_mime_type_icon_entry_get_relative_filename (icon_entry); + if (filename == NULL) { + filename = nautilus_mime_type_icon_entry_get_full_filename (icon_entry); + } gnome_vfs_mime_set_icon (mime_type, filename); - nautilus_mime_type_capplet_update_mime_list_icon (mime_type); + nautilus_mime_type_capplet_update_mime_list_icon_and_description (mime_type); + nautilus_mime_type_capplet_update_info (mime_type); g_free (filename); } static void -gil_icon_selected_cb (GnomeIconList *gil, gint num, GdkEvent *event, gpointer user_data) +icon_chosen_callback (GnomeIconList *gil, gint num, GdkEvent *event, gpointer user_data) { NautilusMimeIconEntry *icon_entry; const gchar * icon; @@ -420,6 +430,7 @@ gil_icon_selected_cb (GnomeIconList *gil, gint num, GdkEvent *event, gpointer us if(event && event->type == GDK_2BUTTON_PRESS && ((GdkEventButton *)event)->button == 1) { gnome_icon_selection_stop_loading(gis); really_change_icon (user_data); + gtk_widget_hide(icon_entry->pick_dialog); } @@ -428,7 +439,7 @@ gil_icon_selected_cb (GnomeIconList *gil, gint num, GdkEvent *event, gpointer us static void change_icon_clicked_cb_real (GnomeDialog *dialog, gint button_number, gpointer user_data) { - if (button_number == 0) { + if (button_number == GNOME_OK) { really_change_icon (user_data); } } @@ -440,13 +451,14 @@ change_icon_clicked (GtkWidget *entry, gpointer user_data) GnomeIconSelection * gis; nautilus_mime_type_show_icon_selection (NAUTILUS_MIME_ICON_ENTRY (user_data)); + dialog = GNOME_DIALOG (NAUTILUS_MIME_ICON_ENTRY (user_data)->pick_dialog); gtk_signal_connect (GTK_OBJECT (dialog), "clicked", change_icon_clicked_cb_real, user_data); gis = gtk_object_get_user_data(GTK_OBJECT(user_data)); gtk_signal_connect_after (GTK_OBJECT(GNOME_ICON_SELECTION(gis)->gil), - "select_icon", gil_icon_selected_cb, user_data); + "select_icon", icon_chosen_callback, user_data); } @@ -474,15 +486,17 @@ change_file_extensions_clicked (GtkWidget *widget, gpointer user_data) { const char *mime_type; char *new_extensions; + gboolean use_new_list; mime_type = get_selected_mime_type (); if (mime_type == NULL) { return; } - new_extensions = nautilus_mime_type_capplet_show_change_extension_window (mime_type); - - gnome_vfs_mime_set_extensions_list (mime_type, new_extensions); + new_extensions = nautilus_mime_type_capplet_show_change_extension_window (mime_type, &use_new_list); + if (use_new_list) { + gnome_vfs_mime_set_extensions_list (mime_type, new_extensions); + } update_extensions_list (mime_type); } @@ -551,6 +565,97 @@ list_reveal_row (GtkCList *clist, int row_index) } } + + +static int +find_row_for_mime_type (const char *mime_type, GtkCList *mime_list) +{ + gboolean found_one; + int index; + const char *row_data; + + if (mime_type == NULL) { + return -1; + } + + found_one = FALSE; + + for (index = 0; index < mime_list->rows; index++) { + row_data = gtk_clist_get_row_data (mime_list, index); + if (row_data != NULL && strcmp (row_data, mime_type) == 0) { + found_one = TRUE; + break; + } + } + + if (found_one) { + return index; + } + + return -1; +} + + +static void +update_description_from_input (GtkEntry *entry) +{ + char *new_description; + const char *mime_type; + + g_assert (GTK_IS_ENTRY (entry)); + g_assert ((gpointer)entry == (gpointer)description_entry); + + description_has_changed = FALSE; + + mime_type = get_selected_mime_type (); + if (mime_type == NULL) { + return; + } + + new_description = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1); + gnome_vfs_mime_set_description (mime_type, new_description); + nautilus_mime_type_capplet_update_mime_list_icon_and_description (mime_type); + g_free (new_description); +} + +static void +description_entry_activate (GtkEntry *entry, gpointer user_data) +{ + g_assert (GTK_IS_ENTRY (entry)); + g_assert ((gpointer)entry == (gpointer)description_entry); + g_assert (user_data == NULL); + + if (description_has_changed) { + update_description_from_input (entry); + } +} + +static void +description_entry_changed (GtkEntry *entry, gpointer user_data) +{ + g_assert (GTK_IS_ENTRY (entry)); + g_assert ((gpointer)entry == (gpointer)description_entry); + g_assert (user_data == NULL); + + description_has_changed = TRUE; +} + +static gboolean +description_entry_lost_focus (GtkEntry *entry, + GdkEventFocus *event, + gpointer user_data) +{ + g_assert (GTK_IS_ENTRY (entry)); + g_assert ((gpointer)entry == (gpointer)description_entry); + g_assert (user_data == NULL); + + if (description_has_changed) { + update_description_from_input (entry); + } + + return FALSE; +} + static void init_mime_capplet (const char *scroll_to_mime_type) { @@ -560,9 +665,7 @@ init_mime_capplet (const char *scroll_to_mime_type) GtkWidget *mime_list_container; GtkWidget *frame; GtkWidget *table; - int index, list_width, column_width; - gboolean found_one; - const char *row_data; + int index, list_width, column_width, found_index; capplet = capplet_widget_new (); @@ -610,13 +713,26 @@ init_mime_capplet (const char *scroll_to_mime_type) (GtkAttachOptions) (GTK_FILL), 0, 0); description_entry = gtk_entry_new (); + description_has_changed = FALSE; gtk_box_pack_start (GTK_BOX (vbox), description_entry, FALSE, FALSE, 0); gtk_widget_make_bold (GTK_WIDGET (description_entry)); + gtk_signal_connect (GTK_OBJECT (description_entry), "activate", + GTK_SIGNAL_FUNC (description_entry_activate), + NULL); + + gtk_signal_connect (GTK_OBJECT (description_entry), "changed", + GTK_SIGNAL_FUNC (description_entry_changed), + NULL); + + gtk_signal_connect (GTK_OBJECT (description_entry), "focus_out_event", + GTK_SIGNAL_FUNC (description_entry_lost_focus), + NULL); + hbox = gtk_hbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (hbox), FALSE, FALSE, 0); - mime_label = GTK_LABEL (gtk_label_new (_("Mime Type"))); + mime_label = GTK_LABEL (gtk_label_new (_("MIME Type"))); gtk_label_set_justify (GTK_LABEL (mime_label), GTK_JUSTIFY_LEFT); gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (mime_label), FALSE, FALSE, 0); @@ -665,11 +781,10 @@ init_mime_capplet (const char *scroll_to_mime_type) gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); default_menu = gtk_option_menu_new(); - gtk_widget_set_usize (GTK_WIDGET (default_menu), 170, 0); gtk_box_pack_start (GTK_BOX (hbox), default_menu, TRUE, TRUE, 0); button = gtk_button_new_with_label (_("Edit List")); - gtk_widget_set_usize (GTK_WIDGET (button), 70, 0); + gtk_misc_set_padding (GTK_MISC (GTK_BIN(button)->child), 2, 1); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); gtk_signal_connect (GTK_OBJECT (button), "clicked", edit_default_clicked, mime_list); } @@ -693,13 +808,13 @@ init_mime_capplet (const char *scroll_to_mime_type) (GtkAttachOptions) (0), 0, 0); gtk_widget_set_usize (hbox, 1, 11); - button = gtk_button_new_with_label (_("Add new Mime type...")); + button = gtk_button_new_with_label (_("Add New MIME Type...")); gtk_signal_connect (GTK_OBJECT (button), "clicked", add_mime_clicked, NULL); gtk_table_attach (GTK_TABLE (small_table), button, 0, 1, 1, 2, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); - button = gtk_button_new_with_label (_("Delete this Mime type...")); + button = gtk_button_new_with_label (_("Delete This MIME Type")); gtk_signal_connect (GTK_OBJECT (button), "clicked", delete_mime_clicked, NULL); gtk_table_attach (GTK_TABLE (small_table), button, 0, 1, 2, 3, (GtkAttachOptions) (GTK_FILL), @@ -718,12 +833,6 @@ init_mime_capplet (const char *scroll_to_mime_type) } - - /* FIXME bugzilla.eazel.com 2765: this call generates a - Gtk-WARNING **: gtk_signal_disconnect_by_data(): could not find handler containing data (0x80FA6F8) - I think it is a bug in the control-center... - */ - /* Yes, show all widgets */ gtk_widget_show_all (capplet); @@ -744,32 +853,80 @@ init_mime_capplet (const char *scroll_to_mime_type) /* Sort by description. The description is the first column in the list. */ gtk_clist_set_sort_column (GTK_CLIST (mime_list), COLUMN_DESCRIPTION); gtk_clist_sort (GTK_CLIST (mime_list)); + GTK_CLIST (mime_list)->sort_type = GTK_SORT_ASCENDING; + + /* Set up initial column click tracking state. We do this so the initial clicks on + * columns will allow us to set the proper sort state for the user. + */ + sort_column_clicked[0] = TRUE; /* First sort column has been click by us in setup code */ + for (index = 1; index < TOTAL_COLUMNS; index++) { + sort_column_clicked[index] = FALSE; + } /* Attempt to select specified mime type in list */ - if (scroll_to_mime_type != NULL) { - found_one = FALSE; - - for (index = 0; index < GTK_CLIST (mime_list)->rows; index++) { - row_data = gtk_clist_get_row_data (GTK_CLIST (mime_list), index); - if (row_data != NULL && strcmp (row_data, scroll_to_mime_type) == 0) { - /* Select mime type and bail */ - found_one = TRUE; - gtk_clist_select_row (GTK_CLIST (mime_list), index, 1); - list_reveal_row (GTK_CLIST (mime_list), index); - break; - } - } - - if (!found_one) { - gtk_clist_select_row (GTK_CLIST (mime_list), 0, 0); + if (scroll_to_mime_type != NULL) { + found_index = find_row_for_mime_type (scroll_to_mime_type, GTK_CLIST (mime_list)); + if (found_index != -1) { + gtk_clist_select_row (GTK_CLIST (mime_list), found_index, 1); + list_reveal_row (GTK_CLIST (mime_list), found_index); + } else { + gtk_clist_select_row (GTK_CLIST (mime_list), 0, 1); + list_reveal_row (GTK_CLIST (mime_list), 0); } } else { gtk_clist_select_row (GTK_CLIST (mime_list), 0, 0); + list_reveal_row (GTK_CLIST (mime_list), 0); } - - capplet_widget_state_changed (CAPPLET_WIDGET (capplet), TRUE); + + /* Inform control center that our changes are immediate */ + capplet_widget_changes_are_immediate (CAPPLET_WIDGET (capplet)); +} + +static gboolean +is_full_path (const char *path_or_name) +{ + return path_or_name[0] == '/'; } +static char * +capplet_get_icon_path (const char *path_or_name) +{ + char *result; + char *alternate_relative_filename; + + if (is_full_path (path_or_name) && g_file_exists (path_or_name)) { + return g_strdup (path_or_name); + } + + result = gnome_vfs_icon_path_from_filename (path_or_name); + if (result != NULL) { + return result; + } + + /* FIXME bugzilla.eazel.com 639: + * It is somewhat evil to special-case the nautilus directory here. + * We should clean this up if/when we come up with a way to handle + * Nautilus themes here. + */ + alternate_relative_filename = g_strconcat ("nautilus/", path_or_name, NULL); + result = gnome_vfs_icon_path_from_filename (alternate_relative_filename); + g_free (alternate_relative_filename); + if (result != NULL) { + return result; + } + + /* FIXME bugzilla.eazel.com 639: + * To work correctly with Nautilus themed icons, if there's no + * suffix we will also try looking in the nautilus dir for a ".png" name. + * This will return the icon for the default theme; there is no + * mechanism for getting a themed icon in the capplet. + */ + alternate_relative_filename = g_strconcat ("nautilus/", path_or_name, ".png", NULL); + result = gnome_vfs_icon_path_from_filename (alternate_relative_filename); + g_free (alternate_relative_filename); + + return result; +} /* * nautilus_mime_type_capplet_update_info @@ -788,14 +945,9 @@ nautilus_mime_type_capplet_update_info (const char *mime_type) { gtk_label_set_text (GTK_LABEL (mime_label), mime_type); description = gnome_vfs_mime_get_description (mime_type); - if (description != NULL && strlen (description) > 0) { - gtk_entry_set_text (GTK_ENTRY (description_entry), description); - } else { - gtk_entry_set_text (GTK_ENTRY (description_entry), _("No Description")); - } + gtk_entry_set_text (GTK_ENTRY (description_entry), description != NULL ? description : ""); + description_has_changed = FALSE; - gtk_editable_set_editable (GTK_EDITABLE (description_entry), FALSE); - /* Update menus */ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (application_button))) { populate_application_menu (default_menu, mime_type); @@ -810,23 +962,16 @@ nautilus_mime_type_capplet_update_info (const char *mime_type) { /* Set icon for mime type */ icon_name = gnome_vfs_mime_get_icon (mime_type); + path = NULL; if (icon_name != NULL) { - path = gnome_vfs_icon_path_from_filename (icon_name); - if (path != NULL) { - nautilus_mime_type_icon_entry_set_icon (NAUTILUS_MIME_ICON_ENTRY (icon_entry), path); - g_free (path); - } else { - /* No icon */ - nautilus_mime_type_icon_entry_set_icon (NAUTILUS_MIME_ICON_ENTRY (icon_entry), - NULL); - } - } else { - /* No icon */ - path = gnome_vfs_icon_path_from_filename (DEFAULT_REGULAR_ICON); - nautilus_mime_type_icon_entry_set_icon (NAUTILUS_MIME_ICON_ENTRY (icon_entry), - path); - g_free (path); + path = capplet_get_icon_path (icon_name); + } + if (path == NULL) { + /* No custom icon specified, or custom icon not found, use default */ + path = capplet_get_icon_path (DEFAULT_REGULAR_ICON); } + nautilus_mime_type_icon_entry_set_icon (NAUTILUS_MIME_ICON_ENTRY (icon_entry), path); + g_free (path); /* Indicate default action */ action = gnome_vfs_mime_get_default_action (mime_type); @@ -1147,9 +1292,18 @@ revert_real_cb (gint reply, gpointer data) gnome_vfs_mime_info_reload (); mime_types_list = gnome_vfs_get_registered_mime_types (); - + + gtk_clist_freeze (GTK_CLIST (mime_list)); gtk_clist_clear (GTK_CLIST (mime_list)); populate_mime_list (mime_types_list, GTK_CLIST (mime_list)); + + /* Sort list using current sort type and select the first item. */ + gtk_clist_sort (GTK_CLIST (mime_list)); + gtk_clist_select_row (GTK_CLIST (mime_list), 0, 0); + list_reveal_row (GTK_CLIST (mime_list), 0); + + gtk_clist_thaw (GTK_CLIST (mime_list)); + } else { /* NO */ } @@ -1161,10 +1315,9 @@ revert_mime_clicked (GtkWidget *widget, gpointer data) { GtkWidget *dialog; - dialog = gnome_question_dialog_modal (_("Reverting to system settings\n" - "will lose all your personal \n" - "Mime configuration.\n" - "Revert to System Settings ?\n"), + dialog = gnome_question_dialog_modal (_("Reverting to system settings will lose any changes\n" + "you have ever made to File Types and Programs.\n" + "Revert anyway?"), revert_real_cb, NULL); } @@ -1204,9 +1357,10 @@ add_mime_clicked (GtkWidget *widget, gpointer data) GnomeVFSMimeAction *action; GnomeVFSMimeApplication *default_app; OAF_ServerInfo *default_component; + int found_index; mime_string = nautilus_mime_type_capplet_show_new_mime_window (); - if (mime_string != NULL) { + if (mime_string != NULL && mime_string[0] != '\0') { /* Add new type to mime list */ pixbuf = NULL; @@ -1240,7 +1394,7 @@ add_mime_clicked (GtkWidget *widget, gpointer data) pixbuf = capplet_get_icon_pixbuf (mime_string, FALSE); if (pixbuf != NULL) { - pixbuf = capplet_gdk_pixbuf_scale_to_fit (pixbuf, 18, 18); + pixbuf = capplet_gdk_pixbuf_scale_to_fit (pixbuf, MAX_ICON_WIDTH_IN_LIST, MAX_ICON_HEIGHT_IN_LIST); gdk_pixbuf_render_pixmap_and_mask (pixbuf, &pixmap, &bitmap, 100); gtk_clist_set_pixtext (GTK_CLIST (mime_list), row, 0, text[0], 5, pixmap, bitmap); gdk_pixbuf_unref (pixbuf); @@ -1257,7 +1411,11 @@ add_mime_clicked (GtkWidget *widget, gpointer data) g_free (text[3]); text[3] = g_strdup (default_app->name); - pixbuf = capplet_get_icon_pixbuf (mime_string, TRUE); + filename = capplet_get_icon_path (DEFAULT_ACTION_ICON); + if (filename != NULL) { + pixbuf = gdk_pixbuf_new_from_file (filename); + g_free (filename); + } gnome_vfs_mime_application_free (default_app); break; @@ -1269,9 +1427,11 @@ add_mime_clicked (GtkWidget *widget, gpointer data) tmp_text = name_from_oaf_server_info (default_component); text[3] = g_strdup_printf (_("View as %s"), tmp_text); g_free (tmp_text); - filename = gnome_vfs_icon_path_from_filename ("nautilus/gnome-library.png"); - pixbuf = gdk_pixbuf_new_from_file (filename); - g_free (filename); + filename = capplet_get_icon_path ("nautilus/gnome-library.png"); + if (filename != NULL) { + pixbuf = gdk_pixbuf_new_from_file (filename); + g_free (filename); + } CORBA_free (default_component); break; @@ -1283,12 +1443,20 @@ add_mime_clicked (GtkWidget *widget, gpointer data) /* Set column icon */ if (pixbuf != NULL) { - pixbuf = capplet_gdk_pixbuf_scale_to_fit (pixbuf, 18, 18); + pixbuf = capplet_gdk_pixbuf_scale_to_fit (pixbuf, MAX_ICON_WIDTH_IN_LIST, MAX_ICON_HEIGHT_IN_LIST); gdk_pixbuf_render_pixmap_and_mask (pixbuf, &pixmap, &bitmap, 100); gtk_clist_set_pixtext (GTK_CLIST (mime_list), row, 3, text[3], 5, pixmap, bitmap); gdk_pixbuf_unref (pixbuf); } + /* Sort, select and scroll to new mime type */ + gtk_clist_sort (GTK_CLIST (mime_list)); + found_index = find_row_for_mime_type (mime_string, GTK_CLIST (mime_list)); + if (found_index != -1) { + gtk_clist_select_row (GTK_CLIST (mime_list), found_index, 1); + list_reveal_row (GTK_CLIST (mime_list), found_index); + } + g_free (text[0]); g_free (text[1]); g_free (text[2]); @@ -1336,7 +1504,7 @@ edit_default_clicked (GtkWidget *widget, gpointer data) void -nautilus_mime_type_capplet_update_mime_list_icon (const char *mime_string) +nautilus_mime_type_capplet_update_mime_list_icon_and_description (const char *mime_string) { char *text; const char *description; @@ -1366,7 +1534,7 @@ nautilus_mime_type_capplet_update_mime_list_icon (const char *mime_string) pixbuf = capplet_get_icon_pixbuf (mime_string, FALSE); if (pixbuf != NULL) { - pixbuf = capplet_gdk_pixbuf_scale_to_fit (pixbuf, 18, 18); + pixbuf = capplet_gdk_pixbuf_scale_to_fit (pixbuf, MAX_ICON_WIDTH_IN_LIST, MAX_ICON_HEIGHT_IN_LIST); gdk_pixbuf_render_pixmap_and_mask (pixbuf, &pixmap, &bitmap, 100); gtk_clist_set_pixtext (clist, row, 0, text, 5, pixmap, bitmap); gdk_pixbuf_unref (pixbuf); @@ -1410,9 +1578,7 @@ update_mime_list_action (const char *mime_string) GnomeVFSMimeAction *action; GnomeVFSMimeApplication *default_app; OAF_ServerInfo *default_component; - const char *action_icon_name; - char *text, *tmp_text; - char *action_icon_path; + char *text, *tmp_text, *icon_path; int row; pixbuf = NULL; @@ -1423,22 +1589,19 @@ update_mime_list_action (const char *mime_string) action = gnome_vfs_mime_get_default_action (mime_string); if (action != NULL) { switch (action->action_type) { + /* FIXME: Big hunks of this code are copied/pasted in several + * places in this file. Need to use common routines. One way + * to find them is to search for "nautilus/gnome-library.png" + */ case GNOME_VFS_MIME_ACTION_TYPE_APPLICATION: /* Get the default application */ default_app = gnome_vfs_mime_get_default_application (mime_string); g_free (text); - text = g_strdup (default_app->name); - action_icon_name = gnome_vfs_mime_get_icon (mime_string); - if (action_icon_name != NULL) { - /* Get custom icon */ - action_icon_path = gnome_pixmap_file (action_icon_name); - if (action_icon_path != NULL) { - pixbuf = gdk_pixbuf_new_from_file (action_icon_path); - g_free (action_icon_path); - } - } else { - /* Use default icon */ - pixbuf = gdk_pixbuf_new_from_file (DEFAULT_ACTION_ICON); + text = g_strdup (default_app->name); + icon_path = capplet_get_icon_path (DEFAULT_ACTION_ICON); + if (icon_path != NULL) { + pixbuf = gdk_pixbuf_new_from_file (icon_path); + g_free (icon_path); } gnome_vfs_mime_application_free (default_app); break; @@ -1450,7 +1613,11 @@ update_mime_list_action (const char *mime_string) tmp_text = name_from_oaf_server_info (default_component); text = g_strdup_printf (_("View as %s"), tmp_text); g_free (tmp_text); - pixbuf = gdk_pixbuf_new_from_file ("/gnome/share/pixmaps/nautilus/gnome-library.png"); + icon_path = capplet_get_icon_path ("nautilus/gnome-library.png"); + if (icon_path != NULL) { + pixbuf = gdk_pixbuf_new_from_file (icon_path); + g_free (icon_path); + } CORBA_free (default_component); break; @@ -1462,7 +1629,7 @@ update_mime_list_action (const char *mime_string) /* Set column icon */ if (pixbuf != NULL) { - pixbuf = capplet_gdk_pixbuf_scale_to_fit (pixbuf, 18, 18); + pixbuf = capplet_gdk_pixbuf_scale_to_fit (pixbuf, MAX_ICON_WIDTH_IN_LIST, MAX_ICON_HEIGHT_IN_LIST); gdk_pixbuf_render_pixmap_and_mask (pixbuf, &pixmap, &bitmap, 100); gtk_clist_set_pixtext (GTK_CLIST (mime_list), row, 3, text, 5, pixmap, bitmap); gdk_pixbuf_unref (pixbuf); @@ -1473,30 +1640,30 @@ update_mime_list_action (const char *mime_string) g_free (text); } +/* FIXME: + * This routine is never called with is_executable TRUE anymore. It + * could be simplified, possibly out of existence. + */ static GdkPixbuf * capplet_get_icon_pixbuf (const char *mime_string, gboolean is_executable) { - const char *description_icon_name; - char *description_icon_path; + const char *icon_name; + char *icon_path; GdkPixbuf *pixbuf; pixbuf = NULL; - description_icon_name = gnome_vfs_mime_get_icon (mime_string); - if (description_icon_name != NULL) { - /* Get custom icon */ - description_icon_path = gnome_vfs_icon_path_from_filename (description_icon_name); - if (description_icon_path != NULL) { - pixbuf = gdk_pixbuf_new_from_file (description_icon_path); - g_free (description_icon_path); - } - } else { - if (!is_executable) { - description_icon_path = gnome_vfs_icon_path_from_filename (DEFAULT_REGULAR_ICON); - } else { - description_icon_path = gnome_vfs_icon_path_from_filename (DEFAULT_ACTION_ICON); - } - pixbuf = gdk_pixbuf_new_from_file (description_icon_path); + icon_name = gnome_vfs_mime_get_icon (mime_string); + if (icon_name == NULL) { + icon_name = is_executable + ? DEFAULT_ACTION_ICON + : DEFAULT_REGULAR_ICON; + } + + icon_path = capplet_get_icon_path (icon_name); + if (icon_path != NULL) { + pixbuf = gdk_pixbuf_new_from_file (icon_path); + g_free (icon_path); } return pixbuf; @@ -1507,6 +1674,7 @@ populate_mime_list (GList *type_list, GtkCList *clist) { char *text[4], *tmp_text; const char *description; + char *icon_path; char *extensions, *mime_string; gint row; GList *element; @@ -1552,7 +1720,11 @@ populate_mime_list (GList *type_list, GtkCList *clist) pixbuf = capplet_get_icon_pixbuf (mime_string, FALSE); if (pixbuf != NULL) { - pixbuf = capplet_gdk_pixbuf_scale_to_fit (pixbuf, 18, 18); + /* FIXME: Big hunks of this code are copied/pasted in several + * places in this file. Need to use common routines. One way + * to find them is to search for MAX_ICON_WIDTH_IN_LIST + */ + pixbuf = capplet_gdk_pixbuf_scale_to_fit (pixbuf, MAX_ICON_WIDTH_IN_LIST, MAX_ICON_HEIGHT_IN_LIST); gdk_pixbuf_render_pixmap_and_mask (pixbuf, &pixmap, &bitmap, 100); gtk_clist_set_pixtext (clist, row, 0, text[0], 5, pixmap, bitmap); gdk_pixbuf_unref (pixbuf); @@ -1569,7 +1741,11 @@ populate_mime_list (GList *type_list, GtkCList *clist) g_free (text[3]); text[3] = g_strdup (default_app->name); - pixbuf = capplet_get_icon_pixbuf (mime_string, TRUE); + icon_path = capplet_get_icon_path (DEFAULT_ACTION_ICON); + if (icon_path != NULL) { + pixbuf = gdk_pixbuf_new_from_file (icon_path); + g_free (icon_path); + } gnome_vfs_mime_application_free (default_app); break; @@ -1580,7 +1756,11 @@ populate_mime_list (GList *type_list, GtkCList *clist) tmp_text = name_from_oaf_server_info (default_component); text[3] = g_strdup_printf (_("View as %s"), tmp_text); g_free (tmp_text); - pixbuf = gdk_pixbuf_new_from_file ("/gnome/share/pixmaps/nautilus/gnome-library.png"); + icon_path = capplet_get_icon_path ("nautilus/gnome-library.png"); + if (icon_path != NULL) { + pixbuf = gdk_pixbuf_new_from_file (icon_path); + g_free (icon_path); + } CORBA_free (default_component); break; @@ -1592,7 +1772,7 @@ populate_mime_list (GList *type_list, GtkCList *clist) /* Set column icon */ if (pixbuf != NULL) { - pixbuf = capplet_gdk_pixbuf_scale_to_fit (pixbuf, 18, 18); + pixbuf = capplet_gdk_pixbuf_scale_to_fit (pixbuf, MAX_ICON_WIDTH_IN_LIST, MAX_ICON_HEIGHT_IN_LIST); gdk_pixbuf_render_pixmap_and_mask (pixbuf, &pixmap, &bitmap, 100); gtk_clist_set_pixtext (clist, row, 3, text[3], 5, pixmap, bitmap); gdk_pixbuf_unref (pixbuf); @@ -1650,16 +1830,22 @@ sort_case_insensitive (GtkCList *clist, gpointer ptr1, gpointer ptr2) return strcasecmp (text1, text2); } - static void column_clicked (GtkCList *clist, gint column, gpointer user_data) { gtk_clist_set_sort_column (clist, column); + /* If the user has not clicked the column yet, make sure + * that the sort type is descending the first time. + */ + if (!sort_column_clicked [column]) { + clist->sort_type = GTK_SORT_DESCENDING; + sort_column_clicked [column] = TRUE; + } + /* Toggle sort type */ if (clist->sort_type == GTK_SORT_ASCENDING) { gtk_clist_set_sort_type (clist, GTK_SORT_DESCENDING); - } else { gtk_clist_set_sort_type (clist, GTK_SORT_ASCENDING); } @@ -1667,6 +1853,17 @@ column_clicked (GtkCList *clist, gint column, gpointer user_data) gtk_clist_sort (clist); } +static void +mime_list_reset_row_height (GtkCList *list) +{ + guint height_for_icon; + guint height_for_text; + + height_for_icon = MAX_ICON_HEIGHT_IN_LIST + 1; + height_for_text = GTK_WIDGET (list)->style->font->ascent + + GTK_WIDGET (list)->style->font->descent + 1; + gtk_clist_set_row_height (list, MAX (height_for_icon, height_for_text)); +} static GtkWidget * create_mime_list_and_scroller (void) @@ -1677,7 +1874,7 @@ create_mime_list_and_scroller (void) int index; titles[0] = _("Description"); - titles[1] = _("Mime Type"); + titles[1] = _("MIME Type"); titles[2] = _("Extension"); titles[3] = _("Default Action"); @@ -1706,6 +1903,17 @@ create_mime_list_and_scroller (void) for (index = 0; index < TOTAL_COLUMNS; index++) { gtk_clist_set_column_auto_resize (GTK_CLIST (mime_list), index, FALSE); } + + /* Make height tall enough for icons to look good. + * This must be done after the list widget is realized, due to + * a bug/design flaw in nautilus_clist_set_row_height. Connecting to + * the "realize" signal is slightly too early, so we connect to + * "map". + */ + gtk_signal_connect (GTK_OBJECT (mime_list), + "map", + mime_list_reset_row_height, + NULL); return window; } diff --git a/capplets/file-types/file-types-capplet.desktop.in b/capplets/file-types/file-types-capplet.desktop.in new file mode 100644 index 000000000..63ce82810 --- /dev/null +++ b/capplets/file-types/file-types-capplet.desktop.in @@ -0,0 +1,7 @@ +[Desktop Entry] +_Name=File Types and Programs +_Comment=Specify which programs are used to open or view each file type +Icon=gnome-ccmime.png +Exec=file-types-capplet +Terminal=0 +Type=Application diff --git a/capplets/file-types/file-types-capplet.h b/capplets/file-types/file-types-capplet.h index 245fe4388..914a2cb58 100644 --- a/capplets/file-types/file-types-capplet.h +++ b/capplets/file-types/file-types-capplet.h @@ -25,11 +25,11 @@ #ifndef NAUTILUS_MIME_TYPE_CAPPLET_H #define NAUTILUS_MIME_TYPE_CAPPLET_H -void nautilus_mime_type_capplet_update_info (const char *mime_type); -void nautilus_mime_type_capplet_update_application_info (const char *mime_type); -void nautilus_mime_type_capplet_update_viewer_info (const char *mime_type); -void nautilus_mime_type_capplet_add_extension (const char *extension); -const char *nautilus_mime_type_capplet_get_selected_item_mime_type (void); -void nautilus_mime_type_capplet_update_mime_list_icon (const char *mime_string); +void nautilus_mime_type_capplet_update_info (const char *mime_type); +void nautilus_mime_type_capplet_update_application_info (const char *mime_type); +void nautilus_mime_type_capplet_update_viewer_info (const char *mime_type); +void nautilus_mime_type_capplet_add_extension (const char *extension); +const char *nautilus_mime_type_capplet_get_selected_item_mime_type (void); +void nautilus_mime_type_capplet_update_mime_list_icon_and_description (const char *mime_string); #endif /* NAUTILUS_MIME_TYPE_CAPPLET_H */ diff --git a/capplets/file-types/file-types-icon-entry.c b/capplets/file-types/file-types-icon-entry.c index 78365ad56..e2133743a 100644 --- a/capplets/file-types/file-types-icon-entry.c +++ b/capplets/file-types/file-types-icon-entry.c @@ -142,6 +142,7 @@ entry_activated(GtkWidget *widget, NautilusMimeIconEntry *ientry) struct stat buf; GnomeIconSelection * gis; gchar *filename; + GtkButton *OK_button; g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_ENTRY (widget)); @@ -161,9 +162,11 @@ entry_activated(GtkWidget *widget, NautilusMimeIconEntry *ientry) if (gis->file_list) gnome_icon_selection_show_icons(gis); } else { - /* We pretend like ok has been called */ - entry_changed (NULL, ientry); - gtk_widget_hide (ientry->pick_dialog); + /* FIXME: This is a hack to act exactly like we've clicked the + * OK button. This should be structured more cleanly. + */ + OK_button = GTK_BUTTON (GNOME_DIALOG (ientry->pick_dialog)->buttons->data); + gtk_button_clicked (OK_button); } } @@ -275,41 +278,6 @@ browse_clicked (GnomeFileEntry *fentry, NautilusMimeIconEntry *ientry) } static void -icon_selected_cb (GtkButton *button, NautilusMimeIconEntry *icon_entry) -{ - const gchar *icon; - GnomeIconSelection *gis; - gchar *path, *filename; - const char *mime_type; - GtkWidget *entry; - - g_return_if_fail (icon_entry != NULL); - g_return_if_fail (NAUTILUS_MIME_IS_ICON_ENTRY (icon_entry)); - - gis = gtk_object_get_user_data (GTK_OBJECT (icon_entry)); - gnome_icon_selection_stop_loading (gis); - icon = gnome_icon_selection_get_icon (gis, TRUE); - - if (icon != NULL) { - entry = nautilus_mime_type_icon_entry_gtk_entry (icon_entry); - gtk_entry_set_text (GTK_ENTRY (entry), icon); - entry_changed (NULL, icon_entry); - - path = nautilus_mime_type_icon_entry_get_relative_filename (NAUTILUS_MIME_ICON_ENTRY (icon_entry)); - if (path != NULL) { - filename = strrchr (path, '/'); - if (filename != NULL) { - filename++; - mime_type = nautilus_mime_type_capplet_get_selected_item_mime_type (); - gnome_vfs_mime_set_icon (mime_type, filename); - nautilus_mime_type_capplet_update_mime_list_icon (mime_type); - } - g_free (path); - } - } -} - -static void cancel_pressed (GtkButton * button, NautilusMimeIconEntry * icon_entry) { GnomeIconSelection * gis; @@ -322,31 +290,6 @@ cancel_pressed (GtkButton * button, NautilusMimeIconEntry * icon_entry) } -static void -gil_icon_selected_cb (GnomeIconList *gil, gint num, GdkEvent *event, NautilusMimeIconEntry *icon_entry) -{ - const gchar * icon; - GnomeIconSelection * gis; - - g_return_if_fail (icon_entry != NULL); - g_return_if_fail (NAUTILUS_MIME_IS_ICON_ENTRY (icon_entry)); - - gis = gtk_object_get_user_data(GTK_OBJECT(icon_entry)); - icon = gnome_icon_selection_get_icon(gis, TRUE); - - if (icon != NULL) { - GtkWidget *e = nautilus_mime_type_icon_entry_gtk_entry(icon_entry); - gtk_entry_set_text(GTK_ENTRY(e),icon); - - } - - if(event && event->type == GDK_2BUTTON_PRESS && ((GdkEventButton *)event)->button == 1) { - gnome_icon_selection_stop_loading(gis); - entry_changed (NULL, icon_entry); - gtk_widget_hide(icon_entry->pick_dialog); - } -} - void nautilus_mime_type_show_icon_selection (NautilusMimeIconEntry *icon_entry) { @@ -360,7 +303,7 @@ nautilus_mime_type_show_icon_selection (NautilusMimeIconEntry *icon_entry) fe = GNOME_FILE_ENTRY (icon_entry->fentry); p = gnome_file_entry_get_full_path (fe, FALSE); - curfile = nautilus_mime_type_icon_entry_get_filename (icon_entry); + curfile = nautilus_mime_type_icon_entry_get_full_filename (icon_entry); /* Are we part of a modal window? If so, we need to be modal too. */ tl = gtk_widget_get_toplevel (GTK_WIDGET (icon_entry->frame)); @@ -434,12 +377,12 @@ nautilus_mime_type_show_icon_selection (NautilusMimeIconEntry *icon_entry) gtk_object_set_user_data(GTK_OBJECT(icon_entry), iconsel); gnome_icon_selection_add_directory (GNOME_ICON_SELECTION(iconsel), icon_entry->pick_dialog_dir); - - /* Hide the file entry until we figure out how to deal with icon paths - outside of the standard gnome paths */ - /*gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (icon_entry->pick_dialog)->vbox), + + gtk_window_set_title (GTK_WINDOW (icon_entry->pick_dialog), _("Select an icon")); + + gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (icon_entry->pick_dialog)->vbox), icon_entry->fentry, FALSE, FALSE, 0); - */ + gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(icon_entry->pick_dialog)->vbox), iconsel, TRUE, TRUE, 0); @@ -451,17 +394,15 @@ nautilus_mime_type_show_icon_selection (NautilusMimeIconEntry *icon_entry) gnome_icon_selection_select_icon(GNOME_ICON_SELECTION(iconsel), g_filename_pointer(curfile)); - gnome_dialog_button_connect(GNOME_DIALOG (icon_entry->pick_dialog), - 0, /* OK button */ - GTK_SIGNAL_FUNC (icon_selected_cb), - icon_entry); + /* FIXME: + * OK button is handled by caller, Cancel button is handled here. + * This could be cleaned up further. + */ gnome_dialog_button_connect(GNOME_DIALOG(icon_entry->pick_dialog), 1, /* Cancel button */ GTK_SIGNAL_FUNC(cancel_pressed), icon_entry); - gtk_signal_connect_after(GTK_OBJECT(GNOME_ICON_SELECTION(iconsel)->gil), "select_icon", - GTK_SIGNAL_FUNC(gil_icon_selected_cb), - icon_entry); + } else { GnomeIconSelection *gis = gtk_object_get_user_data(GTK_OBJECT(icon_entry)); @@ -476,27 +417,24 @@ nautilus_mime_type_show_icon_selection (NautilusMimeIconEntry *icon_entry) gchar * nautilus_mime_type_icon_entry_get_relative_filename (NautilusMimeIconEntry *ientry) { - char *filename; - char **path_parts; - - - filename = nautilus_mime_type_icon_entry_get_filename (NAUTILUS_MIME_ICON_ENTRY (ientry)); - - path_parts = g_strsplit (filename, "/share/pixmaps/", 0); - g_free (filename); - filename = NULL; + char *filename; + char *result; + char **path_parts; + + result = NULL; + filename = nautilus_mime_type_icon_entry_get_full_filename (NAUTILUS_MIME_ICON_ENTRY (ientry)); + if (filename != NULL) { + path_parts = g_strsplit (filename, "/share/pixmaps/", 0); + g_free (filename); + + if (path_parts[1] != NULL) { + result = g_strdup (path_parts[1]); + } - if (path_parts[1] != NULL) { - filename = g_strdup (path_parts[1]); - } else { - /* FIXME: bugzilla.eazel.com 4797 */ - g_warning ("user picked up an icon not in $(prefix)/share/pixmaps\n"); - filename = g_strdup (""); + g_strfreev (path_parts); } - g_strfreev (path_parts); - - return filename; + return result; } static void @@ -690,7 +628,7 @@ nautilus_mime_type_icon_entry_set_icon (NautilusMimeIconEntry *ientry, const gch } /** - * nautilus_mime_type_icon_entry_get_filename: + * nautilus_mime_type_icon_entry_get_full_filename: * @ientry: the NautilusMimeIconEntry to work with * * Description: Gets the file name of the image if it was possible @@ -701,7 +639,7 @@ nautilus_mime_type_icon_entry_set_icon (NautilusMimeIconEntry *ientry, const gch * couldn't load the file **/ gchar * -nautilus_mime_type_icon_entry_get_filename (NautilusMimeIconEntry *ientry) +nautilus_mime_type_icon_entry_get_full_filename (NautilusMimeIconEntry *ientry) { GtkWidget *child; diff --git a/capplets/file-types/file-types-icon-entry.h b/capplets/file-types/file-types-icon-entry.h index 7da6f0301..1ffb954fe 100644 --- a/capplets/file-types/file-types-icon-entry.h +++ b/capplets/file-types/file-types-icon-entry.h @@ -63,7 +63,7 @@ GtkWidget *nautilus_mime_type_icon_entry_gnome_entry (NautilusMimeIconEntry *ien GtkWidget *nautilus_mime_type_icon_entry_gtk_entry (NautilusMimeIconEntry *ientry); /*only return a file if it was possible to load it with imlib*/ -gchar *nautilus_mime_type_icon_entry_get_filename (NautilusMimeIconEntry *ientry); +gchar *nautilus_mime_type_icon_entry_get_full_filename (NautilusMimeIconEntry *ientry); gchar *nautilus_mime_type_icon_entry_get_relative_filename (NautilusMimeIconEntry *ientry); void nautilus_mime_type_show_icon_selection (NautilusMimeIconEntry * ientry); diff --git a/capplets/file-types/libuuid/.cvsignore b/capplets/file-types/libuuid/.cvsignore new file mode 100644 index 000000000..051d1bd50 --- /dev/null +++ b/capplets/file-types/libuuid/.cvsignore @@ -0,0 +1,3 @@ +Makefile +Makefile.in +.deps diff --git a/capplets/file-types/libuuid/Makefile.am b/capplets/file-types/libuuid/Makefile.am new file mode 100644 index 000000000..b89fb23b5 --- /dev/null +++ b/capplets/file-types/libuuid/Makefile.am @@ -0,0 +1,27 @@ +NULL = + +noinst_LIBRARIES = libuuid.a + + +noinst_HEADERS = \ + uuid.h \ + uuidP.h \ + $(NULL) + +libuuid_a_SOURCES = \ + clear.c \ + compare.c \ + copy.c \ + gen_uuid.c \ + isnull.c \ + pack.c \ + parse.c \ + unpack.c \ + unparse.c \ + uuid_time.c \ + $(NULL) + +INCLUDES = \ + $(GLIB_CFLAGS) \ + $(WERROR) \ + $(NULL) diff --git a/capplets/file-types/libuuid/clear.c b/capplets/file-types/libuuid/clear.c new file mode 100644 index 000000000..32e26d4fb --- /dev/null +++ b/capplets/file-types/libuuid/clear.c @@ -0,0 +1,20 @@ +/* + * clear.c -- Clear a UUID + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include "string.h" + +#include "uuidP.h" + +void uuid_clear(uuid_t uu) +{ + memset(uu, 0, 16); +} + diff --git a/capplets/file-types/libuuid/compare.c b/capplets/file-types/libuuid/compare.c new file mode 100644 index 000000000..3d07b5dbc --- /dev/null +++ b/capplets/file-types/libuuid/compare.c @@ -0,0 +1,32 @@ +/* + * compare.c --- compare whether or not two UUID's are the same + * + * Returns 0 if the two UUID's are different, and 1 if they are the same. + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include "uuidP.h" +#include <string.h> + +#define UUCMP(u1,u2) if (u1 != u2) return((u1 < u2) ? -1 : 1); + +int uuid_compare(uuid_t uu1, uuid_t uu2) +{ + struct uuid uuid1, uuid2; + + uuid_unpack(uu1, &uuid1); + uuid_unpack(uu2, &uuid2); + + UUCMP(uuid1.time_low, uuid2.time_low); + UUCMP(uuid1.time_mid, uuid2.time_mid); + UUCMP(uuid1.time_hi_and_version, uuid2.time_hi_and_version); + UUCMP(uuid1.clock_seq, uuid2.clock_seq); + return memcmp(uuid1.node, uuid2.node, 6); +} + diff --git a/capplets/file-types/libuuid/copy.c b/capplets/file-types/libuuid/copy.c new file mode 100644 index 000000000..5d0efc4aa --- /dev/null +++ b/capplets/file-types/libuuid/copy.c @@ -0,0 +1,21 @@ +/* + * copy.c --- copy UUIDs + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include "uuidP.h" + +void uuid_copy(uuid_t uu1, uuid_t uu2) +{ + unsigned char *cp1, *cp2; + int i; + + for (i=0, cp1 = uu1, cp2 = uu2; i < 16; i++) + *cp1++ = *cp2++; +} diff --git a/capplets/file-types/libuuid/gen_uuid.c b/capplets/file-types/libuuid/gen_uuid.c new file mode 100644 index 000000000..1b3b88105 --- /dev/null +++ b/capplets/file-types/libuuid/gen_uuid.c @@ -0,0 +1,257 @@ +/* + * gen_uuid.c --- generate a DCE-compatible uuid + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include <config.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#ifdef HAVE_SYS_SOCKIO_H +#include <sys/sockio.h> +#endif +#ifdef HAVE_NET_IF_H +#include <net/if.h> +#endif +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif + +#include "uuidP.h" + +#ifdef HAVE_SRANDOM +#define srand(x) srandom(x) +#define rand() random() +#endif + +/* + * Generate a series of random bytes. Use /dev/urandom if possible, + * and if not, use srandom/random. + */ +static void get_random_bytes(void *buf, int nbytes) +{ + static int fd = -2; + int i; + char *cp = (char *) buf; + + if (fd == -2) { + fd = open("/dev/urandom", O_RDONLY); + srand((getpid() << 16) ^ getuid() ^ time(0)); + } + if (fd >= 0) { + while (nbytes > 0) { + i = read(fd, cp, nbytes); + if (i < 0) { + if ((errno == EINTR) || (errno == EAGAIN)) + continue; + break; + } + nbytes -= i; + cp += i; + } + } + if (nbytes == 0) + return; + + /* XXX put something better here if no /dev/random! */ + for (i=0; i < nbytes; i++) + *cp++ = rand() & 0xFF; + return; + +} + +/* + * Get the ethernet hardware address, if we can find it... + */ +static int get_node_id(unsigned char *node_id) +{ +#ifdef HAVE_NET_IF_H + int sd; + struct ifreq ifr, *ifrp; + struct ifconf ifc; + char buf[1024]; + int n, i; + unsigned char *a; + +/* + * BSD 4.4 defines the size of an ifreq to be + * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len + * However, under earlier systems, sa_len isn't present, so the size is + * just sizeof(struct ifreq) + */ +#ifdef HAVE_SA_LEN +#ifndef max +#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif +#define ifreq_size(i) max(sizeof(struct ifreq),\ + sizeof((i).ifr_name)+(i).ifr_addr.sa_len) +#else +#define ifreq_size(i) sizeof(struct ifreq) +#endif /* HAVE_SA_LEN*/ + + sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (sd < 0) { + return -1; + } + memset(buf, 0, sizeof(buf)); + ifc.ifc_len = sizeof(buf); + ifc.ifc_buf = buf; + if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) { + close(sd); + return -1; + } + n = ifc.ifc_len; + for (i = 0; i < n; i+= ifreq_size(*ifr) ) { + ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i); + strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ); +#ifdef SIOCGIFHWADDR + if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0) + continue; + a = (unsigned char *) &ifr.ifr_hwaddr.sa_data; +#else +#ifdef SIOCGENADDR + if (ioctl(sd, SIOCGENADDR, &ifr) < 0) + continue; + a = (unsigned char *) ifr.ifr_enaddr; +#else + /* + * XXX we don't have a way of getting the hardware + * address + */ + close(sd); + return 0; +#endif /* SIOCGENADDR */ +#endif /* SIOCGIFHWADDR */ + if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) + continue; + if (node_id) { + memcpy(node_id, a, 6); + close(sd); + return 1; + } + } + close(sd); +#endif + return 0; +} + +/* Assume that the gettimeofday() has microsecond granularity */ +#define MAX_ADJUSTMENT 10 + +static int get_clock(guint32 *clock_high, guint32 *clock_low, guint16 *ret_clock_seq) +{ + static int adjustment = 0; + static struct timeval last = {0, 0}; + static guint16 clock_seq; + struct timeval tv; + unsigned long long clock_reg; + +try_again: + gettimeofday(&tv, 0); + if ((last.tv_sec == 0) && (last.tv_usec == 0)) { + get_random_bytes(&clock_seq, sizeof(clock_seq)); + clock_seq &= 0x1FFF; + last = tv; + last.tv_sec--; + } + if ((tv.tv_sec < last.tv_sec) || + ((tv.tv_sec == last.tv_sec) && + (tv.tv_usec < last.tv_usec))) { + clock_seq = (clock_seq+1) & 0x1FFF; + adjustment = 0; + } else if ((tv.tv_sec == last.tv_sec) && + (tv.tv_usec == last.tv_usec)) { + if (adjustment >= MAX_ADJUSTMENT) + goto try_again; + adjustment++; + } else + adjustment = 0; + + clock_reg = tv.tv_usec*10 + adjustment; + clock_reg += ((unsigned long long) tv.tv_sec)*10000000; + clock_reg += (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000; + + *clock_high = clock_reg >> 32; + *clock_low = clock_reg; + *ret_clock_seq = clock_seq; + return 0; +} + +void uuid_generate_time(uuid_t out) +{ + static unsigned char node_id[6]; + static int has_init = 0; + struct uuid uu; + guint32 clock_mid; + + if (!has_init) { + if (get_node_id(node_id) <= 0) { + get_random_bytes(node_id, 6); + /* + * Set multicast bit, to prevent conflicts + * with IEEE 802 addresses obtained from + * network cards + */ + node_id[0] |= 0x80; + } + has_init = 1; + } + get_clock(&clock_mid, &uu.time_low, &uu.clock_seq); + uu.clock_seq |= 0x8000; + uu.time_mid = (guint16) clock_mid; + uu.time_hi_and_version = (clock_mid >> 16) | 0x1000; + memcpy(uu.node, node_id, 6); + uuid_pack(&uu, out); +} + +void uuid_generate_random(uuid_t out) +{ + uuid_t buf; + struct uuid uu; + + get_random_bytes(buf, sizeof(buf)); + uuid_unpack(buf, &uu); + + uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000; + uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x4000; + uuid_pack(&uu, out); +} + +/* + * This is the generic front-end to uuid_generate_random and + * uuid_generate_time. It uses uuid_generate_random only if + * /dev/urandom is available, since otherwise we won't have + * high-quality randomness. + */ +void uuid_generate(uuid_t out) +{ + static int has_random = -1; + + if (has_random < 0) { + if (access("/dev/urandom", R_OK) == 0) + has_random = 1; + else + has_random = 0; + } + if (has_random) + uuid_generate_random(out); + else + uuid_generate_time(out); +} + diff --git a/capplets/file-types/libuuid/gen_uuid_nt.c b/capplets/file-types/libuuid/gen_uuid_nt.c new file mode 100644 index 000000000..6092c070d --- /dev/null +++ b/capplets/file-types/libuuid/gen_uuid_nt.c @@ -0,0 +1,92 @@ +/*
+ * gen_uuid_nt.c -- Use NT api to generate uuid
+ *
+ * Written by Andrey Shedel (andreys@ns.cr.cyco.com)
+ */
+
+
+#include "uuidP.h"
+
+#pragma warning(push,4)
+
+#pragma comment(lib, "ntdll.lib")
+
+//
+// Here is a nice example why it's not a good idea
+// to use native API in ordinary applications.
+// Number of parameters in function below was changed from 3 to 4
+// for NT5.
+//
+//
+// NTSYSAPI
+// NTSTATUS
+// NTAPI
+// NtAllocateUuids(
+// OUT PULONG p1,
+// OUT PULONG p2,
+// OUT PULONG p3,
+// OUT PUCHAR Seed // 6 bytes
+// );
+//
+//
+
+unsigned long
+__stdcall
+NtAllocateUuids(
+ void* p1, // 8 bytes
+ void* p2, // 4 bytes
+ void* p3 // 4 bytes
+ );
+
+typedef
+unsigned long
+(__stdcall*
+NtAllocateUuids_2000)(
+ void* p1, // 8 bytes
+ void* p2, // 4 bytes
+ void* p3, // 4 bytes
+ void* seed // 6 bytes
+ );
+
+
+
+//
+// Nice, but instead of including ntddk.h ot winnt.h
+// I should define it here because they MISSED __stdcall in those headers.
+//
+
+__declspec(dllimport)
+struct _TEB*
+__stdcall
+NtCurrentTeb(void);
+
+
+//
+// The only way to get version information from the system is to examine
+// one stored in PEB. But it's pretty dangerouse because this value could
+// be altered in image header.
+//
+
+static
+int
+Nt5(void)
+{
+ //return NtCuttentTeb()->Peb->OSMajorVersion >= 5;
+ return (int)*(int*)((char*)(int)(*(int*)((char*)NtCurrentTeb() + 0x30)) + 0xA4) >= 5;
+}
+
+
+
+
+void uuid_generate(uuid_t out)
+{
+ if(Nt5())
+ {
+ unsigned char seed[6];
+ ((NtAllocateUuids_2000)NtAllocateUuids)(out, ((char*)out)+8, ((char*)out)+12, &seed[0] );
+ }
+ else
+ {
+ NtAllocateUuids(out, ((char*)out)+8, ((char*)out)+12);
+ }
+}
diff --git a/capplets/file-types/libuuid/isnull.c b/capplets/file-types/libuuid/isnull.c new file mode 100644 index 000000000..43b81f879 --- /dev/null +++ b/capplets/file-types/libuuid/isnull.c @@ -0,0 +1,25 @@ +/* + * isnull.c --- Check whether or not the UUID is null + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include "uuidP.h" + +/* Returns 1 if the uuid is the NULL uuid */ +int uuid_is_null(uuid_t uu) +{ + unsigned char *cp; + int i; + + for (i=0, cp = uu; i < 16; i++) + if (*cp++) + return 0; + return 1; +} + diff --git a/capplets/file-types/libuuid/pack.c b/capplets/file-types/libuuid/pack.c new file mode 100644 index 000000000..94be488aa --- /dev/null +++ b/capplets/file-types/libuuid/pack.c @@ -0,0 +1,46 @@ +/* + * Internal routine for packing UUID's + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include <string.h> +#include "uuidP.h" + +void uuid_pack(struct uuid *uu, uuid_t ptr) +{ + guint32 tmp; + unsigned char *out = ptr; + + tmp = uu->time_low; + out[3] = (unsigned char) tmp; + tmp >>= 8; + out[2] = (unsigned char) tmp; + tmp >>= 8; + out[1] = (unsigned char) tmp; + tmp >>= 8; + out[0] = (unsigned char) tmp; + + tmp = uu->time_mid; + out[5] = (unsigned char) tmp; + tmp >>= 8; + out[4] = (unsigned char) tmp; + + tmp = uu->time_hi_and_version; + out[7] = (unsigned char) tmp; + tmp >>= 8; + out[6] = (unsigned char) tmp; + + tmp = uu->clock_seq; + out[9] = (unsigned char) tmp; + tmp >>= 8; + out[8] = (unsigned char) tmp; + + memcpy(out+10, uu->node, 6); +} + diff --git a/capplets/file-types/libuuid/parse.c b/capplets/file-types/libuuid/parse.c new file mode 100644 index 000000000..ea6ce7909 --- /dev/null +++ b/capplets/file-types/libuuid/parse.c @@ -0,0 +1,52 @@ +/* + * parse.c --- UUID parsing + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> + +#include "uuidP.h" + +int uuid_parse(char *in, uuid_t uu) +{ + struct uuid uuid; + int i; + char *cp, buf[3]; + + if (strlen(in) != 36) + return -1; + for (i=0, cp = in; i <= 36; i++,cp++) { + if ((i == 8) || (i == 13) || (i == 18) || + (i == 23)) + if (*cp == '-') + continue; + if (i== 36) + if (*cp == 0) + continue; + if (!isxdigit((guchar) *cp)) + return -1; + } + uuid.time_low = strtoul(in, NULL, 16); + uuid.time_mid = strtoul(in+9, NULL, 16); + uuid.time_hi_and_version = strtoul(in+14, NULL, 16); + uuid.clock_seq = strtoul(in+19, NULL, 16); + cp = in+24; + buf[2] = 0; + for (i=0; i < 6; i++) { + buf[0] = *cp++; + buf[1] = *cp++; + uuid.node[i] = strtoul(buf, NULL, 16); + } + + uuid_pack(&uuid, uu); + return 0; +} diff --git a/capplets/file-types/libuuid/tst_uuid.c b/capplets/file-types/libuuid/tst_uuid.c new file mode 100644 index 000000000..b9fc5f69a --- /dev/null +++ b/capplets/file-types/libuuid/tst_uuid.c @@ -0,0 +1,119 @@ +/* + * tst_uuid.c --- test program from the UUID library + * + * Copyright (C) 1996, 1997, 1998 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include <stdio.h> +#include <linux/ext2_fs.h> + +#include "uuid.h" + +int +main(int argc, char **argv) +{ + uuid_t buf, tst; + char str[100]; + struct timeval tv; + time_t time_reg; + unsigned char *cp; + int i; + int failed = 0; + int type, variant; + + uuid_generate(buf); + uuid_unparse(buf, str); + printf("UUID generate = %s\n", str); + printf("UUID: "); + for (i=0, cp = (unsigned char *) &buf; i < 16; i++) { + printf("%02x", *cp++); + } + printf("\n"); + type = uuid_type(buf); variant = uuid_variant(buf); + printf("UUID type = %d, UUID variant = %d\n", type, variant); + if (variant != UUID_VARIANT_DCE) { + printf("Incorrect UUID Variant; was expecting DCE!\n"); + failed++; + } + printf("\n"); + + uuid_generate_random(buf); + uuid_unparse(buf, str); + printf("UUID random string = %s\n", str); + printf("UUID: "); + for (i=0, cp = (unsigned char *) &buf; i < 16; i++) { + printf("%02x", *cp++); + } + printf("\n"); + type = uuid_type(buf); variant = uuid_variant(buf); + printf("UUID type = %d, UUID variant = %d\n", type, variant); + if (variant != UUID_VARIANT_DCE) { + printf("Incorrect UUID Variant; was expecting DCE!\n"); + failed++; + } + if (type != 4) { + printf("Incorrect UUID type; was expecting " + "4 (random type)!\n"); + failed++; + } + printf("\n"); + + uuid_generate_time(buf); + uuid_unparse(buf, str); + printf("UUID string = %s\n", str); + printf("UUID time: "); + for (i=0, cp = (unsigned char *) &buf; i < 16; i++) { + printf("%02x", *cp++); + } + printf("\n"); + type = uuid_type(buf); variant = uuid_variant(buf); + printf("UUID type = %d, UUID variant = %d\n", type, variant); + if (variant != UUID_VARIANT_DCE) { + printf("Incorrect UUID Variant; was expecting DCE!\n"); + failed++; + } + if (type != 1) { + printf("Incorrect UUID type; was expecting " + "1 (time-based type)!\\n"); + failed++; + } + tv.tv_sec = 0; + tv.tv_usec = 0; + time_reg = uuid_time(buf, &tv); + printf("UUID time is: (%d, %d): %s\n", tv.tv_sec, tv.tv_usec, + ctime(&time_reg)); + uuid_parse(str, tst); + if (!uuid_compare(buf, tst)) + printf("UUID parse and compare succeeded.\n"); + else { + printf("UUID parse and compare failed!\n"); + failed++; + } + uuid_clear(tst); + if (uuid_is_null(tst)) + printf("UUID clear and is null succeeded.\n"); + else { + printf("UUID clear and is null failed!\n"); + failed++; + } + uuid_copy(buf, tst); + if (!uuid_compare(buf, tst)) + printf("UUID copy and compare succeeded.\n"); + else { + printf("UUID copy and compare failed!\n"); + failed++; + } + if (failed) { + printf("%d failures.\n", failed); + exit(1); + } + return 0; +} + + + diff --git a/capplets/file-types/libuuid/unpack.c b/capplets/file-types/libuuid/unpack.c new file mode 100644 index 000000000..8a80a9962 --- /dev/null +++ b/capplets/file-types/libuuid/unpack.c @@ -0,0 +1,40 @@ +/* + * Internal routine for unpacking UUID + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include <string.h> +#include "uuidP.h" + +void uuid_unpack(uuid_t in, struct uuid *uu) +{ + guint8 *ptr = in; + guint32 tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + tmp = (tmp << 8) | *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->time_low = tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->time_mid = tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->time_hi_and_version = tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->clock_seq = tmp; + + memcpy(uu->node, ptr, 6); +} + diff --git a/capplets/file-types/libuuid/unparse.c b/capplets/file-types/libuuid/unparse.c new file mode 100644 index 000000000..ab904bc16 --- /dev/null +++ b/capplets/file-types/libuuid/unparse.c @@ -0,0 +1,28 @@ +/* + * unparse.c -- convert a UUID to string + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include <stdio.h> + +#include "uuidP.h" + +void uuid_unparse(uuid_t uu, char *out) +{ + struct uuid uuid; + + uuid_unpack(uu, &uuid); + sprintf(out, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, + uuid.clock_seq >> 8, uuid.clock_seq & 0xFF, + uuid.node[0], uuid.node[1], uuid.node[2], + uuid.node[3], uuid.node[4], uuid.node[5]); +} + diff --git a/capplets/file-types/libuuid/uuid.h b/capplets/file-types/libuuid/uuid.h new file mode 100644 index 000000000..12afabffe --- /dev/null +++ b/capplets/file-types/libuuid/uuid.h @@ -0,0 +1,50 @@ +/* + * Public include file for the UUID library + * + * Copyright (C) 1996, 1997, 1998 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include <sys/types.h> +#include <sys/time.h> +#include <time.h> + +typedef unsigned char uuid_t[16]; + +/* UUID Variant definitions */ +#define UUID_VARIANT_NCS 0 +#define UUID_VARIANT_DCE 1 +#define UUID_VARIANT_MICROSOFT 2 +#define UUID_VARIANT_OTHER 3 + +/* clear.c */ +void uuid_clear(uuid_t uu); + +/* compare.c */ +int uuid_compare(uuid_t uu1, uuid_t uu2); + +/* copy.c */ +void uuid_copy(uuid_t uu1, uuid_t uu2); + +/* gen_uuid.c */ +void uuid_generate(uuid_t out); +void uuid_generate_random(uuid_t out); +void uuid_generate_time(uuid_t out); + +/* isnull.c */ +int uuid_is_null(uuid_t uu); + +/* parse.c */ +int uuid_parse(char *in, uuid_t uu); + +/* unparse.c */ +void uuid_unparse(uuid_t uu, char *out); + +/* uuid_time.c */ +time_t uuid_time(uuid_t uu, struct timeval *ret_tv); +int uuid_type(uuid_t uu); +int uuid_variant(uuid_t uu); diff --git a/capplets/file-types/libuuid/uuidP.h b/capplets/file-types/libuuid/uuidP.h new file mode 100644 index 000000000..995db687c --- /dev/null +++ b/capplets/file-types/libuuid/uuidP.h @@ -0,0 +1,40 @@ +/* + * uuid.h -- private header file for uuids + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include <sys/types.h> +#include <glib.h> + +#include "uuid.h" + +/* + * Offset between 15-Oct-1582 and 1-Jan-70 + */ +#define TIME_OFFSET_HIGH 0x01B21DD2 +#define TIME_OFFSET_LOW 0x13814000 + +struct uuid { + guint32 time_low; + guint16 time_mid; + guint16 time_hi_and_version; + guint16 clock_seq; + guint8 node[6]; +}; + + +/* + * prototypes + */ +void uuid_pack(struct uuid *uu, uuid_t ptr); +void uuid_unpack(uuid_t in, struct uuid *uu); + + + + diff --git a/capplets/file-types/libuuid/uuid_time.c b/capplets/file-types/libuuid/uuid_time.c new file mode 100644 index 000000000..9a302202a --- /dev/null +++ b/capplets/file-types/libuuid/uuid_time.c @@ -0,0 +1,138 @@ +/* + * uuid_time.c --- Interpret the time field from a uuid. This program + * violates the UUID abstraction barrier by reaching into the guts + * of a UUID and interpreting it. + * + * Copyright (C) 1998, 1999 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/time.h> +#include <time.h> + +#include "uuidP.h" + +time_t uuid_time(uuid_t uu, struct timeval *ret_tv) +{ + struct uuid uuid; + guint32 high; + struct timeval tv; + unsigned long long clock_reg; + + uuid_unpack(uu, &uuid); + + high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16); + clock_reg = uuid.time_low | ((unsigned long long) high << 32); + + clock_reg -= (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000; + tv.tv_sec = clock_reg / 10000000; + tv.tv_usec = (clock_reg % 10000000) / 10; + + if (ret_tv) + *ret_tv = tv; + + return tv.tv_sec; +} + +int uuid_type(uuid_t uu) +{ + struct uuid uuid; + + uuid_unpack(uu, &uuid); + return ((uuid.time_hi_and_version >> 12) & 0xF); +} + +int uuid_variant(uuid_t uu) +{ + struct uuid uuid; + int var; + + uuid_unpack(uu, &uuid); + var = uuid.clock_seq; + + if ((var & 0x8000) == 0) + return UUID_VARIANT_NCS; + if ((var & 0x4000) == 0) + return UUID_VARIANT_DCE; + if ((var & 0x2000) == 0) + return UUID_VARIANT_MICROSOFT; + return UUID_VARIANT_OTHER; +} + +#ifdef DEBUG +static const char *variant_string(int variant) +{ + switch (variant) { + case UUID_VARIANT_NCS: + return "NCS"; + case UUID_VARIANT_DCE: + return "DCE"; + case UUID_VARIANT_MICROSOFT: + return "Microsoft"; + default: + return "Other"; + } +} + + +int +main(int argc, char **argv) +{ + uuid_t buf; + time_t time_reg; + struct timeval tv; + int type, variant; + + if (argc != 2) { + fprintf(stderr, "Usage: %s uuid\n", argv[0]); + exit(1); + } + if (uuid_parse(argv[1], buf)) { + fprintf(stderr, "Invalid UUID: %s\n", argv[1]); + exit(1); + } + variant = uuid_variant(buf); + type = uuid_type(buf); + time_reg = uuid_time(buf, &tv); + + printf("UUID variant is %d (%s)\n", variant, variant_string(variant)); + if (variant != UUID_VARIANT_DCE) { + printf("Warning: This program only knows how to interpret " + "DCE UUIDs.\n\tThe rest of the output is likely " + "to be incorrect!!\n"); + } + printf("UUID type is %d", type); + switch (type) { + case 1: + printf(" (time based)\n"); + break; + case 2: + printf(" (DCE)\n"); + break; + case 3: + printf(" (name-based)\n"); + break; + case 4: + printf(" (random)\n"); + break; + default: + printf("\n"); + } + if (type != 1) { + printf("Warning: not a time-based UUID, so UUID time " + "decoding will likely not work!\n"); + } + printf("UUID time is: (%u, %u): %s\n", (unsigned)tv.tv_sec, (unsigned)tv.tv_usec, + ctime(&time_reg)); + + return 0; +} +#endif diff --git a/capplets/file-types/nautilus-mime-type.desktop b/capplets/file-types/nautilus-mime-type.desktop deleted file mode 100644 index 93e0278d1..000000000 --- a/capplets/file-types/nautilus-mime-type.desktop +++ /dev/null @@ -1,21 +0,0 @@ -[Desktop Entry] -Name=File Types and Programs -Name[pt_BR]=Tipos de Arquivos e Programas -Name[da]=Filtyper og programmer -Name[fi]=Tiedostotyypit ja ohjelmat -Name[fr]=Type de fichiers et programmes -Name[no]=Filtyper og programmer -Name[sk]=Typy súborov a programy -Name[tr]=Dosya türleri ve uygulamarı -Comment=We need a good explanation here. -Comment[fi]=Aseta, millä ohjelmilla tietyn tyyppisiä tiedostoja käsitellään. -Comment[pt_BR]=Precisamos de uma boa explicação aqui. -Comment[da]=Vi har brug for en god forklaring her. -Comment[fr]=Éditeur d'association de type de fichiers et d'applications -Comment[no]=Koblinger mellom filtyper og programmer -Comment[sk]=Sem by to chcelo nejaké rozumné vysvetlenie... -Comment[tr]=Eh, buraya da iyi bir anlatım gerek ... -Icon=gnome-ccmime.png -Exec=nautilus-mime-type-capplet -Terminal=0 -Type=Application |