home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / gwm18a.zip / user.c < prev    next >
C/C++ Source or Header  |  1995-07-03  |  41KB  |  1,347 lines

  1. /* Copyright 1989 GROUPE BULL -- See license conditions in file COPYRIGHT
  2.  * Copyright 1989 Massachusetts Institute of Technology
  3.  */
  4. /*************************************************\
  5. *                           *
  6. *     BULL WINDOW MANAGER for X11 .          *
  7. *                           *
  8. *     MODULE handling interactions with user      *
  9. *                           *
  10. \*************************************************/
  11.  
  12. /*  include  */
  13.  
  14. #include        "EXTERN.h"
  15. #include    "wool.h"
  16. #include     "wl_atom.h"
  17. #include     "gwm.h"
  18. #include     "wl_number.h"
  19. #include     "wl_string.h"
  20. #include     "wl_pixmap.h"
  21. #include     "wl_cursor.h"
  22.  
  23. /*  local  */
  24.                          
  25. static int    inner_ulx, inner_uly;/* ul corner of inner window */
  26. static int    inner_lrbx, inner_lrby;/* lr corner of inner window, counted
  27.                           from the lr corner of outer window
  28.                           */
  29.     /* inner dims are the inner of the client window */
  30. #define MAKE_INNER_DIMS \
  31.   { int tmp;\
  32.     tmp = cw -> inner_x + cw -> box.borderwidth;\
  33.     inner_ulx = Max(1, tmp);\
  34.     tmp = cw -> inner_y + cw -> box.borderwidth;\
  35.     inner_uly = Max(1, tmp);\
  36.     tmp = lrx - ulx - cw -> inner_width - cw -> \
  37.     box.borderwidth - cw -> inner_x - 2 * cw -> inner_borderwidth + 1;\
  38.     inner_lrbx = Max(1, tmp);\
  39.     tmp = lry - uly - cw -> inner_height - cw ->\
  40.     box.borderwidth - cw -> inner_y - 2 * cw -> inner_borderwidth + 1;\
  41.     inner_lrby = Max(1, tmp);\
  42.   }
  43.  
  44. static    int             xdir, ydir;    /* resize dirs */
  45. char * MakeUserDims(), *MakePairUserDims();
  46.  
  47. /*  global  */
  48.  
  49. extern Wob    GetTarget();
  50. extern WOOL_OBJECT MeterClose();
  51.  
  52. /*  routines  */
  53.  
  54. /*
  55.  * type of grid:
  56.  *     0    outer rectangle of the window (default)
  57.  *     1    outer rectangle divided in 9 (uwm-style)
  58.  *     2    outer rectangle with center cross (X) inside
  59.  *     3    outer rectangle + inner (client) outline
  60.  *     4    styles 1 and 3 combined
  61.  *    5    2-pixel wide grid
  62.  */
  63.  
  64. #define MAX_GRID_SEGMENTS    1024
  65.  
  66. int 
  67. StoreBox(type, box, ulx, uly, lrx, lry)
  68. int type;            /* the type of grid */
  69. XSegment box[];
  70. int ulx;            /* Upper left X coordinate. */
  71. int uly;            /* Upper left Y coordinate. */
  72. int lrx;            /* Lower right X coordinate. */
  73. int lry;            /* Lower right Y coordinate. */
  74. {
  75.     int             number_of_segments = 8;
  76.  
  77.     box[0].x1 = ulx;
  78.     box[0].y1 = uly;
  79.     box[0].x2 = lrx;
  80.     box[0].y2 = uly;
  81.  
  82.     box[1].x1 = lrx;
  83.     box[1].y1 = uly;
  84.     box[1].x2 = lrx;
  85.     box[1].y2 = lry;
  86.  
  87.     box[2].x1 = lrx;
  88.     box[2].y1 = lry;
  89.     box[2].x2 = ulx;
  90.     box[2].y2 = lry;
  91.  
  92.     box[3].x1 = ulx;
  93.     box[3].y1 = lry;
  94.     box[3].x2 = ulx;
  95.     box[3].y2 = uly;
  96.  
  97.     switch (type) {
  98.     case 5:            /* MwmLike grid */
  99.     box[4].x1 = ulx + 1;
  100.     box[4].y1 = uly + 1;
  101.     box[4].x2 = lrx - 1;
  102.     box[4].y2 = uly + 1;
  103.  
  104.     box[5].x1 = ulx + 1;
  105.     box[5].y1 = uly + 1;
  106.     box[5].x2 = ulx + 1;
  107.     box[5].y2 = lry - 1;
  108.  
  109.     box[6].x1 = ulx + 1;
  110.     box[6].y1 = lry - 1;
  111.     box[6].x2 = lrx - 1;
  112.     box[6].y2 = lry - 1;
  113.  
  114.     box[7].x1 = lrx - 1;
  115.     box[7].y1 = uly + 1;
  116.     box[7].x2 = lrx - 1;
  117.     box[7].y2 = lry - 1;
  118.  
  119.     return (8) ;
  120.  
  121.     case 4:            /* 9-squares grid + inner outline */
  122.     box[8].x1 = ulx + (lrx - ulx) / 3;
  123.     box[8].y1 = uly;
  124.     box[8].x2 = box[8].x1;
  125.     box[8].y2 = lry;
  126.  
  127.     box[9].x1 = lrx - (lrx - ulx) / 3;
  128.     box[9].y1 = uly;
  129.     box[9].x2 = box[9].x1;
  130.     box[9].y2 = lry;
  131.  
  132.     box[10].x1 = ulx;
  133.     box[10].y1 = uly + (lry - uly) / 3;
  134.     box[10].x2 = lrx;
  135.     box[10].y2 = box[10].y1;
  136.  
  137.     box[11].x1 = ulx;
  138.     box[11].y1 = lry - (lry - uly) / 3;
  139.     box[11].x2 = lrx;
  140.     box[11].y2 = box[11].y1;
  141.  
  142.     number_of_segments = 12;
  143.  
  144.     case 3:            /* + inner outline */
  145.     if (inner_uly) {
  146.         box[4].x1 = ulx + inner_ulx;
  147.         box[4].y1 = uly + inner_uly;
  148.         box[4].x2 = lrx - inner_lrbx;
  149.         box[4].y2 = box[4].y1;
  150.     } else {
  151.         box[4].x1 = box[4].y1 = box[4].x2 = box[4].y2 = 0;
  152.     }
  153.     if (inner_lrbx) {
  154.         box[5].x1 = lrx - inner_lrbx;
  155.         box[5].y1 = uly + inner_uly;
  156.         box[5].x2 = box[5].x1;
  157.         box[5].y2 = lry - inner_lrby;
  158.     } else {
  159.         box[5].x1 = box[5].y1 = box[5].x2 = box[5].y2 = 0;
  160.     }
  161.     if (inner_lrby) {
  162.         box[6].x1 = lrx - inner_lrbx;
  163.         box[6].y1 = lry - inner_lrby;
  164.         box[6].x2 = ulx + inner_ulx;
  165.         box[6].y2 = lry - inner_lrby;
  166.     } else {
  167.         box[6].x1 = box[6].y1 = box[6].x2 = box[6].y2 = 0;
  168.     }
  169.     if (inner_ulx) {
  170.         box[7].x1 = ulx + inner_ulx;
  171.         box[7].y1 = lry - inner_lrby;
  172.         box[7].x2 = ulx + inner_ulx;
  173.         box[7].y2 = uly + inner_uly;
  174.     } else {
  175.         box[7].x1 = box[7].y1 = box[7].x2 = box[7].y2 = 0;
  176.     }
  177.  
  178.     return number_of_segments;
  179.  
  180.     case 2:            /* cross grid */
  181.     box[4].x1 = ulx;
  182.     box[4].y1 = uly;
  183.     box[4].x2 = lrx;
  184.     box[4].y2 = lry;
  185.  
  186.     box[5].x1 = ulx;
  187.     box[5].y1 = lry;
  188.     box[5].x2 = lrx;
  189.     box[5].y2 = uly;
  190.  
  191.     return (6);
  192.  
  193.     case 1:            /* 9-squares grid */
  194.     box[4].x1 = ulx + (lrx - ulx) / 3;
  195.     box[4].y1 = uly;
  196.     box[4].x2 = box[4].x1;
  197.     box[4].y2 = lry;
  198.  
  199.     box[5].x1 = lrx - (lrx - ulx) / 3;
  200.     box[5].y1 = uly;
  201.     box[5].x2 = box[5].x1;
  202.     box[5].y2 = lry;
  203.  
  204.     box[6].x1 = ulx;
  205.     box[6].y1 = uly + (lry - uly) / 3;
  206.     box[6].x2 = lrx;
  207.     box[6].y2 = box[6].y1;
  208.  
  209.     box[7].x1 = ulx;
  210.     box[7].y1 = lry - (lry - uly) / 3;
  211.     box[7].x2 = lrx;
  212.     box[7].y2 = box[7].y1;
  213.  
  214.     return (8);
  215.  
  216.     default:            /* simple outer square */
  217.     return (4);
  218.     }
  219. }
  220. int 
  221. AddBox(Nprevious, type , box, ulx, uly, lrx, lry)
  222. int type, Nprevious;            /* the type of grid */
  223. XSegment box[];
  224. int ulx;            /* Upper left X coordinate. */
  225. int uly;            /* Upper left Y coordinate. */
  226. int lrx;            /* Lower right X coordinate. */
  227. int lry;            /* Lower right Y coordinate. */
  228. {
  229.     int             number_of_segments = 8;
  230.  
  231.     box[Nprevious + 0].x1 = ulx;
  232.     box[Nprevious + 0].y1 = uly;
  233.     box[Nprevious + 0].x2 = lrx;
  234.     box[Nprevious + 0].y2 = uly;
  235.  
  236.     box[Nprevious + 1].x1 = lrx;
  237.     box[Nprevious + 1].y1 = uly;
  238.     box[Nprevious + 1].x2 = lrx;
  239.     box[Nprevious + 1].y2 = lry;
  240.  
  241.     box[Nprevious + 2].x1 = lrx;
  242.     box[Nprevious + 2].y1 = lry;
  243.     box[Nprevious + 2].x2 = ulx;
  244.     box[Nprevious + 2].y2 = lry;
  245.  
  246.     box[Nprevious + 3].x1 = ulx;
  247.     box[Nprevious + 3].y1 = lry;
  248.     box[Nprevious + 3].x2 = ulx;
  249.     box[Nprevious + 3].y2 = uly;
  250.  
  251.     /* simple outer square */
  252.     return (Nprevious + 4);
  253. }
  254.  
  255. WOOL_OBJECT
  256. UserMoveWindow(cw)
  257.     ClientWindow cw;
  258. {
  259.     int       prev_x;            /* Previous evt window X location. */
  260.     int       prev_y;            /* Previous evt window Y location. */
  261.     int       cur_x;            /* Current event window X location. */
  262.     int       cur_y;            /* Current event window Y location. */
  263.     int       root_x;            /* Root window X location. */
  264.     int       root_y;            /* Root window Y location. */
  265.     int       ulx, uly;            /* Event window upper left X, Y. */
  266.     int       lrx, lry;            /* Event window lower right X, Y. */
  267.     int       num_vectors;        /* Number of vectors in box. */
  268.     unsigned int ptrmask;        /* state of ptr when queried */
  269.     Window    sub_window;        /* Query mouse event sub-window. */
  270.     Window    root;            /* Query mouse event root. */
  271.     XEvent    button_event;        /* Button event packet. */
  272.     XSegment  box[MAX_GRID_SEGMENTS];    /* Box vertex buffer. */
  273.     unsigned long mask = ButtonPressMask | ButtonReleaseMask;
  274.     int       called_from_press;    /* aborts on press! */
  275.     int       called_from_press_button;    /* aborts on press! */
  276.     WOOL_Cursor cursor;
  277.  
  278.     /* Get Position of pointer of the event */
  279.     XQueryPointer(dpy, Context->root,
  280.     &root, &sub_window,
  281.     &root_x, &root_y, &cur_x, &cur_y, &ptrmask);
  282.     if (root != Context->root) {    /* cursor is on another screen */
  283.     return (WOOL_OBJECT) WLNumber_make(1);
  284.     }
  285.     if (TriggeringEvent && TriggeringEvent->type == ButtonPress) {
  286.     cur_x = TriggeringEvent->xbutton.x_root;
  287.     cur_y = TriggeringEvent->xbutton.y_root;
  288.     called_from_press = 1;
  289.     called_from_press_button = TriggeringEvent->xbutton.button;
  290.     /* if button has been released, aborts! */
  291.     if (GWM_UserSynchronous && !(ptrmask &
  292.         (Button1Mask << (called_from_press_button - Button1))))
  293.         return (WOOL_OBJECT) WLNumber_make(3);
  294.     }
  295.     else {
  296.     /* put the pointer always inside the window */
  297.     cur_x = Max(cur_x, cw->box.x);
  298.     cur_y = Max(cur_y, cw->box.y);
  299.     cur_x = Min(cur_x, cw->box.x + cw->box.width +
  300.         2 * cw->box.borderwidth);
  301.     cur_y = Min(cur_y, cw->box.y + cw->box.height +
  302.         2 * cw->box.borderwidth);
  303.     called_from_press = 0;
  304.     }
  305.  
  306.     cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursor, (WA_cursor));
  307.     if (XGrabPointer(dpy, Context->root, FALSE, mask,
  308.         GrabModeAsync, GrabModeAsync, None,
  309.         (cursor == (WOOL_Cursor) NIL ? None : cursor->cursor),
  310.         CurrentTime)
  311.     != GrabSuccess)
  312.     return (WOOL_OBJECT) WLNumber_make(0);
  313.     if (GWM_GrabServer)
  314.     XGrabServer(dpy);
  315.     XSetForeground(dpy, Context->gc.Draw, Context->pixel.GridColor);
  316.  
  317.     /* Initialize movement variables. */
  318.     ulx = cw->box.x;
  319.     uly = cw->box.y;
  320.     lrx = cw->box.x + cw->box.width + (cw->box.borderwidth * 2) - 1;
  321.     lry = cw->box.y + cw->box.height + (cw->box.borderwidth * 2) - 1;
  322.     MAKE_INNER_DIMS
  323.  
  324.     /* Store the box. */
  325.     num_vectors = StoreBox(GWM_Movegrid, box, ulx, uly, lrx, lry);
  326.  
  327.     /* Initialize the previous location variables. */
  328.     prev_x = cur_x;
  329.     prev_y = cur_y;
  330.  
  331.     /* Now draw the box. */
  332.     XDrawSegments(dpy, Context->root, Context->gc.Draw, box, num_vectors);
  333.     if (GWM_Move_meter) {
  334.     MeterOpen("(100,100)");
  335.     MeterUpdate(MakePairUserDims(ulx, uly));
  336.     }
  337.  
  338.     /* Main loop. */
  339.     while (TRUE) {
  340.     if (XCheckMaskEvent(dpy, ButtonReleaseMask | ButtonPressMask,
  341.         &button_event)) {
  342.         /* The button was released, so move the window. */
  343.         XDrawSegments(dpy, Context->root, Context->gc.Draw,
  344.         box, num_vectors);
  345.         if (!called_from_press || button_event.type == ButtonRelease) {
  346.         /* MOVE HOOK */
  347.         XMoveWindow(dpy, cw->hook,    /* only move if released */
  348.             button_event.xbutton.x_root + ulx - prev_x,
  349.             button_event.xbutton.y_root + uly - prev_y);
  350.         cw->box.x = button_event.xbutton.x_root + ulx - prev_x;
  351.         cw->box.y = button_event.xbutton.y_root + uly - prev_y;
  352.         SendSyntheticMoveEvent(cw);
  353.         if (button_event.type == ButtonPress)
  354.             wait_for_button_release(button_event.xbutton.button);
  355.         if (GWM_Move_meter)
  356.             MeterClose();
  357.         XUngrabPointer(dpy, CurrentTime);
  358.         if (GWM_GrabServer)
  359.             XUngrabServer(dpy);
  360.         return NIL;
  361.         }
  362.         else {            /* another buttonpress = abort! */
  363.         wait_for_button_release(button_event.xbutton.button);
  364.         wait_for_button_release(called_from_press_button);
  365.         if (GWM_Move_meter)
  366.             MeterClose();
  367.         XUngrabPointer(dpy, CurrentTime);
  368.         if (GWM_GrabServer)
  369.             XUngrabServer(dpy);
  370.         return (WOOL_OBJECT) WLNumber_make(2);
  371.         }
  372.     }
  373.     /* track ghost window */
  374.     XQueryPointer(dpy,
  375.         RootWindow(dpy, Context->screen), &root, &sub_window,
  376.         &root_x, &root_y, &cur_x, &cur_y, &ptrmask);
  377.     if ((cur_x != prev_x) || (cur_y != prev_y)) {
  378.         /* erase the old box first! */
  379.         XDrawSegments(dpy, Context->root, Context->gc.Draw, box,
  380.         num_vectors);
  381.         ulx += cur_x - prev_x;    /* change Box position. */
  382.         uly += cur_y - prev_y;
  383.         lrx += cur_x - prev_x;
  384.         lry += cur_y - prev_y;
  385.         if (GWM_confine_windows) {
  386.         if (ulx < 0) {
  387.             lrx -= ulx;
  388.             ulx = 0;
  389.         }
  390.         if (uly < 0) {
  391.             lry -= uly;
  392.             uly = 0;
  393.         }
  394.         if (lrx >= Context->width) {
  395.             ulx -= (lrx - Context->width) + 1;
  396.             lrx = Context->width - 1;
  397.         }
  398.         if (lry >= Context->height) {
  399.             uly -= (lry - Context->height) + 1;
  400.             lry = Context->height - 1;
  401.         }
  402.         }
  403.         num_vectors = StoreBox(GWM_Movegrid, box, ulx, uly, lrx, lry);
  404.         /* Draw the new box. */
  405.         XDrawSegments(dpy, Context->root, Context->gc.Draw, box,
  406.         num_vectors);
  407.         if (GWM_Move_meter)
  408.         MeterUpdate(MakePairUserDims(ulx, uly));
  409.     }
  410.     /* Save old box position. */
  411.     prev_x = cur_x;
  412.     prev_y = cur_y;
  413.     }
  414. }
  415.  
  416. /* move several windows at once */
  417. WOOL_OBJECT
  418. UserMoveSeveralWindows(Ncw, cwl)
  419.     ClientWindow cwl[];
  420.     int       Ncw;
  421. {
  422.     int       prev_x;            /* Previous evt window X location. */
  423.     int       prev_y;            /* Previous evt window Y location. */
  424.     int       cur_x;            /* Current event window X location. */
  425.     int       cur_y;            /* Current event window Y location. */
  426.     int       root_x;            /* Root window X location. */
  427.     int       root_y;            /* Root window Y location. */
  428.     int       ulx, uly;            /* Event window upper left X, Y. */
  429.     int       lrx, lry;            /* Event window lower right X, Y. */
  430.     int       num_vectors;        /* Number of vectors in box. */
  431.     unsigned int ptrmask;        /* state of ptr when queried */
  432.     Window    sub_window;        /* Query mouse event sub-window. */
  433.     Window    root;            /* Query mouse event root. */
  434.     XEvent    button_event;        /* Button event packet. */
  435.     XSegment  box[MAX_GRID_SEGMENTS];    /* Box vertex buffer. */
  436.     unsigned long mask = ButtonPressMask | ButtonReleaseMask;
  437.     int       called_from_press;    /* aborts on press! */
  438.     int       called_from_press_button;    /* aborts on press! */
  439.     WOOL_Cursor cursor;
  440.     int       max_num_vectors;
  441.     ClientWindow cw;
  442.     int       i;
  443.  
  444.     if (Ncw < 1)
  445.     return (WOOL_OBJECT) WLNumber_make(0);
  446.     cw = cwl[0];
  447.  
  448.     /* Get Position of pointer of the event */
  449.     XQueryPointer(dpy, Context->root,
  450.     &root, &sub_window,
  451.     &root_x, &root_y, &cur_x, &cur_y, &ptrmask);
  452.     if (root != Context->root) {    /* cursor is on another screen */
  453.     return (WOOL_OBJECT) WLNumber_make(1);
  454.     }
  455.     if (TriggeringEvent && TriggeringEvent->type == ButtonPress) {
  456.     cur_x = TriggeringEvent->xbutton.x_root;
  457.     cur_y = TriggeringEvent->xbutton.y_root;
  458.     called_from_press = 1;
  459.     called_from_press_button = TriggeringEvent->xbutton.button;
  460.     /* if button has been released, aborts! */
  461.     if (GWM_UserSynchronous && !(ptrmask &
  462.         (Button1Mask << (called_from_press_button - Button1))))
  463.         return (WOOL_OBJECT) WLNumber_make(3);
  464.     }
  465.     else {
  466.     /* put the pointer always inside the window */
  467.     cur_x = Max(cur_x, cw->box.x);
  468.     cur_y = Max(cur_y, cw->box.y);
  469.     cur_x = Min(cur_x, cw->box.x + cw->box.width +
  470.         2 * cw->box.borderwidth);
  471.     cur_y = Min(cur_y, cw->box.y + cw->box.height +
  472.         2 * cw->box.borderwidth);
  473.     called_from_press = 0;
  474.     }
  475.  
  476.     cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursor, (WA_cursor));
  477.     if (XGrabPointer(dpy, Context->root, FALSE, mask,
  478.         GrabModeAsync, GrabModeAsync, None,
  479.         (cursor == (WOOL_Cursor) NIL ? None : cursor->cursor),
  480.         CurrentTime)
  481.     != GrabSuccess)
  482.     return (WOOL_OBJECT) WLNumber_make(0);
  483.     if (GWM_GrabServer)
  484.     XGrabServer(dpy);
  485.     XSetForeground(dpy, Context->gc.Draw, Context->pixel.GridColor);
  486.  
  487.     /* Initialize movement variables. */
  488.     ulx = cw->box.x;
  489.     uly = cw->box.y;
  490.     lrx = cw->box.x + cw->box.width + (cw->box.borderwidth * 2) - 1;
  491.     lry = cw->box.y + cw->box.height + (cw->box.borderwidth * 2) - 1;
  492.     MAKE_INNER_DIMS
  493.  
  494.     /* Store the box. */
  495.     num_vectors = StoreBox(GWM_Movegrid, box, ulx, uly, lrx, lry);
  496.     for (i = 1; i < Ncw; i++)
  497.     num_vectors = AddBox(num_vectors, GWM_Movegrid,
  498.         box, cwl[i]->box.x, cwl[i]->box.y,
  499.         cwl[i]->box.x + cwl[i]->box.width + (cwl[i]->box.borderwidth * 2) - 1,
  500.         cwl[i]->box.y + cwl[i]->box.height + (cwl[i]->box.borderwidth * 2) - 1);
  501.     max_num_vectors = num_vectors;
  502.     /* Initialize the previous location variables. */
  503.     prev_x = cur_x;
  504.     prev_y = cur_y;
  505.  
  506.     /* Now draw the box. */
  507.     XDrawSegments(dpy, Context->root, Context->gc.Draw, box, num_vectors);
  508.     if (GWM_Move_meter) {
  509.     MeterOpen("(100,100)");
  510.     MeterUpdate(MakePairUserDims(ulx, uly));
  511.     }
  512.  
  513.     /* Main loop. */
  514.     while (TRUE) {
  515.     if (XCheckMaskEvent(dpy, ButtonReleaseMask | ButtonPressMask,
  516.         &button_event)) {
  517.         /* The button was released, so move the window. */
  518.         XDrawSegments(dpy, Context->root, Context->gc.Draw,
  519.         box, num_vectors);
  520.         if (!called_from_press || button_event.type == ButtonRelease) {
  521.         int WindowIndex;
  522.         int DeltaX, DeltaY;
  523.         
  524.         DeltaX =  button_event.xbutton.x_root - prev_x+ulx-cw->box.x;
  525.         DeltaY =  button_event.xbutton.y_root - prev_y+uly-cw->box.y;
  526.         /* MOVE HOOK */
  527. #ifdef ToBeDeleted
  528.         XMoveWindow(dpy, cw->hook,    /* only move if released */
  529.                 DeltaX + cw->box.x, DeltaY+ cw->box.y);
  530.         cw->box.x += DeltaX;
  531.         cw->box.y += DeltaY;
  532.         SendSyntheticMoveEvent(cw);
  533. #endif        
  534.         for (WindowIndex = 0 ; WindowIndex < Ncw; WindowIndex++)
  535.         {
  536.             XMoveWindow(dpy, cwl[WindowIndex]->hook,
  537.             cwl[WindowIndex]->box.x + DeltaX,
  538.             cwl[WindowIndex]->box.y + DeltaY);
  539.             cwl[WindowIndex]->box.x += DeltaX;
  540.             cwl[WindowIndex]->box.y += DeltaY;
  541.             SendSyntheticMoveEvent(cwl[WindowIndex]);
  542.         }
  543.             
  544.         if (button_event.type == ButtonPress)
  545.             wait_for_button_release(button_event.xbutton.button);
  546.         if (GWM_Move_meter)
  547.             MeterClose();
  548.         XUngrabPointer(dpy, CurrentTime);
  549.         if (GWM_GrabServer)
  550.             XUngrabServer(dpy);
  551.         return NIL;
  552.         }
  553.         else {            /* another buttonpress = abort! */
  554.         wait_for_button_release(button_event.xbutton.button);
  555.         wait_for_button_release(called_from_press_button);
  556.         if (GWM_Move_meter)
  557.             MeterClose();
  558.         XUngrabPointer(dpy, CurrentTime);
  559.         if (GWM_GrabServer)
  560.             XUngrabServer(dpy);
  561.         return (WOOL_OBJECT) WLNumber_make(2);
  562.         }
  563.     }
  564.     /* track ghost window */
  565.     XQueryPointer(dpy,
  566.         RootWindow(dpy, Context->screen), &root, &sub_window,
  567.         &root_x, &root_y, &cur_x, &cur_y, &ptrmask);
  568.     if ((cur_x != prev_x) || (cur_y != prev_y)) {
  569.         /* erase the old box first! */
  570.         XDrawSegments(dpy, Context->root, Context->gc.Draw, box,
  571.         num_vectors);
  572.         ulx += cur_x - prev_x;    /* change Box position. */
  573.         uly += cur_y - prev_y;
  574.         lrx += cur_x - prev_x;
  575.         lry += cur_y - prev_y;
  576.         if (GWM_confine_windows) {
  577.         if (ulx < 0) {
  578.             lrx -= ulx;
  579.             ulx = 0;
  580.         }
  581.         if (uly < 0) {
  582.             lry -= uly;
  583.             uly = 0;
  584.         }
  585.         if (lrx >= Context->width) {
  586.             ulx -= (lrx - Context->width) + 1;
  587.             lrx = Context->width - 1;
  588.         }
  589.         if (lry >= Context->height) {
  590.             uly -= (lry - Context->height) + 1;
  591.             lry = Context->height - 1;
  592.         }
  593.         }
  594.         num_vectors = StoreBox(GWM_Movegrid, box, ulx, uly, lrx, lry);
  595.         for (i = num_vectors; i < max_num_vectors; i++) {
  596.         box[i].x1 += cur_x - prev_x;
  597.         box[i].x2 += cur_x - prev_x;
  598.         box[i].y1 += cur_y - prev_y;
  599.         box[i].y2 += cur_y - prev_y;
  600.         }
  601.         num_vectors = max_num_vectors;
  602.         /* Draw the new box. */
  603.         XDrawSegments(dpy, Context->root, Context->gc.Draw, box,
  604.         num_vectors);
  605.         if (GWM_Move_meter)
  606.         MeterUpdate(MakePairUserDims(ulx, uly));
  607.     }
  608.     /* Save old box position. */
  609.     prev_x = cur_x;
  610.     prev_y = cur_y;
  611.     }
  612. }
  613.  
  614. WOOL_OBJECT
  615. UserResizeWindow(cw)
  616. ClientWindow    cw;
  617. {
  618.     int    prev_x2;            /* Previous evt window X location. */
  619.     int    prev_y2;            /* Previous evt window Y location. */
  620.     int             init_x, init_y;
  621.     int             init_x2, init_y2;
  622.     int             x1, y1;        /* fixed point */
  623.     int             x2, y2;        /* varying point */
  624.     int             cur_x;        /* Current event window X location. */
  625.     int             cur_y;        /* Current event window Y location. */
  626.     int             root_x;        /* Root window X location. */
  627.     int             root_y;        /* Root window Y location. */
  628.     int             ulx, uly;        /* Event window upper left X, Y. */
  629.     int             lrx, lry;        /* Event window lower right X, Y. */
  630.     int             init_ulx, init_uly;    /* Init window upper left X and Y. */
  631.     int             init_lrx, init_lry;    /* Init window lower right X and Y. */
  632.     int             num_vectors;    /* Number of vectors in box. */
  633.     unsigned int    ptrmask;        /* state of ptr when queried */
  634.     Window          sub_window;        /* Query mouse event sub-window. */
  635.     Window          root;        /* Query mouse event root. */
  636.     XEvent          button_event;    /* Button event packet. */
  637.     XSegment        box[MAX_GRID_SEGMENTS]; /* Box vertex buffer. */
  638.     unsigned long   mask = ButtonPressMask | ButtonReleaseMask;
  639.     int             inner_width, inner_height;
  640.     int             called_from_press;    /* aborts on press! */
  641.     int             called_from_press_button; /* aborts on press! */
  642.     WOOL_Cursor     cursor;
  643.  
  644.     /* Get Position of pointer of the event */
  645.     XQueryPointer(dpy, Context -> root,
  646.           &root, &sub_window,
  647.           &root_x, &root_y, &cur_x, &cur_y, &ptrmask);
  648.     if (root != Context -> root) {    /* cursor is on another screen */
  649.     return (WOOL_OBJECT) WLNumber_make(1);
  650.     }
  651.     if (TriggeringEvent && TriggeringEvent -> type == ButtonPress) {
  652.     cur_x = TriggeringEvent -> xbutton.x_root;
  653.     cur_y = TriggeringEvent -> xbutton.y_root;
  654.     called_from_press = 1;
  655.     called_from_press_button = TriggeringEvent -> xbutton.button;
  656.     /* if button has been released, aborts! */
  657.     if (GWM_UserSynchronous && !(ptrmask &
  658.                      (Button1Mask << (called_from_press_button - Button1))))
  659.         return (WOOL_OBJECT) WLNumber_make(3);
  660.     } else {
  661.     /* put the pointer always inside the window */
  662.     cur_x = Max(cur_x, cw -> box.x);
  663.     cur_y = Max(cur_y, cw -> box.y);
  664.     cur_x = Min(cur_x, cw -> box.x + cw -> box.width +
  665.             2 * cw -> box.borderwidth);
  666.     cur_y = Min(cur_y, cw -> box.y + cw -> box.height +
  667.             2 * cw -> box.borderwidth);
  668.     called_from_press = 0;
  669.     }
  670.  
  671.     init_x = cur_x;
  672.     init_y = cur_y;
  673.  
  674.     cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursor, (WA_cursor));
  675.     if (XGrabPointer(dpy, Context -> root, FALSE, mask,
  676.              GrabModeAsync, GrabModeAsync, None,
  677.              (cursor == (WOOL_Cursor) NIL ? None : cursor -> cursor),
  678.              CurrentTime)
  679.     != GrabSuccess)
  680.     return (WOOL_OBJECT) WLNumber_make(0);
  681.     if (GWM_GrabServer)
  682.     XGrabServer(dpy);
  683.     XSetForeground(dpy, Context -> gc.Draw, Context -> pixel.GridColor);
  684.  
  685.     /* Initialize movement variables. */
  686.     init_ulx = ulx = cw -> box.x;
  687.     init_uly = uly = cw -> box.y;
  688.     init_lrx = lrx = cw -> box.x + cw -> box.width +
  689.     (cw -> box.borderwidth * 2) - 1;
  690.     init_lry = lry = cw -> box.y + cw -> box.height +
  691.     (cw -> box.borderwidth * 2) - 1;
  692.     MAKE_INNER_DIMS
  693.  
  694.     /* determine the direction of resize 0, 1 or 2 */
  695.     xdir = ((cur_x - ulx) * 3) / (lrx - ulx);
  696.     ydir = ((cur_y - uly) * 3) / (lry - uly);
  697.     /* handle cur_x == lrx case */
  698.     if (xdir == 3)
  699.     xdir = 2;
  700.     if (ydir == 3)
  701.     ydir = 2;
  702.     /* determine the fixed & varying points */
  703.     if (xdir) {
  704.     x1 = ulx;
  705.     x2 = lrx;
  706.     } else {
  707.     x1 = lrx;
  708.     x2 = ulx;
  709.     }
  710.     if (ydir) {
  711.     y1 = uly;
  712.     y2 = lry;
  713.     } else {
  714.     y1 = lry;
  715.     y2 = uly;
  716.     }
  717.  
  718.     /* Initialize the previous location variables. */
  719.     init_x2 = prev_x2 = x2;
  720.     init_y2 = prev_y2 = y2;
  721.  
  722.     /* Store the box. */
  723.     num_vectors = StoreBox(GWM_Resizegrid, box, Min(x1, x2), Min(y1, y2),
  724.                Max(x1, x2), Max(y1, y2));
  725.     /* Now draw the box. */
  726.     XDrawSegments(dpy, Context -> root, Context -> gc.Draw, box, num_vectors);
  727.     if (GWM_Resize_meter) {
  728.     MeterOpen("80x24");
  729.     MeterUpdate(MakeUserDims(&(cw -> cached_props -> normal_hints),
  730.                  cw -> inner_width, cw -> inner_height));
  731.     }
  732.     /* Main loop. */
  733.     while (TRUE) {
  734.     if (XCheckMaskEvent(dpy, ButtonReleaseMask | ButtonPressMask,
  735.                 &button_event)) {
  736.         /* The button was released, so move the window. */
  737.         XDrawSegments(dpy, Context -> root, Context -> gc.Draw,
  738.               box, num_vectors);
  739.         /* OK, let's resize! */
  740.         if (!called_from_press || button_event.type == ButtonRelease) {
  741.         int             delta, borderwidth, depth;
  742.  
  743.         delta = Min(x1, x2) - init_ulx;
  744.         cw -> box.x += delta;
  745.         delta = Min(y1, y2) - init_uly;
  746.         cw -> box.y += delta;
  747.         delta = Max(x1, x2) - init_lrx - (Min(x1, x2) - init_ulx);
  748.         cw -> inner_width += delta;
  749.         cw -> box.width += delta;
  750.         delta = Max(y1, y2) - init_lry - (Min(y1, y2) - init_uly);
  751.         cw -> inner_height += delta;
  752.         cw -> box.height += delta;
  753.         XResizeWindow(dpy, cw -> client,
  754.                   cw -> inner_width, cw -> inner_height);
  755.         ReconfigureClientWindow(cw, cw -> client);
  756.         if (button_event.type == ButtonPress)
  757.             wait_for_button_release(button_event.xbutton.button);
  758.         if (GWM_Resize_meter)
  759.             MeterClose();
  760.         XUngrabPointer(dpy, CurrentTime);
  761.         if (GWM_GrabServer)
  762.             XUngrabServer(dpy);
  763.         return NIL;
  764.         } else {            /* another buttonpress = abort! */
  765.         wait_for_button_release(button_event.xbutton.button);
  766.         wait_for_button_release(called_from_press_button);
  767.         if (GWM_Resize_meter)
  768.             MeterClose();
  769.         XUngrabPointer(dpy, CurrentTime);
  770.         if (GWM_GrabServer)
  771.             XUngrabServer(dpy);
  772.         return (WOOL_OBJECT) WLNumber_make(2);
  773.         }
  774.     }
  775.     /* track ghost window */
  776.     XQueryPointer(dpy,
  777.               RootWindow(dpy, Context -> screen), &root, &sub_window,
  778.               &root_x, &root_y, &cur_x, &cur_y, &ptrmask);
  779.     x2 = validate_dir(xdir, cur_x - init_x, cw -> inner_width);
  780.     y2 = validate_dir(ydir, cur_y - init_y, cw -> inner_height);
  781.     inner_width = cw -> inner_width + (xdir ? x2 : -x2);
  782.     inner_height = cw -> inner_height + (ydir ? y2 : -y2);
  783.     conform_to_hints(&(cw -> cached_props -> normal_hints),
  784.              &inner_width, &inner_height);
  785.     x2 = init_x2 + (xdir ? inner_width - cw -> inner_width :
  786.             cw -> inner_width - inner_width);
  787.     y2 = init_y2 + (ydir ? inner_height - cw -> inner_height :
  788.             cw -> inner_height - inner_height);
  789.     if (GWM_confine_windows) {
  790.         int readjust = 0;
  791.         if (x2 < 0) {
  792.         x2 = 0;
  793.         inner_width = (cw -> box.x - x2) + cw -> inner_width;
  794.         readjust = 1;
  795.         } else if (x2 >= Context -> width) {
  796.         x2 = Context -> width;
  797.         inner_width = cw -> inner_width + x2 
  798.             - (cw -> box.x + cw->box.width + 2*(cw->box.borderwidth));
  799.         readjust = 1;
  800.         }
  801.  
  802.         if (y2<0) {
  803.         y2 = 0;
  804.         inner_height = (cw -> box.y - y2) + cw -> inner_height;
  805.         readjust = 1;
  806.         } else if (y2 >= Context -> height) {
  807.         y2 = Context -> height;
  808.         inner_height = cw -> inner_height + y2
  809.             - (cw->box.y + cw->box.height + 2*(cw->box.borderwidth));
  810.         readjust = 1;
  811.         }
  812.         if (readjust) {
  813.         conform_to_hints(&(cw -> cached_props -> normal_hints),
  814.                  &inner_width, &inner_height);
  815.         x2 = init_x2 + (xdir ? inner_width - cw -> inner_width :
  816.                 cw -> inner_width - inner_width);
  817.         y2 = init_y2 + (ydir ? inner_height - cw -> inner_height :
  818.                 cw -> inner_height - inner_height);
  819.         }
  820.     }
  821.     if ((x2 != prev_x2) || (y2 != prev_y2)) {
  822.         /* erase the old box first! */
  823.         XDrawSegments(dpy, Context -> root, Context -> gc.Draw, box,
  824.               num_vectors);
  825.         num_vectors = StoreBox(GWM_Resizegrid, box,
  826.                    Min(x1, x2), Min(y1, y2),
  827.                    Max(x1, x2), Max(y1, y2));
  828.         /* Draw the new box. */
  829.         XDrawSegments(dpy, Context -> root, Context -> gc.Draw, box,
  830.               num_vectors);
  831.         if (GWM_Resize_meter)
  832.         MeterUpdate(MakeUserDims(
  833.                      &(cw -> cached_props -> normal_hints),
  834.                      inner_width, inner_height));
  835.         /* Save old box position. */
  836.         prev_x2 = x2;
  837.         prev_y2 = y2;
  838.     }
  839.     }
  840. }
  841.  
  842. int
  843. validate_dir(dir, delta, margin)
  844. int dir, delta, margin;
  845. {
  846.     switch (dir) {
  847.     case 0:
  848.     return Min(margin, delta);
  849.     case 2:
  850.     return Max(-margin, delta);
  851.     }
  852.     return 0;
  853. }
  854.  
  855.  
  856. int
  857. conform_to_hints(hints, width, height)
  858. XSizeHints    *hints;
  859. int *width, *height;
  860. {
  861.     if (hints -> flags & PMinSize) {
  862.     if (*width < hints -> min_width)
  863.         *width = hints -> min_width;
  864.     if (*height < hints -> min_height)
  865.         *height = hints -> min_height;
  866.     }
  867.     if (hints -> flags & PMaxSize) {
  868.     if (*width > hints -> max_width)
  869.         *width = hints -> max_width;
  870.     if (*height > hints -> max_height)
  871.         *height = hints -> max_height;
  872.     }
  873.     if (hints -> flags & PAspect) {
  874.     if (hints -> min_aspect.y * (*width)
  875.         < hints -> min_aspect.x * (*height)) {
  876.         if (xdir == 1) {
  877.         *height = ((*width) * hints -> min_aspect.y)
  878.             / hints -> min_aspect.x;
  879.         } else {
  880.         *width = ((*height) * hints -> min_aspect.x)
  881.             / hints -> min_aspect.y;
  882.         }
  883.     }
  884.     if (hints -> max_aspect.y * (*width)
  885.         > hints -> max_aspect.x * (*height)) {
  886.         if (ydir == 1) {
  887.         *width = ((*height) * hints -> max_aspect.x)
  888.             / hints -> max_aspect.y;
  889.         } else {
  890.         *height = ((*width) * hints -> max_aspect.y)
  891.             / hints -> max_aspect.x;
  892.         }
  893.     }
  894.     }
  895. #ifdef NOBASEDIMS
  896.     if (hints -> flags & PResizeInc) {
  897.     *width = hints -> min_width + hints -> width_inc *
  898.         (((*width) - hints -> min_width) / hints -> width_inc);
  899.     *height = hints -> min_height + hints -> height_inc *
  900.         (((*height) - hints -> min_height) / hints -> height_inc);
  901.     }
  902. #else /* NOBASEDIMS */
  903.     if (hints -> flags & PResizeInc) {
  904.     *width = hints -> base_width + hints -> width_inc *
  905.         (((*width) - hints -> base_width) / hints -> width_inc);
  906.     *height = hints -> base_height + hints -> height_inc *
  907.         (((*height) - hints -> base_height) / hints -> height_inc);
  908.     }
  909. #endif /* NOBASEDIMS */
  910. }
  911.  
  912. /*
  913.  * Updates the sizehints for consitency with themselves and the screen dims.
  914.  */
  915.  
  916. CheckConsistency(hints)
  917. XSizeHints *hints;
  918. {
  919. #ifndef NOBASEDIMS
  920.     if((hints -> flags & PMinSize) && !(hints -> flags & PBaseSize)) {
  921.     hints -> flags |= PBaseSize;
  922.     hints -> base_width = hints -> min_width;
  923.     hints -> base_height = hints -> min_height;
  924.     }
  925.     if((hints -> flags & PResizeInc) && !(hints -> flags & PBaseSize)) {
  926.     hints -> base_width = 0;
  927.     hints -> base_height = 0;
  928.     }
  929. #else /* NOBASEDIMS */
  930.     if((hints -> flags & PResizeInc) && !(hints -> flags & PMinSize)) {
  931.     hints -> min_width = 0;
  932.     hints -> min_height = 0;
  933.     }
  934. #endif /* NOBASEDIMS */
  935.     if (hints -> flags & PResizeInc && 
  936.     (hints -> width_inc <= 0 || hints -> height_inc <= 0)) {
  937.     hints -> height_inc = hints -> width_inc = 1;
  938.     trace(0, "Bogus increment hints\n");
  939.     }
  940. }
  941.  
  942. /*
  943.  * user feedback
  944.  */
  945.  
  946. static    char            meter_str[20];
  947.  
  948. char *
  949. MakePairUserDims(x, y)
  950. int    x, y;
  951. {
  952.     sprintf(meter_str, "(%d, %d)", x, y    );
  953.     return meter_str;
  954. }
  955.  
  956. char *
  957. MakeUserDims(hints, width, height)
  958. XSizeHints *hints;
  959. int    width, height;
  960. {
  961.     unsigned int rw, rh;
  962.  
  963.     pixel_to_logical_size(hints, width, height, &rw, &rh);
  964.     sprintf(meter_str, "%d x %d", rw, rh);
  965.     return meter_str;
  966. }
  967.  
  968. pixel_to_logical_size(hints, width, height, rw, rh)
  969. XSizeHints *hints;
  970. unsigned int width, height, *rw, *rh;
  971. {
  972.     *rw = width;
  973.     *rh = height;
  974. #ifdef NOBASEDIMS
  975.     if (hints->flags & PResizeInc) {
  976.     *rw = ((width) - hints->min_width) / hints->width_inc;
  977.     *rh = ((height) - hints->min_height) / hints->height_inc;
  978.     }
  979. #else /* NOBASEDIMS */
  980.     if (hints->flags & PResizeInc) {
  981.     *rw = ((width) - hints->base_width) / hints->width_inc;
  982.     *rh = ((height) - hints->base_height) / hints->height_inc;
  983.     }
  984. #endif /* NOBASEDIMS */
  985. }
  986.  
  987. logical_to_pixel_size(hints, width, height, rw, rh)
  988. XSizeHints *hints;
  989. unsigned int width, height, *rw, *rh;
  990. {
  991.     *rw = width;
  992.     *rh = height;
  993. #ifdef NOBASEDIMS
  994.     if (hints -> flags & PResizeInc) {
  995.     *rw = hints -> min_width + width * hints -> width_inc;
  996.     *rh = hints -> min_height + height * hints -> height_inc;
  997.     }
  998. #else /* NOBASEDIMS */
  999.     if (hints -> flags & PResizeInc) {
  1000.     *rw = hints -> base_width + width * hints -> width_inc;
  1001.     *rh = hints -> base_height + height * hints -> height_inc;
  1002.     }
  1003. #endif /* NOBASEDIMS */
  1004. }
  1005.  
  1006. Cursor
  1007. get_zone_cursor(zone)
  1008. int zone;
  1009. {
  1010. WOOL_Cursor cursor ;
  1011.  
  1012. switch (zone)
  1013.  {
  1014.   case 0:
  1015.     cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursorNW, (WA_cursorNW));
  1016.     break;
  1017.   case 1:
  1018.     cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursorN, (WA_cursorN));
  1019.     break;
  1020.   case 2:
  1021.     cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursorNE, (WA_cursorNE));
  1022.     break;
  1023.   case 3:
  1024.     cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursorW, (WA_cursorW));
  1025.     break;
  1026.   case 5:
  1027.     cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursorE, (WA_cursorE));
  1028.     break;
  1029.   case 6:
  1030.     cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursorSW, (WA_cursorSW));
  1031.     break;
  1032.   case 7:
  1033.     cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursorS, (WA_cursorS));
  1034.     break;
  1035.   case 8:
  1036.     cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursorSE, (WA_cursorSE));
  1037.     break;
  1038.   default: cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursor, (WA_cursor));
  1039.  }
  1040.     return (cursor == (WOOL_Cursor) NIL ? None : cursor -> cursor);
  1041. }
  1042.  
  1043. /* MWM-like resize
  1044.  * code by Frederic Charton
  1045.  */
  1046.  
  1047. WOOL_OBJECT
  1048. MwmLikeUserResizeWindow(cw)
  1049. ClientWindow    cw;
  1050. {
  1051.     int    prev_x2;            /* Previous evt window X location. */
  1052.     int    prev_y2;            /* Previous evt window Y location. */
  1053.     int             init_x, init_y;
  1054.     int             init_x2, init_y2;
  1055.     int             x1, y1;        /* fixed point */
  1056.     int             x2, y2;        /* varying point */
  1057.     int             cur_x;        /* Current event window X location. */
  1058.     int             cur_y;        /* Current event window Y location. */
  1059.     int             root_x;        /* Root window X location. */
  1060.     int             root_y;        /* Root window Y location. */
  1061.     int             ulx, uly;        /* Event window upper left X, Y. */
  1062.     int             lrx, lry;        /* Event window lower right X, Y. */
  1063.     int             init_ulx, init_uly;    /* Init window upper left X and Y. */
  1064.     int             init_lrx, init_lry;    /* Init window lower right X and Y. */
  1065.     int             num_vectors;    /* Number of vectors in box. */
  1066.     unsigned int    ptrmask;        /* state of ptr when queried */
  1067.     Window          sub_window;        /* Query mouse event sub-window. */
  1068.     Window          root;        /* Query mouse event root. */
  1069.     XEvent          button_event;    /* Button event packet. */
  1070.     XSegment        box[MAX_GRID_SEGMENTS]; /* Box vertex buffer. */
  1071.     unsigned long   mask = ButtonPressMask | ButtonReleaseMask;
  1072.     int             inner_width, inner_height;
  1073.     int             called_from_press;    /* aborts on press! */
  1074.     int             called_from_press_button; /* aborts on press! */
  1075.     int             zone;
  1076.     int             new_xdir, new_ydir, new_zone;
  1077.     WOOL_Cursor     cursor;
  1078.  
  1079.     /* Get Position of pointer of the event */
  1080.     XQueryPointer(dpy, Context -> root,
  1081.           &root, &sub_window,
  1082.           &root_x, &root_y, &cur_x, &cur_y, &ptrmask);
  1083.     if (root != Context -> root) {    /* cursor is on another screen */
  1084.     return (WOOL_OBJECT) WLNumber_make(1);
  1085.     }
  1086.     if (TriggeringEvent && TriggeringEvent -> type == ButtonPress) {
  1087.     cur_x = TriggeringEvent -> xbutton.x_root;
  1088.     cur_y = TriggeringEvent -> xbutton.y_root;
  1089.     called_from_press = 1;
  1090.     called_from_press_button = TriggeringEvent -> xbutton.button;
  1091.     /* if button has been released, aborts! */
  1092.     if (GWM_UserSynchronous && !(ptrmask &
  1093.                      (Button1Mask << (called_from_press_button - Button1))))
  1094.         return (WOOL_OBJECT) WLNumber_make(3);
  1095.     } else {
  1096.     /* put the pointer always inside the window */
  1097.     cur_x = Max(cur_x, cw -> box.x);
  1098.     cur_y = Max(cur_y, cw -> box.y);
  1099.     cur_x = Min(cur_x, cw -> box.x + cw -> box.width +
  1100.             2 * cw -> box.borderwidth);
  1101.     cur_y = Min(cur_y, cw -> box.y + cw -> box.height +
  1102.             2 * cw -> box.borderwidth);
  1103.     called_from_press = 0;
  1104.     }
  1105.  
  1106.     init_x = cur_x;
  1107.     init_y = cur_y;
  1108.  
  1109.     cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursor, (WA_cursor));
  1110.     if (XGrabPointer(dpy, Context -> root, FALSE, mask,
  1111.              GrabModeAsync, GrabModeAsync, None,
  1112.              (cursor == (WOOL_Cursor) NIL ? None : cursor -> cursor),
  1113.              CurrentTime)
  1114.     != GrabSuccess)
  1115.     return (WOOL_OBJECT) WLNumber_make(0);
  1116.     if (GWM_GrabServer)
  1117.     XGrabServer(dpy);
  1118.     XSetForeground(dpy, Context -> gc.Draw, Context -> pixel.GridColor);
  1119.  
  1120.     /* Initialize movement variables. */
  1121.     init_ulx = ulx = cw -> box.x;
  1122.     init_uly = uly = cw -> box.y;
  1123.     init_lrx = lrx = cw -> box.x + cw -> box.width +
  1124.     (cw -> box.borderwidth * 2) - 1;
  1125.     init_lry = lry = cw -> box.y + cw -> box.height +
  1126.     (cw -> box.borderwidth * 2) - 1;
  1127.     MAKE_INNER_DIMS
  1128.  
  1129.     /* determine the direction of resize 0, 1 or 2 */
  1130.     if (GWM_window_cutting_size > 0) {
  1131.         if (cur_x < (ulx + GWM_window_cutting_size))
  1132.         xdir = 0;
  1133.         else if (cur_x > (lrx - GWM_window_cutting_size))
  1134.         xdir = 2;
  1135.         else
  1136.         xdir = 1;
  1137.         if (cur_y < (uly + GWM_window_cutting_size))
  1138.         ydir = 0;
  1139.         else if (cur_y > (lry - GWM_window_cutting_size))
  1140.         ydir = 2;
  1141.         else
  1142.         ydir = 1;
  1143.     } else {
  1144.         xdir = ((cur_x - ulx) * 3) / (lrx - ulx);
  1145.         ydir = ((cur_y - uly) * 3) / (lry - uly);
  1146.         /* handle cur_x == lrx case */
  1147.         if (xdir == 3)
  1148.         xdir = 2;
  1149.         if (ydir == 3)
  1150.         ydir = 2;
  1151.     }
  1152.  
  1153.     /* determine the fixed & varying points */
  1154.     if (xdir) {
  1155.     x1 = ulx;
  1156.     x2 = lrx;
  1157.     } else {
  1158.     x1 = lrx;
  1159.     x2 = ulx;
  1160.     }
  1161.     if (ydir) {
  1162.     y1 = uly;
  1163.     y2 = lry;
  1164.     } else {
  1165.     y1 = lry;
  1166.     y2 = uly;
  1167.     }
  1168.  
  1169.     zone = 3 * ydir + xdir;
  1170.     XChangeActivePointerGrab(dpy, mask, get_zone_cursor(zone), CurrentTime);
  1171.  
  1172.     /* Initialize the previous location variables. */
  1173.     init_x2 = prev_x2 = x2;
  1174.     init_y2 = prev_y2 = y2;
  1175.  
  1176.     /* Store the box. */
  1177.     num_vectors = StoreBox(GWM_Resizegrid, box, Min(x1, x2), Min(y1, y2),
  1178.                Max(x1, x2), Max(y1, y2));
  1179.     /* Now draw the box. */
  1180.     XDrawSegments(dpy, Context -> root, Context -> gc.Draw, box, num_vectors);
  1181.     if (GWM_Resize_meter) {
  1182.     MeterOpen("80x24");
  1183.     MeterUpdate(MakeUserDims(&(cw -> cached_props -> normal_hints),
  1184.                  cw -> inner_width, cw -> inner_height));
  1185.     }
  1186.     /* Main loop. */
  1187.     while (TRUE) {
  1188.     if (XCheckMaskEvent(dpy, ButtonReleaseMask | ButtonPressMask,
  1189.                 &button_event)) {
  1190.         /* The button was released, so move the window. */
  1191.         XDrawSegments(dpy, Context -> root, Context -> gc.Draw,
  1192.               box, num_vectors);
  1193.         /* OK, let's resize! */
  1194.         if (!called_from_press || button_event.type == ButtonRelease) {
  1195.         int             delta, borderwidth, depth;
  1196.  
  1197.         delta = Min(x1, x2) - init_ulx;
  1198.         cw -> box.x += delta;
  1199.         delta = Min(y1, y2) - init_uly;
  1200.         cw -> box.y += delta;
  1201.         delta = Max(x1, x2) - init_lrx - (Min(x1, x2) - init_ulx);
  1202.         cw -> inner_width += delta;
  1203.         cw -> box.width += delta;
  1204.         delta = Max(y1, y2) - init_lry - (Min(y1, y2) - init_uly);
  1205.         cw -> inner_height += delta;
  1206.         cw -> box.height += delta;
  1207.         XResizeWindow(dpy, cw -> client,
  1208.                   cw -> inner_width, cw -> inner_height);
  1209.         ReconfigureClientWindow(cw, cw -> client);
  1210.         if (button_event.type == ButtonPress)
  1211.             wait_for_button_release(button_event.xbutton.button);
  1212.         if (GWM_Resize_meter)
  1213.             MeterClose();
  1214.         XUngrabPointer(dpy, CurrentTime);
  1215.         if (GWM_GrabServer)
  1216.             XUngrabServer(dpy);
  1217.         return NIL;
  1218.         } else {            /* another buttonpress = abort! */
  1219.         wait_for_button_release(button_event.xbutton.button);
  1220.         wait_for_button_release(called_from_press_button);
  1221.         if (GWM_Resize_meter)
  1222.             MeterClose();
  1223.         XUngrabPointer(dpy, CurrentTime);
  1224.         if (GWM_GrabServer)
  1225.             XUngrabServer(dpy);
  1226.         return (WOOL_OBJECT) WLNumber_make(2);
  1227.         }
  1228.     }
  1229.     /* track ghost window */
  1230.     XQueryPointer(dpy,
  1231.               RootWindow(dpy, Context -> screen), &root, &sub_window,
  1232.               &root_x, &root_y, &cur_x, &cur_y, &ptrmask);
  1233.     x2 = validate_dir(xdir, cur_x - init_x, cw -> inner_width);
  1234.     y2 = validate_dir(ydir, cur_y - init_y, cw -> inner_height);
  1235.     inner_width = cw -> inner_width + (xdir ? x2 : -x2);
  1236.     inner_height = cw -> inner_height + (ydir ? y2 : -y2);
  1237.     if (inner_width < 2 * GWM_window_cutting_size)
  1238.         inner_width = 2 * GWM_window_cutting_size;
  1239.     if (inner_height < 2 * GWM_window_cutting_size)
  1240.         inner_height = 2 * GWM_window_cutting_size;
  1241.     conform_to_hints(&(cw -> cached_props -> normal_hints),
  1242.              &inner_width, &inner_height);
  1243.     x2 = init_x2 + (xdir ? inner_width - cw -> inner_width :
  1244.             cw -> inner_width - inner_width);
  1245.     y2 = init_y2 + (ydir ? inner_height - cw -> inner_height :
  1246.             cw -> inner_height - inner_height);
  1247.     if (GWM_confine_windows) {
  1248.         int readjust = 0;
  1249.         if (x2 < 0) {
  1250.         x2 = 0;
  1251.         inner_width = (cw -> box.x - x2) + cw -> inner_width;
  1252.         readjust = 1;
  1253.         } else if (x2 >= Context -> width) {
  1254.         x2 = Context -> width;
  1255.         inner_width = cw -> inner_width + x2 
  1256.             - (cw -> box.x + cw->box.width + 2*(cw->box.borderwidth));
  1257.         readjust = 1;
  1258.         }
  1259.  
  1260.         if (y2<0) {
  1261.         y2 = 0;
  1262.         inner_height = (cw -> box.y - y2) + cw -> inner_height;
  1263.         readjust = 1;
  1264.         } else if (y2 >= Context -> height) {
  1265.         y2 = Context -> height;
  1266.         inner_height = cw -> inner_height + y2
  1267.             - (cw->box.y + cw->box.height + 2*(cw->box.borderwidth));
  1268.         readjust = 1;
  1269.         }
  1270.         if (readjust) {
  1271.         conform_to_hints(&(cw -> cached_props -> normal_hints),
  1272.                  &inner_width, &inner_height);
  1273.         x2 = init_x2 + (xdir ? inner_width - cw -> inner_width :
  1274.                 cw -> inner_width - inner_width);
  1275.         y2 = init_y2 + (ydir ? inner_height - cw -> inner_height :
  1276.                 cw -> inner_height - inner_height);
  1277.         }
  1278.     }
  1279.     if (GWM_Mwm_catch_corners &&
  1280.         (GWM_window_cutting_size > 0)) {
  1281.         ulx = Min(x1, x2);
  1282.         uly = Min(y1, y2);
  1283.         lrx = Max(x1, x2);
  1284.         lry = Max(y1, y2);
  1285.         new_xdir = xdir;
  1286.         if (xdir == 1)
  1287.         if (cur_x < (ulx + GWM_window_cutting_size))
  1288.             new_xdir = 0;
  1289.         else if (cur_x > (lrx - GWM_window_cutting_size))
  1290.             new_xdir = 2;
  1291.         new_ydir = ydir;
  1292.         if (ydir == 1)
  1293.         if (cur_y < (uly + GWM_window_cutting_size))
  1294.             new_ydir = 0;
  1295.         else if (cur_y > (lry - GWM_window_cutting_size))
  1296.             new_ydir = 2;
  1297.         new_zone = 3 * new_ydir + new_xdir;
  1298.         if (new_zone != zone) {
  1299.         XChangeActivePointerGrab(dpy, mask,
  1300.             get_zone_cursor(new_zone), CurrentTime);
  1301.         zone = new_zone;
  1302.         /* determine if the varying point is changing */
  1303.         if ((xdir == 1) && (new_xdir == 0))
  1304.           init_x2 = x1;
  1305.         if ((ydir == 1) && (new_ydir == 0))
  1306.           init_y2 = y1;
  1307.         xdir = new_xdir;
  1308.         ydir = new_ydir;
  1309.         init_x = init_x2;
  1310.         init_y = init_y2;
  1311.         /* determine the new points */
  1312.         if (xdir) {
  1313.             x1 = ulx;
  1314.             x2 = lrx;
  1315.         } else {
  1316.             x1 = lrx;
  1317.             x2 = ulx;
  1318.         }
  1319.         if (ydir) {
  1320.             y1 = uly;
  1321.             y2 = lry;
  1322.         } else {
  1323.             y1 = lry;
  1324.             y2 = uly;
  1325.         }
  1326.         }
  1327.     }
  1328.     if ((x2 != prev_x2) || (y2 != prev_y2)) {
  1329.         /* erase the old box first! */
  1330.         XDrawSegments(dpy, Context -> root, Context -> gc.Draw, box,
  1331.               num_vectors);
  1332.         num_vectors = StoreBox(GWM_Resizegrid, box,
  1333.             Min(x1, x2), Min(y1, y2), Max(x1, x2), Max(y1, y2));
  1334.         /* Draw the new box. */
  1335.         XDrawSegments(dpy, Context -> root, Context -> gc.Draw, box,
  1336.               num_vectors);
  1337.         if (GWM_Resize_meter)
  1338.         MeterUpdate(MakeUserDims(
  1339.                       &(cw -> cached_props -> normal_hints),
  1340.                      inner_width, inner_height));
  1341.         /* Save old box position. */
  1342.         prev_x2 = x2;
  1343.         prev_y2 = y2;
  1344.     }
  1345.     }
  1346. }
  1347.