home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / xv310a / xvevent.c < prev    next >
C/C++ Source or Header  |  1995-06-12  |  82KB  |  2,959 lines

  1. /*
  2.  * xvevent.c - EventLoop and support routines for XV
  3.  *
  4.  *  Author:    John Bradley, University of Pennsylvania
  5.  *                (bradley@cis.upenn.edu)
  6.  *
  7.  *  Contains:
  8.  *            int  EventLoop()
  9.  *            void DrawWindow(x,y,w,h)
  10.  *            void WResize(w,h)
  11.  *            void WRotate()
  12.  *            void WCrop(w,h,dx,dy)
  13.  *            void WUnCrop()
  14.  *            void GetWindowPos(&xwa)
  15.  *            void SetWindowPos(&xwa)
  16.  *            void SetEpicMode()
  17.  *            int  xvErrorHandler(disp, err)
  18.  */
  19.  
  20. #include "copyright.h"
  21.  
  22. #define NEEDSTIME    /* for -wait handling in eventloop */
  23.  
  24. #include "xv.h"
  25.  
  26. #include "bits/dropper"
  27. #include "bits/dropperm"
  28. #include "bits/pen"
  29. #include "bits/penm"
  30. #include "bits/blur"
  31. #include "bits/blurm"
  32.  
  33. static int   rotatesLeft = 0;
  34. static int   origcropx, origcropy, origcropvalid=0;
  35. static int   canstartwait;
  36. static int   frominterrupt = 0;
  37. static char *xevPriSel = NULL;
  38. static Time  lastEventTime;
  39. static Cursor dropper = 0, pen = 0, blur = 0;
  40.  
  41.  
  42. static void debugEvent         PARM((XEvent *));
  43. static char *win2name          PARM((Window));
  44. static void handleButtonEvent  PARM((XEvent *, int *, int *));
  45. static void handleKeyEvent     PARM((XEvent *, int *, int *));
  46. static void zoomCurs           PARM((u_int));
  47. static void textViewCmd        PARM((void));
  48. static void setSizeCmd         PARM((void));
  49. static void WMaximize          PARM((void));
  50. static void CropKey            PARM((int, int, int, int));
  51. static void TrackPicValues     PARM((int, int));
  52. static int  CheckForConfig     PARM((void));
  53. static Bool IsConfig           PARM((Display *, XEvent *, char *));
  54. static void onInterrupt        PARM((int));
  55.  
  56. static void   Paint            PARM((void));
  57. static void   paintPixel       PARM((int, int));
  58. static void   paintLine        PARM((int, int, int, int));
  59. static void   paintXLine       PARM((int, int, int, int, int));
  60. static void   BlurPaint        PARM((void));
  61. static int    highbit          PARM((u_long));
  62. static u_long RGBToXColor      PARM((int, int, int));
  63. static void   blurPixel        PARM((int, int));
  64.  
  65. static void   annotatePic      PARM((void));
  66.  
  67.  
  68. /****************/
  69. int EventLoop()
  70. /****************/
  71. {
  72.   XEvent event;
  73.   int    retval,done,waiting;
  74.   time_t orgtime, curtime;
  75.  
  76.  
  77. #ifndef NOSIGNAL
  78.   signal(SIGQUIT, onInterrupt);
  79. #endif
  80.  
  81.   /* note: there's no special event handling if we're using the root window.
  82.      if we're using the root window, we will recieve NO events for mainW */
  83.  
  84.   /* note: 'canstartwait' is magically turned 'true' in HandleEvent when I
  85.      think I've finally gotten 'mainW' drawn.  It does not necessarily
  86.      mean that any waiting is/will be done.  Also note that if we're
  87.      using a root mode, canstartwait is instantly turned on, as we aren't
  88.      going to be getting Expose/Configure events on the root window */
  89.  
  90.   done = retval = waiting = canstartwait = 0;
  91.  
  92.   if (useroot) canstartwait = 1;
  93.   else if (mainW) {           /* if mainW iconified, start wait now */
  94.     XWindowAttributes xwa;
  95.     XSync(theDisp, False);
  96.     if (XGetWindowAttributes(theDisp, mainW, &xwa)) {
  97.       if (xwa.map_state != IsViewable) canstartwait = 1;
  98.     }
  99.   }
  100.  
  101.   while (!done) {
  102.  
  103.     if (waitsec > -1 && canstartwait && !waiting && XPending(theDisp)==0) {
  104.       /* we wanna wait, we can wait, we haven't started waiting yet, and 
  105.      all pending events (ie, drawing the image the first time) 
  106.      have been dealt with:  START WAITING */
  107.       time((time_t *) &orgtime);
  108.       waiting = 1;
  109.     }
  110.  
  111.  
  112.     /* if there's an XEvent pending *or* we're not doing anything 
  113.        in real-time (polling, flashing the selection, etc.) get next event */
  114.     if ((waitsec==-1 && !polling && !HaveSelection()) || XPending(theDisp)>0) {
  115.       XNextEvent(theDisp, &event);
  116.       retval = HandleEvent(&event,&done);
  117.     }
  118.  
  119.     else {                      /* no events.  check wait status */
  120.       if (HaveSelection()) {
  121.     DrawSelection(0);
  122.     DrawSelection(1);
  123.     XFlush(theDisp);
  124.     Timer(200);
  125.       }
  126.  
  127.       if (polling) {
  128.     if (CheckPoll(2)) return POLLED;
  129.     else if (!XPending(theDisp)) sleep(1);
  130.       }
  131.  
  132.       if (waitsec>-1 && waiting) {
  133.     time((time_t *) &curtime);
  134.     if (curtime - orgtime < waitsec) sleep(1);
  135.     else {
  136.       if (waitloop) return NEXTLOOP;
  137.       else return NEXTQUIT;
  138.     }
  139.       }
  140.     }
  141.   }  /* while (!done) */
  142.  
  143.   if (!useroot && origcropvalid) WUnCrop();
  144.   origcropvalid = 0;
  145.  
  146.   return(retval);
  147. }
  148.  
  149.  
  150.  
  151. /****************/
  152. int HandleEvent(event, donep)
  153.      XEvent *event;
  154.      int    *donep;
  155. {
  156.   static int wasInfoUp=0, wasCtrlUp=0, wasDirUp=0, wasGamUp=0, wasPsUp=0;
  157.   static int wasJpegUp=0, wasTiffUp=0;
  158.  
  159.   static int mainWKludge=0;  /* force first mainW expose after a mainW config
  160.                 to redraw all of mainW */
  161.  
  162.   int done=0, retval=0;
  163.  
  164.  
  165.   if (DEBUG) debugEvent((XEvent *) event);
  166.  
  167.  
  168.   switch (event->type) {
  169.  
  170.   case ButtonPress:
  171.     lastEventTime = ((XButtonEvent *) event)->time;
  172.     handleButtonEvent(event, &done, &retval);
  173.     break;
  174.  
  175.  
  176.   case KeyRelease:
  177.   case KeyPress:
  178.     lastEventTime = ((XKeyEvent *) event)->time;
  179.     handleKeyEvent(event, &done, &retval);
  180.     break;
  181.  
  182.  
  183.   case Expose: {
  184.     XExposeEvent *exp_event = (XExposeEvent *) event;
  185.     int x,y,w,h;
  186.     Window win;
  187.  
  188. #ifdef VMS
  189.     static int borders_sized = 0;
  190.   
  191.     if (!borders_sized  && !useroot && exp_event->window == mainW) {
  192.       /*
  193.        * Initial expose of main window, find the size of the ancestor
  194.        * window just prior to the root window and adjust saved size
  195.        * of display so that maximize functions will allow for window
  196.        * decorations.
  197.        */
  198.       int status, count, mwid, mhgt, x, y, w, h, b, d, mbrd;
  199.       Window root, parent, *children, crw = exp_event->window;
  200.       borders_sized = 1;
  201.       status = XGetGeometry(theDisp, crw, 
  202.                 &root, &x, &y, &mwid, &mhgt, &mbrd, &d);
  203.       
  204.       for ( parent = crw, w=mwid, h=mhgt;
  205.        status && (parent != root) && (parent != vrootW); ) {
  206.     crw = parent;
  207.     status = XQueryTree ( theDisp, crw, &root, &parent, 
  208.                  &children, &count );
  209.     if ( children != NULL ) XFree ( children );
  210.       }
  211.       status = XGetGeometry(theDisp, crw, &root, &x, &y, &w, &h, &b, &d);
  212.       if ( status ) {
  213.     dispWIDE = dispWIDE + mwid - w + (2*b);
  214.     dispHIGH = dispHIGH + mhgt - h + b;
  215.     /*printf("New display dims: %d %d\n", dispWIDE, dispHIGH ); */
  216.       }
  217.     }
  218. #endif
  219.  
  220.  
  221.     win = exp_event->window;
  222.     x = exp_event->x;      y = exp_event->y;
  223.     w = exp_event->width;  h = exp_event->height;
  224.     
  225.     if (PUCheckEvent  (event)) break;   /* event has been processed */
  226.     if (PSCheckEvent  (event)) break;   /* event has been processed */
  227.  
  228. #ifdef HAVE_JPEG
  229.     if (JPEGCheckEvent(event)) break;   /* event has been processed */
  230. #endif
  231.  
  232. #ifdef HAVE_TIFF
  233.     if (TIFFCheckEvent(event)) break;   /* event has been processed */
  234. #endif
  235.  
  236.     if (GamCheckEvent (event)) break;   /* event has been processed */
  237.     if (BrowseCheckEvent (event, &retval, &done)) break;   /* event eaten */
  238.     if (TextCheckEvent   (event, &retval, &done)) break;   /* event eaten */
  239.  
  240.     /* if the window doesn't do intelligent redraw, drop but last expose */
  241.     if (exp_event->count>0 && 
  242.     win != mainW && win != ctrlW &&    win != dirW && win != infoW) break;
  243.  
  244.  
  245.  
  246.     if (win == mainW && CheckForConfig()) {
  247.       if (DEBUG) fprintf(stderr,"Expose mainW ignored.  Config pending.\n");
  248.       break;
  249.     }
  250.  
  251.  
  252.  
  253.  
  254.     if (win==mainW || win==ctrlW || win==dirW || win==infoW) {
  255.       /* must be a 'smart' window.  group exposes into an expose 'region' */
  256.       int           count;
  257.       Region        reg;
  258.       XRectangle    rect;
  259.       XEvent        evt;
  260.  
  261.       xvbcopy((char *) exp_event, (char *) &evt, sizeof(XEvent));
  262.       reg = XCreateRegion();
  263.       count = 0;
  264.  
  265.       do {
  266.     rect.x      = evt.xexpose.x;
  267.     rect.y      = evt.xexpose.y;
  268.     rect.width  = evt.xexpose.width;
  269.     rect.height = evt.xexpose.height;
  270.     XUnionRectWithRegion(&rect, reg, reg);
  271.     count++;
  272.  
  273.     if (DEBUG) debugEvent((XEvent *) &evt);
  274.  
  275.       } while (XCheckWindowEvent(theDisp,evt.xexpose.window,
  276.                  ExposureMask, &evt));
  277.  
  278.       XClipBox(reg, &rect);  /* bounding box of region */
  279.       XSetRegion(theDisp, theGC, reg);
  280.  
  281.       x = rect.x;      y = rect.y;
  282.       w = rect.width;  h = rect.height;
  283.  
  284.       if (DEBUG) fprintf(stderr,"window: 0x%08x  collapsed %d expose events\n",
  285.              (u_int) exp_event->window, count);
  286.       if (DEBUG) fprintf(stderr,"        region bounding box: %d,%d %dx%d\n",
  287.              x, y, w, h);
  288.  
  289.  
  290.       if (win == mainW) {
  291.     if (DEBUG) fprintf(stderr,"EXPOSE:  ");
  292.     if (!CheckForConfig()) {
  293.  
  294.       if (mainWKludge) {
  295.         if (DEBUG) fprintf(stderr, "Using mainWKludge\n");
  296.         x = 0; y = 0;  w = eWIDE;  h = eHIGH;
  297.         XSetClipMask(theDisp, theGC, None);
  298.         mainWKludge = 0;
  299.       }
  300.  
  301.       if (DEBUG) fprintf(stderr,"No configs pending.\n");
  302.       /* if (DEBUG) XClearArea(theDisp, mainW, x,y,w,h, False); */
  303.       DrawWindow(x,y,w,h);
  304.         
  305.       if (HaveSelection()) DrawSelection(0);
  306.  
  307.       canstartwait = 1;  /* finished drawing */
  308.       XSync(theDisp, False);
  309.     }
  310.     else
  311.       if (DEBUG) fprintf(stderr,"Ignored.  Config pending\n");
  312.       }
  313.  
  314.       else if (win == infoW)          RedrawInfo(x,y,w,h);
  315.       else if (win == ctrlW)          RedrawCtrl(x,y,w,h);
  316.       else if (win == dirW)           RedrawDirW(x,y,w,h);
  317.       
  318.       XSetClipMask(theDisp, theGC, None);
  319.       XDestroyRegion(reg);
  320.     }
  321.  
  322.     else if (win == nList.win)      LSRedraw(&nList,0);
  323.     else if (win == nList.scrl.win) SCRedraw(&nList.scrl);
  324.     else if (win == dList.win)      LSRedraw(&dList,0);
  325.     else if (win == dList.scrl.win) SCRedraw(&dList.scrl);
  326.     else if (win == dnamW)          RedrawDNamW();
  327.   }      
  328.     break;
  329.  
  330.     
  331.  
  332.   case ClientMessage: {
  333.     Atom proto, delwin;
  334.     XClientMessageEvent *client_event = (XClientMessageEvent *) event;
  335.  
  336.     if (PUCheckEvent (event)) break;   /* event has been processed */
  337.  
  338.     proto = XInternAtom(theDisp, "WM_PROTOCOLS", FALSE);
  339.     delwin = XInternAtom(theDisp, "WM_DELETE_WINDOW", FALSE);
  340.  
  341.     if (client_event->message_type == proto &&
  342.     client_event->data.l[0]    == delwin) {
  343.       /* it's a WM_DELETE_WINDOW event */
  344.  
  345.       if (BrowseDelWin(client_event->window)) break;
  346.       if (TextDelWin(client_event->window)) break;
  347.  
  348.       if      (client_event->window == infoW) InfoBox(0);
  349.       else if (client_event->window == gamW)  GamBox(0);
  350.       else if (client_event->window == ctrlW) CtrlBox(0);
  351.       else if (client_event->window == dirW)  DirBox(0);
  352.       else if (client_event->window == psW)   PSDialog(0);
  353.  
  354. #ifdef HAVE_JPEG
  355.       else if (client_event->window == jpegW) JPEGDialog(0);
  356. #endif
  357.  
  358. #ifdef HAVE_TIFF
  359.       else if (client_event->window == tiffW) TIFFDialog(0);
  360. #endif
  361.  
  362.       else if (client_event->window == mainW) Quit(0);
  363.     }
  364.   }
  365.     break;
  366.  
  367.  
  368.   case ConfigureNotify: {
  369.     XConfigureEvent *cevt = (XConfigureEvent *) event;
  370.     Window           win  = cevt->window;
  371.  
  372.     if (BrowseCheckEvent (event, &retval, &done)) break;   /* event eaten */
  373.     if (TextCheckEvent   (event, &retval, &done)) break;   /* event eaten */
  374.  
  375.     /*
  376.      * if it's a configure of one of the 'major' xv windows, update the
  377.      * NORMAL position hints for this window appropriately (so it can be
  378.      * iconified and deiconified correctly)
  379.      */
  380.  
  381.     if (win==ctrlW || win==gamW || win==infoW || win==mainW || win==dirW) {
  382.       XSizeHints hints;
  383.  
  384.       /*
  385.        * if there's a virtual window manager running (e.g. tvtwm / olvwm), 
  386.        * we're going to get 'cevt' values in terms of the 
  387.        * 'real' root window (the one that is the size of the screen).
  388.        * We'll want to translate them into values that are in terms of
  389.        * the 'virtual' root window (the 'big' one)
  390.        */
  391.  
  392.       if (vrootW != rootW) {
  393.     int x1,y1;  Window child;
  394.  
  395.     XTranslateCoordinates(theDisp, rootW, vrootW, cevt->x, cevt->y, 
  396.                   &x1, &y1, &child);
  397.     if (DEBUG) fprintf(stderr,"  CONFIG trans %d,%d root -> %d,%d vroot\n",
  398.                cevt->x, cevt->y, x1, y1);
  399.     cevt->x = x1;  cevt->y = y1;
  400.       }
  401.  
  402. #ifndef VMS
  403.       /* read hints for this window and adjust any position hints, but
  404.          only if this is a 'synthetic' event sent to us by the WM 
  405.      ('real' events from the server have useless x,y info, since the
  406.      mainW has been reparented by the WM) */
  407.  
  408.       if (cevt->send_event && 
  409.       XGetNormalHints(theDisp, cevt->window, &hints)) {
  410.  
  411.     if (DEBUG) fprintf(stderr,"  CONFIG got hints (0x%x  %d,%d)\n",
  412.                (u_int) hints.flags, hints.x, hints.y);
  413.  
  414.     hints.x = cevt->x;
  415.     hints.y = cevt->y;
  416.     XSetNormalHints(theDisp, cevt->window, &hints);
  417.  
  418.     if (DEBUG) fprintf(stderr,"  CONFIG set hints (0x%x  %d,%d)\n",
  419.         (u_int) hints.flags, hints.x, hints.y);
  420.       }
  421. #endif
  422.     }
  423.  
  424.  
  425.     if (cevt->window == mainW) {
  426.  
  427.       /* when we load a new image, we may get *2* configure events from
  428.        * the 'XMoveResizeWindow()' call.  One at the 'old' size, in the
  429.        * new position, and one at the new size at the new position.
  430.        * We want to *IGNORE* the one at the old size, as we don't want to
  431.        * call Resize() for images that we won't need.
  432.        *
  433.        * Note that we may also only get *one* Configure event (if the window
  434.        * didn't move), and we may also only get *one* Configure event in
  435.        * some unasked for size (if the asked for size wasn't acceptable to
  436.        * the window manager), and we may also get *no* Configure event
  437.        * if the window doesn't move or change size
  438.        *
  439.        * This sucks!
  440.        *
  441.        * So, if we have just loaded an image, and we get a Synthetic conf
  442.        * that is not the desired size (eWIDExeHIGH), ignore it, as it's 
  443.        * just the conf generated by moving the old window.  And stop
  444.        * ignoring further config events
  445.        *
  446.        * EVIL KLUDGE:  do *not* ignore configs that are <100x100.  Not 
  447.        * ignoring them won't be a big performance problem, and it'll get
  448.        * around the 'I only got one config in the wrong size' problem when
  449.        * initially displaying small images
  450.        */
  451.  
  452.       if (cevt->width<100 && cevt->height < 100 ) ignoreConfigs = 0;
  453.  
  454. /* fprintf(stderr,"***mainw, ignore=%d, send_event=%d, evtSize=%d,%d, size=%d,%d\n", ignoreConfigs, cevt->send_event, cevt->width, cevt->height, eWIDE, eHIGH); */
  455.  
  456.       if (ignoreConfigs==1 && cevt->send_event && 
  457.       (cevt->width != eWIDE || cevt->height != eHIGH)) {
  458.     ignoreConfigs=0;        /* ignore this one only */
  459.     break;
  460.       }
  461.  
  462.       ignoreConfigs = 0;
  463.  
  464.  
  465.       if (!rotatesLeft) {
  466.     if (CheckForConfig()) {
  467.       if (DEBUG) fprintf(stderr,"more configs pending.  ignored\n");
  468.     }
  469.  
  470.     else {
  471.       XEvent xev;
  472.       if (DEBUG) fprintf(stderr,"No configs pend.");
  473.       
  474.       if (cevt->width == eWIDE && cevt->height == eHIGH) {
  475.         if (DEBUG) fprintf(stderr,"No redraw\n");
  476.       }
  477.       else {
  478.         if (DEBUG) fprintf(stderr,"Do full redraw\n");
  479.  
  480.         Resize(cevt->width, cevt->height);
  481.         
  482.         /* eat any pending expose events and do a full redraw */
  483.         while (XCheckTypedWindowEvent(theDisp, mainW, Expose, &xev)) {
  484.           XExposeEvent *exp = (XExposeEvent *) &xev;
  485.  
  486.           if (DEBUG) 
  487.         fprintf(stderr,"  ate expose (%s) (count=%d) %d,%d %dx%d\n",
  488.             exp->send_event ? "synth" : "real", exp->count,
  489.             exp->x, exp->y, exp->width, exp->height);
  490.         }
  491.  
  492.         DrawWindow(0,0,cevt->width, cevt->height);
  493.  
  494.         if (HaveSelection()) DrawSelection(0);
  495.             canstartwait=1;
  496.         XSync(theDisp, False);
  497.         SetCursors(-1);
  498.       }
  499.     }
  500.       }
  501.  
  502.       if (rotatesLeft>0) {
  503.     rotatesLeft--;
  504.     if (!rotatesLeft) mainWKludge = 1;
  505.       }
  506.       if (!rotatesLeft) SetCursors(-1);
  507.     }
  508.  
  509.   }
  510.     break;
  511.     
  512.  
  513.     
  514.   case CirculateNotify:
  515.   case DestroyNotify:
  516.   case GravityNotify:       break;
  517.  
  518.   case MapNotify: {
  519.     XMapEvent *map_event = (XMapEvent *) event;
  520.  
  521.     if (map_event->window == mainW ||
  522.     (map_event->window == ctrlW && dispMode != RMB_WINDOW)) {
  523.       if (DEBUG) fprintf(stderr,"map event received on mainW/ctrlW\n");
  524.  
  525.       if (autoclose) {
  526.     if (autoclose>1) autoclose -= 2;  /* grab kludge */
  527.     if (wasInfoUp) { InfoBox(wasInfoUp);     wasInfoUp=0; }
  528.     if (wasCtrlUp) { CtrlBox(wasCtrlUp);     wasCtrlUp=0; }
  529.     if (wasDirUp)  { DirBox(wasDirUp);       wasDirUp=0; }
  530.     UnHideBrowseWindows();
  531.     UnHideTextWindows();
  532.     if (wasGamUp)  { GamBox(wasGamUp);       wasGamUp=0; }
  533.     if (wasPsUp)   { PSDialog(wasPsUp);      wasPsUp=0; }
  534. #ifdef HAVE_JPEG
  535.     if (wasJpegUp) { JPEGDialog(wasJpegUp);  wasJpegUp=0; }
  536. #endif
  537.  
  538. #ifdef HAVE_TIFF
  539.     if (wasTiffUp) { TIFFDialog(wasTiffUp);  wasTiffUp=0; }
  540. #endif
  541.       }
  542.     }
  543.   }
  544.     break;
  545.  
  546.  
  547.   case UnmapNotify: {
  548.     XUnmapEvent *unmap_event = (XUnmapEvent *) event;
  549.  
  550.     if (unmap_event->window == mainW ||
  551.     (unmap_event->window == ctrlW && dispMode != RMB_WINDOW)) {
  552.       if (DEBUG) fprintf(stderr,"unmap event received on mainW/ctrlW\n");
  553.       if (DEBUG) fprintf(stderr,"dispMode = %d\n", dispMode);
  554.  
  555.       /* don't do it if we've just switched to a root mode */
  556.       if ((unmap_event->window == mainW && dispMode == 0) ||
  557.       (unmap_event->window == ctrlW && dispMode != 0)) {  
  558.  
  559.     if (autoclose) {
  560.       if (autoclose>1) autoclose -= 2;  /* grab kludge */
  561.  
  562.       if (unmap_event->window == mainW) {
  563.         if (ctrlUp) { wasCtrlUp = ctrlUp;  CtrlBox(0); }
  564.       }
  565.  
  566.       if (infoUp) { wasInfoUp = infoUp;  InfoBox(0); }
  567.       if (dirUp)  { wasDirUp  = dirUp;   DirBox(0); }
  568.       HideBrowseWindows();
  569.       HideTextWindows();
  570.       if (gamUp)  { wasGamUp  = gamUp;   GamBox(0); }
  571.       if (psUp)   { wasPsUp   = psUp;    PSDialog(0); }
  572. #ifdef HAVE_JPEG
  573.       if (jpegUp) { wasJpegUp = jpegUp;  JPEGDialog(0); }
  574. #endif
  575.  
  576. #ifdef HAVE_TIFF
  577.       if (tiffUp) { wasTiffUp = tiffUp;  TIFFDialog(0); }
  578. #endif
  579.     }
  580.       }
  581.     }
  582.   }
  583.     break;
  584.  
  585.   case ReparentNotify: {
  586.     XReparentEvent *reparent_event = (XReparentEvent *) event;
  587.  
  588.     if (DEBUG) {
  589.       fprintf(stderr,"Reparent: mainW=%x ->win=%x ->ev=%x  ->parent=%x  ", 
  590.           (u_int) mainW,                 (u_int) reparent_event->window, 
  591.           (u_int) reparent_event->event, (u_int) reparent_event->parent);
  592.       fprintf(stderr,"%d,%d\n", reparent_event->x, reparent_event->y);
  593.     }
  594.  
  595.     if (reparent_event->window == mainW) {
  596.       ch_offx = reparent_event->x;  /* offset required for ChangeAttr call */
  597.       ch_offy = reparent_event->y;
  598.  
  599.       p_offx = p_offy = 0;          /* topleft correction for WMs titlebar */
  600.  
  601.       if (ch_offx == 0 && ch_offy == 0) {  
  602.     /* looks like the user is running MWM or OLWM */
  603.  
  604.     XWindowAttributes xwa;
  605.  
  606.     /* first query the attributes of mainW.  x,y should be the offset
  607.        from the parent's topleft corner to the windows topleft.
  608.        OLWM puts the info here */
  609.  
  610.     XSync(theDisp, False);
  611.     XGetWindowAttributes(theDisp, mainW, &xwa);
  612.     
  613.     if (DEBUG) 
  614.       fprintf(stderr,"XGetAttr: mainW %d,%d %dx%d\n", xwa.x, xwa.y,
  615.           xwa.width, xwa.height);
  616.  
  617.     if (xwa.x == 0 && xwa.y == 0) {
  618.       /* MWM, at least mine, puts 0's in those fields.  To get the
  619.          info, we'll have to query the parent window */
  620.  
  621.       XSync(theDisp, False);
  622.       XGetWindowAttributes(theDisp, reparent_event->parent, &xwa);
  623.     
  624.       if (DEBUG) 
  625.         fprintf(stderr,"XGetAttr: parent %d,%d %dx%d\n", xwa.x, xwa.y,
  626.             xwa.width, xwa.height);
  627.     }
  628.     else {
  629.       /* KLUDGE:  if we're running olwm, xwa.{x,y} won't be 0,0.
  630.          in olwm, the window drifts down and right each time
  631.          SetWindowPos() is called.  God knows why.  Anyway, I'm
  632.          inserting a kludge here to increase 'ch_offx' and 'ch_offy'
  633.          by bwidth so that this drifting won't happen.  No doubt this'll
  634.          screw up behavior on some *other* window manager, but it should
  635.          work with TWM, OLWM, and MWM (the big three) */
  636.       ch_offx += bwidth;
  637.       ch_offy += bwidth;
  638.     }
  639.  
  640.     p_offx = xwa.x;
  641.     p_offy = xwa.y;
  642.       }
  643.  
  644.       
  645.       /* move window around a bit... */
  646.       {
  647.     XWindowAttributes xwa;
  648.     GetWindowPos(&xwa);
  649.     xwa.width = eWIDE;  xwa.height = eHIGH;
  650.     
  651.     /* try to keep the damned thing on-screen, if possible */
  652.     if (xwa.x + xwa.width  > dispWIDE) xwa.x = dispWIDE - xwa.width;
  653.     if (xwa.y + xwa.height > dispHIGH) xwa.y = dispHIGH - xwa.height;
  654.     if (xwa.x < 0) xwa.x = 0;
  655.     if (xwa.y < 0) xwa.y = 0;
  656.     
  657.     SetWindowPos(&xwa);
  658.       }
  659.  
  660.     }
  661.   }
  662.     break;
  663.     
  664.  
  665.   case EnterNotify:
  666.   case LeaveNotify: {
  667.     XCrossingEvent *cross_event = (XCrossingEvent *) event;
  668.     if (cross_event->window == mainW || 0
  669.     /* (cross_event->window == gamW && cmapInGam) */ ) {
  670.       
  671.       if (cross_event->type == EnterNotify && cross_event->window == mainW) {
  672.     zoomCurs(cross_event->state);
  673.       }
  674.  
  675.  
  676.       if (cross_event->type == EnterNotify && LocalCmap && !ninstall) 
  677.     XInstallColormap(theDisp,LocalCmap);
  678.  
  679.       if (cross_event->type == LeaveNotify && LocalCmap && !ninstall) 
  680.     XUninstallColormap(theDisp,LocalCmap);
  681.     }
  682.   }
  683.     break;
  684.  
  685.  
  686.   case SelectionClear:  break;
  687.  
  688.   case SelectionRequest: 
  689.     {
  690.       XSelectionRequestEvent *xsrevt = (XSelectionRequestEvent *) event;
  691.       XSelectionEvent  xse;
  692.  
  693.       if (xsrevt->owner     != ctrlW      || 
  694.       xsrevt->selection != XA_PRIMARY ||
  695.       xsrevt->target    != XA_STRING) {  /* can't do it. */
  696.     xse.property = None;
  697.       }
  698.       else {
  699.     if (xsrevt->property == None) xse.property = xsrevt->target;
  700.                              else xse.property = xsrevt->property;
  701.  
  702.     if (xse.property != None) {
  703.           xerrcode = 0;
  704.       XChangeProperty(theDisp, xsrevt->requestor, xse.property,
  705.               XA_STRING, 8, PropModeReplace, 
  706.               (byte *) ((xevPriSel) ? xevPriSel           : "\0"),
  707.               (int)    ((xevPriSel) ? strlen(xevPriSel)+1 : 1));
  708.           XSync(theDisp, False);
  709.           if (!xerrcode) xse.property = None;
  710.     }
  711.       }
  712.  
  713.       xse.type       = SelectionNotify;
  714.       xse.send_event = True;
  715.       xse.display    = theDisp;
  716.       xse.requestor  = xsrevt->requestor;
  717.       xse.selection  = xsrevt->selection;
  718.       xse.target     = xsrevt->target;
  719.       xse.time       = xsrevt->time;
  720.       XSendEvent(theDisp, xse.requestor, False, NoEventMask, (XEvent *) &xse);
  721.       XSync(theDisp, False);
  722.     }
  723.     break;
  724.     
  725.       
  726.     
  727.   default: break;        /* ignore unexpected events */
  728.   }  /* switch */
  729.  
  730.   frominterrupt = 0;
  731.   *donep = done;
  732.   return(retval);
  733. }
  734.  
  735.  
  736. /***********************************/
  737. void SelectDispMB(i)
  738.      int i;
  739. {
  740.   /* called to handle selection of a dispMB item */
  741.   
  742.   if (i<0 || i>=DMB_MAX) return;
  743.  
  744.   if (dispMB.dim[i]) return;    /* disabled */
  745.  
  746.   if (i>=DMB_RAW && i<=DMB_SMOOTH) {
  747.     if      (i==DMB_RAW)  epicMode = EM_RAW;
  748.     else if (i==DMB_DITH) epicMode = EM_DITH;
  749.     else                  epicMode = EM_SMOOTH;
  750.     
  751.     SetEpicMode();                  
  752.     GenerateEpic(eWIDE, eHIGH);
  753.     DrawEpic();
  754.     SetCursors(-1);
  755.   }
  756.   
  757.   else if (i==DMB_COLRW) {   /* toggle rw on/off */
  758.     dispMB.flags[i] = !dispMB.flags[i];
  759.     allocMode = (dispMB.flags[i]) ? AM_READWRITE : AM_READONLY;
  760.     ChangeCmapMode(colorMapMode, 1, 0);
  761.   }
  762.   
  763.   else if (i>=DMB_COLNORM && i<=DMB_COLSTDC && !dispMB.flags[i]) {
  764.     switch (i) {
  765.     case DMB_COLNORM:  
  766.       ChangeCmapMode(CM_NORMAL, 1, 0);   
  767.       defaultCmapMode = CM_NORMAL;    
  768.       break;
  769.     case DMB_COLPERF:  
  770.       ChangeCmapMode(CM_PERFECT,1, 0);
  771.       defaultCmapMode = CM_PERFECT;   
  772.       break;
  773.     case DMB_COLOWNC:  
  774.       ChangeCmapMode(CM_OWNCMAP,1, 0);
  775.       defaultCmapMode = CM_OWNCMAP;   
  776.       break;
  777.     case DMB_COLSTDC:  
  778.       ChangeCmapMode(CM_STDCMAP,1, 0);
  779.       defaultCmapMode = CM_STDCMAP;   
  780.       break;
  781.     }
  782.   }
  783. }
  784.  
  785.  
  786. /***********************************/
  787. void SelectRootMB(i)
  788.      int i;
  789. {
  790.   /* called to handle selection of a rootMB item */
  791.   
  792.   if (i<0 || i>=RMB_MAX) return;
  793.   if (rootMB.flags[i])   return;
  794.   if (rootMB.dim[i])     return;
  795.  
  796.   dispMode = i;
  797.   
  798.   /* move checkmark */
  799.   for (i=RMB_WINDOW; i<RMB_MAX; i++) rootMB.flags[i] = 0;
  800.   rootMB.flags[dispMode] = 1;
  801.   
  802.   HandleDispMode();
  803. }
  804.  
  805.  
  806. /***********************************/
  807. void Select24to8MB(i)
  808.      int i;
  809. {
  810.   if (i<0 || i>=CONV24_MAX) return;
  811.  
  812.   if (conv24MB.dim[i]) return;
  813.  
  814.   if (i==CONV24_8BIT || i==CONV24_24BIT) {
  815.     if (i != picType) {
  816.       Change824Mode(i);
  817.       if (i==CONV24_8BIT && state824==0) state824 = 1;  /* did 24->8 */
  818.       else if (i==CONV24_24BIT && state824==1) {
  819.     /* went 24->8->24 */
  820.     char buf[512];
  821.     
  822.     sprintf(buf,"Warning:  You appear to have taken a 24-bit ");
  823.     strcat(buf, "image, turned it to an 8-bit image, and turned ");
  824.     strcat(buf, "it back into a 24-bit image.  Understand that ");
  825.     strcat(buf, "image data has probably been lost in this ");
  826.     strcat(buf, "transformation.  You *may* want to reload the ");
  827.     strcat(buf, "original image to avoid this problem.");
  828.     
  829.     ErrPopUp(buf, "\nI Know!");
  830.     
  831.     state824 = 2;   /* shut up until next image is loaded */
  832.       }
  833.     }
  834.   }
  835.   
  836.   else if (i==CONV24_LOCK) {
  837.     conv24MB.flags[i] = !conv24MB.flags[i];
  838.   }
  839.   
  840.   else if (i>=CONV24_FAST && i<=CONV24_BEST) {
  841.     conv24 = i;
  842.     for (i=CONV24_FAST; i<=CONV24_BEST; i++) {
  843.       conv24MB.flags[i] = (i==conv24);
  844.     }
  845.   }
  846. }
  847.  
  848.  
  849. /***********************************/
  850. void SelectWindowMB(i)
  851.      int i;
  852. {
  853.   if (i<0 || i>=WMB_MAX) return;
  854.   if (windowMB.dim[i]) return;
  855.  
  856.   switch (i) {
  857.   case WMB_BROWSE:
  858.     if (strlen(searchdir)) chdir(searchdir);
  859.     else chdir(initdir);
  860.     OpenBrowse();
  861.     break;
  862.     
  863.   case WMB_COLEDIT:  GamBox (!gamUp);   break;
  864.   case WMB_INFO:     InfoBox(!infoUp);  break;
  865.     
  866.   case WMB_COMMENT:  
  867.     if (!commentUp) OpenCommentText();
  868.     else CloseCommentText();
  869.     break;
  870.     
  871.   case WMB_TEXTVIEW:  textViewCmd();  break;
  872.   case WMB_ABOUTXV:   ShowLicense();  break;
  873.   case WMB_KEYHELP:   ShowKeyHelp();  break;
  874.  
  875.   default:  break;
  876.   }
  877. }
  878.  
  879.  
  880. /***********************************/
  881. void SelectSizeMB(i)
  882.      int i;
  883. {
  884.   int w,h;
  885.  
  886.   if (i<0 || i>=SZMB_MAX) return;
  887.   if (sizeMB.dim[i]) return;
  888.  
  889.   switch (i) {
  890.   case SZMB_NORM:
  891.     if (cWIDE>maxWIDE || cHIGH>maxHIGH) {
  892.       double r,wr,hr;
  893.       wr = ((double) cWIDE) / maxWIDE;
  894.       hr = ((double) cHIGH) / maxHIGH;
  895.       
  896.       r = (wr>hr) ? wr : hr;   /* r is the max(wr,hr) */
  897.       w = (int) ((cWIDE / r) + 0.5);
  898.       h = (int) ((cHIGH / r) + 0.5);
  899.     }
  900.     else { w = cWIDE;  h = cHIGH; }
  901.     
  902.     WResize(w, h);
  903.     break;
  904.  
  905.   case SZMB_MAXPIC:   WMaximize();  break;
  906.  
  907.   case SZMB_MAXPECT: 
  908.     {
  909.       int w1,h1;
  910.       w1 = eWIDE;  h1 = eHIGH;
  911.       eWIDE = dispWIDE;  eHIGH = dispHIGH;
  912.       FixAspect(0,&w,&h);
  913.       eWIDE = w1;  eHIGH = h1;  /* play it safe */
  914.       WResize(w,h);
  915.     }
  916.     break;
  917.  
  918.   case SZMB_DOUBLE:  WResize(eWIDE*2,      eHIGH*2);       break;
  919.   case SZMB_HALF:    WResize(eWIDE/2,      eHIGH/2);       break;
  920.   case SZMB_M10:     WResize((eWIDE*9)/10, (eHIGH*9)/10);  break;
  921.  
  922.   case SZMB_P10:
  923.     w = (eWIDE*11)/10;  h = (eHIGH*11)/10;
  924.     if (w==eWIDE) w++;
  925.     if (h==eHIGH) h++;
  926.     WResize(w,h);
  927.     break;
  928.     
  929.     
  930.   case SZMB_SETSIZE:  setSizeCmd();  break;
  931.   case SZMB_ASPECT:   FixAspect(1, &w, &h);  WResize(w,h);  break;
  932.  
  933.   case SZMB_4BY3:   
  934.     w = eWIDE;  h = (w * 3) / 4;
  935.     if (h>maxHIGH) { h = eHIGH;  w = (h*4)/3; }
  936.     WResize(w,h);
  937.     break;
  938.  
  939.   case SZMB_INTEXP:  
  940.     {
  941.       /* round  (eWIDE/cWIDE),(eHIGH/cHIGH) to nearest
  942.      integer expansion/compression values */
  943.       
  944.       double w,h;
  945.       
  946.       if (eWIDE >= cWIDE) {
  947.     w = ((double) eWIDE) / cWIDE;
  948.     w = floor(w + 0.5);
  949.     if (w < 1.0) w = 1.0;
  950.       }
  951.       else {     /* eWIDE < cWIDE */
  952.     int i;  double t,d,min,pick;
  953.  
  954.     w = (double) eWIDE / (double) cWIDE;
  955.     min = 1.0;  pick=1.0;
  956.     for (i=1; i<cWIDE; i++) {
  957.       t = 1.0 / (double) i;
  958.       d = fabs(w - t);
  959.       if (d < min) { pick = t;  min = d; }
  960.       if (t < w) break;
  961.     }
  962.     w = pick;
  963.       }
  964.       
  965.       if (eHIGH >= cHIGH) {
  966.     h = ((double) eHIGH) / cHIGH;
  967.     h = floor(h + 0.5);
  968.     if (h<1.0) h = 1.0;
  969.       }
  970.       else {   /* eHIGH < cHIGH */
  971.     int i;  double t,d,min,pick;
  972.  
  973.     h = (double) eHIGH / (double) cHIGH;
  974.     min = 1.0;  pick=1.0;
  975.     for (i=1; i<cHIGH; i++) {
  976.       t = 1.0 / (double) i;
  977.       d = fabs(h - t);
  978.       if (d < min) { pick = t;  min = d; }
  979.       if (t < h) break;
  980.     }
  981.     h = pick;
  982.       }
  983.       
  984.       WResize((int) (w*cWIDE), (int) (h*cHIGH));
  985.     }
  986.     break;
  987.     
  988.   default: break;
  989.   }
  990. }
  991.  
  992.  
  993. /***********************************/
  994. void DoPrint()
  995. {
  996.   /* pops open appropriate dialog boxes, issues print command */
  997.  
  998.   int          i;
  999.   char         txt[512], str[PRINTCMDLEN + 10];
  1000.   static char *labels[] = { " Color", " Grayscale", " B/W", "\033Cancel" };
  1001.   
  1002.   strcpy(txt, "Print:  Enter a command that will read a PostScript file ");
  1003.   strcat(txt, "from stdin and print it to the desired printer.\n\n");
  1004. #ifndef VMS
  1005.   strcat(txt, "(e.g., 'lpr -Pname' on Unix systems)");
  1006. #else
  1007.   strcat(txt, "(e.g., 'Print /Queue = XV_Queue' on a VMS system)");
  1008. #endif
  1009.  
  1010.   i = GetStrPopUp(txt, labels, 4, printCmd, PRINTCMDLEN, "", 0);
  1011.   if (i == 3 || strlen(printCmd)==0) return;   /* CANCEL */
  1012.  
  1013.   if (dirUp == BLOAD) DirBox(0);
  1014.   
  1015.   SetDirSaveMode(F_FORMAT, F_PS);
  1016.   SetDirSaveMode(F_COLORS, i);
  1017.  
  1018.   if (printCmd[0] != '|' && printCmd[0] != '!') 
  1019.     sprintf(str, "| %s", printCmd);
  1020.   else strcpy(str, printCmd);
  1021.  
  1022.   DirBox(BSAVE);
  1023.   SetDirFName(str);
  1024.  
  1025.   FakeButtonPress(&dbut[S_BOK]);
  1026. }
  1027.  
  1028.  
  1029. /***********************************/
  1030. static void debugEvent(e)
  1031.      XEvent *e;
  1032. {
  1033.   switch (e->type) {
  1034.   case ButtonPress:
  1035.   case ButtonRelease:
  1036.     fprintf(stderr,"DBGEVT: %s %s %d,%d, state=%x, button=%d\n",
  1037.         (e->type == ButtonPress) ? "ButtonPress  " : "ButtonRelease",
  1038.         win2name(e->xbutton.window), e->xbutton.x, e->xbutton.y,
  1039.         e->xbutton.state, e->xbutton.button);
  1040.     break;
  1041.  
  1042.   case KeyPress:
  1043.   case KeyRelease:
  1044.     fprintf(stderr,"DBGEVT: %s %s state=%x, keycode=%d\n",
  1045.         (e->type == KeyPress) ? "KeyPress  " : "KeyRelease",
  1046.         win2name(e->xkey.window),
  1047.         e->xkey.state, e->xkey.keycode);
  1048.     break;
  1049.  
  1050.   case Expose:
  1051.     fprintf(stderr,"DBGEVT: Expose %s %d,%d %dx%d count=%d\n",
  1052.         win2name(e->xexpose.window), e->xexpose.x, e->xexpose.y,
  1053.         e->xexpose.width, e->xexpose.height, e->xexpose.count);
  1054.     break;
  1055.  
  1056.   case ClientMessage:
  1057.     fprintf(stderr,"DBGEVT: ClientMessage %s\n",win2name(e->xclient.window));
  1058.     break;
  1059.  
  1060.   case ConfigureNotify:
  1061.     fprintf(stderr,"DBGEVT: ConfigureNotify %s %d,%d %dx%d  %s\n",
  1062.         win2name(e->xconfigure.window), e->xconfigure.x, e->xconfigure.y,
  1063.         e->xconfigure.width, e->xconfigure.height,
  1064.         (e->xconfigure.send_event) ? "synthetic" : "real");
  1065.     break;
  1066.  
  1067.   case MapNotify:
  1068.     fprintf(stderr,"DBGEVT: MapNotify %s\n", win2name(e->xany.window));
  1069.     break;
  1070.  
  1071.   case ReparentNotify:
  1072.     fprintf(stderr,"DBGEVT: ReparentNotify %s\n", win2name(e->xany.window));
  1073.     break;
  1074.  
  1075.   case EnterNotify:
  1076.   case LeaveNotify:
  1077.     fprintf(stderr,"DBGEVT: %s %s\n",
  1078.         (e->type==EnterNotify) ? "EnterNotify" : "LeaveNotify",
  1079.         win2name(e->xany.window));
  1080.     break;
  1081.  
  1082.   default:
  1083.     fprintf(stderr,"DBGEVT: unknown event type (%d), window %s\n",
  1084.         e->type, win2name(e->xany.window));
  1085.     break;
  1086.   }
  1087. }
  1088.  
  1089. static char *win2name(win)
  1090.      Window win;
  1091. {
  1092.   static char foo[16];
  1093.   
  1094.   if      (win == mainW)  return "mainW";
  1095.   else if (win == rootW)  return "rootW";
  1096.   else if (win == vrootW) return "vrootW";
  1097.   else if (win == infoW)  return "infoW";
  1098.   else if (win == ctrlW)  return "ctrlW";
  1099.   else if (win == dirW)   return "dirW";
  1100.   else if (win == gamW)   return "gamW";
  1101.   else if (win == psW)    return "psW";
  1102.  
  1103.   else {
  1104.     sprintf(foo, "0x%08x", (u_int) win);
  1105.     return foo;
  1106.   }
  1107. }
  1108.  
  1109.         
  1110. /***********************************/
  1111. static void handleButtonEvent(event, donep, retvalp)
  1112.   XEvent *event;
  1113.   int    *donep, *retvalp;
  1114. {
  1115.   XButtonEvent *but_event;
  1116.   int i,x,y, done, retval, shift;
  1117.   Window win;
  1118.  
  1119.   but_event = (XButtonEvent *) event;
  1120.   done = *donep;  retval = *retvalp;
  1121.  
  1122.   win = but_event->window;
  1123.   x = but_event->x;  y = but_event->y;
  1124.   shift = but_event->state & ShiftMask;
  1125.  
  1126.   switch (event->type) {
  1127.   case ButtonPress:
  1128.     /* *always* check for pop-up events, as errors can happen... */
  1129.     if (PUCheckEvent  (event)) break;
  1130.     
  1131.     if (autoquit && win == mainW) Quit(0);
  1132.     
  1133.     if (viewonly) break;     /* ignore all other button presses */
  1134.     
  1135.     if (win == mainW && !useroot && showzoomcursor) {
  1136.       DoZoom(x, y, but_event->button);
  1137.       break;
  1138.     }
  1139.     
  1140.     if (PSCheckEvent  (event)) break;
  1141.     
  1142. #ifdef HAVE_JPEG
  1143.     if (JPEGCheckEvent(event)) break;
  1144. #endif
  1145.     
  1146. #ifdef HAVE_TIFF
  1147.     if (TIFFCheckEvent(event)) break;
  1148. #endif
  1149.     
  1150.     if (GamCheckEvent (event)) break;
  1151.     if (BrowseCheckEvent (event, &retval, &done)) break;
  1152.     if (TextCheckEvent   (event, &retval, &done)) break;
  1153.     
  1154.     switch (but_event->button) {
  1155.       
  1156.     case Button1:  
  1157.       if      (win == mainW) DoSelection(but_event);
  1158.       
  1159.       else if (win == ctrlW) {
  1160.     int   w,h;
  1161.     
  1162.     if      (MBClick(&dispMB,   x,y)) SelectDispMB  (MBTrack(&dispMB)  );
  1163.     else if (MBClick(&conv24MB, x,y)) Select24to8MB (MBTrack(&conv24MB));
  1164.     else if (MBClick(&rootMB,   x,y)) SelectRootMB  (MBTrack(&rootMB)  );
  1165.     else if (MBClick(&windowMB, x,y)) SelectWindowMB(MBTrack(&windowMB));
  1166.     else if (MBClick(&sizeMB,   x,y)) SelectSizeMB  (MBTrack(&sizeMB)  );
  1167.     else if (MBClick(&algMB, x,y)) {
  1168.       algMB.dim[ALG_BLEND] = !HaveSelection();
  1169.       i = MBTrack(&algMB);
  1170.       if (i>=0) DoAlg(i);
  1171.       break;
  1172.     }
  1173.     
  1174.     i=ClickCtrl(x,y);
  1175.     
  1176.     switch (i) {
  1177.     case BNEXT:   retval= NEXTPIC;  done=1;     break;
  1178.     case BPREV:   retval= PREVPIC;  done=1;     break;
  1179.     case BLOAD:   DirBox(BLOAD);                break;
  1180.     case BSAVE:   DirBox(BSAVE);                break;
  1181.     case BDELETE: if (DeleteCmd()) { done = 1;  retval = DELETE; }  break;
  1182.     case BPRINT:  DoPrint();                    break;
  1183.  
  1184.     case BCOPY:   DoImgCopy();                  break;
  1185.     case BCUT:    DoImgCut();                   break;
  1186.     case BPASTE:  DoImgPaste();                 break;
  1187.     case BCLEAR:  DoImgClear();                 break;
  1188.     case BGRAB:   if (Grab()) {done=1; retval = GRABBED;}  break;
  1189.     case BUP10:   SelectSizeMB(SZMB_P10);       break;
  1190.     case BDN10:   SelectSizeMB(SZMB_M10);       break;
  1191.     case BROTL:   Rotate(1);                    break;
  1192.     case BROTR:   Rotate(0);                    break;
  1193.     case BFLIPH:  Flip(0);                      break;
  1194.     case BFLIPV:  Flip(1);                      break;
  1195.       
  1196.     case BCROP:   Crop();                       break;
  1197.     case BUNCROP: UnCrop();                     break;
  1198.     case BACROP:  AutoCrop();                   break;
  1199.       
  1200.     case BPAD:
  1201.       {
  1202.         int mode, wide, high, opaque, omode;  char *str;
  1203.         
  1204.         while (PadPopUp(&mode, &str, &wide, &high, &opaque, &omode)==0) {
  1205.           if (DoPad(mode, str, wide, high, opaque, omode)) { 
  1206.         done = 1;  retval = PADDED;  break;
  1207.           }
  1208.         }     
  1209.       }  
  1210.       break;
  1211.  
  1212.     case BANNOT:  annotatePic();                break;
  1213.  
  1214.     case BABOUT:  SelectWindowMB(WMB_ABOUTXV);  break;
  1215.     case BXV:     retval = DFLTPIC;  done=1;    break;
  1216.     case BQUIT:   retval = QUIT;     done=1;    break;
  1217.       
  1218.     default:      break;
  1219.     }
  1220.     
  1221.     if (i==BFLIPH || i==BFLIPV) {
  1222.       DrawEpic();
  1223.       SetCursors(-1);
  1224.     }
  1225.       }
  1226.       
  1227.       else if (win == nList.win) {
  1228.     i=LSClick(&nList,but_event);
  1229.     if (curname<0) ActivePrevNext();
  1230.     if (i>=0) { done = 1;  retval = i; }
  1231.       }
  1232.       
  1233.       else if (win == nList.scrl.win) SCTrack(&nList.scrl, x, y);
  1234.       
  1235.       else if (win == dirW) {
  1236.     i=ClickDirW(x,y);
  1237.     
  1238.     switch (i) {
  1239.     case S_BOK:   if (dirUp == BLOAD) {
  1240.       if (!DirCheckCD()) {
  1241.         retval = LOADPIC;
  1242.         done=1;
  1243.       }
  1244.     }
  1245.     else if (dirUp == BSAVE) {
  1246.       DoSave();
  1247.     }
  1248.       break;
  1249.       
  1250.     case S_BCANC: DirBox(0);  break;
  1251.       
  1252.     case S_BRESCAN:
  1253.       WaitCursor();  LoadCurrentDirectory();  SetCursors(-1);
  1254.       break;
  1255.     }
  1256.       }
  1257.       
  1258.       else if (win == dList.win) {
  1259.     i=LSClick(&dList,but_event);
  1260.     SelectDir(i);
  1261.       }
  1262.       
  1263.       else if (win == dList.scrl.win) SCTrack(&dList.scrl, x,y);
  1264.       else if (win == infoW)          InfoBox(0);  /* close info */
  1265.       
  1266.       break;
  1267.       
  1268.       
  1269.     case Button2:  
  1270.       if (win == mainW && !useroot) {
  1271.     if (!shift && !DoSelection(but_event)) TrackPicValues(x,y);
  1272.     else if (shift) Paint();
  1273.       }
  1274.       break;
  1275.       
  1276.     case Button3:  /* if using root, MUST NOT get rid of ctrlbox. */
  1277.       if (!shift && !useroot) CtrlBox(!ctrlUp); 
  1278.       else if (shift) BlurPaint();
  1279.       break;
  1280.       
  1281.     default:       break;
  1282.     }
  1283.   }
  1284.   
  1285.   *donep = done;  *retvalp = retval;
  1286. }
  1287.  
  1288.     
  1289. /***********************************/
  1290. static void handleKeyEvent(event, donep, retvalp)
  1291.   XEvent *event;
  1292.   int    *donep, *retvalp;
  1293. {
  1294.   /* handles KeyPress and KeyRelease events, called from HandleEvent */
  1295.   
  1296.   XKeyEvent *key_event;
  1297.   KeySym     ks;
  1298.   char       buf[128];
  1299.   int        stlen, dealt, done, retval, shift, ctrl, meta, ck;
  1300.   u_int      svkeystate;
  1301.  
  1302.   key_event = (XKeyEvent *) event;
  1303.   done      = *donep;
  1304.   retval    = *retvalp;
  1305.  
  1306.   switch (event->type) {
  1307.   case KeyRelease:
  1308.     if (viewonly) break;     /* ignore all user input */
  1309.     
  1310.     stlen = XLookupString(key_event,buf,128,&ks,(XComposeStatus *) NULL);
  1311.     dealt = 0;
  1312.     
  1313.     if (key_event->window == mainW) {
  1314.       u_int foo = key_event->state;
  1315.  
  1316.       if (ks == XK_Shift_L   || ks == XK_Shift_R)   
  1317.     foo = foo & (u_int) (~ShiftMask);
  1318.       if (ks == XK_Control_L || ks == XK_Control_R) 
  1319.     foo = foo & (u_int) (~ControlMask);
  1320.       if (ks == XK_Meta_L    || ks == XK_Meta_R)    
  1321.     foo = foo & (u_int) (~Mod1Mask);
  1322.       if (ks == XK_Alt_L     || ks == XK_Alt_R)     
  1323.     foo = foo & (u_int) (~Mod1Mask);
  1324.  
  1325.       zoomCurs(foo);
  1326.     }
  1327.     break;
  1328.     
  1329.  
  1330.   case KeyPress:
  1331.     svkeystate = key_event->state;
  1332.     key_event->state &= ~Mod1Mask;      /* remove meta from translation */
  1333.     stlen = XLookupString(key_event,buf,128,&ks,(XComposeStatus *) NULL);
  1334.     key_event->state = svkeystate;
  1335.  
  1336.     shift = key_event->state & ShiftMask;
  1337.     ctrl  = key_event->state & ControlMask;
  1338.     meta  = key_event->state & Mod1Mask;
  1339.     dealt = 0;
  1340.  
  1341.     RemapKeyCheck(ks, buf, &stlen);
  1342.  
  1343.     if (PUCheckEvent  (event)) break;          /* always check popups */
  1344.  
  1345.     if (autoquit && key_event->window == mainW) Quit(0);
  1346.     
  1347.     if (viewonly && !frominterrupt) break;     /* ignore all user input */
  1348.     
  1349.     if (PSCheckEvent  (event)) break;
  1350.     
  1351.     if (key_event->window == mainW) {
  1352.       u_int foo = key_event->state;
  1353.  
  1354.       if (ks == XK_Shift_L   || ks == XK_Shift_R)   foo = foo | ShiftMask;
  1355.       if (ks == XK_Control_L || ks == XK_Control_R) foo = foo | ControlMask;
  1356.       if (ks == XK_Meta_L    || ks == XK_Meta_R)    foo = foo | Mod1Mask;
  1357.       if (ks == XK_Alt_L     || ks == XK_Alt_R)     foo = foo | Mod1Mask;
  1358.       zoomCurs(foo);
  1359.     }
  1360.  
  1361. #ifdef HAVE_JPEG
  1362.     if (JPEGCheckEvent(event)) break;
  1363. #endif
  1364.  
  1365. #ifdef HAVE_TIFF
  1366.     if (TIFFCheckEvent(event)) break;
  1367. #endif
  1368.  
  1369.     if (GamCheckEvent (event)) break;
  1370.     if (BrowseCheckEvent (event, &retval, &done)) break;
  1371.     if (TextCheckEvent   (event, &retval, &done)) break;
  1372.  
  1373.  
  1374.     /* check for pageup/pagedown, 'p' in main window 
  1375.        (you can use shift-up or shift-down if no crop rectangle drawn)
  1376.        (for viewing multipage docs) */
  1377.  
  1378.     if (key_event->window == mainW) {
  1379.       dealt = 1;
  1380.  
  1381.       ck = CursorKey(ks, shift, 0);
  1382.       if (ck==CK_PAGEUP || (ck==CK_UP && shift && !but[BCROP].active)) {
  1383.     if (strlen(pageBaseName) && numPages>1) {
  1384.       done = 1;  retval = OP_PAGEUP;
  1385.     }
  1386.     else XBell(theDisp,0);
  1387.       }
  1388.  
  1389.       else if (ck==CK_PAGEDOWN || 
  1390.            (ck==CK_DOWN && shift && !but[BCROP].active)) {
  1391.     if (strlen(pageBaseName) && numPages>1) {
  1392.       done = 1;  retval = OP_PAGEDN;
  1393.     }
  1394.     else XBell(theDisp,0);
  1395.       }
  1396.  
  1397.       else if (buf[0] == 'p' && stlen>0) {
  1398.     if (strlen(pageBaseName) && numPages>1) {
  1399.       int  i,j, okay;
  1400.       char buf[64], txt[512];
  1401.       static char *labels[] = { "\nOk", "\033Cancel" };
  1402.  
  1403.       /* ask what page to go to */
  1404.       sprintf(txt, "Go to page number...   (1-%d)", numPages);
  1405.       sprintf(buf, "%d", curPage + 1);
  1406.  
  1407.       okay = 0;
  1408.       do {
  1409.         i = GetStrPopUp(txt, labels, 2, buf, 64, "0123456789", 1);
  1410.         if (!i && strlen(buf) > (size_t) 0) {
  1411.           /* hit 'Ok', had a string entered */
  1412.           /* check for page in range */
  1413.           j = atoi(buf);
  1414.           if (j>=1 && j<=numPages) {
  1415.         curPage = j;   /* one page past desired page */
  1416.         done = 1;
  1417.         retval = OP_PAGEUP;
  1418.         okay=1;
  1419.           }
  1420.           else XBell(theDisp, 0);
  1421.         }
  1422.         else okay = 1;
  1423.       } while (!okay);
  1424.     }
  1425.     else XBell(theDisp, 0);
  1426.       }
  1427.  
  1428.       else dealt = 0;
  1429.  
  1430.       if (dealt) break;
  1431.     }
  1432.     
  1433.  
  1434.  
  1435.     /* check for crop rect keys */
  1436.     if (key_event->window == mainW) {
  1437.       dealt = 1;
  1438.       ck = CursorKey(ks, shift, 0);
  1439.       if      (ck==CK_LEFT)  CropKey(-1, 0,shift,ctrl);
  1440.       else if (ck==CK_RIGHT) CropKey( 1, 0,shift,ctrl);
  1441.       else if (ck==CK_UP)    CropKey( 0,-1,shift,ctrl);
  1442.       else if (ck==CK_DOWN)  CropKey( 0, 1,shift,ctrl);
  1443.       else dealt = 0;
  1444.       if (dealt) break;
  1445.     }
  1446.  
  1447.  
  1448.     /* check for List keys */
  1449.     if (key_event->window == ctrlW || key_event->window == dirW) {
  1450.       LIST *theList;
  1451.  
  1452.       ck = CursorKey(ks, shift, 1);
  1453.       if (key_event->window == dirW) theList = &dList;
  1454.       else theList = &nList;
  1455.  
  1456.       dealt = 1;
  1457.  
  1458.       if      (ck==CK_PAGEUP)   LSKey(theList,LS_PAGEUP);
  1459.       else if (ck==CK_PAGEDOWN) LSKey(theList,LS_PAGEDOWN);
  1460.       else if (ck==CK_UP)       LSKey(theList,LS_LINEUP);
  1461.       else if (ck==CK_DOWN)     LSKey(theList,LS_LINEDOWN);
  1462.       else if (ck==CK_HOME)     LSKey(theList,LS_HOME);
  1463.       else if (ck==CK_END)      LSKey(theList,LS_END);
  1464.       else dealt = 0;
  1465.  
  1466.       if (theList == &nList && dealt && curname<0) ActivePrevNext();
  1467.  
  1468.       if (theList == &dList && dealt) {  /* changed dir selection */
  1469.     SelectDir(-1);  /* nothing was double-clicked */
  1470.       }
  1471.       
  1472.       if (dealt) break;
  1473.     }
  1474.  
  1475.  
  1476.     /* check dir filename arrows */
  1477.     ck = CursorKey(ks, shift, 1);
  1478.     if (key_event->window == dirW && ck==CK_LEFT)  { DirKey('\002'); break; }
  1479.     if (key_event->window == dirW && ck==CK_RIGHT) { DirKey('\006'); break; }
  1480.  
  1481.  
  1482.     /* check for preset keys     (meta-1, meta-2, meta-3, meta-4, meta-0)
  1483.      * and cut/copy/paste/clear  (meta-x, meta-c, meta-v, meta-d)
  1484.      * and 8/24 bit toggle       (meta-8)
  1485.      * and some algorithms       (meta-b, meta-t, meta-p, meta-l, etc.)
  1486.      */
  1487.  
  1488.     if (meta) {  /* meta is down */
  1489.       dealt = 1;
  1490.       if      (ks==XK_1) FakeButtonPress(&gbut[G_B1]);
  1491.       else if (ks==XK_2) FakeButtonPress(&gbut[G_B2]);
  1492.       else if (ks==XK_3) FakeButtonPress(&gbut[G_B3]);
  1493.       else if (ks==XK_4) FakeButtonPress(&gbut[G_B4]);
  1494.       else if (ks==XK_r || ks==XK_0) 
  1495.                      FakeButtonPress(&gbut[G_BRESET]);
  1496.  
  1497.       else if (ks==XK_x) FakeButtonPress(&but[BCUT]);
  1498.       else if (ks==XK_c) FakeButtonPress(&but[BCOPY]);
  1499.       else if (ks==XK_v) FakeButtonPress(&but[BPASTE]);
  1500.       else if (ks==XK_d) FakeButtonPress(&but[BCLEAR]);
  1501.  
  1502.       else if (ks==XK_u) DoAlg(ALG_NONE);
  1503.       else if (ks==XK_b) DoAlg(ALG_BLUR);
  1504.       else if (ks==XK_s) DoAlg(ALG_SHARPEN);
  1505.       else if (ks==XK_e) DoAlg(ALG_EDGE);
  1506.       else if (ks==XK_m) DoAlg(ALG_TINF);
  1507.       else if (ks==XK_o) DoAlg(ALG_OIL);
  1508.       else if (ks==XK_k) DoAlg(ALG_MEDIAN);
  1509.  
  1510.       else if ((ks==XK_B  || (ks==XK_b && shift)) && HaveSelection())
  1511.                                             DoAlg(ALG_BLEND);
  1512.  
  1513.       else if (ks==XK_p)                        DoAlg(ALG_PIXEL);
  1514.  
  1515.       else if (ks==XK_S || (ks==XK_s && shift)) DoAlg(ALG_SPREAD);
  1516.  
  1517.       else if (ks==XK_t || ks==XK_T) {
  1518.     if (ctrl || shift || ks==XK_T)          DoAlg(ALG_ROTATE);
  1519.         else                                    DoAlg(ALG_ROTATECLR);
  1520.       }
  1521.  
  1522.       else if (ks==XK_a) FakeButtonPress(&gbut[G_BAPPLY]);
  1523.  
  1524.       else if (ks==XK_8) { 
  1525.     if (picType==PIC8) Select24to8MB(CONV24_24BIT);
  1526.                   else Select24to8MB(CONV24_8BIT);
  1527.       }
  1528.  
  1529.       else dealt = 0;
  1530.  
  1531.       if (dealt) break;
  1532.     }
  1533.     
  1534.     if (!stlen) break;
  1535.     
  1536.     if (key_event->window == dirW) {
  1537.       if (DirKey(buf[0])) XBell(theDisp,0);
  1538.     }
  1539.     else {                               /* commands valid in any window */
  1540.       switch (buf[0]) {
  1541.     
  1542.     /* things in dispMB */
  1543.       case 'r':    SelectDispMB(DMB_RAW);           break;
  1544.       case 'd':    SelectDispMB(DMB_DITH);          break;
  1545.       case 's':    SelectDispMB(DMB_SMOOTH);        break;
  1546.     
  1547.     /* things in sizeMB */
  1548.       case 'n':    SelectSizeMB(SZMB_NORM);         break;
  1549.       case 'm':    SelectSizeMB(SZMB_MAXPIC);       break;
  1550.       case 'M':    SelectSizeMB(SZMB_MAXPECT);      break;
  1551.       case '>':    SelectSizeMB(SZMB_DOUBLE);       break;
  1552.       case '<':    SelectSizeMB(SZMB_HALF);         break;
  1553.       case '.':    SelectSizeMB(SZMB_P10);          break;
  1554.       case ',':    SelectSizeMB(SZMB_M10);          break;
  1555.       case 'S':    SelectSizeMB(SZMB_SETSIZE);      break;
  1556.       case 'a':    SelectSizeMB(SZMB_ASPECT);       break;
  1557.       case '4':    SelectSizeMB(SZMB_4BY3);         break;
  1558.       case 'I':    SelectSizeMB(SZMB_INTEXP);       break;
  1559.     
  1560.     /* things in windowMB */
  1561.       case '\026':
  1562.       case 'V':    SelectWindowMB(WMB_BROWSE);      break;  /* ^V or V */
  1563.       case 'e':    SelectWindowMB(WMB_COLEDIT);     break;  /*  e */
  1564.       case 'i':    SelectWindowMB(WMB_INFO);        break;  /*  i */
  1565.       case '\003': SelectWindowMB(WMB_COMMENT);     break;  /* ^C */
  1566.       case '\024': SelectWindowMB(WMB_TEXTVIEW);    break;  /* ^T */
  1567.       case '\001': SelectWindowMB(WMB_ABOUTXV);     break;  /* ^A */
  1568.     
  1569.     
  1570.     
  1571.     /* buttons in ctrlW */
  1572.       case '\t':
  1573.       case ' ':    FakeButtonPress(&but[BNEXT]);    break;
  1574.     
  1575.       case '\r':
  1576.       case '\n':
  1577.     if (nList.selected >= 0 && nList.selected < nList.nstr) {
  1578.       done = 1;  retval = nList.selected; 
  1579.       if (frominterrupt) retval = RELOAD;
  1580.     }
  1581.     break;
  1582.     
  1583.       case '\010':
  1584.       case '\177': FakeButtonPress(&but[BPREV]);    break;
  1585.     
  1586.     
  1587.       case '\014': FakeButtonPress(&but[BLOAD]);    break;  /* ^L */
  1588.       case '\023': FakeButtonPress(&but[BSAVE]);    break;  /* ^S */
  1589.       case '\020': FakeButtonPress(&but[BPRINT]);   break;  /* ^P */
  1590.       case '\004': FakeButtonPress(&but[BDELETE]);  break;  /* ^D */
  1591.     
  1592.     /* BCOPY, BCUT, BPASTE, BCLEAR handled in 'meta' case */
  1593.     
  1594.       case '\007': FakeButtonPress(&but[BGRAB]);    break;  /* ^G */
  1595.     
  1596.     /* BUP10, BDN10 handled in sizeMB case */
  1597.     
  1598.       case 'T':    FakeButtonPress(&but[BROTL]);    break;
  1599.       case 't':    FakeButtonPress(&but[BROTR]);    break;
  1600.       case 'h':    FakeButtonPress(&but[BFLIPH]);   break;
  1601.       case 'v':    FakeButtonPress(&but[BFLIPV]);   break;
  1602.       case 'c':    FakeButtonPress(&but[BCROP]);    break;
  1603.       case 'u':    FakeButtonPress(&but[BUNCROP]);  break;
  1604.       case 'C':    FakeButtonPress(&but[BACROP]);   break;
  1605.       case 'P':    FakeButtonPress(&but[BPAD]);     break;
  1606.       case 'A':    FakeButtonPress(&but[BANNOT]);   break;
  1607.     
  1608.     /* BABOUT handled in windowMB case */
  1609.     
  1610.       case '\021': /* ^Q */
  1611.       case 'q':    FakeButtonPress(&but[BQUIT]);    break;
  1612.     
  1613.       case '?':    if (!useroot) CtrlBox(!ctrlUp);  break;
  1614.     
  1615.     /* things in color editor */
  1616.       case 'R':    FakeButtonPress(&gbut[G_BRESET]);   break;
  1617.       case 'H':    FakeButtonPress(&gbut[G_BHISTEQ]);  break;
  1618.       case 'N':    FakeButtonPress(&gbut[G_BMAXCONT]); break;
  1619.     
  1620.       default:     break;
  1621.       }
  1622.     }
  1623.   }
  1624.   
  1625.   *donep = done;  *retvalp = retval;
  1626. }
  1627.  
  1628.  
  1629. /***********************************/
  1630. static void zoomCurs(mask)
  1631.      u_int mask;
  1632. {
  1633.   int zc;
  1634.   zc = ((mask & ControlMask) && !(mask & ShiftMask) && !(mask & Mod1Mask));
  1635.  
  1636.   if (zc != showzoomcursor) {
  1637.     showzoomcursor = zc;
  1638.     SetCursors(-1);
  1639.   }
  1640. }
  1641.  
  1642.  
  1643. /***********************************/
  1644. static void textViewCmd()
  1645. {
  1646.   int   i;
  1647.   char *name;
  1648.  
  1649.   i = nList.selected;
  1650.   if (i<0 || i>=numnames) return;     /* shouldn't happen */
  1651.  
  1652.   if (namelist[i][0] != '/') {  /* prepend 'initdir' */
  1653.     name = (char *) malloc(strlen(namelist[i]) + strlen(initdir) + 2);
  1654.     if (!name) FatalError("malloc in textViewCmd failed");
  1655.     sprintf(name,"%s/%s", initdir, namelist[i]);
  1656.   }
  1657.   else name = namelist[i];
  1658.  
  1659.   TextView(name);
  1660.   
  1661.   if (name != namelist[i]) free(name);
  1662. }
  1663.  
  1664.  
  1665. /***********************************/
  1666. static void setSizeCmd()
  1667. {
  1668.   /* open 'set size' prompt window, get a string, parse it, and try to
  1669.      set the window size accordingly */
  1670.  
  1671.   int   i, arg1, arg2, numargs, pct1, pct2, state, neww, newh;
  1672.   char  txt[512], buf[64], *sp, ch;
  1673.   static char *labels[] = { "\nOk", "\033Cancel" };
  1674.   
  1675.   sprintf(txt, "Enter new image display size (ex. '400 x 300'),\n");
  1676.   strcat (txt, "expansion ratio (ex. '75%'),\n");
  1677.   strcat (txt, "or expansion ratios (ex. '200% x 125%'):");
  1678.  
  1679.   sprintf(buf, "%d x %d", eWIDE, eHIGH);    /* current vals */
  1680.  
  1681.   i = GetStrPopUp(txt, labels, 2, buf, 64, "0123456789x% ", 1);
  1682.  
  1683.   if (i) return;     /* cancelled */
  1684.   if (strlen(buf) == 0) return;     /* no command */
  1685.  
  1686.  
  1687.   /* attempt to parse the string accordingly...
  1688.    * parses strings of the type: <num> [%] [ x <num> [%] ] 
  1689.    * (-ish.  <num> all by itself isn't legal)
  1690.    * there may be any # of spaces between items, including zero
  1691.    */
  1692.  
  1693.   arg1 = arg2 = numargs = pct1 = pct2 = state = 0;
  1694.   sp = buf;
  1695.  
  1696.   do  {
  1697.     ch = *sp++;
  1698.  
  1699.     switch (state) {
  1700.     case 0:             /* haven't seen arg1 yet */
  1701.       if      (ch == ' ') {}
  1702.       else if (ch == '%' || ch == 'x' || ch == '\0') state = 99;  /* no arg1 */
  1703.       else { arg1  = (ch - '0');  state = 1; }
  1704.       break;
  1705.  
  1706.     case 1:             /* parsing arg1 */
  1707.       numargs = 1;
  1708.       if      (ch == ' ')  state = 2;
  1709.       else if (ch == '%')  state = 3;
  1710.       else if (ch == 'x')  state = 4;
  1711.       else if (ch == '\0') state = 99;
  1712.       else arg1 = (arg1 * 10) + (ch - '0');
  1713.       break;
  1714.  
  1715.     case 2:             /* got arg1 and whitespace */
  1716.       if      (ch == ' ') {}
  1717.       else if (ch == '%') state = 3;
  1718.       else if (ch == 'x') state = 4;
  1719.       else state = 99;
  1720.       break;
  1721.  
  1722.     case 3:             /* got arg1 % */
  1723.       pct1 = 1;
  1724.       if      (ch == ' ')  {}
  1725.       else if (ch == '%')  state = 99;
  1726.       else if (ch == 'x')  state = 4;
  1727.       else if (ch == '\0') state = 100;
  1728.       else state = 99;
  1729.       break;
  1730.  
  1731.     case 4:             /* got arg1 [%] x */
  1732.       if      (ch == ' ') {}
  1733.       else if (ch == '%' || ch == 'x' || ch == '\0') state = 99;
  1734.       else { arg2 = (ch - '0');  state = 5; }
  1735.       break;
  1736.  
  1737.     case 5:             /* parsing arg2 */
  1738.       numargs = 2;
  1739.       if      (ch == ' ')  state = 6;
  1740.       else if (ch == '%')  state = 7;
  1741.       else if (ch == 'x')  state = 99;
  1742.       else if (ch == '\0') state = 100;
  1743.       else arg2 = (arg2 * 10) + (ch - '0');
  1744.       break;
  1745.  
  1746.     case 6:             /* got arg2 and whitespace */
  1747.       if      (ch == ' ')  {}
  1748.       else if (ch == '%')  state = 7;
  1749.       else if (ch == 'x')  state = 99;
  1750.       else if (ch == '\0') state = 100;
  1751.       else state = 99;
  1752.       break;
  1753.  
  1754.     case 7:             /* got arg1 [%] x arg2 % */
  1755.       pct2  = 1;
  1756.       state = 100;
  1757.       break;
  1758.  
  1759.     case 99:            /* error in parsing */
  1760.       break;
  1761.  
  1762.     case 100:           /* successful parse */
  1763.       break;
  1764.     }
  1765.   } while (state!=99 && state!=100);
  1766.  
  1767.   /* done parsing... */
  1768.   if (state == 99) {
  1769.     ErrPopUp("Error:  The entered SetSize string is not valid.", "\nRight.");
  1770.     return;
  1771.   }
  1772.  
  1773.   if (DEBUG)
  1774.     fprintf(stderr,"setSize:  arg1=%d, arg2=%d, numargs=%d, pct=%d,%d\n",
  1775.         arg1, arg2, numargs, pct1, pct2);
  1776.  
  1777.   /* otherwise... */
  1778.   if (numargs == 1) {
  1779.     if (pct1) {
  1780.       neww = (cWIDE * arg1) / 100;
  1781.       newh = (cHIGH * arg1) / 100;
  1782.     }
  1783.     else return;    /* shouldn't happen */
  1784.   }
  1785.   else {   /* numargs = 2; */
  1786.     neww = (pct1) ? (cWIDE * arg1) / 100 : arg1;
  1787.     newh = (pct2) ? (cHIGH * arg2) / 100 : arg2;
  1788.   }
  1789.  
  1790.   if (neww < 1 || newh < 1 || neww > 64000 || newh > 64000) {
  1791.     sprintf(txt, "The new desired image display size of '%d x %d' is %s",
  1792.         neww, newh, "ludicrous.  Ignored.");
  1793.     ErrPopUp(txt, "\nSez you!");
  1794.     return;
  1795.   }
  1796.  
  1797.   WResize(neww, newh);
  1798. }
  1799.  
  1800.  
  1801. /***********************************/
  1802. void NewCutBuffer(str)
  1803.      char *str;
  1804. {
  1805.   /* called whenever contents of CUT_BUFFER0 and PRIMARY selection should
  1806.      be changed.  Only works for strings.  Copies the data, so the string
  1807.      doesn't have to be static. */
  1808.  
  1809.   if (!str) return;
  1810.  
  1811.   XStoreBytes(theDisp, str, (int) strlen(str));   /* CUT_BUFFER0 */
  1812.   XSetSelectionOwner(theDisp, XA_PRIMARY, ctrlW, lastEventTime);
  1813.  
  1814.   if (xevPriSel) free(xevPriSel);
  1815.   xevPriSel = (char *) malloc(strlen(str) + 1);
  1816.   if (xevPriSel) strcpy(xevPriSel, str);
  1817. }
  1818.  
  1819. /***********************************/
  1820. void DrawWindow(x,y,w,h)
  1821.      int x,y,w,h;
  1822. {
  1823.   if (x+w < eWIDE) w++;  /* add one for broken servers (?) */
  1824.   if (y+h < eHIGH) h++;
  1825.  
  1826.   if (theImage)
  1827.     XPutImage(theDisp,mainW,theGC,theImage,x,y,x,y, (u_int) w, (u_int) h);
  1828.   else 
  1829.     if (DEBUG) fprintf(stderr,"Tried to DrawWindow when theImage was NULL\n");
  1830. }
  1831.  
  1832.  
  1833. /***********************************/
  1834. void WResize(w,h)
  1835.      int w,h;
  1836. {
  1837.   XWindowAttributes xwa;
  1838.  
  1839.   RANGE(w,1,maxWIDE);  RANGE(h,1,maxHIGH);
  1840.  
  1841.   if (useroot) {
  1842.     Resize(w,h);
  1843.     MakeRootPic();
  1844.     SetCursors(-1);
  1845.     return;
  1846.   }
  1847.  
  1848.   /* determine if new size goes off edge of screen.  if so move window so it
  1849.      doesn't go off screen */
  1850.  
  1851.   GetWindowPos(&xwa);
  1852.   if (xwa.x + w > vrWIDE) xwa.x = vrWIDE - w;
  1853.   if (xwa.y + h > vrHIGH) xwa.y = vrHIGH - h;
  1854.  
  1855.   if (DEBUG) fprintf(stderr,"%s: resizing window to %d,%d at %d,%d\n",
  1856.              cmd,w,h,xwa.x,xwa.y);
  1857.  
  1858.   /* resize the window */
  1859.   xwa.width = w;  xwa.height = h;
  1860.  
  1861.   SetWindowPos(&xwa);
  1862. }
  1863.  
  1864.  
  1865.  
  1866.  
  1867. /***********************************/
  1868. static void WMaximize()
  1869. {
  1870.   if (useroot) WResize((int) dispWIDE, (int) dispHIGH);
  1871.   else {
  1872.     XWindowAttributes xwa;
  1873.     xvbzero((char *) &xwa, sizeof(XWindowAttributes));
  1874.     xwa.x = xwa.y = 0;
  1875.     xwa.width  = dispWIDE;  
  1876.     xwa.height = dispHIGH;
  1877.     SetWindowPos(&xwa);
  1878.   }
  1879. }
  1880.  
  1881.  
  1882.  
  1883.  
  1884. /***********************************/
  1885. void WRotate()
  1886. {
  1887.   /* rotate the window and redraw the contents  */
  1888.  
  1889.   if (but[BCROP].active) BTSetActive(&but[BCROP],0);
  1890.  
  1891.   if (useroot || eWIDE == eHIGH) {
  1892.     /* won't see any configure events.  Manually redraw image */
  1893.     DrawEpic();
  1894.     SetCursors(-1);
  1895.     return;
  1896.   }
  1897.   else {
  1898.     rotatesLeft++;
  1899.     XClearWindow(theDisp, mainW);  /* get rid of old bits */
  1900.     GenExpose(mainW, 0, 0, (u_int) eWIDE, (u_int) eHIGH);
  1901.     { int ew, eh; 
  1902.       ew = eWIDE;  eh = eHIGH;
  1903.       WResize(eWIDE, eHIGH);
  1904.       if (ew>maxWIDE || eh>maxHIGH) {   /* rotated pic too big, scale down */
  1905.     double r,wr,hr;
  1906.     wr = ((double) ew) / maxWIDE;
  1907.     hr = ((double) eh) / maxHIGH;
  1908.     
  1909.     r = (wr>hr) ? wr : hr;   /* r is the max(wr,hr) */
  1910.     ew = (int) ((ew / r) + 0.5);
  1911.     eh = (int) ((eh / r) + 0.5);
  1912.     WResize(ew,eh);
  1913.       }
  1914.     }
  1915.   }
  1916. }
  1917.  
  1918.  
  1919. /***********************************/
  1920. void WCrop(w,h,dx,dy)
  1921.      int w,h,dx,dy;
  1922. {
  1923.   int cx, cy, cw, ch, ex, ey;
  1924.   XWindowAttributes xwa;
  1925.  
  1926.   if (useroot) {
  1927.     MakeRootPic();
  1928.     SetCursors(-1);
  1929.   }
  1930.  
  1931.   else {
  1932.     /* we want to move window to old x,y + dx,dy (in pic coords) */
  1933.     GetWindowPos(&xwa);
  1934.   
  1935.     if (!origcropvalid) {  /* first crop.  remember win pos */
  1936.       origcropvalid = 1;
  1937.       origcropx = xwa.x;
  1938.       origcropy = xwa.y;
  1939.     }
  1940.  
  1941.     CoordC2E(dx, dy, &ex, &ey);
  1942.     
  1943.     xwa.x += ex;  xwa.y += ey;
  1944.     xwa.width = w;  xwa.height = h;
  1945.     GenExpose(mainW, 0, 0, (u_int) eWIDE, (u_int) eHIGH);
  1946.     SetWindowPos(&xwa);
  1947.   }
  1948. }
  1949.  
  1950.  
  1951. /***********************************/
  1952. void WUnCrop()
  1953. {
  1954.   int w,h;
  1955.   XWindowAttributes xwa;
  1956.  
  1957.   /* a proper epic has been generated.  eWIDE,eHIGH are the new window size */
  1958.  
  1959.  
  1960.   if (useroot) {
  1961.     MakeRootPic();
  1962.     SetCursors(-1);
  1963.   }
  1964.  
  1965.   else {   /* !useroot */
  1966.     GetWindowPos(&xwa);
  1967.  
  1968.     w = eWIDE;  h = eHIGH;
  1969.  
  1970.     /* restore to position when originally cropped */
  1971.     if (origcropvalid) {  /* *should* always be true... */
  1972.       origcropvalid = 0;
  1973.       xwa.x = origcropx;
  1974.       xwa.y = origcropy;
  1975.     }
  1976.  
  1977.     if (xwa.x + w > vrWIDE) xwa.x = vrWIDE - w;   /* keep on screen */
  1978.     if (xwa.y + h > vrHIGH) xwa.y = vrHIGH - h;
  1979.  
  1980.     if (xwa.x<0) xwa.x = 0;
  1981.     if (xwa.y<0) xwa.y = 0;
  1982.     xwa.width = w;  xwa.height = h;
  1983.     
  1984.     if (!useroot) {
  1985.       SetWindowPos(&xwa);
  1986.       GenExpose(mainW, 0, 0, (u_int) eWIDE, (u_int) eHIGH);
  1987.     }
  1988.   }
  1989. }
  1990.  
  1991.  
  1992.  
  1993. /***********************************/
  1994. void GetWindowPos(xwa)
  1995. XWindowAttributes *xwa;
  1996. {
  1997.   Window child;
  1998.   
  1999.   /* returns the x,y,w,h coords of mainW.  x,y are relative to rootW 
  2000.      the border is not included (x,y map to top-left pixel in window) */
  2001.  
  2002.   /* Get the window width/height */
  2003.   XGetWindowAttributes(theDisp,mainW,xwa);
  2004.  
  2005.   /* Get the window origin */
  2006.   XTranslateCoordinates(theDisp,mainW,rootW,0,0,&xwa->x,&xwa->y,&child);
  2007. }
  2008.  
  2009.  
  2010. /***********************************/
  2011. void SetWindowPos(xwa)
  2012. XWindowAttributes *xwa;
  2013. {
  2014.   /* sets window x,y,w,h values */
  2015.   XWindowChanges    xwc;
  2016.  
  2017.   /* Adjust from window origin, to border origin */
  2018.   xwc.x = xwa->x - xwa->border_width - ch_offx;
  2019.   xwc.y = xwa->y - xwa->border_width - ch_offy;
  2020.  
  2021.   if (!xwa->border_width) xwa->border_width = bwidth;
  2022.   xwc.border_width = xwa->border_width;
  2023.  
  2024.   /* if we're less than max size in one axis, allow window manager doohickeys
  2025.      on the screen */
  2026.   
  2027.   if (xwa->width  < dispWIDE && xwc.x < p_offx) xwc.x = p_offx;
  2028.   if (xwa->height < dispHIGH && xwc.y < p_offy) xwc.y = p_offy;
  2029.  
  2030.   xwc.width  = xwa->width;
  2031.   xwc.height = xwa->height;
  2032.  
  2033.  
  2034. #ifdef BAD_IDEA
  2035.   /* if there is a virtual window manager running, then we should translate
  2036.      the coordinates that are in terms of 'real' screen into coordinates
  2037.      that are in terms of the 'virtual' root window 
  2038.      from: Daren W. Latham <dwl@mentat.udev.cdc.com> */
  2039.   
  2040.   if (vrootW != rootW) { /* virtual window manager running */
  2041.     int x1,y1;
  2042.     Window child;
  2043.     XTranslateCoordinates(theDisp, rootW, vrootW,xwc.x,xwc.y,&x1,&y1,&child);
  2044.     if (DEBUG) fprintf(stderr,"SWP: translate: %d,%d -> %d,%d\n",
  2045.                xwc.x,xwc.y,x1,y1);
  2046.     xwc.x = x1;  xwc.y = y1;
  2047.   }
  2048. #endif  
  2049.  
  2050.  
  2051.   if (DEBUG) {
  2052.     fprintf(stderr,
  2053.         "SWP: xwa=%d,%d %dx%d xwc=%d,%d %dx%d off=%d,%d bw=%d klg=%d,%d\n",
  2054.         xwa->x, xwa->y, xwa->width, xwa->height,
  2055.         xwc.x, xwc.y, xwc.width, xwc.height, p_offx, p_offy, 
  2056.         xwa->border_width, kludge_offx, kludge_offy);
  2057.   }
  2058.  
  2059.   xwc.x += kludge_offx;
  2060.   xwc.y += kludge_offy;
  2061.  
  2062. #if defined(DXWM) || defined(HAVE_XUI)
  2063.   /* dxwm seems to *only* pay attention to the hints */
  2064.   {
  2065.     XSizeHints hints;
  2066.     if (DEBUG) fprintf(stderr,"SWP: doing the DXWM thing\n");
  2067.     /* read hints for this window and adjust any position hints */
  2068.     if (XGetNormalHints(theDisp, mainW, &hints)) {
  2069.       hints.flags |= USPosition | USSize;
  2070.       hints.x = xwc.x;  hints.y = xwc.y;
  2071.       hints.width = xwc.width; hints.height = xwc.height;
  2072.       XSetNormalHints(theDisp, mainW, &hints);
  2073.     }
  2074.  
  2075. #ifndef MWM     /* don't do this if you're running MWM */
  2076.     xwc.x -= 5;   xwc.y -= 25;    /* EVIL KLUDGE */
  2077. #endif /* MWM */
  2078.   }
  2079. #endif
  2080.  
  2081.   /* all non-DXWM window managers (?) */
  2082.   /* Move/Resize the window. */
  2083.   XConfigureWindow(theDisp, mainW, 
  2084.            CWX | CWY | CWWidth | CWHeight /*| CWBorderWidth*/, &xwc);
  2085. }
  2086.  
  2087.  
  2088.  
  2089. /***********************************/
  2090. static void CropKey(dx,dy,grow,crop)
  2091.      int dx,dy,grow,crop;
  2092. {
  2093.   int x1,x2,y1,y2,active, ocx, ocy;
  2094.  
  2095.   if (crop) { /* chop off a pixel from the appropriate edge */
  2096.     int dealt=1;
  2097.  
  2098.     ocx = cXOFF;  ocy = cYOFF;
  2099.     if      (dx<0 && cWIDE>1) DoCrop(cXOFF,   cYOFF,   cWIDE-1, cHIGH);
  2100.     else if (dx>0 && cWIDE>1) DoCrop(cXOFF+1, cYOFF,   cWIDE-1, cHIGH);
  2101.     else if (dy<0 && cHIGH>1) DoCrop(cXOFF,   cYOFF,   cWIDE,   cHIGH-1);
  2102.     else if (dy>0 && cHIGH>1) DoCrop(cXOFF,   cYOFF+1, cWIDE,   cHIGH-1);
  2103.     else { dealt = 0;  XBell(theDisp, 0); }
  2104.  
  2105.     if (dealt) {
  2106.       if (useroot) DrawEpic();
  2107.       else {
  2108.     if (HaveSelection()) EnableSelection(0);
  2109.     CreateXImage();
  2110.     WCrop(eWIDE, eHIGH, cXOFF-ocx, cYOFF-ocy);
  2111.       }
  2112.     }
  2113.     return;
  2114.   }
  2115.       
  2116.   if (grow) MoveGrowSelection(0,  0,  dx, dy);
  2117.        else MoveGrowSelection(dx, dy, 0,  0);
  2118. }
  2119.  
  2120.  
  2121. /***********************************/
  2122. static void TrackPicValues(mx,my)
  2123.      int mx,my;
  2124. {
  2125.   Window       rW,cW;
  2126.   int          rx,ry,ox,oy,x,y, orgx,orgy;
  2127.   u_int        mask;
  2128.   u_long       wh, bl;
  2129.   int          ty, w, ecol, done1;
  2130.   char         foo[128];
  2131.   char         *str  = 
  2132.    "8888,8888 = 123,123,123  #123456  (123,123,123 HSV)  [-2345,-2345]";
  2133.  
  2134.   ecol = 0;  wh = infobg;  bl = infofg;
  2135.  
  2136.   if (!dropper) {
  2137.     Pixmap      pix, mask;
  2138.     XColor      cfg, cbg;
  2139.     
  2140.     cfg.red = cfg.green = cfg.blue = 0x0000;
  2141.     cbg.red = cbg.green = cbg.blue = 0xffff;
  2142.     
  2143.     pix = MakePix1(rootW, dropper_bits,  dropper_width,  dropper_height);
  2144.     mask= MakePix1(rootW, dropperm_bits, dropperm_width, dropperm_height);
  2145.     if (pix && mask) 
  2146.       dropper = XCreatePixmapCursor(theDisp, pix, mask, &cfg, &cbg, 
  2147.                     dropper_x_hot, dropper_y_hot);
  2148.     if (pix)  XFreePixmap(theDisp, pix);
  2149.     if (mask) XFreePixmap(theDisp, mask);
  2150.   }
  2151.  
  2152.   if (dropper) XDefineCursor(theDisp, mainW, dropper);
  2153.  
  2154.   /* do a colormap search for black and white if LocalCmap 
  2155.      and use those colors instead of infobg and infofg */
  2156.  
  2157.   if (LocalCmap) {
  2158.     XColor ctab[256];   int  i;   long cval;
  2159.  
  2160.     for (i=0; i<nfcols; i++) ctab[i].pixel = freecols[i];
  2161.     XQueryColors(theDisp,LocalCmap,ctab,nfcols);
  2162.     
  2163.     /* find 'blackest' pixel */
  2164.     cval = 0x10000 * 3;
  2165.     for (i=0; i<nfcols; i++)
  2166.       if ((long)ctab[i].red + (long)ctab[i].green + (long)ctab[i].blue <cval) {
  2167.     cval = ctab[i].red + ctab[i].green + ctab[i].blue;
  2168.     bl = ctab[i].pixel;
  2169.       }
  2170.  
  2171.     /* find 'whitest' pixel */
  2172.     cval = -1;
  2173.     for (i=0; i<nfcols; i++)
  2174.       if ((long)ctab[i].red + (long)ctab[i].green + (long)ctab[i].blue >cval) {
  2175.     cval = ctab[i].red + ctab[i].green + ctab[i].blue;
  2176.     wh = ctab[i].pixel;
  2177.       }
  2178.   }
  2179.   
  2180.  
  2181.   XSetFont(theDisp, theGC, monofont);
  2182.   w = XTextWidth(monofinfo, str, (int) strlen(str));
  2183.  
  2184.   if (my > eHIGH/2) ty = 0;
  2185.                else ty = eHIGH-(monofinfo->ascent + mfinfo->descent)-4;
  2186.  
  2187.   XSetForeground(theDisp, theGC, bl);
  2188.   XFillRectangle(theDisp, mainW, theGC, 0, ty, (u_int) w + 8, 
  2189.          (u_int) (monofinfo->ascent+monofinfo->descent) + 4);
  2190.   XSetForeground(theDisp, theGC, wh);
  2191.   XSetBackground(theDisp, theGC, bl);
  2192.   foo[0] = '\0';
  2193.  
  2194.  
  2195.   done1 = ox = oy = orgx = orgy = 0;
  2196.   while (1) {
  2197.     int px, py, pix;
  2198.  
  2199.     if (!XQueryPointer(theDisp,mainW,&rW,&cW,&rx,&ry,&x,&y,&mask)) continue;
  2200.     if (done1 && !(mask & Button2Mask)) break;    /* button released */
  2201.     
  2202.     CoordE2P(x,y, &px, &py);
  2203.     RANGE(px,0,pWIDE-1);  
  2204.     RANGE(py,0,pHIGH-1);
  2205.     
  2206.     if (px!=ox || py!=oy || !done1) {  /* moved, or firsttime.  erase & draw */
  2207.       double h1, s1, v1;
  2208.       int    rval, gval, bval;
  2209.       
  2210.       if (picType == PIC8) {
  2211.     ecol = pix = pic[py * pWIDE + px];
  2212.     rval = rcmap[pix];  gval = gcmap[pix];  bval = bcmap[pix];
  2213.       }
  2214.       else {  /* PIC24 */
  2215.     rval = pic[py * pWIDE * 3 + px * 3];
  2216.     gval = pic[py * pWIDE * 3 + px * 3 + 1];
  2217.     bval = pic[py * pWIDE * 3 + px * 3 + 2];
  2218.       }
  2219.       
  2220.       clearR = rval;  clearG = gval;  clearB = bval;
  2221.  
  2222.       rgb2hsv(rval, gval, bval, &h1, &s1, &v1);
  2223.       if (h1<0.0) h1 = 0.0;   /* map 'NOHUE' to 0.0 */
  2224.  
  2225.       if (!done1) { orgx = px;  orgy = py; }
  2226.  
  2227.       sprintf(foo,
  2228.    "%4d,%4d = %3d,%3d,%3d  #%02x%02x%02x  (%3d %3d %3d HSV)  [%5d,%5d]",
  2229.           px, py, rval, gval, bval, rval, gval, bval,
  2230.           (int) h1, (int) (s1 * 100), (int) (v1 * 100),
  2231.           px-orgx, py-orgy);
  2232.       
  2233.       XDrawImageString(theDisp,mainW,theGC, 4, ty + 2 + monofinfo->ascent, 
  2234.                foo, (int) strlen(foo));
  2235.       ox = px;  oy = py;
  2236.       done1 = 1;
  2237.     }
  2238.   }
  2239.   SetCursors(-1);
  2240.  
  2241.  
  2242.   if (foo[0]) {
  2243.     strcat(foo, "\n");
  2244.     NewCutBuffer(foo);
  2245.   }
  2246.  
  2247.   XSetFont(theDisp, theGC, mfont);
  2248.   DrawWindow(0,ty,eWIDE,(monofinfo->ascent+monofinfo->descent)+4);
  2249.  
  2250.   if (picType == PIC8 && ecol != editColor) ChangeEC(ecol);
  2251. }
  2252.  
  2253.  
  2254. /***********************************/
  2255. static Bool IsConfig(dpy, ev, arg)
  2256.      Display *dpy;
  2257.      XEvent  *ev;
  2258.      char    *arg;
  2259. {
  2260.   XConfigureEvent *cev;
  2261.  
  2262.   if (ev->type == ConfigureNotify) {
  2263.     cev = (XConfigureEvent *) ev;
  2264.     if (cev->window == mainW && (cev->width != eWIDE || cev->height != eHIGH))
  2265.       *arg = 1;
  2266.   }
  2267.   return False;
  2268. }
  2269.  
  2270. /***********************************/
  2271. static int CheckForConfig()
  2272. {
  2273.   XEvent ev;
  2274.   char   foo;
  2275.  
  2276.   /* returns true if there's a config event in which mainW changes size
  2277.      in the event queue */
  2278.   
  2279.   XSync(theDisp, False);
  2280.   foo = 0;
  2281.   XCheckIfEvent(theDisp, &ev, IsConfig, &foo);
  2282.   return foo;
  2283. }
  2284.  
  2285.  
  2286. /************************************************************************/
  2287. void SetEpicMode()
  2288. {
  2289.   if (epicMode == EM_RAW) {
  2290.     dispMB.dim[DMB_RAW]    = 1;
  2291.     dispMB.dim[DMB_DITH]   = !(ncols>0 && picType == PIC8);
  2292.     dispMB.dim[DMB_SMOOTH] = 0;
  2293.   }
  2294.  
  2295.   else if (epicMode == EM_DITH) {
  2296.     dispMB.dim[DMB_RAW]    = 0;
  2297.     dispMB.dim[DMB_DITH]   = 1;
  2298.     dispMB.dim[DMB_SMOOTH] = 0;
  2299.   }
  2300.  
  2301.   else if (epicMode == EM_SMOOTH) {
  2302.     dispMB.dim[DMB_RAW]    = 0;
  2303.     dispMB.dim[DMB_DITH]   = 1;
  2304.     dispMB.dim[DMB_SMOOTH] = 1;
  2305.   }
  2306. }
  2307.  
  2308.  
  2309. /************************************************************************/
  2310. int xvErrorHandler(disp, err)
  2311.      Display *disp;
  2312.      XErrorEvent *err;
  2313. {
  2314.   char buf[128];
  2315.  
  2316.   /* in case the error occurred during the Grab command... */
  2317.   XUngrabServer(theDisp);
  2318.   XUngrabButton(theDisp, (u_int) AnyButton, 0, rootW);
  2319.  
  2320.   xerrcode = err->error_code;
  2321.  
  2322.   /* non-fatal errors:   (sets xerrcode and returns)
  2323.    *    BadAlloc
  2324.    *    BadAccess errors on XFreeColors call
  2325.    *    Any error on the 'XKillClient()' call
  2326.    *    BadWindow errors (on a GetProperty call) (workaround SGI problem)
  2327.    *    BadLength errors on XChangeProperty
  2328.    *    BadMatch  errors on XGetImage
  2329.    */
  2330.  
  2331.   if ((xerrcode == BadAlloc)                                               || 
  2332.       (xerrcode == BadAccess && err->request_code==88 /* X_FreeColors */ ) ||
  2333.       (err->request_code == 113                       /* X_KillClient */ ) ||
  2334.       (xerrcode == BadLength && err->request_code==18 /* X_ChangeProp */ ) ||
  2335.       (xerrcode == BadMatch  && err->request_code==73 /* X_GetImage   */ ) ||
  2336.       (xerrcode == BadWindow && err->request_code==20 /* X_GetProperty*/))
  2337.     return 0;
  2338.  
  2339.   else {
  2340.     /* all other errors are 'fatal' */
  2341.     XGetErrorText(disp, xerrcode, buf, 128);
  2342.     fprintf(stderr,"X Error: %s\n",buf);
  2343.     fprintf(stderr,"  Major Opcode:  %d\n",err->request_code);
  2344.  
  2345.     if (DEBUG) {   /* crash 'n' burn for debugging purposes */
  2346.       char *str;
  2347.       str  = NULL;
  2348.       *str = '0';
  2349.     }
  2350.  
  2351.     exit(-1);
  2352.   }
  2353.  
  2354.   return 0;
  2355. }
  2356.  
  2357.  
  2358. /************************************************************************/
  2359. static void onInterrupt(i)
  2360.      int i;
  2361. {
  2362.   /* but first, if any input-grabbing popups are active, we have to 'cancel'
  2363.      them. */
  2364.   
  2365.   if (psUp) PSDialog(0);      /* close PS window */
  2366.  
  2367. #ifdef HAVE_JPEG
  2368.   if (jpegUp) JPEGDialog(0);  /* close jpeg window */
  2369. #endif
  2370.  
  2371. #ifdef HAVE_TIFF
  2372.   if (tiffUp) TIFFDialog(0);  /* close tiff window */
  2373. #endif
  2374.  
  2375.   ClosePopUp();
  2376.  
  2377.   /* make the interrupt signal look like a '\n' keypress in ctrlW */
  2378.   FakeKeyPress(ctrlW, XK_Return);
  2379.  
  2380.   frominterrupt = 1;
  2381. }
  2382.  
  2383.  
  2384.  
  2385.  
  2386.  
  2387. /***********************************/
  2388. static void Paint()
  2389. {
  2390.   Window  rW,cW;
  2391.   int     rx,ry, x,y, px,py, px1,py1, state;
  2392.   int     lx, ly, line, seenRelease;
  2393.   u_int   mask, nmask;
  2394.  
  2395.   /* paint pixels in either editCol (PIC8) or clear{R,G,B} (PIC24) until
  2396.      'shift' key is released.  beep on button presses other than B2.
  2397.      When shift is released, regen all pics (ala 'clearSelectedArea()') */
  2398.  
  2399.  
  2400.   if (!pen) {
  2401.     Pixmap      pix, pmask;
  2402.     XColor      cfg, cbg;
  2403.     
  2404.     cfg.red = cfg.green = cfg.blue = 0x0000;
  2405.     cbg.red = cbg.green = cbg.blue = 0xffff;
  2406.     
  2407.     pix = MakePix1(rootW, pen_bits,  pen_width,  pen_height);
  2408.     pmask= MakePix1(rootW, penm_bits, penm_width, penm_height);
  2409.     if (pix && pmask) 
  2410.       pen = XCreatePixmapCursor(theDisp, pix, pmask, &cfg, &cbg, 
  2411.                     pen_x_hot, pen_y_hot);
  2412.     if (pix)   XFreePixmap(theDisp, pix);
  2413.     if (pmask) XFreePixmap(theDisp, pmask);
  2414.   }
  2415.  
  2416.   if (pen) XDefineCursor(theDisp, mainW, pen);
  2417.  
  2418.  
  2419.   XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask 
  2420.            | StructureNotifyMask /* | ButtonPressMask */
  2421.            | KeyReleaseMask | ColormapChangeMask
  2422.            | EnterWindowMask | LeaveWindowMask );
  2423.  
  2424.  
  2425.  
  2426.   state = 0;
  2427.   line = lx = ly = seenRelease = 0;
  2428.  
  2429.   while (state<100) {
  2430.     if (!XQueryPointer(theDisp,mainW,&rW,&cW,&rx,&ry,&x,&y,&mask)) continue;
  2431.  
  2432.     nmask = (~mask);
  2433.     px1 = px;  py1 = py;
  2434.     CoordE2P(x,y, &px, &py);
  2435.  
  2436.     switch (state) {
  2437.     case 0:               /* initial state:  make sure we do one pixel */
  2438.       px1 = lx = px;  py1 = ly = py;  
  2439.       paintPixel(px, py);
  2440.  
  2441.       if      (nmask & ShiftMask  ) state = 99;
  2442.       else if (nmask & Button2Mask) state = 1;
  2443.       else if ( mask & ControlMask) state = 20;
  2444.       else                          state = 10;
  2445.       break;
  2446.  
  2447.       
  2448.     case 1:               /* waiting for click */
  2449.       if      (nmask & ShiftMask) state = 99;
  2450.       else if ( mask & Button2Mask) {
  2451.     paintPixel(px, py);
  2452.     if (mask & ControlMask) {
  2453.       lx = px;  ly = py;
  2454.       paintXLine(lx, ly, px, py, 1);
  2455.       line = 1;
  2456.       state = 20;
  2457.     }
  2458.     else state = 10;
  2459.       }
  2460.       break;
  2461.  
  2462.       
  2463.     case 10:               /* in freehand drawing mode */
  2464.       if      (nmask & ShiftMask  ) state = 99;
  2465.       else if (nmask & Button2Mask) state = 1;
  2466.       else if ( mask & ControlMask) {
  2467.     lx = px;  ly = py;
  2468.     paintXLine(lx, ly, px, py, 1);
  2469.     line = 1;
  2470.     state = 20;
  2471.       }
  2472.       else paintLine(px1,py1,px,py);
  2473.       break;
  2474.  
  2475.  
  2476.     case 20:               /* in line-drawing mode */
  2477.       if      (nmask & ShiftMask  ) state = 99;
  2478.       else if (nmask & ControlMask) {
  2479.     /* remove xor-line, switch to freehand drawing mode or click-wait */
  2480.     paintXLine(lx, ly, px1, py1, 0);
  2481.     line = 0;
  2482.     if (mask & Button2Mask) state = 10;
  2483.                        else state = 1;
  2484.       }
  2485.  
  2486.       else if ((mask & Button2Mask) && seenRelease) {
  2487.     /* remove xor-line, draw line to pt, start xor-line from new pt */
  2488.     paintXLine(lx, ly, px1, py1, 0);
  2489.     paintLine (lx, ly, px1, py1);
  2490.     paintXLine(px1,py1,px,  py,  1);
  2491.     line = 1;
  2492.     lx = px1;  ly = py1;
  2493.  
  2494.     seenRelease = 0;
  2495.       }
  2496.  
  2497.       else {
  2498.     /* if moved, erase old xor-line, draw new xor-line */
  2499.     if (px != px1 || py != py1) {
  2500.       paintXLine(lx, ly, px1, py1, 0);
  2501.       paintXLine(lx, ly, px,  py,  1);
  2502.       line = 1;
  2503.     }
  2504.     else {
  2505.       paintXLine(lx, ly, px1, py1, 0);
  2506.       paintXLine(lx, ly, px1, py1, 1);
  2507.       XSync(theDisp, False);
  2508.       Timer(100);
  2509.     }
  2510.       
  2511.     if (nmask & Button2Mask) seenRelease = 1;
  2512.       }
  2513.       break;
  2514.       
  2515.     case 99:              /* EXIT loop:  cleanup */
  2516.       if (line) { /* erase old xor-line */
  2517.     paintXLine(lx, ly, px1, py1, 0);
  2518.     line = 0;
  2519.       }
  2520.       state = 100;     /* exit while loop */
  2521.       break;
  2522.     }
  2523.   }
  2524.     
  2525.   
  2526.   WaitCursor();
  2527.   
  2528.   XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask 
  2529.            | StructureNotifyMask | ButtonPressMask
  2530.            | KeyReleaseMask | ColormapChangeMask
  2531.            | EnterWindowMask | LeaveWindowMask );
  2532.  
  2533.   GenerateCpic();
  2534.   WaitCursor();
  2535.   GenerateEpic(eWIDE,eHIGH);
  2536.   WaitCursor();
  2537.   DrawEpic();        /* redraws selection, also */
  2538.   SetCursors(-1);
  2539. }
  2540.  
  2541.  
  2542. /***********************/
  2543. static void paintPixel(x,y)
  2544.      int x,y;
  2545. {
  2546.   /* paints pixel x,y (pic coords) into pic in editColor (PIC8) or clearR,G,B
  2547.      (PIC24) and does appropriate screen feedback. */
  2548.  
  2549.   int ex,ey,ex1,ey1,ew,eh;
  2550.  
  2551.   if (!PTINRECT(x,y,0,0,pWIDE,pHIGH)) return;
  2552.  
  2553.   if (picType == PIC8) {
  2554.     pic[y * pWIDE + x] = editColor;
  2555.   }
  2556.   else {  /* PIC24 */
  2557.     byte *pp = pic + (y * pWIDE + x) * 3;
  2558.     pp[0] = clearR;  pp[1] = clearG;  pp[2] = clearB;
  2559.   }
  2560.   
  2561.   /* visual feedback */
  2562.   CoordP2E(x,   y,   &ex,  &ey);
  2563.   CoordP2E(x+1, y+1, &ex1, &ey1);
  2564.   
  2565.   ew = ex1-ex;  eh = ey1-ey;
  2566.   
  2567.   if (picType == PIC8) XSetForeground(theDisp, theGC, cols[editColor]);
  2568.   else XSetForeground(theDisp, theGC, RGBToXColor(clearR, clearG, clearB));
  2569.   
  2570.   if (ew>0 && eh>0) 
  2571.     XFillRectangle(theDisp,mainW,theGC, ex,ey, (u_int) ew, (u_int) eh);
  2572. }
  2573.  
  2574.  
  2575. /***********************************/
  2576. static void paintLine(x,y,x1,y1)
  2577.   int x,y,x1,y1;
  2578. {
  2579.   int dx,dy,i,lx,ly,adx,ady;
  2580.   
  2581.   dx = x1-x;  dy = y1-y;
  2582.   adx = abs(dx);  ady = abs(dy);
  2583.  
  2584.   if (dx == 0 && dy == 0) paintPixel(x,y);
  2585.  
  2586.   else if (adx > ady) {           /* X is major axis */
  2587.     for (i=0; i<=adx; i++) {
  2588.       lx = x + (i * dx + (adx/2)) / abs(dx);
  2589.       ly = y + (i * dy + (adx/2)) / abs(dx);
  2590.       paintPixel(lx,ly);
  2591.     }
  2592.   }
  2593.  
  2594.   else {                                /* Y is major axis */
  2595.     for (i=0; i<=ady; i++) {
  2596.       lx = x + (i * dx + (ady/2)) / ady;
  2597.       ly = y + (i * dy + (ady/2)) / ady;
  2598.       paintPixel(lx,ly);
  2599.     }
  2600.   }
  2601.   
  2602.  
  2603. }
  2604.  
  2605.  
  2606. static int pntxlcol = 0;  /* index into xorMasks */
  2607.  
  2608. /***********************************/
  2609. static void paintXLine(x,y,x1,y1,newcol)
  2610.   int x,y,x1,y1,newcol;
  2611. {
  2612.   /* draws a xor'd line on image from x,y to x1,y1 (pic coords) */
  2613.   int ex,ey, ex1,ey1,  tx,ty,tx1,ty1;
  2614.  
  2615.   if (newcol) pntxlcol = (pntxlcol+1) & 0x7;
  2616.  
  2617.   CoordP2E(x,  y,  &tx, &ty);
  2618.   CoordP2E(x+1,y+1,&tx1,&ty1);
  2619.   ex = tx + (tx1 - tx)/2;
  2620.   ey = ty + (ty1 - ty)/2;
  2621.   
  2622.   CoordP2E(x1,  y1,  &tx, &ty);
  2623.   CoordP2E(x1+1,y1+1,&tx1,&ty1);
  2624.   ex1 = tx + (tx1 - tx)/2;
  2625.   ey1 = ty + (ty1 - ty)/2;
  2626.   
  2627.   if (ex==ex1 && ey==ey1) return;
  2628.   
  2629.   XSetPlaneMask(theDisp, theGC, xorMasks[pntxlcol]);
  2630.   XSetFunction(theDisp, theGC, GXinvert);
  2631.   XDrawLine(theDisp, mainW, theGC, ex, ey, ex1, ey1);
  2632.   XSetFunction(theDisp, theGC, GXcopy);
  2633.   XSetPlaneMask(theDisp, theGC, AllPlanes);
  2634. }
  2635.  
  2636.  
  2637. /***********************************/
  2638. static void BlurPaint()
  2639. {
  2640.   Window  rW,cW;
  2641.   int     rx,ry,ox,oy,x,y, px,py, ex,ey, ex1,ey1, ew, eh, done1, dragging;
  2642.   int     uppedpic;
  2643.   u_int   mask;
  2644.   byte   *pp;
  2645.  
  2646.   /* blurs pixels in either editCol (PIC8) or clear{R,G,B} (PIC24) until
  2647.      'shift' key is released.  */
  2648.  
  2649.  
  2650.   /* if PIC8, uprev it to PIC24 */
  2651.   if (picType == PIC8) Select24to8MB(CONV24_24BIT);
  2652.  
  2653.   if (!blur) {
  2654.     Pixmap      pix, mask;
  2655.     XColor      cfg, cbg;
  2656.     
  2657.     cfg.red = cfg.green = cfg.blue = 0x0000;
  2658.     cbg.red = cbg.green = cbg.blue = 0xffff;
  2659.     
  2660.     pix = MakePix1(rootW, blur_bits,  blur_width,  blur_height);
  2661.     mask= MakePix1(rootW, blurm_bits, blurm_width, blurm_height);
  2662.     if (pix && mask) 
  2663.       blur = XCreatePixmapCursor(theDisp, pix, mask, &cfg, &cbg, 
  2664.                     blur_x_hot, blur_y_hot);
  2665.     if (pix)  XFreePixmap(theDisp, pix);
  2666.     if (mask) XFreePixmap(theDisp, mask);
  2667.   }
  2668.  
  2669.   if (blur) XDefineCursor(theDisp, mainW, blur);
  2670.  
  2671.  
  2672.   XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask 
  2673.            | StructureNotifyMask /* | ButtonPressMask */
  2674.            | KeyReleaseMask | ColormapChangeMask
  2675.            | EnterWindowMask | LeaveWindowMask );
  2676.  
  2677.  
  2678.   done1 = dragging = ox = oy = 0;
  2679.   while (1) {
  2680.     if (!XQueryPointer(theDisp,mainW,&rW,&cW,&rx,&ry,&x,&y,&mask)) continue;
  2681.     if (done1 && !(mask & ShiftMask)) break;    /* Shift released */
  2682.     if (!(mask & Button3Mask)) { dragging = 0;  continue; }
  2683.  
  2684.     CoordE2P(x,y, &px, &py);
  2685.     
  2686.     if (!dragging || (dragging && (px!=ox || py!=oy))) {  /* click or drag */
  2687.       if (!dragging) blurPixel(px,py);
  2688.       else {
  2689.     int dx,dy,i,lx,ly;
  2690.     
  2691.     dx = px-ox;  dy = py-oy;   /* at least one will be non-zero */
  2692.     if (abs(dx) > abs(dy)) {   /* X is major axis */
  2693.       for (i=0; i<=abs(dx); i++) {
  2694.         lx = ox + (i * dx)/abs(dx);
  2695.         ly = oy + (i * dy)/abs(dx);
  2696.         blurPixel(lx,ly);
  2697.       }
  2698.     } else {                   /* Y is major axis */
  2699.       for (i=0; i<=abs(dy); i++) {
  2700.         lx = ox + (i * dx)/abs(dy);
  2701.         ly = oy + (i * dy)/abs(dy);
  2702.         blurPixel(lx,ly);
  2703.       }
  2704.     }
  2705.       }
  2706.  
  2707.       done1 = 1;  dragging = 1;  ox = px;  oy = py;
  2708.     }
  2709.   }
  2710.   
  2711.   WaitCursor();
  2712.   
  2713.   XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask 
  2714.            | StructureNotifyMask | ButtonPressMask
  2715.            | KeyReleaseMask | ColormapChangeMask
  2716.            | EnterWindowMask | LeaveWindowMask );
  2717.  
  2718.   GenerateCpic();
  2719.   WaitCursor();
  2720.   GenerateEpic(eWIDE,eHIGH);
  2721.   WaitCursor();
  2722.   DrawEpic();        /* redraws selection, also */
  2723.   SetCursors(-1);
  2724. }
  2725.  
  2726.  
  2727.  
  2728. /***********************/
  2729. static int highbit(ul)
  2730.      unsigned long ul;
  2731. {
  2732.   /* returns position of highest set bit in 'ul' as an integer (0-31),
  2733.      or -1 if none */
  2734.   
  2735.   int i;  unsigned long hb;
  2736.   
  2737.   hb = 0x80;  hb = hb << 24;   /* hb = 0x80000000UL */
  2738.   for (i=31; ((ul & hb) == 0) && i>=0;  i--, ul<<=1);
  2739.   return i;
  2740. }
  2741.  
  2742.  
  2743. /***********************/
  2744. static unsigned long RGBToXColor(r,g,b)
  2745.      int r,g,b;
  2746. {
  2747.   /* converts arbitrary rgb values (0-255) into an appropriate X color value,
  2748.      suitable for XSetForeground().  Works for ncols==0, all visual types,
  2749.      etc.  Note that it doesn't do the *best* job, it's really only for
  2750.      visual feedback during Painting, etc.  Should call GenEpic and such
  2751.      after modifying picture to redither, etc.  */
  2752.  
  2753.   unsigned long rv;
  2754.  
  2755.   if (picType == PIC8) {    /* simply find closest color in rgb map */
  2756.     int i,j,d,di;
  2757.  
  2758.     d = 3*(256*256);  j=0;
  2759.     for (i=0; i<numcols; i++) {
  2760.       di = ((r-rMap[i]) * (r-rMap[i])) + 
  2761.        ((g-gMap[i]) + (g-gMap[i])) +
  2762.            ((b-bMap[i]) * (b-bMap[i]));
  2763.       if (i==0 || di<d) { j=i;  d=di; }
  2764.     }
  2765.  
  2766.     rv = cols[j];
  2767.   }
  2768.  
  2769.  
  2770.   else {    /* PIC24 */
  2771.     if (theVisual->class==TrueColor || theVisual->class==DirectColor) {
  2772.       unsigned long rmask, gmask, bmask;
  2773.       int           rshift, gshift, bshift, cshift, maplen;
  2774.       
  2775.       /* compute various shifting constants that we'll need... */
  2776.       
  2777.       rmask = theVisual->red_mask;
  2778.       gmask = theVisual->green_mask;
  2779.       bmask = theVisual->blue_mask;
  2780.       
  2781.       rshift = 7 - highbit(rmask);
  2782.       gshift = 7 - highbit(gmask);
  2783.       bshift = 7 - highbit(bmask);
  2784.       
  2785.       if (theVisual->class == DirectColor) {
  2786.     maplen = theVisual->map_entries;
  2787.     if (maplen>256) maplen=256;
  2788.     cshift = 7 - highbit((u_long) (maplen-1));
  2789.     
  2790.     r = (u_long) directConv[(r>>cshift) & 0xff] << cshift;
  2791.     g = (u_long) directConv[(g>>cshift) & 0xff] << cshift;
  2792.     b = (u_long) directConv[(b>>cshift) & 0xff] << cshift;
  2793.       }
  2794.       
  2795.       
  2796.       /* shift the bits around */
  2797.       if (rshift<0) r = r << (-rshift);
  2798.       else r = r >> rshift;
  2799.       
  2800.       if (gshift<0) g = g << (-gshift);
  2801.       else g = g >> gshift;
  2802.       
  2803.       if (bshift<0) b = b << (-bshift);
  2804.       else b = b >> bshift;
  2805.       
  2806.       r = r & rmask;
  2807.       g = g & gmask;
  2808.       b = b & bmask;
  2809.       
  2810.       rv =r | g | b;
  2811.     }
  2812.     
  2813.     else {                          /* non-TrueColor/DirectColor visual */
  2814.       if (!ncols)
  2815.     rv = ((r + g + b >= 128*3) ? white : black);
  2816.       else                         /* use closest color in stdcmap */
  2817.     rv = stdcols[(r&0xe0) | ((g&0xe0)>>3) | ((b&0xc0) >> 6)];
  2818.     }
  2819.   }
  2820.  
  2821.   return rv;
  2822. }
  2823.       
  2824.     
  2825. /***********************/
  2826. static void blurPixel(x,y)
  2827.      int x,y;
  2828. {
  2829.   /* blurs pixel x,y (pic coords) into pic in editColor (PIC8) or clearR,G,B
  2830.      (PIC24) and does appropriate screen feedback.  Does a 3x3 average 
  2831.      around the pixel, and replaces it with the average value (PIC24), or
  2832.      the closest existing color to the average value (PIC8) */
  2833.  
  2834.   byte *pp;
  2835.   int i, j, d, di;
  2836.   int ex,ey,ex1,ey1,ew,eh;
  2837.   int ar,ag,ab,ac;
  2838.  
  2839.   if (!PTINRECT(x,y,0,0,pWIDE,pHIGH)) return;
  2840.  
  2841.   ar = ag = ab = ac = 0;
  2842.   for (i=y-1; i<=y+1; i++) {
  2843.     for (j=x-1; j<=x+1; j++) {
  2844.       if (PTINRECT(j,i, 0,0,pWIDE,pHIGH)) {
  2845.     if (picType == PIC8) {
  2846.       pp = pic + i * pWIDE + j;
  2847.       ar += rMap[*pp];  ag += gMap[*pp];  ab += bMap[*pp];
  2848.     }
  2849.     else {
  2850.       pp = pic + (i * pWIDE + j) * 3;
  2851.       ar += pp[0];  ag += pp[1];  ab += pp[2];
  2852.     }
  2853.     ac++;
  2854.       }
  2855.     }
  2856.   }
  2857.  
  2858.   ar /= ac;  ag /= ac;  ab /= ac;
  2859.  
  2860.  
  2861.   if (picType == PIC8) {  /* find nearest actual color */
  2862.     d = 3*(256*256);  j=0;
  2863.     for (i=0; i<numcols; i++) {
  2864.       di = ((ar-rMap[i]) * (ar-rMap[i])) + 
  2865.        ((ag-gMap[i]) + (ag-gMap[i])) +
  2866.            ((ab-bMap[i]) * (ab-bMap[i]));
  2867.       if (i==0 || di<d) { j=i;  d=di; }
  2868.     }
  2869.  
  2870.     ac = j;
  2871.     pic[y * pWIDE + x] = ac;
  2872.   }
  2873.   else {  /* PIC24 */
  2874.     pp = pic + (y * pWIDE + x) * 3;
  2875.     pp[0] = ar;  pp[1] = ag;  pp[2] = ab;
  2876.   }
  2877.   
  2878.   /* visual feedback */
  2879.   CoordP2E(x,   y,   &ex,  &ey);
  2880.   CoordP2E(x+1, y+1, &ex1, &ey1);
  2881.   
  2882.   ew = ex1-ex;  eh = ey1-ey;
  2883.   
  2884.   if (picType == PIC8) XSetForeground(theDisp, theGC, cols[ac]);
  2885.   else XSetForeground(theDisp, theGC, RGBToXColor(ar, ag, ab));
  2886.   
  2887.   if (ew>0 && eh>0) 
  2888.     XFillRectangle(theDisp,mainW,theGC, ex,ey, (u_int) ew, (u_int) eh);
  2889. }
  2890.  
  2891.  
  2892.  
  2893.  
  2894.  
  2895. /***********************/
  2896. static void annotatePic()
  2897. {
  2898.   int          i, w,h, len;
  2899.   byte        *cimg;
  2900.   char         txt[256];
  2901.   static char  buf[256] = {'\0'};
  2902.   static char *labels[] = {"\nOk", "\033Cancel" };
  2903.  
  2904.   sprintf(txt, "Image Annotation:\n\n%s", 
  2905.       "Enter string to be placed on image.");
  2906.   
  2907.   i = GetStrPopUp(txt, labels, 2, buf, 256, "", 0);
  2908.   if (i==1 || strlen(buf)==0) return;
  2909.   
  2910.   
  2911.   /* build a 'cimg' array to be pasted on clipboard */
  2912.   w = strlen(buf) * 6 - 1;  h = 9;
  2913.   len = CIMG_PIC8 + w*h;
  2914.  
  2915.   cimg = (byte *) malloc((size_t) len);
  2916.   if (!cimg) {
  2917.     ErrPopUp("Error:  Unable to allocate memory for this operation.", "\nOk");
  2918.     return;
  2919.   }
  2920.  
  2921.   cimg[CIMG_LEN  ] =  len      & 0xff;
  2922.   cimg[CIMG_LEN+1] = (len>> 8) & 0xff;
  2923.   cimg[CIMG_LEN+2] = (len>>16) & 0xff;
  2924.   cimg[CIMG_LEN+3] = (len>>24) & 0xff;
  2925.  
  2926.   cimg[CIMG_W  ] =  w     & 0xff;
  2927.   cimg[CIMG_W+1] = (w>>8) & 0xff;
  2928.  
  2929.   cimg[CIMG_H  ] =  h     & 0xff;
  2930.   cimg[CIMG_H+1] = (h>>8) & 0xff;
  2931.  
  2932.   cimg[CIMG_24]    = 0;
  2933.   cimg[CIMG_TRANS] = 1;
  2934.   cimg[CIMG_TRVAL] = 0;
  2935.  
  2936.   xvbzero((char *) cimg + CIMG_PIC8, (size_t) w*h);
  2937.  
  2938.   if (picType == PIC8) {
  2939.     cimg[CIMG_CMAP + 3 + 0] = rMap[editColor];
  2940.     cimg[CIMG_CMAP + 3 + 1] = gMap[editColor];
  2941.     cimg[CIMG_CMAP + 3 + 2] = bMap[editColor];
  2942.   } else {
  2943.     cimg[CIMG_CMAP + 3 + 0] = clearR;
  2944.     cimg[CIMG_CMAP + 3 + 1] = clearG;
  2945.     cimg[CIMG_CMAP + 3 + 2] = clearB;
  2946.   }
  2947.  
  2948.   DrawStr2Pic(buf, w/2, h/2, cimg+CIMG_PIC8, w,h, 1);
  2949.  
  2950.   SaveToClip(cimg);
  2951.   free(cimg);
  2952.  
  2953.   /* if (HaveSelection()) EnableSelection(0); */
  2954.   DoImgPaste();
  2955. }
  2956.  
  2957.  
  2958.