Merge branch 'linux' of git://github.com/chneukirchen/cwm into linux

Conflicts:
	group.c
	xutil.c
This commit is contained in:
Michael Weber 2012-11-29 23:29:56 +01:00
commit 1fad01ad39
18 changed files with 836 additions and 156 deletions

14
LICENSE
View File

@ -1,14 +0,0 @@
Copyright (c) 2004,2005 Marius Aamodt Eriksen <marius@monkey.org>
Copyright (c) 2004 Andy Adamson <dros@monkey.org>
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.

View File

@ -19,7 +19,7 @@
*/ */
#include <sys/param.h> #include <sys/param.h>
#include <sys/queue.h> #include "queue.h"
#include <sys/wait.h> #include <sys/wait.h>
#include <err.h> #include <err.h>
@ -27,9 +27,9 @@
#include <getopt.h> #include <getopt.h>
#include <locale.h> #include <locale.h>
#include <signal.h> #include <signal.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include "calmwm.h" #include "calmwm.h"

View File

@ -88,6 +88,10 @@ size_t strlcat(char *, const char *, size_t);
#define CWM_RCYCLE 0x0002 #define CWM_RCYCLE 0x0002
#define CWM_INGROUP 0x0004 #define CWM_INGROUP 0x0004
/* menu */
#define CWM_MENU_DUMMY 0x0001
#define CWM_MENU_FILE 0x0002
#define KBTOGROUP(X) ((X) - 1) #define KBTOGROUP(X) ((X) - 1)
union arg { union arg {
@ -283,7 +287,7 @@ TAILQ_HEAD(cmd_q, cmd);
struct menu { struct menu {
TAILQ_ENTRY(menu) entry; TAILQ_ENTRY(menu) entry;
TAILQ_ENTRY(menu) resultentry; TAILQ_ENTRY(menu) resultentry;
#define MENU_MAXENTRY 50 #define MENU_MAXENTRY 200
char text[MENU_MAXENTRY + 1]; char text[MENU_MAXENTRY + 1];
char print[MENU_MAXENTRY + 1]; char print[MENU_MAXENTRY + 1];
void *ctx; void *ctx;
@ -380,6 +384,10 @@ void search_match_client(struct menu_q *, struct menu_q *,
char *); char *);
void search_match_exec(struct menu_q *, struct menu_q *, void search_match_exec(struct menu_q *, struct menu_q *,
char *); char *);
void search_match_exec_path(struct menu_q *, struct menu_q *,
char *);
void search_match_path_any(struct menu_q *, struct menu_q *,
char *);
void search_match_text(struct menu_q *, struct menu_q *, void search_match_text(struct menu_q *, struct menu_q *,
char *); char *);
void search_print_client(struct menu *, int); void search_print_client(struct menu *, int);
@ -463,9 +471,9 @@ int font_descent(struct screen_ctx *);
void font_draw(struct screen_ctx *, const char *, int, void font_draw(struct screen_ctx *, const char *, int,
Drawable, int, int); Drawable, int, int);
u_int font_height(struct screen_ctx *); u_int font_height(struct screen_ctx *);
void font_init(struct screen_ctx *, const char *); void font_init(struct screen_ctx *, const char *,
const char *);
int font_width(struct screen_ctx *, const char *, int); int font_width(struct screen_ctx *, const char *, int);
XftFont *font_make(struct screen_ctx *, const char *);
void xev_loop(void); void xev_loop(void);
@ -498,7 +506,7 @@ void xu_ewmh_net_wm_number_of_desktops(struct screen_ctx *);
void xu_ewmh_net_showing_desktop(struct screen_ctx *); void xu_ewmh_net_showing_desktop(struct screen_ctx *);
void xu_ewmh_net_virtual_roots(struct screen_ctx *); void xu_ewmh_net_virtual_roots(struct screen_ctx *);
void xu_ewmh_net_current_desktop(struct screen_ctx *, long); void xu_ewmh_net_current_desktop(struct screen_ctx *, long);
void xu_ewmh_net_desktop_names(struct screen_ctx *, unsigned char *, int); void xu_ewmh_net_desktop_names(struct screen_ctx *, char *, int);
void xu_ewmh_net_wm_desktop(struct client_ctx *); void xu_ewmh_net_wm_desktop(struct client_ctx *);
@ -507,9 +515,11 @@ void u_exec(char *);
void u_spawn(char *); void u_spawn(char *);
void *xcalloc(size_t, size_t); void *xcalloc(size_t, size_t);
void xfree(void *);
void *xmalloc(size_t); void *xmalloc(size_t);
char *xstrdup(const char *); char *xstrdup(const char *);
int xasprintf(char **, const char *, ...)
__attribute__((__format__ (printf, 2, 3)))
__attribute__((__nonnull__ (2)));
/* Externs */ /* Externs */
extern Display *X_Dpy; extern Display *X_Dpy;

View File

@ -19,14 +19,14 @@
*/ */
#include <sys/param.h> #include <sys/param.h>
#include <sys/queue.h> #include "queue.h"
#include <assert.h> #include <assert.h>
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include "calmwm.h" #include "calmwm.h"
@ -166,12 +166,12 @@ client_delete(struct client_ctx *cc)
while ((wn = TAILQ_FIRST(&cc->nameq)) != NULL) { while ((wn = TAILQ_FIRST(&cc->nameq)) != NULL) {
TAILQ_REMOVE(&cc->nameq, wn, entry); TAILQ_REMOVE(&cc->nameq, wn, entry);
if (wn->name != emptystring) if (wn->name != emptystring)
xfree(wn->name); free(wn->name);
xfree(wn); free(wn);
} }
client_freehints(cc); client_freehints(cc);
xfree(cc); free(cc);
} }
void void
@ -582,8 +582,8 @@ match:
assert(wn != NULL); assert(wn != NULL);
TAILQ_REMOVE(&cc->nameq, wn, entry); TAILQ_REMOVE(&cc->nameq, wn, entry);
if (wn->name != emptystring) if (wn->name != emptystring)
xfree(wn->name); free(wn->name);
xfree(wn); free(wn);
cc->nameqlen--; cc->nameqlen--;
} }
} }

90
conf.c
View File

