]> code.delx.au - spectrwm/blobdiff - scrotwm.c
Fix setting of window property strings to use actual number of
[spectrwm] / scrotwm.c
index 3ea31dbacbcd99da8f58357988fba550d456c33d..cd8b68a3535118b240e9631aed16cbf6b515730e 100644 (file)
--- a/scrotwm.c
+++ b/scrotwm.c
 #include <sys/queue.h>
 #include <sys/param.h>
 #include <sys/select.h>
+#if defined(__linux__)
+#include "tree.h"
+#elif defined(__OpenBSD__)
+#include <sys/tree.h>
+#elif defined(__FreeBSD__)
+#include <sys/tree.h>
+#else
+#include <sys/tree.h>
+#endif
 
 #include <X11/cursorfont.h>
 #include <X11/keysym.h>
@@ -110,15 +119,15 @@ static const char *buildstr = SCROTWM_VERSION;
 #ifdef SWM_DEBUG
 #define DPRINTF(x...)          do { if (swm_debug) fprintf(stderr, x); } while (0)
 #define DNPRINTF(n,x...)       do { if (swm_debug & n) fprintf(stderr, x); } while (0)
-#define        SWM_D_MISC              0x0001
-#define        SWM_D_EVENT             0x0002
-#define        SWM_D_WS                0x0004
-#define        SWM_D_FOCUS             0x0008
-#define        SWM_D_MOVE              0x0010
-#define        SWM_D_STACK             0x0020
-#define        SWM_D_MOUSE             0x0040
-#define        SWM_D_PROP              0x0080
-#define        SWM_D_CLASS             0x0100
+#define SWM_D_MISC             0x0001
+#define SWM_D_EVENT            0x0002
+#define SWM_D_WS               0x0004
+#define SWM_D_FOCUS            0x0008
+#define SWM_D_MOVE             0x0010
+#define SWM_D_STACK            0x0020
+#define SWM_D_MOUSE            0x0040
+#define SWM_D_PROP             0x0080
+#define SWM_D_CLASS            0x0100
 #define SWM_D_KEY              0x0200
 #define SWM_D_QUIRK            0x0400
 #define SWM_D_SPAWN            0x0800
@@ -423,9 +432,11 @@ struct workspace {
                                int horizontal_msize;
                                int horizontal_mwin;
                                int horizontal_stacks;
+                               int horizontal_flip;
                                int vertical_msize;
                                int vertical_mwin;
                                int vertical_stacks;
+                               int vertical_flip;
        } l_state;
 };
 
