summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--calmwm.h24
-rw-r--r--conf.c88
-rw-r--r--cwmrc.561
-rw-r--r--mousefunc.c126
-rw-r--r--parse.y20
-rw-r--r--xevents.c109
7 files changed, 329 insertions, 101 deletions
diff --git a/Makefile b/Makefile
index b0be0e4..00b4aca 100644
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@ PROG=		cwm
 
 SRCS=		calmwm.c screen.c xmalloc.c client.c grab.c menu.c \
 		search.c util.c xutil.c conf.c input.c xevents.c group.c \
-		kbfunc.c font.c parse.y
+		kbfunc.c mousefunc.c font.c parse.y
 
 CPPFLAGS+=	-I${X11BASE}/include -I${X11BASE}/include/freetype2 -I${.CURDIR}
 
diff --git a/calmwm.h b/calmwm.h
index 0f84038..67bb1df 100644
--- a/calmwm.h
+++ b/calmwm.h
@@ -249,8 +249,20 @@ struct cmd {
 	/* (argv) */
 };
 
+struct mousebinding {
+	int				modmask;
+	int			 	button;
+	int				context;
+	void			 	(*callback)(struct client_ctx *, void *);
+	TAILQ_ENTRY(mousebinding)	entry;
+};
+
+#define MOUSEBIND_CTX_ROOT	1
+#define MOUSEBIND_CTX_WIN	2
+
 TAILQ_HEAD(keybinding_q, keybinding);
 TAILQ_HEAD(cmd_q, cmd);
+TAILQ_HEAD(mousebinding_q, mousebinding);
 
 /* Global configuration */
 struct conf {
@@ -259,6 +271,7 @@ struct conf {
 	struct winmatch_q	 ignoreq;
 	char			 conf_path[MAXPATHLEN];
 	struct cmd_q		 cmdq;
+	struct mousebinding_q	 mousebindingq;
 
 #define	CONF_STICKY_GROUPS	 0x0001
 	int			 flags;
@@ -424,6 +437,8 @@ void			 conf_setup(struct conf *, const char *);
 void			 conf_client(struct client_ctx *);
 void			 conf_bindname(struct conf *, char *, char *);
 void			 conf_unbind(struct conf *, struct keybinding *);
+void			 conf_mousebind(struct conf *, char *, char *);
+void			 conf_mouseunbind(struct conf *, struct mousebinding *);
 int			 conf_changed(char *);
 void			 conf_reload(struct conf *);
 
@@ -450,6 +465,15 @@ void			 kbfunc_ssh(struct client_ctx *, void *);
 void			 kbfunc_term(struct client_ctx *, void *);
 void			 kbfunc_lock(struct client_ctx *, void *);
 
+void			 mousefunc_window_resize(struct client_ctx *, void *);
+void			 mousefunc_window_move(struct client_ctx *, void *);
+void			 mousefunc_window_grouptoggle(struct client_ctx *,
+			    void *);
+void			 mousefunc_window_lower(struct client_ctx *, void *);
+void			 mousefunc_menu_group(struct client_ctx *, void *);
+void			 mousefunc_menu_unhide(struct client_ctx *, void *);
+void			 mousefunc_menu_cmd(struct client_ctx *, void *);
+
 void			 search_match_client(struct menu_q *, struct menu_q *,
 			     char *);
 void			 search_print_client(struct menu *, int);
diff --git a/conf.c b/conf.c
index 33a02dc..ea22d59 100644
--- a/conf.c
+++ b/conf.c
@@ -90,6 +90,7 @@ conf_init(struct conf *c)
 	TAILQ_INIT(&c->cmdq);
 	TAILQ_INIT(&c->keybindingq);
 	TAILQ_INIT(&c->autogroupq);
+	TAILQ_INIT(&c->mousebindingq);
 
 	conf_bindname(c, "CM-Return", "terminal");
 	conf_bindname(c, "CM-Delete", "lock");
@@ -149,6 +150,14 @@ conf_init(struct conf *c)
 	conf_bindname(c, "CS-Up", "bigptrmoveup");
 	conf_bindname(c, "CS-Right", "bigptrmoveright");
 
+	conf_mousebind(c, "1", "menu_unhide");
+	conf_mousebind(c, "2", "menu_group");
+	conf_mousebind(c, "3", "menu_cmd");
+	conf_mousebind(c, "M-1", "window_move");
+	conf_mousebind(c, "CM-1", "window_grouptoggle");
+	conf_mousebind(c, "M-2", "window_resize");
+	conf_mousebind(c, "M-3", "window_lower");
+
 	/* Default term/lock */
 	strlcpy(c->termpath, "xterm", sizeof(c->termpath));
 	strlcpy(c->lockpath, "xlock", sizeof(c->lockpath));
@@ -379,3 +388,82 @@ void conf_unbind(struct conf *c, struct keybinding *unbind)
 		}
 	}
 }
