win_main.c 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388
  1. // Copyright (C) 2004-2025 Artifex Software, Inc.
  2. //
  3. // This file is part of MuPDF.
  4. //
  5. // MuPDF is free software: you can redistribute it and/or modify it under the
  6. // terms of the GNU Affero General Public License as published by the Free
  7. // Software Foundation, either version 3 of the License, or (at your option)
  8. // any later version.
  9. //
  10. // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
  11. // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  12. // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  13. // details.
  14. //
  15. // You should have received a copy of the GNU Affero General Public License
  16. // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
  17. //
  18. // Alternative licensing terms are available from the licensor.
  19. // For commercial licensing, see <https://www.artifex.com/> or contact
  20. // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
  21. // CA 94129, USA, for further information.
  22. #ifndef UNICODE
  23. #define UNICODE
  24. #endif
  25. #ifndef _UNICODE
  26. #define _UNICODE
  27. #endif
  28. #define WIN32_LEAN_AND_MEAN
  29. #include <windows.h>
  30. #include <commdlg.h>
  31. #include <shellapi.h>
  32. /* Include pdfapp.h *AFTER* the UNICODE defines */
  33. #include "pdfapp.h"
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <assert.h>
  37. #ifndef WM_MOUSEWHEEL
  38. #define WM_MOUSEWHEEL 0x020A
  39. #endif
  40. #define MIN(x,y) ((x) < (y) ? (x) : (y))
  41. #define ID_ABOUT 0x1000
  42. #define ID_DOCINFO 0x1001
  43. static HWND hwndframe = NULL;
  44. static HWND hwndview = NULL;
  45. static HDC hdc;
  46. static HBRUSH bgbrush;
  47. static BITMAPINFO *dibinf = NULL;
  48. static HCURSOR arrowcurs, handcurs, waitcurs, caretcurs;
  49. static LRESULT CALLBACK frameproc(HWND, UINT, WPARAM, LPARAM);
  50. static LRESULT CALLBACK viewproc(HWND, UINT, WPARAM, LPARAM);
  51. static int timer_pending = 0;
  52. static char *password = NULL;
  53. static int justcopied = 0;
  54. static pdfapp_t gapp;
  55. static wchar_t wbuf[PATH_MAX];
  56. static char filename[PATH_MAX];
  57. /*
  58. * Create registry keys to associate MuPDF with PDF and XPS files.
  59. */
  60. #define OPEN_KEY(parent, name, ptr) \
  61. RegCreateKeyExA(parent, name, 0, 0, 0, KEY_WRITE, 0, &ptr, 0)
  62. #define SET_KEY(parent, name, value) \
  63. RegSetValueExA(parent, name, 0, REG_SZ, (const BYTE *)(value), (DWORD)strlen(value) + 1)
  64. static void install_app(char *argv0)
  65. {
  66. char buf[512];
  67. HKEY software, classes, mupdf, dotpdf, dotxps, dotepub, dotfb2;
  68. HKEY shell, open, command, supported_types;
  69. HKEY pdf_progids, xps_progids, epub_progids, fb2_progids;
  70. OPEN_KEY(HKEY_CURRENT_USER, "Software", software);
  71. OPEN_KEY(software, "Classes", classes);
  72. OPEN_KEY(classes, ".pdf", dotpdf);
  73. OPEN_KEY(dotpdf, "OpenWithProgids", pdf_progids);
  74. OPEN_KEY(classes, ".xps", dotxps);
  75. OPEN_KEY(dotxps, "OpenWithProgids", xps_progids);
  76. OPEN_KEY(classes, ".epub", dotepub);
  77. OPEN_KEY(dotepub, "OpenWithProgids", epub_progids);
  78. OPEN_KEY(classes, ".fb2", dotfb2);
  79. OPEN_KEY(dotfb2, "OpenWithProgids", fb2_progids);
  80. OPEN_KEY(classes, "MuPDF", mupdf);
  81. OPEN_KEY(mupdf, "SupportedTypes", supported_types);
  82. OPEN_KEY(mupdf, "shell", shell);
  83. OPEN_KEY(shell, "open", open);
  84. OPEN_KEY(open, "command", command);
  85. sprintf(buf, "\"%s\" \"%%1\"", argv0);
  86. SET_KEY(open, "FriendlyAppName", "MuPDF");
  87. SET_KEY(command, "", buf);
  88. SET_KEY(supported_types, ".pdf", "");
  89. SET_KEY(supported_types, ".xps", "");
  90. SET_KEY(supported_types, ".epub", "");
  91. SET_KEY(pdf_progids, "MuPDF", "");
  92. SET_KEY(xps_progids, "MuPDF", "");
  93. SET_KEY(epub_progids, "MuPDF", "");
  94. SET_KEY(fb2_progids, "MuPDF", "");
  95. RegCloseKey(dotfb2);
  96. RegCloseKey(dotepub);
  97. RegCloseKey(dotxps);
  98. RegCloseKey(dotpdf);
  99. RegCloseKey(mupdf);
  100. RegCloseKey(classes);
  101. RegCloseKey(software);
  102. }
  103. /*
  104. * Dialog boxes
  105. */
  106. void winwarn(pdfapp_t *app, char *msg)
  107. {
  108. MessageBoxA(hwndframe, msg, "MuPDF: Warning", MB_ICONWARNING);
  109. }
  110. void winerror(pdfapp_t *app, char *msg)
  111. {
  112. MessageBoxA(hwndframe, msg, "MuPDF: Error", MB_ICONERROR);
  113. exit(1);
  114. }
  115. void winalert(pdfapp_t *app, pdf_alert_event *alert)
  116. {
  117. int buttons = MB_OK;
  118. int icon = MB_ICONWARNING;
  119. int pressed = PDF_ALERT_BUTTON_NONE;
  120. switch (alert->icon_type)
  121. {
  122. case PDF_ALERT_ICON_ERROR:
  123. icon = MB_ICONERROR;
  124. break;
  125. case PDF_ALERT_ICON_WARNING:
  126. icon = MB_ICONWARNING;
  127. break;
  128. case PDF_ALERT_ICON_QUESTION:
  129. icon = MB_ICONQUESTION;
  130. break;
  131. case PDF_ALERT_ICON_STATUS:
  132. icon = MB_ICONINFORMATION;
  133. break;
  134. }
  135. switch (alert->button_group_type)
  136. {
  137. case PDF_ALERT_BUTTON_GROUP_OK:
  138. buttons = MB_OK;
  139. break;
  140. case PDF_ALERT_BUTTON_GROUP_OK_CANCEL:
  141. buttons = MB_OKCANCEL;
  142. break;
  143. case PDF_ALERT_BUTTON_GROUP_YES_NO:
  144. buttons = MB_YESNO;
  145. break;
  146. case PDF_ALERT_BUTTON_GROUP_YES_NO_CANCEL:
  147. buttons = MB_YESNOCANCEL;
  148. break;
  149. }
  150. pressed = MessageBoxA(hwndframe, alert->message, alert->title, icon|buttons);
  151. switch (pressed)
  152. {
  153. case IDOK:
  154. alert->button_pressed = PDF_ALERT_BUTTON_OK;
  155. break;
  156. case IDCANCEL:
  157. alert->button_pressed = PDF_ALERT_BUTTON_CANCEL;
  158. break;
  159. case IDNO:
  160. alert->button_pressed = PDF_ALERT_BUTTON_NO;
  161. break;
  162. case IDYES:
  163. alert->button_pressed = PDF_ALERT_BUTTON_YES;
  164. }
  165. }
  166. void winprint(pdfapp_t *app)
  167. {
  168. MessageBoxA(hwndframe, "The MuPDF library supports printing, but this application currently does not", "Print document", MB_ICONWARNING);
  169. }
  170. int winsavequery(pdfapp_t *app)
  171. {
  172. switch(MessageBoxA(hwndframe, "File has unsaved changes. Do you want to save", "MuPDF", MB_YESNOCANCEL))
  173. {
  174. case IDYES: return SAVE;
  175. case IDNO: return DISCARD;
  176. default: return CANCEL;
  177. }
  178. }
  179. int winquery(pdfapp_t *app, const char *query)
  180. {
  181. switch(MessageBoxA(hwndframe, query, "MuPDF", MB_YESNOCANCEL))
  182. {
  183. case IDYES: return QUERY_YES;
  184. case IDNO:
  185. default: return QUERY_NO;
  186. }
  187. }
  188. static int winfilename(wchar_t *buf, int len)
  189. {
  190. OPENFILENAME ofn;
  191. buf[0] = 0;
  192. memset(&ofn, 0, sizeof(OPENFILENAME));
  193. ofn.lStructSize = sizeof(OPENFILENAME);
  194. ofn.hwndOwner = hwndframe;
  195. ofn.lpstrFile = buf;
  196. ofn.nMaxFile = len;
  197. ofn.lpstrInitialDir = NULL;
  198. ofn.lpstrTitle = L"MuPDF: Open PDF file";
  199. ofn.lpstrFilter = L"Documents (*.pdf;*.xps;*.cbz;*.epub;*.fb2;*.zip;*.png;*.jpeg;*.tiff)\0*.zip;*.cbz;*.xps;*.epub;*.fb2;*.pdf;*.jpe;*.jpg;*.jpeg;*.jfif;*.tif;*.tiff\0PDF Files (*.pdf)\0*.pdf\0XPS Files (*.xps)\0*.xps\0CBZ Files (*.cbz;*.zip)\0*.zip;*.cbz\0EPUB Files (*.epub)\0*.epub\0FictionBook 2 Files (*.fb2)\0*.fb2\0Image Files (*.png;*.jpeg;*.tiff)\0*.png;*.jpg;*.jpe;*.jpeg;*.jfif;*.tif;*.tiff\0All Files\0*\0\0";
  200. ofn.Flags = OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
  201. return GetOpenFileNameW(&ofn);
  202. }
  203. int wingetcertpath(pdfapp_t *app, char *buf, int len)
  204. {
  205. wchar_t twbuf[PATH_MAX] = {0};
  206. OPENFILENAME ofn;
  207. buf[0] = 0;
  208. memset(&ofn, 0, sizeof(OPENFILENAME));
  209. ofn.lStructSize = sizeof(OPENFILENAME);
  210. ofn.hwndOwner = hwndframe;
  211. ofn.lpstrFile = twbuf;
  212. ofn.nMaxFile = PATH_MAX;
  213. ofn.lpstrInitialDir = NULL;
  214. ofn.lpstrTitle = L"MuPDF: Select certificate file";
  215. ofn.lpstrFilter = L"Certificates (*.pfx)\0*.pfx\0All files\0*\0\0";
  216. ofn.Flags = OFN_FILEMUSTEXIST;
  217. if (GetOpenFileNameW(&ofn))
  218. {
  219. int code = WideCharToMultiByte(CP_UTF8, 0, twbuf, -1, buf, MIN(PATH_MAX, len), NULL, NULL);
  220. if (code == 0)
  221. {
  222. pdfapp_error(app, "cannot convert filename to utf-8");
  223. return 0;
  224. }
  225. return 1;
  226. }
  227. else
  228. {
  229. return 0;
  230. }
  231. }
  232. int wingetsavepath(pdfapp_t *app, char *buf, int len)
  233. {
  234. wchar_t twbuf[PATH_MAX];
  235. OPENFILENAME ofn;
  236. wcscpy(twbuf, wbuf);
  237. memset(&ofn, 0, sizeof(OPENFILENAME));
  238. ofn.lStructSize = sizeof(OPENFILENAME);
  239. ofn.hwndOwner = hwndframe;
  240. ofn.lpstrFile = twbuf;
  241. ofn.nMaxFile = PATH_MAX;
  242. ofn.lpstrInitialDir = NULL;
  243. ofn.lpstrTitle = L"MuPDF: Save PDF file";
  244. ofn.lpstrFilter = L"PDF Documents (*.pdf)\0*.pdf\0All Files\0*\0\0";
  245. ofn.Flags = OFN_HIDEREADONLY;
  246. if (GetSaveFileName(&ofn))
  247. {
  248. int code = WideCharToMultiByte(CP_UTF8, 0, twbuf, -1, buf, MIN(PATH_MAX, len), NULL, NULL);
  249. if (code == 0)
  250. {
  251. pdfapp_error(app, "cannot convert filename to utf-8");
  252. return 0;
  253. }
  254. wcscpy(wbuf, twbuf);
  255. fz_strlcpy(filename, buf, sizeof filename);
  256. return 1;
  257. }
  258. else
  259. {
  260. return 0;
  261. }
  262. }
  263. void winreplacefile(pdfapp_t *app, char *source, char *target)
  264. {
  265. wchar_t wsource[PATH_MAX];
  266. wchar_t wtarget[PATH_MAX];
  267. int sz = MultiByteToWideChar(CP_UTF8, 0, source, -1, wsource, PATH_MAX);
  268. if (sz == 0)
  269. {
  270. pdfapp_error(app, "cannot convert filename to Unicode");
  271. return;
  272. }
  273. sz = MultiByteToWideChar(CP_UTF8, 0, target, -1, wtarget, PATH_MAX);
  274. if (sz == 0)
  275. {
  276. pdfapp_error(app, "cannot convert filename to Unicode");
  277. return;
  278. }
  279. #if (_WIN32_WINNT >= 0x0500)
  280. ReplaceFile(wtarget, wsource, NULL, REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL);
  281. #else
  282. DeleteFile(wtarget);
  283. MoveFile(wsource, wtarget);
  284. #endif
  285. }
  286. void wincopyfile(pdfapp_t *app, char *source, char *target)
  287. {
  288. wchar_t wsource[PATH_MAX];
  289. wchar_t wtarget[PATH_MAX];
  290. int sz = MultiByteToWideChar(CP_UTF8, 0, source, -1, wsource, PATH_MAX);
  291. if (sz == 0)
  292. {
  293. pdfapp_error(app, "cannot convert filename to Unicode");
  294. return;
  295. }
  296. sz = MultiByteToWideChar(CP_UTF8, 0, target, -1, wtarget, PATH_MAX);
  297. if (sz == 0)
  298. {
  299. pdfapp_error(app, "cannot convert filename to Unicode");
  300. return;
  301. }
  302. CopyFile(wsource, wtarget, FALSE);
  303. }
  304. static char pd_password[256] = "";
  305. static wchar_t pd_passwordw[256] = {0};
  306. static char td_textinput[1024] = "";
  307. static int td_retry = 0;
  308. static int cd_nopts;
  309. static int *cd_nvals;
  310. static const char **cd_opts;
  311. static const char **cd_vals;
  312. static int pd_okay = 0;
  313. static INT_PTR CALLBACK
  314. dlogpassproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  315. {
  316. switch(message)
  317. {
  318. case WM_INITDIALOG:
  319. SetDlgItemTextA(hwnd, 4, "The file is encrypted.");
  320. return TRUE;
  321. case WM_COMMAND:
  322. switch(wParam)
  323. {
  324. case 1:
  325. pd_okay = 1;
  326. GetDlgItemTextW(hwnd, 3, pd_passwordw, nelem(pd_passwordw));
  327. EndDialog(hwnd, 1);
  328. WideCharToMultiByte(CP_UTF8, 0, pd_passwordw, -1, pd_password, sizeof pd_password, NULL, NULL);
  329. return TRUE;
  330. case 2:
  331. pd_okay = 0;
  332. EndDialog(hwnd, 1);
  333. return TRUE;
  334. }
  335. break;
  336. }
  337. return FALSE;
  338. }
  339. static INT_PTR CALLBACK
  340. dlogtextproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  341. {
  342. switch(message)
  343. {
  344. case WM_INITDIALOG:
  345. SetDlgItemTextA(hwnd, 3, td_textinput);
  346. if (!td_retry)
  347. ShowWindow(GetDlgItem(hwnd, 4), SW_HIDE);
  348. return TRUE;
  349. case WM_COMMAND:
  350. switch(wParam)
  351. {
  352. case 1:
  353. pd_okay = 1;
  354. GetDlgItemTextA(hwnd, 3, td_textinput, sizeof td_textinput);
  355. EndDialog(hwnd, 1);
  356. return TRUE;
  357. case 2:
  358. pd_okay = 0;
  359. EndDialog(hwnd, 1);
  360. return TRUE;
  361. }
  362. break;
  363. case WM_CTLCOLORSTATIC:
  364. if ((HWND)lParam == GetDlgItem(hwnd, 4))
  365. {
  366. SetTextColor((HDC)wParam, RGB(255,0,0));
  367. SetBkMode((HDC)wParam, TRANSPARENT);
  368. return (INT_PTR)GetStockObject(NULL_BRUSH);
  369. }
  370. break;
  371. }
  372. return FALSE;
  373. }
  374. static INT_PTR CALLBACK
  375. dlogchoiceproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  376. {
  377. HWND listbox;
  378. int i;
  379. int item;
  380. int sel;
  381. switch(message)
  382. {
  383. case WM_INITDIALOG:
  384. listbox = GetDlgItem(hwnd, 3);
  385. for (i = 0; i < cd_nopts; i++)
  386. SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)cd_opts[i]);
  387. /* FIXME: handle multiple select */
  388. if (*cd_nvals > 0)
  389. {
  390. item = SendMessageA(listbox, LB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)cd_vals[0]);
  391. if (item != LB_ERR)
  392. SendMessageA(listbox, LB_SETCURSEL, item, 0);
  393. }
  394. return TRUE;
  395. case WM_COMMAND:
  396. switch(wParam)
  397. {
  398. case 1:
  399. listbox = GetDlgItem(hwnd, 3);
  400. *cd_nvals = 0;
  401. for (i = 0; i < cd_nopts; i++)
  402. {
  403. item = SendMessageA(listbox, LB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)cd_opts[i]);
  404. sel = SendMessageA(listbox, LB_GETSEL, item, 0);
  405. if (sel && sel != LB_ERR)
  406. cd_vals[(*cd_nvals)++] = cd_opts[i];
  407. }
  408. pd_okay = 1;
  409. EndDialog(hwnd, 1);
  410. return TRUE;
  411. case 2:
  412. pd_okay = 0;
  413. EndDialog(hwnd, 1);
  414. return TRUE;
  415. }
  416. break;
  417. }
  418. return FALSE;
  419. }
  420. char *winpassword(pdfapp_t *app, char *filename)
  421. {
  422. int code;
  423. if (password)
  424. {
  425. char *p = password;
  426. password = NULL;
  427. return p;
  428. }
  429. code = DialogBoxW(NULL, L"IDD_DLOGPASS", hwndframe, dlogpassproc);
  430. if (code <= 0)
  431. pdfapp_error(app, "cannot create password dialog");
  432. if (pd_okay)
  433. return pd_password;
  434. return NULL;
  435. }
  436. char *wintextinput(pdfapp_t *app, char *inittext, int retry)
  437. {
  438. int code;
  439. td_retry = retry;
  440. fz_strlcpy(td_textinput, inittext ? inittext : "", sizeof td_textinput);
  441. code = DialogBoxW(NULL, L"IDD_DLOGTEXT", hwndframe, dlogtextproc);
  442. if (code <= 0)
  443. pdfapp_error(app, "cannot create text input dialog");
  444. if (pd_okay)
  445. return td_textinput;
  446. return NULL;
  447. }
  448. int winchoiceinput(pdfapp_t *app, int nopts, const char *opts[], int *nvals, const char *vals[])
  449. {
  450. int code;
  451. cd_nopts = nopts;
  452. cd_nvals = nvals;
  453. cd_opts = opts;
  454. cd_vals = vals;
  455. code = DialogBoxW(NULL, L"IDD_DLOGLIST", hwndframe, dlogchoiceproc);
  456. if (code <= 0)
  457. pdfapp_error(app, "cannot create text input dialog");
  458. return pd_okay;
  459. }
  460. static INT_PTR CALLBACK
  461. dloginfoproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  462. {
  463. char buf[256];
  464. wchar_t bufx[256];
  465. fz_context *ctx = gapp.ctx;
  466. fz_document *doc = gapp.doc;
  467. switch(message)
  468. {
  469. case WM_INITDIALOG:
  470. SetDlgItemTextW(hwnd, 0x10, wbuf);
  471. if (fz_lookup_metadata(ctx, doc, FZ_META_FORMAT, buf, sizeof buf) >= 0)
  472. {
  473. SetDlgItemTextA(hwnd, 0x11, buf);
  474. }
  475. else
  476. {
  477. SetDlgItemTextA(hwnd, 0x11, "Unknown");
  478. SetDlgItemTextA(hwnd, 0x12, "None");
  479. SetDlgItemTextA(hwnd, 0x13, "n/a");
  480. return TRUE;
  481. }
  482. if (fz_lookup_metadata(ctx, doc, FZ_META_ENCRYPTION, buf, sizeof buf) >= 0)
  483. {
  484. SetDlgItemTextA(hwnd, 0x12, buf);
  485. }
  486. else
  487. {
  488. SetDlgItemTextA(hwnd, 0x12, "None");
  489. }
  490. buf[0] = 0;
  491. if (fz_has_permission(ctx, doc, FZ_PERMISSION_PRINT))
  492. strcat(buf, "print, ");
  493. if (fz_has_permission(ctx, doc, FZ_PERMISSION_COPY))
  494. strcat(buf, "copy, ");
  495. if (fz_has_permission(ctx, doc, FZ_PERMISSION_EDIT))
  496. strcat(buf, "edit, ");
  497. if (fz_has_permission(ctx, doc, FZ_PERMISSION_ANNOTATE))
  498. strcat(buf, "annotate, ");
  499. if (strlen(buf) > 2)
  500. buf[strlen(buf)-2] = 0;
  501. else
  502. strcpy(buf, "none");
  503. SetDlgItemTextA(hwnd, 0x13, buf);
  504. #define SETUTF8(ID, STRING) \
  505. if (fz_lookup_metadata(ctx, doc, "info:" STRING, buf, sizeof buf) >= 0) \
  506. { \
  507. MultiByteToWideChar(CP_UTF8, 0, buf, -1, bufx, nelem(bufx)); \
  508. SetDlgItemTextW(hwnd, ID, bufx); \
  509. }
  510. SETUTF8(0x20, "Title");
  511. SETUTF8(0x21, "Author");
  512. SETUTF8(0x22, "Subject");
  513. SETUTF8(0x23, "Keywords");
  514. SETUTF8(0x24, "Creator");
  515. SETUTF8(0x25, "Producer");
  516. SETUTF8(0x26, "CreationDate");
  517. SETUTF8(0x27, "ModDate");
  518. return TRUE;
  519. case WM_COMMAND:
  520. EndDialog(hwnd, 1);
  521. return TRUE;
  522. }
  523. return FALSE;
  524. }
  525. static void info()
  526. {
  527. int code = DialogBoxW(NULL, L"IDD_DLOGINFO", hwndframe, dloginfoproc);
  528. if (code <= 0)
  529. pdfapp_error(&gapp, "cannot create info dialog");
  530. }
  531. static INT_PTR CALLBACK
  532. dlogaboutproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  533. {
  534. switch(message)
  535. {
  536. case WM_INITDIALOG:
  537. SetDlgItemTextA(hwnd, 2, pdfapp_version(&gapp));
  538. SetDlgItemTextA(hwnd, 3, pdfapp_usage(&gapp));
  539. return TRUE;
  540. case WM_COMMAND:
  541. EndDialog(hwnd, 1);
  542. return TRUE;
  543. }
  544. return FALSE;
  545. }
  546. void winhelp(pdfapp_t*app)
  547. {
  548. int code = DialogBoxW(NULL, L"IDD_DLOGABOUT", hwndframe, dlogaboutproc);
  549. if (code <= 0)
  550. pdfapp_error(&gapp, "cannot create help dialog");
  551. }
  552. /*
  553. * Main window
  554. */
  555. static void winopen()
  556. {
  557. WNDCLASS wc;
  558. HMENU menu;
  559. RECT r;
  560. ATOM a;
  561. /* Create and register window frame class */
  562. memset(&wc, 0, sizeof(wc));
  563. wc.style = 0;
  564. wc.lpfnWndProc = frameproc;
  565. wc.cbClsExtra = 0;
  566. wc.cbWndExtra = 0;
  567. wc.hInstance = GetModuleHandle(NULL);
  568. wc.hIcon = LoadIconA(wc.hInstance, "IDI_ICONAPP");
  569. wc.hCursor = NULL; //LoadCursor(NULL, IDC_ARROW);
  570. wc.hbrBackground = NULL;
  571. wc.lpszMenuName = NULL;
  572. wc.lpszClassName = L"FrameWindow";
  573. a = RegisterClassW(&wc);
  574. if (!a)
  575. pdfapp_error(&gapp, "cannot register frame window class");
  576. /* Create and register window view class */
  577. memset(&wc, 0, sizeof(wc));
  578. wc.style = CS_HREDRAW | CS_VREDRAW;
  579. wc.lpfnWndProc = viewproc;
  580. wc.cbClsExtra = 0;
  581. wc.cbWndExtra = 0;
  582. wc.hInstance = GetModuleHandle(NULL);
  583. wc.hIcon = NULL;
  584. wc.hCursor = NULL;
  585. wc.hbrBackground = NULL;
  586. wc.lpszMenuName = NULL;
  587. wc.lpszClassName = L"ViewWindow";
  588. a = RegisterClassW(&wc);
  589. if (!a)
  590. pdfapp_error(&gapp, "cannot register view window class");
  591. /* Get screen size */
  592. SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
  593. gapp.scrw = r.right - r.left;
  594. gapp.scrh = r.bottom - r.top;
  595. /* Create cursors */
  596. arrowcurs = LoadCursor(NULL, IDC_ARROW);
  597. handcurs = LoadCursor(NULL, IDC_HAND);
  598. waitcurs = LoadCursor(NULL, IDC_WAIT);
  599. caretcurs = LoadCursor(NULL, IDC_IBEAM);
  600. /* And a background color */
  601. bgbrush = CreateSolidBrush(RGB(0x70,0x70,0x70));
  602. /* Init DIB info for buffer */
  603. dibinf = malloc(sizeof(BITMAPINFO) + 12);
  604. assert(dibinf);
  605. dibinf->bmiHeader.biSize = sizeof(dibinf->bmiHeader);
  606. dibinf->bmiHeader.biPlanes = 1;
  607. dibinf->bmiHeader.biBitCount = 32;
  608. dibinf->bmiHeader.biCompression = BI_RGB;
  609. dibinf->bmiHeader.biXPelsPerMeter = 2834;
  610. dibinf->bmiHeader.biYPelsPerMeter = 2834;
  611. dibinf->bmiHeader.biClrUsed = 0;
  612. dibinf->bmiHeader.biClrImportant = 0;
  613. dibinf->bmiHeader.biClrUsed = 0;
  614. /* Create window */
  615. hwndframe = CreateWindowW(L"FrameWindow", // window class name
  616. NULL, // window caption
  617. WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
  618. CW_USEDEFAULT, CW_USEDEFAULT, // initial position
  619. 300, // initial x size
  620. 300, // initial y size
  621. 0, // parent window handle
  622. 0, // window menu handle
  623. 0, // program instance handle
  624. 0); // creation parameters
  625. if (!hwndframe)
  626. pdfapp_error(&gapp, "cannot create frame");
  627. hwndview = CreateWindowW(L"ViewWindow", // window class name
  628. NULL,
  629. WS_VISIBLE | WS_CHILD,
  630. CW_USEDEFAULT, CW_USEDEFAULT,
  631. CW_USEDEFAULT, CW_USEDEFAULT,
  632. hwndframe, 0, 0, 0);
  633. if (!hwndview)
  634. pdfapp_error(&gapp, "cannot create view");
  635. hdc = NULL;
  636. SetWindowTextW(hwndframe, L"MuPDF");
  637. menu = GetSystemMenu(hwndframe, 0);
  638. AppendMenuW(menu, MF_SEPARATOR, 0, NULL);
  639. AppendMenuW(menu, MF_STRING, ID_ABOUT, L"About MuPDF...");
  640. AppendMenuW(menu, MF_STRING, ID_DOCINFO, L"Document Properties...");
  641. SetCursor(arrowcurs);
  642. }
  643. static void
  644. do_close(pdfapp_t *app)
  645. {
  646. fz_context *ctx = app->ctx;
  647. pdfapp_close(app);
  648. free(dibinf);
  649. fz_drop_context(ctx);
  650. }
  651. void winclose(pdfapp_t *app)
  652. {
  653. if (pdfapp_preclose(app))
  654. {
  655. do_close(app);
  656. exit(0);
  657. }
  658. }
  659. void wincursor(pdfapp_t *app, int curs)
  660. {
  661. if (curs == ARROW)
  662. SetCursor(arrowcurs);
  663. if (curs == HAND)
  664. SetCursor(handcurs);
  665. if (curs == WAIT)
  666. SetCursor(waitcurs);
  667. if (curs == CARET)
  668. SetCursor(caretcurs);
  669. }
  670. int winisresolutionacceptable(pdfapp_t *app, fz_matrix ctm)
  671. {
  672. return 1;
  673. }
  674. void wintitle(pdfapp_t *app, char *title)
  675. {
  676. wchar_t wide[256], *dp;
  677. char *sp;
  678. int rune;
  679. dp = wide;
  680. sp = title;
  681. while (*sp && dp < wide + 255)
  682. {
  683. sp += fz_chartorune(&rune, sp);
  684. *dp++ = rune;
  685. }
  686. *dp = 0;
  687. SetWindowTextW(hwndframe, wide);
  688. }
  689. static void windrawrect(pdfapp_t *app, int x0, int y0, int x1, int y1)
  690. {
  691. RECT r;
  692. r.left = x0;
  693. r.top = y0;
  694. r.right = x1;
  695. r.bottom = y1;
  696. FillRect(hdc, &r, (HBRUSH)GetStockObject(WHITE_BRUSH));
  697. }
  698. void windrawstring(pdfapp_t *app, int x, int y, char *s)
  699. {
  700. HFONT font = (HFONT)GetStockObject(ANSI_FIXED_FONT);
  701. SelectObject(hdc, font);
  702. TextOutA(hdc, x, y - 12, s, (int)strlen(s));
  703. }
  704. static void winblitsearch()
  705. {
  706. if (gapp.issearching)
  707. {
  708. char buf[sizeof(gapp.search) + 50];
  709. sprintf(buf, "Search: %s", gapp.search);
  710. windrawrect(&gapp, 0, 0, gapp.winw, 30);
  711. windrawstring(&gapp, 10, 20, buf);
  712. }
  713. }
  714. static void winblit()
  715. {
  716. int image_w = fz_pixmap_width(gapp.ctx, gapp.image);
  717. int image_h = fz_pixmap_height(gapp.ctx, gapp.image);
  718. int image_n = fz_pixmap_components(gapp.ctx, gapp.image);
  719. unsigned char *samples = fz_pixmap_samples(gapp.ctx, gapp.image);
  720. int x0 = gapp.panx;
  721. int y0 = gapp.pany;
  722. int x1 = gapp.panx + image_w;
  723. int y1 = gapp.pany + image_h;
  724. RECT r;
  725. HBRUSH brush;
  726. if (gapp.image)
  727. {
  728. if (gapp.iscopying || justcopied)
  729. {
  730. pdfapp_invert(&gapp, gapp.selr);
  731. justcopied = 1;
  732. }
  733. pdfapp_inverthit(&gapp);
  734. dibinf->bmiHeader.biWidth = image_w;
  735. dibinf->bmiHeader.biHeight = -image_h;
  736. dibinf->bmiHeader.biSizeImage = image_h * 4;
  737. if (image_n == 2)
  738. {
  739. size_t i = image_w * (size_t)image_h;
  740. unsigned char *color = malloc(i*4);
  741. unsigned char *s = samples;
  742. unsigned char *d = color;
  743. for (; i > 0 ; i--)
  744. {
  745. d[2] = d[1] = d[0] = *s++;
  746. d[3] = *s++;
  747. d += 4;
  748. }
  749. SetDIBitsToDevice(hdc,
  750. gapp.panx, gapp.pany, image_w, image_h,
  751. 0, 0, 0, image_h, color,
  752. dibinf, DIB_RGB_COLORS);
  753. free(color);
  754. }
  755. if (image_n == 4)
  756. {
  757. SetDIBitsToDevice(hdc,
  758. gapp.panx, gapp.pany, image_w, image_h,
  759. 0, 0, 0, image_h, samples,
  760. dibinf, DIB_RGB_COLORS);
  761. }
  762. pdfapp_inverthit(&gapp);
  763. if (gapp.iscopying || justcopied)
  764. {
  765. pdfapp_invert(&gapp, gapp.selr);
  766. justcopied = 1;
  767. }
  768. }
  769. if (gapp.invert)
  770. brush = (HBRUSH)GetStockObject(BLACK_BRUSH);
  771. else
  772. brush = bgbrush;
  773. /* Grey background */
  774. r.top = 0; r.bottom = gapp.winh;
  775. r.left = 0; r.right = x0;
  776. FillRect(hdc, &r, brush);
  777. r.left = x1; r.right = gapp.winw;
  778. FillRect(hdc, &r, brush);
  779. r.left = 0; r.right = gapp.winw;
  780. r.top = 0; r.bottom = y0;
  781. FillRect(hdc, &r, brush);
  782. r.top = y1; r.bottom = gapp.winh;
  783. FillRect(hdc, &r, brush);
  784. winblitsearch();
  785. }
  786. void winresize(pdfapp_t *app, int w, int h)
  787. {
  788. ShowWindow(hwndframe, SW_SHOWDEFAULT);
  789. w += GetSystemMetrics(SM_CXFRAME) * 2;
  790. h += GetSystemMetrics(SM_CYFRAME) * 2;
  791. h += GetSystemMetrics(SM_CYCAPTION);
  792. SetWindowPos(hwndframe, 0, 0, 0, w, h, SWP_NOZORDER | SWP_NOMOVE);
  793. }
  794. void winrepaint(pdfapp_t *app)
  795. {
  796. InvalidateRect(hwndview, NULL, 0);
  797. }
  798. void winrepaintsearch(pdfapp_t *app)
  799. {
  800. // TODO: invalidate only search area and
  801. // call only search redraw routine.
  802. InvalidateRect(hwndview, NULL, 0);
  803. }
  804. void winfullscreen(pdfapp_t *app, int state)
  805. {
  806. static WINDOWPLACEMENT savedplace;
  807. static int isfullscreen = 0;
  808. if (state && !isfullscreen)
  809. {
  810. GetWindowPlacement(hwndframe, &savedplace);
  811. SetWindowLong(hwndframe, GWL_STYLE, WS_POPUP | WS_VISIBLE);
  812. SetWindowPos(hwndframe, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);
  813. ShowWindow(hwndframe, SW_SHOWMAXIMIZED);
  814. isfullscreen = 1;
  815. }
  816. if (!state && isfullscreen)
  817. {
  818. SetWindowLong(hwndframe, GWL_STYLE, WS_OVERLAPPEDWINDOW);
  819. SetWindowPos(hwndframe, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);
  820. SetWindowPlacement(hwndframe, &savedplace);
  821. isfullscreen = 0;
  822. }
  823. }
  824. /*
  825. * Event handling
  826. */
  827. void windocopy(pdfapp_t *app)
  828. {
  829. HGLOBAL handle;
  830. unsigned short *ucsbuf;
  831. if (!OpenClipboard(hwndframe))
  832. return;
  833. EmptyClipboard();
  834. handle = GlobalAlloc(GMEM_MOVEABLE, 4096 * sizeof(unsigned short));
  835. if (!handle)
  836. {
  837. CloseClipboard();
  838. return;
  839. }
  840. ucsbuf = GlobalLock(handle);
  841. pdfapp_oncopy(&gapp, ucsbuf, 4096);
  842. GlobalUnlock(handle);
  843. SetClipboardData(CF_UNICODETEXT, handle);
  844. CloseClipboard();
  845. justcopied = 1; /* keep inversion around for a while... */
  846. }
  847. void winreloadpage(pdfapp_t *app)
  848. {
  849. SendMessage(hwndview, WM_APP, 0, 0);
  850. }
  851. void winopenuri(pdfapp_t *app, char *buf)
  852. {
  853. ShellExecuteA(hwndframe, "open", buf, 0, 0, SW_SHOWNORMAL);
  854. }
  855. #define OUR_TIMER_ID 1
  856. void winadvancetimer(pdfapp_t *app, float delay)
  857. {
  858. timer_pending = 1;
  859. SetTimer(hwndview, OUR_TIMER_ID, (unsigned int)(1000*delay), NULL);
  860. }
  861. static void killtimer(pdfapp_t *app)
  862. {
  863. timer_pending = 0;
  864. }
  865. static void handlekey(int c)
  866. {
  867. int modifier = (GetAsyncKeyState(VK_SHIFT) < 0);
  868. modifier |= ((GetAsyncKeyState(VK_CONTROL) < 0)<<2);
  869. modifier |= ((GetAsyncKeyState(VK_MENU) < 0)<<3);
  870. if (timer_pending)
  871. killtimer(&gapp);
  872. if (GetCapture() == hwndview)
  873. return;
  874. if (justcopied)
  875. {
  876. justcopied = 0;
  877. winrepaint(&gapp);
  878. }
  879. /* translate VK into ASCII equivalents */
  880. if (c > 256)
  881. {
  882. switch (c - 256)
  883. {
  884. case VK_ESCAPE: c = '\033'; break;
  885. case VK_DOWN: c = 'j'; break;
  886. case VK_UP: c = 'k'; break;
  887. case VK_LEFT: c = 'h'; break;
  888. case VK_RIGHT: c = 'l'; break;
  889. case VK_PRIOR: c = ','; break;
  890. case VK_NEXT: c = '.'; break;
  891. }
  892. }
  893. pdfapp_onkey(&gapp, c, modifier);
  894. winrepaint(&gapp);
  895. }
  896. static void handlemouse(int x, int y, int btn, int state)
  897. {
  898. int modifier = (GetAsyncKeyState(VK_SHIFT) < 0);
  899. modifier |= ((GetAsyncKeyState(VK_CONTROL) < 0)<<2);
  900. if (state != 0 && timer_pending)
  901. killtimer(&gapp);
  902. if (state != 0 && justcopied)
  903. {
  904. justcopied = 0;
  905. winrepaint(&gapp);
  906. }
  907. if (state == 1)
  908. SetCapture(hwndview);
  909. if (state == -1)
  910. ReleaseCapture();
  911. pdfapp_onmouse(&gapp, x, y, btn, modifier, state);
  912. }
  913. static LRESULT CALLBACK
  914. frameproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  915. {
  916. switch(message)
  917. {
  918. case WM_SETFOCUS:
  919. PostMessage(hwnd, WM_APP+5, 0, 0);
  920. return 0;
  921. case WM_APP+5:
  922. SetFocus(hwndview);
  923. return 0;
  924. case WM_DESTROY:
  925. PostQuitMessage(0);
  926. return 0;
  927. case WM_SYSCOMMAND:
  928. if (wParam == ID_ABOUT)
  929. {
  930. winhelp(&gapp);
  931. return 0;
  932. }
  933. if (wParam == ID_DOCINFO)
  934. {
  935. info();
  936. return 0;
  937. }
  938. break;
  939. case WM_SIZE:
  940. {
  941. // More generally, you should use GetEffectiveClientRect
  942. // if you have a toolbar etc.
  943. RECT rect;
  944. GetClientRect(hwnd, &rect);
  945. MoveWindow(hwndview, rect.left, rect.top,
  946. rect.right-rect.left, rect.bottom-rect.top, TRUE);
  947. if (wParam == SIZE_MAXIMIZED)
  948. gapp.shrinkwrap = 0;
  949. return 0;
  950. }
  951. case WM_SIZING:
  952. gapp.shrinkwrap = 0;
  953. break;
  954. case WM_NOTIFY:
  955. case WM_COMMAND:
  956. return SendMessage(hwndview, message, wParam, lParam);
  957. case WM_CLOSE:
  958. if (!pdfapp_preclose(&gapp))
  959. return 0;
  960. }
  961. return DefWindowProc(hwnd, message, wParam, lParam);
  962. }
  963. static LRESULT CALLBACK
  964. viewproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  965. {
  966. static int oldx = 0;
  967. static int oldy = 0;
  968. int x = (signed short) LOWORD(lParam);
  969. int y = (signed short) HIWORD(lParam);
  970. switch (message)
  971. {
  972. case WM_SIZE:
  973. if (wParam == SIZE_MINIMIZED)
  974. return 0;
  975. if (wParam == SIZE_MAXIMIZED)
  976. gapp.shrinkwrap = 0;
  977. pdfapp_onresize(&gapp, LOWORD(lParam), HIWORD(lParam));
  978. break;
  979. /* Paint events are low priority and automagically catenated
  980. * so we don't need to do any fancy waiting to defer repainting.
  981. */
  982. case WM_PAINT:
  983. {
  984. //puts("WM_PAINT");
  985. PAINTSTRUCT ps;
  986. hdc = BeginPaint(hwnd, &ps);
  987. winblit();
  988. hdc = NULL;
  989. EndPaint(hwnd, &ps);
  990. pdfapp_postblit(&gapp);
  991. return 0;
  992. }
  993. case WM_ERASEBKGND:
  994. return 1; // well, we don't need to erase to redraw cleanly
  995. /* Mouse events */
  996. case WM_LBUTTONDOWN:
  997. SetFocus(hwndview);
  998. oldx = x; oldy = y;
  999. handlemouse(x, y, 1, 1);
  1000. return 0;
  1001. case WM_MBUTTONDOWN:
  1002. SetFocus(hwndview);
  1003. oldx = x; oldy = y;
  1004. handlemouse(x, y, 2, 1);
  1005. return 0;
  1006. case WM_RBUTTONDOWN:
  1007. SetFocus(hwndview);
  1008. oldx = x; oldy = y;
  1009. handlemouse(x, y, 3, 1);
  1010. return 0;
  1011. case WM_LBUTTONUP:
  1012. oldx = x; oldy = y;
  1013. handlemouse(x, y, 1, -1);
  1014. return 0;
  1015. case WM_MBUTTONUP:
  1016. oldx = x; oldy = y;
  1017. handlemouse(x, y, 2, -1);
  1018. return 0;
  1019. case WM_RBUTTONUP:
  1020. oldx = x; oldy = y;
  1021. handlemouse(x, y, 3, -1);
  1022. return 0;
  1023. case WM_MOUSEMOVE:
  1024. oldx = x; oldy = y;
  1025. handlemouse(x, y, 0, 0);
  1026. return 0;
  1027. /* Mouse wheel */
  1028. case WM_MOUSEWHEEL:
  1029. if ((signed short)HIWORD(wParam) <= 0)
  1030. {
  1031. handlemouse(oldx, oldy, 5, 1);
  1032. handlemouse(oldx, oldy, 5, -1);
  1033. }
  1034. else
  1035. {
  1036. handlemouse(oldx, oldy, 4, 1);
  1037. handlemouse(oldx, oldy, 4, -1);
  1038. }
  1039. return 0;
  1040. /* Timer */
  1041. case WM_TIMER:
  1042. if (wParam == OUR_TIMER_ID && timer_pending && gapp.presentation_mode)
  1043. {
  1044. timer_pending = 0;
  1045. handlekey(VK_RIGHT + 256);
  1046. handlemouse(oldx, oldy, 0, 0); /* update cursor */
  1047. return 0;
  1048. }
  1049. break;
  1050. /* Keyboard events */
  1051. case WM_KEYDOWN:
  1052. /* only handle special keys */
  1053. switch (wParam)
  1054. {
  1055. case VK_F1:
  1056. winhelp(&gapp);
  1057. return 0;
  1058. case VK_LEFT:
  1059. case VK_UP:
  1060. case VK_PRIOR:
  1061. case VK_RIGHT:
  1062. case VK_DOWN:
  1063. case VK_NEXT:
  1064. case VK_ESCAPE:
  1065. handlekey(wParam + 256);
  1066. handlemouse(oldx, oldy, 0, 0); /* update cursor */
  1067. return 0;
  1068. }
  1069. return 1;
  1070. case WM_SYSKEYDOWN:
  1071. /* alt keys */
  1072. switch (wParam)
  1073. {
  1074. case VK_LEFT:
  1075. case VK_RIGHT:
  1076. handlekey(wParam + 256);
  1077. handlemouse(oldx, oldy, 0, 0); /* update cursor */
  1078. return 0;
  1079. }
  1080. break;
  1081. /* unicode encoded chars, including escape, backspace etc... */
  1082. case WM_CHAR:
  1083. if (wParam < 256)
  1084. {
  1085. handlekey(wParam);
  1086. handlemouse(oldx, oldy, 0, 0); /* update cursor */
  1087. }
  1088. return 0;
  1089. /* We use WM_APP to trigger a reload and repaint of a page */
  1090. case WM_APP:
  1091. pdfapp_reloadpage(&gapp);
  1092. break;
  1093. }
  1094. fflush(stdout);
  1095. /* Pass on unhandled events to Windows */
  1096. return DefWindowProc(hwnd, message, wParam, lParam);
  1097. }
  1098. typedef BOOL (SetProcessDPIAwareFn)(void);
  1099. static int
  1100. get_system_dpi(void)
  1101. {
  1102. HMODULE hUser32 = LoadLibrary(TEXT("user32.dll"));
  1103. SetProcessDPIAwareFn *ptr;
  1104. int hdpi, vdpi;
  1105. HDC desktopDC;
  1106. ptr = (SetProcessDPIAwareFn *)GetProcAddress(hUser32, "SetProcessDPIAware");
  1107. if (ptr != NULL)
  1108. ptr();
  1109. FreeLibrary(hUser32);
  1110. desktopDC = GetDC(NULL);
  1111. hdpi = GetDeviceCaps(desktopDC, LOGPIXELSX);
  1112. vdpi = GetDeviceCaps(desktopDC, LOGPIXELSY);
  1113. /* hdpi,vdpi = 100 means 96dpi. */
  1114. return ((hdpi + vdpi) * 96 + 0.5f) / 200;
  1115. }
  1116. static void usage(const char *argv0)
  1117. {
  1118. const char *msg =
  1119. "usage: mupdf [options] file.pdf [page]\n"
  1120. "\t-p -\tpassword\n"
  1121. "\t-r -\tresolution\n"
  1122. "\t-A -\tset anti-aliasing quality in bits (0=off, 8=best)\n"
  1123. "\t-C -\tRRGGBB (tint color in hexadecimal syntax)\n"
  1124. "\t-W -\tpage width for EPUB layout\n"
  1125. "\t-H -\tpage height for EPUB layout\n"
  1126. "\t-I -\tinvert colors\n"
  1127. "\t-S -\tfont size for EPUB layout\n"
  1128. "\t-U -\tuser style sheet for EPUB layout\n"
  1129. "\t-X\tdisable document styles for EPUB layout\n";
  1130. MessageBoxA(NULL, msg, "MuPDF: Usage", MB_OK);
  1131. exit(1);
  1132. }
  1133. int WINAPI
  1134. WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
  1135. {
  1136. int argc;
  1137. LPWSTR *wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
  1138. char **argv;
  1139. char argv0[256];
  1140. MSG msg;
  1141. int code;
  1142. fz_context *ctx;
  1143. char *profile_name = NULL;
  1144. int kbps = 0;
  1145. int displayRes = get_system_dpi();
  1146. int c;
  1147. ctx = fz_new_context(NULL, NULL, FZ_STORE_DEFAULT);
  1148. if (!ctx)
  1149. {
  1150. MessageBoxA(NULL, "Cannot initialize MuPDF context.", "MuPDF: Error", MB_OK);
  1151. exit(1);
  1152. }
  1153. /* stderr goes nowhere. Get us a debug stream we have a chance
  1154. * of seeing. */
  1155. fz_set_stddbg(ctx, fz_stdods(ctx));
  1156. pdfapp_init(ctx, &gapp);
  1157. argv = fz_argv_from_wargv(argc, wargv);
  1158. while ((c = fz_getopt(argc, argv, "Ip:r:A:C:W:H:S:U:Xb:c:")) != -1)
  1159. {
  1160. switch (c)
  1161. {
  1162. case 'C':
  1163. c = strtol(fz_optarg, NULL, 16);
  1164. gapp.tint = 1;
  1165. gapp.tint_white = c;
  1166. break;
  1167. case 'p': password = fz_optarg; break;
  1168. case 'r': displayRes = fz_atoi(fz_optarg); break;
  1169. case 'I': gapp.invert = 1; break;
  1170. case 'A': fz_set_aa_level(ctx, fz_atoi(fz_optarg)); break;
  1171. case 'c': profile_name = fz_optarg; break;
  1172. case 'W': gapp.layout_w = fz_atoi(fz_optarg); break;
  1173. case 'H': gapp.layout_h = fz_atoi(fz_optarg); break;
  1174. case 'S': gapp.layout_em = fz_atoi(fz_optarg); break;
  1175. case 'b': kbps = fz_atoi(fz_optarg); break;
  1176. case 'U': gapp.layout_css = fz_optarg; break;
  1177. case 'X': gapp.layout_use_doc_css = 0; break;
  1178. default: usage(argv[0]);
  1179. }
  1180. }
  1181. pdfapp_setresolution(&gapp, displayRes);
  1182. GetModuleFileNameA(NULL, argv0, sizeof argv0);
  1183. install_app(argv0);
  1184. winopen();
  1185. if (fz_optind < argc)
  1186. {
  1187. fz_strlcpy(filename, argv[fz_optind++], sizeof filename);
  1188. }
  1189. else
  1190. {
  1191. if (!winfilename(wbuf, nelem(wbuf)))
  1192. exit(0);
  1193. code = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, filename, sizeof filename, NULL, NULL);
  1194. if (code == 0)
  1195. pdfapp_error(&gapp, "cannot convert filename to utf-8");
  1196. }
  1197. if (fz_optind < argc)
  1198. gapp.pageno = atoi(argv[fz_optind++]);
  1199. if (profile_name)
  1200. pdfapp_load_profile(&gapp, profile_name);
  1201. if (kbps)
  1202. pdfapp_open_progressive(&gapp, filename, 0, kbps);
  1203. else
  1204. pdfapp_open(&gapp, filename, 0);
  1205. while (GetMessage(&msg, NULL, 0, 0))
  1206. {
  1207. TranslateMessage(&msg);
  1208. DispatchMessage(&msg);
  1209. }
  1210. fz_free_argv(argc, argv);
  1211. do_close(&gapp);
  1212. return 0;
  1213. }