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>
|
2006-02-16 03:05:16 +03:00
|
|
|
#include <string.h>
|
2006-02-02 15:20:07 +03:00
|
|
|
#include <unistd.h>
|
2005-11-18 18:54:58 +03:00
|
|
|
|
|
|
|
#include "wm.h"
|
|
|
|
|
2006-05-12 22:06:06 +04:00
|
|
|
#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
|
|
|
{
|
2006-05-31 19:49:18 +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 {
|
2006-05-31 21:01:00 +04:00
|
|
|
rect->y += rect->height;
|
2006-05-31 19:21:52 +04:00
|
|
|
rect->height = dy - rect->height;
|
|
|
|
new_mask ^= NORTH|SOUTH;
|
|
|
|
}
|
|
|
|
}
|
2006-05-31 21:01:00 +04:00
|
|
|
if(*mask & SOUTH) {
|
|
|
|
if(rect->height + dy >= 0 || *mask & NORTH)
|
|
|
|
rect->height += dy;
|
2006-05-31 19:21:52 +04:00
|
|
|
else {
|
2006-05-31 21:01:00 +04:00
|
|
|
rect->height = -dy - rect->height;
|
|
|
|
rect->y -= rect->height;
|
|
|
|
new_mask ^= NORTH|SOUTH;
|
2006-05-31 19:21:52 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if(*mask & EAST) {
|
|
|
|
if(rect->width + dx >= 0 || *mask & WEST)
|
|
|
|
rect->width += dx;
|
|
|
|
else {
|
|
|
|
rect->width = -dx - rect->width;
|
2006-05-31 21:01:00 +04:00
|
|
|
rect->x -= rect->width;
|
2006-05-31 19:21:52 +04:00
|
|
|
new_mask ^= EAST|WEST;
|
|
|
|
}
|
2006-05-31 18:22:56 +04:00
|
|
|
}
|
2006-05-31 21:01:00 +04:00
|
|
|
if(*mask & WEST) {
|
|
|
|
if(rect->width - dx >= 0 || *mask & EAST) {
|
|
|
|
rect->x += dx;
|
|
|
|
rect->width -= dx;
|
|
|
|
}
|
2006-05-31 19:21:52 +04:00
|
|
|
else {
|
2006-05-31 21:01:00 +04:00
|
|
|
rect->x += rect->width;
|
|
|
|
rect->width = dx - rect->width;
|
|
|
|
new_mask ^= EAST|WEST;
|
2006-05-31 19:21:52 +04:00
|
|
|
}
|
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-06-06 00:01:31 +04:00
|
|
|
typedef struct {
|
|
|
|
XRectangle *rects;
|
|
|
|
int num;
|
|
|
|
int x1, y1, x2, y2;
|
|
|
|
BlitzAlign mask;
|
|
|
|
int *delta;
|
|
|
|
} SnapArgs;
|
|
|
|
|
2006-05-31 10:47:07 +04:00
|
|
|
static void
|
2006-06-06 00:01:31 +04:00
|
|
|
snap_line(SnapArgs *a)
|
2006-05-31 18:22:56 +04:00
|
|
|
{
|
|
|
|
int i, t_xy;
|
2006-05-31 19:21:52 +04:00
|
|
|
|
2006-05-31 18:22:56 +04:00
|
|
|
/* horizontal */
|
2006-06-06 00:01:31 +04:00
|
|
|
if(a->y1 == a->y2 && (a->mask & (NORTH|SOUTH))) {
|
|
|
|
for(i=0; i < a->num; i++) {
|
|
|
|
if(!((a->rects[i].x + a->rects[i].width < a->x1) ||
|
|
|
|
(a->rects[i].x > a->x2))) {
|
2006-05-31 19:21:52 +04:00
|
|
|
|
2006-06-06 00:01:31 +04:00
|
|
|
if(abs(a->rects[i].y - a->y1) <= abs(*a->delta))
|
|
|
|
*a->delta = a->rects[i].y - a->y1;
|
2006-05-31 19:21:52 +04:00
|
|
|
|
2006-06-06 00:01:31 +04:00
|
|
|
t_xy = a->rects[i].y + a->rects[i].height;
|
|
|
|
if(abs(t_xy - a->y1) < abs(*a->delta))
|
|
|
|
*a->delta = t_xy - a->y1;
|
2006-05-31 18:22:56 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-06-06 00:01:31 +04:00
|
|
|
else if (a->mask & (EAST|WEST)) {
|
2006-05-31 18:22:56 +04:00
|
|
|
/* This is the same as above, tr/xy/yx/,
|
|
|
|
* s/width/height/, s/height/width/ */
|
2006-06-06 00:01:31 +04:00
|
|
|
for(i=0; i < a->num; i++) {
|
|
|
|
if(!((a->rects[i].y + a->rects[i].height < a->y1) ||
|
|
|
|
(a->rects[i].y > a->y2))) {
|
2006-05-31 19:21:52 +04:00
|
|
|
|
2006-06-06 00:01:31 +04:00
|
|
|
if(abs(a->rects[i].x - a->x1) <= abs(*a->delta))
|
|
|
|
*a->delta = a->rects[i].x - a->x1;
|
2006-05-31 19:21:52 +04:00
|
|
|
|
2006-06-06 00:01:31 +04:00
|
|
|
t_xy = a->rects[i].x + a->rects[i].width;
|
|
|
|
if(abs(t_xy - a->x1) < abs(*a->delta))
|
|
|
|
*a->delta = t_xy - a->x1;
|
2006-05-31 18:22:56 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-11-18 18:54:58 +03:00
|
|
|
}
|
|
|
|
|
2006-06-05 07:47:09 +04:00
|
|
|
BlitzAlign
|
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
|
|
|
{
|
2006-06-06 00:01:31 +04:00
|
|
|
SnapArgs a = { rects, num, 0, 0, 0, 0, *mask, nil };
|
2006-06-05 07:47:09 +04:00
|
|
|
BlitzAlign ret;
|
2006-05-31 18:22:56 +04:00
|
|
|
int dx = snap + 1, dy = snap + 1;
|
|
|
|
|
2006-06-06 00:01:31 +04:00
|
|
|
a.x1 = current->x;
|
|
|
|
a.x2 = current->x + current->width;
|
|
|
|
a.delta = &dy;
|
|
|
|
if(*mask & NORTH) {
|
|
|
|
a.y2 = a.y1 = current->y;
|
|
|
|
snap_line(&a);
|
|
|
|
}
|
|
|
|
if(*mask & SOUTH) {
|
|
|
|
a.y2 = a.y1 = current->y + current->height;
|
|
|
|
snap_line(&a);
|
|
|
|
}
|
|
|
|
|
|
|
|
a.y1 = current->y;
|
|
|
|
a.y2 = current->y + current->height;
|
|
|
|
a.delta = &dx;
|
|
|
|
if(*mask & EAST) {
|
|
|
|
a.x1 = a.x2 = current->x + current->width;
|
|
|
|
snap_line(&a);
|
|
|
|
}
|
|
|
|
if(*mask & WEST) {
|
|
|
|
a.x1 = a.x2 = current->x;
|
|
|
|
snap_line(&a);
|
|
|
|
}
|
2006-05-31 18:22:56 +04:00
|
|
|
|
|
|
|
rect_morph_xy(current, abs(dx) <= snap ? dx : 0,
|
|
|
|
abs(dy) <= snap ? dy : 0, mask);
|
2006-06-05 07:47:09 +04:00
|
|
|
ret = *mask;
|
|
|
|
if(abs(dx) <= snap)
|
|
|
|
ret ^= EAST|WEST;
|
2006-06-06 00:20:31 +04:00
|
|
|
if(abs(dy) <= snap)
|
2006-06-05 07:47:09 +04:00
|
|
|
ret ^= NORTH|SOUTH;
|
|
|
|
return ret ^ CENTER;
|
2005-11-18 18:54:58 +03:00
|
|
|
}
|
|
|
|
|
2006-05-29 16:15:16 +04:00
|
|
|
static void
|
|
|
|
draw_xor_border(XRectangle *r)
|
2005-11-18 18:54:58 +03:00
|
|
|
{
|
2006-05-29 16:15:16 +04: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;
|
2006-05-29 16:15:16 +04:00
|
|
|
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
|
2006-05-12 23:17:03 +04:00
|
|
|
do_mouse_resize(Client *c, BlitzAlign align)
|
2005-11-18 18:54:58 +03:00
|
|
|
{
|
2006-06-05 07:47:09 +04:00
|
|
|
BlitzAlign grav;
|
2006-05-31 21:48:44 +04:00
|
|
|
int px, py, ox, oy, i;
|
2006-05-31 21:33:54 +04:00
|
|
|
float rx, ry;
|
2006-05-29 17:25:32 +04:00
|
|
|
Window dummy;
|
2006-03-23 16:22:43 +03:00
|
|
|
XEvent ev;
|
2006-05-31 21:48:44 +04:00
|
|
|
unsigned int num = 0, di;
|
2006-04-26 20:46:54 +04:00
|
|
|
Frame *f = c->frame.data[c->sel];
|
2006-05-29 11:50:11 +04:00
|
|
|
int aidx = idx_of_area(f->area);
|
2006-05-31 10:47:07 +04:00
|
|
|
int snap = aidx ? 0 : rect.height / 66;
|
2006-05-29 11:50:11 +04:00
|
|
|
XRectangle *rects = aidx ? nil : rects_of_view(f->area->view, &num);
|
2006-06-05 07:47:09 +04:00
|
|
|
XRectangle frect = f->rect, ofrect;
|
2006-03-23 16:22:43 +03:00
|
|
|
XRectangle origin = frect;
|
2006-05-31 10:47:07 +04:00
|
|
|
XPoint pt;
|
2006-03-23 16:22:43 +03:00
|
|
|
|
2006-05-31 21:33:54 +04:00
|
|
|
XQueryPointer(dpy, c->framewin, &dummy, &dummy, &i, &i, &ox, &oy, &di);
|
|
|
|
rx = (float)ox / frect.width;
|
|
|
|
ry = (float)oy / frect.height;
|
|
|
|
|
2006-05-31 21:01:00 +04:00
|
|
|
if (!aidx || align != CENTER) {
|
|
|
|
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;
|
|
|
|
if(align&WEST)
|
|
|
|
ox -= px;
|
|
|
|
|
|
|
|
XWarpPointer(dpy, None, c->framewin, 0, 0, 0, 0, ox, oy);
|
|
|
|
}
|
|
|
|
|
2006-05-31 21:33:54 +04:00
|
|
|
XTranslateCoordinates(dpy, c->framewin, root, ox, oy, &ox, &oy, &dummy);
|
2006-05-31 10:47:07 +04:00
|
|
|
pt.x = ox; pt.y = oy;
|
2006-05-01 22:40:33 +04:00
|
|
|
|
2006-05-31 21:33:54 +04:00
|
|
|
XSync(dpy, False);
|
2006-05-12 22:06:06 +04:00
|
|
|
if(XGrabPointer(dpy, c->framewin, False, MouseMask, GrabModeAsync, GrabModeAsync,
|
2006-05-31 10:47:07 +04:00
|
|
|
None, cursor[CurResize], CurrentTime) != GrabSuccess)
|
2006-05-01 22:40:33 +04:00
|
|
|
return;
|
2006-05-31 10:47:07 +04:00
|
|
|
|
2006-05-29 16:15:16 +04:00
|
|
|
XGrabServer(dpy);
|
|
|
|
draw_xor_border(&frect);
|
2006-03-23 16:22:43 +03:00
|
|
|
for(;;) {
|
2006-05-29 13:04:29 +04:00
|
|
|
XMaskEvent(dpy, MouseMask | ExposureMask, &ev);
|
2006-03-23 16:22:43 +03:00
|
|
|
switch (ev.type) {
|
|
|
|
case ButtonRelease:
|
2006-05-29 17:25:32 +04:00
|
|
|
draw_xor_border(&frect);
|
2006-05-29 11:50:11 +04:00
|
|
|
if(aidx)
|
2006-05-31 10:47:07 +04:00
|
|
|
resize_column(c, &frect, (align == CENTER) ? &pt : nil);
|
2006-05-12 23:17:03 +04:00
|
|
|
else
|
|
|
|
resize_client(c, &frect, False);
|
2006-05-29 13:04:29 +04:00
|
|
|
if(rects)
|
|
|
|
free(rects);
|
2006-05-29 16:15:16 +04:00
|
|
|
XUngrabServer(dpy);
|
2006-05-12 23:17:03 +04:00
|
|
|
XUngrabPointer(dpy, CurrentTime);
|
2006-03-23 16:22:43 +03:00
|
|
|
XSync(dpy, False);
|
2006-05-31 21:33:54 +04:00
|
|
|
|
|
|
|
XWarpPointer(dpy, None, c->framewin, 0, 0, 0, 0,
|
|
|
|
frect.width * rx, frect.height * ry);
|
2006-03-23 16:22:43 +03:00
|
|
|
return;
|
|
|
|
break;
|
|
|
|
case MotionNotify:
|
2006-06-05 07:47:09 +04:00
|
|
|
ofrect = frect;
|
2006-05-31 10:47:07 +04:00
|
|
|
|
|
|
|
pt.x = ev.xmotion.x;
|
|
|
|
pt.y = ev.xmotion.y;
|
2006-03-23 16:22:43 +03:00
|
|
|
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-06-05 07:47:09 +04:00
|
|
|
grav = snap_rect(rects, num, &frect, &align, snap);
|
|
|
|
else
|
|
|
|
grav = align ^ CENTER;
|
|
|
|
match_sizehints(c, &frect, aidx, grav);
|
2006-05-31 10:47:07 +04:00
|
|
|
|
2006-06-05 07:47:09 +04:00
|
|
|
draw_xor_border(&ofrect);
|
2006-05-29 16:15:16 +04:00
|
|
|
draw_xor_border(&frect);
|
2006-05-29 13:04:29 +04:00
|
|
|
break;
|
|
|
|
case Expose:
|
|
|
|
(handler[Expose])(&ev);
|
2006-03-23 16:22:43 +03:00
|
|
|
break;
|
2006-05-12 22:06:06 +04:00
|
|
|
default: break;
|
2006-03-23 16:22:43 +03:00
|
|
|
}
|
|
|
|
}
|
2005-11-18 18:54:58 +03:00
|
|
|
}
|
2006-02-09 21:40:12 +03:00
|
|
|
|
|
|
|
void
|
|
|
|
grab_mouse(Window w, unsigned long mod, unsigned int button)
|
|
|
|
{
|
2006-05-12 23:17:03 +04:00
|
|
|
XGrabButton(dpy, button, mod, w, False, ButtonMask,
|
|
|
|
GrabModeAsync, GrabModeSync, None, None);
|
2006-03-23 16:22:43 +03:00
|
|
|
if((mod != AnyModifier) && num_lock_mask) {
|
2006-05-12 23:17:03 +04:00
|
|
|
XGrabButton(dpy, button, mod | num_lock_mask, w, False, ButtonMask,
|
|
|
|
GrabModeAsync, GrabModeSync, None, None);
|
2006-03-23 16:22:43 +03:00
|
|
|
XGrabButton(dpy, button, mod | num_lock_mask | LockMask, w, False,
|
2006-05-12 23:17:03 +04:00
|
|
|
ButtonMask, GrabModeAsync, GrabModeSync, None, None);
|
2006-03-23 16:22:43 +03:00
|
|
|
}
|
2006-02-09 21:40:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ungrab_mouse(Window w, unsigned long mod, unsigned int button)
|
|
|
|
{
|
2006-03-23 16:22:43 +03:00
|
|
|
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);
|
|
|
|
}
|
2006-02-09 21:40:12 +03:00
|
|
|
}
|