aewl

changeset 18:1efa34c6e1b6

added mouse-based resizals
author Anselm R. Garbe <garbeam@wmii.de>
date Tue, 11 Jul 2006 21:24:10 +0200
parents aaf520f53110
children b5510d0c6d43
files Makefile README client.c event.c kb.c mouse.c wm.h
diffstat 8 files changed, 236 insertions(+), 74 deletions(-) [+]
line diff
     1.1 --- a/Makefile	Tue Jul 11 18:59:09 2006 +0200
     1.2 +++ b/Makefile	Tue Jul 11 21:24:10 2006 +0200
     1.3 @@ -3,7 +3,7 @@
     1.4  
     1.5  include config.mk
     1.6  
     1.7 -WMSRC = bar.c client.c cmd.c draw.c event.c key.c util.c wm.c
     1.8 +WMSRC = bar.c client.c cmd.c draw.c event.c kb.c mouse.c util.c wm.c
     1.9  WMOBJ = ${WMSRC:.c=.o}
    1.10  MENSRC = menu.c draw.c util.c
    1.11  MENOBJ = ${MENSRC:.c=.o}
     2.1 --- a/README	Tue Jul 11 18:59:09 2006 +0200
     2.2 +++ b/README	Tue Jul 11 21:24:10 2006 +0200
     2.3 @@ -5,14 +5,6 @@
     2.4  arranges all windows in a grid.
     2.5  
     2.6  
     2.7 -Configuration
     2.8 --------------
     2.9 -You have to edit the source code for configuration, this WM is intended to
    2.10 -provide sane defaults, if something doesn't fits your needs, edit config.h and
    2.11 -maybe key.c. To change the status output edit that status variable definition
    2.12 -in wm.c.
    2.13 -
    2.14 -
    2.15  Requirements
    2.16  ------------
    2.17  In order to build gridwm you need the Xlib header files.
    2.18 @@ -46,6 +38,6 @@
    2.19  Configuration
    2.20  -------------
    2.21  The configuration of gridwm is done by customizing the config.h source file. To
    2.22 -customize the key bindings edit key.c. To change the status output, edit the
    2.23 +customize the key bindings edit kb.c. To change the status output, edit the
    2.24  status command definition in wm.c.
    2.25  
     3.1 --- a/client.c	Tue Jul 11 18:59:09 2006 +0200
     3.2 +++ b/client.c	Tue Jul 11 21:24:10 2006 +0200
     3.3 @@ -10,6 +10,8 @@
     3.4  #include "util.h"
     3.5  #include "wm.h"
     3.6  
     3.7 +#define CLIENT_MASK		(StructureNotifyMask | PropertyChangeMask | EnterWindowMask)
     3.8 +
     3.9  void
    3.10  update_name(Client *c)
    3.11  {
    3.12 @@ -70,7 +72,7 @@
    3.13  	c->r[RFloat].height = wa->height;
    3.14  	c->border = wa->border_width;
    3.15  	XSetWindowBorderWidth(dpy, c->win, 0);
    3.16 -	XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
    3.17 +	XSelectInput(dpy, c->win, CLIENT_MASK);
    3.18  	XGetTransientForHint(dpy, c->win, &c->trans);
    3.19  	if(!XGetWMNormalHints(dpy, c->win, &c->size, &msize) || !c->size.flags)
    3.20  		c->size.flags = PSize;
    3.21 @@ -95,9 +97,34 @@
    3.22  	c->snext = stack;
    3.23  	stack = c;
    3.24  	XMapWindow(dpy, c->win);
    3.25 +	XGrabButton(dpy, AnyButton, Mod1Mask, c->win, False, ButtonPressMask,
    3.26 +			GrabModeAsync, GrabModeSync, None, None);
    3.27  	focus(c);
    3.28  }
    3.29  
    3.30 +void
    3.31 +resize(Client *c)
    3.32 +{
    3.33 +	XConfigureEvent e;
    3.34 +
    3.35 +	XMoveResizeWindow(dpy, c->win, c->r[RFloat].x, c->r[RFloat].y,
    3.36 +			c->r[RFloat].width, c->r[RFloat].height);
    3.37 +	e.type = ConfigureNotify;
    3.38 +	e.event = c->win;
    3.39 +	e.window = c->win;
    3.40 +	e.x = c->r[RFloat].x;
    3.41 +	e.y = c->r[RFloat].y;
    3.42 +	e.width = c->r[RFloat].width;
    3.43 +	e.height = c->r[RFloat].height;
    3.44 +	e.border_width = c->border;
    3.45 +	e.above = None;
    3.46 +	e.override_redirect = False;
    3.47 +	XSelectInput(dpy, c->win, CLIENT_MASK & ~StructureNotifyMask);
    3.48 +	XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&e);
    3.49 +	XSelectInput(dpy, c->win, CLIENT_MASK);
    3.50 +	XFlush(dpy);
    3.51 +}
    3.52 +
    3.53  static int
    3.54  dummy_error_handler(Display *dpy, XErrorEvent *error)
    3.55  {
    3.56 @@ -112,6 +139,7 @@
    3.57  	XGrabServer(dpy);
    3.58  	XSetErrorHandler(dummy_error_handler);
    3.59  
    3.60 +	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
    3.61  	XUnmapWindow(dpy, c->win);
    3.62  	XDestroyWindow(dpy, c->title);
    3.63  
    3.64 @@ -126,7 +154,7 @@
    3.65  	XFlush(dpy);
    3.66  	XSetErrorHandler(error_handler);
    3.67  	XUngrabServer(dpy);
    3.68 -	flush_events(EnterWindowMask);
    3.69 +	discard_events(EnterWindowMask);
    3.70  	if(stack)
    3.71  		focus(stack);
    3.72  }
     4.1 --- a/event.c	Tue Jul 11 18:59:09 2006 +0200
     4.2 +++ b/event.c	Tue Jul 11 21:24:10 2006 +0200
     4.3 @@ -12,6 +12,7 @@
     4.4  #include "wm.h"
     4.5  
     4.6  /* local functions */
     4.7 +static void buttonpress(XEvent *e);
     4.8  static void configurerequest(XEvent *e);
     4.9  static void destroynotify(XEvent *e);
    4.10  static void enternotify(XEvent *e);
    4.11 @@ -23,6 +24,7 @@
    4.12  static void unmapnotify(XEvent *e);
    4.13  
    4.14  void (*handler[LASTEvent]) (XEvent *) = {
    4.15 +	[ButtonPress] = buttonpress,
    4.16  	[ConfigureRequest] = configurerequest,
    4.17  	[DestroyNotify] = destroynotify,
    4.18  	[EnterNotify] = enternotify,
    4.19 @@ -36,7 +38,7 @@
    4.20  };
    4.21  
    4.22  unsigned int
    4.23 -flush_events(long even_mask)
    4.24 +discard_events(long even_mask)
    4.25  {
    4.26  	XEvent ev;
    4.27  	unsigned int n = 0;
    4.28 @@ -45,15 +47,37 @@
    4.29  }
    4.30  
    4.31  static void
    4.32 +buttonpress(XEvent *e)
    4.33 +{
    4.34 +	XButtonPressedEvent *ev = &e->xbutton;
    4.35 +	Client *c;
    4.36 +
    4.37 +	if((c = getclient(ev->window))) {
    4.38 +		switch(ev->button) {
    4.39 +		default:
    4.40 +			break;
    4.41 +		case Button1:
    4.42 +			mmove(c);
    4.43 +			break;
    4.44 +		case Button2:
    4.45 +			XLowerWindow(dpy, c->win);
    4.46 +			break;
    4.47 +		case Button3:
    4.48 +			mresize(c);
    4.49 +			break;
    4.50 +		}
    4.51 +	}
    4.52 +}
    4.53 +
    4.54 +static void
    4.55  configurerequest(XEvent *e)
    4.56  {
    4.57  	XConfigureRequestEvent *ev = &e->xconfigurerequest;
    4.58  	XWindowChanges wc;
    4.59  	Client *c;
    4.60  
    4.61 -	c = getclient(ev->window);
    4.62  	ev->value_mask &= ~CWSibling;
    4.63 -	if(c) {
    4.64 +	if((c = getclient(ev->window))) {
    4.65  		if(ev->value_mask & CWX)
    4.66  			c->r[RFloat].x = ev->x;
    4.67  		if(ev->value_mask & CWY)
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/kb.c	Tue Jul 11 21:24:10 2006 +0200
     5.3 @@ -0,0 +1,55 @@
     5.4 +/*
     5.5 + * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
     5.6 + * See LICENSE file for license details.
     5.7 + */
     5.8 +
     5.9 +#include "wm.h"
    5.10 +
    5.11 +#include <X11/keysym.h>
    5.12 +
    5.13 +static const char *term[] = { 
    5.14 +	"xterm", "-u8", "-bg", "black", "-fg", "white", "-fn",
    5.15 +	"-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*", 0 
    5.16 +};
    5.17 +
    5.18 +static const char *proglist[] = {
    5.19 +		"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
    5.20 +};
    5.21 +
    5.22 +static Key key[] = {
    5.23 +	{ Mod1Mask, XK_Return, run, term },
    5.24 +	{ Mod1Mask, XK_p, run, proglist }, 
    5.25 +	{ Mod1Mask | ShiftMask, XK_c, kill, NULL}, 
    5.26 +	{ Mod1Mask | ShiftMask, XK_q, quit, NULL},
    5.27 +};
    5.28 +
    5.29 +void
    5.30 +update_keys()
    5.31 +{
    5.32 +	unsigned int i, len;
    5.33 +	KeyCode code;
    5.34 +
    5.35 +	len = sizeof(key) / sizeof(key[0]);
    5.36 +	for(i = 0; i < len; i++) {
    5.37 +		code = XKeysymToKeycode(dpy, key[i].keysym);
    5.38 +		XUngrabKey(dpy, code, key[i].mod, root);
    5.39 +		XGrabKey(dpy, code, key[i].mod, root, True, GrabModeAsync, GrabModeAsync);
    5.40 +	}
    5.41 +}
    5.42 +
    5.43 +void
    5.44 +keypress(XEvent *e)
    5.45 +{
    5.46 +	XKeyEvent *ev = &e->xkey;
    5.47 +	unsigned int i, len;
    5.48 +	KeySym keysym;
    5.49 +
    5.50 +	keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
    5.51 +	len = sizeof(key) / sizeof(key[0]);
    5.52 +	for(i = 0; i < len; i++)
    5.53 +		if((keysym == key[i].keysym) && (key[i].mod == ev->state)) {
    5.54 +			if(key[i].func)
    5.55 +				key[i].func(key[i].aux);
    5.56 +			return;
    5.57 +		}
    5.58 +}
     6.1 --- a/key.c	Tue Jul 11 18:59:09 2006 +0200
     6.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.3 @@ -1,55 +0,0 @@
     6.4 -/*
     6.5 - * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
     6.6 - * See LICENSE file for license details.
     6.7 - */
     6.8 -
     6.9 -#include "wm.h"
    6.10 -
    6.11 -#include <X11/keysym.h>
    6.12 -
    6.13 -static const char *term[] = { 
    6.14 -	"xterm", "-u8", "-bg", "black", "-fg", "white", "-fn",
    6.15 -	"-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*", 0 
    6.16 -};
    6.17 -
    6.18 -static const char *proglist[] = {
    6.19 -		"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
    6.20 -};
    6.21 -
    6.22 -static Key key[] = {
    6.23 -	{ Mod1Mask, XK_Return, run, term },
    6.24 -	{ Mod1Mask, XK_p, run, proglist }, 
    6.25 -	{ Mod1Mask | ShiftMask, XK_c, kill, NULL}, 
    6.26 -	{ Mod1Mask | ShiftMask, XK_q, quit, NULL},
    6.27 -};
    6.28 -
    6.29 -void
    6.30 -update_keys()
    6.31 -{
    6.32 -	unsigned int i, len;
    6.33 -	KeyCode code;
    6.34 -
    6.35 -	len = sizeof(key) / sizeof(key[0]);
    6.36 -	for(i = 0; i < len; i++) {
    6.37 -		code = XKeysymToKeycode(dpy, key[i].keysym);
    6.38 -		XUngrabKey(dpy, code, key[i].mod, root);
    6.39 -		XGrabKey(dpy, code, key[i].mod, root, True, GrabModeAsync, GrabModeAsync);
    6.40 -	}
    6.41 -}
    6.42 -
    6.43 -void
    6.44 -keypress(XEvent *e)
    6.45 -{
    6.46 -	XKeyEvent *ev = &e->xkey;
    6.47 -	unsigned int i, len;
    6.48 -	KeySym keysym;
    6.49 -
    6.50 -	keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
    6.51 -	len = sizeof(key) / sizeof(key[0]);
    6.52 -	for(i = 0; i < len; i++)
    6.53 -		if((keysym == key[i].keysym) && (key[i].mod == ev->state)) {
    6.54 -			if(key[i].func)
    6.55 -				key[i].func(key[i].aux);
    6.56 -			return;
    6.57 -		}
    6.58 -}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/mouse.c	Tue Jul 11 21:24:10 2006 +0200
     7.3 @@ -0,0 +1,100 @@
     7.4 +/*
     7.5 + * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
     7.6 + * (C)opyright MMVI Kris Maglione <fbsdaemon@gmail.com>
     7.7 + * See LICENSE file for license details.
     7.8 + */
     7.9 +
    7.10 +#include <stdlib.h>
    7.11 +#include <string.h>
    7.12 +#include <unistd.h>
    7.13 +
    7.14 +#include "wm.h"
    7.15 +
    7.16 +#define ButtonMask      (ButtonPressMask | ButtonReleaseMask)
    7.17 +#define MouseMask       (ButtonMask | PointerMotionMask)
    7.18 +
    7.19 +static void
    7.20 +mmatch(Client *c, int x1, int y1, int x2, int y2)
    7.21 +{
    7.22 +	c->r[RFloat].width = abs(x1 - x2);
    7.23 +	c->r[RFloat].height = abs(y1 - y2);
    7.24 +	c->r[RFloat].width -=
    7.25 +		(c->r[RFloat].width - c->size.base_width) % c->size.width_inc;
    7.26 +	c->r[RFloat].height -=
    7.27 +		(c->r[RFloat].height - c->size.base_height) % c->size.height_inc;
    7.28 +	if(c->size.min_width && c->r[RFloat].width < c->size.min_width)
    7.29 +		c->r[RFloat].width = c->size.min_width;
    7.30 +	if(c->size.min_height && c->r[RFloat].height < c->size.min_height)
    7.31 +		c->r[RFloat].height = c->size.min_height;
    7.32 +	if(c->size.max_width && c->r[RFloat].width > c->size.max_width)
    7.33 +		c->r[RFloat].width = c->size.max_width;
    7.34 +	if(c->size.max_height && c->r[RFloat].height > c->size.max_height)
    7.35 +		c->r[RFloat].height = c->size.max_height;
    7.36 +	c->r[RFloat].x = (x1 <= x2) ? x1 : x1 - c->r[RFloat].width;
    7.37 +	c->r[RFloat].y = (y1 <= y2) ? y1 : y1 - c->r[RFloat].height;
    7.38 +}
    7.39 +
    7.40 +void
    7.41 +mresize(Client *c)
    7.42 +{
    7.43 +	XEvent ev;
    7.44 +	int old_cx, old_cy;
    7.45 +
    7.46 +	old_cx = c->r[RFloat].x;
    7.47 +	old_cy = c->r[RFloat].y;
    7.48 +	if(XGrabPointer(dpy, c->win, False, MouseMask, GrabModeAsync, GrabModeAsync,
    7.49 +				None, cursor[CurResize], CurrentTime) != GrabSuccess)
    7.50 +		return;
    7.51 +	XGrabServer(dpy);
    7.52 +	XWarpPointer(dpy, None, c->win, 0, 0, 0, 0,
    7.53 +			c->r[RFloat].width, c->r[RFloat].height);
    7.54 +	for(;;) {
    7.55 +		XMaskEvent(dpy, MouseMask, &ev);
    7.56 +		switch(ev.type) {
    7.57 +		default: break;
    7.58 +		case MotionNotify:
    7.59 +			XUngrabServer(dpy);
    7.60 +			mmatch(c, old_cx, old_cy, ev.xmotion.x, ev.xmotion.y);
    7.61 +			resize(c);
    7.62 +			XGrabServer(dpy);
    7.63 +			break;
    7.64 +		case ButtonRelease:
    7.65 +			XUngrabPointer(dpy, CurrentTime);
    7.66 +			return;
    7.67 +		}
    7.68 +	}
    7.69 +}
    7.70 +
    7.71 +void
    7.72 +mmove(Client *c)
    7.73 +{
    7.74 +	XEvent ev;
    7.75 +	int x1, y1, old_cx, old_cy, di;
    7.76 +	unsigned int dui;
    7.77 +	Window dummy;
    7.78 +
    7.79 +	old_cx = c->r[RFloat].x;
    7.80 +	old_cy = c->r[RFloat].y;
    7.81 +	if(XGrabPointer(dpy, c->win, False, MouseMask, GrabModeAsync, GrabModeAsync,
    7.82 +				None, cursor[CurMove], CurrentTime) != GrabSuccess)
    7.83 +		return;
    7.84 +	XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
    7.85 +	XGrabServer(dpy);
    7.86 +	for(;;) {
    7.87 +		XMaskEvent(dpy, MouseMask, &ev);
    7.88 +		switch (ev.type) {
    7.89 +		default: break;
    7.90 +		case MotionNotify:
    7.91 +			XUngrabServer(dpy);
    7.92 +			c->r[RFloat].x = old_cx + (ev.xmotion.x - x1);
    7.93 +			c->r[RFloat].y = old_cy + (ev.xmotion.y - y1);
    7.94 +			resize(c);
    7.95 +			XGrabServer(dpy);
    7.96 +			break;
    7.97 +		case ButtonRelease:
    7.98 +			XUngrabServer(dpy);
    7.99 +			XUngrabPointer(dpy, CurrentTime);
   7.100 +			return;
   7.101 +		}
   7.102 +	}
   7.103 +}
     8.1 --- a/wm.h	Tue Jul 11 18:59:09 2006 +0200
     8.2 +++ b/wm.h	Tue Jul 11 21:24:10 2006 +0200
     8.3 @@ -11,6 +11,22 @@
     8.4  
     8.5  #define WM_PROTOCOL_DELWIN 1
     8.6  
     8.7 +typedef struct Client Client;
     8.8 +typedef struct Key Key;
     8.9 +typedef enum Align Align;
    8.10 +
    8.11 +enum Align {
    8.12 +	NORTH = 0x01,
    8.13 +	EAST  = 0x02,
    8.14 +	SOUTH = 0x04,
    8.15 +	WEST  = 0x08,
    8.16 +	NEAST = NORTH | EAST,
    8.17 +	NWEST = NORTH | WEST,
    8.18 +	SEAST = SOUTH | EAST,
    8.19 +	SWEST = SOUTH | WEST,
    8.20 +	CENTER = NEAST | SWEST
    8.21 +};
    8.22 +
    8.23  /* atoms */
    8.24  enum { WMProtocols, WMDelete, WMLast };
    8.25  enum { NetSupported, NetWMName, NetLast };
    8.26 @@ -21,9 +37,6 @@
    8.27  /* rects */
    8.28  enum { RFloat, RGrid, RLast };
    8.29  
    8.30 -typedef struct Client Client;
    8.31 -typedef struct Key Key;
    8.32 -
    8.33  struct Client {
    8.34  	char name[256];
    8.35  	char tag[256];
    8.36 @@ -75,14 +88,19 @@
    8.37  extern void focus(Client *c);
    8.38  extern void update_name(Client *c);
    8.39  extern void draw_client(Client *c);
    8.40 +extern void resize(Client *c);
    8.41  
    8.42  /* event.c */
    8.43 -extern unsigned int flush_events(long even_mask);
    8.44 +extern unsigned int discard_events(long even_mask);
    8.45  
    8.46  /* key.c */
    8.47  extern void update_keys();
    8.48  extern void keypress(XEvent *e);
    8.49  
    8.50 +/* mouse.c */
    8.51 +extern void mresize(Client *c);
    8.52 +extern void mmove(Client *c);
    8.53 +
    8.54  /* wm.c */
    8.55  extern int error_handler(Display *dpy, XErrorEvent *error);
    8.56  extern void send_message(Window w, Atom a, long value);