JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
added mouse-based resizals
authorAnselm R. Garbe <garbeam@wmii.de>
Tue, 11 Jul 2006 19:24:10 +0000 (21:24 +0200)
committerAnselm R. Garbe <garbeam@wmii.de>
Tue, 11 Jul 2006 19:24:10 +0000 (21:24 +0200)
Makefile
README
client.c
event.c
kb.c [new file with mode: 0644]
key.c [deleted file]
mouse.c [new file with mode: 0644]
wm.h

index e324e5b..223f6f7 100644 (file)
--- 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 4f46c8b..bd60b68 100644 (file)
--- 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.
 
index 9407f0a..e05fdd7 100644 (file)
--- 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 344a0cc..ad4a16b 100644 (file)
--- 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;
@@ -45,15 +47,37 @@ flush_events(long even_mask)
 }
 
 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)
diff --git a/kb.c b/kb.c
new file mode 100644 (file)
index 0000000..7caae15
--- /dev/null
+++ b/kb.c
@@ -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;
+               }
+}
diff --git a/key.c b/key.c
deleted file mode 100644 (file)
index 7caae15..0000000
--- a/key.c
+++ /dev/null
@@ -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;
-               }
-}
diff --git a/mouse.c b/mouse.c
new file mode 100644 (file)
index 0000000..2b5d63b
--- /dev/null
+++ b/mouse.c
@@ -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;
+               }
+       }
+}
diff --git a/wm.h b/wm.h
index 055ef62..7ee6103 100644 (file)
--- a/wm.h
+++ b/wm.h
 
 #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);