Bug 932076 - Add check for MediaExtractor creation failure. r=doublec
[gecko.git] / widget / gtk / nsPrintDialogGTK.cpp
blobf4f436b1af2b9eadd76b946507f83cf9dc29e643
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 #if (MOZ_WIDGET_GTK == 2)
8 #include <gtk/gtkprintunixdialog.h>
9 #else
10 #include <gtk/gtkunixprint.h>
11 #endif
12 #include <stdlib.h>
14 #include "mozilla/Util.h"
16 #include "mozcontainer.h"
17 #include "nsIPrintSettings.h"
18 #include "nsIWidget.h"
19 #include "nsPrintDialogGTK.h"
20 #include "nsPrintSettingsGTK.h"
21 #include "nsString.h"
22 #include "nsReadableUtils.h"
23 #include "nsIFile.h"
24 #include "nsNetUtil.h"
25 #include "nsIStringBundle.h"
26 #include "nsIPrintSettingsService.h"
27 #include "nsIDOMWindow.h"
28 #include "nsPIDOMWindow.h"
29 #include "nsIBaseWindow.h"
30 #include "nsIDocShellTreeItem.h"
31 #include "nsIDocShell.h"
32 #include "WidgetUtils.h"
34 using namespace mozilla;
35 using namespace mozilla::widget;
37 static const char header_footer_tags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
39 #define CUSTOM_VALUE_INDEX gint(ArrayLength(header_footer_tags))
41 static GtkWindow *
42 get_gtk_window_for_nsiwidget(nsIWidget *widget)
44 return GTK_WINDOW(widget->GetNativeData(NS_NATIVE_SHELLWIDGET));
47 static void
48 ShowCustomDialog(GtkComboBox *changed_box, gpointer user_data)
50 if (gtk_combo_box_get_active(changed_box) != CUSTOM_VALUE_INDEX) {
51 g_object_set_data(G_OBJECT(changed_box), "previous-active", GINT_TO_POINTER(gtk_combo_box_get_active(changed_box)));
52 return;
55 GtkWindow* printDialog = GTK_WINDOW(user_data);
56 nsCOMPtr<nsIStringBundleService> bundleSvc =
57 do_GetService(NS_STRINGBUNDLE_CONTRACTID);
59 nsCOMPtr<nsIStringBundle> printBundle;
60 bundleSvc->CreateBundle("chrome://global/locale/printdialog.properties", getter_AddRefs(printBundle));
61 nsXPIDLString intlString;
63 printBundle->GetStringFromName(NS_LITERAL_STRING("headerFooterCustom").get(), getter_Copies(intlString));
64 GtkWidget* prompt_dialog = gtk_dialog_new_with_buttons(NS_ConvertUTF16toUTF8(intlString).get(), printDialog,
65 #if (MOZ_WIDGET_GTK == 2)
66 (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR),
67 #else
68 (GtkDialogFlags)(GTK_DIALOG_MODAL),
69 #endif
70 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
71 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
72 nullptr);
73 gtk_dialog_set_default_response(GTK_DIALOG(prompt_dialog), GTK_RESPONSE_ACCEPT);
74 gtk_dialog_set_alternative_button_order(GTK_DIALOG(prompt_dialog),
75 GTK_RESPONSE_ACCEPT,
76 GTK_RESPONSE_REJECT,
77 -1);
79 printBundle->GetStringFromName(NS_LITERAL_STRING("customHeaderFooterPrompt").get(), getter_Copies(intlString));
80 GtkWidget* custom_label = gtk_label_new(NS_ConvertUTF16toUTF8(intlString).get());
81 GtkWidget* custom_entry = gtk_entry_new();
82 GtkWidget* question_icon = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
84 // To be convenient, prefill the textbox with the existing value, if any, and select it all so they can easily
85 // both edit it and type in a new one.
86 const char* current_text = (const char*) g_object_get_data(G_OBJECT(changed_box), "custom-text");
87 if (current_text) {
88 gtk_entry_set_text(GTK_ENTRY(custom_entry), current_text);
89 gtk_editable_select_region(GTK_EDITABLE(custom_entry), 0, -1);
91 gtk_entry_set_activates_default(GTK_ENTRY(custom_entry), TRUE);
93 GtkWidget* custom_vbox = gtk_vbox_new(TRUE, 2);
94 gtk_box_pack_start(GTK_BOX(custom_vbox), custom_label, FALSE, FALSE, 0);
95 gtk_box_pack_start(GTK_BOX(custom_vbox), custom_entry, FALSE, FALSE, 5); // Make entry 5px underneath label
96 GtkWidget* custom_hbox = gtk_hbox_new(FALSE, 2);
97 gtk_box_pack_start(GTK_BOX(custom_hbox), question_icon, FALSE, FALSE, 0);
98 gtk_box_pack_start(GTK_BOX(custom_hbox), custom_vbox, FALSE, FALSE, 10); // Make question icon 10px away from content
99 gtk_container_set_border_width(GTK_CONTAINER(custom_hbox), 2);
100 gtk_widget_show_all(custom_hbox);
102 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(prompt_dialog))),
103 custom_hbox, FALSE, FALSE, 0);
104 gint diag_response = gtk_dialog_run(GTK_DIALOG(prompt_dialog));
106 if (diag_response == GTK_RESPONSE_ACCEPT) {
107 const gchar* response_text = gtk_entry_get_text(GTK_ENTRY(custom_entry));
108 g_object_set_data_full(G_OBJECT(changed_box), "custom-text", strdup(response_text), (GDestroyNotify) free);
109 g_object_set_data(G_OBJECT(changed_box), "previous-active", GINT_TO_POINTER(CUSTOM_VALUE_INDEX));
110 } else {
111 // Go back to the previous index
112 gint previous_active = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(changed_box), "previous-active"));
113 gtk_combo_box_set_active(changed_box, previous_active);
116 gtk_widget_destroy(prompt_dialog);
119 class nsPrintDialogWidgetGTK {
120 public:
121 nsPrintDialogWidgetGTK(nsIDOMWindow *aParent, nsIPrintSettings *aPrintSettings);
122 ~nsPrintDialogWidgetGTK() { gtk_widget_destroy(dialog); }
123 NS_ConvertUTF16toUTF8 GetUTF8FromBundle(const char* aKey);
124 const gint Run();
126 nsresult ImportSettings(nsIPrintSettings *aNSSettings);
127 nsresult ExportSettings(nsIPrintSettings *aNSSettings);
129 private:
130 GtkWidget* dialog;
131 GtkWidget* radio_as_laid_out;
132 GtkWidget* radio_selected_frame;
133 GtkWidget* radio_separate_frames;
134 GtkWidget* shrink_to_fit_toggle;
135 GtkWidget* print_bg_colors_toggle;
136 GtkWidget* print_bg_images_toggle;
137 GtkWidget* selection_only_toggle;
138 GtkWidget* header_dropdown[3]; // {left, center, right}
139 GtkWidget* footer_dropdown[3];
141 nsCOMPtr<nsIStringBundle> printBundle;
143 bool useNativeSelection;
145 GtkWidget* ConstructHeaderFooterDropdown(const PRUnichar *currentString);
146 const char* OptionWidgetToString(GtkWidget *dropdown);
148 /* Code to copy between GTK and NS print settings structures.
149 * In the following,
150 * "Import" means to copy from NS to GTK
151 * "Export" means to copy from GTK to NS
153 void ExportFramePrinting(nsIPrintSettings *aNS, GtkPrintSettings *aSettings);
154 void ExportHeaderFooter(nsIPrintSettings *aNS);
157 nsPrintDialogWidgetGTK::nsPrintDialogWidgetGTK(nsIDOMWindow *aParent, nsIPrintSettings *aSettings)
159 nsCOMPtr<nsIWidget> widget = WidgetUtils::DOMWindowToWidget(aParent);
160 NS_ASSERTION(widget, "Need a widget for dialog to be modal.");
161 GtkWindow* gtkParent = get_gtk_window_for_nsiwidget(widget);
162 NS_ASSERTION(gtkParent, "Need a GTK window for dialog to be modal.");
164 nsCOMPtr<nsIStringBundleService> bundleSvc = do_GetService(NS_STRINGBUNDLE_CONTRACTID);
165 bundleSvc->CreateBundle("chrome://global/locale/printdialog.properties", getter_AddRefs(printBundle));
167 dialog = gtk_print_unix_dialog_new(GetUTF8FromBundle("printTitleGTK").get(), gtkParent);
169 gtk_print_unix_dialog_set_manual_capabilities(GTK_PRINT_UNIX_DIALOG(dialog),
170 GtkPrintCapabilities(
171 GTK_PRINT_CAPABILITY_PAGE_SET
172 | GTK_PRINT_CAPABILITY_COPIES
173 | GTK_PRINT_CAPABILITY_COLLATE
174 | GTK_PRINT_CAPABILITY_REVERSE
175 | GTK_PRINT_CAPABILITY_SCALE
176 | GTK_PRINT_CAPABILITY_GENERATE_PDF
177 | GTK_PRINT_CAPABILITY_GENERATE_PS
181 // The vast majority of magic numbers in this widget construction are padding. e.g. for
182 // the set_border_width below, 12px matches that of just about every other window.
183 GtkWidget* custom_options_tab = gtk_vbox_new(FALSE, 0);
184 gtk_container_set_border_width(GTK_CONTAINER(custom_options_tab), 12);
185 GtkWidget* tab_label = gtk_label_new(GetUTF8FromBundle("optionsTabLabelGTK").get());
187 int16_t frameUIFlag;
188 aSettings->GetHowToEnableFrameUI(&frameUIFlag);
189 radio_as_laid_out = gtk_radio_button_new_with_mnemonic(nullptr, GetUTF8FromBundle("asLaidOut").get());
190 if (frameUIFlag == nsIPrintSettings::kFrameEnableNone)
191 gtk_widget_set_sensitive(radio_as_laid_out, FALSE);
193 radio_selected_frame = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(radio_as_laid_out),
194 GetUTF8FromBundle("selectedFrame").get());
195 if (frameUIFlag == nsIPrintSettings::kFrameEnableNone ||
196 frameUIFlag == nsIPrintSettings::kFrameEnableAsIsAndEach)
197 gtk_widget_set_sensitive(radio_selected_frame, FALSE);
199 radio_separate_frames = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(radio_as_laid_out),
200 GetUTF8FromBundle("separateFrames").get());
201 if (frameUIFlag == nsIPrintSettings::kFrameEnableNone)
202 gtk_widget_set_sensitive(radio_separate_frames, FALSE);
204 // "Print Frames" options label, bold and center-aligned
205 GtkWidget* print_frames_label = gtk_label_new(nullptr);
206 char* pangoMarkup = g_markup_printf_escaped("<b>%s</b>", GetUTF8FromBundle("printFramesTitleGTK").get());
207 gtk_label_set_markup(GTK_LABEL(print_frames_label), pangoMarkup);
208 g_free(pangoMarkup);
209 gtk_misc_set_alignment(GTK_MISC(print_frames_label), 0, 0);
211 // Align the radio buttons slightly so they appear to fall under the aforementioned label as per the GNOME HIG
212 GtkWidget* frames_radio_container = gtk_alignment_new(0, 0, 0, 0);
213 gtk_alignment_set_padding(GTK_ALIGNMENT(frames_radio_container), 8, 0, 12, 0);
215 // Radio buttons for the print frames options
216 GtkWidget* frames_radio_list = gtk_vbox_new(TRUE, 2);
217 gtk_box_pack_start(GTK_BOX(frames_radio_list), radio_as_laid_out, FALSE, FALSE, 0);
218 gtk_box_pack_start(GTK_BOX(frames_radio_list), radio_selected_frame, FALSE, FALSE, 0);
219 gtk_box_pack_start(GTK_BOX(frames_radio_list), radio_separate_frames, FALSE, FALSE, 0);
220 gtk_container_add(GTK_CONTAINER(frames_radio_container), frames_radio_list);
222 // Check buttons for shrink-to-fit and print selection
223 GtkWidget* check_buttons_container = gtk_vbox_new(TRUE, 2);
224 shrink_to_fit_toggle = gtk_check_button_new_with_mnemonic(GetUTF8FromBundle("shrinkToFit").get());
225 gtk_box_pack_start(GTK_BOX(check_buttons_container), shrink_to_fit_toggle, FALSE, FALSE, 0);
227 // GTK+2.18 and above allow us to add a "Selection" option to the main settings screen,
228 // rather than adding an option on a custom tab like we must do on older versions.
229 bool canSelectText;
230 aSettings->GetPrintOptions(nsIPrintSettings::kEnableSelectionRB, &canSelectText);
231 if (gtk_major_version > 2 ||
232 (gtk_major_version == 2 && gtk_minor_version >= 18)) {
233 useNativeSelection = true;
234 g_object_set(dialog,
235 "support-selection", TRUE,
236 "has-selection", canSelectText,
237 "embed-page-setup", TRUE,
238 nullptr);
239 } else {
240 useNativeSelection = false;
241 selection_only_toggle = gtk_check_button_new_with_mnemonic(GetUTF8FromBundle("selectionOnly").get());
242 gtk_widget_set_sensitive(selection_only_toggle, canSelectText);
243 gtk_box_pack_start(GTK_BOX(check_buttons_container), selection_only_toggle, FALSE, FALSE, 0);
246 // Check buttons for printing background
247 GtkWidget* appearance_buttons_container = gtk_vbox_new(TRUE, 2);
248 print_bg_colors_toggle = gtk_check_button_new_with_mnemonic(GetUTF8FromBundle("printBGColors").get());
249 print_bg_images_toggle = gtk_check_button_new_with_mnemonic(GetUTF8FromBundle("printBGImages").get());
250 gtk_box_pack_start(GTK_BOX(appearance_buttons_container), print_bg_colors_toggle, FALSE, FALSE, 0);
251 gtk_box_pack_start(GTK_BOX(appearance_buttons_container), print_bg_images_toggle, FALSE, FALSE, 0);
253 // "Appearance" options label, bold and center-aligned
254 GtkWidget* appearance_label = gtk_label_new(nullptr);
255 pangoMarkup = g_markup_printf_escaped("<b>%s</b>", GetUTF8FromBundle("printBGOptions").get());
256 gtk_label_set_markup(GTK_LABEL(appearance_label), pangoMarkup);
257 g_free(pangoMarkup);
258 gtk_misc_set_alignment(GTK_MISC(appearance_label), 0, 0);
260 GtkWidget* appearance_container = gtk_alignment_new(0, 0, 0, 0);
261 gtk_alignment_set_padding(GTK_ALIGNMENT(appearance_container), 8, 0, 12, 0);
262 gtk_container_add(GTK_CONTAINER(appearance_container), appearance_buttons_container);
264 GtkWidget* appearance_vertical_squasher = gtk_vbox_new(FALSE, 0);
265 gtk_box_pack_start(GTK_BOX(appearance_vertical_squasher), appearance_label, FALSE, FALSE, 0);
266 gtk_box_pack_start(GTK_BOX(appearance_vertical_squasher), appearance_container, FALSE, FALSE, 0);
268 // "Header & Footer" options label, bold and center-aligned
269 GtkWidget* header_footer_label = gtk_label_new(nullptr);
270 pangoMarkup = g_markup_printf_escaped("<b>%s</b>", GetUTF8FromBundle("headerFooter").get());
271 gtk_label_set_markup(GTK_LABEL(header_footer_label), pangoMarkup);
272 g_free(pangoMarkup);
273 gtk_misc_set_alignment(GTK_MISC(header_footer_label), 0, 0);
275 GtkWidget* header_footer_container = gtk_alignment_new(0, 0, 0, 0);
276 gtk_alignment_set_padding(GTK_ALIGNMENT(header_footer_container), 8, 0, 12, 0);
279 // --- Table for making the header and footer options ---
280 GtkWidget* header_footer_table = gtk_table_new(3, 3, FALSE); // 3x3 table
281 nsXPIDLString header_footer_str[3];
283 aSettings->GetHeaderStrLeft(getter_Copies(header_footer_str[0]));
284 aSettings->GetHeaderStrCenter(getter_Copies(header_footer_str[1]));
285 aSettings->GetHeaderStrRight(getter_Copies(header_footer_str[2]));
287 for (unsigned int i = 0; i < ArrayLength(header_dropdown); i++) {
288 header_dropdown[i] = ConstructHeaderFooterDropdown(header_footer_str[i].get());
289 // Those 4 magic numbers in the middle provide the position in the table.
290 // The last two numbers mean 2 px padding on every side.
291 gtk_table_attach(GTK_TABLE(header_footer_table), header_dropdown[i], i, (i + 1),
292 0, 1, (GtkAttachOptions) 0, (GtkAttachOptions) 0, 2, 2);
295 const char labelKeys[][7] = {"left", "center", "right"};
296 for (unsigned int i = 0; i < ArrayLength(labelKeys); i++) {
297 gtk_table_attach(GTK_TABLE(header_footer_table),
298 gtk_label_new(GetUTF8FromBundle(labelKeys[i]).get()),
299 i, (i + 1), 1, 2, (GtkAttachOptions) 0, (GtkAttachOptions) 0, 2, 2);
302 aSettings->GetFooterStrLeft(getter_Copies(header_footer_str[0]));
303 aSettings->GetFooterStrCenter(getter_Copies(header_footer_str[1]));
304 aSettings->GetFooterStrRight(getter_Copies(header_footer_str[2]));
306 for (unsigned int i = 0; i < ArrayLength(footer_dropdown); i++) {
307 footer_dropdown[i] = ConstructHeaderFooterDropdown(header_footer_str[i].get());
308 gtk_table_attach(GTK_TABLE(header_footer_table), footer_dropdown[i], i, (i + 1),
309 2, 3, (GtkAttachOptions) 0, (GtkAttachOptions) 0, 2, 2);
311 // ---
313 gtk_container_add(GTK_CONTAINER(header_footer_container), header_footer_table);
315 GtkWidget* header_footer_vertical_squasher = gtk_vbox_new(FALSE, 0);
316 gtk_box_pack_start(GTK_BOX(header_footer_vertical_squasher), header_footer_label, FALSE, FALSE, 0);
317 gtk_box_pack_start(GTK_BOX(header_footer_vertical_squasher), header_footer_container, FALSE, FALSE, 0);
319 // Construction of everything
320 gtk_box_pack_start(GTK_BOX(custom_options_tab), print_frames_label, FALSE, FALSE, 0);
321 gtk_box_pack_start(GTK_BOX(custom_options_tab), frames_radio_container, FALSE, FALSE, 0);
322 gtk_box_pack_start(GTK_BOX(custom_options_tab), check_buttons_container, FALSE, FALSE, 10); // 10px padding
323 gtk_box_pack_start(GTK_BOX(custom_options_tab), appearance_vertical_squasher, FALSE, FALSE, 10);
324 gtk_box_pack_start(GTK_BOX(custom_options_tab), header_footer_vertical_squasher, FALSE, FALSE, 0);
326 gtk_print_unix_dialog_add_custom_tab(GTK_PRINT_UNIX_DIALOG(dialog), custom_options_tab, tab_label);
327 gtk_widget_show_all(custom_options_tab);
330 NS_ConvertUTF16toUTF8
331 nsPrintDialogWidgetGTK::GetUTF8FromBundle(const char *aKey)
333 nsXPIDLString intlString;
334 printBundle->GetStringFromName(NS_ConvertUTF8toUTF16(aKey).get(), getter_Copies(intlString));
335 return NS_ConvertUTF16toUTF8(intlString); // Return the actual object so we don't lose reference
338 const char*
339 nsPrintDialogWidgetGTK::OptionWidgetToString(GtkWidget *dropdown)
341 gint index = gtk_combo_box_get_active(GTK_COMBO_BOX(dropdown));
343 NS_ASSERTION(index <= CUSTOM_VALUE_INDEX, "Index of dropdown is higher than expected!");
345 if (index == CUSTOM_VALUE_INDEX)
346 return (const char*) g_object_get_data(G_OBJECT(dropdown), "custom-text");
347 else
348 return header_footer_tags[index];
351 const gint
352 nsPrintDialogWidgetGTK::Run()
354 const gint response = gtk_dialog_run(GTK_DIALOG(dialog));
355 gtk_widget_hide(dialog);
356 return response;
359 void
360 nsPrintDialogWidgetGTK::ExportFramePrinting(nsIPrintSettings *aNS, GtkPrintSettings *aSettings)
362 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_as_laid_out)))
363 aNS->SetPrintFrameType(nsIPrintSettings::kFramesAsIs);
364 else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_selected_frame)))
365 aNS->SetPrintFrameType(nsIPrintSettings::kSelectedFrame);
366 else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_separate_frames)))
367 aNS->SetPrintFrameType(nsIPrintSettings::kEachFrameSep);
368 else
369 aNS->SetPrintFrameType(nsIPrintSettings::kNoFrames);
372 void
373 nsPrintDialogWidgetGTK::ExportHeaderFooter(nsIPrintSettings *aNS)
375 const char* header_footer_str;
376 header_footer_str = OptionWidgetToString(header_dropdown[0]);
377 aNS->SetHeaderStrLeft(NS_ConvertUTF8toUTF16(header_footer_str).get());
379 header_footer_str = OptionWidgetToString(header_dropdown[1]);
380 aNS->SetHeaderStrCenter(NS_ConvertUTF8toUTF16(header_footer_str).get());
382 header_footer_str = OptionWidgetToString(header_dropdown[2]);
383 aNS->SetHeaderStrRight(NS_ConvertUTF8toUTF16(header_footer_str).get());
385 header_footer_str = OptionWidgetToString(footer_dropdown[0]);
386 aNS->SetFooterStrLeft(NS_ConvertUTF8toUTF16(header_footer_str).get());
388 header_footer_str = OptionWidgetToString(footer_dropdown[1]);
389 aNS->SetFooterStrCenter(NS_ConvertUTF8toUTF16(header_footer_str).get());
391 header_footer_str = OptionWidgetToString(footer_dropdown[2]);
392 aNS->SetFooterStrRight(NS_ConvertUTF8toUTF16(header_footer_str).get());
395 nsresult
396 nsPrintDialogWidgetGTK::ImportSettings(nsIPrintSettings *aNSSettings)
398 NS_PRECONDITION(aNSSettings, "aSettings must not be null");
399 NS_ENSURE_TRUE(aNSSettings, NS_ERROR_FAILURE);
401 nsCOMPtr<nsPrintSettingsGTK> aNSSettingsGTK(do_QueryInterface(aNSSettings));
402 if (!aNSSettingsGTK)
403 return NS_ERROR_FAILURE;
405 GtkPrintSettings* settings = aNSSettingsGTK->GetGtkPrintSettings();
406 GtkPageSetup* setup = aNSSettingsGTK->GetGtkPageSetup();
408 bool geckoBool;
409 aNSSettings->GetShrinkToFit(&geckoBool);
410 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(shrink_to_fit_toggle), geckoBool);
412 aNSSettings->GetPrintBGColors(&geckoBool);
413 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(print_bg_colors_toggle), geckoBool);
415 aNSSettings->GetPrintBGImages(&geckoBool);
416 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(print_bg_images_toggle), geckoBool);
418 gtk_print_unix_dialog_set_settings(GTK_PRINT_UNIX_DIALOG(dialog), settings);
419 gtk_print_unix_dialog_set_page_setup(GTK_PRINT_UNIX_DIALOG(dialog), setup);
421 return NS_OK;
424 nsresult
425 nsPrintDialogWidgetGTK::ExportSettings(nsIPrintSettings *aNSSettings)
427 NS_PRECONDITION(aNSSettings, "aSettings must not be null");
428 NS_ENSURE_TRUE(aNSSettings, NS_ERROR_FAILURE);
430 GtkPrintSettings* settings = gtk_print_unix_dialog_get_settings(GTK_PRINT_UNIX_DIALOG(dialog));
431 GtkPageSetup* setup = gtk_print_unix_dialog_get_page_setup(GTK_PRINT_UNIX_DIALOG(dialog));
432 GtkPrinter* printer = gtk_print_unix_dialog_get_selected_printer(GTK_PRINT_UNIX_DIALOG(dialog));
433 if (settings && setup && printer) {
434 ExportFramePrinting(aNSSettings, settings);
435 ExportHeaderFooter(aNSSettings);
437 aNSSettings->SetOutputFormat(nsIPrintSettings::kOutputFormatNative);
439 // Print-to-file is true by default. This must be turned off or else printing won't occur!
440 // (We manually copy the spool file when this flag is set, because we love our embedders)
441 // Even if it is print-to-file in GTK's case, GTK does The Right Thing when we send the job.
442 aNSSettings->SetPrintToFile(false);
444 aNSSettings->SetShrinkToFit(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(shrink_to_fit_toggle)));
446 aNSSettings->SetPrintBGColors(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(print_bg_colors_toggle)));
447 aNSSettings->SetPrintBGImages(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(print_bg_images_toggle)));
449 // Try to save native settings in the session object
450 nsCOMPtr<nsPrintSettingsGTK> aNSSettingsGTK(do_QueryInterface(aNSSettings));
451 if (aNSSettingsGTK) {
452 aNSSettingsGTK->SetGtkPrintSettings(settings);
453 aNSSettingsGTK->SetGtkPageSetup(setup);
454 aNSSettingsGTK->SetGtkPrinter(printer);
455 bool printSelectionOnly;
456 if (useNativeSelection) {
457 _GtkPrintPages pageSetting = (_GtkPrintPages)gtk_print_settings_get_print_pages(settings);
458 printSelectionOnly = (pageSetting == _GTK_PRINT_PAGES_SELECTION);
459 } else {
460 printSelectionOnly = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(selection_only_toggle));
462 aNSSettingsGTK->SetForcePrintSelectionOnly(printSelectionOnly);
466 if (settings)
467 g_object_unref(settings);
468 return NS_OK;
471 GtkWidget*
472 nsPrintDialogWidgetGTK::ConstructHeaderFooterDropdown(const PRUnichar *currentString)
474 #if (MOZ_WIDGET_GTK == 2)
475 GtkWidget* dropdown = gtk_combo_box_new_text();
476 #else
477 GtkWidget* dropdown = gtk_combo_box_text_new();
478 #endif
479 const char hf_options[][22] = {"headerFooterBlank", "headerFooterTitle",
480 "headerFooterURL", "headerFooterDate",
481 "headerFooterPage", "headerFooterPageTotal",
482 "headerFooterCustom"};
484 for (unsigned int i = 0; i < ArrayLength(hf_options); i++) {
485 #if (MOZ_WIDGET_GTK == 2)
486 gtk_combo_box_append_text(GTK_COMBO_BOX(dropdown), GetUTF8FromBundle(hf_options[i]).get());
487 #else
488 gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(dropdown), nullptr,
489 GetUTF8FromBundle(hf_options[i]).get());
490 #endif
493 bool shouldBeCustom = true;
494 NS_ConvertUTF16toUTF8 currentStringUTF8(currentString);
496 for (unsigned int i = 0; i < ArrayLength(header_footer_tags); i++) {
497 if (!strcmp(currentStringUTF8.get(), header_footer_tags[i])) {
498 gtk_combo_box_set_active(GTK_COMBO_BOX(dropdown), i);
499 g_object_set_data(G_OBJECT(dropdown), "previous-active", GINT_TO_POINTER(i));
500 shouldBeCustom = false;
501 break;
505 if (shouldBeCustom) {
506 gtk_combo_box_set_active(GTK_COMBO_BOX(dropdown), CUSTOM_VALUE_INDEX);
507 g_object_set_data(G_OBJECT(dropdown), "previous-active", GINT_TO_POINTER(CUSTOM_VALUE_INDEX));
508 char* custom_string = strdup(currentStringUTF8.get());
509 g_object_set_data_full(G_OBJECT(dropdown), "custom-text", custom_string, (GDestroyNotify) free);
512 g_signal_connect(dropdown, "changed", (GCallback) ShowCustomDialog, dialog);
513 return dropdown;
516 NS_IMPL_ISUPPORTS1(nsPrintDialogServiceGTK, nsIPrintDialogService)
518 nsPrintDialogServiceGTK::nsPrintDialogServiceGTK()
522 nsPrintDialogServiceGTK::~nsPrintDialogServiceGTK()
526 NS_IMETHODIMP
527 nsPrintDialogServiceGTK::Init()
529 return NS_OK;
532 NS_IMETHODIMP
533 nsPrintDialogServiceGTK::Show(nsIDOMWindow *aParent, nsIPrintSettings *aSettings,
534 nsIWebBrowserPrint *aWebBrowserPrint)
536 NS_PRECONDITION(aParent, "aParent must not be null");
537 NS_PRECONDITION(aSettings, "aSettings must not be null");
539 nsPrintDialogWidgetGTK printDialog(aParent, aSettings);
540 nsresult rv = printDialog.ImportSettings(aSettings);
542 NS_ENSURE_SUCCESS(rv, rv);
544 const gint response = printDialog.Run();
546 // Handle the result
547 switch (response) {
548 case GTK_RESPONSE_OK: // Proceed
549 rv = printDialog.ExportSettings(aSettings);
550 break;
552 case GTK_RESPONSE_CANCEL:
553 case GTK_RESPONSE_CLOSE:
554 case GTK_RESPONSE_DELETE_EVENT:
555 case GTK_RESPONSE_NONE:
556 rv = NS_ERROR_ABORT;
557 break;
559 case GTK_RESPONSE_APPLY: // Print preview
560 default:
561 NS_WARNING("Unexpected response");
562 rv = NS_ERROR_ABORT;
564 return rv;
567 NS_IMETHODIMP
568 nsPrintDialogServiceGTK::ShowPageSetup(nsIDOMWindow *aParent,
569 nsIPrintSettings *aNSSettings)
571 NS_PRECONDITION(aParent, "aParent must not be null");
572 NS_PRECONDITION(aNSSettings, "aSettings must not be null");
573 NS_ENSURE_TRUE(aNSSettings, NS_ERROR_FAILURE);
575 nsCOMPtr<nsIWidget> widget = WidgetUtils::DOMWindowToWidget(aParent);
576 NS_ASSERTION(widget, "Need a widget for dialog to be modal.");
577 GtkWindow* gtkParent = get_gtk_window_for_nsiwidget(widget);
578 NS_ASSERTION(gtkParent, "Need a GTK window for dialog to be modal.");
580 nsCOMPtr<nsPrintSettingsGTK> aNSSettingsGTK(do_QueryInterface(aNSSettings));
581 if (!aNSSettingsGTK)
582 return NS_ERROR_FAILURE;
584 // We need to init the prefs here because aNSSettings in its current form is a dummy in both uses of the word
585 nsCOMPtr<nsIPrintSettingsService> psService = do_GetService("@mozilla.org/gfx/printsettings-service;1");
586 if (psService) {
587 nsXPIDLString printName;
588 aNSSettings->GetPrinterName(getter_Copies(printName));
589 if (!printName) {
590 psService->GetDefaultPrinterName(getter_Copies(printName));
591 aNSSettings->SetPrinterName(printName.get());
593 psService->InitPrintSettingsFromPrefs(aNSSettings, true, nsIPrintSettings::kInitSaveAll);
596 GtkPrintSettings* gtkSettings = aNSSettingsGTK->GetGtkPrintSettings();
597 GtkPageSetup* oldPageSetup = aNSSettingsGTK->GetGtkPageSetup();
599 GtkPageSetup* newPageSetup = gtk_print_run_page_setup_dialog(gtkParent, oldPageSetup, gtkSettings);
601 aNSSettingsGTK->SetGtkPageSetup(newPageSetup);
603 // Now newPageSetup has a refcount of 2 (SetGtkPageSetup will addref), put it to 1 so if
604 // this gets replaced we don't leak.
605 g_object_unref(newPageSetup);
607 if (psService)
608 psService->SavePrintSettingsToPrefs(aNSSettings, true, nsIPrintSettings::kInitSaveAll);
610 return NS_OK;