@ -19,14 +19,14 @@
*/ */
#include <sys/param.h> #include <sys/param.h>
#include <sys/queue.h> #include "queue.h"
#include <sys/stat.h> #include <sys/stat.h>
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include "calmwm.h" #include "calmwm.h"
@ -62,8 +62,7 @@ conf_gap(struct conf *c, struct screen_ctx *sc)
void void
conf_font(struct conf *c, struct screen_ctx *sc) conf_font(struct conf *c, struct screen_ctx *sc)
{ {
font_init(sc, c->color[CWM_COLOR_FONT].name); font_init(sc, c->font, c->color[CWM_COLOR_FONT].name);
sc->font = font_make(sc, c->font);
} }
static struct color color_binds[] = { static struct color color_binds[] = {
@ -210,20 +209,19 @@ conf_clear(struct conf *c)
while ((cmd = TAILQ_FIRST(&c->cmdq)) != NULL) { while ((cmd = TAILQ_FIRST(&c->cmdq)) != NULL) {
TAILQ_REMOVE(&c->cmdq, cmd, entry); TAILQ_REMOVE(&c->cmdq, cmd, entry);
xfree(cmd); free(cmd);
} }
while ((kb = TAILQ_FIRST(&c->keybindingq)) != NULL) { while ((kb = TAILQ_FIRST(&c->keybindingq)) != NULL) {
TAILQ_REMOVE(&c->keybindingq, kb, entry); TAILQ_REMOVE(&c->keybindingq, kb, entry);
xfree(kb); free(kb);
} }
while ((ag = TAILQ_FIRST(&c->autogroupq)) != NULL) { while ((ag = TAILQ_FIRST(&c->autogroupq)) != NULL) {
TAILQ_REMOVE(&c->autogroupq, ag, entry); TAILQ_REMOVE(&c->autogroupq, ag, entry);
xfree(ag->class); free(ag->class);
if (ag->name) free(ag->name);
xfree(ag->name); free(ag);
xfree(ag);
} }
while ((as = TAILQ_FIRST(&c->autostartq)) != NULL) { while ((as = TAILQ_FIRST(&c->autostartq)) != NULL) {
@ -234,18 +232,18 @@ conf_clear(struct conf *c)
while ((wm = TAILQ_FIRST(&c->ignoreq)) != NULL) { while ((wm = TAILQ_FIRST(&c->ignoreq)) != NULL) {
TAILQ_REMOVE(&c->ignoreq, wm, entry); TAILQ_REMOVE(&c->ignoreq, wm, entry);
xfree(wm); free(wm);
} }
while ((mb = TAILQ_FIRST(&c->mousebindingq)) != NULL) { while ((mb = TAILQ_FIRST(&c->mousebindingq)) != NULL) {
TAILQ_REMOVE(&c->mousebindingq, mb, entry); TAILQ_REMOVE(&c->mousebindingq, mb, entry);
xfree(mb); free(mb);
} }
for (i = 0; i < CWM_COLOR_MAX; i++) for (i = 0; i < CWM_COLOR_MAX; i++)
xfree(c->color[i].name); free(c->color[i].name);
xfree(c->font); free(c->font);
} }
void void
@ -473,24 +471,22 @@ conf_bindname(struct conf *c, char *name, char *binding)
{ {
struct keybinding *current_binding; struct keybinding *current_binding;
char *substring, *tmp; char *substring, *tmp;
int iter; int i;
current_binding = xcalloc(1, sizeof(*current_binding)); current_binding = xcalloc(1, sizeof(*current_binding));
if ((substring = strchr(name, '-')) != NULL) { if ((substring = strchr(name, '-')) != NULL) {
for (iter = 0; iter < nitems(bind_mods); iter++) { for (i = 0; i < nitems(bind_mods); i++) {
if ((tmp = strchr(name, bind_mods[iter].chr)) != if ((tmp = strchr(name, bind_mods[i].chr)) !=
NULL && tmp < substring) { NULL && tmp < substring) {
current_binding->modmask |= current_binding->modmask |= bind_mods[i].mask;
bind_mods[iter].mask;
} }
} }
/* skip past the modifiers */ /* skip past the modifiers */
substring++; substring++;
} else { } else
substring = name; substring = name;
}
if (substring[0] == '[' && if (substring[0] == '[' &&
substring[strlen(substring)-1] == ']') { substring[strlen(substring)-1] == ']') {
@ -503,23 +499,25 @@ conf_bindname(struct conf *c, char *name, char *binding)
if (current_binding->keysym == NoSymbol && if (current_binding->keysym == NoSymbol &&
current_binding->keycode == 0) { current_binding->keycode == 0) {
xfree(current_binding); free(current_binding);
return; return;
} }
/* We now have the correct binding, remove duplicates. */ /* We now have the correct binding, remove duplicates. */
conf_unbind(c, current_binding); conf_unbind(c, current_binding);
if (strcmp("unmap", binding) == 0) if (strcmp("unmap", binding) == 0) {
free(current_binding);
return; return;
}
for (iter = 0; iter < nitems(name_to_kbfunc); iter++) { for (i = 0; i < nitems(name_to_kbfunc); i++) {
if (strcmp(name_to_kbfunc[iter].tag, binding) != 0) if (strcmp(name_to_kbfunc[i].tag, binding) != 0)
continue; continue;
current_binding->callback = name_to_kbfunc[iter].handler; current_binding->callback = name_to_kbfunc[i].handler;
current_binding->flags = name_to_kbfunc[iter].flags; current_binding->flags = name_to_kbfunc[i].flags;
current_binding->argument = name_to_kbfunc[iter].argument; current_binding->argument = name_to_kbfunc[i].argument;
conf_grab(c, current_binding); conf_grab(c, current_binding);
TAILQ_INSERT_TAIL(&c->keybindingq, current_binding, entry); TAILQ_INSERT_TAIL(&c->keybindingq, current_binding, entry);
return; return;
@ -537,10 +535,7 @@ conf_unbind(struct conf *c, struct keybinding *unbind)
{ {
struct keybinding *key = NULL, *keynxt; struct keybinding *key = NULL, *keynxt;
for (key = TAILQ_FIRST(&c->keybindingq); TAILQ_FOREACH_SAFE(key, &c->keybindingq, entry, keynxt) {
key != TAILQ_END(&c->keybindingq); key = keynxt) {
keynxt = TAILQ_NEXT(key, entry);
if (key->modmask != unbind->modmask) if (key->modmask != unbind->modmask)
continue; continue;
@ -549,7 +544,7 @@ conf_unbind(struct conf *c, struct keybinding *unbind)
key->keysym == unbind->keysym) { key->keysym == unbind->keysym) {
conf_ungrab(c, key); conf_ungrab(c, key);
TAILQ_REMOVE(&c->keybindingq, key, entry); TAILQ_REMOVE(&c->keybindingq, key, entry);
xfree(key); free(key);
} }
} }
} }
@ -577,16 +572,15 @@ conf_mousebind(struct conf *c, char *name, char *binding)
struct mousebinding *current_binding; struct mousebinding *current_binding;
char *substring, *tmp; char *substring, *tmp;
const char *errstr; const char *errstr;
int iter; int i;
current_binding = xcalloc(1, sizeof(*current_binding)); current_binding = xcalloc(1, sizeof(*current_binding));
if ((substring = strchr(name, '-')) != NULL) { if ((substring = strchr(name, '-')) != NULL) {
for (iter = 0; iter < nitems(bind_mods); iter++) { for (i = 0; i < nitems(bind_mods); i++) {
if ((tmp = strchr(name, bind_mods[iter].chr)) != if ((tmp = strchr(name, bind_mods[i].chr)) !=
NULL && tmp < substring) { NULL && tmp < substring) {
current_binding->modmask |= current_binding->modmask |= bind_mods[i].mask;
bind_mods[iter].mask;
} }
} }
@ -599,17 +593,20 @@ conf_mousebind(struct conf *c, char *name, char *binding)
if (errstr) if (errstr)
warnx("number of buttons is %s: %s", errstr, substring); warnx("number of buttons is %s: %s", errstr, substring);
/* We now have the correct binding, remove duplicates. */
conf_mouseunbind(c, current_binding); conf_mouseunbind(c, current_binding);
if (strcmp("unmap", binding) == 0) if (strcmp("unmap", binding) == 0) {
free(current_binding);
return; return;
}
for (iter = 0; iter < nitems(name_to_mousefunc); iter++) { for (i = 0; i < nitems(name_to_mousefunc); i++) {
if (strcmp(name_to_mousefunc[iter].tag, binding) != 0) if (strcmp(name_to_mousefunc[i].tag, binding) != 0)
continue; continue;
current_binding->context = name_to_mousefunc[iter].context; current_binding->context = name_to_mousefunc[i].context;
current_binding->callback = name_to_mousefunc[iter].handler; current_binding->callback = name_to_mousefunc[i].handler;
TAILQ_INSERT_TAIL(&c->mousebindingq, current_binding, entry); TAILQ_INSERT_TAIL(&c->mousebindingq, current_binding, entry);
return; return;
} }
@ -620,16 +617,13 @@ conf_mouseunbind(struct conf *c, struct mousebinding *unbind)
{ {
struct mousebinding *mb = NULL, *mbnxt; struct mousebinding *mb = NULL, *mbnxt;
for (mb = TAILQ_FIRST(&c->mousebindingq); TAILQ_FOREACH_SAFE(mb, &c->mousebindingq, entry, mbnxt) {
mb != TAILQ_END(&c->mousebindingq); mb = mbnxt) {
mbnxt = TAILQ_NEXT(mb, entry);
if (mb->modmask != unbind->modmask) if (mb->modmask != unbind->modmask)
continue; continue;
if (mb->button == unbind->button) { if (mb->button == unbind->button) {
TAILQ_REMOVE(&c->mousebindingq, mb, entry); TAILQ_REMOVE(&c->mousebindingq, mb, entry);
xfree(mb); free(mb);
} }
} }
} }

View File

@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: October 31 2012 $ .Dd $Mdocdate: November 7 2012 $
.Dt CWMRC 5 .Dt CWMRC 5
.Os .Os
.Sh NAME .Sh NAME
@ -59,7 +59,7 @@ used to override
.Dq sticky group mode . .Dq sticky group mode .
.Pp .Pp
The name and class values, respectively, for existing windows The name and class values, respectively, for existing windows
may be obtained using are both set in the WM_CLASS property and may be obtained using
.Xr xprop 1 . .Xr xprop 1 .
.Pp .Pp
.It Ic bind Ar keys command .It Ic bind Ar keys command

28
font.c
View File

@ -19,13 +19,13 @@
*/ */
#include <sys/param.h> #include <sys/param.h>
#include <sys/queue.h> #include "queue.h"
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include "calmwm.h" #include "calmwm.h"
@ -49,7 +49,7 @@ font_height(struct screen_ctx *sc)
} }
void void
font_init(struct screen_ctx *sc, const char *color) font_init(struct screen_ctx *sc, const char *name, const char *color)
{ {
sc->xftdraw = XftDrawCreate(X_Dpy, sc->rootwin, sc->xftdraw = XftDrawCreate(X_Dpy, sc->rootwin,
DefaultVisual(X_Dpy, sc->which), DefaultColormap(X_Dpy, sc->which)); DefaultVisual(X_Dpy, sc->which), DefaultColormap(X_Dpy, sc->which));
@ -59,6 +59,10 @@ font_init(struct screen_ctx *sc, const char *color)
if (!XftColorAllocName(X_Dpy, DefaultVisual(X_Dpy, sc->which), if (!XftColorAllocName(X_Dpy, DefaultVisual(X_Dpy, sc->which),
DefaultColormap(X_Dpy, sc->which), color, &sc->xftcolor)) DefaultColormap(X_Dpy, sc->which), color, &sc->xftcolor))
errx(1, "XftColorAllocName"); errx(1, "XftColorAllocName");
sc->font = XftFontOpenName(X_Dpy, sc->which, name);
if (sc->font == NULL)
errx(1, "XftFontOpenName");
} }
int int
@ -80,21 +84,3 @@ font_draw(struct screen_ctx *sc, const char *text, int len,
XftDrawStringUtf8(sc->xftdraw, &sc->xftcolor, sc->font, x, y, XftDrawStringUtf8(sc->xftdraw, &sc->xftcolor, sc->font, x, y,
(const FcChar8*)text, len); (const FcChar8*)text, len);
} }
XftFont *
font_make(struct screen_ctx *sc, const char *name)
{
XftFont *fn = NULL;
FcPattern *pat, *patx;
XftResult res;
if ((pat = FcNameParse((const FcChar8*)name)) == NULL)
return (NULL);
if ((patx = XftFontMatch(X_Dpy, sc->which, pat, &res)) != NULL)
fn = XftFontOpenPattern(X_Dpy, patx);
FcPatternDestroy(pat);
return (fn);
}

15
group.c
View File

@ -20,11 +20,12 @@
*/ */
#include <sys/param.h> #include <sys/param.h>
#include <sys/queue.h> #include "queue.h"
#include <assert.h> #include <assert.h>
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
@ -130,7 +131,7 @@ group_show(struct screen_ctx *sc, struct group_ctx *gc)
} }
XRestackWindows(X_Dpy, winlist, gc->nhidden); XRestackWindows(X_Dpy, winlist, gc->nhidden);
xfree(winlist); free(winlist);
gc->hidden = 0; gc->hidden = 0;
group_setactive(sc, gc->shortcut - 1); group_setactive(sc, gc->shortcut - 1);
@ -420,7 +421,7 @@ group_menu(XButtonEvent *e)
cleanup: cleanup:
while ((mi = TAILQ_FIRST(&menuq)) != NULL) { while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry); TAILQ_REMOVE(&menuq, mi, entry);
xfree(mi); free(mi);
} }
} }
@ -526,7 +527,7 @@ group_update_names(struct screen_ctx *sc)
strings = xmalloc((nstrings < CALMWM_NGROUPS ? CALMWM_NGROUPS : strings = xmalloc((nstrings < CALMWM_NGROUPS ? CALMWM_NGROUPS :
nstrings) * sizeof(*strings)); nstrings) * sizeof(*strings));
p = (char *) prop_ret; p = (char *)prop_ret;
while (n < nstrings) { while (n < nstrings) {
strings[n++] = xstrdup(p); strings[n++] = xstrdup(p);
p += strlen(p) + 1; p += strlen(p) + 1;
@ -545,7 +546,7 @@ group_update_names(struct screen_ctx *sc)
if (prop_ret != NULL) if (prop_ret != NULL)
XFree(prop_ret); XFree(prop_ret);
if (sc->group_nonames != 0) if (sc->group_nonames != 0)
xfree(sc->group_names); free(sc->group_names);
sc->group_names = strings; sc->group_names = strings;
sc->group_nonames = n; sc->group_nonames = n;
@ -556,7 +557,7 @@ group_update_names(struct screen_ctx *sc)
static void static void
group_set_names(struct screen_ctx *sc) group_set_names(struct screen_ctx *sc)
{ {
unsigned char *p, *q; char *p, *q;
size_t len = 0, tlen, slen; size_t len = 0, tlen, slen;
int i; int i;
@ -567,7 +568,7 @@ group_set_names(struct screen_ctx *sc)
tlen = len; tlen = len;
for (i = 0; i < sc->group_nonames; i++) { for (i = 0; i < sc->group_nonames; i++) {
slen = strlen(sc->group_names[i]) + 1; slen = strlen(sc->group_names[i]) + 1;
(void)strlcpy((char *) q, sc->group_names[i], tlen); (void)strlcpy(q, sc->group_names[i], tlen);
tlen -= slen; tlen -= slen;
q += slen; q += slen;
} }

View File

@ -19,16 +19,16 @@
*/ */
#include <sys/param.h> #include <sys/param.h>
#include <sys/queue.h> #include "queue.h"
#include <dirent.h> #include <dirent.h>
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>
#include <paths.h> #include <paths.h>
#include <signal.h> #include <signal.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include "calmwm.h" #include "calmwm.h"
@ -246,7 +246,7 @@ kbfunc_client_search(struct client_ctx *cc, union arg *arg)
while ((mi = TAILQ_FIRST(&menuq)) != NULL) { while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry); TAILQ_REMOVE(&menuq, mi, entry);
xfree(mi); free(mi);
} }
} }
@ -273,7 +273,7 @@ kbfunc_menu_search(struct client_ctx *cc, union arg *arg)
while ((mi = TAILQ_FIRST(&menuq)) != NULL) { while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry); TAILQ_REMOVE(&menuq, mi, entry);
xfree(mi); free(mi);
} }
} }
@ -373,10 +373,11 @@ kbfunc_exec(struct client_ctx *cc, union arg *arg)
} }
(void)closedir(dirp); (void)closedir(dirp);
} }
xfree(path); free(path);
if ((mi = menu_filter(sc, &menuq, label, NULL, 1, if ((mi = menu_filter(sc, &menuq, label, NULL,
search_match_exec, NULL)) != NULL) { CWM_MENU_DUMMY | CWM_MENU_FILE,
search_match_exec_path, NULL)) != NULL) {
if (mi->text[0] == '\0') if (mi->text[0] == '\0')
goto out; goto out;
switch (cmd) { switch (cmd) {
@ -394,10 +395,10 @@ kbfunc_exec(struct client_ctx *cc, union arg *arg)
} }
out: out:
if (mi != NULL && mi->dummy) if (mi != NULL && mi->dummy)
xfree(mi); free(mi);
while ((mi = TAILQ_FIRST(&menuq)) != NULL) { while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry); TAILQ_REMOVE(&menuq, mi, entry);
xfree(mi); free(mi);
} }
} }
@ -450,10 +451,10 @@ kbfunc_ssh(struct client_ctx *cc, union arg *arg)
(void)strlcpy(mi->text, hostbuf, sizeof(mi->text)); (void)strlcpy(mi->text, hostbuf, sizeof(mi->text));
TAILQ_INSERT_TAIL(&menuq, mi, entry); TAILQ_INSERT_TAIL(&menuq, mi, entry);
} }
xfree(lbuf); free(lbuf);
(void)fclose(fp); (void)fclose(fp);
if ((mi = menu_filter(sc, &menuq, "ssh", NULL, 1, if ((mi = menu_filter(sc, &menuq, "ssh", NULL, CWM_MENU_DUMMY,
search_match_exec, NULL)) != NULL) { search_match_exec, NULL)) != NULL) {
if (mi->text[0] == '\0') if (mi->text[0] == '\0')
goto out; goto out;
@ -464,10 +465,10 @@ kbfunc_ssh(struct client_ctx *cc, union arg *arg)
} }
out: out:
if (mi != NULL && mi->dummy) if (mi != NULL && mi->dummy)
xfree(mi); free(mi);
while ((mi = TAILQ_FIRST(&menuq)) != NULL) { while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry); TAILQ_REMOVE(&menuq, mi, entry);
xfree(mi); free(mi);
} }
} }
@ -480,15 +481,14 @@ kbfunc_client_label(struct client_ctx *cc, union arg *arg)
TAILQ_INIT(&menuq); TAILQ_INIT(&menuq);
/* dummy is set, so this will always return */ /* dummy is set, so this will always return */
mi = menu_filter(cc->sc, &menuq, "label", cc->label, 1, mi = menu_filter(cc->sc, &menuq, "label", cc->label, CWM_MENU_DUMMY,
search_match_text, NULL); search_match_text, NULL);
if (!mi->abort) { if (!mi->abort) {
if (cc->label != NULL) free(cc->label);
xfree(cc->label);
cc->label = xstrdup(mi->text); cc->label = xstrdup(mi->text);
} }
xfree(mi); free(mi);
} }
void void

