[GTK][WK2] WebKit2 does not build if gtk-unix-printing-3.0 is not available
[WebKit-https.git] / Source / WebKit2 / UIProcess / API / gtk / WebKitPrintOperation.cpp
1 /*
2  * Copyright (C) 2012 Igalia S.L.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library 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.
8  *
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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #include "config.h"
21 #include "WebKitPrintOperation.h"
22
23 #include "PrintInfo.h"
24 #include "WebKitPrintOperationPrivate.h"
25 #include "WebKitPrivate.h"
26 #include "WebKitWebViewBasePrivate.h"
27 #include "WebPageProxy.h"
28 #include <WebCore/GtkUtilities.h>
29 #include <WebCore/NotImplemented.h>
30 #include <glib/gi18n-lib.h>
31 #include <wtf/gobject/GRefPtr.h>
32
33 #ifdef HAVE_GTK_UNIX_PRINTING
34 #include <gtk/gtkunixprint.h>
35 #endif
36
37 using namespace WebKit;
38
39 enum {
40     PROP_0,
41
42     PROP_WEB_VIEW,
43     PROP_PRINT_SETTINGS,
44     PROP_PAGE_SETUP
45 };
46
47 enum {
48     FINISHED,
49
50     LAST_SIGNAL
51 };
52
53 struct _WebKitPrintOperationPrivate {
54     WebKitWebView* webView;
55     gulong webViewDestroyedId;
56
57     GRefPtr<GtkPrintSettings> printSettings;
58     GRefPtr<GtkPageSetup> pageSetup;
59 };
60
61 static guint signals[LAST_SIGNAL] = { 0, };
62
63 G_DEFINE_TYPE(WebKitPrintOperation, webkit_print_operation, G_TYPE_OBJECT)
64
65 static void webkitPrintOperationFinalize(GObject* object)
66 {
67     WebKitPrintOperationPrivate* priv = WEBKIT_PRINT_OPERATION(object)->priv;
68     g_signal_handler_disconnect(priv->webView, priv->webViewDestroyedId);
69
70     priv->~WebKitPrintOperationPrivate();
71     G_OBJECT_CLASS(webkit_print_operation_parent_class)->finalize(object);
72 }
73
74 static void webViewDestroyed(GtkWidget* webView, GObject* printOperation)
75 {
76     g_object_unref(printOperation);
77 }
78
79 static void webkitPrintOperationConstructed(GObject* object)
80 {
81     WebKitPrintOperation* printOperation = WEBKIT_PRINT_OPERATION(object);
82     WebKitPrintOperationPrivate* priv = printOperation->priv;
83
84     if (G_OBJECT_CLASS(webkit_print_operation_parent_class)->constructed)
85         G_OBJECT_CLASS(webkit_print_operation_parent_class)->constructed(object);
86
87     priv->webViewDestroyedId = g_signal_connect(priv->webView, "destroy", G_CALLBACK(webViewDestroyed), printOperation);
88 }
89
90 static void webkitPrintOperationGetProperty(GObject* object, guint propId, GValue* value, GParamSpec* paramSpec)
91 {
92     WebKitPrintOperation* printOperation = WEBKIT_PRINT_OPERATION(object);
93
94     switch (propId) {
95     case PROP_WEB_VIEW:
96         g_value_take_object(value, printOperation->priv->webView);
97         break;
98     case PROP_PRINT_SETTINGS:
99         g_value_set_object(value, printOperation->priv->printSettings.get());
100         break;
101     case PROP_PAGE_SETUP:
102         g_value_set_object(value, printOperation->priv->pageSetup.get());
103         break;
104     default:
105         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec);
106     }
107 }
108
109 static void webkitPrintOperationSetProperty(GObject* object, guint propId, const GValue* value, GParamSpec* paramSpec)
110 {
111     WebKitPrintOperation* printOperation = WEBKIT_PRINT_OPERATION(object);
112
113     switch (propId) {
114     case PROP_WEB_VIEW:
115         printOperation->priv->webView = WEBKIT_WEB_VIEW(g_value_get_object(value));
116         break;
117     case PROP_PRINT_SETTINGS:
118         webkit_print_operation_set_print_settings(printOperation, GTK_PRINT_SETTINGS(g_value_get_object(value)));
119         break;
120     case PROP_PAGE_SETUP:
121         webkit_print_operation_set_page_setup(printOperation, GTK_PAGE_SETUP(g_value_get_object(value)));
122         break;
123     default:
124         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec);
125     }
126 }
127
128 static void webkit_print_operation_init(WebKitPrintOperation* printOperation)
129 {
130     WebKitPrintOperationPrivate* priv = G_TYPE_INSTANCE_GET_PRIVATE(printOperation, WEBKIT_TYPE_PRINT_OPERATION, WebKitPrintOperationPrivate);
131     printOperation->priv = priv;
132     new (priv) WebKitPrintOperationPrivate();
133 }
134
135 static void webkit_print_operation_class_init(WebKitPrintOperationClass* printOperationClass)
136 {
137     GObjectClass* gObjectClass = G_OBJECT_CLASS(printOperationClass);
138     gObjectClass->finalize = webkitPrintOperationFinalize;
139     gObjectClass->constructed = webkitPrintOperationConstructed;
140     gObjectClass->get_property = webkitPrintOperationGetProperty;
141     gObjectClass->set_property = webkitPrintOperationSetProperty;
142
143     /**
144      * WebKitPrintOperation:web-view:
145      *
146      * The #WebKitWebView that will be printed.
147      */
148     g_object_class_install_property(gObjectClass,
149                                     PROP_WEB_VIEW,
150                                     g_param_spec_object("web-view",
151                                                         _("Web View"),
152                                                         _("The web view that will be printed"),
153                                                         WEBKIT_TYPE_WEB_VIEW,
154                                                         static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
155
156     /**
157      * WebKitPrintOperation:print-settings:
158      *
159      * The initial #GtkPrintSettings for the print operation.
160      */
161     g_object_class_install_property(gObjectClass,
162                                     PROP_PRINT_SETTINGS,
163                                     g_param_spec_object("print-settings",
164                                                         _("Print Settings"),
165                                                         _("The initial print settings for the print operation"),
166                                                         GTK_TYPE_PRINT_SETTINGS,
167                                                         WEBKIT_PARAM_READWRITE));
168     /**
169      * WebKitPrintOperation:page-setup:
170      *
171      * The initial #GtkPageSetup for the print operation.
172      */
173     g_object_class_install_property(gObjectClass,
174                                      PROP_PAGE_SETUP,
175                                      g_param_spec_object("page-setup",
176                                                          _("Page Setup"),
177                                                          _("The initial page setup for the print operation"),
178                                                          GTK_TYPE_PAGE_SETUP,
179                                                          WEBKIT_PARAM_READWRITE));
180
181     /**
182      * WebKitPrintOperation::finished:
183      * @print_operation: the #WebKitPrintOperation on which the signal was emitted
184      *
185      * Emitted when the print operation has finished doing everything
186      * required for printing.
187      */
188     signals[FINISHED] =
189         g_signal_new("finished",
190                      G_TYPE_FROM_CLASS(gObjectClass),
191                      G_SIGNAL_RUN_LAST,
192                      0, 0, 0,
193                      g_cclosure_marshal_VOID__VOID,
194                      G_TYPE_NONE, 0);
195
196     g_type_class_add_private(printOperationClass, sizeof(WebKitPrintOperationPrivate));
197 }
198
199 #ifdef HAVE_GTK_UNIX_PRINTING
200 static WebKitPrintOperationResponse webkitPrintOperationRunDialog(WebKitPrintOperation* printOperation, GtkWindow* parent)
201 {
202     GtkPrintUnixDialog* printDialog = GTK_PRINT_UNIX_DIALOG(gtk_print_unix_dialog_new(0, parent));
203     gtk_print_unix_dialog_set_manual_capabilities(printDialog, static_cast<GtkPrintCapabilities>(GTK_PRINT_CAPABILITY_NUMBER_UP
204                                                                                                  | GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT
205                                                                                                  | GTK_PRINT_CAPABILITY_PAGE_SET
206                                                                                                  | GTK_PRINT_CAPABILITY_REVERSE
207                                                                                                  | GTK_PRINT_CAPABILITY_COPIES
208                                                                                                  | GTK_PRINT_CAPABILITY_COLLATE
209                                                                                                  | GTK_PRINT_CAPABILITY_SCALE));
210
211     WebKitPrintOperationPrivate* priv = printOperation->priv;
212     if (priv->printSettings)
213         gtk_print_unix_dialog_set_settings(printDialog, priv->printSettings.get());
214
215     if (priv->pageSetup)
216         gtk_print_unix_dialog_set_page_setup(printDialog, priv->pageSetup.get());
217
218     gtk_print_unix_dialog_set_embed_page_setup(printDialog, TRUE);
219
220     WebKitPrintOperationResponse returnValue = WEBKIT_PRINT_OPERATION_RESPONSE_CANCEL;
221     if (gtk_dialog_run(GTK_DIALOG(printDialog)) == GTK_RESPONSE_OK) {
222         priv->printSettings = adoptGRef(gtk_print_unix_dialog_get_settings(printDialog));
223         priv->pageSetup = gtk_print_unix_dialog_get_page_setup(printDialog);
224         returnValue = WEBKIT_PRINT_OPERATION_RESPONSE_PRINT;
225     }
226
227     gtk_widget_destroy(GTK_WIDGET(printDialog));
228
229     return returnValue;
230 }
231 #else
232 // TODO: We need to add an implementation for Windows.
233 static WebKitPrintOperationResponse webkitPrintOperationRunDialog(WebKitPrintOperation*, GtkWindow*)
234 {
235     notImplemented();
236     return WEBKIT_PRINT_OPERATION_RESPONSE_CANCEL;
237 }
238 #endif
239
240 static void drawPagesForPrintingCompleted(WKErrorRef, void* context)
241 {
242     GRefPtr<WebKitPrintOperation> printOperation = adoptGRef(WEBKIT_PRINT_OPERATION(context));
243     WebPageProxy* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(printOperation->priv->webView));
244     page->endPrinting();
245     g_signal_emit(printOperation.get(), signals[FINISHED], 0, NULL);
246 }
247
248 static void webkitPrintOperationPrintPagesForFrame(WebKitPrintOperation* printOperation, WebFrameProxy* webFrame, GtkPrintSettings* printSettings, GtkPageSetup* pageSetup)
249 {
250     PrintInfo printInfo(printSettings, pageSetup);
251     WebPageProxy* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(printOperation->priv->webView));
252     page->drawPagesForPrinting(webFrame, printInfo, VoidCallback::create(g_object_ref(printOperation), &drawPagesForPrintingCompleted));
253 }
254
255 WebKitPrintOperationResponse webkitPrintOperationRunDialogForFrame(WebKitPrintOperation* printOperation, GtkWindow* parent, WebFrameProxy* webFrame)
256 {
257     WebKitPrintOperationPrivate* priv = printOperation->priv;
258     if (!parent) {
259         GtkWidget* toplevel = gtk_widget_get_toplevel(GTK_WIDGET(priv->webView));
260         if (WebCore::widgetIsOnscreenToplevelWindow(toplevel))
261             parent = GTK_WINDOW(toplevel);
262     }
263
264     WebKitPrintOperationResponse response = webkitPrintOperationRunDialog(printOperation, parent);
265     if (response == WEBKIT_PRINT_OPERATION_RESPONSE_CANCEL)
266         return response;
267
268     webkitPrintOperationPrintPagesForFrame(printOperation, webFrame, priv->printSettings.get(), priv->pageSetup.get());
269     return response;
270 }
271
272 /**
273  * webkit_print_operation_new:
274  * @web_view: a #WebKitWebView
275  *
276  * Create a new #WebKitPrintOperation to print @web_view contents.
277  *
278  * Returns: (transfer full): a new #WebKitPrintOperation.
279  */
280 WebKitPrintOperation* webkit_print_operation_new(WebKitWebView* webView)
281 {
282     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
283
284     return WEBKIT_PRINT_OPERATION(g_object_new(WEBKIT_TYPE_PRINT_OPERATION, "web-view", webView, NULL));
285 }
286
287 /**
288  * webkit_print_operation_get_print_settings:
289  * @print_operation: a #WebKitPrintOperation
290  *
291  * Return the current print settings of @print_operation. It returns %NULL until
292  * either webkit_print_operation_set_print_settings() or webkit_print_operation_run_dialog()
293  * have been called.
294  *
295  * Returns: (transfer none): the current #GtkPrintSettings of @print_operation.
296  */
297 GtkPrintSettings* webkit_print_operation_get_print_settings(WebKitPrintOperation* printOperation)
298 {
299     g_return_val_if_fail(WEBKIT_IS_PRINT_OPERATION(printOperation), 0);
300
301     return printOperation->priv->printSettings.get();
302 }
303
304 /**
305  * webkit_print_operation_set_print_settings:
306  * @print_operation: a #WebKitPrintOperation
307  * @print_settings: a #GtkPrintSettings to set
308  *
309  * Set the current print settings of @print_operation. Current print settings are used for
310  * the initial values of the print dialog when webkit_print_operation_run_dialog() is called.
311  */
312 void webkit_print_operation_set_print_settings(WebKitPrintOperation* printOperation, GtkPrintSettings* printSettings)
313 {
314     g_return_if_fail(WEBKIT_IS_PRINT_OPERATION(printOperation));
315     g_return_if_fail(GTK_IS_PRINT_SETTINGS(printSettings));
316
317     if (printOperation->priv->printSettings.get() == printSettings)
318         return;
319
320     printOperation->priv->printSettings = printSettings;
321     g_object_notify(G_OBJECT(printOperation), "print-settings");
322 }
323
324 /**
325  * webkit_print_operation_get_page_setup:
326  * @print_operation: a #WebKitPrintOperation
327  *
328  * Return the current page setup of @print_operation. It returns %NULL until
329  * either webkit_print_operation_set_print_settings() or webkit_print_operation_run_dialog()
330  * have been called.
331  *
332  * Returns: (transfer none): the current #GtkPageSetup of @print_operation.
333  */
334 GtkPageSetup* webkit_print_operation_get_page_setup(WebKitPrintOperation* printOperation)
335 {
336     g_return_val_if_fail(WEBKIT_IS_PRINT_OPERATION(printOperation), 0);
337
338     return printOperation->priv->pageSetup.get();
339 }
340
341 /**
342  * webkit_print_operation_set_page_setup:
343  * @print_operation: a #WebKitPrintOperation
344  * @page_setup: a #GtkPageSetup to set
345  *
346  * Set the current page setup of @print_operation. Current page setup is used for the
347  * initial values of the print dialog when webkit_print_operation_run_dialog() is called.
348  */
349 void webkit_print_operation_set_page_setup(WebKitPrintOperation* printOperation, GtkPageSetup* pageSetup)
350 {
351     g_return_if_fail(WEBKIT_IS_PRINT_OPERATION(printOperation));
352     g_return_if_fail(GTK_IS_PAGE_SETUP(pageSetup));
353
354     if (printOperation->priv->pageSetup.get() == pageSetup)
355         return;
356
357     printOperation->priv->pageSetup = pageSetup;
358     g_object_notify(G_OBJECT(printOperation), "page-setup");
359 }
360
361 /**
362  * webkit_print_operation_run_dialog:
363  * @print_operation: a #WebKitPrintOperation
364  * @parent: (allow-none): transient parent of the print dialog
365  *
366  * Run the print dialog and start printing using the options selected by
367  * the user. This method returns when the print dialog is closed.
368  * If the print dialog is cancelled %WEBKIT_PRINT_OPERATION_RESPONSE_CANCEL
369  * is returned. If the user clicks on the print button, %WEBKIT_PRINT_OPERATION_RESPONSE_PRINT
370  * is returned and the print operation starts. In this case, the WebKitPrintOperation::finished
371  * signal is emitted when the operation finishes.
372  * If the print dialog is not cancelled current print settings and page setup of @print_operation
373  * are updated with options selected by the user when Print button is pressed in print dialog.
374  * You can get the updated print settings and page setup by calling
375  * webkit_print_operation_get_print_settings() and webkit_print_operation_get_page_setup()
376  * after this method.
377  *
378  * Returns: the #WebKitPrintOperationResponse of the print dialog
379  */
380 WebKitPrintOperationResponse webkit_print_operation_run_dialog(WebKitPrintOperation* printOperation, GtkWindow* parent)
381 {
382     g_return_val_if_fail(WEBKIT_IS_PRINT_OPERATION(printOperation), WEBKIT_PRINT_OPERATION_RESPONSE_CANCEL);
383
384     WebPageProxy* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(printOperation->priv->webView));
385     return webkitPrintOperationRunDialogForFrame(printOperation, parent, page->mainFrame());
386 }
387
388 /**
389  * webkit_print_operation_print:
390  * @print_operation: a #WebKitPrintOperation
391  *
392  * Start a print operation using current print settings and page setup
393  * without showing the print dialog. If either print settings or page setup
394  * are not set with webkit_print_operation_set_print_settings() and
395  * webkit_print_operation_set_page_setup(), the default options will be used
396  * and the print job will be sent to the default printer.
397  * The WebKitPrintOperation::finished signal is emitted when the printing
398  * operation finishes.
399  */
400 void webkit_print_operation_print(WebKitPrintOperation* printOperation)
401 {
402     g_return_if_fail(WEBKIT_IS_PRINT_OPERATION(printOperation));
403
404     WebKitPrintOperationPrivate* priv = printOperation->priv;
405     GRefPtr<GtkPrintSettings> printSettings = priv->printSettings ? priv->printSettings : adoptGRef(gtk_print_settings_new());
406     GRefPtr<GtkPageSetup> pageSetup = priv->pageSetup ? priv->pageSetup : adoptGRef(gtk_page_setup_new());
407
408     WebPageProxy* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(printOperation->priv->webView));
409     webkitPrintOperationPrintPagesForFrame(printOperation, page->mainFrame(), printSettings.get(), pageSetup.get());
410 }