683 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			683 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* GTK - The GIMP Toolkit
 | |
|  * gtkprintoperation-portal.c: Print Operation Details for sandboxed apps
 | |
|  * Copyright (C) 2016, Red Hat, Inc.
 | |
|  *
 | |
|  * This library is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU Lesser General Public
 | |
|  * License as published by the Free Software Foundation; either
 | |
|  * version 2 of the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This library is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|  * Lesser General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU Lesser General Public
 | |
|  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 | |
|  */
 | |
| 
 | |
| #include "config.h"
 | |
| 
 | |
| #include <string.h>
 | |
| 
 | |
| #include <sys/types.h>
 | |
| #include <sys/stat.h>
 | |
| #include <fcntl.h>
 | |
| 
 | |
| #include <cairo-pdf.h>
 | |
| #include <cairo-ps.h>
 | |
| 
 | |
| #include <gio/gunixfdlist.h>
 | |
| 
 | |
| #include "gtkprintoperation-private.h"
 | |
| #include "gtkprintoperation-portal.h"
 | |
| #include "gtkprintsettings.h"
 | |
| #include "gtkpagesetup.h"
 | |
| #include "gtkprintbackend.h"
 | |
| #include "gtkshow.h"
 | |
| #include "gtkintl.h"
 | |
| #include "gtkwindowprivate.h"
 | |
| #include "gtkprivate.h"
 | |
| 
 | |
| 
 | |
| typedef struct {
 | |
|   GtkPrintOperation *op;
 | |
|   GDBusProxy *proxy;
 | |
|   guint response_signal_id;
 | |
|   gboolean do_print;
 | |
|   GtkPrintOperationResult result;
 | |
|   GtkPrintOperationPrintFunc print_cb;
 | |
|   GtkWindow *parent;
 | |
|   GMainLoop *loop;
 | |
|   guint32 token;
 | |
|   GDestroyNotify destroy;
 | |
|   GVariant *settings;
 | |
|   GVariant *setup;
 | |
|   GVariant *options;
 | |
|   char *prepare_print_handle;
 | |
| } PortalData;
 | |
| 
 | |
| static void
 | |
| portal_data_free (gpointer data)
 | |
| {
 | |
|   PortalData *portal = data;
 | |
| 
 | |
|   g_object_unref (portal->op);
 | |
|   g_object_unref (portal->proxy);
 | |
|   if (portal->loop)
 | |
|     g_main_loop_unref (portal->loop);
 | |
|   if (portal->settings)
 | |
|     g_variant_unref (portal->settings);
 | |
|   if (portal->setup)
 | |
|     g_variant_unref (portal->setup);
 | |
|   if (portal->options)
 | |
|     g_variant_unref (portal->options);
 | |
|   g_free (portal->prepare_print_handle);
 | |
|   g_free (portal);
 | |
| }
 | |
| 
 | |
| typedef struct {
 | |
|   GDBusProxy *proxy;
 | |
|   GtkPrintJob *job;
 | |
|   guint32 token;
 | |
|   cairo_surface_t *surface;
 | |
|   GMainLoop *loop;
 | |
|   gboolean file_written;
 | |
| } GtkPrintOperationPortal;
 | |
| 
 | |
| static void
 | |
| op_portal_free (GtkPrintOperationPortal *op_portal)
 | |
| {
 | |
|   g_clear_object (&op_portal->proxy);
 | |
|   g_clear_object (&op_portal->job);
 | |
|   if (op_portal->loop)
 | |
|     g_main_loop_unref (op_portal->loop);
 | |
|   g_free (op_portal);
 | |
| }
 | |
| 
 | |
| static void
 | |
| portal_start_page (GtkPrintOperation *op,
 | |
|                    GtkPrintContext   *print_context,
 | |
|                    GtkPageSetup      *page_setup)
 | |
| {
 | |
|   GtkPrintOperationPortal *op_portal = op->priv->platform_data;
 | |
|   GtkPaperSize *paper_size;
 | |
|   cairo_surface_type_t type;
 | |
|   gdouble w, h;
 | |
| 
 | |
|   paper_size = gtk_page_setup_get_paper_size (page_setup);
 | |
| 
 | |
|   w = gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS);
 | |
