diff options
Diffstat (limited to 'embedding/components/printingui/win')
9 files changed, 1693 insertions, 0 deletions
diff --git a/embedding/components/printingui/win/moz.build b/embedding/components/printingui/win/moz.build new file mode 100644 index 000000000..fe7b11b2d --- /dev/null +++ b/embedding/components/printingui/win/moz.build @@ -0,0 +1,18 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +UNIFIED_SOURCES += [ + 'nsPrintDialogUtil.cpp', + 'nsPrintingPromptService.cpp', + 'nsPrintProgress.cpp', + 'nsPrintProgressParams.cpp', +] + +EXPORTS += [ + 'nsPrintDialogUtil.h', +] + +FINAL_LIBRARY = 'xul' diff --git a/embedding/components/printingui/win/nsPrintDialogUtil.cpp b/embedding/components/printingui/win/nsPrintDialogUtil.cpp new file mode 100644 index 000000000..896c58e85 --- /dev/null +++ b/embedding/components/printingui/win/nsPrintDialogUtil.cpp @@ -0,0 +1,854 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* ------------------------------------------------------------------- +To Build This: + + You need to add this to the the makefile.win in mozilla/dom/base: + + .\$(OBJDIR)\nsFlyOwnPrintDialog.obj \ + + + And this to the makefile.win in mozilla/content/build: + +WIN_LIBS= \ + winspool.lib \ + comctl32.lib \ + comdlg32.lib + +---------------------------------------------------------------------- */ + +#include "plstr.h" +#include <windows.h> +#include <tchar.h> + +#include <unknwn.h> +#include <commdlg.h> + +#include "nsIWebBrowserPrint.h" +#include "nsString.h" +#include "nsIServiceManager.h" +#include "nsReadableUtils.h" +#include "nsIPrintSettings.h" +#include "nsIPrintSettingsWin.h" +#include "nsIPrinterEnumerator.h" + +#include "nsRect.h" + +#include "nsIPrefService.h" +#include "nsIPrefBranch.h" + +#include "nsCRT.h" +#include "prenv.h" /* for PR_GetEnv */ + +#include <windows.h> +#include <winspool.h> + +// For Localization +#include "nsIStringBundle.h" + +// For NS_CopyUnicodeToNative +#include "nsNativeCharsetUtils.h" + +// This is for extending the dialog +#include <dlgs.h> + +#include "nsWindowsHelpers.h" +#include "WinUtils.h" + +// Default labels for the radio buttons +static const char* kAsLaidOutOnScreenStr = "As &laid out on the screen"; +static const char* kTheSelectedFrameStr = "The selected &frame"; +static const char* kEachFrameSeparately = "&Each frame separately"; + + +//----------------------------------------------- +// Global Data +//----------------------------------------------- +// Identifies which new radio btn was cliked on +static UINT gFrameSelectedRadioBtn = 0; + +// Indicates whether the native print dialog was successfully extended +static bool gDialogWasExtended = false; + +#define PRINTDLG_PROPERTIES "chrome://global/locale/printdialog.properties" + +static HWND gParentWnd = nullptr; + +//---------------------------------------------------------------------------------- +// Return localized bundle for resource strings +static nsresult +GetLocalizedBundle(const char * aPropFileName, nsIStringBundle** aStrBundle) +{ + NS_ENSURE_ARG_POINTER(aPropFileName); + NS_ENSURE_ARG_POINTER(aStrBundle); + + nsresult rv; + nsCOMPtr<nsIStringBundle> bundle; + + + // Create bundle + nsCOMPtr<nsIStringBundleService> stringService = + do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv) && stringService) { + rv = stringService->CreateBundle(aPropFileName, aStrBundle); + } + + return rv; +} + +//-------------------------------------------------------- +// Return localized string +static nsresult +GetLocalizedString(nsIStringBundle* aStrBundle, const char* aKey, nsString& oVal) +{ + NS_ENSURE_ARG_POINTER(aStrBundle); + NS_ENSURE_ARG_POINTER(aKey); + + // Determine default label from string bundle + nsXPIDLString valUni; + nsAutoString key; + key.AssignWithConversion(aKey); + nsresult rv = aStrBundle->GetStringFromName(key.get(), getter_Copies(valUni)); + if (NS_SUCCEEDED(rv) && valUni) { + oVal.Assign(valUni); + } else { + oVal.Truncate(); + } + return rv; +} + +//-------------------------------------------------------- +// Set a multi-byte string in the control +static void SetTextOnWnd(HWND aControl, const nsString& aStr) +{ + nsAutoCString text; + if (NS_SUCCEEDED(NS_CopyUnicodeToNative(aStr, text))) { + ::SetWindowText(aControl, text.get()); + } +} + +//-------------------------------------------------------- +// Will get the control and localized string by "key" +static void SetText(HWND aParent, + UINT aId, + nsIStringBundle* aStrBundle, + const char* aKey) +{ + HWND wnd = GetDlgItem (aParent, aId); + if (!wnd) { + return; + } + nsAutoString str; + nsresult rv = GetLocalizedString(aStrBundle, aKey, str); + if (NS_SUCCEEDED(rv)) { + SetTextOnWnd(wnd, str); + } +} + +//-------------------------------------------------------- +static void SetRadio(HWND aParent, + UINT aId, + bool aIsSet, + bool isEnabled = true) +{ + HWND wnd = ::GetDlgItem (aParent, aId); + if (!wnd) { + return; + } + if (!isEnabled) { + ::EnableWindow(wnd, FALSE); + return; + } + ::EnableWindow(wnd, TRUE); + ::SendMessage(wnd, BM_SETCHECK, (WPARAM)aIsSet, (LPARAM)0); +} + +//-------------------------------------------------------- +static void SetRadioOfGroup(HWND aDlg, int aRadId) +{ + int radioIds[] = {rad4, rad5, rad6}; + int numRads = 3; + + for (int i=0;i<numRads;i++) { + HWND radWnd = ::GetDlgItem(aDlg, radioIds[i]); + if (radWnd != nullptr) { + ::SendMessage(radWnd, BM_SETCHECK, (WPARAM)(radioIds[i] == aRadId), (LPARAM)0); + } + } +} + +//-------------------------------------------------------- +typedef struct { + const char * mKeyStr; + long mKeyId; +} PropKeyInfo; + +// These are the control ids used in the dialog and +// defined by MS-Windows in commdlg.h +static PropKeyInfo gAllPropKeys[] = { + {"printFramesTitleWindows", grp3}, + {"asLaidOutWindows", rad4}, + {"selectedFrameWindows", rad5}, + {"separateFramesWindows", rad6}, + {nullptr, 0}}; + +//-------------------------------------------------------- +//-------------------------------------------------------- +//-------------------------------------------------------- +//-------------------------------------------------------- +// Get the absolute coords of the child windows relative +// to its parent window +static void GetLocalRect(HWND aWnd, RECT& aRect, HWND aParent) +{ + ::GetWindowRect(aWnd, &aRect); + + // MapWindowPoints converts screen coordinates to client coordinates. + // It works correctly in both left-to-right and right-to-left windows. + ::MapWindowPoints(nullptr, aParent, (LPPOINT)&aRect, 2); +} + +//-------------------------------------------------------- +// Show or Hide the control +static void Show(HWND aWnd, bool bState) +{ + if (aWnd) { + ::ShowWindow(aWnd, bState?SW_SHOW:SW_HIDE); + } +} + +//-------------------------------------------------------- +// Create a child window "control" +static HWND CreateControl(LPCTSTR aType, + DWORD aStyle, + HINSTANCE aHInst, + HWND aHdlg, + int aId, + const nsAString& aStr, + const nsIntRect& aRect) +{ + nsAutoCString str; + if (NS_FAILED(NS_CopyUnicodeToNative(aStr, str))) + return nullptr; + + HWND hWnd = ::CreateWindow (aType, str.get(), + WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | aStyle, + aRect.x, aRect.y, aRect.width, aRect.height, + (HWND)aHdlg, (HMENU)(intptr_t)aId, + aHInst, nullptr); + if (hWnd == nullptr) return nullptr; + + // get the native font for the dialog and + // set it into the new control + HFONT hFont = (HFONT)::SendMessage(aHdlg, WM_GETFONT, (WPARAM)0, (LPARAM)0); + if (hFont != nullptr) { + ::SendMessage(hWnd, WM_SETFONT, (WPARAM) hFont, (LPARAM)0); + } + return hWnd; +} + +//-------------------------------------------------------- +// Create a Radio Button +static HWND CreateRadioBtn(HINSTANCE aHInst, + HWND aHdlg, + int aId, + const char* aStr, + const nsIntRect& aRect) +{ + nsString cStr; + cStr.AssignWithConversion(aStr); + return CreateControl("BUTTON", BS_RADIOBUTTON, aHInst, aHdlg, aId, cStr, aRect); +} + +//-------------------------------------------------------- +// Create a Group Box +static HWND CreateGroupBox(HINSTANCE aHInst, + HWND aHdlg, + int aId, + const nsAString& aStr, + const nsIntRect& aRect) +{ + return CreateControl("BUTTON", BS_GROUPBOX, aHInst, aHdlg, aId, aStr, aRect); +} + +//-------------------------------------------------------- +// Localizes and initializes the radio buttons and group +static void InitializeExtendedDialog(HWND hdlg, int16_t aHowToEnableFrameUI) +{ + MOZ_ASSERT(aHowToEnableFrameUI != nsIPrintSettings::kFrameEnableNone, + "should not be called"); + + // Localize the new controls in the print dialog + nsCOMPtr<nsIStringBundle> strBundle; + if (NS_SUCCEEDED(GetLocalizedBundle(PRINTDLG_PROPERTIES, getter_AddRefs(strBundle)))) { + int32_t i = 0; + while (gAllPropKeys[i].mKeyStr != nullptr) { + SetText(hdlg, gAllPropKeys[i].mKeyId, strBundle, gAllPropKeys[i].mKeyStr); + i++; + } + } + + // Set up radio buttons + if (aHowToEnableFrameUI == nsIPrintSettings::kFrameEnableAll) { + SetRadio(hdlg, rad4, false); + SetRadio(hdlg, rad5, true); + SetRadio(hdlg, rad6, false); + // set default so user doesn't have to actually press on it + gFrameSelectedRadioBtn = rad5; + + } else { // nsIPrintSettings::kFrameEnableAsIsAndEach + SetRadio(hdlg, rad4, false); + SetRadio(hdlg, rad5, false, false); + SetRadio(hdlg, rad6, true); + // set default so user doesn't have to actually press on it + gFrameSelectedRadioBtn = rad6; + } +} + + +//-------------------------------------------------------- +// Special Hook Procedure for handling the print dialog messages +static UINT CALLBACK PrintHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) +{ + + if (uiMsg == WM_COMMAND) { + UINT id = LOWORD(wParam); + if (id == rad4 || id == rad5 || id == rad6) { + gFrameSelectedRadioBtn = id; + SetRadioOfGroup(hdlg, id); + } + + } else if (uiMsg == WM_INITDIALOG) { + PRINTDLG * printDlg = (PRINTDLG *)lParam; + if (printDlg == nullptr) return 0L; + + int16_t howToEnableFrameUI = (int16_t)printDlg->lCustData; + // don't add frame options if they would be disabled anyway + // because there are no frames + if (howToEnableFrameUI == nsIPrintSettings::kFrameEnableNone) + return TRUE; + + HINSTANCE hInst = (HINSTANCE)::GetWindowLongPtr(hdlg, GWLP_HINSTANCE); + if (hInst == nullptr) return 0L; + + // Start by getting the local rects of several of the controls + // so we can calculate where the new controls are + HWND wnd = ::GetDlgItem(hdlg, grp1); + if (wnd == nullptr) return 0L; + RECT dlgRect; + GetLocalRect(wnd, dlgRect, hdlg); + + wnd = ::GetDlgItem(hdlg, rad1); // this is the top control "All" + if (wnd == nullptr) return 0L; + RECT rad1Rect; + GetLocalRect(wnd, rad1Rect, hdlg); + + wnd = ::GetDlgItem(hdlg, rad2); // this is the bottom control "Selection" + if (wnd == nullptr) return 0L; + RECT rad2Rect; + GetLocalRect(wnd, rad2Rect, hdlg); + + wnd = ::GetDlgItem(hdlg, rad3); // this is the middle control "Pages" + if (wnd == nullptr) return 0L; + RECT rad3Rect; + GetLocalRect(wnd, rad3Rect, hdlg); + + HWND okWnd = ::GetDlgItem(hdlg, IDOK); + if (okWnd == nullptr) return 0L; + RECT okRect; + GetLocalRect(okWnd, okRect, hdlg); + + wnd = ::GetDlgItem(hdlg, grp4); // this is the "Print range" groupbox + if (wnd == nullptr) return 0L; + RECT prtRect; + GetLocalRect(wnd, prtRect, hdlg); + + + // calculate various different "gaps" for layout purposes + + int rbGap = rad3Rect.top - rad1Rect.bottom; // gap between radiobtns + int grpBotGap = dlgRect.bottom - rad2Rect.bottom; // gap from bottom rb to bottom of grpbox + int grpGap = dlgRect.top - prtRect.bottom ; // gap between group boxes + int top = dlgRect.bottom + grpGap; + int radHgt = rad1Rect.bottom - rad1Rect.top + 1; // top of new group box + int y = top+(rad1Rect.top-dlgRect.top); // starting pos of first radio + int rbWidth = dlgRect.right - rad1Rect.left - 5; // measure from rb left to the edge of the groupbox + // (5 is arbitrary) + nsIntRect rect; + + // Create and position the radio buttons + // + // If any one control cannot be created then + // hide the others and bail out + // + rect.SetRect(rad1Rect.left, y, rbWidth,radHgt); + HWND rad4Wnd = CreateRadioBtn(hInst, hdlg, rad4, kAsLaidOutOnScreenStr, rect); + if (rad4Wnd == nullptr) return 0L; + y += radHgt + rbGap; + + rect.SetRect(rad1Rect.left, y, rbWidth, radHgt); + HWND rad5Wnd = CreateRadioBtn(hInst, hdlg, rad5, kTheSelectedFrameStr, rect); + if (rad5Wnd == nullptr) { + Show(rad4Wnd, FALSE); // hide + return 0L; + } + y += radHgt + rbGap; + + rect.SetRect(rad1Rect.left, y, rbWidth, radHgt); + HWND rad6Wnd = CreateRadioBtn(hInst, hdlg, rad6, kEachFrameSeparately, rect); + if (rad6Wnd == nullptr) { + Show(rad4Wnd, FALSE); // hide + Show(rad5Wnd, FALSE); // hide + return 0L; + } + y += radHgt + grpBotGap; + + // Create and position the group box + rect.SetRect (dlgRect.left, top, dlgRect.right-dlgRect.left+1, y-top+1); + HWND grpBoxWnd = CreateGroupBox(hInst, hdlg, grp3, NS_LITERAL_STRING("Print Frame"), rect); + if (grpBoxWnd == nullptr) { + Show(rad4Wnd, FALSE); // hide + Show(rad5Wnd, FALSE); // hide + Show(rad6Wnd, FALSE); // hide + return 0L; + } + + // Here we figure out the old height of the dlg + // then figure its gap from the old grpbx to the bottom + // then size the dlg + RECT pr, cr; + ::GetWindowRect(hdlg, &pr); + ::GetClientRect(hdlg, &cr); + + int dlgHgt = (cr.bottom - cr.top) + 1; + int bottomGap = dlgHgt - okRect.bottom; + pr.bottom += (dlgRect.bottom-dlgRect.top) + grpGap + 1 - (dlgHgt-dlgRect.bottom) + bottomGap; + + ::SetWindowPos(hdlg, nullptr, pr.left, pr.top, pr.right-pr.left+1, pr.bottom-pr.top+1, + SWP_NOMOVE|SWP_NOREDRAW|SWP_NOZORDER); + + // figure out the new height of the dialog + ::GetClientRect(hdlg, &cr); + dlgHgt = (cr.bottom - cr.top) + 1; + + // Reposition the OK and Cancel btns + int okHgt = okRect.bottom - okRect.top + 1; + ::SetWindowPos(okWnd, nullptr, okRect.left, dlgHgt-bottomGap-okHgt, 0, 0, + SWP_NOSIZE|SWP_NOREDRAW|SWP_NOZORDER); + + HWND cancelWnd = ::GetDlgItem(hdlg, IDCANCEL); + if (cancelWnd == nullptr) return 0L; + + RECT cancelRect; + GetLocalRect(cancelWnd, cancelRect, hdlg); + int cancelHgt = cancelRect.bottom - cancelRect.top + 1; + ::SetWindowPos(cancelWnd, nullptr, cancelRect.left, dlgHgt-bottomGap-cancelHgt, 0, 0, + SWP_NOSIZE|SWP_NOREDRAW|SWP_NOZORDER); + + // localize and initialize the groupbox and radiobuttons + InitializeExtendedDialog(hdlg, howToEnableFrameUI); + + // Looks like we were able to extend the dialog + gDialogWasExtended = true; + return TRUE; + } + return 0L; +} + +//---------------------------------------------------------------------------------- +// Returns a Global Moveable Memory Handle to a DevMode +// from the Printer by the name of aPrintName +// +// NOTE: +// This function assumes that aPrintName has already been converted from +// unicode +// +static nsReturnRef<nsHGLOBAL> +CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName, + nsIPrintSettings* aPS) +{ + nsHPRINTER hPrinter = nullptr; + // const cast kludge for silly Win32 api's + LPWSTR printName = const_cast<wchar_t*>(static_cast<const wchar_t*>(aPrintName.get())); + BOOL status = ::OpenPrinterW(printName, &hPrinter, nullptr); + if (!status) { + return nsReturnRef<nsHGLOBAL>(); + } + + // Make sure hPrinter is closed on all paths + nsAutoPrinter autoPrinter(hPrinter); + + // Get the buffer size + LONG needed = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, nullptr, + nullptr, 0); + if (needed < 0) { + return nsReturnRef<nsHGLOBAL>(); + } + + // Allocate a buffer of the correct size. + nsAutoDevMode newDevMode((LPDEVMODEW)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, + needed)); + if (!newDevMode) { + return nsReturnRef<nsHGLOBAL>(); + } + + nsHGLOBAL hDevMode = ::GlobalAlloc(GHND, needed); + nsAutoGlobalMem globalDevMode(hDevMode); + if (!hDevMode) { + return nsReturnRef<nsHGLOBAL>(); + } + + LONG ret = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, newDevMode, + nullptr, DM_OUT_BUFFER); + if (ret != IDOK) { + return nsReturnRef<nsHGLOBAL>(); + } + + // Lock memory and copy contents from DEVMODE (current printer) + // to Global Memory DEVMODE + LPDEVMODEW devMode = (DEVMODEW *)::GlobalLock(hDevMode); + if (!devMode) { + return nsReturnRef<nsHGLOBAL>(); + } + + memcpy(devMode, newDevMode.get(), needed); + // Initialize values from the PrintSettings + nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(aPS); + MOZ_ASSERT(psWin); + psWin->CopyToNative(devMode); + + // Sets back the changes we made to the DevMode into the Printer Driver + ret = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, devMode, devMode, + DM_IN_BUFFER | DM_OUT_BUFFER); + if (ret != IDOK) { + ::GlobalUnlock(hDevMode); + return nsReturnRef<nsHGLOBAL>(); + } + + ::GlobalUnlock(hDevMode); + + return globalDevMode.out(); +} + +//------------------------------------------------------------------ +// helper +static void GetDefaultPrinterNameFromGlobalPrinters(nsXPIDLString &printerName) +{ + nsCOMPtr<nsIPrinterEnumerator> prtEnum = do_GetService("@mozilla.org/gfx/printerenumerator;1"); + if (prtEnum) { + prtEnum->GetDefaultPrinterName(getter_Copies(printerName)); + } +} + +// Determine whether we have a completely native dialog +// or whether we cshould extend it +static bool ShouldExtendPrintDialog() +{ + nsresult rv; + nsCOMPtr<nsIPrefService> prefs = + do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, true); + nsCOMPtr<nsIPrefBranch> prefBranch; + rv = prefs->GetBranch(nullptr, getter_AddRefs(prefBranch)); + NS_ENSURE_SUCCESS(rv, true); + + bool result; + rv = prefBranch->GetBoolPref("print.extend_native_print_dialog", &result); + NS_ENSURE_SUCCESS(rv, true); + return result; +} + +//------------------------------------------------------------------ +// Displays the native Print Dialog +static nsresult +ShowNativePrintDialog(HWND aHWnd, + nsIPrintSettings* aPrintSettings) +{ + //NS_ENSURE_ARG_POINTER(aHWnd); + NS_ENSURE_ARG_POINTER(aPrintSettings); + + gDialogWasExtended = false; + + // Get the Print Name to be used + nsXPIDLString printerName; + aPrintSettings->GetPrinterName(getter_Copies(printerName)); + + // If there is no name then use the default printer + if (printerName.IsEmpty()) { + GetDefaultPrinterNameFromGlobalPrinters(printerName); + } else { + HANDLE hPrinter = nullptr; + if(!::OpenPrinterW(const_cast<wchar_t*>(static_cast<const wchar_t*>(printerName.get())), + &hPrinter, nullptr)) { + // If the last used printer is not found, we should use default printer. + GetDefaultPrinterNameFromGlobalPrinters(printerName); + } else { + ::ClosePrinter(hPrinter); + } + } + + // Now create a DEVNAMES struct so the the dialog is initialized correctly. + + uint32_t len = printerName.Length(); + nsHGLOBAL hDevNames = ::GlobalAlloc(GHND, sizeof(wchar_t) * (len + 1) + + sizeof(DEVNAMES)); + nsAutoGlobalMem autoDevNames(hDevNames); + if (!hDevNames) { + return NS_ERROR_OUT_OF_MEMORY; + } + + DEVNAMES* pDevNames = (DEVNAMES*)::GlobalLock(hDevNames); + if (!pDevNames) { + return NS_ERROR_FAILURE; + } + pDevNames->wDriverOffset = sizeof(DEVNAMES)/sizeof(wchar_t); + pDevNames->wDeviceOffset = sizeof(DEVNAMES)/sizeof(wchar_t); + pDevNames->wOutputOffset = sizeof(DEVNAMES)/sizeof(wchar_t)+len; + pDevNames->wDefault = 0; + + memcpy(pDevNames+1, printerName, (len + 1) * sizeof(wchar_t)); + ::GlobalUnlock(hDevNames); + + // Create a Moveable Memory Object that holds a new DevMode + // from the Printer Name + // The PRINTDLG.hDevMode requires that it be a moveable memory object + // NOTE: autoDevMode is automatically freed when any error occurred + nsAutoGlobalMem autoDevMode(CreateGlobalDevModeAndInit(printerName, aPrintSettings)); + + // Prepare to Display the Print Dialog + PRINTDLGW prntdlg; + memset(&prntdlg, 0, sizeof(PRINTDLGW)); + + prntdlg.lStructSize = sizeof(prntdlg); + prntdlg.hwndOwner = aHWnd; + prntdlg.hDevMode = autoDevMode.get(); + prntdlg.hDevNames = hDevNames; + prntdlg.hDC = nullptr; + prntdlg.Flags = PD_ALLPAGES | PD_RETURNIC | + PD_USEDEVMODECOPIESANDCOLLATE | PD_COLLATE; + + // if there is a current selection then enable the "Selection" radio button + int16_t howToEnableFrameUI = nsIPrintSettings::kFrameEnableNone; + bool isOn; + aPrintSettings->GetPrintOptions(nsIPrintSettings::kEnableSelectionRB, &isOn); + if (!isOn) { + prntdlg.Flags |= PD_NOSELECTION; + } + aPrintSettings->GetHowToEnableFrameUI(&howToEnableFrameUI); + + int32_t pg = 1; + aPrintSettings->GetStartPageRange(&pg); + prntdlg.nFromPage = pg; + + aPrintSettings->GetEndPageRange(&pg); + prntdlg.nToPage = pg; + + prntdlg.nMinPage = 1; + prntdlg.nMaxPage = 0xFFFF; + prntdlg.nCopies = 1; + prntdlg.lpfnSetupHook = nullptr; + prntdlg.lpSetupTemplateName = nullptr; + prntdlg.hPrintTemplate = nullptr; + prntdlg.hSetupTemplate = nullptr; + + prntdlg.hInstance = nullptr; + prntdlg.lpPrintTemplateName = nullptr; + + if (!ShouldExtendPrintDialog()) { + prntdlg.lCustData = 0; + prntdlg.lpfnPrintHook = nullptr; + } else { + // Set up print dialog "hook" procedure for extending the dialog + prntdlg.lCustData = (DWORD)howToEnableFrameUI; + prntdlg.lpfnPrintHook = (LPPRINTHOOKPROC)PrintHookProc; + prntdlg.Flags |= PD_ENABLEPRINTHOOK; + } + + BOOL result; + { + mozilla::widget::WinUtils::AutoSystemDpiAware dpiAwareness; + result = ::PrintDlgW(&prntdlg); + } + + if (TRUE == result) { + // check to make sure we don't have any nullptr pointers + NS_ENSURE_TRUE(aPrintSettings && prntdlg.hDevMode, NS_ERROR_FAILURE); + + if (prntdlg.hDevNames == nullptr) { + return NS_ERROR_FAILURE; + } + // Lock the deviceNames and check for nullptr + DEVNAMES *devnames = (DEVNAMES *)::GlobalLock(prntdlg.hDevNames); + if (devnames == nullptr) { + return NS_ERROR_FAILURE; + } + + char16_t* device = &(((char16_t *)devnames)[devnames->wDeviceOffset]); + char16_t* driver = &(((char16_t *)devnames)[devnames->wDriverOffset]); + + // Check to see if the "Print To File" control is checked + // then take the name from devNames and set it in the PrintSettings + // + // NOTE: + // As per Microsoft SDK documentation the returned value offset from + // devnames->wOutputOffset is either "FILE:" or nullptr + // if the "Print To File" checkbox is checked it MUST be "FILE:" + // We assert as an extra safety check. + if (prntdlg.Flags & PD_PRINTTOFILE) { + char16ptr_t fileName = &(((wchar_t *)devnames)[devnames->wOutputOffset]); + NS_ASSERTION(wcscmp(fileName, L"FILE:") == 0, "FileName must be `FILE:`"); + aPrintSettings->SetToFileName(fileName); + aPrintSettings->SetPrintToFile(true); + } else { + // clear "print to file" info + aPrintSettings->SetPrintToFile(false); + aPrintSettings->SetToFileName(nullptr); + } + + nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(aPrintSettings)); + if (!psWin) { + return NS_ERROR_FAILURE; + } + + // Setup local Data members + psWin->SetDeviceName(device); + psWin->SetDriverName(driver); + +#if defined(DEBUG_rods) || defined(DEBUG_dcone) + wprintf(L"printer: driver %s, device %s flags: %d\n", driver, device, prntdlg.Flags); +#endif + // fill the print options with the info from the dialog + + aPrintSettings->SetPrinterName(device); + + if (prntdlg.Flags & PD_SELECTION) { + aPrintSettings->SetPrintRange(nsIPrintSettings::kRangeSelection); + + } else if (prntdlg.Flags & PD_PAGENUMS) { + aPrintSettings->SetPrintRange(nsIPrintSettings::kRangeSpecifiedPageRange); + aPrintSettings->SetStartPageRange(prntdlg.nFromPage); + aPrintSettings->SetEndPageRange(prntdlg.nToPage); + + } else { // (prntdlg.Flags & PD_ALLPAGES) + aPrintSettings->SetPrintRange(nsIPrintSettings::kRangeAllPages); + } + + if (howToEnableFrameUI != nsIPrintSettings::kFrameEnableNone) { + // make sure the dialog got extended + if (gDialogWasExtended) { + // check to see about the frame radio buttons + switch (gFrameSelectedRadioBtn) { + case rad4: + aPrintSettings->SetPrintFrameType(nsIPrintSettings::kFramesAsIs); + break; + case rad5: + aPrintSettings->SetPrintFrameType(nsIPrintSettings::kSelectedFrame); + break; + case rad6: + aPrintSettings->SetPrintFrameType(nsIPrintSettings::kEachFrameSep); + break; + } // switch + } else { + // if it didn't get extended then have it default to printing + // each frame separately + aPrintSettings->SetPrintFrameType(nsIPrintSettings::kEachFrameSep); + } + } else { + aPrintSettings->SetPrintFrameType(nsIPrintSettings::kNoFrames); + } + // Unlock DeviceNames + ::GlobalUnlock(prntdlg.hDevNames); + + // Transfer the settings from the native data to the PrintSettings + LPDEVMODEW devMode = (LPDEVMODEW)::GlobalLock(prntdlg.hDevMode); + if (!devMode || !prntdlg.hDC) { + return NS_ERROR_FAILURE; + } + psWin->SetDevMode(devMode); // copies DevMode + psWin->CopyFromNative(prntdlg.hDC, devMode); + ::GlobalUnlock(prntdlg.hDevMode); + ::DeleteDC(prntdlg.hDC); + +#if defined(DEBUG_rods) || defined(DEBUG_dcone) + bool printSelection = prntdlg.Flags & PD_SELECTION; + bool printAllPages = prntdlg.Flags & PD_ALLPAGES; + bool printNumPages = prntdlg.Flags & PD_PAGENUMS; + int32_t fromPageNum = 0; + int32_t toPageNum = 0; + + if (printNumPages) { + fromPageNum = prntdlg.nFromPage; + toPageNum = prntdlg.nToPage; + } + if (printSelection) { + printf("Printing the selection\n"); + + } else if (printAllPages) { + printf("Printing all the pages\n"); + + } else { + printf("Printing from page no. %d to %d\n", fromPageNum, toPageNum); + } +#endif + + } else { + ::SetFocus(aHWnd); + aPrintSettings->SetIsCancelled(true); + return NS_ERROR_ABORT; + } + + return NS_OK; +} + +//------------------------------------------------------------------ +static void +PrepareForPrintDialog(nsIWebBrowserPrint* aWebBrowserPrint, nsIPrintSettings* aPS) +{ + NS_ASSERTION(aWebBrowserPrint, "Can't be null"); + NS_ASSERTION(aPS, "Can't be null"); + + bool isFramesetDocument; + bool isFramesetFrameSelected; + bool isIFrameSelected; + bool isRangeSelection; + + aWebBrowserPrint->GetIsFramesetDocument(&isFramesetDocument); + aWebBrowserPrint->GetIsFramesetFrameSelected(&isFramesetFrameSelected); + aWebBrowserPrint->GetIsIFrameSelected(&isIFrameSelected); + aWebBrowserPrint->GetIsRangeSelection(&isRangeSelection); + + // Setup print options for UI + if (isFramesetDocument) { + if (isFramesetFrameSelected) { + aPS->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAll); + } else { + aPS->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAsIsAndEach); + } + } else { + aPS->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableNone); + } + + // Now determine how to set up the Frame print UI + aPS->SetPrintOptions(nsIPrintSettings::kEnableSelectionRB, isRangeSelection || isIFrameSelected); + +} + +//---------------------------------------------------------------------------------- +//-- Show Print Dialog +//---------------------------------------------------------------------------------- +nsresult NativeShowPrintDialog(HWND aHWnd, + nsIWebBrowserPrint* aWebBrowserPrint, + nsIPrintSettings* aPrintSettings) +{ + PrepareForPrintDialog(aWebBrowserPrint, aPrintSettings); + + nsresult rv = ShowNativePrintDialog(aHWnd, aPrintSettings); + if (aHWnd) { + ::DestroyWindow(aHWnd); + } + + return rv; +} + diff --git a/embedding/components/printingui/win/nsPrintDialogUtil.h b/embedding/components/printingui/win/nsPrintDialogUtil.h new file mode 100644 index 000000000..ada3da239 --- /dev/null +++ b/embedding/components/printingui/win/nsPrintDialogUtil.h @@ -0,0 +1,12 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef nsFlyOwnDialog_h___ +#define nsFlyOwnDialog_h___ + +nsresult NativeShowPrintDialog(HWND aHWnd, + nsIWebBrowserPrint* aWebBrowserPrint, + nsIPrintSettings* aPrintSettings); + +#endif /* nsFlyOwnDialog_h___ */ diff --git a/embedding/components/printingui/win/nsPrintProgress.cpp b/embedding/components/printingui/win/nsPrintProgress.cpp new file mode 100644 index 000000000..0b1c10a2c --- /dev/null +++ b/embedding/components/printingui/win/nsPrintProgress.cpp @@ -0,0 +1,293 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsPrintProgress.h" + +#include "nsArray.h" +#include "nsIBaseWindow.h" +#include "nsIDocShell.h" +#include "nsIDocShellTreeOwner.h" +#include "nsIInterfaceRequestorUtils.h" +#include "nsIXULWindow.h" +#include "nsXPCOM.h" +#include "nsISupportsPrimitives.h" +#include "nsIComponentManager.h" +#include "nsIServiceManager.h" +#include "nsPIDOMWindow.h" + +#if 0 +NS_IMPL_ADDREF(nsPrintProgress) +NS_IMPL_RELEASE(nsPrintProgress) +#else +NS_IMETHODIMP_(MozExternalRefCountType) nsPrintProgress::AddRef(void) +{ + NS_PRECONDITION(int32_t(mRefCnt) >= 0, "illegal refcnt"); + nsrefcnt count; + count = ++mRefCnt; + //NS_LOG_ADDREF(this, count, "nsPrintProgress", sizeof(*this)); + return count; +} + +NS_IMETHODIMP_(MozExternalRefCountType) nsPrintProgress::Release(void) +{ + nsrefcnt count; + NS_PRECONDITION(0 != mRefCnt, "dup release"); + count = --mRefCnt; + //NS_LOG_RELEASE(this, count, "nsPrintProgress"); + if (0 == count) { + mRefCnt = 1; /* stabilize */ + /* enable this to find non-threadsafe destructors: */ + /* NS_ASSERT_OWNINGTHREAD(nsPrintProgress); */ + delete this; + return 0; + } + return count; +} + +#endif + +NS_INTERFACE_MAP_BEGIN(nsPrintProgress) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrintStatusFeedback) + NS_INTERFACE_MAP_ENTRY(nsIPrintProgress) + NS_INTERFACE_MAP_ENTRY(nsIPrintStatusFeedback) + NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener) +NS_INTERFACE_MAP_END_THREADSAFE + + +nsPrintProgress::nsPrintProgress() +{ + m_closeProgress = false; + m_processCanceled = false; + m_pendingStateFlags = -1; + m_pendingStateValue = NS_OK; +} + +nsPrintProgress::~nsPrintProgress() +{ + (void)ReleaseListeners(); +} + +NS_IMETHODIMP nsPrintProgress::OpenProgressDialog(mozIDOMWindowProxy *parent, + const char *dialogURL, + nsISupports *parameters, + nsIObserver *openDialogObserver, + bool *notifyOnOpen) +{ + *notifyOnOpen = true; + m_observer = openDialogObserver; + + nsresult rv = NS_ERROR_FAILURE; + + if (m_dialog) + return NS_ERROR_ALREADY_INITIALIZED; + + if (!dialogURL || !*dialogURL) + return NS_ERROR_INVALID_ARG; + + if (parent) + { + // Set up window.arguments[0]... + nsCOMPtr<nsIMutableArray> array = nsArray::Create(); + + nsCOMPtr<nsISupportsInterfacePointer> ifptr = + do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + ifptr->SetData(static_cast<nsIPrintProgress*>(this)); + ifptr->SetDataIID(&NS_GET_IID(nsIPrintProgress)); + + array->AppendElement(ifptr, /*weak =*/ false); + + array->AppendElement(parameters, /*weak = */ false); + + // We will set the opener of the dialog to be the nsIDOMWindow for the + // browser XUL window itself, as opposed to the content. That way, the + // progress window has access to the opener. + nsCOMPtr<nsPIDOMWindowOuter> pParentWindow = nsPIDOMWindowOuter::From(parent); + NS_ENSURE_STATE(pParentWindow); + + nsCOMPtr<nsIDocShell> docShell = pParentWindow->GetDocShell(); + NS_ENSURE_STATE(docShell); + + nsCOMPtr<nsIDocShellTreeOwner> owner; + docShell->GetTreeOwner(getter_AddRefs(owner)); + + nsCOMPtr<nsIXULWindow> ownerXULWindow = do_GetInterface(owner); + nsCOMPtr<mozIDOMWindowProxy> ownerWindow = do_GetInterface(ownerXULWindow); + NS_ENSURE_STATE(ownerWindow); + + nsCOMPtr<nsPIDOMWindowOuter> piOwnerWindow = nsPIDOMWindowOuter::From(ownerWindow); + + // Open the dialog. + nsCOMPtr<nsPIDOMWindowOuter> newWindow; + rv = piOwnerWindow->OpenDialog(NS_ConvertASCIItoUTF16(dialogURL), + NS_LITERAL_STRING("_blank"), + NS_LITERAL_STRING("chrome,titlebar,dependent,centerscreen"), + array, getter_AddRefs(newWindow)); + } + + return rv; +} + +NS_IMETHODIMP nsPrintProgress::CloseProgressDialog(bool forceClose) +{ + m_closeProgress = true; + // XXX Casting from bool to nsresult + return OnStateChange(nullptr, nullptr, nsIWebProgressListener::STATE_STOP, + static_cast<nsresult>(forceClose)); +} + +NS_IMETHODIMP nsPrintProgress::GetPrompter(nsIPrompt **_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = nullptr; + + if (! m_closeProgress && m_dialog) { + nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryInterface(m_dialog); + MOZ_ASSERT(window); + return window->GetPrompter(_retval); + } + + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP nsPrintProgress::GetProcessCanceledByUser(bool *aProcessCanceledByUser) +{ + NS_ENSURE_ARG_POINTER(aProcessCanceledByUser); + *aProcessCanceledByUser = m_processCanceled; + return NS_OK; +} +NS_IMETHODIMP nsPrintProgress::SetProcessCanceledByUser(bool aProcessCanceledByUser) +{ + m_processCanceled = aProcessCanceledByUser; + OnStateChange(nullptr, nullptr, nsIWebProgressListener::STATE_STOP, NS_OK); + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgress::RegisterListener(nsIWebProgressListener * listener) +{ + if (!listener) //Nothing to do with a null listener! + return NS_OK; + + m_listenerList.AppendObject(listener); + if (m_closeProgress || m_processCanceled) + listener->OnStateChange(nullptr, nullptr, + nsIWebProgressListener::STATE_STOP, NS_OK); + else + { + listener->OnStatusChange(nullptr, nullptr, NS_OK, m_pendingStatus.get()); + if (m_pendingStateFlags != -1) + listener->OnStateChange(nullptr, nullptr, m_pendingStateFlags, m_pendingStateValue); + } + + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgress::UnregisterListener(nsIWebProgressListener *listener) +{ + if (listener) + m_listenerList.RemoveObject(listener); + + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgress::DoneIniting() +{ + if (m_observer) { + m_observer->Observe(nullptr, nullptr, nullptr); + } + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgress::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, uint32_t aStateFlags, nsresult aStatus) +{ + m_pendingStateFlags = aStateFlags; + m_pendingStateValue = aStatus; + + uint32_t count = m_listenerList.Count(); + for (uint32_t i = count - 1; i < count; i --) + { + nsCOMPtr<nsIWebProgressListener> progressListener = m_listenerList.SafeObjectAt(i); + if (progressListener) + progressListener->OnStateChange(aWebProgress, aRequest, aStateFlags, aStatus); + } + + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgress::OnProgressChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, int32_t aCurSelfProgress, int32_t aMaxSelfProgress, int32_t aCurTotalProgress, int32_t aMaxTotalProgress) +{ + uint32_t count = m_listenerList.Count(); + for (uint32_t i = count - 1; i < count; i --) + { + nsCOMPtr<nsIWebProgressListener> progressListener = m_listenerList.SafeObjectAt(i); + if (progressListener) + progressListener->OnProgressChange(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress); + } + + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgress::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location, uint32_t aFlags) +{ + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgress::OnStatusChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsresult aStatus, const char16_t *aMessage) +{ + if (aMessage && *aMessage) + m_pendingStatus = aMessage; + + uint32_t count = m_listenerList.Count(); + for (uint32_t i = count - 1; i < count; i --) + { + nsCOMPtr<nsIWebProgressListener> progressListener = m_listenerList.SafeObjectAt(i); + if (progressListener) + progressListener->OnStatusChange(aWebProgress, aRequest, aStatus, aMessage); + } + + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgress::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, uint32_t state) +{ + return NS_OK; +} + +nsresult nsPrintProgress::ReleaseListeners() +{ + m_listenerList.Clear(); + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgress::ShowStatusString(const char16_t *status) +{ + return OnStatusChange(nullptr, nullptr, NS_OK, status); +} + +NS_IMETHODIMP nsPrintProgress::StartMeteors() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsPrintProgress::StopMeteors() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsPrintProgress::ShowProgress(int32_t percent) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsPrintProgress::SetDocShell(nsIDocShell *shell, mozIDOMWindowProxy *window) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsPrintProgress::CloseWindow() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} diff --git a/embedding/components/printingui/win/nsPrintProgress.h b/embedding/components/printingui/win/nsPrintProgress.h new file mode 100644 index 000000000..adc5a14cc --- /dev/null +++ b/embedding/components/printingui/win/nsPrintProgress.h @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __nsPrintProgress_h +#define __nsPrintProgress_h + +#include "nsIPrintProgress.h" + +#include "nsCOMArray.h" +#include "nsCOMPtr.h" +#include "nsIDOMWindow.h" +#include "nsIPrintStatusFeedback.h" +#include "nsString.h" +#include "nsIWindowWatcher.h" +#include "nsIObserver.h" + +class nsPrintProgress : public nsIPrintProgress, public nsIPrintStatusFeedback +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIPRINTPROGRESS + NS_DECL_NSIWEBPROGRESSLISTENER + NS_DECL_NSIPRINTSTATUSFEEDBACK + + nsPrintProgress(); + virtual ~nsPrintProgress(); + +private: + nsresult ReleaseListeners(); + + bool m_closeProgress; + bool m_processCanceled; + nsString m_pendingStatus; + int32_t m_pendingStateFlags; + nsresult m_pendingStateValue; + nsCOMPtr<nsIDOMWindow> m_dialog; + nsCOMArray<nsIWebProgressListener> m_listenerList; + nsCOMPtr<nsIObserver> m_observer; +}; + +#endif diff --git a/embedding/components/printingui/win/nsPrintProgressParams.cpp b/embedding/components/printingui/win/nsPrintProgressParams.cpp new file mode 100644 index 000000000..eba86b298 --- /dev/null +++ b/embedding/components/printingui/win/nsPrintProgressParams.cpp @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsPrintProgressParams.h" +#include "nsReadableUtils.h" + + +NS_IMPL_ISUPPORTS(nsPrintProgressParams, nsIPrintProgressParams) + +nsPrintProgressParams::nsPrintProgressParams() +{ +} + +nsPrintProgressParams::~nsPrintProgressParams() +{ +} + +NS_IMETHODIMP nsPrintProgressParams::GetDocTitle(char16_t * *aDocTitle) +{ + NS_ENSURE_ARG(aDocTitle); + + *aDocTitle = ToNewUnicode(mDocTitle); + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgressParams::SetDocTitle(const char16_t * aDocTitle) +{ + mDocTitle = aDocTitle; + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgressParams::GetDocURL(char16_t * *aDocURL) +{ + NS_ENSURE_ARG(aDocURL); + + *aDocURL = ToNewUnicode(mDocURL); + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgressParams::SetDocURL(const char16_t * aDocURL) +{ + mDocURL = aDocURL; + return NS_OK; +} + diff --git a/embedding/components/printingui/win/nsPrintProgressParams.h b/embedding/components/printingui/win/nsPrintProgressParams.h new file mode 100644 index 000000000..aebfbff7f --- /dev/null +++ b/embedding/components/printingui/win/nsPrintProgressParams.h @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __nsPrintProgressParams_h +#define __nsPrintProgressParams_h + +#include "nsIPrintProgressParams.h" +#include "nsString.h" + +class nsPrintProgressParams : public nsIPrintProgressParams +{ + virtual ~nsPrintProgressParams(); + +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPRINTPROGRESSPARAMS + + nsPrintProgressParams(); + +private: + nsString mDocTitle; + nsString mDocURL; +}; + +#endif diff --git a/embedding/components/printingui/win/nsPrintingPromptService.cpp b/embedding/components/printingui/win/nsPrintingPromptService.cpp new file mode 100644 index 000000000..83727ee4e --- /dev/null +++ b/embedding/components/printingui/win/nsPrintingPromptService.cpp @@ -0,0 +1,341 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsCOMPtr.h" + +#include "nsPrintingPromptService.h" +#include "nsIPrintingPromptService.h" +#include "nsIFactory.h" +#include "nsPIDOMWindow.h" +#include "nsReadableUtils.h" +#include "nsIEmbeddingSiteWindow.h" +#include "nsIServiceManager.h" +#include "nsIWebBrowserChrome.h" +#include "nsIWindowWatcher.h" +#include "nsPrintDialogUtil.h" + +// Printing Progress Includes +#include "nsPrintProgress.h" +#include "nsPrintProgressParams.h" +#include "nsIWebProgressListener.h" + +// XP Dialog includes +#include "nsArray.h" +#include "nsIDialogParamBlock.h" +#include "nsISupportsUtils.h" + +// Includes need to locate the native Window +#include "nsIWidget.h" +#include "nsIBaseWindow.h" +#include "nsIWebBrowserChrome.h" +#include "nsIDocShellTreeOwner.h" +#include "nsIDocShellTreeItem.h" +#include "nsIDocShell.h" +#include "nsIInterfaceRequestorUtils.h" + + +static const char *kPrintProgressDialogURL = "chrome://global/content/printProgress.xul"; +static const char *kPrtPrvProgressDialogURL = "chrome://global/content/printPreviewProgress.xul"; +static const char *kPageSetupDialogURL = "chrome://global/content/printPageSetup.xul"; + +/**************************************************************** + ************************* ParamBlock *************************** + ****************************************************************/ + +class ParamBlock { + +public: + ParamBlock() + { + mBlock = 0; + } + ~ParamBlock() + { + NS_IF_RELEASE(mBlock); + } + nsresult Init() { + return CallCreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID, &mBlock); + } + nsIDialogParamBlock * operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { return mBlock; } + operator nsIDialogParamBlock * const () { return mBlock; } + +private: + nsIDialogParamBlock *mBlock; +}; + +//***************************************************************************** + +NS_IMPL_ISUPPORTS(nsPrintingPromptService, nsIPrintingPromptService, nsIWebProgressListener) + +nsPrintingPromptService::nsPrintingPromptService() +{ +} + +//----------------------------------------------------------- +nsPrintingPromptService::~nsPrintingPromptService() +{ +} + +//----------------------------------------------------------- +nsresult +nsPrintingPromptService::Init() +{ + nsresult rv; + mWatcher = do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv); + return rv; +} + +//----------------------------------------------------------- +HWND +nsPrintingPromptService::GetHWNDForDOMWindow(mozIDOMWindowProxy *aWindow) +{ + nsCOMPtr<nsIWebBrowserChrome> chrome; + + // We might be embedded so check this path first + if (mWatcher) { + nsCOMPtr<mozIDOMWindowProxy> fosterParent; + if (!aWindow) + { // it will be a dependent window. try to find a foster parent. + mWatcher->GetActiveWindow(getter_AddRefs(fosterParent)); + aWindow = fosterParent; + } + mWatcher->GetChromeForWindow(aWindow, getter_AddRefs(chrome)); + } + + if (chrome) { + nsCOMPtr<nsIEmbeddingSiteWindow> site(do_QueryInterface(chrome)); + if (site) + { + HWND w; + site->GetSiteWindow(reinterpret_cast<void **>(&w)); + return w; + } + } + + // Now we might be the Browser so check this path + nsCOMPtr<nsPIDOMWindowOuter> window = nsPIDOMWindowOuter::From(aWindow); + + nsCOMPtr<nsIDocShellTreeItem> treeItem = + do_QueryInterface(window->GetDocShell()); + if (!treeItem) return nullptr; + + nsCOMPtr<nsIDocShellTreeOwner> treeOwner; + treeItem->GetTreeOwner(getter_AddRefs(treeOwner)); + if (!treeOwner) return nullptr; + + nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome(do_GetInterface(treeOwner)); + if (!webBrowserChrome) return nullptr; + + nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(webBrowserChrome)); + if (!baseWin) return nullptr; + + nsCOMPtr<nsIWidget> widget; + baseWin->GetMainWidget(getter_AddRefs(widget)); + if (!widget) return nullptr; + + return (HWND)widget->GetNativeData(NS_NATIVE_TMP_WINDOW); + +} + + +/////////////////////////////////////////////////////////////////////////////// +// nsIPrintingPromptService + +//----------------------------------------------------------- +NS_IMETHODIMP +nsPrintingPromptService::ShowPrintDialog(mozIDOMWindowProxy *parent, nsIWebBrowserPrint *webBrowserPrint, nsIPrintSettings *printSettings) +{ + NS_ENSURE_ARG(parent); + + HWND hWnd = GetHWNDForDOMWindow(parent); + NS_ASSERTION(hWnd, "Couldn't get native window for PRint Dialog!"); + + return NativeShowPrintDialog(hWnd, webBrowserPrint, printSettings); +} + + +NS_IMETHODIMP +nsPrintingPromptService::ShowProgress(mozIDOMWindowProxy* parent, + nsIWebBrowserPrint* webBrowserPrint, // ok to be null + nsIPrintSettings* printSettings, // ok to be null + nsIObserver* openDialogObserver, // ok to be null + bool isForPrinting, + nsIWebProgressListener** webProgressListener, + nsIPrintProgressParams** printProgressParams, + bool* notifyOnOpen) +{ + NS_ENSURE_ARG(webProgressListener); + NS_ENSURE_ARG(printProgressParams); + NS_ENSURE_ARG(notifyOnOpen); + + *notifyOnOpen = false; + if (mPrintProgress) { + *webProgressListener = nullptr; + *printProgressParams = nullptr; + return NS_ERROR_FAILURE; + } + + nsPrintProgress* prtProgress = new nsPrintProgress(); + mPrintProgress = prtProgress; + mWebProgressListener = prtProgress; + + nsCOMPtr<nsIPrintProgressParams> prtProgressParams = new nsPrintProgressParams(); + + nsCOMPtr<mozIDOMWindowProxy> parentWindow = parent; + + if (mWatcher && !parentWindow) { + mWatcher->GetActiveWindow(getter_AddRefs(parentWindow)); + } + + if (parentWindow) { + mPrintProgress->OpenProgressDialog(parentWindow, + isForPrinting ? kPrintProgressDialogURL : kPrtPrvProgressDialogURL, + prtProgressParams, openDialogObserver, notifyOnOpen); + } + + prtProgressParams.forget(printProgressParams); + NS_ADDREF(*webProgressListener = this); + + return NS_OK; +} + +NS_IMETHODIMP +nsPrintingPromptService::ShowPageSetup(mozIDOMWindowProxy *parent, nsIPrintSettings *printSettings, nsIObserver *aObs) +{ + NS_ENSURE_ARG(printSettings); + + ParamBlock block; + nsresult rv = block.Init(); + if (NS_FAILED(rv)) + return rv; + + block->SetInt(0, 0); + rv = DoDialog(parent, block, printSettings, kPageSetupDialogURL); + + // if aWebBrowserPrint is not null then we are printing + // so we want to pass back NS_ERROR_ABORT on cancel + if (NS_SUCCEEDED(rv)) + { + int32_t status; + block->GetInt(0, &status); + return status == 0?NS_ERROR_ABORT:NS_OK; + } + + return rv; +} + +NS_IMETHODIMP +nsPrintingPromptService::ShowPrinterProperties(mozIDOMWindowProxy *parent, const char16_t *printerName, nsIPrintSettings *printSettings) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +//----------------------------------------------------------- +// Helper to Fly XP Dialog +nsresult +nsPrintingPromptService::DoDialog(mozIDOMWindowProxy *aParent, + nsIDialogParamBlock *aParamBlock, + nsIPrintSettings* aPS, + const char *aChromeURL) +{ + NS_ENSURE_ARG(aParamBlock); + NS_ENSURE_ARG(aPS); + NS_ENSURE_ARG(aChromeURL); + + if (!mWatcher) + return NS_ERROR_FAILURE; + + // get a parent, if at all possible + // (though we'd rather this didn't fail, it's OK if it does. so there's + // no failure or null check.) + nsCOMPtr<mozIDOMWindowProxy> activeParent; // retain ownership for method lifetime + if (!aParent) + { + mWatcher->GetActiveWindow(getter_AddRefs(activeParent)); + aParent = activeParent; + } + + // create a nsIMutableArray of the parameters + // being passed to the window + nsCOMPtr<nsIMutableArray> array = nsArray::Create(); + + nsCOMPtr<nsISupports> psSupports(do_QueryInterface(aPS)); + NS_ASSERTION(psSupports, "PrintSettings must be a supports"); + array->AppendElement(psSupports, /*weak =*/ false); + + nsCOMPtr<nsISupports> blkSupps(do_QueryInterface(aParamBlock)); + NS_ASSERTION(blkSupps, "IOBlk must be a supports"); + array->AppendElement(blkSupps, /*weak =*/ false); + + nsCOMPtr<mozIDOMWindowProxy> dialog; + nsresult rv = mWatcher->OpenWindow(aParent, aChromeURL, "_blank", + "centerscreen,chrome,modal,titlebar", array, + getter_AddRefs(dialog)); + + return rv; +} + +////////////////////////////////////////////////////////////////////// +// nsIWebProgressListener +////////////////////////////////////////////////////////////////////// + +NS_IMETHODIMP +nsPrintingPromptService::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, uint32_t aStateFlags, nsresult aStatus) +{ + if ((aStateFlags & STATE_STOP) && mWebProgressListener) + { + mWebProgressListener->OnStateChange(aWebProgress, aRequest, aStateFlags, aStatus); + if (mPrintProgress) + { + mPrintProgress->CloseProgressDialog(true); + } + mPrintProgress = nullptr; + mWebProgressListener = nullptr; + } + return NS_OK; +} + +NS_IMETHODIMP +nsPrintingPromptService::OnProgressChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, int32_t aCurSelfProgress, int32_t aMaxSelfProgress, int32_t aCurTotalProgress, int32_t aMaxTotalProgress) +{ + if (mWebProgressListener) + { + return mWebProgressListener->OnProgressChange(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress); + } + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsPrintingPromptService::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location, uint32_t aFlags) +{ + if (mWebProgressListener) + { + return mWebProgressListener->OnLocationChange(aWebProgress, aRequest, location, aFlags); + } + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsPrintingPromptService::OnStatusChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsresult aStatus, const char16_t *aMessage) +{ + if (mWebProgressListener) + { + return mWebProgressListener->OnStatusChange(aWebProgress, aRequest, aStatus, aMessage); + } + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsPrintingPromptService::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, uint32_t state) +{ + if (mWebProgressListener) + { + return mWebProgressListener->OnSecurityChange(aWebProgress, aRequest, state); + } + return NS_ERROR_FAILURE; +} + + diff --git a/embedding/components/printingui/win/nsPrintingPromptService.h b/embedding/components/printingui/win/nsPrintingPromptService.h new file mode 100644 index 000000000..76bc7a804 --- /dev/null +++ b/embedding/components/printingui/win/nsPrintingPromptService.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __nsPrintingPromptService_h +#define __nsPrintingPromptService_h + +#include <windows.h> + +// {E042570C-62DE-4bb6-A6E0-798E3C07B4DF} +#define NS_PRINTINGPROMPTSERVICE_CID \ + {0xe042570c, 0x62de, 0x4bb6, { 0xa6, 0xe0, 0x79, 0x8e, 0x3c, 0x7, 0xb4, 0xdf}} +#define NS_PRINTINGPROMPTSERVICE_CONTRACTID \ + "@mozilla.org/embedcomp/printingprompt-service;1" + +#include "nsCOMPtr.h" +#include "nsIPrintingPromptService.h" +#include "nsPIPromptService.h" +#include "nsIWindowWatcher.h" + +// Printing Progress Includes +#include "nsPrintProgress.h" +#include "nsPrintProgressParams.h" +#include "nsIWebProgressListener.h" + +class nsIDOMWindow; +class nsIDialogParamBlock; + +class nsPrintingPromptService: public nsIPrintingPromptService, + public nsIWebProgressListener +{ + virtual ~nsPrintingPromptService(); + +public: + nsPrintingPromptService(); + + nsresult Init(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIPRINTINGPROMPTSERVICE + NS_DECL_NSIWEBPROGRESSLISTENER + +private: + HWND GetHWNDForDOMWindow(mozIDOMWindowProxy *parent); + nsresult DoDialog(mozIDOMWindowProxy *aParent, + nsIDialogParamBlock *aParamBlock, + nsIPrintSettings* aPS, + const char *aChromeURL); + + nsCOMPtr<nsIWindowWatcher> mWatcher; + nsCOMPtr<nsIPrintProgress> mPrintProgress; + nsCOMPtr<nsIWebProgressListener> mWebProgressListener; + +}; + +#endif + |