597 lines
20 KiB
C
597 lines
20 KiB
C
|
|
/* vi:set et ai sw=2 sts=2 ts=2: */
|
||
|
|
/*-
|
||
|
|
* Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>
|
||
|
|
* Copyright (c) 2010 Nick Schermer <nick@xfce.org>
|
||
|
|
* Copyright (c) 2009-2011 Jannis Pohlmann <jannis@xfce.org>
|
||
|
|
*
|
||
|
|
* This program is free software; you can redistribute it and/or
|
||
|
|
* modify it under the terms of the GNU General Public License as
|
||
|
|
* published by the Free Software Foundation; either version 2 of
|
||
|
|
* the License, or (at your option) any later version.
|
||
|
|
*
|
||
|
|
* This program is distributed in the hope that it will be useful,
|
||
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
|
* GNU General Public License for more details.
|
||
|
|
*
|
||
|
|
* You should have received a copy of the GNU General Public
|
||
|
|
* License along with this program; if not, write to the Free
|
||
|
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||
|
|
* Boston, MA 02110-1301, USA.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#ifdef HAVE_CONFIG_H
|
||
|
|
#include "config.h"
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#include "thunar/thunar-chooser-button.h"
|
||
|
|
#include "thunar/thunar-chooser-dialog.h"
|
||
|
|
#include "thunar/thunar-dialogs.h"
|
||
|
|
#include "thunar/thunar-gobject-extensions.h"
|
||
|
|
#include "thunar/thunar-gtk-extensions.h"
|
||
|
|
#include "thunar/thunar-icon-factory.h"
|
||
|
|
#include "thunar/thunar-pango-extensions.h"
|
||
|
|
#include "thunar/thunar-private.h"
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
/* Property identifiers */
|
||
|
|
enum
|
||
|
|
{
|
||
|
|
PROP_0,
|
||
|
|
PROP_FILE,
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
enum
|
||
|
|
{
|
||
|
|
THUNAR_CHOOSER_BUTTON_STORE_COLUMN_NAME,
|
||
|
|
THUNAR_CHOOSER_BUTTON_STORE_COLUMN_ICON,
|
||
|
|
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_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);
|
||
|
|
static void
|
||
|
|
thunar_chooser_button_popup (ThunarChooserButton *chooser_button);
|
||
|
|
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
|
||
|
|
{
|
||
|
|
GtkComboBoxClass __parent__;
|
||
|
|
};
|
||
|
|
|
||
|
|
struct _ThunarChooserButton
|
||
|
|
{
|
||
|
|
GtkComboBox __parent__;
|
||
|
|
|
||
|
|
GtkListStore *store;
|
||
|
|
ThunarFile *file;
|
||
|
|
gboolean has_default_application;
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
G_DEFINE_TYPE (ThunarChooserButton, thunar_chooser_button, GTK_TYPE_COMBO_BOX)
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
static void
|
||
|
|
thunar_chooser_button_class_init (ThunarChooserButtonClass *klass)
|
||
|
|
{
|
||
|
|
GObjectClass *gobject_class;
|
||
|
|
GtkWidgetClass *gtkwidget_class;
|
||
|
|
|
||
|
|
gobject_class = G_OBJECT_CLASS (klass);
|
||
|
|
gobject_class->finalize = thunar_chooser_button_finalize;
|
||
|
|
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:
|
||
|
|
*
|
||
|
|
* The #ThunarFile for which a preferred application should
|
||
|
|
* be chosen.
|
||
|
|
**/
|
||
|
|
g_object_class_install_property (gobject_class,
|
||
|
|
PROP_FILE,
|
||
|
|
g_param_spec_object ("file", "file", "file",
|
||
|
|
THUNAR_TYPE_FILE,
|
||
|
|
EXO_PARAM_READWRITE));
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
static void
|
||
|
|
thunar_chooser_button_init (ThunarChooserButton *chooser_button)
|
||
|
|
{
|
||
|
|
GtkCellRenderer *renderer;
|
||
|
|
|
||
|
|
/* allocate a new store for the combo box */
|
||
|
|
chooser_button->store = gtk_list_store_new (THUNAR_CHOOSER_BUTTON_STORE_N_COLUMNS,
|
||
|
|
G_TYPE_STRING,
|
||
|
|
G_TYPE_ICON,
|
||
|
|
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 (chooser_button, "changed",
|
||
|
|
G_CALLBACK (thunar_chooser_button_changed), NULL);
|
||
|
|
g_signal_connect (chooser_button, "popup",
|
||
|
|
G_CALLBACK (thunar_chooser_button_popup), NULL);
|
||
|
|
|
||
|
|
/* set separator function */
|
||
|
|
gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (chooser_button),
|
||
|
|
thunar_chooser_button_row_separator,
|
||
|
|
NULL, NULL);
|
||
|
|
|
||
|
|
/* add renderer for the application icon */
|
||
|
|
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,
|
||
|
|
"gicon",
|
||
|
|
THUNAR_CHOOSER_BUTTON_STORE_COLUMN_ICON,
|
||
|
|
"sensitive",
|
||
|
|
THUNAR_CHOOSER_BUTTON_STORE_COLUMN_SENSITIVE,
|
||
|
|
NULL);
|
||
|
|
|
||
|
|
/* add renderer for the application name */
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
static void
|
||
|
|
thunar_chooser_button_finalize (GObject *object)
|
||
|
|
{
|
||
|
|
ThunarChooserButton *chooser_button = THUNAR_CHOOSER_BUTTON (object);
|
||
|
|
|
||
|
|
/* reset the "file" property */
|
||
|
|
thunar_chooser_button_set_file (chooser_button, NULL);
|
||
|
|
|
||
|
|
/* release the store */
|
||
|
|
g_object_unref (G_OBJECT (chooser_button->store));
|
||
|
|
|
||
|
|
(*G_OBJECT_CLASS (thunar_chooser_button_parent_class)->finalize) (object);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
static void
|
||
|
|
thunar_chooser_button_get_property (GObject *object,
|
||
|
|
guint prop_id,
|
||
|
|
GValue *value,
|
||
|
|
GParamSpec *pspec)
|
||
|
|
{
|
||
|
|
ThunarChooserButton *chooser_button = THUNAR_CHOOSER_BUTTON (object);
|
||
|
|
|
||
|
|
switch (prop_id)
|
||
|
|
{
|
||
|
|
case PROP_FILE:
|
||
|
|
g_value_set_object (value, chooser_button->file);
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
static void
|
||
|
|
thunar_chooser_button_set_property (GObject *object,
|
||
|
|
guint prop_id,
|
||
|
|
const GValue *value,
|
||
|
|
GParamSpec *pspec)
|
||
|
|
{
|
||
|
|
ThunarChooserButton *chooser_button = THUNAR_CHOOSER_BUTTON (object);
|
||
|
|
|
||
|
|
switch (prop_id)
|
||
|
|
{
|
||
|
|
case PROP_FILE:
|
||
|
|
thunar_chooser_button_set_file (chooser_button, g_value_get_object (value));
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
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);
|
||
|
|
|
||
|
|
g_return_val_if_fail (THUNAR_IS_CHOOSER_BUTTON (chooser_button), FALSE);
|
||
|
|
|
||
|
|
/* 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_changed (GtkComboBox *combo_box)
|
||
|
|
{
|
||
|
|
ThunarChooserButton *chooser_button = THUNAR_CHOOSER_BUTTON (combo_box);
|
||
|
|
GtkTreeIter iter;
|
||
|
|
const gchar *content_type;
|
||
|
|
GAppInfo *app_info;
|
||
|
|
GError *error = NULL;
|
||
|
|
|
||
|
|
_thunar_return_if_fail (THUNAR_IS_CHOOSER_BUTTON (chooser_button));
|
||
|
|
_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;
|
||
|
|
|
||
|
|
/* get the selected item in the combo box */
|
||
|
|
if (!gtk_combo_box_get_active_iter (combo_box, &iter))
|
||
|
|
return;
|
||
|
|
|
||
|
|
/* determine the application that was set for the item */
|
||
|
|
gtk_tree_model_get (GTK_TREE_MODEL (chooser_button->store), &iter,
|
||
|
|
THUNAR_CHOOSER_BUTTON_STORE_COLUMN_APPLICATION,
|
||
|
|
&app_info, -1);
|
||
|
|
|
||
|
|
if (G_LIKELY (app_info != NULL))
|
||
|
|
{
|
||
|
|
/* determine the mime info for the file */
|
||
|
|
content_type = thunar_file_get_content_type (chooser_button->file);
|
||
|
|
|
||
|
|
/* try to set application as default for these kind of file */
|
||
|
|
if (!g_app_info_set_as_default_for_type (app_info, content_type, &error))
|
||
|
|
{
|
||
|
|
/* tell the user that it didn't work */
|
||
|
|
if (g_strcmp0 (thunar_file_get_display_name (chooser_button->file), thunar_file_get_basename (chooser_button->file)) != 0)
|
||
|
|
thunar_dialogs_show_error (GTK_WIDGET (chooser_button), error,
|
||
|
|
_("Failed to set default application for \"%s\" (%s)"),
|
||
|
|
thunar_file_get_display_name (chooser_button->file),
|
||
|
|
thunar_file_get_basename (chooser_button->file));
|
||
|
|
else
|
||
|
|
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 (app_info);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
/* no application was found in the store, looks like the other... option */
|
||
|
|
thunar_chooser_button_chooser_dialog (chooser_button);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
static void
|
||
|
|
thunar_chooser_button_popup (ThunarChooserButton *chooser_button)
|
||
|
|
{
|
||
|
|
_thunar_return_if_fail (THUNAR_IS_CHOOSER_BUTTON (chooser_button));
|
||
|
|
|
||
|
|
if (!chooser_button->has_default_application)
|
||
|
|
{
|
||
|
|
/* don't show the menu */
|
||
|
|
gtk_combo_box_popdown (GTK_COMBO_BOX (chooser_button));
|
||
|
|
|
||
|
|
/* open the chooser dialog if the filetype has no default action */
|
||
|
|
thunar_chooser_button_chooser_dialog (chooser_button);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
static gint
|
||
|
|
thunar_chooser_button_sort_applications (gconstpointer a,
|
||
|
|
gconstpointer b)
|
||
|
|
{
|
||
|
|
_thunar_return_val_if_fail (G_IS_APP_INFO (a), -1);
|
||
|
|
_thunar_return_val_if_fail (G_IS_APP_INFO (b), -1);
|
||
|
|
|
||
|
|
return g_utf8_collate (g_app_info_get_name (G_APP_INFO (a)),
|
||
|
|
g_app_info_get_name (G_APP_INFO (b)));
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
static gboolean
|
||
|
|
thunar_chooser_button_row_separator (GtkTreeModel *model,
|
||
|
|
GtkTreeIter *iter,
|
||
|
|
gpointer data)
|
||
|
|
{
|
||
|
|
gchar *name;
|
||
|
|
|
||
|
|
/* 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))
|
||
|
|
{
|
||
|
|
g_free (name);
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
static void
|
||
|
|
thunar_chooser_button_chooser_dialog (ThunarChooserButton *chooser_button)
|
||
|
|
{
|
||
|
|
GtkWidget *toplevel;
|
||
|
|
GtkWidget *dialog;
|
||
|
|
|
||
|
|
_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);
|
||
|
|
g_object_bind_property (G_OBJECT (chooser_button), "file",
|
||
|
|
G_OBJECT (dialog), "file",
|
||
|
|
G_BINDING_SYNC_CREATE);
|
||
|
|
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_file_changed (ThunarChooserButton *chooser_button,
|
||
|
|
ThunarFile *file)
|
||
|
|
{
|
||
|
|
const gchar *content_type;
|
||
|
|
GtkTreeIter iter;
|
||
|
|
GAppInfo *app_info;
|
||
|
|
GList *app_infos;
|
||
|
|
GList *lp;
|
||
|
|
gchar *description;
|
||
|
|
guint i = 0;
|
||
|
|
|
||
|
|
_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));
|
||
|
|
|
||
|
|
/* clear the store */
|
||
|
|
gtk_list_store_clear (chooser_button->store);
|
||
|
|
|
||
|
|
/* reset the default application flag */
|
||
|
|
chooser_button->has_default_application = FALSE;
|
||
|
|
|
||
|
|
/* block the changed signal for a moment */
|
||
|
|
g_signal_handlers_block_by_func (chooser_button,
|
||
|
|
thunar_chooser_button_changed,
|
||
|
|
NULL);
|
||
|
|
|
||
|
|
/* determine the content type of the file */
|
||
|
|
content_type = thunar_file_get_content_type (file);
|
||
|
|
if (content_type != NULL)
|
||
|
|
{
|
||
|
|
/* setup a useful tooltip for the button */
|
||
|
|
description = g_content_type_get_description (content_type);
|
||
|
|
thunar_gtk_widget_set_tooltip (GTK_WIDGET (chooser_button),
|
||
|
|
_("The selected application is used to open "
|
||
|
|
"this and other files of type \"%s\"."),
|
||
|
|
description);
|
||
|
|
g_free (description);
|
||
|
|
|
||
|
|
/* determine the default application for that content type */
|
||
|
|
app_info = g_app_info_get_default_for_type (content_type, FALSE);
|
||
|
|
if (G_LIKELY (app_info != NULL))
|
||
|
|
{
|
||
|
|
/* determine all applications that claim to be able to handle the file */
|
||
|
|
app_infos = g_app_info_get_all_for_type (content_type);
|
||
|
|
app_infos = g_list_sort (app_infos, thunar_chooser_button_sort_applications);
|
||
|
|
|
||
|
|
/* add all possible applications */
|
||
|
|
for (lp = app_infos, i = 0; lp != NULL; lp = lp->next, ++i)
|
||
|
|
{
|
||
|
|
if (thunar_g_app_info_should_show (lp->data))
|
||
|
|
{
|
||
|
|
/* insert the item into the store */
|
||
|
|
gtk_list_store_insert_with_values (chooser_button->store, &iter, i,
|
||
|
|
THUNAR_CHOOSER_BUTTON_STORE_COLUMN_NAME,
|
||
|
|
g_app_info_get_name (lp->data),
|
||
|
|
THUNAR_CHOOSER_BUTTON_STORE_COLUMN_APPLICATION,
|
||
|
|
lp->data,
|
||
|
|
THUNAR_CHOOSER_BUTTON_STORE_COLUMN_ICON,
|
||
|
|
g_app_info_get_icon (lp->data),
|
||
|
|
THUNAR_CHOOSER_BUTTON_STORE_COLUMN_SENSITIVE,
|
||
|
|
TRUE,
|
||
|
|
-1);
|
||
|
|
|
||
|
|
/* pre-select the default application */
|
||
|
|
if (g_app_info_equal (lp->data, app_info))
|
||
|
|
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (chooser_button), &iter);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* release the application */
|
||
|
|
g_object_unref (lp->data);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* release the application list */
|
||
|
|
g_list_free (app_infos);
|
||
|
|
|
||
|
|
/* release the default application */
|
||
|
|
g_object_unref (app_info);
|
||
|
|
|
||
|
|
/* assume we have some applications in the list */
|
||
|
|
chooser_button->has_default_application = TRUE;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (content_type == NULL || !chooser_button->has_default_application)
|
||
|
|
{
|
||
|
|
/* 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 a separator */
|
||
|
|
gtk_list_store_insert_with_values (chooser_button->store, NULL, ++i, -1);
|
||
|
|
|
||
|
|
/* add the "Other Application..." option */
|
||
|
|
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);
|
||
|
|
|
||
|
|
/* unblock the changed signal */
|
||
|
|
g_signal_handlers_unblock_by_func (chooser_button,
|
||
|
|
thunar_chooser_button_changed,
|
||
|
|
NULL);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* thunar_chooser_button_new:
|
||
|
|
*
|
||
|
|
* Allocates a new #ThunarChooserButton instance.
|
||
|
|
*
|
||
|
|
* Return value: the newly allocated #ThunarChooserButton.
|
||
|
|
**/
|
||
|
|
GtkWidget *
|
||
|
|
thunar_chooser_button_new (void)
|
||
|
|
{
|
||
|
|
return g_object_new (THUNAR_TYPE_CHOOSER_BUTTON, NULL);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* thunar_chooser_button_set_file:
|
||
|
|
* @chooser_button : a #ThunarChooserButton instance.
|
||
|
|
* @file : a #ThunarFile or %NULL.
|
||
|
|
*
|
||
|
|
* Associates @chooser_button with the specified @file.
|
||
|
|
**/
|
||
|
|
void
|
||
|
|
thunar_chooser_button_set_file (ThunarChooserButton *chooser_button,
|
||
|
|
ThunarFile *file)
|
||
|
|
{
|
||
|
|
_thunar_return_if_fail (THUNAR_IS_CHOOSER_BUTTON (chooser_button));
|
||
|
|
_thunar_return_if_fail (file == NULL || THUNAR_IS_FILE (file));
|
||
|
|
|
||
|
|
/* check if we already use that file */
|
||
|
|
if (G_UNLIKELY (chooser_button->file == file))
|
||
|
|
return;
|
||
|
|
|
||
|
|
/* disconnect from the previous file */
|
||
|
|
if (G_UNLIKELY (chooser_button->file != NULL))
|
||
|
|
{
|
||
|
|
g_signal_handlers_disconnect_by_func (G_OBJECT (chooser_button->file), thunar_chooser_button_file_changed, chooser_button);
|
||
|
|
g_object_unref (G_OBJECT (chooser_button->file));
|
||
|
|
}
|
||
|
|
|
||
|
|
/* activate the new file */
|
||
|
|
chooser_button->file = file;
|
||
|
|
|
||
|
|
/* connect to the new file */
|
||
|
|
if (G_LIKELY (file != NULL))
|
||
|
|
{
|
||
|
|
/* take a reference */
|
||
|
|
g_object_ref (G_OBJECT (file));
|
||
|
|
|
||
|
|
/* stay informed about changes */
|
||
|
|
g_signal_connect_swapped (G_OBJECT (file), "changed", G_CALLBACK (thunar_chooser_button_file_changed), chooser_button);
|
||
|
|
|
||
|
|
/* update our state now */
|
||
|
|
thunar_chooser_button_file_changed (chooser_button, file);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* notify listeners */
|
||
|
|
g_object_notify (G_OBJECT (chooser_button), "file");
|
||
|
|
}
|