|   h = gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS);
 | |
| 
 | |
|   type = cairo_surface_get_type (op_portal->surface);
 | |
| 
 | |
|   if ((op->priv->manual_number_up < 2) ||
 | |
|       (op->priv->page_position % op->priv->manual_number_up == 0))
 | |
|     {
 | |
|       if (type == CAIRO_SURFACE_TYPE_PS)
 | |
|         {
 | |
|           cairo_ps_surface_set_size (op_portal->surface, w, h);
 | |
|           cairo_ps_surface_dsc_begin_page_setup (op_portal->surface);
 | |
|           switch (gtk_page_setup_get_orientation (page_setup))
 | |
|             {
 | |
|               case GTK_PAGE_ORIENTATION_PORTRAIT:
 | |
|               case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
 | |
|                 cairo_ps_surface_dsc_comment (op_portal->surface, "%%PageOrientation: Portrait");
 | |
|                 break;
 | |
| 
 | |
|               case GTK_PAGE_ORIENTATION_LANDSCAPE:
 | |
|               case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
 | |
|                 cairo_ps_surface_dsc_comment (op_portal->surface, "%%PageOrientation: Landscape");
 | |
|                 break;
 | |
|             }
 | |
|          }
 | |
|       else if (type == CAIRO_SURFACE_TYPE_PDF)
 | |
|         {
 | |
|           if (!op->priv->manual_orientation)
 | |
|             {
 | |
|               w = gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_POINTS);
 | |
|               h = gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_POINTS);
 | |
|             }
 | |
|           cairo_pdf_surface_set_size (op_portal->surface, w, h);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| portal_end_page (GtkPrintOperation *op,
 | |
|                  GtkPrintContext   *print_context)
 | |
| {
 | |
|   cairo_t *cr;
 | |
| 
 | |
|   cr = gtk_print_context_get_cairo_context (print_context);
 | |
| 
 | |
|   if ((op->priv->manual_number_up < 2) ||
 | |
|       ((op->priv->page_position + 1) % op->priv->manual_number_up == 0) ||
 | |
|       (op->priv->page_position == op->priv->nr_of_pages_to_print - 1))
 | |
|     cairo_show_page (cr);
 | |
| }
 | |
| 
 | |
| static void
 | |
| print_file_done (GObject *source,
 | |
|                  GAsyncResult *result,
 | |
|                  gpointer data)
 | |
| {
 | |
|   GtkPrintOperation *op = data;
 | |
|   GtkPrintOperationPortal *op_portal = op->priv->platform_data;
 | |
|   GError *error = NULL;
 | |
|   GVariant *ret;
 | |
| 
 | |
|   ret = g_dbus_proxy_call_finish (op_portal->proxy,
 | |
|                                   result,
 | |
|                                   &error);
 | |
|   if (ret == NULL)
 | |
|     {
 | |
|       if (op->priv->error == NULL)
 | |
|         op->priv->error = g_error_copy (error);
 | |
|       g_warning ("Print file failed: %s", error->message);
 | |
|       g_error_free (error);
 | |
|     }
 | |
|   else
 | |
|     g_variant_unref (ret);
 | |
| 
 | |
|   if (op_portal->loop)
 | |
|     g_main_loop_quit (op_portal->loop);
 | |
| 
 | |
|   g_object_unref (op);
 | |
| }
 | |
| 
 | |
| static void
 | |
| portal_job_complete (GtkPrintJob  *job,
 | |
|                      gpointer      data,
 | |
|                      const GError *error)
 | |
| {
 | |
|   GtkPrintOperation *op = data;
 | |
|   GtkPrintOperationPortal *op_portal = op->priv->platform_data;
 | |
|   GtkPrintSettings *settings;
 | |
|   const char *uri;
 | |
|   char *filename;
 | |
|   int fd, idx;
 | |
|   GVariantBuilder opt_builder;
 | |
|   GUnixFDList *fd_list;
 | |
| 
 | |
|   if (error != NULL && op->priv->error == NULL)
 | |
|     {
 | |
|       g_warning ("Print job failed: %s", error->message);
 | |
|       op->priv->error = g_error_copy (error);
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   op_portal->file_written = TRUE;
 | |
| 
 | |
|   settings = gtk_print_job_get_settings (job);
 | |
|   uri = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_OUTPUT_URI);
 | |
|   filename = g_filename_from_uri (uri, NULL, NULL);
 | |
| 
 | |
|   fd = open (filename, O_RDONLY|O_CLOEXEC);
 | |
|   fd_list = g_unix_fd_list_new ();
 | |
|   idx = g_unix_fd_list_append (fd_list, fd, NULL);
 | |
|   close (fd);
 | |
| 
 | |
|   g_free (filename);
 | |
| 
 | |
|   g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT);
 | |
|   g_variant_builder_add (&opt_builder, "{sv}",  "token", g_variant_new_uint32 (op_portal->token));
 | |
| 
 | |
|   g_dbus_proxy_call_with_unix_fd_list (op_portal->proxy,
 | |
|                                        "Print",
 | |
|                                        g_variant_new ("(ssh@a{sv})",
 | |
|                                                       "", /* window */
 | |
|                                                       _("Print"), /* title */
 | |
|                                                       idx,
 | |
|                                                       g_variant_builder_end (&opt_builder)),
 | |
|                                        G_DBUS_CALL_FLAGS_NONE,
 | |
|                                        -1,
 | |
|                                        fd_list,
 | |
|                                        NULL,
 | |
|                                        print_file_done,
 | |
|                                        op);
 | |
|   g_object_unref (fd_list);
 | |
| }
 | |
| 
 | |
| static void
 | |
| portal_end_run (GtkPrintOperation *op,
 | |
|                 gboolean           wait,
 | |
|                 gboolean           cancelled)
 | |
