]> code.delx.au - spectrwm/blobdiff - spectrwm.c
Add new quirk IGNORESPAWNWS.
[spectrwm] / spectrwm.c
index 3719d0d965a27ca9364eafe7074e4997f94e43d2..03f5fdd58c8adcafeab4df86d8d43e16940ea2da 100644 (file)
@@ -671,6 +671,8 @@ struct quirk {
 #define SWM_Q_NOFOCUSONMAP     (1<<6)  /* Don't focus on window when mapped. */
 #define SWM_Q_FOCUSONMAP_SINGLE        (1<<7)  /* Only focus if single win of type. */
 #define SWM_Q_OBEYAPPFOCUSREQ  (1<<8)  /* Focus when applications ask. */
+#define SWM_Q_IGNOREPID                (1<<9)  /* Ignore PID when determining ws. */
+#define SWM_Q_IGNORESPAWNWS    (1<<10) /* Ignore _SWM_WS when managing win. */
 };
 TAILQ_HEAD(quirk_list, quirk);
 struct quirk_list              quirks = TAILQ_HEAD_INITIALIZER(quirks);
@@ -1037,7 +1039,7 @@ int32_t    get_swm_ws(xcb_window_t);
 char   *get_win_name(xcb_window_t);
 uint8_t         get_win_state(xcb_window_t);
 void    get_wm_protocols(struct ws_win *);
-int     get_ws_idx(xcb_window_t);
+int     get_ws_idx(struct ws_win *);
 void    grabbuttons(struct ws_win *);
 void    grabkeys(void);
 void    grab_windows(void);
@@ -3490,7 +3492,7 @@ unfocus_win(struct ws_win *win)
 void
 focus_win(struct ws_win *win)
 {
-       struct ws_win                   *cfw = NULL, *parent = NULL, *w;
+       struct ws_win                   *cfw = NULL, *parent = NULL, *w, *tmpw;
        struct workspace                *ws;
        xcb_get_input_focus_reply_t     *gifr;
 
@@ -3573,20 +3575,25 @@ focus_win(struct ws_win *win)
                                map_window(parent);
 
                                /* Map siblings next. */
-                               TAILQ_FOREACH(w, &ws->winlist, entry)
+                               TAILQ_FOREACH_SAFE(w, &ws->stack, stack_entry,
+                                   tmpw)
                                        if (w != win && !ICONIC(w) &&
-                                           win->transient == parent->id)
+                                           w->transient == parent->id) {
+                                               raise_window(w);
                                                map_window(w);
+                                       }
                        }
 
                        /* Map focused window. */
                        raise_window(win);
                        map_window(win);
 
-                       /* Finally, map children of focus window. */
-                       TAILQ_FOREACH(w, &ws->winlist, entry)
-                               if (w->transient == win->id && !ICONIC(w))
+                       /* Stack any children of focus window. */
+                       TAILQ_FOREACH_SAFE(w, &ws->stack, stack_entry, tmpw)
+                               if (w->transient == win->id && !ICONIC(w)) {
+                                       raise_window(w);
                                        map_window(w);
+                               }
                } else if (tile_gap < 0 && !ABOVE(win)) {
                        /*
                         * Windows overlap in the layout.
@@ -4238,17 +4245,21 @@ focus(struct swm_region *r, union arg *args)
        if (!(r && r->ws))
                goto out;
 
-       DNPRINTF(SWM_D_FOCUS, "focus: id: %d\n", args->id);
-
        cur_focus = r->ws->focus;
        ws = r->ws;
        wl = &ws->winlist;
 
+       DNPRINTF(SWM_D_FOCUS, "focus: id: %d, cur_focus: %#x\n", args->id,
+           WINID(cur_focus));
+
        /* Make sure an uniconified window has focus, if one exists. */
        if (cur_focus == NULL) {
                cur_focus = TAILQ_FIRST(wl);
                while (cur_focus != NULL && ICONIC(cur_focus))
                        cur_focus = TAILQ_NEXT(cur_focus, entry);
+
+               DNPRINTF(SWM_D_FOCUS, "focus: new cur_focus: %#x\n",
+                   WINID(cur_focus));
        }
 
        switch (args->id) {
@@ -4263,8 +4274,10 @@ focus(struct swm_region *r, union arg *args)
                                winfocus = TAILQ_LAST(wl, ws_win_list);
                        if (winfocus == cur_focus)
                                break;
-               } while (winfocus != NULL &&
-                   (ICONIC(winfocus) || winfocus->id == cur_focus->transient));
+               } while (winfocus && (ICONIC(winfocus) ||
+                   winfocus->id == cur_focus->transient ||
+                   (cur_focus->transient != XCB_WINDOW_NONE &&
+                   winfocus->transient == cur_focus->transient)));
                break;
        case SWM_ARG_ID_FOCUSNEXT:
                if (cur_focus == NULL)
