//[ ACCESSKEY_GROUP Installer void OnCreateWindow(HWND hwnd) { ClientRect r(hwnd); gHwndButtonInstUninst = CreateDefaultButton(hwnd, _TR("Install SumatraPDF"), IDOK); SIZE btnSize; gHwndButtonOptions = CreateButton(hwnd, _TR("&Options"), ID_BUTTON_OPTIONS, BS_PUSHBUTTON, btnSize); int x = WINDOW_MARGIN; int y = r.dy - btnSize.cy - WINDOW_MARGIN; SetWindowPos(gHwndButtonOptions, nullptr, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW); gButtonDy = btnSize.cy; gBottomPartDy = gButtonDy + (WINDOW_MARGIN * 2); SizeI size = TextSizeInHwnd(hwnd, L"Foo"); int staticDy = size.dy + dpiAdjust(4); y = r.dy - gBottomPartDy; int dx = r.dx - (WINDOW_MARGIN * 2) - dpiAdjust(2); x += dpiAdjust(2); // build options controls going from the bottom y -= (staticDy + WINDOW_MARGIN); ScopedMem<WCHAR> defaultViewer(GetDefaultPdfViewer()); BOOL hasOtherViewer = !str::EqI(defaultViewer, APP_NAME_STR); BOOL isSumatraDefaultViewer = defaultViewer && !hasOtherViewer; // only show this checkbox if the CPU arch of DLL and OS match // (assuming that the installer has the same CPU arch as its content!) if (IsProcessAndOsArchSame()) { // only show this checkbox if the browser plugin has been installed before if (IsBrowserPluginInstalled()) { gHwndCheckboxKeepBrowserPlugin = CreateWindowExW( 0, WC_BUTTON, _TR("Keep the PDF &browser plugin installed (no longer supported)"), WS_CHILD | BS_AUTOCHECKBOX | WS_TABSTOP, x, y, dx, staticDy, hwnd, (HMENU) ID_CHECKBOX_BROWSER_PLUGIN, GetModuleHandle(nullptr), nullptr); SetWindowFont(gHwndCheckboxKeepBrowserPlugin, gFontDefault, TRUE); Button_SetCheck(gHwndCheckboxKeepBrowserPlugin, gGlobalData.keepBrowserPlugin); y -= staticDy; } // for Windows XP, this means only basic thumbnail support gHwndCheckboxRegisterPdfPreviewer = CreateWindowExW( 0, WC_BUTTON, _TR("Let Windows show &previews of PDF documents"), WS_CHILD | BS_AUTOCHECKBOX | WS_TABSTOP, x, y, dx, staticDy, hwnd, (HMENU) ID_CHECKBOX_PDF_PREVIEWER, GetModuleHandle(nullptr), nullptr); SetWindowFont(gHwndCheckboxRegisterPdfPreviewer, gFontDefault, TRUE); Button_SetCheck(gHwndCheckboxRegisterPdfPreviewer, gGlobalData.installPdfPreviewer || IsPdfPreviewerInstalled()); y -= staticDy; gHwndCheckboxRegisterPdfFilter = CreateWindowEx( 0, WC_BUTTON, _TR("Let Windows Desktop Search &search PDF documents"), WS_CHILD | BS_AUTOCHECKBOX | WS_TABSTOP, x, y, dx, staticDy, hwnd, (HMENU) ID_CHECKBOX_PDF_FILTER, GetModuleHandle(nullptr), nullptr); SetWindowFont(gHwndCheckboxRegisterPdfFilter, gFontDefault, TRUE); Button_SetCheck(gHwndCheckboxRegisterPdfFilter, gGlobalData.installPdfFilter || IsPdfFilterInstalled()); y -= staticDy; } // only show the checbox if Sumatra is not already a default viewer. // the alternative (disabling the checkbox) is more confusing if (!isSumatraDefaultViewer) { gHwndCheckboxRegisterDefault = CreateWindowExW( 0, WC_BUTTON, _TR("Use SumatraPDF as the &default PDF reader"), WS_CHILD | BS_AUTOCHECKBOX | WS_TABSTOP, x, y, dx, staticDy, hwnd, (HMENU) ID_CHECKBOX_MAKE_DEFAULT, GetModuleHandle(nullptr), nullptr); SetWindowFont(gHwndCheckboxRegisterDefault, gFontDefault, TRUE); // only check the "Use as default" checkbox when no other PDF viewer // is currently selected (not going to intrude) Button_SetCheck(gHwndCheckboxRegisterDefault, !hasOtherViewer || gGlobalData.registerAsDefault); y -= staticDy; } // a bit more space between text box and checkboxes y -= (dpiAdjust(4) + WINDOW_MARGIN); const WCHAR *s = _TR("&..."); SizeI btnSize2 = TextSizeInHwnd(hwnd, s); btnSize.cx += dpiAdjust(4); gHwndButtonBrowseDir = CreateButton(hwnd, s, ID_BUTTON_BROWSE, BS_PUSHBUTTON, btnSize); x = r.dx - WINDOW_MARGIN - btnSize2.dx; SetWindowPos(gHwndButtonBrowseDir, nullptr, x, y, btnSize2.dx, staticDy, SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_FRAMECHANGED); x = WINDOW_MARGIN; dx = r.dx - (2 * WINDOW_MARGIN) - btnSize2.dx - dpiAdjust(4); gHwndTextboxInstDir = CreateWindowExW(0, WC_EDIT, gGlobalData.installDir, WS_CHILD | WS_TABSTOP | WS_BORDER | ES_LEFT | ES_AUTOHSCROLL, x, y, dx, staticDy, hwnd, nullptr, GetModuleHandle(nullptr), nullptr); SetWindowFont(gHwndTextboxInstDir, gFontDefault, TRUE); y -= staticDy; gHwndStaticInstDir = CreateWindowExW( 0, WC_STATIC, _TR("Install SumatraPDF in &folder:"),WS_CHILD, x, y, r.dx, staticDy, hwnd, nullptr, GetModuleHandle(nullptr), nullptr); SetWindowFont(gHwndStaticInstDir, gFontDefault, TRUE); gShowOptions = !gShowOptions; OnButtonOptions(); SetFocus(gHwndButtonInstUninst); if (gGlobalData.autoUpdate) { // click the Install button PostMessage(hwnd, WM_COMMAND, IDOK, 0); } }
static void CreateButtonRunSumatra(HWND hwndParent) { gHwndButtonRunSumatra = CreateDefaultButton(hwndParent, _TR("Start SumatraPDF"), ID_BUTTON_START_SUMATRA); }
DWORD WINAPI InstallerThread(LPVOID data) { UNUSED(data); gGlobalData.success = false; if (!CreateInstallationDirectory()) goto Error; ProgressStep(); if (!InstallCopyFiles()) goto Error; // all files have been extracted at this point if (gGlobalData.justExtractFiles) return 0; if (gGlobalData.registerAsDefault) { // need to sublaunch SumatraPDF.exe instead of replicating the code // because registration uses translated strings ScopedMem<WCHAR> installedExePath(GetInstalledExePath()); CreateProcessHelper(installedExePath, L"-register-for-pdf"); } if (gGlobalData.installPdfFilter) InstallPdfFilter(); else if (IsPdfFilterInstalled()) UninstallPdfFilter(); if (gGlobalData.installPdfPreviewer) InstallPdfPreviewer(); else if (IsPdfPreviewerInstalled()) UninstallPdfPreviewer(); if (!gGlobalData.keepBrowserPlugin) UninstallBrowserPlugin(); if (!CreateAppShortcut(true) && !CreateAppShortcut(false)) { NotifyFailed(_TR("Failed to create a shortcut")); goto Error; } // consider installation a success from here on // (still warn, if we've failed to create the uninstaller, though) gGlobalData.success = true; if (!WriteUninstallerRegistryInfo(HKEY_LOCAL_MACHINE) && !WriteUninstallerRegistryInfo(HKEY_CURRENT_USER)) { NotifyFailed(_TR("Failed to write the uninstallation information to the registry")); } if (!WriteExtendedFileExtensionInfo(HKEY_LOCAL_MACHINE) && !WriteExtendedFileExtensionInfo(HKEY_CURRENT_USER)) { NotifyFailed(_TR("Failed to write the extended file extension information to the registry")); } ProgressStep(); Error: // TODO: roll back installation on failure (restore previous installation!) if (gHwndFrame && !gGlobalData.silent) { Sleep(500); // allow a glimpse of the completed progress bar before hiding it PostMessage(gHwndFrame, WM_APP_INSTALLATION_FINISHED, 0, 0); } return 0; }
bool PrintFile(const WCHAR *fileName, const WCHAR *printerName, bool displayErrors, const WCHAR *settings) { if (!HasPermission(Perm_PrinterAccess)) return false; ScopedMem<WCHAR> fileName2(path::Normalize(fileName)); BaseEngine *engine = EngineManager::CreateEngine(!gUseEbookUI, fileName2); if (!engine || !engine->IsPrintingAllowed()) { if (displayErrors) MessageBox(NULL, _TR("Cannot print this file"), _TR("Printing problem."), MB_ICONEXCLAMATION | MB_OK | (IsUIRightToLeft() ? MB_RTLREADING : 0)); return false; } HANDLE printer; bool ok = OpenPrinter((WCHAR *)printerName, &printer, NULL); if (!ok) { if (displayErrors) MessageBox(NULL, _TR("Printer with given name doesn't exist"), _TR("Printing problem."), MB_ICONEXCLAMATION | MB_OK | (IsUIRightToLeft() ? MB_RTLREADING : 0)); return false; } // get printer driver information DWORD needed = 0; GetPrinter(printer, 2, NULL, 0, &needed); ScopedMem<PRINTER_INFO_2> infoData((PRINTER_INFO_2 *)AllocArray<BYTE>(needed)); if (infoData) ok = GetPrinter(printer, 2, (LPBYTE)infoData.Get(), needed, &needed); if (!ok || !infoData || needed <= sizeof(PRINTER_INFO_2)) goto Exit; LONG structSize = DocumentProperties(NULL, printer, /* Handle to our printer. */ (WCHAR *)printerName, /* Name of the printer. */ NULL, /* Asking for size, so */ NULL, /* these are not used. */ 0); /* Zero returns buffer size. */ if (structSize < sizeof(DEVMODE)) { // If failure, inform the user, cleanup and return failure. if (displayErrors) MessageBox(NULL, _TR("Could not obtain Printer properties"), _TR("Printing problem."), MB_ICONEXCLAMATION | MB_OK | (IsUIRightToLeft() ? MB_RTLREADING : 0)); goto Exit; } LPDEVMODE devMode = (LPDEVMODE)malloc(structSize); if (!devMode) goto Exit; // Get the default DevMode for the printer and modify it for your needs. LONG returnCode = DocumentProperties(NULL, printer, (WCHAR *)printerName, devMode, /* The address of the buffer to fill. */ NULL, /* Not using the input buffer. */ DM_OUT_BUFFER); /* Have the output buffer filled. */ if (IDOK != returnCode) { // If failure, inform the user, cleanup and return failure. if (displayErrors) MessageBox(NULL, _TR("Could not obtain Printer properties"), _TR("Printing problem."), MB_ICONEXCLAMATION | MB_OK | (IsUIRightToLeft() ? MB_RTLREADING : 0)); goto Exit; } ClosePrinter(printer); printer = NULL; { Print_Advanced_Data advanced; Vec<PRINTPAGERANGE> ranges; ApplyPrintSettings(settings, engine->PageCount(), ranges, advanced); PrintData pd(engine, infoData, devMode, ranges, advanced); ok = PrintToDevice(pd); if (!ok && displayErrors) MessageBox(NULL, _TR("Couldn't initialize printer"), _TR("Printing problem."), MB_ICONEXCLAMATION | MB_OK | (IsUIRightToLeft() ? MB_RTLREADING : 0)); } Exit: free(devMode); if (printer) ClosePrinter(printer); delete engine; return ok; }
// TODO: since we have a variable UI, for better layout (anchored to the bottom, // not the top), we should layout controls starting at the bottom and go up void OnCreateWindow(HWND hwnd) { // TODO: this button might be too narrow for some translations gHwndButtonInstUninst = CreateDefaultButton(hwnd, _TR("Install SumatraPDF"), 140); RectI rc(WINDOW_MARGIN, 0, dpiAdjust(96), PUSH_BUTTON_DY); ClientRect r(hwnd); rc.y = r.dy - rc.dy - WINDOW_MARGIN; gHwndButtonOptions = CreateWindow(WC_BUTTON, _TR("&Options"), BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, rc.x, rc.y, rc.dx, rc.dy, hwnd, (HMENU)ID_BUTTON_OPTIONS, ghinst, NULL); SetWindowFont(gHwndButtonOptions, gFontDefault, TRUE); int staticDy = dpiAdjust(20); rc.y = TITLE_PART_DY + WINDOW_MARGIN; gHwndStaticInstDir = CreateWindow(WC_STATIC, _TR("Install SumatraPDF in &folder:"), WS_CHILD, rc.x, rc.y, r.dx - 2 * rc.x, staticDy, hwnd, NULL, ghinst, NULL); SetWindowFont(gHwndStaticInstDir, gFontDefault, TRUE); rc.y += staticDy; gHwndTextboxInstDir = CreateWindow(WC_EDIT, gGlobalData.installDir, WS_CHILD | WS_TABSTOP | WS_BORDER | ES_LEFT | ES_AUTOHSCROLL, rc.x, rc.y, r.dx - 3 * rc.x - staticDy, staticDy, hwnd, NULL, ghinst, NULL); SetWindowFont(gHwndTextboxInstDir, gFontDefault, TRUE); gHwndButtonBrowseDir = CreateWindow(WC_BUTTON, L"&...", BS_PUSHBUTTON | WS_CHILD | WS_TABSTOP, r.dx - rc.x - staticDy, rc.y, staticDy, staticDy, hwnd, (HMENU)ID_BUTTON_BROWSE, ghinst, NULL); SetWindowFont(gHwndButtonBrowseDir, gFontDefault, TRUE); rc.y += 2 * staticDy; ScopedMem<WCHAR> defaultViewer(GetDefaultPdfViewer()); BOOL hasOtherViewer = !str::EqI(defaultViewer, APP_NAME_STR); BOOL isSumatraDefaultViewer = defaultViewer && !hasOtherViewer; // only show the checbox if Sumatra is not already a default viewer. // the alternative (disabling the checkbox) is more confusing if (!isSumatraDefaultViewer) { gHwndCheckboxRegisterDefault = CreateWindow( WC_BUTTON, _TR("Use SumatraPDF as the &default PDF reader"), WS_CHILD | BS_AUTOCHECKBOX | WS_TABSTOP, rc.x, rc.y, r.dx - 2 * rc.x, staticDy, hwnd, (HMENU)ID_CHECKBOX_MAKE_DEFAULT, ghinst, NULL); SetWindowFont(gHwndCheckboxRegisterDefault, gFontDefault, TRUE); // only check the "Use as default" checkbox when no other PDF viewer // is currently selected (not going to intrude) Button_SetCheck(gHwndCheckboxRegisterDefault, !hasOtherViewer || gGlobalData.registerAsDefault); rc.y += staticDy; } gHwndCheckboxRegisterBrowserPlugin = CreateWindow( WC_BUTTON, _TR("Install PDF &browser plugin for Firefox, Chrome and Opera"), WS_CHILD | BS_AUTOCHECKBOX | WS_TABSTOP, rc.x, rc.y, r.dx - 2 * rc.x, staticDy, hwnd, (HMENU)ID_CHECKBOX_BROWSER_PLUGIN, ghinst, NULL); SetWindowFont(gHwndCheckboxRegisterBrowserPlugin, gFontDefault, TRUE); Button_SetCheck(gHwndCheckboxRegisterBrowserPlugin, gGlobalData.installBrowserPlugin || IsBrowserPluginInstalled()); rc.y += staticDy; // only show this checkbox if the CPU arch of DLL and OS match // (assuming that the installer has the same CPU arch as its content!) #ifndef _WIN64 if (!IsRunningInWow64()) #endif { gHwndCheckboxRegisterPdfFilter = CreateWindow( WC_BUTTON, _TR("Let Windows Desktop Search &search PDF documents"), WS_CHILD | BS_AUTOCHECKBOX | WS_TABSTOP, rc.x, rc.y, r.dx - 2 * rc.x, staticDy, hwnd, (HMENU)ID_CHECKBOX_PDF_FILTER, ghinst, NULL); SetWindowFont(gHwndCheckboxRegisterPdfFilter, gFontDefault, TRUE); Button_SetCheck(gHwndCheckboxRegisterPdfFilter, gGlobalData.installPdfFilter || IsPdfFilterInstalled()); rc.y += staticDy; } // for Windows XP, this means only basic thumbnail support gHwndCheckboxRegisterPdfPreviewer = CreateWindow( WC_BUTTON, _TR("Let Windows show &previews of PDF documents"), WS_CHILD | BS_AUTOCHECKBOX | WS_TABSTOP, rc.x, rc.y, r.dx - 2 * rc.x, staticDy, hwnd, (HMENU)ID_CHECKBOX_PDF_PREVIEWER, ghinst, NULL); SetWindowFont(gHwndCheckboxRegisterPdfPreviewer, gFontDefault, TRUE); Button_SetCheck(gHwndCheckboxRegisterPdfPreviewer, gGlobalData.installPdfPreviewer || IsPdfPreviewerInstalled()); rc.y += staticDy; gShowOptions = !gShowOptions; OnButtonOptions(); SetFocus(gHwndButtonInstUninst); }
static void GetProps(Doc doc, PropertiesLayout *layoutData, DisplayModel *dm, bool extended) { CrashIf(!doc.IsEngine() && !doc.IsEbook()); DocType docType = doc.GetDocType(); EngineType engineType = (docType >= Doc_BaseEngine) ? (EngineType)(docType - Doc_BaseEngine) : Engine_None; WCHAR *str = str::Dup(gPluginMode ? gPluginURL : doc.GetFilePath()); layoutData->AddProperty(_TR("File:"), str); str = doc.GetProperty(Prop_Title); layoutData->AddProperty(_TR("Title:"), str); str = doc.GetProperty(Prop_Subject); layoutData->AddProperty(_TR("Subject:"), str); str = doc.GetProperty(Prop_Author); layoutData->AddProperty(_TR("Author:"), str); str = doc.GetProperty(Prop_Copyright); layoutData->AddProperty(_TR("Copyright:"), str); str = doc.GetProperty(Prop_CreationDate); if (Engine_PDF == engineType) ConvDateToDisplay(&str, PdfDateParse); else ConvDateToDisplay(&str, IsoDateParse); layoutData->AddProperty(_TR("Created:"), str); str = doc.GetProperty(Prop_ModificationDate); if (Engine_PDF == engineType) ConvDateToDisplay(&str, PdfDateParse); else ConvDateToDisplay(&str, IsoDateParse); layoutData->AddProperty(_TR("Modified:"), str); str = doc.GetProperty(Prop_CreatorApp); layoutData->AddProperty(_TR("Application:"), str); str = doc.GetProperty(Prop_PdfProducer); layoutData->AddProperty(_TR("PDF Producer:"), str); str = doc.GetProperty(Prop_PdfVersion); layoutData->AddProperty(_TR("PDF Version:"), str); str = FormatPdfFileStructure(doc); layoutData->AddProperty(_TR("PDF Optimizations:"), str); int64 fileSize = file::GetSize(doc.GetFilePath()); if (-1 == fileSize && doc.IsEngine()) { size_t fileSizeT; if (ScopedMem<unsigned char>(doc.AsEngine()->GetFileData(&fileSizeT))) fileSize = fileSizeT; } if (-1 != fileSize) { str = FormatFileSize((size_t)fileSize); layoutData->AddProperty(_TR("File Size:"), str); } if (doc.IsEngine()) { str = str::Format(L"%d", doc.AsEngine()->PageCount()); layoutData->AddProperty(_TR("Number of Pages:"), str); } if (dm && dm->engineType != Engine_Chm) { str = FormatPageSize(dm->engine, dm->CurrentPageNo(), dm->Rotation()); if (IsUIRightToLeft() && IsVistaOrGreater()) { // ensure that the size remains ungarbled left-to-right // (note: XP doesn't know about \u202A...\u202C) str = str::Format(L"\u202A%s\u202C", ScopedMem<WCHAR>(str)); } layoutData->AddProperty(_TR("Page Size:"), str); } str = FormatPermissions(doc); layoutData->AddProperty(_TR("Denied Permissions:"), str); #if defined(DEBUG) || defined(ENABLE_EXTENDED_PROPERTIES) if (extended) { // TODO: FontList extraction can take a while str = doc.GetProperty(Prop_FontList); if (str) { // add a space between basic and extended file properties layoutData->AddProperty(L" ", str::Dup(L" ")); } layoutData->AddProperty(_TR("Fonts:"), str); } #endif }
static INT_PTR CALLBACK Dialog_Settings_Proc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { GlobalPrefs *prefs; switch (msg) { //[ ACCESSKEY_GROUP Settings Dialog case WM_INITDIALOG: prefs = (GlobalPrefs *)lParam; assert(prefs); SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)prefs); // Fill the page layouts into the select box SendDlgItemMessage(hDlg, IDC_DEFAULT_LAYOUT, CB_ADDSTRING, 0, (LPARAM)_TR("Automatic")); SendDlgItemMessage(hDlg, IDC_DEFAULT_LAYOUT, CB_ADDSTRING, 0, (LPARAM)_TR("Single Page")); SendDlgItemMessage(hDlg, IDC_DEFAULT_LAYOUT, CB_ADDSTRING, 0, (LPARAM)_TR("Facing")); SendDlgItemMessage(hDlg, IDC_DEFAULT_LAYOUT, CB_ADDSTRING, 0, (LPARAM)_TR("Book View")); SendDlgItemMessage(hDlg, IDC_DEFAULT_LAYOUT, CB_ADDSTRING, 0, (LPARAM)_TR("Continuous")); SendDlgItemMessage(hDlg, IDC_DEFAULT_LAYOUT, CB_ADDSTRING, 0, (LPARAM)_TR("Continuous Facing")); SendDlgItemMessage(hDlg, IDC_DEFAULT_LAYOUT, CB_ADDSTRING, 0, (LPARAM)_TR("Continuous Book View")); SendDlgItemMessage(hDlg, IDC_DEFAULT_LAYOUT, CB_SETCURSEL, prefs->defaultDisplayModeEnum - DM_FIRST, 0); SetupZoomComboBox(hDlg, IDC_DEFAULT_ZOOM, false, prefs->defaultZoomFloat); CheckDlgButton(hDlg, IDC_DEFAULT_SHOW_TOC, prefs->showToc ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hDlg, IDC_REMEMBER_STATE_PER_DOCUMENT, prefs->rememberStatePerDocument ? BST_CHECKED : BST_UNCHECKED); EnableWindow(GetDlgItem(hDlg, IDC_REMEMBER_STATE_PER_DOCUMENT), prefs->rememberOpenedFiles); CheckDlgButton(hDlg, IDC_USE_TABS, prefs->useTabs? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hDlg, IDC_CHECK_FOR_UPDATES, prefs->checkForUpdates ? BST_CHECKED : BST_UNCHECKED); EnableWindow(GetDlgItem(hDlg, IDC_CHECK_FOR_UPDATES), HasPermission(Perm_InternetAccess)); CheckDlgButton(hDlg, IDC_REMEMBER_OPENED_FILES, prefs->rememberOpenedFiles ? BST_CHECKED : BST_UNCHECKED); if (IsExeAssociatedWithPdfExtension()) { SetDlgItemText(hDlg, IDC_SET_DEFAULT_READER, _TR("SumatraPDF is your default PDF reader")); EnableWindow(GetDlgItem(hDlg, IDC_SET_DEFAULT_READER), FALSE); } else if (IsRunningInPortableMode()) { SetDlgItemText(hDlg, IDC_SET_DEFAULT_READER, _TR("Default PDF reader can't be changed in portable mode")); EnableWindow(GetDlgItem(hDlg, IDC_SET_DEFAULT_READER), FALSE); } else { SetDlgItemText(hDlg, IDC_SET_DEFAULT_READER, _TR("Make SumatraPDF my default PDF reader")); EnableWindow(GetDlgItem(hDlg, IDC_SET_DEFAULT_READER), HasPermission(Perm_RegistryAccess)); } win::SetText(hDlg, _TR("SumatraPDF Options")); SetDlgItemText(hDlg, IDC_SECTION_VIEW, _TR("View")); SetDlgItemText(hDlg, IDC_DEFAULT_LAYOUT_LABEL, _TR("Default &Layout:")); SetDlgItemText(hDlg, IDC_DEFAULT_ZOOM_LABEL, _TR("Default &Zoom:")); SetDlgItemText(hDlg, IDC_DEFAULT_SHOW_TOC, _TR("Show the &bookmarks sidebar when available")); SetDlgItemText(hDlg, IDC_REMEMBER_STATE_PER_DOCUMENT, _TR("&Remember these settings for each document")); SetDlgItemText(hDlg, IDC_SECTION_ADVANCED, _TR("Advanced")); SetDlgItemText(hDlg, IDC_USE_TABS, _TR("Use &tabs")); SetDlgItemText(hDlg, IDC_CHECK_FOR_UPDATES, _TR("Automatically check for &updates")); SetDlgItemText(hDlg, IDC_REMEMBER_OPENED_FILES, _TR("Remember &opened files")); SetDlgItemText(hDlg, IDC_SECTION_INVERSESEARCH, _TR("Set inverse search command-line")); SetDlgItemText(hDlg, IDC_CMDLINE_LABEL, _TR("Enter the command-line to invoke when you double-click on the PDF document:")); SetDlgItemText(hDlg, IDOK, _TR("OK")); SetDlgItemText(hDlg, IDCANCEL, _TR("Cancel")); if (prefs->enableTeXEnhancements && HasPermission(Perm_DiskAccess)) { // Fill the combo with the list of possible inverse search commands // Try to select a correct default when first showing this dialog const WCHAR *cmdLine = prefs->inverseSearchCmdLine; ScopedMem<WCHAR> inverseSearch; if (!cmdLine) { inverseSearch.Set(AutoDetectInverseSearchCommands(GetDlgItem(hDlg, IDC_CMDLINE))); cmdLine = inverseSearch; } // Find the index of the active command line LRESULT ind = SendMessage(GetDlgItem(hDlg, IDC_CMDLINE), CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM) cmdLine); if (CB_ERR == ind) { // if no existing command was selected then set the user custom command in the combo ComboBox_AddItemData(GetDlgItem(hDlg, IDC_CMDLINE), cmdLine); SetDlgItemText(hDlg, IDC_CMDLINE, cmdLine); } else { // select the active command SendMessage(GetDlgItem(hDlg, IDC_CMDLINE), CB_SETCURSEL, (WPARAM) ind , 0); } } else { RemoveDialogItem(hDlg, IDC_SECTION_INVERSESEARCH, IDC_SECTION_ADVANCED); } CenterDialog(hDlg); SetFocus(GetDlgItem(hDlg, IDC_DEFAULT_LAYOUT)); return FALSE; //] ACCESSKEY_GROUP Settings Dialog case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: prefs = (GlobalPrefs *)GetWindowLongPtr(hDlg, GWLP_USERDATA); assert(prefs); prefs->defaultDisplayModeEnum = (DisplayMode)(SendDlgItemMessage(hDlg, IDC_DEFAULT_LAYOUT, CB_GETCURSEL, 0, 0) + DM_FIRST); prefs->defaultZoomFloat = GetZoomComboBoxValue(hDlg, IDC_DEFAULT_ZOOM, false, prefs->defaultZoomFloat); prefs->showToc = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_DEFAULT_SHOW_TOC)); prefs->rememberStatePerDocument = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_REMEMBER_STATE_PER_DOCUMENT)); prefs->useTabs = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_USE_TABS)); prefs->checkForUpdates = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_CHECK_FOR_UPDATES)); prefs->rememberOpenedFiles = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_REMEMBER_OPENED_FILES)); if (prefs->enableTeXEnhancements && HasPermission(Perm_DiskAccess)) { free(prefs->inverseSearchCmdLine); prefs->inverseSearchCmdLine = win::GetText(GetDlgItem(hDlg, IDC_CMDLINE)); } EndDialog(hDlg, IDOK); return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; case IDC_REMEMBER_OPENED_FILES: { bool rememberOpenedFiles = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_REMEMBER_OPENED_FILES)); EnableWindow(GetDlgItem(hDlg, IDC_REMEMBER_STATE_PER_DOCUMENT), rememberOpenedFiles); } return TRUE; case IDC_DEFAULT_SHOW_TOC: case IDC_REMEMBER_STATE_PER_DOCUMENT: case IDC_CHECK_FOR_UPDATES: return TRUE; case IDC_SET_DEFAULT_READER: if (!HasPermission(Perm_RegistryAccess)) return TRUE; AssociateExeWithPdfExtension(); if (IsExeAssociatedWithPdfExtension()) { SetDlgItemText(hDlg, IDC_SET_DEFAULT_READER, _TR("SumatraPDF is your default PDF reader")); EnableWindow(GetDlgItem(hDlg, IDC_SET_DEFAULT_READER), FALSE); SendMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hDlg, IDOK), TRUE); } else { SetDlgItemText(hDlg, IDC_SET_DEFAULT_READER, _TR("SumatraPDF should now be your default PDF reader")); } return TRUE; } break; } return FALSE; }
// returns true if the double-click was handled and false if it wasn't bool OnInverseSearch(WindowInfo *win, int x, int y) { if (!HasPermission(Perm_DiskAccess) || gPluginMode) return false; if (!win->IsDocLoaded() || win->dm->engineType != Engine_PDF) return false; // Clear the last forward-search result win->fwdSearchMark.rects.Reset(); InvalidateRect(win->hwndCanvas, NULL, FALSE); // On double-clicking error message will be shown to the user // if the PDF does not have a synchronization file if (!win->pdfsync) { int err = Synchronizer::Create(win->loadedFilePath, static_cast<PdfEngine *>(win->dm->engine), &win->pdfsync); if (err == PDFSYNCERR_SYNCFILE_NOTFOUND) { // We used to warn that "No synchronization file found" at this // point if gGlobalPrefs.enableTeXEnhancements is set; we no longer // so do because a double-click has several other meanings // (selecting a word or an image, navigating quickly using links) // and showing an unrelated warning in all those cases seems wrong return false; } if (err != PDFSYNCERR_SUCCESS) { ShowNotification(win, _TR("Synchronization file cannot be opened")); return true; } gGlobalPrefs.enableTeXEnhancements = true; } int pageNo = win->dm->GetPageNoByPoint(PointI(x, y)); if (!win->dm->ValidPageNo(pageNo)) return false; PointI pt = win->dm->CvtFromScreen(PointI(x, y), pageNo).Convert<int>(); ScopedMem<WCHAR> srcfilepath; UINT line, col; int err = win->pdfsync->DocToSource(pageNo, pt, srcfilepath, &line, &col); if (err != PDFSYNCERR_SUCCESS) { ShowNotification(win, _TR("No synchronization info at this position")); return true; } WCHAR *inverseSearch = gGlobalPrefs.inverseSearchCmdLine; if (!inverseSearch) // Detect a text editor and use it as the default inverse search handler for now inverseSearch = AutoDetectInverseSearchCommands(); ScopedMem<WCHAR> cmdline; if (inverseSearch) cmdline.Set(win->pdfsync->PrepareCommandline(inverseSearch, srcfilepath, line, col)); if (!str::IsEmpty(cmdline.Get())) { // resolve relative paths with relation to SumatraPDF.exe's directory ScopedMem<WCHAR> appDir(GetExePath()); if (appDir) appDir.Set(path::GetDir(appDir)); ScopedHandle process(LaunchProcess(cmdline, appDir)); if (!process) ShowNotification(win, _TR("Cannot start inverse search command. Please check the command line in the settings.")); } else if (gGlobalPrefs.enableTeXEnhancements) ShowNotification(win, _TR("Cannot start inverse search command. Please check the command line in the settings.")); if (inverseSearch != gGlobalPrefs.inverseSearchCmdLine) free(inverseSearch); return true; }
void LinkHandler::LaunchFile(const WCHAR *path, PageDestination *link) { // for safety, only handle relative paths and only open them in SumatraPDF // (unless they're of an allowed perceived type) and never launch any external // file in plugin mode (where documents are supposed to be self-contained) WCHAR drive; if (str::StartsWith(path, L"\\") || str::Parse(path, L"%c:\\", &drive) || gPluginMode) { return; } // TODO: link is deleted when opening the document in a new tab RemoteDestination *remoteLink = nullptr; if (link) { remoteLink = new RemoteDestination(link); link = nullptr; } ScopedMem<WCHAR> fullPath(path::GetDir(owner->ctrl->FilePath())); fullPath.Set(path::Join(fullPath, path)); fullPath.Set(path::Normalize(fullPath)); // TODO: respect link->ld.gotor.new_window for PDF documents ? WindowInfo *newWin = FindWindowInfoByFile(fullPath, true); // TODO: don't show window until it's certain that there was no error if (!newWin) { LoadArgs args(fullPath, owner); newWin = LoadDocument(args); if (!newWin) { delete remoteLink; return; } } if (!newWin->IsDocLoaded()) { CloseTab(newWin); // OpenFileExternally rejects files we'd otherwise // have to show a notification to be sure (which we // consider bad UI and thus simply don't) bool ok = OpenFileExternally(fullPath); if (!ok) { ScopedMem<WCHAR> msg(str::Format(_TR("Error loading %s"), fullPath)); owner->ShowNotification(msg, NOS_HIGHLIGHT); } delete remoteLink; return; } newWin->Focus(); if (!remoteLink) return; ScopedMem<WCHAR> destName(remoteLink->GetDestName()); if (destName) { PageDestination *dest = newWin->ctrl->GetNamedDest(destName); if (dest) { newWin->linkHandler->ScrollTo(dest); delete dest; } } else { newWin->linkHandler->ScrollTo(remoteLink); } delete remoteLink; }
bool PrintFile(const WCHAR *fileName, WCHAR *printerName, bool displayErrors, const WCHAR *settings) { bool ok = false; if (!HasPermission(Perm_PrinterAccess)) return false; ScopedMem<WCHAR> fileName2(path::Normalize(fileName)); BaseEngine *engine = EngineManager::CreateEngine(fileName2, true /* prefer Chm2Engine */); #ifndef DISABLE_DOCUMENT_RESTRICTIONS if (engine && !engine->AllowsPrinting()) { delete engine; engine = NULL; } #endif if (!engine) { if (displayErrors) MessageBoxWarning(NULL, _TR("Cannot print this file"), _TR("Printing problem.")); return false; } HANDLE printer; BOOL res = OpenPrinter(printerName, &printer, NULL); if (0 == res) { if (displayErrors) MessageBoxWarning(NULL, _TR("Printer with given name doesn't exist"), _TR("Printing problem.")); return false; } LPDEVMODE devMode = NULL; // get printer driver information DWORD needed = 0; GetPrinter(printer, 2, NULL, 0, &needed); ScopedMem<PRINTER_INFO_2> infoData((PRINTER_INFO_2 *)AllocArray<BYTE>(needed)); if (infoData) res = GetPrinter(printer, 2, (LPBYTE)infoData.Get(), needed, &needed); if ((0 == res) || !infoData || needed <= sizeof(PRINTER_INFO_2)) goto Exit; LONG structSize = DocumentProperties(NULL, printer, printerName, NULL, /* Asking for size, so */ NULL, /* not used. */ 0); /* Zero returns buffer size. */ if (structSize < sizeof(DEVMODE)) { // If failure, inform the user, cleanup and return failure. if (displayErrors) MessageBoxWarning(NULL, _TR("Could not obtain Printer properties"), _TR("Printing problem.")); goto Exit; } devMode = (LPDEVMODE)malloc(structSize); if (!devMode) goto Exit; // Get the default DevMode for the printer and modify it for your needs. LONG returnCode = DocumentProperties(NULL, printer, printerName, devMode, /* The address of the buffer to fill. */ NULL, /* Not using the input buffer. */ DM_OUT_BUFFER); /* Have the output buffer filled. */ if (IDOK != returnCode) { // If failure, inform the user, cleanup and return failure. if (displayErrors) MessageBoxWarning(NULL, _TR("Could not obtain Printer properties"), _TR("Printing problem.")); goto Exit; } ClosePrinter(printer); printer = NULL; { Print_Advanced_Data advanced; Vec<PRINTPAGERANGE> ranges; ApplyPrintSettings(settings, engine->PageCount(), ranges, advanced, devMode); PrintData pd(engine, infoData, devMode, ranges, advanced); ok = PrintToDevice(pd); if (!ok && displayErrors) MessageBoxWarning(NULL, _TR("Couldn't initialize printer"), _TR("Printing problem.")); } Exit: free(devMode); if (printer) ClosePrinter(printer); delete engine; return ok; }
void OnCreateWindow(HWND hwnd) { gHwndButtonInstUninst = CreateDefaultButton(hwnd, _TR("Uninstall SumatraPDF"), IDOK); }
PrintThreadData(WindowInfo *win, PrintData *data) : win(win), data(data), isCanceled(false), thread(NULL) { wnd = new NotificationWnd(win->hwndCanvas, L"", _TR("Printing page %d of %d..."), this); win->notifications->Add(wnd); }
void OnMenuPrint(WindowInfo *win, bool waitForCompletion) { // we remember some printer settings per process static ScopedMem<DEVMODE> defaultDevMode; static PrintScaleAdv defaultScaleAdv = PrintScaleShrink; static bool defaultAsImage = false; bool printSelection = false; Vec<PRINTPAGERANGE> ranges; PRINTER_INFO_2 printerInfo = { 0 }; if (!HasPermission(Perm_PrinterAccess)) return; DisplayModel *dm = win->dm; assert(dm); if (!dm) return; if (!dm->engine || !dm->engine->AllowsPrinting()) return; if (win->IsChm()) { win->dm->AsChmEngine()->PrintCurrentPage(); return; } if (win->printThread) { int res = MessageBox(win->hwndFrame, _TR("Printing is still in progress. Abort and start over?"), _TR("Printing in progress."), MB_ICONEXCLAMATION | MB_YESNO | (IsUIRightToLeft() ? MB_RTLREADING : 0)); if (res == IDNO) return; } AbortPrinting(win); PRINTDLGEX pd; ZeroMemory(&pd, sizeof(PRINTDLGEX)); pd.lStructSize = sizeof(PRINTDLGEX); pd.hwndOwner = win->hwndFrame; pd.Flags = PD_USEDEVMODECOPIESANDCOLLATE | PD_COLLATE; if (!win->selectionOnPage) pd.Flags |= PD_NOSELECTION; pd.nCopies = 1; /* by default print all pages */ pd.nPageRanges = 1; pd.nMaxPageRanges = MAXPAGERANGES; PRINTPAGERANGE *ppr = AllocArray<PRINTPAGERANGE>(MAXPAGERANGES); pd.lpPageRanges = ppr; ppr->nFromPage = 1; ppr->nToPage = dm->PageCount(); pd.nMinPage = 1; pd.nMaxPage = dm->PageCount(); pd.nStartPage = START_PAGE_GENERAL; Print_Advanced_Data advanced(PrintRangeAll, defaultScaleAdv, defaultAsImage); ScopedMem<DLGTEMPLATE> dlgTemplate; // needed for RTL languages HPROPSHEETPAGE hPsp = CreatePrintAdvancedPropSheet(&advanced, dlgTemplate); pd.lphPropertyPages = &hPsp; pd.nPropertyPages = 1; // restore remembered settings if (defaultDevMode) pd.hDevMode = GlobalMemDup(defaultDevMode.Get(), defaultDevMode.Get()->dmSize + defaultDevMode.Get()->dmDriverExtra); if (PrintDlgEx(&pd) != S_OK) { if (CommDlgExtendedError() != 0) { /* if PrintDlg was cancelled then CommDlgExtendedError is zero, otherwise it returns the error code, which we could look at here if we wanted. for now just warn the user that printing has stopped becasue of an error */ MessageBox(win->hwndFrame, _TR("Couldn't initialize printer"), _TR("Printing problem."), MB_ICONEXCLAMATION | MB_OK | (IsUIRightToLeft() ? MB_RTLREADING : 0)); } goto Exit; } if (pd.dwResultAction == PD_RESULT_PRINT || pd.dwResultAction == PD_RESULT_APPLY) { // remember settings for this process LPDEVMODE devMode = (LPDEVMODE)GlobalLock(pd.hDevMode); if (devMode) { defaultDevMode.Set((LPDEVMODE)memdup(devMode, devMode->dmSize + devMode->dmDriverExtra)); GlobalUnlock(pd.hDevMode); } defaultScaleAdv = advanced.scale; defaultAsImage = advanced.asImage; } if (pd.dwResultAction != PD_RESULT_PRINT) goto Exit; if (pd.Flags & PD_CURRENTPAGE) { PRINTPAGERANGE pr = { dm->CurrentPageNo(), dm->CurrentPageNo() }; ranges.Append(pr); } else if (win->selectionOnPage && (pd.Flags & PD_SELECTION)) { printSelection = true; } else if (!(pd.Flags & PD_PAGENUMS)) { PRINTPAGERANGE pr = { 1, dm->PageCount() }; ranges.Append(pr); } else { assert(pd.nPageRanges > 0); for (DWORD i = 0; i < pd.nPageRanges; i++) ranges.Append(pd.lpPageRanges[i]); } LPDEVNAMES devNames = (LPDEVNAMES)GlobalLock(pd.hDevNames); LPDEVMODE devMode = (LPDEVMODE)GlobalLock(pd.hDevMode); if (devNames) { printerInfo.pDriverName = (LPWSTR)devNames + devNames->wDriverOffset; printerInfo.pPrinterName = (LPWSTR)devNames + devNames->wDeviceOffset; printerInfo.pPortName = (LPWSTR)devNames + devNames->wOutputOffset; } PrintData *data = new PrintData(dm->engine, &printerInfo, devMode, ranges, advanced, dm->Rotation(), printSelection ? win->selectionOnPage : NULL); if (devNames) GlobalUnlock(pd.hDevNames); if (devMode) GlobalUnlock(pd.hDevMode); // if a file is missing and the engine can't thus be cloned, // we print using the original engine on the main thread // so that the document can't be closed and the original engine // unexpectedly deleted // TODO: instead prevent closing the document so that printing // can still happen on a separate thread and be interruptible bool failedEngineClone = dm->engine && !data->engine; if (failedEngineClone) data->engine = dm->engine; if (!waitForCompletion && !failedEngineClone) PrintToDeviceOnThread(win, data); else { PrintToDevice(*data); if (failedEngineClone) data->engine = NULL; delete data; } Exit: free(ppr); GlobalFree(pd.hDevNames); GlobalFree(pd.hDevMode); }
LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) { NPP instance = (NPP)GetWindowLongPtr(hWnd, GWLP_USERDATA); if (uiMsg == WM_PAINT) { InstanceData *data = (InstanceData *)instance->pdata; PAINTSTRUCT ps; HDC hDC = BeginPaint(hWnd, &ps); HBRUSH brushBg = CreateSolidBrush(COL_WINDOW_BG); HFONT hFont = GetSimpleFont(hDC, L"MS Shell Dlg", 14); bool isRtL = IsLanguageRtL(gTranslationIdx); // set up double buffering RectI rcClient = ClientRect(hWnd); DoubleBuffer buffer(hWnd, rcClient); HDC hDCBuffer = buffer.GetDC(); // display message centered in the window FillRect(hDCBuffer, &rcClient.ToRECT(), brushBg); hFont = (HFONT)SelectObject(hDCBuffer, hFont); SetTextColor(hDCBuffer, RGB(0, 0, 0)); SetBkMode(hDCBuffer, TRANSPARENT); DrawCenteredText(hDCBuffer, rcClient, data->message, isRtL); // draw a progress bar, if a download is in progress if (0 < data->progress && data->progress <= 1) { SIZE msgSize; RectI rcProgress = rcClient; HBRUSH brushProgress = CreateSolidBrush(RGB(0x80, 0x80, 0xff)); GetTextExtentPoint32(hDCBuffer, data->message, (int)str::Len(data->message), &msgSize); rcProgress.Inflate(-(rcProgress.dx - msgSize.cx) / 2, -(rcProgress.dy - msgSize.cy) / 2 + 2); rcProgress.Offset(0, msgSize.cy + 4 + 2); FillRect(hDCBuffer, &rcProgress.ToRECT(), GetStockBrush(WHITE_BRUSH)); RectI rcProgressAll = rcProgress; rcProgress.dx = (int)(data->progress * rcProgress.dx); FillRect(hDCBuffer, &rcProgress.ToRECT(), brushProgress); DeleteObject(brushProgress); ScopedMem<WCHAR> currSize(FormatSizeSuccint(data->currSize)); if (0 == data->totalSize || data->currSize > data->totalSize) { // total size unknown or bogus => show just the current size DrawCenteredText(hDCBuffer, rcProgressAll, currSize, isRtL); } else { ScopedMem<WCHAR> totalSize(FormatSizeSuccint(data->totalSize)); ScopedMem<WCHAR> s(str::Format(_TR("%s of %s"), currSize, totalSize)); DrawCenteredText(hDCBuffer, rcProgressAll, s, isRtL); } } // draw the buffer on screen buffer.Flush(hDC); DeleteObject(SelectObject(hDCBuffer, hFont)); DeleteObject(brushBg); EndPaint(hWnd, &ps); HWND hChild = FindWindowEx(hWnd, NULL, NULL, NULL); if (hChild) InvalidateRect(hChild, NULL, FALSE); } else if (uiMsg == WM_SIZE) { HWND hChild = FindWindowEx(hWnd, NULL, NULL, NULL); if (hChild) { ClientRect rcClient(hWnd); MoveWindow(hChild, rcClient.x, rcClient.y, rcClient.dx, rcClient.dy, FALSE); } } else if (uiMsg == WM_COPYDATA) { COPYDATASTRUCT *cds = (COPYDATASTRUCT *)lParam; if (cds && 0x4C5255 /* URL */ == cds->dwData) { plogf("sp: NPN_GetURL %s", cds->dwData, (const char *)cds->lpData); gNPNFuncs.geturl(instance, (const char *)cds->lpData, "_blank"); return TRUE; } } return DefWindowProc(hWnd, uiMsg, wParam, lParam); }
void OnCreateWindow(HWND hwnd) { // TODO: this button might be too narrow for some translations gHwndButtonInstUninst = CreateDefaultButton(hwnd, _TR("Uninstall SumatraPDF"), 150); }
void OnMenuPrint(WindowInfo *win, bool waitForCompletion) { // we remember some printer settings per process static ScopedMem<DEVMODE> defaultDevMode; static PrintScaleAdv defaultScaleAdv = PrintScaleShrink; static bool hasDefaults = false; if (!hasDefaults) { hasDefaults = true; if (str::EqI(gGlobalPrefs->printerDefaults.printScale, "fit")) defaultScaleAdv = PrintScaleFit; else if (str::EqI(gGlobalPrefs->printerDefaults.printScale, "none")) defaultScaleAdv = PrintScaleNone; } bool printSelection = false; Vec<PRINTPAGERANGE> ranges; PRINTER_INFO_2 printerInfo = { 0 }; //if (!HasPermission(Perm_PrinterAccess)) // return; if (!win->IsDocLoaded()) return; if (win->AsChm()) { // the Print dialog allows access to the file system, so fall back // to printing the entire document without dialog if that isn't desired bool showUI = HasPermission(Perm_DiskAccess); win->AsChm()->PrintCurrentPage(showUI); return; } if (win->AsEbook()) { // TODO: use EbookEngine for printing? return; } CrashIf(!win->AsFixed()); if (!win->AsFixed()) return; DisplayModel *dm = win->AsFixed(); #ifndef DISABLE_DOCUMENT_RESTRICTIONS if (!dm->GetEngine()->AllowsPrinting()) return; #endif if (win->printThread) { int res = MessageBox( win->hwndFrame, _TR("Printing is still in progress. Abort and start over?"), _TR("Printing in progress."), MB_ICONEXCLAMATION | MB_YESNO | MbRtlReadingMaybe()); if (res == IDNO) return; } AbortPrinting(win); // the Print dialog allows access to the file system, so fall back // to printing the entire document without dialog if that isn't desired if (!HasPermission(Perm_DiskAccess)) { PrintFile(dm->GetEngine()); return; } PRINTDLGEX pd; ZeroMemory(&pd, sizeof(PRINTDLGEX)); pd.lStructSize = sizeof(PRINTDLGEX); pd.hwndOwner = win->hwndFrame; pd.Flags = PD_USEDEVMODECOPIESANDCOLLATE | PD_COLLATE; if (!win->currentTab->selectionOnPage) pd.Flags |= PD_NOSELECTION; pd.nCopies = 1; /* by default print all pages */ pd.nPageRanges = 1; pd.nMaxPageRanges = MAXPAGERANGES; PRINTPAGERANGE *ppr = AllocArray<PRINTPAGERANGE>(MAXPAGERANGES); pd.lpPageRanges = ppr; ppr->nFromPage = 1; ppr->nToPage = dm->PageCount(); pd.nMinPage = 1; pd.nMaxPage = dm->PageCount(); pd.nStartPage = START_PAGE_GENERAL; Print_Advanced_Data advanced(PrintRangeAll, defaultScaleAdv); ScopedMem<DLGTEMPLATE> dlgTemplate; // needed for RTL languages HPROPSHEETPAGE hPsp = CreatePrintAdvancedPropSheet(&advanced, dlgTemplate); pd.lphPropertyPages = &hPsp; pd.nPropertyPages = 1; LPDEVNAMES devNames; LPDEVMODE devMode; bool failedEngineClone; PrintData *data = nullptr; // restore remembered settings if (defaultDevMode) { DEVMODE *p = defaultDevMode.Get(); pd.hDevMode = GlobalMemDup(p, p->dmSize + p->dmDriverExtra); } if (PrintDlgEx(&pd) != S_OK) { if (CommDlgExtendedError() != 0) { /* if PrintDlg was cancelled then CommDlgExtendedError is zero, otherwise it returns the error code, which we could look at here if we wanted. for now just warn the user that printing has stopped becasue of an error */ MessageBoxWarning(win->hwndFrame, _TR("Couldn't initialize printer"), _TR("Printing problem.")); } goto Exit; } if (pd.dwResultAction == PD_RESULT_PRINT || pd.dwResultAction == PD_RESULT_APPLY) { // remember settings for this process devMode = (LPDEVMODE)GlobalLock(pd.hDevMode); if (devMode) { defaultDevMode.Set( (LPDEVMODE)memdup(devMode, devMode->dmSize + devMode->dmDriverExtra)); GlobalUnlock(pd.hDevMode); } defaultScaleAdv = advanced.scale; } if (pd.dwResultAction != PD_RESULT_PRINT) goto Exit; if (pd.Flags & PD_CURRENTPAGE) { PRINTPAGERANGE pr = { (DWORD)dm->CurrentPageNo(), (DWORD)dm->CurrentPageNo() }; ranges.Append(pr); } else if (win->currentTab->selectionOnPage && (pd.Flags & PD_SELECTION)) { printSelection = true; } else if (!(pd.Flags & PD_PAGENUMS)) { PRINTPAGERANGE pr = { 1, (DWORD)dm->PageCount() }; ranges.Append(pr); } else { assert(pd.nPageRanges > 0); for (DWORD i = 0; i < pd.nPageRanges; i++) ranges.Append(pd.lpPageRanges[i]); } devNames = (LPDEVNAMES)GlobalLock(pd.hDevNames); devMode = (LPDEVMODE)GlobalLock(pd.hDevMode); if (devNames) { printerInfo.pDriverName = (LPWSTR)devNames + devNames->wDriverOffset; printerInfo.pPrinterName = (LPWSTR)devNames + devNames->wDeviceOffset; printerInfo.pPortName = (LPWSTR)devNames + devNames->wOutputOffset; } data = new PrintData(dm->GetEngine(), &printerInfo, devMode, ranges, advanced, dm->GetRotation(), printSelection ? win->currentTab->selectionOnPage : nullptr); if (devNames) GlobalUnlock(pd.hDevNames); if (devMode) GlobalUnlock(pd.hDevMode); // if a file is missing and the engine can't thus be cloned, // we print using the original engine on the main thread // so that the document can't be closed and the original engine // unexpectedly deleted // TODO: instead prevent closing the document so that printing // can still happen on a separate thread and be interruptible failedEngineClone = dm->GetEngine() && !data->engine; if (failedEngineClone) data->engine = dm->GetEngine(); if (!waitForCompletion && !failedEngineClone) PrintToDeviceOnThread(win, data); else { PrintToDevice(*data); if (failedEngineClone) data->engine = nullptr; delete data; } Exit: free(ppr); GlobalFree(pd.hDevNames); GlobalFree(pd.hDevMode); }
{ return (x > 0.0f ? 20.0f * ::log10f(x) : -60.0f); } static inline float pow10f2 ( float x ) { return ::powf(10.0f, 0.05f * x); } // Translatable macro contextualizer. #undef _TR #define _TR(x) QT_TR_NOOP(x) //---------------------------------------------------------------------------- // Fade types curves. const char *g_aFadeTypeNames[] = { _TR("Linear"), // Linear (obvious:) _TR("Quadratic 1"), // InQuad _TR("Quadratic 2"), // OutQuad _TR("Quadratic 3"), // InOutQuad _TR("Cubic 1"), // InCubic _TR("Cubic 2"), // OutCubic _TR("Cubic 3"), // InOutCubic NULL }; struct FadeTypeInfo { QString name; QIcon iconFadeIn; QIcon iconFadeOut;
bool PrintFile(BaseEngine *engine, WCHAR *printerName, bool displayErrors, const WCHAR *settings) { bool ok = false; //if (!HasPermission(Perm_PrinterAccess)) // return false; #ifndef DISABLE_DOCUMENT_RESTRICTIONS if (engine && !engine->AllowsPrinting()) engine = nullptr; #endif if (!engine) { if (displayErrors) MessageBoxWarning(nullptr, _TR("Cannot print this file"), _TR("Printing problem.")); return false; } ScopedMem<WCHAR> defaultPrinter; if (!printerName) { defaultPrinter.Set(GetDefaultPrinterName()); printerName = defaultPrinter; } HANDLE printer; BOOL res = OpenPrinter(printerName, &printer, nullptr); if (!res) { if (displayErrors) MessageBoxWarning(nullptr, _TR("Printer with given name doesn't exist"), _TR("Printing problem.")); return false; } LONG returnCode = 0; LONG structSize = 0; LPDEVMODE devMode = nullptr; // get printer driver information DWORD needed = 0; GetPrinter(printer, 2, nullptr, 0, &needed); ScopedMem<PRINTER_INFO_2> infoData((PRINTER_INFO_2 *)AllocArray<BYTE>(needed)); if (infoData) res = GetPrinter(printer, 2, (LPBYTE)infoData.Get(), needed, &needed); if (!res || !infoData || needed <= sizeof(PRINTER_INFO_2)) goto Exit; structSize = DocumentProperties(nullptr, printer, printerName, nullptr, /* Asking for size, so */ nullptr, /* not used. */ 0); /* Zero returns buffer size. */ if (structSize < sizeof(DEVMODE)) { // If failure, inform the user, cleanup and return failure. if (displayErrors) MessageBoxWarning(nullptr, _TR("Could not obtain Printer properties"), _TR("Printing problem.")); goto Exit; } devMode = (LPDEVMODE)malloc(structSize); if (!devMode) goto Exit; // Get the default DevMode for the printer and modify it for your needs. returnCode = DocumentProperties(nullptr, printer, printerName, devMode, /* The address of the buffer to fill. */ nullptr, /* Not using the input buffer. */ DM_OUT_BUFFER); /* Have the output buffer filled. */ if (IDOK != returnCode) { // If failure, inform the user, cleanup and return failure. if (displayErrors) MessageBoxWarning(nullptr, _TR("Could not obtain Printer properties"), _TR("Printing problem.")); goto Exit; } ClosePrinter(printer); printer = nullptr; // set paper size to match the size of the document's first page // (will be overridden by any paper= value in -print-settings) devMode->dmPaperSize = GetPaperSize(engine); { Print_Advanced_Data advanced; Vec<PRINTPAGERANGE> ranges; ApplyPrintSettings(settings, engine->PageCount(), ranges, advanced, devMode); PrintData pd(engine, infoData, devMode, ranges, advanced); ok = PrintToDevice(pd); if (!ok && displayErrors) MessageBoxWarning(nullptr, _TR("Couldn't initialize printer"), _TR("Printing problem.")); } Exit: free(devMode); if (printer) ClosePrinter(printer); return ok; }
static INT_PTR CALLBACK Dialog_ChangeLanguage_Proc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { Dialog_ChangeLanguage_Data * data; HWND langList; if (WM_INITDIALOG == msg) { DIALOG_SIZER_START(sz) DIALOG_SIZER_ENTRY(IDOK, DS_MoveX | DS_MoveY) DIALOG_SIZER_ENTRY(IDCANCEL, DS_MoveX | DS_MoveY) DIALOG_SIZER_ENTRY(IDC_CHANGE_LANG_LANG_LIST, DS_SizeY | DS_SizeX) DIALOG_SIZER_END() DialogSizer_Set(hDlg, sz, TRUE); data = (Dialog_ChangeLanguage_Data*)lParam; assert(data); SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)data); // for non-latin languages this depends on the correct fonts being installed, // otherwise all the user will see are squares win::SetText(hDlg, _TR("Change Language")); langList = GetDlgItem(hDlg, IDC_CHANGE_LANG_LANG_LIST); int itemToSelect = 0; for (int i = 0; i < trans::GetLangsCount(); i++) { const char *name = trans::GetLangNameByIdx(i); const char *langCode = trans::GetLangCodeByIdx(i); ScopedMem<WCHAR> langName(str::conv::FromUtf8(name)); ListBox_AppendString_NoSort(langList, langName); if (str::Eq(langCode, data->langCode)) itemToSelect = i; } ListBox_SetCurSel(langList, itemToSelect); // the language list is meant to be laid out left-to-right ToggleWindowStyle(langList, WS_EX_LAYOUTRTL, false, GWL_EXSTYLE); SetDlgItemText(hDlg, IDOK, _TR("OK")); SetDlgItemText(hDlg, IDCANCEL, _TR("Cancel")); CenterDialog(hDlg); SetFocus(langList); return FALSE; } switch (msg) { case WM_COMMAND: data = (Dialog_ChangeLanguage_Data*)GetWindowLongPtr(hDlg, GWLP_USERDATA); assert(data); if (HIWORD(wParam) == LBN_DBLCLK) { assert(IDC_CHANGE_LANG_LANG_LIST == LOWORD(wParam)); langList = GetDlgItem(hDlg, IDC_CHANGE_LANG_LANG_LIST); assert(langList == (HWND)lParam); int langIdx = (int)ListBox_GetCurSel(langList); data->langCode = trans::GetLangCodeByIdx(langIdx); EndDialog(hDlg, IDOK); return FALSE; } switch (LOWORD(wParam)) { case IDOK: { langList = GetDlgItem(hDlg, IDC_CHANGE_LANG_LANG_LIST); int langIdx = ListBox_GetCurSel(langList); data->langCode = trans::GetLangCodeByIdx(langIdx); EndDialog(hDlg, IDOK); } return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; } break; } return FALSE; }
static void CreateButtonRunSumatra(HWND hwndParent) { // TODO: this button might be too narrow for some translations gHwndButtonRunSumatra = CreateDefaultButton(hwndParent, _TR("Start SumatraPDF"), 140, ID_BUTTON_START_SUMATRA); }
static INT_PTR CALLBACK Sheet_Print_Advanced_Proc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { Print_Advanced_Data *data; switch (msg) { //[ ACCESSKEY_GROUP Advanced Print Tab case WM_INITDIALOG: data = (Print_Advanced_Data *)((PROPSHEETPAGE *)lParam)->lParam; assert(data); SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)data); SetDlgItemText(hDlg, IDC_SECTION_PRINT_RANGE, _TR("Print range")); SetDlgItemText(hDlg, IDC_PRINT_RANGE_ALL, _TR("&All selected pages")); SetDlgItemText(hDlg, IDC_PRINT_RANGE_EVEN, _TR("&Even pages only")); SetDlgItemText(hDlg, IDC_PRINT_RANGE_ODD, _TR("&Odd pages only")); SetDlgItemText(hDlg, IDC_SECTION_PRINT_SCALE, _TR("Page scaling")); SetDlgItemText(hDlg, IDC_PRINT_SCALE_SHRINK, _TR("&Shrink pages to printable area (if necessary)")); SetDlgItemText(hDlg, IDC_PRINT_SCALE_FIT, _TR("&Fit pages to printable area")); SetDlgItemText(hDlg, IDC_PRINT_SCALE_NONE, _TR("&Use original page sizes")); SetDlgItemText(hDlg, IDC_SECTION_PRINT_COMPATIBILITY, _TR("Compatibility")); SetDlgItemText(hDlg, IDC_PRINT_AS_IMAGE, _TR("Print as &image (requires more memory)")); CheckRadioButton(hDlg, IDC_PRINT_RANGE_ALL, IDC_PRINT_RANGE_ODD, data->range == PrintRangeEven ? IDC_PRINT_RANGE_EVEN : data->range == PrintRangeOdd ? IDC_PRINT_RANGE_ODD : IDC_PRINT_RANGE_ALL); CheckRadioButton(hDlg, IDC_PRINT_SCALE_SHRINK, IDC_PRINT_SCALE_NONE, data->scale == PrintScaleFit ? IDC_PRINT_SCALE_FIT : data->scale == PrintScaleShrink ? IDC_PRINT_SCALE_SHRINK : IDC_PRINT_SCALE_NONE); CheckDlgButton(hDlg, IDC_PRINT_AS_IMAGE, data->asImage ? BST_CHECKED : BST_UNCHECKED); return FALSE; //] ACCESSKEY_GROUP Advanced Print Tab case WM_NOTIFY: if (((LPNMHDR)lParam)->code == PSN_APPLY) { data = (Print_Advanced_Data *)GetWindowLongPtr(hDlg, GWLP_USERDATA); assert(data); if (IsDlgButtonChecked(hDlg, IDC_PRINT_RANGE_EVEN)) data->range = PrintRangeEven; else if (IsDlgButtonChecked(hDlg, IDC_PRINT_RANGE_ODD)) data->range = PrintRangeOdd; else data->range = PrintRangeAll; if (IsDlgButtonChecked(hDlg, IDC_PRINT_SCALE_FIT)) data->scale = PrintScaleFit; else if (IsDlgButtonChecked(hDlg, IDC_PRINT_SCALE_SHRINK)) data->scale = PrintScaleShrink; else data->scale = PrintScaleNone; data->asImage = BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_PRINT_AS_IMAGE); return TRUE; } break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_PRINT_RANGE_ALL: case IDC_PRINT_RANGE_EVEN: case IDC_PRINT_RANGE_ODD: case IDC_PRINT_SCALE_SHRINK: case IDC_PRINT_SCALE_FIT: case IDC_PRINT_SCALE_NONE: case IDC_PRINT_AS_IMAGE: { HWND hApplyButton = GetDlgItem(GetParent(hDlg), ID_APPLY_NOW); EnableWindow(hApplyButton, TRUE); } break; } } return FALSE; }
void DrawStartPage(WindowInfo& win, HDC hdc, FileHistory& fileHistory, COLORREF colorRange[2]) { HPEN penBorder = CreatePen(PS_SOLID, DOCLIST_SEPARATOR_DY, WIN_COL_BLACK); HPEN penThumbBorder = CreatePen(PS_SOLID, DOCLIST_THUMBNAIL_BORDER_W, WIN_COL_BLACK); HPEN penLinkLine = CreatePen(PS_SOLID, 1, COL_BLUE_LINK); ScopedFont fontSumatraTxt(GetSimpleFont(hdc, L"MS Shell Dlg", 24)); ScopedFont fontLeftTxt(GetSimpleFont(hdc, L"MS Shell Dlg", 14)); HGDIOBJ origFont = SelectObject(hdc, fontSumatraTxt); /* Just to remember the orig font */ ClientRect rc(win.hwndCanvas); FillRect(hdc, &rc.ToRECT(), gBrushLogoBg); SelectObject(hdc, gBrushLogoBg); SelectObject(hdc, penBorder); bool isRtl = IsUIRightToLeft(); /* render title */ RectI titleBox = RectI(PointI(0, 0), CalcSumatraVersionSize(hdc)); titleBox.x = rc.dx - titleBox.dx - 3; DrawSumatraVersion(hdc, titleBox); PaintLine(hdc, RectI(0, titleBox.dy, rc.dx, 0)); /* render recent files list */ SelectObject(hdc, penThumbBorder); SetBkMode(hdc, TRANSPARENT); SetTextColor(hdc, WIN_COL_BLACK); rc.y += titleBox.dy; rc.dy -= titleBox.dy; FillRect(hdc, &rc.ToRECT(), gBrushAboutBg); rc.dy -= DOCLIST_BOTTOM_BOX_DY; Vec<DisplayState *> list; fileHistory.GetFrequencyOrder(list); int width = limitValue((rc.dx - DOCLIST_MARGIN_LEFT - DOCLIST_MARGIN_RIGHT + DOCLIST_MARGIN_BETWEEN_X) / (THUMBNAIL_DX + DOCLIST_MARGIN_BETWEEN_X), 1, DOCLIST_MAX_THUMBNAILS_X); int height = min((rc.dy - DOCLIST_MARGIN_TOP - DOCLIST_MARGIN_BOTTOM + DOCLIST_MARGIN_BETWEEN_Y) / (THUMBNAIL_DY + DOCLIST_MARGIN_BETWEEN_Y), FILE_HISTORY_MAX_FREQUENT / width); PointI offset(rc.x + DOCLIST_MARGIN_LEFT + (rc.dx - width * THUMBNAIL_DX - (width - 1) * DOCLIST_MARGIN_BETWEEN_X - DOCLIST_MARGIN_LEFT - DOCLIST_MARGIN_RIGHT) / 2, rc.y + DOCLIST_MARGIN_TOP); if (offset.x < ABOUT_INNER_PADDING) offset.x = ABOUT_INNER_PADDING; else if (list.Count() == 0) offset.x = DOCLIST_MARGIN_LEFT; SelectObject(hdc, fontSumatraTxt); SIZE txtSize; const WCHAR *txt = _TR("Frequently Read"); GetTextExtentPoint32(hdc, txt, (int)str::Len(txt), &txtSize); RectI headerRect(offset.x, rc.y + (DOCLIST_MARGIN_TOP - txtSize.cy) / 2, txtSize.cx, txtSize.cy); if (isRtl) headerRect.x = rc.dx - offset.x - headerRect.dx; DrawText(hdc, txt, -1, &headerRect.ToRECT(), (isRtl ? DT_RTLREADING : DT_LEFT) | DT_NOPREFIX); SelectObject(hdc, fontLeftTxt); SelectObject(hdc, GetStockBrush(NULL_BRUSH)); win.staticLinks.Reset(); for (int h = 0; h < height; h++) { for (int w = 0; w < width; w++) { if (h * width + w >= (int)list.Count()) { // display the "Open a document" link right below the last row height = w > 0 ? h + 1 : h; break; } DisplayState *state = list.At(h * width + w); RectI page(offset.x + w * (int)(THUMBNAIL_DX + DOCLIST_MARGIN_BETWEEN_X * win.uiDPIFactor), offset.y + h * (int)(THUMBNAIL_DY + DOCLIST_MARGIN_BETWEEN_Y * win.uiDPIFactor), THUMBNAIL_DX, THUMBNAIL_DY); if (isRtl) page.x = rc.dx - page.x - page.dx; bool loadOk = true; if (!state->thumbnail) loadOk = LoadThumbnail(*state); if (loadOk && state->thumbnail) { SizeI thumbSize = state->thumbnail->Size(); if (thumbSize.dx != THUMBNAIL_DX || thumbSize.dy != THUMBNAIL_DY) { page.dy = thumbSize.dy * THUMBNAIL_DX / thumbSize.dx; page.y += THUMBNAIL_DY - page.dy; } HRGN clip = CreateRoundRectRgn(page.x, page.y, page.x + page.dx, page.y + page.dy, 10, 10); SelectClipRgn(hdc, clip); RenderedBitmap *clone = state->thumbnail->Clone(); UpdateBitmapColorRange(clone->GetBitmap(), colorRange); clone->StretchDIBits(hdc, page); SelectClipRgn(hdc, NULL); DeleteObject(clip); delete clone; } RoundRect(hdc, page.x, page.y, page.x + page.dx, page.y + page.dy, 10, 10); int iconSpace = (int)(20 * win.uiDPIFactor); RectI rect(page.x + iconSpace, page.y + page.dy + 3, page.dx - iconSpace, iconSpace); if (isRtl) rect.x -= iconSpace; DrawText(hdc, path::GetBaseName(state->filePath), -1, &rect.ToRECT(), DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX | (isRtl ? DT_RIGHT : DT_LEFT)); SHFILEINFO sfi; HIMAGELIST himl = (HIMAGELIST)SHGetFileInfo(state->filePath, 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES); ImageList_Draw(himl, sfi.iIcon, hdc, isRtl ? page.x + page.dx - (int)(16 * win.uiDPIFactor) : page.x, rect.y, ILD_TRANSPARENT); win.staticLinks.Append(StaticLinkInfo(rect.Union(page), state->filePath, state->filePath)); } } /* render bottom links */ rc.y += DOCLIST_MARGIN_TOP + height * THUMBNAIL_DY + (height - 1) * DOCLIST_MARGIN_BETWEEN_Y + DOCLIST_MARGIN_BOTTOM; rc.dy = DOCLIST_BOTTOM_BOX_DY; SetTextColor(hdc, COL_BLUE_LINK); SelectObject(hdc, penLinkLine); HIMAGELIST himl = (HIMAGELIST)SendMessage(win.hwndToolbar, TB_GETIMAGELIST, 0, 0); RectI rectIcon(offset.x, rc.y, 0, 0); ImageList_GetIconSize(himl, &rectIcon.dx, &rectIcon.dy); rectIcon.y += (rc.dy - rectIcon.dy) / 2; if (isRtl) rectIcon.x = rc.dx - offset.x - rectIcon.dx; ImageList_Draw(himl, 0 /* index of Open icon */, hdc, rectIcon.x, rectIcon.y, ILD_NORMAL); txt = _TR("Open a document..."); GetTextExtentPoint32(hdc, txt, (int)str::Len(txt), &txtSize); RectI rect(offset.x + rectIcon.dx + 3, rc.y + (rc.dy - txtSize.cy) / 2, txtSize.cx, txtSize.cy); if (isRtl) rect.x = rectIcon.x - rect.dx - 3; DrawText(hdc, txt, -1, &rect.ToRECT(), isRtl ? DT_RTLREADING : DT_LEFT); PaintLine(hdc, RectI(rect.x, rect.y + rect.dy, rect.dx, 0)); // make the click target larger rect = rect.Union(rectIcon); rect.Inflate(10, 10); win.staticLinks.Append(StaticLinkInfo(rect, SLINK_OPEN_FILE)); rect = DrawBottomRightLink(win.hwndCanvas, hdc, _TR("Hide frequently read")); win.staticLinks.Append(StaticLinkInfo(rect, SLINK_LIST_HIDE)); SelectObject(hdc, origFont); DeleteObject(penBorder); DeleteObject(penThumbBorder); DeleteObject(penLinkLine); }