@@ -467,6 +478,7 @@ union arg {
 #define SWM_ARG_ID_MASTERGROW  (21)
 #define SWM_ARG_ID_MASTERADD   (22)
 #define SWM_ARG_ID_MASTERDEL   (23)
+#define SWM_ARG_ID_FLIPLAYOUT  (24)
 #define SWM_ARG_ID_STACKRESET  (30)
 #define SWM_ARG_ID_STACKINIT   (31)
 #define SWM_ARG_ID_CYCLEWS_UP  (40)
@@ -1215,10 +1227,12 @@ fancy_stacker(struct workspace *ws)
 {
        strlcpy(ws->stacker, "[   ]", sizeof ws->stacker);
        if (ws->cur_layout->l_stack == vertical_stack)
-               snprintf(ws->stacker, sizeof ws->stacker, "[%d|%d]",
+               snprintf(ws->stacker, sizeof ws->stacker,
+                   ws->l_state.vertical_flip ? "[%d>%d]" : "[%d|%d]",
                    ws->l_state.vertical_mwin, ws->l_state.vertical_stacks);
        if (ws->cur_layout->l_stack == horizontal_stack)
-               snprintf(ws->stacker, sizeof ws->stacker, "[%d-%d]",
+               snprintf(ws->stacker, sizeof ws->stacker,
+                   ws->l_state.horizontal_flip ? "[%dv%d]" : "[%d-%d]",
                    ws->l_state.horizontal_mwin, ws->l_state.horizontal_stacks);
 }
 
@@ -1227,9 +1241,11 @@ plain_stacker(struct workspace *ws)
 {
        strlcpy(ws->stacker, "[ ]", sizeof ws->stacker);
        if (ws->cur_layout->l_stack == vertical_stack)
-               strlcpy(ws->stacker, "[|]", sizeof ws->stacker);
+               strlcpy(ws->stacker, ws->l_state.vertical_flip ? "[>]" : "[|]",
+                   sizeof ws->stacker);
        if (ws->cur_layout->l_stack == horizontal_stack)
-               strlcpy(ws->stacker, "[-]", sizeof ws->stacker);
+               strlcpy(ws->stacker, ws->l_state.horizontal_flip ? "[v]" : "[-]",
+                   sizeof ws->stacker);
 }
 
 void
@@ -1301,7 +1317,7 @@ bar_print(struct swm_region *r, char *s)
                x = SWM_BAR_OFFSET;
 
        DRAWSTRING(display, r->bar_window, bar_fs, r->s->bar_gc,
-           x, (bar_fs_extents->max_logical_extent.height - lbox.height) / 2 - 
+           x, (bar_fs_extents->max_logical_extent.height - lbox.height) / 2 -
            lbox.y, s, len);
 }
 
@@ -1477,6 +1493,13 @@ bar_update(void)
        alarm(bar_delay);
 }
 
+void
+bar_check_opts(void)
+{
+       if (title_class_enabled || title_name_enabled || window_name_enabled)
+               bar_update();
+}
+
 void
 bar_signal(int sig)
 {
@@ -2208,8 +2231,7 @@ focus_win(struct ws_win *win)
                    PropModeReplace, (unsigned char *)&win->id,1);
        }
 
-       if (window_name_enabled || title_class_enabled || title_name_enabled)
-               bar_update();
+       bar_check_opts();
 }
 
 void
@@ -2474,7 +2496,7 @@ swapwin(struct swm_region *r, union arg *args)
 void
 focus_prev(struct ws_win *win)
 {
-       struct ws_win           *winfocus = NULL, *winlostfocus = NULL;
+       struct ws_win           *winfocus = NULL;
        struct ws_win           *cur_focus = NULL;
        struct ws_win_list      *wl = NULL;
        struct workspace        *ws = NULL;
@@ -2487,7 +2509,6 @@ focus_prev(struct ws_win *win)
        ws = win->ws;
        wl = &ws->winlist;
        cur_focus = ws->focus;
-       winlostfocus = cur_focus;
 
        /* pickle, just focus on whatever */
        if (cur_focus == NULL) {
@@ -2525,22 +2546,15 @@ focus_prev(struct ws_win *win)
                winfocus = TAILQ_LAST(wl, ws_win_list);
        if (winfocus == NULL || winfocus == win)
                winfocus = TAILQ_NEXT(cur_focus, entry);
-done:
-       if (winfocus == winlostfocus || winfocus == NULL) {
-               /* update the bar so that title/class/name will be cleared. */
-               if (window_name_enabled || title_name_enabled ||
-                   title_class_enabled)
-                       bar_update();
-               return;
-       }
 
+done:
        focus_magic(winfocus);
 }
 
 void
 focus(struct swm_region *r, union arg *args)
 {
-       struct ws_win           *winfocus = NULL, *winlostfocus = NULL, *head;
+       struct ws_win           *winfocus = NULL, *head;
        struct ws_win           *cur_focus = NULL;
        struct ws_win_list      *wl = NULL;
        struct workspace        *ws = NULL;
@@ -2582,8 +2596,6 @@ focus(struct swm_region *r, union arg *args)
        if (all_iconics)
                return;
 
-       winlostfocus = cur_focus;
-
        switch (args->id) {
        case SWM_ARG_ID_FOCUSPREV:
                head = TAILQ_PREV(cur_focus, ws_win_list, entry);
@@ -2637,14 +2649,6 @@ focus(struct swm_region *r, union arg *args)
        default:
                return;
        }
-       if (winfocus == winlostfocus || winfocus == NULL) {
-               /* update the bar so that title/class/name will be cleared. */
-               if (window_name_enabled || title_name_enabled ||
-                   title_class_enabled)
-                       bar_update();
-
-               return;
-       }
 
        focus_magic(winfocus);
 }
@@ -3091,6 +3095,9 @@ vertical_config(struct workspace *ws, int id)
                if (ws->l_state.vertical_stacks > 1)
                        ws->l_state.vertical_stacks--;
                break;
+       case SWM_ARG_ID_FLIPLAYOUT:
+               ws->l_state.vertical_flip = !ws->l_state.vertical_flip;
+               break;
        default:
                return;
        }
