Logo Search packages:      
Sourcecode: 9wm version File versions  Download package

grab.c

/* Copyright (c) 1994-1996 David Hogan, see README for licence details */
#include <stdio.h>
#include <X11/X.h>
#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "dat.h"
#include "fns.h"

int
nobuttons(e)      /* Einstuerzende */
XButtonEvent *e;
{
      int state;

      state = (e->state & AllButtonMask);
      return (e->type == ButtonRelease) && (state & (state - 1)) == 0;
}

int
grab(w, constrain, mask, curs, t)
Window w;
Window constrain;
int mask;
Cursor curs;
int t;
{
      int status;

      if (t == 0)
            t = timestamp();
      status = XGrabPointer(dpy, w, False, mask,
            GrabModeAsync, GrabModeAsync, constrain, curs, t);
      return status;
}

void
ungrab(e)
XButtonEvent *e;
{
      XEvent ev;

      if (!nobuttons(e))
            for (;;) {
                  XMaskEvent(dpy, ButtonMask | ButtonMotionMask, &ev);
                  if (ev.type == MotionNotify)
                        continue;
                  e = &ev.xbutton;
                  if (nobuttons(e))
                        break;
            }
      XUngrabPointer(dpy, e->time);
      curtime = e->time;
}

int
menuhit(e, m)
XButtonEvent *e;
Menu *m;
{
      XEvent ev;
      int i, n, cur, old, wide, high, status, drawn, warp;
      int x, y, dx, dy, xmax, ymax;
      int tx, ty;
      ScreenInfo *s;

      if (font == 0)
            return -1;
      s = getscreen(e->root);
      if (s == 0 || e->window == s->menuwin)       /* ugly event mangling */
            return -1;

      dx = 0;
      for (n = 0; m->item[n]; n++) {
            wide = XTextWidth(font, m->item[n], strlen(m->item[n])) + 4;
            if (wide > dx)
                  dx = wide;
      }
      wide = dx;
      cur = m->lasthit;
      if (cur >= n)
            cur = n - 1;

      high = font->ascent + font->descent + 1;
      dy = n*high;
      x = e->x - wide/2;
      y = e->y - cur*high - high/2;
      warp = 0;
      xmax = DisplayWidth(dpy, s->num);
      ymax = DisplayHeight(dpy, s->num);
      if (x < 0) {
            e->x -= x;
            x = 0;
            warp++;
      }
      if (x+wide >= xmax) {
            e->x -= x+wide-xmax;
            x = xmax-wide;
            warp++;
      }
      if (y < 0) {
            e->y -= y;
            y = 0;
            warp++;
      }
      if (y+dy >= ymax) {
            e->y -= y+dy-ymax;
            y = ymax-dy;
            warp++;
      }
      if (warp)
            setmouse(e->x, e->y, s);
      XMoveResizeWindow(dpy, s->menuwin, x, y, dx, dy);
      XSelectInput(dpy, s->menuwin, MenuMask);
      XMapRaised(dpy, s->menuwin);
      status = grab(s->menuwin, None, MenuGrabMask, None, e->time);
      if (status != GrabSuccess) {
            /* graberror("menuhit", status); */
            XUnmapWindow(dpy, s->menuwin);
            return -1;
      }
      drawn = 0;
      for (;;) {
            XMaskEvent(dpy, MenuMask, &ev);
            switch (ev.type) {
            default:
                  fprintf(stderr, "9wm: menuhit: unknown ev.type %d\n", ev.type);
                  break;
            case ButtonPress:
                  break;
            case ButtonRelease:
                  if (ev.xbutton.button != e->button)
                        break;
                  x = ev.xbutton.x;
                  y = ev.xbutton.y;
                  i = y/high;
                  if (cur >= 0 && y >= cur*high-3 && y < (cur+1)*high+3)
                        i = cur;
                  if (x < 0 || x > wide || y < -3)
                        i = -1;
                  else if (i < 0 || i >= n)
                        i = -1;
                  else
                        m->lasthit = i;
                  if (!nobuttons(&ev.xbutton))
                        i = -1;
                  ungrab(&ev.xbutton);
                  XUnmapWindow(dpy, s->menuwin);
                  return i;
            case MotionNotify:
                  if (!drawn)
                        break;
                  x = ev.xbutton.x;
                  y = ev.xbutton.y;
                  old = cur;
                  cur = y/high;
                  if (old >= 0 && y >= old*high-3 && y < (old+1)*high+3)
                        cur = old;
                  if (x < 0 || x > wide || y < -3)
                        cur = -1;
                  else if (cur < 0 || cur >= n)
                        cur = -1;
                  if (cur == old)
                        break;
                  if (old >= 0 && old < n)
                        XFillRectangle(dpy, s->menuwin, s->gc, 0, old*high, wide, high);
                  if (cur >= 0 && cur < n)
                        XFillRectangle(dpy, s->menuwin, s->gc, 0, cur*high, wide, high);
                  break;
            case Expose:
                  XClearWindow(dpy, s->menuwin);
                  for (i = 0; i < n; i++) {
                        tx = (wide - XTextWidth(font, m->item[i], strlen(m->item[i])))/2;
                        ty = i*high + font->ascent + 1;
                        XDrawString(dpy, s->menuwin, s->gc, tx, ty, m->item[i], strlen(m->item[i]));
                  }
                  if (cur >= 0 && cur < n)
                        XFillRectangle(dpy, s->menuwin, s->gc, 0, cur*high, wide, high);
                  drawn = 1;
            }
      }
}

Client *
selectwin(release, shift, s)
int release;
int *shift;
ScreenInfo *s;
{
      XEvent ev;
      XButtonEvent *e;
      int status;
      Window w;
      Client *c;

      status = grab(s->root, s->root, ButtonMask, s->target, 0);
      if (status != GrabSuccess) {
            graberror("selectwin", status); /* */
            return 0;
      }
      w = None;
      for (;;) {
            XMaskEvent(dpy, ButtonMask, &ev);
            e = &ev.xbutton;
            switch (ev.type) {
            case ButtonPress:
                  if (e->button != Button3) {
                        ungrab(e);
                        return 0;
                  }
                  w = e->subwindow;
                  if (!release) {
                        c = getclient(w, 0);
                        if (c == 0)
                              ungrab(e);
                        if (shift != 0)
                              *shift = (e->state&ShiftMask) != 0;
                        return c;
                  }
                  break;
            case ButtonRelease:
                  ungrab(e);
                  if (e->button != Button3 || e->subwindow != w)
                        return 0;
                  if (shift != 0)
                        *shift = (e->state&ShiftMask) != 0;
                  return getclient(w, 0);
            }
      }
}

void
sweepcalc(c, x, y)
Client *c;
int x;
int y;
{
      int dx, dy, sx, sy;

      dx = x - c->x;
      dy = y - c->y;
      sx = sy = 1;
      if (dx < 0) {
            dx = -dx;
            sx = -1;
      }
      if (dy < 0) {
            dy = -dy;
            sy = -1;
      }

      dx -= 2*BORDER;
      dy -= 2*BORDER;

      if (!c->is9term) {
            if (dx < c->min_dx)
                  dx = c->min_dx;
            if (dy < c->min_dy)
                  dy = c->min_dy;
      }

      if (c->size.flags & PResizeInc) {
            dx = c->min_dx + (dx-c->min_dx)/c->size.width_inc*c->size.width_inc;
            dy = c->min_dy + (dy-c->min_dy)/c->size.height_inc*c->size.height_inc;
      }

      if (c->size.flags & PMaxSize) {
            if (dx > c->size.max_width)
                  dx = c->size.max_width;
            if (dy > c->size.max_height)
                  dy = c->size.max_height;
      }
      c->dx = sx*(dx + 2*BORDER);
      c->dy = sy*(dy + 2*BORDER);
}

void
dragcalc(c, x, y)
Client *c;
int x;
int y;
{
      c->x = x;
      c->y = y;
}

void
drawbound(c)
Client *c;
{
      int x, y, dx, dy;
      ScreenInfo *s;

      s = c->screen;
      x = c->x;
      y = c->y;
      dx = c->dx;
      dy = c->dy;
      if (dx < 0) {
            x += dx;
            dx = -dx;
      }
      if (dy < 0) {
            y += dy;
            dy = -dy;
      }
      if (dx <= 2 || dy <= 2)
            return;
      XDrawRectangle(dpy, s->root, s->gc, x, y, dx-1, dy-1);
      XDrawRectangle(dpy, s->root, s->gc, x+1, y+1, dx-3, dy-3);
}

void
misleep(msec)
int msec;
{
      struct timeval t;

      t.tv_sec = msec/1000;
      t.tv_usec = (msec%1000)*1000;
      select(0, 0, 0, 0, &t);
}