| {
 | |
|   GtkPrintOperationPortal *op_portal = op->priv->platform_data;
 | |
| 
 | |
|   cairo_surface_finish (op_portal->surface);
 | |
| 
 | |
|   if (cancelled)
 | |
|     return;
 | |
| 
 | |
|   if (wait)
 | |
|     op_portal->loop = g_main_loop_new (NULL, FALSE);
 | |
| 
 | |
|   /* TODO: Check for error */
 | |
|   if (op_portal->job != NULL)
 | |
|     {
 | |
|       g_object_ref (op);
 | |
|       gtk_print_job_send (op_portal->job, portal_job_complete, op, NULL);
 | |
|     }
 | |
| 
 | |
|   if (wait)
 | |
|     {
 | |
|       g_object_ref (op);
 | |
|       if (!op_portal->file_written)
 | |
|         {
 | |
|           gdk_threads_leave ();
 | |
|           g_main_loop_run (op_portal->loop);
 | |
|           gdk_threads_enter ();
 | |
|         }
 | |
|       g_object_unref (op);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| finish_print (PortalData        *portal,
 | |
|               GtkPrinter        *printer,
 | |
|               GtkPageSetup      *page_setup,
 | |
|               GtkPrintSettings  *settings)
 | |
| {
 | |
|   GtkPrintOperation *op = portal->op;
 | |
|   GtkPrintOperationPrivate *priv = op->priv;
 | |
|   GtkPrintJob *job;
 | |
|   GtkPrintOperationPortal *op_portal;
 | |
|   cairo_t *cr;
 | |
| 
 | |
|   if (portal->do_print)
 | |
|     {
 | |
|       gtk_print_operation_set_print_settings (op, settings);
 | |
|       priv->print_context = _gtk_print_context_new (op);
 | |
| 
 | |
|       _gtk_print_context_set_hard_margins (priv->print_context, 0, 0, 0, 0);
 | |
| 
 | |
|       gtk_print_operation_set_default_page_setup (op, page_setup);
 | |
|       _gtk_print_context_set_page_setup (priv->print_context, page_setup);
 | |
| 
 | |
|       op_portal = g_new0 (GtkPrintOperationPortal, 1);
 | |
|       priv->platform_data = op_portal;
 | |
|       priv->free_platform_data = (GDestroyNotify) op_portal_free;
 | |
| 
 | |
|       priv->start_page = portal_start_page;
 | |
|       priv->end_page = portal_end_page;
 | |
|       priv->end_run = portal_end_run;
 | |
| 
 | |
|       job = gtk_print_job_new (priv->job_name, printer, settings, page_setup);
 | |
|       op_portal->job = job;
 | |
| 
 | |
|       op_portal->proxy = g_object_ref (portal->proxy);
 | |
|       op_portal->token = portal->token;
 | |
| 
 | |
|       op_portal->surface = gtk_print_job_get_surface (job, &priv->error);
 | |
|       if (op_portal->surface == NULL)
 | |
|         {
 | |
|           portal->result = GTK_PRINT_OPERATION_RESULT_ERROR;
 | |
|           portal->do_print = FALSE;
 | |
|           goto out;
 | |
|         }
 | |
| 
 | |
|       cr = cairo_create (op_portal->surface);
 | |
|       gtk_print_context_set_cairo_context (priv->print_context, cr, 72, 72);
 | |
|       cairo_destroy (cr);
 | |
| 
 | |
|       priv->print_pages = gtk_print_job_get_pages (job);
 | |
|       priv->page_ranges = gtk_print_job_get_page_ranges (job, &priv->num_page_ranges);
 | |
|       priv->manual_num_copies = gtk_print_job_get_num_copies (job);
 | |
|       priv->manual_collation = gtk_print_job_get_collate (job);
 | |
|       priv->manual_reverse = gtk_print_job_get_reverse (job);
 | |
|       priv->manual_page_set = gtk_print_job_get_page_set (job);
 | |
|       priv->manual_scale = gtk_print_job_get_scale (job);
 | |
|       priv->manual_orientation = gtk_print_job_get_rotate (job);
 | |
|       priv->manual_number_up = gtk_print_job_get_n_up (job);
 | |
|       priv->manual_number_up_layout = gtk_print_job_get_n_up_layout (job);
 | |
|     }
 | |
| 
 | |
| out:
 | |
|   if (portal->print_cb)
 | |
|     portal->print_cb (op, portal->parent, portal->do_print, portal->result);
 | |
| 
 | |
|   if (portal->destroy)
 | |
|     portal->destroy (portal);
 | |
| }
 | |
| 
 | |
| static GtkPrinter *
 | |
| find_file_printer (void)
 | |
| {
 | |
|   GList *backends, *l, *printers;
 | |
|   GtkPrinter *printer;
 | |
| 
 | |
|   printer = NULL;
 | |
| 
 | |
|   backends = gtk_print_backend_load_modules ();
 | |
|   for (l = backends; l; l = l->next)
 | |
|     {
 | |
|       GtkPrintBackend *backend = l->data;
 | |
|       if (strcmp (G_OBJECT_TYPE_NAME (backend), "GtkPrintBackendFile") == 0)
 | |
|         {
 | |
|           printers = gtk_print_backend_get_printer_list (backend);
 | |
|           printer = printers->data;
 | |
|           g_list_free (printers);
 | |
|           break;
 | |
|         }
 | |
|     }
 | |
|   g_list_free (backends);
 | |
| 
 | |
|   return printer;
 | |
| }
 | |
| 
 | |
| static void
 | |
| prepare_print_response (GDBusConnection *connection,
 | |
|                         const char      *sender_name,
 | |
|                         const char      *object_path,
 | |
|                         const char      *interface_name,
 | |
|                         const char      *signal_name,
 | |
|                         GVariant        *parameters,
 | |
|                         gpointer         data)
 | |
| {
 | |
|   PortalData *portal = data;
 | |
|   guint32 response;
 | |
|   GVariant *options;
 | |
| 
 | |
|   if (portal->response_signal_id != 0)
 | |
|     {
 | |
|       g_dbus_connection_signal_unsubscribe (connection,
 | |
|                                             portal->response_signal_id);
 | |
|       portal->response_signal_id = 0;
 | |
|     }
 | |
| 
 | |
|   g_variant_get (parameters, "(u@a{sv})", &response, &options);
 | |
| 
 | |
|   portal->do_print = (response == 0);
 | |
| 
 | |
|   if (portal->do_print)
 | |
|     {
 | |
|       GVariant *v;
 | |
|       GtkPrintSettings *settings;
 | |
|       GtkPageSetup *page_setup;
 | |
|       GtkPrinter *printer;
 | |
|       char *filename;
 | |
|       char *uri;
 | |
|       int fd;
 | |
| 
 | |
|       portal->result = GTK_PRINT_OPERATION_RESULT_APPLY;
 | |
| 
 | |
|       v = g_variant_lookup_value (options, "settings", G_VARIANT_TYPE_VARDICT);
 | |
|       settings = gtk_print_settings_new_from_gvariant (v);
 | |
|       g_variant_unref (v);
 | |
| 
 | |
|       v = g_variant_lookup_value (options, "page-setup", G_VARIANT_TYPE_VARDICT);
 | |
|       page_setup = gtk_page_setup_new_from_gvariant (v);
 | |
|       g_variant_unref (v);
 | |
| 
 | |
|       g_variant_lookup (options, "token", "u", &portal->token);
 | |
| 
 | |
|       printer = find_file_printer ();
 | |
| 
 | |
|       fd = g_file_open_tmp ("gtkprintXXXXXX", &filename, NULL);
 | |
|       uri = g_filename_to_uri (filename, NULL, NULL);
 | |
|       gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_OUTPUT_URI, uri);
 | |
|       g_free (uri);
 | |
|       close (fd);
 | |
| 
 | |
|       finish_print (portal, printer, page_setup, settings);
 | |
|       g_free (filename);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       portal->result = GTK_PRINT_OPERATION_RESULT_CANCEL;
 | |
| 
 | |
|       if (portal->print_cb)
 | |
| 	  portal->print_cb (portal->op, portal->parent, portal->do_print, portal->result);
 | |
| 
 | |
|       if (portal->destroy)
 | |
| 	  portal->destroy (portal);
 | |
|     }
 | |
|   if (portal->loop)
 | |
|     g_main_loop_quit (portal->loop);
 | |
| }
 | |
| 
 | |
| static void
 | |
| prepare_print_called (GObject      *source,
 | |
|                       GAsyncResult *result,
 | |
|                       gpointer      data)
 | |
| {
 | |
|   PortalData *portal = data;
 | |
|   GError *error = NULL;
 | |
|   const char *handle = NULL;
 | |
|   GVariant *ret;
 | |
| 
 | |
|   ret = g_dbus_proxy_call_finish (portal->proxy, result, &error);
 | |
|   if (ret == NULL)
 | |
|     {
 | |
|       if (portal->op->priv->error == NULL)
 | |
|         portal->op->priv->error = g_error_copy (error);
 | |
|       g_error_free (error);
 | |
|       if (portal->loop)
 | |
|         g_main_loop_quit (portal->loop);
 | |
|       return;
 | |
|     }
 | |
|   else
 | |
|     g_variant_get (ret, "(&o)", &handle);
 | |
| 
 | |
|   if (strcmp (portal->prepare_print_handle, handle) != 0)
 | |
|     {
 | |
|       g_free (portal->prepare_print_handle);
 | |
|       portal->prepare_print_handle = g_strdup (handle);
 | |
|       g_dbus_connection_signal_unsubscribe (g_dbus_proxy_get_connection (G_DBUS_PROXY (portal->proxy)),
 | |
|                                             portal->response_signal_id);
 | |
|       portal->response_signal_id =
 | |
|         g_dbus_connection_signal_subscribe (g_dbus_proxy_get_connection (G_DBUS_PROXY (portal->proxy)),
 | |
|                                             "org.freedesktop.portal.Desktop",
 | |
|                                             "org.freedesktop.portal.Request",
 | |
|                                             "Response",
 | |
|                                             handle,
 | |
|                                             NULL,
 | |
|                                             G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
 | |
|                                             prepare_print_response,
 | |
|                                             portal, NULL);
 | |
|      }
 | |
| 
 | |
|   g_variant_unref (ret);
 | |
| }
 | |
| 
 | |
| PortalData *
 | |
| create_portal_data (GtkPrintOperation          *op,
 | |
|                     GtkWindow                  *parent,
 | |
|                     GtkPrintOperationPrintFunc  print_cb)
 | |
| {
 | |
|   GDBusProxy *proxy;
 | |
|   PortalData *portal;
 | |
|   guint signal_id;
 | |
|   GError *error = NULL;
 | |
| 
 | |
|   signal_id = g_signal_lookup ("create-custom-widget", GTK_TYPE_PRINT_OPERATION);
 | |
|   if (g_signal_has_handler_pending (op, signal_id, 0, TRUE))
 | |
|     g_warning ("GtkPrintOperation::create-custom-widget not supported with portal");
 | |
| 
 | |
|   proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
 | |
|                                          G_DBUS_PROXY_FLAGS_NONE,
 | |
|                                          NULL,
 | |
|                                          "org.freedesktop.portal.Desktop",
 | |
|                                          "/org/freedesktop/portal/desktop",
 | |
|                                          "org.freedesktop.portal.Print",
 | |
|                                          NULL,
 | |
|                                          &error);
 | |
| 
 | |
|   if (proxy == NULL)
 | |
|     {
 | |
|       if (op->priv->error == NULL)
 | |
|         op->priv->error = g_error_copy (error);
 | |
|       g_error_free (error);
 | |
|       return NULL;
 | |
|     }
 | |
| 
 | |
|   portal = g_new0 (PortalData, 1);
 | |
|   portal->proxy = proxy;
 | |
|   portal->op = g_object_ref (op);
 | |
|   portal->parent = parent;
 | |
|   portal->result = GTK_PRINT_OPERATION_RESULT_CANCEL;
 | |
|   portal->print_cb = print_cb;
 | |
| 
 | |
|   if (print_cb) /* async case */
 | |
|     {
 | |
|       portal->loop = NULL;
 | |
|       portal->destroy = portal_data_free;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       portal->loop = g_main_loop_new (NULL, FALSE);
 | |
|       portal->destroy = NULL;
 | |
|     }
 | |
| 
 | |
|   return portal;
 | |
| }
 | |
