diff options
-rw-r--r-- | gtk/gtkfilechoosernative.c | 130 | ||||
-rw-r--r-- | gtk/gtkfilechoosernativeportal.c | 130 | ||||
-rw-r--r-- | gtk/gtkfilechoosernativeprivate.h | 9 |
3 files changed, 203 insertions, 66 deletions
diff --git a/gtk/gtkfilechoosernative.c b/gtk/gtkfilechoosernative.c index 0b142b8781..a3e5636d52 100644 --- a/gtk/gtkfilechoosernative.c +++ b/gtk/gtkfilechoosernative.c @@ -303,6 +303,131 @@ gtk_file_chooser_native_set_cancel_label (GtkFileChooserNative *self, g_object_notify_by_pspec (G_OBJECT (self), native_props[PROP_CANCEL_LABEL]); } +static GtkFileChooserNativeChoice * +find_choice (GtkFileChooserNative *self, + const char *id) +{ + GSList *l; + + for (l = self->choices; l; l = l->next) + { + GtkFileChooserNativeChoice *choice = l->data; + + if (strcmp (choice->id, id) == 0) + return choice; + } + + return NULL; +} + +static void +gtk_file_chooser_native_choice_free (GtkFileChooserNativeChoice *choice) +{ + g_free (choice->id); + g_free (choice->label); + g_strfreev (choice->options); + g_strfreev (choice->option_labels); + g_free (choice->selected); + g_free (choice); +} + +static void +gtk_file_chooser_native_add_choice (GtkFileChooser *chooser, + const char *id, + const char *label, + const char **options, + const char **option_labels) +{ + GtkFileChooserNative *self = GTK_FILE_CHOOSER_NATIVE (chooser); + GtkFileChooserNativeChoice *choice = find_choice (self, id); + + if (choice != NULL) + { + g_warning ("Choice with id %s already added to %s %p", id, G_OBJECT_TYPE_NAME (self), self); + return; + } + + g_assert ((options == NULL && option_labels == NULL) || + g_strv_length ((char **)options) == g_strv_length ((char **)option_labels)); + + choice = g_new0 (GtkFileChooserNativeChoice, 1); + choice->id = g_strdup (id); + choice->label = g_strdup (label); + choice->options = g_strdupv ((char **)options); + choice->option_labels = g_strdupv ((char **)option_labels); + + self->choices = g_slist_prepend (self->choices, choice); + + gtk_file_chooser_add_choice (GTK_FILE_CHOOSER (self->dialog), + id, label, options, option_labels); +} + +static void +gtk_file_chooser_native_remove_choice (GtkFileChooser *chooser, + const char *id) +{ + GtkFileChooserNative *self = GTK_FILE_CHOOSER_NATIVE (chooser); + GtkFileChooserNativeChoice *choice = find_choice (self, id); + + if (choice == NULL) + { + g_warning ("No choice with id %s found in %s %p", id, G_OBJECT_TYPE_NAME (self), self); + return; + } + + self->choices = g_slist_remove (self->choices, choice); + + gtk_file_chooser_native_choice_free (choice); + + gtk_file_chooser_remove_choice (GTK_FILE_CHOOSER (self->dialog), id); +} + +static void +gtk_file_chooser_native_set_choice (GtkFileChooser *chooser, + const char *id, + const char *selected) +{ + GtkFileChooserNative *self = GTK_FILE_CHOOSER_NATIVE (chooser); + GtkFileChooserNativeChoice *choice = find_choice (self, id); + + if (choice == NULL) + { + g_warning ("No choice with id %s found in %s %p", id, G_OBJECT_TYPE_NAME (self), self); + return; + } + + if ((choice->options && !g_strv_contains ((const char *const*)choice->options, selected)) || + (!choice->options && !g_str_equal (selected, "true") && !g_str_equal (selected, "false"))) + { + g_warning ("Not a valid option for %s: %s", id, selected); + return; + } + + g_free (choice->selected); + choice->selected = g_strdup (selected); + + gtk_file_chooser_set_choice (GTK_FILE_CHOOSER (self->dialog), id, selected); +} + +static const char * +gtk_file_chooser_native_get_choice (GtkFileChooser *chooser, + const char *id) +{ + GtkFileChooserNative *self = GTK_FILE_CHOOSER_NATIVE (chooser); + GtkFileChooserNativeChoice *choice = find_choice (self, id); + + if (choice == NULL) + { + g_warning ("No choice with id %s found in %s %p", id, G_OBJECT_TYPE_NAME (self), self); + return NULL; + } + + if (self->mode == MODE_FALLBACK) + return gtk_file_chooser_get_choice (GTK_FILE_CHOOSER (self->dialog), id); + + return choice->selected; +} + static void gtk_file_chooser_native_set_property (GObject *object, guint prop_id, @@ -366,6 +491,7 @@ gtk_file_chooser_native_finalize (GObject *object) gtk_widget_destroy (self->dialog); g_slist_free_full (self->custom_files, g_object_unref); + g_slist_free_full (self->choices, (GDestroyNotify)gtk_file_chooser_native_choice_free); G_OBJECT_CLASS (gtk_file_chooser_native_parent_class)->finalize (object); } @@ -679,4 +805,8 @@ _gtk_file_chooser_native_iface_init (GtkFileChooserIface *iface) iface->set_current_name = gtk_file_chooser_native_set_current_name; iface->set_current_folder = gtk_file_chooser_native_set_current_folder; iface->get_files = gtk_file_chooser_native_get_files; + iface->add_choice = gtk_file_chooser_native_add_choice; + iface->remove_choice = gtk_file_chooser_native_remove_choice; + iface->set_choice = gtk_file_chooser_native_set_choice; + iface->get_choice = gtk_file_chooser_native_get_choice; } diff --git a/gtk/gtkfilechoosernativeportal.c b/gtk/gtkfilechoosernativeportal.c index 8ff2a46bc1..883861779b 100644 --- a/gtk/gtkfilechoosernativeportal.c +++ b/gtk/gtkfilechoosernativeportal.c @@ -55,7 +55,6 @@ typedef struct { GDBusConnection *connection; char *portal_handle; guint portal_response_signal_id; - GDBusSignalCallback signal_callback; gboolean modal; gboolean hidden; @@ -86,73 +85,35 @@ filechooser_portal_data_free (FilechooserPortalData *data) } static void -one_file_response (GDBusConnection *connection, - const gchar *sender_name, - const gchar *object_path, - const gchar *interface_name, - const gchar *signal_name, - GVariant *parameters, - gpointer user_data) +response_cb (GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) { GtkFileChooserNative *self = user_data; FilechooserPortalData *data = self->mode_data; guint32 portal_response; int gtk_response; - char *uri, *handle; - GVariant *response_data; - - g_variant_get (parameters, "(&ou&s@a{sv})", &handle, &portal_response, &uri, &response_data); - - if (data->portal_handle == NULL || - strcmp (handle, data->portal_handle) != 0) - return; - - g_slist_free_full (self->custom_files, g_object_unref); - self->custom_files = g_slist_prepend (NULL, g_file_new_for_uri (uri)); - - switch (portal_response) - { - case 0: - gtk_response = GTK_RESPONSE_OK; - break; - case 1: - gtk_response = GTK_RESPONSE_CANCEL; - break; - case 2: - default: - gtk_response = GTK_RESPONSE_DELETE_EVENT; - break; - } - - filechooser_portal_data_free (data); - self->mode_data = NULL; - - _gtk_native_dialog_emit_response (GTK_NATIVE_DIALOG (self), gtk_response); -} - -static void -multi_file_response (GDBusConnection *connection, - const gchar *sender_name, - const gchar *object_path, - const gchar *interface_name, - const gchar *signal_name, - GVariant *parameters, - gpointer user_data) -{ - GtkFileChooserNative *self = user_data; - FilechooserPortalData *data = self->mode_data; - guint32 portal_response; - int gtk_response; - char *handle; - char **uris; + const char **uris; int i; GVariant *response_data; + g_autoptr (GVariant) choices = NULL; - g_variant_get (parameters, "(&ou^a&s@a{sv})", &handle, &portal_response, &uris, &response_data); + g_variant_get (parameters, "(u@a{sv})", &portal_response, &response_data); + g_variant_lookup (response_data, "uris", "^a&s", &uris); - if (data->portal_handle == NULL || - strcmp (handle, data->portal_handle) != 0) - return; + choices = g_variant_lookup_value (response_data, "choices", G_VARIANT_TYPE ("a(ss)")); + if (choices) + for (i = 0; i < g_variant_n_children (choices); i++) + { + const char *id; + const char *selected; + g_variant_get_child (choices, i, "(&s&s)", &id, &selected); + gtk_file_chooser_set_choice (GTK_FILE_CHOOSER (self), id, selected); + } g_slist_free_full (self->custom_files, g_object_unref); self->custom_files = NULL; @@ -250,7 +211,7 @@ open_file_msg_cb (GObject *source_object, data->portal_handle, NULL, G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE, - data->signal_callback, + response_cb, self, NULL); } @@ -275,6 +236,44 @@ get_filters (GtkFileChooser *self) return g_variant_builder_end (&builder); } +static GVariant * +gtk_file_chooser_native_choice_to_variant (GtkFileChooserNativeChoice *choice) +{ + GVariantBuilder choices; + int i; + + g_variant_builder_init (&choices, G_VARIANT_TYPE ("a(ss)")); + if (choice->options) + { + for (i = 0; choice->options[i]; i++) + g_variant_builder_add (&choices, "(&s&s)", choice->options[i], choice->option_labels[i]); + } + + return g_variant_new ("(&s&s@a(ss)&s)", + choice->id, + choice->label, + g_variant_builder_end (&choices), + choice->selected ? choice->selected : ""); +} + +static GVariant * +serialize_choices (GtkFileChooserNative *self) +{ + GVariantBuilder builder; + GSList *l; + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ssa(ss)s)")); + for (l = self->choices; l; l = l->next) + { + GtkFileChooserNativeChoice *choice = l->data; + + g_variant_builder_add (&builder, "@(ssa(ss)s)", + gtk_file_chooser_native_choice_to_variant (choice)); + } + + return g_variant_builder_end (&builder); +} + gboolean gtk_file_chooser_native_portal_show (GtkFileChooserNative *self) { @@ -312,11 +311,6 @@ gtk_file_chooser_native_portal_show (GtkFileChooserNative *self) data->self = g_object_ref (self); data->connection = connection; - if (strcmp (method_name, "OpenFiles") == 0) - data->signal_callback = multi_file_response; - else - data->signal_callback = one_file_response; - message = g_dbus_message_new_method_call ("org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop", "org.freedesktop.portal.FileChooser", @@ -336,7 +330,7 @@ gtk_file_chooser_native_portal_show (GtkFileChooserNative *self) if (gtk_native_dialog_get_modal (GTK_NATIVE_DIALOG (self))) data->modal = TRUE; - if (data->modal && transient_for) + if (data->modal && transient_for != NULL) { data->grab_widget = gtk_invisible_new_for_screen (gtk_widget_get_screen (GTK_WIDGET (transient_for))); gtk_grab_add (GTK_WIDGET (data->grab_widget)); @@ -376,6 +370,10 @@ gtk_file_chooser_native_portal_show (GtkFileChooserNative *self) g_free (path); } + if (GTK_FILE_CHOOSER_NATIVE (self)->choices) + g_variant_builder_add (&opt_builder, "{sv}", "choices", + serialize_choices (GTK_FILE_CHOOSER_NATIVE (self))); + g_dbus_message_set_body (message, g_variant_new ("(ss@a{sv})", parent_window_str ? parent_window_str : "", diff --git a/gtk/gtkfilechoosernativeprivate.h b/gtk/gtkfilechoosernativeprivate.h index ab3b6cf0c7..283eda902d 100644 --- a/gtk/gtkfilechoosernativeprivate.h +++ b/gtk/gtkfilechoosernativeprivate.h @@ -23,6 +23,14 @@ G_BEGIN_DECLS +typedef struct { + char *id; + char *label; + char **options; + char **option_labels; + char *selected; +} GtkFileChooserNativeChoice; + struct _GtkFileChooserNative { GtkNativeDialog parent_instance; @@ -36,6 +44,7 @@ struct _GtkFileChooserNative GFile *current_folder; GFile *current_file; char *current_name; + GSList *choices; /* Fallback mode */ GtkWidget *dialog; |