1 | /* GTK - The GIMP Toolkit |
2 | * gtkprintoperation-portal.c: Print Operation Details for sandboxed apps |
3 | * Copyright (C) 2016, Red Hat, Inc. |
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 <string.h> |
22 | |
23 | #include <sys/types.h> |
24 | #include <sys/stat.h> |
25 | #include <fcntl.h> |
26 | |
27 | #include <cairo-pdf.h> |
28 | #include <cairo-ps.h> |
29 | |
30 | #include <gio/gunixfdlist.h> |
31 | |
32 | #include "gtkprintoperation-private.h" |
33 | #include "gtkprintoperation-portal.h" |
34 | #include "gtkprintsettings.h" |
35 | #include "gtkpagesetup.h" |
36 | #include "gtkprintbackendprivate.h" |
37 | #include "gtkshow.h" |
38 | #include "gtkintl.h" |
39 | #include "gtkwindowprivate.h" |
40 | #include "gtkprivate.h" |
41 | |
42 | |
43 | typedef struct { |
44 | GtkPrintOperation *op; |
45 | GDBusProxy *proxy; |
46 | guint response_signal_id; |
47 | gboolean do_print; |
48 | GtkPrintOperationResult result; |
49 | GtkPrintOperationPrintFunc print_cb; |
50 | GtkWindow *parent; |
51 | GMainLoop *loop; |
52 | guint32 token; |
53 | GDestroyNotify destroy; |
54 | GVariant *settings; |
55 | GVariant *setup; |
56 | GVariant *options; |
57 | char *prepare_print_handle; |
58 | } PortalData; |
59 | |
60 | static void |
61 | portal_data_free (gpointer data) |
62 | { |
63 | PortalData *portal = data; |
64 | |
65 | if (portal->parent) |
66 | gtk_window_unexport_handle (window: portal->parent); |
67 | g_object_unref (object: portal->op); |
68 | g_object_unref (object: portal->proxy); |
69 | if (portal->loop) |
70 | g_main_loop_unref (loop: portal->loop); |
71 | if (portal->settings) |
72 | g_variant_unref (value: portal->settings); |
73 | if (portal->setup) |
74 | g_variant_unref (value: portal->setup); |
75 | if (portal->options) |
76 | g_variant_unref (value: portal->options); |
77 | g_free (mem: portal->prepare_print_handle); |
78 | g_free (mem: portal); |
79 | } |
80 | |
81 | typedef struct { |
82 | GDBusProxy *proxy; |
83 | GtkPrintJob *job; |
84 | guint32 token; |
85 | cairo_surface_t *surface; |
86 | GMainLoop *loop; |
87 | gboolean file_written; |
88 | } GtkPrintOperationPortal; |
89 | |
90 | static void |
91 | op_portal_free (GtkPrintOperationPortal *op_portal) |
92 | { |
93 | g_clear_object (&op_portal->proxy); |
94 | g_clear_object (&op_portal->job); |
95 | if (op_portal->loop) |
96 | g_main_loop_unref (loop: op_portal->loop); |
97 | g_free (mem: op_portal); |
98 | } |
99 | |
100 | static void |
101 | portal_start_page (GtkPrintOperation *op, |
102 | GtkPrintContext *print_context, |
103 | GtkPageSetup *page_setup) |
104 | { |
105 | GtkPrintOperationPortal *op_portal = op->priv->platform_data; |
106 | GtkPaperSize *paper_size; |
107 | cairo_surface_type_t type; |
108 | double w, h; |
109 | |
110 | paper_size = gtk_page_setup_get_paper_size (setup: page_setup); |
111 | |
112 | w = gtk_paper_size_get_width (size: paper_size, unit: GTK_UNIT_POINTS); |
113 | h = gtk_paper_size_get_height (size: paper_size, unit: GTK_UNIT_POINTS); |
114 | |
115 | type = cairo_surface_get_type (surface: op_portal->surface); |
116 | |
117 | if ((op->priv->manual_number_up < 2) || |
118 | (op->priv->page_position % op->priv->manual_number_up == 0)) |
119 | { |
120 | if (type == CAIRO_SURFACE_TYPE_PS) |
121 | { |
122 | cairo_ps_surface_set_size (surface: op_portal->surface, width_in_points: w, height_in_points: h); |
123 | cairo_ps_surface_dsc_begin_page_setup (surface: op_portal->surface); |
124 | switch (gtk_page_setup_get_orientation (setup: page_setup)) |
125 | { |
126 | case GTK_PAGE_ORIENTATION_PORTRAIT: |
127 | case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT: |
128 | cairo_ps_surface_dsc_comment (surface: op_portal->surface, comment: "%%PageOrientation: Portrait" ); |
129 | break; |
130 | |
131 | case GTK_PAGE_ORIENTATION_LANDSCAPE: |
132 | case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE: |
133 | cairo_ps_surface_dsc_comment (surface: op_portal->surface, comment: "%%PageOrientation: Landscape" ); |
134 | break; |
135 | |
136 | default: |
137 | break; |
138 | } |
139 | } |
140 | else if (type == CAIRO_SURFACE_TYPE_PDF) |
141 | { |
142 | if (!op->priv->manual_orientation) |
143 | { |
144 | w = gtk_page_setup_get_paper_width (setup: page_setup, unit: GTK_UNIT_POINTS); |
145 | h = gtk_page_setup_get_paper_height (setup: page_setup, unit: GTK_UNIT_POINTS); |
146 | } |
147 | cairo_pdf_surface_set_size (surface: op_portal->surface, width_in_points: w, height_in_points: h); |
148 | } |
149 | } |
150 | } |
151 | |
152 | static void |
153 | portal_end_page (GtkPrintOperation *op, |
154 | GtkPrintContext *print_context) |
155 | { |
156 | cairo_t *cr; |
157 | |
158 | cr = gtk_print_context_get_cairo_context (context: print_context); |
159 | |
160 | if ((op->priv->manual_number_up < 2) || |
161 | ((op->priv->page_position + 1) % op->priv->manual_number_up == 0) || |
162 | (op->priv->page_position == op->priv->nr_of_pages_to_print - 1)) |
163 | cairo_show_page (cr); |
164 | } |
165 | |
166 | static void |
167 | print_file_done (GObject *source, |
168 | GAsyncResult *result, |
169 | gpointer data) |
170 | { |
171 | GtkPrintOperation *op = data; |
172 | GtkPrintOperationPortal *op_portal = op->priv->platform_data; |
173 | GError *error = NULL; |
174 | GVariant *ret; |
175 | |
176 | ret = g_dbus_proxy_call_finish (proxy: op_portal->proxy, |
177 | res: result, |
178 | error: &error); |
179 | if (ret == NULL) |
180 | { |
181 | if (op->priv->error == NULL) |
182 | op->priv->error = g_error_copy (error); |
183 | g_warning ("Print file failed: %s" , error->message); |
184 | g_error_free (error); |
185 | } |
186 | else |
187 | g_variant_unref (value: ret); |
188 | |
189 | if (op_portal->loop) |
190 | g_main_loop_quit (loop: op_portal->loop); |
191 | |
192 | g_object_unref (object: op); |
193 | } |
194 | |
195 | static void |
196 | portal_job_complete (GtkPrintJob *job, |
197 | gpointer data, |
198 | const GError *error) |
199 | { |
200 | GtkPrintOperation *op = data; |
201 | GtkPrintOperationPortal *op_portal = op->priv->platform_data; |
202 | GtkPrintSettings *settings; |
203 | const char *uri; |
204 | char *filename; |
205 | int fd, idx; |
206 | GVariantBuilder opt_builder; |
207 | GUnixFDList *fd_list; |
208 | |
209 | if (error != NULL && op->priv->error == NULL) |
210 | { |
211 | g_warning ("Print job failed: %s" , error->message); |
212 | op->priv->error = g_error_copy (error); |
213 | return; |
214 | } |
215 | |
216 | op_portal->file_written = TRUE; |
217 | |
218 | settings = gtk_print_job_get_settings (job); |
219 | uri = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_OUTPUT_URI); |
220 | filename = g_filename_from_uri (uri, NULL, NULL); |
221 | |
222 | fd = open (file: filename, O_RDONLY|O_CLOEXEC); |
223 | fd_list = g_unix_fd_list_new (); |
224 | idx = g_unix_fd_list_append (list: fd_list, fd, NULL); |
225 | close (fd: fd); |
226 | |
227 | g_free (mem: filename); |
228 | |
229 | g_variant_builder_init (builder: &opt_builder, G_VARIANT_TYPE_VARDICT); |
230 | g_variant_builder_add (builder: &opt_builder, format_string: "{sv}" , "token" , g_variant_new_uint32 (value: op_portal->token)); |
231 | |
232 | g_dbus_proxy_call_with_unix_fd_list (proxy: op_portal->proxy, |
233 | method_name: "Print" , |
234 | parameters: g_variant_new (format_string: "(ssh@a{sv})" , |
235 | "" , /* window */ |
236 | _("Print" ), /* title */ |
237 | idx, |
238 | g_variant_builder_end (builder: &opt_builder)), |
239 | flags: G_DBUS_CALL_FLAGS_NONE, |
240 | timeout_msec: -1, |
241 | fd_list, |
242 | NULL, |
243 | callback: print_file_done, |
244 | user_data: op); |
245 | g_object_unref (object: fd_list); |
246 | } |
247 | |
248 | static void |
249 | portal_end_run (GtkPrintOperation *op, |
250 | gboolean wait, |
251 | gboolean cancelled) |
252 | { |
253 | GtkPrintOperationPortal *op_portal = op->priv->platform_data; |
254 | |
255 | cairo_surface_finish (surface: op_portal->surface); |
256 | |
257 | if (cancelled) |
258 | return; |
259 | |
260 | if (wait) |
261 | op_portal->loop = g_main_loop_new (NULL, FALSE); |
262 | |
263 | /* TODO: Check for error */ |
264 | if (op_portal->job != NULL) |
265 | { |
266 | g_object_ref (op); |
267 | gtk_print_job_send (job: op_portal->job, callback: portal_job_complete, user_data: op, NULL); |
268 | } |
269 | |
270 | if (wait) |
271 | { |
272 | g_object_ref (op); |
273 | if (!op_portal->file_written) |
274 | g_main_loop_run (loop: op_portal->loop); |
275 | g_object_unref (object: op); |
276 | } |
277 | } |
278 | |
279 | static void |
280 | finish_print (PortalData *portal, |
281 | GtkPrinter *printer, |
282 | GtkPageSetup *page_setup, |
283 | GtkPrintSettings *settings) |
284 | { |
285 | GtkPrintOperation *op = portal->op; |
286 | GtkPrintOperationPrivate *priv = op->priv; |
287 | GtkPrintJob *job; |
288 | GtkPrintOperationPortal *op_portal; |
289 | cairo_t *cr; |
290 | |
291 | if (portal->do_print) |
292 | { |
293 | gtk_print_operation_set_print_settings (op, print_settings: settings); |
294 | priv->print_context = _gtk_print_context_new (op); |
295 | |
296 | _gtk_print_context_set_hard_margins (context: priv->print_context, top: 0, bottom: 0, left: 0, right: 0); |
297 | |
298 | gtk_print_operation_set_default_page_setup (op, default_page_setup: page_setup); |
299 | _gtk_print_context_set_page_setup (context: priv->print_context, page_setup); |
300 | |
301 | op_portal = g_new0 (GtkPrintOperationPortal, 1); |
302 | priv->platform_data = op_portal; |
303 | priv->free_platform_data = (GDestroyNotify) op_portal_free; |
304 | |
305 | priv->start_page = portal_start_page; |
306 | priv->end_page = portal_end_page; |
307 | priv->end_run = portal_end_run; |
308 | |
309 | job = gtk_print_job_new (title: priv->job_name, printer, settings, page_setup); |
310 | op_portal->job = job; |
311 | |
312 | op_portal->proxy = g_object_ref (portal->proxy); |
313 | op_portal->token = portal->token; |
314 | |
315 | op_portal->surface = gtk_print_job_get_surface (job, error: &priv->error); |
316 | if (op_portal->surface == NULL) |
317 | { |
318 | portal->result = GTK_PRINT_OPERATION_RESULT_ERROR; |
319 | portal->do_print = FALSE; |
320 | goto out; |
321 | } |
322 | |
323 | cr = cairo_create (target: op_portal->surface); |
324 | gtk_print_context_set_cairo_context (context: priv->print_context, cr, dpi_x: 72, dpi_y: 72); |
325 | cairo_destroy (cr); |
326 | |
327 | priv->print_pages = gtk_print_job_get_pages (job); |
328 | priv->page_ranges = gtk_print_job_get_page_ranges (job, n_ranges: &priv->num_page_ranges); |
329 | priv->manual_num_copies = gtk_print_job_get_num_copies (job); |
330 | priv->manual_collation = gtk_print_job_get_collate (job); |
331 | priv->manual_reverse = gtk_print_job_get_reverse (job); |
332 | priv->manual_page_set = gtk_print_job_get_page_set (job); |
333 | priv->manual_scale = gtk_print_job_get_scale (job); |
334 | priv->manual_orientation = gtk_print_job_get_rotate (job); |
335 | priv->manual_number_up = gtk_print_job_get_n_up (job); |
336 | priv->manual_number_up_layout = gtk_print_job_get_n_up_layout (job); |
337 | } |
338 | |
339 | out: |
340 | if (portal->print_cb) |
341 | portal->print_cb (op, portal->parent, portal->do_print, portal->result); |
342 | |
343 | if (portal->destroy) |
344 | portal->destroy (portal); |
345 | } |
346 | |
347 | static GtkPrinter * |
348 | find_file_printer (void) |
349 | { |
350 | GList *backends, *l, *printers; |
351 | GtkPrinter *printer; |
352 | |
353 | printer = NULL; |
354 | |
355 | backends = gtk_print_backend_load_modules (); |
356 | for (l = backends; l; l = l->next) |
357 | { |
358 | GtkPrintBackend *backend = l->data; |
359 | if (strcmp (G_OBJECT_TYPE_NAME (backend), s2: "GtkPrintBackendFile" ) == 0) |
360 | { |
361 | printers = gtk_print_backend_get_printer_list (print_backend: backend); |
362 | printer = printers->data; |
363 | g_list_free (list: printers); |
364 | break; |
365 | } |
366 | } |
367 | g_list_free (list: backends); |
368 | |
369 | return printer; |
370 | } |
371 | |
372 | static void |
373 | prepare_print_response (GDBusConnection *connection, |
374 | const char *sender_name, |
375 | const char *object_path, |
376 | const char *interface_name, |
377 | const char *signal_name, |
378 | GVariant *parameters, |
379 | gpointer data) |
380 | { |
381 | PortalData *portal = data; |
382 | guint32 response; |
383 | GVariant *options = NULL; |
384 | |
385 | if (portal->response_signal_id != 0) |
386 | { |
387 | g_dbus_connection_signal_unsubscribe (connection, |
388 | subscription_id: portal->response_signal_id); |
389 | portal->response_signal_id = 0; |
390 | } |
391 | |
392 | g_variant_get (value: parameters, format_string: "(u@a{sv})" , &response, &options); |
393 | |
394 | portal->do_print = (response == 0); |
395 | |
396 | if (portal->do_print) |
397 | { |
398 | GVariant *v; |
399 | GtkPrintSettings *settings; |
400 | GtkPageSetup *page_setup; |
401 | GtkPrinter *printer; |
402 | char *filename; |
403 | char *uri; |
404 | int fd; |
405 | |
406 | portal->result = GTK_PRINT_OPERATION_RESULT_APPLY; |
407 | |
408 | v = g_variant_lookup_value (dictionary: options, key: "settings" , G_VARIANT_TYPE_VARDICT); |
409 | settings = gtk_print_settings_new_from_gvariant (variant: v); |
410 | g_variant_unref (value: v); |
411 | |
412 | v = g_variant_lookup_value (dictionary: options, key: "page-setup" , G_VARIANT_TYPE_VARDICT); |
413 | page_setup = gtk_page_setup_new_from_gvariant (variant: v); |
414 | g_variant_unref (value: v); |
415 | |
416 | g_variant_lookup (dictionary: options, key: "token" , format_string: "u" , &portal->token); |
417 | |
418 | printer = find_file_printer (); |
419 | |
420 | fd = g_file_open_tmp (tmpl: "gtkprintXXXXXX" , name_used: &filename, NULL); |
421 | uri = g_filename_to_uri (filename, NULL, NULL); |
422 | gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_OUTPUT_URI, value: uri); |
423 | g_free (mem: uri); |
424 | close (fd: fd); |
425 | |
426 | finish_print (portal, printer, page_setup, settings); |
427 | g_free (mem: filename); |
428 | } |
429 | else |
430 | { |
431 | portal->result = GTK_PRINT_OPERATION_RESULT_CANCEL; |
432 | |
433 | if (portal->print_cb) |
434 | portal->print_cb (portal->op, portal->parent, portal->do_print, portal->result); |
435 | |
436 | if (portal->destroy) |
437 | portal->destroy (portal); |
438 | } |
439 | |
440 | if (options) |
441 | g_variant_unref (value: options); |
442 | |
443 | if (portal->loop) |
444 | g_main_loop_quit (loop: portal->loop); |
445 | } |
446 | |
447 | static void |
448 | prepare_print_called (GObject *source, |
449 | GAsyncResult *result, |
450 | gpointer data) |
451 | { |
452 | PortalData *portal = data; |
453 | GError *error = NULL; |
454 | const char *handle = NULL; |
455 | GVariant *ret; |
456 | |
457 | ret = g_dbus_proxy_call_finish (proxy: portal->proxy, res: result, error: &error); |
458 | if (ret == NULL) |
459 | { |
460 | if (portal->op->priv->error == NULL) |
461 | portal->op->priv->error = g_error_copy (error); |
462 | g_error_free (error); |
463 | if (portal->loop) |
464 | g_main_loop_quit (loop: portal->loop); |
465 | return; |
466 | } |
467 | else |
468 | g_variant_get (value: ret, format_string: "(&o)" , &handle); |
469 | |
470 | if (strcmp (s1: portal->prepare_print_handle, s2: handle) != 0) |
471 | { |
472 | g_free (mem: portal->prepare_print_handle); |
473 | portal->prepare_print_handle = g_strdup (str: handle); |
474 | g_dbus_connection_signal_unsubscribe (connection: g_dbus_proxy_get_connection (G_DBUS_PROXY (portal->proxy)), |
475 | subscription_id: portal->response_signal_id); |
476 | portal->response_signal_id = |
477 | g_dbus_connection_signal_subscribe (connection: g_dbus_proxy_get_connection (G_DBUS_PROXY (portal->proxy)), |
478 | PORTAL_BUS_NAME, |
479 | PORTAL_REQUEST_INTERFACE, |
480 | member: "Response" , |
481 | object_path: handle, |
482 | NULL, |
483 | flags: G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE, |
484 | callback: prepare_print_response, |
485 | user_data: portal, NULL); |
486 | } |
487 | |
488 | g_variant_unref (value: ret); |
489 | } |
490 | |
491 | static PortalData * |
492 | create_portal_data (GtkPrintOperation *op, |
493 | GtkWindow *parent, |
494 | GtkPrintOperationPrintFunc print_cb) |
495 | { |
496 | GDBusProxy *proxy; |
497 | PortalData *portal; |
498 | guint signal_id; |
499 | GError *error = NULL; |
500 | |
501 | signal_id = g_signal_lookup (name: "create-custom-widget" , GTK_TYPE_PRINT_OPERATION); |
502 | if (g_signal_has_handler_pending (instance: op, signal_id, detail: 0, TRUE)) |
503 | g_warning ("GtkPrintOperation::create-custom-widget not supported with portal" ); |
504 | |
505 | proxy = g_dbus_proxy_new_for_bus_sync (bus_type: G_BUS_TYPE_SESSION, |
506 | flags: G_DBUS_PROXY_FLAGS_NONE, |
507 | NULL, |
508 | PORTAL_BUS_NAME, |
509 | PORTAL_OBJECT_PATH, |
510 | PORTAL_PRINT_INTERFACE, |
511 | NULL, |
512 | error: &error); |
513 | |
514 | if (proxy == NULL) |
515 | { |
516 | if (op->priv->error == NULL) |
517 | op->priv->error = g_error_copy (error); |
518 | g_error_free (error); |
519 | return NULL; |
520 | } |
521 | |
522 | portal = g_new0 (PortalData, 1); |
523 | portal->proxy = proxy; |
524 | portal->op = g_object_ref (op); |
525 | portal->parent = parent; |
526 | portal->result = GTK_PRINT_OPERATION_RESULT_CANCEL; |
527 | portal->print_cb = print_cb; |
528 | |
529 | if (print_cb) /* async case */ |
530 | { |
531 | portal->loop = NULL; |
532 | portal->destroy = portal_data_free; |
533 | } |
534 | else |
535 | { |
536 | portal->loop = g_main_loop_new (NULL, FALSE); |
537 | portal->destroy = NULL; |
538 | } |
539 | |
540 | return portal; |
541 | } |
542 | |
543 | static void |
544 | window_handle_exported (GtkWindow *window, |
545 | const char *handle_str, |
546 | gpointer user_data) |
547 | { |
548 | PortalData *portal = user_data; |
549 | |
550 | g_dbus_proxy_call (proxy: portal->proxy, |
551 | method_name: "PreparePrint" , |
552 | parameters: g_variant_new (format_string: "(ss@a{sv}@a{sv}@a{sv})" , |
553 | handle_str, |
554 | _("Print" ), /* title */ |
555 | portal->settings, |
556 | portal->setup, |
557 | portal->options), |
558 | flags: G_DBUS_CALL_FLAGS_NONE, |
559 | timeout_msec: -1, |
560 | NULL, |
561 | callback: prepare_print_called, |
562 | user_data: portal); |
563 | } |
564 | |
565 | static void |
566 | call_prepare_print (GtkPrintOperation *op, |
567 | PortalData *portal) |
568 | { |
569 | GtkPrintOperationPrivate *priv = op->priv; |
570 | GVariantBuilder opt_builder; |
571 | char *token; |
572 | |
573 | portal->prepare_print_handle = |
574 | gtk_get_portal_request_path (connection: g_dbus_proxy_get_connection (proxy: portal->proxy), token: &token); |
575 | |
576 | portal->response_signal_id = |
577 | g_dbus_connection_signal_subscribe (connection: g_dbus_proxy_get_connection (G_DBUS_PROXY (portal->proxy)), |
578 | PORTAL_BUS_NAME, |
579 | PORTAL_REQUEST_INTERFACE, |
580 | member: "Response" , |
581 | object_path: portal->prepare_print_handle, |
582 | NULL, |
583 | flags: G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE, |
584 | callback: prepare_print_response, |
585 | user_data: portal, NULL); |
586 | |
587 | g_variant_builder_init (builder: &opt_builder, G_VARIANT_TYPE_VARDICT); |
588 | g_variant_builder_add (builder: &opt_builder, format_string: "{sv}" , "handle_token" , g_variant_new_string (string: token)); |
589 | g_free (mem: token); |
590 | portal->options = g_variant_builder_end (builder: &opt_builder); |
591 | |
592 | if (priv->print_settings) |
593 | portal->settings = gtk_print_settings_to_gvariant (settings: priv->print_settings); |
594 | else |
595 | { |
596 | GVariantBuilder builder; |
597 | g_variant_builder_init (builder: &builder, G_VARIANT_TYPE_VARDICT); |
598 | portal->settings = g_variant_builder_end (builder: &builder); |
599 | } |
600 | |
601 | if (priv->default_page_setup) |
602 | portal->setup = gtk_page_setup_to_gvariant (setup: priv->default_page_setup); |
603 | else |
604 | { |
605 | GtkPageSetup *page_setup = gtk_page_setup_new (); |
606 | portal->setup = gtk_page_setup_to_gvariant (setup: page_setup); |
607 | g_object_unref (object: page_setup); |
608 | } |
609 | |
610 | g_variant_ref_sink (value: portal->options); |
611 | g_variant_ref_sink (value: portal->settings); |
612 | g_variant_ref_sink (value: portal->setup); |
613 | |
614 | if (portal->parent != NULL && |
615 | gtk_widget_is_visible (GTK_WIDGET (portal->parent)) && |
616 | gtk_window_export_handle (window: portal->parent, callback: window_handle_exported, user_data: portal)) |
617 | return; |
618 | |
619 | g_dbus_proxy_call (proxy: portal->proxy, |
620 | method_name: "PreparePrint" , |
621 | parameters: g_variant_new (format_string: "(ss@a{sv}@a{sv}@a{sv})" , |
622 | "" , |
623 | _("Print" ), /* title */ |
624 | portal->settings, |
625 | portal->setup, |
626 | portal->options), |
627 | flags: G_DBUS_CALL_FLAGS_NONE, |
628 | timeout_msec: -1, |
629 | NULL, |
630 | callback: prepare_print_called, |
631 | user_data: portal); |
632 | } |
633 | |
634 | GtkPrintOperationResult |
635 | gtk_print_operation_portal_run_dialog (GtkPrintOperation *op, |
636 | gboolean show_dialog, |
637 | GtkWindow *parent, |
638 | gboolean *do_print) |
639 | { |
640 | PortalData *portal; |
641 | GtkPrintOperationResult result; |
642 | |
643 | portal = create_portal_data (op, parent, NULL); |
644 | if (portal == NULL) |
645 | return GTK_PRINT_OPERATION_RESULT_ERROR; |
646 | |
647 | call_prepare_print (op, portal); |
648 | |
649 | g_main_loop_run (loop: portal->loop); |
650 | |
651 | *do_print = portal->do_print; |
652 | result = portal->result; |
653 | |
654 | portal_data_free (data: portal); |
655 | |
656 | return result; |
657 | } |
658 | |
659 | void |
660 | gtk_print_operation_portal_run_dialog_async (GtkPrintOperation *op, |
661 | gboolean show_dialog, |
662 | GtkWindow *parent, |
663 | GtkPrintOperationPrintFunc print_cb) |
664 | { |
665 | PortalData *portal; |
666 | |
667 | portal = create_portal_data (op, parent, print_cb); |
668 | if (portal == NULL) |
669 | return; |
670 | |
671 | call_prepare_print (op, portal); |
672 | } |
673 | |
674 | void |
675 | gtk_print_operation_portal_launch_preview (GtkPrintOperation *op, |
676 | cairo_surface_t *surface, |
677 | GtkWindow *parent, |
678 | const char *filename) |
679 | { |
680 | char *uri; |
681 | |
682 | uri = g_filename_to_uri (filename, NULL, NULL); |
683 | gtk_show_uri (parent, uri, GDK_CURRENT_TIME); |
684 | g_free (mem: uri); |
685 | } |
686 | |