X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=spectrwm.c;h=9d08e6e9fc1b06edd352b4e7ea694eac7151928f;hb=56230c5c167acf308dc45b98d5adeadac58f2e2f;hp=41bd6d47cd8eeb8131731d2da0f51f073490c6b7;hpb=2bf2ca8bf0ccb6580817dbff60adac273b8cbe5d;p=spectrwm.git diff --git a/spectrwm.c b/spectrwm.c index 41bd6d4..9d08e6e 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -373,6 +373,7 @@ int bar_justify = SWM_BAR_JUSTIFY_LEFT; char *bar_format = NULL; int stack_enabled = 1; int clock_enabled = 1; +int iconic_enabled = 0; int urgent_enabled = 0; char *clock_format = NULL; int window_class_enabled = 0; @@ -869,6 +870,7 @@ RB_HEAD(key_tree, key); /* function prototypes */ void adjust_font(struct ws_win *); +char *argsep(char **); void bar_cleanup(struct swm_region *); void bar_extra_setup(void); void bar_extra_stop(void); @@ -2077,6 +2079,8 @@ bar_workspace_name(char *s, size_t sz, struct swm_region *r) void bar_fmt(const char *fmtexp, char *fmtnew, struct swm_region *r, size_t sz) { + struct ws_win *w; + /* if format provided, just copy the buffers */ if (bar_format != NULL) { strlcpy(fmtnew, fmtexp, sz); @@ -2094,6 +2098,15 @@ bar_fmt(const char *fmtexp, char *fmtnew, struct swm_region *r, size_t sz) /* only show the workspace name if there's actually one */ if (r != NULL && r->ws != NULL && r->ws->name != NULL) strlcat(fmtnew, "<+D>", sz); + + /* If enabled, only show the iconic count if there are iconic wins. */ + if (iconic_enabled && r != NULL && r->ws != NULL) + TAILQ_FOREACH(w, &r->ws->winlist, entry) + if (w->iconic) { + strlcat(fmtnew, "{+M}", sz); + break; + } + strlcat(fmtnew, "+3<", sz); if (clock_enabled) { @@ -2143,9 +2156,10 @@ char * bar_replace_seq(char *fmt, char *fmtrep, struct swm_region *r, size_t *offrep, size_t sz) { + struct ws_win *w; char *ptr; char tmp[SWM_BAR_MAX]; - int limit, size; + int limit, size, count; size_t len; /* reset strlcat(3) buffer */ @@ -2183,6 +2197,14 @@ bar_replace_seq(char *fmt, char *fmtrep, struct swm_region *r, size_t *offrep, case 'I': snprintf(tmp, sizeof tmp, "%d", r->ws->idx + 1); break; + case 'M': + count = 0; + TAILQ_FOREACH(w, &r->ws->winlist, entry) + if (w->iconic) + ++count; + + snprintf(tmp, sizeof tmp, "%d", count); + break; case 'N': snprintf(tmp, sizeof tmp, "%d", r->s->idx + 1); break; @@ -6234,24 +6256,73 @@ spawn_select(struct swm_region *r, union arg *args, const char *spawn_name, free(real_args); } +/* Argument tokenizer. */ +char * +argsep(char **sp) { + int single_quoted = 0, double_quoted = 0; + char *arg, *cp, *next; + + if (*sp == NULL) + return NULL; + + /* Eat and move characters until end of argument is found. */ + for (arg = next = cp = *sp; *cp != '\0'; ++cp) { + if (!double_quoted && *cp == '\'') { + /* Eat single-quote. */ + single_quoted = !single_quoted; + } else if (!single_quoted && *cp == '"') { + /* Eat double-quote. */ + double_quoted = !double_quoted; + } else if (!single_quoted && *cp == '\\' && *(cp + 1) == '"') { + /* Eat backslash; copy escaped character to arg. */ + *next++ = *(++cp); + } else if (!single_quoted && !double_quoted && *cp == '\\' && + (*(cp + 1) == '\'' || *(cp + 1) == ' ')) { + /* Eat backslash; move escaped character. */ + *next++ = *(++cp); + } else if (!single_quoted && !double_quoted && + (*cp == ' ' || *cp == '\t')) { + /* Terminate argument. */ + *next++ = '\0'; + /* Point sp to beginning of next argument. */ + *sp = ++cp; + break; + } else { + /* Move regular character. */ + *next++ = *cp; + } + } + + /* Terminate argument if end of string. */ + if (*cp == '\0') { + *next = '\0'; + *sp = NULL; + } + + return arg; +} + void spawn_insert(const char *name, const char *args, int flags) { - char *arg, *cp, *ptr; struct spawn_prog *sp; + char *arg, *dup, *ptr; - DNPRINTF(SWM_D_SPAWN, "spawn_insert: %s\n", name); + DNPRINTF(SWM_D_SPAWN, "spawn_insert: %s[%s]\n", name, args); + + if (args == NULL || *args == '\0') + return; if ((sp = calloc(1, sizeof *sp)) == NULL) err(1, "spawn_insert: calloc"); if ((sp->name = strdup(name)) == NULL) err(1, "spawn_insert: strdup"); - /* convert the arguments to an argument list */ - if ((ptr = cp = strdup(args)) == NULL) + /* Convert the arguments to an argument list. */ + if ((ptr = dup = strdup(args)) == NULL) err(1, "spawn_insert: strdup"); - while ((arg = strsep(&ptr, " \t")) != NULL) { - /* empty field; skip it */ + while ((arg = argsep(&ptr)) != NULL) { + /* Null argument; skip it. */ if (*arg == '\0') continue; @@ -6262,10 +6333,11 @@ spawn_insert(const char *name, const char *args, int flags) if ((sp->argv[sp->argc - 1] = strdup(arg)) == NULL) err(1, "spawn_insert: strdup"); } - free(cp); + free(dup); sp->flags = flags; + DNPRINTF(SWM_D_SPAWN, "arg %d: [%s]\n", sp->argc, sp->argv[sp->argc-1]); TAILQ_INSERT_TAIL(&spawns, sp, entry); DNPRINTF(SWM_D_SPAWN, "spawn_insert: leave\n"); } @@ -6326,6 +6398,9 @@ setconfspawn(const char *selector, const char *value, int flags) { char *args; + if (selector == NULL || strlen(selector) == 0) + return (1); + args = expand_tilde(value); DNPRINTF(SWM_D_SPAWN, "setconfspawn: [%s] [%s]\n", selector, args); @@ -6574,8 +6649,9 @@ setconfbinding(const char *selector, const char *value, int flags) /* suppress unused warning since var is needed */ (void)flags; - DNPRINTF(SWM_D_KEY, "setconfbinding: enter\n"); - if (selector == NULL) { + DNPRINTF(SWM_D_KEY, "setconfbinding: enter selector: [%s], " + "value: [%s]\n", selector, value); + if (selector == NULL || strlen(selector) == 0) { DNPRINTF(SWM_D_KEY, "setconfbinding: unbind %s\n", value); if (parsekeys(value, mod_key, &mod, &ks) == 0) { kfid = KF_INVALID; @@ -6797,9 +6873,11 @@ updatenumlockmask(void) + j]; keycode = xcb_key_symbols_get_keycode(syms, XK_Num_Lock); - if (kc == *keycode) - numlockmask = (1 << i); - free(keycode); + if (keycode) { + if (kc == *keycode) + numlockmask = (1 << i); + free(keycode); + } } } free(modmap_r); @@ -7090,7 +7168,7 @@ setconfquirk(const char *selector, const char *value, int flags) /* suppress unused warning since var is needed */ (void)flags; - if (selector == NULL) + if (selector == NULL || strlen(selector) == 0) return (0); if ((str = strdup(selector)) == NULL) @@ -7138,19 +7216,19 @@ setconfquirk(const char *selector, const char *value, int flags) void setup_quirks(void) { - setquirk("MPlayer", "xv", "", SWM_Q_FLOAT | SWM_Q_FULLSCREEN | SWM_Q_FOCUSPREV); - setquirk("OpenOffice.org 3.2", "VCLSalFrame", "", SWM_Q_FLOAT); - setquirk("Firefox-bin", "firefox-bin", "", SWM_Q_TRANSSZ); - setquirk("Firefox", "Dialog", "", SWM_Q_FLOAT); - setquirk("Gimp", "gimp", "", SWM_Q_FLOAT | SWM_Q_ANYWHERE); - setquirk("XTerm", "xterm", "", SWM_Q_XTERM_FONTADJ); - setquirk("xine", "Xine Window", "", SWM_Q_FLOAT | SWM_Q_ANYWHERE); - setquirk("Xitk", "Xitk Combo", "", SWM_Q_FLOAT | SWM_Q_ANYWHERE); - setquirk("xine", "xine Panel", "", SWM_Q_FLOAT | SWM_Q_ANYWHERE); - setquirk("Xitk", "Xine Window", "", SWM_Q_FLOAT | SWM_Q_ANYWHERE); - setquirk("xine", "xine Video Fullscreen Window", "", SWM_Q_FULLSCREEN | SWM_Q_FLOAT); - setquirk("pcb", "pcb", "", SWM_Q_FLOAT); - setquirk("SDL_App", "SDL_App", "", SWM_Q_FLOAT | SWM_Q_FULLSCREEN); + setquirk("MPlayer", "xv", ".*", SWM_Q_FLOAT | SWM_Q_FULLSCREEN | SWM_Q_FOCUSPREV); + setquirk("OpenOffice.org 3.2", "VCLSalFrame", ".*", SWM_Q_FLOAT); + setquirk("Firefox-bin", "firefox-bin", ".*", SWM_Q_TRANSSZ); + setquirk("Firefox", "Dialog", ".*", SWM_Q_FLOAT); + setquirk("Gimp", "gimp", ".*", SWM_Q_FLOAT | SWM_Q_ANYWHERE); + setquirk("XTerm", "xterm", ".*", SWM_Q_XTERM_FONTADJ); + setquirk("xine", "Xine Window", ".*", SWM_Q_FLOAT | SWM_Q_ANYWHERE); + setquirk("Xitk", "Xitk Combo", ".*", SWM_Q_FLOAT | SWM_Q_ANYWHERE); + setquirk("xine", "xine Panel", ".*", SWM_Q_FLOAT | SWM_Q_ANYWHERE); + setquirk("Xitk", "Xine Window", ".*", SWM_Q_FLOAT | SWM_Q_ANYWHERE); + setquirk("xine", "xine Video Fullscreen Window", ".*", SWM_Q_FULLSCREEN | SWM_Q_FLOAT); + setquirk("pcb", "pcb", ".*", SWM_Q_FLOAT); + setquirk("SDL_App", "SDL_App", ".*", SWM_Q_FLOAT | SWM_Q_FULLSCREEN); } /* conf file stuff */ @@ -7179,6 +7257,7 @@ enum { SWM_S_FOCUS_CLOSE_WRAP, SWM_S_FOCUS_DEFAULT, SWM_S_FOCUS_MODE, + SWM_S_ICONIC_ENABLED, SWM_S_REGION_PADDING, SWM_S_SPAWN_ORDER, SWM_S_SPAWN_TERM, @@ -7202,9 +7281,6 @@ setconfvalue(const char *selector, const char *value, int flags) int i, ws_id, num_screens; char *b, *str; - /* suppress unused warning since var is needed */ - (void)selector; - switch (flags) { case SWM_S_BAR_ACTION: free(bar_argv[0]); @@ -7346,6 +7422,9 @@ setconfvalue(const char *selector, const char *value, int flags) else errx(1, "focus_mode"); break; + case SWM_S_ICONIC_ENABLED: + iconic_enabled = atoi(value); + break; case SWM_S_REGION_PADDING: region_padding = atoi(value); if (region_padding < 0) @@ -7441,7 +7520,9 @@ setconfmodkey(const char *selector, const char *value, int flags) int setconfcolor(const char *selector, const char *value, int flags) { - setscreencolor(value, ((selector == NULL)?-1:atoi(selector)), flags); + setscreencolor(value, + (selector == NULL || strlen(selector) == 0) ? -1 : atoi(selector), + flags); return (0); } @@ -7649,6 +7730,7 @@ struct config_option configopt[] = { { "focus_close_wrap", setconfvalue, SWM_S_FOCUS_CLOSE_WRAP }, { "focus_default", setconfvalue, SWM_S_FOCUS_DEFAULT }, { "focus_mode", setconfvalue, SWM_S_FOCUS_MODE }, + { "iconic_enabled", setconfvalue, SWM_S_ICONIC_ENABLED }, { "keyboard_mapping", setkeymapping, 0 }, { "layout", setlayout, 0 }, { "modkey", setconfmodkey, 0 }, @@ -7953,7 +8035,7 @@ manage_window(xcb_window_t id, uint16_t mapped) struct ws_win *win, *ww; int ws_idx; char ws_idx_str[SWM_PROPLEN]; - char *name; + char *class, *instance, *name; struct swm_region *r; struct pid_e *p; struct quirk *qp; @@ -8079,40 +8161,38 @@ manage_window(xcb_window_t id, uint16_t mapped) ewmh_autoquirk(win); /* Determine initial quirks. */ - if (xcb_icccm_get_wm_class_reply(conn, + xcb_icccm_get_wm_class_reply(conn, xcb_icccm_get_wm_class(conn, win->id), - &win->ch, NULL)) { - name = get_win_name(win->id); + &win->ch, NULL); - DNPRINTF(SWM_D_CLASS, "manage_window: class: %s, instance: %s, " - "name: %s\n", - win->ch.class_name, win->ch.instance_name, name); - - /* java is retarded so treat it special */ - if (strstr(win->ch.instance_name, "sun-awt")) { - DNPRINTF(SWM_D_CLASS, "manage_window: java window " - "detected.\n"); - win->java = 1; - } - - TAILQ_FOREACH(qp, &quirks, entry) { - if (regexec(&qp->regex_class, win->ch.class_name, 0, - NULL, 0) == 0 && regexec(&qp->regex_instance, - win->ch.instance_name, 0, NULL, 0) == 0 && - regexec(&qp->regex_name, name, 0, NULL, 0) == 0) { - DNPRINTF(SWM_D_CLASS, "manage_window: matched " - "quirk: %s:%s:%s mask: %#lx\n", qp->class, - qp->instance, qp->name, qp->quirk); - if (qp->quirk & SWM_Q_FLOAT) - win->floating = 1; - win->quirks = qp->quirk; - } + class = win->ch.class_name ? win->ch.class_name : ""; + instance = win->ch.instance_name ? win->ch.instance_name : ""; + name = get_win_name(win->id); - } + DNPRINTF(SWM_D_CLASS, "manage_window: class: %s, instance: %s, " + "name: %s\n", class, instance, name); - free(name); + /* java is retarded so treat it special */ + if (win->ch.instance_name && strstr(win->ch.instance_name, "sun-awt")) { + DNPRINTF(SWM_D_CLASS, "manage_window: java window detected.\n"); + win->java = 1; } + TAILQ_FOREACH(qp, &quirks, entry) { + if (regexec(&qp->regex_class, class, 0, NULL, 0) == 0 && + regexec(&qp->regex_instance, instance, 0, NULL, 0) == 0 && + regexec(&qp->regex_name, name, 0, NULL, 0) == 0) { + DNPRINTF(SWM_D_CLASS, "manage_window: matched " + "quirk: %s:%s:%s mask: %#lx\n", qp->class, + qp->instance, qp->name, qp->quirk); + if (qp->quirk & SWM_Q_FLOAT) + win->floating = 1; + win->quirks = qp->quirk; + } + } + + free(name); + /* Alter window position if quirky */ if (win->quirks & SWM_Q_ANYWHERE) win->manual = 1; @@ -8745,10 +8825,22 @@ mapnotify(xcb_map_notify_event_t *e) void mappingnotify(xcb_mapping_notify_event_t *e) { + struct ws_win *w; + int i, j, num_screens; + xcb_refresh_keyboard_mapping(syms, e); - if (e->request == XCB_MAPPING_KEYBOARD) + if (e->request == XCB_MAPPING_KEYBOARD) { grabkeys(); + + /* Regrab buttons on all managed windows. */ + num_screens = get_screen_count(); + for (i = 0; i < num_screens; i++) + for (j = 0; j < workspace_limit; j++) + TAILQ_FOREACH(w, &screens[i].ws[j].winlist, + entry) + grabbuttons(w); + } } void @@ -8934,6 +9026,10 @@ propertynotify(xcb_property_notify_event_t *e) focus_flush(); } } else if (e->state == XCB_PROPERTY_DELETE) { + /* Reload floating geometry in case region changed. */ + if (win->floating) + load_float_geom(win); + /* The window is no longer iconic, restack ws. */ if (focus_mode != SWM_FOCUS_FOLLOW) ws->focus_pending = get_focus_magic(win);