@@ -3101,7 +3108,7 @@ vertical_stack(struct workspace *ws, struct swm_geometry *g)
 {
        DNPRINTF(SWM_D_STACK, "vertical_stack: workspace: %d\n", ws->idx);
 
-       stack_master(ws, g, 0, 0);
+       stack_master(ws, g, 0, ws->l_state.vertical_flip);
 }
 
 void
@@ -3138,6 +3145,9 @@ horizontal_config(struct workspace *ws, int id)
                if (ws->l_state.horizontal_stacks > 1)
                        ws->l_state.horizontal_stacks--;
                break;
+       case SWM_ARG_ID_FLIPLAYOUT:
+               ws->l_state.horizontal_flip = !ws->l_state.horizontal_flip;
+               break;
        default:
                return;
        }
@@ -3148,7 +3158,7 @@ horizontal_stack(struct workspace *ws, struct swm_geometry *g)
 {
        DNPRINTF(SWM_D_STACK, "horizontal_stack: workspace: %d\n", ws->idx);
 
-       stack_master(ws, g, 1, 0);
+       stack_master(ws, g, 1, ws->l_state.horizontal_flip);
 }
 
 /* fullscreen view */
@@ -3270,7 +3280,7 @@ send_to_ws(struct swm_region *r, union arg *args)
                DNPRINTF(SWM_D_PROP, "send_to_ws: set property: _SWM_WS: %s\n",
                    ws_idx_str);
                XChangeProperty(display, win->id, ws_idx_atom, XA_STRING, 8,
-                   PropModeReplace, ws_idx_str, SWM_PROPLEN);
+                   PropModeReplace, ws_idx_str, strlen((char *)ws_idx_str));
        }
 
        stack();
@@ -3963,7 +3973,7 @@ resize(struct ws_win *win, union arg *args)
                        }
 
                        /* horizontal */
