Bug Summary

File:ctk/ctkprintoperation-portal.c
Warning:line 592, column 41
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ctkprintoperation-portal.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/ctk -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I .. -D G_LOG_DOMAIN="Ctk" -D G_LOG_USE_STRUCTURED=1 -D CTK_VERSION="3.25.5" -D CTK_BINARY_VERSION="3.0.0" -D CTK_COMPILATION -D CTK_PRINT_BACKEND_ENABLE_UNSUPPORTED -D CTK_LIBDIR="/usr/lib" -D CTK_LOCALEDIR="/usr/share/locale" -D CTK_DATADIR="/usr/share" -D CTK_DATA_PREFIX="/usr" -D CTK_SYSCONFDIR="/usr/etc" -D CTK_HOST="x86_64-pc-linux-gnu" -D CTK_PRINT_BACKENDS="file,cups" -D X11_DATA_PREFIX="/usr" -D ISO_CODES_PREFIX="" -I .. -I ../ctk -I .. -I ../cdk -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -D G_ENABLE_DEBUG -D G_ENABLE_CONSISTENCY_CHECKS -D GLIB_MIN_REQUIRED_VERSION=GLIB_VERSION_2_66 -D GLIB_MAX_ALLOWED_VERSION=GLIB_VERSION_2_66 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/atk-1.0 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gio-unix-2.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/pango-1.0 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/ctk -ferror-limit 19 -fvisibility=hidden -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-09-19-172619-43637-1 -x c ctkprintoperation-portal.c
1/* CTK - The GIMP Toolkit
2 * ctkprintoperation-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 "ctkprintoperation-private.h"
33#include "ctkprintoperation-portal.h"
34#include "ctkprintsettings.h"
35#include "ctkpagesetup.h"
36#include "ctkprintbackend.h"
37#include "ctkshow.h"
38#include "ctkintl.h"
39#include "ctkwindowprivate.h"
40#include "ctkprivate.h"
41
42
43typedef struct {
44 CtkPrintOperation *op;
45 GDBusProxy *proxy;
46 guint response_signal_id;
47 gboolean do_print;
48 CtkPrintOperationResult result;
49 CtkPrintOperationPrintFunc print_cb;
50 CtkWindow *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
60static void
61portal_data_free (gpointer data)
62{
63 PortalData *portal = data;
64
65 g_object_unref (portal->op);
66 g_object_unref (portal->proxy);
67 if (portal->loop)
68 g_main_loop_unref (portal->loop);
69 if (portal->settings)
70 g_variant_unref (portal->settings);
71 if (portal->setup)
72 g_variant_unref (portal->setup);
73 if (portal->options)
74 g_variant_unref (portal->options);
75 g_free (portal->prepare_print_handle);
76 g_free (portal);
77}
78
79typedef struct {
80 GDBusProxy *proxy;
81 CtkPrintJob *job;
82 guint32 token;
83 cairo_surface_t *surface;
84 GMainLoop *loop;
85 gboolean file_written;
86} CtkPrintOperationPortal;
87
88static void
89op_portal_free (CtkPrintOperationPortal *op_portal)
90{
91 g_clear_object (&op_portal->proxy)do { _Static_assert (sizeof *((&op_portal->proxy)) == sizeof
(gpointer), "Expression evaluates to false"); __typeof__ (((
&op_portal->proxy))) _pp = ((&op_portal->proxy)
); __typeof__ (*((&op_portal->proxy))) _ptr = *_pp; *_pp
= ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while (0)
;
92 g_clear_object (&op_portal->job)do { _Static_assert (sizeof *((&op_portal->job)) == sizeof
(gpointer), "Expression evaluates to false"); __typeof__ (((
&op_portal->job))) _pp = ((&op_portal->job)); __typeof__
(*((&op_portal->job))) _ptr = *_pp; *_pp = ((void*)0)
; if (_ptr) (g_object_unref) (_ptr); } while (0)
;
93 if (op_portal->loop)
94 g_main_loop_unref (op_portal->loop);
95 g_free (op_portal);
96}
97
98static void
99portal_start_page (CtkPrintOperation *op,
100 CtkPrintContext *print_context G_GNUC_UNUSED__attribute__ ((__unused__)),
101 CtkPageSetup *page_setup)
102{
103 CtkPrintOperationPortal *op_portal = op->priv->platform_data;
104 CtkPaperSize *paper_size;
105 cairo_surface_type_t type;
106 gdouble w, h;
107
108 paper_size = ctk_page_setup_get_paper_size (page_setup);
109
110 w = ctk_paper_size_get_width (paper_size, CTK_UNIT_POINTS);
111 h = ctk_paper_size_get_height (paper_size, CTK_UNIT_POINTS);
112
113 type = cairo_surface_get_type (op_portal->surface);
114
115 if ((op->priv->manual_number_up < 2) ||
116 (op->priv->page_position % op->priv->manual_number_up == 0))
117 {
118 if (type == CAIRO_SURFACE_TYPE_PS)
119 {
120 cairo_ps_surface_set_size (op_portal->surface, w, h);
121 cairo_ps_surface_dsc_begin_page_setup (op_portal->surface);
122 switch (ctk_page_setup_get_orientation (page_setup))
123 {
124 case CTK_PAGE_ORIENTATION_PORTRAIT:
125 case CTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
126 cairo_ps_surface_dsc_comment (op_portal->surface, "%%PageOrientation: Portrait");
127 break;
128
129 case CTK_PAGE_ORIENTATION_LANDSCAPE:
130 case CTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
131 cairo_ps_surface_dsc_comment (op_portal->surface, "%%PageOrientation: Landscape");
132 break;
133 }
134 }
135 else if (type == CAIRO_SURFACE_TYPE_PDF)
136 {
137 if (!op->priv->manual_orientation)
138 {
139 w = ctk_page_setup_get_paper_width (page_setup, CTK_UNIT_POINTS);
140 h = ctk_page_setup_get_paper_height (page_setup, CTK_UNIT_POINTS);
141 }
142 cairo_pdf_surface_set_size (op_portal->surface, w, h);
143 }
144 }
145}
146
147static void
148portal_end_page (CtkPrintOperation *op,
149 CtkPrintContext *print_context)
150{
151 cairo_t *cr;
152
153 cr = ctk_print_context_get_cairo_context (print_context);
154
155 if ((op->priv->manual_number_up < 2) ||
156 ((op->priv->page_position + 1) % op->priv->manual_number_up == 0) ||
157 (op->priv->page_position == op->priv->nr_of_pages_to_print - 1))
158 cairo_show_page (cr);
159}
160
161static void
162print_file_done (GObject *source G_GNUC_UNUSED__attribute__ ((__unused__)),
163 GAsyncResult *result,
164 gpointer data)
165{
166 CtkPrintOperation *op = data;
167 CtkPrintOperationPortal *op_portal = op->priv->platform_data;
168 GError *error = NULL((void*)0);
169 GVariant *ret;
170
171 ret = g_dbus_proxy_call_finish (op_portal->proxy,
172 result,
173 &error);
174 if (ret == NULL((void*)0))
175 {
176 if (op->priv->error == NULL((void*)0))
177 op->priv->error = g_error_copy (error);
178 g_warning ("Print file failed: %s", error->message);
179 g_error_free (error);
180 }
181 else
182 g_variant_unref (ret);
183
184 if (op_portal->loop)
185 g_main_loop_quit (op_portal->loop);
186
187 g_object_unref (op);
188}
189
190static void
191portal_job_complete (CtkPrintJob *job,
192 gpointer data,
193 const GError *error)
194{
195 CtkPrintOperation *op = data;
196 CtkPrintOperationPortal *op_portal = op->priv->platform_data;
197 CtkPrintSettings *settings;
198 const char *uri;
199 char *filename;
200 int fd, idx;
201 GVariantBuilder opt_builder;
202 GUnixFDList *fd_list;
203
204 if (error != NULL((void*)0) && op->priv->error == NULL((void*)0))
205 {
206 g_warning ("Print job failed: %s", error->message);
207 op->priv->error = g_error_copy (error);
208 return;
209 }
210
211 op_portal->file_written = TRUE(!(0));
212
213 settings = ctk_print_job_get_settings (job);
214 uri = ctk_print_settings_get (settings, CTK_PRINT_SETTINGS_OUTPUT_URI"output-uri");
215 filename = g_filename_from_uri (uri, NULL((void*)0), NULL((void*)0));
216
217 fd = open (filename, O_RDONLY00|O_CLOEXEC02000000);
218 fd_list = g_unix_fd_list_new ();
219 idx = g_unix_fd_list_append (fd_list, fd, NULL((void*)0));
220 close (fd);
221
222 g_free (filename);
223
224 g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT((const GVariantType *) "a{sv}"));
225 g_variant_builder_add (&opt_builder, "{sv}", "token", g_variant_new_uint32 (op_portal->token));
226
227 g_dbus_proxy_call_with_unix_fd_list (op_portal->proxy,
228 "Print",
229 g_variant_new ("(ssh@a{sv})",
230 "", /* window */
231 _("Print")((char *) g_dgettext ("ctk30", "Print")), /* title */
232 idx,
233 g_variant_builder_end (&opt_builder)),
234 G_DBUS_CALL_FLAGS_NONE,
235 -1,
236 fd_list,
237 NULL((void*)0),
238 print_file_done,
239 op);
240 g_object_unref (fd_list);
241}
242
243static void
244portal_end_run (CtkPrintOperation *op,
245 gboolean wait,
246 gboolean cancelled)
247{
248 CtkPrintOperationPortal *op_portal = op->priv->platform_data;
249
250 cairo_surface_finish (op_portal->surface);
251
252 if (cancelled)
253 return;
254
255 if (wait)
256 op_portal->loop = g_main_loop_new (NULL((void*)0), FALSE(0));
257
258 /* TODO: Check for error */
259 if (op_portal->job != NULL((void*)0))
260 {
261 g_object_ref (op)((__typeof__ (op)) (g_object_ref) (op));
262 ctk_print_job_send (op_portal->job, portal_job_complete, op, NULL((void*)0));
263 }
264
265 if (wait)
266 {
267 g_object_ref (op)((__typeof__ (op)) (g_object_ref) (op));
268 if (!op_portal->file_written)
269 {
270 cdk_threads_leave ();
271 g_main_loop_run (op_portal->loop);
272 cdk_threads_enter ();
273 }
274 g_object_unref (op);
275 }
276}
277
278static void
279finish_print (PortalData *portal,
280 CtkPrinter *printer,
281 CtkPageSetup *page_setup,
282 CtkPrintSettings *settings)
283{
284 CtkPrintOperation *op = portal->op;
285 CtkPrintOperationPrivate *priv = op->priv;
286 CtkPrintJob *job;
287 CtkPrintOperationPortal *op_portal;
288 cairo_t *cr;
289
290 if (portal->do_print)
291 {
292 ctk_print_operation_set_print_settings (op, settings);
293 priv->print_context = _ctk_print_context_new (op);
294
295 _ctk_print_context_set_hard_margins (priv->print_context, 0, 0, 0, 0);
296
297 ctk_print_operation_set_default_page_setup (op, page_setup);
298 _ctk_print_context_set_page_setup (priv->print_context, page_setup);
299
300 op_portal = g_new0 (CtkPrintOperationPortal, 1)((CtkPrintOperationPortal *) g_malloc0_n ((1), sizeof (CtkPrintOperationPortal
)))
;
301 priv->platform_data = op_portal;
302 priv->free_platform_data = (GDestroyNotify) op_portal_free;
303
304 priv->start_page = portal_start_page;
305 priv->end_page = portal_end_page;
306 priv->end_run = portal_end_run;
307
308 job = ctk_print_job_new (priv->job_name, printer, settings, page_setup);
309 op_portal->job = job;
310
311 op_portal->proxy = g_object_ref (portal->proxy)((__typeof__ (portal->proxy)) (g_object_ref) (portal->proxy
))
;
312 op_portal->token = portal->token;
313
314 op_portal->surface = ctk_print_job_get_surface (job, &priv->error);
315 if (op_portal->surface == NULL((void*)0))
316 {
317 portal->result = CTK_PRINT_OPERATION_RESULT_ERROR;
318 portal->do_print = FALSE(0);
319 goto out;
320 }
321
322 cr = cairo_create (op_portal->surface);
323 ctk_print_context_set_cairo_context (priv->print_context, cr, 72, 72);
324 cairo_destroy (cr);
325
326 priv->print_pages = ctk_print_job_get_pages (job);
327 priv->page_ranges = ctk_print_job_get_page_ranges (job, &priv->num_page_ranges);
328 priv->manual_num_copies = ctk_print_job_get_num_copies (job);
329 priv->manual_collation = ctk_print_job_get_collate (job);
330 priv->manual_reverse = ctk_print_job_get_reverse (job);
331 priv->manual_page_set = ctk_print_job_get_page_set (job);
332 priv->manual_scale = ctk_print_job_get_scale (job);
333 priv->manual_orientation = ctk_print_job_get_rotate (job);
334 priv->manual_number_up = ctk_print_job_get_n_up (job);
335 priv->manual_number_up_layout = ctk_print_job_get_n_up_layout (job);
336 }
337
338out:
339 if (portal->print_cb)
340 portal->print_cb (op, portal->parent, portal->do_print, portal->result);
341
342 if (portal->destroy)
343 portal->destroy (portal);
344}
345
346static CtkPrinter *
347find_file_printer (void)
348{
349 GList *backends, *l, *printers;
350 CtkPrinter *printer;
351
352 printer = NULL((void*)0);
353
354 backends = ctk_print_backend_load_modules ();
355 for (l = backends; l; l = l->next)
356 {
357 CtkPrintBackend *backend = l->data;
358 if (strcmp (G_OBJECT_TYPE_NAME (backend)(g_type_name ((((((GTypeClass*) (((GTypeInstance*) (backend))
->g_class))->g_type)))))
, "CtkPrintBackendFile") == 0)
359 {
360 printers = ctk_print_backend_get_printer_list (backend);
361 printer = printers->data;
362 g_list_free (printers);
363 break;
364 }
365 }
366 g_list_free (backends);
367
368 return printer;
369}
370
371static void
372prepare_print_response (GDBusConnection *connection,
373 const char *sender_name G_GNUC_UNUSED__attribute__ ((__unused__)),
374 const char *object_path G_GNUC_UNUSED__attribute__ ((__unused__)),
375 const char *interface_name G_GNUC_UNUSED__attribute__ ((__unused__)),
376 const char *signal_name G_GNUC_UNUSED__attribute__ ((__unused__)),
377 GVariant *parameters,
378 gpointer data)
379{
380 PortalData *portal = data;
381 guint32 response;
382 GVariant *options;
383
384 if (portal->response_signal_id != 0)
385 {
386 g_dbus_connection_signal_unsubscribe (connection,
387 portal->response_signal_id);
388 portal->response_signal_id = 0;
389 }
390
391 g_variant_get (parameters, "(u@a{sv})", &response, &options);
392
393 portal->do_print = (response == 0);
394
395 if (portal->do_print)
396 {
397 GVariant *v;
398 CtkPrintSettings *settings;
399 CtkPageSetup *page_setup;
400 CtkPrinter *printer;
401 char *filename;
402 char *uri;
403 int fd;
404
405 portal->result = CTK_PRINT_OPERATION_RESULT_APPLY;
406
407 v = g_variant_lookup_value (options, "settings", G_VARIANT_TYPE_VARDICT((const GVariantType *) "a{sv}"));
408 settings = ctk_print_settings_new_from_gvariant (v);
409 g_variant_unref (v);
410
411 v = g_variant_lookup_value (options, "page-setup", G_VARIANT_TYPE_VARDICT((const GVariantType *) "a{sv}"));
412 page_setup = ctk_page_setup_new_from_gvariant (v);
413 g_variant_unref (v);
414
415 g_variant_lookup (options, "token", "u", &portal->token);
416
417 printer = find_file_printer ();
418
419 fd = g_file_open_tmp ("ctkprintXXXXXX", &filename, NULL((void*)0));
420 uri = g_filename_to_uri (filename, NULL((void*)0), NULL((void*)0));
421 ctk_print_settings_set (settings, CTK_PRINT_SETTINGS_OUTPUT_URI"output-uri", uri);
422 g_free (uri);
423 close (fd);
424
425 finish_print (portal, printer, page_setup, settings);
426 g_free (filename);
427 }
428 else
429 {
430 portal->result = CTK_PRINT_OPERATION_RESULT_CANCEL;
431
432 if (portal->print_cb)
433 portal->print_cb (portal->op, portal->parent, portal->do_print, portal->result);
434
435 if (portal->destroy)
436 portal->destroy (portal);
437 }
438 if (portal->loop)
439 g_main_loop_quit (portal->loop);
440}
441
442static void
443prepare_print_called (GObject *source G_GNUC_UNUSED__attribute__ ((__unused__)),
444 GAsyncResult *result,
445 gpointer data)
446{
447 PortalData *portal = data;
448 GError *error = NULL((void*)0);
449 const char *handle = NULL((void*)0);
450 GVariant *ret;
451
452 ret = g_dbus_proxy_call_finish (portal->proxy, result, &error);
453 if (ret == NULL((void*)0))
454 {
455 if (portal->op->priv->error == NULL((void*)0))
456 portal->op->priv->error = g_error_copy (error);
457 g_error_free (error);
458 if (portal->loop)
459 g_main_loop_quit (portal->loop);
460 return;
461 }
462 else
463 g_variant_get (ret, "(&o)", &handle);
464
465 if (strcmp (portal->prepare_print_handle, handle) != 0)
466 {
467 g_free (portal->prepare_print_handle);
468 portal->prepare_print_handle = g_strdup (handle)g_strdup_inline (handle);
469 g_dbus_connection_signal_unsubscribe (g_dbus_proxy_get_connection (G_DBUS_PROXY (portal->proxy)((((GDBusProxy*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((portal->proxy)), ((g_dbus_proxy_get_type ()))))))
),
470 portal->response_signal_id);
471 portal->response_signal_id =
472 g_dbus_connection_signal_subscribe (g_dbus_proxy_get_connection (G_DBUS_PROXY (portal->proxy)((((GDBusProxy*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((portal->proxy)), ((g_dbus_proxy_get_type ()))))))
),
473 "org.freedesktop.portal.Desktop",
474 "org.freedesktop.portal.Request",
475 "Response",
476 handle,
477 NULL((void*)0),
478 G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
479 prepare_print_response,
480 portal, NULL((void*)0));
481 }
482
483 g_variant_unref (ret);
484}
485
486PortalData *
487create_portal_data (CtkPrintOperation *op,
488 CtkWindow *parent,
489 CtkPrintOperationPrintFunc print_cb)
490{
491 GDBusProxy *proxy;
492 PortalData *portal;
493 guint signal_id;
494 GError *error = NULL((void*)0);
495
496 signal_id = g_signal_lookup ("create-custom-widget", CTK_TYPE_PRINT_OPERATION(ctk_print_operation_get_type ()));
497 if (g_signal_has_handler_pending (op, signal_id, 0, TRUE(!(0))))
498 g_warning ("CtkPrintOperation::create-custom-widget not supported with portal");
499
500 proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
501 G_DBUS_PROXY_FLAGS_NONE,
502 NULL((void*)0),
503 "org.freedesktop.portal.Desktop",
504 "/org/freedesktop/portal/desktop",
505 "org.freedesktop.portal.Print",
506 NULL((void*)0),
507 &error);
508
509 if (proxy == NULL((void*)0))
510 {
511 if (op->priv->error == NULL((void*)0))
512 op->priv->error = g_error_copy (error);
513 g_error_free (error);
514 return NULL((void*)0);
515 }
516
517 portal = g_new0 (PortalData, 1)((PortalData *) g_malloc0_n ((1), sizeof (PortalData)));
518 portal->proxy = proxy;
519 portal->op = g_object_ref (op)((__typeof__ (op)) (g_object_ref) (op));
520 portal->parent = parent;
521 portal->result = CTK_PRINT_OPERATION_RESULT_CANCEL;
522 portal->print_cb = print_cb;
523
524 if (print_cb) /* async case */
525 {
526 portal->loop = NULL((void*)0);
527 portal->destroy = portal_data_free;
528 }
529 else
530 {
531 portal->loop = g_main_loop_new (NULL((void*)0), FALSE(0));
532 portal->destroy = NULL((void*)0);
533 }
534
535 return portal;
536}
537
538static void
539window_handle_exported (CtkWindow *window G_GNUC_UNUSED__attribute__ ((__unused__)),
540 const char *handle_str,
541 gpointer user_data)
542{
543 PortalData *portal = user_data;
544
545 g_dbus_proxy_call (portal->proxy,
546 "PreparePrint",
547 g_variant_new ("(ss@a{sv}@a{sv}@a{sv})",
548 handle_str,
549 _("Print")((char *) g_dgettext ("ctk30", "Print")), /* title */
550 portal->settings,
551 portal->setup,
552 portal->options),
553 G_DBUS_CALL_FLAGS_NONE,
554 -1,
555 NULL((void*)0),
556 prepare_print_called,
557 portal);
558}
559
560static void
561call_prepare_print (CtkPrintOperation *op,
562 PortalData *portal)
563{
564 CtkPrintOperationPrivate *priv = op->priv;
565 GVariantBuilder opt_builder;
566 char *token;
567
568 portal->prepare_print_handle =
569 ctk_get_portal_request_path (g_dbus_proxy_get_connection (portal->proxy), &token);
570
571 portal->response_signal_id =
572 g_dbus_connection_signal_subscribe (g_dbus_proxy_get_connection (G_DBUS_PROXY (portal->proxy)((((GDBusProxy*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((portal->proxy)), ((g_dbus_proxy_get_type ()))))))
),
573 "org.freedesktop.portal.Desktop",
574 "org.freedesktop.portal.Request",
575 "Response",
576 portal->prepare_print_handle,
577 NULL((void*)0),
578 G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
579 prepare_print_response,
580 portal, NULL((void*)0));
581
582 g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT((const GVariantType *) "a{sv}"));
583 g_variant_builder_add (&opt_builder, "{sv}", "handle_token", g_variant_new_string (token));
584 g_free (token);
585 portal->options = g_variant_builder_end (&opt_builder);
586
587 if (priv->print_settings)
588 portal->settings = ctk_print_settings_to_gvariant (priv->print_settings);
589 else
590 {
591 GVariantBuilder builder;
592 g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT((const GVariantType *) "a{sv}"));
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption
593 portal->settings = g_variant_builder_end (&builder);
594 }
595
596 if (priv->default_page_setup)
597 portal->setup = ctk_page_setup_to_gvariant (priv->default_page_setup);
598 else
599 {
600 CtkPageSetup *page_setup = ctk_page_setup_new ();
601 portal->setup = ctk_page_setup_to_gvariant (page_setup);
602 g_object_unref (page_setup);
603 }
604
605 g_variant_ref_sink (portal->options);
606 g_variant_ref_sink (portal->settings);
607 g_variant_ref_sink (portal->setup);
608
609 if (portal->parent != NULL((void*)0) &&
610 ctk_widget_is_visible (CTK_WIDGET (portal->parent)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((portal->parent)), ((ctk_widget_get_type ()))))))
) &&
611 ctk_window_export_handle (portal->parent, window_handle_exported, portal))
612 return;
613
614 g_dbus_proxy_call (portal->proxy,
615 "PreparePrint",
616 g_variant_new ("(ss@a{sv}@a{sv}@a{sv})",
617 "",
618 _("Print")((char *) g_dgettext ("ctk30", "Print")), /* title */
619 portal->settings,
620 portal->setup,
621 portal->options),
622 G_DBUS_CALL_FLAGS_NONE,
623 -1,
624 NULL((void*)0),
625 prepare_print_called,
626 portal);
627}
628
629CtkPrintOperationResult
630ctk_print_operation_portal_run_dialog (CtkPrintOperation *op,
631 gboolean show_dialog G_GNUC_UNUSED__attribute__ ((__unused__)),
632 CtkWindow *parent,
633 gboolean *do_print)
634{
635 PortalData *portal;
636 CtkPrintOperationResult result;
637
638 portal = create_portal_data (op, parent, NULL((void*)0));
639 if (portal == NULL((void*)0))
640 return CTK_PRINT_OPERATION_RESULT_ERROR;
641
642 call_prepare_print (op, portal);
643
644 cdk_threads_leave ();
645 g_main_loop_run (portal->loop);
646 cdk_threads_enter ();
647
648 *do_print = portal->do_print;
649 result = portal->result;
650
651 portal_data_free (portal);
652
653 return result;
654}
655
656void
657ctk_print_operation_portal_run_dialog_async (CtkPrintOperation *op,
658 gboolean show_dialog G_GNUC_UNUSED__attribute__ ((__unused__)),
659 CtkWindow *parent,
660 CtkPrintOperationPrintFunc print_cb)
661{
662 PortalData *portal;
663
664 portal = create_portal_data (op, parent, print_cb);
665 if (portal == NULL((void*)0))
666 return;
667
668 call_prepare_print (op, portal);
669}
670
671void
672ctk_print_operation_portal_launch_preview (CtkPrintOperation *op G_GNUC_UNUSED__attribute__ ((__unused__)),
673 cairo_surface_t *surface G_GNUC_UNUSED__attribute__ ((__unused__)),
674 CtkWindow *parent,
675 const char *filename)
676{
677 char *uri;
678
679 uri = g_filename_to_uri (filename, NULL((void*)0), NULL((void*)0));
680 ctk_show_uri_on_window (parent, uri, CDK_CURRENT_TIME0L, NULL((void*)0));
681 g_free (uri);
682}