confable menu and window mouse bindings from rivo nurges (thanks!) with

some minor fixups, man page bits and knf.

ok oga@
This commit is contained in:
okan 2008-06-14 21:48:54 +00:00
parent b4ae492b7b
commit bdcbbe7f53
7 changed files with 329 additions and 101 deletions

View File

@ -6,7 +6,7 @@ PROG= cwm
SRCS= calmwm.c screen.c xmalloc.c client.c grab.c menu.c \ 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 \ 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} CPPFLAGS+= -I${X11BASE}/include -I${X11BASE}/include/freetype2 -I${.CURDIR}

View File

@ -249,8 +249,20 @@ struct cmd {
/* (argv) */ /* (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(keybinding_q, keybinding);
TAILQ_HEAD(cmd_q, cmd); TAILQ_HEAD(cmd_q, cmd);
TAILQ_HEAD(mousebinding_q, mousebinding);
/* Global configuration */ /* Global configuration */
struct conf { struct conf {
@ -259,6 +271,7 @@ struct conf {
struct winmatch_q ignoreq; struct winmatch_q ignoreq;
char conf_path[MAXPATHLEN]; char conf_path[MAXPATHLEN];
struct cmd_q cmdq; struct cmd_q cmdq;
struct mousebinding_q mousebindingq;
#define CONF_STICKY_GROUPS 0x0001 #define CONF_STICKY_GROUPS 0x0001
int flags; int flags;
@ -424,6 +437,8 @@ void conf_setup(struct conf *, const char *);
void conf_client(struct client_ctx *); void conf_client(struct client_ctx *);
void conf_bindname(struct conf *, char *, char *); void conf_bindname(struct conf *, char *, char *);
void conf_unbind(struct conf *, struct keybinding *); 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 *); int conf_changed(char *);
void conf_reload(struct conf *); 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_term(struct client_ctx *, void *);
void kbfunc_lock(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 *, void search_match_client(struct menu_q *, struct menu_q *,
char *); char *);
void search_print_client(struct menu *, int); void search_print_client(struct menu *, int);

88
conf.c
View File

@ -90,6 +90,7 @@ conf_init(struct conf *c)
TAILQ_INIT(&c->cmdq); TAILQ_INIT(&c->cmdq);
TAILQ_INIT(&c->keybindingq); TAILQ_INIT(&c->keybindingq);
TAILQ_INIT(&c->autogroupq); TAILQ_INIT(&c->autogroupq);
TAILQ_INIT(&c->mousebindingq);
conf_bindname(c, "CM-Return", "terminal"); conf_bindname(c, "CM-Return", "terminal");
conf_bindname(c, "CM-Delete", "lock"); 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-Up", "bigptrmoveup");
conf_bindname(c, "CS-Right", "bigptrmoveright"); 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 */ /* Default term/lock */
strlcpy(c->termpath, "xterm", sizeof(c->termpath)); strlcpy(c->termpath, "xterm", sizeof(c->termpath));
strlcpy(c->lockpath, "xlock", sizeof(c->lockpath)); 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);
}
}
}

61
cwmrc.5
View File

@ -15,7 +15,7 @@
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.\" The following requests are required for all man pages. .\" The following requests are required for all man pages.
.Dd $Mdocdate: May 19 2008 $ .Dd $Mdocdate: June 13 2008 $
.Dt CWMRC 5 .Dt CWMRC 5
.Os .Os
.Sh NAME .Sh NAME
@ -130,6 +130,41 @@ where the user may wish to remain visible.
Ignore drawing borders around a window with the name Ignore drawing borders around a window with the name
.Ar windowname . .Ar windowname .
.Pp .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 .It Ic sticky Ic yes Ns \&| Ns Ic no
Toggle sticky group mode. Toggle sticky group mode.
The default behavior for new windows is to not assign any group. The default behavior for new windows is to not assign any group.
@ -161,9 +196,13 @@ ignore xapm
ignore xclock ignore xclock
# Keybindings # Keybindings
bind CM-r "label" bind CM-r label
bind CS-Return "xterm -e top" 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 .Ed
.Sh BIND COMMAND LIST .Sh BIND COMMAND LIST
.Bl -tag -width 18n -compact .Bl -tag -width 18n -compact
@ -267,6 +306,22 @@ move pointer 10 pixels right
.It bigptrmoveleft .It bigptrmoveleft
move pointer 10 pixels left move pointer 10 pixels left
.El .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 .Sh FILES
.Bl -tag -width "~/.cwmrcXXX" -compact .Bl -tag -width "~/.cwmrcXXX" -compact
.It Pa ~/.cwmrc .It Pa ~/.cwmrc