+
+struct {
+	char *tag;
+	void (*handler)(struct client_ctx *, void *);
+	int context;
+} name_to_mousefunc[] = {
+	{ "window_move", mousefunc_window_move, MOUSEBIND_CTX_WIN },
+	{ "window_resize", mousefunc_window_resize, MOUSEBIND_CTX_WIN },
+	{ "window_grouptoggle", mousefunc_window_grouptoggle,
+	    MOUSEBIND_CTX_WIN },
+	{ "window_lower", mousefunc_window_lower, MOUSEBIND_CTX_WIN },
+	{ "menu_group", mousefunc_menu_group, MOUSEBIND_CTX_ROOT },
+	{ "menu_unhide", mousefunc_menu_unhide, MOUSEBIND_CTX_ROOT },
+	{ "menu_cmd", mousefunc_menu_cmd, MOUSEBIND_CTX_ROOT },
+	{ NULL, NULL, 0 },
+};
+
+void
+conf_mousebind(struct conf *c, char *name, char *binding)
+{
+	int iter;
+	struct mousebinding *current_binding;
+	char *substring;
+	const char *errstr;
+
+	XCALLOC(current_binding, struct mousebinding);
+
+	if (strchr(name, 'C') != NULL &&
+	    strchr(name, 'C') < strchr(name, '-'))
+		current_binding->modmask |= ControlMask;
+
+	if (strchr(name, 'M') != NULL &&
+	    strchr(name, 'M') < strchr(name, '-'))
+		current_binding->modmask |= Mod1Mask;
+
+	substring = strchr(name, '-') + 1;
+
+	if (strchr(name, '-') == NULL)
+		substring = name;
+
+	current_binding->button = strtonum(substring);
+	if (errstr)
+		warnx("number of buttons is %s: %s", errstr, substring);
+
+	conf_mouseunbind(c, current_binding);
+
+	if (strcmp("unmap", binding) == 0)
+		return;
+
+	for (iter = 0; name_to_mousefunc[iter].tag != NULL; iter++) {
+		if (strcmp(name_to_mousefunc[iter].tag, binding) != 0)
+			continue;
+
+		current_binding->context = name_to_mousefunc[iter].context;
+		current_binding->callback = name_to_mousefunc[iter].handler;
+		TAILQ_INSERT_TAIL(&c->mousebindingq, current_binding, entry);
+		return;
+	}
+}
+
+void
+conf_mouseunbind(struct conf *c, struct mousebinding *unbind)
+{
+	struct mousebinding *mb = NULL, *mbnxt;
+
+	for (mb = TAILQ_FIRST(&c->mousebindingq);
+	    mb != TAILQ_END(&c->mousebindingq); mb = mbnxt) {
+		mbnxt = TAILQ_NEXT(mb, entry);
+
+		if (mb->modmask != unbind->modmask)
+			continue;
+
+		if (mb->button == unbind->button) {
+			TAILQ_REMOVE(&c->mousebindingq, mb, entry);
+			xfree(mb);
+		}
+	}
+}
+
diff --git a/cwmrc.5 b/cwmrc.5
index 7114431..10be912 100644
--- a/cwmrc.5
+++ b/cwmrc.5
@@ -15,7 +15,7 @@
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
 .\" The following requests are required for all man pages.
-.Dd $Mdocdate: May 19 2008 $
+.Dd $Mdocdate: June 13 2008 $
 .Dt CWMRC 5
 .Os
 .Sh NAME
