Allow binding GdkContentFormatsBuilder
authorEmmanuele Bassi <ebassi@gnome.org>
Thu, 1 Feb 2018 16:43:15 +0000 (17:43 +0100)
committerBenjamin Otte <otte@redhat.com>
Sat, 3 Feb 2018 15:24:13 +0000 (16:24 +0100)
GdkContentFormatsBuilder is currently not introspectable, as it does not
have a GType. We can turn it into a boxed type, but we need to implement
memory management for it.

The current gdk_content_formats_builder_free() function returns a newly
constructed value, so we cannot use it as a GBoxedFreeFunc; additionally
copying a GdkContentFormatsBuilder contents would make it a bit odd, as
you could get multiple identical GdkContentFormats out of the copies.

A simple approach is to model the GdkContentFormatsBuilder API to follow
the GBytes one: use reference counting for memory management, and have
a function to release a reference, return a GdkContentFormats, and reset
the GdkContentFormatsBuilder state.

For language bindings, we can provide a get_formats() function that
returns the GdkContentFormats instance and resets the builder instance,
leaving the reference count untouched.

For C convenience we can keep gdk_content_formats_builder_free(), and
make it a wrapper around gdk_content_formats_builder_get_formats(), with
the guarantee that it'll free the builder instance regardless of its
current reference count.

https://bugzilla.gnome.org/show_bug.cgi?id=793097
https://blogs.gnome.org/otte/2018/02/03/builders/

12 files changed:
docs/reference/gdk/gdk4-sections.txt
gdk/gdkclipboard.c
gdk/gdkcontentdeserializer.c
gdk/gdkcontentformats.c
gdk/gdkcontentformats.h
gdk/gdkcontentproviderimpl.c
gdk/gdkcontentserializer.c
gdk/wayland/gdkprimary-wayland.c
gdk/wayland/gdkselection-wayland.c
gdk/win32/gdkdnd-win32.c
gdk/x11/gdkclipboard-x11.c
gtk/gtkselection.c

index d492279d1eb4df9df373b9bf8f283fed16cd4cce..cf58129a4e50e1dd7df242056cb4fc291d037d52 100644 (file)
@@ -438,11 +438,16 @@ gdk_content_formats_union_deserialize_mime_types
 <SUBSECTION>
 GdkContentFormatsBuilder
 gdk_content_formats_builder_new
-gdk_content_formats_builder_free
+gdk_content_formats_builder_free_to_formats
 gdk_content_formats_builder_add_formats
 gdk_content_formats_builder_add_gtype
 gdk_content_formats_builder_add_mime_type
 
+<SUBSECTION>
+gdk_content_formats_builder_ref
+gdk_content_formats_builder_unref
+gdk_content_formats_builder_to_formats
+
 <SUBSECTION Private>
 GDK_TYPE_FILE_LIST
 gdk_file_list_get_type
index ee9d8e991b79602d1867fdc769c85c549d50b1fc..df821477f22e7adfc2f1b3e7ffdf4c7c9c6f288a 100644 (file)
@@ -820,7 +820,7 @@ gdk_clipboard_read_value_internal (GdkClipboard        *clipboard,
 
   builder = gdk_content_formats_builder_new ();
   gdk_content_formats_builder_add_gtype (builder, type);
-  formats = gdk_content_formats_builder_free (builder);
+  formats = gdk_content_formats_builder_free_to_formats (builder);
   formats = gdk_content_formats_union_deserialize_mime_types (formats);
 
   gdk_clipboard_read_internal (clipboard,
index c9df08dba99c645bf22f9d752df88391c82af331..b0df54cb1228dde649b9c1a68f1a1017f0974c3f 100644 (file)
@@ -458,7 +458,7 @@ gdk_content_formats_union_deserialize_gtypes (GdkContentFormats *formats)
 
   gdk_content_formats_unref (formats);
 
-  return gdk_content_formats_builder_free (builder);
+  return gdk_content_formats_builder_free_to_formats (builder);
 }
 
 /**
@@ -493,7 +493,7 @@ gdk_content_formats_union_deserialize_mime_types (GdkContentFormats *formats)
 
   gdk_content_formats_unref (formats);
 
-  return gdk_content_formats_builder_free (builder);
+  return gdk_content_formats_builder_free_to_formats (builder);
 }
 
 static void
index 04bd0647f48431cd6240245d28e281c182a26f31..cd3293f0a334b9a4e8c66a1f04900ef0f13e611f 100644 (file)
@@ -307,7 +307,7 @@ gdk_content_formats_union (GdkContentFormats       *first,
   gdk_content_formats_unref (first);
   gdk_content_formats_builder_add_formats (builder, second);
 
-  return gdk_content_formats_builder_free (builder);
+  return gdk_content_formats_builder_free_to_formats (builder);
 }
 
 static gboolean
@@ -510,12 +510,22 @@ gdk_content_formats_get_mime_types (GdkContentFormats *formats,
 
 struct _GdkContentFormatsBuilder
 {
+  int ref_count;
+
+  /* (element-type GType) */
   GSList *gtypes;
   gsize n_gtypes;
+
+  /* (element-type utf8) (interned) */
   GSList *mime_types;
   gsize n_mime_types;
 };
 
+G_DEFINE_BOXED_TYPE (GdkContentFormatsBuilder,
+                     gdk_content_formats_builder,
+                     gdk_content_formats_builder_ref,
+                     gdk_content_formats_builder_unref)
+
 /**
  * gdk_content_formats_builder_new:
  *
@@ -528,19 +538,106 @@ struct _GdkContentFormatsBuilder
 GdkContentFormatsBuilder *
 gdk_content_formats_builder_new (void)
 {
-  return g_slice_new0 (GdkContentFormatsBuilder);
+  GdkContentFormatsBuilder *builder;
+
+  builder = g_slice_new0 (GdkContentFormatsBuilder);
+  builder->ref_count = 1;
+
+  return builder;
 }
 
 /**
- * gdk_content_formats_builder_free:
+ * gdk_content_formats_builder_ref:
  * @builder: a #GdkContentFormatsBuilder
  *
- * Frees @builder and creates a new #GdkContentFormats from it.
+ * Acquires a reference on the given @builder.
  *
- * Returns: a new #GdkContentFormats with all the formats added to @builder
- **/
+ * This function is intended primarily for bindings. #GdkContentFormatsBuilder objects
+ * should not be kept around.
+ *
+ * Returns: (transfer none): the given #GdkContentFormatsBuilder with
+ *   its reference count increased
+ */
+GdkContentFormatsBuilder *
+gdk_content_formats_builder_ref (GdkContentFormatsBuilder *builder)
+{
+  g_return_val_if_fail (builder != NULL, NULL);
+  g_return_val_if_fail (builder->ref_count > 0, NULL);
+
+  builder->ref_count += 1;
+
+  return builder;
+}
+
+static void
+gdk_content_formats_builder_clear (GdkContentFormatsBuilder *builder)
+{
+  g_clear_pointer (&builder->gtypes, g_slist_free);
+  g_clear_pointer (&builder->mime_types, g_slist_free);
+}
+
+/**
+ * gdk_content_formats_builder_unref:
+ * @builder: a #GdkContentFormatsBuilder
+ *
+ * Releases a reference on the given @builder.
+ */
+void
+gdk_content_formats_builder_unref (GdkContentFormatsBuilder *builder)
+{
+  g_return_if_fail (builder != NULL);
+  g_return_if_fail (builder->ref_count > 0);
+
+  builder->ref_count -= 1;
+
+  if (builder->ref_count > 0)
+    return;
+  
+  gdk_content_formats_builder_clear (builder);
+  g_slice_free (GdkContentFormatsBuilder, builder);
+}
+
+/**
+ * gdk_content_formats_builder_free_to_formats: (skip)
+ * @builder: a #GdkContentFormatsBuilder
+ *
+ * Creates a new #GdkContentFormats from the current state of the
+ * given @builder, and frees the @builder instance.
+ *
+ * Returns: (transfer full): the newly created #GdkContentFormats
+ *   with all the formats added to @builder
+ */
+GdkContentFormats *
+gdk_content_formats_builder_free_to_formats (GdkContentFormatsBuilder *builder)
+{
+  GdkContentFormats *res;
+
+  g_return_val_if_fail (builder != NULL, NULL);
+
+  res = gdk_content_formats_builder_to_formats (builder);
+
+  gdk_content_formats_builder_unref (builder);
+
+  return res;
+}
+
+/**
+ * gdk_content_formats_builder_to_formats:
+ * @builder: a #GdkContentFormatsBuilder
+ *
+ * Creates a new #GdkContentFormats from the given @builder.
+ *
+ * The given #GdkContentFormatsBuilder is reset once this function returns;
+ * you cannot call this function multiple times on the same @builder instance.
+ *
+ * This function is intended primarily for bindings. C code should use
+ * gdk_content_formats_builder_free_to_formats().
+ *
+ * Returns: (transfer full): the newly created #GdkContentFormats
+ *   with all the formats added to @builder
+ */
 GdkContentFormats *
-gdk_content_formats_builder_free (GdkContentFormatsBuilder *builder)
+gdk_content_formats_builder_to_formats (GdkContentFormatsBuilder *builder)
 {
   GdkContentFormats *result;
   GType *gtypes;
@@ -567,9 +664,7 @@ gdk_content_formats_builder_free (GdkContentFormatsBuilder *builder)
   result = gdk_content_formats_new_take (gtypes, builder->n_gtypes,
                                          mime_types, builder->n_mime_types);
 
-  g_slist_free (builder->gtypes);
-  g_slist_free (builder->mime_types);
-  g_slice_free (GdkContentFormatsBuilder, builder);
+  gdk_content_formats_builder_clear (builder);
 
   return result;
 }
index 58bbb103fdc29fa004b5af67836e8109fbc32911..a3834344f423b1ae1bef3f9fc6f264eead3b4b9e 100644 (file)
@@ -77,12 +77,23 @@ GDK_AVAILABLE_IN_3_94
 gboolean                gdk_content_formats_contain_mime_type   (const GdkContentFormats        *formats,
                                                                  const char                     *mime_type);
 
+#define GDK_TYPE_CONTENT_FORMATS_BUILDER (gdk_content_formats_builder_get_type ())
+
 typedef struct _GdkContentFormatsBuilder GdkContentFormatsBuilder;
 
 GDK_AVAILABLE_IN_3_94
-GdkContentFormatsBuilder*gdk_content_formats_builder_new        (void);
+GType                   gdk_content_formats_builder_get_type    (void) G_GNUC_CONST;
+
+GDK_AVAILABLE_IN_3_94
+GdkContentFormatsBuilder *gdk_content_formats_builder_new        (void);
+GDK_AVAILABLE_IN_3_94
+GdkContentFormatsBuilder *gdk_content_formats_builder_ref       (GdkContentFormatsBuilder       *builder);
+GDK_AVAILABLE_IN_3_94
+void                    gdk_content_formats_builder_unref       (GdkContentFormatsBuilder       *builder);
+GDK_AVAILABLE_IN_3_94
+GdkContentFormats *     gdk_content_formats_builder_free_to_formats (GdkContentFormatsBuilder  *builder) G_GNUC_WARN_UNUSED_RESULT;
 GDK_AVAILABLE_IN_3_94
-GdkContentFormats *     gdk_content_formats_builder_free        (GdkContentFormatsBuilder       *builder) G_GNUC_WARN_UNUSED_RESULT;
+GdkContentFormats *     gdk_content_formats_builder_to_formats  (GdkContentFormatsBuilder  *builder) G_GNUC_WARN_UNUSED_RESULT;
 GDK_AVAILABLE_IN_3_94
 void                    gdk_content_formats_builder_add_formats (GdkContentFormatsBuilder       *builder,
                                                                  const GdkContentFormats        *formats);
index 9ae14e0a4075776ee8e04a4d12561d85263c4fcb..e7b70c28ab0d35b80c2621f1234c6c9d93ea6d1a 100644 (file)
@@ -168,7 +168,7 @@ gdk_content_provider_bytes_ref_formats (GdkContentProvider *provider)
 
   builder = gdk_content_formats_builder_new ();
   gdk_content_formats_builder_add_mime_type (builder, content->mime_type);
-  return gdk_content_formats_builder_free (builder);
+  return gdk_content_formats_builder_free_to_formats (builder);
 }
 
 static void
index 843c613485bea8aee7ac56dc748aae8273744f2c..92cbb2df6b68c0e7d3a011bc134dca3ebb50e518 100644 (file)
@@ -461,7 +461,7 @@ gdk_content_formats_union_serialize_gtypes (GdkContentFormats *formats)
 
   gdk_content_formats_unref (formats);
 
-  return gdk_content_formats_builder_free (builder);
+  return gdk_content_formats_builder_free_to_formats (builder);
 }
 
 /**
@@ -496,7 +496,7 @@ gdk_content_formats_union_serialize_mime_types (GdkContentFormats *formats)
 
   gdk_content_formats_unref (formats);
 
-  return gdk_content_formats_builder_free (builder);
+  return gdk_content_formats_builder_free_to_formats (builder);
 }
 
 static void
index 89f02e65ffc0940ed67b43d1bc360eb3dcb3a2cd..62a6941db2f3e6449cfbdf073fa6fd4590ba8084 100644 (file)
@@ -58,7 +58,7 @@ gdk_wayland_primary_discard_pending (GdkWaylandPrimary *cb)
 {
   if (cb->pending_builder)
     {
-      GdkContentFormats *ignore = gdk_content_formats_builder_free (cb->pending_builder);
+      GdkContentFormats *ignore = gdk_content_formats_builder_free_to_formats (cb->pending_builder);
       gdk_content_formats_unref (ignore);
       cb->pending_builder = NULL;
     }
@@ -178,7 +178,7 @@ primary_selection_selection (void                                *data,
       return;
     }
 
-  formats = gdk_content_formats_builder_free (cb->pending_builder);
+  formats = gdk_content_formats_builder_free_to_formats (cb->pending_builder);
   cb->pending_builder = NULL;
   cb->pending = NULL;
 
index 0db6bad4ad12b4abeb1c352996fab030b8388052..9f7826e1da75ab84250bcc4174e4e9fc718f22a8 100644 (file)
@@ -124,7 +124,7 @@ data_offer_offer (void                 *data,
   gdk_content_formats_builder_add_formats (builder, info->targets);
   gdk_content_formats_builder_add_mime_type (builder, type);
   gdk_content_formats_unref (info->targets);
-  info->targets = gdk_content_formats_builder_free (builder);
+  info->targets = gdk_content_formats_builder_free_to_formats (builder);
 }
 
 static inline GdkDragAction
index 190386c25a198031ca099af2515862d56a8456cd..1d844a8185d3e9183c932df0f6465a22a7109374 100644 (file)
@@ -552,7 +552,7 @@ query_targets (LPDATAOBJECT  pDataObj,
   for (p = g_list_reverse (result); p; p = p->next)
     gdk_content_formats_builder_add_mime_type (builder, (const gchar *) p->data);
 
-  result_formats = gdk_content_formats_builder_free (builder);
+  result_formats = gdk_content_formats_builder_free_to_formats (builder);
   g_list_free (result);
 
   return result_formats;
index 02a0b4e8ce7bfc3ec4e23aebd2cd1cc1b0eedb58..c7b3780885672438131f1dd07931a4ca64fe3df0 100644 (file)
@@ -243,7 +243,7 @@ gdk_x11_clipboard_formats_from_atoms (GdkDisplay *display,
         }
     }
 
-  return gdk_content_formats_builder_free (builder);
+  return gdk_content_formats_builder_free_to_formats (builder);
 }
 
 static void
index 66dbd02aa8644fe3f6afb90b1f3c006aa3fb6027..5dc56a7fca9d95259a8d48e24b95bbde034b5448 100644 (file)
@@ -176,7 +176,7 @@ gtk_content_formats_add_text_targets (GdkContentFormats *list)
     gdk_content_formats_builder_add_mime_type (builder, text_plain_locale_atom);  
   gdk_content_formats_builder_add_mime_type (builder, text_plain_atom);  
 
-  return gdk_content_formats_builder_free (builder);
+  return gdk_content_formats_builder_free_to_formats (builder);
 }
 
 /**
@@ -243,7 +243,7 @@ gtk_content_formats_add_image_targets (GdkContentFormats *list,
 
   g_slist_free (formats);
 
-  return gdk_content_formats_builder_free (builder);
+  return gdk_content_formats_builder_free_to_formats (builder);
 }
 
 /**
@@ -270,7 +270,7 @@ gtk_content_formats_add_uri_targets (GdkContentFormats *list)
 
   gdk_content_formats_builder_add_mime_type (builder, text_uri_list_atom);  
 
-  return gdk_content_formats_builder_free (builder);
+  return gdk_content_formats_builder_free_to_formats (builder);
 }
 
 /**