126
mousefunc.c Normal file
View File

@ -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);
}
}

20
parse.y
View File

@ -66,7 +66,7 @@ typedef struct {
%} %}
%token FONTNAME STICKY GAP %token FONTNAME STICKY GAP MOUSEBIND
%token AUTOGROUP BIND COMMAND IGNORE %token AUTOGROUP BIND COMMAND IGNORE
%token YES NO %token YES NO
%token ERROR %token ERROR
@ -167,6 +167,11 @@ main : FONTNAME STRING {
conf->gap_left = $4; conf->gap_left = $4;
conf->gap_right = $5; 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}, { "fontname", FONTNAME},
{ "gap", GAP}, { "gap", GAP},
{ "ignore", IGNORE}, { "ignore", IGNORE},
{ "mousebind", MOUSEBIND},
{ "no", NO}, { "no", NO},
{ "sticky", STICKY}, { "sticky", STICKY},
{ "yes", YES} { "yes", YES}
@ -469,6 +475,7 @@ conf_clear(struct conf *c)
struct keybinding *kb; struct keybinding *kb;
struct winmatch *wm; struct winmatch *wm;
struct cmd *cmd; struct cmd *cmd;
struct mousebinding *mb;
while (cmd = TAILQ_FIRST(&c->cmdq)) { while (cmd = TAILQ_FIRST(&c->cmdq)) {
TAILQ_REMOVE(&c->cmdq, cmd, entry); TAILQ_REMOVE(&c->cmdq, cmd, entry);
@ -494,6 +501,11 @@ conf_clear(struct conf *c)
free(wm); free(wm);
} }
while (mb = TAILQ_FIRST(&c->mousebindingq)) {
TAILQ_REMOVE(&c->mousebindingq, mb, entry);
free(mb);
}
if (c->DefaultFontName != NULL && if (c->DefaultFontName != NULL &&
c->DefaultFontName != DEFAULTFONTNAME) c->DefaultFontName != DEFAULTFONTNAME)
free(c->DefaultFontName); free(c->DefaultFontName);
@ -529,6 +541,7 @@ parse_config(const char *filename, struct conf *xconf)
struct keybinding *kb; struct keybinding *kb;
struct winmatch *wm; struct winmatch *wm;
struct cmd *cmd; struct cmd *cmd;
struct mousebinding *mb;
conf_clear(xconf); conf_clear(xconf);
@ -554,6 +567,11 @@ parse_config(const char *filename, struct conf *xconf)
TAILQ_INSERT_TAIL(&xconf->ignoreq, wm, entry); 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, strlcpy(xconf->termpath, conf->termpath,
sizeof(xconf->termpath)); sizeof(xconf->termpath));
strlcpy(xconf->lockpath, conf->lockpath, strlcpy(xconf->lockpath, conf->lockpath,

109
xevents.c
View File

@ -221,113 +221,30 @@ void
xev_handle_buttonpress(struct xevent *xev, XEvent *ee) xev_handle_buttonpress(struct xevent *xev, XEvent *ee)
{ {
XButtonEvent *e = &ee->xbutton; XButtonEvent *e = &ee->xbutton;
struct client_ctx *cc, *old_cc = client_current(); struct client_ctx *cc;
struct screen_ctx *sc = screen_fromroot(e->root); struct screen_ctx *sc = screen_fromroot(e->root);
char *wname; char *wname;
int altcontrol = e->state == (ControlMask|Mod1Mask); struct mousebinding *mb;
cc = client_find(e->window); cc = client_find(e->window);
if (sc->rootwin == e->window && !altcontrol) { if (sc->rootwin == e->window)
struct menu_q menuq; TAILQ_FOREACH(mb, &Conf.mousebindingq, entry) {
struct menu *mi; if(e->button!=mb->button || e->state!=mb->modmask ||
mb->context!=MOUSEBIND_CTX_ROOT)
/* XXXSIGH!!!! */ continue;
if (e->button == Button2) { (*mb->callback)(cc, e);
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);
}
goto out;
}
if (cc == NULL || e->state == 0) if (cc == NULL || e->state == 0)
goto out; 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) { (*mb->callback)(cc, NULL);
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);
break; break;
} }
out: out: