diff --git a/LICENSE b/LICENSE deleted file mode 100644 index de3b872..0000000 --- a/LICENSE +++ /dev/null @@ -1,14 +0,0 @@ - Copyright (c) 2004,2005 Marius Aamodt Eriksen - Copyright (c) 2004 Andy Adamson - - 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. diff --git a/calmwm.c b/calmwm.c index f908a04..08d0b53 100644 --- a/calmwm.c +++ b/calmwm.c @@ -19,7 +19,7 @@ */ #include -#include +#include "queue.h" #include #include @@ -27,9 +27,9 @@ #include #include #include +#include #include #include -#include #include #include "calmwm.h" diff --git a/calmwm.h b/calmwm.h index b0e1512..36c2eab 100644 --- a/calmwm.h +++ b/calmwm.h @@ -88,6 +88,10 @@ size_t strlcat(char *, const char *, size_t); #define CWM_RCYCLE 0x0002 #define CWM_INGROUP 0x0004 +/* menu */ +#define CWM_MENU_DUMMY 0x0001 +#define CWM_MENU_FILE 0x0002 + #define KBTOGROUP(X) ((X) - 1) union arg { @@ -283,7 +287,7 @@ TAILQ_HEAD(cmd_q, cmd); struct menu { TAILQ_ENTRY(menu) entry; TAILQ_ENTRY(menu) resultentry; -#define MENU_MAXENTRY 50 +#define MENU_MAXENTRY 200 char text[MENU_MAXENTRY + 1]; char print[MENU_MAXENTRY + 1]; void *ctx; @@ -380,6 +384,10 @@ void search_match_client(struct menu_q *, struct menu_q *, char *); void search_match_exec(struct menu_q *, struct menu_q *, 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 *, char *); 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, Drawable, int, int); 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); -XftFont *font_make(struct screen_ctx *, const char *); 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_virtual_roots(struct screen_ctx *); 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 *); @@ -507,9 +515,11 @@ void u_exec(char *); void u_spawn(char *); void *xcalloc(size_t, size_t); -void xfree(void *); void *xmalloc(size_t); char *xstrdup(const char *); +int xasprintf(char **, const char *, ...) + __attribute__((__format__ (printf, 2, 3))) + __attribute__((__nonnull__ (2))); /* Externs */ extern Display *X_Dpy; diff --git a/client.c b/client.c index 8cb119f..455f5ef 100644 --- a/client.c +++ b/client.c @@ -19,14 +19,14 @@ */ #include -#include +#include "queue.h" #include #include #include +#include #include #include -#include #include #include "calmwm.h" @@ -166,12 +166,12 @@ client_delete(struct client_ctx *cc) while ((wn = TAILQ_FIRST(&cc->nameq)) != NULL) { TAILQ_REMOVE(&cc->nameq, wn, entry); if (wn->name != emptystring) - xfree(wn->name); - xfree(wn); + free(wn->name); + free(wn); } client_freehints(cc); - xfree(cc); + free(cc); } void @@ -582,8 +582,8 @@ match: assert(wn != NULL); TAILQ_REMOVE(&cc->nameq, wn, entry); if (wn->name != emptystring) - xfree(wn->name); - xfree(wn); + free(wn->name); + free(wn); cc->nameqlen--; } } diff --git a/conf.c b/conf.c index 7d187a8..30ede1a 100644 --- a/conf.c +++ b/conf.c @@ -19,14 +19,14 @@ */ #include -#include +#include "queue.h" #include #include #include +#include #include #include -#include #include #include "calmwm.h" @@ -62,8 +62,7 @@ conf_gap(struct conf *c, struct screen_ctx *sc) void conf_font(struct conf *c, struct screen_ctx *sc) { - font_init(sc, c->color[CWM_COLOR_FONT].name); - sc->font = font_make(sc, c->font); + font_init(sc, c->font, c->color[CWM_COLOR_FONT].name); } static struct color color_binds[] = { @@ -210,20 +209,19 @@ conf_clear(struct conf *c) while ((cmd = TAILQ_FIRST(&c->cmdq)) != NULL) { TAILQ_REMOVE(&c->cmdq, cmd, entry); - xfree(cmd); + free(cmd); } while ((kb = TAILQ_FIRST(&c->keybindingq)) != NULL) { TAILQ_REMOVE(&c->keybindingq, kb, entry); - xfree(kb); + free(kb); } while ((ag = TAILQ_FIRST(&c->autogroupq)) != NULL) { TAILQ_REMOVE(&c->autogroupq, ag, entry); - xfree(ag->class); - if (ag->name) - xfree(ag->name); - xfree(ag); + free(ag->class); + free(ag->name); + free(ag); } while ((as = TAILQ_FIRST(&c->autostartq)) != NULL) { @@ -234,18 +232,18 @@ conf_clear(struct conf *c) while ((wm = TAILQ_FIRST(&c->ignoreq)) != NULL) { TAILQ_REMOVE(&c->ignoreq, wm, entry); - xfree(wm); + free(wm); } while ((mb = TAILQ_FIRST(&c->mousebindingq)) != NULL) { TAILQ_REMOVE(&c->mousebindingq, mb, entry); - xfree(mb); + free(mb); } 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 @@ -473,24 +471,22 @@ conf_bindname(struct conf *c, char *name, char *binding) { struct keybinding *current_binding; char *substring, *tmp; - int iter; + int i; current_binding = xcalloc(1, sizeof(*current_binding)); if ((substring = strchr(name, '-')) != NULL) { - for (iter = 0; iter < nitems(bind_mods); iter++) { - if ((tmp = strchr(name, bind_mods[iter].chr)) != + for (i = 0; i < nitems(bind_mods); i++) { + if ((tmp = strchr(name, bind_mods[i].chr)) != NULL && tmp < substring) { - current_binding->modmask |= - bind_mods[iter].mask; + current_binding->modmask |= bind_mods[i].mask; } } /* skip past the modifiers */ substring++; - } else { + } else substring = name; - } if (substring[0] == '[' && substring[strlen(substring)-1] == ']') { @@ -503,23 +499,25 @@ conf_bindname(struct conf *c, char *name, char *binding) if (current_binding->keysym == NoSymbol && current_binding->keycode == 0) { - xfree(current_binding); + free(current_binding); return; } /* We now have the correct binding, remove duplicates. */ conf_unbind(c, current_binding); - if (strcmp("unmap", binding) == 0) + if (strcmp("unmap", binding) == 0) { + free(current_binding); return; + } - for (iter = 0; iter < nitems(name_to_kbfunc); iter++) { - if (strcmp(name_to_kbfunc[iter].tag, binding) != 0) + for (i = 0; i < nitems(name_to_kbfunc); i++) { + if (strcmp(name_to_kbfunc[i].tag, binding) != 0) continue; - current_binding->callback = name_to_kbfunc[iter].handler; - current_binding->flags = name_to_kbfunc[iter].flags; - current_binding->argument = name_to_kbfunc[iter].argument; + current_binding->callback = name_to_kbfunc[i].handler; + current_binding->flags = name_to_kbfunc[i].flags; + current_binding->argument = name_to_kbfunc[i].argument; conf_grab(c, current_binding); TAILQ_INSERT_TAIL(&c->keybindingq, current_binding, entry); return; @@ -537,10 +535,7 @@ conf_unbind(struct conf *c, struct keybinding *unbind) { struct keybinding *key = NULL, *keynxt; - for (key = TAILQ_FIRST(&c->keybindingq); - key != TAILQ_END(&c->keybindingq); key = keynxt) { - keynxt = TAILQ_NEXT(key, entry); - + TAILQ_FOREACH_SAFE(key, &c->keybindingq, entry, keynxt) { if (key->modmask != unbind->modmask) continue; @@ -549,7 +544,7 @@ conf_unbind(struct conf *c, struct keybinding *unbind) key->keysym == unbind->keysym) { conf_ungrab(c, key); 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; char *substring, *tmp; const char *errstr; - int iter; + int i; current_binding = xcalloc(1, sizeof(*current_binding)); if ((substring = strchr(name, '-')) != NULL) { - for (iter = 0; iter < nitems(bind_mods); iter++) { - if ((tmp = strchr(name, bind_mods[iter].chr)) != + for (i = 0; i < nitems(bind_mods); i++) { + if ((tmp = strchr(name, bind_mods[i].chr)) != NULL && tmp < substring) { - current_binding->modmask |= - bind_mods[iter].mask; + current_binding->modmask |= bind_mods[i].mask; } } @@ -599,17 +593,20 @@ conf_mousebind(struct conf *c, char *name, char *binding) if (errstr) warnx("number of buttons is %s: %s", errstr, substring); + /* We now have the correct binding, remove duplicates. */ conf_mouseunbind(c, current_binding); - if (strcmp("unmap", binding) == 0) + if (strcmp("unmap", binding) == 0) { + free(current_binding); return; + } - for (iter = 0; iter < nitems(name_to_mousefunc); iter++) { - if (strcmp(name_to_mousefunc[iter].tag, binding) != 0) + for (i = 0; i < nitems(name_to_mousefunc); i++) { + if (strcmp(name_to_mousefunc[i].tag, binding) != 0) continue; - current_binding->context = name_to_mousefunc[iter].context; - current_binding->callback = name_to_mousefunc[iter].handler; + current_binding->context = name_to_mousefunc[i].context; + current_binding->callback = name_to_mousefunc[i].handler; TAILQ_INSERT_TAIL(&c->mousebindingq, current_binding, entry); return; } @@ -620,16 +617,13 @@ 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); - + TAILQ_FOREACH_SAFE(mb, &c->mousebindingq, entry, mbnxt) { if (mb->modmask != unbind->modmask) continue; if (mb->button == unbind->button) { TAILQ_REMOVE(&c->mousebindingq, mb, entry); - xfree(mb); + free(mb); } } } diff --git a/cwmrc.5 b/cwmrc.5 index ffc4d0c..39ab221 100644 --- a/cwmrc.5 +++ b/cwmrc.5 @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: October 31 2012 $ +.Dd $Mdocdate: November 7 2012 $ .Dt CWMRC 5 .Os .Sh NAME @@ -58,8 +58,8 @@ is 0, matching windows will not be added to any group; this may be used to override .Dq sticky group mode . .Pp -The name and class values, respectively, for existing windows -may be obtained using +The name and class values, respectively, for existing windows +are both set in the WM_CLASS property and may be obtained using .Xr xprop 1 . .Pp .It Ic bind Ar keys command diff --git a/font.c b/font.c index 88d6519..4267e91 100644 --- a/font.c +++ b/font.c @@ -19,13 +19,13 @@ */ #include -#include +#include "queue.h" #include #include +#include #include #include -#include #include #include "calmwm.h" @@ -49,7 +49,7 @@ font_height(struct screen_ctx *sc) } 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, 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), DefaultColormap(X_Dpy, sc->which), color, &sc->xftcolor)) errx(1, "XftColorAllocName"); + + sc->font = XftFontOpenName(X_Dpy, sc->which, name); + if (sc->font == NULL) + errx(1, "XftFontOpenName"); } 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, (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); -} diff --git a/group.c b/group.c index 14c08ed..b621878 100644 --- a/group.c +++ b/group.c @@ -20,11 +20,12 @@ */ #include -#include +#include "queue.h" #include #include #include +#include #include #include #include @@ -130,7 +131,7 @@ group_show(struct screen_ctx *sc, struct group_ctx *gc) } XRestackWindows(X_Dpy, winlist, gc->nhidden); - xfree(winlist); + free(winlist); gc->hidden = 0; group_setactive(sc, gc->shortcut - 1); @@ -420,7 +421,7 @@ group_menu(XButtonEvent *e) cleanup: while ((mi = TAILQ_FIRST(&menuq)) != NULL) { 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 : nstrings) * sizeof(*strings)); - p = (char *) prop_ret; + p = (char *)prop_ret; while (n < nstrings) { strings[n++] = xstrdup(p); p += strlen(p) + 1; @@ -545,7 +546,7 @@ group_update_names(struct screen_ctx *sc) if (prop_ret != NULL) XFree(prop_ret); if (sc->group_nonames != 0) - xfree(sc->group_names); + free(sc->group_names); sc->group_names = strings; sc->group_nonames = n; @@ -556,7 +557,7 @@ group_update_names(struct screen_ctx *sc) static void group_set_names(struct screen_ctx *sc) { - unsigned char *p, *q; + char *p, *q; size_t len = 0, tlen, slen; int i; @@ -567,7 +568,7 @@ group_set_names(struct screen_ctx *sc) tlen = len; for (i = 0; i < sc->group_nonames; i++) { 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; q += slen; } diff --git a/kbfunc.c b/kbfunc.c index c141f80..7101c8a 100644 --- a/kbfunc.c +++ b/kbfunc.c @@ -19,16 +19,16 @@ */ #include -#include +#include "queue.h" #include #include #include #include #include +#include #include #include -#include #include #include "calmwm.h" @@ -246,7 +246,7 @@ kbfunc_client_search(struct client_ctx *cc, union arg *arg) while ((mi = TAILQ_FIRST(&menuq)) != NULL) { 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) { 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); } - xfree(path); + free(path); - if ((mi = menu_filter(sc, &menuq, label, NULL, 1, - search_match_exec, NULL)) != NULL) { + if ((mi = menu_filter(sc, &menuq, label, NULL, + CWM_MENU_DUMMY | CWM_MENU_FILE, + search_match_exec_path, NULL)) != NULL) { if (mi->text[0] == '\0') goto out; switch (cmd) { @@ -394,10 +395,10 @@ kbfunc_exec(struct client_ctx *cc, union arg *arg) } out: if (mi != NULL && mi->dummy) - xfree(mi); + free(mi); while ((mi = TAILQ_FIRST(&menuq)) != NULL) { 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)); TAILQ_INSERT_TAIL(&menuq, mi, entry); } - xfree(lbuf); + free(lbuf); (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) { if (mi->text[0] == '\0') goto out; @@ -464,10 +465,10 @@ kbfunc_ssh(struct client_ctx *cc, union arg *arg) } out: if (mi != NULL && mi->dummy) - xfree(mi); + free(mi); while ((mi = TAILQ_FIRST(&menuq)) != NULL) { 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); /* 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); if (!mi->abort) { - if (cc->label != NULL) - xfree(cc->label); + free(cc->label); cc->label = xstrdup(mi->text); } - xfree(mi); + free(mi); } void diff --git a/menu.c b/menu.c index 4a532a9..dcf801d 100644 --- a/menu.c +++ b/menu.c @@ -20,13 +20,14 @@ */ #include -#include +#include "queue.h" +#include #include #include +#include #include #include -#include #include #include "calmwm.h" @@ -37,10 +38,11 @@ enum ctltype { CTL_NONE = -1, 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 screen_ctx *sc; char searchstr[MENU_MAXENTRY + 1]; char dispstr[MENU_MAXENTRY*2 + 1]; char promptstr[MENU_MAXENTRY + 1]; @@ -54,6 +56,7 @@ struct menu_ctx { int height; int width; int num; + int flags; int x; int y; void (*match)(struct menu_q *, struct menu_q *, char *); @@ -93,7 +96,7 @@ menu_init(struct screen_ctx *sc) struct menu * 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 (*print)(struct menu *, int)) { @@ -114,6 +117,8 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt, xsave = mc.x; ysave = mc.y; + mc.sc = sc; + mc.flags = flags; if (prompt == NULL) { evmask = MENUMASK; mc.promptstr[0] = '\0'; @@ -181,8 +186,9 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt, } } out: - if (dummy == 0 && mi->dummy) { /* no mouse based match */ - xfree(mi); + if ((mc.flags & CWM_MENU_DUMMY) == 0 && mi->dummy) { + /* no mouse based match */ + free(mi); mi = NULL; } @@ -199,6 +205,38 @@ out: 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 * menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq, 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->changed = 1; 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: mc->list = !mc->list; break; @@ -484,6 +549,9 @@ menu_keycode(XKeyEvent *ev, enum ctltype *ctl, char *chr) case XK_Return: *ctl = CTL_RETURN; break; + case XK_Tab: + *ctl = CTL_TAB; + break; case XK_Up: *ctl = CTL_UP; break; diff --git a/mousefunc.c b/mousefunc.c index c615052..37dd7a1 100644 --- a/mousefunc.c +++ b/mousefunc.c @@ -20,13 +20,13 @@ */ #include -#include +#include "queue.h" #include #include +#include #include #include -#include #include #include "calmwm.h" @@ -253,7 +253,7 @@ mousefunc_menu_unhide(struct client_ctx *cc, void *arg) } else { while ((mi = TAILQ_FIRST(&menuq)) != NULL) { TAILQ_REMOVE(&menuq, mi, entry); - xfree(mi); + free(mi); } } } @@ -282,6 +282,6 @@ mousefunc_menu_cmd(struct client_ctx *cc, void *arg) else while ((mi = TAILQ_FIRST(&menuq)) != NULL) { TAILQ_REMOVE(&menuq, mi, entry); - xfree(mi); + free(mi); } } diff --git a/queue.h b/queue.h new file mode 100644 index 0000000..5442699 --- /dev/null +++ b/queue.h @@ -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_ */ diff --git a/screen.c b/screen.c index 69a638a..c723378 100644 --- a/screen.c +++ b/screen.c @@ -19,13 +19,13 @@ */ #include -#include +#include "queue.h" #include #include +#include #include #include -#include #include #include "calmwm.h" diff --git a/search.c b/search.c index 8d58067..815f6bb 100644 --- a/search.c +++ b/search.c @@ -19,19 +19,22 @@ */ #include -#include +#include "queue.h" #include #include #include #include +#include +#include #include #include -#include #include #include "calmwm.h" +#define PATH_EXEC 0x1 + 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 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 strsubmatch(char *sub, char *str, int zeroidx) { diff --git a/util.c b/util.c index 54faaea..c175165 100644 --- a/util.c +++ b/util.c @@ -19,13 +19,13 @@ */ #include -#include +#include "queue.h" #include #include +#include #include #include -#include #include #include "calmwm.h" diff --git a/xevents.c b/xevents.c index 0d91067..acfb2bc 100644 --- a/xevents.c +++ b/xevents.c @@ -25,14 +25,14 @@ */ #include -#include +#include "queue.h" #include #include #include +#include #include #include -#include #include #include "calmwm.h" diff --git a/xmalloc.c b/xmalloc.c index 7860b97..3248124 100644 --- a/xmalloc.c +++ b/xmalloc.c @@ -19,13 +19,14 @@ */ #include -#include +#include "queue.h" #include #include +#include +#include #include #include -#include #include #include "calmwm.h" @@ -35,6 +36,8 @@ xmalloc(size_t siz) { void *p; + if (siz == 0) + errx(1, "xmalloc: zero size"); if ((p = malloc(siz)) == NULL) err(1, "malloc"); @@ -46,18 +49,16 @@ xcalloc(size_t no, size_t siz) { 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) err(1, "calloc"); return (p); } -void -xfree(void *p) -{ - free(p); -} - char * xstrdup(const char *str) { @@ -68,3 +69,19 @@ xstrdup(const char *str) 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); +} diff --git a/xutil.c b/xutil.c index 46540c5..6588abe 100644 --- a/xutil.c +++ b/xutil.c @@ -19,10 +19,11 @@ */ #include -#include +#include "queue.h" #include #include +#include #include #include #include @@ -188,7 +189,7 @@ xu_getstrprop(Window win, Atom atm, char **text) { XTextProperty prop2; if (Xutf8TextListToTextProperty(X_Dpy, list, nitems, XUTF8StringStyle, &prop2) == Success) { - *text = xstrdup((char *) prop2.value); + *text = xstrdup((const char *)prop2.value); XFree(prop2.value); } } 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, XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1); 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 @@ -339,7 +341,7 @@ xu_ewmh_net_client_list(struct screen_ctx *sc) winlist[j++] = cc->win; XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_CLIENT_LIST].atom, XA_WINDOW, 32, PropModeReplace, (unsigned char *)winlist, i); - xfree(winlist); + free(winlist); } void @@ -396,10 +398,10 @@ xu_ewmh_net_current_desktop(struct screen_ctx *sc, long idx) } 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, - cwmh[UTF8_STRING].atom, 8, PropModeReplace, data, n); + cwmh[UTF8_STRING].atom, 8, PropModeReplace, (unsigned char *)data, n); } /* Application Window Properties */