1 /* Copyright (c) 1994-1996 David Hogan, see README for licence details */
11 nobuttons(XButtonEvent *e) /* Einstuerzende */
15 state = (e->state & AllButtonMask);
16 return (e->type == ButtonRelease) && (state & (state - 1)) == 0;
20 grab(Window w, Window constrain, int mask, Cursor curs, int t)
26 status = XGrabPointer(dpy, w, False, mask,
27 GrabModeAsync, GrabModeAsync, constrain, curs, t);
32 ungrab(XButtonEvent *e)
38 XMaskEvent(dpy, ButtonMask | ButtonMotionMask, &ev);
39 if(ev.type == MotionNotify)
45 XUngrabPointer(dpy, e->time);
50 drawstring(Display *dpy, ScreenInfo *s, Menu *m, int wide, int high, int i, int selected)
54 tx = (wide - XTextWidth(font, m->item[i], strlen(m->item[i])))/2;
55 ty = i*high + font->ascent + 1;
56 XFillRectangle(dpy, s->menuwin, selected ? s->gcmenubgs : s->gcmenubg, 0, i*high, wide, high);
57 XDrawString(dpy, s->menuwin, selected ? s->gcmenufgs : s->gcmenufg, tx, ty, m->item[i], strlen(m->item[i]));
61 menuhit(XButtonEvent *e, Menu *m)
64 int i, n, cur, old, wide, high, status, drawn, warp;
65 int x, y, dx, dy, xmax, ymax;
70 s = getscreen(e->root);
71 if(s == 0 || e->window == s->menuwin) /* ugly event mangling */
75 for(n = 0; m->item[n]; n++){
76 wide = XTextWidth(font, m->item[n], strlen(m->item[n])) + 4;
85 high = font->ascent + font->descent + 1;
88 y = e->y - cur*high - high/2;
90 xmax = DisplayWidth(dpy, s->num);
91 ymax = DisplayHeight(dpy, s->num);
113 setmouse(e->x, e->y, s);
114 XMoveResizeWindow(dpy, s->menuwin, x, y, dx, dy);
115 XSelectInput(dpy, s->menuwin, MenuMask);
116 XMapRaised(dpy, s->menuwin);
117 status = grab(s->menuwin, None, MenuGrabMask, None, e->time);
118 if(status != GrabSuccess){
119 /* graberror("menuhit", status); */
120 XUnmapWindow(dpy, s->menuwin);
125 XMaskEvent(dpy, MenuMask, &ev);
128 fprintf(stderr, "rio: menuhit: unknown ev.type %d\n", ev.type);
133 if(ev.xbutton.button != e->button)
138 if(cur >= 0 && y >= cur*high-3 && y < (cur+1)*high+3)
140 if(x < 0 || x > wide || y < -3)
142 else if(i < 0 || i >= n)
146 if(!nobuttons(&ev.xbutton))
149 XUnmapWindow(dpy, s->menuwin);
158 if(old >= 0 && y >= old*high-3 && y < (old+1)*high+3)
160 if(x < 0 || x > wide || y < -3)
162 else if(cur < 0 || cur >= n)
166 if(old >= 0 && old < n)
167 drawstring(dpy, s, m, wide, high, old, 0);
168 if(cur >= 0 && cur < n)
169 drawstring(dpy, s, m, wide, high, cur, 1);
172 XClearWindow(dpy, s->menuwin);
173 for(i = 0; i < n; i++)
174 drawstring(dpy, s, m, wide, high, i, cur==i);
181 selectwin(int release, int *shift, ScreenInfo *s)
189 status = grab(s->root, s->root, ButtonMask, s->target, 0);
190 if(status != GrabSuccess){
191 graberror("selectwin", status); /* */
196 XMaskEvent(dpy, ButtonMask, &ev);
200 if(e->button != Button3){
210 *shift = (e->state&ShiftMask) != 0;
216 if(e->button != Button3 || e->subwindow != w)
219 *shift = (e->state&ShiftMask) != 0;
220 return getclient(w, 0);
226 sweepcalc(Client *c, int x, int y, BorderOrient bl, int ignored)
254 if(c->size.flags & PResizeInc){
255 dx = c->min_dx + (dx-c->min_dx)/c->size.width_inc*c->size.width_inc;
256 dy = c->min_dy + (dy-c->min_dy)/c->size.height_inc*c->size.height_inc;
259 if(c->size.flags & PMaxSize){
260 if(dx > c->size.max_width)
261 dx = c->size.max_width;
262 if(dy > c->size.max_height)
263 dy = c->size.max_height;
265 c->dx = sx*(dx + 2*BORDER);
266 c->dy = sy*(dy + 2*BORDER);
272 dragcalc(Client *c, int x, int y, BorderOrient bl, int ignored)
281 pullcalc(Client *c, int x, int y, BorderOrient bl, int init)
283 int dx, dy, sx, sy, px, py, spx, spy, rdx, rdy, xoff, yoff, xcorn, ycorn;
297 dy = (c->y + c->dy) - y;
303 yoff = (c->y + c->dy) - y;
307 xoff = (c->x + c->dx) - x;
311 dx = (c->x + c->dx) - x;
318 dx = (c->x + c->dx) - x;
321 dy = (c->y + c->dy) - y;
330 dy = (c->y + c->dy) - y;
332 xoff = (c->x + c->dx) - x;
339 xoff = (c->x + c->dx) - x;
340 yoff = (c->y + c->dy) - y;
345 dx = (c->x + c->dx) - x;
349 yoff = (c->y + c->dy) - y;
369 || xoff < 0 || (xcorn && xoff > CORNER) || (!xcorn && xoff > BORDER)
370 || yoff < 0 || (ycorn && yoff > CORNER) || (!ycorn && yoff > BORDER)){
376 if(debug) fprintf(stderr, "c %dx%d+%d+%d m +%d+%d r %dx%d+%d+%d sp (%d,%d) bl %d\n",
377 c->dx, c->dy, c->x, c->y, x, y, dx, dy, px, py, spx, spy, bl);
387 /* remember requested size;
388 * after applying size hints we may have to correct position
393 /* apply size hints */
394 dx -= (2*BORDER - xoff);
395 dy -= (2*BORDER - yoff);
404 if(c->size.flags & PResizeInc){
405 dx = c->min_dx + (dx-c->min_dx)/c->size.width_inc*c->size.width_inc;
406 dy = c->min_dy + (dy-c->min_dy)/c->size.height_inc*c->size.height_inc;
409 if(c->size.flags & PMaxSize){
410 if(dx > c->size.max_width)
411 dx = c->size.max_width;
412 if(dy > c->size.max_height)
413 dy = c->size.max_height;
416 /* set size and position */
417 c->dx = sx*(dx + 2*BORDER );
418 c->dy = sy*(dy + 2*BORDER );
422 /* compensate position for size changed due to size hints */
432 xcopy(int fwd, Display *dpy, Drawable src, Drawable dst, GC gc, int x, int y, int dx, int dy, int x1, int y1)
435 XCopyArea(dpy, src, dst, gc, x, y, dx, dy, x1, y1);
437 XCopyArea(dpy, dst, src, gc, x1, y1, dx, dy, x, y);
441 drawbound(Client *c, int drawing)
446 if(debug) fprintf(stderr, "drawbound %d %dx%d+%d+%d\n", drawing, c->dx, c->dy, c->x, c->y);
461 if(dx <= 2 || dy <= 2)
466 XUnmapWindow(dpy, s->sweepwin);
476 XMoveResizeWindow(dpy, s->sweepwin, x, y, dx, dy);
477 XSelectInput(dpy, s->sweepwin, MenuMask);
478 XMapRaised(dpy, s->sweepwin);
486 xcopy(drawing, dpy, s->root, s->bkup[0], s->gccopy, x, y, dx, BORDER, 0, 0);
487 xcopy(drawing, dpy, s->root, s->bkup[0], s->gccopy, x, y+dy-BORDER, dx, BORDER, dx, 0);
488 xcopy(drawing, dpy, s->root, s->bkup[1], s->gccopy, x, y, BORDER, dy, 0, 0);
489 xcopy(drawing, dpy, s->root, s->bkup[1], s->gccopy, x+dx-BORDER, y, BORDER, dy, 0, dy);
492 XFillRectangle(dpy, s->root, s->gcred, x, y, dx, BORDER);
493 XFillRectangle(dpy, s->root, s->gcred, x, y+dy-BORDER, dx, BORDER);
494 XFillRectangle(dpy, s->root, s->gcred, x, y, BORDER, dy);
495 XFillRectangle(dpy, s->root, s->gcred, x+dx-BORDER, y, BORDER, dy);
504 t.tv_sec = msec/1000;
505 t.tv_usec = (msec%1000)*1000;
506 select(0, 0, 0, 0, &t);
510 sweepdrag(Client *c, int but, XButtonEvent *e0, BorderOrient bl, int (*recalc)(Client*, int, int, BorderOrient, int))
515 int ox, oy, odx, ody;
528 if(bl != BorderUnknown || e0 == 0)
529 getmouse(&cx, &cy, c->screen);
531 getmouse(&c->x, &c->y, c->screen);
533 if(bl != BorderUnknown){
534 notmoved = recalc(c, cx, cy, bl, notmoved);
539 if(XCheckMaskEvent(dpy, ButtonMask, &ev) == 0){
540 getmouse(&rx, &ry, c->screen);
541 if(rx != cx || ry != cy || ++idle > 300){
543 if(rx == cx && ry == cy){
550 if(e0 || bl != BorderUnknown)
551 notmoved = recalc(c, rx, ry, bl, notmoved);
553 notmoved = recalc(c, rx-cx, ry-cy, bl, notmoved);
569 if(e->button != but && c->init)
583 if(c->dx < 4 || c->dy < 4 || c->dx < c->min_dx || c->dy < c->min_dy)
589 if(debug) fprintf(stderr, "sweepdrag bad\n");
599 sweep(Client *c, int but, XButtonEvent *ignored)
609 status = grab(s->root, s->root, ButtonMask, s->sweep0, 0);
610 if(status != GrabSuccess){
611 graberror("sweep", status); /* */
615 XMaskEvent(dpy, ButtonMask, &ev);
617 if(e->button != but){
621 XChangeActivePointerGrab(dpy, ButtonMask, s->boxcurs, e->time);
622 return sweepdrag(c, but, e, BorderUnknown, sweepcalc);
626 pull(Client *c, int but, XButtonEvent *e)
632 bl = borderorient(c, e->x, e->y);
633 /* assert(bl > BorderUnknown && bl < NBorder); */
636 status = grab(s->root, s->root, ButtonMask, s->bordcurs[bl], 0);
637 if(status != GrabSuccess){
638 graberror("pull", status); /* */
642 return sweepdrag(c, but, 0, bl, pullcalc);
646 drag(Client *c, int but)
652 status = grab(s->root, s->root, ButtonMask, s->boxcurs, 0);
653 if(status != GrabSuccess){
654 graberror("drag", status); /* */
657 return sweepdrag(c, but, 0, BorderUnknown, dragcalc);
661 getmouse(int *x, int *y, ScreenInfo *s)
667 XQueryPointer(dpy, s->root, &dw1, &dw2, x, y, &t1, &t2, &t3);
668 if(debug) fprintf(stderr, "getmouse: %d %d\n", *x, *y);
672 setmouse(int x, int y, ScreenInfo *s)
674 XWarpPointer(dpy, None, s->root, None, None, None, None, x, y);