--- a/Makefile Tue Jul 11 18:59:09 2006 +0200
+++ b/Makefile Tue Jul 11 21:24:10 2006 +0200
@@ -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}
--- a/README Tue Jul 11 18:59:09 2006 +0200
+++ b/README Tue Jul 11 21:24:10 2006 +0200
@@ -5,14 +5,6 @@
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 @@
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.
--- a/client.c Tue Jul 11 18:59:09 2006 +0200
+++ b/client.c Tue Jul 11 21:24:10 2006 +0200
@@ -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 @@
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 @@
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 @@
XGrabServer(dpy);
XSetErrorHandler(dummy_error_handler);
+ XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
XUnmapWindow(dpy, c->win);
XDestroyWindow(dpy, c->title);
@@ -126,7 +154,7 @@
XFlush(dpy);
XSetErrorHandler(error_handler);
XUngrabServer(dpy);
- flush_events(EnterWindowMask);
+ discard_events(EnterWindowMask);
if(stack)
focus(stack);
}
--- a/event.c Tue Jul 11 18:59:09 2006 +0200
+++ b/event.c Tue Jul 11 21:24:10 2006 +0200
@@ -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 unmapnotify(XEvent *e);
void (*handler[LASTEvent]) (XEvent *) = {
+ [ButtonPress] = buttonpress,
[ConfigureRequest] = configurerequest,
[DestroyNotify] = destroynotify,
[EnterNotify] = enternotify,
@@ -36,7 +38,7 @@
};
unsigned int
-flush_events(long even_mask)
+discard_events(long even_mask)
{
XEvent ev;
unsigned int n = 0;
@@ -45,15 +47,37 @@
}
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)
{
XConfigureRequestEvent *ev = &e->xconfigurerequest;
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)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kb.c Tue Jul 11 21:24:10 2006 +0200
@@ -0,0 +1,55 @@
+/*
+ * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
+ * See LICENSE file for license details.
+ */
+
+#include "wm.h"
+
+#include <X11/keysym.h>
+
+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;
+ }
+}
--- a/key.c Tue Jul 11 18:59:09 2006 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
- * See LICENSE file for license details.
- */
-
-#include "wm.h"
-
-#include <X11/keysym.h>
-
-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;
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mouse.c Tue Jul 11 21:24:10 2006 +0200
@@ -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;
+ }
+ }
+}
--- a/wm.h Tue Jul 11 18:59:09 2006 +0200
+++ b/wm.h Tue Jul 11 21:24:10 2006 +0200
@@ -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 @@
/* 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 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);