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