home *** CD-ROM | disk | FTP | other *** search
/ Stars of Shareware: Programmierung / SOURCE.mdf / programm / msdos / c / xv221src / xvevent.c < prev    next >
C/C++ Source or Header  |  1992-04-29  |  41KB  |  1,465 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)
  13.  *            void WUnCrop()
  14.  *            void GetWindowPos(&xwa)
  15.  *            void SetWindowPos(&xwa)
  16.  *     static void TrackCrop(mx,my)
  17.  *     static void CropKey(dx,dy,grow)
  18.  *     static int  Rect(x,y,x1,y1)
  19.  *            void InvCropRect()
  20.  *     static void TrackPicValues(mx,my)
  21.  *     static int  CheckForConfig()
  22.  *            void SetEpicMode()
  23.  *            int  xvErrorHandler(disp, err)
  24.  */
  25.  
  26.  
  27. /*
  28.  * Copyright 1989, 1990, 1991, 1992 by John Bradley and
  29.  *                       The University of Pennsylvania
  30.  *
  31.  * Permission to use, copy, and distribute for non-commercial purposes,
  32.  * is hereby granted without fee, providing that the above copyright
  33.  * notice appear in all copies and that both the copyright notice and this
  34.  * permission notice appear in supporting documentation. 
  35.  *
  36.  * The software may be modified for your own purposes, but modified versions
  37.  * may not be distributed.
  38.  *
  39.  * This software is provided "as is" without any expressed or implied warranty.
  40.  *
  41.  * The author may be contacted via:
  42.  *    US Mail:   John Bradley
  43.  *               GRASP Lab, Room 301C
  44.  *               3401 Walnut St.  
  45.  *               Philadelphia, PA  19104
  46.  *
  47.  *    Phone:     (215) 898-8813
  48.  *    EMail:     bradley@cis.upenn.edu       
  49.  */
  50.  
  51.  
  52. #define NEEDSTIME    /* for -wait handling in eventloop */
  53.  
  54. #include "xv.h"
  55.  
  56. static int rotatesLeft = 0;
  57. static int origcropx, origcropy, origcropvalid=0;
  58. static int canstartwait;
  59.  
  60.  
  61. /* local function pre-definitions */
  62. #ifdef __STDC__
  63. static void WMaximize(void);
  64. static void TrackCrop(int, int);
  65. static void CropKey(int, int, int);
  66. static int  Rect(int, int, int, int);
  67. static void TrackPicValues(int, int);
  68. static int  CheckForConfig(void);
  69. static void onInterrupt(void);
  70. #else
  71. static void WMaximize(), TrackCrop(), CropKey(), TrackPicValues();
  72. static int  Rect(), CheckForConfig();
  73. static void onInterrupt();
  74. #endif
  75.  
  76.  
  77.  
  78.  
  79. /****************/
  80. int EventLoop()
  81. /****************/
  82. {
  83.   XEvent event;
  84.   int    retval,done,waiting;
  85.   time_t orgtime, curtime;
  86.  
  87.  
  88. #ifndef NOSIGNAL
  89.   signal(SIGQUIT, onInterrupt);
  90. #endif
  91.  
  92.   /* note: there's no special event handling if we're using the root window.
  93.      if we're using the root window, we will recieve NO events for mainW */
  94.  
  95.   /* note: 'canstartwait' is magically turned 'true' in HandleEvent when I
  96.      think I've finally gotten 'mainW' drawn.  It does not necessarily
  97.      mean that any waiting is/will be done.  Also note that if we're
  98.      using a root mode, canstartwait is instantly turned on, as we aren't
  99.      going to be getting Expose/Configure events on the root window */
  100.  
  101.   done = retval = waiting = canstartwait = 0;
  102.  
  103.   if (useroot) canstartwait = 1;
  104.  
  105.   while (!done) {
  106.  
  107.     if (waitsec > -1 && canstartwait && !waiting && XPending(theDisp)==0) {
  108.       /* we wanna wait, we can wait, we haven't started waiting yet, and 
  109.      all pending events (ie, drawing the image the first time) 
  110.      have been dealt with:  START WAITING */
  111.       time((time_t *) &orgtime);
  112.       waiting = 1;
  113.     }
  114.  
  115.  
  116.     if (waitsec == -1 || XPending(theDisp)>0) {
  117.       XNextEvent(theDisp, &event);
  118.       retval = HandleEvent(&event,&done);
  119.     }
  120.  
  121.     else {                      /* no events.  check wait status */
  122.       if (waitsec>-1 && waiting) {
  123.     time((time_t *) &curtime);
  124.     if (curtime - orgtime < waitsec) sleep(1);
  125.     else {
  126.       if (waitloop) return NEXTLOOP;
  127.       else return NEXTQUIT;
  128.     }
  129.       }
  130.     }
  131.   }  /* while (!done) */
  132.  
  133.   if (!useroot && origcropvalid) WUnCrop();
  134.   origcropvalid = 0;
  135.  
  136.   return(retval);
  137. }
  138.  
  139.  
  140.  
  141. /****************/
  142. int HandleEvent(event, donep)
  143. XEvent *event;
  144. int *donep;
  145. {
  146.   static int wasInfoUp=0, wasCtrlUp=0, wasDirUp=0, wasGamUp=0, wasPsUp=0;
  147.   static int wasJpegUp=0, wasTiffUp=0;
  148.  
  149.   int done=0, retval=0;
  150.  
  151.   switch (event->type) {
  152.  
  153.   case ColormapNotify: {
  154.     XColormapEvent *cev = (XColormapEvent *) event;
  155.     if (cev->window == mainW || cev->window == rootW ||
  156.     (cev->window == gamW && cmapInGam)) {
  157.  
  158.       if (LocalCmap) {
  159.     if (cev->colormap == LocalCmap)
  160.       cmapinstalled = (cev->state == ColormapInstalled);
  161.  
  162.     else if (cev->window == rootW && 
  163.          cev->colormap != LocalCmap &&
  164.          cev->state == ColormapInstalled)
  165.       cmapinstalled = 0;
  166.  
  167.     else if (cev->window == mainW &&
  168.          cev->colormap != LocalCmap &&
  169.          cev->state == ColormapInstalled) {
  170.       cmapinstalled = 1;    /* KLUDGE */
  171.     }
  172.  
  173.     if (DEBUG) fprintf(stderr,"Cmapinstalled = %d\n", cmapinstalled);
  174.       }
  175.  
  176.       if (DEBUG) {
  177.     fprintf(stderr, "Colormap event:  window = %s",
  178.         (cev->window == mainW) ? "mainW" :
  179.         ((cev->window == rootW) ? "rootW" : "gamW/other"));
  180.     
  181.     fprintf(stderr, "  colormap = %s, state = %s\n",
  182.         (cev->colormap == None) ? "None" :
  183.         (cev->colormap == LocalCmap) ? "LocalCmap" : "???",
  184.         (cev->state == ColormapInstalled) ?
  185.         "installed" : "deinstalled");
  186.       }
  187.     }
  188.   }
  189.     break;
  190.  
  191.   case ClientMessage: {
  192.     Atom proto, delwin;
  193.     XClientMessageEvent *client_event = (XClientMessageEvent *) event;
  194.  
  195.     if (PUCheckEvent (event)) break;   /* event has been processed */
  196.  
  197.     proto = XInternAtom(theDisp, "WM_PROTOCOLS", FALSE);
  198.     delwin = XInternAtom(theDisp, "WM_DELETE_WINDOW", FALSE);
  199.  
  200.     if (client_event->message_type == proto &&
  201.     client_event->data.l[0]    == delwin) {
  202.       /* it's a WM_DELETE_WINDOW event */
  203.  
  204.       if      (client_event->window == infoW) InfoBox(0);
  205.       else if (client_event->window == gamW)  GamBox(0);
  206.       else if (client_event->window == ctrlW) CtrlBox(0);
  207.       else if (client_event->window == dirW)  DirBox(0);
  208.       else if (client_event->window == psW)   PSDialog(0);
  209.  
  210. #ifdef HAVE_JPEG
  211.       else if (client_event->window == jpegW) JPEGDialog(0);
  212. #endif
  213.  
  214. #ifdef HAVE_TIFF
  215.       else if (client_event->window == tiffW) TIFFDialog(0);
  216. #endif
  217.  
  218.       else if (client_event->window == mainW) exit(0);
  219.     }
  220.   }
  221.     break;
  222.  
  223.  
  224.   case Expose: {
  225.     XExposeEvent *exp_event = (XExposeEvent *) event;
  226.     int x,y,w,h;
  227.     Window win;
  228.  
  229. #ifdef VMS
  230.     static int borders_sized = 0;
  231.   
  232.     if (!borders_sized  && !useroot && exp_event->window == mainW) {
  233.       /*
  234.        * Initial expose of main window, find the size of the ancestor
  235.        * window just prior to the root window and adjust saved size
  236.        * of display so that maximize functions will allow for window
  237.        * decorations.
  238.        */
  239.       int status, count, mwid, mhgt, x, y, w, h, b, d, mbrd;
  240.       Window root, parent, *children, crw = exp_event->window;
  241.       borders_sized = 1;
  242.       status = XGetGeometry(theDisp, crw, 
  243.                 &root, &x, &y, &mwid, &mhgt, &mbrd, &d);
  244.       
  245.       for ( parent = crw, w=mwid, h=mhgt;
  246.        status && (parent != root) && (parent != vrootW); ) {
  247.     crw = parent;
  248.     status = XQueryTree ( theDisp, crw, &root, &parent, 
  249.                  &children, &count );
  250.     if ( children != NULL ) XFree ( children );
  251.       }
  252.       status = XGetGeometry(theDisp, crw, &root, &x, &y, &w, &h, &b, &d);
  253.       if ( status ) {
  254.     dispWIDE = dispWIDE + mwid - w + (2*b);
  255.     dispHIGH = dispHIGH + mhgt - h + b;
  256.     /*printf("New display dims: %d %d\n", dispWIDE, dispHIGH ); */
  257.       }
  258.     }
  259. #endif
  260.  
  261.  
  262.     win = exp_event->window;
  263.     x = exp_event->x;      y = exp_event->y;
  264.     w = exp_event->width;  h = exp_event->height;
  265.     
  266.     if (PUCheckEvent  (event)) break;   /* event has been processed */
  267.     if (PSCheckEvent  (event)) break;   /* event has been processed */
  268.  
  269. #ifdef HAVE_JPEG
  270.     if (JPEGCheckEvent(event)) break;   /* event has been processed */
  271. #endif
  272.  
  273. #ifdef HAVE_TIFF
  274.     if (TIFFCheckEvent(event)) break;   /* event has been processed */
  275. #endif
  276.  
  277.     if (GamCheckEvent (event)) break;   /* event has been processed */
  278.  
  279.     /* if the window doesn't do intelligent redraw, drop all-1 exposes */
  280.     if (exp_event->count>0 && exp_event->window != mainW 
  281.                        && exp_event->window != ctrlW
  282.                        && exp_event->window != dirW
  283.                        && exp_event->window != infoW) break;
  284.  
  285.     if (win == mainW) {
  286.       if (DEBUG) fprintf(stderr,"EXPOSE:  ");
  287.       if (!CheckForConfig()) {
  288.     if (DEBUG) fprintf(stderr,"No configs. Expose %d,%d %dx%d\n",x,y,w,h);
  289.     if (DEBUG) XClearArea(theDisp, mainW, x,y,w,h, False);
  290.  
  291.     DrawWindow(x,y,w,h);
  292.         
  293.     if (but[BCROP].active) {
  294.       XRectangle xr;
  295.       xr.x = x;  xr.y = y;  xr.width = w;  xr.height = h;
  296.       
  297.       XSetClipRectangles(theDisp,theGC,0,0,&xr,1,Unsorted);
  298.       InvCropRect();
  299.       XSetClipMask(theDisp,theGC,None);
  300.     }
  301.  
  302.     if (exp_event->count == 0) {
  303.       canstartwait = 1;  /* finished drawing */
  304.       XSync(theDisp, False);
  305.     }
  306.       }
  307.       else
  308.     if (DEBUG) 
  309.       fprintf(stderr,"Ignoring expose event.  Config pending\n");
  310.     }
  311.  
  312.     else if (win == infoW)          RedrawInfo(x,y,w,h);
  313.     else if (win == ctrlW)          RedrawCtrl(x,y,w,h);
  314.     else if (win == nList.win)      LSRedraw(&nList);
  315.     else if (win == nList.scrl.win) SCRedraw(&nList.scrl);
  316.     else if (win == dirW)           RedrawDirW(x,y,w,h);
  317.     else if (win == dList.win)      LSRedraw(&dList);
  318.     else if (win == dList.scrl.win) SCRedraw(&dList.scrl);
  319.     else if (win == dnamW)          RedrawDNamW();
  320.   }      
  321.     break;
  322.     
  323.  
  324.   case ButtonPress: {
  325.     XButtonEvent *but_event = (XButtonEvent *) event;
  326.     int i,x,y;
  327.     Window win;
  328.  
  329.     win = but_event->window;
  330.     x = but_event->x;  y = but_event->y;
  331.  
  332.     if (win == mainW && !useroot && showzoomcursor) {
  333.       DoZoom(x, y, but_event->button);
  334.       break;
  335.     }
  336.  
  337.     if (PUCheckEvent  (event)) break;
  338.     if (PSCheckEvent  (event)) break;
  339.  
  340. #ifdef HAVE_JPEG
  341.     if (JPEGCheckEvent(event)) break;
  342. #endif
  343.  
  344. #ifdef HAVE_TIFF
  345.     if (TIFFCheckEvent(event)) break;
  346. #endif
  347.  
  348.     if (GamCheckEvent (event)) break;
  349.  
  350.     switch (but_event->button) {
  351.  
  352.     case Button1:  
  353.       if      (win == mainW) TrackPicValues(x,y);
  354.  
  355.       else if (win == ctrlW) {
  356.     int   w,h;
  357.  
  358.     if (MBClick(&dispMB, x,y)) {
  359.       if (MBTrack(&dispMB)) HandleDispMode();
  360.       break;
  361.     }
  362.  
  363.     if (MBClick(&conv24MB, x,y)) {
  364.       if (MBTrack(&conv24MB)) { conv24 = conv24MB.selected; }
  365.       break;
  366.     }
  367.  
  368.     i=ClickCtrl(x,y);
  369.  
  370.     switch (i) {
  371.     case BNEXT:   retval= NEXTPIC;  done=1;  break;
  372.     case BPREV:   retval= PREVPIC;  done=1;  break;
  373.     case BLOAD:   DirBox(BLOAD);    break;
  374.     case BSAVE:   DirBox(BSAVE);    break;
  375.     case BQUIT:   retval= QUIT;     done=1;  break;
  376.         
  377.     case BCROP:   DoCrop();  break;
  378.     case BUNCROP: UnCrop();  break;
  379.     case BNORM:   WResize(cWIDE/normFact, cHIGH/normFact);  break;
  380.     case BMAX:    WMaximize();  break;
  381.     case BUP10:   w = (eWIDE*11)/10;  h = (eHIGH*11)/10;
  382.                   if (w==eWIDE) w++;
  383.                   if (h==eHIGH) h++;
  384.                   WResize(w,h);
  385.                   break;
  386.  
  387.     case BDN10:   WResize((eWIDE*9)/10, (eHIGH*9)/10);  break;
  388.     case BUP2:    WResize(eWIDE*2, eHIGH*2);  break;
  389.     case BDN2:    WResize(eWIDE/2, eHIGH/2);  break;
  390.     case B4BY3:   w = eWIDE;  h = (w * 3) / 4;
  391.                       if (h>maxHIGH) { h = eHIGH;  w = (h*4)/3; }
  392.                       WResize(w,h);
  393.                       break;
  394.  
  395.     case BASPECT: FixAspect(1,&w,&h);  WResize(w,h);  break;
  396.     case BMAXPECT: { int w1,h1;
  397.              w1 = eWIDE;  h1 = eHIGH;
  398.              eWIDE = dispWIDE;  eHIGH = dispHIGH;
  399.              FixAspect(0,&w,&h);
  400.              eWIDE = w1;  eHIGH = h1;  /* play it safe */
  401.              WResize(w,h);
  402.                }   break;
  403.  
  404.     case BROTL:   Rotate(1);  break;
  405.     case BROTR:   Rotate(0);  break;
  406.  
  407.     case BACROP:  AutoCrop();  break;
  408.  
  409.     case BFLIPH:  Flip(0);   break;
  410.     case BFLIPV:  Flip(1);   break;
  411.     case BSMOOTH: Smooth();  break; 
  412.     case BDITH:   ColorDither(NULL, eWIDE, eHIGH);  break;
  413.     case BRAW:    xvDestroyImage(theImage);
  414.               theImage = NULL;
  415.               Resize(eWIDE,eHIGH);
  416.               break;
  417.  
  418.     case BINFO:   InfoBox(!infoUp); break;
  419.     case BGAMMA:  GamBox(!gamUp);   break;
  420.  
  421.     case BDELETE: if (DeleteCmd()) { done = 1;  retval = DELETE; }
  422.                   break;
  423.  
  424.     case BGRAB:   if (Grab()) { done = 1;  retval = GRABBED; }
  425.                   break;
  426.  
  427.     default:      break;
  428.     }
  429.  
  430.     if (i==BFLIPH || i==BFLIPV || i==BSMOOTH || i==BDITH || i==BRAW) {
  431.       if (useroot) MakeRootPic();
  432.               else DrawWindow(0,0,eWIDE,eHIGH);
  433.       if (but[BCROP].active) InvCropRect();
  434.       SetCursors(-1);
  435.     }
  436.       }
  437.  
  438.       else if (win == nList.win) {
  439.     i=LSClick(&nList,but_event);
  440.     if (i>=0) { done = 1;  retval = i; }
  441.       }
  442.  
  443.       else if (win == nList.scrl.win) SCTrack(&nList.scrl, x, y);
  444.  
  445.       else if (win == dirW) {
  446.     i=ClickDirW(x,y);
  447.         
  448.     switch (i) {
  449.     case S_BOK:   if (dirUp == BLOAD) {
  450.                     retval = LOADPIC;
  451.                 done=1;
  452.               }
  453.                   else if (dirUp == BSAVE) {
  454.                 DoSave();
  455.               }
  456.                   break;
  457.  
  458.     case S_BCANC: DirBox(0);  break;
  459.  
  460.     case S_BRESCAN:
  461.                   WaitCursor();  LoadCurrentDirectory();  SetCursors(-1);
  462.                   break;
  463.     }
  464.       }
  465.  
  466.       else if (win == dList.win) {
  467.     i=LSClick(&dList,but_event);
  468.     SelectDir(i);
  469.       }
  470.  
  471.       else if (win == dList.scrl.win) SCTrack(&dList.scrl, x,y);
  472.       else if (win == infoW)          InfoBox(0);  /* close info */
  473.  
  474.       break;
  475.  
  476.  
  477.     case Button2:  if (win == mainW) TrackCrop(x,y);
  478.                    break;
  479.  
  480.     case Button3:  /* if using root, MUST NOT get rid of ctrlbox. */
  481.                if (!useroot) CtrlBox(!ctrlUp); 
  482.                    break;
  483.  
  484.     default:       break;
  485.     }
  486.   }
  487.     break;
  488.  
  489.     
  490.   case KeyRelease: {
  491.     XKeyEvent *key_event = (XKeyEvent *) event;
  492.     char buf[128];  KeySym ks;
  493.     int stlen, dealt, shift;
  494.     
  495.     stlen = XLookupString(key_event,buf,128,&ks,(XComposeStatus *) NULL);
  496.     dealt = 0;
  497.  
  498.     if (key_event->window == mainW &&
  499.     (ks == XK_Control_L || ks == XK_Control_R)) {
  500.       if (showzoomcursor) {
  501.     showzoomcursor = 0;
  502.     SetCursors(-1);
  503.       }
  504.     }
  505.   }
  506.     break;
  507.  
  508.   case KeyPress: {
  509.     XKeyEvent *key_event = (XKeyEvent *) event;
  510.     char buf[128];  KeySym ks;
  511.     int stlen, dealt, shift;
  512.     
  513.     stlen = XLookupString(key_event,buf,128,&ks,(XComposeStatus *) NULL);
  514.     dealt = 0;
  515.  
  516.     if (PUCheckEvent  (event)) break;
  517.     if (PSCheckEvent  (event)) break;
  518.  
  519.     if (key_event->window == mainW &&
  520.     (ks == XK_Control_L || ks == XK_Control_R)) {
  521.       if (!showzoomcursor) {
  522.     showzoomcursor = 1;
  523.     SetCursors(-1);
  524.       }
  525.     }
  526.  
  527. #ifdef HAVE_JPEG
  528.     if (JPEGCheckEvent(event)) break;
  529. #endif
  530.  
  531. #ifdef HAVE_TIFF
  532.     if (TIFFCheckEvent(event)) break;
  533. #endif
  534.  
  535.     if (GamCheckEvent (event)) break;
  536.  
  537.     /* check for crop rect keys */
  538.     if (key_event->window == mainW  /*  && !dirUp */) {
  539.       dealt = 1;  shift = key_event->state & ShiftMask;
  540.       if      (ks==XK_Left  || ks==XK_KP_4 || ks==XK_F30) CropKey(-1, 0,shift);
  541.       else if (ks==XK_Right || ks==XK_KP_6 || ks==XK_F32) CropKey( 1, 0,shift);
  542.       else if (ks==XK_Up    || ks==XK_KP_8 || ks==XK_F28) CropKey( 0,-1,shift);
  543.       else if (ks==XK_Down  || ks==XK_KP_2 || ks==XK_F34) CropKey( 0, 1,shift);
  544.       else dealt = 0;
  545.       if (dealt) break;
  546.     }
  547.  
  548.  
  549.     /* check for List keys */
  550.     if (key_event->window == ctrlW || key_event->window == dirW /*||dirUp*/) {
  551.       LIST *theList;
  552.  
  553.       if (key_event->window == dirW /*|| dirUp*/) theList = &dList;
  554.       else theList = &nList;
  555.  
  556.       dealt = 1;
  557.       if      (ks==XK_Prior) LSKey(theList,LS_PAGEUP);
  558.       else if (ks==XK_Next)  LSKey(theList,LS_PAGEDOWN);
  559.       else if (ks==XK_Up)    LSKey(theList,LS_LINEUP);
  560.       else if (ks==XK_Down)  LSKey(theList,LS_LINEDOWN);
  561.       else if (ks==XK_Home)  LSKey(theList,LS_HOME);
  562.       else if (ks==XK_End)   LSKey(theList,LS_END);
  563.       else dealt = 0;
  564.  
  565.       if (theList == &dList && dealt) {  /* changed dir selection */
  566.     SelectDir(-1);  /* nothing was double-clicked */
  567.       }
  568.       
  569.       if (dealt) break;
  570.     }
  571.  
  572.     /* check dir filename arrows */
  573.     if (key_event->window == dirW && ks==XK_Left)  { DirKey('\002'); break; }
  574.     if (key_event->window == dirW && ks==XK_Right) { DirKey('\006'); break; }
  575.  
  576.  
  577.     if (!stlen) break;
  578.  
  579.     /* if dirUp, send all keystrokes to it OR NOT */
  580.     if (key_event->window == dirW /* || dirUp */) {
  581.       if (DirKey(buf[0])) XBell(theDisp,0);
  582.     }
  583.  
  584.     else {
  585.       /* commands valid in any window */
  586.       
  587.       switch (buf[0]) {
  588.       case '\t':
  589.       case ' ':    FakeButtonPress(&but[BNEXT]);    break;
  590.  
  591.       case '\r':
  592.       case '\n':   if (nList.selected >= 0 && nList.selected < nList.nstr) {
  593.                  done = 1;  retval = nList.selected; 
  594.            }
  595.                break;
  596.  
  597.       case '\010':
  598.       case '\177': FakeButtonPress(&but[BPREV]);    break;
  599.  
  600.       case '\004': FakeButtonPress(&but[BDELETE]);  break;  /* ^D */
  601.       case '\014': FakeButtonPress(&but[BLOAD]);    break;  /* ^L */
  602.       case '\023': FakeButtonPress(&but[BSAVE]);    break;  /* ^S */
  603.       case '\007': FakeButtonPress(&but[BGRAB]);    break;  /* ^G */
  604.  
  605.       case 'q':    FakeButtonPress(&but[BQUIT]);    break;
  606.     
  607.       case '?':    if (!useroot) CtrlBox(!ctrlUp);  break;
  608.  
  609.       case 's':    FakeButtonPress(&but[BSMOOTH]);  break;
  610.       case 'd':    FakeButtonPress(&but[BDITH]);    break;
  611.       case 'r':    FakeButtonPress(&but[BRAW]);     break;
  612.         
  613.       case 'a':    FakeButtonPress(&but[BASPECT]);  break;
  614.       case 'A':    FakeButtonPress(&but[BACROP]);   break;
  615.  
  616.       case 'T':    FakeButtonPress(&but[BROTL]);    break;
  617.       case 't':    FakeButtonPress(&but[BROTR]);    break;
  618.       case 'h':    FakeButtonPress(&but[BFLIPH]);   break;
  619.       case 'v':    FakeButtonPress(&but[BFLIPV]);   break;
  620.       case '4':    FakeButtonPress(&but[B4BY3]);    break;
  621.       case 'c':    FakeButtonPress(&but[BCROP]);    break;
  622.       case 'u':    FakeButtonPress(&but[BUNCROP]);  break;
  623.       case 'n':    FakeButtonPress(&but[BNORM]);    break;
  624.       case 'm':    FakeButtonPress(&but[BMAX]);     break;
  625.       case 'M':    FakeButtonPress(&but[BMAXPECT]); break;
  626.       case ',':    FakeButtonPress(&but[BDN10]);    break;
  627.       case '.':    FakeButtonPress(&but[BUP10]);    break;
  628.       case '<':    FakeButtonPress(&but[BDN2]);     break;
  629.       case '>':    FakeButtonPress(&but[BUP2]);     break;
  630.  
  631.       case 'i':    FakeButtonPress(&but[BINFO]);    break;
  632.       case 'e':    FakeButtonPress(&but[BGAMMA]);   break;
  633.  
  634.       case 'R':    FakeButtonPress(&gbut[G_BRESET]);   break;
  635.       case 'p':    FakeButtonPress(&gbut[G_BAPPLY]);   break;
  636.       case 'H':    FakeButtonPress(&gbut[G_BHISTEQ]);  break;
  637.       case 'N':    FakeButtonPress(&gbut[G_BMAXCONT]); break;
  638.  
  639.       default:     break;
  640.       }
  641.     }
  642.   }
  643.     break;
  644.     
  645.  
  646.  
  647.   case ConfigureNotify: {
  648.     XConfigureEvent *conf_event = (XConfigureEvent *) event;
  649.  
  650.     if (conf_event->window == ctrlW ||
  651.     conf_event->window == gamW  ||
  652.     conf_event->window == infoW ||
  653.     conf_event->window == mainW ||
  654.     conf_event->window == dirW) {
  655.       XSizeHints hints;
  656.       if (DEBUG) fprintf(stderr,"got configure event.  %d,%d %dx%d\n",
  657.           conf_event->x, conf_event->y, conf_event->width,
  658.           conf_event->height);
  659.  
  660.       /* if there's a virtual window manager running (e.g. tvtwm), 
  661.      we're going to get 'conf_event' values in terms of the 
  662.      'real' root window (the one that is the size of the screen).
  663.      We'll want to translate them into values that are in terms of
  664.      the 'virtual' root window (the 'big' one) */
  665.  
  666.       if (vrootW != rootW) { /* virtual window manager running */
  667.     int x1,y1;
  668.     Window child;
  669.     XTranslateCoordinates(theDisp, rootW, vrootW, 
  670.                   conf_event->x, conf_event->y, 
  671.                   &x1, &y1, &child);
  672.     if (DEBUG) fprintf(stderr,"  conf translate:  -> %d,%d\n", x1,y1);
  673.     conf_event->x = x1;  conf_event->y = y1;
  674.       }
  675.  
  676. #ifndef VMS
  677.       /* read hints for this window and adjust any position hints */
  678.       if (XGetNormalHints(theDisp, conf_event->window, &hints)) {
  679.     if (DEBUG) fprintf(stderr,"  got hints (0x%x  %d,%d)\n",
  680.         hints.flags, hints.x, hints.y);
  681.     hints.x = conf_event->x;
  682.     hints.y = conf_event->y;
  683.     XSetNormalHints(theDisp, conf_event->window, &hints);
  684.     if (DEBUG) fprintf(stderr,"  set hints (0x%x  %d,%d)\n",
  685.         hints.flags, hints.x, hints.y);
  686.       }
  687. #endif
  688.     }
  689.  
  690.  
  691.     if (conf_event->window == mainW) {
  692.       if (!rotatesLeft) {
  693.     if (DEBUG) fprintf(stderr,"CONFIG: (%d,%d %dx%d) ", 
  694.                conf_event->x, conf_event->y,
  695.                conf_event->width, conf_event->height);
  696.  
  697.     if (CheckForConfig()) {
  698.       if (DEBUG) fprintf(stderr,"more configs pending.  ignored\n");
  699.     }
  700.     else {
  701.       XEvent xev;
  702.       if (DEBUG) fprintf(stderr,"No configs pend.");
  703.       
  704.       if (conf_event->width == eWIDE && conf_event->height == eHIGH) {
  705.         if (DEBUG) fprintf(stderr,"No redraw\n");
  706.       }
  707.       else {
  708.         if (DEBUG) fprintf(stderr,"Do full redraw\n");
  709.         Resize(conf_event->width, conf_event->height);
  710.         
  711.         /* eat any pending expose events and do a full redraw */
  712.         while (XCheckTypedWindowEvent(theDisp, mainW, Expose, &xev)) {
  713.           XExposeEvent *exp = (XExposeEvent *) &xev;
  714.           if (DEBUG) 
  715.         fprintf(stderr,"  ate expose (%s) (count=%d) %d,%d %dx%d\n",
  716.             exp->send_event ? "program" : "user", exp->count,
  717.             exp->x, exp->y, exp->width, exp->height);
  718.         }
  719.  
  720.         DrawWindow(0,0,conf_event->width, conf_event->height);
  721.             canstartwait=1;
  722.         XSync(theDisp, False);
  723.         SetCursors(-1);
  724.       }
  725.     }
  726.       }
  727.  
  728.       if (rotatesLeft>0) rotatesLeft--;
  729.       if (!rotatesLeft) SetCursors(-1);
  730.     }
  731.  
  732.   }
  733.     break;
  734.     
  735.  
  736.     
  737.   case CirculateNotify:
  738.   case DestroyNotify:
  739.   case GravityNotify:       break;
  740.  
  741.   case MapNotify: {
  742.     XMapEvent *map_event = (XMapEvent *) event;
  743.  
  744.     if (map_event->window == mainW ||
  745.     (map_event->window == ctrlW && dispMB.selected != 0)) {
  746.       if (DEBUG) fprintf(stderr,"map event received on mainW/ctrlW\n");
  747.  
  748.       if (autoclose) {
  749.     if (wasInfoUp) { InfoBox(wasInfoUp);     wasInfoUp=0; }
  750.     if (wasCtrlUp) { CtrlBox(wasCtrlUp);     wasCtrlUp=0; }
  751.     if (wasDirUp)  { DirBox(wasDirUp);       wasDirUp=0; }
  752.     if (wasGamUp)  { GamBox(wasGamUp);       wasGamUp=0; }
  753.     if (wasPsUp)   { PSDialog(wasPsUp);      wasPsUp=0; }
  754. #ifdef HAVE_JPEG
  755.     if (wasJpegUp) { JPEGDialog(wasJpegUp);  wasJpegUp=0; }
  756. #endif
  757.  
  758. #ifdef HAVE_TIFF
  759.     if (wasTiffUp) { TIFFDialog(wasTiffUp);  wasTiffUp=0; }
  760. #endif
  761.       }
  762.     }
  763.   }
  764.     break;
  765.  
  766.  
  767.   case UnmapNotify: {
  768.     XUnmapEvent *unmap_event = (XUnmapEvent *) event;
  769.  
  770.     if (unmap_event->window == mainW ||
  771.     (unmap_event->window == ctrlW && dispMB.selected != 0)) {
  772.       if (DEBUG) fprintf(stderr,"unmap event received on mainW/ctrlW\n");
  773.       if (DEBUG) fprintf(stderr,"dispMB.selected = %d\n", dispMB.selected);
  774.  
  775.       /* don't do it if we've just switched to a root mode */
  776.       if ((unmap_event->window == mainW && dispMB.selected == 0) ||
  777.       (unmap_event->window == ctrlW && dispMB.selected != 0)) {  
  778.  
  779.     if (autoclose) {
  780.       if (unmap_event->window == mainW) {
  781.         if (ctrlUp) { wasCtrlUp = ctrlUp;  CtrlBox(0); }
  782.       }
  783.  
  784.       if (infoUp) { wasInfoUp = infoUp;  InfoBox(0); }
  785.       if (dirUp)  { wasDirUp  = dirUp;   DirBox(0); }
  786.       if (gamUp)  { wasGamUp  = gamUp;   GamBox(0); }
  787.       if (psUp)   { wasPsUp   = psUp;    PSDialog(0); }
  788. #ifdef HAVE_JPEG
  789.       if (jpegUp) { wasJpegUp = jpegUp;  JPEGDialog(0); }
  790. #endif
  791.  
  792. #ifdef HAVE_TIFF
  793.       if (tiffUp) { wasTiffUp = tiffUp;  TIFFDialog(0); }
  794. #endif
  795.     }
  796.       }
  797.     }
  798.   }
  799.     break;
  800.  
  801.   case ReparentNotify: {
  802.     XReparentEvent *reparent_event = (XReparentEvent *) event;
  803.  
  804.     if (DEBUG) {
  805.       fprintf(stderr,"Reparent: mainW=%x ->win=%x ->ev=%x  ->parent=%x  ", 
  806.           mainW, reparent_event->window, reparent_event->event, 
  807.           reparent_event->parent);
  808.       fprintf(stderr,"%d,%d\n", reparent_event->x, reparent_event->y);
  809.     }
  810.  
  811.     if (reparent_event->window == mainW) {
  812.       ch_offx = reparent_event->x;  /* offset required for ChangeAttr call */
  813.       ch_offy = reparent_event->y;
  814.  
  815.       p_offx = p_offy = 0;          /* topleft correction for WMs titlebar */
  816.  
  817.       if (ch_offx == 0 && ch_offy == 0) {  
  818.     /* looks like the user is running MWM or OLWM */
  819.  
  820.     XWindowAttributes xwa;
  821.  
  822.     /* first query the attributes of mainW.  x,y should be the offset
  823.        from the parent's topleft corner to the windows topleft.
  824.        OLWM puts the info here */
  825.  
  826.     XSync(theDisp, False);
  827.     XGetWindowAttributes(theDisp, mainW, &xwa);
  828.     
  829.     if (DEBUG) 
  830.       fprintf(stderr,"XGetAttr: mainW %d,%d %dx%d\n", xwa.x, xwa.y,
  831.           xwa.width, xwa.height);
  832.  
  833.     if (xwa.x == 0 && xwa.y == 0) {
  834.       /* MWM, at least mine, puts 0's in those fields.  To get the
  835.          info, we'll have to query the parent window */
  836.  
  837.       XSync(theDisp, False);
  838.       XGetWindowAttributes(theDisp, reparent_event->parent, &xwa);
  839.     
  840.       if (DEBUG) 
  841.         fprintf(stderr,"XGetAttr: parent %d,%d %dx%d\n", xwa.x, xwa.y,
  842.             xwa.width, xwa.height);
  843.     }
  844.     else {
  845.       /* KLUDGE:  if we're running olwm, xwa.{x,y} won't be 0,0.
  846.          in olwm, the window drifts down and right each time
  847.          SetWindowPos() is called.  God knows why.  Anyway, I'm
  848.          inserting a kludge here to increase 'ch_offx' and 'ch_offy'
  849.          by bwidth so that this drifting won't happen.  No doubt this'll
  850.          screw up behavior on some *other* window manager, but it should
  851.          work with TWM, OLWM, and MWM (the big three) */
  852.       ch_offx += bwidth;
  853.       ch_offy += bwidth;
  854.     }
  855.  
  856.     p_offx = xwa.x;
  857.     p_offy = xwa.y;
  858.       }
  859.     }
  860.   }
  861.     break;
  862.     
  863.  
  864.   case EnterNotify:
  865.   case LeaveNotify: {
  866.     XCrossingEvent *cross_event = (XCrossingEvent *) event;
  867.     if (cross_event->window == mainW || 0
  868.     /* (cross_event->window == gamW && cmapInGam) */ ) {
  869.  
  870.       if (cross_event->type == EnterNotify && cross_event->window == mainW) {
  871.     if (cross_event->state & ControlMask) {  /* ctrl pressed */
  872.       if (!showzoomcursor) {
  873.         showzoomcursor = 1;
  874.         SetCursors(-1);
  875.       }
  876.     }
  877.     else {
  878.       if (showzoomcursor) {
  879.         showzoomcursor = 0;
  880.         SetCursors(-1);
  881.       }
  882.     }
  883.       }
  884.  
  885.  
  886.       if (cross_event->type == EnterNotify && LocalCmap && !ninstall) 
  887.     XInstallColormap(theDisp,LocalCmap);
  888.  
  889.       if (cross_event->type == LeaveNotify && LocalCmap && !ninstall) 
  890.     XUninstallColormap(theDisp,LocalCmap);
  891.     }
  892.   }
  893.     break;
  894.     
  895.     
  896.   default: break;        /* ignore unexpected events */
  897.   }  /* switch */
  898.  
  899.   *donep = done;
  900.   return(retval);
  901. }
  902.  
  903.  
  904.  
  905. /***********************************/
  906. void DrawWindow(x,y,w,h)
  907. int x,y,w,h;
  908. {
  909.   if (x+w < eWIDE) w++;  /* add one for broken servers (?) */
  910.   if (y+h < eHIGH) h++;
  911.  
  912.   if (theImage)
  913.     XPutImage(theDisp,mainW,theGC,theImage,x,y,x,y,w,h);
  914.   else 
  915.     if (DEBUG) fprintf(stderr,"Tried to DrawWindow when theImage was NIL\n");
  916. }
  917.  
  918.  
  919. /***********************************/
  920. void WResize(w,h)
  921. int w,h;
  922. {
  923.   XWindowAttributes xwa;
  924.  
  925.   RANGE(w,1,maxWIDE);  RANGE(h,1,maxHIGH);
  926.  
  927.   if (useroot) {
  928.     Resize(w,h);
  929.     MakeRootPic();
  930.     SetCursors(-1);
  931.     return;
  932.   }
  933.  
  934.   /* determine if new size goes off edge of screen.  if so move window so it
  935.      doesn't go off screen */
  936.  
  937.   GetWindowPos(&xwa);
  938.   if (xwa.x + w > vrWIDE) xwa.x = vrWIDE - w;
  939.   if (xwa.y + h > vrHIGH) xwa.y = vrHIGH - h;
  940.  
  941.   if (DEBUG) fprintf(stderr,"%s: resizing window to %d,%d at %d,%d\n",
  942.              cmd,w,h,xwa.x,xwa.y);
  943.  
  944.   /* resize the window */
  945.   xwa.width = w;  xwa.height = h;
  946.  
  947.   SetWindowPos(&xwa);
  948. }
  949.  
  950.  
  951.  
  952.  
  953. /***********************************/
  954. static void WMaximize()
  955. {
  956.   if (useroot) WResize(dispWIDE, dispHIGH);
  957.   else {
  958.     XWindowAttributes xwa;
  959.     bzero((char *) &xwa, sizeof(XWindowAttributes));
  960.     xwa.x = xwa.y = 0;
  961.     xwa.width  = dispWIDE;  
  962.     xwa.height = dispHIGH;
  963.     SetWindowPos(&xwa);
  964.   }
  965. }
  966.  
  967.  
  968.  
  969.  
  970. /***********************************/
  971. void WRotate()
  972. {
  973.   /* rotate the window and redraw the contents  */
  974.  
  975.   if (but[BCROP].active) BTSetActive(&but[BCROP],0);
  976.   if (useroot) {
  977.     MakeRootPic();
  978.     SetCursors(-1);
  979.     return;
  980.   }
  981.  
  982.   if (eWIDE == eHIGH) {     /* no configure events will be gen'd */
  983.     Resize(eWIDE, eHIGH);   /* to regen Ximage */
  984.     DrawWindow(0, 0, eWIDE, eHIGH);
  985.     SetCursors(-1);
  986.   }
  987.   else {
  988.     rotatesLeft++;
  989.     XClearWindow(theDisp, mainW);  /* get rid of old bits */
  990.     GenExpose(mainW, 0, 0, eWIDE, eHIGH);
  991.     WResize(eWIDE, eHIGH);
  992.   }
  993. }
  994.  
  995.  
  996. /***********************************/
  997. void WCrop(w,h)
  998. int w,h;
  999. {
  1000.   XWindowAttributes xwa;
  1001.  
  1002.   if (useroot) {
  1003.     MakeRootPic();
  1004.     SetCursors(-1);
  1005.   }
  1006.  
  1007.   else {
  1008.     /* we want to move window to old x,y + crx1,cry1 */
  1009.     GetWindowPos(&xwa);
  1010.   
  1011.     if (!origcropvalid) {  /* first crop.  remember win pos */
  1012.       origcropvalid = 1;
  1013.       origcropx = xwa.x;
  1014.       origcropy = xwa.y;
  1015.     }
  1016.  
  1017.     xwa.x += crx1;  xwa.y += cry1;
  1018.     xwa.width = w;  xwa.height = h;
  1019.     GenExpose(mainW, 0, 0, eWIDE, eHIGH);
  1020.     SetWindowPos(&xwa);
  1021.   }
  1022. }
  1023.  
  1024.  
  1025. /***********************************/
  1026. void WUnCrop()
  1027. {
  1028.   int w,h;
  1029.   XWindowAttributes xwa;
  1030.  
  1031.   /* a proper epic has been generated.  eWIDE,eHIGH are the new window size */
  1032.  
  1033.  
  1034.   if (useroot) {
  1035.     MakeRootPic();
  1036.     SetCursors(-1);
  1037.   }
  1038.  
  1039.   else {   /* !useroot */
  1040.     GetWindowPos(&xwa);
  1041.  
  1042.     w = eWIDE;  h = eHIGH;
  1043.  
  1044.     /* restore to position when originally cropped */
  1045.     if (origcropvalid) {  /* *should* always be true... */
  1046.       origcropvalid = 0;
  1047.       xwa.x = origcropx;
  1048.       xwa.y = origcropy;
  1049.     }
  1050.  
  1051.     if (xwa.x + w > vrWIDE) xwa.x = vrWIDE - w;   /* keep on screen */
  1052.     if (xwa.y + h > vrHIGH) xwa.y = vrHIGH - h;
  1053.  
  1054.     if (xwa.x<0) xwa.x = 0;
  1055.     if (xwa.y<0) xwa.y = 0;
  1056.     xwa.width = w;  xwa.height = h;
  1057.     
  1058.     if (!useroot) {
  1059.       SetWindowPos(&xwa);
  1060.       GenExpose(mainW, 0, 0, eWIDE, eHIGH);
  1061.     }
  1062.   }
  1063. }
  1064.  
  1065.  
  1066.  
  1067. /***********************************/
  1068. void GetWindowPos(xwa)
  1069. XWindowAttributes *xwa;
  1070. {
  1071.   Window child;
  1072.   
  1073.   /* returns the x,y,w,h coords of mainW.  x,y are relative to rootW 
  1074.      the border is not included (x,y map to top-left pixel in window) */
  1075.  
  1076.   /* Get the window width/height */
  1077.   XGetWindowAttributes(theDisp,mainW,xwa);
  1078.  
  1079.   /* Get the window origin */
  1080.   XTranslateCoordinates(theDisp,mainW,rootW,0,0,&xwa->x,&xwa->y,&child);
  1081. }
  1082.  
  1083.  
  1084. /***********************************/
  1085. void SetWindowPos(xwa)
  1086. XWindowAttributes *xwa;
  1087. {
  1088.   /* sets window x,y,w,h values */
  1089.   XWindowChanges    xwc;
  1090.  
  1091.   /* Adjust from window origin, to border origin */
  1092.   xwc.x = xwa->x - xwa->border_width - ch_offx;
  1093.   xwc.y = xwa->y - xwa->border_width - ch_offy;
  1094.  
  1095.   if (!xwa->border_width) xwa->border_width = bwidth;
  1096.   xwc.border_width = xwa->border_width;
  1097.  
  1098.   /* if we're less than max size in one axis, allow window manager doohickeys
  1099.      on the screen */
  1100.   
  1101.   if (xwa->width  < dispWIDE && xwc.x < p_offx) xwc.x = p_offx;
  1102.   if (xwa->height < dispHIGH && xwc.y < p_offy) xwc.y = p_offy;
  1103.  
  1104.   xwc.width  = xwa->width;
  1105.   xwc.height = xwa->height;
  1106.  
  1107.   if (DEBUG) {
  1108.     fprintf(stderr,"SWP: xwa=%d,%d %dx%d  xwc=%d,%d %dx%d  off=%d,%d bw=%d\n",
  1109.         xwa->x, xwa->y, xwa->width, xwa->height,
  1110.         xwc.x, xwc.y, xwc.width, xwc.height, p_offx, p_offy, 
  1111.         xwa->border_width);
  1112.   }
  1113.  
  1114. #ifdef DXWM  /* dxwm seems to *only* pay attention to the hints */
  1115.   {
  1116.     XSizeHints hints;
  1117.     if (DEBUG) fprintf(stderr,"SWP: doing the DXWM thing\n");
  1118.     /* read hints for this window and adjust any position hints */
  1119.     if (XGetNormalHints(theDisp, mainW, &hints)) {
  1120.       hints.flags |= USPosition | USSize;
  1121.       hints.x = xwc.x;  hints.y = xwc.y;
  1122.       hints.width = xwc.width; hints.height = xwc.height;
  1123.       XSetNormalHints(theDisp, mainW, &hints);
  1124.     }
  1125.  
  1126.     xwc.x -= 5;   xwc.y -= 25;    /* EVIL KLUDGE */
  1127.   }
  1128. #endif
  1129.  
  1130.   /* all non-DXWM window managers (?) */
  1131.   /* Move/Resize the window. */
  1132.   XConfigureWindow(theDisp, mainW, 
  1133.            CWX | CWY | CWWidth | CWHeight /*| CWBorderWidth*/, &xwc);
  1134. }
  1135.  
  1136.  
  1137. /***********************************/
  1138. static void TrackCrop(mx,my)
  1139. int mx,my;
  1140. {
  1141.   Window       rW,cW;
  1142.   int          rx,ry,ox,oy,x,y,active;
  1143.   unsigned int mask;
  1144.  
  1145.   if (but[BCROP].active) {             /* turn off old cropping rectangle */
  1146.     XSetFunction(theDisp,theGC,GXinvert);
  1147.     Rect(crx1,cry1,crx2,cry2);
  1148.     XSetFunction(theDisp,theGC,GXcopy);
  1149.   }
  1150.   active = 0;
  1151.   SetCropString(active);
  1152.  
  1153.   crx1 = ox = mx;  cry1 = oy = my;         /* nail down one corner */
  1154.  
  1155.   while (1) {
  1156.     if (XQueryPointer(theDisp,mainW,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
  1157.       if (!(mask & Button2Mask)) break;    /* button released */
  1158.  
  1159.       if (x!=ox || y!=oy) {                /* moved.  erase and redraw */
  1160.     crx2 = x;  cry2 = y;
  1161.     XSetFunction(theDisp,theGC,GXinvert);
  1162.     Rect(crx1,cry1,ox,oy);
  1163.     active = Rect(crx1,cry1,crx2,cry2);
  1164.     XSetFunction(theDisp,theGC,GXcopy);
  1165.     XFlush(theDisp);
  1166.     ox=crx2;  oy=cry2;
  1167.     if (infoUp) SetCropString(active);
  1168.       }
  1169.     }
  1170.   }
  1171.  
  1172.   RANGE(crx1,0,eWIDE);  RANGE(cry1,0,eHIGH);
  1173.   RANGE(crx2,0,eWIDE);  RANGE(cry2,0,eHIGH);
  1174.   BTSetActive(&but[BCROP],active);
  1175.   SetCropString(active);
  1176. }
  1177.  
  1178.  
  1179. /***********************************/
  1180. static void CropKey(dx,dy,grow)
  1181. int dx,dy,grow;
  1182. {
  1183.   int x1,x2,y1,y2,active;
  1184.  
  1185.   if (!but[BCROP].active) return;
  1186.  
  1187.   /* x1,y1 = top-left,  x2,y2 = bot-right */
  1188.   if (crx1<crx2) { x1=crx1;  x2=crx2; }   else { x1=crx2;  x2=crx1; }
  1189.   if (cry1<cry2) { y1=cry1;  y2=cry2; }   else { y1=cry2;  y2=cry1; }
  1190.  
  1191.   if (!grow) {    /* move the rectangle */
  1192.     x1 += dx;  x2 += dx;  y1 += dy;  y2 += dy;
  1193.     if (x1<0 || x2>=eWIDE) { x1 -= dx;  x2 -= dx; }
  1194.     if (y1<0 || y2>=eHIGH) { y1 -= dy;  y2 -= dy; }
  1195.   }
  1196.   else {          /* grow the rectangle, pref. keeping top-left anchored */
  1197.     x2 += dx;  y2 += dy;
  1198.     if (x2>=eWIDE) { 
  1199.       x1 -= dx;  x2 -= dx;
  1200.       if (x1<0) x1=0;
  1201.     }
  1202.  
  1203.     if (y2>=eHIGH) { 
  1204.       y1 -= dy;  y2 -= dy;
  1205.       if (y1<0) y1=0;
  1206.     }
  1207.   }
  1208.     
  1209.   XSetFunction(theDisp,theGC,GXinvert);
  1210.   Rect(crx1,cry1,crx2,cry2);
  1211.   crx1 = x1;  cry1 = y1;  crx2 = x2;  cry2 = y2;
  1212.   active = Rect(crx1,cry1,crx2,cry2);
  1213.   XSetFunction(theDisp,theGC,GXcopy);
  1214.  
  1215.   BTSetActive(&but[BCROP], active);
  1216.   SetCropString(active);
  1217. }
  1218.  
  1219.   
  1220. /***********************************/
  1221. static int Rect(x,y,x1,y1)
  1222. int x,y,x1,y1;
  1223. {
  1224.   int w,h;
  1225.  
  1226.   /* returns 0 if it didn't draw anything (rect is too small), 1 if it did */
  1227.   w = abs(x-x1);  h = abs(y-y1);
  1228.   if (x>x1) x = x1;
  1229.   if (y>y1) y = y1;
  1230.  
  1231.   /* keep rectangle inside window */  
  1232.   if (x<0) { w+=x; x=0; }
  1233.   if (y<0) { h+=y; y=0; }
  1234.   if (x+w>=eWIDE) w=eWIDE-x-1;  
  1235.   if (y+h>=eHIGH) h=eHIGH-y-1;
  1236.  
  1237.   if (w<4 || h<4) return 0;   /* too small */
  1238.  
  1239.   XSetPlaneMask(theDisp, theGC, AllPlanes);
  1240.   XDrawRectangle(theDisp, mainW, theGC, x, y, w, h);
  1241.   XSetPlaneMask(theDisp, theGC, 1L);
  1242.   XDrawRectangle(theDisp, mainW, theGC, x+1, y+1, w-2, h-2);
  1243.   XSetPlaneMask(theDisp, theGC, AllPlanes);
  1244.   return 1;
  1245. }
  1246.  
  1247.  
  1248. /***********************************/
  1249. void InvCropRect()
  1250. {
  1251.   XSetFunction(theDisp,theGC,GXinvert);
  1252.   Rect(crx1,cry1,crx2,cry2);
  1253.   XSetFunction(theDisp,theGC,GXcopy);
  1254. }
  1255.  
  1256.  
  1257. /***********************************/
  1258. static void TrackPicValues(mx,my)
  1259. int mx,my;
  1260. {
  1261.   Window       rW,cW;
  1262.   int          rx,ry,ox,oy,x,y;
  1263.   unsigned int mask;
  1264.   int          ty, w, ecol;
  1265.   char         foo[64];
  1266.   unsigned long wh, bl;
  1267.   char         *str  = "8888,8888 = 123,123,123  (123,123,123 HSV)";
  1268.  
  1269.   wh = infobg;  bl = infofg;
  1270.  
  1271.   /* do a colormap search for black and white if LocalCmap 
  1272.      and use those colors instead of infobg and infofg */
  1273.   if (LocalCmap) {
  1274.     XColor ctab[256];
  1275.     int  i;
  1276.     long cval;
  1277.  
  1278.     for (i=0; i<nfcols; i++) ctab[i].pixel = freecols[i];
  1279.     XQueryColors(theDisp,LocalCmap,ctab,nfcols);
  1280.     
  1281.     /* find 'blackest' pixel */
  1282.     cval = 0x10000 * 3;
  1283.     for (i=0; i<nfcols; i++)
  1284.       if (ctab[i].red + ctab[i].green + ctab[i].blue < cval) {
  1285.     cval = ctab[i].red + ctab[i].green + ctab[i].blue;
  1286.     bl = ctab[i].pixel;
  1287.       }
  1288.  
  1289.     /* find 'whitest' pixel */
  1290.     cval = -1;
  1291.     for (i=0; i<nfcols; i++)
  1292.       if ((long)ctab[i].red + (long)ctab[i].green + (long)ctab[i].blue >cval) {
  1293.     cval = ctab[i].red + ctab[i].green + ctab[i].blue;
  1294.     wh = ctab[i].pixel;
  1295.       }
  1296.   }
  1297.  
  1298.   XSetFont(theDisp, theGC, monofont);
  1299.   w = XTextWidth(monofinfo, str, strlen(str));
  1300.  
  1301.   if (my > eHIGH/2) ty = 0;
  1302.                else ty = eHIGH-(monofinfo->ascent + mfinfo->descent)-4;
  1303.  
  1304.   ox = oy = -1;  /* kludge to force redraw first time through */
  1305.  
  1306.   XSetForeground(theDisp, theGC, bl);
  1307.   XFillRectangle(theDisp, mainW, theGC, 0, ty, w + 8, 
  1308.          (monofinfo->ascent+monofinfo->descent) + 4);
  1309.   XSetForeground(theDisp, theGC, wh);
  1310.   XSetBackground(theDisp, theGC, bl);
  1311.   foo[0] = '\0';
  1312.  
  1313.   x = mx;  y = my;
  1314.   RANGE(x,0,eWIDE-1);   RANGE(y,0,eHIGH-1);
  1315.   rx = cXOFF + (x * cWIDE) / eWIDE;
  1316.   ry = cYOFF + (y * cHIGH) / eHIGH;
  1317.   ecol = pic[ry * pWIDE + rx];
  1318.  
  1319.   while (1) {
  1320.     int px, py, pix;
  1321.  
  1322.     if (XQueryPointer(theDisp,mainW,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
  1323.       if (!(mask & Button1Mask)) break;    /* button released */
  1324.  
  1325.       RANGE(x,0,eWIDE-1);  
  1326.       RANGE(y,0,eHIGH-1);
  1327.  
  1328.       px = cXOFF + (x * cWIDE) / eWIDE;
  1329.       py = cYOFF + (y * cHIGH) / eHIGH;
  1330.  
  1331.       if (px!=ox || py!=oy) {                /* moved.  erase and redraw */
  1332.     double h1, s1, v1;
  1333.  
  1334.     ecol = pix = pic[py * pWIDE + px];
  1335.  
  1336.     rgb2hsv(rcmap[pix],gcmap[pix],bcmap[pix],&h1,&s1,&v1);
  1337.     if (h1<0.0) h1 = 0.0;   /* map 'NOHUE' to 0.0 */
  1338.  
  1339.     sprintf(foo,"%4d,%4d = %3d,%3d,%3d  (%3d %3d %3d HSV)",
  1340.         px, py, rcmap[pix],gcmap[pix],bcmap[pix], 
  1341.         (int) h1, (int) (s1 * 100), (int) (v1 * 100));
  1342.     
  1343.     XDrawImageString(theDisp,mainW,theGC, 4, ty + 2 + monofinfo->ascent, 
  1344.             foo, strlen(foo));
  1345.     ox = px;  oy = py;
  1346.       }
  1347.     }
  1348.   }
  1349.  
  1350.   if (foo[0]) {
  1351.     strcat(foo, "\n");
  1352.     XStoreBytes(theDisp, foo, strlen(foo));
  1353.   }
  1354.  
  1355.   XSetFont(theDisp, theGC, mfont);
  1356.   DrawWindow(0,ty,eWIDE,(monofinfo->ascent+monofinfo->descent)+4);
  1357.   if (ecol != editColor) ChangeEC(ecol);
  1358. }
  1359.  
  1360.  
  1361. /***********************************/
  1362. static Bool IsConfig(dpy, ev, arg)
  1363. Display *dpy;
  1364. XEvent  *ev;
  1365. char    *arg;
  1366. {
  1367.   XConfigureEvent *cev;
  1368.  
  1369.   if (ev->type == ConfigureNotify) {
  1370.     cev = (XConfigureEvent *) ev;
  1371.     if (cev->window == mainW && (cev->width != eWIDE || cev->height != eHIGH))
  1372.       *arg = 1;
  1373.   }
  1374.   return False;
  1375. }
  1376.  
  1377. /***********************************/
  1378. static int CheckForConfig()
  1379. {
  1380.   XEvent ev;
  1381.   char   foo;
  1382.  
  1383.   /* returns true if there's a config event in which mainW changes size
  1384.      in the event queue */
  1385.   
  1386.   XSync(theDisp, False);
  1387.   foo = 0;
  1388.   XCheckIfEvent(theDisp, &ev, IsConfig, &foo);
  1389.   return foo;
  1390. }
  1391.  
  1392.  
  1393. /************************************************************************/
  1394. void SetEpicMode()
  1395. {
  1396.   if (epicmode == EM_RAW) {
  1397.     BTSetActive(&but[BRAW],   0);
  1398.     BTSetActive(&but[BDITH],  (ncols>0) );  /* only enable dith if ncols>0 */
  1399.     BTSetActive(&but[BSMOOTH],1);
  1400.   }
  1401.  
  1402.   else if (epicmode == EM_DITH) {
  1403.     BTSetActive(&but[BRAW],   1);
  1404.     BTSetActive(&but[BDITH],  0);
  1405.     BTSetActive(&but[BSMOOTH],1);
  1406.   }
  1407.  
  1408.   else if (epicmode == EM_SMOOTH) {
  1409.     BTSetActive(&but[BRAW],   1);
  1410.     BTSetActive(&but[BDITH],  0);
  1411.     BTSetActive(&but[BSMOOTH],1);  /* color editing may require a re-smooth */
  1412.   }
  1413. }
  1414.  
  1415.  
  1416. /************************************************************************/
  1417. int xvErrorHandler(disp, err)
  1418. Display *disp;
  1419. XErrorEvent *err;
  1420. {
  1421.   char buf[128];
  1422.  
  1423.   XUngrabPointer(theDisp, CurrentTime);   /* in case error occurred in Grab */
  1424.  
  1425.   xerrcode = err->error_code;
  1426.  
  1427.   /* BadAlloc errors (on a XCreatePixmap() call)
  1428.      and BadAccess errors on XFreeColors are 'ignoreable' errors */
  1429.  
  1430.   if (xerrcode == BadAlloc || 
  1431.       (xerrcode == BadAccess && err->request_code==88)) return 0;
  1432.  
  1433.   else {
  1434.     /* all other errors are 'fatal' */
  1435.     XGetErrorText(disp, xerrcode, buf, 128);
  1436.     fprintf(stderr,"X Error: %s\n",buf);
  1437.     fprintf(stderr,"  Major Opcode:  %d\n",err->request_code);
  1438.     
  1439.     exit(-1);
  1440.   }
  1441.  
  1442.   return 0;
  1443. }
  1444.  
  1445.  
  1446. static void onInterrupt()
  1447. {
  1448.   /* make the interrupt signal look like a '\n' keypress in ctrlW */
  1449.   XKeyEvent ev;
  1450.  
  1451.   ev.type = KeyPress;
  1452.   ev.send_event = True;
  1453.   ev.display = theDisp;
  1454.   ev.window = ctrlW;
  1455.   ev.root = rootW;
  1456.   ev.subwindow = (Window) NULL;
  1457.   ev.time = CurrentTime;
  1458.   ev.x = ev.y = ev.x_root = ev.y_root = 0;
  1459.   ev.state = 0;
  1460.   ev.keycode = XKeysymToKeycode(theDisp, XK_Return);
  1461.   ev.same_screen = True;
  1462.   XSendEvent(theDisp, ctrlW, False, NoEventMask, (XEvent *) &ev);
  1463.   XFlush(theDisp);
  1464. }
  1465.