widget/gtk/nsPrintDialogGTK.cpp

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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/ArrayUtils.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)
    43 {
    44   return GTK_WINDOW(widget->GetNativeData(NS_NATIVE_SHELLWIDGET));
    45 }
    47 static void
    48 ShowCustomDialog(GtkComboBox *changed_box, gpointer user_data)
    49 {
    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;
    53   }
    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(MOZ_UTF16("headerFooterCustom"), 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(MOZ_UTF16("customHeaderFooterPrompt"), 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);
    90   }
    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);
   114   }
   116   gtk_widget_destroy(prompt_dialog);
   117 }
   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 char16_t *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
   152      */
   153     void ExportFramePrinting(nsIPrintSettings *aNS, GtkPrintSettings *aSettings);
   154     void ExportHeaderFooter(nsIPrintSettings *aNS);
   155 };
   157 nsPrintDialogWidgetGTK::nsPrintDialogWidgetGTK(nsIDOMWindow *aParent, nsIPrintSettings *aSettings)
   158 {
   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
   178                     )
   179                   );
   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);
   244   }
   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);
   293   }
   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);
   300   }
   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);
   310   }
   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);
   328 }
   330 NS_ConvertUTF16toUTF8
   331 nsPrintDialogWidgetGTK::GetUTF8FromBundle(const char *aKey)
   332 {
   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
   336 }
   338 const char*
   339 nsPrintDialogWidgetGTK::OptionWidgetToString(GtkWidget *dropdown)
   340 {
   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];
   349 }
   351 const gint
   352 nsPrintDialogWidgetGTK::Run()
   353 {
   354   const gint response = gtk_dialog_run(GTK_DIALOG(dialog));
   355   gtk_widget_hide(dialog);
   356   return response;
   357 }
   359 void
   360 nsPrintDialogWidgetGTK::ExportFramePrinting(nsIPrintSettings *aNS, GtkPrintSettings *aSettings)
   361 {
   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);
   370 }
   372 void
   373 nsPrintDialogWidgetGTK::ExportHeaderFooter(nsIPrintSettings *aNS)
   374 {
   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());
   393 }
   395 nsresult
   396 nsPrintDialogWidgetGTK::ImportSettings(nsIPrintSettings *aNSSettings)
   397 {
   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;
   422 }
   424 nsresult
   425 nsPrintDialogWidgetGTK::ExportSettings(nsIPrintSettings *aNSSettings)
   426 {
   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));
   461       }
   462       aNSSettingsGTK->SetForcePrintSelectionOnly(printSelectionOnly);
   463     }
   464   }
   466   if (settings)
   467     g_object_unref(settings);
   468   return NS_OK;
   469 }
   471 GtkWidget*
   472 nsPrintDialogWidgetGTK::ConstructHeaderFooterDropdown(const char16_t *currentString)
   473 {
   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
   491   }
   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;
   502     }
   503   }
   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);
   510   }
   512   g_signal_connect(dropdown, "changed", (GCallback) ShowCustomDialog, dialog);
   513   return dropdown;
   514 }
   516 NS_IMPL_ISUPPORTS(nsPrintDialogServiceGTK, nsIPrintDialogService)
   518 nsPrintDialogServiceGTK::nsPrintDialogServiceGTK()
   519 {
   520 }
   522 nsPrintDialogServiceGTK::~nsPrintDialogServiceGTK()
   523 {
   524 }
   526 NS_IMETHODIMP
   527 nsPrintDialogServiceGTK::Init()
   528 {
   529   return NS_OK;
   530 }
   532 NS_IMETHODIMP
   533 nsPrintDialogServiceGTK::Show(nsIDOMWindow *aParent, nsIPrintSettings *aSettings,
   534                               nsIWebBrowserPrint *aWebBrowserPrint)
   535 {
   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;
   563   }
   564   return rv;
   565 }
   567 NS_IMETHODIMP
   568 nsPrintDialogServiceGTK::ShowPageSetup(nsIDOMWindow *aParent,
   569                                        nsIPrintSettings *aNSSettings)
   570 {
   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());
   592     }
   593     psService->InitPrintSettingsFromPrefs(aNSSettings, true, nsIPrintSettings::kInitSaveAll);
   594   }
   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;
   611 }

mercurial