Index: thunar/thunar-chooser-button.c =================================================================== --- thunar/thunar-chooser-button.c (revision 28984) +++ thunar/thunar-chooser-button.c (working copy) @@ -39,45 +39,62 @@ PROP_FILE, }; +enum +{ + THUNAR_CHOOSER_BUTTON_STORE_COLUMN_NAME, + THUNAR_CHOOSER_BUTTON_STORE_COLUMN_PIXBUF, + THUNAR_CHOOSER_BUTTON_STORE_COLUMN_APPLICATION, + THUNAR_CHOOSER_BUTTON_STORE_COLUMN_SENSITIVE, + THUNAR_CHOOSER_BUTTON_STORE_COLUMN_STYLE, + THUNAR_CHOOSER_BUTTON_STORE_N_COLUMNS +}; -static void thunar_chooser_button_class_init (ThunarChooserButtonClass *klass); -static void thunar_chooser_button_init (ThunarChooserButton *chooser_button); -static void thunar_chooser_button_finalize (GObject *object); -static void thunar_chooser_button_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void thunar_chooser_button_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void thunar_chooser_button_activate (ThunarChooserButton *chooser_button, - GtkWidget *item); -static void thunar_chooser_button_activate_other (ThunarChooserButton *chooser_button); -static void thunar_chooser_button_file_changed (ThunarChooserButton *chooser_button, - ThunarFile *file); -static void thunar_chooser_button_pressed (ThunarChooserButton *chooser_button, - GtkWidget *button); +static void thunar_chooser_button_class_init (ThunarChooserButtonClass *klass); +static void thunar_chooser_button_init (ThunarChooserButton *chooser_button); +static void thunar_chooser_button_finalize (GObject *object); +static void thunar_chooser_button_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void thunar_chooser_button_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static gboolean thunar_chooser_button_scroll_event (GtkWidget *widget, + GdkEventScroll *event); +static void thunar_chooser_button_changed (GtkComboBox *combo_box); +#if GTK_CHECK_VERSION (2, 12, 0) +static void thunar_chooser_button_popup (ThunarChooserButton *chooser_button); +#endif +static gint thunar_chooser_button_sort_applications (gconstpointer a, + gconstpointer b); +static gboolean thunar_chooser_button_row_separator (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data); +static void thunar_chooser_button_chooser_dialog (ThunarChooserButton *chooser_button); +static void thunar_chooser_button_file_changed (ThunarChooserButton *chooser_button, + ThunarFile *file); + struct _ThunarChooserButtonClass { - GtkHBoxClass __parent__; + GtkComboBoxClass __parent__; }; struct _ThunarChooserButton { - GtkHBox __parent__; + GtkComboBox __parent__; - GtkWidget *image; - GtkWidget *label; - GtkWidget *button; + GtkListStore *store; ThunarFile *file; ThunarVfsMimeDatabase *database; + + gboolean has_default_application; }; @@ -107,7 +124,7 @@ NULL, }; - type = g_type_register_static (GTK_TYPE_HBOX, I_("ThunarChooserButton"), &info, 0); + type = g_type_register_static (GTK_TYPE_COMBO_BOX, I_("ThunarChooserButton"), &info, 0); } return type; @@ -118,7 +135,8 @@ static void thunar_chooser_button_class_init (ThunarChooserButtonClass *klass) { - GObjectClass *gobject_class; + GObjectClass *gobject_class; + GtkWidgetClass *gtkwidget_class; /* determine the parent type class */ thunar_chooser_button_parent_class = g_type_class_peek_parent (klass); @@ -128,6 +146,9 @@ gobject_class->get_property = thunar_chooser_button_get_property; gobject_class->set_property = thunar_chooser_button_set_property; + gtkwidget_class = GTK_WIDGET_CLASS (klass); + gtkwidget_class->scroll_event = thunar_chooser_button_scroll_event; + /** * ThunarChooserButton:file: * @@ -146,41 +167,36 @@ static void thunar_chooser_button_init (ThunarChooserButton *chooser_button) { - GtkWidget *separator; - GtkWidget *arrow; - GtkWidget *hbox; + GtkCellRenderer *renderer; /* grab a reference on the mime database */ chooser_button->database = thunar_vfs_mime_database_get_default (); - gtk_widget_push_composite_child (); + /* allocate a new store for the combo box */ + chooser_button->store = gtk_list_store_new (THUNAR_CHOOSER_BUTTON_STORE_N_COLUMNS, G_TYPE_STRING, GDK_TYPE_PIXBUF, + G_TYPE_OBJECT, G_TYPE_BOOLEAN, PANGO_TYPE_STYLE); + gtk_combo_box_set_model (GTK_COMBO_BOX (chooser_button), GTK_TREE_MODEL (chooser_button->store)); + g_signal_connect (G_OBJECT (chooser_button), "changed", G_CALLBACK (thunar_chooser_button_changed), NULL); +#if GTK_CHECK_VERSION (2, 12, 0) + g_signal_connect (G_OBJECT (chooser_button), "popup", G_CALLBACK (thunar_chooser_button_popup), NULL); +#endif - chooser_button->button = gtk_button_new (); - g_signal_connect_swapped (G_OBJECT (chooser_button->button), "pressed", G_CALLBACK (thunar_chooser_button_pressed), chooser_button); - gtk_box_pack_start (GTK_BOX (chooser_button), chooser_button->button, TRUE, TRUE, 0); - gtk_widget_show (chooser_button->button); + /* set the separator function */ + gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (chooser_button), thunar_chooser_button_row_separator, NULL, NULL); - hbox = gtk_hbox_new (FALSE, 4); - gtk_container_add (GTK_CONTAINER (chooser_button->button), hbox); - gtk_widget_show (hbox); + /* add renderers */ + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (chooser_button), renderer, FALSE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (chooser_button), renderer, + "pixbuf", THUNAR_CHOOSER_BUTTON_STORE_COLUMN_PIXBUF, + "sensitive", THUNAR_CHOOSER_BUTTON_STORE_COLUMN_SENSITIVE, NULL); - chooser_button->image = gtk_image_new (); - gtk_box_pack_start (GTK_BOX (hbox), chooser_button->image, FALSE, FALSE, 0); - gtk_widget_show (chooser_button->image); - - chooser_button->label = g_object_new (GTK_TYPE_LABEL, "xalign", 0.0f, "yalign", 0.0f, NULL); - gtk_box_pack_start (GTK_BOX (hbox), chooser_button->label, TRUE, TRUE, 0); - gtk_widget_show (chooser_button->label); - - separator = g_object_new (GTK_TYPE_VSEPARATOR, "height-request", 16, NULL); - gtk_box_pack_start (GTK_BOX (hbox), separator, FALSE, FALSE, 0); - gtk_widget_show (separator); - - arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); - gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 0); - gtk_widget_show (arrow); - - gtk_widget_pop_composite_child (); + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (chooser_button), renderer, FALSE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (chooser_button), renderer, + "text", THUNAR_CHOOSER_BUTTON_STORE_COLUMN_NAME, + "sensitive", THUNAR_CHOOSER_BUTTON_STORE_COLUMN_SENSITIVE, + "style", THUNAR_CHOOSER_BUTTON_STORE_COLUMN_STYLE, NULL); } @@ -196,6 +212,9 @@ /* disconnect from the mime database */ g_object_unref (G_OBJECT (chooser_button->database)); + /* release the store */ + g_object_unref (G_OBJECT (chooser_button->store)); + (*G_OBJECT_CLASS (thunar_chooser_button_parent_class)->finalize) (object); } @@ -245,175 +264,161 @@ +static gboolean +thunar_chooser_button_scroll_event (GtkWidget *widget, + GdkEventScroll *event) +{ + ThunarChooserButton *chooser_button = THUNAR_CHOOSER_BUTTON (widget); + GtkTreeIter iter; + GObject *application; + GtkTreeModel *model = GTK_TREE_MODEL (chooser_button->store); + + /* check if the next application in the store is valid if we scroll down, + * else drop the event so we don't popup the chooser dailog */ + if (event->direction != GDK_SCROLL_UP + && gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter) + && gtk_tree_model_iter_next (model, &iter)) + { + gtk_tree_model_get (model, &iter, THUNAR_CHOOSER_BUTTON_STORE_COLUMN_APPLICATION, &application, -1); + if (application == NULL) + return FALSE; + g_object_unref (G_OBJECT (application)); + } + + return (*GTK_WIDGET_CLASS (thunar_chooser_button_parent_class)->scroll_event) (widget, event); +} + + + static void -thunar_chooser_button_activate (ThunarChooserButton *chooser_button, - GtkWidget *item) +thunar_chooser_button_changed (GtkComboBox *combo_box) { + ThunarChooserButton *chooser_button = THUNAR_CHOOSER_BUTTON (combo_box); + GtkTreeIter iter; ThunarVfsMimeApplication *application; ThunarVfsMimeInfo *info; GError *error = NULL; _thunar_return_if_fail (THUNAR_IS_CHOOSER_BUTTON (chooser_button)); - _thunar_return_if_fail (GTK_IS_MENU_ITEM (item)); + _thunar_return_if_fail (GTK_IS_LIST_STORE (chooser_button->store)); /* verify that we still have a valid file */ if (G_UNLIKELY (chooser_button->file == NULL)) return; - /* determine the application that was set for the item */ - application = g_object_get_data (G_OBJECT (item), "thunar-vfs-mime-application"); - if (G_UNLIKELY (application == NULL)) + /* get the selected item in the combo box */ + if (!gtk_combo_box_get_active_iter (combo_box, &iter)) return; - /* determine the mime info for the file */ - info = thunar_file_get_mime_info (chooser_button->file); + /* get the selected application from the store */ + gtk_tree_model_get (GTK_TREE_MODEL (chooser_button->store), &iter, + THUNAR_CHOOSER_BUTTON_STORE_COLUMN_APPLICATION, &application, -1); + if (G_LIKELY (application != NULL)) + { + /* determine the mime info for the file */ + info = thunar_file_get_mime_info (chooser_button->file); - /* try to set application as default for these kind of file */ - if (!thunar_vfs_mime_database_set_default_application (chooser_button->database, info, application, &error)) - { - /* tell the user that it didn't work */ - thunar_dialogs_show_error (GTK_WIDGET (chooser_button), error, _("Failed to set default application for \"%s\""), - thunar_file_get_display_name (chooser_button->file)); - g_error_free (error); + /* try to set application as default for this kind of file */ + if (!thunar_vfs_mime_database_set_default_application (chooser_button->database, info, application, &error)) + { + /* tell the user that it didn't work */ + thunar_dialogs_show_error (GTK_WIDGET (chooser_button), error, _("Failed to set default application for \"%s\""), + thunar_file_get_display_name (chooser_button->file)); + g_error_free (error); + } + else + { + /* emit "changed" on the file, so everybody updates its state */ + thunar_file_changed (chooser_button->file); + } + + /* release the application */ + g_object_unref (G_OBJECT (application)); } else { - /* emit "changed" on the file, so everybody updates its state */ - thunar_file_changed (chooser_button->file); + /* no application was found in the store, looks like the other... option */ + thunar_chooser_button_chooser_dialog (chooser_button); } } +#if GTK_CHECK_VERSION (2, 12, 0) static void -thunar_chooser_button_activate_other (ThunarChooserButton *chooser_button) +thunar_chooser_button_popup (ThunarChooserButton *chooser_button) { - GtkWidget *toplevel; - GtkWidget *dialog; + if (chooser_button->has_default_application == FALSE) + { + /* don't show the menu */ + gtk_combo_box_popdown (GTK_COMBO_BOX (chooser_button)); - _thunar_return_if_fail (THUNAR_IS_CHOOSER_BUTTON (chooser_button)); - - /* determine the toplevel window for the chooser */ - toplevel = gtk_widget_get_toplevel (GTK_WIDGET (chooser_button)); - if (G_UNLIKELY (toplevel == NULL)) - return; - - /* popup the application chooser dialog */ - dialog = g_object_new (THUNAR_TYPE_CHOOSER_DIALOG, "open", FALSE, NULL); - exo_binding_new (G_OBJECT (chooser_button), "file", G_OBJECT (dialog), "file"); - gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (toplevel)); - gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); - gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); + /* open the chooser dialog if the filetype has no default action */ + thunar_chooser_button_chooser_dialog (chooser_button); + } } +#endif -static void -thunar_chooser_button_file_changed (ThunarChooserButton *chooser_button, - ThunarFile *file) +static gint +thunar_chooser_button_sort_applications (gconstpointer a, + gconstpointer b) { - ThunarVfsMimeApplication *application; - ThunarVfsMimeInfo *info; - ThunarIconFactory *icon_factory; - GtkIconTheme *icon_theme; - const gchar *icon_name; - GdkPixbuf *icon = NULL; - gint icon_size; + return g_utf8_collate (thunar_vfs_mime_handler_get_name (THUNAR_VFS_MIME_HANDLER (a)), + thunar_vfs_mime_handler_get_name (THUNAR_VFS_MIME_HANDLER (b))); +} - _thunar_return_if_fail (THUNAR_IS_CHOOSER_BUTTON (chooser_button)); - _thunar_return_if_fail (chooser_button->file == file); - _thunar_return_if_fail (THUNAR_IS_FILE (file)); - /* determine the mime info for the file */ - info = thunar_file_get_mime_info (file); - /* determine the default application for that mime info */ - application = thunar_vfs_mime_database_get_default_application (chooser_button->database, info); - if (G_LIKELY (application != NULL)) - { - /* determine the icon size for menus */ - gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_size, &icon_size); +static gboolean +thunar_chooser_button_row_separator (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + gchar *name; - /* setup the image for the application */ - icon_factory = thunar_icon_factory_get_default (); - icon_theme = thunar_icon_factory_get_icon_theme (icon_factory); - icon_name = thunar_vfs_mime_handler_lookup_icon_name (THUNAR_VFS_MIME_HANDLER (application), icon_theme); - if (G_LIKELY (icon_name != NULL)) - icon = thunar_icon_factory_load_icon (icon_factory, icon_name, icon_size, NULL, FALSE); - gtk_image_set_from_pixbuf (GTK_IMAGE (chooser_button->image), icon); - g_object_unref (G_OBJECT (icon_factory)); - if (G_LIKELY (icon != NULL)) - g_object_unref (G_OBJECT (icon)); - - /* setup the label for the application */ - gtk_label_set_attributes (GTK_LABEL (chooser_button->label), NULL); - gtk_label_set_text (GTK_LABEL (chooser_button->label), thunar_vfs_mime_handler_get_name (THUNAR_VFS_MIME_HANDLER (application))); - - /* cleanup */ - g_object_unref (G_OBJECT (application)); - } - else + /* determine the value of the "name" column */ + gtk_tree_model_get (model, iter, THUNAR_CHOOSER_BUTTON_STORE_COLUMN_NAME, &name, -1); + if (G_LIKELY (name != NULL)) { - /* no default application specified */ - gtk_label_set_attributes (GTK_LABEL (chooser_button->label), thunar_pango_attr_list_italic ()); - gtk_label_set_text (GTK_LABEL (chooser_button->label), _("No application selected")); - gtk_image_set_from_pixbuf (GTK_IMAGE (chooser_button->image), NULL); + g_free (name); + return FALSE; } - /* setup a useful tooltip for the button */ - thunar_gtk_widget_set_tooltip (chooser_button->button, - _("The selected application is used to open " - "this and other files of type \"%s\"."), - thunar_vfs_mime_info_get_comment (info)); + return TRUE; } static void -menu_position (GtkMenu *menu, - gint *x, - gint *y, - gboolean *push_in, - gpointer chooser) +thunar_chooser_button_chooser_dialog (ThunarChooserButton *chooser_button) { - GtkRequisition chooser_request; - GtkRequisition menu_request; - GdkRectangle geometry; - GdkScreen *screen; - GtkWidget *toplevel = gtk_widget_get_toplevel (chooser); - gint monitor; - gint x0; - gint y0; + GtkWidget *toplevel; + GtkWidget *dialog; - gtk_widget_translate_coordinates (GTK_WIDGET (chooser), toplevel, 0, 0, &x0, &y0); + _thunar_return_if_fail (THUNAR_IS_CHOOSER_BUTTON (chooser_button)); - gtk_widget_size_request (GTK_WIDGET (chooser), &chooser_request); - gtk_widget_size_request (GTK_WIDGET (menu), &menu_request); + /* determine the toplevel window for the chooser */ + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (chooser_button)); + if (G_UNLIKELY (toplevel == NULL)) + return; - gdk_window_get_position (GTK_WIDGET (chooser)->window, x, y); - - *y += y0; - *x += x0; - - /* verify the the menu is on-screen */ - screen = gtk_widget_get_screen (GTK_WIDGET (chooser)); - if (G_LIKELY (screen != NULL)) - { - monitor = gdk_screen_get_monitor_at_point (screen, *x, *y); - gdk_screen_get_monitor_geometry (screen, monitor, &geometry); - if (*y + menu_request.height > geometry.y + geometry.height) - *y -= menu_request.height - chooser_request.height; - } - - *push_in = TRUE; + /* popup the application chooser dialog */ + dialog = g_object_new (THUNAR_TYPE_CHOOSER_DIALOG, "open", FALSE, NULL); + exo_binding_new (G_OBJECT (chooser_button), "file", G_OBJECT (dialog), "file"); + gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (toplevel)); + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_ACCEPT) + thunar_chooser_button_file_changed (chooser_button, chooser_button->file); + gtk_widget_destroy (dialog); } static void -thunar_chooser_button_pressed (ThunarChooserButton *chooser_button, - GtkWidget *button) +thunar_chooser_button_file_changed (ThunarChooserButton *chooser_button, + ThunarFile *file) { ThunarVfsMimeApplication *default_application; ThunarVfsMimeInfo *info; @@ -421,104 +426,118 @@ GtkIconTheme *icon_theme; const gchar *icon_name; GdkPixbuf *icon; - GtkWidget *image; - GtkWidget *item; - GtkWidget *menu; GList *applications; GList *lp; gint icon_size; + guint i = 0; + GtkTreeIter iter; _thunar_return_if_fail (THUNAR_IS_CHOOSER_BUTTON (chooser_button)); - _thunar_return_if_fail (chooser_button->button == button); - _thunar_return_if_fail (GTK_IS_BUTTON (button)); + _thunar_return_if_fail (GTK_IS_LIST_STORE (chooser_button->store)); + _thunar_return_if_fail (chooser_button->file == file); + _thunar_return_if_fail (THUNAR_IS_FILE (file)); + /* clear the store */ + gtk_list_store_clear (chooser_button->store); + + /* nod efault application form now on */ + chooser_button->has_default_application = FALSE; + /* verify that we have a valid file */ if (G_UNLIKELY (chooser_button->file == NULL)) return; + /* block the changed signal */ + g_signal_handlers_block_by_func (G_OBJECT (chooser_button), thunar_chooser_button_changed, NULL); + /* determine the mime info for the file */ info = thunar_file_get_mime_info (chooser_button->file); + /* setup a useful tooltip for the combo box */ + thunar_gtk_widget_set_tooltip (GTK_WIDGET (chooser_button), + _("The selected application is used to open " + "this and other files of type \"%s\"."), + thunar_vfs_mime_info_get_comment (info)); + /* determine the default application */ default_application = thunar_vfs_mime_database_get_default_application (chooser_button->database, info); - if (G_UNLIKELY (default_application == NULL)) + if (G_LIKELY (default_application != NULL)) { - /* no default application, just popup the application chooser */ - thunar_chooser_button_activate_other (chooser_button); - return; - } + /* determine all applications that claim to be able to handle the file */ + applications = thunar_vfs_mime_database_get_applications (chooser_button->database, info); + applications = g_list_sort (applications, thunar_chooser_button_sort_applications); - /* determine all applications that claim to be able to handle the file */ - applications = thunar_vfs_mime_database_get_applications (chooser_button->database, info); + /* determine the icon size for menus */ + gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_size, &icon_size); - /* make sure the default application comes first */ - lp = g_list_find (applications, default_application); - if (G_LIKELY (lp != NULL)) - { - applications = g_list_delete_link (applications, lp); - g_object_unref (G_OBJECT (default_application)); - } - applications = g_list_prepend (applications, default_application); + /* determine the icon factory for our screen */ + icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (chooser_button))); + icon_factory = thunar_icon_factory_get_for_icon_theme (icon_theme); - /* allocate a new popup menu */ - menu = gtk_menu_new (); + /* add all possible applications */ + for (lp = applications, i = 0; lp != NULL; lp = lp->next, i++) + { + /* get the icon for the application */ + icon_name = thunar_vfs_mime_handler_lookup_icon_name (lp->data, icon_theme); + icon = thunar_icon_factory_load_icon (icon_factory, icon_name, icon_size, NULL, FALSE); - /* determine the icon size for menus */ - gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_size, &icon_size); + /* insert the item in the store */ + gtk_list_store_insert_with_values (chooser_button->store, &iter, i, + THUNAR_CHOOSER_BUTTON_STORE_COLUMN_NAME, + thunar_vfs_mime_handler_get_name (lp->data), + THUNAR_CHOOSER_BUTTON_STORE_COLUMN_APPLICATION, lp->data, + THUNAR_CHOOSER_BUTTON_STORE_COLUMN_PIXBUF, icon, + THUNAR_CHOOSER_BUTTON_STORE_COLUMN_SENSITIVE, TRUE, -1); - /* determine the icon factory for our screen */ - icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (button)); - icon_factory = thunar_icon_factory_get_for_icon_theme (icon_theme); + /* select the active application */ + if (G_UNLIKELY (lp->data == default_application)) + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (chooser_button), &iter); - /* add the other possible applications */ - for (lp = applications; lp != NULL; lp = lp->next) - { - item = gtk_image_menu_item_new_with_label (thunar_vfs_mime_handler_get_name (lp->data)); - g_object_set_data_full (G_OBJECT (item), I_("thunar-vfs-mime-application"), lp->data, g_object_unref); - g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_chooser_button_activate), chooser_button); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); + /* release the icon */ + if (G_LIKELY (icon != NULL)) + g_object_unref (G_OBJECT (icon)); - /* setup the icon for the application */ - icon_name = thunar_vfs_mime_handler_lookup_icon_name (lp->data, icon_theme); - icon = thunar_icon_factory_load_icon (icon_factory, icon_name, icon_size, NULL, FALSE); - image = gtk_image_new_from_pixbuf (icon); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); - gtk_widget_show (image); - if (G_LIKELY (icon != NULL)) - g_object_unref (icon); - } + /* release the application */ + g_object_unref (G_OBJECT (lp->data)); + } - /* cleanup */ - g_object_unref (G_OBJECT (icon_factory)); + /* cleanup */ + g_object_unref (G_OBJECT (icon_factory)); + g_object_unref (G_OBJECT (default_application)); - /* append a separator */ - item = gtk_separator_menu_item_new (); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); + /* release the applications list */ + g_list_free (applications); - /* release the applications list */ - g_list_free (applications); + /* assume we have some applications in the list */ + chooser_button->has_default_application = TRUE; + } + else + { + /* add the "No application selected" item and set as active */ + gtk_list_store_insert_with_values (chooser_button->store, &iter, 0, + THUNAR_CHOOSER_BUTTON_STORE_COLUMN_NAME, + _("No application selected"), + THUNAR_CHOOSER_BUTTON_STORE_COLUMN_STYLE, + PANGO_STYLE_ITALIC, -1); + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (chooser_button), &iter); + } + /* insert empty row that will appear as separator */ + gtk_list_store_insert_with_values (chooser_button->store, NULL, ++i, -1); + /* add the "Other Application..." choice */ - item = gtk_image_menu_item_new_with_mnemonic (_("_Other Application...")); - g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_chooser_button_activate_other), chooser_button); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); + gtk_list_store_insert_with_values (chooser_button->store, NULL, ++i, + THUNAR_CHOOSER_BUTTON_STORE_COLUMN_NAME, + _("Other Application..."), + THUNAR_CHOOSER_BUTTON_STORE_COLUMN_SENSITIVE, TRUE, -1); - /* make sure the menu has atleast the same width as the chooser */ - if (menu->allocation.width < button->allocation.width) - gtk_widget_set_size_request (menu, button->allocation.width, -1); + /* release the changed signal */ + g_signal_handlers_unblock_by_func (G_OBJECT (chooser_button), thunar_chooser_button_changed, NULL); +} - /* run the menu on the button's screen (takes over the floating reference of menu) */ - thunar_gtk_menu_run (GTK_MENU (menu), button, menu_position, button, 0, gtk_get_current_event_time ()); - /* yeppa, that's a requirement */ - gtk_button_released (GTK_BUTTON (button)); -} - /** * thunar_chooser_button_new: *