added mouse-based resizals
This commit is contained in:
		
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								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}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								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.
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										32
									
								
								client.c
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								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);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										30
									
								
								event.c
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								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)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										100
									
								
								mouse.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								mouse.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,100 @@
 | 
			
		||||
/*
 | 
			
		||||
 * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
 | 
			
		||||
 * (C)opyright MMVI Kris Maglione <fbsdaemon@gmail.com>
 | 
			
		||||
 * See LICENSE file for license details.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#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;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								wm.h
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								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);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user