PageRenderTime 71ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/apps/win_main.c

https://github.com/Lafriks/mupdf
C | 903 lines | 739 code | 127 blank | 37 comment | 86 complexity | 8a781fa9a18b3beaf49377d8c73c4331 MD5 | raw file
  1. #include "fitz.h"
  2. #include "mupdf.h"
  3. #include "muxps.h"
  4. #include "pdfapp.h"
  5. #ifndef UNICODE
  6. #define UNICODE
  7. #endif
  8. #ifndef _UNICODE
  9. #define _UNICODE
  10. #endif
  11. #define WIN32_LEAN_AND_MEAN
  12. #include <windows.h>
  13. #include <commdlg.h>
  14. #include <shellapi.h>
  15. #ifndef WM_MOUSEWHEEL
  16. #define WM_MOUSEWHEEL 0x020A
  17. #endif
  18. #define ID_ABOUT 0x1000
  19. #define ID_DOCINFO 0x1001
  20. static HWND hwndframe = NULL;
  21. static HWND hwndview = NULL;
  22. static HDC hdc;
  23. static HBRUSH bgbrush;
  24. static HBRUSH shbrush;
  25. static BITMAPINFO *dibinf;
  26. static HCURSOR arrowcurs, handcurs, waitcurs;
  27. static LRESULT CALLBACK frameproc(HWND, UINT, WPARAM, LPARAM);
  28. static LRESULT CALLBACK viewproc(HWND, UINT, WPARAM, LPARAM);
  29. static int justcopied = 0;
  30. static pdfapp_t gapp;
  31. static wchar_t wbuf[1024];
  32. static char filename[1024];
  33. static fz_context *context;
  34. /*
  35. * Create registry keys to associate MuPDF with PDF and XPS files.
  36. */
  37. #define OPEN_KEY(parent, name, ptr) \
  38. RegCreateKeyExA(parent, name, 0, 0, 0, KEY_WRITE, 0, &ptr, 0)
  39. #define SET_KEY(parent, name, value) \
  40. RegSetValueExA(parent, name, 0, REG_SZ, value, strlen(value) + 1)
  41. void install_app(char *argv0)
  42. {
  43. char buf[512];
  44. HKEY software, classes, mupdf, dotpdf, dotxps;
  45. HKEY shell, open, command, supported_types;
  46. HKEY pdf_progids, xps_progids;
  47. OPEN_KEY(HKEY_CURRENT_USER, "Software", software);
  48. OPEN_KEY(software, "Classes", classes);
  49. OPEN_KEY(classes, ".pdf", dotpdf);
  50. OPEN_KEY(dotpdf, "OpenWithProgids", pdf_progids);
  51. OPEN_KEY(classes, ".xps", dotxps);
  52. OPEN_KEY(dotxps, "OpenWithProgids", xps_progids);
  53. OPEN_KEY(classes, "MuPDF", mupdf);
  54. OPEN_KEY(mupdf, "SupportedTypes", supported_types);
  55. OPEN_KEY(mupdf, "shell", shell);
  56. OPEN_KEY(shell, "open", open);
  57. OPEN_KEY(open, "command", command);
  58. sprintf(buf, "\"%s\" \"%%1\"", argv0);
  59. SET_KEY(open, "FriendlyAppName", "MuPDF");
  60. SET_KEY(command, "", buf);
  61. SET_KEY(supported_types, ".pdf", "");
  62. SET_KEY(supported_types, ".xps", "");
  63. SET_KEY(pdf_progids, "MuPDF", "");
  64. SET_KEY(xps_progids, "MuPDF", "");
  65. RegCloseKey(dotxps);
  66. RegCloseKey(dotpdf);
  67. RegCloseKey(mupdf);
  68. RegCloseKey(classes);
  69. RegCloseKey(software);
  70. }
  71. /*
  72. * Dialog boxes
  73. */
  74. void winwarn(pdfapp_t *app, char *msg)
  75. {
  76. MessageBoxA(hwndframe, msg, "MuPDF: Warning", MB_ICONWARNING);
  77. }
  78. void winerror(pdfapp_t *app, fz_error error)
  79. {
  80. char msgbuf[160 * 30];
  81. int i;
  82. /* TODO: redirect stderr to a log file and display here */
  83. fz_error_handle(app->ctx, error, "displaying error message to user");
  84. fz_strlcpy(msgbuf, "An error has occurred.\n\n", sizeof msgbuf);
  85. for (i = 0; i < fz_get_error_count(app->ctx); i++)
  86. {
  87. fz_strlcat(msgbuf, fz_get_error_line(app->ctx, i), sizeof msgbuf);
  88. fz_strlcat(msgbuf, "\n", sizeof msgbuf);
  89. }
  90. MessageBoxA(hwndframe, msgbuf, "MuPDF: Error", MB_ICONERROR);
  91. exit(1);
  92. }
  93. void win32error(pdfapp_t *app, char *msg)
  94. {
  95. LPSTR buf;
  96. int code = GetLastError();
  97. FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  98. FORMAT_MESSAGE_FROM_SYSTEM |
  99. FORMAT_MESSAGE_IGNORE_INSERTS,
  100. NULL,
  101. code,
  102. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  103. (LPSTR)&buf, 0, NULL);
  104. winerror(&gapp, fz_error_make(app->ctx, "%s:\n%s", msg, buf));
  105. }
  106. int winfilename(wchar_t *buf, int len)
  107. {
  108. OPENFILENAME ofn;
  109. buf[0] = 0;
  110. memset(&ofn, 0, sizeof(OPENFILENAME));
  111. ofn.lStructSize = sizeof(OPENFILENAME);
  112. ofn.hwndOwner = hwndframe;
  113. ofn.lpstrFile = buf;
  114. ofn.nMaxFile = len;
  115. ofn.lpstrInitialDir = NULL;
  116. ofn.lpstrTitle = L"MuPDF: Open PDF file";
  117. ofn.lpstrFilter = L"Documents (*.pdf;*.xps)\0*.xps;*.pdf\0PDF Files (*.pdf)\0*.pdf\0XPS Files (*.xps)\0*.xps\0All Files\0*\0\0";
  118. ofn.Flags = OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
  119. return GetOpenFileNameW(&ofn);
  120. }
  121. static char pd_filename[256] = "The file is encrypted.";
  122. static char pd_password[256] = "";
  123. static int pd_okay = 0;
  124. INT CALLBACK
  125. dlogpassproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  126. {
  127. switch(message)
  128. {
  129. case WM_INITDIALOG:
  130. SetDlgItemTextA(hwnd, 4, pd_filename);
  131. return TRUE;
  132. case WM_COMMAND:
  133. switch(wParam)
  134. {
  135. case 1:
  136. pd_okay = 1;
  137. GetDlgItemTextA(hwnd, 3, pd_password, sizeof pd_password);
  138. EndDialog(hwnd, 1);
  139. return TRUE;
  140. case 2:
  141. pd_okay = 0;
  142. EndDialog(hwnd, 1);
  143. return TRUE;
  144. }
  145. break;
  146. }
  147. return FALSE;
  148. }
  149. char *winpassword(pdfapp_t *app, char *filename)
  150. {
  151. char buf[1024], *s;
  152. int code;
  153. strcpy(buf, filename);
  154. s = buf;
  155. if (strrchr(s, '\\')) s = strrchr(s, '\\') + 1;
  156. if (strrchr(s, '/')) s = strrchr(s, '/') + 1;
  157. if (strlen(s) > 32)
  158. strcpy(s + 30, "...");
  159. sprintf(pd_filename, "The file \"%s\" is encrypted.", s);
  160. code = DialogBoxW(NULL, L"IDD_DLOGPASS", hwndframe, dlogpassproc);
  161. if (code <= 0)
  162. win32error(app, "cannot create password dialog");
  163. if (pd_okay)
  164. return pd_password;
  165. return NULL;
  166. }
  167. INT CALLBACK
  168. dloginfoproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  169. {
  170. char buf[256];
  171. pdf_xref *xref = gapp.xref;
  172. fz_obj *info, *obj;
  173. switch(message)
  174. {
  175. case WM_INITDIALOG:
  176. SetDlgItemTextW(hwnd, 0x10, wbuf);
  177. if (!xref)
  178. {
  179. SetDlgItemTextA(hwnd, 0x11, "XPS");
  180. SetDlgItemTextA(hwnd, 0x12, "None");
  181. SetDlgItemTextA(hwnd, 0x13, "n/a");
  182. return TRUE;
  183. }
  184. sprintf(buf, "PDF %d.%d", xref->version / 10, xref->version % 10);
  185. SetDlgItemTextA(hwnd, 0x11, buf);
  186. if (xref->crypt)
  187. {
  188. sprintf(buf, "Standard V%d %d-bit %s", pdf_get_crypt_revision(xref),
  189. pdf_get_crypt_length(xref), pdf_get_crypt_method(xref));
  190. SetDlgItemTextA(hwnd, 0x12, buf);
  191. strcpy(buf, "");
  192. if (pdf_has_permission(xref, PDF_PERM_PRINT))
  193. strcat(buf, "print, ");
  194. if (pdf_has_permission(xref, PDF_PERM_CHANGE))
  195. strcat(buf, "modify, ");
  196. if (pdf_has_permission(xref, PDF_PERM_COPY))
  197. strcat(buf, "copy, ");
  198. if (pdf_has_permission(xref, PDF_PERM_NOTES))
  199. strcat(buf, "annotate, ");
  200. if (strlen(buf) > 2)
  201. buf[strlen(buf)-2] = 0;
  202. else
  203. strcpy(buf, "none");
  204. SetDlgItemTextA(hwnd, 0x13, buf);
  205. }
  206. else
  207. {
  208. SetDlgItemTextA(hwnd, 0x12, "None");
  209. SetDlgItemTextA(hwnd, 0x13, "n/a");
  210. }
  211. info = fz_dict_gets(xref->ctx, xref->trailer, "Info");
  212. if (!info)
  213. return TRUE;
  214. #define SETUCS(ID) \
  215. { \
  216. unsigned short *ucs; \
  217. ucs = pdf_to_ucs2(xref->ctx, obj); \
  218. SetDlgItemTextW(hwnd, ID, ucs); \
  219. fz_free(context, ucs); \
  220. }
  221. if ((obj = fz_dict_gets(xref->ctx, info, "Title")))
  222. SETUCS(0x20);
  223. if ((obj = fz_dict_gets(xref->ctx, info, "Author")))
  224. SETUCS(0x21);
  225. if ((obj = fz_dict_gets(xref->ctx, info, "Subject")))
  226. SETUCS(0x22);
  227. if ((obj = fz_dict_gets(xref->ctx, info, "Keywords")))
  228. SETUCS(0x23);
  229. if ((obj = fz_dict_gets(xref->ctx, info, "Creator")))
  230. SETUCS(0x24);
  231. if ((obj = fz_dict_gets(xref->ctx, info, "Producer")))
  232. SETUCS(0x25);
  233. if ((obj = fz_dict_gets(xref->ctx, info, "CreationDate")))
  234. SETUCS(0x26);
  235. if ((obj = fz_dict_gets(xref->ctx, info, "ModDate")))
  236. SETUCS(0x27);
  237. return TRUE;
  238. case WM_COMMAND:
  239. EndDialog(hwnd, 1);
  240. return TRUE;
  241. }
  242. return FALSE;
  243. }
  244. void info(pdfapp_t *app)
  245. {
  246. int code = DialogBoxW(NULL, L"IDD_DLOGINFO", hwndframe, dloginfoproc);
  247. if (code <= 0)
  248. win32error(app, "cannot create info dialog");
  249. }
  250. INT CALLBACK
  251. dlogaboutproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  252. {
  253. switch(message)
  254. {
  255. case WM_INITDIALOG:
  256. SetDlgItemTextA(hwnd, 2, pdfapp_version(&gapp));
  257. SetDlgItemTextA(hwnd, 3, pdfapp_usage(&gapp));
  258. return TRUE;
  259. case WM_COMMAND:
  260. EndDialog(hwnd, 1);
  261. return TRUE;
  262. }
  263. return FALSE;
  264. }
  265. void winhelp(pdfapp_t *app)
  266. {
  267. int code = DialogBoxW(NULL, L"IDD_DLOGABOUT", hwndframe, dlogaboutproc);
  268. if (code <= 0)
  269. win32error(app, "cannot create help dialog");
  270. }
  271. /*
  272. * Main window
  273. */
  274. void winopen(pdfapp_t *app)
  275. {
  276. WNDCLASS wc;
  277. HMENU menu;
  278. RECT r;
  279. ATOM a;
  280. /* Create and register window frame class */
  281. memset(&wc, 0, sizeof(wc));
  282. wc.style = 0;
  283. wc.lpfnWndProc = frameproc;
  284. wc.cbClsExtra = 0;
  285. wc.cbWndExtra = 0;
  286. wc.hInstance = GetModuleHandle(NULL);
  287. wc.hIcon = LoadIconA(wc.hInstance, "IDI_ICONAPP");
  288. wc.hCursor = NULL; //LoadCursor(NULL, IDC_ARROW);
  289. wc.hbrBackground = NULL;
  290. wc.lpszMenuName = NULL;
  291. wc.lpszClassName = L"FrameWindow";
  292. a = RegisterClassW(&wc);
  293. if (!a)
  294. win32error(app, "cannot register frame window class");
  295. /* Create and register window view class */
  296. memset(&wc, 0, sizeof(wc));
  297. wc.style = CS_HREDRAW | CS_VREDRAW;
  298. wc.lpfnWndProc = viewproc;
  299. wc.cbClsExtra = 0;
  300. wc.cbWndExtra = 0;
  301. wc.hInstance = GetModuleHandle(NULL);
  302. wc.hIcon = NULL;
  303. wc.hCursor = NULL;
  304. wc.hbrBackground = NULL;
  305. wc.lpszMenuName = NULL;
  306. wc.lpszClassName = L"ViewWindow";
  307. a = RegisterClassW(&wc);
  308. if (!a)
  309. win32error(app, "cannot register view window class");
  310. /* Get screen size */
  311. SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
  312. gapp.scrw = r.right - r.left;
  313. gapp.scrh = r.bottom - r.top;
  314. /* Create cursors */
  315. arrowcurs = LoadCursor(NULL, IDC_ARROW);
  316. handcurs = LoadCursor(NULL, IDC_HAND);
  317. waitcurs = LoadCursor(NULL, IDC_WAIT);
  318. /* And a background color */
  319. bgbrush = CreateSolidBrush(RGB(0x70,0x70,0x70));
  320. shbrush = CreateSolidBrush(RGB(0x40,0x40,0x40));
  321. /* Init DIB info for buffer */
  322. dibinf = malloc(sizeof(BITMAPINFO) + 12);
  323. assert(dibinf != NULL);
  324. dibinf->bmiHeader.biSize = sizeof(dibinf->bmiHeader);
  325. dibinf->bmiHeader.biPlanes = 1;
  326. dibinf->bmiHeader.biBitCount = 32;
  327. dibinf->bmiHeader.biCompression = BI_RGB;
  328. dibinf->bmiHeader.biXPelsPerMeter = 2834;
  329. dibinf->bmiHeader.biYPelsPerMeter = 2834;
  330. dibinf->bmiHeader.biClrUsed = 0;
  331. dibinf->bmiHeader.biClrImportant = 0;
  332. dibinf->bmiHeader.biClrUsed = 0;
  333. /* Create window */
  334. hwndframe = CreateWindowW(L"FrameWindow", // window class name
  335. NULL, // window caption
  336. WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
  337. CW_USEDEFAULT, CW_USEDEFAULT, // initial position
  338. 300, // initial x size
  339. 300, // initial y size
  340. 0, // parent window handle
  341. 0, // window menu handle
  342. 0, // program instance handle
  343. 0); // creation parameters
  344. if (!hwndframe)
  345. win32error(app, "cannot create frame: %s");
  346. hwndview = CreateWindowW(L"ViewWindow", // window class name
  347. NULL,
  348. WS_VISIBLE | WS_CHILD,
  349. CW_USEDEFAULT, CW_USEDEFAULT,
  350. CW_USEDEFAULT, CW_USEDEFAULT,
  351. hwndframe, 0, 0, 0);
  352. if (!hwndview)
  353. win32error(app, "cannot create view: %s");
  354. hdc = NULL;
  355. SetWindowTextW(hwndframe, L"MuPDF");
  356. menu = GetSystemMenu(hwndframe, 0);
  357. AppendMenuW(menu, MF_SEPARATOR, 0, NULL);
  358. AppendMenuW(menu, MF_STRING, ID_ABOUT, L"About MuPDF...");
  359. AppendMenuW(menu, MF_STRING, ID_DOCINFO, L"Document Properties...");
  360. SetCursor(arrowcurs);
  361. }
  362. void winclose(pdfapp_t *app)
  363. {
  364. pdfapp_close(app);
  365. exit(0);
  366. }
  367. void wincursor(pdfapp_t *app, int curs)
  368. {
  369. if (curs == ARROW)
  370. SetCursor(arrowcurs);
  371. if (curs == HAND)
  372. SetCursor(handcurs);
  373. if (curs == WAIT)
  374. SetCursor(waitcurs);
  375. }
  376. void wintitle(pdfapp_t *app, char *title)
  377. {
  378. wchar_t wide[256], *dp;
  379. char *sp;
  380. int rune;
  381. dp = wide;
  382. sp = title;
  383. while (*sp && dp < wide + 255)
  384. {
  385. sp += chartorune(&rune, sp);
  386. *dp++ = rune;
  387. }
  388. *dp = 0;
  389. SetWindowTextW(hwndframe, wide);
  390. }
  391. void windrawrect(pdfapp_t *app, int x0, int y0, int x1, int y1)
  392. {
  393. RECT r;
  394. r.left = x0;
  395. r.top = y0;
  396. r.right = x1;
  397. r.bottom = y1;
  398. FillRect(hdc, &r, (HBRUSH)GetStockObject(WHITE_BRUSH));
  399. }
  400. void windrawstring(pdfapp_t *app, int x, int y, char *s)
  401. {
  402. HFONT font = (HFONT)GetStockObject(ANSI_FIXED_FONT);
  403. SelectObject(hdc, font);
  404. TextOutA(hdc, x, y - 12, s, strlen(s));
  405. }
  406. void winblitsearch()
  407. {
  408. if (gapp.isediting)
  409. {
  410. char buf[sizeof(gapp.search) + 50];
  411. sprintf(buf, "Search: %s", gapp.search);
  412. windrawrect(&gapp, 0, 0, gapp.winw, 30);
  413. windrawstring(&gapp, 10, 20, buf);
  414. }
  415. }
  416. void winblit()
  417. {
  418. int x0 = gapp.panx;
  419. int y0 = gapp.pany;
  420. int x1 = gapp.panx + gapp.image->w;
  421. int y1 = gapp.pany + gapp.image->h;
  422. RECT r;
  423. if (gapp.image)
  424. {
  425. if (gapp.iscopying || justcopied)
  426. {
  427. pdfapp_invert(&gapp, gapp.selr);
  428. justcopied = 1;
  429. }
  430. pdfapp_inverthit(&gapp);
  431. dibinf->bmiHeader.biWidth = gapp.image->w;
  432. dibinf->bmiHeader.biHeight = -gapp.image->h;
  433. dibinf->bmiHeader.biSizeImage = gapp.image->h * 4;
  434. if (gapp.image->n == 2)
  435. {
  436. int i = gapp.image->w * gapp.image->h;
  437. unsigned char *color = malloc(i*4);
  438. unsigned char *s = gapp.image->samples;
  439. unsigned char *d = color;
  440. for (; i > 0 ; i--)
  441. {
  442. d[2] = d[1] = d[0] = *s++;
  443. d[3] = *s++;
  444. d += 4;
  445. }
  446. SetDIBitsToDevice(hdc,
  447. gapp.panx, gapp.pany, gapp.image->w, gapp.image->h,
  448. 0, 0, 0, gapp.image->h, color,
  449. dibinf, DIB_RGB_COLORS);
  450. free(color);
  451. }
  452. if (gapp.image->n == 4)
  453. {
  454. SetDIBitsToDevice(hdc,
  455. gapp.panx, gapp.pany, gapp.image->w, gapp.image->h,
  456. 0, 0, 0, gapp.image->h, gapp.image->samples,
  457. dibinf, DIB_RGB_COLORS);
  458. }
  459. pdfapp_inverthit(&gapp);
  460. if (gapp.iscopying || justcopied)
  461. {
  462. pdfapp_invert(&gapp, gapp.selr);
  463. justcopied = 1;
  464. }
  465. }
  466. /* Grey background */
  467. r.top = 0; r.bottom = gapp.winh;
  468. r.left = 0; r.right = x0;
  469. FillRect(hdc, &r, bgbrush);
  470. r.left = x1; r.right = gapp.winw;
  471. FillRect(hdc, &r, bgbrush);
  472. r.left = 0; r.right = gapp.winw;
  473. r.top = 0; r.bottom = y0;
  474. FillRect(hdc, &r, bgbrush);
  475. r.top = y1; r.bottom = gapp.winh;
  476. FillRect(hdc, &r, bgbrush);
  477. /* Drop shadow */
  478. r.left = x0 + 2;
  479. r.right = x1 + 2;
  480. r.top = y1;
  481. r.bottom = y1 + 2;
  482. FillRect(hdc, &r, shbrush);
  483. r.left = x1;
  484. r.right = x1 + 2;
  485. r.top = y0 + 2;
  486. r.bottom = y1;
  487. FillRect(hdc, &r, shbrush);
  488. winblitsearch();
  489. }
  490. void winresize(pdfapp_t *app, int w, int h)
  491. {
  492. ShowWindow(hwndframe, SW_SHOWDEFAULT);
  493. w += GetSystemMetrics(SM_CXFRAME) * 2;
  494. h += GetSystemMetrics(SM_CYFRAME) * 2;
  495. h += GetSystemMetrics(SM_CYCAPTION);
  496. SetWindowPos(hwndframe, 0, 0, 0, w, h, SWP_NOZORDER | SWP_NOMOVE);
  497. }
  498. void winrepaint(pdfapp_t *app)
  499. {
  500. InvalidateRect(hwndview, NULL, 0);
  501. }
  502. void winrepaintsearch(pdfapp_t *app)
  503. {
  504. // TODO: invalidate only search area and
  505. // call only search redraw routine.
  506. InvalidateRect(hwndview, NULL, 0);
  507. }
  508. /*
  509. * Event handling
  510. */
  511. void windocopy(pdfapp_t *app)
  512. {
  513. HGLOBAL handle;
  514. unsigned short *ucsbuf;
  515. if (!OpenClipboard(hwndframe))
  516. return;
  517. EmptyClipboard();
  518. handle = GlobalAlloc(GMEM_MOVEABLE, 4096 * sizeof(unsigned short));
  519. if (!handle)
  520. {
  521. CloseClipboard();
  522. return;
  523. }
  524. ucsbuf = GlobalLock(handle);
  525. pdfapp_oncopy(&gapp, ucsbuf, 4096);
  526. GlobalUnlock(handle);
  527. SetClipboardData(CF_UNICODETEXT, handle);
  528. CloseClipboard();
  529. justcopied = 1; /* keep inversion around for a while... */
  530. }
  531. void winreloadfile(pdfapp_t *app)
  532. {
  533. int fd;
  534. pdfapp_close(app);
  535. fd = _wopen(wbuf, O_BINARY | O_RDONLY, 0666);
  536. if (fd < 0)
  537. winerror(&gapp, fz_error_make(app->ctx, "cannot reload file '%s'", filename));
  538. pdfapp_open(app, filename, fd, 1);
  539. }
  540. void winopenuri(pdfapp_t *app, char *buf)
  541. {
  542. ShellExecuteA(hwndframe, "open", buf, 0, 0, SW_SHOWNORMAL);
  543. }
  544. void handlekey(int c)
  545. {
  546. if (GetCapture() == hwndview)
  547. return;
  548. if (justcopied)
  549. {
  550. justcopied = 0;
  551. winrepaint(&gapp);
  552. }
  553. /* translate VK into ascii equivalents */
  554. if (c > 256)
  555. {
  556. switch (c - 256)
  557. {
  558. case VK_F1: c = '?'; break;
  559. case VK_ESCAPE: c = '\033'; break;
  560. case VK_DOWN: c = 'j'; break;
  561. case VK_UP: c = 'k'; break;
  562. case VK_LEFT: c = 'b'; break;
  563. case VK_RIGHT: c = ' '; break;
  564. case VK_PRIOR: c = ','; break;
  565. case VK_NEXT: c = '.'; break;
  566. }
  567. }
  568. pdfapp_onkey(&gapp, c);
  569. winrepaint(&gapp);
  570. }
  571. void handlemouse(int x, int y, int btn, int state)
  572. {
  573. if (state != 0 && justcopied)
  574. {
  575. justcopied = 0;
  576. winrepaint(&gapp);
  577. }
  578. if (state == 1)
  579. SetCapture(hwndview);
  580. if (state == -1)
  581. ReleaseCapture();
  582. pdfapp_onmouse(&gapp, x, y, btn, 0, state);
  583. }
  584. LRESULT CALLBACK
  585. frameproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  586. {
  587. switch(message)
  588. {
  589. case WM_SETFOCUS:
  590. PostMessage(hwnd, WM_APP+5, 0, 0);
  591. return 0;
  592. case WM_APP+5:
  593. SetFocus(hwndview);
  594. return 0;
  595. case WM_DESTROY:
  596. PostQuitMessage(0);
  597. return 0;
  598. case WM_SYSCOMMAND:
  599. if (wParam == ID_ABOUT)
  600. {
  601. winhelp(&gapp);
  602. return 0;
  603. }
  604. if (wParam == ID_DOCINFO)
  605. {
  606. info(&gapp);
  607. return 0;
  608. }
  609. if (wParam == SC_MAXIMIZE)
  610. gapp.shrinkwrap = 0;
  611. break;
  612. case WM_SIZE:
  613. {
  614. // More generally, you should use GetEffectiveClientRect
  615. // if you have a toolbar etc.
  616. RECT rect;
  617. GetClientRect(hwnd, &rect);
  618. MoveWindow(hwndview, rect.left, rect.top,
  619. rect.right-rect.left, rect.bottom-rect.top, TRUE);
  620. return 0;
  621. }
  622. case WM_SIZING:
  623. gapp.shrinkwrap = 0;
  624. break;
  625. case WM_NOTIFY:
  626. case WM_COMMAND:
  627. return SendMessage(hwndview, message, wParam, lParam);
  628. }
  629. return DefWindowProc(hwnd, message, wParam, lParam);
  630. }
  631. LRESULT CALLBACK
  632. viewproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  633. {
  634. static int oldx = 0;
  635. static int oldy = 0;
  636. int x = (signed short) LOWORD(lParam);
  637. int y = (signed short) HIWORD(lParam);
  638. switch (message)
  639. {
  640. case WM_SIZE:
  641. if (wParam == SIZE_MINIMIZED)
  642. return 0;
  643. if (wParam == SIZE_MAXIMIZED)
  644. gapp.shrinkwrap = 0;
  645. pdfapp_onresize(&gapp, LOWORD(lParam), HIWORD(lParam));
  646. break;
  647. /* Paint events are low priority and automagically catenated
  648. * so we don't need to do any fancy waiting to defer repainting.
  649. */
  650. case WM_PAINT:
  651. {
  652. //puts("WM_PAINT");
  653. PAINTSTRUCT ps;
  654. hdc = BeginPaint(hwnd, &ps);
  655. winblit();
  656. hdc = NULL;
  657. EndPaint(hwnd, &ps);
  658. return 0;
  659. }
  660. case WM_ERASEBKGND:
  661. return 1; // well, we don't need to erase to redraw cleanly
  662. /* Mouse events */
  663. case WM_LBUTTONDOWN:
  664. SetFocus(hwndview);
  665. oldx = x; oldy = y;
  666. handlemouse(x, y, 1, 1);
  667. return 0;
  668. case WM_MBUTTONDOWN:
  669. SetFocus(hwndview);
  670. oldx = x; oldy = y;
  671. handlemouse(x, y, 2, 1);
  672. return 0;
  673. case WM_RBUTTONDOWN:
  674. SetFocus(hwndview);
  675. oldx = x; oldy = y;
  676. handlemouse(x, y, 3, 1);
  677. return 0;
  678. case WM_LBUTTONUP:
  679. oldx = x; oldy = y;
  680. handlemouse(x, y, 1, -1);
  681. return 0;
  682. case WM_MBUTTONUP:
  683. oldx = x; oldy = y;
  684. handlemouse(x, y, 2, -1);
  685. return 0;
  686. case WM_RBUTTONUP:
  687. oldx = x; oldy = y;
  688. handlemouse(x, y, 3, -1);
  689. return 0;
  690. case WM_MOUSEMOVE:
  691. oldx = x; oldy = y;
  692. handlemouse(x, y, 0, 0);
  693. return 0;
  694. /* Mouse wheel */
  695. case WM_MOUSEWHEEL:
  696. if ((signed short)HIWORD(wParam) > 0)
  697. handlekey(LOWORD(wParam) & MK_SHIFT ? '+' : 'k');
  698. else
  699. handlekey(LOWORD(wParam) & MK_SHIFT ? '-' : 'j');
  700. return 0;
  701. /* Keyboard events */
  702. case WM_KEYDOWN:
  703. /* only handle special keys */
  704. switch (wParam)
  705. {
  706. case VK_F1:
  707. case VK_LEFT:
  708. case VK_UP:
  709. case VK_PRIOR:
  710. case VK_RIGHT:
  711. case VK_DOWN:
  712. case VK_NEXT:
  713. case VK_ESCAPE:
  714. handlekey(wParam + 256);
  715. handlemouse(oldx, oldy, 0, 0); /* update cursor */
  716. return 0;
  717. }
  718. return 1;
  719. /* unicode encoded chars, including escape, backspace etc... */
  720. case WM_CHAR:
  721. if (wParam < 256)
  722. {
  723. handlekey(wParam);
  724. handlemouse(oldx, oldy, 0, 0); /* update cursor */
  725. }
  726. return 0;
  727. }
  728. fflush(stdout);
  729. /* Pass on unhandled events to Windows */
  730. return DefWindowProc(hwnd, message, wParam, lParam);
  731. }
  732. int WINAPI
  733. WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
  734. {
  735. int argc;
  736. LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &argc);
  737. char argv0[256];
  738. MSG msg;
  739. int fd;
  740. int code;
  741. fz_context *ctx;
  742. fz_accelerate();
  743. ctx = fz_context_init(&fz_alloc_default);
  744. if (ctx == NULL)
  745. {
  746. fprintf(stderr, "Failed to init context");
  747. exit(1);
  748. }
  749. pdfapp_init(ctx, &gapp);
  750. GetModuleFileNameA(NULL, argv0, sizeof argv0);
  751. install_app(argv0);
  752. winopen(&gapp);
  753. if (argc == 2)
  754. {
  755. wcscpy(wbuf, argv[1]);
  756. }
  757. else
  758. {
  759. if (!winfilename(wbuf, nelem(wbuf)))
  760. exit(0);
  761. }
  762. fd = _wopen(wbuf, O_BINARY | O_RDONLY, 0666);
  763. if (fd < 0)
  764. winerror(&gapp, fz_error_make(ctx, "cannot open file '%s'", filename));
  765. code = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, filename, sizeof filename, NULL, NULL);
  766. if (code == 0)
  767. win32error(&gapp, "cannot convert filename to utf-8");
  768. pdfapp_open(&gapp, filename, fd, 0);
  769. while (GetMessage(&msg, NULL, 0, 0))
  770. {
  771. TranslateMessage(&msg);
  772. DispatchMessage(&msg);
  773. }
  774. pdfapp_close(&gapp);
  775. return 0;
  776. }