[gtk+/wip/native-file-chooser: 10/14] GtkFileChooserButton: Use native dialogs
- From: Alexander Larsson <alexl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/native-file-chooser: 10/14] GtkFileChooserButton: Use native dialogs
- Date: Thu, 5 Nov 2015 15:53:30 +0000 (UTC)
commit b3b68ea16bd440b1308812ebc3daa7e7a2177ca9
Author: Alexander Larsson <alexl redhat com>
Date: Thu Oct 29 15:13:14 2015 +0100
GtkFileChooserButton: Use native dialogs
Unless you explicitly set the dialog constructor property we use a
native dialog (GtkFileChooserNative).
gtk/gtkfilechooserbutton.c | 231 +++++++++++++++++++++++++++++---------------
1 files changed, 153 insertions(+), 78 deletions(-)
---
diff --git a/gtk/gtkfilechooserbutton.c b/gtk/gtkfilechooserbutton.c
index baff523..1df73bc 100644
--- a/gtk/gtkfilechooserbutton.c
+++ b/gtk/gtkfilechooserbutton.c
@@ -44,6 +44,7 @@
#include "gtktreemodelfilter.h"
#include "gtkseparator.h"
#include "gtkfilechooserdialog.h"
+#include "gtkfilechoosernative.h"
#include "gtkfilechooserprivate.h"
#include "gtkfilechooserutils.h"
#include "gtkmarshalers.h"
@@ -167,7 +168,9 @@ RowType;
struct _GtkFileChooserButtonPrivate
{
- GtkWidget *dialog;
+ GtkFileChooser *chooser; /* Points to either dialog or native, depending on which is set */
+ GtkWidget *dialog; /* Set if you explicitly enable */
+ GtkFileChooserNative *native; /* Otherwise this is set */
GtkWidget *button;
GtkWidget *image;
GtkWidget *label;
@@ -328,9 +331,9 @@ static void combo_box_notify_popup_shown_cb (GObject *object,
static void button_clicked_cb (GtkButton *real_button,
gpointer user_data);
-static void dialog_update_preview_cb (GtkFileChooser *dialog,
+static void chooser_update_preview_cb (GtkFileChooser *dialog,
gpointer user_data);
-static void dialog_notify_cb (GObject *dialog,
+static void chooser_notify_cb (GObject *dialog,
GParamSpec *pspec,
gpointer user_data);
static gboolean dialog_delete_event_cb (GtkWidget *dialog,
@@ -339,6 +342,9 @@ static gboolean dialog_delete_event_cb (GtkWidget *dialog,
static void dialog_response_cb (GtkDialog *dialog,
gint response,
gpointer user_data);
+static void native_response_cb (GtkFileChooserNative *native,
+ gint response,
+ gpointer user_data);
static guint file_chooser_button_signals[LAST_SIGNAL] = { 0 };
@@ -542,7 +548,7 @@ gtk_file_chooser_button_set_current_folder (GtkFileChooser *chooser,
g_signal_emit_by_name (button, "current-folder-changed");
if (priv->active)
- gtk_file_chooser_set_current_folder_file (GTK_FILE_CHOOSER (priv->dialog), file, NULL);
+ gtk_file_chooser_set_current_folder_file (GTK_FILE_CHOOSER (priv->chooser), file, NULL);
return TRUE;
}
@@ -578,7 +584,7 @@ gtk_file_chooser_button_select_file (GtkFileChooser *chooser,
update_combo_box (button);
if (priv->active)
- gtk_file_chooser_select_file (GTK_FILE_CHOOSER (priv->dialog), file, NULL);
+ gtk_file_chooser_select_file (GTK_FILE_CHOOSER (priv->chooser), file, NULL);
return TRUE;
}
@@ -611,7 +617,7 @@ gtk_file_chooser_button_unselect_file (GtkFileChooser *chooser,
unselect_current_file (button);
if (priv->active)
- gtk_file_chooser_unselect_file (GTK_FILE_CHOOSER (priv->dialog), file);
+ gtk_file_chooser_unselect_file (GTK_FILE_CHOOSER (priv->chooser), file);
}
static void
@@ -623,7 +629,7 @@ gtk_file_chooser_button_unselect_all (GtkFileChooser *chooser)
unselect_current_file (button);
if (priv->active)
- gtk_file_chooser_unselect_all (GTK_FILE_CHOOSER (priv->dialog));
+ gtk_file_chooser_unselect_all (GTK_FILE_CHOOSER (priv->chooser));
}
static GFile *
@@ -636,7 +642,7 @@ get_selected_file (GtkFileChooserButton *button)
if (priv->selection_while_inactive)
retval = priv->selection_while_inactive;
- else if (gtk_file_chooser_get_action (GTK_FILE_CHOOSER (priv->dialog)) ==
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+ else if (priv->chooser && gtk_file_chooser_get_action (priv->chooser) ==
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
{
/* If there is no "real" selection in SELECT_FOLDER mode, then we'll just return
* the current folder, since that is what GtkFileChooserWidget would do.
@@ -770,46 +776,42 @@ gtk_file_chooser_button_constructed (GObject *object)
if (!priv->dialog)
{
- priv->dialog = gtk_file_chooser_dialog_new (NULL, NULL,
+ priv->native = gtk_file_chooser_native_new (NULL,
+ NULL,
GTK_FILE_CHOOSER_ACTION_OPEN,
- _("_Cancel"), GTK_RESPONSE_CANCEL,
- _("_Open"), GTK_RESPONSE_ACCEPT,
+ NULL,
NULL);
-
- gtk_dialog_set_default_response (GTK_DIALOG (priv->dialog),
- GTK_RESPONSE_ACCEPT);
-G_GNUC_BEGIN_IGNORE_DEPRECATIONS
- gtk_dialog_set_alternative_button_order (GTK_DIALOG (priv->dialog),
- GTK_RESPONSE_ACCEPT,
- GTK_RESPONSE_CANCEL,
- -1);
-G_GNUC_END_IGNORE_DEPRECATIONS
-
+ priv->chooser = GTK_FILE_CHOOSER (priv->native);
gtk_file_chooser_button_set_title (button, _(DEFAULT_TITLE));
+
+ g_signal_connect (priv->native, "response",
+ G_CALLBACK (native_response_cb), object);
}
- else if (!gtk_window_get_title (GTK_WINDOW (priv->dialog)))
+ else /* dialog set */
{
- gtk_file_chooser_button_set_title (button, _(DEFAULT_TITLE));
+ priv->chooser = GTK_FILE_CHOOSER (priv->dialog);
+
+ if (!gtk_window_get_title (GTK_WINDOW (priv->dialog)))
+ gtk_file_chooser_button_set_title (button, _(DEFAULT_TITLE));
+
+ 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);
+
+ g_object_add_weak_pointer (G_OBJECT (priv->dialog),
+ (gpointer) (&priv->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);
+ g_signal_connect (priv->chooser, "notify",
+ G_CALLBACK (chooser_notify_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);
-
- 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));
+ g_object_set_qdata (object, GTK_FILE_CHOOSER_DELEGATE_QUARK, priv->chooser);
priv->fs =
- g_object_ref (_gtk_file_chooser_get_file_system (GTK_FILE_CHOOSER (priv->dialog)));
+ g_object_ref (_gtk_file_chooser_get_file_system (priv->chooser));
model_add_special (button);
@@ -839,7 +841,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS
* the label, image and combobox
*/
g_object_set (object,
- "action", gtk_file_chooser_get_action (GTK_FILE_CHOOSER (priv->dialog)),
+ "action", gtk_file_chooser_get_action (GTK_FILE_CHOOSER (priv->chooser)),
NULL);
priv->fs_volumes_changed_id =
@@ -888,7 +890,7 @@ gtk_file_chooser_button_set_property (GObject *object,
break;
}
- g_object_set_property (G_OBJECT (priv->dialog), pspec->name, value);
+ g_object_set_property (G_OBJECT (priv->chooser), pspec->name, value);
update_label_and_image (GTK_FILE_CHOOSER_BUTTON (object));
update_combo_box (GTK_FILE_CHOOSER_BUTTON (object));
@@ -917,11 +919,11 @@ gtk_file_chooser_button_set_property (GObject *object,
case GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN:
case GTK_FILE_CHOOSER_PROP_DO_OVERWRITE_CONFIRMATION:
case GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS:
- g_object_set_property (G_OBJECT (priv->dialog), pspec->name, value);
+ g_object_set_property (G_OBJECT (priv->chooser), pspec->name, value);
break;
case GTK_FILE_CHOOSER_PROP_LOCAL_ONLY:
- g_object_set_property (G_OBJECT (priv->dialog), pspec->name, value);
+ g_object_set_property (G_OBJECT (priv->chooser), pspec->name, value);
fs_volumes_changed_cb (priv->fs, button);
bookmarks_changed_cb (button);
break;
@@ -964,7 +966,7 @@ gtk_file_chooser_button_get_property (GObject *object,
case GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN:
case GTK_FILE_CHOOSER_PROP_DO_OVERWRITE_CONFIRMATION:
case GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS:
- g_object_get_property (G_OBJECT (priv->dialog), pspec->name, value);
+ g_object_get_property (G_OBJECT (priv->chooser), pspec->name, value);
break;
default:
@@ -1006,6 +1008,10 @@ gtk_file_chooser_button_destroy (GtkWidget *widget)
priv->dialog = NULL;
}
+ g_clear_object (&priv->native);
+
+ priv->chooser = NULL;
+
if (priv->model && gtk_tree_model_get_iter_first (priv->model, &iter))
{
do
@@ -1173,7 +1179,7 @@ gtk_file_chooser_button_drag_data_received (GtkWidget *widget,
info->uris = uris;
info->selected = FALSE;
info->file_system = priv->fs;
- g_object_get (priv->dialog, "action", &info->action, NULL);
+ g_object_get (priv->chooser, "action", &info->action, NULL);
info->file = g_file_new_for_uri (info->uris[info->i]);
@@ -1190,7 +1196,7 @@ gtk_file_chooser_button_drag_data_received (GtkWidget *widget,
case TEXT_PLAIN:
text = (char*) gtk_selection_data_get_text (data);
file = g_file_new_for_uri (text);
- gtk_file_chooser_select_file (GTK_FILE_CHOOSER (priv->dialog), file, NULL);
+ gtk_file_chooser_select_file (GTK_FILE_CHOOSER (priv->chooser), file, NULL);
g_object_unref (file);
g_free (text);
g_signal_emit (button, file_chooser_button_signals[FILE_SET], 0);
@@ -1228,7 +1234,10 @@ gtk_file_chooser_button_hide (GtkWidget *widget)
GtkFileChooserButton *button = GTK_FILE_CHOOSER_BUTTON (widget);
GtkFileChooserButtonPrivate *priv = button->priv;
- gtk_widget_hide (priv->dialog);
+ if (priv->dialog)
+ gtk_widget_hide (priv->dialog);
+ else
+ gtk_native_dialog_hide (GTK_NATIVE_DIALOG (priv->native));
if (GTK_WIDGET_CLASS (gtk_file_chooser_button_parent_class)->hide)
GTK_WIDGET_CLASS (gtk_file_chooser_button_parent_class)->hide (widget);
@@ -1247,7 +1256,7 @@ gtk_file_chooser_button_mnemonic_activate (GtkWidget *widget,
GtkFileChooserButton *button = GTK_FILE_CHOOSER_BUTTON (widget);
GtkFileChooserButtonPrivate *priv = button->priv;
- switch (gtk_file_chooser_get_action (GTK_FILE_CHOOSER (priv->dialog)))
+ switch (gtk_file_chooser_get_action (GTK_FILE_CHOOSER (priv->chooser)))
{
case GTK_FILE_CHOOSER_ACTION_OPEN:
gtk_widget_grab_focus (priv->button);
@@ -1840,7 +1849,7 @@ model_add_volumes (GtkFileChooserButton *button,
store = GTK_LIST_STORE (button->priv->model);
pos = model_get_type_position (button, ROW_TYPE_VOLUME);
- local_only = gtk_file_chooser_get_local_only (GTK_FILE_CHOOSER (button->priv->dialog));
+ local_only = gtk_file_chooser_get_local_only (GTK_FILE_CHOOSER (button->priv->chooser));
for (l = volumes; l; l = l->next)
{
@@ -1912,7 +1921,7 @@ model_add_bookmarks (GtkFileChooserButton *button,
store = GTK_LIST_STORE (button->priv->model);
pos = model_get_type_position (button, ROW_TYPE_BOOKMARK);
- local_only = gtk_file_chooser_get_local_only (GTK_FILE_CHOOSER (button->priv->dialog));
+ local_only = gtk_file_chooser_get_local_only (GTK_FILE_CHOOSER (button->priv->chooser));
for (l = bookmarks; l; l = l->next)
{
@@ -2195,7 +2204,7 @@ filter_model_visible_func (GtkTreeModel *model,
type = ROW_TYPE_INVALID;
data = NULL;
- local_only = gtk_file_chooser_get_local_only (GTK_FILE_CHOOSER (priv->dialog));
+ local_only = gtk_file_chooser_get_local_only (GTK_FILE_CHOOSER (priv->chooser));
gtk_tree_model_get (model, iter,
TYPE_COLUMN, &type,
@@ -2616,8 +2625,8 @@ save_inactive_state (GtkFileChooserButton *button)
if (priv->selection_while_inactive)
g_object_unref (priv->selection_while_inactive);
- priv->current_folder_while_inactive = gtk_file_chooser_get_current_folder_file (GTK_FILE_CHOOSER
(priv->dialog));
- priv->selection_while_inactive = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (priv->dialog));
+ priv->current_folder_while_inactive = gtk_file_chooser_get_current_folder_file (GTK_FILE_CHOOSER
(priv->chooser));
+ priv->selection_while_inactive = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (priv->chooser));
}
static void
@@ -2626,12 +2635,12 @@ restore_inactive_state (GtkFileChooserButton *button)
GtkFileChooserButtonPrivate *priv = button->priv;
if (priv->current_folder_while_inactive)
- gtk_file_chooser_set_current_folder_file (GTK_FILE_CHOOSER (priv->dialog),
priv->current_folder_while_inactive, NULL);
+ gtk_file_chooser_set_current_folder_file (GTK_FILE_CHOOSER (priv->chooser),
priv->current_folder_while_inactive, NULL);
if (priv->selection_while_inactive)
- gtk_file_chooser_select_file (GTK_FILE_CHOOSER (priv->dialog), priv->selection_while_inactive, NULL);
+ gtk_file_chooser_select_file (GTK_FILE_CHOOSER (priv->chooser), priv->selection_while_inactive, NULL);
else
- gtk_file_chooser_unselect_all (GTK_FILE_CHOOSER (priv->dialog));
+ gtk_file_chooser_unselect_all (GTK_FILE_CHOOSER (priv->chooser));
}
/* Dialog */
@@ -2639,34 +2648,63 @@ static void
open_dialog (GtkFileChooserButton *button)
{
GtkFileChooserButtonPrivate *priv = button->priv;
+ GtkWidget *toplevel;
+
+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
/* Setup the dialog parent to be chooser button's toplevel, and be modal
as needed. */
- if (!gtk_widget_get_visible (priv->dialog))
+ if (priv->dialog != NULL)
{
- GtkWidget *toplevel;
-
- toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
+ if (!gtk_widget_get_visible (priv->dialog))
+ {
+ if (gtk_widget_is_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));
- if (gtk_widget_is_toplevel (toplevel) && GTK_IS_WINDOW (toplevel))
+ gtk_window_set_modal (GTK_WINDOW (priv->dialog),
+ gtk_window_get_modal (GTK_WINDOW (toplevel)));
+ }
+ }
+ }
+ else
+ {
+ if (!gtk_native_dialog_get_visible (GTK_NATIVE_DIALOG (priv->native)))
{
- 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));
+ if (gtk_widget_is_toplevel (toplevel) && GTK_IS_WINDOW (toplevel))
+ {
+ if (GTK_WINDOW (toplevel) != gtk_native_dialog_get_transient_for (GTK_NATIVE_DIALOG
(priv->native)))
+ gtk_native_dialog_set_transient_for (GTK_NATIVE_DIALOG (priv->native),
+ GTK_WINDOW (toplevel));
- gtk_window_set_modal (GTK_WINDOW (priv->dialog),
- gtk_window_get_modal (GTK_WINDOW (toplevel)));
- }
+ gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (priv->native),
+ gtk_window_get_modal (GTK_WINDOW (toplevel)));
+ }
+ }
}
if (!priv->active)
{
restore_inactive_state (button);
priv->active = TRUE;
+
+ /* Only handle update-preview handler if it is handled on the button */
+ if (g_signal_has_handler_pending (button,
+ g_signal_lookup ("update-preview", GTK_TYPE_FILE_CHOOSER),
+ 0, TRUE))
+ {
+ g_signal_connect (priv->chooser, "update-preview",
+ G_CALLBACK (chooser_update_preview_cb), button);
+ }
}
gtk_widget_set_sensitive (priv->combo_box, FALSE);
- gtk_window_present (GTK_WINDOW (priv->dialog));
+ if (priv->dialog)
+ gtk_window_present (GTK_WINDOW (priv->dialog));
+ else
+ gtk_native_dialog_show (GTK_NATIVE_DIALOG (priv->native));
}
/* Combo Box */
@@ -2787,16 +2825,16 @@ button_clicked_cb (GtkButton *real_button,
/* Dialog */
static void
-dialog_update_preview_cb (GtkFileChooser *dialog,
- gpointer user_data)
+chooser_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)
+chooser_notify_cb (GObject *dialog,
+ GParamSpec *pspec,
+ gpointer user_data)
{
gpointer iface;
@@ -2826,7 +2864,7 @@ dialog_notify_cb (GObject *dialog,
/* If the path isn't local but we're in local-only mode now, remove
* the custom-folder row */
if (data && _gtk_file_has_native_path (G_FILE (data)) &&
- gtk_file_chooser_get_local_only (GTK_FILE_CHOOSER (priv->dialog)))
+ gtk_file_chooser_get_local_only (GTK_FILE_CHOOSER (priv->chooser)))
{
pos--;
model_remove_rows (user_data, pos, 2);
@@ -2849,11 +2887,9 @@ dialog_delete_event_cb (GtkWidget *dialog,
}
static void
-dialog_response_cb (GtkDialog *dialog,
- gint response,
- gpointer user_data)
+common_response_cb (GtkFileChooserButton *button,
+ gint response)
{
- GtkFileChooserButton *button = GTK_FILE_CHOOSER_BUTTON (user_data);
GtkFileChooserButtonPrivate *priv = button->priv;
if (response == GTK_RESPONSE_ACCEPT ||
@@ -2870,12 +2906,29 @@ dialog_response_cb (GtkDialog *dialog,
}
if (priv->active)
- priv->active = FALSE;
+ {
+ priv->active = FALSE;
+
+ g_signal_handlers_disconnect_by_func (priv->chooser, chooser_update_preview_cb, button);
+ }
update_label_and_image (button);
update_combo_box (button);
gtk_widget_set_sensitive (priv->combo_box, TRUE);
+}
+
+
+static void
+dialog_response_cb (GtkDialog *dialog,
+ gint response,
+ gpointer user_data)
+{
+ GtkFileChooserButton *button = GTK_FILE_CHOOSER_BUTTON (user_data);
+ GtkFileChooserButtonPrivate *priv = button->priv;
+
+ common_response_cb (button, response);
+
gtk_widget_hide (priv->dialog);
if (response == GTK_RESPONSE_ACCEPT ||
@@ -2883,6 +2936,22 @@ dialog_response_cb (GtkDialog *dialog,
g_signal_emit (button, file_chooser_button_signals[FILE_SET], 0);
}
+static void
+native_response_cb (GtkFileChooserNative *native,
+ gint response,
+ gpointer user_data)
+{
+ GtkFileChooserButton *button = GTK_FILE_CHOOSER_BUTTON (user_data);
+
+ common_response_cb (button, response);
+
+ /* dialog already hidden */
+
+ if (response == GTK_RESPONSE_ACCEPT ||
+ response == GTK_RESPONSE_OK)
+ g_signal_emit (button, file_chooser_button_signals[FILE_SET], 0);
+}
+
/* ************************************************************************** *
* Public API *
@@ -2956,7 +3025,10 @@ gtk_file_chooser_button_set_title (GtkFileChooserButton *button,
{
g_return_if_fail (GTK_IS_FILE_CHOOSER_BUTTON (button));
- gtk_window_set_title (GTK_WINDOW (button->priv->dialog), title);
+ if (button->priv->dialog)
+ gtk_window_set_title (GTK_WINDOW (button->priv->dialog), title);
+ else
+ gtk_native_dialog_set_title (GTK_NATIVE_DIALOG (button->priv->native), title);
g_object_notify (G_OBJECT (button), "title");
}
@@ -2976,7 +3048,10 @@ 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));
+ if (button->priv->dialog)
+ return gtk_window_get_title (GTK_WINDOW (button->priv->dialog));
+ else
+ return gtk_native_dialog_get_title (GTK_NATIVE_DIALOG (button->priv->native));
}
/**
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]