summaryrefslogtreecommitdiff
path: root/gtk/gtkfilechooserbutton.c
diff options
context:
space:
mode:
authorJames M. Cape <jcape@ignore-your.tv>2004-10-26 04:29:56 +0000
committerJames M. Cape <jcape@src.gnome.org>2004-10-26 04:29:56 +0000
commitede3c3991802f5ca0a0472e980e81de1a1b36a30 (patch)
tree5a0abd33b49a34c97b7cc10d4e071fda4b1e4df5 /gtk/gtkfilechooserbutton.c
parent64facb3c4b3381c3e8066faf55ce4689ae553cb3 (diff)
downloadgtk+-ede3c3991802f5ca0a0472e980e81de1a1b36a30.tar.gz
Rework of GtkFileChooserButton, some cleanups. Fixes #154388, #154390,
2004-10-25 James M. Cape <jcape@ignore-your.tv> Rework of GtkFileChooserButton, some cleanups. Fixes #154388, #154390, #154390, #156272. * docs/reference/gtk/gtk-docs.sgml: Moved GtkFileChooserButton below GtkFileChooser. * docs/reference/gtk/gtk-sections.txt: Added gtk_file_chooser_button_get_width_chars(), gtk_file_chooser_button_set_width_chars(), gtk_label_set_width_chars(), gtk_label_get_width_chars(). * docs/reference/gtk/gtk.types: Added gtk_cell_renderer_combo_get_type, gtk_cell_view_get_type, gtk_text_iter_get_type. * docs/reference/gtk/tmpl/gtkaboutdialog.sgml: Add "logo-icon-name" property. * docs/reference/gtk/tmpl/gtkcellview.sgml: Updates for properties (b/c of get_type() inclusion above). * docs/reference/gtk/tmpl/gtkfilechooserbutton.sgml: * docs/reference/gtk/tmpl/gtklabel.sgml: Add "width-chars" property, getters/setters. * docs/reference/gtk/tmpl/gtkcellrenderercombo.sgml: Added. * gtk/gtkentrycompletion.c: (_gtk_entry_completion_popdown): Don't show if the entry isn't mapped. * gtk/gtkfilechooserbutton.[c,h]: (*): About 45% rewritten, adds "width-chars" property, icons, working save modes, volume/Home/Desktop friendly-naming support. * gtk/gtklabel.[c,h]: (gtk_label_class_init), (gtk_label_init), (gtk_label_get_property), (gtk_label_set_property), (gtk_label_get_width_chars), (gtk_label_set_width_chars), (gtk_label_size_request): Add "width-chars" property. * tests/testfilechooserbutton.c: Update, use 4 different buttons for the different ACTIONs. * gtk/.cvsignore: Ignore gtk-update-icon-cache. * tests/.cvsignore: Ignore testimage.
Diffstat (limited to 'gtk/gtkfilechooserbutton.c')
-rw-r--r--gtk/gtkfilechooserbutton.c1007
1 files changed, 752 insertions, 255 deletions
diff --git a/gtk/gtkfilechooserbutton.c b/gtk/gtkfilechooserbutton.c
index 5ebdac05b5..3c262df93b 100644
--- a/gtk/gtkfilechooserbutton.c
+++ b/gtk/gtkfilechooserbutton.c
@@ -56,7 +56,12 @@
#define GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE(object) (GTK_FILE_CHOOSER_BUTTON ((object))->priv)
#define DEFAULT_FILENAME N_("(None)")
-#define DEFAULT_SPACING 0
+#define MIN_LABEL_WIDTH 100
+#define ENTRY_BUTTON_SPACING 0
+#define FALLBACK_ICON_SIZE 20
+#define FALLBACK_ICON_NAME "stock_unknown"
+#define NEW_FILE_ICON_NAME "stock_new"
+#define NEW_DIR_ICON_NAME "stock_new-dir"
/* ********************** *
* Private Enumerations *
@@ -69,7 +74,8 @@ enum
PROP_DIALOG,
PROP_TITLE,
- PROP_ACTIVE
+ PROP_ACTIVE,
+ PROP_WIDTH_CHARS
};
@@ -80,17 +86,24 @@ enum
struct _GtkFileChooserButtonPrivate
{
GtkWidget *dialog;
+ GtkWidget *accept_button;
+ GtkWidget *entry_box;
+ GtkWidget *entry_image;
GtkWidget *entry;
+ GtkWidget *label_box;
+ GtkWidget *label_image;
GtkWidget *label;
- GtkWidget *separator;
GtkWidget *button;
- gchar *filesystem;
+ gchar *backend;
gulong entry_changed_id;
gulong dialog_file_activated_id;
gulong dialog_folder_changed_id;
gulong dialog_selection_changed_id;
+ gulong dialog_selection_changed_proxy_id;
+ gulong settings_signal_id;
guint update_id;
+ gint icon_size;
};
@@ -109,12 +122,15 @@ enum
* ********************* */
/* GObject Functions */
+static GObject *gtk_file_chooser_button_constructor (GType type,
+ guint n_params,
+ GObjectConstructParam *params);
static void gtk_file_chooser_button_set_property (GObject *object,
- guint id,
+ guint param_id,
const GValue *value,
GParamSpec *pspec);
static void gtk_file_chooser_button_get_property (GObject *object,
- guint id,
+ guint param_id,
GValue *value,
GParamSpec *pspec);
@@ -131,14 +147,22 @@ static void gtk_file_chooser_button_drag_data_received (GtkWidget *wi
guint drag_time);
static void gtk_file_chooser_button_show_all (GtkWidget *widget);
static void gtk_file_chooser_button_hide_all (GtkWidget *widget);
+static void gtk_file_chooser_button_show (GtkWidget *widget);
+static void gtk_file_chooser_button_hide (GtkWidget *widget);
static gboolean gtk_file_chooser_button_mnemonic_activate (GtkWidget *widget,
gboolean group_cycling);
+static void gtk_file_chooser_button_style_set (GtkWidget *widget,
+ GtkStyle *old_style);
+static void gtk_file_chooser_button_screen_changed (GtkWidget *widget,
+ GdkScreen *old_screen);
/* Child Widget Callbacks */
static void dialog_update_preview_cb (GtkFileChooser *dialog,
gpointer user_data);
static void dialog_selection_changed_cb (GtkFileChooser *dialog,
gpointer user_data);
+static void dialog_selection_changed_proxy_cb (GtkFileChooser *dialog,
+ gpointer user_data);
static void dialog_file_activated_cb (GtkFileChooser *dialog,
gpointer user_data);
static void dialog_current_folder_changed_cb (GtkFileChooser *dialog,
@@ -162,16 +186,17 @@ static void button_notify_active_cb (GObject *re
static void entry_size_allocate_cb (GtkWidget *entry,
GtkAllocation *allocation,
gpointer user_data);
-static void entry_changed_cb (GtkEditable *chooser_entry,
+static void entry_changed_cb (GtkEditable *editable,
gpointer user_data);
/* Utility Functions */
-static void gtk_file_chooser_button_set_dialog (GObject *object,
- GtkWidget *dialog);
+static void remove_settings_signal (GtkFileChooserButton *button,
+ GdkScreen *screen);
-static gboolean update_dialog (gpointer user_data);
-static gboolean update_dialog_idle (gpointer user_data);
+static void update_dialog (GtkFileChooserButton *button);
static void update_entry (GtkFileChooserButton *button);
+static void update_label (GtkFileChooserButton *button);
+static void update_icons (GtkFileChooserButton *button);
/* ******************* *
@@ -198,6 +223,7 @@ gtk_file_chooser_button_class_init (GtkFileChooserButtonClass * class)
gtkobject_class = GTK_OBJECT_CLASS (class);
widget_class = GTK_WIDGET_CLASS (class);
+ gobject_class->constructor = gtk_file_chooser_button_constructor;
gobject_class->set_property = gtk_file_chooser_button_set_property;
gobject_class->get_property = gtk_file_chooser_button_get_property;
@@ -206,6 +232,10 @@ gtk_file_chooser_button_class_init (GtkFileChooserButtonClass * class)
widget_class->drag_data_received = gtk_file_chooser_button_drag_data_received;
widget_class->show_all = gtk_file_chooser_button_show_all;
widget_class->hide_all = gtk_file_chooser_button_hide_all;
+ widget_class->show = gtk_file_chooser_button_show;
+ widget_class->hide = gtk_file_chooser_button_hide;
+ widget_class->style_set = gtk_file_chooser_button_style_set;
+ widget_class->screen_changed = gtk_file_chooser_button_screen_changed;
widget_class->mnemonic_activate = gtk_file_chooser_button_mnemonic_activate;
g_object_class_install_property (gobject_class, PROP_DIALOG,
@@ -226,6 +256,12 @@ gtk_file_chooser_button_class_init (GtkFileChooserButtonClass * class)
P_("Active"),
P_("Whether the browse dialog is visible or not."),
FALSE, G_PARAM_READWRITE));
+ g_object_class_install_property (gobject_class, PROP_WIDTH_CHARS,
+ g_param_spec_int ("width-chars",
+ P_("Width In Characters"),
+ P_("The desired width of the button widget, in characters."),
+ -1, G_MAXINT, -1,
+ G_PARAM_READWRITE));
_gtk_file_chooser_install_properties (gobject_class);
@@ -237,18 +273,29 @@ static void
gtk_file_chooser_button_init (GtkFileChooserButton *button)
{
GtkFileChooserButtonPrivate *priv;
- GtkWidget *box, *image;
+ GtkWidget *box, *image, *sep;
- gtk_box_set_spacing (GTK_BOX (button), DEFAULT_SPACING);
+ gtk_box_set_spacing (GTK_BOX (button), ENTRY_BUTTON_SPACING);
priv = G_TYPE_INSTANCE_GET_PRIVATE (button, GTK_TYPE_FILE_CHOOSER_BUTTON,
GtkFileChooserButtonPrivate);
button->priv = priv;
+ priv->icon_size = FALLBACK_ICON_SIZE;
+
gtk_widget_push_composite_child ();
+ priv->entry_box = gtk_hbox_new (FALSE, 4);
+ gtk_container_add (GTK_CONTAINER (button), priv->entry_box);
+
+ priv->entry_image = gtk_image_new ();
+ gtk_box_pack_start (GTK_BOX (priv->entry_box), priv->entry_image,
+ FALSE, FALSE, 0);
+ gtk_widget_show (priv->entry_image);
+
priv->entry = _gtk_file_chooser_entry_new (FALSE);
- gtk_container_add (GTK_CONTAINER (button), priv->entry);
+ gtk_container_add (GTK_CONTAINER (priv->entry_box), priv->entry);
+ gtk_widget_show (priv->entry);
priv->button = gtk_toggle_button_new ();
g_signal_connect (priv->button, "toggled",
@@ -263,22 +310,31 @@ gtk_file_chooser_button_init (GtkFileChooserButton *button)
box = gtk_hbox_new (FALSE, 4);
gtk_container_add (GTK_CONTAINER (priv->button), box);
gtk_widget_show (box);
+
+ priv->label_box = gtk_hbox_new (FALSE, 6);
+ gtk_container_add (GTK_CONTAINER (box), priv->label_box);
+ gtk_widget_show (priv->label_box);
+
+ priv->label_image = gtk_image_new ();
+ gtk_box_pack_start (GTK_BOX (priv->label_box), priv->label_image,
+ FALSE, FALSE, 0);
+ gtk_widget_show (priv->label_image);
priv->label = gtk_label_new (_(DEFAULT_FILENAME));
gtk_label_set_ellipsize (GTK_LABEL (priv->label), PANGO_ELLIPSIZE_START);
gtk_misc_set_alignment (GTK_MISC (priv->label), 0.0, 0.5);
- gtk_box_pack_start (GTK_BOX (box), priv->label, TRUE, TRUE, 2);
+ gtk_container_add (GTK_CONTAINER (priv->label_box), priv->label);
gtk_widget_show (priv->label);
+ sep = gtk_vseparator_new ();
+ gtk_box_pack_end (GTK_BOX (priv->label_box), sep, FALSE, FALSE, 0);
+ gtk_widget_show (sep);
+
image = gtk_image_new_from_stock (GTK_STOCK_OPEN,
GTK_ICON_SIZE_SMALL_TOOLBAR);
gtk_box_pack_end (GTK_BOX (box), image, FALSE, FALSE, 0);
gtk_widget_show (image);
- priv->separator = gtk_vseparator_new ();
- gtk_box_pack_end (GTK_BOX (box), priv->separator, FALSE, FALSE, 0);
- gtk_widget_show (priv->separator);
-
gtk_widget_pop_composite_child ();
/* DnD */
@@ -297,10 +353,92 @@ gtk_file_chooser_button_init (GtkFileChooserButton *button)
* GObject Functions *
* ******************* */
+static GObject *
+gtk_file_chooser_button_constructor (GType type,
+ guint n_params,
+ GObjectConstructParam *params)
+{
+ GObject *object;
+ GtkFileChooserButtonPrivate *priv;
+ GtkFilePath *path;
+
+ object = (*G_OBJECT_CLASS (gtk_file_chooser_button_parent_class)->constructor) (type,
+ n_params,
+ params);
+ priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (object);
+
+ if (!priv->dialog)
+ {
+ if (priv->backend)
+ priv->dialog = gtk_file_chooser_dialog_new_with_backend (NULL, NULL,
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ priv->backend, NULL);
+ else
+ priv->dialog = gtk_file_chooser_dialog_new (NULL, NULL,
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ NULL);
+
+ gtk_dialog_add_button (GTK_DIALOG (priv->dialog),
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+ priv->accept_button = gtk_dialog_add_button (GTK_DIALOG (priv->dialog),
+ GTK_STOCK_OPEN,
+ GTK_RESPONSE_ACCEPT);
+ gtk_dialog_set_default_response (GTK_DIALOG (priv->dialog),
+ GTK_RESPONSE_ACCEPT);
+
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (priv->dialog),
+ GTK_RESPONSE_ACCEPT,
+ GTK_RESPONSE_CANCEL,
+ -1);
+ }
+
+ g_free (priv->backend);
+ priv->backend = NULL;
+
+ g_signal_connect (priv->dialog, "delete-event",
+ G_CALLBACK (dialog_delete_event_cb), object);
+ g_signal_connect (priv->dialog, "response",
+ G_CALLBACK (dialog_response_cb), object);
+
+ /* This is used, instead of the standard delegate, to ensure that signals are only
+ * delegated when the OK button is pressed. */
+ g_object_set_qdata (object, GTK_FILE_CHOOSER_DELEGATE_QUARK, priv->dialog);
+ priv->dialog_folder_changed_id =
+ g_signal_connect (priv->dialog, "current-folder-changed",
+ G_CALLBACK (dialog_current_folder_changed_cb), object);
+ priv->dialog_file_activated_id =
+ g_signal_connect (priv->dialog, "file-activated",
+ G_CALLBACK (dialog_file_activated_cb), object);
+ priv->dialog_selection_changed_id =
+ g_signal_connect (priv->dialog, "selection-changed",
+ G_CALLBACK (dialog_selection_changed_cb), object);
+ priv->dialog_selection_changed_proxy_id =
+ g_signal_connect (priv->dialog, "selection-changed",
+ G_CALLBACK (dialog_selection_changed_proxy_cb), object);
+ g_signal_connect (priv->dialog, "update-preview",
+ G_CALLBACK (dialog_update_preview_cb), object);
+ g_signal_connect (priv->dialog, "notify",
+ G_CALLBACK (dialog_notify_cb), object);
+ g_object_add_weak_pointer (G_OBJECT (priv->dialog),
+ (gpointer *) (&priv->dialog));
+
+ _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (priv->entry),
+ _gtk_file_chooser_get_file_system (GTK_FILE_CHOOSER (priv->dialog)));
+ path = gtk_file_path_new_steal ("/");
+ _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (priv->entry),
+ path);
+ priv->entry_changed_id = g_signal_connect (priv->entry, "changed",
+ G_CALLBACK (entry_changed_cb),
+ object);
+
+ update_label (GTK_FILE_CHOOSER_BUTTON (object));
+
+ return object;
+}
static void
gtk_file_chooser_button_set_property (GObject *object,
- guint id,
+ guint param_id,
const GValue *value,
GParamSpec *pspec)
{
@@ -308,39 +446,26 @@ gtk_file_chooser_button_set_property (GObject *object,
priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (object);
- switch (id)
+ switch (param_id)
{
case PROP_DIALOG:
- {
- GtkWidget *widget;
-
- widget = g_value_get_object (value);
-
- if (widget == NULL)
- {
- widget = g_object_new (GTK_TYPE_FILE_CHOOSER_DIALOG,
- "file-system-backend", priv->filesystem, NULL);
- g_free (priv->filesystem);
- priv->filesystem = NULL;
-
- gtk_dialog_add_button (GTK_DIALOG (widget),
- GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
- gtk_dialog_add_button (GTK_DIALOG (widget),
- GTK_STOCK_OK, GTK_RESPONSE_ACCEPT);
- }
-
- gtk_file_chooser_button_set_dialog (object, widget);
- }
+ /* Construct-only */
+ priv->dialog = g_value_get_object (value);
break;
case PROP_ACTIVE:
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button),
g_value_get_boolean (value));
break;
+ case PROP_WIDTH_CHARS:
+ gtk_file_chooser_button_set_width_chars (GTK_FILE_CHOOSER_BUTTON (object),
+ g_value_get_int (value));
+ break;
case GTK_FILE_CHOOSER_PROP_ACTION:
g_object_set_property (G_OBJECT (priv->dialog), pspec->name, value);
- _gtk_file_chooser_entry_set_action (priv->entry,
- (GtkFileChooserAction)g_value_get_enum (value));
+ _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (priv->entry),
+ (GtkFileChooserAction) g_value_get_enum (value));
+ update_icons (GTK_FILE_CHOOSER_BUTTON (object));
switch (g_value_get_enum (value))
{
@@ -348,22 +473,24 @@ gtk_file_chooser_button_set_property (GObject *object,
gtk_file_chooser_unselect_all (GTK_FILE_CHOOSER (priv->dialog));
/* Fall through to set the widget states */
case GTK_FILE_CHOOSER_ACTION_OPEN:
- gtk_widget_hide (priv->entry);
- gtk_widget_show (priv->label);
- gtk_widget_show (priv->separator);
+ gtk_widget_hide (priv->entry_box);
+ gtk_widget_show (priv->label_box);
gtk_box_set_child_packing (GTK_BOX (object), priv->button,
TRUE, TRUE, 0, GTK_PACK_START);
+ gtk_button_set_label (GTK_BUTTON (priv->accept_button),
+ GTK_STOCK_OPEN);
break;
case GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER:
gtk_file_chooser_unselect_all (GTK_FILE_CHOOSER (priv->dialog));
/* Fall through to set the widget states */
case GTK_FILE_CHOOSER_ACTION_SAVE:
- gtk_widget_show (priv->entry);
- gtk_widget_hide (priv->label);
- gtk_widget_hide (priv->separator);
+ gtk_widget_show (priv->entry_box);
+ gtk_widget_hide (priv->label_box);
gtk_box_set_child_packing (GTK_BOX (object), priv->button,
FALSE, FALSE, 0, GTK_PACK_START);
+ gtk_button_set_label (GTK_BUTTON (priv->accept_button),
+ GTK_STOCK_SAVE);
break;
}
break;
@@ -381,7 +508,7 @@ gtk_file_chooser_button_set_property (GObject *object,
case GTK_FILE_CHOOSER_PROP_FILE_SYSTEM_BACKEND:
/* Construct-only */
- priv->filesystem = g_value_dup_string (value);
+ priv->backend = g_value_dup_string (value);
break;
case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE:
@@ -389,24 +516,30 @@ gtk_file_chooser_button_set_property (GObject *object,
G_STRFUNC, G_OBJECT_TYPE_NAME (object));
break;
default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, id, pspec);
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
-
static void
gtk_file_chooser_button_get_property (GObject *object,
- guint id,
+ guint param_id,
GValue *value,
GParamSpec *pspec)
{
- GtkFileChooserButtonPrivate *priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (object);
+ GtkFileChooserButtonPrivate *priv;
- switch (id)
+ priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (object);
+
+ switch (param_id)
{
case PROP_ACTIVE:
- g_value_set_boolean (value, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->button)));
+ g_value_set_boolean (value,
+ gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->button)));
+ break;
+ case PROP_WIDTH_CHARS:
+ g_value_set_int (value,
+ gtk_entry_get_width_chars (GTK_ENTRY (priv->entry)));
break;
case PROP_TITLE:
@@ -424,7 +557,7 @@ gtk_file_chooser_button_get_property (GObject *object,
break;
default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, id, pspec);
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
@@ -441,11 +574,14 @@ gtk_file_chooser_button_destroy (GtkObject * object)
priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (object);
+ if (priv->update_id)
+ g_source_remove (priv->update_id);
+
if (priv->dialog != NULL)
gtk_widget_destroy (priv->dialog);
- if (priv->update_id != 0)
- g_source_remove (priv->update_id);
+ remove_settings_signal (GTK_FILE_CHOOSER_BUTTON (object),
+ gtk_widget_get_screen (GTK_WIDGET (object)));
if (GTK_OBJECT_CLASS (gtk_file_chooser_button_parent_class)->destroy != NULL)
(*GTK_OBJECT_CLASS (gtk_file_chooser_button_parent_class)->destroy) (object);
@@ -494,7 +630,6 @@ gtk_file_chooser_button_drag_data_received (GtkWidget *widget,
break;
selected = FALSE;
- g_signal_handler_block (priv->entry, priv->entry_changed_id);
for (i = 0; !selected && uris[i] != NULL; i++)
{
GtkFileSystem *fs;
@@ -542,7 +677,6 @@ gtk_file_chooser_button_drag_data_received (GtkWidget *widget,
gtk_file_path_free (path);
}
- g_signal_handler_unblock (priv->entry, priv->entry_changed_id);
g_strfreev (uris);
}
@@ -558,44 +692,151 @@ gtk_file_chooser_button_drag_data_received (GtkWidget *widget,
gtk_drag_finish (context, TRUE, FALSE, drag_time);
}
-
static void
gtk_file_chooser_button_show_all (GtkWidget *widget)
{
gtk_widget_show (widget);
}
-
static void
gtk_file_chooser_button_hide_all (GtkWidget *widget)
{
gtk_widget_hide (widget);
}
+static void
+gtk_file_chooser_button_show (GtkWidget *widget)
+{
+ GtkFileChooserButtonPrivate *priv;
+
+ priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (widget);
+
+ if (GTK_WIDGET_CLASS (gtk_file_chooser_button_parent_class)->show)
+ (*GTK_WIDGET_CLASS (gtk_file_chooser_button_parent_class)->show) (widget);
+
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->button)))
+ gtk_widget_show (priv->dialog);
+}
+
+static void
+gtk_file_chooser_button_hide (GtkWidget *widget)
+{
+ GtkFileChooserButtonPrivate *priv;
+
+ priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (widget);
+
+ gtk_widget_hide (priv->dialog);
+
+ if (GTK_WIDGET_CLASS (gtk_file_chooser_button_parent_class)->hide)
+ (*GTK_WIDGET_CLASS (gtk_file_chooser_button_parent_class)->hide) (widget);
+}
static gboolean
gtk_file_chooser_button_mnemonic_activate (GtkWidget *widget,
gboolean group_cycling)
{
- GtkFileChooserButton *button;
+ GtkFileChooserButtonPrivate *priv;
- button = GTK_FILE_CHOOSER_BUTTON (widget);
+ priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (widget);
- switch (gtk_file_chooser_get_action (GTK_FILE_CHOOSER (button->priv->dialog)))
+ switch (gtk_file_chooser_get_action (GTK_FILE_CHOOSER (priv->dialog)))
{
case GTK_FILE_CHOOSER_ACTION_OPEN:
case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
- gtk_widget_grab_focus (button->priv->button);
+ gtk_widget_grab_focus (priv->button);
break;
case GTK_FILE_CHOOSER_ACTION_SAVE:
case GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER:
- gtk_widget_grab_focus (button->priv->entry);
+ gtk_widget_grab_focus (priv->entry);
break;
}
return TRUE;
}
+/* Changes the icons wherever it is needed */
+static void
+change_icon_theme (GtkFileChooserButton *button)
+{
+ GtkSettings *settings;
+ gint width, height;
+
+ settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (button)));
+
+ if (gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_SMALL_TOOLBAR,
+ &width, &height))
+ button->priv->icon_size = MAX (width, height);
+ else
+ button->priv->icon_size = FALLBACK_ICON_SIZE;
+
+ update_icons (button);
+}
+
+/* Callback used when a GtkSettings value changes */
+static void
+settings_notify_cb (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ const char *name;
+
+ name = g_param_spec_get_name (pspec);
+
+ if (strcmp (name, "gtk-icon-theme-name") == 0
+ || strcmp (name, "gtk-icon-sizes") == 0)
+ change_icon_theme (user_data);
+}
+
+/* Installs a signal handler for GtkSettings so that we can monitor changes in
+ * the icon theme.
+ */
+static void
+check_icon_theme (GtkFileChooserButton *button)
+{
+ GtkSettings *settings;
+
+ if (button->priv->settings_signal_id)
+ return;
+
+ if (gtk_widget_has_screen (GTK_WIDGET (button)))
+ {
+ settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (button)));
+ button->priv->settings_signal_id = g_signal_connect (settings, "notify",
+ G_CALLBACK (settings_notify_cb),
+ button);
+
+ change_icon_theme (button);
+ }
+}
+
+static void
+gtk_file_chooser_button_style_set (GtkWidget *widget,
+ GtkStyle *old_style)
+{
+ if (GTK_WIDGET_CLASS (gtk_file_chooser_button_parent_class)->style_set)
+ (*GTK_WIDGET_CLASS (gtk_file_chooser_button_parent_class)->style_set) (widget,
+ old_style);
+
+ if (gtk_widget_has_screen (widget))
+ change_icon_theme (GTK_FILE_CHOOSER_BUTTON (widget));
+}
+
+static void
+gtk_file_chooser_button_screen_changed (GtkWidget *widget,
+ GdkScreen *old_screen)
+{
+ GtkFileChooserButton *button;
+
+ button = GTK_FILE_CHOOSER_BUTTON (widget);
+
+ if (GTK_WIDGET_CLASS (gtk_file_chooser_button_parent_class)->screen_changed)
+ (*GTK_WIDGET_CLASS (gtk_file_chooser_button_parent_class)->screen_changed) (widget,
+ old_screen);
+
+ remove_settings_signal (button, old_screen);
+ check_icon_theme (button);
+}
+
/* ************************************************************************** *
* Public API *
@@ -614,7 +855,9 @@ gtk_file_chooser_button_mnemonic_activate (GtkWidget *widget,
GtkWidget *
gtk_file_chooser_button_new (const gchar *title)
{
- return g_object_new (GTK_TYPE_FILE_CHOOSER_BUTTON, "title", title, NULL);
+ return g_object_new (GTK_TYPE_FILE_CHOOSER_BUTTON,
+ "title", title,
+ NULL);
}
/**
@@ -632,11 +875,12 @@ GtkWidget *
gtk_file_chooser_button_new_with_backend (const gchar *title,
const gchar *backend)
{
- return g_object_new (GTK_TYPE_FILE_CHOOSER_BUTTON, "title", title,
- "file-system-backend", backend, NULL);
+ return g_object_new (GTK_TYPE_FILE_CHOOSER_BUTTON,
+ "title", title,
+ "file-system-backend", backend,
+ NULL);
}
-
/**
* gtk_file_chooser_button_new_with_dialog:
* @dialog: the #GtkDialog widget to use.
@@ -654,10 +898,11 @@ gtk_file_chooser_button_new_with_dialog (GtkWidget *dialog)
{
g_return_val_if_fail (GTK_IS_FILE_CHOOSER_DIALOG (dialog), NULL);
- return g_object_new (GTK_TYPE_FILE_CHOOSER_BUTTON, "dialog", dialog, NULL);
+ return g_object_new (GTK_TYPE_FILE_CHOOSER_BUTTON,
+ "dialog", dialog,
+ NULL);
}
-
/**
* gtk_file_chooser_button_set_title:
* @button: the button widget to modify.
@@ -677,7 +922,6 @@ gtk_file_chooser_button_set_title (GtkFileChooserButton *button,
g_object_notify (G_OBJECT (button), "title");
}
-
/**
* gtk_file_chooser_button_get_title:
* @button: the button widget to examine.
@@ -697,7 +941,6 @@ gtk_file_chooser_button_get_title (GtkFileChooserButton *button)
return gtk_window_get_title (GTK_WINDOW (button->priv->dialog));
}
-
/**
* gtk_file_chooser_button_set_active:
* @button: the button widget to modify.
@@ -716,7 +959,6 @@ gtk_file_chooser_button_set_active (GtkFileChooserButton *button,
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button->priv->button), is_active);
}
-
/**
* gtk_file_chooser_button_get_active:
* @button: the button widget to examine.
@@ -735,193 +977,411 @@ gtk_file_chooser_button_get_active (GtkFileChooserButton *button)
return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button->priv->button));
}
+/**
+ * gtk_file_chooser_button_get_width_chars:
+ * @button: the button widget to examine.
+ *
+ * Retrieves the width in characters of the @button widget's entry and/or label.
+ *
+ * Returns: an integer width (in characters) that the button will use to size itself.
+ *
+ * Since: 2.6
+ **/
+gint
+gtk_file_chooser_button_get_width_chars (GtkFileChooserButton *button)
+{
+ g_return_val_if_fail (GTK_IS_FILE_CHOOSER_BUTTON (button), -1);
+
+ return gtk_entry_get_width_chars (GTK_ENTRY (button->priv->entry));
+}
+
+/**
+ * gtk_file_chooser_button_set_width_chars:
+ * @button: the button widget to examine.
+ * @n_chars: the new width, in chracters.
+ *
+ * Sets the width (in characters) that @button will use to @n_chars.
+ *
+ * Since: 2.6
+ **/
+void
+gtk_file_chooser_button_set_width_chars (GtkFileChooserButton *button,
+ gint n_chars)
+{
+ g_return_if_fail (GTK_IS_FILE_CHOOSER_BUTTON (button));
+
+ gtk_entry_set_width_chars (GTK_ENTRY (button->priv->entry), n_chars);
+ gtk_label_set_width_chars (GTK_LABEL (button->priv->label), n_chars);
+ g_object_notify (G_OBJECT (button), "width-chars");
+}
+
/* ******************* *
* Utility Functions *
* ******************* */
+/* Removes the settings signal handler. It's safe to call multiple times */
static void
-gtk_file_chooser_button_set_dialog (GObject *object,
- GtkWidget *dialog)
+remove_settings_signal (GtkFileChooserButton *button,
+ GdkScreen *screen)
{
- GtkFileChooserButtonPrivate *priv;
- GtkFilePath *path;
-
- priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (object);
-
- priv->dialog = dialog;
+ if (button->priv->settings_signal_id)
+ {
+ GtkSettings *settings;
- g_signal_connect (priv->dialog, "delete-event",
- G_CALLBACK (dialog_delete_event_cb), object);
- g_signal_connect (priv->dialog, "response",
- G_CALLBACK (dialog_response_cb), object);
+ settings = gtk_settings_get_for_screen (screen);
+ g_signal_handler_disconnect (settings,
+ button->priv->settings_signal_id);
+ button->priv->settings_signal_id = 0;
+ }
+}
- /* This is used, instead of the standard delegate, to ensure that signals are only
- * delegated when the OK button is pressed. */
- g_object_set_qdata (object, GTK_FILE_CHOOSER_DELEGATE_QUARK, priv->dialog);
- priv->dialog_folder_changed_id =
- g_signal_connect (priv->dialog, "current-folder-changed",
- G_CALLBACK (dialog_current_folder_changed_cb), object);
- priv->dialog_file_activated_id =
- g_signal_connect (priv->dialog, "file-activated",
- G_CALLBACK (dialog_file_activated_cb), object);
- priv->dialog_selection_changed_id =
- g_signal_connect (priv->dialog, "selection-changed",
- G_CALLBACK (dialog_selection_changed_cb), object);
- g_signal_connect (priv->dialog, "update-preview",
- G_CALLBACK (dialog_update_preview_cb), object);
- g_signal_connect (priv->dialog, "notify",
- G_CALLBACK (dialog_notify_cb), object);
- g_object_add_weak_pointer (G_OBJECT (priv->dialog),
- (gpointer *) (&priv->dialog));
+static GtkIconTheme *
+get_icon_theme (GtkWidget *widget)
+{
+ if (gtk_widget_has_screen (widget))
+ return gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget));
- /* Kinda ugly to set this here... */
- _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (priv->entry),
- _gtk_file_chooser_get_file_system (GTK_FILE_CHOOSER (priv->dialog)));
- path = gtk_file_path_new_steal ("/");
- _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (priv->entry),
- path);
- priv->entry_changed_id = g_signal_connect_after (priv->entry, "changed",
- G_CALLBACK (entry_changed_cb),
- object);
+ return gtk_icon_theme_get_default ();
}
-
-static gchar *
-get_display_name (gchar *filename)
+static gboolean
+check_if_path_exists (GtkFileSystem *fs,
+ const GtkFilePath *path)
{
- const gchar *home_dir;
- gchar *tmp;
- gsize filename_len, home_dir_len;
+ gboolean path_exists;
+ GtkFilePath *parent_path;
- filename_len = strlen (filename);
+ path_exists = FALSE;
+ parent_path = NULL;
- if (g_file_test (filename, G_FILE_TEST_IS_DIR))
+ if (gtk_file_system_get_parent (fs, path, &parent_path, NULL))
{
- tmp = g_new (gchar, filename_len + 2);
- strcpy (tmp, filename);
- tmp[filename_len] = '/';
- tmp[filename_len + 1] = '\0';
- g_free (filename);
- filename = tmp;
+ GtkFileFolder *folder;
+
+ folder = gtk_file_system_get_folder (fs, parent_path, 0, NULL);
+ if (folder)
+ {
+ GtkFileInfo *info;
+
+ info = gtk_file_folder_get_info (folder, path, NULL);
+ if (info)
+ {
+ path_exists = TRUE;
+ gtk_file_info_free (info);
+ }
+
+ g_object_unref (folder);
+ }
+
+ gtk_file_path_free (parent_path);
}
- home_dir = g_get_home_dir ();
- if (home_dir != NULL)
+ return path_exists;
+}
+
+static void
+update_icons (GtkFileChooserButton *button)
+{
+ GtkFileChooserButtonPrivate *priv;
+ GdkPixbuf *pixbuf;
+ GSList *paths;
+
+ priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (button);
+ pixbuf = NULL;
+ paths = _gtk_file_chooser_get_paths (GTK_FILE_CHOOSER (priv->dialog));
+
+ if (paths)
{
- home_dir_len = strlen (home_dir);
+ GtkFilePath *path;
+ GtkFileSystem *fs;
- if (strncmp (home_dir, filename, home_dir_len) == 0)
+ path = paths->data;
+ fs = _gtk_file_chooser_get_file_system (GTK_FILE_CHOOSER (priv->dialog));
+
+ switch (gtk_file_chooser_get_action (GTK_FILE_CHOOSER (priv->dialog)))
{
- tmp = g_build_filename ("~", filename + home_dir_len, NULL);
- g_free (filename);
- filename = tmp;
+ case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
+ {
+ GtkFileSystemVolume *volume;
+
+ volume = gtk_file_system_get_volume_for_path (fs, path);
+ if (volume)
+ {
+ GtkFilePath *base_path;
+
+ base_path = gtk_file_system_volume_get_base_path (fs, volume);
+
+ if (base_path && gtk_file_path_compare (base_path, path) == 0)
+ pixbuf = gtk_file_system_volume_render_icon (fs, volume,
+ GTK_WIDGET (button),
+ priv->icon_size,
+ NULL);
+
+ if (base_path)
+ gtk_file_path_free (base_path);
+
+ gtk_file_system_volume_free (fs, volume);
+ }
+ }
+
+ case GTK_FILE_CHOOSER_ACTION_OPEN:
+ if (!pixbuf)
+ pixbuf = gtk_file_system_render_icon (fs, path, GTK_WIDGET (button),
+ priv->icon_size, NULL);
+ break;
+
+ case GTK_FILE_CHOOSER_ACTION_SAVE:
+ if (check_if_path_exists (fs, path))
+ pixbuf = gtk_icon_theme_load_icon (get_icon_theme (GTK_WIDGET (button)),
+ GTK_STOCK_DIALOG_WARNING,
+ priv->icon_size, 0, NULL);
+ else
+ pixbuf = gtk_icon_theme_load_icon (get_icon_theme (GTK_WIDGET (button)),
+ NEW_FILE_ICON_NAME,
+ priv->icon_size, 0, NULL);
+ break;
+ case GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER:
+ if (check_if_path_exists (fs, path))
+ pixbuf = gtk_icon_theme_load_icon (get_icon_theme (GTK_WIDGET (button)),
+ GTK_STOCK_DIALOG_WARNING,
+ priv->icon_size, 0, NULL);
+ else
+ pixbuf = gtk_icon_theme_load_icon (get_icon_theme (GTK_WIDGET (button)),
+ NEW_DIR_ICON_NAME,
+ priv->icon_size, 0, NULL);
+ break;
}
+
+ gtk_file_paths_free (paths);
}
- return filename;
+ if (!pixbuf)
+ pixbuf = gtk_icon_theme_load_icon (get_icon_theme (GTK_WIDGET (button)),
+ FALLBACK_ICON_NAME,
+ priv->icon_size, 0, NULL);
+
+ gtk_image_set_from_pixbuf (GTK_IMAGE (priv->entry_image), pixbuf);
+ gtk_image_set_from_pixbuf (GTK_IMAGE (priv->label_image), pixbuf);
+
+ if (pixbuf)
+ g_object_unref (pixbuf);
}
static void
-update_entry (GtkFileChooserButton *button)
+update_label (GtkFileChooserButton *button)
{
- gchar *filename;
+ GtkFileChooserButtonPrivate *priv;
+ gchar *label_text;
+ GSList *paths;
+
+ priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (button);
+ paths = _gtk_file_chooser_get_paths (GTK_FILE_CHOOSER (button->priv->dialog));
+ label_text = NULL;
- switch (gtk_file_chooser_get_action (GTK_FILE_CHOOSER (button->priv->dialog)))
+ if (paths)
{
- case GTK_FILE_CHOOSER_ACTION_OPEN:
- case GTK_FILE_CHOOSER_ACTION_SAVE:
- filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (button->priv->dialog));
- break;
- case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
- case GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER:
- filename = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (button->priv->dialog));
- break;
- default:
- g_assert_not_reached ();
- filename = NULL;
- break;
- }
+ GtkFileSystem *fs;
+ GtkFilePath *path;
+ GtkFileSystemVolume *volume;
+
+ path = paths->data;
- if (filename != NULL)
- filename = get_display_name (filename);
+ fs = _gtk_file_chooser_get_file_system (GTK_FILE_CHOOSER (priv->dialog));
- g_signal_handler_block (button->priv->entry, button->priv->entry_changed_id);
- if (filename != NULL)
- gtk_entry_set_text (GTK_ENTRY (button->priv->entry), filename);
- else
- gtk_entry_set_text (GTK_ENTRY (button->priv->entry), "");
- g_signal_handler_unblock (button->priv->entry, button->priv->entry_changed_id);
+ volume = gtk_file_system_get_volume_for_path (fs, path);
+ if (volume)
+ {
+ GtkFilePath *base_path;
+
+ base_path = gtk_file_system_volume_get_base_path (fs, volume);
+ if (base_path && gtk_file_path_compare (base_path, path) == 0)
+ label_text = gtk_file_system_volume_get_display_name (fs, volume);
+
+ if (base_path)
+ gtk_file_path_free (base_path);
+
+ gtk_file_system_volume_free (fs, volume);
+
+ if (label_text)
+ goto out;
+ }
+
+ if (gtk_file_system_path_is_local (fs, path))
+ {
+ const gchar *home;
+ gchar *tmp;
+ gchar *filename;
+
+ filename = gtk_file_system_path_to_filename (fs, path);
+
+ if (!filename)
+ goto out;
+
+ home = g_get_home_dir ();
+
+ /* Munging for psuedo-volumes and files in the user's home tree */
+ if (home)
+ {
+ if (strcmp (filename, home) == 0)
+ {
+ label_text = g_strdup (_("Home"));
+ goto localout;
+ }
+
+ tmp = g_build_filename (home, "Desktop", NULL);
+
+ if (strcmp (filename, tmp) == 0)
+ label_text = g_strdup (_("Desktop"));
+
+ g_free (tmp);
- if (filename != NULL)
- gtk_label_set_text (GTK_LABEL (button->priv->label), filename);
+ if (label_text)
+ goto out;
+
+ if (g_str_has_prefix (filename, home))
+ {
+ label_text = g_strconcat ("~", filename + strlen (home), NULL);
+ goto localout;
+ }
+ }
+
+ if (!label_text)
+ label_text = g_strdup (filename);
+
+ localout:
+ g_free (filename);
+ }
+ else
+ {
+ gchar *uri;
+
+ uri = gtk_file_system_path_to_uri (fs, path);
+
+ if (uri)
+ label_text = uri;
+ }
+
+ out:
+ gtk_file_paths_free (paths);
+ }
+
+ if (label_text)
+ {
+ gtk_label_set_text (GTK_LABEL (priv->label), label_text);
+ g_free (label_text);
+ }
else
- gtk_label_set_text (GTK_LABEL (button->priv->label), _(DEFAULT_FILENAME));
- g_free (filename);
+ gtk_label_set_text (GTK_LABEL (priv->label), _(DEFAULT_FILENAME));
}
-
-static gboolean
-update_dialog (gpointer user_data)
+static void
+update_entry (GtkFileChooserButton *button)
{
GtkFileChooserButtonPrivate *priv;
- const GtkFilePath *folder_path;
- const gchar *file_part;
- gchar *full_uri;
+ GSList *paths;
+ gchar *filename;
- priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (user_data);
- folder_path =
- _gtk_file_chooser_entry_get_current_folder (GTK_FILE_CHOOSER_ENTRY (priv->entry));
- file_part =
- _gtk_file_chooser_entry_get_file_part (GTK_FILE_CHOOSER_ENTRY (priv->entry));
-
- if (folder_path != NULL)
- full_uri = g_build_filename (gtk_file_path_get_string (folder_path),
- file_part, NULL);
- else if (file_part != NULL)
- full_uri = g_build_filename ("file://", file_part, NULL);
- else
- full_uri = NULL;
+ priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (button);
- if (full_uri != NULL)
- {
- gchar *display_name;
+ paths = _gtk_file_chooser_get_paths (GTK_FILE_CHOOSER (priv->dialog));
- display_name = g_filename_from_uri (full_uri, NULL, NULL);
- if (display_name)
+ if (paths)
+ {
+ GtkFileSystem *fs;
+ GtkFilePath *path;
+
+ path = paths->data;
+ fs = _gtk_file_chooser_get_file_system (GTK_FILE_CHOOSER (priv->dialog));
+
+ if (gtk_file_system_path_is_local (fs, path))
{
- display_name = get_display_name (display_name);
- gtk_label_set_text (GTK_LABEL (priv->label), display_name);
- g_free (display_name);
+ filename = gtk_file_system_path_to_filename (fs, path);
+
+ if (filename)
+ {
+ const gchar *home;
+ gchar *tmp;
+
+ if (g_file_test (filename, G_FILE_TEST_IS_DIR))
+ {
+ tmp = g_strconcat (filename, "/", NULL);
+ g_free (filename);
+ filename = tmp;
+ }
+
+ home = g_get_home_dir ();
+
+ if (home && g_str_has_prefix (filename, home))
+ {
+ tmp = g_strconcat ("~", filename + strlen (home), NULL);
+ g_free (filename);
+ filename = tmp;
+ }
+ }
}
+ else
+ filename = gtk_file_system_path_to_uri (fs, path);
}
else
+ filename = NULL;
+
+ if (filename)
{
- gtk_label_set_text (GTK_LABEL (priv->label), _(DEFAULT_FILENAME));
+ gchar *entry_text;
+
+ entry_text = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
+ g_free (filename);
+
+ gtk_entry_set_text (GTK_ENTRY (priv->entry), entry_text);
+ g_free (entry_text);
}
+ else
+ gtk_entry_set_text (GTK_ENTRY (priv->entry), "");
+}
+
+static void
+update_dialog (GtkFileChooserButton *button)
+{
+ GtkFileChooserButtonPrivate *priv;
+ GtkFilePath *current_folder;
+ GtkFileSystem *fs;
+ GtkFilePath *folder_part, *full_path;
+ gchar *file_part;
+ const gchar *text;
+ GtkFilePath *base_path;
+
+ priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (button);
+ file_part = NULL;
+ folder_part = NULL;
+ fs = _gtk_file_chooser_get_file_system (GTK_FILE_CHOOSER (priv->dialog));
+
+ text = gtk_entry_get_text (GTK_ENTRY (priv->entry));
+
+ base_path = gtk_file_path_new_dup ("/");
+ gtk_file_system_parse (fs, base_path, text, &folder_part, &file_part, NULL);
+ gtk_file_path_free (base_path);
switch (gtk_file_chooser_get_action (GTK_FILE_CHOOSER (priv->dialog)))
{
case GTK_FILE_CHOOSER_ACTION_OPEN:
- if (folder_path != NULL)
+ gtk_file_chooser_unselect_all (GTK_FILE_CHOOSER (priv->dialog));
+ if (folder_part)
{
- GtkFileSystem *fs;
GtkFileFolder *folder;
- GtkFilePath *full_path;
GtkFileInfo *info;
- fs = _gtk_file_chooser_get_file_system (GTK_FILE_CHOOSER (priv->dialog));
- folder = gtk_file_system_get_folder (fs, folder_path,
+ folder = gtk_file_system_get_folder (fs, folder_part,
GTK_FILE_INFO_IS_FOLDER, NULL);
- full_path = gtk_file_system_make_path (fs, folder_path, file_part, NULL);
+ full_path = gtk_file_system_make_path (fs, folder_part, file_part, NULL);
info = gtk_file_folder_get_info (folder, full_path, NULL);
/* Entry contents don't exist. */
if (info == NULL)
_gtk_file_chooser_set_current_folder_path (GTK_FILE_CHOOSER (priv->dialog),
- folder_path, NULL);
+ folder_part, NULL);
/* Entry contents are a folder */
else if (gtk_file_info_get_is_folder (info))
_gtk_file_chooser_set_current_folder_path (GTK_FILE_CHOOSER (priv->dialog),
@@ -930,64 +1390,55 @@ update_dialog (gpointer user_data)
else
_gtk_file_chooser_select_path (GTK_FILE_CHOOSER (priv->dialog),
full_path, NULL);
-
+
if (info)
gtk_file_info_free (info);
+
gtk_file_path_free (full_path);
}
- else
- g_free (full_uri);
break;
case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
- if (folder_path != NULL)
+ gtk_file_chooser_unselect_all (GTK_FILE_CHOOSER (priv->dialog));
+ if (folder_part)
{
- GtkFileSystem *fs;
- GtkFilePath *full_path;
-
- fs = _gtk_file_chooser_get_file_system (GTK_FILE_CHOOSER (priv->dialog));
- full_path = gtk_file_system_make_path (fs, folder_path, file_part, NULL);
+ full_path = gtk_file_system_make_path (fs, folder_part, file_part, NULL);
/* Entry contents don't exist. */
- if (full_path != NULL)
+ if (full_path)
_gtk_file_chooser_select_path (GTK_FILE_CHOOSER (priv->dialog),
full_path, NULL);
else
_gtk_file_chooser_set_current_folder_path (GTK_FILE_CHOOSER (priv->dialog),
- folder_path, NULL);
+ folder_part, NULL);
gtk_file_path_free (full_path);
}
- else
- g_free (full_uri);
break;
case GTK_FILE_CHOOSER_ACTION_SAVE:
case GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER:
- if (folder_path != NULL)
- _gtk_file_chooser_set_current_folder_path (GTK_FILE_CHOOSER (priv->dialog),
- folder_path, NULL);
+ gtk_file_chooser_unselect_all (GTK_FILE_CHOOSER (priv->dialog));
+ if (folder_part)
+ {
+ current_folder = _gtk_file_chooser_get_current_folder_path (GTK_FILE_CHOOSER (priv->dialog));
+
+ if (!current_folder ||
+ gtk_file_path_compare (current_folder, folder_part) != 0)
+ {
+ _gtk_file_chooser_set_current_folder_path (GTK_FILE_CHOOSER (priv->dialog),
+ folder_part, NULL);
+ g_signal_emit_by_name (button, "current-folder-changed");
+ }
+
+ if (current_folder)
+ gtk_file_path_free (current_folder);
+ }
gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (priv->dialog),
file_part);
- g_free (full_uri);
+ g_signal_emit_by_name (button, "selection-changed");
break;
}
-
- priv->update_id = 0;
- return FALSE;
-}
-
-static gboolean
-update_dialog_idle (gpointer user_data)
-{
- gboolean result;
-
- GDK_THREADS_ENTER ();
- result = update_dialog (user_data);
- GDK_THREADS_LEAVE ();
-
- return result;
-
}
/* ************************ *
@@ -1001,7 +1452,6 @@ dialog_current_folder_changed_cb (GtkFileChooser *dialog,
g_signal_emit_by_name (user_data, "current-folder-changed");
}
-
static void
dialog_file_activated_cb (GtkFileChooser *dialog,
gpointer user_data)
@@ -1009,15 +1459,31 @@ dialog_file_activated_cb (GtkFileChooser *dialog,
g_signal_emit_by_name (user_data, "file-activated");
}
-
static void
dialog_selection_changed_cb (GtkFileChooser *dialog,
gpointer user_data)
{
+ GtkFileChooserButtonPrivate *priv;
+
+ priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (user_data);
+
+ g_signal_handler_block (priv->entry, priv->entry_changed_id);
update_entry (user_data);
- g_signal_emit_by_name (user_data, "selection-changed");
+ g_signal_handler_unblock (priv->entry, priv->entry_changed_id);
+ update_icons (user_data);
+ update_label (user_data);
}
+static void
+dialog_selection_changed_proxy_cb (GtkFileChooser *dialog,
+ gpointer user_data)
+{
+ GtkFileChooserButtonPrivate *priv;
+
+ priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (user_data);
+
+ g_signal_emit_by_name (user_data, "selection-changed");
+}
static void
dialog_update_preview_cb (GtkFileChooser *dialog,
@@ -1026,7 +1492,6 @@ dialog_update_preview_cb (GtkFileChooser *dialog,
g_signal_emit_by_name (user_data, "update-preview");
}
-
static void
dialog_notify_cb (GObject *dialog,
GParamSpec *pspec,
@@ -1040,7 +1505,6 @@ dialog_notify_cb (GObject *dialog,
g_object_notify (user_data, pspec->name);
}
-
static gboolean
dialog_delete_event_cb (GtkWidget *dialog,
GdkEvent *event,
@@ -1051,7 +1515,6 @@ dialog_delete_event_cb (GtkWidget *dialog,
return TRUE;
}
-
static void
dialog_response_cb (GtkFileChooser *dialog,
gint response,
@@ -1063,7 +1526,11 @@ dialog_response_cb (GtkFileChooser *dialog,
if (response == GTK_RESPONSE_ACCEPT)
{
+ g_signal_handler_block (priv->entry, priv->entry_changed_id);
update_entry (user_data);
+ g_signal_handler_unblock (priv->entry, priv->entry_changed_id);
+ update_label (user_data);
+ update_icons (user_data);
g_signal_emit_by_name (user_data, "current-folder-changed");
g_signal_emit_by_name (user_data, "selection-changed");
@@ -1110,7 +1577,7 @@ button_toggled_cb (GtkToggleButton *real_button,
g_signal_handler_block (priv->dialog,
priv->dialog_file_activated_id);
g_signal_handler_block (priv->dialog,
- priv->dialog_selection_changed_id);
+ priv->dialog_selection_changed_proxy_id);
gtk_widget_set_sensitive (priv->entry, FALSE);
gtk_window_present (GTK_WINDOW (priv->dialog));
}
@@ -1121,13 +1588,12 @@ button_toggled_cb (GtkToggleButton *real_button,
g_signal_handler_unblock (priv->dialog,
priv->dialog_file_activated_id);
g_signal_handler_unblock (priv->dialog,
- priv->dialog_selection_changed_id);
+ priv->dialog_selection_changed_proxy_id);
gtk_widget_set_sensitive (priv->entry, TRUE);
gtk_widget_hide (priv->dialog);
}
}
-
static void
button_notify_active_cb (GObject *real_button,
GParamSpec *pspec,
@@ -1137,26 +1603,57 @@ button_notify_active_cb (GObject *real_button,
}
-/* Ensure the button height == entry height */
-static void
-entry_size_allocate_cb (GtkWidget *entry,
- GtkAllocation *allocation,
- gpointer user_data)
+static gboolean
+update_idler (gpointer user_data)
{
- gtk_widget_set_size_request (user_data, -1, allocation->height);
-}
+ GtkFileChooserButtonPrivate *priv;
+ gboolean retval;
+
+ GDK_THREADS_ENTER ();
+ priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (user_data);
+
+ if (!gtk_editable_get_selection_bounds (GTK_EDITABLE (priv->entry),
+ NULL, NULL))
+ {
+ g_signal_handler_block (priv->dialog,
+ priv->dialog_selection_changed_id);
+ update_dialog (user_data);
+ g_signal_handler_unblock (priv->dialog,
+ priv->dialog_selection_changed_id);
+ update_icons (user_data);
+ update_label (user_data);
+ priv->update_id = 0;
+ retval = FALSE;
+ }
+ else
+ retval = TRUE;
+
+ GDK_THREADS_LEAVE ();
+
+ return retval;
+}
static void
-entry_changed_cb (GtkEditable *chooser_entry,
+entry_changed_cb (GtkEditable *editable,
gpointer user_data)
{
GtkFileChooserButtonPrivate *priv;
priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (user_data);
- /* We do this in an idle handler to avoid totally screwing up chooser_entry's
- * completion */
- if (priv->update_id != 0)
- priv->update_id = g_idle_add (update_dialog_idle, user_data);
+ if (priv->update_id)
+ g_source_remove (priv->update_id);
+
+ priv->update_id = g_idle_add_full (G_PRIORITY_LOW, update_idler,
+ user_data, NULL);
+}
+
+/* Ensure the button height == entry height */
+static void
+entry_size_allocate_cb (GtkWidget *entry,
+ GtkAllocation *allocation,
+ gpointer user_data)
+{
+ gtk_widget_set_size_request (user_data, -1, allocation->height);
}