Bug 193001 - "Use gnome's native print dialog" [p=ventnor.bugzilla@yahoo.com.au (Michael Ventnor) r+sr+a1.9=roc]
authorreed@reedloden.com
Sun, 20 Jan 2008 19:47:25 -0800
changeset 10489 f366e46977d1b387dc29f65a938e879fe319ee9c
parent 10488 60aef131e29c0d9259eaf4c8fc824ed556996df2
child 10490 adf51d8b60d5f092f6620a777211ce46ccc1cedc
push idunknown
push userunknown
push dateunknown
bugs193001
milestone1.9b3pre
Bug 193001 - "Use gnome's native print dialog" [p=ventnor.bugzilla@yahoo.com.au (Michael Ventnor) r+sr+a1.9=roc]
config/system-headers
configure.in
embedding/components/printingui/src/unixshared/nsPrintingPromptService.cpp
layout/base/nsDocumentViewer.cpp
layout/printing/nsPrintEngine.cpp
toolkit/locales/en-US/chrome/global/gnomeprintdialog.properties
toolkit/locales/jar.mn
widget/public/Makefile.in
widget/public/nsIPrintDialogService.h
widget/public/nsIPrintSettings.idl
widget/public/nsWidgetsCID.h
widget/src/gtk2/Makefile.in
widget/src/gtk2/nsDeviceContextSpecG.cpp
widget/src/gtk2/nsDeviceContextSpecG.h
widget/src/gtk2/nsIPrintJobGTK.h
widget/src/gtk2/nsPrintDialogGTK.cpp
widget/src/gtk2/nsPrintDialogGTK.h
widget/src/gtk2/nsPrintJobFactoryGTK.cpp
widget/src/gtk2/nsPrintJobFactoryGTK.h
widget/src/gtk2/nsPrintJobGTK.cpp
widget/src/gtk2/nsPrintJobGTK.h
widget/src/gtk2/nsPrintOptionsGTK.cpp
widget/src/gtk2/nsPrintOptionsGTK.h
widget/src/gtk2/nsPrintSettingsGTK.cpp
widget/src/gtk2/nsPrintSettingsGTK.h
widget/src/gtk2/nsWidgetFactory.cpp
widget/src/xpwidgets/nsPrintSettingsImpl.cpp
--- a/config/system-headers
+++ b/config/system-headers
@@ -245,16 +245,19 @@ gtk/gtkfixed.h
 gtk/gtk.h
 gtk/gtkiconfactory.h
 gtk/gtkimage.h
 gtk/gtkimmulticontext.h
 gtk/gtkinvisible.h
 gtk/gtkmain.h
 gtk/gtkmessagedialog.h
 gtk/gtkobject.h
+gtk/gtkprinter.h
+gtk/gtkprintjob.h
+gtk/gtkprintunixdialog.h
 gtk/gtkprivate.h
 gtk/gtkselection.h
 gtk/gtksignal.h
 gtk/gtksocket.h
 gtk/gtkstock.h
 gtk/gtkstyle.h
 gtk/gtktextview.h
 gtk/gtkvscrollbar.h
--- a/configure.in
+++ b/configure.in
@@ -4594,17 +4594,17 @@ esac
 
 if test "$MOZ_ENABLE_XREMOTE"; then
     AC_DEFINE(MOZ_ENABLE_XREMOTE)
 fi
 
 if test "$COMPILE_ENVIRONMENT"; then
 if test "$MOZ_ENABLE_GTK2"
 then
-    PKG_CHECK_MODULES(MOZ_GTK2, gtk+-2.0 >= $GTK2_VERSION gdk-x11-2.0 glib-2.0 gobject-2.0)
+    PKG_CHECK_MODULES(MOZ_GTK2, gtk+-2.0 >= $GTK2_VERSION gtk+-unix-print-2.0 gdk-x11-2.0 glib-2.0 gobject-2.0)
 fi
 fi # COMPILE_ENVIRONMENT
 
 AC_SUBST(MOZ_DEFAULT_TOOLKIT)
 
 dnl ========================================================
 dnl = startup-notification support module
 dnl ========================================================
--- a/embedding/components/printingui/src/unixshared/nsPrintingPromptService.cpp
+++ b/embedding/components/printingui/src/unixshared/nsPrintingPromptService.cpp
@@ -39,16 +39,17 @@
 
 #include "nsIComponentManager.h"
 #include "nsIDialogParamBlock.h"
 #include "nsIDOMWindow.h"
 #include "nsIServiceManager.h"
 #include "nsISupportsUtils.h"
 #include "nsISupportsArray.h"
 #include "nsString.h"
+#include "nsIPrintDialogService.h"
 
 // Printing Progress Includes
 #include "nsPrintProgress.h"
 #include "nsPrintProgressParams.h"
 
 static const char *kPrintDialogURL         = "chrome://global/content/printdialog.xul";
 static const char *kPrintProgressDialogURL = "chrome://global/content/printProgress.xul";
 static const char *kPrtPrvProgressDialogURL = "chrome://global/content/printPreviewProgress.xul";
@@ -104,16 +105,23 @@ nsPrintingPromptService::Init()
 
 /* void showPrintDialog (in nsIDOMWindow parent, in nsIWebBrowserPrint webBrowserPrint, in nsIPrintSettings printSettings); */
 NS_IMETHODIMP 
 nsPrintingPromptService::ShowPrintDialog(nsIDOMWindow *parent, nsIWebBrowserPrint *webBrowserPrint, nsIPrintSettings *printSettings)
 {
     NS_ENSURE_ARG(webBrowserPrint);
     NS_ENSURE_ARG(printSettings);
 
+    // Try to access a component dialog
+    nsCOMPtr<nsIPrintDialogService> dlgPrint(do_GetService(
+                                             NS_PRINTDIALOGSERVICE_CONTRACTID));
+    if (dlgPrint)
+      return dlgPrint->Show(printSettings);
+
+    // Show the built-in dialog instead
     ParamBlock block;
     nsresult rv = block.Init();
     if (NS_FAILED(rv))
       return rv;
 
     block->SetInt(0, 0);
     return DoDialog(parent, block, webBrowserPrint, printSettings, kPrintDialogURL);
 }
@@ -172,16 +180,22 @@ nsPrintingPromptService::ShowProgress(ns
 }
 
 /* void showPageSetup (in nsIDOMWindow parent, in nsIPrintSettings printSettings); */
 NS_IMETHODIMP 
 nsPrintingPromptService::ShowPageSetup(nsIDOMWindow *parent, nsIPrintSettings *printSettings, nsIObserver *aObs)
 {
     NS_ENSURE_ARG(printSettings);
 
+    // Try to access a component dialog
+    nsCOMPtr<nsIPrintDialogService> dlgPrint(do_GetService(
+                                             NS_PRINTDIALOGSERVICE_CONTRACTID));
+    if (dlgPrint)
+      return dlgPrint->ShowPageSetup(printSettings);
+
     ParamBlock block;
     nsresult rv = block.Init();
     if (NS_FAILED(rv))
       return rv;
 
     block->SetInt(0, 0);
     return DoDialog(parent, block, nsnull, printSettings, kPageSetupDialogURL);
 }
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -3426,16 +3426,21 @@ DocumentViewerImpl::Print(nsIPrintSettin
   // Temporary code for Bug 136185 / Bug 240490
   nsCOMPtr<nsIXULDocument> xulDoc(do_QueryInterface(mDocument));
   if (xulDoc) {
     nsPrintEngine::ShowPrintErrorDialog(NS_ERROR_GFX_PRINTER_NO_XUL);
     return NS_ERROR_FAILURE;
   }
 #endif
 
+  if (!mContainer) {
+    PR_PL(("Container was destroyed yet we are still trying to use it!"));
+    return NS_ERROR_FAILURE;
+  }
+
   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mContainer));
   NS_ASSERTION(docShell, "This has to be a docshell");
 
   // Check to see if this document is still busy
   // If it is busy and we aren't already "queued" up to print then
   // Indicate there is a print pending and cache the args for later
   PRUint32 busyFlags = nsIDocShell::BUSY_FLAGS_NONE;
   if ((NS_FAILED(docShell->GetBusyFlags(&busyFlags)) ||
@@ -3520,16 +3525,21 @@ DocumentViewerImpl::PrintPreview(nsIPrin
   nsCOMPtr<nsIXULDocument> xulDoc(do_QueryInterface(mDocument));
   if (xulDoc) {
     nsPrintEngine::CloseProgressDialog(aWebProgressListener);
     nsPrintEngine::ShowPrintErrorDialog(NS_ERROR_GFX_PRINTER_NO_XUL, PR_FALSE);
     return NS_ERROR_FAILURE;
   }
 #endif
 
+  if (!mContainer) {
+    PR_PL(("Container was destroyed yet we are still trying to use it!"));
+    return NS_ERROR_FAILURE;
+  }
+
   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mContainer));
   NS_ASSERTION(docShell, "This has to be a docshell");
   nsCOMPtr<nsIPresShell> presShell;
   docShell->GetPresShell(getter_AddRefs(presShell));
   if (!presShell || !mDocument || !mDeviceContext || !mParentWidget) {
     PR_PL(("Can't Print Preview without pres shell, document etc"));
     return NS_ERROR_FAILURE;
   }
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -592,19 +592,24 @@ nsPrintEngine::DoCommonPrint(PRBool     
           // but they choose not to implement this dialog and 
           // are looking for default behavior from the toolkit
           rv = NS_OK;
         } else if (NS_SUCCEEDED(rv)) {
           // since we got the dialog and it worked then make sure we 
           // are telling GFX we want to print silent
           printSilently = PR_TRUE;
         }
+        // The user might have changed shrink-to-fit in the print dialog, so update our copy of its state
+        mPrt->mPrintSettings->GetShrinkToFit(&mPrt->mShrinkToFit);
       } else {
         rv = NS_ERROR_GFX_NO_PRINTROMPTSERVICE;
       }
+    } else {
+      // Call any code that requires a run of the event loop.
+      rv = mPrt->mPrintSettings->SetupSilentPrinting();
     }
     // Check explicitly for abort because it's expected
     if (rv == NS_ERROR_ABORT) 
       return rv;
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   rv = devspec->Init(nsnull, mPrt->mPrintSettings, aIsPrintPreview);
new file mode 100644
--- /dev/null
+++ b/toolkit/locales/en-US/chrome/global/gnomeprintdialog.properties
@@ -0,0 +1,28 @@
+printTitle=Print
+optionsTabLabel=Options
+printFramesTitle=Print Frames
+
+# TRANSLATOR NOTE: For radio button labels and check button labels, an underscore _
+# before a character will turn that character into an accesskey.
+# e.g. "_As laid out" will make A the accesskey.
+
+asLaidOut=_As Laid Out on the Screen
+selectedFrame=The _Selected Frame
+separateFrames=Each Frame on Separate _Pages
+shrinkToFit=Ignore Scaling and S_hrink To Fit Page Width
+selectionOnly=Print Selection _Only
+printBGOptions=Print Backgrounds
+printBGColors=Print Background _Colors
+printBGImages=Print Background I_mages
+headerFooter=Header and Footer
+left=Left
+center=Center
+right=Right
+headerFooterBlank=--blank--
+headerFooterTitle=Title
+headerFooterURL=URL
+headerFooterDate=Date/Time
+headerFooterPage=Page #
+headerFooterPageTotal=Page # of #
+headerFooterCustom=Custom...
+customHeaderFooterPrompt=Please enter your custom header/footer text
--- a/toolkit/locales/jar.mn
+++ b/toolkit/locales/jar.mn
@@ -35,16 +35,17 @@
   locale/@AB_CD@/global/mozilla.dtd                     (%chrome/global/mozilla.dtd)
   locale/@AB_CD@/global/notification.dtd                (%chrome/global/notification.dtd)
   locale/@AB_CD@/global/preferences.dtd                 (%chrome/global/preferences.dtd)
 + locale/@AB_CD@/global/printdialog.dtd                 (%chrome/global/printdialog.dtd)
 + locale/@AB_CD@/global/printjoboptions.dtd             (%chrome/global/printjoboptions.dtd)
 + locale/@AB_CD@/global/printPageSetup.dtd              (%chrome/global/printPageSetup.dtd)
 + locale/@AB_CD@/global/printPreview.dtd                (%chrome/global/printPreview.dtd)
 + locale/@AB_CD@/global/printPreviewProgress.dtd        (%chrome/global/printPreviewProgress.dtd)
+  locale/@AB_CD@/global/gnomeprintdialog.properties     (%chrome/global/gnomeprintdialog.properties)
 + locale/@AB_CD@/global/printProgress.dtd               (%chrome/global/printProgress.dtd)
 + locale/@AB_CD@/global/regionNames.properties          (%chrome/global/regionNames.properties)
 + locale/@AB_CD@/global/dialog.properties               (%chrome/global/dialog.properties)
 + locale/@AB_CD@/global/tree.dtd                        (%chrome/global/tree.dtd)
 + locale/@AB_CD@/global/textcontext.dtd                 (%chrome/global/textcontext.dtd)
 + locale/@AB_CD@/global/viewSource.dtd                  (%chrome/global/viewSource.dtd)
 + locale/@AB_CD@/global/viewSource.properties           (%chrome/global/viewSource.properties)
 + locale/@AB_CD@/global/wizard.dtd                      (%chrome/global/wizard.dtd)
--- a/widget/public/Makefile.in
+++ b/widget/public/Makefile.in
@@ -74,17 +74,20 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),os2)
 EXPORTS		+= nsIDragSessionOS2.h
 endif
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),beos)
 EXPORTS		+= nsIDragSessionBeOS.h
 endif
 
 ifneq (,$(filter gtk2,$(MOZ_WIDGET_TOOLKIT)))
-EXPORTS		+= nsIDragSessionGTK.h
+EXPORTS		+= \
+		nsIDragSessionGTK.h \
+		nsIPrintDialogService.h \
+		$(NULL)
 endif
 
 XPIDLSRCS	= \
 		nsIAppShell.idl \
 		nsIFilePicker.idl \
 		nsIToolkit.idl \
 		nsISound.idl \
 		nsITransferable.idl \
new file mode 100644
--- /dev/null
+++ b/widget/public/nsIPrintDialogService.h
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Kenneth Herron <kherron@fmailbox.com>
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsIPrintDialogService_h__
+#define nsIPrintDialogService_h__
+
+#include "nsISupports.h"
+
+class nsIPrintSettings;
+
+/*
+ * Interface to a print dialog accessed through the widget library.
+ */
+
+#define NS_IPRINTDIALOGSERVICE_IID \
+{ 0x3715eb1a, 0xb314, 0x447c, \
+{ 0x95, 0x33, 0xd0, 0x6a, 0x6d, 0xa6, 0xa6, 0xf0 } }
+
+
+/**
+ *
+ */
+class nsIPrintDialogService  : public nsISupports
+{
+public:
+  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IPRINTDIALOGSERVICE_IID)
+
+  /**
+   * Initialize the service.
+   * @return NS_OK or a suitable error.
+   */
+  NS_IMETHOD Init() = 0;
+
+  /**
+   * Show the print dialog.
+   * @param aSettings On entry, this contains initial settings for the
+   *                  print dialog. On return, if the print operation should
+   *                  proceed then this contains settings for the print
+   *                  operation.
+   * @return NS_OK if the print operation should proceed
+   * @return NS_ERROR_ABORT if the user indicated not to proceed
+   * @return a suitable error for failures to show the print dialog.
+   */
+  NS_IMETHOD Show(nsIPrintSettings *aSettings) = 0;
+
+  /**
+   * Show the page setup dialog. Note that there is no way to tell whether the user clicked OK or Cancel on the
+   * dialog.
+   * @param aSettings On entry, this contains initial settings for the
+   *                  page setup dialog. On return, this contains new default page setup options.
+   * @return NS_OK if everything is OK.
+   * @return a suitable error for failures to show the page setup dialog.
+   */
+  NS_IMETHOD ShowPageSetup(nsIPrintSettings *aSettings) = 0;
+
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIPrintDialogService, NS_IPRINTDIALOGSERVICE_IID)
+
+#define NS_PRINTDIALOGSERVICE_CONTRACTID ("@mozilla.org/widget/printdialog-service;1")
+
+#endif // nsIPrintDialogService_h__
+
--- a/widget/public/nsIPrintSettings.idl
+++ b/widget/public/nsIPrintSettings.idl
@@ -53,17 +53,17 @@
   
 interface nsIPrintSession;
 
 /**
  * Simplified graphics interface for JS rendering.
  *
  * @status UNDER_REVIEW
  */
