From b9da4b082eb658b4142b61c149212f414f7653b6 Mon Sep 17 00:00:00 2001 From: "Anselm R. Garbe" Date: Tue, 11 Jul 2006 21:24:10 +0200 Subject: added mouse-based resizals --- Makefile | 2 +- README | 10 +------ client.c | 32 ++++++++++++++++++-- event.c | 30 +++++++++++++++++-- kb.c | 55 +++++++++++++++++++++++++++++++++++ key.c | 55 ----------------------------------- mouse.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ wm.h | 26 ++++++++++++++--- 8 files changed, 236 insertions(+), 74 deletions(-) create mode 100644 kb.c delete mode 100644 key.c create mode 100644 mouse.c diff --git a/Makefile b/Makefile index e324e5b2..223f6f73 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ include config.mk -WMSRC = bar.c client.c cmd.c draw.c event.c key.c util.c wm.c +WMSRC = bar.c client.c cmd.c draw.c event.c kb.c mouse.c util.c wm.c WMOBJ = ${WMSRC:.c=.o} MENSRC = menu.c draw.c util.c MENOBJ = ${MENSRC:.c=.o} diff --git a/README b/README index 4f46c8bd..bd60b689 100644 --- a/README +++ b/README @@ -5,14 +5,6 @@ gridwm is an extremly fast, small, and automatic X11 window manager. It arranges all windows in a grid. -Configuration -------------- -You have to edit the source code for configuration, this WM is intended to -provide sane defaults, if something doesn't fits your needs, edit config.h and -maybe key.c. To change the status output edit that status variable definition -in wm.c. - - Requirements ------------ In order to build gridwm you need the Xlib header files. @@ -46,6 +38,6 @@ This will start gridwm on display :1 of the host foo.bar. Configuration ------------- The configuration of gridwm is done by customizing the config.h source file. To -customize the key bindings edit key.c. To change the status output, edit the +customize the key bindings edit kb.c. To change the status output, edit the status command definition in wm.c. diff --git a/client.c b/client.c index 9407f0a4..e05fdd73 100644 --- a/client.c +++ b/client.c @@ -10,6 +10,8 @@ #include "util.h" #include "wm.h" +#define CLIENT_MASK (StructureNotifyMask | PropertyChangeMask | EnterWindowMask) + void update_name(Client *c) { @@ -70,7 +72,7 @@ manage(Window w, XWindowAttributes *wa) c->r[RFloat].height = wa->height; c->border = wa->border_width; XSetWindowBorderWidth(dpy, c->win, 0); - XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | EnterWindowMask); + XSelectInput(dpy, c->win, CLIENT_MASK); XGetTransientForHint(dpy, c->win, &c->trans); if(!XGetWMNormalHints(dpy, c->win, &c->size, &msize) || !c->size.flags) c->size.flags = PSize; @@ -95,9 +97,34 @@ manage(Window w, XWindowAttributes *wa) c->snext = stack; stack = c; XMapWindow(dpy, c->win); + XGrabButton(dpy, AnyButton, Mod1Mask, c->win, False, ButtonPressMask, + GrabModeAsync, GrabModeSync, None, None); focus(c); } +void +resize(Client *c) +{ + XConfigureEvent e; + + XMoveResizeWindow(dpy, c->win, c->r[RFloat].x, c->r[RFloat].y, + c->r[RFloat].width, c->r[RFloat].height); + e.type = ConfigureNotify; + e.event = c->win; + e.window = c->win; + e.x = c->r[RFloat].x; + e.y = c->r[RFloat].y; + e.width = c->r[RFloat].width; + e.height = c->r[RFloat].height; + e.border_width = c->border; + e.above = None; + e.override_redirect = False; + XSelectInput(dpy, c->win, CLIENT_MASK & ~StructureNotifyMask); + XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&e); + XSelectInput(dpy, c->win, CLIENT_MASK); + XFlush(dpy); +} + static int dummy_error_handler(Display *dpy, XErrorEvent *error) { @@ -112,6 +139,7 @@ unmanage(Client *c) XGrabServer(dpy); XSetErrorHandler(dummy_error_handler); + XUngrabButton(dpy, AnyButton, AnyModifier, c->win); XUnmapWindow(dpy, c->win); XDestroyWindow(dpy, c->title); @@ -126,7 +154,7 @@ unmanage(Client *c) XFlush(dpy); XSetErrorHandler(error_handler); XUngrabServer(dpy); - flush_events(EnterWindowMask); + discard_events(EnterWindowMask); if(stack) focus(stack); } diff --git a/event.c b/event.c index 344a0cc9..ad4a16b8 100644 --- a/event.c +++ b/event.c @@ -12,6 +12,7 @@ #include "wm.h" /* local functions */ +static void buttonpress(XEvent *e); static void configurerequest(XEvent *e); static void destroynotify(XEvent *e); static void enternotify(XEvent *e); @@ -23,6 +24,7 @@ static void propertynotify(XEvent *e); static void unmapnotify(XEvent *e); void (*handler[LASTEvent]) (XEvent *) = { + [ButtonPress] = buttonpress, [ConfigureRequest] = configurerequest, [DestroyNotify] = destroynotify, [EnterNotify] = enternotify, @@ -36,7 +38,7 @@ void (*handler[LASTEvent]) (XEvent *) = { }; unsigned int -flush_events(long even_mask) +discard_events(long even_mask) { XEvent ev; unsigned int n = 0; @@ -44,6 +46,29 @@ flush_events(long even_mask) return n; } +static void +buttonpress(XEvent *e) +{ + XButtonPressedEvent *ev = &e->xbutton; + Client *c; + + if((c = getclient(ev->window))) { + switch(ev->button) { + default: + break; + case Button1: + mmove(c); + break; + case Button2: + XLowerWindow(dpy, c->win); + break; + case Button3: + mresize(c); + break; + } + } +} + static void configurerequest(XEvent *e) { @@ -51,9 +76,8 @@ configurerequest(XEvent *e) XWindowChanges wc; Client *c; - c = getclient(ev->window); ev->value_mask &= ~CWSibling; - if(c) { + if((c = getclient(ev->window))) { if(ev->value_mask & CWX) c->r[RFloat].x = ev->x; if(ev->value_mask & CWY) diff --git a/kb.c b/kb.c new file mode 100644 index 00000000..7caae15d --- /dev/null +++ b/kb.c @@ -0,0 +1,55 @@ +/* + * (C)opyright MMVI Anselm R. Garbe + * See LICENSE file for license details. + */ + +#include "wm.h" + +#include + +static const char *term[] = { + "xterm", "-u8", "-bg", "black", "-fg", "white", "-fn", + "-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*", 0 +}; + +static const char *proglist[] = { + "sh", "-c", "exec `ls -lL /bin /sbin /usr/bin /usr/local/bin 2>/dev/null | awk 'NF>2 && $1 ~ /^[^d].*x/ {print $NF}' | sort | uniq | gridmenu`", 0 +}; + +static Key key[] = { + { Mod1Mask, XK_Return, run, term }, + { Mod1Mask, XK_p, run, proglist }, + { Mod1Mask | ShiftMask, XK_c, kill, NULL}, + { Mod1Mask | ShiftMask, XK_q, quit, NULL}, +}; + +void +update_keys() +{ + unsigned int i, len; + KeyCode code; + + len = sizeof(key) / sizeof(key[0]); + for(i = 0; i < len; i++) { + code = XKeysymToKeycode(dpy, key[i].keysym); + XUngrabKey(dpy, code, key[i].mod, root); + XGrabKey(dpy, code, key[i].mod, root, True, GrabModeAsync, GrabModeAsync); + } +} + +void +keypress(XEvent *e) +{ + XKeyEvent *ev = &e->xkey; + unsigned int i, len; + KeySym keysym; + + keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); + len = sizeof(key) / sizeof(key[0]); + for(i = 0; i < len; i++) + if((keysym == key[i].keysym) && (key[i].mod == ev->state)) { + if(key[i].func) + key[i].func(key[i].aux); + return; + } +} diff --git a/key.c b/key.c deleted file mode 100644 index 7caae15d..00000000 --- a/key.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * (C)opyright MMVI Anselm R. Garbe - * See LICENSE file for license details. - */ - -#include "wm.h" - -#include - -static const char *term[] = { - "xterm", "-u8", "-bg", "black", "-fg", "white", "-fn", - "-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*", 0 -}; - -static const char *proglist[] = { - "sh", "-c", "exec `ls -lL /bin /sbin /usr/bin /usr/local/bin 2>/dev/null | awk 'NF>2 && $1 ~ /^[^d].*x/ {print $NF}' | sort | uniq | gridmenu`", 0 -}; - -static Key key[] = { - { Mod1Mask, XK_Return, run, term }, - { Mod1Mask, XK_p, run, proglist }, - { Mod1Mask | ShiftMask, XK_c, kill, NULL}, - { Mod1Mask | ShiftMask, XK_q, quit, NULL}, -}; - -void -update_keys() -{ - unsigned int i, len; - KeyCode code; - - len = sizeof(key) / sizeof(key[0]); - for(i = 0; i < len; i++) { - code = XKeysymToKeycode(dpy, key[i].keysym); - XUngrabKey(dpy, code, key[i].mod, root); - XGrabKey(dpy, code, key[i].mod, root, True, GrabModeAsync, GrabModeAsync); - } -} - -void -keypress(XEvent *e) -{ - XKeyEvent *ev = &e->xkey; - unsigned int i, len; - KeySym keysym; - - keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); - len = sizeof(key) / sizeof(key[0]); - for(i = 0; i < len; i++) - if((keysym == key[i].keysym) && (key[i].mod == ev->state)) { - if(key[i].func) - key[i].func(key[i].aux); - return; - } -} diff --git a/mouse.c b/mouse.c new file mode 100644 index 00000000..2b5d63b9 --- /dev/null +++ b/mouse.c @@ -0,0 +1,100 @@ +/* + * (C)opyright MMVI Anselm R. Garbe + * (C)opyright MMVI Kris Maglione + * See LICENSE file for license details. + */ + +#include +#include +#include + +#include "wm.h" + +#define ButtonMask (ButtonPressMask | ButtonReleaseMask) +#define MouseMask (ButtonMask | PointerMotionMask) + +static void +mmatch(Client *c, int x1, int y1, int x2, int y2) +{ + c->r[RFloat].width = abs(x1 - x2); + c->r[RFloat].height = abs(y1 - y2); + c->r[RFloat].width -= + (c->r[RFloat].width - c->size.base_width) % c->size.width_inc; + c->r[RFloat].height -= + (c->r[RFloat].height - c->size.base_height) % c->size.height_inc; + if(c->size.min_width && c->r[RFloat].width < c->size.min_width) + c->r[RFloat].width = c->size.min_width; + if(c->size.min_height && c->r[RFloat].height < c->size.min_height) + c->r[RFloat].height = c->size.min_height; + if(c->size.max_width && c->r[RFloat].width > c->size.max_width) + c->r[RFloat].width = c->size.max_width; + if(c->size.max_height && c->r[RFloat].height > c->size.max_height) + c->r[RFloat].height = c->size.max_height; + c->r[RFloat].x = (x1 <= x2) ? x1 : x1 - c->r[RFloat].width; + c->r[RFloat].y = (y1 <= y2) ? y1 : y1 - c->r[RFloat].height; +} + +void +mresize(Client *c) +{ + XEvent ev; + int old_cx, old_cy; + + old_cx = c->r[RFloat].x; + old_cy = c->r[RFloat].y; + if(XGrabPointer(dpy, c->win, False, MouseMask, GrabModeAsync, GrabModeAsync, + None, cursor[CurResize], CurrentTime) != GrabSuccess) + return; + XGrabServer(dpy); + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, + c->r[RFloat].width, c->r[RFloat].height); + for(;;) { + XMaskEvent(dpy, MouseMask, &ev); + switch(ev.type) { + default: break; + case MotionNotify: + XUngrabServer(dpy); + mmatch(c, old_cx, old_cy, ev.xmotion.x, ev.xmotion.y); + resize(c); + XGrabServer(dpy); + break; + case ButtonRelease: + XUngrabPointer(dpy, CurrentTime); + return; + } + } +} + +void +mmove(Client *c) +{ + XEvent ev; + int x1, y1, old_cx, old_cy, di; + unsigned int dui; + Window dummy; + + old_cx = c->r[RFloat].x; + old_cy = c->r[RFloat].y; + if(XGrabPointer(dpy, c->win, False, MouseMask, GrabModeAsync, GrabModeAsync, + None, cursor[CurMove], CurrentTime) != GrabSuccess) + return; + XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui); + XGrabServer(dpy); + for(;;) { + XMaskEvent(dpy, MouseMask, &ev); + switch (ev.type) { + default: break; + case MotionNotify: + XUngrabServer(dpy); + c->r[RFloat].x = old_cx + (ev.xmotion.x - x1); + c->r[RFloat].y = old_cy + (ev.xmotion.y - y1); + resize(c); + XGrabServer(dpy); + break; + case ButtonRelease: + XUngrabServer(dpy); + XUngrabPointer(dpy, CurrentTime); + return; + } + } +} diff --git a/wm.h b/wm.h index 055ef62e..7ee6103d 100644 --- a/wm.h +++ b/wm.h @@ -11,6 +11,22 @@ #define WM_PROTOCOL_DELWIN 1 +typedef struct Client Client; +typedef struct Key Key; +typedef enum Align Align; + +enum Align { + NORTH = 0x01, + EAST = 0x02, + SOUTH = 0x04, + WEST = 0x08, + NEAST = NORTH | EAST, + NWEST = NORTH | WEST, + SEAST = SOUTH | EAST, + SWEST = SOUTH | WEST, + CENTER = NEAST | SWEST +}; + /* atoms */ enum { WMProtocols, WMDelete, WMLast }; enum { NetSupported, NetWMName, NetLast }; @@ -21,9 +37,6 @@ enum { CurNormal, CurResize, CurMove, CurInput, CurLast }; /* rects */ enum { RFloat, RGrid, RLast }; -typedef struct Client Client; -typedef struct Key Key; - struct Client { char name[256]; char tag[256]; @@ -75,14 +88,19 @@ extern Client *getclient(Window w); extern void focus(Client *c); extern void update_name(Client *c); extern void draw_client(Client *c); +extern void resize(Client *c); /* event.c */ -extern unsigned int flush_events(long even_mask); +extern unsigned int discard_events(long even_mask); /* key.c */ extern void update_keys(); extern void keypress(XEvent *e); +/* mouse.c */ +extern void mresize(Client *c); +extern void mmove(Client *c); + /* wm.c */ extern int error_handler(Display *dpy, XErrorEvent *error); extern void send_message(Window w, Atom a, long value); -- cgit v1.2.3