2016-07-05 05:36:56 +00:00
|
|
|
/* 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"
|
2016-07-26 19:45:39 +00:00
|
|
|
#include "gtkwindowprivate.h"
|
2016-07-05 05:36:56 +00:00
|
|
|
|
|
|
|
|
|
|
|
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;
|
2016-07-26 19:45:39 +00:00
|
|
|
GVariant *settings;
|
|
|
|
GVariant *setup;
|
|
|
|
GVariant *options;
|
2017-07-02 00:14:15 +00:00
|
|
|
char *prepare_print_handle;
|
2016-07-05 05:36:56 +00:00
|
|
|
} 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);
|
2016-07-26 19:45:39 +00:00
|
|
|
if (portal->settings)
|
|
|
|
g_variant_unref (portal->settings);
|
|
|
|
if (portal->setup)
|
|
|
|
g_variant_unref (portal->setup);
|
|
|
|
if (portal->options)
|
|
|
|
g_variant_unref (portal->options);
|
2017-07-02 00:14:15 +00:00
|
|
|
g_free (portal->prepare_print_handle);
|
2016-07-05 05:36:56 +00:00
|
|
|
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->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);
|
|
|
|
|
2017-07-02 00:14:15 +00:00
|
|
|
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);
|
|
|
|
}
|
2016-07-05 05:36:56 +00:00
|
|
|
|
|
|
|
g_variant_unref (ret);
|
|
|
|
}
|
|
|
|
|
2016-10-15 20:29:45 +00:00
|
|
|
static PortalData *
|
2016-07-05 05:36:56 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-07-26 19:45:39 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2016-07-05 05:36:56 +00:00
|
|
|
static void
|
|
|
|
call_prepare_print (GtkPrintOperation *op,
|
|
|
|
PortalData *portal)
|
|
|
|
{
|
|
|
|
GtkPrintOperationPrivate *priv = op->priv;
|
|
|
|
GVariantBuilder opt_builder;
|
2017-07-02 00:14:15 +00:00
|
|
|
char *token;
|
|
|
|
char *sender;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
token = g_strdup_printf ("gtk%d", g_random_int_range (0, G_MAXINT));
|
|
|
|
sender = g_strdup (g_dbus_connection_get_unique_name (g_dbus_proxy_get_connection (portal->proxy)) + 1);
|
|
|
|
for (i = 0; sender[i]; i++)
|
|
|
|
if (sender[i] == '.')
|
|
|
|
sender[i] = '_';
|
|
|
|
|
|
|
|
portal->prepare_print_handle = g_strdup_printf ("/org/fredesktop/portal/desktop/request/%s/%s", sender, token);
|
|
|
|
g_free (sender);
|
|
|
|
|
|
|
|
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);
|
2016-07-05 05:36:56 +00:00
|
|
|
|
|
|
|
g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT);
|
2017-07-02 00:14:15 +00:00
|
|
|
g_variant_builder_add (&opt_builder, "{sv}", "handle_token", g_variant_new_string (token));
|
|
|
|
g_free (token);
|
2016-07-26 19:45:39 +00:00
|
|
|
portal->options = g_variant_builder_end (&opt_builder);
|
2016-07-05 05:36:56 +00:00
|
|
|
|
|
|
|
if (priv->print_settings)
|
2016-07-26 19:45:39 +00:00
|
|
|
portal->settings = gtk_print_settings_to_gvariant (priv->print_settings);
|
2016-07-05 05:36:56 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
GVariantBuilder builder;
|
|
|
|
g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
|
2016-07-26 19:45:39 +00:00
|
|
|
portal->settings = g_variant_builder_end (&builder);
|
2016-07-05 05:36:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (priv->default_page_setup)
|
2016-07-26 19:45:39 +00:00
|
|
|
portal->setup = gtk_page_setup_to_gvariant (priv->default_page_setup);
|
2016-07-05 05:36:56 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
GtkPageSetup *page_setup = gtk_page_setup_new ();
|
2016-07-26 19:45:39 +00:00
|
|
|
portal->setup = gtk_page_setup_to_gvariant (page_setup);
|
2016-07-05 05:36:56 +00:00
|
|
|
g_object_unref (page_setup);
|
|
|
|
}
|
|
|
|
|
2016-07-26 19:45:39 +00:00
|
|
|
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;
|
2016-07-05 05:36:56 +00:00
|
|
|
|
|
|
|
g_dbus_proxy_call (portal->proxy,
|
|
|
|
"PreparePrint",
|
|
|
|
g_variant_new ("(ss@a{sv}@a{sv}@a{sv})",
|
2016-07-26 19:45:39 +00:00
|
|
|
"",
|
2016-07-05 05:36:56 +00:00
|
|
|
_("Print"), /* title */
|
2016-07-26 19:45:39 +00:00
|
|
|
portal->settings,
|
|
|
|
portal->setup,
|
|
|
|
portal->options),
|
2016-07-05 05:36:56 +00:00
|
|
|
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);
|
|
|
|
}
|