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 \
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}

View File

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

88
conf.c
View File

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

61
cwmrc.5
View File

@ -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

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 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,

109
xevents.c
View File

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