home *** CD-ROM | disk | FTP | other *** search
/ Fractal Frenzy 1 / WalnutCreekFractalFrenzy-1.iso / pc / viewers / x11 / xloadimg.tz / xloadimg / window.c < prev    next >
C/C++ Source or Header  |  1991-05-20  |  27KB  |  977 lines

  1. /* window.c:
  2.  *
  3.  * display an image in a window
  4.  *
  5.  * jim frost 10.03.89
  6.  *
  7.  * Copyright 1989, 1990, 1991 Jim Frost.
  8.  * See included file "copyright.h" for complete copyright information.
  9.  */
  10.  
  11. #include "copyright.h"
  12. #include "xloadimage.h"
  13. #include <ctype.h>
  14. #include <X11/cursorfont.h>
  15. #include <X11/Xatom.h>
  16. #include <signal.h>
  17. #include <errno.h>
  18. #include <sys/types.h>
  19. #ifdef _AIX
  20. #include <sys/select.h>
  21. #endif
  22.  
  23. /* SUPPRESS 560 */
  24.  
  25. static Window    ImageWindow= 0;
  26. static Window    ViewportWin= 0;
  27. static Colormap  ImageColormap;
  28.  
  29. static int AlarmWentOff = 0;
  30.  
  31. static void delayAlarmHandler()
  32. {
  33.     AlarmWentOff = 1;
  34. }
  35.  
  36. /* this is a bogus function whose only purpose is to interrupt
  37.  * the XNextEvent signal call in imageInWindow().
  38.  * This is added to allow automatic cycling through the specified list
  39.  * of pictures. The amount of wait time is specified using the -delay
  40.  * option, which is the number of seconds to pause between pictures.
  41.  * - mfc 90/10/08
  42.  */
  43.  
  44. static int getNextEventWithTimeout(disp, event)
  45.      Display      *disp;
  46.      XEvent       *event;
  47. {
  48.   fd_set rmask;
  49.   int nfound;
  50.  
  51.   /* force any output to occur before we set & spin
  52.    */
  53.  
  54.   XFlush(disp);
  55.  
  56.   /* wait for alarm
  57.    */
  58.  
  59.   while ((AlarmWentOff == 0)) {
  60.     if (XPending(disp)) {
  61.       XNextEvent(disp, event);
  62.       return(1);
  63.     }
  64.     FD_ZERO(&rmask);
  65.     FD_SET(ConnectionNumber(disp), &rmask);
  66.     nfound = select(ConnectionNumber(disp)+1, &rmask,
  67.             (fd_set *) 0, (fd_set *) 0, /*(struct timeval *)*/0);
  68.     switch (nfound) {
  69.     case -1:
  70.       if (errno == EINTR) {
  71.     continue;
  72.       } else {
  73.     perror("select");
  74.     continue;
  75.       }
  76.     }
  77.   }
  78.   return(0);
  79. }
  80.  
  81. static void setCursor(disp, window, iw, ih, ww, wh, cursor)
  82.      Display      *disp;
  83.      Window        window;
  84.      unsigned int  iw, ih;
  85.      unsigned int  ww, wh;
  86.      Cursor       *cursor;
  87. { XSetWindowAttributes swa;
  88.  
  89.   if ((ww >= iw) && (wh >= ih))
  90.     swa.cursor= XCreateFontCursor(disp, XC_icon);
  91.   else if ((ww < iw) && (wh >= ih))
  92.     swa.cursor= XCreateFontCursor(disp, XC_sb_h_double_arrow);
  93.   else if ((ww >= iw) && (wh < ih))
  94.     swa.cursor= XCreateFontCursor(disp, XC_sb_v_double_arrow);
  95.   else
  96.     swa.cursor= XCreateFontCursor(disp, XC_fleur);
  97.   XChangeWindowAttributes(disp, window, CWCursor, &swa);
  98.   XFreeCursor(disp, *cursor);
  99.   *cursor= swa.cursor;
  100. }
  101.  
  102. /* place an image
  103.  */
  104.  
  105. static void placeImage(disp, width, height, winwidth, winheight, rx, ry)
  106.      Display *disp;
  107.      int width, height, winwidth, winheight;
  108.      int *rx, *ry; /* supplied and returned */
  109. { int pixx, pixy;
  110.  
  111.   pixx= *rx;
  112.   pixy= *ry;
  113.  
  114.   if (winwidth > width)
  115.     pixx= (winwidth - width) / 2;
  116.   else {
  117.     if ((pixx < 0) && (pixx + width < winwidth))
  118.       pixx= winwidth - width;
  119.     if (pixx > 0)
  120.       pixx= 0;
  121.   }
  122.   if (winheight > height)
  123.     pixy= (winheight - height) / 2;
  124.   else {
  125.     if ((pixy < 0) && (pixy + height < winheight))
  126.       pixy= winheight - height;
  127.     if (pixy > 0)
  128.       pixy= 0;
  129.   }
  130.   *rx= pixx;
  131.   *ry= pixy;
  132.   XMoveWindow(disp, ImageWindow, pixx, pixy);
  133. }
  134.  
  135. /* blit an image
  136.  */
  137.  
  138. static void blitImage(ximageinfo, width, height,
  139.               x, y, w, h)
  140.      XImageInfo      *ximageinfo;
  141.      unsigned int  width, height;
  142.      int       x, y, w, h;
  143. {
  144.   if (w > width)
  145.     w= width;
  146.   if (h > height)
  147.     h= height;
  148.   if (x < 0) {
  149.     XClearArea(ximageinfo->disp, ximageinfo->drawable, x, y, -x, h, False);
  150.     w -= (0 - x);
  151.     x= 0;
  152.   }
  153.   if (y < 0) {
  154.     XClearArea(ximageinfo->disp, ximageinfo->drawable, x, y, w, -y, False);
  155.     h -= (0 - y);
  156.     y= 0;
  157.   }
  158.   if (x + w > width) {
  159.     XClearArea(ximageinfo->disp, ximageinfo->drawable,
  160.            x + width, y, x + w - width, h, False);
  161.     w -= x + w - width;
  162.   }
  163.   if (y + h > height) {
  164.     XClearArea(ximageinfo->disp, ximageinfo->drawable,
  165.            x, y + height, w, y + h - height, False);
  166.     h -= y + h - height;
  167.   }
  168.   sendXImage(ximageinfo, x, y, x, y, w, h);
  169. }
  170.  
  171. /* clean up static window if we're through with it
  172.  */
  173.  
  174. void cleanUpWindow(disp)
  175.      Display *disp;
  176. {
  177.   if (ImageWindow)
  178.     XDestroyWindow(disp, ImageWindow);
  179.   ImageWindow= 0;
  180.   if (ViewportWin)
  181.     XDestroyWindow(disp, ViewportWin);
  182.   ViewportWin= 0;
  183. }
  184.  
  185. /* clean up after displaying an image
  186.  */
  187.  
  188. static void cleanUpImage(disp, scrn, cursor, pixmap, image, ximageinfo)
  189.      Display      *disp;
  190.      int           scrn;
  191.      Cursor        cursor;
  192.      Pixmap        pixmap;
  193.      Image        *image;
  194.      XImageInfo      *ximageinfo;
  195. {
  196.   XFreeCursor(disp, cursor);
  197.   if (pixmap != None)
  198.       XFreePixmap(disp, pixmap);
  199.   freeXImage(image, ximageinfo);
  200. }
  201.  
  202. /* this sets the colormap and WM_COLORMAP_WINDOWS properly for the
  203.  * viewport.
  204.  */
  205.  
  206. void setViewportColormap(disp, scrn, visual)
  207.      Display *disp;
  208.      int scrn;
  209.      Visual *visual;
  210. { XSetWindowAttributes swa;
  211.   static cmap_atom= None;
  212.   Window cmap_windows[2];
  213.  
  214.   if (cmap_atom == None)
  215.     cmap_atom = XInternAtom(disp, "WM_COLORMAP_WINDOWS", False);
  216.  
  217.   /* if the visual we're using is the same as the default visual (used by
  218.    * the viewport window) then we can set the viewport window to use the
  219.    * image's colormap.  this keeps most window managers happy.
  220.    */
  221.  
  222.   if (visual == DefaultVisual(disp, scrn)) {
  223.     swa.colormap= ImageColormap;
  224.     XChangeWindowAttributes(disp, ViewportWin, CWColormap, &swa);
  225.     XDeleteProperty(disp, ViewportWin, cmap_atom);
  226.   }
  227.  
  228.   /* smart window managers can handle it when we use a different colormap
  229.    * in our subwindow so long as we set the WM_COLORMAP_WINDOWS property
  230.    * ala ICCCM.
  231.    */
  232.  
  233.   else {
  234.     cmap_windows[0]= ImageWindow;
  235.     cmap_windows[1]= ViewportWin;
  236.     XChangeProperty(disp, ViewportWin, cmap_atom, XA_WINDOW, 32,
  237.             PropModePrepend, cmap_windows, 2);
  238.   }
  239.  
  240. }
  241.  
  242. /* this attempts to convert an image title into a reasonable icon name
  243.  */
  244.  
  245. static char *iconName(s)
  246.      char *s;
  247. { static char buf[BUFSIZ];
  248.   char *t;
  249.  
  250.   if (!s)
  251.     return("Unnamed");
  252.   buf[BUFSIZ - 1]= '\0';
  253.   strncpy(buf, s, BUFSIZ - 1);
  254.   t= index(buf, ' '); /* strip off stuff following 1st word.  this strips */
  255.   if (t)              /* info added by processing functions too. */
  256.     *t= '\0';
  257.  
  258.   /* strip off leading path.  if you don't use unix-style paths, you might
  259.    * want to change this.
  260.    */
  261.  
  262.   if (t= rindex(buf, '/')) {
  263.     for (s= buf, t++; *t; s++, t++)
  264.       *s= *t;
  265.     *s= '\0';
  266.   }
  267.   t= index(buf, '.'); /* look for an extension and strip it off */
  268.   if (t)
  269.     *t= '\0';
  270.   return(buf);
  271. }
  272.  
  273. /* visual class to name table
  274.  */
  275.  
  276. static struct visual_class_name {
  277.   int   class; /* numerical value of class */
  278.   char *name;  /* actual name of class */
  279. } VisualClassName[] = {
  280.   TrueColor,   "TrueColor",
  281.   DirectColor, "DirectColor",
  282.   PseudoColor, "PseudoColor",
  283.   StaticColor, "StaticColor",
  284.   GrayScale,   "GrayScale",
  285.   StaticGray,  "StaticGray",
  286.   StaticGray,  "StaticGrey",
  287.   -1,          NULL
  288. };
  289.  
  290. int visualClassFromName(name)
  291.      char *name;
  292. { int a;
  293.   char *s1, *s2;
  294.   int class= -1;
  295.  
  296.   for (a= 0; VisualClassName[a].name; a++) {
  297.     for (s1= VisualClassName[a].name, s2= name; *s1 && *s2; s1++, s2++)
  298.       if ((isupper(*s1) ? tolower(*s1) : *s1) !=
  299.       (isupper(*s2) ? tolower(*s2) : *s2))
  300.     break;
  301.  
  302.     if ((*s1 == '\0') || (*s2 == '\0')) {
  303.  
  304.       /* check for uniqueness.  we special-case StaticGray because we have two
  305.        * spellings but they are unique if either is found
  306.        */
  307.     
  308.       if ((class != -1) && (class != StaticGray)) {
  309.     fprintf(stderr, "%s does not uniquely describe a visual class (ignored)\n", name);
  310.     return(-1);
  311.       }
  312.       class= VisualClassName[a].class;
  313.     }
  314.   }
  315.   if (class == -1)
  316.     fprintf(stderr, "%s is not a visual class (ignored)\n", name);
  317.   return(class);
  318. }
  319.  
  320. char *nameOfVisualClass(class)
  321.      int class;
  322. { int a;
  323.  
  324.   for (a= 0; VisualClassName[a].name; a++)
  325.     if (VisualClassName[a].class == class)
  326.       return(VisualClassName[a].name);
  327.   return("[Unknown Visual Class]");
  328. }
  329.  
  330. /* find the best visual of a particular class with a particular depth
  331.  */
  332.  
  333. static Visual *bestVisualOfClassAndDepth(disp, scrn, class, depth)
  334.      Display      *disp;
  335.      int           scrn;
  336.      int           class;
  337.      unsigned int  depth;
  338. { Visual *best= NULL;
  339.   XVisualInfo template, *info;
  340.   int nvisuals;
  341.  
  342.   template.screen= scrn;
  343.   template.class= class;
  344.   template.depth= depth;
  345.   if (! (info= XGetVisualInfo(disp, VisualScreenMask | VisualClassMask |
  346.                   VisualDepthMask, &template, &nvisuals)))
  347.     return(NULL); /* no visuals of this depth */
  348.  
  349.   /* not sure what to do if this gives more than one visual of a particular
  350.    * class and depth, so just return the first one.
  351.    */
  352.  
  353.   best= info->visual;
  354.   XFree(info);
  355.   return(best);
  356. }
  357.  
  358. /* this tries to determine the best available visual to use for a particular
  359.  * image
  360.  */
  361.  
  362. static void bestVisual(disp, scrn, image, rvisual, rdepth)
  363.      Display       *disp;
  364.      int            scrn;
  365.      Image         *image;
  366.      Visual       **rvisual;
  367.      unsigned int  *rdepth;
  368. { unsigned int  depth, a;
  369.   Screen       *screen;
  370.   Visual       *visual, *default_visual;
  371.  
  372.   /* figure out the best depth the server supports.  note that some servers
  373.    * (such as the HP 11.3 server) actually say they support some depths but
  374.    * have no visuals that support that depth.  seems silly to me....
  375.    */
  376.  
  377.   depth= 0;
  378.   screen= ScreenOfDisplay(disp, scrn);
  379.   for (a= 0; a < screen->ndepths; a++) {
  380.     if (screen->depths[a].nvisuals &&
  381.     ((!depth ||
  382.       ((depth < image->depth) && (screen->depths[a].depth > depth)) ||
  383.       ((screen->depths[a].depth >= image->depth) &&
  384.        (screen->depths[a].depth < depth)))))
  385.       depth= screen->depths[a].depth;
  386.   }
  387.   if (!depth) { /* this shouldn't happen */
  388.     printf("bestVisual: didn't find any depths?!?\n");
  389.     depth= DefaultDepth(disp, scrn);
  390.   }
  391.  
  392.   /* given this depth, find the best possible visual
  393.    */
  394.  
  395.   default_visual= DefaultVisual(disp, scrn);
  396.   switch (image->type) {
  397.   case ITRUE:
  398.  
  399.     /* if the default visual is DirectColor or TrueColor prioritize such
  400.      * that we use the default type if it exists at this depth
  401.      */
  402.  
  403.     if (default_visual->class == TrueColor) {
  404.       visual= bestVisualOfClassAndDepth(disp, scrn, TrueColor, depth);
  405.       if (!visual)
  406.     visual= bestVisualOfClassAndDepth(disp, scrn, DirectColor, depth);
  407.     }
  408.     else {
  409.       visual= bestVisualOfClassAndDepth(disp, scrn, DirectColor, depth);
  410.       if (!visual)
  411.     visual= bestVisualOfClassAndDepth(disp, scrn, TrueColor, depth);
  412.     }
  413.  
  414.     if (!visual || ((depth <= 8) &&
  415.             bestVisualOfClassAndDepth(disp, scrn, PseudoColor, depth)))
  416.       visual= bestVisualOfClassAndDepth(disp, scrn, PseudoColor, depth);
  417.     if (!visual)
  418.       visual= bestVisualOfClassAndDepth(disp, scrn, StaticColor, depth);
  419.     if (!visual)
  420.       visual= bestVisualOfClassAndDepth(disp, scrn, GrayScale, depth);
  421.     if (!visual)
  422.       visual= bestVisualOfClassAndDepth(disp, scrn, StaticGray, depth);
  423.     break;
  424.  
  425.   case IRGB:
  426.  
  427.     /* if it's an RGB image, we want PseudoColor if we can get it
  428.      */
  429.  
  430.     visual= bestVisualOfClassAndDepth(disp, scrn, PseudoColor, depth);
  431.     if (!visual)
  432.       visual= bestVisualOfClassAndDepth(disp, scrn, DirectColor, depth);
  433.     if (!visual)
  434.       visual= bestVisualOfClassAndDepth(disp, scrn, TrueColor, depth);
  435.     if (!visual)
  436.       visual= bestVisualOfClassAndDepth(disp, scrn, StaticColor, depth);
  437.     if (!visual)
  438.       visual= bestVisualOfClassAndDepth(disp, scrn, GrayScale, depth);
  439.     if (!visual)
  440.       visual= bestVisualOfClassAndDepth(disp, scrn, StaticGray, depth);
  441.     break;
  442.  
  443.   case IBITMAP:
  444.     visual= bestVisualOfClassAndDepth(disp, scrn, PseudoColor, depth);
  445.     if (!visual)
  446.       visual= bestVisualOfClassAndDepth(disp, scrn, StaticColor, depth);
  447.     if (!visual)
  448.       visual= bestVisualOfClassAndDepth(disp, scrn, GrayScale, depth);
  449.     if (!visual)
  450.       visual= bestVisualOfClassAndDepth(disp, scrn, StaticGray, depth);
  451.  
  452.     /* it seems pretty wasteful to use a TrueColor or DirectColor visual
  453.      * to display a bitmap (2-color) image, so we look for those last
  454.      */
  455.  
  456.     if (!visual)
  457.       visual= bestVisualOfClassAndDepth(disp, scrn, DirectColor, depth);
  458.     if (!visual)
  459.       visual= bestVisualOfClassAndDepth(disp, scrn, TrueColor, depth);
  460.     break;
  461.   }
  462.  
  463.   if (!visual) { /* this shouldn't happen */
  464.     fprintf(stderr, "bestVisual: couldn't find one?!?\n");
  465.     depth= DefaultDepth(disp, scrn);
  466.     visual= DefaultVisual(disp, scrn);
  467.   }
  468.   *rvisual= visual;
  469.   *rdepth= depth;
  470. }
  471.  
  472. /* given a visual class, try to find the best visual of that class at
  473.  * the best depth.  returns a null visual and depth if it couldn't find
  474.  * any visual of that type at any depth
  475.  */
  476.  
  477. void bestVisualOfClass(disp, scrn, image, visual_class, rvisual, rdepth)
  478.      Display      *disp;
  479.      int           scrn;
  480.      Image        *image;
  481.      int           visual_class;
  482.      Visual      **rvisual;
  483.      unsigned int *rdepth;
  484. {
  485.   Visual       *visual;
  486.   Screen       *screen;
  487.   unsigned int  a, b, depth;
  488.  
  489.   /* loop through depths looking for a visual of a good depth which matches
  490.    * our visual class.
  491.    */
  492.  
  493.   screen= ScreenOfDisplay(disp, scrn);
  494.   visual= (Visual *)NULL;
  495.   depth= 0;
  496.   for (a= 0; a < screen->ndepths; a++) {
  497.     for (b= 0; b < screen->depths[a].nvisuals; b++) {
  498.       if ((screen->depths[a].visuals[b].class == visual_class) &&
  499.       (!depth ||
  500.        ((depth < image->depth) && (screen->depths[a].depth > depth)) ||
  501.        ((screen->depths[a].depth >= image->depth) &&
  502.         (screen->depths[a].depth < depth)))) {
  503.     depth= screen->depths[a].depth;
  504.     visual= &(screen->depths[a].visuals[b]);
  505.       }
  506.     }
  507.   }
  508.   *rvisual= visual;
  509.   *rdepth= depth;
  510. }
  511.  
  512. char imageInWindow(disp, scrn, image, user_geometry, fullscreen, install,
  513.            private_cmap, fit, use_pixmap, delay, visual_class,
  514.            argc, argv, verbose)
  515.      Display      *disp;
  516.      int           scrn;
  517.      Image        *image;
  518.      char         *user_geometry;
  519.      unsigned int  fullscreen;
  520.      unsigned int  install;
  521.      unsigned int  private_cmap;
  522.      unsigned int  fit;
  523.      unsigned int  use_pixmap;
  524.      unsigned int  delay;
  525.      int           visual_class; /* visual class user wants (or -1) */
  526.      int           argc;
  527.      char         *argv[];
  528.      unsigned int  verbose;
  529. { Pixmap                pixmap = None;
  530.   XImageInfo           *ximageinfo;
  531.   Visual               *visual;
  532.   unsigned int          depth;
  533.   Window                oldimagewindow;
  534.   Colormap              oldcmap;
  535.   XSetWindowAttributes  swa_img;
  536.   XSetWindowAttributes  swa_view;
  537.   XClassHint            classhint;
  538.   unsigned int          wa_mask_img;
  539.   XSizeHints            sh;
  540.   XWMHints              wmh;
  541.   int                   pixx= -1, pixy= -1;
  542.   int                   lastx, lasty, mousex, mousey;
  543.   int                   paint;
  544.   static int            old_width= -1, old_height= -1;
  545.   static Atom           proto_atom= None, delete_atom= None;
  546.   union {
  547.     XEvent              event;
  548.     XAnyEvent           any;
  549.     XButtonEvent        button;
  550.     XKeyEvent           key;
  551.     XConfigureEvent     configure;
  552.     XExposeEvent        expose;
  553.     XMotionEvent        motion;
  554.     XResizeRequestEvent resize;
  555.     XClientMessageEvent message;
  556.   } event;
  557.   unsigned int          winx, winy, winwidth, winheight;
  558.  
  559.   /* figure out the window size.  unless specifically requested to do so,
  560.    * we will not exceed 90% of display real estate.
  561.    */
  562.  
  563.   if (user_geometry == NULL) {
  564.     winx= winy= winwidth= winheight= 0;
  565.   }
  566.   else {
  567.     char                def_geom[30];
  568.  
  569.     sprintf(def_geom, "%ux%u+0+0", image->width, image->height);
  570.     XGeometry(disp, scrn, user_geometry, def_geom, 0, 1, 1, 0, 0,
  571.           &winx, &winy, &winwidth, &winheight);
  572.   }
  573.  
  574.   if (fullscreen) {
  575.     winwidth= DisplayWidth(disp, scrn);
  576.     winheight= DisplayHeight(disp, scrn);
  577.   }
  578.   else {
  579.     lastx= (winwidth || winheight); /* user set size flag */
  580.     if (!winwidth) {
  581.       winwidth= image->width;
  582.       if (winwidth > DisplayWidth(disp, scrn) * 0.9)
  583.     winwidth= DisplayWidth(disp, scrn) * 0.9;
  584.     }
  585.     if (!winheight) {
  586.       winheight= image->height;
  587.       if (winheight > DisplayHeight(disp, scrn) * 0.9)
  588.     winheight= DisplayHeight(disp, scrn) * 0.9;
  589.     }
  590.   }
  591.  
  592.   /* if the user told us to fit the colormap, we must use the default
  593.    * visual.
  594.    */
  595.  
  596.   if (fit) {
  597.     visual= DefaultVisual(disp, scrn);
  598.     depth= DefaultDepth(disp, scrn);
  599.   }
  600.   else {
  601.  
  602.     visual= (Visual *)NULL;
  603.     if (visual_class == -1) {
  604.  
  605.       /* try to pick the best visual for the image.
  606.        */
  607.  
  608.       bestVisual(disp, scrn, image, &visual, &depth);
  609.       if (verbose && (visual != DefaultVisual(disp, scrn)))
  610.     printf("  Using %s visual\n", nameOfVisualClass(visual->class));
  611.     }
  612.     else {
  613.  
  614.       /* try to find a visual of the specified class
  615.        */
  616.  
  617.       bestVisualOfClass(disp, scrn, image, visual_class, &visual, &depth);
  618.       if (!visual) {
  619.     bestVisual(disp, scrn, image, &visual, &depth);
  620.     fprintf(stderr, "Server does not support %s visual, using %s\n",
  621.         nameOfVisualClass(visual_class),
  622.         nameOfVisualClass(visual->class));
  623.       }
  624.     }
  625.   }
  626.  
  627.   /* if we're in slideshow mode and the user told us to fit the colormap,
  628.    * free it here.
  629.    */
  630.  
  631.   if (ViewportWin) {
  632.     if (fit) {
  633.       XDestroyWindow(disp, ImageWindow);
  634.       ImageWindow= 0;
  635.       ImageColormap= 0;
  636.     }
  637.  
  638.     /* for the 1st image we display we can use the default cmap.  subsequent
  639.      * images use a private colormap (unless they're bitmaps) so we don't get
  640.      * color erosion when switching images.
  641.      */
  642.  
  643.     else if (!BITMAPP(image))
  644.       private_cmap= 1;
  645.   }
  646.  
  647.   if (! (ximageinfo= imageToXImage(disp, scrn, visual, depth, image,
  648.                    private_cmap, fit, verbose))) {
  649.     fprintf(stderr, "Cannot convert Image to XImage\n");
  650.     exit(1);
  651.   }
  652.  
  653.   swa_view.background_pixel= WhitePixel(disp,scrn);
  654.   swa_view.backing_store= NotUseful;
  655.   swa_view.cursor= XCreateFontCursor(disp, XC_watch);
  656.   swa_view.event_mask= ButtonPressMask | Button1MotionMask | KeyPressMask |
  657.     StructureNotifyMask | EnterWindowMask | LeaveWindowMask;
  658.   swa_view.save_under= False;
  659.  
  660.   classhint.res_class = "Xloadimage";
  661.   classhint.res_name=NULL;
  662.   if (!ViewportWin) {
  663.     ViewportWin= XCreateWindow(disp, RootWindow(disp, scrn), winx, winy,
  664.                    winwidth, winheight, 0,
  665.                    DefaultDepth(disp, scrn), InputOutput,
  666.                    DefaultVisual(disp, scrn),
  667.                    CWBackingStore | CWBackPixel | CWCursor |
  668.                    CWEventMask | CWSaveUnder,
  669.                    &swa_view);
  670.     oldimagewindow= 0;
  671.     XSetCommand(disp, ViewportWin, argv, argc);
  672.     XSetClassHint(disp,ViewportWin,&classhint);
  673.     proto_atom = XInternAtom(disp, "WM_PROTOCOLS", False);
  674.     delete_atom = XInternAtom(disp, "WM_DELETE_WINDOW", False);
  675.     if ((proto_atom != None) && (delete_atom != None))
  676.       XChangeProperty(disp, ViewportWin, proto_atom, XA_ATOM, 32,
  677.               PropModePrepend, &delete_atom, 1);
  678.    paint= 0;
  679.   }
  680.   else {
  681.     oldimagewindow= ImageWindow;
  682.     oldcmap= ImageColormap;
  683.     paint= 1;
  684.   }
  685.  
  686.   /* create image window
  687.    */
  688.  
  689.   swa_img.bit_gravity= NorthWestGravity;
  690.   swa_img.save_under= False;
  691.   swa_img.colormap= ximageinfo->cmap;
  692.   swa_img.border_pixel= 0;
  693.   ImageWindow= XCreateWindow(disp, ViewportWin, winx, winy,
  694.                  image->width, image->height, 0,
  695.                  ximageinfo->depth, InputOutput, visual,
  696.                  CWBitGravity | CWColormap | CWSaveUnder |
  697.                  CWBorderPixel, &swa_img);
  698.   ImageColormap= ximageinfo->cmap;
  699.   XSetCommand(disp, ImageWindow, argv, argc);
  700.   XSetClassHint(disp,ImageWindow,&classhint);
  701.  
  702.   /* decide how we're going to handle repaints.  we have three modes:
  703.    * use backing-store, use background pixmap, and use exposures.
  704.    * if the server supports backing-store, we enable it and use it.
  705.    * this really helps servers which are memory constrained.  if the
  706.    * server does not have backing-store, we try to send the image to
  707.    * a pixmap and use that as backing-store.  if that fails, we use
  708.    * exposures to blit the image (which is ugly but it works).
  709.    *
  710.    * the "use_pixmap" flag forces background pixmap mode, which may
  711.    * improve performance.
  712.    */
  713.  
  714.   ximageinfo->drawable= ImageWindow;
  715.   if ((DoesBackingStore(ScreenOfDisplay(disp,scrn)) == NotUseful) ||
  716.       use_pixmap) {
  717.     if (((pixmap= ximageToPixmap(disp, ImageWindow, ximageinfo)) ==
  718.      None) && verbose)
  719.       printf("  Cannot create image in server, repaints will be ugly!\n");
  720.   }
  721.  
  722.   /* build window attributes for the image window
  723.    */
  724.  
  725.   wa_mask_img= 0;
  726.   if (pixmap == None) {
  727.  
  728.     /* No pixmap.  Must paint over the wire.  Ask for BackingStore
  729.      * to cut down on the painting.  But, ask for Exposures so we can
  730.      * paint both viewables and backingstore.
  731.      */
  732.  
  733.     swa_img.background_pixel= WhitePixel(disp,scrn);
  734.     wa_mask_img |= CWBackPixel;
  735.     swa_img.event_mask= ExposureMask;
  736.     wa_mask_img |= CWEventMask;
  737.     swa_img.backing_store= WhenMapped;
  738.     wa_mask_img |= CWBackingStore;
  739.   }
  740.   else {
  741.  
  742.     /* we have a pixmap so tile the window.  to move the image we only
  743.      * have to move the window and the server should do the rest.
  744.      */
  745.  
  746.     swa_img.background_pixmap= pixmap;
  747.     wa_mask_img |= CWBackPixmap;
  748.     swa_img.event_mask= 0;    /* no exposures please */
  749.     wa_mask_img |= CWEventMask;
  750.     swa_img.backing_store= NotUseful;
  751.     wa_mask_img |= CWBackingStore;
  752.   }
  753.   XChangeWindowAttributes(disp, ImageWindow, wa_mask_img, &swa_img);
  754.  
  755.   if (image->title)
  756.     XStoreName(disp, ViewportWin, image->title);
  757.   else
  758.     XStoreName(disp, ViewportWin, "Unnamed");
  759.   XSetIconName(disp, ViewportWin, iconName(image->title));
  760.  
  761.   sh.width= winwidth;
  762.   sh.height= winheight;
  763.   if (fullscreen) {
  764.     sh.min_width= sh.max_width= winwidth;
  765.     sh.min_height= sh.max_height= winheight;
  766.   }
  767.   else {
  768.     sh.min_width= 1;
  769.     sh.min_height= 1;
  770.     sh.max_width= image->width;
  771.     sh.max_height= image->height;
  772.   }
  773.   sh.width_inc= 1;
  774.   sh.height_inc= 1;
  775.   sh.flags= PMinSize | PMaxSize | PResizeInc;
  776.   if (lastx || fullscreen)
  777.     sh.flags |= USSize;
  778.   else
  779.     sh.flags |= PSize;
  780.   if (fullscreen) {
  781.     sh.x= sh.y= 0;
  782.     sh.flags |= USPosition;
  783.   }
  784.   else if (winx || winy) {
  785.     sh.x= winx;
  786.     sh.y= winy;
  787.     sh.flags |= USPosition;
  788.   }
  789.   XSetNormalHints(disp, ViewportWin, &sh);
  790.   sh.min_width= sh.max_width;
  791.   sh.min_height= sh.max_height;
  792.   XSetNormalHints(disp, ImageWindow, &sh);    /* Image doesn't shrink */
  793.  
  794.   wmh.input= True;
  795.   wmh.flags= InputHint;
  796.   XSetWMHints(disp, ViewportWin, &wmh);
  797.  
  798.   setViewportColormap(disp, scrn, visual);
  799.  
  800.   /* map windows and clean up old window if there was one.
  801.    */
  802.  
  803.   XMapWindow(disp, ImageWindow);
  804.   XMapWindow(disp, ViewportWin);
  805.   if (oldimagewindow) {
  806.     if (oldcmap && (oldcmap != DefaultColormap(disp, scrn)))
  807.       XFreeColormap(disp, oldcmap);
  808.     XDestroyWindow(disp, oldimagewindow);
  809.   }
  810.  
  811.   /* start displaying image
  812.    */
  813.  
  814.   placeImage(disp, image->width, image->height, winwidth, winheight, &pixx, &pixy);
  815.   if (paint) {
  816.     if ((winwidth != old_width) || (winheight != old_height)) {
  817.     XResizeWindow(disp, ViewportWin, winwidth, winheight);
  818.     }
  819.     XResizeWindow(disp, ImageWindow, image->width, image->height);
  820.     /* Clear the image window.  Ask for exposure if there is no tile. */
  821.     XClearArea(disp, ImageWindow, 0, 0, 0, 0, (pixmap == None));
  822.   }
  823.   old_width= winwidth;
  824.   old_height= winheight;
  825.  
  826.   /* flush output. this is so that -delay will be close to what was
  827.    * asked for (i.e., do the flushing of output outside of the loop).
  828.    */
  829.   XSync(disp,False);
  830.  
  831.   setCursor(disp, ViewportWin, image->width, image->height,
  832.         winwidth, winheight, &(swa_view.cursor));
  833.   lastx= lasty= -1;
  834.   if (delay) {
  835.       /* reset alarm to -delay seconds after every event */
  836.       AlarmWentOff = 0;
  837.       signal(SIGALRM, delayAlarmHandler);
  838.       alarm(delay);
  839.   }
  840.  
  841.   for (;;) {
  842.  
  843.     if (delay) {
  844.       if (!getNextEventWithTimeout(disp, &event.event)) {
  845.     Cursor cursor= swa_view.cursor;
  846.  
  847.     /* timeout expired.  clean up and exit.
  848.      */
  849.  
  850.     swa_view.cursor= XCreateFontCursor(disp, XC_watch);
  851.     XChangeWindowAttributes(disp, ImageWindow, CWCursor, &swa_view);
  852.     XFreeCursor(disp, cursor);
  853.     XFlush(disp);
  854.     cleanUpImage(disp, scrn, swa_view.cursor, pixmap,
  855.              image, ximageinfo);
  856.     return('n');
  857.       }
  858.     }
  859.     else
  860.       XNextEvent(disp, &event.event);
  861.  
  862.     switch (event.any.type) {
  863.     case ButtonPress:
  864.       if (event.button.button == 1) {
  865.     lastx= event.button.x;
  866.     lasty= event.button.y;
  867.     break;
  868.       }
  869.       break;
  870.  
  871.     case KeyPress: {
  872.       char buf[128];
  873.       KeySym ks;
  874.       XComposeStatus status;
  875.       char ret;
  876.       Cursor cursor;
  877.  
  878.       if (XLookupString(&event.key,buf,128,&ks,&status) != 1)
  879.     break;
  880.       ret= buf[0];
  881.       if (isupper(ret))
  882.     ret= tolower(ret);
  883.       switch (ret) {
  884.       case ' ':
  885.       case 'n':
  886.       case 'p':
  887.     if (delay)
  888.       alarm(0);
  889.     cursor= swa_view.cursor;
  890.     swa_view.cursor= XCreateFontCursor(disp, XC_watch);
  891.     XChangeWindowAttributes(disp, ViewportWin, CWCursor, &swa_view);
  892.     XFreeCursor(disp, cursor);
  893.     XFlush(disp);
  894.     cleanUpImage(disp, scrn, swa_view.cursor, pixmap,
  895.              image, ximageinfo);
  896.     return(ret);
  897.       case '\003': /* ^C */
  898.       case 'q':
  899.     if (delay)
  900.       alarm(0);
  901.     cleanUpImage(disp, scrn, swa_view.cursor, pixmap,
  902.              image, ximageinfo);
  903.     return(ret);
  904.       }
  905.       break;
  906.     }
  907.  
  908.     case MotionNotify:
  909.       if ((image->width <= winwidth) && (image->height <= winheight))
  910.     break; /* we're AT&T */
  911.       mousex= event.button.x;
  912.       mousey= event.button.y;
  913.       /*XSync(disp, False); */
  914.       while (XCheckTypedEvent(disp, MotionNotify, &event) == True) {
  915.     mousex= event.button.x;
  916.     mousey= event.button.y;
  917.       }
  918.       pixx -= (lastx - mousex);
  919.       pixy -= (lasty - mousey);
  920.       lastx= mousex;
  921.       lasty= mousey;
  922.       placeImage(disp, image->width, image->height, winwidth, winheight,
  923.          &pixx, &pixy);
  924.       break;
  925.  
  926.     case ConfigureNotify:
  927.       winwidth= old_width= event.configure.width;
  928.       winheight= old_height= event.configure.height;
  929.  
  930.       placeImage(disp, image->width, image->height, winwidth, winheight,
  931.          &pixx, &pixy);
  932.  
  933.       /* configure the cursor to indicate which directions we can drag
  934.        */
  935.  
  936.       setCursor(disp, ViewportWin, image->width, image->height,
  937.         winwidth, winheight, &(swa_view.cursor));
  938.       break;
  939.  
  940.     case DestroyNotify:
  941.       cleanUpImage(disp, scrn, swa_view.cursor, pixmap,
  942.            image, ximageinfo);
  943.       return('\0');
  944.  
  945.     case Expose:
  946.       blitImage(ximageinfo, image->width, image->height,
  947.         event.expose.x, event.expose.y,
  948.         event.expose.width, event.expose.height);
  949.       break;
  950.  
  951.     case EnterNotify:
  952.       if (install)
  953.     XInstallColormap(disp, ximageinfo->cmap);
  954.       break;
  955.  
  956.     case LeaveNotify:
  957.       if (install)
  958.     XUninstallColormap(disp, ximageinfo->cmap);
  959.       break;
  960.  
  961.     case ClientMessage:
  962.       /* if we get a client message for the viewport window which has the
  963.        * value of the delete atom, it means the window manager wants us to
  964.        * die.
  965.        */
  966.  
  967.       if ((event.message.window == ViewportWin) &&
  968.       (event.message.data.l[0] == delete_atom)) {
  969.     cleanUpImage(disp, scrn, swa_view.cursor, pixmap,
  970.               image, ximageinfo);
  971.     return('q');
  972.       }
  973.       break;
  974.     }
  975.   }
  976. }
  977.