comparison mupdf-source/platform/x11/win_main.c @ 2:b50eed0cc0ef upstream

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