summaryrefslogtreecommitdiff
path: root/platform/x11/win_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'platform/x11/win_main.c')
-rw-r--r--platform/x11/win_main.c1163
1 files changed, 1163 insertions, 0 deletions
diff --git a/platform/x11/win_main.c b/platform/x11/win_main.c
new file mode 100644
index 00000000..bf765d6b
--- /dev/null
+++ b/platform/x11/win_main.c
@@ -0,0 +1,1163 @@
+#include "pdfapp.h"
+
+#ifndef UNICODE
+#define UNICODE
+#endif
+#ifndef _UNICODE
+#define _UNICODE
+#endif
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <commdlg.h>
+#include <shellapi.h>
+
+#ifndef WM_MOUSEWHEEL
+#define WM_MOUSEWHEEL 0x020A
+#endif
+
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+
+#define ID_ABOUT 0x1000
+#define ID_DOCINFO 0x1001
+
+static HWND hwndframe = NULL;
+static HWND hwndview = NULL;
+static HDC hdc;
+static HBRUSH bgbrush;
+static HBRUSH shbrush;
+static BITMAPINFO *dibinf;
+static HCURSOR arrowcurs, handcurs, waitcurs, caretcurs;
+static LRESULT CALLBACK frameproc(HWND, UINT, WPARAM, LPARAM);
+static LRESULT CALLBACK viewproc(HWND, UINT, WPARAM, LPARAM);
+static int timer_pending = 0;
+
+static int justcopied = 0;
+
+static pdfapp_t gapp;
+
+#define PATH_MAX (1024)
+
+static wchar_t wbuf[PATH_MAX];
+static char filename[PATH_MAX];
+
+/*
+ * Create registry keys to associate MuPDF with PDF and XPS files.
+ */
+
+#define OPEN_KEY(parent, name, ptr) \
+ RegCreateKeyExA(parent, name, 0, 0, 0, KEY_WRITE, 0, &ptr, 0)
+
+#define SET_KEY(parent, name, value) \
+ RegSetValueExA(parent, name, 0, REG_SZ, (const BYTE *)(value), strlen(value) + 1)
+
+void install_app(char *argv0)
+{
+ char buf[512];
+ HKEY software, classes, mupdf, dotpdf, dotxps;
+ HKEY shell, open, command, supported_types;
+ HKEY pdf_progids, xps_progids;
+
+ OPEN_KEY(HKEY_CURRENT_USER, "Software", software);
+ OPEN_KEY(software, "Classes", classes);
+ OPEN_KEY(classes, ".pdf", dotpdf);
+ OPEN_KEY(dotpdf, "OpenWithProgids", pdf_progids);
+ OPEN_KEY(classes, ".xps", dotxps);
+ OPEN_KEY(dotxps, "OpenWithProgids", xps_progids);
+ OPEN_KEY(classes, "MuPDF", mupdf);
+ OPEN_KEY(mupdf, "SupportedTypes", supported_types);
+ OPEN_KEY(mupdf, "shell", shell);
+ OPEN_KEY(shell, "open", open);
+ OPEN_KEY(open, "command", command);
+
+ sprintf(buf, "\"%s\" \"%%1\"", argv0);
+
+ SET_KEY(open, "FriendlyAppName", "MuPDF");
+ SET_KEY(command, "", buf);
+ SET_KEY(supported_types, ".pdf", "");
+ SET_KEY(supported_types, ".xps", "");
+ SET_KEY(pdf_progids, "MuPDF", "");
+ SET_KEY(xps_progids, "MuPDF", "");
+
+ RegCloseKey(dotxps);
+ RegCloseKey(dotpdf);
+ RegCloseKey(mupdf);
+ RegCloseKey(classes);
+ RegCloseKey(software);
+}
+
+/*
+ * Dialog boxes
+ */
+
+void winwarn(pdfapp_t *app, char *msg)
+{
+ MessageBoxA(hwndframe, msg, "MuPDF: Warning", MB_ICONWARNING);
+}
+
+void winerror(pdfapp_t *app, char *msg)
+{
+ MessageBoxA(hwndframe, msg, "MuPDF: Error", MB_ICONERROR);
+ exit(1);
+}
+
+void winalert(pdfapp_t *app, pdf_alert_event *alert)
+{
+ int buttons = MB_OK;
+ int icon = MB_ICONWARNING;
+ int pressed = PDF_ALERT_BUTTON_NONE;
+
+ switch (alert->icon_type)
+ {
+ case PDF_ALERT_ICON_ERROR:
+ icon = MB_ICONERROR;
+ break;
+ case PDF_ALERT_ICON_WARNING:
+ icon = MB_ICONWARNING;
+ break;
+ case PDF_ALERT_ICON_QUESTION:
+ icon = MB_ICONQUESTION;
+ break;
+ case PDF_ALERT_ICON_STATUS:
+ icon = MB_ICONINFORMATION;
+ break;
+ }
+
+ switch (alert->button_group_type)
+ {
+ case PDF_ALERT_BUTTON_GROUP_OK:
+ buttons = MB_OK;
+ break;
+ case PDF_ALERT_BUTTON_GROUP_OK_CANCEL:
+ buttons = MB_OKCANCEL;
+ break;
+ case PDF_ALERT_BUTTON_GROUP_YES_NO:
+ buttons = MB_YESNO;
+ break;
+ case PDF_ALERT_BUTTON_GROUP_YES_NO_CANCEL:
+ buttons = MB_YESNOCANCEL;
+ break;
+ }
+
+ pressed = MessageBoxA(hwndframe, alert->message, alert->title, icon|buttons);
+
+ switch (pressed)
+ {
+ case IDOK:
+ alert->button_pressed = PDF_ALERT_BUTTON_OK;
+ break;
+ case IDCANCEL:
+ alert->button_pressed = PDF_ALERT_BUTTON_CANCEL;
+ break;
+ case IDNO:
+ alert->button_pressed = PDF_ALERT_BUTTON_NO;
+ break;
+ case IDYES:
+ alert->button_pressed = PDF_ALERT_BUTTON_YES;
+ }
+}
+
+void winprint(pdfapp_t *app)
+{
+ MessageBoxA(hwndframe, "The MuPDF library supports printing, but this application currently does not", "Print document", MB_ICONWARNING);
+}
+
+int winsavequery(pdfapp_t *app)
+{
+ switch(MessageBoxA(hwndframe, "File has unsaved changes. Do you want to save", "MuPDF", MB_YESNOCANCEL))
+ {
+ case IDYES: return SAVE;
+ case IDNO: return DISCARD;
+ default: return CANCEL;
+ }
+}
+
+int winfilename(wchar_t *buf, int len)
+{
+ OPENFILENAME ofn;
+ buf[0] = 0;
+ memset(&ofn, 0, sizeof(OPENFILENAME));
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = hwndframe;
+ ofn.lpstrFile = buf;
+ ofn.nMaxFile = len;
+ ofn.lpstrInitialDir = NULL;
+ ofn.lpstrTitle = L"MuPDF: Open PDF file";
+ 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";
+ ofn.Flags = OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
+ return GetOpenFileNameW(&ofn);
+}
+
+int wingetsavepath(pdfapp_t *app, char *buf, int len)
+{
+ wchar_t twbuf[PATH_MAX];
+ OPENFILENAME ofn;
+
+ wcscpy(twbuf, wbuf);
+ memset(&ofn, 0, sizeof(OPENFILENAME));
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = hwndframe;
+ ofn.lpstrFile = twbuf;
+ ofn.nMaxFile = PATH_MAX;
+ ofn.lpstrInitialDir = NULL;
+ ofn.lpstrTitle = L"MuPDF: Save PDF file";
+ 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";
+ ofn.Flags = OFN_HIDEREADONLY;
+ if (GetSaveFileName(&ofn))
+ {
+ int code = WideCharToMultiByte(CP_UTF8, 0, twbuf, -1, buf, MIN(PATH_MAX, len), NULL, NULL);
+ if (code == 0)
+ {
+ winerror(&gapp, "cannot convert filename to utf-8");
+ return 0;
+ }
+
+ wcscpy(wbuf, twbuf);
+ strcpy(filename, buf);
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void winreplacefile(char *source, char *target)
+{
+ wchar_t wsource[PATH_MAX];
+ wchar_t wtarget[PATH_MAX];
+
+ int sz = MultiByteToWideChar(CP_UTF8, 0, source, -1, wsource, PATH_MAX);
+ if (sz == 0)
+ {
+ winerror(&gapp, "cannot convert filename to Unicode");
+ return;
+ }
+
+ sz = MultiByteToWideChar(CP_UTF8, 0, target, -1, wtarget, PATH_MAX);
+ if (sz == 0)
+ {
+ winerror(&gapp, "cannot convert filename to Unicode");
+ return;
+ }
+
+#if (_WIN32_WINNT >= 0x0500)
+ ReplaceFile(wtarget, wsource, NULL, REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL);
+#else
+ DeleteFile(wtarget);
+ MoveFile(wsource, wtarget);
+#endif
+}
+
+static char pd_filename[256] = "The file is encrypted.";
+static char pd_password[256] = "";
+static wchar_t pd_passwordw[256] = {0};
+static char td_textinput[1024] = "";
+static int td_retry = 0;
+static int cd_nopts;
+static int *cd_nvals;
+static char **cd_opts;
+static char **cd_vals;
+static int pd_okay = 0;
+
+INT CALLBACK
+dlogpassproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch(message)
+ {
+ case WM_INITDIALOG:
+ SetDlgItemTextA(hwnd, 4, pd_filename);
+ return TRUE;
+ case WM_COMMAND:
+ switch(wParam)
+ {
+ case 1:
+ pd_okay = 1;
+ GetDlgItemTextW(hwnd, 3, pd_passwordw, nelem(pd_passwordw));
+ EndDialog(hwnd, 1);
+ WideCharToMultiByte(CP_UTF8, 0, pd_passwordw, -1, pd_password, sizeof pd_password, NULL, NULL);
+ return TRUE;
+ case 2:
+ pd_okay = 0;
+ EndDialog(hwnd, 1);
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+INT CALLBACK
+dlogtextproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch(message)
+ {
+ case WM_INITDIALOG:
+ SetDlgItemTextA(hwnd, 3, td_textinput);
+ if (!td_retry)
+ ShowWindow(GetDlgItem(hwnd, 4), SW_HIDE);
+ return TRUE;
+ case WM_COMMAND:
+ switch(wParam)
+ {
+ case 1:
+ pd_okay = 1;
+ GetDlgItemTextA(hwnd, 3, td_textinput, sizeof td_textinput);
+ EndDialog(hwnd, 1);
+ return TRUE;
+ case 2:
+ pd_okay = 0;
+ EndDialog(hwnd, 1);
+ return TRUE;
+ }
+ break;
+ case WM_CTLCOLORSTATIC:
+ if ((HWND)lParam == GetDlgItem(hwnd, 4))
+ {
+ SetTextColor((HDC)wParam, RGB(255,0,0));
+ SetBkMode((HDC)wParam, TRANSPARENT);
+
+ return (INT)GetStockObject(NULL_BRUSH);
+ }
+ break;
+ }
+ return FALSE;
+}
+
+INT CALLBACK
+dlogchoiceproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ HWND listbox;
+ int i;
+ int item;
+ int sel;
+ switch(message)
+ {
+ case WM_INITDIALOG:
+ listbox = GetDlgItem(hwnd, 3);
+ for (i = 0; i < cd_nopts; i++)
+ SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)cd_opts[i]);
+
+ /* FIXME: handle multiple select */
+ if (*cd_nvals > 0)
+ {
+ item = SendMessageA(listbox, LB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)cd_vals[0]);
+ if (item != LB_ERR)
+ SendMessageA(listbox, LB_SETCURSEL, item, 0);
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch(wParam)
+ {
+ case 1:
+ listbox = GetDlgItem(hwnd, 3);
+ *cd_nvals = 0;
+ for (i = 0; i < cd_nopts; i++)
+ {
+ item = SendMessageA(listbox, LB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)cd_opts[i]);
+ sel = SendMessageA(listbox, LB_GETSEL, item, 0);
+ if (sel && sel != LB_ERR)
+ cd_vals[(*cd_nvals)++] = cd_opts[i];
+ }
+ pd_okay = 1;
+ EndDialog(hwnd, 1);
+ return TRUE;
+ case 2:
+ pd_okay = 0;
+ EndDialog(hwnd, 1);
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+char *winpassword(pdfapp_t *app, char *filename)
+{
+ char buf[1024], *s;
+ int code;
+ strcpy(buf, filename);
+ s = buf;
+ if (strrchr(s, '\\')) s = strrchr(s, '\\') + 1;
+ if (strrchr(s, '/')) s = strrchr(s, '/') + 1;
+ if (strlen(s) > 32)
+ strcpy(s + 30, "...");
+ sprintf(pd_filename, "The file \"%s\" is encrypted.", s);
+ code = DialogBoxW(NULL, L"IDD_DLOGPASS", hwndframe, dlogpassproc);
+ if (code <= 0)
+ winerror(app, "cannot create password dialog");
+ if (pd_okay)
+ return pd_password;
+ return NULL;
+}
+
+char *wintextinput(pdfapp_t *app, char *inittext, int retry)
+{
+ int code;
+ td_retry = retry;
+ fz_strlcpy(td_textinput, inittext ? inittext : "", sizeof td_textinput);
+ code = DialogBoxW(NULL, L"IDD_DLOGTEXT", hwndframe, dlogtextproc);
+ if (code <= 0)
+ winerror(app, "cannot create text input dialog");
+ if (pd_okay)
+ return td_textinput;
+ return NULL;
+}
+
+int winchoiceinput(pdfapp_t *app, int nopts, char *opts[], int *nvals, char *vals[])
+{
+ int code;
+ cd_nopts = nopts;
+ cd_nvals = nvals;
+ cd_opts = opts;
+ cd_vals = vals;
+ code = DialogBoxW(NULL, L"IDD_DLOGLIST", hwndframe, dlogchoiceproc);
+ if (code <= 0)
+ winerror(app, "cannot create text input dialog");
+ return pd_okay;
+}
+
+INT CALLBACK
+dloginfoproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ char buf[256];
+ fz_document *doc = gapp.doc;
+
+ switch(message)
+ {
+ case WM_INITDIALOG:
+
+ SetDlgItemTextW(hwnd, 0x10, wbuf);
+
+ if (fz_meta(doc, FZ_META_FORMAT_INFO, buf, 256) < 0)
+ {
+ SetDlgItemTextA(hwnd, 0x11, "Unknown");
+ SetDlgItemTextA(hwnd, 0x12, "None");
+ SetDlgItemTextA(hwnd, 0x13, "n/a");
+ return TRUE;
+ }
+
+ SetDlgItemTextA(hwnd, 0x11, buf);
+
+ if (fz_meta(doc, FZ_META_CRYPT_INFO, buf, 256) == 0)
+ {
+ SetDlgItemTextA(hwnd, 0x12, buf);
+ }
+ else
+ {
+ SetDlgItemTextA(hwnd, 0x12, "None");
+ }
+ buf[0] = 0;
+ if (fz_meta(doc, FZ_META_HAS_PERMISSION, NULL, FZ_PERMISSION_PRINT) == 0)
+ strcat(buf, "print, ");
+ if (fz_meta(doc, FZ_META_HAS_PERMISSION, NULL, FZ_PERMISSION_CHANGE) == 0)
+ strcat(buf, "modify, ");
+ if (fz_meta(doc, FZ_META_HAS_PERMISSION, NULL, FZ_PERMISSION_COPY) == 0)
+ strcat(buf, "copy, ");
+ if (fz_meta(doc, FZ_META_HAS_PERMISSION, NULL, FZ_PERMISSION_NOTES) == 0)
+ strcat(buf, "annotate, ");
+ if (strlen(buf) > 2)
+ buf[strlen(buf)-2] = 0;
+ else
+ strcpy(buf, "None");
+ SetDlgItemTextA(hwnd, 0x13, buf);
+
+#define SETUTF8(ID, STRING) \
+ { \
+ *(char **)buf = STRING; \
+ if (fz_meta(doc, FZ_META_INFO, buf, 256) <= 0) \
+ buf[0] = 0; \
+ SetDlgItemTextA(hwnd, ID, buf); \
+ }
+
+ SETUTF8(0x20, "Title");
+ SETUTF8(0x21, "Author");
+ SETUTF8(0x22, "Subject");
+ SETUTF8(0x23, "Keywords");
+ SETUTF8(0x24, "Creator");
+ SETUTF8(0x25, "Producer");
+ SETUTF8(0x26, "CreationDate");
+ SETUTF8(0x27, "ModDate");
+ return TRUE;
+
+ case WM_COMMAND:
+ EndDialog(hwnd, 1);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void info()
+{
+ int code = DialogBoxW(NULL, L"IDD_DLOGINFO", hwndframe, dloginfoproc);
+ if (code <= 0)
+ winerror(&gapp, "cannot create info dialog");
+}
+
+INT CALLBACK
+dlogaboutproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch(message)
+ {
+ case WM_INITDIALOG:
+ SetDlgItemTextA(hwnd, 2, pdfapp_version(&gapp));
+ SetDlgItemTextA(hwnd, 3, pdfapp_usage(&gapp));
+ return TRUE;
+ case WM_COMMAND:
+ EndDialog(hwnd, 1);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void winhelp(pdfapp_t*app)
+{
+ int code = DialogBoxW(NULL, L"IDD_DLOGABOUT", hwndframe, dlogaboutproc);
+ if (code <= 0)
+ winerror(&gapp, "cannot create help dialog");
+}
+
+/*
+ * Main window
+ */
+
+void winopen()
+{
+ WNDCLASS wc;
+ HMENU menu;
+ RECT r;
+ ATOM a;
+
+ /* Create and register window frame class */
+ memset(&wc, 0, sizeof(wc));
+ wc.style = 0;
+ wc.lpfnWndProc = frameproc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = GetModuleHandle(NULL);
+ wc.hIcon = LoadIconA(wc.hInstance, "IDI_ICONAPP");
+ wc.hCursor = NULL; //LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = L"FrameWindow";
+ a = RegisterClassW(&wc);
+ if (!a)
+ winerror(&gapp, "cannot register frame window class");
+
+ /* Create and register window view class */
+ memset(&wc, 0, sizeof(wc));
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc = viewproc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = GetModuleHandle(NULL);
+ wc.hIcon = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = L"ViewWindow";
+ a = RegisterClassW(&wc);
+ if (!a)
+ winerror(&gapp, "cannot register view window class");
+
+ /* Get screen size */
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
+ gapp.scrw = r.right - r.left;
+ gapp.scrh = r.bottom - r.top;
+
+ /* Create cursors */
+ arrowcurs = LoadCursor(NULL, IDC_ARROW);
+ handcurs = LoadCursor(NULL, IDC_HAND);
+ waitcurs = LoadCursor(NULL, IDC_WAIT);
+ caretcurs = LoadCursor(NULL, IDC_IBEAM);
+
+ /* And a background color */
+ bgbrush = CreateSolidBrush(RGB(0x70,0x70,0x70));
+ shbrush = CreateSolidBrush(RGB(0x40,0x40,0x40));
+
+ /* Init DIB info for buffer */
+ dibinf = malloc(sizeof(BITMAPINFO) + 12);
+ assert(dibinf);
+ dibinf->bmiHeader.biSize = sizeof(dibinf->bmiHeader);
+ dibinf->bmiHeader.biPlanes = 1;
+ dibinf->bmiHeader.biBitCount = 32;
+ dibinf->bmiHeader.biCompression = BI_RGB;
+ dibinf->bmiHeader.biXPelsPerMeter = 2834;
+ dibinf->bmiHeader.biYPelsPerMeter = 2834;
+ dibinf->bmiHeader.biClrUsed = 0;
+ dibinf->bmiHeader.biClrImportant = 0;
+ dibinf->bmiHeader.biClrUsed = 0;
+
+ /* Create window */
+ hwndframe = CreateWindowW(L"FrameWindow", // window class name
+ NULL, // window caption
+ WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
+ CW_USEDEFAULT, CW_USEDEFAULT, // initial position
+ 300, // initial x size
+ 300, // initial y size
+ 0, // parent window handle
+ 0, // window menu handle
+ 0, // program instance handle
+ 0); // creation parameters
+ if (!hwndframe)
+ winerror(&gapp, "cannot create frame");
+
+ hwndview = CreateWindowW(L"ViewWindow", // window class name
+ NULL,
+ WS_VISIBLE | WS_CHILD,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ hwndframe, 0, 0, 0);
+ if (!hwndview)
+ winerror(&gapp, "cannot create view");
+
+ hdc = NULL;
+
+ SetWindowTextW(hwndframe, L"MuPDF");
+
+ menu = GetSystemMenu(hwndframe, 0);
+ AppendMenuW(menu, MF_SEPARATOR, 0, NULL);
+ AppendMenuW(menu, MF_STRING, ID_ABOUT, L"About MuPDF...");
+ AppendMenuW(menu, MF_STRING, ID_DOCINFO, L"Document Properties...");
+
+ SetCursor(arrowcurs);
+}
+
+void winclose(pdfapp_t *app)
+{
+ if (pdfapp_preclose(app))
+ {
+ pdfapp_close(app);
+ exit(0);
+ }
+}
+
+void wincursor(pdfapp_t *app, int curs)
+{
+ if (curs == ARROW)
+ SetCursor(arrowcurs);
+ if (curs == HAND)
+ SetCursor(handcurs);
+ if (curs == WAIT)
+ SetCursor(waitcurs);
+ if (curs == CARET)
+ SetCursor(caretcurs);
+}
+
+void wintitle(pdfapp_t *app, char *title)
+{
+ wchar_t wide[256], *dp;
+ char *sp;
+ int rune;
+
+ dp = wide;
+ sp = title;
+ while (*sp && dp < wide + 255)
+ {
+ sp += fz_chartorune(&rune, sp);
+ *dp++ = rune;
+ }
+ *dp = 0;
+
+ SetWindowTextW(hwndframe, wide);
+}
+
+void windrawrect(pdfapp_t *app, int x0, int y0, int x1, int y1)
+{
+ RECT r;
+ r.left = x0;
+ r.top = y0;
+ r.right = x1;
+ r.bottom = y1;
+ FillRect(hdc, &r, (HBRUSH)GetStockObject(WHITE_BRUSH));
+}
+
+void windrawstring(pdfapp_t *app, int x, int y, char *s)
+{
+ HFONT font = (HFONT)GetStockObject(ANSI_FIXED_FONT);
+ SelectObject(hdc, font);
+ TextOutA(hdc, x, y - 12, s, strlen(s));
+}
+
+void winblitsearch()
+{
+ if (gapp.isediting)
+ {
+ char buf[sizeof(gapp.search) + 50];
+ sprintf(buf, "Search: %s", gapp.search);
+ windrawrect(&gapp, 0, 0, gapp.winw, 30);
+ windrawstring(&gapp, 10, 20, buf);
+ }
+}
+
+void winblit()
+{
+ int image_w = fz_pixmap_width(gapp.ctx, gapp.image);
+ int image_h = fz_pixmap_height(gapp.ctx, gapp.image);
+ int image_n = fz_pixmap_components(gapp.ctx, gapp.image);
+ unsigned char *samples = fz_pixmap_samples(gapp.ctx, gapp.image);
+ int x0 = gapp.panx;
+ int y0 = gapp.pany;
+ int x1 = gapp.panx + image_w;
+ int y1 = gapp.pany + image_h;
+ RECT r;
+
+ if (gapp.image)
+ {
+ if (gapp.iscopying || justcopied)
+ {
+ pdfapp_invert(&gapp, &gapp.selr);
+ justcopied = 1;
+ }
+
+ pdfapp_inverthit(&gapp);
+
+ dibinf->bmiHeader.biWidth = image_w;
+ dibinf->bmiHeader.biHeight = -image_h;
+ dibinf->bmiHeader.biSizeImage = image_h * 4;
+
+ if (image_n == 2)
+ {
+ int i = image_w * image_h;
+ unsigned char *color = malloc(i*4);
+ unsigned char *s = samples;
+ unsigned char *d = color;
+ for (; i > 0 ; i--)
+ {
+ d[2] = d[1] = d[0] = *s++;
+ d[3] = *s++;
+ d += 4;
+ }
+ SetDIBitsToDevice(hdc,
+ gapp.panx, gapp.pany, image_w, image_h,
+ 0, 0, 0, image_h, color,
+ dibinf, DIB_RGB_COLORS);
+ free(color);
+ }
+ if (image_n == 4)
+ {
+ SetDIBitsToDevice(hdc,
+ gapp.panx, gapp.pany, image_w, image_h,
+ 0, 0, 0, image_h, samples,
+ dibinf, DIB_RGB_COLORS);
+ }
+
+ pdfapp_inverthit(&gapp);
+
+ if (gapp.iscopying || justcopied)
+ {
+ pdfapp_invert(&gapp, &gapp.selr);
+ justcopied = 1;
+ }
+ }
+
+ /* Grey background */
+ r.top = 0; r.bottom = gapp.winh;
+ r.left = 0; r.right = x0;
+ FillRect(hdc, &r, bgbrush);
+ r.left = x1; r.right = gapp.winw;
+ FillRect(hdc, &r, bgbrush);
+ r.left = 0; r.right = gapp.winw;
+ r.top = 0; r.bottom = y0;
+ FillRect(hdc, &r, bgbrush);
+ r.top = y1; r.bottom = gapp.winh;
+ FillRect(hdc, &r, bgbrush);
+
+ /* Drop shadow */
+ r.left = x0 + 2;
+ r.right = x1 + 2;
+ r.top = y1;
+ r.bottom = y1 + 2;
+ FillRect(hdc, &r, shbrush);
+ r.left = x1;
+ r.right = x1 + 2;
+ r.top = y0 + 2;
+ r.bottom = y1;
+ FillRect(hdc, &r, shbrush);
+
+ winblitsearch();
+}
+
+void winresize(pdfapp_t *app, int w, int h)
+{
+ ShowWindow(hwndframe, SW_SHOWDEFAULT);
+ w += GetSystemMetrics(SM_CXFRAME) * 2;
+ h += GetSystemMetrics(SM_CYFRAME) * 2;
+ h += GetSystemMetrics(SM_CYCAPTION);
+ SetWindowPos(hwndframe, 0, 0, 0, w, h, SWP_NOZORDER | SWP_NOMOVE);
+}
+
+void winrepaint(pdfapp_t *app)
+{
+ InvalidateRect(hwndview, NULL, 0);
+}
+
+void winrepaintsearch(pdfapp_t *app)
+{
+ // TODO: invalidate only search area and
+ // call only search redraw routine.
+ InvalidateRect(hwndview, NULL, 0);
+}
+
+void winfullscreen(pdfapp_t *app, int state)
+{
+ static WINDOWPLACEMENT savedplace;
+ static int isfullscreen = 0;
+ if (state && !isfullscreen)
+ {
+ GetWindowPlacement(hwndframe, &savedplace);
+ SetWindowLong(hwndframe, GWL_STYLE, WS_POPUP | WS_VISIBLE);
+ SetWindowPos(hwndframe, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);
+ ShowWindow(hwndframe, SW_SHOWMAXIMIZED);
+ isfullscreen = 1;
+ }
+ if (!state && isfullscreen)
+ {
+ SetWindowLong(hwndframe, GWL_STYLE, WS_OVERLAPPEDWINDOW);
+ SetWindowPos(hwndframe, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);
+ SetWindowPlacement(hwndframe, &savedplace);
+ isfullscreen = 0;
+ }
+}
+
+/*
+ * Event handling
+ */
+
+void windocopy(pdfapp_t *app)
+{
+ HGLOBAL handle;
+ unsigned short *ucsbuf;
+
+ if (!OpenClipboard(hwndframe))
+ return;
+ EmptyClipboard();
+
+ handle = GlobalAlloc(GMEM_MOVEABLE, 4096 * sizeof(unsigned short));
+ if (!handle)
+ {
+ CloseClipboard();
+ return;
+ }
+
+ ucsbuf = GlobalLock(handle);
+ pdfapp_oncopy(&gapp, ucsbuf, 4096);
+ GlobalUnlock(handle);
+
+ SetClipboardData(CF_UNICODETEXT, handle);
+ CloseClipboard();
+
+ justcopied = 1; /* keep inversion around for a while... */
+}
+
+void winreloadfile(pdfapp_t *app)
+{
+ pdfapp_close(app);
+ pdfapp_open(app, filename, 1);
+}
+
+void winopenuri(pdfapp_t *app, char *buf)
+{
+ ShellExecuteA(hwndframe, "open", buf, 0, 0, SW_SHOWNORMAL);
+}
+
+#define OUR_TIMER_ID 1
+
+void winadvancetimer(pdfapp_t *app, float delay)
+{
+ timer_pending = 1;
+ SetTimer(hwndview, OUR_TIMER_ID, (unsigned int)(1000*delay), NULL);
+}
+
+static void killtimer(pdfapp_t *app)
+{
+ timer_pending = 0;
+}
+
+void handlekey(int c)
+{
+ if (timer_pending)
+ killtimer(&gapp);
+
+ if (GetCapture() == hwndview)
+ return;
+
+ if (justcopied)
+ {
+ justcopied = 0;
+ winrepaint(&gapp);
+ }
+
+ /* translate VK into ASCII equivalents */
+ if (c > 256)
+ {
+ switch (c - 256)
+ {
+ case VK_F1: c = '?'; break;
+ case VK_ESCAPE: c = '\033'; break;
+ case VK_DOWN: c = 'j'; break;
+ case VK_UP: c = 'k'; break;
+ case VK_LEFT: c = 'b'; break;
+ case VK_RIGHT: c = ' '; break;
+ case VK_PRIOR: c = ','; break;
+ case VK_NEXT: c = '.'; break;
+ }
+ }
+
+ pdfapp_onkey(&gapp, c);
+ winrepaint(&gapp);
+}
+
+void handlemouse(int x, int y, int btn, int state)
+{
+ if (state != 0 && timer_pending)
+ killtimer(&gapp);
+
+ if (state != 0 && justcopied)
+ {
+ justcopied = 0;
+ winrepaint(&gapp);
+ }
+
+ if (state == 1)
+ SetCapture(hwndview);
+ if (state == -1)
+ ReleaseCapture();
+
+ pdfapp_onmouse(&gapp, x, y, btn, 0, state);
+}
+
+LRESULT CALLBACK
+frameproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch(message)
+ {
+ case WM_SETFOCUS:
+ PostMessage(hwnd, WM_APP+5, 0, 0);
+ return 0;
+ case WM_APP+5:
+ SetFocus(hwndview);
+ return 0;
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0;
+
+ case WM_SYSCOMMAND:
+ if (wParam == ID_ABOUT)
+ {
+ winhelp(&gapp);
+ return 0;
+ }
+ if (wParam == ID_DOCINFO)
+ {
+ info();
+ return 0;
+ }
+ if (wParam == SC_MAXIMIZE)
+ gapp.shrinkwrap = 0;
+ break;
+
+ case WM_SIZE:
+ {
+ // More generally, you should use GetEffectiveClientRect
+ // if you have a toolbar etc.
+ RECT rect;
+ GetClientRect(hwnd, &rect);
+ MoveWindow(hwndview, rect.left, rect.top,
+ rect.right-rect.left, rect.bottom-rect.top, TRUE);
+ return 0;
+ }
+
+ case WM_SIZING:
+ gapp.shrinkwrap = 0;
+ break;
+
+ case WM_NOTIFY:
+ case WM_COMMAND:
+ return SendMessage(hwndview, message, wParam, lParam);
+
+ case WM_CLOSE:
+ if (!pdfapp_preclose(&gapp))
+ return 0;
+ }
+
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+LRESULT CALLBACK
+viewproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ static int oldx = 0;
+ static int oldy = 0;
+ int x = (signed short) LOWORD(lParam);
+ int y = (signed short) HIWORD(lParam);
+
+ switch (message)
+ {
+ case WM_SIZE:
+ if (wParam == SIZE_MINIMIZED)
+ return 0;
+ if (wParam == SIZE_MAXIMIZED)
+ gapp.shrinkwrap = 0;
+ pdfapp_onresize(&gapp, LOWORD(lParam), HIWORD(lParam));
+ break;
+
+ /* Paint events are low priority and automagically catenated
+ * so we don't need to do any fancy waiting to defer repainting.
+ */
+ case WM_PAINT:
+ {
+ //puts("WM_PAINT");
+ PAINTSTRUCT ps;
+ hdc = BeginPaint(hwnd, &ps);
+ winblit();
+ hdc = NULL;
+ EndPaint(hwnd, &ps);
+ pdfapp_postblit(&gapp);
+ return 0;
+ }
+
+ case WM_ERASEBKGND:
+ return 1; // well, we don't need to erase to redraw cleanly
+
+ /* Mouse events */
+
+ case WM_LBUTTONDOWN:
+ SetFocus(hwndview);
+ oldx = x; oldy = y;
+ handlemouse(x, y, 1, 1);
+ return 0;
+ case WM_MBUTTONDOWN:
+ SetFocus(hwndview);
+ oldx = x; oldy = y;
+ handlemouse(x, y, 2, 1);
+ return 0;
+ case WM_RBUTTONDOWN:
+ SetFocus(hwndview);
+ oldx = x; oldy = y;
+ handlemouse(x, y, 3, 1);
+ return 0;
+
+ case WM_LBUTTONUP:
+ oldx = x; oldy = y;
+ handlemouse(x, y, 1, -1);
+ return 0;
+ case WM_MBUTTONUP:
+ oldx = x; oldy = y;
+ handlemouse(x, y, 2, -1);
+ return 0;
+ case WM_RBUTTONUP:
+ oldx = x; oldy = y;
+ handlemouse(x, y, 3, -1);
+ return 0;
+
+ case WM_MOUSEMOVE:
+ oldx = x; oldy = y;
+ handlemouse(x, y, 0, 0);
+ return 0;
+
+ /* Mouse wheel */
+
+ case WM_MOUSEWHEEL:
+ if ((signed short)HIWORD(wParam) > 0)
+ handlekey(LOWORD(wParam) & MK_SHIFT ? '+' : 'k');
+ else
+ handlekey(LOWORD(wParam) & MK_SHIFT ? '-' : 'j');
+ return 0;
+
+ /* Timer */
+ case WM_TIMER:
+ if (wParam == OUR_TIMER_ID && timer_pending && gapp.presentation_mode)
+ {
+ timer_pending = 0;
+ handlekey(VK_RIGHT + 256);
+ handlemouse(oldx, oldy, 0, 0); /* update cursor */
+ return 0;
+ }
+ break;
+
+ /* Keyboard events */
+
+ case WM_KEYDOWN:
+ /* only handle special keys */
+ switch (wParam)
+ {
+ case VK_F1:
+ case VK_LEFT:
+ case VK_UP:
+ case VK_PRIOR:
+ case VK_RIGHT:
+ case VK_DOWN:
+ case VK_NEXT:
+ case VK_ESCAPE:
+ handlekey(wParam + 256);
+ handlemouse(oldx, oldy, 0, 0); /* update cursor */
+ return 0;
+ }
+ return 1;
+
+ /* unicode encoded chars, including escape, backspace etc... */
+ case WM_CHAR:
+ if (wParam < 256)
+ {
+ handlekey(wParam);
+ handlemouse(oldx, oldy, 0, 0); /* update cursor */
+ }
+ return 0;
+ }
+
+ fflush(stdout);
+
+ /* Pass on unhandled events to Windows */
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+int WINAPI
+WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
+{
+ int argc;
+ LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &argc);
+ char argv0[256];
+ MSG msg;
+ int code;
+ fz_context *ctx;
+
+ ctx = fz_new_context(NULL, NULL, FZ_STORE_DEFAULT);
+ if (!ctx)
+ {
+ fprintf(stderr, "cannot initialise context\n");
+ exit(1);
+ }
+ pdfapp_init(ctx, &gapp);
+
+ GetModuleFileNameA(NULL, argv0, sizeof argv0);
+ install_app(argv0);
+
+ winopen();
+
+ if (argc == 2)
+ {
+ wcscpy(wbuf, argv[1]);
+ }
+ else
+ {
+ if (!winfilename(wbuf, nelem(wbuf)))
+ exit(0);
+ }
+
+ code = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, filename, sizeof filename, NULL, NULL);
+ if (code == 0)
+ winerror(&gapp, "cannot convert filename to utf-8");
+
+ pdfapp_open(&gapp, filename, 0);
+
+ while (GetMessage(&msg, NULL, 0, 0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ pdfapp_close(&gapp);
+
+ return 0;
+}