summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog23
-rw-r--r--ChangeLog.pre-2-1023
-rw-r--r--ChangeLog.pre-2-623
-rw-r--r--ChangeLog.pre-2-823
-rw-r--r--gtk/Makefile.am3
-rw-r--r--gtk/gtk.h1
-rw-r--r--gtk/gtk.symbols8
-rw-r--r--gtk/gtkfilechooserbutton.c1122
-rw-r--r--gtk/gtkfilechooserbutton.h89
-rw-r--r--gtk/gtkfilechooserdefault.c4
-rw-r--r--gtk/gtkfilechooserentry.c14
-rw-r--r--gtk/gtkfilechooserentry.h2
-rw-r--r--gtk/gtkfilechooserutils.c14
-rw-r--r--gtk/gtkfilechooserutils.h4
-rw-r--r--tests/Makefile.am7
-rw-r--r--tests/testfilechooserbutton.c167
16 files changed, 1520 insertions, 7 deletions
diff --git a/ChangeLog b/ChangeLog
index ec2d48de32..ef058165c6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2004-08-17 Matthias Clasen <mclasen@redhat.com>
+
+ * gtk/gtkfilechooserbutton.[hc]: New widget to go along with
+ GtkFontButton and GtkColorButton for use in preference dialogs.
+ Replaces GnomeFileEntry. (#148108, James M. Cape)
+
+ * gtk/gtk.h: Include gtkfilechooserbutton.h
+
+ * gtk/Makefile.am (gtk_public_h_sources): Add gtkfilechooserbutton.h
+ (gtk_c_sources): Add gtkfilechooserbutton.c
+
+ * gtk/gtk.symbols: Add the GtkFileChooserButton symbols.
+
+ * gtk/gtkfilechooserutils.[hc]: Make the delegate quark available.
+
+ * gtk/gtkfilechooserentry.[hc] (_gtk_file_chooser_entry_new): Allow
+ to suppress tab-eating using the new eat_tabs argument. Adjust all
+ callers.
+
+ * tests/testfilechooserbutton.c: Test for GtkFileChooserButton.
+
+ * tests/Makefile.am (noinst_PROGRAMS): Add testfilechooserbutton
+
2004-08-16 Matthias Clasen <mclasen@redhat.com>
* gtk/gtkwidget.c (gtk_widget_render_icon): Doc update.
diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10
index ec2d48de32..ef058165c6 100644
--- a/ChangeLog.pre-2-10
+++ b/ChangeLog.pre-2-10
@@ -1,3 +1,26 @@
+2004-08-17 Matthias Clasen <mclasen@redhat.com>
+
+ * gtk/gtkfilechooserbutton.[hc]: New widget to go along with
+ GtkFontButton and GtkColorButton for use in preference dialogs.
+ Replaces GnomeFileEntry. (#148108, James M. Cape)
+
+ * gtk/gtk.h: Include gtkfilechooserbutton.h
+
+ * gtk/Makefile.am (gtk_public_h_sources): Add gtkfilechooserbutton.h
+ (gtk_c_sources): Add gtkfilechooserbutton.c
+
+ * gtk/gtk.symbols: Add the GtkFileChooserButton symbols.
+
+ * gtk/gtkfilechooserutils.[hc]: Make the delegate quark available.
+
+ * gtk/gtkfilechooserentry.[hc] (_gtk_file_chooser_entry_new): Allow
+ to suppress tab-eating using the new eat_tabs argument. Adjust all
+ callers.
+
+ * tests/testfilechooserbutton.c: Test for GtkFileChooserButton.
+
+ * tests/Makefile.am (noinst_PROGRAMS): Add testfilechooserbutton
+
2004-08-16 Matthias Clasen <mclasen@redhat.com>
* gtk/gtkwidget.c (gtk_widget_render_icon): Doc update.
diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6
index ec2d48de32..ef058165c6 100644
--- a/ChangeLog.pre-2-6
+++ b/ChangeLog.pre-2-6
@@ -1,3 +1,26 @@
+2004-08-17 Matthias Clasen <mclasen@redhat.com>
+
+ * gtk/gtkfilechooserbutton.[hc]: New widget to go along with
+ GtkFontButton and GtkColorButton for use in preference dialogs.
+ Replaces GnomeFileEntry. (#148108, James M. Cape)
+
+ * gtk/gtk.h: Include gtkfilechooserbutton.h
+
+ * gtk/Makefile.am (gtk_public_h_sources): Add gtkfilechooserbutton.h
+ (gtk_c_sources): Add gtkfilechooserbutton.c
+
+ * gtk/gtk.symbols: Add the GtkFileChooserButton symbols.
+
+ * gtk/gtkfilechooserutils.[hc]: Make the delegate quark available.
+
+ * gtk/gtkfilechooserentry.[hc] (_gtk_file_chooser_entry_new): Allow
+ to suppress tab-eating using the new eat_tabs argument. Adjust all
+ callers.
+
+ * tests/testfilechooserbutton.c: Test for GtkFileChooserButton.
+
+ * tests/Makefile.am (noinst_PROGRAMS): Add testfilechooserbutton
+
2004-08-16 Matthias Clasen <mclasen@redhat.com>
* gtk/gtkwidget.c (gtk_widget_render_icon): Doc update.
diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8
index ec2d48de32..ef058165c6 100644
--- a/ChangeLog.pre-2-8
+++ b/ChangeLog.pre-2-8
@@ -1,3 +1,26 @@
+2004-08-17 Matthias Clasen <mclasen@redhat.com>
+
+ * gtk/gtkfilechooserbutton.[hc]: New widget to go along with
+ GtkFontButton and GtkColorButton for use in preference dialogs.
+ Replaces GnomeFileEntry. (#148108, James M. Cape)
+
+ * gtk/gtk.h: Include gtkfilechooserbutton.h
+
+ * gtk/Makefile.am (gtk_public_h_sources): Add gtkfilechooserbutton.h
+ (gtk_c_sources): Add gtkfilechooserbutton.c
+
+ * gtk/gtk.symbols: Add the GtkFileChooserButton symbols.
+
+ * gtk/gtkfilechooserutils.[hc]: Make the delegate quark available.
+
+ * gtk/gtkfilechooserentry.[hc] (_gtk_file_chooser_entry_new): Allow
+ to suppress tab-eating using the new eat_tabs argument. Adjust all
+ callers.
+
+ * tests/testfilechooserbutton.c: Test for GtkFileChooserButton.
+
+ * tests/Makefile.am (noinst_PROGRAMS): Add testfilechooserbutton
+
2004-08-16 Matthias Clasen <mclasen@redhat.com>
* gtk/gtkwidget.c (gtk_widget_render_icon): Doc update.
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 26e223ac9a..2feac995f1 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -159,6 +159,7 @@ gtk_public_h_sources = \
gtkeventbox.h \
gtkexpander.h \
gtkfilechooser.h \
+ gtkfilechooserbutton.h \
gtkfilechooserdialog.h \
gtkfilechooserwidget.h \
gtkfilefilter.h \
@@ -363,6 +364,7 @@ gtk_c_sources = \
gtkeventbox.c \
gtkexpander.c \
gtkfilechooser.c \
+ gtkfilechooserbutton.c \
gtkfilechooserdialog.c \
gtkfilechooserembed.c \
gtkfilechooserentry.c \
@@ -731,4 +733,3 @@ EXTRA_DIST += \
abicheck.sh
install-data-local:
-
diff --git a/gtk/gtk.h b/gtk/gtk.h
index dd5a3d902a..cce4ef82b6 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -78,6 +78,7 @@
#include <gtk/gtkexpander.h>
#include <gtk/gtkfilesel.h>
#include <gtk/gtkfixed.h>
+#include <gtk/gtkfilechooserbutton.h>
#include <gtk/gtkfilechooserdialog.h>
#include <gtk/gtkfilechooserwidget.h>
#include <gtk/gtkfontbutton.h>
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index 026ad7cd8c..78e906706a 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -749,6 +749,14 @@ gtk_file_chooser_action_get_type
gtk_file_chooser_add_filter
gtk_file_chooser_add_shortcut_folder
gtk_file_chooser_add_shortcut_folder_uri
+gtk_file_chooser_button_get_active
+gtk_file_chooser_button_get_type
+gtk_file_chooser_button_get_title
+gtk_file_chooser_button_new
+gtk_file_chooser_button_new_with_backend
+gtk_file_chooser_button_new_with_dialog
+gtk_file_chooser_button_set_active
+gtk_file_chooser_button_set_title
gtk_file_chooser_dialog_get_type
gtk_file_chooser_dialog_new
gtk_file_chooser_dialog_new_with_backend
diff --git a/gtk/gtkfilechooserbutton.c b/gtk/gtkfilechooserbutton.c
new file mode 100644
index 0000000000..dfc1b68c41
--- /dev/null
+++ b/gtk/gtkfilechooserbutton.c
@@ -0,0 +1,1122 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 2 -*- */
+
+/* GTK+: gtkfilechooserbutton.c
+ *
+ * Copyright (c) 2004 James M. Cape <jcape@ignore-your.tv>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <string.h>
+
+#include "gtkalias.h"
+#include "gtkintl.h"
+#include "gtkdnd.h"
+#include "gtkentry.h"
+#include "gtkhbox.h"
+#include "gtkicontheme.h"
+#include "gtkimage.h"
+#include "gtklabel.h"
+#include "gtkstock.h"
+#include "gtktogglebutton.h"
+#include "gtkvseparator.h"
+#include "gtkfilechooserdialog.h"
+#include "gtkfilechooserentry.h"
+#include "gtkfilechooserprivate.h"
+#include "gtkfilechooserutils.h"
+
+#include "gtkfilechooserbutton.h"
+
+
+/* **************** *
+ * Private Macros *
+ * **************** */
+
+#define GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE(object) (GTK_FILE_CHOOSER_BUTTON ((object))->priv)
+
+#define DEFAULT_TITLE N_("Select a File")
+#define DEFAULT_FILENAME N_("(None)")
+#define DEFAULT_SPACING 0
+
+
+/* ********************** *
+ * Private Enumerations *
+ * ********************** */
+
+/* Property IDs */
+enum
+{
+ PROP_0,
+
+ PROP_DIALOG,
+ PROP_TITLE,
+ PROP_ACTIVE
+};
+
+
+/* ******************** *
+ * Private Structures *
+ * ******************** */
+
+struct _GtkFileChooserButtonPrivate
+{
+ GtkWidget *dialog;
+ GtkWidget *entry;
+ GtkWidget *label;
+ GtkWidget *separator;
+ GtkWidget *button;
+
+ gchar *filesystem;
+ gulong entry_changed_id;
+ gulong dialog_file_activated_id;
+ gulong dialog_folder_changed_id;
+ gulong dialog_selection_changed_id;
+ guint update_id;
+};
+
+
+/* ************* *
+ * DnD Support *
+ * ************* */
+
+enum
+{
+ TEXT_URI_LIST,
+ TEXT_PLAIN
+};
+
+static const GtkTargetEntry drop_targets[] = {
+ { "text/uri-list", 0, TEXT_URI_LIST },
+ { "text/plain", 0, TEXT_PLAIN }
+};
+
+
+/* ********************* *
+ * Function Prototypes *
+ * ********************* */
+
+/* GObject Functions */
+static void gtk_file_chooser_button_set_property (GObject *object,
+ guint id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gtk_file_chooser_button_get_property (GObject *object,
+ guint id,
+ GValue *value,
+ GParamSpec *pspec);
+
+/* GtkObject Functions */
+static void gtk_file_chooser_button_destroy (GtkObject *object);
+
+/* GtkWidget Functions */
+static void gtk_file_chooser_button_drag_data_received (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *data,
+ guint info,
+ guint drag_time);
+static void gtk_file_chooser_button_show_all (GtkWidget *widget);
+static void gtk_file_chooser_button_hide_all (GtkWidget *widget);
+
+/* 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_file_activated_cb (GtkFileChooser *dialog,
+ gpointer user_data);
+static void dialog_current_folder_changed_cb (GtkFileChooser *dialog,
+ gpointer user_data);
+static void dialog_notify_cb (GObject *dialog,
+ GParamSpec *pspec,
+ gpointer user_data);
+static gboolean dialog_delete_event_cb (GtkWidget *dialog,
+ GdkEvent *event,
+ gpointer user_data);
+static void dialog_response_cb (GtkFileChooser *dialog,
+ gint response,
+ gpointer user_data);
+
+static void button_toggled_cb (GtkToggleButton *real_button,
+ gpointer user_data);
+static void button_notify_active_cb (GObject *real_button,
+ GParamSpec *pspec,
+ gpointer user_data);
+
+static void entry_size_allocate_cb (GtkWidget *entry,
+ GtkAllocation *allocation,
+ gpointer user_data);
+static void entry_changed_cb (GtkEditable *chooser_entry,
+ gpointer user_data);
+
+/* Utility Functions */
+static void gtk_file_chooser_button_set_dialog (GObject *object,
+ GtkWidget *dialog);
+
+static gboolean update_dialog (gpointer user_data);
+static void update_entry (GtkFileChooserButton *button);
+
+
+/* ******************* *
+ * GType Declaration *
+ * ******************* */
+
+G_DEFINE_TYPE_WITH_CODE (GtkFileChooserButton, gtk_file_chooser_button, GTK_TYPE_HBOX, { \
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_FILE_CHOOSER, _gtk_file_chooser_delegate_iface_init) \
+});
+
+
+/* ***************** *
+ * GType Functions *
+ * ***************** */
+
+static void
+gtk_file_chooser_button_class_init (GtkFileChooserButtonClass * class)
+{
+ GObjectClass *gobject_class;
+ GtkObjectClass *gtkobject_class;
+ GtkWidgetClass *widget_class;
+
+ gobject_class = G_OBJECT_CLASS (class);
+ gtkobject_class = GTK_OBJECT_CLASS (class);
+ widget_class = GTK_WIDGET_CLASS (class);
+
+ gobject_class->set_property = gtk_file_chooser_button_set_property;
+ gobject_class->get_property = gtk_file_chooser_button_get_property;
+
+ gtkobject_class->destroy = gtk_file_chooser_button_destroy;
+
+ 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;
+
+ g_object_class_install_property (gobject_class, PROP_DIALOG,
+ g_param_spec_object ("dialog",
+ P_("Dialog"),
+ P_("The file chooser dialog to use."),
+ GTK_TYPE_FILE_CHOOSER_DIALOG,
+ (G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY)));
+ g_object_class_install_property (gobject_class, PROP_TITLE,
+ g_param_spec_string ("title",
+ P_("Title"),
+ P_("The title of the file chooser dialog."),
+ _(DEFAULT_TITLE),
+ G_PARAM_READWRITE));
+ g_object_class_install_property (gobject_class, PROP_ACTIVE,
+ g_param_spec_boolean ("active",
+ P_("Active"),
+ P_("Whether the browse dialog is visible or not."),
+ FALSE, G_PARAM_READWRITE));
+
+ _gtk_file_chooser_install_properties (gobject_class);
+
+ g_type_class_add_private (class, sizeof (GtkFileChooserButtonPrivate));
+}
+
+
+static void
+gtk_file_chooser_button_init (GtkFileChooserButton *button)
+{
+ GtkFileChooserButtonPrivate *priv;
+ GtkWidget *box, *image;
+
+ gtk_box_set_spacing (GTK_BOX (button), DEFAULT_SPACING);
+
+ priv = G_TYPE_INSTANCE_GET_PRIVATE (button, GTK_TYPE_FILE_CHOOSER_BUTTON,
+ GtkFileChooserButtonPrivate);
+ button->priv = priv;
+
+ gtk_widget_push_composite_child ();
+
+ priv->entry = _gtk_file_chooser_entry_new (FALSE);
+ gtk_container_add (GTK_CONTAINER (button), priv->entry);
+
+ priv->button = gtk_toggle_button_new ();
+ g_signal_connect (priv->button, "toggled",
+ G_CALLBACK (button_toggled_cb), button);
+ g_signal_connect (priv->button, "notify::active",
+ G_CALLBACK (button_notify_active_cb), button);
+ g_signal_connect (priv->entry, "size-allocate",
+ G_CALLBACK (entry_size_allocate_cb), priv->button);
+ gtk_box_pack_start (GTK_BOX (button), priv->button, TRUE, TRUE, 0);
+ gtk_widget_show (priv->button);
+
+ box = gtk_hbox_new (FALSE, 4);
+ gtk_container_add (GTK_CONTAINER (priv->button), box);
+ gtk_widget_show (box);
+
+ 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_widget_show (priv->label);
+
+ 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 */
+ gtk_drag_dest_unset (priv->entry);
+ gtk_drag_dest_set (GTK_WIDGET (button),
+ (GTK_DEST_DEFAULT_MOTION |
+ GTK_DEST_DEFAULT_HIGHLIGHT |
+ GTK_DEST_DEFAULT_DROP),
+ drop_targets, G_N_ELEMENTS (drop_targets),
+ GDK_ACTION_COPY);
+}
+
+
+/* ******************* *
+ * GObject Functions *
+ * ******************* */
+
+
+static void
+gtk_file_chooser_button_set_property (GObject *object,
+ guint id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkFileChooserButtonPrivate *priv;
+
+ priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (object);
+
+ switch (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);
+ }
+ break;
+ case PROP_ACTIVE:
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button),
+ g_value_get_boolean (value));
+ break;
+
+ case GTK_FILE_CHOOSER_PROP_ACTION:
+ g_object_set_property (G_OBJECT (priv->dialog), pspec->name, value);
+
+ switch (g_value_get_enum (value))
+ {
+ case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
+ 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_box_set_child_packing (GTK_BOX (object), priv->button,
+ TRUE, TRUE, 0, GTK_PACK_START);
+ 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_box_set_child_packing (GTK_BOX (object), priv->button,
+ FALSE, FALSE, 0, GTK_PACK_START);
+ break;
+ }
+ break;
+
+ case PROP_TITLE:
+ case GTK_FILE_CHOOSER_PROP_FILTER:
+ case GTK_FILE_CHOOSER_PROP_LOCAL_ONLY:
+ case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET:
+ case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET_ACTIVE:
+ case GTK_FILE_CHOOSER_PROP_USE_PREVIEW_LABEL:
+ case GTK_FILE_CHOOSER_PROP_EXTRA_WIDGET:
+ case GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN:
+ g_object_set_property (G_OBJECT (priv->dialog), pspec->name, value);
+ break;
+
+ case GTK_FILE_CHOOSER_PROP_FILE_SYSTEM_BACKEND:
+ /* Construct-only */
+ priv->filesystem = g_value_dup_string (value);
+ break;
+
+ case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE:
+ g_warning ("%s: Choosers of type `%s` do not support selecting multiple files.",
+ G_STRFUNC, G_OBJECT_TYPE_NAME (object));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, id, pspec);
+ break;
+ }
+}
+
+
+static void
+gtk_file_chooser_button_get_property (GObject *object,
+ guint id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkFileChooserButtonPrivate *priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (object);
+
+ switch (id)
+ {
+ case PROP_ACTIVE:
+ g_value_set_boolean (value, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->button)));
+ break;
+
+ case PROP_TITLE:
+ case GTK_FILE_CHOOSER_PROP_ACTION:
+ case GTK_FILE_CHOOSER_PROP_FILE_SYSTEM_BACKEND:
+ case GTK_FILE_CHOOSER_PROP_FILTER:
+ case GTK_FILE_CHOOSER_PROP_LOCAL_ONLY:
+ case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET:
+ case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET_ACTIVE:
+ case GTK_FILE_CHOOSER_PROP_USE_PREVIEW_LABEL:
+ case GTK_FILE_CHOOSER_PROP_EXTRA_WIDGET:
+ case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE:
+ case GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN:
+ g_object_get_property (G_OBJECT (priv->dialog), pspec->name, value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, id, pspec);
+ break;
+ }
+}
+
+
+/* ********************* *
+ * GtkObject Functions *
+ * ********************* */
+
+static void
+gtk_file_chooser_button_destroy (GtkObject * object)
+{
+ GtkFileChooserButtonPrivate *priv;
+
+ priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (object);
+
+ if (priv->dialog != NULL)
+ gtk_widget_destroy (priv->dialog);
+
+ if (priv->update_id != 0)
+ g_source_remove (priv->update_id);
+
+ if (GTK_OBJECT_CLASS (gtk_file_chooser_button_parent_class)->destroy != NULL)
+ (*GTK_OBJECT_CLASS (gtk_file_chooser_button_parent_class)->destroy) (object);
+}
+
+
+/* ********************* *
+ * GtkWidget Functions *
+ * ********************* */
+
+static void
+gtk_file_chooser_button_drag_data_received (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *data,
+ guint info,
+ guint drag_time)
+{
+ GtkFileChooserButtonPrivate *priv;
+
+ if (GTK_WIDGET_CLASS (gtk_file_chooser_button_parent_class)->drag_data_received != NULL)
+ (*GTK_WIDGET_CLASS (gtk_file_chooser_button_parent_class)->drag_data_received) (widget,
+ context,
+ x, y,
+ data, info,
+ drag_time);
+
+ if (widget == NULL || context == NULL || data == NULL || data->length < 0)
+ return;
+
+ priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (widget);
+
+ switch (info)
+ {
+ case TEXT_URI_LIST:
+ {
+ gchar **uris;
+ guint i;
+ gboolean selected;
+
+ uris = g_strsplit (data->data, "\r\n", -1);
+
+ if (uris == NULL)
+ break;
+
+ selected = FALSE;
+ g_signal_handler_block (priv->entry, priv->entry_changed_id);
+ for (i = 0; !selected && uris[i] != NULL; i++)
+ {
+ GtkFileSystem *fs;
+ GtkFilePath *path, *base_path;
+
+ fs = _gtk_file_chooser_get_file_system (GTK_FILE_CHOOSER (priv->dialog));
+ path = gtk_file_system_uri_to_path (fs, uris[i]);
+
+ base_path = NULL;
+ if (path != NULL &&
+ gtk_file_system_get_parent (fs, path, &base_path, NULL))
+ {
+ GtkFileFolder *folder;
+ GtkFileInfo *info;
+
+ folder = gtk_file_system_get_folder (fs, base_path,
+ GTK_FILE_INFO_IS_FOLDER,
+ NULL);
+
+ info = gtk_file_folder_get_info (folder, base_path, NULL);
+
+ if (info != NULL)
+ {
+ GtkFileChooserAction action;
+
+ g_object_get (priv->dialog, "action", &action, NULL);
+
+ selected =
+ ((((action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER ||
+ action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) &&
+ gtk_file_info_get_is_folder (info)) ||
+ ((action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+ action == GTK_FILE_CHOOSER_ACTION_SAVE) &&
+ !gtk_file_info_get_is_folder (info))) &&
+ _gtk_file_chooser_select_path (GTK_FILE_CHOOSER (priv->dialog),
+ path, NULL));
+
+ gtk_file_info_free (info);
+ }
+ else
+ selected = FALSE;
+
+ gtk_file_path_free (base_path);
+ }
+
+ gtk_file_path_free (path);
+ }
+ g_signal_handler_unblock (priv->entry, priv->entry_changed_id);
+
+ g_strfreev (uris);
+ }
+ break;
+
+ case TEXT_PLAIN:
+ gtk_entry_set_text (GTK_ENTRY (priv->entry), data->data);
+ break;
+ }
+
+ gtk_drag_finish (context, FALSE, 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);
+}
+
+
+/* ************************************************************************** *
+ * Public API *
+ * ************************************************************************** */
+
+/**
+ * gtk_file_chooser_button_new:
+ * @title: the title of the browse dialog.
+ *
+ * Creates a new file-selecting button widget.
+ *
+ * Returns: a new button widget.
+ *
+ * Since: 2.6
+ **/
+GtkWidget *
+gtk_file_chooser_button_new (const gchar *title)
+{
+ return g_object_new (GTK_TYPE_FILE_CHOOSER_BUTTON, "title", title, NULL);
+}
+
+/**
+ * gtk_file_chooser_button_new_with_backend:
+ * @title: the title of the browse dialog.
+ * @backend: the name of the #GtkFileSystem backend to use.
+ *
+ * Creates a new file-selecting button widget using @backend.
+ *
+ * Returns: a new button widget.
+ *
+ * Since: 2.6
+ **/
+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);
+}
+
+
+/**
+ * gtk_file_chooser_button_new_with_dialog:
+ * @dialog: the #GtkDialog widget to use.
+ *
+ * Creates a #GtkFileChooserButton widget which uses @dialog as it's
+ * file-picking window. Note that @dialog must be a #GtkFileChooserDialog (or
+ * subclass).
+ *
+ * Returns: a new button widget.
+ *
+ * Since: 2.6
+ **/
+GtkWidget *
+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);
+}
+
+
+/**
+ * gtk_file_chooser_button_set_title:
+ * @button: the button widget to modify.
+ * @title: the new browse dialog title.
+ *
+ * Modifies the @title of the browse dialog used by @button.
+ *
+ * Since: 2.6
+ **/
+void
+gtk_file_chooser_button_set_title (GtkFileChooserButton *button,
+ const gchar *title)
+{
+ g_return_if_fail (GTK_IS_FILE_CHOOSER_BUTTON (button));
+
+ gtk_window_set_title (GTK_WINDOW (button->priv->dialog), title);
+ g_object_notify (G_OBJECT (button), "title");
+}
+
+
+/**
+ * gtk_file_chooser_button_get_title:
+ * @button: the button widget to examine.
+ *
+ * Retrieves the title of the browse dialog used by @button. The returned value
+ * should not be modified or freed.
+ *
+ * Returns: a pointer to the browse dialog's title.
+ *
+ * Since: 2.6
+ **/
+G_CONST_RETURN gchar *
+gtk_file_chooser_button_get_title (GtkFileChooserButton *button)
+{
+ g_return_val_if_fail (GTK_IS_FILE_CHOOSER_BUTTON (button), NULL);
+
+ return gtk_window_get_title (GTK_WINDOW (button->priv->dialog));
+}
+
+
+/**
+ * gtk_file_chooser_button_set_active:
+ * @button: the button widget to modify.
+ * @is_active: whether or not the dialog is visible.
+ *
+ * Modifies whether or not the dialog attached to @button is visible or not.
+ *
+ * Since: 2.6
+ **/
+void
+gtk_file_chooser_button_set_active (GtkFileChooserButton *button,
+ gboolean is_active)
+{
+ g_return_if_fail (GTK_IS_FILE_CHOOSER_BUTTON (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.
+ *
+ * Retrieves whether or not the dialog attached to @button is visible.
+ *
+ * Returns: a boolean whether the dialog is visible or not.
+ *
+ * Since: 2.6
+ **/
+gboolean
+gtk_file_chooser_button_get_active (GtkFileChooserButton *button)
+{
+ g_return_val_if_fail (GTK_IS_FILE_CHOOSER_BUTTON (button), FALSE);
+
+ return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button->priv->button));
+}
+
+
+/* ******************* *
+ * Utility Functions *
+ * ******************* */
+
+static void
+gtk_file_chooser_button_set_dialog (GObject *object,
+ GtkWidget *dialog)
+{
+ GtkFileChooserButtonPrivate *priv;
+ GtkFilePath *path;
+
+ priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (object);
+
+ priv->dialog = dialog;
+
+ 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);
+ 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));
+
+ /* 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 ("file:///");
+ _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);
+}
+
+
+static gchar *
+get_display_name (gchar *filename)
+{
+ const gchar *home_dir;
+ gchar *tmp;
+ gsize filename_len, home_dir_len;
+
+ filename_len = strlen (filename);
+
+ if (g_file_test (filename, G_FILE_TEST_IS_DIR))
+ {
+ tmp = g_new (gchar, filename_len + 2);
+ strcpy (tmp, filename);
+ tmp[filename_len] = '/';
+ tmp[filename_len + 1] = '\0';
+ g_free (filename);
+ filename = tmp;
+ }
+
+ home_dir = g_get_home_dir ();
+ if (home_dir != NULL)
+ {
+ home_dir_len = strlen (home_dir);
+
+ if (strncmp (home_dir, filename, home_dir_len) == 0)
+ {
+ tmp = g_build_filename ("~", filename + home_dir_len, NULL);
+ g_free (filename);
+ filename = tmp;
+ }
+ }
+
+ return filename;
+}
+
+
+static void
+update_entry (GtkFileChooserButton *button)
+{
+ gchar *filename;
+
+ switch (gtk_file_chooser_get_action (GTK_FILE_CHOOSER (button->priv->dialog)))
+ {
+ 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;
+ }
+
+ if (filename != NULL)
+ filename = get_display_name (filename);
+
+ 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);
+
+ if (filename != NULL)
+ gtk_label_set_text (GTK_LABEL (button->priv->label), filename);
+ else
+ gtk_label_set_text (GTK_LABEL (button->priv->label), _(DEFAULT_FILENAME));
+ g_free (filename);
+}
+
+
+static gboolean
+update_dialog (gpointer user_data)
+{
+ GtkFileChooserButtonPrivate *priv;
+ const GtkFilePath *folder_path;
+ const gchar *file_part;
+ gchar *full_uri;
+
+ 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;
+
+ if (full_uri != NULL)
+ {
+ gchar *display_name;
+
+ display_name = g_filename_from_uri (full_uri, NULL, NULL);
+ display_name = get_display_name (display_name);
+ gtk_label_set_text (GTK_LABEL (priv->label), display_name);
+ g_free (display_name);
+ }
+ else
+ {
+ gtk_label_set_text (GTK_LABEL (priv->label), _(DEFAULT_FILENAME));
+ }
+
+ switch (gtk_file_chooser_get_action (GTK_FILE_CHOOSER (priv->dialog)))
+ {
+ case GTK_FILE_CHOOSER_ACTION_OPEN:
+ if (folder_path != NULL)
+ {
+ 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,
+ GTK_FILE_INFO_IS_FOLDER, NULL);
+
+ full_path = gtk_file_system_make_path (fs, folder_path, 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);
+ /* 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),
+ full_path, NULL);
+ /* Entry contents must be a file. */
+ else
+ _gtk_file_chooser_select_path (GTK_FILE_CHOOSER (priv->dialog),
+ full_path, NULL);
+
+ 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)
+ {
+ 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);
+
+ /* Entry contents don't exist. */
+ if (full_path != NULL)
+ _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);
+
+ 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_set_current_name (GTK_FILE_CHOOSER (priv->dialog),
+ file_part);
+ g_free (full_uri);
+ break;
+ }
+
+ priv->update_id = 0;
+ return FALSE;
+}
+
+/* ************************ *
+ * Child-Widget Callbacks *
+ * ************************ */
+
+static void
+dialog_current_folder_changed_cb (GtkFileChooser *dialog,
+ gpointer user_data)
+{
+ g_signal_emit_by_name (user_data, "current-folder-changed");
+}
+
+
+static void
+dialog_file_activated_cb (GtkFileChooser *dialog,
+ gpointer user_data)
+{
+ g_signal_emit_by_name (user_data, "file-activated");
+}
+
+
+static void
+dialog_selection_changed_cb (GtkFileChooser *dialog,
+ gpointer user_data)
+{
+ update_entry (user_data);
+ g_signal_emit_by_name (user_data, "selection-changed");
+}
+
+
+static void
+dialog_update_preview_cb (GtkFileChooser *dialog,
+ gpointer user_data)
+{
+ g_signal_emit_by_name (user_data, "update-preview");
+}
+
+
+static void
+dialog_notify_cb (GObject *dialog,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ gpointer iface;
+
+ iface = g_type_interface_peek (g_type_class_peek (G_OBJECT_TYPE (dialog)),
+ GTK_TYPE_FILE_CHOOSER);
+ if (g_object_interface_find_property (iface, pspec->name))
+ g_object_notify (user_data, pspec->name);
+}
+
+
+static gboolean
+dialog_delete_event_cb (GtkWidget *dialog,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ g_signal_emit_by_name (dialog, "response", GTK_RESPONSE_DELETE_EVENT);
+
+ return TRUE;
+}
+
+
+static void
+dialog_response_cb (GtkFileChooser *dialog,
+ gint response,
+ gpointer user_data)
+{
+ GtkFileChooserButtonPrivate *priv;
+
+ priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (user_data);
+
+ if (response == GTK_RESPONSE_ACCEPT)
+ {
+ update_entry (user_data);
+
+ g_signal_emit_by_name (user_data, "current-folder-changed");
+ g_signal_emit_by_name (user_data, "selection-changed");
+ }
+ else
+ {
+ update_dialog (user_data);
+ }
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button), FALSE);
+}
+
+
+static void
+button_toggled_cb (GtkToggleButton *real_button,
+ gpointer user_data)
+{
+ GtkFileChooserButtonPrivate *priv;
+
+ priv = GTK_FILE_CHOOSER_BUTTON_GET_PRIVATE (user_data);
+
+ if (gtk_toggle_button_get_active (real_button))
+ {
+ /* Setup the dialog parent to be chooser button's toplevel, and be modal
+ as needed. */
+ if (!GTK_WIDGET_VISIBLE (priv->dialog))
+ {
+ GtkWidget *toplevel;
+
+ toplevel = gtk_widget_get_toplevel (user_data);
+
+ if (GTK_WIDGET_TOPLEVEL (toplevel) && GTK_IS_WINDOW (toplevel))
+ {
+ if (GTK_WINDOW (toplevel) !=
+ gtk_window_get_transient_for (GTK_WINDOW (priv->dialog)))
+ {
+ gtk_window_set_transient_for (GTK_WINDOW (priv->dialog),
+ GTK_WINDOW (toplevel));
+ }
+ gtk_window_set_modal (GTK_WINDOW (priv->dialog),
+ gtk_window_get_modal (GTK_WINDOW (toplevel)));
+ }
+ }
+
+ g_signal_handler_block (priv->dialog,
+ priv->dialog_folder_changed_id);
+ g_signal_handler_block (priv->dialog,
+ priv->dialog_file_activated_id);
+ g_signal_handler_block (priv->dialog,
+ priv->dialog_selection_changed_id);
+ gtk_widget_set_sensitive (priv->entry, FALSE);
+ gtk_window_present (GTK_WINDOW (priv->dialog));
+ }
+ else
+ {
+ g_signal_handler_unblock (priv->dialog,
+ priv->dialog_folder_changed_id);
+ g_signal_handler_unblock (priv->dialog,
+ priv->dialog_file_activated_id);
+ g_signal_handler_unblock (priv->dialog,
+ priv->dialog_selection_changed_id);
+ gtk_widget_set_sensitive (priv->entry, TRUE);
+ gtk_widget_hide (priv->dialog);
+ }
+}
+
+
+static void
+button_notify_active_cb (GObject *real_button,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ g_object_notify (user_data, "active");
+}
+
+
+/* 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);
+}
+
+
+static void
+entry_changed_cb (GtkEditable *chooser_entry,
+ 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, user_data);
+}
diff --git a/gtk/gtkfilechooserbutton.h b/gtk/gtkfilechooserbutton.h
new file mode 100644
index 0000000000..151bbaf5e9
--- /dev/null
+++ b/gtk/gtkfilechooserbutton.h
@@ -0,0 +1,89 @@
+/* GTK+: gtkfilechooserbutton.h
+ *
+ * Copyright (c) 2004 James M. Cape <jcape@ignore-your.tv>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_FILE_CHOOSER_BUTTON_H__
+#define __GTK_FILE_CHOOSER_BUTTON_H__ 1
+
+#include "gtkhbox.h"
+#include "gtkfilechooser.h"
+
+G_BEGIN_DECLS
+
+
+#define GTK_TYPE_FILE_CHOOSER_BUTTON \
+ (gtk_file_chooser_button_get_type ())
+#define GTK_FILE_CHOOSER_BUTTON(object) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((object), GTK_TYPE_FILE_CHOOSER_BUTTON, GtkFileChooserButton))
+#define GTK_FILE_CHOOSER_BUTTON_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_CHOOSER_BUTTON, GtkFileChooserButtonClass))
+#define GTK_IS_FILE_CHOOSER_BUTTON(object) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((object), GTK_TYPE_FILE_CHOOSER_BUTTON))
+#define GTK_IS_FILE_CHOOSER_BUTTON_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_CHOOSER_BUTTON))
+#define GTK_FILE_CHOOSER_BUTTON_GET_CLASS(object) \
+ (G_TYPE_INSTANCE_GET_CLASS ((object), GTK_TYPE_FILE_CHOOSER_BUTTON, GtkFileChooserButtonClass))
+
+
+typedef struct _GtkFileChooserButton GtkFileChooserButton;
+typedef struct _GtkFileChooserButtonPrivate GtkFileChooserButtonPrivate;
+typedef struct _GtkFileChooserButtonClass GtkFileChooserButtonClass;
+
+struct _GtkFileChooserButton
+{
+ /* <private> */
+ GtkHBox parent;
+
+ GtkFileChooserButtonPrivate *priv;
+};
+
+struct _GtkFileChooserButtonClass
+{
+ /* <private> */
+ GtkHBoxClass parent_class;
+
+ void (*__gtk_reserved1);
+ void (*__gtk_reserved2);
+ void (*__gtk_reserved3);
+ void (*__gtk_reserved4);
+ void (*__gtk_reserved5);
+ void (*__gtk_reserved6);
+ void (*__gtk_reserved7);
+ void (*__gtk_reserved8);
+};
+
+
+GType gtk_file_chooser_button_get_type (void) G_GNUC_CONST;
+
+GtkWidget *gtk_file_chooser_button_new (const gchar *title);
+GtkWidget *gtk_file_chooser_button_new_with_backend (const gchar *title,
+ const gchar *backend);
+GtkWidget *gtk_file_chooser_button_new_with_dialog (GtkWidget *dialog);
+
+G_CONST_RETURN gchar *gtk_file_chooser_button_get_title (GtkFileChooserButton *button);
+void gtk_file_chooser_button_set_title (GtkFileChooserButton *button,
+ const gchar *title);
+gboolean gtk_file_chooser_button_get_active (GtkFileChooserButton *button);
+void gtk_file_chooser_button_set_active (GtkFileChooserButton *button,
+ gboolean is_active);
+
+
+G_END_DECLS
+
+#endif /* !__GTK_FILE_CHOOSER_BUTTON_H__ */
diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c
index f0a9225410..80defef934 100644
--- a/gtk/gtkfilechooserdefault.c
+++ b/gtk/gtkfilechooserdefault.c
@@ -3172,7 +3172,7 @@ save_widgets_create (GtkFileChooserDefault *impl)
0, 0);
gtk_widget_show (widget);
- impl->save_file_name_entry = _gtk_file_chooser_entry_new ();
+ impl->save_file_name_entry = _gtk_file_chooser_entry_new (TRUE);
_gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry),
impl->file_system);
gtk_entry_set_width_chars (GTK_ENTRY (impl->save_file_name_entry), 45);
@@ -5467,7 +5467,7 @@ location_entry_create (GtkFileChooserDefault *impl)
{
GtkWidget *entry;
- entry = _gtk_file_chooser_entry_new ();
+ entry = _gtk_file_chooser_entry_new (TRUE);
/* Pick a good width for the entry */
gtk_entry_set_width_chars (GTK_ENTRY (entry), 30);
gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
diff --git a/gtk/gtkfilechooserentry.c b/gtk/gtkfilechooserentry.c
index 24a18c4a88..1d942a099d 100644
--- a/gtk/gtkfilechooserentry.c
+++ b/gtk/gtkfilechooserentry.c
@@ -57,6 +57,7 @@ struct _GtkFileChooserEntry
guint has_completion : 1;
guint in_change : 1;
+ guint eat_tabs : 1;
};
enum
@@ -633,6 +634,9 @@ gtk_file_chooser_entry_focus (GtkWidget *widget,
GdkModifierType state;
gboolean control_pressed = FALSE;
+ if (!chooser_entry->eat_tabs)
+ return GTK_WIDGET_CLASS (parent_class)->focus (widget, direction);
+
if (gtk_get_current_event_state (&state))
{
if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
@@ -789,6 +793,7 @@ clear_completion_callback (GtkFileChooserEntry *chooser_entry,
/**
* _gtk_file_chooser_entry_new:
+ * @eat_tabs: If %FALSE, allow focus navigation with the tab key.
*
* Creates a new #GtkFileChooserEntry object. #GtkFileChooserEntry
* is an internal implementation widget for the GTK+ file chooser
@@ -798,9 +803,14 @@ clear_completion_callback (GtkFileChooserEntry *chooser_entry,
* Return value: the newly created #GtkFileChooserEntry
**/
GtkWidget *
-_gtk_file_chooser_entry_new (void)
+_gtk_file_chooser_entry_new (gboolean eat_tabs)
{
- return g_object_new (GTK_TYPE_FILE_CHOOSER_ENTRY, NULL);
+ GtkFileChooserEntry *chooser_entry;
+
+ chooser_entry = g_object_new (GTK_TYPE_FILE_CHOOSER_ENTRY, NULL);
+ chooser_entry->eat_tabs = (eat_tabs != FALSE);
+
+ return GTK_WIDGET (chooser_entry);
}
/**
diff --git a/gtk/gtkfilechooserentry.h b/gtk/gtkfilechooserentry.h
index 6c960b5bff..3a47869c02 100644
--- a/gtk/gtkfilechooserentry.h
+++ b/gtk/gtkfilechooserentry.h
@@ -33,7 +33,7 @@ G_BEGIN_DECLS
typedef struct _GtkFileChooserEntry GtkFileChooserEntry;
GType _gtk_file_chooser_entry_get_type (void);
-GtkWidget * _gtk_file_chooser_entry_new (void);
+GtkWidget * _gtk_file_chooser_entry_new (gboolean eat_tab);
void _gtk_file_chooser_entry_set_file_system (GtkFileChooserEntry *chooser_entry,
GtkFileSystem *file_system);
void _gtk_file_chooser_entry_set_base_folder (GtkFileChooserEntry *chooser_entry,
diff --git a/gtk/gtkfilechooserutils.c b/gtk/gtkfilechooserutils.c
index 917a4cd487..2ba38fbf52 100644
--- a/gtk/gtkfilechooserutils.c
+++ b/gtk/gtkfilechooserutils.c
@@ -175,10 +175,22 @@ _gtk_file_chooser_set_delegate (GtkFileChooser *receiver,
G_CALLBACK (delegate_file_activated), receiver);
}
+GQuark
+_gtk_file_chooser_delegate_get_quark (void)
+{
+ static GQuark quark = 0;
+
+ if (G_UNLIKELY (quark == 0))
+ quark = g_quark_from_static_string ("gtk-file-chooser-delegate");
+
+ return quark;
+}
+
static GtkFileChooser *
get_delegate (GtkFileChooser *receiver)
{
- return g_object_get_data (G_OBJECT (receiver), "gtk-file-chooser-delegate");
+ return g_object_get_qdata (G_OBJECT (receiver),
+ GTK_FILE_CHOOSER_DELEGATE_QUARK);
}
static gboolean
diff --git a/gtk/gtkfilechooserutils.h b/gtk/gtkfilechooserutils.h
index 604564ece5..41e3158545 100644
--- a/gtk/gtkfilechooserutils.h
+++ b/gtk/gtkfilechooserutils.h
@@ -26,6 +26,8 @@
G_BEGIN_DECLS
+#define GTK_FILE_CHOOSER_DELEGATE_QUARK (_gtk_file_chooser_delegate_get_quark ())
+
typedef enum {
GTK_FILE_CHOOSER_PROP_FIRST = 0x1000,
GTK_FILE_CHOOSER_PROP_ACTION = GTK_FILE_CHOOSER_PROP_FIRST,
@@ -47,6 +49,8 @@ void _gtk_file_chooser_delegate_iface_init (GtkFileChooserIface *iface);
void _gtk_file_chooser_set_delegate (GtkFileChooser *receiver,
GtkFileChooser *delegate);
+GQuark _gtk_file_chooser_delegate_get_quark (void) G_GNUC_CONST;
+
G_END_DECLS
#endif /* __GTK_FILE_CHOOSER_UTILS_H__ */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index f03fc56f4c..41b194802f 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -35,6 +35,7 @@ noinst_PROGRAMS = \
testellipsise \
testentrycompletion \
testfilechooser \
+ testfilechooserbutton \
testgtk \
testiconview \
testicontheme \
@@ -76,6 +77,7 @@ testdnd_DEPENDENCIES = $(TEST_DEPS)
testellipsise_DEPENDENCIES = $(TEST_DEPS)
testentrycompletion_DEPENDENCIES = $(TEST_DEPS)
testfilechooser_DEPENDENCIES = $(TEST_DEPS)
+testfilechooserbutton_DEPENDENCIES = $(TEST_DEPS)
testgtk_DEPENDENCIES = $(TEST_DEPS)
testinput_DEPENDENCIES = $(TEST_DEPS)
testmenus_DEPENDENCIES = $(TEST_DEPS)
@@ -108,6 +110,7 @@ testdnd_LDADD = $(LDADDS)
testellipsise_LDADD = $(LDADDS)
testentrycompletion_LDADD = $(LDADDS)
testfilechooser_LDADD = $(LDADDS)
+testfilechooserbutton_LDADD = $(LDADDS)
testgtk_LDADD = $(LDADDS)
testicontheme_LDADD = $(LDADDS)
testiconview_LDADD = $(LDADDS)
@@ -144,6 +147,10 @@ testfilechooser_SOURCES = \
prop-editor.c \
testfilechooser.c
+testfilechooserbutton_SOURCES = \
+ prop-editor.c \
+ testfilechooserbutton.c
+
testgtk_SOURCES = \
prop-editor.c \
testgtk.c
diff --git a/tests/testfilechooserbutton.c b/tests/testfilechooserbutton.c
new file mode 100644
index 0000000000..9635e04a15
--- /dev/null
+++ b/tests/testfilechooserbutton.c
@@ -0,0 +1,167 @@
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+
+#include "prop-editor.h"
+
+
+static void
+win_style_set_cb (GtkWidget *win)
+{
+ gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (win)->vbox), 12);
+ gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (win)->vbox), 24);
+ gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (win)->action_area), 0);
+ gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (win)->action_area), 6);
+}
+
+
+static gboolean
+editor_delete_event_cb (GtkWidget *editor, gint response, gpointer user_data)
+{
+ gtk_widget_hide (editor);
+
+ return TRUE;
+}
+
+
+static void
+properties_button_clicked_cb (GtkWidget *button, GObject *entry)
+{
+ GtkWidget *editor;
+
+ editor = g_object_get_data (entry, "properties-dialog");
+
+ if (editor == NULL)
+ {
+ editor = create_prop_editor (G_OBJECT (entry), G_TYPE_INVALID);
+ gtk_window_set_transient_for (GTK_WINDOW (editor),
+ GTK_WINDOW (gtk_widget_get_toplevel (button)));
+ g_signal_connect (editor, "delete-event", G_CALLBACK (editor_delete_event_cb), NULL);
+ g_object_set_data (entry, "properties-dialog", editor);
+ }
+
+ gtk_window_present (GTK_WINDOW (editor));
+}
+
+
+static void
+chooser_current_folder_changed_cb (GtkFileChooser *chooser, gpointer user_data)
+{
+ gchar *folder, *filename;
+
+ folder = gtk_file_chooser_get_current_folder (chooser);
+ filename = gtk_file_chooser_get_filename (chooser);
+ g_message ("%s:%s:\n`%s`\n\tFolder: `%s'\n\tFilename: `%s'", G_STRFUNC, G_STRLOC,
+ G_OBJECT_TYPE_NAME (chooser), folder, filename);
+ g_free (folder);
+ g_free (filename);
+}
+
+
+static void
+chooser_selection_changed_cb (GtkFileChooser *chooser, gpointer user_data)
+{
+ GSList *selection;
+
+ g_warning ("%s:%s:\n`%s` Selection:", G_STRFUNC, G_STRLOC, G_OBJECT_TYPE_NAME (chooser));
+ for (selection = gtk_file_chooser_get_filenames (chooser); selection != NULL;
+ selection = g_slist_remove_link (selection, selection))
+ {
+ g_print ("`%s'\n", (const gchar *) selection->data);
+ g_free (selection->data);
+ }
+ g_print ("Done.\n");
+}
+
+
+static void
+chooser_file_activated_cb (GtkFileChooser *chooser, gpointer user_data)
+{
+ gchar *folder, *filename;
+
+ folder = gtk_file_chooser_get_current_folder (chooser);
+ filename = gtk_file_chooser_get_filename (chooser);
+ g_warning ("%s:%s:\n`%s`\nFolder: `%s'\nFilename: `%s'", G_STRFUNC, G_STRLOC, G_OBJECT_TYPE_NAME (chooser), folder, filename);
+ g_free (folder);
+ g_free (filename);
+}
+
+
+static void
+chooser_update_preview_cb (GtkFileChooser *chooser, gpointer user_data)
+{
+ gchar *filename;
+
+ filename = gtk_file_chooser_get_preview_filename (chooser);
+ g_warning ("%s:%s:\n`%s`\nPreview Filename: `%s'", G_STRFUNC, G_STRLOC, G_OBJECT_TYPE_NAME (chooser), filename);
+ g_free (filename);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ GtkWidget *win, *vbox, *frame, *alignment, *group_box, *hbox, *label, *chooser, *button;
+ GtkSizeGroup *label_group;
+
+ gtk_init (&argc, &argv);
+
+ win = gtk_dialog_new_with_buttons ("TestFileChooserButton", NULL, GTK_DIALOG_NO_SEPARATOR,
+ GTK_STOCK_QUIT, GTK_RESPONSE_CLOSE, NULL);
+ g_signal_connect (win, "style-set", G_CALLBACK (win_style_set_cb), NULL);
+ g_signal_connect (win, "response", G_CALLBACK (gtk_main_quit), NULL);
+
+ vbox = gtk_vbox_new (FALSE, 18);
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG (win)->vbox), vbox);
+
+ frame = gtk_frame_new ("<b>GtkFileChooserButton</b>");
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
+ gtk_label_set_use_markup (GTK_LABEL (gtk_frame_get_label_widget (GTK_FRAME (frame))), TRUE);
+ gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+
+ alignment = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 12, 0);
+ gtk_container_add (GTK_CONTAINER (frame), alignment);
+
+ label_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+
+ group_box = gtk_vbox_new (FALSE, 6);
+ gtk_container_add (GTK_CONTAINER (alignment), group_box);
+
+ hbox = gtk_hbox_new (FALSE, 12);
+ gtk_container_add (GTK_CONTAINER (group_box), hbox);
+
+ label = gtk_label_new ("Open:");
+ gtk_size_group_add_widget (GTK_SIZE_GROUP (label_group), label);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ chooser = gtk_file_chooser_button_new_with_backend ("Select A File - testfilechooserbutton",
+ "gtk+");
+ g_signal_connect (chooser, "current-folder-changed",
+ G_CALLBACK (chooser_current_folder_changed_cb), NULL);
+ g_signal_connect (chooser, "selection-changed", G_CALLBACK (chooser_selection_changed_cb), NULL);
+ g_signal_connect (chooser, "file-activated", G_CALLBACK (chooser_file_activated_cb), NULL);
+ g_signal_connect (chooser, "update-preview", G_CALLBACK (chooser_update_preview_cb), NULL);
+ gtk_container_add (GTK_CONTAINER (hbox), chooser);
+
+ button = gtk_button_new_with_label ("Properties...");
+ g_signal_connect (button, "clicked", G_CALLBACK (properties_button_clicked_cb), chooser);
+ gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+
+ g_object_unref (label_group);
+
+ gtk_widget_show_all (win);
+ gtk_window_present (GTK_WINDOW (win));
+
+ gtk_main ();
+
+ gtk_widget_destroy (win);
+
+ return 0;
+}