michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* ------------------------------------------------------------------- michael@0: To Build This: michael@0: michael@0: You need to add this to the the makefile.win in mozilla/content/base/src: michael@0: michael@0: .\$(OBJDIR)\nsFlyOwnPrintDialog.obj \ michael@0: michael@0: michael@0: And this to the makefile.win in mozilla/content/build: michael@0: michael@0: WIN_LIBS= \ michael@0: winspool.lib \ michael@0: comctl32.lib \ michael@0: comdlg32.lib michael@0: michael@0: ---------------------------------------------------------------------- */ michael@0: michael@0: #define NOMINMAX 1 michael@0: michael@0: #include "plstr.h" michael@0: #include michael@0: #include michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "nsIWebBrowserPrint.h" michael@0: #include "nsString.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsReadableUtils.h" michael@0: #include "nsIPrintSettings.h" michael@0: #include "nsIPrintSettingsWin.h" michael@0: #include "nsIPrintOptions.h" michael@0: michael@0: #include "nsRect.h" michael@0: michael@0: #include "nsIPrefService.h" michael@0: #include "nsIPrefBranch.h" michael@0: michael@0: #include "nsCRT.h" michael@0: #include "prenv.h" /* for PR_GetEnv */ michael@0: michael@0: #include michael@0: #include michael@0: michael@0: // For Localization michael@0: #include "nsIStringBundle.h" michael@0: michael@0: // For NS_CopyUnicodeToNative michael@0: #include "nsNativeCharsetUtils.h" michael@0: michael@0: // This is for extending the dialog michael@0: #include michael@0: michael@0: // Default labels for the radio buttons michael@0: static const char* kAsLaidOutOnScreenStr = "As &laid out on the screen"; michael@0: static const char* kTheSelectedFrameStr = "The selected &frame"; michael@0: static const char* kEachFrameSeparately = "&Each frame separately"; michael@0: michael@0: michael@0: //----------------------------------------------- michael@0: // Global Data michael@0: //----------------------------------------------- michael@0: // Identifies which new radio btn was cliked on michael@0: static UINT gFrameSelectedRadioBtn = 0; michael@0: michael@0: // Indicates whether the native print dialog was successfully extended michael@0: static bool gDialogWasExtended = false; michael@0: michael@0: #define PRINTDLG_PROPERTIES "chrome://global/locale/printdialog.properties" michael@0: michael@0: static HWND gParentWnd = nullptr; michael@0: michael@0: //****************************************************** michael@0: // Define native paper sizes michael@0: //****************************************************** michael@0: typedef struct { michael@0: short mPaperSize; // native enum michael@0: double mWidth; michael@0: double mHeight; michael@0: bool mIsInches; michael@0: } NativePaperSizes; michael@0: michael@0: // There are around 40 default print sizes defined by Windows michael@0: const NativePaperSizes kPaperSizes[] = { michael@0: {DMPAPER_LETTER, 8.5, 11.0, true}, michael@0: {DMPAPER_LEGAL, 8.5, 14.0, true}, michael@0: {DMPAPER_A4, 210.0, 297.0, false}, michael@0: {DMPAPER_TABLOID, 11.0, 17.0, true}, michael@0: {DMPAPER_LEDGER, 17.0, 11.0, true}, michael@0: {DMPAPER_STATEMENT, 5.5, 8.5, true}, michael@0: {DMPAPER_EXECUTIVE, 7.25, 10.5, true}, michael@0: {DMPAPER_A3, 297.0, 420.0, false}, michael@0: {DMPAPER_A5, 148.0, 210.0, false}, michael@0: {DMPAPER_CSHEET, 17.0, 22.0, true}, michael@0: {DMPAPER_DSHEET, 22.0, 34.0, true}, michael@0: {DMPAPER_ESHEET, 34.0, 44.0, true}, michael@0: {DMPAPER_LETTERSMALL, 8.5, 11.0, true}, michael@0: {DMPAPER_A4SMALL, 210.0, 297.0, false}, michael@0: {DMPAPER_B4, 250.0, 354.0, false}, michael@0: {DMPAPER_B5, 182.0, 257.0, false}, michael@0: {DMPAPER_FOLIO, 8.5, 13.0, true}, michael@0: {DMPAPER_QUARTO, 215.0, 275.0, false}, michael@0: {DMPAPER_10X14, 10.0, 14.0, true}, michael@0: {DMPAPER_11X17, 11.0, 17.0, true}, michael@0: {DMPAPER_NOTE, 8.5, 11.0, true}, michael@0: {DMPAPER_ENV_9, 3.875, 8.875, true}, michael@0: {DMPAPER_ENV_10, 40.125, 9.5, true}, michael@0: {DMPAPER_ENV_11, 4.5, 10.375, true}, michael@0: {DMPAPER_ENV_12, 4.75, 11.0, true}, michael@0: {DMPAPER_ENV_14, 5.0, 11.5, true}, michael@0: {DMPAPER_ENV_DL, 110.0, 220.0, false}, michael@0: {DMPAPER_ENV_C5, 162.0, 229.0, false}, michael@0: {DMPAPER_ENV_C3, 324.0, 458.0, false}, michael@0: {DMPAPER_ENV_C4, 229.0, 324.0, false}, michael@0: {DMPAPER_ENV_C6, 114.0, 162.0, false}, michael@0: {DMPAPER_ENV_C65, 114.0, 229.0, false}, michael@0: {DMPAPER_ENV_B4, 250.0, 353.0, false}, michael@0: {DMPAPER_ENV_B5, 176.0, 250.0, false}, michael@0: {DMPAPER_ENV_B6, 176.0, 125.0, false}, michael@0: {DMPAPER_ENV_ITALY, 110.0, 230.0, false}, michael@0: {DMPAPER_ENV_MONARCH, 3.875, 7.5, true}, michael@0: {DMPAPER_ENV_PERSONAL, 3.625, 6.5, true}, michael@0: {DMPAPER_FANFOLD_US, 14.875, 11.0, true}, michael@0: {DMPAPER_FANFOLD_STD_GERMAN, 8.5, 12.0, true}, michael@0: {DMPAPER_FANFOLD_LGL_GERMAN, 8.5, 13.0, true}, michael@0: }; michael@0: const int32_t kNumPaperSizes = 41; michael@0: michael@0: //---------------------------------------------------------------------------------- michael@0: // Map an incoming size to a Windows Native enum in the DevMode michael@0: static void michael@0: MapPaperSizeToNativeEnum(LPDEVMODEW aDevMode, michael@0: int16_t aType, michael@0: double aW, michael@0: double aH) michael@0: { michael@0: michael@0: #ifdef DEBUG_rods michael@0: BOOL doingOrientation = aDevMode->dmFields & DM_ORIENTATION; michael@0: BOOL doingPaperSize = aDevMode->dmFields & DM_PAPERSIZE; michael@0: BOOL doingPaperLength = aDevMode->dmFields & DM_PAPERLENGTH; michael@0: BOOL doingPaperWidth = aDevMode->dmFields & DM_PAPERWIDTH; michael@0: #endif michael@0: michael@0: const double kThreshold = 0.05; michael@0: for (int32_t i=0;i width-kThreshold && michael@0: aH < height+kThreshold && aH > height-kThreshold) { michael@0: aDevMode->dmPaperSize = kPaperSizes[i].mPaperSize; michael@0: aDevMode->dmFields &= ~DM_PAPERLENGTH; michael@0: aDevMode->dmFields &= ~DM_PAPERWIDTH; michael@0: aDevMode->dmFields |= DM_PAPERSIZE; michael@0: return; michael@0: } michael@0: } michael@0: michael@0: short width = 0; michael@0: short height = 0; michael@0: if (aType == nsIPrintSettings::kPaperSizeInches) { michael@0: width = short(NS_TWIPS_TO_MILLIMETERS(NS_INCHES_TO_TWIPS(float(aW))) / 10); michael@0: height = short(NS_TWIPS_TO_MILLIMETERS(NS_INCHES_TO_TWIPS(float(aH))) / 10); michael@0: michael@0: } else if (aType == nsIPrintSettings::kPaperSizeMillimeters) { michael@0: width = short(aW / 10.0); michael@0: height = short(aH / 10.0); michael@0: } else { michael@0: return; // don't set anything michael@0: } michael@0: michael@0: // width and height is in michael@0: aDevMode->dmPaperSize = 0; michael@0: aDevMode->dmPaperWidth = width; michael@0: aDevMode->dmPaperLength = height; michael@0: michael@0: aDevMode->dmFields |= DM_PAPERSIZE; michael@0: aDevMode->dmFields |= DM_PAPERLENGTH; michael@0: aDevMode->dmFields |= DM_PAPERWIDTH; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------------------- michael@0: // Setup Paper Size & Orientation options into the DevMode michael@0: // michael@0: static void michael@0: SetupDevModeFromSettings(LPDEVMODEW aDevMode, nsIPrintSettings* aPrintSettings) michael@0: { michael@0: // Setup paper size michael@0: if (aPrintSettings) { michael@0: int16_t type; michael@0: aPrintSettings->GetPaperSizeType(&type); michael@0: if (type == nsIPrintSettings::kPaperSizeNativeData) { michael@0: int16_t paperEnum; michael@0: aPrintSettings->GetPaperData(&paperEnum); michael@0: aDevMode->dmPaperSize = paperEnum; michael@0: aDevMode->dmFields &= ~DM_PAPERLENGTH; michael@0: aDevMode->dmFields &= ~DM_PAPERWIDTH; michael@0: aDevMode->dmFields |= DM_PAPERSIZE; michael@0: } else { michael@0: int16_t unit; michael@0: double width, height; michael@0: aPrintSettings->GetPaperSizeUnit(&unit); michael@0: aPrintSettings->GetPaperWidth(&width); michael@0: aPrintSettings->GetPaperHeight(&height); michael@0: MapPaperSizeToNativeEnum(aDevMode, unit, width, height); michael@0: } michael@0: michael@0: // Setup Orientation michael@0: int32_t orientation; michael@0: aPrintSettings->GetOrientation(&orientation); michael@0: aDevMode->dmOrientation = orientation == nsIPrintSettings::kPortraitOrientation?DMORIENT_PORTRAIT:DMORIENT_LANDSCAPE; michael@0: aDevMode->dmFields |= DM_ORIENTATION; michael@0: michael@0: // Setup Number of Copies michael@0: int32_t copies; michael@0: aPrintSettings->GetNumCopies(&copies); michael@0: aDevMode->dmCopies = copies; michael@0: aDevMode->dmFields |= DM_COPIES; michael@0: michael@0: } michael@0: michael@0: } michael@0: michael@0: //---------------------------------------------------------------------------------- michael@0: // Helper Function - Free and reallocate the string michael@0: static nsresult michael@0: SetPrintSettingsFromDevMode(nsIPrintSettings* aPrintSettings, michael@0: LPDEVMODEW aDevMode) michael@0: { michael@0: if (aPrintSettings == nullptr) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: aPrintSettings->SetIsInitializedFromPrinter(true); michael@0: if (aDevMode->dmFields & DM_ORIENTATION) { michael@0: int32_t orientation = aDevMode->dmOrientation == DMORIENT_PORTRAIT? michael@0: nsIPrintSettings::kPortraitOrientation:nsIPrintSettings::kLandscapeOrientation; michael@0: aPrintSettings->SetOrientation(orientation); michael@0: } michael@0: michael@0: // Setup Number of Copies michael@0: if (aDevMode->dmFields & DM_COPIES) { michael@0: aPrintSettings->SetNumCopies(int32_t(aDevMode->dmCopies)); michael@0: } michael@0: michael@0: // Scaling michael@0: // Since we do the scaling, grab their value and reset back to 100 michael@0: if (aDevMode->dmFields & DM_SCALE) { michael@0: double origScale = 1.0; michael@0: aPrintSettings->GetScaling(&origScale); michael@0: double scale = double(aDevMode->dmScale) / 100.0f; michael@0: if (origScale == 1.0 || scale != 1.0) { michael@0: aPrintSettings->SetScaling(scale); michael@0: } michael@0: aDevMode->dmScale = 100; michael@0: // To turn this on you must change where the mPrt->mShrinkToFit is being set in the DocumentViewer michael@0: //aPrintSettings->SetShrinkToFit(false); michael@0: } michael@0: michael@0: if (aDevMode->dmFields & DM_PAPERSIZE) { michael@0: aPrintSettings->SetPaperSizeType(nsIPrintSettings::kPaperSizeNativeData); michael@0: aPrintSettings->SetPaperData(aDevMode->dmPaperSize); michael@0: for (int32_t i=0;idmPaperSize) { michael@0: aPrintSettings->SetPaperSizeUnit(kPaperSizes[i].mIsInches?nsIPrintSettings::kPaperSizeInches:nsIPrintSettings::kPaperSizeMillimeters); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: } else if (aDevMode->dmFields & DM_PAPERLENGTH && aDevMode->dmFields & DM_PAPERWIDTH) { michael@0: bool found = false; michael@0: for (int32_t i=0;idmPaperSize) { michael@0: aPrintSettings->SetPaperSizeType(nsIPrintSettings::kPaperSizeDefined); michael@0: aPrintSettings->SetPaperWidth(kPaperSizes[i].mWidth); michael@0: aPrintSettings->SetPaperHeight(kPaperSizes[i].mHeight); michael@0: aPrintSettings->SetPaperSizeUnit(kPaperSizes[i].mIsInches?nsIPrintSettings::kPaperSizeInches:nsIPrintSettings::kPaperSizeMillimeters); michael@0: found = true; michael@0: break; michael@0: } michael@0: } michael@0: if (!found) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } else { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------------------- michael@0: // Return localized bundle for resource strings michael@0: static nsresult michael@0: GetLocalizedBundle(const char * aPropFileName, nsIStringBundle** aStrBundle) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aPropFileName); michael@0: NS_ENSURE_ARG_POINTER(aStrBundle); michael@0: michael@0: nsresult rv; michael@0: nsCOMPtr bundle; michael@0: michael@0: michael@0: // Create bundle michael@0: nsCOMPtr stringService = michael@0: do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv); michael@0: if (NS_SUCCEEDED(rv) && stringService) { michael@0: rv = stringService->CreateBundle(aPropFileName, aStrBundle); michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: //-------------------------------------------------------- michael@0: // Return localized string michael@0: static nsresult michael@0: GetLocalizedString(nsIStringBundle* aStrBundle, const char* aKey, nsString& oVal) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aStrBundle); michael@0: NS_ENSURE_ARG_POINTER(aKey); michael@0: michael@0: // Determine default label from string bundle michael@0: nsXPIDLString valUni; michael@0: nsAutoString key; michael@0: key.AssignWithConversion(aKey); michael@0: nsresult rv = aStrBundle->GetStringFromName(key.get(), getter_Copies(valUni)); michael@0: if (NS_SUCCEEDED(rv) && valUni) { michael@0: oVal.Assign(valUni); michael@0: } else { michael@0: oVal.Truncate(); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: //-------------------------------------------------------- michael@0: // Set a multi-byte string in the control michael@0: static void SetTextOnWnd(HWND aControl, const nsString& aStr) michael@0: { michael@0: nsAutoCString text; michael@0: if (NS_SUCCEEDED(NS_CopyUnicodeToNative(aStr, text))) { michael@0: ::SetWindowText(aControl, text.get()); michael@0: } michael@0: } michael@0: michael@0: //-------------------------------------------------------- michael@0: // Will get the control and localized string by "key" michael@0: static void SetText(HWND aParent, michael@0: UINT aId, michael@0: nsIStringBundle* aStrBundle, michael@0: const char* aKey) michael@0: { michael@0: HWND wnd = GetDlgItem (aParent, aId); michael@0: if (!wnd) { michael@0: return; michael@0: } michael@0: nsAutoString str; michael@0: nsresult rv = GetLocalizedString(aStrBundle, aKey, str); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: SetTextOnWnd(wnd, str); michael@0: } michael@0: } michael@0: michael@0: //-------------------------------------------------------- michael@0: static void SetRadio(HWND aParent, michael@0: UINT aId, michael@0: bool aIsSet, michael@0: bool isEnabled = true) michael@0: { michael@0: HWND wnd = ::GetDlgItem (aParent, aId); michael@0: if (!wnd) { michael@0: return; michael@0: } michael@0: if (!isEnabled) { michael@0: ::EnableWindow(wnd, FALSE); michael@0: return; michael@0: } michael@0: ::EnableWindow(wnd, TRUE); michael@0: ::SendMessage(wnd, BM_SETCHECK, (WPARAM)aIsSet, (LPARAM)0); michael@0: } michael@0: michael@0: //-------------------------------------------------------- michael@0: static void SetRadioOfGroup(HWND aDlg, int aRadId) michael@0: { michael@0: int radioIds[] = {rad4, rad5, rad6}; michael@0: int numRads = 3; michael@0: michael@0: for (int i=0;i strBundle; michael@0: if (NS_SUCCEEDED(GetLocalizedBundle(PRINTDLG_PROPERTIES, getter_AddRefs(strBundle)))) { michael@0: int32_t i = 0; michael@0: while (gAllPropKeys[i].mKeyStr != nullptr) { michael@0: SetText(hdlg, gAllPropKeys[i].mKeyId, strBundle, gAllPropKeys[i].mKeyStr); michael@0: i++; michael@0: } michael@0: } michael@0: michael@0: // Set up radio buttons michael@0: if (aHowToEnableFrameUI == nsIPrintSettings::kFrameEnableAll) { michael@0: SetRadio(hdlg, rad4, false); michael@0: SetRadio(hdlg, rad5, true); michael@0: SetRadio(hdlg, rad6, false); michael@0: // set default so user doesn't have to actually press on it michael@0: gFrameSelectedRadioBtn = rad5; michael@0: michael@0: } else { // nsIPrintSettings::kFrameEnableAsIsAndEach michael@0: SetRadio(hdlg, rad4, false); michael@0: SetRadio(hdlg, rad5, false, false); michael@0: SetRadio(hdlg, rad6, true); michael@0: // set default so user doesn't have to actually press on it michael@0: gFrameSelectedRadioBtn = rad6; michael@0: } michael@0: } michael@0: michael@0: michael@0: //-------------------------------------------------------- michael@0: // Special Hook Procedure for handling the print dialog messages michael@0: static UINT CALLBACK PrintHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) michael@0: { michael@0: michael@0: if (uiMsg == WM_COMMAND) { michael@0: UINT id = LOWORD(wParam); michael@0: if (id == rad4 || id == rad5 || id == rad6) { michael@0: gFrameSelectedRadioBtn = id; michael@0: SetRadioOfGroup(hdlg, id); michael@0: } michael@0: michael@0: } else if (uiMsg == WM_INITDIALOG) { michael@0: PRINTDLG * printDlg = (PRINTDLG *)lParam; michael@0: if (printDlg == nullptr) return 0L; michael@0: michael@0: int16_t howToEnableFrameUI = (int16_t)printDlg->lCustData; michael@0: // don't add frame options if they would be disabled anyway michael@0: // because there are no frames michael@0: if (howToEnableFrameUI == nsIPrintSettings::kFrameEnableNone) michael@0: return TRUE; michael@0: michael@0: HINSTANCE hInst = (HINSTANCE)::GetWindowLongPtr(hdlg, GWLP_HINSTANCE); michael@0: if (hInst == nullptr) return 0L; michael@0: michael@0: // Start by getting the local rects of several of the controls michael@0: // so we can calculate where the new controls are michael@0: HWND wnd = ::GetDlgItem(hdlg, grp1); michael@0: if (wnd == nullptr) return 0L; michael@0: RECT dlgRect; michael@0: GetLocalRect(wnd, dlgRect, hdlg); michael@0: michael@0: wnd = ::GetDlgItem(hdlg, rad1); // this is the top control "All" michael@0: if (wnd == nullptr) return 0L; michael@0: RECT rad1Rect; michael@0: GetLocalRect(wnd, rad1Rect, hdlg); michael@0: michael@0: wnd = ::GetDlgItem(hdlg, rad2); // this is the bottom control "Selection" michael@0: if (wnd == nullptr) return 0L; michael@0: RECT rad2Rect; michael@0: GetLocalRect(wnd, rad2Rect, hdlg); michael@0: michael@0: wnd = ::GetDlgItem(hdlg, rad3); // this is the middle control "Pages" michael@0: if (wnd == nullptr) return 0L; michael@0: RECT rad3Rect; michael@0: GetLocalRect(wnd, rad3Rect, hdlg); michael@0: michael@0: HWND okWnd = ::GetDlgItem(hdlg, IDOK); michael@0: if (okWnd == nullptr) return 0L; michael@0: RECT okRect; michael@0: GetLocalRect(okWnd, okRect, hdlg); michael@0: michael@0: wnd = ::GetDlgItem(hdlg, grp4); // this is the "Print range" groupbox michael@0: if (wnd == nullptr) return 0L; michael@0: RECT prtRect; michael@0: GetLocalRect(wnd, prtRect, hdlg); michael@0: michael@0: michael@0: // calculate various different "gaps" for layout purposes michael@0: michael@0: int rbGap = rad3Rect.top - rad1Rect.bottom; // gap between radiobtns michael@0: int grpBotGap = dlgRect.bottom - rad2Rect.bottom; // gap from bottom rb to bottom of grpbox michael@0: int grpGap = dlgRect.top - prtRect.bottom ; // gap between group boxes michael@0: int top = dlgRect.bottom + grpGap; michael@0: int radHgt = rad1Rect.bottom - rad1Rect.top + 1; // top of new group box michael@0: int y = top+(rad1Rect.top-dlgRect.top); // starting pos of first radio michael@0: int rbWidth = dlgRect.right - rad1Rect.left - 5; // measure from rb left to the edge of the groupbox michael@0: // (5 is arbitrary) michael@0: nsIntRect rect; michael@0: michael@0: // Create and position the radio buttons michael@0: // michael@0: // If any one control cannot be created then michael@0: // hide the others and bail out michael@0: // michael@0: rect.SetRect(rad1Rect.left, y, rbWidth,radHgt); michael@0: HWND rad4Wnd = CreateRadioBtn(hInst, hdlg, rad4, kAsLaidOutOnScreenStr, rect); michael@0: if (rad4Wnd == nullptr) return 0L; michael@0: y += radHgt + rbGap; michael@0: michael@0: rect.SetRect(rad1Rect.left, y, rbWidth, radHgt); michael@0: HWND rad5Wnd = CreateRadioBtn(hInst, hdlg, rad5, kTheSelectedFrameStr, rect); michael@0: if (rad5Wnd == nullptr) { michael@0: Show(rad4Wnd, FALSE); // hide michael@0: return 0L; michael@0: } michael@0: y += radHgt + rbGap; michael@0: michael@0: rect.SetRect(rad1Rect.left, y, rbWidth, radHgt); michael@0: HWND rad6Wnd = CreateRadioBtn(hInst, hdlg, rad6, kEachFrameSeparately, rect); michael@0: if (rad6Wnd == nullptr) { michael@0: Show(rad4Wnd, FALSE); // hide michael@0: Show(rad5Wnd, FALSE); // hide michael@0: return 0L; michael@0: } michael@0: y += radHgt + grpBotGap; michael@0: michael@0: // Create and position the group box michael@0: rect.SetRect (dlgRect.left, top, dlgRect.right-dlgRect.left+1, y-top+1); michael@0: HWND grpBoxWnd = CreateGroupBox(hInst, hdlg, grp3, NS_LITERAL_STRING("Print Frame"), rect); michael@0: if (grpBoxWnd == nullptr) { michael@0: Show(rad4Wnd, FALSE); // hide michael@0: Show(rad5Wnd, FALSE); // hide michael@0: Show(rad6Wnd, FALSE); // hide michael@0: return 0L; michael@0: } michael@0: michael@0: // Here we figure out the old height of the dlg michael@0: // then figure its gap from the old grpbx to the bottom michael@0: // then size the dlg michael@0: RECT pr, cr; michael@0: ::GetWindowRect(hdlg, &pr); michael@0: ::GetClientRect(hdlg, &cr); michael@0: michael@0: int dlgHgt = (cr.bottom - cr.top) + 1; michael@0: int bottomGap = dlgHgt - okRect.bottom; michael@0: pr.bottom += (dlgRect.bottom-dlgRect.top) + grpGap + 1 - (dlgHgt-dlgRect.bottom) + bottomGap; michael@0: michael@0: ::SetWindowPos(hdlg, nullptr, pr.left, pr.top, pr.right-pr.left+1, pr.bottom-pr.top+1, michael@0: SWP_NOMOVE|SWP_NOREDRAW|SWP_NOZORDER); michael@0: michael@0: // figure out the new height of the dialog michael@0: ::GetClientRect(hdlg, &cr); michael@0: dlgHgt = (cr.bottom - cr.top) + 1; michael@0: michael@0: // Reposition the OK and Cancel btns michael@0: int okHgt = okRect.bottom - okRect.top + 1; michael@0: ::SetWindowPos(okWnd, nullptr, okRect.left, dlgHgt-bottomGap-okHgt, 0, 0, michael@0: SWP_NOSIZE|SWP_NOREDRAW|SWP_NOZORDER); michael@0: michael@0: HWND cancelWnd = ::GetDlgItem(hdlg, IDCANCEL); michael@0: if (cancelWnd == nullptr) return 0L; michael@0: michael@0: RECT cancelRect; michael@0: GetLocalRect(cancelWnd, cancelRect, hdlg); michael@0: int cancelHgt = cancelRect.bottom - cancelRect.top + 1; michael@0: ::SetWindowPos(cancelWnd, nullptr, cancelRect.left, dlgHgt-bottomGap-cancelHgt, 0, 0, michael@0: SWP_NOSIZE|SWP_NOREDRAW|SWP_NOZORDER); michael@0: michael@0: // localize and initialize the groupbox and radiobuttons michael@0: InitializeExtendedDialog(hdlg, howToEnableFrameUI); michael@0: michael@0: // Looks like we were able to extend the dialog michael@0: gDialogWasExtended = true; michael@0: return TRUE; michael@0: } michael@0: return 0L; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------------------- michael@0: // Returns a Global Moveable Memory Handle to a DevMode michael@0: // from the Printer by the name of aPrintName michael@0: // michael@0: // NOTE: michael@0: // This function assumes that aPrintName has already been converted from michael@0: // unicode michael@0: // michael@0: static HGLOBAL CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName, nsIPrintSettings* aPS) michael@0: { michael@0: HGLOBAL hGlobalDevMode = nullptr; michael@0: michael@0: HANDLE hPrinter = nullptr; michael@0: // const cast kludge for silly Win32 api's michael@0: LPWSTR printName = const_cast(static_cast(aPrintName.get())); michael@0: BOOL status = ::OpenPrinterW(printName, &hPrinter, nullptr); michael@0: if (status) { michael@0: michael@0: LPDEVMODEW pNewDevMode; michael@0: DWORD dwNeeded, dwRet; michael@0: michael@0: // Get the buffer size michael@0: dwNeeded = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, nullptr, nullptr, 0); michael@0: if (dwNeeded == 0) { michael@0: return nullptr; michael@0: } michael@0: michael@0: // Allocate a buffer of the correct size. michael@0: pNewDevMode = (LPDEVMODEW)::HeapAlloc (::GetProcessHeap(), HEAP_ZERO_MEMORY, dwNeeded); michael@0: if (!pNewDevMode) return nullptr; michael@0: michael@0: hGlobalDevMode = (HGLOBAL)::GlobalAlloc(GHND, dwNeeded); michael@0: if (!hGlobalDevMode) { michael@0: ::HeapFree(::GetProcessHeap(), 0, pNewDevMode); michael@0: return nullptr; michael@0: } michael@0: michael@0: dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, pNewDevMode, nullptr, DM_OUT_BUFFER); michael@0: michael@0: if (dwRet != IDOK) { michael@0: ::HeapFree(::GetProcessHeap(), 0, pNewDevMode); michael@0: ::GlobalFree(hGlobalDevMode); michael@0: ::ClosePrinter(hPrinter); michael@0: return nullptr; michael@0: } michael@0: michael@0: // Lock memory and copy contents from DEVMODE (current printer) michael@0: // to Global Memory DEVMODE michael@0: LPDEVMODEW devMode = (DEVMODEW *)::GlobalLock(hGlobalDevMode); michael@0: if (devMode) { michael@0: memcpy(devMode, pNewDevMode, dwNeeded); michael@0: // Initialize values from the PrintSettings michael@0: SetupDevModeFromSettings(devMode, aPS); michael@0: michael@0: // Sets back the changes we made to the DevMode into the Printer Driver michael@0: dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, devMode, devMode, DM_IN_BUFFER | DM_OUT_BUFFER); michael@0: if (dwRet != IDOK) { michael@0: ::GlobalUnlock(hGlobalDevMode); michael@0: ::GlobalFree(hGlobalDevMode); michael@0: ::HeapFree(::GetProcessHeap(), 0, pNewDevMode); michael@0: ::ClosePrinter(hPrinter); michael@0: return nullptr; michael@0: } michael@0: michael@0: ::GlobalUnlock(hGlobalDevMode); michael@0: } else { michael@0: ::GlobalFree(hGlobalDevMode); michael@0: hGlobalDevMode = nullptr; michael@0: } michael@0: michael@0: ::HeapFree(::GetProcessHeap(), 0, pNewDevMode); michael@0: michael@0: ::ClosePrinter(hPrinter); michael@0: michael@0: } else { michael@0: return nullptr; michael@0: } michael@0: michael@0: return hGlobalDevMode; michael@0: } michael@0: michael@0: //------------------------------------------------------------------ michael@0: // helper michael@0: static void GetDefaultPrinterNameFromGlobalPrinters(nsXPIDLString &printerName) michael@0: { michael@0: nsCOMPtr prtEnum = do_GetService("@mozilla.org/gfx/printerenumerator;1"); michael@0: if (prtEnum) { michael@0: prtEnum->GetDefaultPrinterName(getter_Copies(printerName)); michael@0: } michael@0: } michael@0: michael@0: // Determine whether we have a completely native dialog michael@0: // or whether we cshould extend it michael@0: static bool ShouldExtendPrintDialog() michael@0: { michael@0: nsresult rv; michael@0: nsCOMPtr prefs = michael@0: do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); michael@0: NS_ENSURE_SUCCESS(rv, true); michael@0: nsCOMPtr prefBranch; michael@0: rv = prefs->GetBranch(nullptr, getter_AddRefs(prefBranch)); michael@0: NS_ENSURE_SUCCESS(rv, true); michael@0: michael@0: bool result; michael@0: rv = prefBranch->GetBoolPref("print.extend_native_print_dialog", &result); michael@0: NS_ENSURE_SUCCESS(rv, true); michael@0: return result; michael@0: } michael@0: michael@0: //------------------------------------------------------------------ michael@0: // Displays the native Print Dialog michael@0: static nsresult michael@0: ShowNativePrintDialog(HWND aHWnd, michael@0: nsIPrintSettings* aPrintSettings) michael@0: { michael@0: //NS_ENSURE_ARG_POINTER(aHWnd); michael@0: NS_ENSURE_ARG_POINTER(aPrintSettings); michael@0: michael@0: gDialogWasExtended = false; michael@0: michael@0: HGLOBAL hGlobalDevMode = nullptr; michael@0: HGLOBAL hDevNames = nullptr; michael@0: michael@0: // Get the Print Name to be used michael@0: nsXPIDLString printerName; michael@0: aPrintSettings->GetPrinterName(getter_Copies(printerName)); michael@0: michael@0: // If there is no name then use the default printer michael@0: if (printerName.IsEmpty()) { michael@0: GetDefaultPrinterNameFromGlobalPrinters(printerName); michael@0: } else { michael@0: HANDLE hPrinter = nullptr; michael@0: if(!::OpenPrinterW(const_cast(static_cast(printerName.get())), &hPrinter, nullptr)) { michael@0: // If the last used printer is not found, we should use default printer. michael@0: GetDefaultPrinterNameFromGlobalPrinters(printerName); michael@0: } else { michael@0: ::ClosePrinter(hPrinter); michael@0: } michael@0: } michael@0: michael@0: // Now create a DEVNAMES struct so the the dialog is initialized correctly. michael@0: michael@0: uint32_t len = printerName.Length(); michael@0: hDevNames = (HGLOBAL)::GlobalAlloc(GHND, sizeof(wchar_t) * (len + 1) + michael@0: sizeof(DEVNAMES)); michael@0: if (!hDevNames) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: DEVNAMES* pDevNames = (DEVNAMES*)::GlobalLock(hDevNames); michael@0: if (!pDevNames) { michael@0: ::GlobalFree(hDevNames); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: pDevNames->wDriverOffset = sizeof(DEVNAMES)/sizeof(wchar_t); michael@0: pDevNames->wDeviceOffset = sizeof(DEVNAMES)/sizeof(wchar_t); michael@0: pDevNames->wOutputOffset = sizeof(DEVNAMES)/sizeof(wchar_t)+len; michael@0: pDevNames->wDefault = 0; michael@0: michael@0: memcpy(pDevNames+1, printerName, (len + 1) * sizeof(wchar_t)); michael@0: ::GlobalUnlock(hDevNames); michael@0: michael@0: // Create a Moveable Memory Object that holds a new DevMode michael@0: // from the Printer Name michael@0: // The PRINTDLG.hDevMode requires that it be a moveable memory object michael@0: // NOTE: We only need to free hGlobalDevMode when the dialog is cancelled michael@0: // When the user prints, it comes back in the printdlg struct and michael@0: // is used and cleaned up later michael@0: hGlobalDevMode = CreateGlobalDevModeAndInit(printerName, aPrintSettings); michael@0: michael@0: // Prepare to Display the Print Dialog michael@0: PRINTDLGW prntdlg; michael@0: memset(&prntdlg, 0, sizeof(PRINTDLGW)); michael@0: michael@0: prntdlg.lStructSize = sizeof(prntdlg); michael@0: prntdlg.hwndOwner = aHWnd; michael@0: prntdlg.hDevMode = hGlobalDevMode; michael@0: prntdlg.hDevNames = hDevNames; michael@0: prntdlg.hDC = nullptr; michael@0: prntdlg.Flags = PD_ALLPAGES | PD_RETURNIC | michael@0: PD_USEDEVMODECOPIESANDCOLLATE | PD_COLLATE; michael@0: michael@0: // if there is a current selection then enable the "Selection" radio button michael@0: int16_t howToEnableFrameUI = nsIPrintSettings::kFrameEnableNone; michael@0: bool isOn; michael@0: aPrintSettings->GetPrintOptions(nsIPrintSettings::kEnableSelectionRB, &isOn); michael@0: if (!isOn) { michael@0: prntdlg.Flags |= PD_NOSELECTION; michael@0: } michael@0: aPrintSettings->GetHowToEnableFrameUI(&howToEnableFrameUI); michael@0: michael@0: int32_t pg = 1; michael@0: aPrintSettings->GetStartPageRange(&pg); michael@0: prntdlg.nFromPage = pg; michael@0: michael@0: aPrintSettings->GetEndPageRange(&pg); michael@0: prntdlg.nToPage = pg; michael@0: michael@0: prntdlg.nMinPage = 1; michael@0: prntdlg.nMaxPage = 0xFFFF; michael@0: prntdlg.nCopies = 1; michael@0: prntdlg.lpfnSetupHook = nullptr; michael@0: prntdlg.lpSetupTemplateName = nullptr; michael@0: prntdlg.hPrintTemplate = nullptr; michael@0: prntdlg.hSetupTemplate = nullptr; michael@0: michael@0: prntdlg.hInstance = nullptr; michael@0: prntdlg.lpPrintTemplateName = nullptr; michael@0: michael@0: if (!ShouldExtendPrintDialog()) { michael@0: prntdlg.lCustData = 0; michael@0: prntdlg.lpfnPrintHook = nullptr; michael@0: } else { michael@0: // Set up print dialog "hook" procedure for extending the dialog michael@0: prntdlg.lCustData = (DWORD)howToEnableFrameUI; michael@0: prntdlg.lpfnPrintHook = (LPPRINTHOOKPROC)PrintHookProc; michael@0: prntdlg.Flags |= PD_ENABLEPRINTHOOK; michael@0: } michael@0: michael@0: BOOL result = ::PrintDlgW(&prntdlg); michael@0: michael@0: if (TRUE == result) { michael@0: // check to make sure we don't have any nullptr pointers michael@0: NS_ENSURE_TRUE(aPrintSettings && prntdlg.hDevMode, NS_ERROR_FAILURE); michael@0: michael@0: if (prntdlg.hDevNames == nullptr) { michael@0: ::GlobalFree(hGlobalDevMode); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: // Lock the deviceNames and check for nullptr michael@0: DEVNAMES *devnames = (DEVNAMES *)::GlobalLock(prntdlg.hDevNames); michael@0: if (devnames == nullptr) { michael@0: ::GlobalFree(hGlobalDevMode); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: char16_t* device = &(((char16_t *)devnames)[devnames->wDeviceOffset]); michael@0: char16_t* driver = &(((char16_t *)devnames)[devnames->wDriverOffset]); michael@0: michael@0: // Check to see if the "Print To File" control is checked michael@0: // then take the name from devNames and set it in the PrintSettings michael@0: // michael@0: // NOTE: michael@0: // As per Microsoft SDK documentation the returned value offset from michael@0: // devnames->wOutputOffset is either "FILE:" or nullptr michael@0: // if the "Print To File" checkbox is checked it MUST be "FILE:" michael@0: // We assert as an extra safety check. michael@0: if (prntdlg.Flags & PD_PRINTTOFILE) { michael@0: char16ptr_t fileName = &(((wchar_t *)devnames)[devnames->wOutputOffset]); michael@0: NS_ASSERTION(wcscmp(fileName, L"FILE:") == 0, "FileName must be `FILE:`"); michael@0: aPrintSettings->SetToFileName(fileName); michael@0: aPrintSettings->SetPrintToFile(true); michael@0: } else { michael@0: // clear "print to file" info michael@0: aPrintSettings->SetPrintToFile(false); michael@0: aPrintSettings->SetToFileName(nullptr); michael@0: } michael@0: michael@0: nsCOMPtr psWin(do_QueryInterface(aPrintSettings)); michael@0: if (!psWin) { michael@0: ::GlobalFree(hGlobalDevMode); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // Setup local Data members michael@0: psWin->SetDeviceName(device); michael@0: psWin->SetDriverName(driver); michael@0: michael@0: #if defined(DEBUG_rods) || defined(DEBUG_dcone) michael@0: wprintf(L"printer: driver %s, device %s flags: %d\n", driver, device, prntdlg.Flags); michael@0: #endif michael@0: // fill the print options with the info from the dialog michael@0: michael@0: aPrintSettings->SetPrinterName(device); michael@0: michael@0: if (prntdlg.Flags & PD_SELECTION) { michael@0: aPrintSettings->SetPrintRange(nsIPrintSettings::kRangeSelection); michael@0: michael@0: } else if (prntdlg.Flags & PD_PAGENUMS) { michael@0: aPrintSettings->SetPrintRange(nsIPrintSettings::kRangeSpecifiedPageRange); michael@0: aPrintSettings->SetStartPageRange(prntdlg.nFromPage); michael@0: aPrintSettings->SetEndPageRange(prntdlg.nToPage); michael@0: michael@0: } else { // (prntdlg.Flags & PD_ALLPAGES) michael@0: aPrintSettings->SetPrintRange(nsIPrintSettings::kRangeAllPages); michael@0: } michael@0: michael@0: if (howToEnableFrameUI != nsIPrintSettings::kFrameEnableNone) { michael@0: // make sure the dialog got extended michael@0: if (gDialogWasExtended) { michael@0: // check to see about the frame radio buttons michael@0: switch (gFrameSelectedRadioBtn) { michael@0: case rad4: michael@0: aPrintSettings->SetPrintFrameType(nsIPrintSettings::kFramesAsIs); michael@0: break; michael@0: case rad5: michael@0: aPrintSettings->SetPrintFrameType(nsIPrintSettings::kSelectedFrame); michael@0: break; michael@0: case rad6: michael@0: aPrintSettings->SetPrintFrameType(nsIPrintSettings::kEachFrameSep); michael@0: break; michael@0: } // switch michael@0: } else { michael@0: // if it didn't get extended then have it default to printing michael@0: // each frame separately michael@0: aPrintSettings->SetPrintFrameType(nsIPrintSettings::kEachFrameSep); michael@0: } michael@0: } else { michael@0: aPrintSettings->SetPrintFrameType(nsIPrintSettings::kNoFrames); michael@0: } michael@0: // Unlock DeviceNames michael@0: ::GlobalUnlock(prntdlg.hDevNames); michael@0: michael@0: // Transfer the settings from the native data to the PrintSettings michael@0: LPDEVMODEW devMode = (LPDEVMODEW)::GlobalLock(prntdlg.hDevMode); michael@0: if (devMode == nullptr) { michael@0: ::GlobalFree(hGlobalDevMode); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: psWin->SetDevMode(devMode); // copies DevMode michael@0: SetPrintSettingsFromDevMode(aPrintSettings, devMode); michael@0: ::GlobalUnlock(prntdlg.hDevMode); michael@0: michael@0: #if defined(DEBUG_rods) || defined(DEBUG_dcone) michael@0: bool printSelection = prntdlg.Flags & PD_SELECTION; michael@0: bool printAllPages = prntdlg.Flags & PD_ALLPAGES; michael@0: bool printNumPages = prntdlg.Flags & PD_PAGENUMS; michael@0: int32_t fromPageNum = 0; michael@0: int32_t toPageNum = 0; michael@0: michael@0: if (printNumPages) { michael@0: fromPageNum = prntdlg.nFromPage; michael@0: toPageNum = prntdlg.nToPage; michael@0: } michael@0: if (printSelection) { michael@0: printf("Printing the selection\n"); michael@0: michael@0: } else if (printAllPages) { michael@0: printf("Printing all the pages\n"); michael@0: michael@0: } else { michael@0: printf("Printing from page no. %d to %d\n", fromPageNum, toPageNum); michael@0: } michael@0: #endif michael@0: michael@0: } else { michael@0: ::SetFocus(aHWnd); michael@0: aPrintSettings->SetIsCancelled(true); michael@0: if (hGlobalDevMode) ::GlobalFree(hGlobalDevMode); michael@0: return NS_ERROR_ABORT; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: //------------------------------------------------------------------ michael@0: static void michael@0: PrepareForPrintDialog(nsIWebBrowserPrint* aWebBrowserPrint, nsIPrintSettings* aPS) michael@0: { michael@0: NS_ASSERTION(aWebBrowserPrint, "Can't be null"); michael@0: NS_ASSERTION(aPS, "Can't be null"); michael@0: michael@0: bool isFramesetDocument; michael@0: bool isFramesetFrameSelected; michael@0: bool isIFrameSelected; michael@0: bool isRangeSelection; michael@0: michael@0: aWebBrowserPrint->GetIsFramesetDocument(&isFramesetDocument); michael@0: aWebBrowserPrint->GetIsFramesetFrameSelected(&isFramesetFrameSelected); michael@0: aWebBrowserPrint->GetIsIFrameSelected(&isIFrameSelected); michael@0: aWebBrowserPrint->GetIsRangeSelection(&isRangeSelection); michael@0: michael@0: // Setup print options for UI michael@0: if (isFramesetDocument) { michael@0: if (isFramesetFrameSelected) { michael@0: aPS->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAll); michael@0: } else { michael@0: aPS->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAsIsAndEach); michael@0: } michael@0: } else { michael@0: aPS->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableNone); michael@0: } michael@0: michael@0: // Now determine how to set up the Frame print UI michael@0: aPS->SetPrintOptions(nsIPrintSettings::kEnableSelectionRB, isRangeSelection || isIFrameSelected); michael@0: michael@0: } michael@0: michael@0: //---------------------------------------------------------------------------------- michael@0: //-- Show Print Dialog michael@0: //---------------------------------------------------------------------------------- michael@0: nsresult NativeShowPrintDialog(HWND aHWnd, michael@0: nsIWebBrowserPrint* aWebBrowserPrint, michael@0: nsIPrintSettings* aPrintSettings) michael@0: { michael@0: PrepareForPrintDialog(aWebBrowserPrint, aPrintSettings); michael@0: michael@0: nsresult rv = ShowNativePrintDialog(aHWnd, aPrintSettings); michael@0: if (aHWnd) { michael@0: ::DestroyWindow(aHWnd); michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: