Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. #include "fitz.h"
  2. #include "mupdf.h"
  3. #include "muxps.h"
  4. #include "pdfapp.h"
  5.  
  6. #include <menuet/os.h>
  7.  
  8. // #include <sys/select.h>
  9. #include <sys/time.h>
  10. #include <sys/types.h>
  11. #include <unistd.h>
  12. #include <signal.h>
  13.  
  14.  
  15.  
  16. #ifndef timeradd
  17. #define timeradd(a, b, result) \
  18.         do { \
  19.                 (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
  20.                 (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
  21.                 if ((result)->tv_usec >= 1000000) \
  22.                 { \
  23.                         ++(result)->tv_sec; \
  24.                         (result)->tv_usec -= 1000000; \
  25.                 } \
  26.         } while (0)
  27. #endif
  28.  
  29. #ifndef timersub
  30. #define timersub(a, b, result) \
  31.         do { \
  32.                 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
  33.                 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
  34.                 if ((result)->tv_usec < 0) { \
  35.                         --(result)->tv_sec; \
  36.                         (result)->tv_usec += 1000000; \
  37.                 } \
  38.         } while (0)
  39. #endif
  40.  
  41. extern int ximage_init(Display *display, int screen, Visual *visual);
  42. extern int ximage_get_depth(void);
  43. extern Visual *ximage_get_visual(void);
  44. extern Colormap ximage_get_colormap(void);
  45. extern void ximage_blit(Drawable d, GC gc, int dstx, int dsty,
  46.         unsigned char *srcdata,
  47.         int srcx, int srcy, int srcw, int srch, int srcstride);
  48.  
  49. static Display *xdpy;
  50. static Atom XA_TARGETS;
  51. static Atom XA_TIMESTAMP;
  52. static Atom XA_UTF8_STRING;
  53. static Atom WM_DELETE_WINDOW;
  54. static int x11fd;
  55. static int xscr;
  56. static Window xwin;
  57. static Pixmap xicon, xmask;
  58. static GC xgc;
  59. static XEvent xevt;
  60. static int mapped = 0;
  61. static Cursor xcarrow, xchand, xcwait;
  62. static int justcopied = 0;
  63. static int dirty = 0;
  64. static int dirtysearch = 0;
  65. static char *password = "";
  66. static XColor xbgcolor;
  67. static XColor xshcolor;
  68. static int reqw = 0;
  69. static int reqh = 0;
  70. static char copylatin1[1024 * 16] = "";
  71. static char copyutf8[1024 * 48] = "";
  72. static Time copytime;
  73. static char *filename;
  74.  
  75. static pdfapp_t gapp;
  76. static int closing = 0;
  77. static int reloading = 0;
  78.  
  79. /*
  80.  * Dialog boxes
  81.  */
  82.  
  83. void winwarn(pdfapp_t *app, char *msg)
  84. {
  85.         fprintf(stderr, "mupdf: %s\n", msg);
  86. }
  87.  
  88. void winerror(pdfapp_t *app, fz_error error)
  89. {
  90.         fz_catch(error, "aborting");
  91.         exit(1);
  92. }
  93.  
  94. char *winpassword(pdfapp_t *app, char *filename)
  95. {
  96.         char *r = password;
  97.         password = NULL;
  98.         return r;
  99. }
  100.  
  101. /*
  102.  * X11 magic
  103.  */
  104.  
  105. static void winopen(void)
  106. {
  107.        
  108.  
  109.         /*
  110.         xwin = XCreateWindow(xdpy, DefaultRootWindow(xdpy),
  111.                 10, 10, 200, 100, 1,
  112.                 ximage_get_depth(),
  113.                 InputOutput,
  114.                 ximage_get_visual(),
  115.                 0,
  116.                 NULL); */
  117.                
  118.  __menuet__define_window(10,10,200,200,
  119.      0,0,0);
  120.        
  121. }
  122.  
  123. void winclose(pdfapp_t *app)
  124. {
  125.         closing = 1;
  126. }
  127.  
  128. void wincursor(pdfapp_t *app, int curs)
  129. {
  130.        
  131. }
  132.  
  133. void wintitle(pdfapp_t *app, char *s)
  134. {
  135.        
  136. }
  137.  
  138. void winhelp(pdfapp_t *app)
  139. {
  140.        
  141. }
  142.  
  143. void winresize(pdfapp_t *app, int w, int h)
  144. {
  145.        
  146.        
  147.  
  148.        
  149. }
  150.  
  151. static void fillrect(int x, int y, int w, int h)
  152. {
  153.         if (w > 0 && h > 0)
  154.                 XFillRectangle(xdpy, xwin, xgc, x, y, w, h);
  155. }
  156.  
  157. static void winblitsearch(pdfapp_t *app)
  158. {
  159.         if (gapp.isediting)
  160.         {
  161.                 char buf[sizeof(gapp.search) + 50];
  162.                 sprintf(buf, "Search: %s", gapp.search);
  163.                 XSetForeground(xdpy, xgc, WhitePixel(xdpy, xscr));
  164.                 fillrect(0, 0, gapp.winw, 30);
  165.                 windrawstring(&gapp, 10, 20, buf);
  166.         }
  167. }
  168.  
  169. static void winblit(pdfapp_t *app)
  170. {
  171.         int x0 = gapp.panx;
  172.         int y0 = gapp.pany;
  173.         int x1 = gapp.panx + gapp.image->w;
  174.         int y1 = gapp.pany + gapp.image->h;
  175.  
  176.         XSetForeground(xdpy, xgc, xbgcolor.pixel);
  177.         fillrect(0, 0, x0, gapp.winh);
  178.         fillrect(x1, 0, gapp.winw - x1, gapp.winh);
  179.         fillrect(0, 0, gapp.winw, y0);
  180.         fillrect(0, y1, gapp.winw, gapp.winh - y1);
  181.  
  182.         XSetForeground(xdpy, xgc, xshcolor.pixel);
  183.         fillrect(x0+2, y1, gapp.image->w, 2);
  184.         fillrect(x1, y0+2, 2, gapp.image->h);
  185.  
  186.         if (gapp.iscopying || justcopied)
  187.         {
  188.                 pdfapp_invert(&gapp, gapp.selr);
  189.                 justcopied = 1;
  190.         }
  191.  
  192.         pdfapp_inverthit(&gapp);
  193.  
  194.         if (gapp.image->n == 4)
  195.                 ximage_blit(xwin, xgc,
  196.                         x0, y0,
  197.                         gapp.image->samples,
  198.                         0, 0,
  199.                         gapp.image->w,
  200.                         gapp.image->h,
  201.                         gapp.image->w * gapp.image->n);
  202.         else if (gapp.image->n == 2)
  203.         {
  204.                 int i = gapp.image->w*gapp.image->h;
  205.                 unsigned char *color = malloc(i*4);
  206.                 if (color != NULL)
  207.                 {
  208.                         unsigned char *s = gapp.image->samples;
  209.                         unsigned char *d = color;
  210.                         for (; i > 0 ; i--)
  211.                         {
  212.                                 d[2] = d[1] = d[0] = *s++;
  213.                                 d[3] = *s++;
  214.                                 d += 4;
  215.                         }
  216.                         ximage_blit(xwin, xgc,
  217.                                 x0, y0,
  218.                                 color,
  219.                                 0, 0,
  220.                                 gapp.image->w,
  221.                                 gapp.image->h,
  222.                                 gapp.image->w * 4);
  223.                         free(color);
  224.                 }
  225.         }
  226.  
  227.         pdfapp_inverthit(&gapp);
  228.  
  229.         if (gapp.iscopying || justcopied)
  230.         {
  231.                 pdfapp_invert(&gapp, gapp.selr);
  232.                 justcopied = 1;
  233.         }
  234.  
  235.         winblitsearch(app);
  236. }
  237.  
  238. void winrepaint(pdfapp_t *app)
  239. {
  240.         dirty = 1;
  241. }
  242.  
  243. void winrepaintsearch(pdfapp_t *app)
  244. {
  245.         dirtysearch = 1;
  246. }
  247.  
  248. void windrawstringxor(pdfapp_t *app, int x, int y, char *s)
  249. {
  250.         int prevfunction;
  251.         XGCValues xgcv;
  252.  
  253.         XGetGCValues(xdpy, xgc, GCFunction, &xgcv);
  254.         prevfunction = xgcv.function;
  255.         xgcv.function = GXxor;
  256.         XChangeGC(xdpy, xgc, GCFunction, &xgcv);
  257.  
  258.         XSetForeground(xdpy, xgc, WhitePixel(xdpy, DefaultScreen(xdpy)));
  259.  
  260.         XDrawString(xdpy, xwin, xgc, x, y, s, strlen(s));
  261.         XFlush(xdpy);
  262.  
  263.         XGetGCValues(xdpy, xgc, GCFunction, &xgcv);
  264.         xgcv.function = prevfunction;
  265.         XChangeGC(xdpy, xgc, GCFunction, &xgcv);
  266.  
  267.         printf("drawstring '%s'\n", s);
  268. }
  269.  
  270. void windrawstring(pdfapp_t *app, int x, int y, char *s)
  271. {
  272.         XSetForeground(xdpy, xgc, BlackPixel(xdpy, DefaultScreen(xdpy)));
  273.         XDrawString(xdpy, xwin, xgc, x, y, s, strlen(s));
  274. }
  275.  
  276. void windocopy(pdfapp_t *app)
  277. {
  278. /*      unsigned short copyucs2[16 * 1024];
  279.         char *latin1 = copylatin1;
  280.         char *utf8 = copyutf8;
  281.         unsigned short *ucs2;
  282.         int ucs;
  283.  
  284.         pdfapp_oncopy(&gapp, copyucs2, 16 * 1024);
  285.  
  286.         for (ucs2 = copyucs2; ucs2[0] != 0; ucs2++)
  287.         {
  288.                 ucs = ucs2[0];
  289.  
  290.                 utf8 += runetochar(utf8, &ucs);
  291.  
  292.                 if (ucs < 256)
  293.                         *latin1++ = ucs;
  294.                 else
  295.                         *latin1++ = '?';
  296.         }
  297.  
  298.         *utf8 = 0;
  299.         *latin1 = 0;
  300.  
  301.         XSetSelectionOwner(xdpy, XA_PRIMARY, xwin, copytime);
  302.  
  303.         justcopied = 1;*/
  304. }
  305.  
  306. void onselreq(Window requestor, Atom selection, Atom target, Atom property, Time time)
  307. {
  308. /*      XEvent nevt;
  309.  
  310.         if (property == None)
  311.                 property = target;
  312.  
  313.         nevt.xselection.type = SelectionNotify;
  314.         nevt.xselection.send_event = True;
  315.         nevt.xselection.display = xdpy;
  316.         nevt.xselection.requestor = requestor;
  317.         nevt.xselection.selection = selection;
  318.         nevt.xselection.target = target;
  319.         nevt.xselection.property = property;
  320.         nevt.xselection.time = time;
  321.  
  322.         if (target == XA_TARGETS)
  323.         {
  324.                 Atom atomlist[4];
  325.                 atomlist[0] = XA_TARGETS;
  326.                 atomlist[1] = XA_TIMESTAMP;
  327.                 atomlist[2] = XA_STRING;
  328.                 atomlist[3] = XA_UTF8_STRING;
  329.                 printf(" -> targets\n");
  330.                 XChangeProperty(xdpy, requestor, property, target,
  331.                         32, PropModeReplace,
  332.                         (unsigned char *)atomlist, sizeof(atomlist)/sizeof(Atom));
  333.         }
  334.  
  335.         else if (target == XA_STRING)
  336.         {
  337.                 XChangeProperty(xdpy, requestor, property, target,
  338.                         8, PropModeReplace,
  339.                         (unsigned char *)copylatin1, strlen(copylatin1));
  340.         }
  341.  
  342.         else if (target == XA_UTF8_STRING)
  343.         {
  344.                 XChangeProperty(xdpy, requestor, property, target,
  345.                         8, PropModeReplace,
  346.                         (unsigned char *)copyutf8, strlen(copyutf8));
  347.         }
  348.  
  349.         else
  350.         {
  351.                 nevt.xselection.property = None;
  352.         }
  353.  
  354.         XSendEvent(xdpy, requestor, False, SelectionNotify, &nevt);
  355.         * */
  356. }
  357.  
  358. void winreloadfile(pdfapp_t *app)
  359. {
  360.         int fd;
  361.  
  362.         pdfapp_close(app);
  363.  
  364.         fd = open(filename, O_BINARY | O_RDONLY, 0666);
  365.         if (fd < 0)
  366.                 winerror(app, fz_throw("cannot reload file '%s'", filename));
  367.  
  368.         pdfapp_open(app, filename, fd, 1);
  369. }
  370.  
  371. void winopenuri(pdfapp_t *app, char *buf)
  372. {
  373.         /*
  374.         char *browser = getenv("BROWSER");
  375.         if (!browser)
  376.                 browser = "open";
  377.         if (fork() == 0)
  378.                 execlp(browser, browser, buf, (char*)0);
  379.                 * */
  380.                
  381. }
  382.  
  383. static void onkey(int c)
  384. {
  385. /*      if (justcopied)
  386.         {
  387.                 justcopied = 0;
  388.                 winrepaint(&gapp);
  389.         }
  390.         * */
  391.  
  392.         pdfapp_onkey(&gapp, c);
  393. }
  394.  
  395. static void onmouse(int x, int y, int btn, int modifiers, int state)
  396. {
  397. /*      if (state != 0 && justcopied)
  398.         {
  399.                 justcopied = 0;
  400.                 winrepaint(&gapp);
  401.         }*/
  402.  
  403.         pdfapp_onmouse(&gapp, x, y, btn, modifiers, state);
  404. }
  405.  
  406. static void signal_handler(int signal)
  407. {
  408.         /*
  409.         if (signal == SIGHUP)
  410.                 reloading = 1;
  411.                 * */
  412.                
  413. }
  414.  
  415. static void usage(void)
  416. {
  417.         fprintf(stderr, "usage: mupdf [options] file.pdf [page]\n");
  418.         fprintf(stderr, "\t-b -\tset anti-aliasing quality in bits (0=off, 8=best)\n");
  419.         fprintf(stderr, "\t-p -\tpassword\n");
  420.         fprintf(stderr, "\t-r -\tresolution\n");
  421.         fprintf(stderr, "\t-A\tdisable accelerated functions\n");
  422.         exit(1);
  423. }
  424.  
  425. int main(int argc, char **argv)
  426. {
  427.         int c;
  428.         int len;
  429.         char buf[128];
  430.         KeySym keysym;
  431.         int oldx = 0;
  432.         int oldy = 0;
  433.         int resolution = 72;
  434.         int pageno = 1;
  435.         int accelerate = 1;
  436.         int fd;
  437.         fd_set fds;
  438.         int width = -1;
  439.         int height = -1;
  440.  
  441.         while ((c = fz_getopt(argc, argv, "p:r:b:A")) != -1)
  442.         {
  443.                 switch (c)
  444.                 {
  445.                 case 'p': password = fz_optarg; break;
  446.                 case 'r': resolution = atoi(fz_optarg); break;
  447.                 case 'A': accelerate = 0; break;
  448.                 case 'b': fz_set_aa_level(atoi(fz_optarg)); break;
  449.                 default: usage();
  450.                 }
  451.         }
  452.  
  453.         if (resolution < MINRES)
  454.                 resolution = MINRES;
  455.         if (resolution > MAXRES)
  456.                 resolution = MAXRES;
  457.  
  458.         if (argc - fz_optind == 0)
  459.                 usage();
  460.  
  461.         filename = argv[fz_optind++];
  462.  
  463.         if (argc - fz_optind == 1)
  464.                 pageno = atoi(argv[fz_optind++]);
  465.  
  466.         if (accelerate)
  467.                 fz_accelerate();
  468.  
  469.         winopen();
  470.  
  471.         pdfapp_init(&gapp);
  472.         gapp.scrw = DisplayWidth(xdpy, xscr);
  473.         gapp.scrh = DisplayHeight(xdpy, xscr);
  474.         gapp.resolution = resolution;
  475.         gapp.pageno = pageno;
  476.  
  477.         fd = open(filename, O_BINARY | O_RDONLY, 0666);
  478.         if (fd < 0)
  479.                 winerror(&gapp, fz_throw("cannot open file '%s'", filename));
  480.  
  481.         pdfapp_open(&gapp, filename, fd, 0);
  482.  
  483.         FD_ZERO(&fds);
  484.         FD_SET(x11fd, &fds);
  485.  
  486.         signal(SIGHUP, signal_handler);
  487.  
  488.         while (!closing)
  489.         {
  490.                 do
  491.                 {
  492.                         XNextEvent(xdpy, &xevt);
  493.  
  494.                         switch (xevt.type)
  495.                         {
  496.                         case Expose:
  497.                                 dirty = 1;
  498.                                 break;
  499.  
  500.                         case ConfigureNotify:
  501.                                 if (gapp.image)
  502.                                 {
  503.                                         if (xevt.xconfigure.width != reqw ||
  504.                                                 xevt.xconfigure.height != reqh)
  505.                                                 gapp.shrinkwrap = 0;
  506.                                 }
  507.                                 width = xevt.xconfigure.width;
  508.                                 height = xevt.xconfigure.height;
  509.  
  510.                                 break;
  511.  
  512.                         case KeyPress:
  513.                                 len = XLookupString(&xevt.xkey, buf, sizeof buf, &keysym, NULL);
  514.  
  515.                                 if (!gapp.isediting)
  516.                                         switch (keysym)
  517.                                         {
  518.                                         case XK_Escape:
  519.                                                 len = 1; buf[0] = '\033';
  520.                                                 break;
  521.  
  522.                                         case XK_Up:
  523.                                                 len = 1; buf[0] = 'k';
  524.                                                 break;
  525.                                         case XK_Down:
  526.                                                 len = 1; buf[0] = 'j';
  527.                                                 break;
  528.  
  529.                                         case XK_Left:
  530.                                                 len = 1; buf[0] = 'b';
  531.                                                 break;
  532.                                         case XK_Right:
  533.                                                 len = 1; buf[0] = ' ';
  534.                                                 break;
  535.  
  536.                                         case XK_Page_Up:
  537.                                                 len = 1; buf[0] = ',';
  538.                                                 break;
  539.                                         case XK_Page_Down:
  540.                                                 len = 1; buf[0] = '.';
  541.                                                 break;
  542.                                         }
  543.                                 if (len)
  544.                                         onkey(buf[0]);
  545.  
  546.                                 onmouse(oldx, oldy, 0, 0, 0);
  547.  
  548.                                 break;
  549.  
  550.                         case MotionNotify:
  551.                                 oldx = xevt.xbutton.x;
  552.                                 oldy = xevt.xbutton.y;
  553.                                 onmouse(xevt.xbutton.x, xevt.xbutton.y, xevt.xbutton.button, xevt.xbutton.state, 0);
  554.                                 break;
  555.  
  556.                         case ButtonPress:
  557.                                 onmouse(xevt.xbutton.x, xevt.xbutton.y, xevt.xbutton.button, xevt.xbutton.state, 1);
  558.                                 break;
  559.  
  560.                         case ButtonRelease:
  561.                                 copytime = xevt.xbutton.time;
  562.                                 onmouse(xevt.xbutton.x, xevt.xbutton.y, xevt.xbutton.button, xevt.xbutton.state, -1);
  563.                                 break;
  564.  
  565.                         case SelectionRequest:
  566.                                 onselreq(xevt.xselectionrequest.requestor,
  567.                                         xevt.xselectionrequest.selection,
  568.                                         xevt.xselectionrequest.target,
  569.                                         xevt.xselectionrequest.property,
  570.                                         xevt.xselectionrequest.time);
  571.                                 break;
  572.  
  573.                         case ClientMessage:
  574.                                 if (xevt.xclient.format == 32 && xevt.xclient.data.l[0] == WM_DELETE_WINDOW)
  575.                                         closing = 1;
  576.                                 break;
  577.                         }
  578.                 }
  579.                 while (!closing && XPending(xdpy));
  580.  
  581.                 if (closing)
  582.                         continue;
  583.  
  584.                 if (width != -1 || height != -1)
  585.                 {
  586.                         pdfapp_onresize(&gapp, width, height);
  587.                         width = -1;
  588.                         height = -1;
  589.                 }
  590.  
  591.                 if (dirty || dirtysearch)
  592.                 {
  593.                         if (dirty)
  594.                                 winblit(&gapp);
  595.                         else if (dirtysearch)
  596.                                 winblitsearch(&gapp);
  597.                         dirty = 0;
  598.                         dirtysearch = 0;
  599.                 }
  600.  
  601.                 if (XPending(xdpy))
  602.                         continue;
  603.  
  604.                 if (select(x11fd + 1, &fds, NULL, NULL, NULL) < 0)
  605.                 {
  606.                         if (reloading)
  607.                         {
  608.                                 winreloadfile(&gapp);
  609.                                 reloading = 0;
  610.                         }
  611.                 }
  612.         }
  613.  
  614.         pdfapp_close(&gapp);
  615.  
  616.         XDestroyWindow(xdpy, xwin);
  617.  
  618.         XFreePixmap(xdpy, xicon);
  619.  
  620.         XFreeCursor(xdpy, xcwait);
  621.         XFreeCursor(xdpy, xchand);
  622.         XFreeCursor(xdpy, xcarrow);
  623.  
  624.         XFreeGC(xdpy, xgc);
  625.  
  626.         XCloseDisplay(xdpy);
  627.  
  628.         return 0;
  629. }
  630.