@@ -130,6 +130,41 @@ where the user may wish to remain visible.
 Ignore drawing borders around a window with the name
 .Ar windowname .
 .Pp
+.It Ic mousebind Ar buttons Ar command
+Cause the creation of a mouse binding, or replacement of a default
+mouse binding.
+The modifier keys come first, followed by a
+.Sq - .
+.Pb
+The following modifiers are recognised:
+.Pp
+.Bl -tag -width Ds -offset indent -compact
+.It C   
+The Control key.
+.It M
+The Meta key.
+.El
+.Pp
+The
+.Sq -
+should be followed by number:
+.Pb
+.Bl -tag -width Ds -offset indent -compact
+.Pp
+.It 1
+Left mouse button.
+.It 2
+Right mouse button.
+.It 3
+Middle mouse button.
+.El
+.Pp
+The
+.Ar command
+may be taken from the
+.Sx MOUSEBIND COMMAND LIST
+(see below).
+.Pp
 .It Ic sticky Ic yes Ns \&| Ns Ic no
 Toggle sticky group mode.
 The default behavior for new windows is to not assign any group.
@@ -161,9 +196,13 @@ ignore xapm
 ignore xclock
 
 # Keybindings
-bind CM-r	"label"
+bind CM-r	label
 bind CS-Return	"xterm -e top"
-bind 4-o	"unmap"
+bind 4-o	unmap
+
+# Mousebindings
+mousebind M-2	window_lower
+mousebind M-3	window_resize
 .Ed
 .Sh BIND COMMAND LIST
 .Bl -tag -width 18n -compact
@@ -267,6 +306,22 @@ move pointer 10 pixels right
 .It bigptrmoveleft
 move pointer 10 pixels left
 .El
+.Sh MOUSEBIND COMMAND LIST
+.Bl -tag -width 18n -compact
+.It window_move
+move a window
+.It window_resize
+resize a window
+.It window_lower
+lower a window
+.It window_grouptoggle
+.It menu_group
+launch group list
+.It menu_unhide
+launch group list
+.It menu_cmd
+launch command list
+.El
 .Sh FILES
 .Bl -tag -width "~/.cwmrcXXX" -compact
 .It Pa ~/.cwmrc
diff --git a/mousefunc.c b/mousefunc.c
new file mode 100644
index 0000000..cd3151f
--- /dev/null
+++ b/mousefunc.c
@@ -0,0 +1,126 @@
+/*
+ *  calmwm - the calm window manager
+ *
+ *  Copyright (c) 2008 rivo nurges <rix@estpak.ee>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $Id$
+ */
+
+#include "headers.h"
+#include "calmwm.h"
+
+void
+mousefunc_window_resize(struct client_ctx *cc, void *arg)
+{
+	grab_sweep(cc);
+	client_resize(cc);
+}
+
+void
+mousefunc_window_move(struct client_ctx *cc, void *arg)
+{
+	grab_drag(cc);
+	client_move(cc);
+}
+
+void
+mousefunc_window_grouptoggle(struct client_ctx *cc, void *arg)
+{
+	group_sticky_toggle_enter(cc);
+}
+
+void
+mousefunc_window_lower(struct client_ctx *cc, void *arg)
+{
+	client_ptrsave(cc);
+	client_lower(cc);
+}
+
+void
+mousefunc_menu_group(struct client_ctx *cc, void *arg)
+{
+	group_menu(arg);
+}
+
+void
+mousefunc_menu_unhide(struct client_ctx *cc, void *arg)
+{
+	struct menu *mi;
+	struct menu_q menuq;
+	char *wname;
+	struct client_ctx *old_cc = client_current();
+
+	TAILQ_INIT(&menuq);
+	TAILQ_FOREACH(cc, &Clientq, entry)
+		if (cc->flags & CLIENT_HIDDEN) {
+			if (cc->label != NULL)
+				wname = cc->label;
+			else
+				wname = cc->name;
+
+			if (wname == NULL)
+				continue;
+
+			XCALLOC(mi, struct menu);
+			strlcpy(mi->text, wname, sizeof(mi->text));
+			mi->ctx = cc;
+			TAILQ_INSERT_TAIL(&menuq, mi, entry);
+		}
+
+	if (TAILQ_EMPTY(&menuq))
+		return;
+
+	mi = menu_filter(&menuq, NULL, NULL, 0, NULL, NULL);
+	if (mi != NULL) {
+		cc = (struct client_ctx *)mi->ctx;
+		client_unhide(cc);
+
+		if (old_cc != NULL)
+			client_ptrsave(old_cc);
+		client_ptrwarp(cc);
+	} else
+		while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
+			TAILQ_REMOVE(&menuq, mi, entry);
+			xfree(mi);
+		}
+}
+
+void
+mousefunc_menu_cmd(struct client_ctx *cc, void *arg)
+{
+	struct menu *mi;
+	struct menu_q menuq;
+	struct cmd *cmd;
+	conf_reload(&Conf);
+
+	TAILQ_INIT(&menuq);
+	TAILQ_FOREACH(cmd, &Conf.cmdq, entry) {
+		XCALLOC(mi, struct menu);
+		strlcpy(mi->text, cmd->label, sizeof(mi->text));
+		mi->ctx = cmd;
+		TAILQ_INSERT_TAIL(&menuq, mi, entry);
+	}
+	if (TAILQ_EMPTY(&menuq))
+		return;
+
+	mi = menu_filter(&menuq, NULL, NULL, 0, NULL, NULL);
+	if (mi != NULL)
+		u_spawn(((struct cmd *)mi->ctx)->image);
+	else
+		while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
+			TAILQ_REMOVE(&menuq, mi, entry);
+			xfree(mi);
+		}
+}
diff --git a/parse.y b/parse.y
index bcdd4b1..1b054bf 100644
--- a/parse.y
+++ b/parse.y
@@ -66,7 +66,7 @@ typedef struct {
 
 %}
 
