home *** CD-ROM | disk | FTP | other *** search
/ ftp.freefriends.org / ftp.freefriends.org.tar / ftp.freefriends.org / arnold / Source / 9wm-1.1.shar.gz / 9wm-1.1.shar / grab.c < prev    next >
C/C++ Source or Header  |  1995-01-15  |  10KB  |  451 lines

  1. /* Copyright (c) 1994 David Hogan, see README for licence details */
  2. #include <stdio.h>
  3. #include <X11/X.h>
  4. #include <X11/Xos.h>
  5. #include <X11/Xlib.h>
  6. #include <X11/Xutil.h>
  7. #include "dat.h"
  8. #include "fns.h"
  9.  
  10. int
  11. nobuttons(e)    /* Einstuerzende */
  12. XButtonEvent *e;
  13. {
  14.     int state;
  15.  
  16.     state = (e->state & AllButtonMask);
  17.     return (e->type == ButtonRelease) && (state & (state - 1)) == 0;
  18. }
  19.  
  20. int
  21. grab(w, mask, curs, t)
  22. Window w;
  23. int mask;
  24. Cursor curs;
  25. int t;
  26. {
  27.     int status;
  28.  
  29.     if (t == 0)
  30.         t = timestamp();
  31.     status = XGrabPointer(dpy, w, False, mask,
  32.         GrabModeAsync, GrabModeAsync, None, curs, t);
  33.     return status;
  34. }
  35.  
  36. void
  37. ungrab(e)
  38. XButtonEvent *e;
  39. {
  40.     XEvent ev;
  41.  
  42.     if (!nobuttons(e))
  43.         for (;;) {
  44.             XMaskEvent(dpy, ButtonMask | ButtonMotionMask, &ev);
  45.             if (ev.type == MotionNotify)
  46.                 continue;
  47.             e = &ev.xbutton;
  48.             if (nobuttons(e))
  49.                 break;
  50.         }
  51.     XUngrabPointer(dpy, e->time);
  52.     curtime = e->time;
  53. }
  54.  
  55. int
  56. menuhit(e, m)
  57. XButtonEvent *e;
  58. Menu *m;
  59. {
  60.     XEvent ev;
  61.     int i, n, cur, old, wide, high, status, drawn, warp;
  62.     int x, y, dx, dy, xmax, ymax;
  63.     int tx, ty;
  64.  
  65.     if (e->window == menuwin)       /* ugly event mangling */
  66.         return -1;
  67.  
  68.     dx = 0;
  69.     for (n = 0; m->item[n]; n++) {
  70.         wide = XTextWidth(font, m->item[n], strlen(m->item[n])) + 4;
  71.         if (wide > dx)
  72.             dx = wide;
  73.     }
  74.     wide = dx;
  75.     cur = m->lasthit;
  76.     if (cur >= n)
  77.         cur = n - 1;
  78.  
  79.     high = font->ascent + font->descent + 1;
  80.     dy = n*high;
  81.     x = e->x - wide/2;
  82.     y = e->y - cur*high - high/2;
  83.     warp = 0;
  84.     xmax = DisplayWidth(dpy, screen);
  85.     ymax = DisplayHeight(dpy, screen);
  86.     if (x < 0) {
  87.         e->x -= x;
  88.         x = 0;
  89.         warp++;
  90.     }
  91.     if (x+wide >= xmax) {
  92.         e->x -= x+wide-xmax;
  93.         x = xmax-wide;
  94.         warp++;
  95.     }
  96.     if (y < 0) {
  97.         e->y -= y;
  98.         y = 0;
  99.         warp++;
  100.     }
  101.     if (y+dy >= ymax) {
  102.         e->y -= y+dy-ymax;
  103.         y = ymax-dy;
  104.         warp++;
  105.     }
  106.     if (warp)
  107.         setmouse(e->x, e->y);
  108.     XMoveResizeWindow(dpy, menuwin, x, y, dx, dy);
  109.     XSelectInput(dpy, menuwin, MenuMask);
  110.     XMapRaised(dpy, menuwin);
  111.     status = grab(menuwin, MenuGrabMask, None, e->time);
  112.     if (status != GrabSuccess) {
  113.         /* graberror("menuhit", status); /* */
  114.         XUnmapWindow(dpy, menuwin);
  115.         return -1;
  116.     }
  117.     drawn = 0;
  118.     for (;;) {
  119.         XMaskEvent(dpy, MenuMask, &ev);
  120.         switch (ev.type) {
  121.         default:
  122.             fprintf(stderr, "9wm: menuhit: unknown ev.type %d\n", ev.type);
  123.             break;
  124.         case ButtonPress:
  125.             break;
  126.         case ButtonRelease:
  127.             if (ev.xbutton.button != e->button)
  128.                 break;
  129.             x = ev.xbutton.x;
  130.             y = ev.xbutton.y;
  131.             i = y/high;
  132.             if (cur >= 0 && y >= cur*high-3 && y < (cur+1)*high+3)
  133.                 i = cur;
  134.             if (x < 0 || x > wide || y < -3)
  135.                 i = -1;
  136.             else if (i < 0 || i >= n)
  137.                 i = -1;
  138.             else 
  139.                 m->lasthit = i;
  140.             if (!nobuttons(&ev.xbutton))
  141.                 i = -1;
  142.             ungrab(&ev.xbutton);
  143.             XUnmapWindow(dpy, menuwin);
  144.             return i;
  145.         case MotionNotify:
  146.             if (!drawn)
  147.                 break;
  148.             x = ev.xbutton.x;
  149.             y = ev.xbutton.y;
  150.             old = cur;
  151.             cur = y/high;
  152.             if (old >= 0 && y >= old*high-3 && y < (old+1)*high+3)
  153.                 cur = old;
  154.             if (x < 0 || x > wide || y < -3)
  155.                 cur = -1;
  156.             else if (cur < 0 || cur >= n)
  157.                 cur = -1;
  158.             if (cur == old)
  159.                 break;
  160.             if (old >= 0 && old < n)
  161.                 XFillRectangle(dpy, menuwin, gc, 0, old*high, wide, high);
  162.             if (cur >= 0 && cur < n)
  163.                 XFillRectangle(dpy, menuwin, gc, 0, cur*high, wide, high);
  164.             break;
  165.         case Expose:
  166.             for (i = 0; i < n; i++) {
  167.                 tx = (wide - XTextWidth(font, m->item[i], strlen(m->item[i])))/2;
  168.                 ty = i*high + font->ascent + 1;
  169.                 XDrawString(dpy, menuwin, gc, tx, ty, m->item[i], strlen(m->item[i]));
  170.             }
  171.             if (cur >= 0 && cur < n)
  172.                 XFillRectangle(dpy, menuwin, gc, 0, cur*high, wide, high);
  173.             drawn = 1;
  174.         }
  175.     }
  176. }
  177.  
  178. Client *
  179. selectwin(release, shift)
  180. int release;
  181. int *shift;
  182. {
  183.     XEvent ev;
  184.     XButtonEvent *e;
  185.     int status;
  186.     Window w;
  187.     Client *c;
  188.  
  189.     status = grab(root, ButtonMask, target, 0);
  190.     if (status != GrabSuccess) {
  191.         graberror("selectwin", status); /* */
  192.         return 0;
  193.     }
  194.     w = None;
  195.     for (;;) {
  196.         XMaskEvent(dpy, ButtonMask, &ev);
  197.         e = &ev.xbutton;
  198.         switch (ev.type) {
  199.         case ButtonPress:
  200.             if (e->button != Button3) {
  201.                 ungrab(e);
  202.                 return 0;
  203.             }
  204.             w = e->subwindow;
  205.             if (!release) {
  206.                 c = getclient(w, 0);
  207.                 if (c == 0)
  208.                     ungrab(e);
  209.                 if (shift != 0)
  210.                     *shift = (e->state&ShiftMask) != 0;
  211.                 return c;
  212.             }
  213.             break;
  214.         case ButtonRelease:
  215.             ungrab(e);
  216.             if (e->button != Button3 || e->subwindow != w)
  217.                 return 0;
  218.             if (shift != 0)
  219.                 *shift = (e->state&ShiftMask) != 0;
  220.             return getclient(w, 0);
  221.         }
  222.     }
  223. }
  224.  
  225. void
  226. sweepcalc(c, x, y)
  227. Client *c;
  228. int x;
  229. int y;
  230. {
  231.     int dx, dy, min_dx, min_dy, sx, sy;
  232.  
  233.     dx = x - c->x;
  234.     dy = y - c->y;
  235.     sx = sy = 1;
  236.     if (dx < 0) {
  237.         x += dx;
  238.         dx = -dx;
  239.         sx = -1;
  240.     }
  241.     if (dy < 0) {
  242.         y += dy;
  243.         dy = -dy;
  244.         sy = -1;
  245.     }
  246.  
  247.     dx -= 2*BORDER;
  248.     dy -= 2*BORDER;
  249.  
  250.     if (!c->is9term) {
  251.         if (dx < c->min_dx)
  252.             dx = c->min_dx;
  253.         if (dy < c->min_dy)
  254.             dy = c->min_dy;
  255.     }
  256.  
  257.     if (c->size.flags & PResizeInc) {
  258.         dx = c->min_dx + (dx-c->min_dx)/c->size.width_inc*c->size.width_inc;
  259.         dy = c->min_dy + (dy-c->min_dy)/c->size.height_inc*c->size.height_inc;
  260.     }
  261.  
  262.     if (c->size.flags & PMaxSize) {
  263.         if (dx > c->size.max_width)
  264.             dx = c->size.max_width;
  265.         if (dy > c->size.max_height)
  266.             dy = c->size.max_height;
  267.     }
  268.     c->dx = sx*(dx + 2*BORDER);
  269.     c->dy = sy*(dy + 2*BORDER);
  270. }
  271.  
  272. void
  273. dragcalc(c, x, y)
  274. Client *c;
  275. int x;
  276. int y;
  277. {
  278.     c->x = x;
  279.     c->y = y;
  280. }
  281.  
  282. void
  283. drawbound(c)
  284. Client *c;
  285. {
  286.     int x, y, dx, dy;
  287.  
  288.     x = c->x;
  289.     y = c->y;
  290.     dx = c->dx;
  291.     dy = c->dy;
  292.     if (dx < 0) {
  293.         x += dx;
  294.         dx = -dx;
  295.     }
  296.     if (dy < 0) {
  297.         y += dy;
  298.         dy = -dy;
  299.     }
  300.     if (dx <= 2 || dy <= 2)
  301.         return;
  302.     XDrawRectangle(dpy, root, gc, x, y, dx-1, dy-1);
  303.     XDrawRectangle(dpy, root, gc, x+1, y+1, dx-3, dy-3);
  304. }
  305.  
  306. int
  307. sweepdrag(c, e0, recalc)
  308. Client *c;
  309. XButtonEvent *e0;
  310. void (*recalc)();
  311. {
  312.     XEvent ev;
  313.     int status;
  314.     int cx, cy, rx, ry;
  315.     int ox, oy, odx, ody;
  316.     struct timeval t;
  317.     XButtonEvent *e;
  318.  
  319.     ox = c->x;
  320.     oy = c->y;
  321.     odx = c->dx;
  322.     ody = c->dy;
  323.     c->x -= BORDER;
  324.     c->y -= BORDER;
  325.     c->dx += 2*BORDER;
  326.     c->dy += 2*BORDER;
  327.     if (e0) {
  328.         c->x = cx = e0->x;
  329.         c->y = cy = e0->y;
  330.         recalc(c, e0->x, e0->y);
  331.     }
  332.     else
  333.         getmouse(&cx, &cy);
  334.     XGrabServer(dpy);
  335.     drawbound(c);
  336.     t.tv_sec = 0;
  337.     t.tv_usec = 50*1000;
  338.     for (;;) {
  339.         if (XCheckMaskEvent(dpy, ButtonMask, &ev) == 0) {
  340.             getmouse(&rx, &ry);
  341.             if (rx == cx && ry == cy)
  342.                 continue;
  343.             drawbound(c);
  344.             recalc(c, rx, ry);
  345.             cx = rx;
  346.             cy = ry;
  347.             drawbound(c);
  348.             XFlush(dpy);
  349.             select(0, 0, 0, 0, &t);
  350.             continue;
  351.         }
  352.         e = &ev.xbutton;
  353.         switch (ev.type) {
  354.         case ButtonPress:
  355.         case ButtonRelease:
  356.             drawbound(c);
  357.             ungrab(e);
  358.             XUngrabServer(dpy);
  359.             if (e->button != Button3 && c->init)
  360.                 goto bad;
  361.             recalc(c, ev.xbutton.x, ev.xbutton.y);
  362.             if (c->dx < 0) {
  363.                 c->x += c->dx;
  364.                 c->dx = -c->dx;
  365.             }
  366.             if (c->dy < 0) {
  367.                 c->y += c->dy;
  368.                 c->dy = -c->dy;
  369.             }
  370.             c->x += BORDER;
  371.             c->y += BORDER;
  372.             c->dx -= 2*BORDER;
  373.             c->dy -= 2*BORDER;
  374.             if (c->dx < 4 || c->dy < 4 || c->dx < c->min_dx || c->dy < c->min_dy)
  375.                 goto bad;
  376.             return 1;
  377.         }
  378.     }
  379. bad:
  380.     c->x = ox;
  381.     c->y = oy;
  382.     c->dx = odx;
  383.     c->dy = ody;
  384.     return 0;
  385. }
  386.  
  387. int
  388. sweep(c)
  389. Client *c;
  390. {
  391.     XEvent ev;
  392.     int status;
  393.     XButtonEvent *e;
  394.  
  395.     status = grab(root, ButtonMask, sweep0, 0);
  396.     if (status != GrabSuccess) {
  397.         graberror("sweep", status); /* */
  398.         return 0;
  399.     }
  400.  
  401.     XMaskEvent(dpy, ButtonMask, &ev);
  402.     e = &ev.xbutton;
  403.     if (e->button != Button3) {
  404.         ungrab(e);
  405.         return 0;
  406.     }
  407.     if (c->size.flags & (PMinSize|PBaseSize))
  408.         setmouse(e->x+c->min_dx, e->y+c->min_dy);
  409.     XChangeActivePointerGrab(dpy, ButtonMask, boxcurs, e->time);
  410.     return sweepdrag(c, e, sweepcalc);
  411. }
  412.  
  413. int
  414. drag(c)
  415. Client *c;
  416. {
  417.     XEvent ev;
  418.     int status;
  419.  
  420.     if (c->init)
  421.         setmouse(c->x-BORDER, c->y-BORDER);
  422.     else
  423.         getmouse(&c->x, &c->y);     /* start at current mouse pos */
  424.     status = grab(root, ButtonMask, boxcurs, 0);
  425.     if (status != GrabSuccess) {
  426.         graberror("drag", status); /* */
  427.         return 0;
  428.     }
  429.     return sweepdrag(c, 0, dragcalc);
  430. }
  431.  
  432. void
  433. getmouse(x, y)
  434. int *x;
  435. int *y;
  436. {
  437.     Window dw1, dw2;
  438.     int t1, t2;
  439.     unsigned int t3;
  440.  
  441.     XQueryPointer(dpy, root, &dw1, &dw2, x, y, &t1, &t2, &t3);
  442. }
  443.  
  444. void
  445. setmouse(x, y)
  446. int x;
  447. int y;
  448. {
  449.     XWarpPointer(dpy, None, root, None, None, None, None, x, y);
  450. }
  451.