home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / x / xlibpr3.zip / winman / winman.c < prev    next >
C/C++ Source or Header  |  1990-01-15  |  27KB  |  808 lines

  1. /*
  2.  * Copyright 1989 O'Reilly and Associates, Inc.
  3.  * See ../Copyright for complete rights and liability information.
  4.  */
  5. #include <X11/Xlib.h>
  6. #include <X11/Xutil.h>
  7. #include <X11/Xatom.h>
  8. #include <X11/Xos.h>
  9. #include <X11/cursorfont.h>
  10.  
  11. #include <stdio.h>
  12. #include <signal.h>
  13.  
  14. #include "bitmaps/focus_frame_bi"    /* name must be <= 14 chars for 
  15.                                 * sys V compatibility */
  16.  
  17. /* include file for printing event types */
  18. #include "eventnames.h"
  19.  
  20. #define MAX_CHOICE 10
  21. #define DRAW 1
  22. #define ERASE 0
  23. #define RAISE 1
  24. #define LOWER 0
  25. #define MOVE 1
  26. #define RESIZE 0
  27. #define NONE 100
  28. #define NOTDEFINED 0
  29. #define BLACK  1
  30. #define WHITE  0
  31.  
  32. Window focus_window;
  33. Window inverted_pane = NONE;
  34.  
  35. static char *menu_label[] =
  36.     {
  37.     "Raise",
  38.     "Lower",
  39.     "Move",
  40.     "Resize",
  41.     "CirculateDn",
  42.     "CirculateUp",
  43.     "(De)Iconify",
  44.     "Kybrd Focus",  
  45.     "New Xterm",
  46.     "Exit",
  47.     };
  48.  
  49.  
  50. Display *display;
  51. int screen_num;
  52. XFontStruct *font_info;
  53. char icon_name[50];
  54.  
  55. main()
  56. {
  57.     Window menuwin;
  58.     Window panes[MAX_CHOICE];
  59.     int menu_width, menu_height, x = 0, y = 0, border_width = 4;
  60.     int winindex;
  61.     int cursor_shape;
  62.     Cursor cursor, hand_cursor;
  63.     char *font_name = "9x15";
  64.     int direction, ascent, descent;
  65.     int char_count;
  66.     char *string;
  67.     XCharStruct overall;
  68.     Bool owner_events;
  69.     int pointer_mode;
  70.     int keyboard_mode;
  71.     Window confine_to;
  72.     GC gc, rgc;
  73.     int pane_height;
  74.     Window assoc_win;
  75.     XEvent event;
  76.     unsigned int button;
  77.  
  78.  
  79.     if ( (display=XOpenDisplay(NULL)) == NULL )
  80.         {
  81.         (void) fprintf( stderr, "winman: cannot connect to \
  82.                 X server %s\n", XDisplayName(NULL));
  83.         exit( -1 );
  84.         }
  85.  
  86.     screen_num = DefaultScreen(display);
  87.  
  88.     /* Access font */
  89.     font_info = XLoadQueryFont(display,font_name);
  90.  
  91.     if (font_info == NULL)
  92.         {
  93.         (void) fprintf( stderr, "winman: Cannot open font %s\n", 
  94.                 font_name);
  95.         exit( -1 );
  96.         }
  97.  
  98.     string = menu_label[6];
  99.     char_count = strlen(string);
  100.  
  101.     /* determine the extent of each menu pane based 
  102.      * on the font size */
  103.     XTextExtents(font_info, string, char_count, &direction, &ascent, 
  104.             &descent, &overall);
  105.  
  106.     menu_width = overall.width + 4;
  107.     pane_height = overall.ascent + overall.descent + 4;
  108.     menu_height = pane_height * MAX_CHOICE;
  109.  
  110.     /* place the window in upper right corner*/
  111.     x = DisplayWidth(display,screen_num) - menu_width - (2*border_width); 
  112.     y = 0;   /* appears at top */
  113.  
  114.     /* create opaque window */
  115.     menuwin = XCreateSimpleWindow(display, RootWindow(display, 
  116.             screen_num), x, y, menu_width, menu_height, 
  117.             border_width, BlackPixel(display,screen_num), 
  118.             WhitePixel(display,screen_num));
  119.  
  120.     /* create the choice windows for the text */
  121.     for (winindex = 0; winindex < MAX_CHOICE; winindex++) {
  122.         panes[winindex] = XCreateSimpleWindow(display, menuwin, 0, 
  123.                 menu_height/MAX_CHOICE*winindex, menu_width, 
  124.                 pane_height, border_width = 1, 
  125.                 BlackPixel(display,screen_num), 
  126.                 WhitePixel(display,screen_num));
  127.         XSelectInput(display, panes[winindex], ButtonPressMask
  128.                 | ButtonReleaseMask |  ExposureMask);
  129.     }
  130.  
  131.     XSelectInput(display, RootWindow(display, screen_num), 
  132.             SubstructureNotifyMask);
  133.  
  134.     /* these don't appear until parent (menuwin) is mapped */
  135.     XMapSubwindows(display,menuwin);
  136.  
  137.     /* create the cursor for the menu */
  138.     cursor = XCreateFontCursor(display, XC_left_ptr);
  139.     hand_cursor = XCreateFontCursor(display, XC_hand2);
  140.  
  141.     XDefineCursor(display, menuwin, cursor);
  142.  
  143.     focus_window = RootWindow(display, screen_num);
  144.  
  145.     /* Create two Graphics Contexts for inverting panes (white on 
  146.      * black).  We invert the panes by changing the background 
  147.      * pixel, clearing the window, and using the GC with the 
  148.      * contrasting color to redraw the text.  Another way is 
  149.      * using XCopyArea.  The default is to generate GraphicsExpose 
  150.      * and NoExpose events to indicate whether the source area 
  151.      * was obscured.  Since the logical function is GXinvert 
  152.      * the destination is also the source.   Therefore if other 
  153.      * windows are obscuring parts of the exposed pane, the 
  154.      * wrong area will be inverted.  Therefore we would need to 
  155.      * handle GraphicsExpose and NoExpose events.  We'll do it the
  156.      * easier way. */
  157.  
  158.     gc = XCreateGC(display, RootWindow(display, screen_num) , 0, NULL);
  159.     XSetForeground(display, gc, BlackPixel(display, screen_num));
  160.     rgc = XCreateGC(display, RootWindow(display, screen_num) , 0, NULL);
  161.     XSetForeground(display, rgc, WhitePixel(display, screen_num));
  162.  
  163.     /* map the menu window (and its subwindows) to the screen_num */
  164.     XMapWindow(display, menuwin);
  165.  
  166.     /* Force child processes to disinherit the TCP file descriptor.
  167.       * This helps the shell command (creating new xterm) forked and 
  168.      * exec'ed from the menu to work properly.  */
  169.     if ((fcntl(ConnectionNumber(display), F_SETFD, 1)) == -1)
  170.         fprintf(stderr, "winman: child cannot disinherit TCP fd");
  171.  
  172.     /* loop getting events on the menu window and icons */
  173.     while (1)
  174.         {
  175.         /* wait for an event */
  176.         XNextEvent(display, &event);
  177.  
  178.         /* if expose, draw text in pane if it is pane */
  179.         switch (event.type) {
  180.         case Expose:
  181.             if  (isIcon(event.xexpose.window, event.xexpose.x, 
  182.                     event.xexpose.y, &assoc_win, icon_name, False))
  183.                 XDrawString(display, event.xexpose.window, gc, 2, 
  184.                         ascent + 2, icon_name, strlen(icon_name));
  185.             else /* it's a pane, might be inverted */
  186.                 {
  187.                 if (inverted_pane == event.xexpose.window)
  188.                     paint_pane(event.xexpose.window, panes, gc, rgc, BLACK);
  189.                 else
  190.                     paint_pane(event.xexpose.window, panes, gc, rgc, WHITE);
  191.                 }
  192.             break;
  193.         case ButtonPress:
  194.  
  195.             paint_pane(event.xbutton.window, panes, gc, rgc, BLACK);
  196.  
  197.             button = event.xbutton.button;
  198.             inverted_pane = event.xbutton.window;
  199.         
  200.             /* get the matching ButtonRelease on same button */
  201.             while (1) {
  202.                 /* get rid of other presses */
  203.                 while (XCheckTypedEvent(display, ButtonPress, 
  204.                         &event))
  205.                     ;
  206.                 /* wait for release; if on correct button exit */
  207.                 XMaskEvent(display, ButtonReleaseMask, &event);
  208.                 if (event.xbutton.button == button) {
  209.                     /* get rid of other releases */
  210.                     while (XCheckTypedEvent(display, ButtonRelease, 
  211.                             &event))
  212.                         ;
  213.                     break;
  214.                 }
  215.             }
  216.  
  217.             /* all events are sent to the grabbing
  218.              * window regardless of
  219.              * whether this is True or False. 
  220.              * owner_events only affects the distribution of
  221.              * events when the pointer is within this
  222.              * application's windows. */
  223.             owner_events = True;    
  224.  
  225.             /* we don't want pointer or keyboard events
  226.              * frozen in the server */
  227.             pointer_mode = GrabModeAsync;
  228.             keyboard_mode = GrabModeAsync;
  229.  
  230.             /* we don't want to confine the cursor */
  231.             confine_to = None;
  232.             XGrabPointer(display, menuwin, owner_events, 
  233.                     ButtonPressMask | ButtonReleaseMask, 
  234.                     pointer_mode, keyboard_mode, 
  235.                     confine_to, hand_cursor, CurrentTime);
  236.     
  237.  
  238.             /* if press and release occured in same window,
  239.              * do command, if not, do nothing */
  240.             if (inverted_pane == event.xbutton.window)
  241.                 {
  242.                 /* convert window ID to 
  243.                  * window array index  */
  244.                 for (winindex = 0; inverted_pane != 
  245.                         panes[winindex]; winindex++) 
  246.                     ;
  247.                 switch (winindex)
  248.                     {
  249.                 case 0:
  250.                     raise_lower(menuwin, RAISE);
  251.                     break;
  252.                 case 1:
  253.                     raise_lower(menuwin, LOWER);
  254.                     break;
  255.                 case 2:
  256.                     move_resize(menuwin, hand_cursor, MOVE);
  257.                     break;
  258.                 case 3:
  259.                     move_resize(menuwin, hand_cursor, RESIZE);
  260.                     break;
  261.                 case 4:
  262.                     circup(menuwin);
  263.                     break;
  264.                 case 5:
  265.                     circdn(menuwin);
  266.                     break;
  267.                 case 6:
  268.                     iconify(menuwin);
  269.                     break;
  270.                 case 7:
  271.                     focus_window = focus(menuwin);
  272.                     break;
  273.                 case 8:
  274.                     execute("xterm&");
  275.                     break;
  276.  
  277.                 case 9: /* exit */
  278.                     XSetInputFocus(display, 
  279.                         RootWindow(display,screen_num), 
  280.                         RevertToPointerRoot, 
  281.                         CurrentTime);
  282.                     /* turn all icons back into windows */
  283.                     /* must clear focus highlights */
  284.                     XClearWindow(display, RootWindow(display, screen_num));
  285.                     /* need to change focus border
  286.                      * width back here */
  287.  
  288.                     XFlush(display);
  289.                     XCloseDisplay(display);
  290.                     exit(1);
  291.                 default:
  292.                     (void) fprintf(stderr, 
  293.                             "Something went wrong\n");
  294.                     break;
  295.                     } /* end switch */
  296.                 } /* end if */
  297.  
  298.             /* Invert Back Here (logical function is invert) */
  299.             paint_pane(event.xexpose.window, panes, gc, rgc, WHITE);
  300.  
  301.             inverted_pane = NONE;
  302.             draw_focus_frame();
  303.             XUngrabPointer(display, CurrentTime);
  304.             XFlush(display);
  305.             break;
  306.         case DestroyNotify:
  307.             /* window we have iconified has died, remove its icon.
  308.              * Don't need to remove window from save set
  309.              * because that is done automatically */
  310.             removeIcon(event.xdestroywindow.window);
  311.             break;
  312.         case CirculateNotify:
  313.         case ConfigureNotify:
  314.         case UnmapNotify:
  315.             /* all these uncover areas of screen_num */
  316.             draw_focus_frame();
  317.             break;
  318.         case CreateNotify:
  319.         case GravityNotify:
  320.         case MapNotify:
  321.         case ReparentNotify:
  322.             /* don't need these but get them anyway 
  323.              * since we need DestroyNotify and UnmapNotify 
  324.              */
  325.             break;
  326.         case ButtonRelease:
  327.             /* throw these way, they are spurious here */
  328.             break;
  329.         case MotionNotify:
  330.             /* throw these way, they are spurious here */
  331.             break;
  332.         default:
  333.             fprintf(stderr, "winman: got unexpected %s event.\n", 
  334.                     event_names[event.type]);
  335.         } /* end switch */
  336.     } /* end menu loop (while) */
  337. } /* end main */
  338.  
  339. paint_pane(window, panes, ngc, rgc, mode)
  340. Window window;
  341. Window panes[];
  342. GC ngc, rgc;
  343. int mode;
  344. {      
  345.     int win;
  346.     int x = 2, y;
  347.     GC gc;
  348.  
  349.     if (mode == BLACK) {
  350.         XSetWindowBackground(display, window, BlackPixel(display, 
  351.                 screen_num));
  352.         gc = rgc;
  353.     }
  354.     else {
  355.         XSetWindowBackground(display, window, WhitePixel(display, 
  356.                 screen_num));
  357.         gc = ngc;
  358.     }
  359.     /* clearing repaints the background */
  360.     XClearWindow(display, window);
  361.  
  362.     /* find out index of window for label text */
  363.     for (win = 0; window != panes[win]; win++)
  364.         ;
  365.  
  366.     y = font_info->max_bounds.ascent;
  367.  
  368.     /* the string length is necessary because strings for
  369.         XDrawString may not be NULL terminated */
  370.     XDrawString(display, window, gc, x, y, menu_label[win], 
  371.             strlen( menu_label[win])); 
  372. }
  373.  
  374. circup(menuwin)
  375. Window menuwin;
  376.     {
  377.     XCirculateSubwindowsUp(display, RootWindow(display,screen_num));
  378.     XRaiseWindow(display, menuwin);
  379.     }
  380.  
  381. circdn(menuwin)
  382. Window menuwin;
  383.     {
  384.     XCirculateSubwindowsDown(display, RootWindow(display,screen_num));
  385.     XRaiseWindow(display, menuwin);
  386.     }
  387.  
  388. raise_lower(menuwin, raise_or_lower)
  389. Window menuwin;
  390. Bool raise_or_lower;
  391. {
  392.     XEvent report;
  393.     int root_x,root_y;
  394.     Window child, root;
  395.     int win_x, win_y;
  396.     unsigned int mask;
  397.     unsigned int button;
  398.  
  399.     /* wait for ButtonPress, find out which subwindow of root */
  400.     XMaskEvent(display, ButtonPressMask, &report); 
  401.     button = report.xbutton.button;
  402.     XQueryPointer(display, RootWindow(display,screen_num), &root, 
  403.             &child, &root_x, &root_y, &win_x, &win_y, 
  404.             &mask);
  405.  
  406.     /* if not RootWindow, raise */
  407.     if (child != NULL)
  408.     {
  409.         if (raise_or_lower == RAISE)
  410.             XRaiseWindow(display, child);
  411.         else
  412.             XLowerWindow(display, child);
  413.     
  414.         /* make sure window manager can never be obscured */
  415.         XRaiseWindow(display, menuwin);
  416.     }
  417.  
  418.     /* wait for ButtonRelease before exiting */
  419.     /* get the matching ButtonRelease on same button */
  420.     while (1)  {
  421.         XMaskEvent(display, ButtonReleaseMask, &report); 
  422.         if (report.xbutton.button == button) {
  423.             break;
  424.         }
  425.     }
  426.  
  427.     /* throw out any remaining events so we start fresh */
  428.     while (XCheckMaskEvent(display, ButtonReleaseMask | ButtonPressMask, 
  429.             &report))
  430.         ;
  431. }
  432.     
  433. iconify(menuwin)  
  434. Window menuwin;
  435.     {
  436.     XEvent report;
  437.     extern Window focus_window;
  438.     Window assoc_win;
  439.     int press_x,press_y;
  440.     Window child;
  441.     Window root;
  442.     int win_x, win_y;
  443.     unsigned int mask;
  444.     unsigned int button;
  445.  
  446.     /* wait for ButtonPress, any win */
  447.     XMaskEvent(display, ButtonPressMask, &report); 
  448.     button = report.xbutton.button;
  449.  
  450.     /* find out which subwindow the mouse was in */
  451.     XQueryPointer(display, RootWindow(display,screen_num), &root,
  452.         &child, &press_x, &press_y, &win_x, &win_y, &mask);
  453.  
  454.     /* Can't iconify rootwindow or menu window */
  455.     if ((child == NULL) || (child == menuwin)) 
  456.         {
  457.         /* wait for ButtonRelease before exiting */
  458.         while (1)  {
  459.             XMaskEvent(display, ButtonReleaseMask, &report); 
  460.             if (report.xbutton.button == button) break;
  461.             }
  462.         return; 
  463.         }
  464.  
  465.     /* returned value of isIcon not used here, but it 
  466.       * is elsewhere in the code */
  467.     isIcon(child, press_x, press_y, &assoc_win, icon_name, True);
  468.     /* window selected is unmapped, whether it is icon
  469.      * or main window.  Associated window is then mapped. */
  470.     XUnmapWindow(display, child);
  471.     XMapWindow(display, assoc_win);
  472.  
  473.     /* wait for ButtonRelease before exiting */
  474.     /* get the matching ButtonRelease on same button */
  475.     while (1)  {
  476.         XMaskEvent(display, ButtonReleaseMask, &report); 
  477.         if (report.xbutton.button == button) break;
  478.     }
  479.  
  480.     /* throw out any remaining events so we start fresh for next op */
  481.     while (XCheckMaskEvent(display, ButtonReleaseMask | ButtonPressMask, 
  482.             &report))
  483.         ;
  484. }
  485.  
  486. focus(menuwin) 
  487. Window menuwin;
  488. {
  489.     XEvent report;
  490.     int x,y;
  491.     Window child;
  492.     Window root;
  493.     Window assoc_win;
  494.     extern Window focus_window;
  495.     int win_x, win_y;
  496.     unsigned int mask;
  497.     unsigned int button;
  498.     XWindowAttributes win_attr;
  499.     static int old_width;
  500.     static Window old_focus;
  501.     int status;
  502.  
  503.  
  504.     /* wait for ButtonPress, any win */
  505.     XMaskEvent(display, ButtonPressMask, &report); 
  506.     button = report.xbutton.button;
  507.  
  508.     /* find out which subwindow the mouse was in */
  509.  
  510.     XQueryPointer(display, RootWindow(display,screen_num), &root,
  511.             &child, &x, &y, &win_x, &win_y, &mask);
  512.  
  513.  
  514.     if ((child == menuwin) || (child == NULL) || (isIcon(child, x, y, &assoc_win, 
  515.             icon_name, True)))
  516.         focus_window = RootWindow(display, screen_num);
  517.     else
  518.         focus_window = child;
  519.  
  520.     if (focus_window != old_focus)  { /* if focus changed */
  521.         /* if not first time set, set border back */
  522.         if  (old_focus != NULL) 
  523.             XSetWindowBorderWidth(display, old_focus, old_width);
  524.  
  525.         XSetInputFocus(display, focus_window, RevertToPointerRoot, 
  526.                 CurrentTime);
  527.         if (focus_window != RootWindow(display, screen_num)) {
  528.             /* get current border width and add one */
  529.             if (!(status = XGetWindowAttributes(display, 
  530.                     focus_window, &win_attr)))
  531.                 fprintf(stderr, "winman: can't get attributes for \
  532.                         focus window\n");
  533.             XSetWindowBorderWidth(display, focus_window, 
  534.                     win_attr.border_width + 1);
  535.             /* keep record so we can change it back */
  536.             old_width = win_attr.border_width;
  537.         }
  538.     }
  539.  
  540.     /* get the matching ButtonRelease on same button */
  541.     while (1)  {
  542.         XMaskEvent(display, ButtonReleaseMask, &report); 
  543.         if (report.xbutton.button == button) break;
  544.     }
  545.  
  546.     /* throw out any remaining events so we start fresh for next op */
  547.     while (XCheckMaskEvent(display, ButtonReleaseMask | ButtonPressMask, 
  548.             &report))
  549.         ;
  550.  
  551.     old_focus = focus_window;
  552.     return(focus_window);
  553. }
  554.  
  555. draw_focus_frame()
  556. {
  557.     XWindowAttributes win_attr;
  558.     int frame_width = 4;
  559.     Pixmap focus_tile;
  560.     GC gc;
  561.     int foreground = BlackPixel(display, screen_num);
  562.     int background = WhitePixel(display, screen_num);
  563.     extern Window focus_window;
  564.     Bool first_time = True;
  565.  
  566.     if (first_time) {
  567.         /* make Bitmap from bitmap data */
  568.         focus_tile = XCreatePixmapFromBitmapData(display, 
  569.                 RootWindow(display,screen_num), 
  570.                 focus_frame_bi_bits, focus_frame_bi_width, 
  571.                 focus_frame_bi_height, foreground, 
  572.                 background, DefaultDepth(display, screen_num));
  573.     
  574.         /* Create Graphics Context */
  575.         gc = XCreateGC(display, RootWindow(display,screen_num), 0, NULL);  
  576.         XSetFillStyle(display, gc, FillTiled);
  577.         XSetTile(display, gc, focus_tile);
  578.         first_time = False;
  579.     }
  580.  
  581.     /* get rid of old frames */
  582.     XClearWindow(display, RootWindow(display,screen_num));
  583.  
  584.     /* if focus is RootWindow, no frame drawn */
  585.     if (focus_window == RootWindow(display,screen_num)) return;
  586.  
  587.     /* get dimensions and position of focus_window*/
  588.     XGetWindowAttributes(display, focus_window, &win_attr); 
  589.  
  590.     XFillRectangle(display, RootWindow(display,screen_num), gc,
  591.         win_attr.x - frame_width, win_attr.y - frame_width,
  592.         win_attr.width + 2 * (win_attr.border_width + frame_width),
  593.         win_attr.height + 2 * (win_attr.border_width + frame_width));
  594. }
  595.  
  596. move_resize(menuwin, hand_cursor, move_or_resize) 
  597. Window menuwin;
  598. Cursor hand_cursor;
  599. Bool move_or_resize;
  600. {
  601.     XEvent report;
  602.     XWindowAttributes win_attr;
  603.     int press_x, press_y, release_x, release_y, move_x, move_y;
  604.     static int box_drawn = False;
  605.     int left, right, top, bottom;
  606.     Window root, child;
  607.     Window win_to_configure;
  608.     int win_x, win_y;
  609.     unsigned int mask;
  610.     unsigned int pressed_button;
  611.     XSizeHints size_hints;
  612.     Bool min_size, increment;
  613.     unsigned int width, height;
  614.     int temp_size;
  615.     static GC gc;
  616.     static int first_time = True;
  617.  
  618.     if (first_time) {
  619.         gc = XCreateGC(display, RootWindow(display,screen_num), 0, NULL);  
  620.         XSetSubwindowMode(display, gc, IncludeInferiors); 
  621.         XSetForeground(display, gc, BlackPixel(display, screen_num));
  622.         XSetFunction(display, gc, GXxor);
  623.         first_time = False;
  624.     }
  625.  
  626.     /* wait for ButtonPress choosing window to configure */
  627.     XMaskEvent(display, ButtonPressMask, &report); 
  628.     pressed_button = report.xbutton.button;
  629.  
  630.     /* which child of root was press in? */
  631.     XQueryPointer(display, RootWindow(display,screen_num), &root, 
  632.             &child, &press_x, &press_y, &win_x, 
  633.             &win_y, &mask);
  634.     win_to_configure = child;
  635.  
  636.     if ((win_to_configure == NULL)  || 
  637.             ((win_to_configure == menuwin) 
  638.             && (move_or_resize == RESIZE)))  {
  639.         /* if in RootWindow or resizing menuwin get 
  640.          * release event and get out */
  641.         while (XCheckMaskEvent(display, ButtonReleaseMask | ButtonPressMask, 
  642.                 &report))
  643.             ;
  644.         return;
  645.     }
  646.  
  647.     /* button press was in a valid subwindow of root */
  648.  
  649.     /* get original position and size of window */
  650.     XGetWindowAttributes(display, win_to_configure, 
  651.             &win_attr); 
  652.  
  653.     /* get size hints for the window */
  654.     XGetNormalHints(display, win_to_configure, &size_hints);
  655.     if (size_hints.flags && PMinSize)
  656.         min_size = True;
  657.     if (size_hints.flags && PResizeInc)
  658.         increment = True;
  659.  
  660.      /* now we need pointer motion events. */
  661.     XChangeActivePointerGrab(display, PointerMotionHintMask | 
  662.             ButtonMotionMask | ButtonReleaseMask | 
  663.             OwnerGrabButtonMask, hand_cursor, CurrentTime);
  664.  
  665.     /* don't allow other display operations during move,
  666.      * because Xor won't work properly otherwise */
  667.     XGrabServer(display);
  668.  
  669.     /* move outline of window until button release */
  670.     while  (1) {
  671.         XNextEvent(display, &report); 
  672.         switch (report.type) {
  673.             case ButtonRelease:
  674.                  if (report.xbutton.button == pressed_button) {
  675.                     if (box_drawn)
  676.                         undraw_box(gc, left, top, right, bottom);   
  677.  
  678.                     XUngrabServer(display);
  679.  
  680.                     /* get final window position */
  681.                     XQueryPointer(display, RootWindow(display,
  682.                             screen_num), &root, &child, &release_x, 
  683.                             &release_y, &win_x, &win_y, &mask);
  684.  
  685.                     /* move or resize window */
  686.                     if (move_or_resize == MOVE)
  687.                           XMoveWindow(display, win_to_configure, 
  688.                             win_attr.x + (release_x - press_x), 
  689.                             win_attr.y + (release_y - press_y));
  690.                     else
  691.                            XResizeWindow(display, win_to_configure, 
  692.                             right - left, bottom - top);
  693.                 
  694.                     XRaiseWindow(display, win_to_configure);
  695.                     XFlush(display);
  696.                     box_drawn = False;
  697.                     while (XCheckMaskEvent(display, ButtonReleaseMask | ButtonPressMask, 
  698.                             &report))
  699.                         ;
  700.                     return;
  701.                 }
  702.                 break;
  703.             
  704.             case MotionNotify:
  705.                 if (box_drawn == True) 
  706.                     undraw_box(gc, left, top, right, bottom);
  707.  
  708.                 /* can get rid of all MotionNotify events in queue, 
  709.                  * since otherwise the round-trip  delays caused by 
  710.                  * XQueryPointer may cause a backlog
  711.                  * of MotionNotify events, which will cause additional
  712.                 * wasted XQueryPointer calls. */
  713.                 while (XCheckTypedEvent(display, MotionNotify, 
  714.                         &report));
  715.         
  716.                 /* get current mouse position */
  717.                 XQueryPointer(display, RootWindow(display,screen_num), 
  718.                         &root, &child, &move_x, &move_y, 
  719.                         &win_x, &win_y, &mask);
  720.         
  721.                 if (move_or_resize == MOVE) {
  722.                        left = move_x - press_x + win_attr.x;
  723.                        top = move_y - press_y + win_attr.y;
  724.                        right = left + win_attr.width; 
  725.                        bottom = top + win_attr.height;
  726.                 }
  727.                 else
  728.                     {
  729.                     if (move_x < win_attr.x) move_x = 0;
  730.                     if (move_y < win_attr.y ) move_y = 0;
  731.                            left = win_attr.x;
  732.                            top = win_attr.y;
  733.                            right = left + win_attr.width + move_x     
  734.                                 - press_x; 
  735.                            bottom = top + win_attr.height + move_y 
  736.                                 - press_y; 
  737.                     /* must adjust size according to size hints */
  738.                     /* enforce minimum dimensions */
  739.                     width = right - left;
  740.                     height = bottom - top;
  741.  
  742.                     /* make sure dimension are increment of
  743.                      * width_inc and height_inc and at least
  744.                      * min_width and min_height */
  745.                     for (temp_size = size_hints.min_width; 
  746.                             temp_size < width; 
  747.                             temp_size += size_hints.width_inc)
  748.                         ;
  749.                         
  750.                     for (temp_size = size_hints.min_height; 
  751.                             temp_size < height; 
  752.                             temp_size += size_hints.height_inc)
  753.                         ;
  754.                     /* most applications (xterm inc.)
  755.                      * pad their right and bottom
  756.                      * dimensions by 2 pixels */
  757.                     right = left + temp_size + 2;
  758.                     bottom = top + temp_size + 2;
  759.                     }
  760.         
  761.                 draw_box(gc, left, top, right, bottom);
  762.                 box_drawn = True;
  763.                 break;
  764.             default:
  765.                 /* StructureNotify events shouldn't appear here,
  766.                  * because of the ChangeActivePointerGrab
  767.                  * call, but they do for some reason. */
  768.                 /* Anyway, it doesn't matter */
  769.                 /* fprintf(stderr, "unexpected event type %s\n", 
  770.                         report.type); */
  771.                 ;
  772.         } /* end switch */
  773.     } /* end outer while */
  774. } /* end move */
  775.  
  776. #ifdef SYSV
  777. #ifndef hpux
  778. #define vfork() fork()
  779. #endif /* hpux */
  780. #endif /* SYSV */
  781.  
  782. /* the following procedure is a copy of the implementation of 
  783.  * system, modified to reset the handling of SIGINT, SIGQUIT, 
  784.  * and SIGHUP before exec-ing */
  785. execute(s)
  786. char *s;
  787. {
  788.     int status, pid, w;
  789.     register int (*istat)(), (*qstat)();
  790.  
  791.     if ((pid = vfork()) == 0) {
  792.         signal(SIGINT, SIG_DFL);
  793.         signal(SIGQUIT, SIG_DFL);
  794.         signal(SIGHUP, SIG_DFL);
  795.         execl("/bin/sh", "sh", "-c", s, 0);
  796.         _exit(127);
  797.     }
  798.     istat = signal(SIGINT, SIG_IGN);
  799.     qstat = signal(SIGQUIT, SIG_IGN);
  800.     while ((w = wait(&status)) != pid && w != -1)
  801.         ;
  802.     if (w == -1)
  803.         status = -1;
  804.     signal(SIGINT, istat);
  805.     signal(SIGQUIT, qstat);
  806.     return(status);
  807. }
  808.