-%token	FONTNAME STICKY GAP
+%token	FONTNAME STICKY GAP MOUSEBIND
 %token	AUTOGROUP BIND COMMAND IGNORE
 %token	YES NO
 %token	ERROR
@@ -167,6 +167,11 @@ main		: FONTNAME STRING		{
 			conf->gap_left = $4;
 			conf->gap_right = $5;
 		}
+		| MOUSEBIND STRING string	{
+			conf_mousebind(conf, $2, $3);
+			free($2);
+			free($3);
+		}
 		;
 %%
 
@@ -206,6 +211,7 @@ lookup(char *s)
 		{ "fontname",		FONTNAME},
 		{ "gap",		GAP},
 		{ "ignore",		IGNORE},
+		{ "mousebind",		MOUSEBIND},
 		{ "no",			NO},
 		{ "sticky",		STICKY},
 		{ "yes",		YES}
@@ -469,6 +475,7 @@ conf_clear(struct conf *c)
 	struct keybinding	*kb;
 	struct winmatch		*wm;
 	struct cmd		*cmd;
+	struct mousebinding	*mb;
 
 	while (cmd = TAILQ_FIRST(&c->cmdq)) {
 		TAILQ_REMOVE(&c->cmdq, cmd, entry);
@@ -494,6 +501,11 @@ conf_clear(struct conf *c)
 		free(wm);
 	}
 
+	while (mb = TAILQ_FIRST(&c->mousebindingq)) {
+		TAILQ_REMOVE(&c->mousebindingq, mb, entry);
+		free(mb);
+	}
+
 	if (c->DefaultFontName != NULL &&
 	    c->DefaultFontName != DEFAULTFONTNAME)
 		free(c->DefaultFontName);
@@ -529,6 +541,7 @@ parse_config(const char *filename, struct conf *xconf)
 		struct keybinding	*kb;
 		struct winmatch		*wm;
 		struct cmd		*cmd;
+		struct mousebinding	*mb;
 
 		conf_clear(xconf);
 
@@ -554,6 +567,11 @@ parse_config(const char *filename, struct conf *xconf)
 			TAILQ_INSERT_TAIL(&xconf->ignoreq, wm, entry);
 		}
 