80
menu.c
View File

@ -20,13 +20,14 @@
*/ */
#include <sys/param.h> #include <sys/param.h>
#include <sys/queue.h> #include "queue.h"
#include <ctype.h>
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include "calmwm.h" #include "calmwm.h"
@ -37,10 +38,11 @@
enum ctltype { enum ctltype {
CTL_NONE = -1, CTL_NONE = -1,
CTL_ERASEONE = 0, CTL_WIPE, CTL_UP, CTL_DOWN, CTL_RETURN, CTL_ERASEONE = 0, CTL_WIPE, CTL_UP, CTL_DOWN, CTL_RETURN,
CTL_ABORT, CTL_ALL CTL_TAB, CTL_ABORT, CTL_ALL
}; };
struct menu_ctx { struct menu_ctx {
struct screen_ctx *sc;
char searchstr[MENU_MAXENTRY + 1]; char searchstr[MENU_MAXENTRY + 1];
char dispstr[MENU_MAXENTRY*2 + 1]; char dispstr[MENU_MAXENTRY*2 + 1];
char promptstr[MENU_MAXENTRY + 1]; char promptstr[MENU_MAXENTRY + 1];
@ -54,6 +56,7 @@ struct menu_ctx {
int height; int height;
int width; int width;
int num; int num;
int flags;
int x; int x;
int y; int y;
void (*match)(struct menu_q *, struct menu_q *, char *); void (*match)(struct menu_q *, struct menu_q *, char *);
@ -93,7 +96,7 @@ menu_init(struct screen_ctx *sc)
struct menu * struct menu *
menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt, menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt,
char *initial, int dummy, char *initial, int flags,
void (*match)(struct menu_q *, struct menu_q *, char *), void (*match)(struct menu_q *, struct menu_q *, char *),
void (*print)(struct menu *, int)) void (*print)(struct menu *, int))
{ {
@ -114,6 +117,8 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt,
xsave = mc.x; xsave = mc.x;
ysave = mc.y; ysave = mc.y;
mc.sc = sc;
mc.flags = flags;
if (prompt == NULL) { if (prompt == NULL) {
evmask = MENUMASK; evmask = MENUMASK;
mc.promptstr[0] = '\0'; mc.promptstr[0] = '\0';
@ -181,8 +186,9 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt,
} }
} }
out: out:
if (dummy == 0 && mi->dummy) { /* no mouse based match */ if ((mc.flags & CWM_MENU_DUMMY) == 0 && mi->dummy) {
xfree(mi); /* no mouse based match */
free(mi);
mi = NULL; mi = NULL;
} }
@ -199,6 +205,38 @@ out:
return (mi); return (mi);
} }
static struct menu *
menu_complete_path(struct menu_ctx *mc)
{
struct menu *mi, *mr;
struct menu_q menuq;
char *path = NULL;
path = xcalloc(1, sizeof(mr->text));
mr = xcalloc(1, sizeof(*mr));
TAILQ_INIT(&menuq);
if ((mi = menu_filter(mc->sc, &menuq, mc->searchstr, NULL,
CWM_MENU_DUMMY, search_match_path_any, NULL)) != NULL) {
mr->abort = mi->abort;
mr->dummy = mi->dummy;
strlcpy(path, mi->text, sizeof(mi->text));
}
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry);
free(mi);
}
if (path[0] != '\0')
snprintf(mr->text, sizeof(mr->text), "%s \"%s\"",
mc->searchstr, path);
else if (!mr->abort)
strlcpy(mr->text, mc->searchstr, sizeof(mr->text));
free(path);
return (mr);
}
static struct menu * static struct menu *
menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq, menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
struct menu_q *resultq) struct menu_q *resultq)
@ -257,6 +295,33 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
mc->searchstr[0] = '\0'; mc->searchstr[0] = '\0';
mc->changed = 1; mc->changed = 1;
break; break;
case CTL_TAB:
if ((mi = TAILQ_FIRST(resultq)) != NULL) {
/*
* - We are in exec_path menu mode
* - It is equal to the input
* We got a command, launch the file menu
*/
if ((mc->flags & CWM_MENU_FILE) &&
(strncmp(mc->searchstr, mi->text,
strlen(mi->text))) == 0)
return (menu_complete_path(mc));
/*
* Put common prefix of the results into searchstr
*/
(void)strlcpy(mc->searchstr,
mi->text, sizeof(mc->searchstr));
while ((mi = TAILQ_NEXT(mi, resultentry)) != NULL) {
i = 0;
while (tolower(mc->searchstr[i]) ==
tolower(mi->text[i]))
i++;
mc->searchstr[i] = '\0';
}
mc->changed = 1;
}
break;
case CTL_ALL: case CTL_ALL:
mc->list = !mc->list; mc->list = !mc->list;
break; break;
@ -484,6 +549,9 @@ menu_keycode(XKeyEvent *ev, enum ctltype *ctl, char *chr)
case XK_Return: case XK_Return:
*ctl = CTL_RETURN; *ctl = CTL_RETURN;
break; break;
case XK_Tab:
*ctl = CTL_TAB;
break;
case XK_Up: case XK_Up:
*ctl = CTL_UP; *ctl = CTL_UP;
break; break;

