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