Bug 1449132 [wpt PR 10194] - [css-grid] Fix resolution of percentage paddings and...
[gecko.git] / widget / gtk / nsPrintDialogGTK.cpp
blobdcd14c93a1a8b40f3473a0a9ba9b9bfc35a0a5e9
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include <gtk/gtk.h>
7 #include <gtk/gtkunixprint.h>
8 #include <stdlib.h>
10 #include "mozilla/ArrayUtils.h"
12 #include "mozcontainer.h"
13 #include "nsIPrintSettings.h"
14 #include "nsIWidget.h"
15 #include "nsPrintDialogGTK.h"
16 #include "nsPrintSettingsGTK.h"
17 #include "nsString.h"
18 #include "nsReadableUtils.h"
19 #include "nsIFile.h"
20 #include "nsIStringBundle.h"
21 #include "nsIPrintSettingsService.h"
22 #include "nsIDOMWindow.h"
23 #include "nsPIDOMWindow.h"
24 #include "nsIBaseWindow.h"
25 #include "nsIDocShellTreeItem.h"
26 #include "nsIDocShell.h"
27 #include "WidgetUtils.h"
29 using namespace mozilla;
30 using namespace mozilla::widget;
32 static const char header_footer_tags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
34 #define CUSTOM_VALUE_INDEX gint(ArrayLength(header_footer_tags))
36 static GtkWindow *
37 get_gtk_window_for_nsiwidget(nsIWidget *widget)
39 return GTK_WINDOW(widget->GetNativeData(NS_NATIVE_SHELLWIDGET));
42 static void
43 ShowCustomDialog(GtkComboBox *changed_box, gpointer user_data)
45 if (gtk_combo_box_get_active(changed_box) != CUSTOM_VALUE_INDEX) {
46 g_object_set_data(G_OBJECT(changed_box), "previous-active", GINT_TO_POINTER(gtk_combo_box_get_active(changed_box)));
47 return;
50 GtkWindow* printDialog = GTK_WINDOW(user_data);
51 nsCOMPtr<nsIStringBundleService> bundleSvc =
52 do_GetService(NS_STRINGBUNDLE_CONTRACTID);
54 nsCOMPtr<nsIStringBundle> printBundle;
55 bundleSvc->CreateBundle("chrome://global/locale/printdialog.properties", getter_AddRefs(printBundle));
56 nsAutoString intlString;
58 printBundle->GetStringFromName("headerFooterCustom", intlString);
59 GtkWidget* prompt_dialog = gtk_dialog_new_with_buttons(NS_ConvertUTF16toUTF8(intlString).get(), printDialog,
60 (GtkDialogFlags)(GTK_DIALOG_MODAL),
61 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
62 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
63 nullptr);
64 gtk_dialog_set_default_response(GTK_DIALOG(prompt_dialog), GTK_RESPONSE_ACCEPT);
65 gtk_dialog_set_alternative_button_order(GTK_DIALOG(prompt_dialog),
66 GTK_RESPONSE_ACCEPT,
67 GTK_RESPONSE_REJECT,
68 -1);
70 printBundle->GetStringFromName("customHeaderFooterPrompt", intlString);
71 GtkWidget* custom_label = gtk_label_new(NS_ConvertUTF16toUTF8(intlString).get());
72 GtkWidget* custom_entry = gtk_entry_new();
73 GtkWidget* question_icon = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
75 // To be convenient, prefill the textbox with the existing value, if any, and select it all so they can easily
76 // both edit it and type in a new one.
77 const char* current_text = (const char*) g_object_get_data(G_OBJECT(changed_box), "custom-text");
78 if (current_text) {
79 gtk_entry_set_text(GTK_ENTRY(custom_entry), current_text);
80 gtk_editable_select_region(GTK_EDITABLE(custom_entry), 0, -1);
82 gtk_entry_set_activates_default(GTK_ENTRY(custom_entry), TRUE);
84 GtkWidget* custom_vbox = gtk_vbox_new(TRUE, 2);
85 gtk_box_pack_start(GTK_BOX(custom_vbox), custom_label, FALSE, FALSE, 0);
86 gtk_box_pack_start(GTK_BOX(custom_vbox), custom_entry, FALSE, FALSE, 5); // Make entry 5px underneath label
87 GtkWidget* custom_hbox = gtk_hbox_new(FALSE, 2);
88 gtk_box_pack_start(GTK_BOX(custom_hbox), question_icon, FALSE, FALSE, 0);
89 gtk_box_pack_start(GTK_BOX(custom_hbox), custom_vbox, FALSE, FALSE, 10); // Make question icon 10px away from content
90 gtk_container_set_border_width(GTK_CONTAINER(custom_hbox), 2);
91 gtk_widget_show_all(custom_hbox);
93 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(prompt_dialog))),
94 custom_hbox, FALSE, FALSE, 0);
95 gint diag_response = gtk_dialog_run(GTK_DIALOG(prompt_dialog));
97 if (diag_response == GTK_RESPONSE_ACCEPT) {
98 const gchar* response_text = gtk_entry_get_text(GTK_ENTRY(custom_entry));
99 g_object_set_data_full(G_OBJECT(changed_box), "custom-text", strdup(response_text), (GDestroyNotify) free);
100 g_object_set_data(G_OBJECT(changed_box), "previous-active", GINT_TO_POINTER(CUSTOM_VALUE_INDEX));
101 } else {
102 // Go back to the previous index
103 gint previous_active = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(changed_box), "previous-active"));
104 gtk_combo_box_set_active(changed_box, previous_active);
107 gtk_widget_destroy(prompt_dialog);
110 class nsPrintDialogWidgetGTK {
111 public:
112 nsPrintDialogWidgetGTK(nsPIDOMWindowOuter *aParent,
113 nsIPrintSettings *aPrintSettings);
114 ~nsPrintDialogWidgetGTK() { gtk_widget_destroy(dialog); }
115 NS_ConvertUTF16toUTF8 GetUTF8FromBundle(const char* aKey);
116 gint Run();
118 nsresult ImportSettings(nsIPrintSettings *aNSSettings);
119 nsresult ExportSettings(nsIPrintSettings *aNSSettings);
121 private:
122 GtkWidget* dialog;
123 GtkWidget* radio_as_laid_out;
124 GtkWidget* radio_selected_frame;
125 GtkWidget* radio_separate_frames;
126 GtkWidget* shrink_to_fit_toggle;
127 GtkWidget* print_bg_colors_toggle;
128 GtkWidget* print_bg_images_toggle;
129 GtkWidget* selection_only_toggle;
130 GtkWidget* header_dropdown[3]; // {left, center, right}
131 GtkWidget* footer_dropdown[3];
133 nsCOMPtr<nsIStringBundle> printBundle;
135 bool useNativeSelection;
137 GtkWidget* ConstructHeaderFooterDropdown(const char16_t *currentString);
138 const char* OptionWidgetToString(GtkWidget *dropdown);
140 /* Code to copy between GTK and NS print settings structures.
141 * In the following,
142 * "Import" means to copy from NS to GTK
143 * "Export" means to copy from GTK to NS
145 void ExportFramePrinting(nsIPrintSettings *aNS, GtkPrintSettings *aSettings);
146 void ExportHeaderFooter(nsIPrintSettings *aNS);
149 nsPrintDialogWidgetGTK::nsPrintDialogWidgetGTK(nsPIDOMWindowOuter *aParent,
150 nsIPrintSettings *aSettings)
152 nsCOMPtr<nsIWidget> widget = WidgetUtils::DOMWindowToWidget(aParent);
153 NS_ASSERTION(widget, "Need a widget for dialog to be modal.");
154 GtkWindow* gtkParent = get_gtk_window_for_nsiwidget(widget);
155 NS_ASSERTION(gtkParent, "Need a GTK window for dialog to be modal.");
157 nsCOMPtr<nsIStringBundleService> bundleSvc = do_GetService(NS_STRINGBUNDLE_CONTRACTID);
158 bundleSvc->CreateBundle("chrome://global/locale/printdialog.properties", getter_AddRefs(printBundle));
160 dialog = gtk_print_unix_dialog_new(GetUTF8FromBundle("printTitleGTK").get(), gtkParent);
162 gtk_print_unix_dialog_set_manual_capabilities(GTK_PRINT_UNIX_DIALOG(dialog),
163 GtkPrintCapabilities(
164 GTK_PRINT_CAPABILITY_PAGE_SET
165 | GTK_PRINT_CAPABILITY_COPIES
166 | GTK_PRINT_CAPABILITY_COLLATE
167 | GTK_PRINT_CAPABILITY_REVERSE
168 | GTK_PRINT_CAPABILITY_SCALE
169 | GTK_PRINT_CAPABILITY_GENERATE_PDF
173 // The vast majority of magic numbers in this widget construction are padding. e.g. for
174 // the set_border_width below, 12px matches that of just about every other window.
175 GtkWidget* custom_options_tab = gtk_vbox_new(FALSE, 0);
176 gtk_container_set_border_width(GTK_CONTAINER(custom_options_tab), 12);
177 GtkWidget* tab_label = gtk_label_new(GetUTF8FromBundle("optionsTabLabelGTK").get());
179 int16_t frameUIFlag;
180 aSettings->GetHowToEnableFrameUI(&frameUIFlag);
181 radio_as_laid_out = gtk_radio_button_new_with_mnemonic(nullptr, GetUTF8FromBundle("asLaidOut").get());
182 if (frameUIFlag == nsIPrintSettings::kFrameEnableNone)
183 gtk_widget_set_sensitive(radio_as_laid_out, FALSE);
185 radio_selected_frame = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(radio_as_laid_out),
186 GetUTF8FromBundle("selectedFrame").get());
187 if (frameUIFlag == nsIPrintSettings::kFrameEnableNone ||
188 frameUIFlag == nsIPrintSettings::kFrameEnableAsIsAndEach)
189 gtk_widget_set_sensitive(radio_selected_frame, FALSE);
191 radio_separate_frames = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(radio_as_laid_out),
192 GetUTF8FromBundle("separateFrames").get());
193 if (frameUIFlag == nsIPrintSettings::kFrameEnableNone)
194 gtk_widget_set_sensitive(radio_separate_frames, FALSE);
196 // "Print Frames" options label, bold and center-aligned
197 GtkWidget* print_frames_label = gtk_label_new(nullptr);
198 char* pangoMarkup = g_markup_printf_escaped("<b>%s</b>", GetUTF8FromBundle("printFramesTitleGTK").get());
199 gtk_label_set_markup(GTK_LABEL(print_frames_label), pangoMarkup);
200 g_free(pangoMarkup);
201 gtk_misc_set_alignment(GTK_MISC(print_frames_label), 0, 0);
203 // Align the radio buttons slightly so they appear to fall under the aforementioned label as per the GNOME HIG
204 GtkWidget* frames_radio_container = gtk_alignment_new(0, 0, 0, 0);
205 gtk_alignment_set_padding(GTK_ALIGNMENT(frames_radio_container), 8, 0, 12, 0);
207 // Radio buttons for the print frames options
208 GtkWidget* frames_radio_list = gtk_vbox_new(TRUE, 2);
209 gtk_box_pack_start(GTK_BOX(frames_radio_list), radio_as_laid_out, FALSE, FALSE, 0);
210 gtk_box_pack_start(GTK_BOX(frames_radio_list), radio_selected_frame, FALSE, FALSE, 0);
211 gtk_box_pack_start(GTK_BOX(frames_radio_list), radio_separate_frames, FALSE, FALSE, 0);
212 gtk_container_add(GTK_CONTAINER(frames_radio_container), frames_radio_list);
214 // Check buttons for shrink-to-fit and print selection
215 GtkWidget* check_buttons_container = gtk_vbox_new(TRUE, 2);
216 shrink_to_fit_toggle = gtk_check_button_new_with_mnemonic(GetUTF8FromBundle("shrinkToFit").get());
217 gtk_box_pack_start(GTK_BOX(check_buttons_container), shrink_to_fit_toggle, FALSE, FALSE, 0);
219 // GTK+2.18 and above allow us to add a "Selection" option to the main settings screen,
220 // rather than adding an option on a custom tab like we must do on older versions.
221 bool canSelectText;
222 aSettings->GetPrintOptions(nsIPrintSettings::kEnableSelectionRB, &canSelectText);
223 if (gtk_major_version > 2 ||
224 (gtk_major_version == 2 && gtk_minor_version >= 18)) {
225 useNativeSelection = true;
226 g_object_set(dialog,
227 "support-selection", TRUE,
228 "has-selection", canSelectText,
229 "embed-page-setup", TRUE,
230 nullptr);
231 } else {
232 useNativeSelection = false;
233 selection_only_toggle = gtk_check_button_new_with_mnemonic(GetUTF8FromBundle("selectionOnly").get());
234 gtk_widget_set_sensitive(selection_only_toggle, canSelectText);
235 gtk_box_pack_start(GTK_BOX(check_buttons_container), selection_only_toggle, FALSE, FALSE, 0);
238 // Check buttons for printing background
239 GtkWidget* appearance_buttons_container = gtk_vbox_new(TRUE, 2);
240 print_bg_colors_toggle = gtk_check_button_new_with_mnemonic(GetUTF8FromBundle("printBGColors").get());
241 print_bg_images_toggle = gtk_check_button_new_with_mnemonic(GetUTF8FromBundle("printBGImages").get());
242 gtk_box_pack_start(GTK_BOX(appearance_buttons_container), print_bg_colors_toggle, FALSE, FALSE, 0);
243 gtk_box_pack_start(GTK_BOX(appearance_buttons_container), print_bg_images_toggle, FALSE, FALSE, 0);
245 // "Appearance" options label, bold and center-aligned
246 GtkWidget* appearance_label = gtk_label_new(nullptr);
247 pangoMarkup = g_markup_printf_escaped("<b>%s</b>", GetUTF8FromBundle("printBGOptions").get());
248 gtk_label_set_markup(GTK_LABEL(appearance_label), pangoMarkup);
249 g_free(pangoMarkup);
250 gtk_misc_set_alignment(GTK_MISC(appearance_label), 0, 0);
252 GtkWidget* appearance_container = gtk_alignment_new(0, 0, 0, 0);
253 gtk_alignment_set_padding(GTK_ALIGNMENT(appearance_container), 8, 0, 12, 0);
254 gtk_container_add(GTK_CONTAINER(appearance_container), appearance_buttons_container);
256 GtkWidget* appearance_vertical_squasher = gtk_vbox_new(FALSE, 0);
257 gtk_box_pack_start(GTK_BOX(appearance_vertical_squasher), appearance_label, FALSE, FALSE, 0);
258 gtk_box_pack_start(GTK_BOX(appearance_vertical_squasher), appearance_container, FALSE, FALSE, 0);
260 // "Header & Footer" options label, bold and center-aligned
261 GtkWidget* header_footer_label = gtk_label_new(nullptr);
262 pangoMarkup = g_markup_printf_escaped("<b>%s</b>", GetUTF8FromBundle("headerFooter").get());
263 gtk_label_set_markup(GTK_LABEL(header_footer_label), pangoMarkup);
264 g_free(pangoMarkup);
265 gtk_misc_set_alignment(GTK_MISC(header_footer_label), 0, 0);
267 GtkWidget* header_footer_container = gtk_alignment_new(0, 0, 0, 0);
268 gtk_alignment_set_padding(GTK_ALIGNMENT(header_footer_container), 8, 0, 12, 0);
271 // --- Table for making the header and footer options ---
272 GtkWidget* header_footer_table = gtk_table_new(3, 3, FALSE); // 3x3 table
273 nsString header_footer_str[3];
275 aSettings->GetHeaderStrLeft(header_footer_str[0]);
276 aSettings->GetHeaderStrCenter(header_footer_str[1]);
277 aSettings->GetHeaderStrRight(header_footer_str[2]);
279 for (unsigned int i = 0; i < ArrayLength(header_dropdown); i++) {
280 header_dropdown[i] = ConstructHeaderFooterDropdown(header_footer_str[i].get());
281 // Those 4 magic numbers in the middle provide the position in the table.
282 // The last two numbers mean 2 px padding on every side.
283 gtk_table_attach(GTK_TABLE(header_footer_table), header_dropdown[i], i, (i + 1),
284 0, 1, (GtkAttachOptions) 0, (GtkAttachOptions) 0, 2, 2);
287 const char labelKeys[][7] = {"left", "center", "right"};
288 for (unsigned int i = 0; i < ArrayLength(labelKeys); i++) {
289 gtk_table_attach(GTK_TABLE(header_footer_table),
290 gtk_label_new(GetUTF8FromBundle(labelKeys[i]).get()),
291 i, (i + 1), 1, 2, (GtkAttachOptions) 0, (GtkAttachOptions) 0, 2, 2);
294 aSettings->GetFooterStrLeft(header_footer_str[0]);
295 aSettings->GetFooterStrCenter(header_footer_str[1]);
296 aSettings->GetFooterStrRight(header_footer_str[2]);
298 for (unsigned int i = 0; i < ArrayLength(footer_dropdown); i++) {
299 footer_dropdown[i] = ConstructHeaderFooterDropdown(header_footer_str[i].get());
300 gtk_table_attach(GTK_TABLE(header_footer_table), footer_dropdown[i], i, (i + 1),
301 2, 3, (GtkAttachOptions) 0, (GtkAttachOptions) 0, 2, 2);
303 // ---
305 gtk_container_add(GTK_CONTAINER(header_footer_container), header_footer_table);
307 GtkWidget* header_footer_vertical_squasher = gtk_vbox_new(FALSE, 0);
308 gtk_box_pack_start(GTK_BOX(header_footer_vertical_squasher), header_footer_label, FALSE, FALSE, 0);
309 gtk_box_pack_start(GTK_BOX(header_footer_vertical_squasher), header_footer_container, FALSE, FALSE, 0);
311 // Construction of everything
312 gtk_box_pack_start(GTK_BOX(custom_options_tab), print_frames_label, FALSE, FALSE, 0);
313 gtk_box_pack_start(GTK_BOX(custom_options_tab), frames_radio_container, FALSE, FALSE, 0);
314 gtk_box_pack_start(GTK_BOX(custom_options_tab), check_buttons_container, FALSE, FALSE, 10); // 10px padding
315 gtk_box_pack_start(GTK_BOX(custom_options_tab), appearance_vertical_squasher, FALSE, FALSE, 10);
316 gtk_box_pack_start(GTK_BOX(custom_options_tab), header_footer_vertical_squasher, FALSE, FALSE, 0);
318 gtk_print_unix_dialog_add_custom_tab(GTK_PRINT_UNIX_DIALOG(dialog), custom_options_tab, tab_label);
319 gtk_widget_show_all(custom_options_tab);
322 NS_ConvertUTF16toUTF8
323 nsPrintDialogWidgetGTK::GetUTF8FromBundle(const char *aKey)
325 nsAutoString intlString;
326 printBundle->GetStringFromName(aKey, intlString);
327 return NS_ConvertUTF16toUTF8(intlString); // Return the actual object so we don't lose reference
330 const char*
331 nsPrintDialogWidgetGTK::OptionWidgetToString(GtkWidget *dropdown)
333 gint index = gtk_combo_box_get_active(GTK_COMBO_BOX(dropdown));
335 NS_ASSERTION(index <= CUSTOM_VALUE_INDEX, "Index of dropdown is higher than expected!");
337 if (index == CUSTOM_VALUE_INDEX)
338 return (const char*) g_object_get_data(G_OBJECT(dropdown), "custom-text");
339 else
340 return header_footer_tags[index];
343 gint
344 nsPrintDialogWidgetGTK::Run()
346 const gint response = gtk_dialog_run(GTK_DIALOG(dialog));
347 gtk_widget_hide(dialog);
348 return response;
351 void
352 nsPrintDialogWidgetGTK::ExportFramePrinting(nsIPrintSettings *aNS, GtkPrintSettings *aSettings)
354 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_as_laid_out)))
355 aNS->SetPrintFrameType(nsIPrintSettings::kFramesAsIs);
356 else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_selected_frame)))
357 aNS->SetPrintFrameType(nsIPrintSettings::kSelectedFrame);
358 else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_separate_frames)))
359 aNS->SetPrintFrameType(nsIPrintSettings::kEachFrameSep);
360 else
361 aNS->SetPrintFrameType(nsIPrintSettings::kNoFrames);
364 void
365 nsPrintDialogWidgetGTK::ExportHeaderFooter(nsIPrintSettings *aNS)
367 const char* header_footer_str;
368 header_footer_str = OptionWidgetToString(header_dropdown[0]);
369 aNS->SetHeaderStrLeft(NS_ConvertUTF8toUTF16(header_footer_str));
371 header_footer_str = OptionWidgetToString(header_dropdown[1]);
372 aNS->SetHeaderStrCenter(NS_ConvertUTF8toUTF16(header_footer_str));
374 header_footer_str = OptionWidgetToString(header_dropdown[2]);
375 aNS->SetHeaderStrRight(NS_ConvertUTF8toUTF16(header_footer_str));
377 header_footer_str = OptionWidgetToString(footer_dropdown[0]);
378 aNS->SetFooterStrLeft(NS_ConvertUTF8toUTF16(header_footer_str));
380 header_footer_str = OptionWidgetToString(footer_dropdown[1]);
381 aNS->SetFooterStrCenter(NS_ConvertUTF8toUTF16(header_footer_str));
383 header_footer_str = OptionWidgetToString(footer_dropdown[2]);
384 aNS->SetFooterStrRight(NS_ConvertUTF8toUTF16(header_footer_str));
387 nsresult
388 nsPrintDialogWidgetGTK::ImportSettings(nsIPrintSettings *aNSSettings)
390 NS_PRECONDITION(aNSSettings, "aSettings must not be null");
391 NS_ENSURE_TRUE(aNSSettings, NS_ERROR_FAILURE);
393 nsCOMPtr<nsPrintSettingsGTK> aNSSettingsGTK(do_QueryInterface(aNSSettings));
394 if (!aNSSettingsGTK)
395 return NS_ERROR_FAILURE;
397 GtkPrintSettings* settings = aNSSettingsGTK->GetGtkPrintSettings();
398 GtkPageSetup* setup = aNSSettingsGTK->GetGtkPageSetup();
400 bool geckoBool;
401 aNSSettings->GetShrinkToFit(&geckoBool);
402 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(shrink_to_fit_toggle), geckoBool);
404 aNSSettings->GetPrintBGColors(&geckoBool);
405 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(print_bg_colors_toggle), geckoBool);
407 aNSSettings->GetPrintBGImages(&geckoBool);
408 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(print_bg_images_toggle), geckoBool);
410 gtk_print_unix_dialog_set_settings(GTK_PRINT_UNIX_DIALOG(dialog), settings);
411 gtk_print_unix_dialog_set_page_setup(GTK_PRINT_UNIX_DIALOG(dialog), setup);
413 return NS_OK;
416 nsresult
417 nsPrintDialogWidgetGTK::ExportSettings(nsIPrintSettings *aNSSettings)
419 NS_PRECONDITION(aNSSettings, "aSettings must not be null");
420 NS_ENSURE_TRUE(aNSSettings, NS_ERROR_FAILURE);
422 GtkPrintSettings* settings = gtk_print_unix_dialog_get_settings(GTK_PRINT_UNIX_DIALOG(dialog));
423 GtkPageSetup* setup = gtk_print_unix_dialog_get_page_setup(GTK_PRINT_UNIX_DIALOG(dialog));
424 GtkPrinter* printer = gtk_print_unix_dialog_get_selected_printer(GTK_PRINT_UNIX_DIALOG(dialog));
425 if (settings && setup && printer) {
426 ExportFramePrinting(aNSSettings, settings);
427 ExportHeaderFooter(aNSSettings);
429 aNSSettings->SetOutputFormat(nsIPrintSettings::kOutputFormatNative);
431 // Print-to-file is true by default. This must be turned off or else printing won't occur!
432 // (We manually copy the spool file when this flag is set, because we love our embedders)
433 // Even if it is print-to-file in GTK's case, GTK does The Right Thing when we send the job.
434 aNSSettings->SetPrintToFile(false);
436 aNSSettings->SetShrinkToFit(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(shrink_to_fit_toggle)));
438 aNSSettings->SetPrintBGColors(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(print_bg_colors_toggle)));
439 aNSSettings->SetPrintBGImages(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(print_bg_images_toggle)));
441 // Try to save native settings in the session object
442 nsCOMPtr<nsPrintSettingsGTK> aNSSettingsGTK(do_QueryInterface(aNSSettings));
443 if (aNSSettingsGTK) {
444 aNSSettingsGTK->SetGtkPrintSettings(settings);
445 aNSSettingsGTK->SetGtkPageSetup(setup);
446 aNSSettingsGTK->SetGtkPrinter(printer);
447 bool printSelectionOnly;
448 if (useNativeSelection) {
449 _GtkPrintPages pageSetting = (_GtkPrintPages)gtk_print_settings_get_print_pages(settings);
450 printSelectionOnly = (pageSetting == _GTK_PRINT_PAGES_SELECTION);
451 } else {
452 printSelectionOnly = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(selection_only_toggle));
454 aNSSettingsGTK->SetForcePrintSelectionOnly(printSelectionOnly);
458 if (settings)
459 g_object_unref(settings);
460 return NS_OK;
463 GtkWidget*
464 nsPrintDialogWidgetGTK::ConstructHeaderFooterDropdown(const char16_t *currentString)
466 GtkWidget* dropdown = gtk_combo_box_text_new();
467 const char hf_options[][22] = {"headerFooterBlank", "headerFooterTitle",
468 "headerFooterURL", "headerFooterDate",
469 "headerFooterPage", "headerFooterPageTotal",
470 "headerFooterCustom"};
472 for (unsigned int i = 0; i < ArrayLength(hf_options); i++) {
473 gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(dropdown), nullptr,
474 GetUTF8FromBundle(hf_options[i]).get());
477 bool shouldBeCustom = true;
478 NS_ConvertUTF16toUTF8 currentStringUTF8(currentString);
480 for (unsigned int i = 0; i < ArrayLength(header_footer_tags); i++) {
481 if (!strcmp(currentStringUTF8.get(), header_footer_tags[i])) {
482 gtk_combo_box_set_active(GTK_COMBO_BOX(dropdown), i);
483 g_object_set_data(G_OBJECT(dropdown), "previous-active", GINT_TO_POINTER(i));
484 shouldBeCustom = false;
485 break;
489 if (shouldBeCustom) {
490 gtk_combo_box_set_active(GTK_COMBO_BOX(dropdown), CUSTOM_VALUE_INDEX);
491 g_object_set_data(G_OBJECT(dropdown), "previous-active", GINT_TO_POINTER(CUSTOM_VALUE_INDEX));
492 char* custom_string = strdup(currentStringUTF8.get());
493 g_object_set_data_full(G_OBJECT(dropdown), "custom-text", custom_string, (GDestroyNotify) free);
496 g_signal_connect(dropdown, "changed", (GCallback) ShowCustomDialog, dialog);
497 return dropdown;
500 NS_IMPL_ISUPPORTS(nsPrintDialogServiceGTK, nsIPrintDialogService)
502 nsPrintDialogServiceGTK::nsPrintDialogServiceGTK()
506 nsPrintDialogServiceGTK::~nsPrintDialogServiceGTK()
510 NS_IMETHODIMP
511 nsPrintDialogServiceGTK::Init()
513 return NS_OK;
516 NS_IMETHODIMP
517 nsPrintDialogServiceGTK::Show(nsPIDOMWindowOuter *aParent,
518 nsIPrintSettings *aSettings,
519 nsIWebBrowserPrint *aWebBrowserPrint)
521 NS_PRECONDITION(aParent, "aParent must not be null");
522 NS_PRECONDITION(aSettings, "aSettings must not be null");
524 nsPrintDialogWidgetGTK printDialog(aParent, aSettings);
525 nsresult rv = printDialog.ImportSettings(aSettings);
527 NS_ENSURE_SUCCESS(rv, rv);
529 const gint response = printDialog.Run();
531 // Handle the result
532 switch (response) {
533 case GTK_RESPONSE_OK: // Proceed
534 rv = printDialog.ExportSettings(aSettings);
535 break;
537 case GTK_RESPONSE_CANCEL:
538 case GTK_RESPONSE_CLOSE:
539 case GTK_RESPONSE_DELETE_EVENT:
540 case GTK_RESPONSE_NONE:
541 rv = NS_ERROR_ABORT;
542 break;
544 case GTK_RESPONSE_APPLY: // Print preview
545 default:
546 NS_WARNING("Unexpected response");
547 rv = NS_ERROR_ABORT;
549 return rv;
552 NS_IMETHODIMP
553 nsPrintDialogServiceGTK::ShowPageSetup(nsPIDOMWindowOuter *aParent,
554 nsIPrintSettings *aNSSettings)
556 NS_PRECONDITION(aParent, "aParent must not be null");
557 NS_PRECONDITION(aNSSettings, "aSettings must not be null");
558 NS_ENSURE_TRUE(aNSSettings, NS_ERROR_FAILURE);
560 nsCOMPtr<nsIWidget> widget = WidgetUtils::DOMWindowToWidget(aParent);
561 NS_ASSERTION(widget, "Need a widget for dialog to be modal.");
562 GtkWindow* gtkParent = get_gtk_window_for_nsiwidget(widget);
563 NS_ASSERTION(gtkParent, "Need a GTK window for dialog to be modal.");
565 nsCOMPtr<nsPrintSettingsGTK> aNSSettingsGTK(do_QueryInterface(aNSSettings));
566 if (!aNSSettingsGTK)
567 return NS_ERROR_FAILURE;
569 // We need to init the prefs here because aNSSettings in its current form is a dummy in both uses of the word
570 nsCOMPtr<nsIPrintSettingsService> psService = do_GetService("@mozilla.org/gfx/printsettings-service;1");
571 if (psService) {
572 nsString printName;
573 aNSSettings->GetPrinterName(printName);
574 if (printName.IsVoid()) {
575 psService->GetDefaultPrinterName(printName);
576 aNSSettings->SetPrinterName(printName);
578 psService->InitPrintSettingsFromPrefs(aNSSettings, true, nsIPrintSettings::kInitSaveAll);
581 GtkPrintSettings* gtkSettings = aNSSettingsGTK->GetGtkPrintSettings();
582 GtkPageSetup* oldPageSetup = aNSSettingsGTK->GetGtkPageSetup();
584 GtkPageSetup* newPageSetup = gtk_print_run_page_setup_dialog(gtkParent, oldPageSetup, gtkSettings);
586 aNSSettingsGTK->SetGtkPageSetup(newPageSetup);
588 // Now newPageSetup has a refcount of 2 (SetGtkPageSetup will addref), put it to 1 so if
589 // this gets replaced we don't leak.
590 g_object_unref(newPageSetup);
592 if (psService)
593 psService->SavePrintSettingsToPrefs(aNSSettings, true, nsIPrintSettings::kInitSaveAll);
595 return NS_OK;