View File

@ -20,13 +20,13 @@
*/ */
#include <sys/param.h> #include <sys/param.h>
#include <sys/queue.h> #include "queue.h"
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include "calmwm.h" #include "calmwm.h"
@ -253,7 +253,7 @@ mousefunc_menu_unhide(struct client_ctx *cc, void *arg)
} else { } else {
while ((mi = TAILQ_FIRST(&menuq)) != NULL) { while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry); TAILQ_REMOVE(&menuq, mi, entry);
xfree(mi); free(mi);
} }
} }
} }
@ -282,6 +282,6 @@ mousefunc_menu_cmd(struct client_ctx *cc, void *arg)
else else
while ((mi = TAILQ_FIRST(&menuq)) != NULL) { while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry); TAILQ_REMOVE(&menuq, mi, entry);
xfree(mi); free(mi);
} }
} }

568
queue.h Normal file
View File

@ -0,0 +1,568 @@
/* $OpenBSD: "queue.h",v 1.36 2012/04/11 13:29:14 naddy Exp $ */
/* $NetBSD: "queue.h",v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)"queue.h" 8.5 (Berkeley) 8/20/94
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
/*
* This file defines five types of data structures: singly-linked lists,
* lists, simple queues, tail queues, and circular queues.
*
*
* A singly-linked list is headed by a single forward pointer. The elements
* are singly linked for minimum space and pointer manipulation overhead at
* the expense of O(n) removal for arbitrary elements. New elements can be
* added to the list after an existing element or at the head of the list.
* Elements being removed from the head of the list should use the explicit
* macro for this purpose for optimum efficiency. A singly-linked list may
* only be traversed in the forward direction. Singly-linked lists are ideal
* for applications with large datasets and few or no removals or for
* implementing a LIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may only be traversed in the forward direction.
*
* A simple queue is headed by a pair of pointers, one the head of the
* list and the other to the tail of the list. The elements are singly
* linked to save space, so elements can only be removed from the
* head of the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the
* list. A simple queue may only be traversed in the forward direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* A circle queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the list.
* A circle queue may be traversed in either direction, but has a more
* complex end of list detection.
*
* For details on the use of these macros, see the queue(3) manual page.
*/
#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
#define _Q_INVALIDATE(a) (a) = ((void *)-1)
#else
#define _Q_INVALIDATE(a)
#endif
/*
* Singly-linked List definitions.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
/*
* Singly-linked List access methods.
*/
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_END(head) NULL
#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_FOREACH(var, head, field) \
for((var) = SLIST_FIRST(head); \
(var) != SLIST_END(head); \
(var) = SLIST_NEXT(var, field))
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SLIST_FIRST(head); \
(var) && ((tvar) = SLIST_NEXT(var, field), 1); \
(var) = (tvar))
/*
* Singly-linked List functions.
*/
#define SLIST_INIT(head) { \
SLIST_FIRST(head) = SLIST_END(head); \
}
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
(elm)->field.sle_next = (slistelm)->field.sle_next; \
(slistelm)->field.sle_next = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) do { \
(elm)->field.sle_next = (head)->slh_first; \
(head)->slh_first = (elm); \
} while (0)
#define SLIST_REMOVE_AFTER(elm, field) do { \
(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
} while (0)
#define SLIST_REMOVE_HEAD(head, field) do { \
(head)->slh_first = (head)->slh_first->field.sle_next; \
} while (0)
#define SLIST_REMOVE(head, elm, type, field) do { \
if ((head)->slh_first == (elm)) { \
SLIST_REMOVE_HEAD((head), field); \
} else { \
struct type *curelm = (head)->slh_first; \
\
while (curelm->field.sle_next != (elm)) \
curelm = curelm->field.sle_next; \
curelm->field.sle_next = \
curelm->field.sle_next->field.sle_next; \
_Q_INVALIDATE((elm)->field.sle_next); \
} \
} while (0)
/*
* List definitions.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List access methods
*/
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_END(head) NULL
#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_FOREACH(var, head, field) \
for((var) = LIST_FIRST(head); \
(var)!= LIST_END(head); \
(var) = LIST_NEXT(var, field))
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = LIST_FIRST(head); \
(var) && ((tvar) = LIST_NEXT(var, field), 1); \
(var) = (tvar))
/*
* List functions.
*/
#define LIST_INIT(head) do { \
LIST_FIRST(head) = LIST_END(head); \
} while (0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
(listelm)->field.le_next->field.le_prev = \
&(elm)->field.le_next; \
(listelm)->field.le_next = (elm); \
(elm)->field.le_prev = &(listelm)->field.le_next; \
} while (0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.le_prev = (listelm)->field.le_prev; \
(elm)->field.le_next = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &(elm)->field.le_next; \
} while (0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
(head)->lh_first = (elm); \
(elm)->field.le_prev = &(head)->lh_first; \
} while (0)
#define LIST_REMOVE(elm, field) do { \
if ((elm)->field.le_next != NULL) \
(elm)->field.le_next->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = (elm)->field.le_next; \
_Q_INVALIDATE((elm)->field.le_prev); \
_Q_INVALIDATE((elm)->field.le_next); \
} while (0)
#define LIST_REPLACE(elm, elm2, field) do { \
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
(elm2)->field.le_next->field.le_prev = \
&(elm2)->field.le_next; \
(elm2)->field.le_prev = (elm)->field.le_prev; \
*(elm2)->field.le_prev = (elm2); \
_Q_INVALIDATE((elm)->field.le_prev); \
_Q_INVALIDATE((elm)->field.le_next); \
} while (0)
/*
* Simple queue definitions.
*/
#define SIMPLEQ_HEAD(name, type) \
struct name { \
struct type *sqh_first; /* first element */ \
struct type **sqh_last; /* addr of last next element */ \
}
#define SIMPLEQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).sqh_first }
#define SIMPLEQ_ENTRY(type) \
struct { \
struct type *sqe_next; /* next element */ \
}
/*
* Simple queue access methods.
*/
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
#define SIMPLEQ_END(head) NULL
#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
#define SIMPLEQ_FOREACH(var, head, field) \
for((var) = SIMPLEQ_FIRST(head); \
(var) != SIMPLEQ_END(head); \
(var) = SIMPLEQ_NEXT(var, field))
#define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SIMPLEQ_FIRST(head); \
(var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \
(var) = (tvar))
/*
* Simple queue functions.
*/
#define SIMPLEQ_INIT(head) do { \
(head)->sqh_first = NULL; \
(head)->sqh_last = &(head)->sqh_first; \
} while (0)
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
(head)->sqh_last = &(elm)->field.sqe_next; \
(head)->sqh_first = (elm); \
} while (0)
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.sqe_next = NULL; \
*(head)->sqh_last = (elm); \
(head)->sqh_last = &(elm)->field.sqe_next; \
} while (0)
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
(head)->sqh_last = &(elm)->field.sqe_next; \
(listelm)->field.sqe_next = (elm); \
} while (0)
#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
(head)->sqh_last = &(head)->sqh_first; \
} while (0)
#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
== NULL) \
(head)->sqh_last = &(elm)->field.sqe_next; \
} while (0)
/*
* Tail queue definitions.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first }
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
}
/*
* tail queue access methods
*/
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_END(head) NULL
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
/* XXX */
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_EMPTY(head) \
(TAILQ_FIRST(head) == TAILQ_END(head))
#define TAILQ_FOREACH(var, head, field) \
for((var) = TAILQ_FIRST(head); \
(var) != TAILQ_END(head); \
(var) = TAILQ_NEXT(var, field))
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = TAILQ_FIRST(head); \
(var) != TAILQ_END(head) && \
((tvar) = TAILQ_NEXT(var, field), 1); \
(var) = (tvar))
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for((var) = TAILQ_LAST(head, headname); \
(var) != TAILQ_END(head); \
(var) = TAILQ_PREV(var, headname, field))
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
for ((var) = TAILQ_LAST(head, headname); \
(var) != TAILQ_END(head) && \
((tvar) = TAILQ_PREV(var, headname, field), 1); \
(var) = (tvar))
/*
* Tail queue functions.
*/
#define TAILQ_INIT(head) do { \
(head)->tqh_first = NULL; \
(head)->tqh_last = &(head)->tqh_first; \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
(head)->tqh_first->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(head)->tqh_first = (elm); \
(elm)->field.tqe_prev = &(head)->tqh_first; \
} while (0)
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.tqe_next = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &(elm)->field.tqe_next; \
} while (0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
(elm)->field.tqe_next->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(listelm)->field.tqe_next = (elm); \
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
} while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
(elm)->field.tqe_next = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
} while (0)
#define TAILQ_REMOVE(head, elm, field) do { \
if (((elm)->field.tqe_next) != NULL) \
(elm)->field.tqe_next->field.tqe_prev = \
(elm)->field.tqe_prev; \
else \
(head)->tqh_last = (elm)->field.tqe_prev; \
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
_Q_INVALIDATE((elm)->field.tqe_prev); \
_Q_INVALIDATE((elm)->field.tqe_next); \
} while (0)
#define TAILQ_REPLACE(head, elm, elm2, field) do { \
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
(elm2)->field.tqe_next->field.tqe_prev = \
&(elm2)->field.tqe_next; \
else \
(head)->tqh_last = &(elm2)->field.tqe_next; \
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
*(elm2)->field.tqe_prev = (elm2); \
_Q_INVALIDATE((elm)->field.tqe_prev); \
_Q_INVALIDATE((elm)->field.tqe_next); \
} while (0)
/*
* Circular queue definitions.
*/
#define CIRCLEQ_HEAD(name, type) \
struct name { \
struct type *cqh_first; /* first element */ \
struct type *cqh_last; /* last element */ \
}
#define CIRCLEQ_HEAD_INITIALIZER(head) \
{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
#define CIRCLEQ_ENTRY(type) \
struct { \
struct type *cqe_next; /* next element */ \
struct type *cqe_prev; /* previous element */ \
}
/*
* Circular queue access methods
*/
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
#define CIRCLEQ_END(head) ((void *)(head))
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
#define CIRCLEQ_EMPTY(head) \
(CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
#define CIRCLEQ_FOREACH(var, head, field) \
for((var) = CIRCLEQ_FIRST(head); \
(var) != CIRCLEQ_END(head); \
(var) = CIRCLEQ_NEXT(var, field))
#define CIRCLEQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = CIRCLEQ_FIRST(head); \
(var) != CIRCLEQ_END(head) && \
((tvar) = CIRCLEQ_NEXT(var, field), 1); \
(var) = (tvar))
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
for((var) = CIRCLEQ_LAST(head); \
(var) != CIRCLEQ_END(head); \
(var) = CIRCLEQ_PREV(var, field))
#define CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
for ((var) = CIRCLEQ_LAST(head, headname); \
(var) != CIRCLEQ_END(head) && \
((tvar) = CIRCLEQ_PREV(var, headname, field), 1); \
(var) = (tvar))
/*
* Circular queue functions.
*/
#define CIRCLEQ_INIT(head) do { \
(head)->cqh_first = CIRCLEQ_END(head); \
(head)->cqh_last = CIRCLEQ_END(head); \
} while (0)
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
(elm)->field.cqe_prev = (listelm); \
if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm); \
else \
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
(listelm)->field.cqe_next = (elm); \
} while (0)
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
(elm)->field.cqe_next = (listelm); \
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm); \
else \
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
(listelm)->field.cqe_prev = (elm); \
} while (0)
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
(elm)->field.cqe_next = (head)->cqh_first; \
(elm)->field.cqe_prev = CIRCLEQ_END(head); \
if ((head)->cqh_last == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm); \
else \
(head)->cqh_first->field.cqe_prev = (elm); \
(head)->cqh_first = (elm); \
} while (0)
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.cqe_next = CIRCLEQ_END(head); \
(elm)->field.cqe_prev = (head)->cqh_last; \
if ((head)->cqh_first == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm); \
else \
(head)->cqh_last->field.cqe_next = (elm); \
(head)->cqh_last = (elm); \
} while (0)
#define CIRCLEQ_REMOVE(head, elm, field) do { \
if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm)->field.cqe_prev; \
else \
(elm)->field.cqe_next->field.cqe_prev = \
(elm)->field.cqe_prev; \
if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm)->field.cqe_next; \
else \
(elm)->field.cqe_prev->field.cqe_next = \
(elm)->field.cqe_next; \
_Q_INVALIDATE((elm)->field.cqe_prev); \
_Q_INVALIDATE((elm)->field.cqe_next); \
} while (0)
#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
CIRCLEQ_END(head)) \
(head).cqh_last = (elm2); \
else \
(elm2)->field.cqe_next->field.cqe_prev = (elm2); \
if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
CIRCLEQ_END(head)) \
(head).cqh_first = (elm2); \
else \
(elm2)->field.cqe_prev->field.cqe_next = (elm2); \
_Q_INVALIDATE((elm)->field.cqe_prev); \
_Q_INVALIDATE((elm)->field.cqe_next); \
} while (0)
#endif /* !_SYS_QUEUE_H_ */

