wmii/cmd/wm/mouse.c

248 lines
6.1 KiB
C
Raw Normal View History

2005-11-18 18:54:58 +03:00
/*
2006-01-20 17:20:24 +03:00
* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
2006-05-31 13:38:54 +04:00
* (C)opyright MMVI Kris Maglione <fbsdaemon@gmail.com>
2005-11-18 18:54:58 +03:00
* See LICENSE file for license details.
*/
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
2005-11-18 18:54:58 +03:00
#include "wm.h"
#define ButtonMask (ButtonPressMask | ButtonReleaseMask)
#define MouseMask (ButtonMask | PointerMotionMask)
2006-05-31 10:47:07 +04:00
static void
2006-05-31 19:21:52 +04:00
rect_morph_xy(XRectangle *rect, int dx, int dy, BlitzAlign *mask)
2006-05-31 18:22:56 +04:00
{
BlitzAlign new_mask = 0;
2006-05-31 19:21:52 +04:00
if(*mask & NORTH) {
if(rect->height - dy >= 0 || *mask & SOUTH) {
rect->y += dy;
rect->height -= dy;
}
else {
rect->y -= rect->height;
rect->height = dy - rect->height;
new_mask ^= NORTH|SOUTH;
}
}
if(*mask & WEST) {
if(rect->width - dx >= 0 || *mask & EAST) {
rect->x += dx;
rect->width -= dx;
}
else {
rect->x -= rect->width;
rect->width = dx - rect->width;
new_mask ^= EAST|WEST;
}
}
if(*mask & EAST) {
if(rect->width + dx >= 0 || *mask & WEST)
rect->width += dx;
else {
rect->x -= rect->width;
rect->width = -dx - rect->width;
new_mask ^= EAST|WEST;
}
2006-05-31 18:22:56 +04:00
}
2006-05-31 19:21:52 +04:00
if(*mask & SOUTH) {
if(rect->height + dy >= 0 || *mask & WEST)
rect->height += dy;
else {
rect->y -= rect->height;
rect->height = -dy - rect->height;
new_mask ^= NORTH|SOUTH;
}
2006-05-31 18:22:56 +04:00
}
2006-05-31 19:21:52 +04:00
*mask ^= new_mask;
2006-05-31 18:22:56 +04:00
}
2005-11-18 18:54:58 +03:00
2006-05-31 10:47:07 +04:00
static void
2006-05-31 18:22:56 +04:00
snap_line(XRectangle *rects, int num, int x1, int y1, int x2, int y2,
int snapw, BlitzAlign mask, int *delta)
{
int i, t_xy;
2006-05-31 19:21:52 +04:00
2006-05-31 18:22:56 +04:00
/* horizontal */
if(y1 == y2 && (mask & (NORTH|SOUTH))) {
for(i=0; i < num; i++) {
if(!((rects[i].x + rects[i].width < x1) ||
2006-05-31 19:21:52 +04:00
(rects[i].x > x2))) {
2006-05-31 18:22:56 +04:00
if(abs(rects[i].y - y1) <= abs(*delta))
*delta = rects[i].y - y1;
2006-05-31 19:21:52 +04:00
2006-05-31 18:22:56 +04:00
t_xy = rects[i].y + rects[i].height;
if(abs(t_xy - y1) < abs(*delta))
*delta = t_xy - y1;
}
}
}
else if (mask & (EAST|WEST)) {
/* This is the same as above, tr/xy/yx/,
* s/width/height/, s/height/width/ */
for(i=0; i < num; i++) {
if(!((rects[i].y + rects[i].height < y1) ||
2006-05-31 19:21:52 +04:00
(rects[i].y > y2))) {
2006-05-31 18:22:56 +04:00
if(abs(rects[i].x - x1) <= abs(*delta))
*delta = rects[i].x - x1;
2006-05-31 19:21:52 +04:00
2006-05-31 18:22:56 +04:00
t_xy = rects[i].x + rects[i].width;
if(abs(t_xy - x1) < abs(*delta))
*delta = t_xy - x1;
}
}
}
2005-11-18 18:54:58 +03:00
}
void
2006-05-31 10:47:07 +04:00
snap_rect(XRectangle *rects, int num, XRectangle *current,
2006-05-31 19:21:52 +04:00
BlitzAlign *mask, int snap)
2006-05-31 18:22:56 +04:00
{
int dx = snap + 1, dy = snap + 1;
2006-05-31 19:21:52 +04:00
if(*mask & NORTH)
2006-05-31 18:22:56 +04:00
snap_line(rects, num, current->x, current->y,
current->x + current->width, current->y,
2006-05-31 19:21:52 +04:00
snap, *mask, &dy);
if(*mask & EAST)
2006-05-31 18:22:56 +04:00
snap_line(rects, num, current->x + current->width, current->y,
current->x + current->width, current->y + current->height,
2006-05-31 19:21:52 +04:00
snap, *mask, &dx);
if(*mask & SOUTH)
2006-05-31 18:22:56 +04:00
snap_line(rects, num, current->x, current->y + current->height,
current->x + current->width, current->y + current->height,
2006-05-31 19:21:52 +04:00
snap, *mask, &dy);
if(*mask & WEST)
2006-05-31 18:22:56 +04:00
snap_line(rects, num, current->x, current->y,
current->x, current->y + current->height,
2006-05-31 19:21:52 +04:00
snap, *mask, &dx);
2006-05-31 18:22:56 +04:00
rect_morph_xy(current, abs(dx) <= snap ? dx : 0,
abs(dy) <= snap ? dy : 0, mask);
2005-11-18 18:54:58 +03:00
}
static void
draw_xor_border(XRectangle *r)
2005-11-18 18:54:58 +03:00
{
XRectangle xor = *r;
xor.x += 2;
xor.y += 2;
2006-05-31 19:21:52 +04:00
xor.width = xor.width > 4 ? xor.width - 4 : 0;
xor.height = xor.height > 4 ? xor.height - 4 : 0;
XSetLineAttributes(dpy, xorgc, 1, LineSolid, CapNotLast, JoinMiter);
XDrawLine(dpy, root, xorgc, xor.x + 2, xor.y + xor.height / 2,
xor.x + xor.width - 2, xor.y + xor.height / 2);
XDrawLine(dpy, root, xorgc, xor.x + xor.width / 2, xor.y + 2,
xor.x + xor.width / 2, xor.y + xor.height - 2);
XSetLineAttributes(dpy, xorgc, 4, LineSolid, CapNotLast, JoinMiter);
XDrawRectangles(dpy, root, xorgc, &xor, 1);
XSync(dpy, False);
2005-11-18 18:54:58 +03:00
}
2005-12-21 18:18:11 +03:00
void
do_mouse_resize(Client *c, BlitzAlign align)
2005-11-18 18:54:58 +03:00
{
2006-05-31 19:53:05 +04:00
int px, py, ox, oy;
Window dummy;
XEvent ev;
2006-05-31 19:21:52 +04:00
unsigned int num = 0;
2006-04-26 20:46:54 +04:00
Frame *f = c->frame.data[c->sel];
int aidx = idx_of_area(f->area);
2006-05-31 10:47:07 +04:00
int snap = aidx ? 0 : rect.height / 66;
XRectangle *rects = aidx ? nil : rects_of_view(f->area->view, &num);
2006-04-26 20:46:54 +04:00
XRectangle frect = f->rect;
XRectangle origin = frect;
2006-05-31 10:47:07 +04:00
XPoint pt;
2006-05-31 19:21:52 +04:00
px = ox = frect.width / 2;
py = oy = frect.height / 2;
if(align&NORTH)
oy -= py;
if(align&SOUTH)
oy += py;
if(align&EAST)
ox += px;
2006-05-31 19:21:52 +04:00
if(align&WEST)
ox -= px;
2006-05-31 19:21:52 +04:00
XWarpPointer(dpy, None, c->framewin, 0, 0, 0, 0, ox, oy);
XTranslateCoordinates(dpy, c->framewin, root, ox, oy, &ox, &oy, &dummy);
2006-05-31 10:47:07 +04:00
pt.x = ox; pt.y = oy;
XSync(dpy, False);
if(XGrabPointer(dpy, c->framewin, False, MouseMask, GrabModeAsync, GrabModeAsync,
2006-05-31 10:47:07 +04:00
None, cursor[CurResize], CurrentTime) != GrabSuccess)
return;
2006-05-31 10:47:07 +04:00
XGrabServer(dpy);
draw_xor_border(&frect);
for(;;) {
XMaskEvent(dpy, MouseMask | ExposureMask, &ev);
switch (ev.type) {
case ButtonRelease:
draw_xor_border(&frect);
if(aidx)
2006-05-31 10:47:07 +04:00
resize_column(c, &frect, (align == CENTER) ? &pt : nil);
else
resize_client(c, &frect, False);
if(rects)
free(rects);
XUngrabServer(dpy);
XUngrabPointer(dpy, CurrentTime);
XSync(dpy, False);
return;
break;
case MotionNotify:
draw_xor_border(&frect);
2006-05-31 10:47:07 +04:00
pt.x = ev.xmotion.x;
pt.y = ev.xmotion.y;
XTranslateCoordinates(dpy, c->framewin, root, ev.xmotion.x,
ev.xmotion.y, &px, &py, &dummy);
2006-05-31 10:47:07 +04:00
2006-05-31 19:21:52 +04:00
rect_morph_xy(&origin, px-ox, py-oy, &align);
2006-05-31 10:47:07 +04:00
frect=origin;
ox=px; oy=py;
if(!aidx)
2006-05-31 19:21:52 +04:00
snap_rect(rects, num, &frect, &align, snap);
2006-05-31 10:47:07 +04:00
draw_xor_border(&frect);
break;
case Expose:
(handler[Expose])(&ev);
break;
default: break;
}
}
2005-11-18 18:54:58 +03:00
}
void
grab_mouse(Window w, unsigned long mod, unsigned int button)
{
XGrabButton(dpy, button, mod, w, False, ButtonMask,
GrabModeAsync, GrabModeSync, None, None);
if((mod != AnyModifier) && num_lock_mask) {
XGrabButton(dpy, button, mod | num_lock_mask, w, False, ButtonMask,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, button, mod | num_lock_mask | LockMask, w, False,
ButtonMask, GrabModeAsync, GrabModeSync, None, None);
}
}
void
ungrab_mouse(Window w, unsigned long mod, unsigned int button)
{
XUngrabButton(dpy, button, mod, w);
if(mod != AnyModifier && num_lock_mask) {
XUngrabButton(dpy, button, mod | num_lock_mask, w);
XUngrabButton(dpy, button, mod | num_lock_mask | LockMask, w);
}
}