]> code.delx.au - spectrwm/blobdiff - spectrwm.c
Add new quirk IGNORESPAWNWS.
[spectrwm] / spectrwm.c
index 0589ebd9807a0bd07a9b52b48f2e89cd7cad6e57..03f5fdd58c8adcafeab4df86d8d43e16940ea2da 100644 (file)
@@ -425,6 +425,7 @@ XftFont             *bar_font;
 int             bar_font_legacy = 1;
 char           *bar_fonts;
 XftColor        bar_font_color;
+XftColor        search_font_color;
 struct passwd  *pwd;
 char           *startup_exception;
 unsigned int    nr_exceptions = 0;
@@ -670,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);
@@ -1036,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);
@@ -2715,6 +2718,12 @@ xft_init(struct swm_region *r)
            DefaultColormap(display, r->s->idx), &color, &bar_font_color))
                warn("Xft error: unable to allocate color.");
 
+       PIXEL_TO_XRENDERCOLOR(r->s->c[SWM_S_COLOR_BAR].pixel, color);
+
+       if (!XftColorAllocValue(display, DefaultVisual(display, r->s->idx),
+           DefaultColormap(display, r->s->idx), &color, &search_font_color))
+               warn("Xft error: unable to allocate color.");
+
        bar_height = bar_font->height + 2 * bar_border_width;
 
        if (bar_height < 1)
@@ -2762,6 +2771,13 @@ bar_setup(struct swm_region *r)
            XCB_COPY_FROM_PARENT, XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL
            | XCB_CW_EVENT_MASK, wa);
 
+       /* Stack bar window above region window to start. */
+       wa[0] = r->id;
+       wa[1] = XCB_STACK_MODE_ABOVE;
+
+       xcb_configure_window(conn, r->bar->id, XCB_CONFIG_WINDOW_SIBLING |
+           XCB_CONFIG_WINDOW_STACK_MODE, wa);
+
        r->bar->buffer = xcb_generate_id(conn);
        xcb_create_pixmap(conn, screen->root_depth, r->bar->buffer, r->bar->id,
            WIDTH(r->bar), HEIGHT(r->bar));
@@ -3476,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;
 
@@ -3559,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.
@@ -4224,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) {
@@ -4249,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)
@@ -4263,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)
@@ -4486,6 +4515,8 @@ update_floater(struct ws_win *win)
 
        DNPRINTF(SWM_D_MISC, "update_floater: win %#x\n", win->id);
 
+       win->bordered = 1;
+
        if (FULLSCREEN(win)) {
                /* _NET_WM_FULLSCREEN: fullscreen without border. */
                if (!win->g_floatvalid)
@@ -4501,14 +4532,11 @@ update_floater(struct ws_win *win)
                win->g = r->g;
 
                if (bar_enabled && ws->bar_enabled) {
-                       win->bordered = 1;
                        if (!bar_at_bottom)
                                Y(win) += bar_height;
                        HEIGHT(win) -= bar_height;
                } else if (disable_border) {
                        win->bordered = 0;
-               } else {
-                       win->bordered = 1;
                }
 
                if (win->bordered) {
@@ -4891,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);
@@ -4954,18 +4982,20 @@ max_stack(struct workspace *ws, struct swm_geometry *g)
                }
        }
 
-       if (TRANS(win)) {
-               parent = find_window(win->transient);
+       /* 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);
 
@@ -5376,7 +5406,8 @@ search_win(struct swm_region *r, union arg *args)
        struct ws_win           *win = NULL;
        struct search_window    *sw = NULL;
        xcb_window_t            w;
-       uint32_t                wa[2];
+       uint32_t                wa[3];
+       xcb_screen_t            *screen;
        int                     i, width, height;
        char                    s[8];
        FILE                    *lfile;
@@ -5397,6 +5428,9 @@ search_win(struct swm_region *r, union arg *args)
        if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL)
                return;
 
+       if ((screen = get_screen(r->s->idx)) == NULL)
+               errx(1, "ERROR: can't get screen %d.", r->s->idx);
+
        TAILQ_INIT(&search_wl);
 
        i = 1;
@@ -5420,6 +5454,7 @@ search_win(struct swm_region *r, union arg *args)
                w = xcb_generate_id(conn);
                wa[0] = r->s->c[SWM_S_COLOR_FOCUS].pixel;
                wa[1] = r->s->c[SWM_S_COLOR_UNFOCUS].pixel;
+               wa[2] = screen->default_colormap;
 
                if (bar_font_legacy) {
                        XmbTextExtents(bar_fs, s, len, &l_ibox, &l_lbox);
@@ -5432,10 +5467,10 @@ search_win(struct swm_region *r, union arg *args)
                        height = bar_font->height + 4;
                }
 
-               xcb_create_window(conn, XCB_COPY_FROM_PARENT, w, win->id, 0, 0,
+               xcb_create_window(conn, screen->root_depth, w, win->id, 0, 0,
                    width, height, 1, XCB_WINDOW_CLASS_INPUT_OUTPUT,
-                   XCB_COPY_FROM_PARENT, XCB_CW_BACK_PIXEL |
-                   XCB_CW_BORDER_PIXEL, wa);
+                   screen->root_visual, XCB_CW_BACK_PIXEL |
+                   XCB_CW_BORDER_PIXEL | XCB_CW_COLORMAP, wa);
 
                xcb_map_window(conn, w);
 
@@ -5460,7 +5495,7 @@ search_win(struct swm_region *r, union arg *args)
                            DefaultVisual(display, r->s->idx),
                            DefaultColormap(display, r->s->idx));
 
-                       XftDrawStringUtf8(draw, &bar_font_color, bar_font, 2,
+                       XftDrawStringUtf8(draw, &search_font_color, bar_font, 2,
                            (HEIGHT(r->bar) + bar_font->height) / 2 -
                            bar_font->descent, (FcChar8 *)s, len);
 
@@ -7517,6 +7552,8 @@ const char *quirkname[] = {
        "NOFOCUSONMAP",
        "FOCUSONMAP_SINGLE",
        "OBEYAPPFOCUSREQ",
+       "IGNOREPID",
+       "IGNORESPAWNWS",
 };
 
 /* SWM_Q_WS: retain '|' for back compat for now (2009-08-11) */
@@ -8278,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);
 }
 
@@ -8645,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) {
@@ -8660,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;
 }
@@ -8766,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);
 
@@ -8834,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 |
@@ -9430,6 +9468,13 @@ enternotify(xcb_enter_notify_event_t *e)
                        return;
                }
        } else {
+               if (e->mode == XCB_NOTIFY_MODE_NORMAL &&
+                   e->detail == XCB_NOTIFY_DETAIL_INFERIOR) {
+                       DNPRINTF(SWM_D_EVENT, "enternotify: entering from "
+                           "inferior; ignoring\n");
+                       return;
+               }
+
                focus_win(get_focus_magic(win));
        }
 
@@ -10476,9 +10521,12 @@ shutdown_cleanup(void)
 
                if (screens[i].bar_gc != XCB_NONE)
                        xcb_free_gc(conn, screens[i].bar_gc);
-               if (!bar_font_legacy)
+               if (!bar_font_legacy) {
                        XftColorFree(display, DefaultVisual(display, i),
                            DefaultColormap(display, i), &bar_font_color);
+                       XftColorFree(display, DefaultVisual(display, i),
+                           DefaultColormap(display, i), &search_font_color);
+               }
        }
 
        if (bar_font_legacy)