View File

@ -19,13 +19,13 @@
*/ */
#include <sys/param.h> #include <sys/param.h>
#include <sys/queue.h> #include "queue.h"
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include "calmwm.h" #include "calmwm.h"

View File

@ -19,19 +19,22 @@
*/ */
#include <sys/param.h> #include <sys/param.h>
#include <sys/queue.h> #include "queue.h"
#include <assert.h> #include <assert.h>
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>
#include <fnmatch.h> #include <fnmatch.h>
#include <glob.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include "calmwm.h" #include "calmwm.h"
#define PATH_EXEC 0x1
static int strsubmatch(char *, char *, int); static int strsubmatch(char *, char *, int);
/* /*
@ -161,6 +164,43 @@ search_print_client(struct menu *mi, int list)
} }
} }
static void
search_match_path(struct menu_q *menuq, struct menu_q *resultq, char *search, int flag)
{
struct menu *mi;
char pattern[MAXPATHLEN];
glob_t g;
int i;
TAILQ_INIT(resultq);
(void)strlcpy(pattern, search, sizeof(pattern));
(void)strlcat(pattern, "*", sizeof(pattern));
if (glob(pattern, GLOB_MARK, NULL, &g) != 0)
return;
for (i = 0; i < g.gl_pathc; i++) {
if ((flag & PATH_EXEC) && access(g.gl_pathv[i], X_OK))
continue;
mi = xcalloc(1, sizeof(*mi));
(void)strlcpy(mi->text, g.gl_pathv[i], sizeof(mi->text));
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
}
globfree(&g);
}
void
search_match_path_exec(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
return (search_match_path(menuq, resultq, search, PATH_EXEC));
}
void
search_match_path_any(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
return (search_match_path(menuq, resultq, search, 0));
}
void void
search_match_text(struct menu_q *menuq, struct menu_q *resultq, char *search) search_match_text(struct menu_q *menuq, struct menu_q *resultq, char *search)
{ {
@ -196,6 +236,14 @@ search_match_exec(struct menu_q *menuq, struct menu_q *resultq, char *search)
} }
} }
void
search_match_exec_path(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
search_match_exec(menuq, resultq, search);
if (TAILQ_EMPTY(resultq))
search_match_path_exec(menuq, resultq, search);
}
static int static int
strsubmatch(char *sub, char *str, int zeroidx) strsubmatch(char *sub, char *str, int zeroidx)
{ {

4
util.c
View File

@ -19,13 +19,13 @@
*/ */
#include <sys/param.h> #include <sys/param.h>
#include <sys/queue.h> #include "queue.h"
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include "calmwm.h" #include "calmwm.h"

View File

@ -25,14 +25,14 @@
*/ */
#include <sys/param.h> #include <sys/param.h>
#include <sys/queue.h> #include "queue.h"
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>
#include <signal.h> #include <signal.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include "calmwm.h" #include "calmwm.h"

View File

@ -19,13 +19,14 @@
*/ */
#include <sys/param.h> #include <sys/param.h>
#include <sys/queue.h> #include "queue.h"
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include "calmwm.h" #include "calmwm.h"
@ -35,6 +36,8 @@ xmalloc(size_t siz)
{ {
void *p; void *p;
if (siz == 0)
errx(1, "xmalloc: zero size");
if ((p = malloc(siz)) == NULL) if ((p = malloc(siz)) == NULL)
err(1, "malloc"); err(1, "malloc");
@ -46,18 +49,16 @@ xcalloc(size_t no, size_t siz)
{ {
void *p; void *p;
if (siz == 0 || no == 0)
errx(1, "xcalloc: zero size");
if (SIZE_MAX / no < siz)
errx(1, "xcalloc: no * siz > SIZE_MAX");
if ((p = calloc(no, siz)) == NULL) if ((p = calloc(no, siz)) == NULL)
err(1, "calloc"); err(1, "calloc");
return (p); return (p);
} }
void
xfree(void *p)
{
free(p);
}
char * char *
xstrdup(const char *str) xstrdup(const char *str)
{ {
@ -68,3 +69,19 @@ xstrdup(const char *str)
return (p); return (p);
} }
int
xasprintf(char **ret, const char *fmt, ...)
{
va_list ap;
int i;
va_start(ap, fmt);
i = vasprintf(ret, fmt, ap);
va_end(ap);
if (i < 0 || *ret == NULL)
err(1, "asprintf");
return (i);
}

14
xutil.c
View File

@ -19,10 +19,11 @@
*/ */
#include <sys/param.h> #include <sys/param.h>
#include <sys/queue.h> #include "queue.h"
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
@ -188,7 +189,7 @@ xu_getstrprop(Window win, Atom atm, char **text) {
XTextProperty prop2; XTextProperty prop2;
if (Xutf8TextListToTextProperty(X_Dpy, list, nitems, if (Xutf8TextListToTextProperty(X_Dpy, list, nitems,
XUTF8StringStyle, &prop2) == Success) { XUTF8StringStyle, &prop2) == Success) {
*text = xstrdup((char *) prop2.value); *text = xstrdup((const char *)prop2.value);
XFree(prop2.value); XFree(prop2.value);
} }
} else { } else {
@ -292,7 +293,8 @@ xu_ewmh_net_supported_wm_check(struct screen_ctx *sc)
XChangeProperty(X_Dpy, w, ewmh[_NET_SUPPORTING_WM_CHECK].atom, XChangeProperty(X_Dpy, w, ewmh[_NET_SUPPORTING_WM_CHECK].atom,
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1); XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1);
XChangeProperty(X_Dpy, w, ewmh[_NET_WM_NAME].atom, XChangeProperty(X_Dpy, w, ewmh[_NET_WM_NAME].atom,
XA_WM_NAME, 8, PropModeReplace, WMNAME, strlen(WMNAME)); XA_WM_NAME, 8, PropModeReplace, (unsigned char *)WMNAME,
strlen(WMNAME));
} }
void void
@ -339,7 +341,7 @@ xu_ewmh_net_client_list(struct screen_ctx *sc)
winlist[j++] = cc->win; winlist[j++] = cc->win;
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_CLIENT_LIST].atom, XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_CLIENT_LIST].atom,
XA_WINDOW, 32, PropModeReplace, (unsigned char *)winlist, i); XA_WINDOW, 32, PropModeReplace, (unsigned char *)winlist, i);
xfree(winlist); free(winlist);
} }
void void
@ -396,10 +398,10 @@ xu_ewmh_net_current_desktop(struct screen_ctx *sc, long idx)
} }
void void
xu_ewmh_net_desktop_names(struct screen_ctx *sc, unsigned char *data, int n) xu_ewmh_net_desktop_names(struct screen_ctx *sc, char *data, int n)
{ {
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_DESKTOP_NAMES].atom, XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_DESKTOP_NAMES].atom,
cwmh[UTF8_STRING].atom, 8, PropModeReplace, data, n); cwmh[UTF8_STRING].atom, 8, PropModeReplace, (unsigned char *)data, n);
} }
/* Application Window Properties */ /* Application Window Properties */