| 
 | |
| static void
 | |
| window_handle_exported (GtkWindow  *window,
 | |
|                         const char *handle_str,
 | |
|                         gpointer    user_data)
 | |
| {
 | |
|   PortalData *portal = user_data;
 | |
| 
 | |
|   g_dbus_proxy_call (portal->proxy,
 | |
|                      "PreparePrint",
 | |
|                      g_variant_new ("(ss@a{sv}@a{sv}@a{sv})",
 | |
|                                     handle_str,
 | |
|                                     _("Print"), /* title */
 | |
|                                     portal->settings,
 | |
|                                     portal->setup,
 | |
|                                     portal->options),
 | |
|                      G_DBUS_CALL_FLAGS_NONE,
 | |
|                      -1,
 | |
|                      NULL,
 | |
|                      prepare_print_called,
 | |
|                      portal);
 | |
| }
 | |
| 
 | |
| static void
 | |
| call_prepare_print (GtkPrintOperation *op,
 | |
|                     PortalData        *portal)
 | |
| {
 | |
|   GtkPrintOperationPrivate *priv = op->priv;
 | |
|   GVariantBuilder opt_builder;
 | |
|   char *token;
 | |
| 
 | |
|   portal->prepare_print_handle =
 | |
|       gtk_get_portal_request_path (g_dbus_proxy_get_connection (portal->proxy), &token);
 | |
| 
 | |
|   portal->response_signal_id =
 | |
|     g_dbus_connection_signal_subscribe (g_dbus_proxy_get_connection (G_DBUS_PROXY (portal->proxy)),
 | |
|                                         "org.freedesktop.portal.Desktop",
 | |
|                                         "org.freedesktop.portal.Request",
 | |
|                                         "Response",
 | |
|                                         portal->prepare_print_handle,
 | |
|                                         NULL,
 | |
|                                         G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
 | |
|                                         prepare_print_response,
 | |
|                                         portal, NULL);
 | |
| 
 | |
|   g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT);
 | |
