1 /* GDK - The GIMP Drawing Kit
2  *
3  * Copyright (C) 2017,2020 Benjamin Otte <otte@gnome.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "config.h"
20 
21 #include "gdkcontentproviderprivate.h"
22 
23 #include <gobject/gvaluecollector.h>
24 
25 #include "gdkcontentformats.h"
26 #include "gdkcontentserializer.h"
27 #include "gdkintl.h"
28 #include "gdkcontentproviderimpl.h"
29 
30 #include "gdk-private.h"
31 
32 #define GDK_TYPE_CONTENT_PROVIDER_VALUE            (gdk_content_provider_value_get_type ())
33 #define GDK_CONTENT_PROVIDER_VALUE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_CONTENT_PROVIDER_VALUE, GdkContentProviderValue))
34 #define GDK_IS_CONTENT_PROVIDER_VALUE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_CONTENT_PROVIDER_VALUE))
35 #define GDK_CONTENT_PROVIDER_VALUE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_CONTENT_PROVIDER_VALUE, GdkContentProviderValueClass))
36 #define GDK_IS_CONTENT_PROVIDER_VALUE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_CONTENT_PROVIDER_VALUE))
37 #define GDK_CONTENT_PROVIDER_VALUE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_CONTENT_PROVIDER_VALUE, GdkContentProviderValueClass))
38 
39 typedef struct _GdkContentProviderValue GdkContentProviderValue;
40 typedef struct _GdkContentProviderValueClass GdkContentProviderValueClass;
41 
42 struct _GdkContentProviderValue
43 {
44   GdkContentProvider parent;
45 
46   GValue value;
47 };
48 
49 struct _GdkContentProviderValueClass
50 {
51   GdkContentProviderClass parent_class;
52 };
53 
54 GType gdk_content_provider_value_get_type (void) G_GNUC_CONST;
55 
G_DEFINE_TYPE(GdkContentProviderValue,gdk_content_provider_value,GDK_TYPE_CONTENT_PROVIDER)56 G_DEFINE_TYPE (GdkContentProviderValue, gdk_content_provider_value, GDK_TYPE_CONTENT_PROVIDER)
57 
58 static void
59 gdk_content_provider_value_finalize (GObject *object)
60 {
61   GdkContentProviderValue *content = GDK_CONTENT_PROVIDER_VALUE (object);
62 
63   g_value_unset (&content->value);
64 
65   G_OBJECT_CLASS (gdk_content_provider_value_parent_class)->finalize (object);
66 }
67 
68 static GdkContentFormats *
gdk_content_provider_value_ref_formats(GdkContentProvider * provider)69 gdk_content_provider_value_ref_formats (GdkContentProvider *provider)
70 {
71   GdkContentProviderValue *content = GDK_CONTENT_PROVIDER_VALUE (provider);
72 
73   return gdk_content_formats_new_for_gtype (G_VALUE_TYPE (&content->value));
74 }
75 
76 static gboolean
gdk_content_provider_value_get_value(GdkContentProvider * provider,GValue * value,GError ** error)77 gdk_content_provider_value_get_value (GdkContentProvider  *provider,
78                                       GValue              *value,
79                                       GError             **error)
80 {
81   GdkContentProviderValue *content = GDK_CONTENT_PROVIDER_VALUE (provider);
82 
83   if (G_VALUE_HOLDS (&content->value, G_VALUE_TYPE (value)))
84     {
85       g_value_copy (&content->value, value);
86       return TRUE;
87     }
88 
89   return GDK_CONTENT_PROVIDER_CLASS (gdk_content_provider_value_parent_class)->get_value (provider, value, error);
90 }
91 
92 static void
gdk_content_provider_value_class_init(GdkContentProviderValueClass * class)93 gdk_content_provider_value_class_init (GdkContentProviderValueClass *class)
94 {
95   GObjectClass *object_class = G_OBJECT_CLASS (class);
96   GdkContentProviderClass *provider_class = GDK_CONTENT_PROVIDER_CLASS (class);
97 
98   object_class->finalize = gdk_content_provider_value_finalize;
99 
100   provider_class->ref_formats = gdk_content_provider_value_ref_formats;
101   provider_class->get_value = gdk_content_provider_value_get_value;
102 }
103 
104 static void
gdk_content_provider_value_init(GdkContentProviderValue * content)105 gdk_content_provider_value_init (GdkContentProviderValue *content)
106 {
107 }
108 
109 /**
110  * gdk_content_provider_new_for_value:
111  * @value: a `GValue`
112  *
113  * Create a content provider that provides the given @value.
114  *
115  * Returns: a new `GdkContentProvider`
116  */
117 GdkContentProvider *
gdk_content_provider_new_for_value(const GValue * value)118 gdk_content_provider_new_for_value (const GValue *value)
119 {
120   GdkContentProviderValue *content;
121 
122   g_return_val_if_fail (G_IS_VALUE (value), NULL);
123 
124   content = g_object_new (GDK_TYPE_CONTENT_PROVIDER_VALUE, NULL);
125   g_value_init (&content->value, G_VALUE_TYPE (value));
126   g_value_copy (value, &content->value);
127 
128   return GDK_CONTENT_PROVIDER (content);
129 }
130 
131 /**
132  * gdk_content_provider_new_typed:
133  * @type: Type of value to follow
134  * @...: value
135  *
136  * Create a content provider that provides the value of the given
137  * @type.
138  *
139  * The value is provided using G_VALUE_COLLECT(), so the same rules
140  * apply as when calling g_object_new() or g_object_set().
141  *
142  * Returns: a new `GdkContentProvider`
143  */
144 GdkContentProvider *
gdk_content_provider_new_typed(GType type,...)145 gdk_content_provider_new_typed (GType type,
146                                 ...)
147 {
148   GdkContentProviderValue *content;
149   va_list args;
150   char *error;
151 
152   content = g_object_new (GDK_TYPE_CONTENT_PROVIDER_VALUE, NULL);
153 
154   va_start (args, type);
155   G_VALUE_COLLECT_INIT (&content->value, type, args, 0, &error);
156   if (error)
157     {
158       g_warning ("%s: %s", G_STRLOC, error);
159       g_free (error);
160       /* we purposely leak the value here, it might not be
161        * in a sane state if an error condition occurred
162        */
163     }
164   va_end (args);
165 
166   return GDK_CONTENT_PROVIDER (content);
167 }
168 
169 #define GDK_TYPE_CONTENT_PROVIDER_UNION            (gdk_content_provider_union_get_type ())
170 #define GDK_CONTENT_PROVIDER_UNION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_CONTENT_PROVIDER_UNION, GdkContentProviderUnion))
171 #define GDK_IS_CONTENT_PROVIDER_UNION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_CONTENT_PROVIDER_UNION))
172 #define GDK_CONTENT_PROVIDER_UNION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_CONTENT_PROVIDER_UNION, GdkContentProviderUnionClass))
173 #define GDK_IS_CONTENT_PROVIDER_UNION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_CONTENT_PROVIDER_UNION))
174 #define GDK_CONTENT_PROVIDER_UNION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_CONTENT_PROVIDER_UNION, GdkContentProviderUnionClass))
175 
176 typedef struct _GdkContentProviderUnion GdkContentProviderUnion;
177 typedef struct _GdkContentProviderUnionClass GdkContentProviderUnionClass;
178 
179 struct _GdkContentProviderUnion
180 {
181   GdkContentProvider parent;
182 
183   GdkContentProvider **providers;
184   gsize n_providers;
185 };
186 
187 struct _GdkContentProviderUnionClass
188 {
189   GdkContentProviderClass parent_class;
190 };
191 
192 GType gdk_content_provider_union_get_type (void) G_GNUC_CONST;
193 
G_DEFINE_TYPE(GdkContentProviderUnion,gdk_content_provider_union,GDK_TYPE_CONTENT_PROVIDER)194 G_DEFINE_TYPE (GdkContentProviderUnion, gdk_content_provider_union, GDK_TYPE_CONTENT_PROVIDER)
195 
196 static void
197 gdk_content_provider_union_attach_clipboard (GdkContentProvider *provider,
198                                              GdkClipboard       *clipboard)
199 {
200   GdkContentProviderUnion *self = GDK_CONTENT_PROVIDER_UNION (provider);
201   gsize i;
202 
203   for (i = 0; i < self->n_providers; i++)
204     gdk_content_provider_attach_clipboard (self->providers[i], clipboard);
205 }
206 
207 static void
gdk_content_provider_union_detach_clipboard(GdkContentProvider * provider,GdkClipboard * clipboard)208 gdk_content_provider_union_detach_clipboard (GdkContentProvider *provider,
209                                              GdkClipboard       *clipboard)
210 {
211   GdkContentProviderUnion *self = GDK_CONTENT_PROVIDER_UNION (provider);
212   gsize i;
213 
214   for (i = 0; i < self->n_providers; i++)
215     gdk_content_provider_detach_clipboard (self->providers[i], clipboard);
216 }
217 
218 static GdkContentFormats *
gdk_content_provider_union_ref_formats(GdkContentProvider * provider)219 gdk_content_provider_union_ref_formats (GdkContentProvider *provider)
220 {
221   GdkContentProviderUnion *self = GDK_CONTENT_PROVIDER_UNION (provider);
222   GdkContentFormatsBuilder *builder;
223   gsize i;
224 
225   builder = gdk_content_formats_builder_new ();
226 
227   for (i = 0; i < self->n_providers; i++)
228     {
229       GdkContentFormats *formats = gdk_content_provider_ref_formats (self->providers[i]);
230       gdk_content_formats_builder_add_formats (builder, formats);
231       gdk_content_formats_unref (formats);
232     }
233 
234   return gdk_content_formats_builder_free_to_formats (builder);
235 }
236 
237 static GdkContentFormats *
gdk_content_provider_union_ref_storable_formats(GdkContentProvider * provider)238 gdk_content_provider_union_ref_storable_formats (GdkContentProvider *provider)
239 {
240   GdkContentProviderUnion *self = GDK_CONTENT_PROVIDER_UNION (provider);
241   GdkContentFormatsBuilder *builder;
242   gsize i;
243 
244   builder = gdk_content_formats_builder_new ();
245 
246   for (i = 0; i < self->n_providers; i++)
247     {
248       GdkContentFormats *formats = gdk_content_provider_ref_storable_formats (self->providers[i]);
249       gdk_content_formats_builder_add_formats (builder, formats);
250       gdk_content_formats_unref (formats);
251     }
252 
253   return gdk_content_formats_builder_free_to_formats (builder);
254 }
255 
256 static void
gdk_content_provider_union_write_mime_type_done(GObject * source_object,GAsyncResult * res,gpointer data)257 gdk_content_provider_union_write_mime_type_done (GObject      *source_object,
258                                                  GAsyncResult *res,
259                                                  gpointer      data)
260 {
261   GTask *task = data;
262   GError *error = NULL;
263 
264   if (!gdk_content_provider_write_mime_type_finish (GDK_CONTENT_PROVIDER (source_object), res, &error))
265     {
266       g_task_return_error (task, error);
267     }
268   else
269     {
270       g_task_return_boolean (task, TRUE);
271     }
272 
273   g_object_unref (task);
274 }
275 
276 static void
gdk_content_provider_union_write_mime_type_async(GdkContentProvider * provider,const char * mime_type,GOutputStream * stream,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)277 gdk_content_provider_union_write_mime_type_async (GdkContentProvider     *provider,
278                                                   const char             *mime_type,
279                                                   GOutputStream          *stream,
280                                                   int                     io_priority,
281                                                   GCancellable           *cancellable,
282                                                   GAsyncReadyCallback     callback,
283                                                   gpointer                user_data)
284 {
285   GdkContentProviderUnion *self = GDK_CONTENT_PROVIDER_UNION (provider);
286   GTask *task;
287   gsize i;
288 
289   task = g_task_new (self, cancellable, callback, user_data);
290   g_task_set_priority (task, io_priority);
291   g_task_set_source_tag (task, gdk_content_provider_union_write_mime_type_async);
292 
293   for (i = 0; i < self->n_providers; i++)
294     {
295       GdkContentFormats *formats = gdk_content_provider_ref_formats (self->providers[i]);
296 
297       if (gdk_content_formats_contain_mime_type (formats, mime_type))
298         {
299           gdk_content_provider_write_mime_type_async (self->providers[i],
300                                                       mime_type,
301                                                       stream,
302                                                       io_priority,
303                                                       cancellable,
304                                                       gdk_content_provider_union_write_mime_type_done,
305                                                       task);
306           gdk_content_formats_unref (formats);
307           return;
308         }
309       gdk_content_formats_unref (formats);
310     }
311 
312   g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
313                            _("Cannot provide contents as “%s”"), mime_type);
314   g_object_unref (task);
315 }
316 
317 static gboolean
gdk_content_provider_union_write_mime_type_finish(GdkContentProvider * provider,GAsyncResult * result,GError ** error)318 gdk_content_provider_union_write_mime_type_finish (GdkContentProvider  *provider,
319                                                    GAsyncResult        *result,
320                                                    GError             **error)
321 {
322   g_return_val_if_fail (g_task_is_valid (result, provider), FALSE);
323   g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == gdk_content_provider_union_write_mime_type_async, FALSE);
324 
325   return g_task_propagate_boolean (G_TASK (result), error);
326 }
327 
328 static gboolean
gdk_content_provider_union_get_value(GdkContentProvider * provider,GValue * value,GError ** error)329 gdk_content_provider_union_get_value (GdkContentProvider  *provider,
330                                       GValue              *value,
331                                       GError             **error)
332 {
333   GdkContentProviderUnion *self = GDK_CONTENT_PROVIDER_UNION (provider);
334   gsize i;
335 
336   for (i = 0; i < self->n_providers; i++)
337     {
338       GError *provider_error = NULL;
339 
340       if (gdk_content_provider_get_value (self->providers[i], value, &provider_error))
341         return TRUE;
342 
343       if (!g_error_matches (provider_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
344         {
345           g_propagate_error (error, provider_error);
346           return FALSE;
347         }
348 
349       g_clear_error (&provider_error);
350     }
351 
352   return GDK_CONTENT_PROVIDER_CLASS (gdk_content_provider_union_parent_class)->get_value (provider, value, error);
353 }
354 
355 static void
gdk_content_provider_union_finalize(GObject * object)356 gdk_content_provider_union_finalize (GObject *object)
357 {
358   GdkContentProviderUnion *self = GDK_CONTENT_PROVIDER_UNION (object);
359   gsize i;
360 
361   for (i = 0; i < self->n_providers; i++)
362     {
363       g_signal_handlers_disconnect_by_func (self->providers[i], gdk_content_provider_content_changed, self);
364       g_object_unref (self->providers[i]);
365     }
366 
367   g_free (self->providers);
368 
369   G_OBJECT_CLASS (gdk_content_provider_union_parent_class)->finalize (object);
370 }
371 
372 static void
gdk_content_provider_union_class_init(GdkContentProviderUnionClass * class)373 gdk_content_provider_union_class_init (GdkContentProviderUnionClass *class)
374 {
375   GObjectClass *object_class = G_OBJECT_CLASS (class);
376   GdkContentProviderClass *provider_class = GDK_CONTENT_PROVIDER_CLASS (class);
377 
378   object_class->finalize = gdk_content_provider_union_finalize;
379 
380   provider_class->attach_clipboard = gdk_content_provider_union_attach_clipboard;
381   provider_class->detach_clipboard = gdk_content_provider_union_detach_clipboard;
382   provider_class->ref_formats = gdk_content_provider_union_ref_formats;
383   provider_class->ref_storable_formats = gdk_content_provider_union_ref_storable_formats;
384   provider_class->write_mime_type_async = gdk_content_provider_union_write_mime_type_async;
385   provider_class->write_mime_type_finish = gdk_content_provider_union_write_mime_type_finish;
386   provider_class->get_value = gdk_content_provider_union_get_value;
387 }
388 
389 static void
gdk_content_provider_union_init(GdkContentProviderUnion * self)390 gdk_content_provider_union_init (GdkContentProviderUnion *self)
391 {
392 }
393 
394 /**
395  * gdk_content_provider_new_union:
396  * @providers: (nullable) (array length=n_providers) (transfer full):
397  *   The `GdkContentProvider`s to present the union of
398  * @n_providers: the number of providers
399  *
400  * Creates a content provider that represents all the given @providers.
401  *
402  * Whenever data needs to be written, the union provider will try the given
403  * @providers in the given order and the first one supporting a format will
404  * be chosen to provide it.
405  *
406  * This allows an easy way to support providing data in different formats.
407  * For example, an image may be provided by its file and by the image
408  * contents with a call such as
409  * ```c
410  * gdk_content_provider_new_union ((GdkContentProvider *[2]) {
411  *                                   gdk_content_provider_new_typed (G_TYPE_FILE, file),
412  *                                   gdk_content_provider_new_typed (G_TYPE_TEXTURE, texture)
413  *                                 }, 2);
414  * ```
415  *
416  * Returns: a new `GdkContentProvider`
417  */
418 GdkContentProvider *
gdk_content_provider_new_union(GdkContentProvider ** providers,gsize n_providers)419 gdk_content_provider_new_union (GdkContentProvider **providers,
420                                 gsize                n_providers)
421 {
422   GdkContentProviderUnion *result;
423   gsize i;
424 
425   g_return_val_if_fail (providers != NULL || n_providers == 0, NULL);
426 
427   result = g_object_new (GDK_TYPE_CONTENT_PROVIDER_UNION, NULL);
428 
429   result->n_providers = n_providers;
430   result->providers = g_memdup2 (providers, sizeof (GdkContentProvider *) * n_providers);
431 
432   for (i = 0; i < n_providers; i++)
433     {
434       g_signal_connect_swapped (result->providers[i],
435                                 "content-changed",
436                                 G_CALLBACK (gdk_content_provider_content_changed),
437                                 result);
438     }
439 
440   return GDK_CONTENT_PROVIDER (result);
441 }
442 
443 #define GDK_TYPE_CONTENT_PROVIDER_BYTES            (gdk_content_provider_bytes_get_type ())
444 #define GDK_CONTENT_PROVIDER_BYTES(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_CONTENT_PROVIDER_BYTES, GdkContentProviderBytes))
445 #define GDK_IS_CONTENT_PROVIDER_BYTES(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_CONTENT_PROVIDER_BYTES))
446 #define GDK_CONTENT_PROVIDER_BYTES_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_CONTENT_PROVIDER_BYTES, GdkContentProviderBytesClass))
447 #define GDK_IS_CONTENT_PROVIDER_BYTES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_CONTENT_PROVIDER_BYTES))
448 #define GDK_CONTENT_PROVIDER_BYTES_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_CONTENT_PROVIDER_BYTES, GdkContentProviderBytesClass))
449 
450 typedef struct _GdkContentProviderBytes GdkContentProviderBytes;
451 typedef struct _GdkContentProviderBytesClass GdkContentProviderBytesClass;
452 
453 struct _GdkContentProviderBytes
454 {
455   GdkContentProvider parent;
456 
457   /* interned */const char *mime_type;
458   GBytes *bytes;
459 };
460 
461 struct _GdkContentProviderBytesClass
462 {
463   GdkContentProviderClass parent_class;
464 };
465 
466 GType gdk_content_provider_bytes_get_type (void) G_GNUC_CONST;
467 
G_DEFINE_TYPE(GdkContentProviderBytes,gdk_content_provider_bytes,GDK_TYPE_CONTENT_PROVIDER)468 G_DEFINE_TYPE (GdkContentProviderBytes, gdk_content_provider_bytes, GDK_TYPE_CONTENT_PROVIDER)
469 
470 static void
471 gdk_content_provider_bytes_finalize (GObject *object)
472 {
473   GdkContentProviderBytes *content = GDK_CONTENT_PROVIDER_BYTES (object);
474 
475   g_bytes_unref (content->bytes);
476 
477   G_OBJECT_CLASS (gdk_content_provider_bytes_parent_class)->finalize (object);
478 }
479 
480 static GdkContentFormats *
gdk_content_provider_bytes_ref_formats(GdkContentProvider * provider)481 gdk_content_provider_bytes_ref_formats (GdkContentProvider *provider)
482 {
483   GdkContentProviderBytes *content = GDK_CONTENT_PROVIDER_BYTES (provider);
484   GdkContentFormatsBuilder *builder;
485 
486   builder = gdk_content_formats_builder_new ();
487   gdk_content_formats_builder_add_mime_type (builder, content->mime_type);
488   return gdk_content_formats_builder_free_to_formats (builder);
489 }
490 
491 static void
gdk_content_provider_bytes_write_mime_type_done(GObject * stream,GAsyncResult * result,gpointer task)492 gdk_content_provider_bytes_write_mime_type_done (GObject      *stream,
493                                                  GAsyncResult *result,
494                                                  gpointer      task)
495 {
496   GError *error = NULL;
497 
498   if (!g_output_stream_write_all_finish (G_OUTPUT_STREAM (stream),
499                                          result,
500                                          NULL,
501                                          &error))
502     {
503       g_task_return_error (task, error);
504     }
505   else
506     {
507       g_task_return_boolean (task, TRUE);
508     }
509 
510   g_object_unref (task);
511 }
512 
513 static void
gdk_content_provider_bytes_write_mime_type_async(GdkContentProvider * provider,const char * mime_type,GOutputStream * stream,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)514 gdk_content_provider_bytes_write_mime_type_async (GdkContentProvider     *provider,
515                                                   const char             *mime_type,
516                                                   GOutputStream          *stream,
517                                                   int                     io_priority,
518                                                   GCancellable           *cancellable,
519                                                   GAsyncReadyCallback     callback,
520                                                   gpointer                user_data)
521 {
522   GdkContentProviderBytes *content = GDK_CONTENT_PROVIDER_BYTES (provider);
523   GTask *task;
524 
525   task = g_task_new (content, cancellable, callback, user_data);
526   g_task_set_priority (task, io_priority);
527   g_task_set_source_tag (task, gdk_content_provider_bytes_write_mime_type_async);
528 
529   if (mime_type != content->mime_type)
530     {
531       g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
532                                _("Cannot provide contents as “%s”"), mime_type);
533       g_object_unref (task);
534       return;
535     }
536 
537   g_output_stream_write_all_async (stream,
538                                    g_bytes_get_data (content->bytes, NULL),
539                                    g_bytes_get_size (content->bytes),
540                                    io_priority,
541                                    cancellable,
542                                    gdk_content_provider_bytes_write_mime_type_done,
543                                    task);
544 }
545 
546 static gboolean
gdk_content_provider_bytes_write_mime_type_finish(GdkContentProvider * provider,GAsyncResult * result,GError ** error)547 gdk_content_provider_bytes_write_mime_type_finish (GdkContentProvider *provider,
548                                                    GAsyncResult       *result,
549                                                    GError            **error)
550 {
551   g_return_val_if_fail (g_task_is_valid (result, provider), FALSE);
552   g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == gdk_content_provider_bytes_write_mime_type_async, FALSE);
553 
554   return g_task_propagate_boolean (G_TASK (result), error);
555 }
556 
557 static void
gdk_content_provider_bytes_class_init(GdkContentProviderBytesClass * class)558 gdk_content_provider_bytes_class_init (GdkContentProviderBytesClass *class)
559 {
560   GObjectClass *object_class = G_OBJECT_CLASS (class);
561   GdkContentProviderClass *provider_class = GDK_CONTENT_PROVIDER_CLASS (class);
562 
563   object_class->finalize = gdk_content_provider_bytes_finalize;
564 
565   provider_class->ref_formats = gdk_content_provider_bytes_ref_formats;
566   provider_class->write_mime_type_async = gdk_content_provider_bytes_write_mime_type_async;
567   provider_class->write_mime_type_finish = gdk_content_provider_bytes_write_mime_type_finish;
568 }
569 
570 static void
gdk_content_provider_bytes_init(GdkContentProviderBytes * content)571 gdk_content_provider_bytes_init (GdkContentProviderBytes *content)
572 {
573 }
574 
575 /**
576  * gdk_content_provider_new_for_bytes:
577  * @mime_type: the mime type
578  * @bytes: (transfer none): a `GBytes` with the data for @mime_type
579  *
580  * Create a content provider that provides the given @bytes as data for
581  * the given @mime_type.
582  *
583  * Returns: a new `GdkContentProvider`
584  */
585 GdkContentProvider *
gdk_content_provider_new_for_bytes(const char * mime_type,GBytes * bytes)586 gdk_content_provider_new_for_bytes (const char *mime_type,
587                                     GBytes     *bytes)
588 {
589   GdkContentProviderBytes *content;
590 
591   g_return_val_if_fail (mime_type != NULL, NULL);
592   g_return_val_if_fail (bytes != NULL, NULL);
593 
594   content = g_object_new (GDK_TYPE_CONTENT_PROVIDER_BYTES, NULL);
595   content->mime_type = g_intern_string (mime_type);
596   content->bytes = g_bytes_ref (bytes);
597 
598   return GDK_CONTENT_PROVIDER (content);
599 }
600 
601