@@ -4277,8 +4290,10 @@ focus(struct swm_region *r, union arg *args)
                                winfocus = TAILQ_FIRST(wl);
                        if (winfocus == cur_focus)
                                break;
-               } while (winfocus != NULL &&
-                   (ICONIC(winfocus) || winfocus->id == cur_focus->transient));
+               } while (winfocus && (ICONIC(winfocus) ||
+                   winfocus->id == cur_focus->transient ||
+                   (cur_focus->transient != XCB_WINDOW_NONE &&
+                   winfocus->transient == cur_focus->transient)));
                break;
        case SWM_ARG_ID_FOCUSMAIN:
                if (cur_focus == NULL)
@@ -4904,7 +4919,7 @@ void
 max_stack(struct workspace *ws, struct swm_geometry *g)
 {
        struct swm_geometry     gg = *g;
-       struct ws_win           *w, *win = NULL, *parent = NULL;
+       struct ws_win           *w, *win = NULL, *parent = NULL, *tmpw;
        int                     winno;
 
        DNPRINTF(SWM_D_STACK, "max_stack: workspace: %d\n", ws->idx);
@@ -4967,17 +4982,20 @@ max_stack(struct workspace *ws, struct swm_geometry *g)
                }
        }
 
+       /* If transient, stack parent and its children. */
        if (TRANS(win) && (parent = find_window(win->transient))) {
                raise_window(parent);
 
-               TAILQ_FOREACH(w, &ws->stack, stack_entry)
+               TAILQ_FOREACH_SAFE(w, &ws->stack, stack_entry, tmpw)
                        if (w->transient == parent->id)
                                raise_window(w);
        }
 
+       /* Make sure focus window is on top. */
        raise_window(win);
 
-       TAILQ_FOREACH(w, &ws->stack, stack_entry)
+       /* Stack any children of focus window. */
+       TAILQ_FOREACH_SAFE(w, &ws->stack, stack_entry, tmpw)
                if (w->transient == win->id)
                        raise_window(w);
 
@@ -7534,6 +7552,8 @@ const char *quirkname[] = {
        "NOFOCUSONMAP",
        "FOCUSONMAP_SINGLE",
        "OBEYAPPFOCUSREQ",
+       "IGNOREPID",
+       "IGNORESPAWNWS",
 };
 
 /* SWM_Q_WS: retain '|' for back compat for now (2009-08-11) */
@@ -8295,32 +8315,26 @@ setlayout(const char *selector, const char *value, int flags)
                        ws[ws_id].cur_layout->l_config(&ws[ws_id],
                            mg >= 0 ?  SWM_ARG_ID_MASTERGROW :
                            SWM_ARG_ID_MASTERSHRINK);
-                       stack();
                }
                /* master add */
                for (x = 0; x < abs(ma); x++) {
                        ws[ws_id].cur_layout->l_config(&ws[ws_id],
                            ma >= 0 ?  SWM_ARG_ID_MASTERADD :
                            SWM_ARG_ID_MASTERDEL);
-                       stack();
                }
                /* stack inc */
                for (x = 0; x < abs(si); x++) {
                        ws[ws_id].cur_layout->l_config(&ws[ws_id],
                            si >= 0 ?  SWM_ARG_ID_STACKINC :
                            SWM_ARG_ID_STACKDEC);
-                       stack();
                }
                /* Apply flip */
                if (f) {
                        ws[ws_id].cur_layout->l_config(&ws[ws_id],
                            SWM_ARG_ID_FLIPLAYOUT);
-                       stack();
                }
        }
 
-       focus_flush();
-
        return (0);
 }
 
@@ -8662,13 +8676,16 @@ get_swm_ws(xcb_window_t id)
 }
 
 int