-[scriptable, uuid(81b8dfee-25cc-479c-ad2c-a5e3875650cb)]
+[scriptable, uuid(3e097aba-c1d6-425d-9c52-b371d5da964a)]
 
 interface nsIPrintSettings : nsISupports
 {
   /**
    * PrintSettings to be Saved Navigation Constants
    */
   const unsigned long kInitSaveOddEvenPages   = 0x00000001;
   const unsigned long kInitSaveHeaderLeft     = 0x00000002;
@@ -296,9 +296,19 @@ interface nsIPrintSettings : nsISupports
   attribute boolean isInitializedFromPrefs;
 
   /* C++ Helper Functions */
   [noscript] void SetMarginInTwips(in nsNativeMarginRef aMargin);
   [noscript] void SetEdgeInTwips(in nsNativeMarginRef aEdge);
   /* Purposely made this an "in" arg */
   [noscript] void GetMarginInTwips(in nsNativeMarginRef aMargin);
   [noscript] void GetEdgeInTwips(in nsNativeMarginRef aEdge);
+
+  /**
+   * We call this function so that anything that requires a run of the event loop
+   * can do so safely. The print dialog runs the event loop but in silent printing
+   * that doesn't happen.
+   *
+   * Either this or ShowPrintDialog (but not both) MUST be called by the print engine
+   * before printing, otherwise printing can fail on some platforms.
+   */
+  [noscript] void SetupSilentPrinting();
 };
--- a/widget/public/nsWidgetsCID.h
+++ b/widget/public/nsWidgetsCID.h
@@ -162,8 +162,11 @@
 #define NS_PRINTER_ENUMERATOR_CID \
 { 0xa6cf9129, 0x15b3, 0x11d2, \
 { 0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} }
 
 #define NS_PRINTSESSION_CID \
 { 0x2f977d53, 0x5485, 0x11d4, \
 { 0x87, 0xe2, 0x00, 0x10, 0xa4, 0xe7, 0x5e, 0xf2 } }
 
+#define NS_PRINTDIALOGSERVICE_CID \
+{ 0x06beec76, 0xa183, 0x4d9f, \
+{ 0x85, 0xdd, 0x08, 0x5f, 0x26, 0xda, 0x56, 0x5a } }
--- a/widget/src/gtk2/Makefile.in
+++ b/widget/src/gtk2/Makefile.in
@@ -103,19 +103,19 @@ CPPSRCS		= \
 		nsSound.cpp \
 		nsNativeKeyBindings.cpp \
 		nsScreenGtk.cpp \
 		nsScreenManagerGtk.cpp \
 		nsDeviceContextSpecG.cpp \
 		nsPrintOptionsGTK.cpp \
 		nsImageToPixbuf.cpp \
 		nsAccessibilityHelper.cpp \
-		nsPrintJobFactoryGTK.cpp \
-		nsPrintJobGTK.cpp \
 		nsIdleServiceGTK.cpp \
+		nsPrintDialogGTK.cpp \
+		nsPrintSettingsGTK.cpp \
 		$(NULL)
 
 # build our subdirs, too
 ifdef ACCESSIBILITY
 REQUIRES	+= accessibility
 endif
 
 SHARED_LIBRARY_LIBS = ../xpwidgets/libxpwidgets_s.a
--- a/widget/src/gtk2/nsDeviceContextSpecG.cpp
+++ b/widget/src/gtk2/nsDeviceContextSpecG.cpp
@@ -18,16 +18,17 @@
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
  *   Ken Herron <kherron+mozilla@fmailbox.com>
  *   Julien Lafon <julien.lafon@gmail.com>
+ *   Michael Ventnor <m.ventnor@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -61,22 +62,25 @@
 #include "nsStringEnumerator.h"
 #include "nsIServiceManager.h" 
 
 #ifdef USE_POSTSCRIPT
 #include "nsPSPrinters.h"
 #include "nsPaperPS.h"  /* Paper size list */
 #endif /* USE_POSTSCRIPT */
 
-#include "nsPrintJobFactoryGTK.h"
-#include "nsIPrintJobGTK.h"
+#include "nsPrintSettingsGTK.h"
 
 #include "nsIFileStreams.h"
 #include "nsILocalFile.h"
 
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
 /* Ensure that the result is always equal to either PR_TRUE or PR_FALSE */
 #define MAKE_PR_BOOL(val) ((val)?(PR_TRUE):(PR_FALSE))
 
 #ifdef PR_LOGGING 
 static PRLogModuleInfo *DeviceContextSpecGTKLM = PR_NewLogModule("DeviceContextSpecGTK");
 #endif /* PR_LOGGING */
 /* Macro to make lines shorter */
 #define DO_PR_DEBUG_LOG(x) PR_LOG(DeviceContextSpecGTKLM, PR_LOG_DEBUG, x)
@@ -377,23 +381,21 @@ void nsPrinterFeatures::SetMultipleConcu
 // static members
 GlobalPrinters GlobalPrinters::mGlobalPrinters;
 nsStringArray* GlobalPrinters::mGlobalPrinterList = nsnull;
 //---------------
 
 nsDeviceContextSpecGTK::nsDeviceContextSpecGTK()
 {
   DO_PR_DEBUG_LOG(("nsDeviceContextSpecGTK::nsDeviceContextSpecGTK()\n"));
-  mPrintJob = nsnull;
 }
 
 nsDeviceContextSpecGTK::~nsDeviceContextSpecGTK()
 {
   DO_PR_DEBUG_LOG(("nsDeviceContextSpecGTK::~nsDeviceContextSpecGTK()\n"));
-  delete mPrintJob;
 }
 
 NS_IMPL_ISUPPORTS1(nsDeviceContextSpecGTK,
                    nsIDeviceContextSpec)
 
 #include "gfxPDFSurface.h"
 #include "gfxPSSurface.h"
 NS_IMETHODIMP nsDeviceContextSpecGTK::GetSurfaceForPrinter(gfxASurface **aSurface)
@@ -405,39 +407,72 @@ NS_IMETHODIMP nsDeviceContextSpecGTK::Ge
 
   double width, height;
   mPrintSettings->GetEffectivePageSize(&width, &height);
   // convert twips to points
   width /= 20;
   height /= 20;
 
   DO_PR_DEBUG_LOG(("\"%s\", %f, %f\n", path, width, height));
+  nsresult rv;
 
-  nsresult rv = nsPrintJobFactoryGTK::CreatePrintJob(this, mPrintJob);
-  if (NS_FAILED(rv))
-    return rv;
+  // Spool file. Use Glib's temporary file function since we're
+  // already dependent on the gtk software stack.
+  gchar *buf;
+  gint fd = g_file_open_tmp("XXXXXX.tmp", &buf, nsnull);
+  if (-1 == fd)
+    return NS_ERROR_GFX_PRINTER_COULD_NOT_OPEN_FILE;
+  close(fd);
 
-  nsCOMPtr<nsILocalFile> file;
-  rv = mPrintJob->GetSpoolFile(getter_AddRefs(file));
-  if (NS_FAILED(rv))
-    return rv;
+  rv = NS_NewNativeLocalFile(nsDependentCString(buf), PR_FALSE,
+                             getter_AddRefs(mSpoolFile));
+  if (NS_FAILED(rv)) {
+    unlink(buf);
+    return NS_ERROR_GFX_PRINTER_COULD_NOT_OPEN_FILE;
+  }
+
+  mSpoolName = buf;
+  g_free(buf);
+
+  mSpoolFile->SetPermissions(0600);
 
   nsCOMPtr<nsIFileOutputStream> stream = do_CreateInstance("@mozilla.org/network/file-output-stream;1");
-  rv = stream->Init(file, -1, -1, 0);
+  rv = stream->Init(mSpoolFile, -1, -1, 0);
   if (NS_FAILED(rv))
     return rv;
 
   PRInt16 format;
   mPrintSettings->GetOutputFormat(&format);
 
   nsRefPtr<gfxASurface> surface;
-  if (nsIPrintSettings::kOutputFormatPDF == format) {
-    surface = new gfxPDFSurface(stream, gfxSize(width, height));
+  gfxSize surfaceSize(width, height);
+
+  // Determine the real format with some GTK magic
+  if (format == nsIPrintSettings::kOutputFormatNative) {
+    if (mIsPPreview) {
+      // There is nothing to detect on Print Preview, use PS.
+      format = nsIPrintSettings::kOutputFormatPS;
+    } else {
+      const gchar* fmtGTK = gtk_print_settings_get(mGtkPrintSettings, GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT);
+      if (!fmtGTK && GTK_IS_PRINTER(mGtkPrinter)) {
+        // Likely not print-to-file, check printer's capabilities
+        format = (gtk_printer_accepts_pdf(mGtkPrinter)) ? nsIPrintSettings::kOutputFormatPDF
+                                                        : nsIPrintSettings::kOutputFormatPS;
+      } else if (nsDependentCString(fmtGTK).EqualsIgnoreCase("pdf")) {
+          format = nsIPrintSettings::kOutputFormatPDF;
+      } else {
+          format = nsIPrintSettings::kOutputFormatPS;
+      }
+    }
+  }
+
+  if (format == nsIPrintSettings::kOutputFormatPDF) {
+    surface = new gfxPDFSurface(stream, surfaceSize);
   } else {
-    surface = new gfxPSSurface(stream, gfxSize(width, height));
+    surface = new gfxPSSurface(stream, surfaceSize);
   }
 
   if (!surface)
     return NS_ERROR_OUT_OF_MEMORY;
 
   surface.swap(*aSurface);
 
   return NS_OK;
@@ -448,114 +483,39 @@ NS_IMETHODIMP nsDeviceContextSpecGTK::Ge
  *  @update   dc 2/15/98
  *  @update   syd 3/2/99
  */
 NS_IMETHODIMP nsDeviceContextSpecGTK::Init(nsIWidget *aWidget,
                                            nsIPrintSettings* aPS,
                                            PRBool aIsPrintPreview)
 {
   DO_PR_DEBUG_LOG(("nsDeviceContextSpecGTK::Init(aPS=%p)\n", aPS));
-  nsresult rv = NS_ERROR_FAILURE;
+
+  if (gtk_major_version < 2 ||
+      (gtk_major_version == 2 && gtk_minor_version < 10))
+    return NS_ERROR_NOT_AVAILABLE;  // I'm so sorry bz
 
   mPrintSettings = aPS;
-
-  // if there is a current selection then enable the "Selection" radio button
-  rv = GlobalPrinters::GetInstance()->InitializeGlobalPrinters();
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  GlobalPrinters::GetInstance()->FreeGlobalPrinters();
+  mIsPPreview = aIsPrintPreview;
 
-  if (aPS) {
-    PRBool     reversed       = PR_FALSE;
-    PRBool     color          = PR_FALSE;
-    PRBool     tofile         = PR_FALSE;
-    PRInt16    printRange     = nsIPrintSettings::kRangeAllPages;
-    PRInt32    orientation    = NS_PORTRAIT;
-    PRInt32    fromPage       = 1;
-    PRInt32    toPage         = 1;
-    PRUnichar *command        = nsnull;
-    PRInt32    copies         = 1;
-    PRUnichar *printer        = nsnull;
-    PRUnichar *papername      = nsnull;
-    PRUnichar *plexname       = nsnull;
-    PRUnichar *resolutionname = nsnull;
-    PRUnichar *colorspace     = nsnull;
-    PRBool     downloadfonts  = PR_TRUE;
-    PRUnichar *printfile      = nsnull;
-    double     dleft          = 0.5;
-    double     dright         = 0.5;
-    double     dtop           = 0.5;
-    double     dbottom        = 0.5; 
+  // This is only set by embedders
+  PRBool toFile;
+  aPS->GetPrintToFile(&toFile);
+
+  mToPrinter = !toFile && !aIsPrintPreview;
 
-    aPS->GetPrinterName(&printer);
-    aPS->GetPrintReversed(&reversed);
-    aPS->GetPrintInColor(&color);
-    aPS->GetPaperName(&papername);
-    aPS->GetResolutionName(&resolutionname);
-    aPS->GetColorspace(&colorspace);
-    aPS->GetDownloadFonts(&downloadfonts);
-    aPS->GetPlexName(&plexname);
-    aPS->GetOrientation(&orientation);
-    aPS->GetPrintCommand(&command);
-    aPS->GetPrintRange(&printRange);
-    aPS->GetToFileName(&printfile);
-    aPS->GetPrintToFile(&tofile);
-    aPS->GetStartPageRange(&fromPage);
-    aPS->GetEndPageRange(&toPage);
-    aPS->GetNumCopies(&copies);
-    aPS->GetMarginTop(&dtop);
-    aPS->GetMarginLeft(&dleft);
-    aPS->GetMarginBottom(&dbottom);
-    aPS->GetMarginRight(&dright);
+  nsCOMPtr<nsPrintSettingsGTK> printSettingsGTK(do_QueryInterface(aPS));
+  if (!printSettingsGTK)
+    return NS_ERROR_NO_INTERFACE;
 
-    if (printfile)
-      PL_strncpyz(mPath,      NS_ConvertUTF16toUTF8(printfile).get(), sizeof(mPath));
-    if (command)
-      PL_strncpyz(mCommand,   NS_ConvertUTF16toUTF8(command).get(),   sizeof(mCommand));  
-    if (printer) 
-      PL_strncpyz(mPrinter,   NS_ConvertUTF16toUTF8(printer).get(),   sizeof(mPrinter));        
-    if (papername) 
-      PL_strncpyz(mPaperName, NS_ConvertUTF16toUTF8(papername).get(), sizeof(mPaperName));  
-    if (plexname) 
-      PL_strncpyz(mPlexName,  NS_ConvertUTF16toUTF8(plexname).get(),  sizeof(mPlexName));  
-    if (resolutionname) 
-      PL_strncpyz(mResolutionName, NS_ConvertUTF16toUTF8(resolutionname).get(), sizeof(mResolutionName));  
-    if (colorspace) 
-      PL_strncpyz(mColorspace, NS_ConvertUTF16toUTF8(colorspace).get(), sizeof(mColorspace));  
+  mGtkPrinter = printSettingsGTK->GetGtkPrinter();
+  mGtkPrintSettings = printSettingsGTK->GetGtkPrintSettings();
+  mGtkPageSetup = printSettingsGTK->GetGtkPageSetup();
 
-    DO_PR_DEBUG_LOG(("margins:   %5.2f,%5.2f,%5.2f,%5.2f\n", dtop, dleft, dbottom, dright));
-    DO_PR_DEBUG_LOG(("printRange %d\n",   printRange));
-    DO_PR_DEBUG_LOG(("fromPage   %d\n",   fromPage));
-    DO_PR_DEBUG_LOG(("toPage     %d\n",   toPage));
-    DO_PR_DEBUG_LOG(("tofile     %d\n",   tofile));
-    DO_PR_DEBUG_LOG(("printfile  '%s'\n", printfile? NS_ConvertUTF16toUTF8(printfile).get():"<NULL>"));
-    DO_PR_DEBUG_LOG(("command    '%s'\n", command? NS_ConvertUTF16toUTF8(command).get():"<NULL>"));
-    DO_PR_DEBUG_LOG(("printer    '%s'\n", printer? NS_ConvertUTF16toUTF8(printer).get():"<NULL>"));
-    DO_PR_DEBUG_LOG(("papername  '%s'\n", papername? NS_ConvertUTF16toUTF8(papername).get():"<NULL>"));
-    DO_PR_DEBUG_LOG(("plexname   '%s'\n", plexname? NS_ConvertUTF16toUTF8(plexname).get():"<NULL>"));
-    DO_PR_DEBUG_LOG(("resolution '%s'\n", resolutionname? NS_ConvertUTF16toUTF8(resolutionname).get():"<NULL>"));
-    DO_PR_DEBUG_LOG(("colorspace '%s'\n", colorspace? NS_ConvertUTF16toUTF8(colorspace).get():"<NULL>"));
-
-    mTop         = dtop;
-    mBottom      = dbottom;
-    mLeft        = dleft;
-    mRight       = dright;
-    mFpf         = !reversed;
-    mDownloadFonts = downloadfonts;
-    mGrayscale   = !color;
-    mOrientation = orientation;
-    mToPrinter   = !tofile;
-    mCopies      = copies;
-    mIsPPreview  = aIsPrintPreview;
-    mCancel      = PR_FALSE;
-  }
-
-  return rv;
+  return NS_OK;
 }
 
 NS_IMETHODIMP nsDeviceContextSpecGTK::GetToPrinter(PRBool &aToPrinter)
 {
   aToPrinter = mToPrinter;
   return NS_OK;
 }
 
@@ -683,24 +643,79 @@ nsresult nsDeviceContextSpecGTK::GetPrin
 #endif
 }
 
 NS_IMETHODIMP nsDeviceContextSpecGTK::ClosePrintManager()
 {
   return NS_OK;
 }
 