+		while (mb = TAILQ_FIRST(&conf->mousebindingq)) {
+			TAILQ_REMOVE(&conf->mousebindingq, mb, entry);
+			TAILQ_INSERT_TAIL(&xconf->mousebindingq, mb, entry);
+		}
+
 		strlcpy(xconf->termpath, conf->termpath,
 		    sizeof(xconf->termpath));
 		strlcpy(xconf->lockpath, conf->lockpath,
diff --git a/xevents.c b/xevents.c
index 076f30b..fed91e6 100644
--- a/xevents.c
+++ b/xevents.c
@@ -221,113 +221,30 @@ void
 xev_handle_buttonpress(struct xevent *xev, XEvent *ee)
 {
 	XButtonEvent *e = &ee->xbutton;
-	struct client_ctx *cc, *old_cc = client_current();
+	struct client_ctx *cc;
 	struct screen_ctx *sc = screen_fromroot(e->root);
 	char *wname;
-	int altcontrol = e->state == (ControlMask|Mod1Mask);
+	struct mousebinding *mb;
 
 	cc = client_find(e->window);
 
-	if (sc->rootwin == e->window && !altcontrol) {
-		struct menu_q menuq;
-		struct menu *mi;
-
-		/* XXXSIGH!!!! */
-		if (e->button == Button2) {
-			group_menu(e);
-			goto out;
-		}
-
-		TAILQ_INIT(&menuq);
-
-		switch (e->button) {
-		case Button1:
-			TAILQ_FOREACH(cc, &Clientq, entry) {
-				if (cc->flags & CLIENT_HIDDEN) {
-					if (cc->label != NULL)
-						wname = cc->label;
-					else
-						wname = cc->name;
-
-					if (wname == NULL)
-						continue;
-
-					XCALLOC(mi, struct menu);
-					strlcpy(mi->text,
-					    wname, sizeof(mi->text));
-					mi->ctx = cc;
-					TAILQ_INSERT_TAIL(&menuq, mi, entry);
-				}
-			}
-			break;
-		case Button3: {
-			struct cmd *cmd;
-			conf_reload(&Conf);
-			TAILQ_FOREACH(cmd, &Conf.cmdq, entry) {
-				XCALLOC(mi, struct menu);
-				strlcpy(mi->text, cmd->label, sizeof(mi->text));
-				mi->ctx = cmd;
-				TAILQ_INSERT_TAIL(&menuq, mi, entry);
-			}
-			break;
-		}
-		default:
-			break;
-		}
-
-		if (TAILQ_EMPTY(&menuq))
-			goto out;
-
-		mi = menu_filter(&menuq, NULL, NULL, 0, NULL, NULL);
-		if (mi == NULL)
-			goto cleanup;
-
-		switch (e->button) {
-		case Button1:
-			cc = (struct client_ctx *)mi->ctx;
-			client_unhide(cc);
-
-			if (old_cc != NULL)
-				client_ptrsave(old_cc);
-			client_ptrwarp(cc);
-			break;
-		case Button3:
-			u_spawn(((struct cmd *)mi->ctx)->image);
-			break;
-		default:
-			break;
-		}
-
-	cleanup:
-		while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
-			TAILQ_REMOVE(&menuq, mi, entry);
-			xfree(mi);
+	if (sc->rootwin == e->window)
+		TAILQ_FOREACH(mb, &Conf.mousebindingq, entry) {
+			if(e->button!=mb->button || e->state!=mb->modmask ||
+			    mb->context!=MOUSEBIND_CTX_ROOT)
+				continue;
+			(*mb->callback)(cc, e);
 		}
 
-		goto out;
-	}
-
 	if (cc == NULL || e->state == 0)
 		goto out;
 
-	sc = CCTOSC(cc);
+	TAILQ_FOREACH(mb, &Conf.mousebindingq, entry) {
+		if(e->button!=mb->button || e->state!=mb->modmask ||
+		   mb->context!=MOUSEBIND_CTX_WIN)
+			continue;
 
-	switch (e->button) {
-	case Button1:
-		if (altcontrol)
-			group_sticky_toggle_enter(cc);
-		else {
-			grab_drag(cc);
-			client_move(cc);
-		}
-		break;
-	case Button2:
-		grab_sweep(cc);
-		client_resize(cc);
-		break;
-	case Button3:
-		client_ptrsave(cc);
-		client_lower(cc);
+		(*mb->callback)(cc, NULL);
 		break;
 	}
 out: