[gtk+/portal: 12/17] Implement combobox apis for GtkFileChooserNativePortal



commit ba2adf7487c01db300d27054d3c93b4b946f2455
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Jul 5 22:13:22 2016 -0400

    Implement combobox apis for GtkFileChooserNativePortal

 gtk/gtkfilechoosernative.c        |  131 +++++++++++++++++++++++++++++++++++++
 gtk/gtkfilechoosernativeportal.c  |  128 ++++++++++++++++++------------------
 gtk/gtkfilechoosernativeprivate.h |    9 +++
 3 files changed, 203 insertions(+), 65 deletions(-)
---
diff --git a/gtk/gtkfilechoosernative.c b/gtk/gtkfilechoosernative.c
index be96b69..b4191e9 100644
--- a/gtk/gtkfilechoosernative.c
+++ b/gtk/gtkfilechoosernative.c
@@ -303,6 +303,132 @@ 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);
+  choice->selected = NULL;
+
+  self->choices = g_slist_append (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 +492,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);
 }
@@ -678,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 87a9906..333796b 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;
@@ -88,73 +87,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;
@@ -247,7 +208,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);
     }
 
@@ -272,6 +233,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)
 {
@@ -311,11 +310,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",
@@ -373,6 +367,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 ab3b6cf..283eda9 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;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]