-NS_IMETHODIMP nsDeviceContextSpecGTK::BeginDocument(PRUnichar * aTitle, PRUnichar * aPrintToFileName, PRInt32 aStartPage, PRInt32 aEndPage)
+static void
+print_callback(GtkPrintJob *aJob, gpointer aData, GError *aError) {
+  g_object_unref(aJob);
+  ((nsILocalFile*) aData)->Remove(PR_FALSE);
+}
+
+static void
+ns_release_macro(gpointer aData) {
+  nsILocalFile* spoolFile = (nsILocalFile*) aData;
+  NS_RELEASE(spoolFile);
+}
+
+NS_IMETHODIMP nsDeviceContextSpecGTK::BeginDocument(PRUnichar * aTitle, PRUnichar * aPrintToFileName,
+                                                    PRInt32 aStartPage, PRInt32 aEndPage)
 {
+  if (mToPrinter) {
+    if (!GTK_IS_PRINTER(mGtkPrinter))
+      return NS_ERROR_FAILURE;
+
+    mPrintJob = gtk_print_job_new(NS_ConvertUTF16toUTF8(aTitle).get(), mGtkPrinter,
+                                  mGtkPrintSettings, mGtkPageSetup);
+  }
+
   return NS_OK;
 }
 
 NS_IMETHODIMP nsDeviceContextSpecGTK::EndDocument()
 {
-  return mPrintJob->Submit();
+  if (mToPrinter) {
+    if (!gtk_print_job_set_source_file(mPrintJob, mSpoolName.get(), NULL))
+      return NS_ERROR_GFX_PRINTER_COULD_NOT_OPEN_FILE;
+
+    NS_ADDREF(mSpoolFile.get());
+    gtk_print_job_send(mPrintJob, print_callback, mSpoolFile, ns_release_macro);
+  } else {
+    // Handle print-to-file ourselves for the benefit of embedders
+    nsXPIDLString targetPath;
+    nsCOMPtr<nsILocalFile> destFile;
+    mPrintSettings->GetToFileName(getter_Copies(targetPath));
+
+    nsresult rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(targetPath),
+                                        PR_FALSE, getter_AddRefs(destFile));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsAutoString destLeafName;
+    rv = destFile->GetLeafName(destLeafName);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIFile> destDir;
+    rv = destFile->GetParent(getter_AddRefs(destDir));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = mSpoolFile->MoveTo(destDir, destLeafName);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // This is the standard way to get the UNIX umask. Ugh.
+    mode_t mask = umask(0);
+    umask(mask);
+    // If you're not familiar with umasks, they contain the bits of what NOT to set in the permissions
+    // (thats because files and directories have different numbers of bits for their permissions)
+    destFile->SetPermissions(0666 & ~(mask));
+  }
+  return NS_OK;
 }
 
 /* Get prefs for printer
  * Search order:
  * - Get prefs per printer name and module name
  * - Get prefs per printer name
  * - Get prefs per module name
  * - Get prefs
--- a/widget/src/gtk2/nsDeviceContextSpecG.h
+++ b/widget/src/gtk2/nsDeviceContextSpecG.h
@@ -38,20 +38,23 @@
 
 #ifndef nsDeviceContextSpecGTK_h___
 #define nsDeviceContextSpecGTK_h___
 
 #include "nsIDeviceContextSpec.h"
 #include "nsIPrintSettings.h"
 #include "nsIPrintOptions.h" 
 #include "nsCOMPtr.h"
+#include "nsString.h"
 
 #include "nsCRT.h" /* should be <limits.h>? */
 
