X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=spectrwm.c;h=b0835a7c765180f710c8025f705e46411b2b39fe;hb=b6d8befdac6e36080add4a17693fa3b4bf81ac66;hp=f47613465d6d8b9e6c1cda9c930dcbe7ba94b5a6;hpb=8d6f43bd88e79d5222889eb3f1a2f0ac25f1695b;p=spectrwm.git diff --git a/spectrwm.c b/spectrwm.c index f476134..b0835a7 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -279,7 +279,6 @@ volatile sig_atomic_t restart_wm = 0; xcb_timestamp_t last_event_time = 0; int outputs = 0; int other_wm; -int ss_enabled = 0; int xrandr_support; int xrandr_eventbase; unsigned int numlockmask = 0; @@ -348,11 +347,10 @@ double dialog_ratio = 0.6; char *bar_argv[] = { NULL, NULL }; int bar_pipe[2]; -unsigned char bar_ext[SWM_BAR_MAX]; +char bar_ext[SWM_BAR_MAX]; +char bar_ext_buf[SWM_BAR_MAX]; char bar_vertext[SWM_BAR_MAX]; int bar_version = 0; -sig_atomic_t bar_alarm = 0; -int bar_delay = 30; int bar_enabled = 1; int bar_border_width = 1; int bar_at_bottom = 0; @@ -494,6 +492,7 @@ struct workspace { int idx; /* workspace index */ char *name; /* workspace name */ int always_raise; /* raise windows on focus */ + int bar_enabled; /* bar visibility */ struct layout *cur_layout; /* current layout handlers */ struct ws_win *focus; /* may be NULL */ struct ws_win *focus_prev; /* may be NULL */ @@ -587,6 +586,8 @@ union arg { #define SWM_ARG_ID_MOVEDOWN (101) #define SWM_ARG_ID_MOVELEFT (102) #define SWM_ARG_ID_MOVERIGHT (103) +#define SWM_ARG_ID_BAR_TOGGLE (110) +#define SWM_ARG_ID_BAR_TOGGLE_WS (111) char **argv; }; @@ -712,6 +713,7 @@ struct spawn_list spawns = TAILQ_HEAD_INITIALIZER(spawns); /* user/key callable function IDs */ enum keyfuncid { KF_BAR_TOGGLE, + KF_BAR_TOGGLE_WS, KF_BUTTON2, KF_CYCLE_LAYOUT, KF_FLIP_LAYOUT, @@ -830,7 +832,6 @@ void bar_replace_pad(char *, int *, size_t); char * bar_replace_seq(char *, char *, struct swm_region *, size_t *, size_t); void bar_setup(struct swm_region *); -void bar_signal(int); void bar_title_name(char *, size_t, struct swm_region *); void bar_toggle(struct swm_region *, union arg *); void bar_update(void); @@ -871,7 +872,7 @@ char *expand_tilde(const char *); void expose(xcb_expose_event_t *); void fake_keypress(struct ws_win *, xcb_keysym_t, uint16_t); struct pid_e *find_pid(pid_t); -struct ws_win *find_unmanaged_window(xcb_window_t); +struct ws_win *find_unmanaged_window(xcb_window_t); struct ws_win *find_window(xcb_window_t); void floating_toggle(struct swm_region *, union arg *); int floating_toggle_win(struct ws_win *); @@ -1852,7 +1853,7 @@ bar_extra_stop(void) kill(bar_pid, SIGTERM); bar_pid = 0; } - strlcpy((char *)bar_ext, "", sizeof bar_ext); + strlcpy(bar_ext, "", sizeof bar_ext); bar_extra = 0; } @@ -2175,6 +2176,14 @@ bar_fmt_print(void) TAILQ_FOREACH(r, &screens[i].rl, entry) { if (r->bar == NULL) continue; + + if (r->ws->bar_enabled) + xcb_map_window(conn, r->bar->id); + else { + xcb_unmap_window(conn, r->bar->id); + continue; + } + bar_fmt(fmtexp, fmtnew, r, sizeof fmtnew); bar_replace(fmtnew, fmtrep, r, sizeof fmtrep); if (bar_font_legacy) @@ -2188,36 +2197,49 @@ bar_fmt_print(void) void bar_update(void) { - size_t len; - char *b; + size_t len; + char b[SWM_BAR_MAX]; - if (!bar_enabled) - return; - if (bar_extra && bar_extra_running) { - /* ignore short reads; it'll correct itself */ - while ((b = fgetln(stdin, &len)) != NULL) - if (b && b[len - 1] == '\n') { - b[len - 1] = '\0'; - strlcpy((char *)bar_ext, b, sizeof bar_ext); + if (bar_enabled && bar_extra && bar_extra_running) { + while (fgets(b, sizeof(b), stdin) != NULL) { + len = strlen(b); + if (b[len - 1] == '\n') { + /* Remove newline. */ + b[--len] = '\0'; + + /* "Clear" bar_ext. */ + bar_ext[0] = '\0'; + + /* Flush buffered output. */ + strlcpy(bar_ext, bar_ext_buf, sizeof(bar_ext)); + bar_ext_buf[0] = '\0'; + + /* Append new output to bar. */ + strlcat(bar_ext, b, sizeof(bar_ext)); + } else { + /* Buffer output. */ + strlcat(bar_ext_buf, b, sizeof(bar_ext_buf)); } - if (b == NULL && errno != EAGAIN) { + } + + if (errno != EAGAIN) { warn("bar_update: bar_extra failed"); bar_extra_stop(); } - } else - strlcpy((char *)bar_ext, "", sizeof bar_ext); + } else { + /* + * Attempt to drain stdin, so it doesn't cause the main loop to + * call us as fast as it can. + */ + fgets(b, sizeof(b), stdin); - bar_fmt_print(); - alarm(bar_delay); -} + if (!bar_enabled) + return; -void -bar_signal(int sig) -{ - /* suppress unused warning since var is needed */ - (void)sig; + bar_ext[0] = '\0'; + } - bar_alarm = 1; + bar_fmt_print(); } void @@ -2232,20 +2254,29 @@ bar_toggle(struct swm_region *r, union arg *args) DNPRINTF(SWM_D_BAR, "bar_toggle\n"); - num_screens = xcb_setup_roots_length(xcb_get_setup(conn)); - if (bar_enabled) { - for (i = 0; i < num_screens; i++) - TAILQ_FOREACH(tmpr, &screens[i].rl, entry) - if (tmpr->bar) - xcb_unmap_window(conn, tmpr->bar->id); - } else { - for (i = 0; i < num_screens; i++) - TAILQ_FOREACH(tmpr, &screens[i].rl, entry) - if (tmpr->bar) - xcb_map_window(conn, tmpr->bar->id); + switch (args->id) { + case SWM_ARG_ID_BAR_TOGGLE_WS: + /* Only change if master switch is enabled. */ + if (bar_enabled) + r->ws->bar_enabled = !r->ws->bar_enabled; + else + bar_enabled = r->ws->bar_enabled = 1; + break; + case SWM_ARG_ID_BAR_TOGGLE: + bar_enabled = !bar_enabled; + break; } - bar_enabled = !bar_enabled; + /* update bars as necessary */ + num_screens = xcb_setup_roots_length(xcb_get_setup(conn)); + for (i = 0; i < num_screens; i++) + TAILQ_FOREACH(tmpr, &screens[i].rl, entry) + if (tmpr->bar) { + if (bar_enabled && tmpr->ws->bar_enabled) + xcb_map_window(conn, tmpr->bar->id); + else + xcb_unmap_window(conn, tmpr->bar->id); + } stack(); @@ -2270,10 +2301,15 @@ bar_refresh(void) err(1, "pipe error"); socket_setnonblock(bar_pipe[0]); socket_setnonblock(bar_pipe[1]); /* XXX hmmm, really? */ + + /* Set stdin to read from the pipe. */ if (dup2(bar_pipe[0], 0) == -1) err(1, "dup2"); + + /* Set stdout to write to the pipe. */ if (dup2(bar_pipe[1], 1) == -1) err(1, "dup2"); + if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) err(1, "could not disable SIGPIPE"); switch (bar_pid = fork()) { @@ -2301,7 +2337,9 @@ bar_refresh(void) xcb_change_window_attributes(conn, r->bar->id, XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL, wa); } + bar_update(); + xcb_flush(conn); } int @@ -2405,7 +2443,7 @@ xft_init(struct swm_region *r) if (!XftColorAllocValue(display, DefaultVisual(display, r->s->idx), DefaultColormap(display, r->s->idx), &color, &bar_font_color)) - warn("unable to allocate Xft color"); + warn("Xft error: unable to allocate color."); bar_height = bar_font->height + 2 * bar_border_width; @@ -2467,8 +2505,6 @@ bar_setup(struct swm_region *r) "%d x %d\n", WINID(r->bar), X(r->bar), Y(r->bar), WIDTH(r->bar), HEIGHT(r->bar)); - if (signal(SIGALRM, bar_signal) == SIG_ERR) - err(1, "could not install bar_signal"); bar_refresh(); } @@ -2802,6 +2838,7 @@ get_pointer_win(xcb_window_t root) } else { DNPRINTF(SWM_D_EVENT, "get_pointer_win: none.\n"); } + free(r); } return win; @@ -3072,6 +3109,7 @@ unfocus_win(struct ws_win *win) kill_refs(win->ws->focus); win->ws->focus = NULL; } + if (validate_win(win->ws->focus_prev)) { kill_refs(win->ws->focus_prev); win->ws->focus_prev = NULL; @@ -3779,7 +3817,7 @@ stack(void) { g = r->g; g.w -= 2 * border_width; g.h -= 2 * border_width; - if (bar_enabled) { + if (bar_enabled && r->ws->bar_enabled) { if (!bar_at_bottom) g.y += bar_height; g.h -= bar_height; @@ -4072,7 +4110,8 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) else win_g.y += last_h + 2 * border_width; - if (disable_border && !bar_enabled && winno == 1){ + if (disable_border && !(bar_enabled && ws->bar_enabled) && + winno == 1){ bordered = 0; win_g.w += 2 * border_width; win_g.h += 2 * border_width; @@ -4289,7 +4328,7 @@ max_stack(struct workspace *ws, struct swm_geometry *g) if (X(w) != gg.x || Y(w) != gg.y || WIDTH(w) != gg.w || HEIGHT(w) != gg.h) { w->g = gg; - if (bar_enabled){ + if (bar_enabled && ws->bar_enabled){ w->bordered = 1; } else { w->bordered = 0; @@ -4488,24 +4527,28 @@ get_win_name(xcb_window_t win) XCB_GET_PROPERTY_TYPE_ANY, 0, UINT_MAX); r = xcb_get_property_reply(conn, c, NULL); - if (!r || r->type == XCB_NONE) { - free(r); - /* Use WM_NAME instead; no UTF-8. */ - c = xcb_get_property(conn, 0, win, XCB_ATOM_WM_NAME, - XCB_GET_PROPERTY_TYPE_ANY, 0, UINT_MAX); - r = xcb_get_property_reply(conn, c, NULL); - - if(!r || r->type == XCB_NONE) { + if (r) { + if (r->type == XCB_NONE) { free(r); - return NULL; + /* Use WM_NAME instead; no UTF-8. */ + c = xcb_get_property(conn, 0, win, XCB_ATOM_WM_NAME, + XCB_GET_PROPERTY_TYPE_ANY, 0, UINT_MAX); + r = xcb_get_property_reply(conn, c, NULL); + + if (!r) + return (NULL); + if (r->type == XCB_NONE) { + free(r); + return (NULL); + } } - } + if (r->length > 0) + name = strndup(xcb_get_property_value(r), + xcb_get_property_value_length(r)); - if (r->length > 0) - name = strndup(xcb_get_property_value(r), - xcb_get_property_value_length(r)); + free(r); + } - free(r); return (name); } @@ -5376,7 +5419,8 @@ struct keyfunc { union arg args; } keyfuncs[KF_INVALID + 1] = { /* name function argument */ - { "bar_toggle", bar_toggle, {0} }, + { "bar_toggle", bar_toggle, {.id = SWM_ARG_ID_BAR_TOGGLE} }, + { "bar_toggle_ws", bar_toggle, {.id = SWM_ARG_ID_BAR_TOGGLE_WS} }, { "button2", pressbutton, {2} }, { "cycle_layout", cycle_layout, {0} }, { "flip_layout", stack_config, {.id = SWM_ARG_ID_FLIPLAYOUT} }, @@ -5940,7 +5984,7 @@ setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid, return; } if (kfid == KF_INVALID) { - warnx("error: setkeybinding: cannot find mod/key combination"); + warnx("bind: Key combination already unbound."); DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n"); return; } @@ -6075,6 +6119,7 @@ setup_keys(void) setkeybinding(MODKEY_SHIFT, XK_F11, KF_MVWS_21, NULL); setkeybinding(MODKEY_SHIFT, XK_F12, KF_MVWS_22, NULL); setkeybinding(MODKEY, XK_b, KF_BAR_TOGGLE, NULL); + setkeybinding(MODKEY_SHIFT, XK_b, KF_BAR_TOGGLE_WS,NULL); setkeybinding(MODKEY, XK_Tab, KF_FOCUS_NEXT, NULL); setkeybinding(MODKEY_SHIFT, XK_Tab, KF_FOCUS_PREV, NULL); setkeybinding(MODKEY_SHIFT, XK_x, KF_WIND_KILL, NULL); @@ -6177,7 +6222,7 @@ grabkeys(void) { struct key *kp; int num_screens, k, j; - unsigned int modifiers[3]; + unsigned int modifiers[4]; xcb_keycode_t *code; DNPRINTF(SWM_D_MISC, "grabkeys\n"); @@ -6185,7 +6230,8 @@ grabkeys(void) modifiers[0] = 0; modifiers[1] = numlockmask; - modifiers[2] = numlockmask | XCB_MOD_MASK_LOCK; + modifiers[2] = XCB_MOD_MASK_LOCK; + modifiers[3] = numlockmask | XCB_MOD_MASK_LOCK; num_screens = xcb_setup_roots_length(xcb_get_setup(conn)); for (k = 0; k < num_screens; k++) { @@ -6211,16 +6257,25 @@ grabkeys(void) void grabbuttons(struct ws_win *win) { - int i; + unsigned int modifiers[4]; + int i, j; DNPRINTF(SWM_D_MOUSE, "grabbuttons: win 0x%x\n", win->id); + updatenumlockmask(); + + modifiers[0] = 0; + modifiers[1] = numlockmask; + modifiers[2] = XCB_MOD_MASK_LOCK; + modifiers[3] = numlockmask | XCB_MOD_MASK_LOCK; for (i = 0; i < LENGTH(buttons); i++) if (buttons[i].action == client_click) - xcb_grab_button(conn, 0, win->id, BUTTONMASK, - XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, - XCB_WINDOW_NONE, XCB_CURSOR_NONE, - buttons[i].button, buttons[i].mask); + for (j = 0; j < LENGTH(modifiers); ++j) + xcb_grab_button(conn, 0, win->id, BUTTONMASK, + XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, + XCB_WINDOW_NONE, XCB_CURSOR_NONE, + buttons[i].button, buttons[i].mask | + modifiers[j]); } const char *quirkname[] = { @@ -6395,6 +6450,7 @@ enum { SWM_S_BAR_BORDER_WIDTH, SWM_S_BAR_DELAY, SWM_S_BAR_ENABLED, + SWM_S_BAR_ENABLED_WS, SWM_S_BAR_FONT, SWM_S_BAR_FORMAT, SWM_S_BAR_JUSTIFY, @@ -6426,8 +6482,9 @@ enum { int setconfvalue(char *selector, char *value, int flags) { - int i; - char *b; + struct workspace *ws; + int i, ws_id, num_screens; + char *b; /* suppress unused warning since var is needed */ (void)selector; @@ -6447,11 +6504,23 @@ setconfvalue(char *selector, char *value, int flags) bar_border_width = 0; break; case SWM_S_BAR_DELAY: - bar_delay = atoi(value); + /* No longer needed; leave to not break old conf files. */ break; case SWM_S_BAR_ENABLED: bar_enabled = atoi(value); break; + case SWM_S_BAR_ENABLED_WS: + ws_id = atoi(selector) - 1; + if (ws_id < 0 || ws_id >= workspace_limit) + errx(1, "setconfvalue: bar_enabled_ws: invalid " + "workspace %d.", ws_id + 1); + + num_screens = xcb_setup_roots_length(xcb_get_setup(conn)); + for (i = 0; i < num_screens; i++) { + ws = (struct workspace *)&screens[i].ws; + ws[ws_id].bar_enabled = atoi(value); + } + break; case SWM_S_BAR_FONT: b = bar_fonts; if (asprintf(&bar_fonts, "%s,%s", value, bar_fonts) == -1) @@ -6568,9 +6637,10 @@ setconfvalue(char *selector, char *value, int flags) setconfspawn("spawn_term", value, 0); break; case SWM_S_SS_APP: + /* No longer needed; leave to not break old conf files. */ break; case SWM_S_SS_ENABLED: - ss_enabled = atoi(value); + /* No longer needed; leave to not break old conf files. */ break; case SWM_S_STACK_ENABLED: stack_enabled = atoi(value); @@ -6817,6 +6887,7 @@ struct config_option { }; struct config_option configopt[] = { { "bar_enabled", setconfvalue, SWM_S_BAR_ENABLED }, + { "bar_enabled_ws", setconfvalue, SWM_S_BAR_ENABLED_WS }, { "bar_at_bottom", setconfvalue, SWM_S_BAR_AT_BOTTOM }, { "bar_border", setconfcolor, SWM_S_COLOR_BAR_BORDER }, { "bar_border_width", setconfvalue, SWM_S_BAR_BORDER_WIDTH }, @@ -7442,7 +7513,13 @@ buttonpress(xcb_button_press_event_t *e) /* Focus on empty region */ /* If no windows on region if its empty. */ r = root_to_region(e->root, SWM_CK_POINTER); - if (r && TAILQ_EMPTY(&r->ws->winlist)) { + if (r == NULL) { + DNPRINTF(SWM_D_EVENT, "buttonpress: " + "NULL region; ignoring.\n"); + goto out; + } + + if (TAILQ_EMPTY(&r->ws->winlist)) { old_r = root_to_region(e->root, SWM_CK_FOCUS); if (old_r && old_r != r) unfocus_win(old_r->ws->focus); @@ -7462,7 +7539,7 @@ buttonpress(xcb_button_press_event_t *e) } if (win == NULL) - return; + goto out; last_event_time = e->time; @@ -7651,9 +7728,10 @@ configurerequest(xcb_configure_request_event_t *e) WIDTH(win) = win->g_float.w; HEIGHT(win) = win->g_float.h; - stack_floater(win, win->ws->r); - - focus_flush(); + if (r) { + stack_floater(win, r); + focus_flush(); + } } else { config_win(win, e); xcb_flush(conn); @@ -7816,6 +7894,12 @@ enternotify(xcb_enter_notify_event_t *e) if (e->event == e->root) { /* If no windows on pointer region, then focus root. */ r = root_to_region(e->root, SWM_CK_POINTER); + if (r == NULL) { + DNPRINTF(SWM_D_EVENT, "enterntoify: " + "NULL region; ignoring.\n"); + return; + } + if (TAILQ_EMPTY(&r->ws->winlist)) { old_r = root_to_region(e->root, SWM_CK_FOCUS); if (old_r && old_r != r) @@ -8576,6 +8660,7 @@ setup_screens(void) ws = &screens[i].ws[j]; ws->idx = j; ws->name = NULL; + ws->bar_enabled = 1; ws->focus = NULL; ws->focus_prev = NULL; ws->focus_pending = NULL; @@ -8769,6 +8854,9 @@ main(int argc, char *argv[]) xcb_generic_event_t *evt; struct timeval tv; fd_set rd; + int rd_max; + int do_bar_update = 0; + int num_readable; /* suppress unused warning since var is needed */ (void)argc; @@ -8899,6 +8987,8 @@ noconfig: xcb_ungrab_server(conn); xcb_flush(conn); + rd_max = xfd > STDIN_FILENO ? xfd : STDIN_FILENO; + while (running) { while ((evt = xcb_poll_for_event(conn))) { if (!running) @@ -8923,22 +9013,29 @@ noconfig: } FD_ZERO(&rd); + FD_SET(STDIN_FILENO, &rd); FD_SET(xfd, &rd); tv.tv_sec = 1; tv.tv_usec = 0; - if (select(xfd + 1, &rd, NULL, NULL, &tv) == -1) - if (errno != EINTR) { - DNPRINTF(SWM_D_MISC, "select failed"); - } + num_readable = select(rd_max + 1, &rd, NULL, NULL, &tv); + if (num_readable == -1 && errno != EINTR) + DNPRINTF(SWM_D_MISC, "select failed"); + else if (num_readable > 0 && FD_ISSET(STDIN_FILENO, &rd)) + do_bar_update = 1; + if (restart_wm) restart(NULL, NULL); + if (search_resp) search_do_resp(); + if (!running) goto done; - if (bar_alarm) { - bar_alarm = 0; + + if (do_bar_update) { + do_bar_update = 0; bar_update(); + xcb_flush(conn); } } done: