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 | |
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 (value: &content->value); |
64 | |
65 | G_OBJECT_CLASS (gdk_content_provider_value_parent_class)->finalize (object); |
66 | } |
67 | |
68 | static GdkContentFormats * |
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 |
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 (src_value: &content->value, dest_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 |
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 |
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 * |
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 (value: &content->value, G_VALUE_TYPE (value)); |
126 | g_value_copy (src_value: value, dest_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 * |
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 (mem: 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 | |
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 (provider: self->providers[i], clipboard); |
205 | } |
206 | |
207 | static void |
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 (provider: self->providers[i], clipboard); |
216 | } |
217 | |
218 | static GdkContentFormats * |
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 (provider: 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 * |
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 (provider: 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 |
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), result: res, error: &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 (object: task); |
274 | } |
275 | |
276 | static void |
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 (source_object: self, cancellable, callback, callback_data: user_data); |
290 | g_task_set_priority (task, priority: 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 (provider: self->providers[i]); |
296 | |
297 | if (gdk_content_formats_contain_mime_type (formats, mime_type)) |
298 | { |
299 | gdk_content_provider_write_mime_type_async (provider: self->providers[i], |
300 | mime_type, |
301 | stream, |
302 | io_priority, |
303 | cancellable, |
304 | callback: gdk_content_provider_union_write_mime_type_done, |
305 | user_data: 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, code: G_IO_ERROR_NOT_SUPPORTED, |
313 | _("Cannot provide contents as ā%sā" ), mime_type); |
314 | g_object_unref (object: task); |
315 | } |
316 | |
317 | static gboolean |
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 |
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 (provider: self->providers[i], value, error: &provider_error)) |
341 | return TRUE; |
342 | |
343 | if (!g_error_matches (error: provider_error, G_IO_ERROR, code: G_IO_ERROR_NOT_SUPPORTED)) |
344 | { |
345 | g_propagate_error (dest: error, src: provider_error); |
346 | return FALSE; |
347 | } |
348 | |
349 | g_clear_error (err: &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 |
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 (object: self->providers[i]); |
365 | } |
366 | |
367 | g_free (mem: self->providers); |
368 | |
369 | G_OBJECT_CLASS (gdk_content_provider_union_parent_class)->finalize (object); |
370 | } |
371 | |
372 | static void |
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 |
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 * |
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 (mem: providers, byte_size: 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 | |
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 (bytes: content->bytes); |
476 | |
477 | G_OBJECT_CLASS (gdk_content_provider_bytes_parent_class)->finalize (object); |
478 | } |
479 | |
480 | static GdkContentFormats * |
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, mime_type: content->mime_type); |
488 | return gdk_content_formats_builder_free_to_formats (builder); |
489 | } |
490 | |
491 | static void |
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: &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 (object: task); |
511 | } |
512 | |
513 | static void |
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 (source_object: content, cancellable, callback, callback_data: user_data); |
526 | g_task_set_priority (task, priority: 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, code: G_IO_ERROR_NOT_SUPPORTED, |
532 | _("Cannot provide contents as ā%sā" ), mime_type); |
533 | g_object_unref (object: task); |
534 | return; |
535 | } |
536 | |
537 | g_output_stream_write_all_async (stream, |
538 | buffer: g_bytes_get_data (bytes: content->bytes, NULL), |
539 | count: g_bytes_get_size (bytes: content->bytes), |
540 | io_priority, |
541 | cancellable, |
542 | callback: gdk_content_provider_bytes_write_mime_type_done, |
543 | user_data: task); |
544 | } |
545 | |
546 | static gboolean |
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 |
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 |
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 * |
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 (string: mime_type); |
596 | content->bytes = g_bytes_ref (bytes); |
597 | |
598 | return GDK_CONTENT_PROVIDER (content); |
599 | } |
600 | |
601 | |