int
sweepdrag(c, e0, recalc)
Client *c;
XButtonEvent *e0;
void (*recalc)();
{
      XEvent ev;
      int idle;
      int cx, cy, rx, ry;
      int ox, oy, odx, ody;
      XButtonEvent *e;

      ox = c->x;
      oy = c->y;
      odx = c->dx;
      ody = c->dy;
      c->x -= BORDER;
      c->y -= BORDER;
      c->dx += 2*BORDER;
      c->dy += 2*BORDER;
      if (e0) {
            c->x = cx = e0->x;
            c->y = cy = e0->y;
            recalc(c, e0->x, e0->y);
      }
      else
            getmouse(&cx, &cy, c->screen);
      XGrabServer(dpy);
      drawbound(c);
      idle = 0;
      for (;;) {
            if (XCheckMaskEvent(dpy, ButtonMask, &ev) == 0) {
                  getmouse(&rx, &ry, c->screen);
                  if (rx != cx || ry != cy || ++idle > 300) {
                        drawbound(c);
                        if (rx == cx && ry == cy) {
                              XUngrabServer(dpy);
                              XFlush(dpy);
                              misleep(500);
                              XGrabServer(dpy);
                              idle = 0;
                        }
                        recalc(c, rx, ry);
                        cx = rx;
                        cy = ry;
                        drawbound(c);
                        XFlush(dpy);
                  }
                  misleep(50);
                  continue;
            }
            e = &ev.xbutton;
            switch (ev.type) {
            case ButtonPress:
            case ButtonRelease:
                  drawbound(c);
                  ungrab(e);
                  XUngrabServer(dpy);
                  if (e->button != Button3 && c->init)
                        goto bad;
                  recalc(c, ev.xbutton.x, ev.xbutton.y);
                  if (c->dx < 0) {
                        c->x += c->dx;
                        c->dx = -c->dx;
                  }
                  if (c->dy < 0) {
                        c->y += c->dy;
                        c->dy = -c->dy;
                  }
                  c->x += BORDER;
                  c->y += BORDER;
                  c->dx -= 2*BORDER;
                  c->dy -= 2*BORDER;
                  if (c->dx < 4 || c->dy < 4 || c->dx < c->min_dx || c->dy < c->min_dy)
                        goto bad;
                  return 1;
            }
      }
bad:
      c->x = ox;
      c->y = oy;
      c->dx = odx;
      c->dy = ody;
      return 0;
}

int
sweep(c)
Client *c;
{
      XEvent ev;
      int status;
      XButtonEvent *e;
      ScreenInfo *s;

      s = c->screen;
      status = grab(s->root, s->root, ButtonMask, s->sweep0, 0);
      if (status != GrabSuccess) {
            graberror("sweep", status); /* */
            return 0;
      }

      XMaskEvent(dpy, ButtonMask, &ev);
      e = &ev.xbutton;
      if (e->button != Button3) {
            ungrab(e);
            return 0;
      }
      if (c->size.flags & (PMinSize|PBaseSize))
             setmouse(e->x+c->min_dx, e->y+c->min_dy, s);
      XChangeActivePointerGrab(dpy, ButtonMask, s->boxcurs, e->time);
      return sweepdrag(c, e, sweepcalc);
}

int
drag(c)
Client *c;
{
      int status;
      ScreenInfo *s;

      s = c->screen;
      if (c->init)
            setmouse(c->x-BORDER, c->y-BORDER, s);
      else {
            getmouse(&c->x, &c->y, s);             /* start at current mouse pos */
            c->x += BORDER;
            c->y += BORDER;
      }
      status = grab(s->root, s->root, ButtonMask, s->boxcurs, 0);
      if (status != GrabSuccess) {
            graberror("drag", status); /* */
            return 0;
      }
      return sweepdrag(c, 0, dragcalc);
}

void
getmouse(x, y, s)
int *x;
int *y;
ScreenInfo *s;
{
      Window dw1, dw2;
      int t1, t2;
      unsigned int t3;

      XQueryPointer(dpy, s->root, &dw1, &dw2, x, y, &t1, &t2, &t3);
}

void
setmouse(x, y, s)
int x;
int y;
ScreenInfo *s;
{
      XWarpPointer(dpy, None, s->root, None, None, None, None, x, y);
}

Generated by  Doxygen 1.6.0   Back to index