-get_ws_idx(xcb_window_t id)
+get_ws_idx(struct ws_win *win)
 {
        xcb_get_property_reply_t        *gpr;
        int                     ws_idx = -1;
 
+       if (win == NULL)
+               return -1;
+
        gpr = xcb_get_property_reply(conn,
-               xcb_get_property(conn, 0, id, ewmh[_NET_WM_DESKTOP].atom,
+               xcb_get_property(conn, 0, win->id, ewmh[_NET_WM_DESKTOP].atom,
                    XCB_ATOM_CARDINAL, 0, 1),
                NULL);
        if (gpr) {
@@ -8677,14 +8694,14 @@ get_ws_idx(xcb_window_t id)
                free(gpr);
        }
 
-       if (ws_idx == -1)
-               if ((ws_idx = get_swm_ws(id)) != -1)
-                       xcb_delete_property(conn, id, a_swm_ws);
+       if (ws_idx == -1 && !(win->quirks & SWM_Q_IGNORESPAWNWS))
+               ws_idx = get_swm_ws(win->id);
 
        if (ws_idx > workspace_limit - 1 || ws_idx < -1)
                ws_idx = -1;
 
-       DNPRINTF(SWM_D_PROP, "get_ws_idx: win %#x, ws_idx: %d\n", id, ws_idx);
+       DNPRINTF(SWM_D_PROP, "get_ws_idx: win %#x, ws_idx: %d\n", win->id,
+           ws_idx);
 
        return ws_idx;
 }
@@ -8783,32 +8800,6 @@ manage_window(xcb_window_t id, int mapped)
        /* Get WM_PROTOCOLS. */
        get_wm_protocols(win);
 
-       /* Figure out which workspace the window belongs to. */
-       if ((p = find_pid(window_get_pid(win->id))) != NULL) {
-               win->ws = &r->s->ws[p->ws];
-               TAILQ_REMOVE(&pidlist, p, entry);
-               free(p);
-               p = NULL;
-       } else if ((ws_idx = get_ws_idx(win->id)) != -1 &&
-           !TRANS(win)) {
-               /* _SWM_WS is set; use that. */
-               win->ws = &r->s->ws[ws_idx];
-       } else if (trans && (ww = find_window(trans)) != NULL) {
-               /* Launch transients in the same ws as parent. */
-               win->ws = ww->ws;
-       } else {
-               win->ws = r->ws;
-       }
-
-       /* Set the _NET_WM_DESKTOP atom. */
-       DNPRINTF(SWM_D_PROP, "manage_window: set _NET_WM_DESKTOP: %d\n",
-           win->ws->idx);
-       xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->id,
-           ewmh[_NET_WM_DESKTOP].atom, XCB_ATOM_CARDINAL, 32, 1, &win->ws->idx);
-
-       /* WS must already be set for this to work. */
-       store_float_geom(win);
-
        /* Set initial quirks based on EWMH. */
        ewmh_autoquirk(win);
 
@@ -8851,6 +8842,36 @@ manage_window(xcb_window_t id, int mapped)
                        fake_keypress(win, XK_KP_Add, XCB_MOD_MASK_SHIFT);
        }
 
+       /* Figure out which workspace the window belongs to. */
+       if (!(win->quirks & SWM_Q_IGNOREPID) &&
+           (p = find_pid(window_get_pid(win->id))) != NULL) {
+               win->ws = &r->s->ws[p->ws];
+               TAILQ_REMOVE(&pidlist, p, entry);
+               free(p);
+               p = NULL;
+       } else if ((ws_idx = get_ws_idx(win)) != -1 &&
+           !TRANS(win)) {
+               /* _SWM_WS is set; use that. */
+               win->ws = &r->s->ws[ws_idx];
+       } else if (trans && (ww = find_window(trans)) != NULL) {
+               /* Launch transients in the same ws as parent. */
+               win->ws = ww->ws;
+       } else {
+               win->ws = r->ws;
+       }
+
+       /* Set the _NET_WM_DESKTOP atom. */
+       DNPRINTF(SWM_D_PROP, "manage_window: set _NET_WM_DESKTOP: %d\n",
+           win->ws->idx);
+       xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->id,
+           ewmh[_NET_WM_DESKTOP].atom, XCB_ATOM_CARDINAL, 32, 1, &win->ws->idx);
+
+       /* Remove any _SWM_WS now that we set _NET_WM_DESKTOP. */
+       xcb_delete_property(conn, win->id, a_swm_ws);
+
+       /* WS must already be set for this to work. */
+       store_float_geom(win);
+
        /* Make sure window is positioned inside its region, if its active. */
        if (win->ws->r) {
                region_containment(win, r, SWM_CW_ALLSIDES |