-class nsIPrintJobGTK;
+#include <gtk/gtk.h>
+#include <gtk/gtkprinter.h>
+#include <gtk/gtkprintjob.h>
 
 #define NS_PORTRAIT  0
 #define NS_LANDSCAPE 1
 
 typedef enum
 {
   pmInvalid = 0,
   pmPostScript
@@ -112,17 +115,25 @@ protected:
   char   mPlexName[256];      /* Plex mode name */
   char   mResolutionName[256];/* Resolution name */
   char   mColorspace[256];    /* Colorspace */
   int    mCopies;             /* number of copies */
   float  mLeft;               /* left margin */
   float  mRight;              /* right margin */
   float  mTop;                /* top margin */
   float  mBottom;             /* bottom margin */
-  nsIPrintJobGTK * mPrintJob;
+
+  GtkPrintJob*      mPrintJob;
+  GtkPrinter*       mGtkPrinter;
+  GtkPrintSettings* mGtkPrintSettings;
+  GtkPageSetup*     mGtkPageSetup;
+
+  nsCString              mSpoolName;
+  nsCOMPtr<nsILocalFile> mSpoolFile;
+
 };
 
 //-------------------------------------------------------------------------
 // Printer Enumerator
 //-------------------------------------------------------------------------
 class nsPrinterEnumeratorGTK : public nsIPrinterEnumerator
 {
 public:
deleted file mode 100644
--- a/widget/src/gtk2/nsIPrintJobGTK.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ex: set tabstop=8 softtabstop=4 shiftwidth=4 expandtab: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Ken Herron <kherron@fastmail.us>.
- * Portions created by the Initial Developer are Copyright (C) 2004
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef nsIPrintJobGTK_h__
-#define nsIPrintJobGTK_h__
-
-#include "nsCOMPtr.h"
-
-class nsDeviceContextSpecGTK;
-class nsILocalFile;
-
-/*
- * This is an interface for a class that accepts and submits print jobs.
- *
- * Instances should be obtained through nsPrintJobFactoryGTK::CreatePrintJob().
- * After obtaining a print job object, the caller can retrieve the spool file
- * object associated with the print job and write the print job to that.
- * Once that is done, the caller may call Submit() to finalize and print
- * the job, or Cancel() to abort the job.
- */
-
-class nsIPrintJobGTK
-{
-public:
-    virtual ~nsIPrintJobGTK();
-
-    /* Allow the print job factory to create instances */
-    friend class nsPrintJobFactoryGTK;
-
-    /**
-     * Set the number of copies for this print job. Some printing systems
-     * allow setting this out of band, instead of embedding it into the
-     * postscript.
-     * @param aNumCopies Number of copies requested. Values <= 1 are
-     *                   interpreted as "do not specify a copy count to the
-     *                   printing system" when possible, or else as
-     *                   one copy.
-     * @return NS_ERROR_NOT_IMPLEMENTED if this print job class doesn't
-     *                   support the specific copy count requested.
-     * @return NS_OK     The print job class will request the specified
-     *                   number of copies when printing the job.
-     */
-    virtual nsresult SetNumCopies(int aNumCopies)
-            { return NS_ERROR_NOT_IMPLEMENTED; }
-
-    /**
-     * Set the print job title. Some printing systems accept a job title
-     * which is displayed on a banner page, in a print queue listing, etc.
-     *
-     * This must be called after Init() and before StartSubmission().
-     * nsIPrintJobGTK provides a stub implementation because most classes
-     * do not make use of this information.
-     * 
-     * @param aTitle  The job title.
-     */
-    virtual void SetJobTitle(const PRUnichar *aTitle) { }
-
-    /**
-     * Get the temporary file that the print job should be written to. The
-     * caller may open this file for writing and write the text of the print
-     * job to it.
-     * 
-     * The spool file is owned by the print job object, and will be removed
-     * by the print job dtor. Each print job object has one spool file.
-     * 
-     * @return NS_ERROR_NOT_INITIALIZED if the object hasn't been initialized.
-     *         NS_OK otherwise.
-     * 
-     * This is currently non-virtual for efficiency.
-     */
-    nsresult GetSpoolFile(nsILocalFile **aFile); 
-
-    /**
-     * Submit a finished print job. The caller may call this after
-     * calling GetSpoolFile(), writing the text of the print job to the
-     * spool file, and closing the spool file. The return value indicates
-     * the overall success or failure of the print operation.
-     * 
-     * The caller must not try to access the spool file in any way after
-     * calling this function.
-     *
-     * @return NS_ERROR_GFX_PRINTING_NOT_IMPLEMENTED if the print
-     *               job object doesn't actually support printing (e.g.
-     *               for print preview)
-     *         NS_OK for success
-     *         Other values indicate failure of the print operation.
-     */
-    virtual nsresult Submit() = 0;
-
-protected:
-    /**
-     * Initialize an object from a device context spec. This must be
-     * called before any of the public methods. Implementations must
-     * initialize mSpoolFile declared below.
-     * 
-     * @param aContext The device context spec describing the
-     *                 desired print job.
-     * @return NS_OK or a suitable error value.
-     */
-    virtual nsresult Init(nsDeviceContextSpecGTK *aContext) = 0;
-    
-    /* The spool file */
-    nsCOMPtr<nsILocalFile> mSpoolFile;
-};
-
-
-#endif /* nsIPrintJobGTK_h__ */
new file mode 100644
--- /dev/null
+++ b/widget/src/gtk2/nsPrintDialogGTK.cpp
@@ -0,0 +1,561 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Mozilla GTK2 print dialog interface.
+ *
+ * The Initial Developer of the Original Code is
+ * Kenneth Herron <kherron@fmailbox.com>
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Michael Ventnor <m.ventnor@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <gtk/gtk.h>
+#include <gtk/gtkprintunixdialog.h>
+#include <stdlib.h>
+
+#include "mozcontainer.h"
+#include "nsAccessibilityHelper.h"
+#include "nsIPrintSettings.h"
+#include "nsIWidget.h"
+#include "nsPrintDialogGTK.h"
+#include "nsPrintSettingsGTK.h"
+#include "nsString.h"
+#include "nsReadableUtils.h"
+#include "nsILocalFile.h"
+#include "nsNetUtil.h"
+#include "nsIStringBundle.h"
+#include "nsIPrintSettingsService.h"
+
+static const char header_footer_tags[][4] =  {"", "&T", "&U", "&D", "&P", "&PT"};
+
+#define CUSTOM_VALUE_INDEX NS_ARRAY_LENGTH(header_footer_tags)
+
+static void
+ShowCustomDialog(GtkComboBox *changed_box, gpointer user_data)
+{
+  if (gtk_combo_box_get_active(changed_box) != CUSTOM_VALUE_INDEX)
+    return;
+
+  nsCOMPtr<nsIStringBundleService> bundleSvc =
+       do_GetService(NS_STRINGBUNDLE_CONTRACTID);
+
+  nsCOMPtr<nsIStringBundle> printBundle;
+  bundleSvc->CreateBundle("chrome://global/locale/gnomeprintdialog.properties", getter_AddRefs(printBundle));
+  nsXPIDLString intlString;
+
+  printBundle->GetStringFromName(NS_LITERAL_STRING("headerFooterCustom").get(), getter_Copies(intlString));
+  GtkWidget* prompt_dialog = gtk_dialog_new_with_buttons(NS_ConvertUTF16toUTF8(intlString).get(), NULL,
+                                                         GTK_DIALOG_MODAL,
+                                                         GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+                                                         GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
+                                                         NULL);
+
+  printBundle->GetStringFromName(NS_LITERAL_STRING("customHeaderFooterPrompt").get(), getter_Copies(intlString));
+  GtkWidget* custom_label = gtk_label_new(NS_ConvertUTF16toUTF8(intlString).get());
+  GtkWidget* custom_entry = gtk_entry_new();
+  GtkWidget* question_icon = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
+
+  // To be convenient, prefill the textbox with the existing value, if any, and select it all so they can easily
+  // both edit it and type in a new one.
+  const char* current_text = (const char*) g_object_get_data(G_OBJECT(changed_box), "custom-text");
+  if (current_text) {
+    gtk_entry_set_text(GTK_ENTRY(custom_entry), current_text);
+    gtk_editable_select_region(GTK_EDITABLE(custom_entry), 0, -1);
+  }
+
+  GtkWidget* custom_vbox = gtk_vbox_new(TRUE, 2);
+  gtk_box_pack_start(GTK_BOX(custom_vbox), custom_label, FALSE, FALSE, 0);
+  gtk_box_pack_start(GTK_BOX(custom_vbox), custom_entry, FALSE, FALSE, 5); // Make entry 5px underneath label
+  GtkWidget* custom_hbox = gtk_hbox_new(FALSE, 2);
+  gtk_box_pack_start(GTK_BOX(custom_hbox), question_icon, FALSE, FALSE, 0);
+  gtk_box_pack_start(GTK_BOX(custom_hbox), custom_vbox, FALSE, FALSE, 10); // Make question icon 10px away from content
+  gtk_container_set_border_width(GTK_CONTAINER(custom_hbox), 2);
+  gtk_widget_show_all(custom_hbox);
+
+  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(prompt_dialog)->vbox), custom_hbox, FALSE, FALSE, 0);
+  gint diag_response = gtk_dialog_run(GTK_DIALOG(prompt_dialog));
+
+  if (diag_response == GTK_RESPONSE_ACCEPT) {
+    const gchar* response_text = gtk_entry_get_text(GTK_ENTRY(custom_entry));
+    g_object_set_data_full(G_OBJECT(changed_box), "custom-text", strdup(response_text), (GDestroyNotify) free);
+  } else {
+    // XXX I wish there was a way to be smarter than this... but at least we were smarter than before
+    // where the dropdown stayed on Custom... even after clicking Cancel.
+    gtk_combo_box_set_active(changed_box, 0);
+  }
+
+  gtk_widget_destroy(prompt_dialog);
+}
+
+class nsPrintDialogWidgetGTK {
+  public:
+    nsPrintDialogWidgetGTK(nsIPrintSettings *aPrintSettings);
+    ~nsPrintDialogWidgetGTK() { gtk_widget_destroy(dialog); }
+    NS_ConvertUTF16toUTF8 GetUTF8FromBundle(const char* aKey);
+    const gint Run();
+
+    nsresult ImportSettings(nsIPrintSettings *aNSSettings);
+    nsresult ExportSettings(nsIPrintSettings *aNSSettings);
+
+  private:
+    GtkWidget* dialog;
+    GtkWidget* radio_as_laid_out;
+    GtkWidget* radio_selected_frame;
+    GtkWidget* radio_separate_frames;
+    GtkWidget* shrink_to_fit_toggle;
+    GtkWidget* print_bg_colors_toggle;
+    GtkWidget* print_bg_images_toggle;
+    GtkWidget* selection_only_toggle;
+    GtkWidget* header_dropdown[3];  // {left, center, right}
+    GtkWidget* footer_dropdown[3];
+
+    nsCOMPtr<nsIStringBundle> printBundle;
+
+    GtkWidget* ConstructHeaderFooterDropdown(const PRUnichar *currentString);
+    const char* OptionWidgetToString(GtkWidget *dropdown);
+
+    /* Code to copy between GTK and NS print settings structures.
+     * In the following, 
+     *   "Import" means to copy from NS to GTK
+     *   "Export" means to copy from GTK to NS
+     */
+    void ExportFramePrinting(nsIPrintSettings *aNS, GtkPrintSettings *aSettings);
+    void ExportHeaderFooter(nsIPrintSettings *aNS);
+};
+
+nsPrintDialogWidgetGTK::nsPrintDialogWidgetGTK(nsIPrintSettings *aSettings)
+{
+  nsCOMPtr<nsIStringBundleService> bundleSvc = do_GetService(NS_STRINGBUNDLE_CONTRACTID);
+  bundleSvc->CreateBundle("chrome://global/locale/gnomeprintdialog.properties", getter_AddRefs(printBundle));
+
+  dialog = gtk_print_unix_dialog_new(GetUTF8FromBundle("printTitle").get(), NULL);
+
+  gtk_print_unix_dialog_set_manual_capabilities(GTK_PRINT_UNIX_DIALOG(dialog),
+                    GtkPrintCapabilities(
+                        GTK_PRINT_CAPABILITY_PAGE_SET
+                      | GTK_PRINT_CAPABILITY_COPIES
+                      | GTK_PRINT_CAPABILITY_COLLATE
+                      | GTK_PRINT_CAPABILITY_REVERSE
+                      | GTK_PRINT_CAPABILITY_SCALE
+                    )
+                  );
+
+  // The vast majority of magic numbers in this widget construction are padding. e.g. for
+  // the set_border_width below, 12px matches that of just about every other window.
+  GtkWidget* custom_options_tab = gtk_vbox_new(FALSE, 0);
+  gtk_container_set_border_width(GTK_CONTAINER(custom_options_tab), 12);
+  GtkWidget* tab_label = gtk_label_new(GetUTF8FromBundle("optionsTabLabel").get());
+
+  PRInt16 frameUIFlag;
+  aSettings->GetHowToEnableFrameUI(&frameUIFlag);
+  radio_as_laid_out = gtk_radio_button_new_with_mnemonic(NULL, GetUTF8FromBundle("asLaidOut").get());
+  if (frameUIFlag == nsIPrintSettings::kFrameEnableNone)
+    gtk_widget_set_sensitive(radio_as_laid_out, FALSE);
+
+  radio_selected_frame = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(radio_as_laid_out),
+                                                                        GetUTF8FromBundle("selectedFrame").get());
+  if (frameUIFlag == nsIPrintSettings::kFrameEnableNone ||
+      frameUIFlag == nsIPrintSettings::kFrameEnableAsIsAndEach)
+    gtk_widget_set_sensitive(radio_selected_frame, FALSE);
+
+  radio_separate_frames = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(radio_as_laid_out),
+                                                                         GetUTF8FromBundle("separateFrames").get());
+  if (frameUIFlag == nsIPrintSettings::kFrameEnableNone)
+    gtk_widget_set_sensitive(radio_separate_frames, FALSE);
+
+  // "Print Frames" options label, bold and center-aligned
+  GtkWidget* print_frames_label = gtk_label_new(NULL);
+  char* pangoMarkup = g_markup_printf_escaped("<b>%s</b>", GetUTF8FromBundle("printFramesTitle").get());
+  gtk_label_set_markup(GTK_LABEL(print_frames_label), pangoMarkup);
+  g_free(pangoMarkup);
+  gtk_misc_set_alignment(GTK_MISC(print_frames_label), 0, 0);
+
+  // Align the radio buttons slightly so they appear to fall under the aforementioned label as per the GNOME HIG
+  GtkWidget* frames_radio_container = gtk_alignment_new(0, 0, 0, 0);
+  gtk_alignment_set_padding(GTK_ALIGNMENT(frames_radio_container), 8, 0, 12, 0);
+
+  // Radio buttons for the print frames options
+  GtkWidget* frames_radio_list = gtk_vbox_new(TRUE, 2);
+  gtk_box_pack_start(GTK_BOX(frames_radio_list), radio_as_laid_out, FALSE, FALSE, 0);
+  gtk_box_pack_start(GTK_BOX(frames_radio_list), radio_selected_frame, FALSE, FALSE, 0);
+  gtk_box_pack_start(GTK_BOX(frames_radio_list), radio_separate_frames, FALSE, FALSE, 0);
+  gtk_container_add(GTK_CONTAINER(frames_radio_container), frames_radio_list);
+
+  // Check buttons for shrink-to-fit and print selection
+  GtkWidget* check_buttons_container = gtk_vbox_new(TRUE, 2);
+  shrink_to_fit_toggle = gtk_check_button_new_with_mnemonic(GetUTF8FromBundle("shrinkToFit").get());
+  selection_only_toggle = gtk_check_button_new_with_mnemonic(GetUTF8FromBundle("selectionOnly").get());
+  PRBool canSelectText;
+  aSettings->GetPrintOptions(nsIPrintSettings::kEnableSelectionRB, &canSelectText);
+  if (!canSelectText)
+    gtk_widget_set_sensitive(selection_only_toggle, FALSE);
+
+  gtk_box_pack_start(GTK_BOX(check_buttons_container), shrink_to_fit_toggle, FALSE, FALSE, 0);
+  gtk_box_pack_start(GTK_BOX(check_buttons_container), selection_only_toggle, FALSE, FALSE, 0);
+
+  // Check buttons for printing background
+  GtkWidget* appearance_buttons_container = gtk_vbox_new(TRUE, 2);
+  print_bg_colors_toggle = gtk_check_button_new_with_mnemonic(GetUTF8FromBundle("printBGColors").get());
+  print_bg_images_toggle = gtk_check_button_new_with_mnemonic(GetUTF8FromBundle("printBGImages").get());
+  gtk_box_pack_start(GTK_BOX(appearance_buttons_container), print_bg_colors_toggle, FALSE, FALSE, 0);
+  gtk_box_pack_start(GTK_BOX(appearance_buttons_container), print_bg_images_toggle, FALSE, FALSE, 0);
+
+  // "Appearance" options label, bold and center-aligned
+  GtkWidget* appearance_label = gtk_label_new(NULL);
+  pangoMarkup = g_markup_printf_escaped("<b>%s</b>", GetUTF8FromBundle("printBGOptions").get());
+  gtk_label_set_markup(GTK_LABEL(appearance_label), pangoMarkup);
+  g_free(pangoMarkup);
+  gtk_misc_set_alignment(GTK_MISC(appearance_label), 0, 0);
+
+  GtkWidget* appearance_container = gtk_alignment_new(0, 0, 0, 0);
+  gtk_alignment_set_padding(GTK_ALIGNMENT(appearance_container), 8, 0, 12, 0);
+  gtk_container_add(GTK_CONTAINER(appearance_container), appearance_buttons_container);
+
+  GtkWidget* appearance_vertical_squasher = gtk_vbox_new(FALSE, 0);
+  gtk_box_pack_start(GTK_BOX(appearance_vertical_squasher), appearance_label, FALSE, FALSE, 0);
+  gtk_box_pack_start(GTK_BOX(appearance_vertical_squasher), appearance_container, FALSE, FALSE, 0);
+
+  // "Header & Footer" options label, bold and center-aligned
+  GtkWidget* header_footer_label = gtk_label_new(NULL);
+  pangoMarkup = g_markup_printf_escaped("<b>%s</b>", GetUTF8FromBundle("headerFooter").get());
+  gtk_label_set_markup(GTK_LABEL(header_footer_label), pangoMarkup);
+  g_free(pangoMarkup);
+  gtk_misc_set_alignment(GTK_MISC(header_footer_label), 0, 0);
+
+  GtkWidget* header_footer_container = gtk_alignment_new(0, 0, 0, 0);
+  gtk_alignment_set_padding(GTK_ALIGNMENT(header_footer_container), 8, 0, 12, 0);
+
+
+  // --- Table for making the header and footer options ---
+  GtkWidget* header_footer_table = gtk_table_new(3, 3, FALSE); // 3x3 table
+  nsXPIDLString header_footer_str[3];
+
+  aSettings->GetHeaderStrLeft(getter_Copies(header_footer_str[0]));
+  aSettings->GetHeaderStrCenter(getter_Copies(header_footer_str[1]));
+  aSettings->GetHeaderStrRight(getter_Copies(header_footer_str[2]));
+
+  for (unsigned int i = 0; i < NS_ARRAY_LENGTH(header_dropdown); i++) {
+    header_dropdown[i] = ConstructHeaderFooterDropdown(header_footer_str[i].get());
+    // Those 4 magic numbers in the middle provide the position in the table.
+    // The last two numbers mean 2 px padding on every side.
+    gtk_table_attach(GTK_TABLE(header_footer_table), header_dropdown[i], i, (i + 1),
+                     0, 1, (GtkAttachOptions) 0, (GtkAttachOptions) 0, 2, 2);
+  }
+
+  const char labelKeys[][7] = {"left", "center", "right"};
+  for (unsigned int i = 0; i < NS_ARRAY_LENGTH(labelKeys); i++) {
+    gtk_table_attach(GTK_TABLE(header_footer_table),
+                     gtk_label_new(GetUTF8FromBundle(labelKeys[i]).get()),
+                     i, (i + 1), 1, 2, (GtkAttachOptions) 0, (GtkAttachOptions) 0, 2, 2);
+  }
+
+  aSettings->GetFooterStrLeft(getter_Copies(header_footer_str[0]));
+  aSettings->GetFooterStrCenter(getter_Copies(header_footer_str[1]));
+  aSettings->GetFooterStrRight(getter_Copies(header_footer_str[2]));
+
+  for (unsigned int i = 0; i < NS_ARRAY_LENGTH(footer_dropdown); i++) {
+    footer_dropdown[i] = ConstructHeaderFooterDropdown(header_footer_str[i].get());
+    gtk_table_attach(GTK_TABLE(header_footer_table), footer_dropdown[i], i, (i + 1),
+                     2, 3, (GtkAttachOptions) 0, (GtkAttachOptions) 0, 2, 2);
+  }
+  // ---
+
+  gtk_container_add(GTK_CONTAINER(header_footer_container), header_footer_table);
+
+  GtkWidget* header_footer_vertical_squasher = gtk_vbox_new(FALSE, 0);
+  gtk_box_pack_start(GTK_BOX(header_footer_vertical_squasher), header_footer_label, FALSE, FALSE, 0);
+  gtk_box_pack_start(GTK_BOX(header_footer_vertical_squasher), header_footer_container, FALSE, FALSE, 0);
+
+  // Construction of everything
+  gtk_box_pack_start(GTK_BOX(custom_options_tab), print_frames_label, FALSE, FALSE, 0);
+  gtk_box_pack_start(GTK_BOX(custom_options_tab), frames_radio_container, FALSE, FALSE, 0);
+  gtk_box_pack_start(GTK_BOX(custom_options_tab), check_buttons_container, FALSE, FALSE, 10); // 10px padding
+  gtk_box_pack_start(GTK_BOX(custom_options_tab), appearance_vertical_squasher, FALSE, FALSE, 10);
+  gtk_box_pack_start(GTK_BOX(custom_options_tab), header_footer_vertical_squasher, FALSE, FALSE, 0);
+
+  gtk_print_unix_dialog_add_custom_tab(GTK_PRINT_UNIX_DIALOG(dialog), custom_options_tab, tab_label);
+  gtk_widget_show_all(custom_options_tab);
+}
+
+NS_ConvertUTF16toUTF8
+nsPrintDialogWidgetGTK::GetUTF8FromBundle(const char *aKey)
+{
+  nsXPIDLString intlString;
+  printBundle->GetStringFromName(NS_ConvertUTF8toUTF16(aKey).get(), getter_Copies(intlString));
+  return NS_ConvertUTF16toUTF8(intlString);  // Return the actual object so we don't lose reference
+}
+
+const char*
+nsPrintDialogWidgetGTK::OptionWidgetToString(GtkWidget *dropdown)
+{
+  gint index = gtk_combo_box_get_active(GTK_COMBO_BOX(dropdown));
+
+  NS_ASSERTION(index <= CUSTOM_VALUE_INDEX, "Index of dropdown is higher than expected!");
+
+  if (index == CUSTOM_VALUE_INDEX)
+    return (const char*) g_object_get_data(G_OBJECT(dropdown), "custom-text");
+  else
+    return header_footer_tags[index];
+}
+
+const gint
+nsPrintDialogWidgetGTK::Run()
+{
+  const gint response = RunDialog(GTK_DIALOG(dialog));
+  gtk_widget_hide(dialog);
+  return response;
+}
+
+void
+nsPrintDialogWidgetGTK::ExportFramePrinting(nsIPrintSettings *aNS, GtkPrintSettings *aSettings)
+{
+  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_as_laid_out)))
+    aNS->SetPrintFrameType(nsIPrintSettings::kFramesAsIs);
+  else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_selected_frame)))
+    aNS->SetPrintFrameType(nsIPrintSettings::kSelectedFrame);
+  else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_separate_frames)))
+    aNS->SetPrintFrameType(nsIPrintSettings::kEachFrameSep);
+  else
+    aNS->SetPrintFrameType(nsIPrintSettings::kNoFrames);
+}
+
+void
+nsPrintDialogWidgetGTK::ExportHeaderFooter(nsIPrintSettings *aNS)
+{
+  const char* header_footer_str;
+  header_footer_str = OptionWidgetToString(header_dropdown[0]);
+  aNS->SetHeaderStrLeft(NS_ConvertUTF8toUTF16(header_footer_str).get());
+
+  header_footer_str = OptionWidgetToString(header_dropdown[1]);
+  aNS->SetHeaderStrCenter(NS_ConvertUTF8toUTF16(header_footer_str).get());
+
+  header_footer_str = OptionWidgetToString(header_dropdown[2]);
+  aNS->SetHeaderStrRight(NS_ConvertUTF8toUTF16(header_footer_str).get());
+
+  header_footer_str = OptionWidgetToString(footer_dropdown[0]);
+  aNS->SetFooterStrLeft(NS_ConvertUTF8toUTF16(header_footer_str).get());
+
+  header_footer_str = OptionWidgetToString(footer_dropdown[1]);
+  aNS->SetFooterStrCenter(NS_ConvertUTF8toUTF16(header_footer_str).get());
+
+  header_footer_str = OptionWidgetToString(footer_dropdown[2]);
+  aNS->SetFooterStrRight(NS_ConvertUTF8toUTF16(header_footer_str).get());
+}
+
+nsresult
+nsPrintDialogWidgetGTK::ImportSettings(nsIPrintSettings *aNSSettings)
+{
+  NS_PRECONDITION(aNSSettings, "aSettings must not be null");
+  NS_ENSURE_TRUE(aNSSettings, NS_ERROR_FAILURE);
+
+  nsCOMPtr<nsPrintSettingsGTK> aNSSettingsGTK(do_QueryInterface(aNSSettings));
+  if (!aNSSettingsGTK)
+    return NS_ERROR_FAILURE;
+
+  GtkPrintSettings* settings = aNSSettingsGTK->GetGtkPrintSettings();
+  GtkPageSetup* setup = aNSSettingsGTK->GetGtkPageSetup();
+
+  PRBool geckoBool;
+  aNSSettings->GetShrinkToFit(&geckoBool);
+  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(shrink_to_fit_toggle), geckoBool);
+
+  aNSSettings->GetPrintBGColors(&geckoBool);
+  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(print_bg_colors_toggle), geckoBool);
+
+  aNSSettings->GetPrintBGImages(&geckoBool);
+  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(print_bg_images_toggle), geckoBool);
+
+  gtk_print_unix_dialog_set_settings(GTK_PRINT_UNIX_DIALOG(dialog), settings);
+  gtk_print_unix_dialog_set_page_setup(GTK_PRINT_UNIX_DIALOG(dialog), setup);
+  
+  return NS_OK;
+}
+
+nsresult
+nsPrintDialogWidgetGTK::ExportSettings(nsIPrintSettings *aNSSettings)
+{
+  NS_PRECONDITION(aNSSettings, "aSettings must not be null");
+  NS_ENSURE_TRUE(aNSSettings, NS_ERROR_FAILURE);
+
+  GtkPrintSettings* settings = gtk_print_unix_dialog_get_settings(GTK_PRINT_UNIX_DIALOG(dialog));
+  GtkPageSetup* setup = gtk_print_unix_dialog_get_page_setup(GTK_PRINT_UNIX_DIALOG(dialog));
+  GtkPrinter* printer = gtk_print_unix_dialog_get_selected_printer(GTK_PRINT_UNIX_DIALOG(dialog));
+  if (settings && setup && printer) {
+    ExportFramePrinting(aNSSettings, settings);
+    ExportHeaderFooter(aNSSettings);
+
+    aNSSettings->SetOutputFormat(nsIPrintSettings::kOutputFormatNative);
+
+    // Print-to-file is true by default. This must be turned off or else printing won't occur!
+    // (We manually copy the spool file when this flag is set, because we love our embedders)
+    // Even if it is print-to-file in GTK's case, GTK does The Right Thing when we send the job.
+    aNSSettings->SetPrintToFile(PR_FALSE);
+
+    aNSSettings->SetShrinkToFit(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(shrink_to_fit_toggle)));
+
+    aNSSettings->SetPrintBGColors(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(print_bg_colors_toggle)));
+    aNSSettings->SetPrintBGImages(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(print_bg_images_toggle)));
+
+    // Try to save native settings in the session object
+    nsCOMPtr<nsPrintSettingsGTK> aNSSettingsGTK(do_QueryInterface(aNSSettings));
+    if (aNSSettingsGTK) {
+      aNSSettingsGTK->SetGtkPrintSettings(settings);
+      aNSSettingsGTK->SetGtkPageSetup(setup);
+      aNSSettingsGTK->SetGtkPrinter(printer);
+      aNSSettingsGTK->SetForcePrintSelectionOnly(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(selection_only_toggle)));
+    }
+  }
+
+  if (settings)
+    g_object_unref(settings);
+  return NS_OK;
+}
+
+GtkWidget*
+nsPrintDialogWidgetGTK::ConstructHeaderFooterDropdown(const PRUnichar *currentString)
+{
+  GtkWidget* dropdown = gtk_combo_box_new_text();
+  const char hf_options[][22] = {"headerFooterBlank", "headerFooterTitle",
+                                 "headerFooterURL", "headerFooterDate",
+                                 "headerFooterPage", "headerFooterPageTotal",
+                                 "headerFooterCustom"};
+
+  for (unsigned int i = 0; i < NS_ARRAY_LENGTH(hf_options); i++) {
+    gtk_combo_box_append_text(GTK_COMBO_BOX(dropdown), GetUTF8FromBundle(hf_options[i]).get());
+  }
+
+  PRPackedBool shouldBeCustom = PR_TRUE;
+  NS_ConvertUTF16toUTF8 currentStringUTF8(currentString);
+
+  for (unsigned int i = 0; i < NS_ARRAY_LENGTH(header_footer_tags); i++) {
+    if (!strcmp(currentStringUTF8.get(), header_footer_tags[i])) {
+      gtk_combo_box_set_active(GTK_COMBO_BOX(dropdown), i);
+      shouldBeCustom = PR_FALSE;
+      break;
+    }
+  }
+
+  if (shouldBeCustom) {
+    gtk_combo_box_set_active(GTK_COMBO_BOX(dropdown), CUSTOM_VALUE_INDEX);
+    char* custom_string = strdup(currentStringUTF8.get());
+    g_object_set_data_full(G_OBJECT(dropdown), "custom-text", custom_string, (GDestroyNotify) free);
+  }
+
+  g_signal_connect(dropdown, "changed", (GCallback) ShowCustomDialog, NULL);
+  return dropdown;
+}
+
+NS_IMPL_ISUPPORTS1(nsPrintDialogServiceGTK, nsIPrintDialogService)
+
+nsPrintDialogServiceGTK::nsPrintDialogServiceGTK()
+{
+}
+
+nsPrintDialogServiceGTK::~nsPrintDialogServiceGTK()
+{
+}
+
+NS_IMETHODIMP
+nsPrintDialogServiceGTK::Init()
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPrintDialogServiceGTK::Show(nsIPrintSettings *aSettings)
+{
+  NS_PRECONDITION(aSettings, "aSettings must not be null");
+
+  nsPrintDialogWidgetGTK printDialog(aSettings);
+  nsresult rv = printDialog.ImportSettings(aSettings);
+
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  const gint response = printDialog.Run();
+
+  // Handle the result
+  switch (response) {
+    case GTK_RESPONSE_OK:                // Proceed
+      rv = printDialog.ExportSettings(aSettings);
+      break;
+
+    case GTK_RESPONSE_CANCEL:
+    case GTK_RESPONSE_CLOSE:
+    case GTK_RESPONSE_DELETE_EVENT:
+    case GTK_RESPONSE_NONE:
+      rv = NS_ERROR_ABORT;
+      break;
+
+    case GTK_RESPONSE_APPLY:                // Print preview
+    default:
+      NS_WARNING("Unexpected response");
+      rv = NS_ERROR_ABORT;
+  }
+  return rv;
+}
+
+NS_IMETHODIMP
+nsPrintDialogServiceGTK::ShowPageSetup(nsIPrintSettings *aNSSettings)
+{
+  NS_PRECONDITION(aNSSettings, "aSettings must not be null");
+  NS_ENSURE_TRUE(aNSSettings, NS_ERROR_FAILURE);
+
+  nsCOMPtr<nsPrintSettingsGTK> aNSSettingsGTK(do_QueryInterface(aNSSettings));
+  if (!aNSSettingsGTK)
+    return NS_ERROR_FAILURE;
+
+  // We need to init the prefs here because aNSSettings in its current form is a dummy in both uses of the word
+  nsCOMPtr<nsIPrintSettingsService> psService = do_GetService("@mozilla.org/gfx/printsettings-service;1");
+  if (psService) {
+    nsXPIDLString printName;
+    aNSSettings->GetPrinterName(getter_Copies(printName));
+    if (!printName) {
+      psService->GetDefaultPrinterName(getter_Copies(printName));
+      aNSSettings->SetPrinterName(printName.get());
+    }
+    psService->InitPrintSettingsFromPrefs(aNSSettings, PR_TRUE, nsIPrintSettings::kInitSaveAll);
+  }
+
+  GtkPrintSettings* gtkSettings = aNSSettingsGTK->GetGtkPrintSettings();
+  GtkPageSetup* oldPageSetup = aNSSettingsGTK->GetGtkPageSetup();
+
+  GtkPageSetup* newPageSetup = gtk_print_run_page_setup_dialog(NULL, oldPageSetup, gtkSettings);
+
+  aNSSettingsGTK->SetGtkPageSetup(newPageSetup);
+
+  // Now newPageSetup has a refcount of 2 (SetGtkPageSetup will addref), put it to 1 so if
+  // this gets replaced we don't leak.
+  g_object_unref(newPageSetup);
+
+  if (psService)
+    psService->SavePrintSettingsToPrefs(aNSSettings, PR_TRUE, nsIPrintSettings::kInitSaveAll);
+
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/widget/src/gtk2/nsPrintDialogGTK.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Mozilla GTK2 print dialog interface.
+ *
+ * The Initial Developer of the Original Code is
+ * Kenneth Herron <kherron@fmailbox.com>
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsPrintDialog_h__
+#define nsPrintDialog_h__
+
+#include "nsIPrintDialogService.h"
+
+class nsIPrintSettings;
+
+class nsPrintDialogServiceGTK : public nsIPrintDialogService
+{
+public:
+  nsPrintDialogServiceGTK();
+  virtual ~nsPrintDialogServiceGTK();
+
+  NS_DECL_ISUPPORTS
+
+  NS_IMETHODIMP Init();
+  NS_IMETHODIMP Show(nsIPrintSettings *aSettings);
+  NS_IMETHODIMP ShowPageSetup(nsIPrintSettings *aSettings);
+};
+
+#endif
deleted file mode 100644
--- a/widget/src/gtk2/nsPrintJobFactoryGTK.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ex: set tabstop=8 softtabstop=4 shiftwidth=4 expandtab: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Kenneth Herron <kherron@fastmail.us>.
- * Portions created by the Initial Developer are Copyright (C) 2004
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-
-#include "nsDebug.h"
-#include "nsPrintJobFactoryGTK.h"
-#include "nsIDeviceContextSpec.h"
-#include "nsDeviceContextSpecG.h"
-#include "nsPrintJobGTK.h"
-#include "nsPSPrinters.h"
-
-/**
- * Construct a print job object for the given device context spec.
- *
- * @param aSpec     An nsDeviceContextSpecGTK object for the print
- *                  job in question.
- * @param aPrintJob A pointer to a print job object which will
- *                  handle the print job.
- * @return NS_OK if all is well, or a suitable error value.
- */
-
-nsresult
-nsPrintJobFactoryGTK::CreatePrintJob(nsDeviceContextSpecGTK *aSpec,
-        nsIPrintJobGTK* &aPrintJob)
-{
-    NS_PRECONDITION(nsnull != aSpec, "aSpec is NULL");
-
-    nsIPrintJobGTK *newPJ;
-
-    PRBool setting;
-    aSpec->GetIsPrintPreview(setting);
-    if (setting)
-        newPJ = new nsPrintJobPreviewGTK();
-    else {
-        aSpec->GetToPrinter(setting);
-        if (!setting)
-            newPJ = new nsPrintJobFileGTK();
-        else
-        {
-            const char *printerName;
-            aSpec->GetPrinterName(&printerName);
-            if (nsPSPrinterList::kTypeCUPS == nsPSPrinterList::GetPrinterType(
-                        nsDependentCString(printerName)))
-                newPJ = new nsPrintJobCUPS();
-            else
-                newPJ = new nsPrintJobPipeGTK();
-        }
-    }
-    if (!newPJ)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    nsresult rv = newPJ->Init(aSpec);
-    if (NS_FAILED(rv))
-        delete newPJ;
-    else
-        aPrintJob = newPJ;
-    return rv;
-}
deleted file mode 100644
--- a/widget/src/gtk2/nsPrintJobFactoryGTK.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ex: set tabstop=8 softtabstop=4 shiftwidth=4 expandtab: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Kenneth Herron <kherron@fastmail.us>.
- * Portions created by the Initial Developer are Copyright (C) 2004
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef nsPrintJobFactoryGTK_h__
-#define nsPrintJobFactoryGTK_h__
-
-class nsIPrintJobGTK;
-class nsDeviceContextSpecGTK;
-
-/* Factory class for the print job subsystem. This class determines
- * which print job class should handle a print job, and constructs
- * an object of the appropriate class.
- */
-
-
-class nsPrintJobFactoryGTK
-{
-public:
-    /**
-     * Construct a print job object for the given device context spec.
-     * On success, the print job object is owned by the caller and should
-     * be destroyed when no longer needed.
-     *
-     * @param aSpec     An nsIDeviceContextSpecGTK object for the print
-     *                  job in question.
-     * @param aPrintJob If NS_OK is returned, this will be filled in with
-     *                  a pointer to a print job object.
-     * @return NS_OK or a suitable error value.
-     */
-    static nsresult CreatePrintJob(nsDeviceContextSpecGTK *aSpec,
-	    nsIPrintJobGTK* &aPrintJob);
-};
-
-
-#endif /* nsPrintJobFactoryGTK_h__ */
deleted file mode 100644
--- a/widget/src/gtk2/nsPrintJobGTK.cpp
+++ /dev/null
@@ -1,481 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ex: set tabstop=8 softtabstop=4 shiftwidth=4 expandtab: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Ken Herron <kherron@fastmail.us>.
- * Portions created by the Initial Developer are Copyright (C) 2004
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-
-#include "nscore.h"
-#include "nsIDeviceContext.h"   // NS_ERROR_GFX_*
-#include "nsIDeviceContextSpec.h"
-#include "nsDeviceContextSpecG.h"
-
-#include "nsPrintJobGTK.h"
-#include "nsPSPrinters.h"
-#include "nsReadableUtils.h"
-#include "nsDirectoryServiceDefs.h"
-#include "nsIFileStreams.h"
-
-#include "prenv.h"
-#include "prinit.h"
-#include "prlock.h"
-#include "prprf.h"
-
-#include <stdlib.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-
-/* Routines to set environment variables. These are defined toward
- * the end of this file.
- */
-static PRStatus EnvLock();
-static PRStatus EnvSetPrinter(nsCString&);
-static void EnvClear();
-
-
-/* Interface class. It implements a spoolfile getter and destructor
- * so that none of the subclasses have to.
- */
-nsIPrintJobGTK::~nsIPrintJobGTK()
-{
-    if (mSpoolFile)
-        mSpoolFile->Remove(PR_FALSE);
-}
-
-nsresult
-nsIPrintJobGTK::GetSpoolFile(nsILocalFile **aFile)
-{
-    if (!mSpoolFile)
-        return NS_ERROR_NOT_INITIALIZED;
-    *aFile = mSpoolFile;
-    NS_ADDREF(*aFile);
-    return NS_OK;
-}
-
-/**** nsPrintJobPreviewGTK - Stub class for print preview ****/
-
-/* nsDeviceContextSpecGTK needs a spool file even for print preview, so this
- * class includes code to create one. Some of the other print job classes
- * inherit from this one to reuse the spoolfile initializer.
- */
-
-nsresult
-nsPrintJobPreviewGTK::InitSpoolFile(PRUint32 aPermissions)
-{
-    nsCOMPtr<nsIFile> spoolFile;
-    nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR,
-                                         getter_AddRefs(spoolFile));
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_GFX_PRINTER_COULD_NOT_OPEN_FILE);
-
-    spoolFile->AppendNative(NS_LITERAL_CSTRING("tmp.prn"));
-    
-    rv = spoolFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, aPermissions);
-    if (NS_FAILED(rv))
-        return NS_ERROR_GFX_PRINTER_COULD_NOT_OPEN_FILE;
-    mSpoolFile = do_QueryInterface(spoolFile, &rv);
-    if (NS_FAILED(rv))
-        spoolFile->Remove(PR_FALSE);
-
-    return rv;
-}
-
-nsresult
-nsPrintJobPreviewGTK::Init(nsDeviceContextSpecGTK *aSpec)
-{
-#ifdef DEBUG
-    PRBool isPreview;
-    aSpec->GetIsPrintPreview(isPreview);
-    NS_PRECONDITION(isPreview, "This print job is to a printer");
-#endif
-    return InitSpoolFile(0600);
-}
-
-/**** nsPrintJobFileGTK - Print-to-file support ****/
-
-/**
- * Initialize the print-to-file object from the printing spec.
- * See nsPrintJobGTK.h for details.
- */
-nsresult
-nsPrintJobFileGTK::Init(nsDeviceContextSpecGTK *aSpec)
-{
-    NS_PRECONDITION(aSpec, "aSpec must not be NULL");
-#ifdef DEBUG
-    PRBool toPrinter;
-    aSpec->GetToPrinter(toPrinter);
-    NS_PRECONDITION(!toPrinter, "This print job is to a printer");
-#endif
-
-    // The final output file will inherit the permissions of the temporary.
-    nsresult rv = InitSpoolFile(0666);
-    if (NS_SUCCEEDED(rv)) {
-        const char *path;
-        aSpec->GetPath(&path);
-        rv = NS_NewNativeLocalFile(nsDependentCString(path), PR_FALSE,
-                                   getter_AddRefs(mDestFile));
-    }
-    return rv;
-}
-
-nsresult
-nsPrintJobFileGTK::Submit()
-{
-    // Move the spool file to the destination
-    nsAutoString destLeafName;
-    nsresult rv = mDestFile->GetLeafName(destLeafName);
-    if (NS_SUCCEEDED(rv)) {
-        nsCOMPtr<nsIFile> mDestDir;
-        rv = mDestFile->GetParent(getter_AddRefs(mDestDir));
-        if (NS_SUCCEEDED(rv)) {
-            rv = mSpoolFile->MoveTo(mDestDir, destLeafName);
-        }
-    }
-    return rv;
-}
-
-/**** Print-to-Pipe for unix and unix-like systems ****/
-
-/* This launches a command using popen(); the print job is then written
- * to the pipe.
- */
-
-/**
- * Initialize a print-to-pipe object.
- * See nsIPrintJobGTK.h and nsPrintJobGTK.h for details.
- */
-nsresult
-nsPrintJobPipeGTK::Init(nsDeviceContextSpecGTK *aSpec)
-{
-    NS_PRECONDITION(aSpec, "argument must not be NULL");
-#ifdef DEBUG
-    PRBool toPrinter;
-    aSpec->GetToPrinter(toPrinter);
-    NS_PRECONDITION(toPrinter, "Wrong class for this print job");
-#endif
-
-    /* Spool file */
-    nsresult rv = InitSpoolFile(0600);
-    if (NS_FAILED(rv))
-        return rv;
-
-    /* Print command */
-    const char *command;
-    aSpec->GetCommand(&command);
-    mCommand = command;
-
-    /* Printer name */
-    const char *printerName;
-    aSpec->GetPrinterName(&printerName);
-    if (printerName) {
-        const char *slash = strchr(printerName, '/');
-        if (slash)
-            printerName = slash + 1;
-        if (0 != strcmp(printerName, "default"))
-            mPrinterName = printerName;
-    }
-    return NS_OK;
-}
-
-
-/* Helper for nsPrintJobPipeGTK::Submit(). Start the print command. */
-static nsresult
-popenPrintCommand(FILE **aPipe, nsCString &aPrinter, nsCString &aCommand)
-{
-    // Set up the environment for the print command
-    if (PR_SUCCESS != EnvLock())
-        return NS_ERROR_OUT_OF_MEMORY;  // Couldn't allocate the object?
-
-    if (!aPrinter.IsEmpty())
-        EnvSetPrinter(aPrinter);
-
-    // Start the print command
-    *aPipe = popen(aCommand.get(), "w");
-    EnvClear();
-    return (*aPipe) ? NS_OK : NS_ERROR_GFX_PRINTER_CMD_FAILURE;
-}
-
-/* Helper for nsPrintJobPipeGTK::Submit(). Copy data from a temporary file
- * to the command pipe.
- */
-static nsresult
-CopySpoolToCommand(nsIFileInputStream *aSource, FILE *aDest)
-{
-    nsresult rv;
-    PRUint32 count;
-    do {
-        char buf[256];
-        count = 0;
-        rv = aSource->Read(buf, sizeof buf, &count);
-        fwrite(buf, 1, count, aDest);
-    } while (NS_SUCCEEDED(rv) && count);
-    return rv;
-}
-        
-/**
- * Launch the print command using popen(), then copy the print job data
- * to the pipe. See nsIPrintJobGTK.h and nsPrintJobGTK.h for details.
- */
-
-nsresult
-nsPrintJobPipeGTK::Submit()
-{
-    NS_PRECONDITION(mSpoolFile, "No spool file");
-
-    // Open the spool file
-    nsCOMPtr<nsIFileInputStream> spoolStream =
-        do_CreateInstance("@mozilla.org/network/file-input-stream;1");
-    if (!spoolStream)
-        return NS_ERROR_OUT_OF_MEMORY;
-    nsresult rv = spoolStream->Init(mSpoolFile, -1, -1,
-        nsIFileInputStream::DELETE_ON_CLOSE|nsIFileInputStream::CLOSE_ON_EOF);
-    NS_ENSURE_SUCCESS(rv, rv);
-    
-    // Start the print command
-    FILE *destPipe = NULL;
-    rv = popenPrintCommand(&destPipe, mPrinterName, mCommand);
-    if (NS_SUCCEEDED(rv)) {
-        rv = CopySpoolToCommand(spoolStream, destPipe);
-        int presult = pclose(destPipe);
-        if (NS_SUCCEEDED(rv)) {
-            if (!WIFEXITED(presult) || (EXIT_SUCCESS != WEXITSTATUS(presult)))
-                rv = NS_ERROR_GFX_PRINTER_CMD_FAILURE;
-        }
-    }            
-    spoolStream->Close();
-    return rv;
-}
-
-/**** Print via CUPS ****/
-
-/* nsPrintJobCUPS doesn't inherit its spoolfile code from the preview
- * class. CupsPrintFile() needs the filename as an 8-bit string, but an
- * nsILocalFile doesn't portably expose the filename in this format.
- * So it's necessary to construct the spoolfile name outside of the 
- * nsILocalFile object, and retain it as a string for use when calling
- * CupsPrintFile().
- */
-
-/**
- * Initialize a print-to-CUPS object.
- * See nsIPrintJobGTK.h and nsPrintJobGTK.h for details.
- */
-nsresult
-nsPrintJobCUPS::Init(nsDeviceContextSpecGTK *aSpec)
-{
-    NS_PRECONDITION(aSpec, "argument must not be NULL");
-#ifdef DEBUG
-    PRBool toPrinter;
-    aSpec->GetToPrinter(toPrinter);
-    NS_PRECONDITION(toPrinter, "Wrong class for this print job");
-#endif
-
-    NS_ENSURE_TRUE(mCups.Init(), NS_ERROR_NOT_INITIALIZED);
-
-    /* Printer name */
-    const char *printerName = nsnull;
-    aSpec->GetPrinterName(&printerName);
-    NS_ENSURE_TRUE(printerName, NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND);
-
-    const char *slash = strchr(printerName, '/');
-    mPrinterName = slash ? slash + 1 : printerName;
-    mJobTitle.SetIsVoid(PR_TRUE);
-    
-    /* Spool file */
-    int fd;
-    char buf[FILENAME_MAX];
-
-    fd = (mCups.mCupsTempFd)(buf, sizeof buf);
-    // The CUPS manual doesn't describe what cupsTempFd() returns to
-    // indicate failure. -1 is a likely value.
-    NS_ENSURE_TRUE(fd > 0, NS_ERROR_GFX_PRINTER_COULD_NOT_OPEN_FILE);
-    close(fd);
-    
-    nsresult rv = NS_NewNativeLocalFile(nsDependentCString(buf), PR_FALSE,
-                                        getter_AddRefs(mSpoolFile));
-    if (NS_FAILED(rv)) {
-        unlink(buf);
-        return NS_ERROR_GFX_PRINTER_COULD_NOT_OPEN_FILE;
-    }
-    mSpoolName = buf;
-    return NS_OK;
-}
-
-nsresult
-nsPrintJobCUPS::SetNumCopies(int aNumCopies)
-{
-    mNumCopies.Truncate();
-    if (aNumCopies > 1)
-        mNumCopies.AppendInt(aNumCopies);
-    return NS_OK;
-}
-
-
-/* According to the cups.development forum, only plain ASCII may be
- * reliably used for CUPS print job titles. See
- * <http://www.cups.org/newsgroups.php?s523+gcups.development+v530+T0>.
- */
-void
-nsPrintJobCUPS::SetJobTitle(const PRUnichar *aTitle)
-{
-    if (aTitle) {
-        LossyCopyUTF16toASCII(aTitle, mJobTitle);
-    }
-}
-
-nsresult
-nsPrintJobCUPS::Submit()
-{
-    NS_ENSURE_TRUE(mCups.IsInitialized(), NS_ERROR_NOT_INITIALIZED);
-    NS_PRECONDITION(!mSpoolName.IsEmpty(), "No spool file");
-
-    nsCStringArray printer(3);
-    printer.ParseString(mPrinterName.get(),"/");
-
-    cups_dest_t *dests, *dest;
-    int num_dests = (mCups.mCupsGetDests)(&dests);
-    
-    if (printer.Count() == 1) {
-        dest = (mCups.mCupsGetDest)(printer.CStringAt(0)->get(), NULL, num_dests, dests);
-    } else {
-        dest = (mCups.mCupsGetDest)(printer.CStringAt(0)->get(), 
-                                    printer.CStringAt(1)->get(), num_dests, dests);
-    }
-
-    // Setting result just to get rid of compilation warning
-    int result=0;
-    if (dest != NULL) {
-        if (!mNumCopies.IsEmpty())
-            dest->num_options = (mCups.mCupsAddOption)("copies",
-                                                       mNumCopies.get(),
-                                                       dest->num_options,
-                                                       &dest->options);
-        const char *title = mJobTitle.IsVoid() ?
-            "Untitled Document" : mJobTitle.get();
-        result = (mCups.mCupsPrintFile)(printer.CStringAt(0)->get(),
-                                            mSpoolName.get(), title, 
-                                            dest->num_options, dest->options);
-    }
-    (mCups.mCupsFreeDests)(num_dests, dests);
-
-    // cupsPrintFile() result codes below 0x0300 indicate success.
-    // Individual success codes are defined in the cups headers, but
-    // we're not including those.
-    if (dest == NULL)
-        return NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND;
-    else
-        return (result < 0x0300) ? NS_OK : NS_ERROR_GFX_PRINTER_CMD_FAILURE;
-}
-
-/* Routines to set the MOZ_PRINTER_NAME environment variable and to
- * single-thread print jobs while the variable is set.
- */
-
-static PRLock *EnvLockObj;
-static PRCallOnceType EnvLockOnce;
-
-/* EnvLock callback function */
-static PRStatus
-EnvLockInit()
-{
-    EnvLockObj = PR_NewLock();
-    return EnvLockObj ? PR_SUCCESS : PR_FAILURE;
-}
-
-
-/**
- * Get the lock for setting printing-related environment variables and
- * running print commands.
- * @return PR_SUCCESS on success
- *         PR_FAILURE if the lock object could not be initialized.
- *                 
- */
-static PRStatus
-EnvLock()
-{
-    if (PR_FAILURE == PR_CallOnce(&EnvLockOnce, EnvLockInit))
-        return PR_FAILURE;
-    PR_Lock(EnvLockObj);
-    return PR_SUCCESS;
-}
-
-
-static char *EnvPrinterString;
-static const char EnvPrinterName[] = { "MOZ_PRINTER_NAME" };
-
-
-/**
- * Set MOZ_PRINTER_NAME to the specified string.
- * @param aPrinter The value for MOZ_PRINTER_NAME. May be an empty string.
- * @return PR_SUCCESS on success.
- *         PR_FAILURE if memory could not be allocated.
- */
-static PRStatus
-EnvSetPrinter(nsCString& aPrinter)
-{
-    /* Construct the new environment string */
-    char *newVar = PR_smprintf("%s=%s", EnvPrinterName, aPrinter.get());
-    if (!newVar)
-        return PR_FAILURE;
-
-    /* Add it to the environment and dispose of any old string */
-    PR_SetEnv(newVar);
-    if (EnvPrinterString)
-        PR_smprintf_free(EnvPrinterString);
-    EnvPrinterString = newVar;
-
-    return PR_SUCCESS;
-}
-
-
-/**
- * Clear the printer environment variable and release the environment lock.
- */
-static void
-EnvClear()
-{
-    if (EnvPrinterString) {
-        /* On some systems, setenv("FOO") will remove FOO
-         * from the environment.
-         */
-        PR_SetEnv(EnvPrinterName);
-        if (!PR_GetEnv(EnvPrinterName)) {
-            /* It must have worked */
-            PR_smprintf_free(EnvPrinterString);
-            EnvPrinterString = nsnull;
-        }
-    }
-    PR_Unlock(EnvLockObj);
-}
deleted file mode 100644
--- a/widget/src/gtk2/nsPrintJobGTK.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ex: set tabstop=8 softtabstop=4 shiftwidth=4 expandtab: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Ken Herron <kherron@fastmail.us>.
- * Portions created by the Initial Developer are Copyright (C) 2004
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef nsPrintJobGTK_h__
-#define nsPrintJobGTK_h__
-
-#include "nsCUPSShim.h"
-#include "nsDebug.h"
-#include "nsIDeviceContext.h"   // for NS_ERROR_GFX_PRINTING_NOT_IMPLEMENTED
-#include "nsILocalFile.h"
-#include "nsIPrintJobGTK.h"
-#include "nsString.h"
-#include "nsDeviceContextSpecG.h"
-
-/* Print job class for print preview operations. */
-
-class nsPrintJobPreviewGTK : public nsIPrintJobGTK {
-    public:
-        /* see nsIPrintJobGTK.h. Print preview doesn't actually
-         * implement printing.
-         */
-        virtual nsresult Submit()
-            { return NS_ERROR_GFX_PRINTING_NOT_IMPLEMENTED; }
-
-    protected:
-        virtual nsresult Init(nsDeviceContextSpecGTK *);
-        nsresult InitSpoolFile(PRUint32 aPermissions);
-};
-
-
-/* Print job class for print-to-file. */
-class nsPrintJobFileGTK : public nsPrintJobPreviewGTK {
-    public:
-        virtual nsresult Submit();
-
-    protected:
-        virtual nsresult Init(nsDeviceContextSpecGTK *);
-        nsCOMPtr<nsILocalFile> mDestFile;
-};
-
-/* This is the class for printing to a pipe. */
-class nsPrintJobPipeGTK : public nsPrintJobPreviewGTK {
-    public:
-        virtual nsresult Submit();
-
-    protected:
-        virtual nsresult Init(nsDeviceContextSpecGTK *);
-
-    private:
-        nsCString mCommand;
-        nsCString mPrinterName;
-};
-
-
-/* This class submits print jobs through CUPS. */
-class nsPrintJobCUPS : public nsIPrintJobGTK {
-    public:
-        virtual nsresult Submit();
-        virtual nsresult SetNumCopies(int aNumCopies);
-        virtual void SetJobTitle(const PRUnichar *aTitle);
-
-    protected:
-        virtual nsresult Init(nsDeviceContextSpecGTK *);
-
-    private:
-        nsCUPSShim mCups;
-        nsCString mPrinterName;
-        nsCString mNumCopies;
-        nsCString mJobTitle;        // IsVoid() if no title
-        nsCString mSpoolName;
-};
-
-#endif /* nsPrintJobPS_h__ */
--- a/widget/src/gtk2/nsPrintOptionsGTK.cpp
+++ b/widget/src/gtk2/nsPrintOptionsGTK.cpp
@@ -30,17 +30,17 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 #include "nsPrintOptionsGTK.h"
-
+#include "nsPrintSettingsGTK.h"
 
 
 /** ---------------------------------------------------
  *  See documentation in nsPrintOptionsWin.h
  *	@update 6/21/00 dwc
  */
 nsPrintOptionsGTK::nsPrintOptionsGTK()
 {
@@ -50,8 +50,21 @@ nsPrintOptionsGTK::nsPrintOptionsGTK()
 /** ---------------------------------------------------
  *  See documentation in nsPrintOptionsImpl.h
  *	@update 6/21/00 dwc
  */
 nsPrintOptionsGTK::~nsPrintOptionsGTK()
 {
 }
 
+/* nsIPrintSettings CreatePrintSettings (); */
+nsresult nsPrintOptionsGTK::_CreatePrintSettings(nsIPrintSettings **_retval)
+{
+  *_retval = nsnull;
+  nsPrintSettingsGTK* printSettings = new nsPrintSettingsGTK(); // does not initially ref count
+  NS_ENSURE_TRUE(printSettings, NS_ERROR_OUT_OF_MEMORY);
+
+  NS_ADDREF(*_retval = printSettings); // ref count
+
+  return NS_OK;
+}
+
+
--- a/widget/src/gtk2/nsPrintOptionsGTK.h
+++ b/widget/src/gtk2/nsPrintOptionsGTK.h
@@ -47,14 +47,15 @@
 //***    nsPrintOptions
 //*****************************************************************************
 class nsPrintOptionsGTK : public nsPrintOptions
 {
 public:
   nsPrintOptionsGTK();
   virtual ~nsPrintOptionsGTK();
 
+  virtual nsresult _CreatePrintSettings(nsIPrintSettings **_retval);
 
 };
 
 
 
 #endif /* nsPrintOptions_h__ */
new file mode 100644
--- /dev/null
+++ b/widget/src/gtk2/nsPrintSettingsGTK.cpp
@@ -0,0 +1,732 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Michael Ventnor <m.ventnor@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsPrintSettingsGTK.h"
+#include "nsILocalFile.h"
+#include "nsNetUtil.h"
+#include <stdlib.h>
+
+static
+gboolean ref_printer(GtkPrinter *aPrinter, gpointer aData)
+{
+  ((nsPrintSettingsGTK*) aData)->SetGtkPrinter(aPrinter);
+  return TRUE;
+}
+
+static
+gboolean printer_enumerator(GtkPrinter *aPrinter, gpointer aData)
+{
+  if (gtk_printer_is_default(aPrinter))
+    return ref_printer(aPrinter, aData);
+
+  return FALSE; // Keep 'em coming...
+}
+
+static
+GtkPaperSize* moz_gtk_paper_size_copy_to_new_custom(GtkPaperSize* oldPaperSize)
+{
+  // We make a "custom-ified" copy of the paper size so it can be changed later.
+  return gtk_paper_size_new_custom(gtk_paper_size_get_name(oldPaperSize),
+                                   gtk_paper_size_get_display_name(oldPaperSize),
+                                   gtk_paper_size_get_width(oldPaperSize, GTK_UNIT_INCH),
+                                   gtk_paper_size_get_height(oldPaperSize, GTK_UNIT_INCH),
+                                   GTK_UNIT_INCH);
+}
+
+NS_IMPL_ISUPPORTS_INHERITED1(nsPrintSettingsGTK, 
+                             nsPrintSettings, 
+                             nsPrintSettingsGTK)
+
+/** ---------------------------------------------------
+ */
+nsPrintSettingsGTK::nsPrintSettingsGTK() :
+  mPageSetup(NULL),
+  mPrintSettings(NULL),
+  mGTKPrinter(NULL)
+{
+  // The aim here is to set up the objects enough that silent printing works well.
+  // These will be replaced anyway if the print dialog is used.
+  mPrintSettings = gtk_print_settings_new();
+  mPageSetup = gtk_page_setup_new();
+
+  SetOutputFormat(nsIPrintSettings::kOutputFormatNative);
+
+  GtkPaperSize* defaultPaperSize = gtk_paper_size_new(NULL);
+  mPaperSize = moz_gtk_paper_size_copy_to_new_custom(defaultPaperSize);
+  gtk_paper_size_free(defaultPaperSize);
+  SaveNewPageSize();
+}
+
+/** ---------------------------------------------------
+ */
+nsPrintSettingsGTK::~nsPrintSettingsGTK()
+{
+  if (mPageSetup) {
+    g_object_unref(mPageSetup);
+    mPageSetup = NULL;
+  }
+  if (mPrintSettings) {
+    g_object_unref(mPrintSettings);
+    mPrintSettings = NULL;
+  }
+  if (mGTKPrinter) {
+    g_object_unref(mGTKPrinter);
+    mGTKPrinter = NULL;
+  }
+  gtk_paper_size_free(mPaperSize);
+}
+
+/** ---------------------------------------------------
+ */
+nsPrintSettingsGTK::nsPrintSettingsGTK(const nsPrintSettingsGTK& aPS) :
+  mPageSetup(NULL),
+  mPrintSettings(NULL),
+  mGTKPrinter(NULL),
+  mPrintSelectionOnly(PR_FALSE)
+{
+  *this = aPS;
+}
+
+/** ---------------------------------------------------
+ */
+nsPrintSettingsGTK& nsPrintSettingsGTK::operator=(const nsPrintSettingsGTK& rhs)
+{
+  if (this == &rhs) {
+    return *this;
+  }
+  
+  nsPrintSettings::operator=(rhs);
+
+  if (mPageSetup)
+    g_object_unref(mPageSetup);
+  mPageSetup = gtk_page_setup_copy(rhs.mPageSetup);
+
+  if (mPrintSettings)
+    g_object_unref(mPrintSettings);
+  mPrintSettings = gtk_print_settings_copy(rhs.mPrintSettings);
+
+  if (mGTKPrinter)
+    g_object_unref(mGTKPrinter);
+  mGTKPrinter = (GtkPrinter*) g_object_ref(rhs.mGTKPrinter);
+
+  mPrintSelectionOnly = rhs.mPrintSelectionOnly;
+
+  return *this;
+}
+
+/** -------------------------------------------
+ */
+nsresult nsPrintSettingsGTK::_Clone(nsIPrintSettings **_retval)
+{
+  NS_ENSURE_ARG_POINTER(_retval);
+  *_retval = nsnull;
+  
+  nsPrintSettingsGTK *newSettings = new nsPrintSettingsGTK(*this);
+  if (!newSettings)
+    return NS_ERROR_FAILURE;
+  *_retval = newSettings;
+  NS_ADDREF(*_retval);
+  return NS_OK;
+}
+
+
+/** -------------------------------------------
+ */
+NS_IMETHODIMP
+nsPrintSettingsGTK::_Assign(nsIPrintSettings *aPS)
+{
+  nsPrintSettingsGTK *printSettingsGTK = static_cast<nsPrintSettingsGTK*>(aPS);
+  if (!printSettingsGTK)
+    return NS_ERROR_UNEXPECTED;
+  *this = *printSettingsGTK;
+  return NS_OK;
+}
+
+/** ---------------------------------------------------
+ */
+void
+nsPrintSettingsGTK::SetGtkPageSetup(GtkPageSetup *aPageSetup)
+{
+  if (mPageSetup)
+    g_object_unref(mPageSetup);
+  
+  mPageSetup = (GtkPageSetup*) g_object_ref(aPageSetup);
+
+  // We make a custom copy of the GtkPaperSize so it can be mutable. If a
+  // GtkPaperSize wasn't made as custom, its properties are immutable.
+  GtkPaperSize* newPaperSize = gtk_page_setup_get_paper_size(aPageSetup);
+  if (newPaperSize) { // Yes, this can be null
+    gtk_paper_size_free(mPaperSize);
+    mPaperSize = moz_gtk_paper_size_copy_to_new_custom(newPaperSize);
+  }
+  // If newPaperSize was not null, we must update our twin too (GtkPrintSettings).
+  // If newPaperSize was null, we must set this object to use mPaperSize.
+  SaveNewPageSize();
+}
+
+/** ---------------------------------------------------
+ */
+void
+nsPrintSettingsGTK::SetGtkPrintSettings(GtkPrintSettings *aPrintSettings)
+{
+  if (mPrintSettings)
+    g_object_unref(mPrintSettings);
+  
+  mPrintSettings = (GtkPrintSettings*) g_object_ref(aPrintSettings);
+
+  GtkPaperSize* newPaperSize = gtk_print_settings_get_paper_size(aPrintSettings);
+  if (newPaperSize) {
+    gtk_paper_size_free(mPaperSize);
+    mPaperSize = moz_gtk_paper_size_copy_to_new_custom(newPaperSize);
+  }
+  SaveNewPageSize();
+}
+
+/** ---------------------------------------------------
+ */
+void
+nsPrintSettingsGTK::SetGtkPrinter(GtkPrinter *aPrinter)
+{
+  if (mGTKPrinter)
+    g_object_unref(mGTKPrinter);
+  
+  mGTKPrinter = (GtkPrinter*) g_object_ref(aPrinter);
+}
+
+/**
+ * Reimplementation of nsPrintSettings functions so that we get the values
+ * from the GTK objects rather than our own variables.
+ */
+
+/* attribute long printRange; */
+NS_IMETHODIMP nsPrintSettingsGTK::GetPrintRange(PRInt16 *aPrintRange)
+{
+  NS_ENSURE_ARG_POINTER(aPrintRange);
+  if (mPrintSelectionOnly) {
+    *aPrintRange = kRangeSelection;
+    return NS_OK;
+  }
+
+  GtkPrintPages gtkRange = gtk_print_settings_get_print_pages(mPrintSettings);
+  if (gtkRange == GTK_PRINT_PAGES_RANGES)
+    *aPrintRange = kRangeSpecifiedPageRange;
+  else
+    *aPrintRange = kRangeAllPages;
+
+  return NS_OK;
+}
+NS_IMETHODIMP nsPrintSettingsGTK::SetPrintRange(PRInt16 aPrintRange)
+{
+  if (aPrintRange == kRangeSelection) {
+    mPrintSelectionOnly = PR_TRUE;
+    return NS_OK;
+  }
+
+  mPrintSelectionOnly = PR_FALSE;
+  if (aPrintRange == kRangeSpecifiedPageRange)
+    gtk_print_settings_set_print_pages(mPrintSettings, GTK_PRINT_PAGES_RANGES);
+  else
+    gtk_print_settings_set_print_pages(mPrintSettings, GTK_PRINT_PAGES_ALL);
+  return NS_OK;
+}
+
+/* attribute long startPageRange; */
+NS_IMETHODIMP
+nsPrintSettingsGTK::GetStartPageRange(PRInt32 *aStartPageRange)
+{
+  gint ctRanges;
+  GtkPageRange* lstRanges = gtk_print_settings_get_page_ranges(mPrintSettings, &ctRanges);
+
+  // Make sure we got a range.
+  if (ctRanges < 1) {
+    *aStartPageRange = 1;
+  } else {
+    // GTK supports multiple page ranges; gecko only supports 1. So find
+    // the lowest start page.
+    PRInt32 start(lstRanges[0].start);
+    for (gint ii = 1; ii < ctRanges; ii++) {
+      start = PR_MIN(lstRanges[ii].start, start);
+    }
+    *aStartPageRange = start + 1;
+  }
+
+  g_free(lstRanges);
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsPrintSettingsGTK::SetStartPageRange(PRInt32 aStartPageRange)
+{
+  PRInt32 endRange;
+  GetEndPageRange(&endRange);
+
+  GtkPageRange gtkRange;
+  gtkRange.start = aStartPageRange - 1;
+  gtkRange.end = endRange - 1;
+
+  gtk_print_settings_set_page_ranges(mPrintSettings, &gtkRange, 1);
+
+  return NS_OK;
+}
+
+/* attribute long endPageRange; */
+NS_IMETHODIMP
+nsPrintSettingsGTK::GetEndPageRange(PRInt32 *aEndPageRange)
+{
+  gint ctRanges;
+  GtkPageRange* lstRanges = gtk_print_settings_get_page_ranges(mPrintSettings, &ctRanges);
+
+  if (ctRanges < 1) {
+    *aEndPageRange = 1;
+  } else {
+    PRInt32 end(lstRanges[0].end);
+    for (gint ii = 1; ii < ctRanges; ii++) {
+      end = PR_MAX(lstRanges[ii].end, end);
+    }
+    *aEndPageRange = end + 1;
+  }
+
+  g_free(lstRanges);
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsPrintSettingsGTK::SetEndPageRange(PRInt32 aEndPageRange)
+{
+  PRInt32 startRange;
+  GetStartPageRange(&startRange);
+
+  GtkPageRange gtkRange;
+  gtkRange.start = startRange - 1;
+  gtkRange.end = aEndPageRange - 1;
+
+  gtk_print_settings_set_page_ranges(mPrintSettings, &gtkRange, 1);
+
+  return NS_OK;
+}
+
+/* attribute boolean printReversed; */
+NS_IMETHODIMP
+nsPrintSettingsGTK::GetPrintReversed(PRBool *aPrintReversed)
+{
+  *aPrintReversed = gtk_print_settings_get_reverse(mPrintSettings);
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsPrintSettingsGTK::SetPrintReversed(PRBool aPrintReversed)
+{
+  gtk_print_settings_set_reverse(mPrintSettings, aPrintReversed);
+  return NS_OK;
+}
+
+/* attribute boolean printInColor; */
+NS_IMETHODIMP
+nsPrintSettingsGTK::GetPrintInColor(PRBool *aPrintInColor)
+{
+  *aPrintInColor = gtk_print_settings_get_use_color(mPrintSettings);
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsPrintSettingsGTK::SetPrintInColor(PRBool aPrintInColor)
+{
+  gtk_print_settings_set_use_color(mPrintSettings, aPrintInColor);
+  return NS_OK;
+}
+
+/* attribute short orientation; */
+NS_IMETHODIMP
+nsPrintSettingsGTK::GetOrientation(PRInt32 *aOrientation)
+{
+  NS_ENSURE_ARG_POINTER(aOrientation);
+
+  GtkPageOrientation gtkOrient = gtk_page_setup_get_orientation(mPageSetup);
+  switch (gtkOrient) {
+    case GTK_PAGE_ORIENTATION_LANDSCAPE:
+    case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
+      *aOrientation = kLandscapeOrientation;
+      break;
+
+    case GTK_PAGE_ORIENTATION_PORTRAIT:
+    case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
+    default:
+      *aOrientation = kPortraitOrientation;
+  }
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsPrintSettingsGTK::SetOrientation(PRInt32 aOrientation)
+{
+  GtkPageOrientation gtkOrient;
+  if (aOrientation == kLandscapeOrientation)
+    gtkOrient = GTK_PAGE_ORIENTATION_LANDSCAPE;
+  else
+    gtkOrient = GTK_PAGE_ORIENTATION_PORTRAIT;
+
+  gtk_print_settings_set_orientation(mPrintSettings, gtkOrient);
+  gtk_page_setup_set_orientation(mPageSetup, gtkOrient);
+  return NS_OK;
+}
+
+/* attribute wstring toFileName; */
+NS_IMETHODIMP
+nsPrintSettingsGTK::GetToFileName(PRUnichar * *aToFileName)
+{
+  // Get the gtk output filename
+  const char* gtk_output_uri = gtk_print_settings_get(mPrintSettings, GTK_PRINT_SETTINGS_OUTPUT_URI);
+  if (!gtk_output_uri) {
+    *aToFileName = ToNewUnicode(mToFileName);
+    return NS_OK;
+  }
+
+  // Convert to an nsIFile
+  nsCOMPtr<nsIFile> file;
+  NS_GetFileFromURLSpec(nsDependentCString(gtk_output_uri), getter_AddRefs(file));
+
+  // Extract the path
+  nsAutoString path;
+  file->GetPath(path);
+
+  *aToFileName = ToNewUnicode(path);
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsPrintSettingsGTK::SetToFileName(const PRUnichar * aToFileName)
+{
+  if (aToFileName[0] == 0) {
+    mToFileName.SetLength(0);
+    gtk_print_settings_set(mPrintSettings, GTK_PRINT_SETTINGS_OUTPUT_URI, NULL);
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsILocalFile> file;
+  NS_NewLocalFile(nsDependentString(aToFileName), PR_TRUE, getter_AddRefs(file));
+
+  // Convert the nsIFile to a URL
+  nsCAutoString url;
+  NS_GetURLSpecFromFile(file, url);
+
+  gtk_print_settings_set(mPrintSettings, GTK_PRINT_SETTINGS_OUTPUT_URI, url.get());
+  mToFileName = aToFileName;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPrintSettingsGTK::GetPrinterName(PRUnichar * *aPrinter)
+{
+  const char* gtkPrintName = gtk_print_settings_get_printer(mPrintSettings);
+  if (!gtkPrintName) {
+    if (GTK_IS_PRINTER(mGTKPrinter)) {
+      gtkPrintName = gtk_printer_get_name(mGTKPrinter);
+    } else {
+      *aPrinter = nsnull;
+      return NS_OK;
+    }
+  }
+  *aPrinter = ToNewUnicode(nsDependentCString(gtkPrintName));
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPrintSettingsGTK::SetPrinterName(const PRUnichar * aPrinter)
+{
+  NS_ConvertUTF16toUTF8 gtkPrinter(aPrinter);
+
+  if (StringBeginsWith(gtkPrinter, NS_LITERAL_CSTRING("PostScript/"))) {
+    // Don't bother importing this name
+    gtkPrinter.AssignLiteral("");
+  }
+
+  if (StringBeginsWith(gtkPrinter, NS_LITERAL_CSTRING("CUPS/"))) {
+    // Strip off "CUPS/"; GTK might recognize the rest
+    gtkPrinter.Cut(0, strlen("CUPS/"));
+  }
+
+  if (!gtkPrinter.Equals(gtk_print_settings_get_printer(mPrintSettings))) {
+    mIsInitedFromPrinter = PR_FALSE;
+    mIsInitedFromPrefs = PR_FALSE;
+    gtk_print_settings_set_printer(mPrintSettings, gtkPrinter.get());
+  }
+
+  return NS_OK;
+}
+
+/* attribute long numCopies; */
+NS_IMETHODIMP
+nsPrintSettingsGTK::GetNumCopies(PRInt32 *aNumCopies)
+{
+  NS_ENSURE_ARG_POINTER(aNumCopies);
+  *aNumCopies = gtk_print_settings_get_n_copies(mPrintSettings);
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsPrintSettingsGTK::SetNumCopies(PRInt32 aNumCopies)
+{
+  gtk_print_settings_set_n_copies(mPrintSettings, aNumCopies);
+  return NS_OK;
+}
+
+/* attribute double edgeTop; */
+NS_IMETHODIMP
+nsPrintSettingsGTK::GetEdgeTop(double *aEdgeTop)
+{
+  NS_ENSURE_ARG_POINTER(aEdgeTop);
+  *aEdgeTop = gtk_page_setup_get_top_margin(mPageSetup, GTK_UNIT_INCH);
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsPrintSettingsGTK::SetEdgeTop(double aEdgeTop)
+{
+  gtk_page_setup_set_top_margin(mPageSetup, aEdgeTop, GTK_UNIT_INCH);
+  return NS_OK;
+}
+
+/* attribute double edgeLeft; */
+NS_IMETHODIMP
+nsPrintSettingsGTK::GetEdgeLeft(double *aEdgeLeft)
+{
+  NS_ENSURE_ARG_POINTER(aEdgeLeft);
+  *aEdgeLeft = gtk_page_setup_get_left_margin(mPageSetup, GTK_UNIT_INCH);
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsPrintSettingsGTK::SetEdgeLeft(double aEdgeLeft)
+{
+  gtk_page_setup_set_left_margin(mPageSetup, aEdgeLeft, GTK_UNIT_INCH);
+  return NS_OK;
+}
+
+/* attribute double edgeBottom; */
+NS_IMETHODIMP
+nsPrintSettingsGTK::GetEdgeBottom(double *aEdgeBottom)
+{
+  NS_ENSURE_ARG_POINTER(aEdgeBottom);
+  *aEdgeBottom = gtk_page_setup_get_bottom_margin(mPageSetup, GTK_UNIT_INCH);
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsPrintSettingsGTK::SetEdgeBottom(double aEdgeBottom)
+{
+  gtk_page_setup_set_bottom_margin(mPageSetup, aEdgeBottom, GTK_UNIT_INCH);
+  return NS_OK;
+}
+
+/* attribute double edgeRight; */
+NS_IMETHODIMP
+nsPrintSettingsGTK::GetEdgeRight(double *aEdgeRight)
+{
+  NS_ENSURE_ARG_POINTER(aEdgeRight);
+  *aEdgeRight = gtk_page_setup_get_right_margin(mPageSetup, GTK_UNIT_INCH);
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsPrintSettingsGTK::SetEdgeRight(double aEdgeRight)
+{
+  gtk_page_setup_set_right_margin(mPageSetup, aEdgeRight, GTK_UNIT_INCH);
+  return NS_OK;
+}
+
+/* attribute double scaling; */
+NS_IMETHODIMP
+nsPrintSettingsGTK::GetScaling(double *aScaling)
+{
+  *aScaling = gtk_print_settings_get_scale(mPrintSettings) / 100.0;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPrintSettingsGTK::SetScaling(double aScaling)
+{
+  gtk_print_settings_set_scale(mPrintSettings, aScaling * 100.0);
+  return NS_OK;
+}
+
+/* attribute wstring paperName; */
+NS_IMETHODIMP
+nsPrintSettingsGTK::GetPaperName(PRUnichar * *aPaperName)
+{
+  NS_ENSURE_ARG_POINTER(aPaperName);
+  *aPaperName = ToNewUnicode(NS_ConvertUTF8toUTF16(gtk_paper_size_get_name(mPaperSize)));
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsPrintSettingsGTK::SetPaperName(const PRUnichar * aPaperName)
+{
+  NS_ConvertUTF16toUTF8 gtkPaperName(aPaperName);
+
+  // Convert these Gecko names to GTK names
+  if (gtkPaperName.EqualsIgnoreCase("letter"))
+    gtkPaperName.AssignLiteral(GTK_PAPER_NAME_LETTER);
+  else if (gtkPaperName.EqualsIgnoreCase("legal"))
+    gtkPaperName.AssignLiteral(GTK_PAPER_NAME_LEGAL);
+
+  // Try to get the display name from the name so our paper size fits in the Page Setup dialog.
+  GtkPaperSize* paperSize = gtk_paper_size_new(gtkPaperName.get());
+  char* displayName = strdup(gtk_paper_size_get_display_name(paperSize));
+  gtk_paper_size_free(paperSize);
+
+  paperSize = gtk_paper_size_new_custom(gtkPaperName.get(), displayName,
+                                        gtk_paper_size_get_width(mPaperSize, GTK_UNIT_INCH),
+                                        gtk_paper_size_get_height(mPaperSize, GTK_UNIT_INCH),
+                                        GTK_UNIT_INCH);
+
+  free(displayName);
+  gtk_paper_size_free(mPaperSize);
+  mPaperSize = paperSize;
+  SaveNewPageSize();
+  return NS_OK;
+}
+
+GtkUnit
+nsPrintSettingsGTK::GetGTKUnit(PRInt16 aGeckoUnit)
+{
+  if (aGeckoUnit == kPaperSizeMillimeters)
+    return GTK_UNIT_MM;
+  else
+    return GTK_UNIT_INCH;
+}
+
+void
+nsPrintSettingsGTK::SaveNewPageSize()
+{
+  gtk_print_settings_set_paper_size(mPrintSettings, mPaperSize);
+  gtk_page_setup_set_paper_size(mPageSetup, mPaperSize);
+}
+
+/* attribute double paperWidth; */
+NS_IMETHODIMP
+nsPrintSettingsGTK::GetPaperWidth(double *aPaperWidth)
+{
+  NS_ENSURE_ARG_POINTER(aPaperWidth);
+  *aPaperWidth = gtk_paper_size_get_width(mPaperSize, GetGTKUnit(mPaperSizeUnit));
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsPrintSettingsGTK::SetPaperWidth(double aPaperWidth)
+{
+  gtk_paper_size_set_size(mPaperSize,
+                          aPaperWidth,
+                          gtk_paper_size_get_height(mPaperSize, GetGTKUnit(mPaperSizeUnit)),
+                          GetGTKUnit(mPaperSizeUnit));
+  SaveNewPageSize();
+  return NS_OK;
+}
+
+/* attribute double paperHeight; */
+NS_IMETHODIMP
+nsPrintSettingsGTK::GetPaperHeight(double *aPaperHeight)
+{
+  NS_ENSURE_ARG_POINTER(aPaperHeight);
+  *aPaperHeight = gtk_paper_size_get_height(mPaperSize, GetGTKUnit(mPaperSizeUnit));
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsPrintSettingsGTK::SetPaperHeight(double aPaperHeight)
+{
+  gtk_paper_size_set_size(mPaperSize,
+                          gtk_paper_size_get_width(mPaperSize, GetGTKUnit(mPaperSizeUnit)),
+                          aPaperHeight,
+                          GetGTKUnit(mPaperSizeUnit));
+  SaveNewPageSize();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPrintSettingsGTK::SetPaperSizeUnit(PRInt16 aPaperSizeUnit)
+{
+  // Convert units internally. e.g. they might have set the values while we're still in mm but
+  // they change to inch just afterwards, expecting that their sizes are in inches.
+  gtk_paper_size_set_size(mPaperSize,
+                          gtk_paper_size_get_width(mPaperSize, GetGTKUnit(mPaperSizeUnit)),
+                          gtk_paper_size_get_height(mPaperSize, GetGTKUnit(mPaperSizeUnit)),
+                          GetGTKUnit(aPaperSizeUnit));
+  SaveNewPageSize();
+
+  mPaperSizeUnit = aPaperSizeUnit;
+  return NS_OK;
+}
+
+// Get/Set our margins as an nsMargin
+NS_IMETHODIMP
+nsPrintSettingsGTK::SetEdgeInTwips(nsMargin& aEdge)
+{
+  gtk_page_setup_set_top_margin(mPageSetup, NS_TWIPS_TO_INCHES(aEdge.top), GTK_UNIT_INCH);
+  gtk_page_setup_set_left_margin(mPageSetup, NS_TWIPS_TO_INCHES(aEdge.left), GTK_UNIT_INCH);
+  gtk_page_setup_set_bottom_margin(mPageSetup, NS_TWIPS_TO_INCHES(aEdge.bottom), GTK_UNIT_INCH);
+  gtk_page_setup_set_right_margin(mPageSetup, NS_TWIPS_TO_INCHES(aEdge.right), GTK_UNIT_INCH);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPrintSettingsGTK::GetEdgeInTwips(nsMargin& aEdge)
+{
+  aEdge.SizeTo(NS_INCHES_TO_TWIPS(gtk_page_setup_get_left_margin(mPageSetup, GTK_UNIT_INCH)),
+               NS_INCHES_TO_TWIPS(gtk_page_setup_get_top_margin(mPageSetup, GTK_UNIT_INCH)),
+               NS_INCHES_TO_TWIPS(gtk_page_setup_get_right_margin(mPageSetup, GTK_UNIT_INCH)),
+               NS_INCHES_TO_TWIPS(gtk_page_setup_get_bottom_margin(mPageSetup, GTK_UNIT_INCH)));
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPrintSettingsGTK::GetEffectivePageSize(double *aWidth, double *aHeight)
+{
+  *aWidth  = NS_INCHES_TO_TWIPS(gtk_paper_size_get_width(mPaperSize, GTK_UNIT_INCH));
+  *aHeight = NS_INCHES_TO_TWIPS(gtk_paper_size_get_height(mPaperSize, GTK_UNIT_INCH));
+
+  GtkPageOrientation gtkOrient = gtk_page_setup_get_orientation(mPageSetup);
+
+  if (gtkOrient == GTK_PAGE_ORIENTATION_LANDSCAPE ||
+      gtkOrient == GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE) {
+    double temp = *aWidth;
+    *aWidth = *aHeight;
+    *aHeight = temp;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPrintSettingsGTK::SetupSilentPrinting()
+{
+  // We have to get a printer here, rather than when the print settings are constructed.
+  // This is because when we request sync, GTK makes us wait in the *event loop* while waiting
+  // for the enumeration to finish. We must do this when event loop runs are expected.
+  gtk_enumerate_printers(printer_enumerator, this, NULL, TRUE);
+
+  // XXX If no default printer set, get the first one.
+  if (!GTK_IS_PRINTER(mGTKPrinter))
+    gtk_enumerate_printers(ref_printer, this, NULL, TRUE);
+
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/widget/src/gtk2/nsPrintSettingsGTK.h
@@ -0,0 +1,177 @@
+/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Mozilla browser.
+ *
+ * The Initial Developer of the Original Code is Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Michael Ventnor <m.ventnor@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsPrintSettingsGTK_h_
+#define nsPrintSettingsGTK_h_
+
+#include "nsPrintSettingsImpl.h"
+
+extern "C" {
+#include <gtk/gtk.h>
+#include <gtk/gtkprinter.h>
+#include <gtk/gtkprintjob.h>
+}
+
+#define NS_PRINTSETTINGSGTK_IID \
+{ 0x758df520, 0xc7c3, 0x11dc, { 0x95, 0xff, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 } }
+ 
+
+//*****************************************************************************
+//***    nsPrintSettingsGTK
+//*****************************************************************************
+
+class nsPrintSettingsGTK : public nsPrintSettings
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECLARE_STATIC_IID_ACCESSOR(NS_PRINTSETTINGSGTK_IID)
+
+  nsPrintSettingsGTK();
+  virtual ~nsPrintSettingsGTK();
+
+  // We're overriding these methods because we want to read/write with GTK objects,
+  // not local variables. This allows a simpler settings implementation between
+  // Gecko and GTK.
+
+  GtkPageSetup* GetGtkPageSetup() { return mPageSetup; };
+  void SetGtkPageSetup(GtkPageSetup *aPageSetup);
+
+  GtkPrintSettings* GetGtkPrintSettings() { return mPrintSettings; };
+  void SetGtkPrintSettings(GtkPrintSettings *aPrintSettings);
+
+  GtkPrinter* GetGtkPrinter() { return mGTKPrinter; };
+  void SetGtkPrinter(GtkPrinter *aPrinter);
+
+  PRBool GetForcePrintSelectionOnly() { return mPrintSelectionOnly; };
+  void SetForcePrintSelectionOnly(PRBool aPrintSelectionOnly) { mPrintSelectionOnly = aPrintSelectionOnly; };
+
+  // If not printing the selection, this is stored in the GtkPrintSettings. Printing the
+  // selection is stored as a protected boolean (mPrintSelectionOnly).
+  NS_IMETHOD GetPrintRange(PRInt16 *aPrintRange);
+  NS_IMETHOD SetPrintRange(PRInt16 aPrintRange);
+
+  // The page range is stored as as single range in the GtkPrintSettings object.
+  NS_IMETHOD GetStartPageRange(PRInt32 *aStartPageRange);
+  NS_IMETHOD SetStartPageRange(PRInt32 aStartPageRange);
+  NS_IMETHOD GetEndPageRange(PRInt32 *aEndPageRange);
+  NS_IMETHOD SetEndPageRange(PRInt32 aEndPageRange);
+
+  // Reversed, color, orientation and file name are all stored in the GtkPrintSettings.
+  // Orientation is also stored in the GtkPageSetup and its setting takes priority when getting the orientation.
+  NS_IMETHOD GetPrintReversed(PRBool *aPrintReversed);
+  NS_IMETHOD SetPrintReversed(PRBool aPrintReversed);
+
+  NS_IMETHOD GetPrintInColor(PRBool *aPrintInColor);
+  NS_IMETHOD SetPrintInColor(PRBool aPrintInColor);
+
+  NS_IMETHOD GetOrientation(PRInt32 *aOrientation);
+  NS_IMETHOD SetOrientation(PRInt32 aOrientation);
+
+  NS_IMETHOD GetToFileName(PRUnichar * *aToFileName);
+  NS_IMETHOD SetToFileName(const PRUnichar * aToFileName);
+
+  // Gets/Sets the printer name in the GtkPrintSettings. If no printer name is specified there,
+  // you will get back the name of the current internal GtkPrinter.
+  NS_IMETHOD GetPrinterName(PRUnichar * *aPrinter);
+  NS_IMETHOD SetPrinterName(const PRUnichar * aPrinter);
+
+  // Number of copies is stored/gotten from the GtkPrintSettings.
+  NS_IMETHOD GetNumCopies(PRInt32 *aNumCopies);
+  NS_IMETHOD SetNumCopies(PRInt32 aNumCopies);
+
+  NS_IMETHOD GetEdgeTop(double *aEdgeTop);
+  NS_IMETHOD SetEdgeTop(double aEdgeTop);
+
+  NS_IMETHOD GetEdgeLeft(double *aEdgeLeft);
+  NS_IMETHOD SetEdgeLeft(double aEdgeLeft);
+
+  NS_IMETHOD GetEdgeBottom(double *aEdgeBottom);
+  NS_IMETHOD SetEdgeBottom(double aEdgeBottom);
+
+  NS_IMETHOD GetEdgeRight(double *aEdgeRight);
+  NS_IMETHOD SetEdgeRight(double aEdgeRight);
+
+  NS_IMETHOD GetScaling(double *aScaling);
+  NS_IMETHOD SetScaling(double aScaling);
+
+  // A name recognised by GTK is strongly advised here, as this is used to create a GtkPaperSize.
+  NS_IMETHOD GetPaperName(PRUnichar * *aPaperName);
+  NS_IMETHOD SetPaperName(const PRUnichar * aPaperName);
+
+  NS_IMETHOD GetPaperWidth(double *aPaperWidth);
+  NS_IMETHOD SetPaperWidth(double aPaperWidth);
+
+  NS_IMETHOD GetPaperHeight(double *aPaperHeight);
+  NS_IMETHOD SetPaperHeight(double aPaperHeight);
+
+  NS_IMETHOD SetPaperSizeUnit(PRInt16 aPaperSizeUnit);
+
+  NS_IMETHOD SetEdgeInTwips(nsMargin& aEdge);
+  NS_IMETHOD GetEdgeInTwips(nsMargin& aEdge);
+
+  NS_IMETHOD GetEffectivePageSize(double *aWidth, double *aHeight);
+
+  NS_IMETHOD SetupSilentPrinting();
+
+protected:
+  nsPrintSettingsGTK(const nsPrintSettingsGTK& src);
+  nsPrintSettingsGTK& operator=(const nsPrintSettingsGTK& rhs);
+
+  virtual nsresult _Clone(nsIPrintSettings **_retval);
+  virtual nsresult _Assign(nsIPrintSettings *aPS);
+
+  GtkUnit GetGTKUnit(PRInt16 aGeckoUnit);
+  void SaveNewPageSize();
+
+  /**
+   * On construction:
+   * - mPrintSettings, mPageSetup and mPaperSize are just new objects with defaults determined by GTK.
+   * - mGTKPrinter is NULL!!! Remember to be careful when accessing this property.
+   */
+  GtkPageSetup* mPageSetup;
+  GtkPrintSettings* mPrintSettings;
+  GtkPrinter* mGTKPrinter;
+  GtkPaperSize* mPaperSize;
+
+  PRBool mPrintSelectionOnly;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsPrintSettingsGTK, NS_PRINTSETTINGSGTK_IID)
+
+
+#endif // nsPrintSettingsGTK_h_
--- a/widget/src/gtk2/nsWidgetFactory.cpp
+++ b/widget/src/gtk2/nsWidgetFactory.cpp
@@ -55,16 +55,17 @@
 #include "nsScreenManagerGtk.h"
 #include "nsPrintOptionsGTK.h"
 #include "nsPrintSession.h"
 #include "nsDeviceContextSpecG.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsImageToPixbuf.h"
 #include "nsIdleServiceGTK.h"
+#include "nsPrintDialogGTK.h"
 
 #ifdef NATIVE_THEME_SUPPORT
 #include "nsNativeThemeGTK.h"
 #endif
 
 #include "nsIComponentRegistrar.h"
 #include "nsComponentManagerUtils.h"
 #include "nsAutoPtr.h"
@@ -92,16 +93,17 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsDeviceC
 #ifdef NATIVE_THEME_SUPPORT
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsNativeThemeGTK)
 #endif
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPrintOptionsGTK, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsPrinterEnumeratorGTK)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPrintSession, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsImageToPixbuf)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsIdleServiceGTK)
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPrintDialogServiceGTK, Init)
 
 static NS_IMETHODIMP
 nsFilePickerConstructor(nsISupports *aOuter, REFNSIID aIID,
                         void **aResult)
 {
   *aResult = nsnull;
   if (aOuter != nsnull) {
     return NS_ERROR_NO_AGGREGATION;
@@ -269,16 +271,20 @@ static const nsModuleComponentInfo compo
   { "Image to gdk-pixbuf converter",
     NS_IMAGE_TO_PIXBUF_CID,
     "@mozilla.org/widget/image-to-gdk-pixbuf;1",
     nsImageToPixbufConstructor },
   { "User Idle Service",
     NS_IDLE_SERVICE_CID,
     "@mozilla.org/widget/idleservice;1",
     nsIdleServiceGTKConstructor },
+  { "Native Print Dialog",
+    NS_PRINTDIALOGSERVICE_CID,
+    NS_PRINTDIALOGSERVICE_CONTRACTID,
+    nsPrintDialogServiceGTKConstructor },
 };
 
 PR_STATIC_CALLBACK(void)
 nsWidgetGtk2ModuleDtor(nsIModule *aSelf)
 {
   nsFilePicker::Shutdown();
   nsSound::Shutdown();
   nsWindow::ReleaseGlobals();
--- a/widget/src/xpwidgets/nsPrintSettingsImpl.cpp
+++ b/widget/src/xpwidgets/nsPrintSettingsImpl.cpp
@@ -967,16 +967,25 @@ nsPrintSettings::GetMarginInTwips(nsMarg
 NS_IMETHODIMP 
 nsPrintSettings::GetEdgeInTwips(nsMargin& aEdge)
 {
   aEdge = mEdge;
   return NS_OK;
 }
 
 /** ---------------------------------------------------
+ * Stub - platform-specific implementations can use this function.
+ */
+NS_IMETHODIMP
+nsPrintSettings::SetupSilentPrinting()
+{
+  return NS_OK;
+}
+
+/** ---------------------------------------------------
  *  See documentation in nsPrintOptionsImpl.h
  */
 NS_IMETHODIMP 
 nsPrintSettings::GetEffectivePageSize(double *aWidth, double *aHeight)
 {
   if (mPaperSizeUnit == kPaperSizeInches) {
     *aWidth  = NS_INCHES_TO_TWIPS(float(mPaperWidth));
     *aHeight = NS_INCHES_TO_TWIPS(float(mPaperHeight));