-                       if (left) 
+                       if (left)
                                dx = -dx;
 
                        if (args->id == SWM_ARG_ID_CENTER) {
@@ -4147,6 +4157,7 @@ move_step(struct swm_region *r, union arg *args)
 /* user/key callable function IDs */
 enum keyfuncid {
        kf_cycle_layout,
+       kf_flip_layout,
        kf_stack_reset,
        kf_master_shrink,
        kf_master_grow,
@@ -4238,6 +4249,7 @@ struct keyfunc {
 } keyfuncs[kf_invalid + 1] = {
        /* name                 function        argument */
        { "cycle_layout",       cycle_layout,   {0} },
+       { "flip_layout",        stack_config,   {.id = SWM_ARG_ID_FLIPLAYOUT} },
        { "stack_reset",        stack_config,   {.id = SWM_ARG_ID_STACKRESET} },
        { "master_shrink",      stack_config,   {.id = SWM_ARG_ID_MASTERSHRINK} },
        { "master_grow",        stack_config,   {.id = SWM_ARG_ID_MASTERGROW} },
@@ -4311,14 +4323,32 @@ struct keyfunc {
        { "invalid key func",   NULL,           {0} },
 };
 struct key {
-       TAILQ_ENTRY(key)        entry;
+       RB_ENTRY(key)           entry;
        unsigned int            mod;
        KeySym                  keysym;
        enum keyfuncid          funcid;
        char                    *spawn_name;
 };
-TAILQ_HEAD(key_list, key);
-struct key_list                        keys = TAILQ_HEAD_INITIALIZER(keys);
+RB_HEAD(key_list, key);
+
+int
+key_cmp(struct key *kp1, struct key *kp2)
+{
+       if (kp1->keysym < kp2->keysym)
+               return (-1);
+       if (kp1->keysym > kp2->keysym)
+               return (1);
+
+       if (kp1->mod < kp2->mod)
+               return (-1);
+       if (kp1->mod > kp2->mod)
+               return (1);
+
+       return (0);
+}
+
+RB_GENERATE_STATIC(key_list, key, entry, key_cmp);
+struct key_list                        keys;
 
 /* mouse */
 enum { client_click, root_click };
@@ -4342,7 +4372,7 @@ update_modkey(unsigned int mod)
        struct key              *kp;
 
        mod_key = mod;
-       TAILQ_FOREACH(kp, &keys, entry)
+       RB_FOREACH(kp, key_list, &keys)
                if (kp->mod & ShiftMask)
                        kp->mod = mod | ShiftMask;
                else
@@ -4710,17 +4740,28 @@ key_insert(unsigned int mod, KeySym ks, enum keyfuncid kfid, char *spawn_name)
        kp->keysym = ks;
        kp->funcid = kfid;
        kp->spawn_name = strdupsafe(spawn_name);
-       TAILQ_INSERT_TAIL(&keys, kp, entry);
+       RB_INSERT(key_list, &keys, kp);
 
        DNPRINTF(SWM_D_KEY, "key_insert: leave\n");
 }
 
+struct key *
+key_lookup(unsigned int mod, KeySym ks)
+{
+       struct key              kp;
+
+       kp.keysym = ks;
+       kp.mod = mod;
+
+       return (RB_FIND(key_list, &keys, &kp));
+}
+
 void
 key_remove(struct key *kp)
 {
        DNPRINTF(SWM_D_KEY, "key_remove: %s\n", keyfuncs[kp->funcid].name);
 
-       TAILQ_REMOVE(&keys, kp, entry);
+       RB_REMOVE(key_list, &keys, kp);
        free(kp->spawn_name);
        free(kp);
 
@@ -4749,15 +4790,13 @@ setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid,
        DNPRINTF(SWM_D_KEY, "setkeybinding: enter %s [%s]\n",
            keyfuncs[kfid].name, spawn_name);
 
-       TAILQ_FOREACH(kp, &keys, entry) {
-               if (kp->mod == mod && kp->keysym == ks) {
-                       if (kfid == kf_invalid)
-                               key_remove(kp);
-                       else
-                               key_replace(kp, mod, ks, kfid, spawn_name);
-                       DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n");
-                       return;
-               }
+       if ((kp = key_lookup(mod, ks)) != NULL) {
+               if (kfid == kf_invalid)
+                       key_remove(kp);
+               else
+                       key_replace(kp, mod, ks, kfid, spawn_name);
+               DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n");
+               return;
        }
        if (kfid == kf_invalid) {
                warnx("error: setkeybinding: cannot find mod/key combination");
@@ -4820,6 +4859,7 @@ void
 setup_keys(void)
 {
        setkeybinding(MODKEY,           XK_space,       kf_cycle_layout,NULL);
+       setkeybinding(MODKEY|ShiftMask, XK_backslash,   kf_flip_layout, NULL);
        setkeybinding(MODKEY|ShiftMask, XK_space,       kf_stack_reset, NULL);
        setkeybinding(MODKEY,           XK_h,           kf_master_shrink,NULL);
        setkeybinding(MODKEY,           XK_l,           kf_master_grow, NULL);
@@ -4898,13 +4938,11 @@ setup_keys(void)
 void
 clear_keys(void)
 {
-       struct key              *kp_loop, *kp_next;
+       struct key              *kp;
 
-       kp_loop = TAILQ_FIRST(&keys);
-       while (kp_loop != NULL) {
-               kp_next = TAILQ_NEXT(kp_loop, entry);
-               key_remove(kp_loop);
-               kp_loop = kp_next;
+       while (RB_EMPTY(&keys) == 0) {
+               kp = RB_ROOT(&keys);
+               key_remove(kp);
        }
 }
 
@@ -4962,7 +5000,7 @@ grabkeys(void)
                if (TAILQ_EMPTY(&screens[k].rl))
                        continue;
                XUngrabKey(display, AnyKey, AnyModifier, screens[k].root);
-               TAILQ_FOREACH(kp, &keys, entry) {
+               RB_FOREACH(kp, key_list, &keys) {
                        if ((code = XKeysymToKeycode(display, kp->keysym)))
                                for (j = 0; j < LENGTH(modifiers); j++)
                                        XGrabKey(display, code,
@@ -5840,7 +5878,7 @@ manage_window(Window id)
                DNPRINTF(SWM_D_PROP, "manage_window: set _SWM_WS: %s\n",
                    ws_idx_str);
                XChangeProperty(display, win->id, ws_idx_atom, XA_STRING, 8,
-                   PropModeReplace, ws_idx_str, SWM_PROPLEN);
+                   PropModeReplace, ws_idx_str, strlen((char *)ws_idx_str));
        }
        if (prop)
                XFree(prop);
@@ -5981,8 +6019,11 @@ focus_magic(struct ws_win *win)
 {
        DNPRINTF(SWM_D_FOCUS, "focus_magic: window: 0x%lx\n", WINID(win));
 
-       if (win == NULL)
+       if (win == NULL) {
+               /* if there are no windows clear the status-bar */
+               bar_check_opts();
                return;
+       }
 
        if (win->child_trans) {
                /* win = parent & has a transient so focus on that */
@@ -5991,7 +6032,7 @@ focus_magic(struct ws_win *win)
                        if (win->child_trans->take_focus)
                                client_msg(win, takefocus);
                } else {
-                       /* make sure transient hasn't dissapeared */
+                       /* make sure transient hasn't disappeared */
                        if (validate_win(win->child_trans) == 0) {
                                focus_win(win->child_trans);
                                if (win->child_trans->take_focus)
@@ -6023,24 +6064,19 @@ keypress(XEvent *e)
        KeySym                  keysym;
        XKeyEvent               *ev = &e->xkey;
        struct key              *kp;
+       struct swm_region       *r;
 
        keysym = XKeycodeToKeysym(display, (KeyCode)ev->keycode, 0);
-       TAILQ_FOREACH(kp, &keys, entry)
-               if (keysym == kp->keysym
-                   && CLEANMASK(kp->mod) == CLEANMASK(ev->state)
-                   && keyfuncs[kp->funcid].func) {
-                       if (kp->funcid == kf_spawn_custom)
-                               spawn_custom(
-                                   root_to_region(ev->root),
-                                   &(keyfuncs[kp->funcid].args),
-                                   kp->spawn_name
-                                   );
-                       else
-                               keyfuncs[kp->funcid].func(
-                                   root_to_region(ev->root),
-                                   &(keyfuncs[kp->funcid].args)
-                                   );
-               }
+       if ((kp = key_lookup(CLEANMASK(ev->state), keysym)) == NULL)
+               return;
+       if (keyfuncs[kp->funcid].func == NULL)
+               return;
+
+       r = root_to_region(ev->root);
+       if (kp->funcid == kf_spawn_custom)
+               spawn_custom(r, &(keyfuncs[kp->funcid].args), kp->spawn_name);
+       else
+               keyfuncs[kp->funcid].func(r, &(keyfuncs[kp->funcid].args));
 }
 
 void