2
* Copyright © 2016 Red Hat, Inc
4
* This program is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU Lesser General Public
6
* License as published by the Free Software Foundation; either
7
* version 2 of the License, or (at your option) any later version.
9
* This library is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* Lesser General Public License for more details.
14
* You should have received a copy of the GNU Lesser General Public
15
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
18
* Matthias Clasen <mclasen@redhat.com>
28
#include <gtk/gtkunixprint.h>
31
#include <gio/gunixfdlist.h>
32
#include <gio/gunixinputstream.h>
33
#include <gio/gunixoutputstream.h>
35
#include "xdg-desktop-portal-dbus.h"
40
#include "externalwindow.h"
42
#include "gtkbackports.h"
46
GtkPageSetup *page_setup;
47
GtkPrintSettings *settings;
53
static GHashTable *print_params;
56
print_params_free (gpointer data)
58
PrintParams *params = data;
60
g_hash_table_remove (print_params, GUINT_TO_POINTER (params->token));
62
g_free (params->app_id);
63
g_object_unref (params->page_setup);
64
g_object_unref (params->settings);
65
g_object_unref (params->printer);
71
ensure_print_params (void)
76
print_params = g_hash_table_new (g_direct_hash, g_direct_equal);
80
print_params_timeout (gpointer data)
82
print_params_free (data);
83
g_debug ("Removing print params, now %d", g_hash_table_size (print_params));
84
return G_SOURCE_REMOVE;
88
print_params_new (const char *app_id,
89
GtkPageSetup *page_setup,
90
GtkPrintSettings *settings,
96
ensure_print_params ();
98
params = g_new0 (PrintParams, 1);
99
params->app_id = g_strdup (app_id);
100
params->page_setup = g_object_ref (page_setup);
101
params->settings = g_object_ref (settings);
102
params->printer = g_object_ref (printer);
106
} while (r == 0 || g_hash_table_lookup (print_params, GUINT_TO_POINTER (r)) != NULL);
109
g_hash_table_insert (print_params, GUINT_TO_POINTER (r), params);
111
g_debug ("Remembering print params for %s, token %u, now %d",
112
params->app_id, params->token,
113
g_hash_table_size (print_params));
115
params->timeout_id = g_timeout_add_seconds (300, print_params_timeout, params);
121
get_print_params (const char *app_id,
126
params = (PrintParams *)g_hash_table_lookup (print_params, GUINT_TO_POINTER (token));
130
if (strcmp (params->app_id, app_id) != 0)
133
g_source_remove (params->timeout_id);
134
g_hash_table_remove (print_params, GUINT_TO_POINTER (token));
141
GDBusMethodInvocation *invocation;
144
ExternalWindow *external_parent;
154
print_dialog_handle_free (gpointer data)
156
PrintDialogHandle *handle = data;
158
g_clear_object (&handle->external_parent);
159
g_object_unref (handle->request);
160
g_object_unref (handle->dialog);
167
print_dialog_handle_close (PrintDialogHandle *handle)
169
gtk_widget_destroy (handle->dialog);
170
print_dialog_handle_free (handle);
177
GtkPrintSettings *settings,
178
GtkPageSetup *page_setup,
182
g_autofree char *title = NULL;
183
#if !GTK_CHECK_VERSION (3, 22, 0)
184
g_autofree char *filename = NULL;
185
g_autoptr(GUnixInputStream) istream = NULL;
186
g_autoptr(GUnixOutputStream) ostream = NULL;
190
title = g_strdup_printf ("Document from %s", app_id);
192
job = gtk_print_job_new (title, printer, settings, page_setup);
194
#if GTK_CHECK_VERSION (3, 22, 0)
195
if (!gtk_print_job_set_source_fd (job, fd, error))
197
g_object_unref (job);
201
istream = g_unix_input_stream_new (fd, FALSE);
203
if ((fd2 = g_file_open_tmp (PACKAGE_NAME "XXXXXX", &filename, error)) == -1)
205
g_object_unref (job);
209
ostream = g_unix_output_stream_new (fd2, TRUE);
211
if (g_output_stream_splice (G_OUTPUT_STREAM (ostream),
212
G_INPUT_STREAM (istream),
213
G_OUTPUT_STREAM_SPLICE_NONE,
217
g_object_unref (job);
221
if (!gtk_print_job_set_source_file (job, filename, error))
223
g_object_unref (job);
227
/* The file will be removed when the GtkPrintJob closes it (once the job is
232
gtk_print_job_send (job, NULL, NULL, NULL);
233
g_object_unref (job);
239
handle_print_response (GtkDialog *dialog,
243
PrintDialogHandle *handle = data;
244
g_autoptr(GError) error = NULL;
249
g_warning ("Unexpected response: %d", response);
251
case GTK_RESPONSE_DELETE_EVENT:
252
handle->response = 2;
255
case GTK_RESPONSE_CANCEL:
256
handle->response = 1;
259
case GTK_RESPONSE_OK:
262
GtkPrintSettings *settings;
263
GtkPageSetup *page_setup;
265
printer = gtk_print_unix_dialog_get_selected_printer (GTK_PRINT_UNIX_DIALOG (handle->dialog));
266
settings = gtk_print_unix_dialog_get_settings (GTK_PRINT_UNIX_DIALOG (handle->dialog));
267
page_setup = gtk_print_unix_dialog_get_page_setup (GTK_PRINT_UNIX_DIALOG (handle->dialog));
269
if (!print_file (handle->fd,
270
handle->request->app_id,
275
handle->response = 2;
277
handle->response = 0;
279
g_object_unref (settings);
284
if (handle->request->exported)
285
request_unexport (handle->request);
289
g_dbus_method_invocation_take_error (handle->invocation, error);
293
GVariantBuilder opt_builder;
295
g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT);
296
xdp_impl_print_complete_print (handle->impl,
300
g_variant_builder_end (&opt_builder));
303
print_dialog_handle_close (handle);
307
handle_close (XdpImplRequest *object,
308
GDBusMethodInvocation *invocation,
309
PrintDialogHandle *handle)
311
GVariantBuilder opt_builder;
313
g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT);
314
xdp_impl_print_complete_print (handle->impl,
318
g_variant_builder_end (&opt_builder));
319
print_dialog_handle_close (handle);
321
if (handle->request->exported)
322
request_unexport (handle->request);
324
xdp_impl_request_complete_close (object, invocation);
330
handle_print (XdpImplPrint *object,
331
GDBusMethodInvocation *invocation,
332
GUnixFDList *fd_list,
333
const char *arg_handle,
334
const char *arg_app_id,
335
const char *arg_parent_window,
336
const char *arg_title,
338
GVariant *arg_options)
340
g_autoptr(Request) request = NULL;
343
PrintDialogHandle *handle;
350
ExternalWindow *external_parent = NULL;
351
GtkWidget *fake_parent;
353
g_variant_get (arg_fd_in, "h", &idx);
354
fd = g_unix_fd_list_get (fd_list, idx, NULL);
356
g_variant_lookup (arg_options, "token", "u", &token);
357
params = get_print_params (arg_app_id, token);
360
GVariantBuilder opt_builder;
369
print_params_free (params);
371
g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT);
372
xdp_impl_print_complete_print (object,
376
g_variant_builder_end (&opt_builder));
380
sender = g_dbus_method_invocation_get_sender (invocation);
381
request = request_new (sender, arg_app_id, arg_handle);
383
if (arg_parent_window)
385
external_parent = create_external_window_from_handle (arg_parent_window);
386
if (!external_parent)
387
g_warning ("Failed to associate portal window with parent window %s",
392
display = external_window_get_display (external_parent);
394
display = gdk_display_get_default ();
395
screen = gdk_display_get_default_screen (display);
397
fake_parent = g_object_new (GTK_TYPE_WINDOW,
398
"type", GTK_WINDOW_TOPLEVEL,
401
g_object_ref_sink (fake_parent);
403
if (!g_variant_lookup (arg_options, "modal", "b", &modal))
406
dialog = gtk_print_unix_dialog_new (arg_title, NULL);
407
gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (fake_parent));
408
gtk_window_set_modal (GTK_WINDOW (dialog), modal);
409
gtk_print_unix_dialog_set_manual_capabilities (GTK_PRINT_UNIX_DIALOG (dialog), 0);
411
handle = g_new0 (PrintDialogHandle, 1);
412
handle->impl = object;
413
handle->invocation = invocation;
414
handle->request = g_object_ref (request);
415
handle->dialog = g_object_ref (dialog);
416
handle->external_parent = external_parent;
419
g_signal_connect (request, "handle-close", G_CALLBACK (handle_close), handle);
421
g_signal_connect (dialog, "response", G_CALLBACK (handle_print_response), handle);
423
gtk_widget_realize (dialog);
426
external_window_set_parent_of (external_parent, gtk_widget_get_window (dialog));
428
request_export (request, g_dbus_method_invocation_get_connection (invocation));
430
gtk_widget_show (dialog);
436
send_prepare_print_response (PrintDialogHandle *handle)
438
GVariantBuilder opt_builder;
440
g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT);
442
if (handle->response == 0)
444
g_variant_builder_add (&opt_builder, "{sv}", "settings", gtk_print_settings_to_gvariant (handle->params->settings));
445
g_variant_builder_add (&opt_builder, "{sv}", "page-setup", gtk_page_setup_to_gvariant (handle->params->page_setup));
446
g_variant_builder_add (&opt_builder, "{sv}", "token", g_variant_new_uint32 (handle->params->token));
449
if (handle->request->exported)
450
request_unexport (handle->request);
452
xdp_impl_print_complete_prepare_print (handle->impl,
455
g_variant_builder_end (&opt_builder));
457
print_dialog_handle_close (handle);
461
handle_prepare_print_response (GtkDialog *dialog,
465
PrintDialogHandle *handle = data;
470
g_warning ("Unexpected response: %d", response);
472
case GTK_RESPONSE_DELETE_EVENT:
473
handle->response = 2;
476
case GTK_RESPONSE_CANCEL:
477
handle->response = 1;
480
case GTK_RESPONSE_OK:
482
handle->response = 0;
484
handle->params = print_params_new (handle->request->app_id,
485
gtk_print_unix_dialog_get_page_setup (GTK_PRINT_UNIX_DIALOG (handle->dialog)),
486
gtk_print_unix_dialog_get_settings (GTK_PRINT_UNIX_DIALOG (handle->dialog)),
487
gtk_print_unix_dialog_get_selected_printer (GTK_PRINT_UNIX_DIALOG (handle->dialog)));
492
send_prepare_print_response (handle);
496
handle_prepare_print (XdpImplPrint *object,
497
GDBusMethodInvocation *invocation,
498
const char *arg_handle,
499
const char *arg_app_id,
500
const char *arg_parent_window,
501
const char *arg_title,
502
GVariant *arg_settings,
503
GVariant *arg_page_setup,
504
GVariant *arg_options)
506
g_autoptr(Request) request = NULL;
509
PrintDialogHandle *handle;
510
GtkPrintSettings *settings;
511
GtkPageSetup *page_setup;
515
ExternalWindow *external_parent = NULL;
516
GtkWidget *fake_parent;
518
sender = g_dbus_method_invocation_get_sender (invocation);
520
request = request_new (sender, arg_app_id, arg_handle);
522
if (arg_parent_window)
524
external_parent = create_external_window_from_handle (arg_parent_window);
525
if (!external_parent)
526
g_warning ("Failed to associate portal window with parent window %s",
531
display = external_window_get_display (external_parent);
533
display = gdk_display_get_default ();
534
screen = gdk_display_get_default_screen (display);
536
fake_parent = g_object_new (GTK_TYPE_WINDOW,
537
"type", GTK_WINDOW_TOPLEVEL,
540
g_object_ref_sink (fake_parent);
542
settings = gtk_print_settings_new_from_gvariant (arg_settings);
543
page_setup = gtk_page_setup_new_from_gvariant (arg_page_setup);
544
if (!g_variant_lookup (arg_options, "modal", "b", &modal))
547
dialog = gtk_print_unix_dialog_new (arg_title, NULL);
548
gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (fake_parent));
549
gtk_window_set_modal (GTK_WINDOW (dialog), modal);
550
gtk_print_unix_dialog_set_manual_capabilities (GTK_PRINT_UNIX_DIALOG (dialog), 0);
551
gtk_print_unix_dialog_set_embed_page_setup (GTK_PRINT_UNIX_DIALOG (dialog), TRUE);
552
gtk_print_unix_dialog_set_settings (GTK_PRINT_UNIX_DIALOG (dialog), settings);
553
gtk_print_unix_dialog_set_page_setup (GTK_PRINT_UNIX_DIALOG (dialog), page_setup);
555
g_object_unref (settings);
556
g_object_unref (page_setup);
558
handle = g_new0 (PrintDialogHandle, 1);
559
handle->impl = object;
560
handle->invocation = invocation;
561
handle->request = g_object_ref (request);
562
handle->dialog = g_object_ref (dialog);
563
handle->external_parent = external_parent;
565
g_signal_connect (request, "handle-close", G_CALLBACK (handle_close), handle);
567
g_signal_connect (dialog, "response", G_CALLBACK (handle_prepare_print_response), handle);
569
gtk_widget_realize (dialog);
572
external_window_set_parent_of (external_parent, gtk_widget_get_window (dialog));
574
gtk_widget_show (dialog);
576
request_export (request, g_dbus_method_invocation_get_connection (invocation));
582
print_init (GDBusConnection *bus,
585
GDBusInterfaceSkeleton *helper;
587
helper = G_DBUS_INTERFACE_SKELETON (xdp_impl_print_skeleton_new ());
589
g_signal_connect (helper, "handle-print", G_CALLBACK (handle_print), NULL);
590
g_signal_connect (helper, "handle-prepare-print", G_CALLBACK (handle_prepare_print), NULL);
592
if (!g_dbus_interface_skeleton_export (helper,
594
DESKTOP_PORTAL_OBJECT_PATH,
598
g_debug ("providing %s", g_dbus_interface_skeleton_get_info (helper)->name);