home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume3 / awm2 / part03 / Resize.c
Encoding:
C/C++ Source or Header  |  1989-02-17  |  15.2 KB  |  536 lines

  1.  
  2.  
  3.  
  4. #ifndef lint
  5. static char *rcsid_Resize_c = "$Header: /usr/graph2/X11.3/contrib/windowmgrs/awm/RCS/Resize.c,v 1.2 89/02/07 21:23:37 jkh Exp $";
  6. #endif    lint
  7.  
  8. #include "X11/copyright.h"
  9. /*
  10.  *
  11.  * Copyright 1987, 1988 by Ardent Computer Corporation, Sunnyvale, Ca.
  12.  *
  13.  * Copyright 1987 by Jordan Hubbard.
  14.  *
  15.  *
  16.  *                         All Rights Reserved
  17.  *
  18.  * Permission to use, copy, modify, and distribute this software and its
  19.  * documentation for any purpose and without fee is hereby granted,
  20.  * provided that the above copyright notice appear in all copies and that
  21.  * both that copyright notice and this permission notice appear in
  22.  * supporting documentation, and that the name of Ardent Computer
  23.  * Corporation or Jordan Hubbard not be used in advertising or publicity
  24.  * pertaining to distribution of the software without specific, written
  25.  * prior permission.
  26.  *
  27.  */
  28.  
  29. /*
  30.  * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
  31.  *
  32.  *                         All Rights Reserved
  33.  *
  34.  * Permission to use, copy, modify, and distribute this software and its
  35.  * documentation for any purpose and without fee is hereby granted,
  36.  * provided that the above copyright notice appear in all copies and that
  37.  * both that copyright notice and this permission notice appear in
  38.  * supporting documentation, and that the name of Digital Equipment
  39.  * Corporation not be used in advertising or publicity pertaining to
  40.  * distribution of the software without specific, written prior permission.
  41.  *
  42.  *
  43.  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  44.  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  45.  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  46.  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  47.  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  48.  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  49.  * SOFTWARE.
  50.  */
  51.  
  52. /*
  53.  * MODIFICATION HISTORY
  54.  *
  55.  * 000 -- M. Gancarz, DEC Ultrix Engineering Group
  56.  * 001 -- Loretta Guarino Reid, DEC Ultrix Engineering Group
  57.  *        Convert to X11
  58.  * 002 -- Jordan Hubbard, U.C. berkeley.
  59.  *    Added alternate placement of resize window, code for title bar
  60.  *     support.
  61.  */
  62.  
  63. #include "awm.h"
  64. #include "X11/Xutil.h"
  65.  
  66. #define max(a,b) ( (a) > (b) ? (a) : (b) )
  67. #define min(a,b) ( (a) > (b) ? (b) : (a) )
  68. #define makemult(a, b) ((b==1) ? (a) : (((int)((a) / (b))) * (b)) )
  69.  
  70. /*ARGSUSED*/
  71. Boolean Resize(window, mask, button, x0, y0)
  72. Window window;                          /* Event window. */
  73. int mask;                               /* Button/key mask. */
  74. int button;                             /* Button event detail. */
  75. int x0, y0;                             /* Event mouse position. */
  76. {
  77.      XWindowAttributes client_info;    /* client window info. */
  78.      XWindowAttributes frame_info;    /* frame window info */
  79.      int x1, y1;                        /* fixed box corner   */
  80.      int x2, y2;                        /* moving box corner   */
  81.      int x, y;
  82.      int xinc, yinc;
  83.      int minwidth, minheight;
  84.      int maxwidth, maxheight;
  85.      int ox, oy;            /* which quadrant of window */
  86.      int pop_x, pop_y;            /* location of pop window */
  87.      int hsize, vsize;            /* dynamic size */
  88.      int delta;    
  89.      int junk_x, junk_y;
  90.      unsigned int ptrmask;        /* pointer status word */
  91.      int num_vectors;            /* Number of vectors to XDraw. */
  92.      Window sub_win;            /* Mouse query sub window. */
  93.      Window root;            /* Root query window. */
  94.      XEvent button_event, *b_ev;    /* Button event packet. */
  95.      XSegment box[MAX_BOX_VECTORS];    /* Box drawing vertex buffer. */
  96.      XSegment zap[MAX_ZAP_VECTORS];    /* Zap drawing vertex buffer. */
  97.      Boolean stop;            /* Should the window stop changing? */
  98.      XSizeHints sizehints;
  99.      XWindowChanges values;
  100.      int width_offset, height_offset;    /* to subtract if resize increments */
  101.      int x_offset, y_offset;        /* add to pointer to get anchor */
  102.      AwmInfoPtr awi;
  103.      int (*storegrid_func)();        /* which StoreGrid routine to use */
  104.      int (*storebox_func)();        /* which StoreBox routing to use */
  105.      int buttonConfirmEvent;
  106.      extern void ungrab_pointer();
  107.      extern void grab_pointer();
  108.  
  109.      Entry("Resize")
  110.  
  111.      /*
  112.       * Do nothing if the event window is the root window.
  113.       */
  114.      if (window == RootWindow(dpy, scr))
  115.       Leave(FALSE)
  116.  
  117.      /*
  118.       * Gather info about the event window.
  119.       */
  120.      awi = GetAwmInfo(window);
  121.      if (!awi)
  122.       Leave(FALSE)
  123.      /*
  124.       * Do not resize an icon window.
  125.       */
  126.      if (window == awi->icon)
  127.       Leave(FALSE)
  128.  
  129.      window = awi->client;
  130.      b_ev = &button_event;
  131.      buttonConfirmEvent = ButtonRelease;
  132.  
  133.      status = XGetWindowAttributes(dpy, window, &client_info);
  134.      if (status == FAILURE)
  135.       Leave(FALSE)
  136.  
  137.      if (awi->frame) { /* we have to compensate */
  138.       status = XGetWindowAttributes(dpy, awi->frame, &frame_info);
  139.       client_info.y = frame_info.y;
  140.       client_info.x = frame_info.x;
  141.       if (status == FAILURE)
  142.            Leave(FALSE)
  143.           if (DECORATED(awi)) {
  144.            if (awi->title)
  145.             client_info.y += titleHeight + 2;
  146.            if (awi->attrs & AT_BORDER) {
  147.             client_info.x += BContext + 1;
  148.             if (!awi->title)
  149.              client_info.y += BContext + 1;
  150.            }
  151.       }
  152.      }
  153.  
  154.      /*
  155.       * Clear The vector buffers.
  156.       */
  157.      bzero(box, sizeof(box));
  158.      if (Zap)
  159.       bzero(zap, sizeof(zap));
  160.      storegrid_func = StoreGridBox;
  161.      storebox_func = StoreBox;
  162.  
  163.      /*
  164.       * If we are here then we have a resize operation in progress.
  165.       */
  166.      
  167.      /*
  168.       * Turn on the resize cursor.
  169.       */
  170.      grab_pointer();
  171.      /*
  172.       * calculate fixed point (x1, y1) and varying point (x2, y2).
  173.       */
  174.      hsize = client_info.width;
  175.      vsize = client_info.height;
  176.      x1 = client_info.x;
  177.      y1 = client_info.y;
  178.      x2 = x1 + hsize;
  179.      y2 = y1 + vsize;
  180.  
  181.      /*
  182.       * Get the event window resize hint.
  183.       */
  184.      sizehints.flags = 0;
  185.      XGetSizeHints(dpy, window, &sizehints, XA_WM_NORMAL_HINTS); 
  186.      CheckConsistency(&sizehints);
  187.  
  188.      /* until there are better WM_HINTS, we'll assume that the client's
  189.       * minimum width and height are the appropriate offsets to subtract
  190.       * when resizing with an explicit resize increment.
  191.       */
  192.      if ((sizehints.flags & PMinSize) && (sizehints.flags & PResizeInc)) {
  193.       width_offset = sizehints.min_width;
  194.       height_offset = sizehints.min_height;
  195.      } else
  196.       width_offset = height_offset = 0;
  197.  
  198.      /*
  199.       * decide what resize mode we are in. Always rubberband if window
  200.       * is too small.
  201.       */
  202.      if (client_info.width > 2 && client_info.height > 2) {
  203.       ox = ((x0 - client_info.x) * 3) / client_info.width;
  204.       oy = ((y0 - client_info.y) * 3) / client_info.height;
  205.       if ((ox + oy) & 1) {
  206.            if (ox & 1) {
  207.             /* fix up size hints so that we will never change width */
  208.             sizehints.min_width = sizehints.max_width =
  209.              client_info.width;
  210.             if ((sizehints.flags & PMinSize) == 0) {
  211.              sizehints.min_height = 0;
  212.              sizehints.flags |= PMinSize;
  213.             }
  214.             if ((sizehints.flags & PMaxSize) == 0) {
  215.              sizehints.max_height = DisplayHeight(dpy, scr);
  216.              sizehints.flags |= PMaxSize;
  217.             }
  218.            }
  219.            if (oy & 1) {
  220.             /* fix up size hints so that we will never change height */
  221.             sizehints.min_height = sizehints.max_height =
  222.              client_info.height;
  223.             if ((sizehints.flags & PMinSize)==0) {
  224.              sizehints.min_width = 0;
  225.              sizehints.flags |= PMinSize;
  226.             }
  227.             if ((sizehints.flags & PMaxSize)==0) {
  228.              sizehints.max_width = DisplayWidth(dpy, scr);
  229.              sizehints.flags |= PMaxSize;
  230.             }
  231.            }
  232.       }
  233.      }
  234.      else ox = oy = 2;
  235.      /* change fixed point to one that shouldn't move */
  236.      if (oy == 0) { 
  237.       y = y1; y1 = y2; y2 = y;
  238.      }
  239.      if (ox == 0) { 
  240.       x = x1; x1 = x2; x2 = x;
  241.      }
  242.      if (sizehints.flags & PMinSize) {
  243.       minwidth = sizehints.min_width;
  244.       minheight = sizehints.min_height;
  245.      } else {
  246.       minwidth = 0;
  247.       minheight = 0;
  248.      }
  249.      if (sizehints.flags & PMaxSize) {
  250.       maxwidth = max(sizehints.max_width, minwidth);
  251.       maxheight = max(sizehints.max_height, minheight);
  252.      } else {
  253.       maxwidth = DisplayWidth(dpy, scr);
  254.       maxheight = DisplayHeight(dpy, scr);
  255.      }
  256.      if (sizehints.flags & PResizeInc) {
  257.       xinc = sizehints.width_inc;
  258.       yinc = sizehints.height_inc;
  259.      } else {
  260.       xinc = 1;
  261.       yinc = 1;
  262.      }
  263.      switch (ox) {
  264.      case 0:
  265.       pop_x = x1 - PWidth;
  266.       break;
  267.      case 1:
  268.       pop_x = x1 + (hsize - PWidth) / 2;
  269.       break;
  270.      case 2:
  271.       pop_x = x1;
  272.       break;
  273.      }
  274.      switch (oy) {
  275.      case 0:
  276.       pop_y = y1 - PHeight;
  277.       break;
  278.      case 1:
  279.       pop_y = y1 + (vsize - PHeight) / 2;
  280.       break;
  281.      case 2:
  282.       pop_y = y1;
  283.       break;
  284.      }
  285.      /*
  286.       * Double expose on the target window is too expensive for some reason
  287.       * or another. Paint the popup window in the upper left hand
  288.       * corner of the screen if RootResizeBox is FALSE. This is also
  289.       * more-or-less consistent with the position of the map request popup.
  290.       */
  291.      if (RootResizeBox == TRUE)
  292.       values.x = values.y = 0;
  293.      else {
  294.       if (pop_x < 0 || pop_x > (DisplayWidth(dpy, scr) - PWidth))
  295.            pop_x = 0;
  296.       if (pop_y < 0 || pop_y > (DisplayHeight(dpy, scr) - PHeight))
  297.            pop_y = 0;
  298.       values.x = pop_x;
  299.       values.y = pop_y;
  300.      }
  301.      values.stack_mode = Above;
  302.      XConfigureWindow(dpy, Pop, (unsigned int) CWX|CWY|CWStackMode, &values);
  303.      XMapWindow(dpy, Pop);
  304.      if (Grid) {
  305.       num_vectors = (*storegrid_func)(box,
  306.                       MIN(x1, x2), MIN(y1, y2),
  307.                       MAX(x1, x2), MAX(y1, y2));
  308.      }
  309.      else {
  310.       num_vectors = (*storebox_func)(box,
  311.                      MIN(x1, x2), MIN(y1, y2),
  312.                      MAX(x1, x2), MAX(y1, y2));
  313.      }
  314.  
  315.      /*
  316.       * If we freeze the server, then we will draw solid
  317.       * lines instead of flickering ones during resizing.
  318.       */
  319.      if (Freeze)
  320.       XGrabServer(dpy);
  321.      /* protect us from ourselves */
  322.      Snatched = True;
  323.      /*
  324.       * Process any pending exposure events before drawing the box.
  325.       */
  326.      while (QLength(dpy) > 0) {
  327.       XPeekEvent(dpy, b_ev);
  328.       if (b_ev->xany.window == RootWindow(dpy, scr))
  329.            break;
  330.       GetButton(b_ev);
  331.      }
  332.      if (ResizeRelative) {
  333.       x_offset = x2 - x0;
  334.       y_offset = y2 - y0;
  335.      }
  336.      else
  337.       x_offset = y_offset = 0;
  338.  
  339.      /*
  340.       * Now draw the box.
  341.       */
  342.      DrawBox();
  343.      Frozen = window;
  344.  
  345.      stop = FALSE;
  346.      x = -1; y = -1;
  347.      
  348.      while (!stop) {
  349.       if (x != x2 || y != y2) {
  350.            x = x2; y = y2;
  351.  
  352.            /*
  353.         * If we've frozen the server, then erase
  354.         * the old box.
  355.         */
  356.            if (Freeze)
  357.             DrawBox();
  358.            
  359.            if (Grid) {
  360.             num_vectors = (*storegrid_func)(box,
  361.                             MIN(x1, x), MIN(y1, y),
  362.                             MAX(x1, x), MAX(y1, y));
  363.            }
  364.            else {
  365.             num_vectors = (*storebox_func)(box,
  366.                            MIN(x1, x), MIN(y1, y),
  367.                            MAX(x1, x), MAX(y1, y));
  368.            }
  369.            
  370.            if (Freeze)
  371.             DrawBox();
  372.            
  373.            {
  374.             int Hsize = (hsize - width_offset) / xinc;
  375.             int Vsize = (vsize - height_offset) / yinc;
  376.             int pos = 4;
  377.             PText[0] = (Hsize>99) ? (Hsize / 100 + '0')      : ' ';
  378.             PText[1] = (Hsize>9)  ? ((Hsize / 10) % 10 + '0') : ' ';
  379.             PText[2] = Hsize % 10 + '0';
  380.             if (Vsize>99) PText[pos++] = Vsize / 100 + '0';
  381.             if (Vsize>9)  PText[pos++] = (Vsize / 10) % 10 + '0';
  382.             PText[pos++] = Vsize % 10 + '0';
  383.             while (pos<7) PText[pos++] = ' ';
  384.            }
  385.            /*
  386.         * If the font is not fixed width we have to
  387.         * clear the window to guarantee that the characters
  388.         * that were there before are erased.
  389.         */
  390.            if (!(PFontInfo->per_char))
  391.             XClearWindow(dpy, Pop);
  392.            XDrawImageString(
  393.                 dpy, Pop, PopGC,
  394.                 PPadding, PPadding+PFontInfo->ascent,
  395.                 PText, PTextSize);
  396.       }
  397.       if (!Freeze) {
  398.            DrawBox();
  399.            DrawBox();
  400.       }
  401.  
  402.       if (XPending(dpy) && !ProcessRequests(box, num_vectors) &&
  403.           GetButton(b_ev)) {
  404.            if ((b_ev->xany.type != ButtonPress) && 
  405.            (b_ev->xany.type != ButtonRelease))
  406.             continue; /* spurious menu event... */
  407.  
  408.            if (Freeze) {
  409.             DrawBox();
  410.             Frozen = (Window)0;
  411.             XUngrabServer(dpy);
  412.            }
  413.  
  414.            if (b_ev->xany.type == buttonConfirmEvent &&
  415.            b_ev->xbutton.button == button)
  416.             stop = TRUE;
  417.            else {
  418.             XUnmapWindow(dpy, Pop);
  419.             ResetCursor(button);
  420.             Snatched = False;
  421.             ungrab_pointer();
  422.             Leave(TRUE)
  423.            }
  424.       }
  425.       else {
  426.            XQueryPointer(dpy, RootWindow(dpy, scr), &root, 
  427.                  &sub_win, &x2, &y2, &junk_x, &junk_y, &ptrmask);
  428.            x2 += x_offset;    /* get to anchor point */
  429.            y2 += y_offset;
  430.       }
  431.       hsize = max(min(abs (x2 - x1), maxwidth), minwidth);
  432.       hsize = makemult(hsize - minwidth, xinc) + minwidth;
  433.  
  434.       vsize = max(min(abs(y2 - y1), maxheight), minheight);
  435.       vsize = makemult(vsize - minheight, yinc) + minheight; 
  436.       if (sizehints.flags & PAspect) {
  437.            if ((hsize * sizehints.max_aspect.y > 
  438.             vsize * sizehints.max_aspect.x)) {
  439.             delta = makemult((hsize * sizehints.max_aspect.y /
  440.                       sizehints.max_aspect.x) - vsize, 
  441.                      yinc);
  442.             if ((vsize + delta <= maxheight))
  443.              vsize += delta;
  444.             else {
  445.              delta = makemult(hsize - 
  446.                       (sizehints.max_aspect.x *
  447.                        vsize/sizehints.max_aspect.y), 
  448.                       xinc);
  449.              if (hsize - delta >= minwidth)
  450.                   hsize -= delta; 
  451.             }
  452.            }  
  453.            if (hsize * sizehints.min_aspect.y < vsize *
  454.            sizehints.min_aspect.x) {
  455.             delta = makemult((sizehints.min_aspect.x * 
  456.                       vsize/sizehints.min_aspect.y) - hsize, 
  457.                      xinc);
  458.             if (hsize + delta <= maxwidth)
  459.              hsize += delta;
  460.             else {
  461.              delta = makemult(vsize - 
  462.                       (hsize*sizehints.min_aspect.y /
  463.                        sizehints.min_aspect.x), 
  464.                       yinc); 
  465.              if (vsize - delta >= minheight)
  466.                 vsize -= delta; 
  467.             }
  468.            }
  469.            
  470.       }
  471.       if (ox == 0)
  472.            x2 = x1 - hsize;
  473.       else
  474.            x2 = x1 + hsize;
  475.       
  476.       if (oy == 0)
  477.            y2 = y1 - vsize;
  478.       else
  479.            y2 = y1 + vsize;
  480.       
  481.      }
  482.      if (x2 < x1) {
  483.       x = x1; x1 = x2; x2 = x;
  484.      }
  485.      if (y2 < y1) {
  486.       y = y1; y1 = y2; y2 = y;
  487.      }
  488.      XUnmapWindow(dpy, Pop);
  489.      if ((x1 !=client_info.x) || (y1 != client_info.y) || 
  490.      (hsize != client_info.width) ||
  491.      (vsize != client_info.height)) {
  492.       XWindowChanges xwc;
  493.            
  494.       xwc.x = x1;
  495.       xwc.y = y1;
  496.       xwc.width = hsize;
  497.       xwc.height = vsize;
  498.       ConfigureWindow(window, 
  499.               (unsigned int) CWX | CWY | CWHeight | CWWidth, &xwc);
  500.      }
  501.      Snatched = False;
  502.      ungrab_pointer();
  503.      Leave(TRUE)
  504. }
  505.  
  506. CheckConsistency(hints)
  507. XSizeHints *hints;
  508. {
  509.      Entry("CheckConsistency")
  510.  
  511.      if (hints->min_height < 0)
  512.       hints->min_height = 0;
  513.      if (hints->min_width < 0)
  514.       hints->min_width = 0;
  515.      
  516.      if (hints->max_height <= 0 || hints->max_width <= 0)
  517.       hints->flags &= ~PMaxSize;
  518.      
  519.      hints->min_height = min(DisplayHeight(dpy, scr), hints->min_height);
  520.      hints->min_width =  min(DisplayWidth(dpy, scr),  hints->min_width);
  521.      
  522.      hints->max_height = min(DisplayHeight(dpy, scr), hints->max_height);
  523.      hints->max_width =  min(DisplayWidth(dpy, scr),  hints->max_width);
  524.      
  525.      if ((hints->flags & PMinSize) && (hints->flags & PMaxSize) && 
  526.      ((hints->min_height > hints->max_height) ||
  527.       (hints->min_width > hints->max_width)))
  528.       hints->flags &= ~(PMinSize|PMaxSize);
  529.      
  530.      if ((hints->flags & PAspect) && 
  531.      (hints->min_aspect.x * hints->max_aspect.y > 
  532.       hints->max_aspect.x * hints->min_aspect.y))
  533.       hints->flags &= ~(PAspect);
  534.      Leave_void
  535. }
  536.