|   g_variant_builder_add (&opt_builder, "{sv}", "handle_token", g_variant_new_string (token));
 | |
|   g_free (token);
 | |
|   portal->options = g_variant_builder_end (&opt_builder);
 | |
| 
 | |
|   if (priv->print_settings)
 | |
|     portal->settings = gtk_print_settings_to_gvariant (priv->print_settings);
 | |
|   else
 | |
|     {
 | |
|       GVariantBuilder builder;
 | |
|       g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
 | |
|       portal->settings = g_variant_builder_end (&builder);
 | |
|     }
 | |
| 
 | |
|   if (priv->default_page_setup)
 | |
|     portal->setup = gtk_page_setup_to_gvariant (priv->default_page_setup);
 | |
|   else
 | |
|     {
 | |
|       GtkPageSetup *page_setup = gtk_page_setup_new ();
 | |
|       portal->setup = gtk_page_setup_to_gvariant (page_setup);
 | |
|       g_object_unref (page_setup);
 | |
|     }
 | |
| 
 | |
|   g_variant_ref_sink (portal->options);
 | |
|   g_variant_ref_sink (portal->settings);
 | |
|   g_variant_ref_sink (portal->setup);
 | |
| 
 | |
|   if (portal->parent != NULL &&
 | |
|       gtk_widget_is_visible (GTK_WIDGET (portal->parent)) &&
 | |
|       gtk_window_export_handle (portal->parent, window_handle_exported, portal))
 | |
