diff options
author | Tor Andersson <tor.andersson@artifex.com> | 2013-06-19 15:29:44 +0200 |
---|---|---|
committer | Tor Andersson <tor.andersson@artifex.com> | 2013-06-20 16:45:35 +0200 |
commit | 0a927854a10e1e6b9770a81e2e1d9f3093631757 (patch) | |
tree | 3d65d820d9fdba2d0d394d99c36290c851b78ca0 /platform/x11/x11_main.c | |
parent | 1ae8f19179c5f0f8c6352b3c7855465325d5449a (diff) | |
download | mupdf-0a927854a10e1e6b9770a81e2e1d9f3093631757.tar.xz |
Rearrange source files.
Diffstat (limited to 'platform/x11/x11_main.c')
-rw-r--r-- | platform/x11/x11_main.c | 993 |
1 files changed, 993 insertions, 0 deletions
diff --git a/platform/x11/x11_main.c b/platform/x11/x11_main.c new file mode 100644 index 00000000..481adce1 --- /dev/null +++ b/platform/x11/x11_main.c @@ -0,0 +1,993 @@ +#include "pdfapp.h" + +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> +#include <X11/cursorfont.h> +#include <X11/keysym.h> + +#include <sys/select.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#include <signal.h> + +#define mupdf_icon_bitmap_16_width 16 +#define mupdf_icon_bitmap_16_height 16 +static unsigned char mupdf_icon_bitmap_16_bits[] = { + 0x00, 0x00, 0x00, 0x1e, 0x00, 0x2b, 0x80, 0x55, 0x8c, 0x62, 0x8c, 0x51, + 0x9c, 0x61, 0x1c, 0x35, 0x3c, 0x1f, 0x3c, 0x0f, 0xfc, 0x0f, 0xec, 0x0d, + 0xec, 0x0d, 0xcc, 0x0c, 0xcc, 0x0c, 0x00, 0x00 }; + +#define mupdf_icon_bitmap_16_mask_width 16 +#define mupdf_icon_bitmap_16_mask_height 16 +static unsigned char mupdf_icon_bitmap_16_mask_bits[] = { + 0x00, 0x1e, 0x00, 0x3f, 0x80, 0x7f, 0xce, 0xff, 0xde, 0xff, 0xde, 0xff, + 0xfe, 0xff, 0xfe, 0x7f, 0xfe, 0x3f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, + 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xce, 0x1c }; + +#ifndef timeradd +#define timeradd(a, b, result) \ + do { \ + (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \ + (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \ + if ((result)->tv_usec >= 1000000) \ + { \ + ++(result)->tv_sec; \ + (result)->tv_usec -= 1000000; \ + } \ + } while (0) +#endif + +#ifndef timersub +#define timersub(a, b, result) \ + do { \ + (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ + (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ + if ((result)->tv_usec < 0) { \ + --(result)->tv_sec; \ + (result)->tv_usec += 1000000; \ + } \ + } while (0) +#endif + +extern int ximage_init(Display *display, int screen, Visual *visual); +extern int ximage_get_depth(void); +extern Visual *ximage_get_visual(void); +extern Colormap ximage_get_colormap(void); +extern void ximage_blit(Drawable d, GC gc, int dstx, int dsty, + unsigned char *srcdata, + int srcx, int srcy, int srcw, int srch, int srcstride); + +void windrawstringxor(pdfapp_t *app, int x, int y, char *s); +void cleanup(pdfapp_t *app); + +static Display *xdpy; +static Atom XA_CLIPBOARD; +static Atom XA_TARGETS; +static Atom XA_TIMESTAMP; +static Atom XA_UTF8_STRING; +static Atom WM_DELETE_WINDOW; +static Atom NET_WM_STATE; +static Atom NET_WM_STATE_FULLSCREEN; +static int x11fd; +static int xscr; +static Window xwin; +static Pixmap xicon, xmask; +static GC xgc; +static XEvent xevt; +static int mapped = 0; +static Cursor xcarrow, xchand, xcwait, xccaret; +static int justcopied = 0; +static int dirty = 0; +static int transition_dirty = 0; +static int dirtysearch = 0; +static char *password = ""; +static XColor xbgcolor; +static XColor xshcolor; +static int reqw = 0; +static int reqh = 0; +static char copylatin1[1024 * 16] = ""; +static char copyutf8[1024 * 48] = ""; +static Time copytime; +static char *filename; + +static pdfapp_t gapp; +static int closing = 0; +static int reloading = 0; +static int showingpage = 0; + +static int advance_scheduled = 0; +static struct timeval tmo_advance; + +/* + * Dialog boxes + */ + +void winerror(pdfapp_t *app, char *msg) +{ + fprintf(stderr, "mupdf: error: %s\n", msg); + cleanup(app); + exit(1); +} + +void winwarn(pdfapp_t *app, char *msg) +{ + fprintf(stderr, "mupdf: warning: %s\n", msg); +} + +void winalert(pdfapp_t *app, pdf_alert_event *alert) +{ + fprintf(stderr, "Alert %s: %s", alert->title, alert->message); + switch (alert->button_group_type) + { + case PDF_ALERT_BUTTON_GROUP_OK: + case PDF_ALERT_BUTTON_GROUP_OK_CANCEL: + alert->button_pressed = PDF_ALERT_BUTTON_OK; + break; + case PDF_ALERT_BUTTON_GROUP_YES_NO: + case PDF_ALERT_BUTTON_GROUP_YES_NO_CANCEL: + alert->button_pressed = PDF_ALERT_BUTTON_YES; + break; + } +} + +void winprint(pdfapp_t *app) +{ + fprintf(stderr, "The MuPDF library supports printing, but this application currently does not"); +} + +char *winpassword(pdfapp_t *app, char *filename) +{ + char *r = password; + password = NULL; + return r; +} + +char *wintextinput(pdfapp_t *app, char *inittext, int retry) +{ + static char buf[256]; + + if (retry) + return NULL; + + printf("> [%s] ", inittext); + fgets(buf, sizeof buf, stdin); + return buf; +} + +int winchoiceinput(pdfapp_t *app, int nopts, char *opts[], int *nvals, char *vals[]) +{ + /* FIXME: temporary dummy implementation */ + return 0; +} + +/* + * X11 magic + */ + +static void winopen(void) +{ + XWMHints *wmhints; + XClassHint *classhint; + + xdpy = XOpenDisplay(NULL); + if (!xdpy) + fz_throw(gapp.ctx, FZ_ERROR_GENERIC, "cannot open display"); + + XA_CLIPBOARD = XInternAtom(xdpy, "CLIPBOARD", False); + XA_TARGETS = XInternAtom(xdpy, "TARGETS", False); + XA_TIMESTAMP = XInternAtom(xdpy, "TIMESTAMP", False); + XA_UTF8_STRING = XInternAtom(xdpy, "UTF8_STRING", False); + WM_DELETE_WINDOW = XInternAtom(xdpy, "WM_DELETE_WINDOW", False); + NET_WM_STATE = XInternAtom(xdpy, "_NET_WM_STATE", False); + NET_WM_STATE_FULLSCREEN = XInternAtom(xdpy, "_NET_WM_STATE_FULLSCREEN", False); + + xscr = DefaultScreen(xdpy); + + ximage_init(xdpy, xscr, DefaultVisual(xdpy, xscr)); + + xcarrow = XCreateFontCursor(xdpy, XC_left_ptr); + xchand = XCreateFontCursor(xdpy, XC_hand2); + xcwait = XCreateFontCursor(xdpy, XC_watch); + xccaret = XCreateFontCursor(xdpy, XC_xterm); + + xbgcolor.red = 0x7000; + xbgcolor.green = 0x7000; + xbgcolor.blue = 0x7000; + + xshcolor.red = 0x4000; + xshcolor.green = 0x4000; + xshcolor.blue = 0x4000; + + XAllocColor(xdpy, DefaultColormap(xdpy, xscr), &xbgcolor); + XAllocColor(xdpy, DefaultColormap(xdpy, xscr), &xshcolor); + + xwin = XCreateWindow(xdpy, DefaultRootWindow(xdpy), + 10, 10, 200, 100, 0, + ximage_get_depth(), + InputOutput, + ximage_get_visual(), + 0, + NULL); + if (xwin == None) + fz_throw(gapp.ctx, FZ_ERROR_GENERIC, "cannot create window"); + + XSetWindowColormap(xdpy, xwin, ximage_get_colormap()); + XSelectInput(xdpy, xwin, + StructureNotifyMask | ExposureMask | KeyPressMask | + PointerMotionMask | ButtonPressMask | ButtonReleaseMask); + + mapped = 0; + + xgc = XCreateGC(xdpy, xwin, 0, NULL); + + XDefineCursor(xdpy, xwin, xcarrow); + + wmhints = XAllocWMHints(); + if (wmhints) + { + wmhints->flags = IconPixmapHint | IconMaskHint; + xicon = XCreateBitmapFromData(xdpy, xwin, + (char*)mupdf_icon_bitmap_16_bits, + mupdf_icon_bitmap_16_width, + mupdf_icon_bitmap_16_height); + xmask = XCreateBitmapFromData(xdpy, xwin, + (char*)mupdf_icon_bitmap_16_mask_bits, + mupdf_icon_bitmap_16_mask_width, + mupdf_icon_bitmap_16_mask_height); + if (xicon && xmask) + { + wmhints->icon_pixmap = xicon; + wmhints->icon_mask = xmask; + XSetWMHints(xdpy, xwin, wmhints); + } + XFree(wmhints); + } + + classhint = XAllocClassHint(); + if (classhint) + { + classhint->res_name = "mupdf"; + classhint->res_class = "MuPDF"; + XSetClassHint(xdpy, xwin, classhint); + XFree(classhint); + } + + XSetWMProtocols(xdpy, xwin, &WM_DELETE_WINDOW, 1); + + x11fd = ConnectionNumber(xdpy); +} + +void winclose(pdfapp_t *app) +{ + closing = 1; +} + +int winsavequery(pdfapp_t *app) +{ + /* FIXME: temporary dummy implementation */ + return DISCARD; +} + +int wingetsavepath(pdfapp_t *app, char *buf, int len) +{ + /* FIXME: temporary dummy implementation */ + return 0; +} + +void winreplacefile(char *source, char *target) +{ + rename(source, target); +} + +void cleanup(pdfapp_t *app) +{ + fz_context *ctx = app->ctx; + + pdfapp_close(app); + + XDestroyWindow(xdpy, xwin); + + XFreePixmap(xdpy, xicon); + + XFreeCursor(xdpy, xccaret); + XFreeCursor(xdpy, xcwait); + XFreeCursor(xdpy, xchand); + XFreeCursor(xdpy, xcarrow); + + XFreeGC(xdpy, xgc); + + XCloseDisplay(xdpy); + + fz_free_context(ctx); +} + +static int winresolution() +{ + return DisplayWidth(xdpy, xscr) * 25.4 / + DisplayWidthMM(xdpy, xscr) + 0.5; +} + +void wincursor(pdfapp_t *app, int curs) +{ + if (curs == ARROW) + XDefineCursor(xdpy, xwin, xcarrow); + if (curs == HAND) + XDefineCursor(xdpy, xwin, xchand); + if (curs == WAIT) + XDefineCursor(xdpy, xwin, xcwait); + if (curs == CARET) + XDefineCursor(xdpy, xwin, xccaret); + XFlush(xdpy); +} + +void wintitle(pdfapp_t *app, char *s) +{ + XStoreName(xdpy, xwin, s); +#ifdef X_HAVE_UTF8_STRING + Xutf8SetWMProperties(xdpy, xwin, s, s, NULL, 0, NULL, NULL, NULL); +#else + XmbSetWMProperties(xdpy, xwin, s, s, NULL, 0, NULL, NULL, NULL); +#endif +} + +void winhelp(pdfapp_t *app) +{ + fprintf(stderr, "%s\n%s", pdfapp_version(app), pdfapp_usage(app)); +} + +void winresize(pdfapp_t *app, int w, int h) +{ + int image_w = fz_pixmap_width(gapp.ctx, gapp.image); + int image_h = fz_pixmap_height(gapp.ctx, gapp.image); + XWindowChanges values; + int mask, width, height; + + mask = CWWidth | CWHeight; + values.width = w; + values.height = h; + XConfigureWindow(xdpy, xwin, mask, &values); + + reqw = w; + reqh = h; + + if (!mapped) + { + gapp.winw = w; + gapp.winh = h; + width = -1; + height = -1; + + XMapWindow(xdpy, xwin); + XFlush(xdpy); + + while (1) + { + XNextEvent(xdpy, &xevt); + if (xevt.type == ConfigureNotify) + { + width = xevt.xconfigure.width; + height = xevt.xconfigure.height; + } + if (xevt.type == MapNotify) + break; + } + + XSetForeground(xdpy, xgc, WhitePixel(xdpy, xscr)); + XFillRectangle(xdpy, xwin, xgc, 0, 0, image_w, image_h); + XFlush(xdpy); + + if (width != reqw || height != reqh) + { + gapp.shrinkwrap = 0; + dirty = 1; + pdfapp_onresize(&gapp, width, height); + } + + mapped = 1; + } +} + +void winfullscreen(pdfapp_t *app, int state) +{ + XEvent xev; + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.window = xwin; + xev.xclient.message_type = NET_WM_STATE; + xev.xclient.format = 32; + xev.xclient.data.l[0] = state; + xev.xclient.data.l[1] = NET_WM_STATE_FULLSCREEN; + xev.xclient.data.l[2] = 0; + XSendEvent(xdpy, DefaultRootWindow(xdpy), False, + SubstructureRedirectMask | SubstructureNotifyMask, + &xev); +} + +static void fillrect(int x, int y, int w, int h) +{ + if (w > 0 && h > 0) + XFillRectangle(xdpy, xwin, xgc, x, y, w, h); +} + +static void winblitsearch(pdfapp_t *app) +{ + if (gapp.isediting) + { + char buf[sizeof(gapp.search) + 50]; + sprintf(buf, "Search: %s", gapp.search); + XSetForeground(xdpy, xgc, WhitePixel(xdpy, xscr)); + fillrect(0, 0, gapp.winw, 30); + windrawstring(&gapp, 10, 20, buf); + } +} + +static void winblit(pdfapp_t *app) +{ + 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 *image_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; + + XSetForeground(xdpy, xgc, xbgcolor.pixel); + fillrect(0, 0, x0, gapp.winh); + fillrect(x1, 0, gapp.winw - x1, gapp.winh); + fillrect(0, 0, gapp.winw, y0); + fillrect(0, y1, gapp.winw, gapp.winh - y1); + + XSetForeground(xdpy, xgc, xshcolor.pixel); + fillrect(x0+2, y1, image_w, 2); + fillrect(x1, y0+2, 2, image_h); + + if (gapp.iscopying || justcopied) + { + pdfapp_invert(&gapp, &gapp.selr); + justcopied = 1; + } + + pdfapp_inverthit(&gapp); + + if (image_n == 4) + ximage_blit(xwin, xgc, + x0, y0, + image_samples, + 0, 0, + image_w, + image_h, + image_w * image_n); + else if (image_n == 2) + { + int i = image_w*image_h; + unsigned char *color = malloc(i*4); + if (color) + { + unsigned char *s = image_samples; + unsigned char *d = color; + for (; i > 0 ; i--) + { + d[2] = d[1] = d[0] = *s++; + d[3] = *s++; + d += 4; + } + ximage_blit(xwin, xgc, + x0, y0, + color, + 0, 0, + image_w, + image_h, + image_w * 4); + free(color); + } + } + + pdfapp_inverthit(&gapp); + + if (gapp.iscopying || justcopied) + { + pdfapp_invert(&gapp, &gapp.selr); + justcopied = 1; + } + + winblitsearch(app); + + if (showingpage) + { + char buf[42]; + snprintf(buf, sizeof buf, "Page %d/%d", gapp.pageno, gapp.pagecount); + windrawstringxor(&gapp, 10, 20, buf); + } +} + +void winrepaint(pdfapp_t *app) +{ + dirty = 1; + if (app->in_transit) + transition_dirty = 1; +} + +void winrepaintsearch(pdfapp_t *app) +{ + dirtysearch = 1; +} + +void winadvancetimer(pdfapp_t *app, float duration) +{ + struct timeval now; + + gettimeofday(&now, NULL); + memset(&tmo_advance, 0, sizeof(tmo_advance)); + tmo_advance.tv_sec = (int)duration; + tmo_advance.tv_usec = 1000000 * (duration - tmo_advance.tv_sec); + timeradd(&tmo_advance, &now, &tmo_advance); + advance_scheduled = 1; +} + +void windrawstringxor(pdfapp_t *app, int x, int y, char *s) +{ + int prevfunction; + XGCValues xgcv; + + XGetGCValues(xdpy, xgc, GCFunction, &xgcv); + prevfunction = xgcv.function; + xgcv.function = GXxor; + XChangeGC(xdpy, xgc, GCFunction, &xgcv); + + XSetForeground(xdpy, xgc, WhitePixel(xdpy, DefaultScreen(xdpy))); + + XDrawString(xdpy, xwin, xgc, x, y, s, strlen(s)); + XFlush(xdpy); + + XGetGCValues(xdpy, xgc, GCFunction, &xgcv); + xgcv.function = prevfunction; + XChangeGC(xdpy, xgc, GCFunction, &xgcv); +} + +void windrawstring(pdfapp_t *app, int x, int y, char *s) +{ + XSetForeground(xdpy, xgc, BlackPixel(xdpy, DefaultScreen(xdpy))); + XDrawString(xdpy, xwin, xgc, x, y, s, strlen(s)); +} + +void docopy(pdfapp_t *app, Atom copy_target) +{ + unsigned short copyucs2[16 * 1024]; + char *latin1 = copylatin1; + char *utf8 = copyutf8; + unsigned short *ucs2; + int ucs; + + pdfapp_oncopy(&gapp, copyucs2, 16 * 1024); + + for (ucs2 = copyucs2; ucs2[0] != 0; ucs2++) + { + ucs = ucs2[0]; + + utf8 += fz_runetochar(utf8, ucs); + + if (ucs < 256) + *latin1++ = ucs; + else + *latin1++ = '?'; + } + + *utf8 = 0; + *latin1 = 0; + + XSetSelectionOwner(xdpy, copy_target, xwin, copytime); + + justcopied = 1; +} + +void windocopy(pdfapp_t *app) +{ + docopy(app, XA_PRIMARY); +} + +void onselreq(Window requestor, Atom selection, Atom target, Atom property, Time time) +{ + XEvent nevt; + + advance_scheduled = 0; + + if (property == None) + property = target; + + nevt.xselection.type = SelectionNotify; + nevt.xselection.send_event = True; + nevt.xselection.display = xdpy; + nevt.xselection.requestor = requestor; + nevt.xselection.selection = selection; + nevt.xselection.target = target; + nevt.xselection.property = property; + nevt.xselection.time = time; + + if (target == XA_TARGETS) + { + Atom atomlist[4]; + atomlist[0] = XA_TARGETS; + atomlist[1] = XA_TIMESTAMP; + atomlist[2] = XA_STRING; + atomlist[3] = XA_UTF8_STRING; + XChangeProperty(xdpy, requestor, property, target, + 32, PropModeReplace, + (unsigned char *)atomlist, sizeof(atomlist)/sizeof(Atom)); + } + + else if (target == XA_STRING) + { + XChangeProperty(xdpy, requestor, property, target, + 8, PropModeReplace, + (unsigned char *)copylatin1, strlen(copylatin1)); + } + + else if (target == XA_UTF8_STRING) + { + XChangeProperty(xdpy, requestor, property, target, + 8, PropModeReplace, + (unsigned char *)copyutf8, strlen(copyutf8)); + } + + else + { + nevt.xselection.property = None; + } + + XSendEvent(xdpy, requestor, False, 0, &nevt); +} + +void winreloadfile(pdfapp_t *app) +{ + pdfapp_close(app); + pdfapp_open(app, filename, 1); +} + +void winopenuri(pdfapp_t *app, char *buf) +{ + char *browser = getenv("BROWSER"); + if (!browser) + { +#ifdef __APPLE__ + browser = "open"; +#else + browser = "xdg-open"; +#endif + } + if (fork() == 0) + { + execlp(browser, browser, buf, (char*)0); + fprintf(stderr, "cannot exec '%s'\n", browser); + exit(0); + } +} + +static void onkey(int c) +{ + advance_scheduled = 0; + + if (justcopied) + { + justcopied = 0; + winrepaint(&gapp); + } + + if (!gapp.isediting && c == 'P') + { + showingpage = 1; + winrepaint(&gapp); + return; + } + + pdfapp_onkey(&gapp, c); +} + +static void onmouse(int x, int y, int btn, int modifiers, int state) +{ + if (state != 0) + advance_scheduled = 0; + + if (state != 0 && justcopied) + { + justcopied = 0; + winrepaint(&gapp); + } + + pdfapp_onmouse(&gapp, x, y, btn, modifiers, state); +} + +static void signal_handler(int signal) +{ + if (signal == SIGHUP) + reloading = 1; +} + +static void usage(void) +{ + fprintf(stderr, "usage: mupdf [options] file.pdf [page]\n"); + fprintf(stderr, "\t-b -\tset anti-aliasing quality in bits (0=off, 8=best)\n"); + fprintf(stderr, "\t-p -\tpassword\n"); + fprintf(stderr, "\t-r -\tresolution\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + int c; + int len; + char buf[128]; + KeySym keysym; + int oldx = 0; + int oldy = 0; + int resolution = -1; + int pageno = 1; + fd_set fds; + int width = -1; + int height = -1; + fz_context *ctx; + struct timeval tmo_at; + struct timeval now; + struct timeval tmo; + struct timeval *timeout; + struct timeval tmo_advance_delay; + + ctx = fz_new_context(NULL, NULL, FZ_STORE_DEFAULT); + if (!ctx) + { + fprintf(stderr, "cannot initialise context\n"); + exit(1); + } + + while ((c = fz_getopt(argc, argv, "p:r:b:")) != -1) + { + switch (c) + { + case 'p': password = fz_optarg; break; + case 'r': resolution = atoi(fz_optarg); break; + case 'b': fz_set_aa_level(ctx, atoi(fz_optarg)); break; + default: usage(); + } + } + + if (argc - fz_optind == 0) + usage(); + + filename = argv[fz_optind++]; + + if (argc - fz_optind == 1) + pageno = atoi(argv[fz_optind++]); + + pdfapp_init(ctx, &gapp); + + winopen(); + + if (resolution == -1) + resolution = winresolution(); + if (resolution < MINRES) + resolution = MINRES; + if (resolution > MAXRES) + resolution = MAXRES; + + gapp.transitions_enabled = 1; + gapp.scrw = DisplayWidth(xdpy, xscr); + gapp.scrh = DisplayHeight(xdpy, xscr); + gapp.resolution = resolution; + gapp.pageno = pageno; + + pdfapp_open(&gapp, filename, 0); + + FD_ZERO(&fds); + + signal(SIGHUP, signal_handler); + + tmo_at.tv_sec = 0; + tmo_at.tv_usec = 0; + + while (!closing) + { + while (!closing && XPending(xdpy) && !transition_dirty) + { + XNextEvent(xdpy, &xevt); + + switch (xevt.type) + { + case Expose: + dirty = 1; + break; + + case ConfigureNotify: + if (gapp.image) + { + if (xevt.xconfigure.width != reqw || + xevt.xconfigure.height != reqh) + gapp.shrinkwrap = 0; + } + width = xevt.xconfigure.width; + height = xevt.xconfigure.height; + + break; + + case KeyPress: + len = XLookupString(&xevt.xkey, buf, sizeof buf, &keysym, NULL); + + if (!gapp.isediting) + switch (keysym) + { + case XK_Escape: + len = 1; buf[0] = '\033'; + break; + + case XK_Up: + len = 1; buf[0] = 'k'; + break; + case XK_Down: + len = 1; buf[0] = 'j'; + break; + + case XK_Left: + len = 1; buf[0] = 'b'; + break; + case XK_Right: + len = 1; buf[0] = ' '; + break; + + case XK_Page_Up: + len = 1; buf[0] = ','; + break; + case XK_Page_Down: + len = 1; buf[0] = '.'; + break; + } + if (xevt.xkey.state & ControlMask && keysym == XK_c) + docopy(&gapp, XA_CLIPBOARD); + else if (len) + onkey(buf[0]); + + onmouse(oldx, oldy, 0, 0, 0); + + break; + + case MotionNotify: + oldx = xevt.xmotion.x; + oldy = xevt.xmotion.y; + onmouse(xevt.xmotion.x, xevt.xmotion.y, 0, xevt.xmotion.state, 0); + break; + + case ButtonPress: + onmouse(xevt.xbutton.x, xevt.xbutton.y, xevt.xbutton.button, xevt.xbutton.state, 1); + break; + + case ButtonRelease: + copytime = xevt.xbutton.time; + onmouse(xevt.xbutton.x, xevt.xbutton.y, xevt.xbutton.button, xevt.xbutton.state, -1); + break; + + case SelectionRequest: + onselreq(xevt.xselectionrequest.requestor, + xevt.xselectionrequest.selection, + xevt.xselectionrequest.target, + xevt.xselectionrequest.property, + xevt.xselectionrequest.time); + break; + + case ClientMessage: + if (xevt.xclient.format == 32 && xevt.xclient.data.l[0] == WM_DELETE_WINDOW) + closing = 1; + break; + } + } + + if (closing) + continue; + + if (width != -1 || height != -1) + { + pdfapp_onresize(&gapp, width, height); + width = -1; + height = -1; + } + + if (dirty || dirtysearch) + { + if (dirty) + winblit(&gapp); + else if (dirtysearch) + winblitsearch(&gapp); + dirty = 0; + transition_dirty = 0; + dirtysearch = 0; + pdfapp_postblit(&gapp); + } + + if (showingpage && !tmo_at.tv_sec && !tmo_at.tv_usec) + { + tmo.tv_sec = 2; + tmo.tv_usec = 0; + + gettimeofday(&now, NULL); + timeradd(&now, &tmo, &tmo_at); + } + + if (XPending(xdpy) || transition_dirty) + continue; + + timeout = NULL; + + if (tmo_at.tv_sec || tmo_at.tv_usec) + { + gettimeofday(&now, NULL); + timersub(&tmo_at, &now, &tmo); + if (tmo.tv_sec <= 0) + { + tmo_at.tv_sec = 0; + tmo_at.tv_usec = 0; + timeout = NULL; + showingpage = 0; + winrepaint(&gapp); + } + else + timeout = &tmo; + } + + if (advance_scheduled) + { + gettimeofday(&now, NULL); + timersub(&tmo_advance, &now, &tmo_advance_delay); + if (tmo_advance_delay.tv_sec <= 0) + { + /* Too late already */ + onkey(' '); + onmouse(oldx, oldy, 0, 0, 0); + advance_scheduled = 0; + } + else if (timeout == NULL) + { + timeout = &tmo_advance_delay; + } + else + { + struct timeval tmp; + timersub(&tmo_advance_delay, timeout, &tmp); + if (tmp.tv_sec < 0) + { + timeout = &tmo_advance_delay; + } + } + } + + FD_SET(x11fd, &fds); + if (select(x11fd + 1, &fds, NULL, NULL, timeout) < 0) + { + if (reloading) + { + winreloadfile(&gapp); + reloading = 0; + } + } + if (!FD_ISSET(x11fd, &fds)) + { + if (timeout == &tmo_advance_delay) + { + onkey(' '); + onmouse(oldx, oldy, 0, 0, 0); + advance_scheduled = 0; + } + else + { + tmo_at.tv_sec = 0; + tmo_at.tv_usec = 0; + timeout = NULL; + showingpage = 0; + winrepaint(&gapp); + } + } + } + + cleanup(&gapp); + + return 0; +} |