|     return;
 | |
| 
 | |
|   g_dbus_proxy_call (portal->proxy,
 | |
|                      "PreparePrint",
 | |
|                      g_variant_new ("(ss@a{sv}@a{sv}@a{sv})",
 | |
|                                     "",
 | |
|                                     _("Print"), /* title */
 | |
|                                     portal->settings,
 | |
|                                     portal->setup,
 | |
|                                     portal->options),
 | |
|                      G_DBUS_CALL_FLAGS_NONE,
 | |
|                      -1,
 | |
|                      NULL,
 | |
|                      prepare_print_called,
 | |
|                      portal);
 | |
| }
 | |
| 
 | |
| GtkPrintOperationResult
 | |
| gtk_print_operation_portal_run_dialog (GtkPrintOperation *op,
 | |
|                                        gboolean           show_dialog,
 | |
|                                        GtkWindow         *parent,
 | |
|                                        gboolean          *do_print)
 | |
| {
 | |
|   PortalData *portal;
 | |
|   GtkPrintOperationResult result;
 | |
| 
 | |
|   portal = create_portal_data (op, parent, NULL);
 | |
|   if (portal == NULL)
 | |
|     return GTK_PRINT_OPERATION_RESULT_ERROR;
 | |
| 
 | |
|   call_prepare_print (op, portal);
 | |
| 
 | |
|   gdk_threads_leave ();
 | |
|   g_main_loop_run (portal->loop);
 | |
|   gdk_threads_enter ();
 | |
| 
 | |
|   *do_print = portal->do_print;
 | |
|   result = portal->result;
 | |
| 
 | |
|   portal_data_free (portal);
 | |
| 
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| void
 | |
| gtk_print_operation_portal_run_dialog_async (GtkPrintOperation          *op,
 | |
|                                              gboolean                    show_dialog,
 | |
|                                              GtkWindow                  *parent,
 | |
|                                              GtkPrintOperationPrintFunc  print_cb)
 | |
| {
 | |
|   PortalData *portal;
 | |
| 
 | |
|   portal = create_portal_data (op, parent, print_cb);
 | |
|   if (portal == NULL)
 | |
|     return;
 | |
| 
 | |
|   call_prepare_print (op, portal);
 | |
| }
 | |
| 
 | |
| void
 | |
| gtk_print_operation_portal_launch_preview (GtkPrintOperation *op,
 | |
|                                            cairo_surface_t   *surface,
 | |
|                                            GtkWindow         *parent,
 | |
|                                            const char        *filename)
 | |
| {
 | |
|   char *uri;
 | |
| 
 | |
|   uri = g_filename_to_uri (filename, NULL, NULL);
 | |
|   gtk_show_uri_on_window (parent, uri, GDK_CURRENT_TIME, NULL);
 | |
|   g_free (uri);
 | |
| }
 | 
