#define SH_INC_W(w) (w)->sh.width_inc
#define SH_INC_H(w) (w)->sh.height_inc
#define SWM_MAX_FONT_STEPS (3)
-#define WINID(w) ((w) ? (w)->id : 0)
+#define WINID(w) ((w) ? (w)->id : XCB_WINDOW_NONE)
+#define WS_FOCUSED(ws) ((ws)->r && (ws)->r->s->r_focus == (ws)->r)
#define YESNO(x) ((x) ? "yes" : "no")
/* Constrain Window flags */
xcb_atom_t a_prot;
xcb_atom_t a_delete;
xcb_atom_t a_takefocus;
-xcb_atom_t a_wmname;
-xcb_atom_t a_netwmname;
xcb_atom_t a_utf8_string;
-xcb_atom_t a_string;
xcb_atom_t a_swm_iconic;
xcb_atom_t a_swm_ws;
volatile sig_atomic_t running = 1;
struct ws_win *get_region_focus(struct swm_region *);
int get_region_index(struct swm_region *);
xcb_screen_t *get_screen(int);
+xcb_window_t get_sibling(struct ws_win *, int);
int get_screen_count(void);
#ifdef SWM_DEBUG
char *get_stack_mode_name(uint8_t);
void spawn_custom(struct swm_region *, union arg *, const char *);
int spawn_expand(struct swm_region *, union arg *, const char *, char ***);
void spawn_insert(const char *, const char *, int);
+struct spawn_prog *spawn_find(const char *);
void spawn_remove(struct spawn_prog *);
void spawn_replace(struct spawn_prog *, const char *, const char *, int);
void spawn_select(struct swm_region *, union arg *, const char *, int *);
if (win == NULL)
return;
- DNPRINTF(SWM_D_EVENT, "map_window: win 0x%x, mapped: %s, sibling: %x\n",
- win->id, YESNO(win->mapped), sibling);
+ DNPRINTF(SWM_D_EVENT, "map_window: win 0x%x, mapped: %s, "
+ "sibling: 0x%x\n", win->id, YESNO(win->mapped), sibling);
xcb_configure_window(conn, win->id, mode, val);
return (1);
}
+xcb_window_t
+get_sibling(struct ws_win *win, int mode)
+{
+ struct ws_win *w = win;
+
+ switch (mode) {
+ case SWM_STACK_TOP:
+ TAILQ_FOREACH_REVERSE(w, &w->ws->winlist, ws_win_list, entry)
+ if (w != win && !w->floating && !w->iconic)
+ break;
+ break;
+ case SWM_STACK_ABOVE:
+ do {
+ w = TAILQ_NEXT(w, entry);
+ } while (w != NULL && (w == win || w->floating || w->iconic));
+ break;
+ case SWM_STACK_BELOW:
+ do {
+ w = TAILQ_PREV(w, ws_win_list, entry);
+ } while (w != NULL && (w == win || w->floating || w->iconic));
+ break;
+ case SWM_STACK_BOTTOM:
+ TAILQ_FOREACH(w, &w->ws->winlist, entry)
+ if (w != win && !w->floating && !w->iconic)
+ break;
+ break;
+ default:
+ w = NULL;
+ }
+
+ if (w == NULL)
+ return (win->ws->r->id);
+ else
+ return (w->id);
+}
+
void
unfocus_win(struct ws_win *win)
{
}
if (win->ws->focus == win) {
+ if (tile_gap < 0 && !win->floating)
+ map_window(win, get_sibling(win, SWM_STACK_BELOW));
win->ws->focus = NULL;
win->ws->focus_prev = win;
}
TAILQ_FOREACH(w, &ws->winlist, entry)
if (w->transient == win->id && !w->iconic)
map_window(w, XCB_WINDOW_NONE);
+ } else if (tile_gap < 0 && !win->floating) {
+ /*
+ * Windows overlap in the layout.
+ * Raise focused win above all tiled wins.
+ */
+ if (tile_gap < 0 && !win->floating)
+ map_window(win,
+ get_sibling(win, SWM_STACK_TOP));
}
set_region(ws->r);
void
switchws(struct swm_region *r, union arg *args)
{
- int wsid = args->id, unmap_old = 0;
struct swm_region *this_r, *other_r;
struct ws_win *win;
struct workspace *new_ws, *old_ws;
+ xcb_window_t none = XCB_WINDOW_NONE;
+ int wsid = args->id, unmap_old = 0;
if (!(r && r->s))
return;
if (new_ws == old_ws)
return;
- unfocus_win(old_ws->focus);
+ if ((win = old_ws->focus) != NULL) {
+ xcb_change_window_attributes(conn, win->id, XCB_CW_BORDER_PIXEL,
+ &win->ws->r->s->c[SWM_S_COLOR_UNFOCUS].pixel);
+
+ xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->s->root,
+ ewmh[_NET_ACTIVE_WINDOW].atom, XCB_ATOM_WINDOW, 32, 1,
+ &none);
+ }
other_r = new_ws->r;
if (other_r == NULL) {
/* Set focus_pending before stacking, if needed. */
if (focus_mode != SWM_FOCUS_FOLLOW && (!new_ws->focus_pending ||
- validate_win(new_ws->focus_pending)))
+ validate_win(new_ws->focus_pending))) {
new_ws->focus_pending = get_region_focus(new_ws->r);
+ new_ws->focus = new_ws->focus_prev;
+ new_ws->focus_prev = NULL;
+ }
stack();
DNPRINTF(SWM_D_FOCUS, "focusrg: id: %d\n", ridx);
rr = TAILQ_FIRST(&r->s->rl);
- for (i = 0; i < ridx; ++i)
+ for (i = 0; i < ridx && rr != NULL; ++i)
rr = TAILQ_NEXT(rr, entry);
if (rr == NULL)
stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip)
{
struct swm_geometry win_g, r_g = *g;
- struct ws_win *win, *fs_win = NULL, *wtmp;
- xcb_window_t sibling;
+ struct ws_win *win, *fs_win = NULL;
int i, j, s, stacks;
int w_inc = 1, h_inc, w_base = 1, h_base;
int hrh, extra = 0, h_slice, last_h = 0;
update_window(win);
}
- wtmp = TAILQ_PREV(win, ws_win_list, entry);
- if (wtmp)
- sibling = wtmp->id;
- else
- sibling = ws->r->bar->id;
-
- map_window(win, sibling);
+ map_window(win, get_sibling(win, SWM_STACK_BELOW));
last_h = win_g.h;
i++;
j++;
}
+ /* Map/raise focused tiled window to top if windows could overlap. */
+ if (tile_gap < 0 && ws->focus != NULL && !ws->focus->floating)
+ map_window(ws->focus, get_sibling(ws->focus, SWM_STACK_TOP));
+
notiles:
/* now, stack all the floaters and transients */
TAILQ_FOREACH(win, &ws->winlist, entry) {
DNPRINTF(SWM_D_FOCUS, "send_to_rg: id: %d\n", ridx);
rr = TAILQ_FIRST(&r->s->rl);
- for (i = 0; i < ridx; ++i)
+ for (i = 0; i < ridx && rr != NULL; ++i)
rr = TAILQ_NEXT(rr, entry);
if (rr == NULL)
xcb_get_property_reply_t *r;
/* First try _NET_WM_NAME for UTF-8. */
- c = xcb_get_property(conn, 0, win, a_netwmname,
+ c = xcb_get_property(conn, 0, win, ewmh[_NET_WM_NAME].atom,
XCB_GET_PROPERTY_TYPE_ANY, 0, UINT_MAX);
r = xcb_get_property_reply(conn, c, NULL);
int
floating_toggle_win(struct ws_win *win)
{
- struct swm_region *r;
-
if (win == NULL)
return (0);
if (!win->ws->r)
return (0);
- r = win->ws->r;
-
/* reject floating toggles in max stack mode */
if (win->ws->cur_layout == &layouts[SWM_MAX_STACK])
return (0);
{
xcb_timestamp_t timestamp = 0;
int move_stp = 0, moving;
- struct swm_region *r = NULL;
xcb_query_pointer_reply_t *qpr = NULL;
xcb_generic_event_t *evt;
xcb_motion_notify_event_t *mne;
if (win == NULL)
return;
- r = win->ws->r;
if (win->ewmh_flags & EWMH_F_FULLSCREEN)
return;
char ***ret_args)
{
struct spawn_prog *prog = NULL;
- int i;
+ int i, c;
char *ap, **real_args;
/* suppress unused warning since var is needed */
err(1, "spawn_custom: calloc real_args");
/* expand spawn_args into real_args */
- for (i = 0; i < prog->argc; i++) {
+ for (i = c = 0; i < prog->argc; i++) {
ap = prog->argv[i];
DNPRINTF(SWM_D_SPAWN, "spawn_custom: raw arg: %s\n", ap);
if (!strcasecmp(ap, "$bar_border")) {
- if ((real_args[i] =
+ if ((real_args[c] =
strdup(r->s->c[SWM_S_COLOR_BAR_BORDER].name))
== NULL)
err(1, "spawn_custom border color");
} else if (!strcasecmp(ap, "$bar_color")) {
- if ((real_args[i] =
+ if ((real_args[c] =
strdup(r->s->c[SWM_S_COLOR_BAR].name))
== NULL)
err(1, "spawn_custom bar color");
} else if (!strcasecmp(ap, "$bar_font")) {
- if ((real_args[i] = strdup(bar_fonts))
+ if ((real_args[c] = strdup(bar_fonts))
== NULL)
err(1, "spawn_custom bar fonts");
} else if (!strcasecmp(ap, "$bar_font_color")) {
- if ((real_args[i] =
+ if ((real_args[c] =
strdup(r->s->c[SWM_S_COLOR_BAR_FONT].name))
== NULL)
err(1, "spawn_custom color font");
} else if (!strcasecmp(ap, "$color_focus")) {
- if ((real_args[i] =
+ if ((real_args[c] =
strdup(r->s->c[SWM_S_COLOR_FOCUS].name))
== NULL)
err(1, "spawn_custom color focus");
} else if (!strcasecmp(ap, "$color_unfocus")) {
- if ((real_args[i] =
+ if ((real_args[c] =
strdup(r->s->c[SWM_S_COLOR_UNFOCUS].name))
== NULL)
err(1, "spawn_custom color unfocus");
} else if (!strcasecmp(ap, "$region_index")) {
- if (asprintf(&real_args[i], "%d",
+ if (asprintf(&real_args[c], "%d",
get_region_index(r) + 1) < 1)
err(1, "spawn_custom region index");
} else if (!strcasecmp(ap, "$workspace_index")) {
- if (asprintf(&real_args[i], "%d", r->ws->idx + 1) < 1)
+ if (asprintf(&real_args[c], "%d", r->ws->idx + 1) < 1)
+ err(1, "spawn_custom workspace index");
+ } else if (!strcasecmp(ap, "$dmenu_bottom")) {
+ if (!bar_at_bottom)
+ continue;
+ if ((real_args[c] = strdup("-b")) == NULL)
err(1, "spawn_custom workspace index");
} else {
/* no match --> copy as is */
- if ((real_args[i] = strdup(ap)) == NULL)
+ if ((real_args[c] = strdup(ap)) == NULL)
err(1, "spawn_custom strdup(ap)");
}
DNPRINTF(SWM_D_SPAWN, "spawn_custom: cooked arg: %s\n",
- real_args[i]);
+ real_args[c]);
+ ++c;
}
#ifdef SWM_DEBUG
DNPRINTF(SWM_D_SPAWN, "spawn_custom: result: ");
- for (i = 0; i < prog->argc; i++)
- DNPRINTF(SWM_D_SPAWN, "\"%s\" ", real_args[i]);
- DNPRINTF(SWM_D_SPAWN, "\n");
+ for (i = 0; i < c; ++i)
+ DPRINTF("\"%s\" ", real_args[i]);
+ DPRINTF("\n");
#endif
*ret_args = real_args;
- return (prog->argc);
+ return (c);
}
void
DNPRINTF(SWM_D_SPAWN, "spawn_remove: leave\n");
}
+struct spawn_prog*
+spawn_find(const char *name)
+{
+ struct spawn_prog *sp;
+
+ TAILQ_FOREACH(sp, &spawns, entry)
+ if (!strcasecmp(sp->name, name))
+ return sp;
+
+ return NULL;
+}
+
void
setspawn(const char *name, const char *args, int flags)
{
return;
/* Remove any old spawn under the same name. */
- TAILQ_FOREACH(sp, &spawns, entry)
- if (!strcmp(sp->name, name)) {
- spawn_remove(sp);
- break;
- }
+ if ((sp = spawn_find(name)) != NULL)
+ spawn_remove(sp);
if (*args != '\0')
spawn_insert(name, args, flags);
continue;
/* find program */
- TAILQ_FOREACH(sp, &spawns, entry) {
- if (!strcasecmp(kp->spawn_name, sp->name))
- break;
- }
-
+ sp = spawn_find(kp->spawn_name);
if (sp == NULL || sp->flags & SWM_SPAWN_OPTIONAL)
continue;
setconfspawn("spawn_term", "xterm", 0);
setconfspawn("menu", "dmenu_run"
+ " $dmenu_bottom"
" -fn $bar_font"
" -nb $bar_color"
" -nf $bar_font_color"
" -sf $bar_color", 0);
setconfspawn("search", "dmenu"
+ " $dmenu_bottom"
" -i"
" -fn $bar_font"
" -nb $bar_color"
" -sf $bar_color", 0);
setconfspawn("name_workspace", "dmenu"
+ " $dmenu_bottom"
" -p Workspace"
" -fn $bar_font"
" -nb $bar_color"
}
}
/* search by custom spawn name */
- TAILQ_FOREACH(sp, &spawns, entry) {
- if (strcasecmp(selector, sp->name) == 0) {
- DNPRINTF(SWM_D_KEY, "setconfbinding: %s: match "
- "spawn\n", selector);
- if (parsekeys(value, mod_key, &mod, &ks) == 0) {
- setkeybinding(mod, ks, KF_SPAWN_CUSTOM,
- sp->name);
- return (0);
- } else
- return (1);
- }
+ if ((sp = spawn_find(selector)) != NULL) {
+ DNPRINTF(SWM_D_KEY, "setconfbinding: %s: match "
+ "spawn\n", selector);
+ if (parsekeys(value, mod_key, &mod, &ks) == 0) {
+ setkeybinding(mod, ks, KF_SPAWN_CUSTOM,
+ sp->name);
+ return (0);
+ } else
+ return (1);
}
DNPRINTF(SWM_D_KEY, "setconfbinding: no match\n");
return (1);
break;
case SWM_S_TILE_GAP:
tile_gap = atoi(value);
- if (tile_gap < 0)
- tile_gap = 0;
break;
case SWM_S_TITLE_CLASS_ENABLED:
title_class_enabled = atoi(value);
unmanage_window(win);
stack();
- if (focus_mode != SWM_FOCUS_FOLLOW) {
+ if (focus_mode != SWM_FOCUS_FOLLOW && WS_FOCUSED(win->ws)) {
if (win->ws->focus_pending) {
focus_win(win->ws->focus_pending);
win->ws->focus_pending = NULL;
- } else if (win == win->ws->focus && win->ws->r) {
+ } else if (win == win->ws->focus) {
xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT,
win->ws->r->id, XCB_CURRENT_TIME);
}
win->mapped = 1;
set_win_state(win, XCB_ICCCM_WM_STATE_NORMAL);
- if (focus_mode != SWM_FOCUS_FOLLOW) {
+ if (focus_mode != SWM_FOCUS_FOLLOW && WS_FOCUSED(win->ws)) {
if (win->ws->focus_pending == win) {
focus_win(win);
win->ws->focus_pending = NULL;
if (w == win || !w->mapped)
continue;
- if (!strcmp(w->ch.class_name,
+ if (w->ch.class_name &&
+ win->ch.class_name &&
+ !strcmp(w->ch.class_name,
win->ch.class_name) &&
+ w->ch.instance_name &&
+ win->ch.instance_name &&
!strcmp(w->ch.instance_name,
win->ch.instance_name))
break;
if (ws->r) {
stack();
- if (focus_mode != SWM_FOCUS_FOLLOW) {
+ if (focus_mode != SWM_FOCUS_FOLLOW &&
+ WS_FOCUSED(ws)) {
if (ws->focus_pending) {
focus_win(ws->focus_pending);
ws->focus_pending = NULL;
} else if (e->atom == a_state) {
/* State just changed, make sure it gets focused if mapped. */
if (e->state == XCB_PROPERTY_NEW_VALUE) {
- if (focus_mode != SWM_FOCUS_FOLLOW) {
+ if (focus_mode != SWM_FOCUS_FOLLOW && WS_FOCUSED(ws)) {
if (win->mapped &&
ws->focus_pending == win) {
focus_win(ws->focus_pending);
if (ws->r)
stack();
- if (focus_mode == SWM_FOCUS_FOLLOW) {
- if (ws->r)
+ if (WS_FOCUSED(ws)) {
+ if (focus_mode == SWM_FOCUS_FOLLOW) {
focus_win(get_pointer_win(ws->r->s->root));
- } else if (ws->focus_pending) {
- focus_win(ws->focus_pending);
- ws->focus_pending = NULL;
- } else if (ws->focus == NULL && ws->r) {
- xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT,
- ws->r->id, XCB_CURRENT_TIME);
+ } else if (ws->focus_pending) {
+ focus_win(ws->focus_pending);
+ ws->focus_pending = NULL;
+ } else if (ws->focus == NULL) {
+ xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT,
+ ws->r->id, XCB_CURRENT_TIME);
+ }
}
}
if (e->type == ewmh[_NET_ACTIVE_WINDOW].atom) {
DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_ACTIVE_WINDOW\n");
- focus_win(win);
+ if (WS_FOCUSED(win->ws))
+ focus_win(win);
+ else
+ win->ws->focus_pending = win;
}
if (e->type == ewmh[_NET_CLOSE_WINDOW].atom) {
DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_CLOSE_WINDOW\n");
a_prot = get_atom_from_string("WM_PROTOCOLS");
a_delete = get_atom_from_string("WM_DELETE_WINDOW");
a_takefocus = get_atom_from_string("WM_TAKE_FOCUS");
- a_wmname = get_atom_from_string("WM_NAME");
- a_netwmname = get_atom_from_string("_NET_WM_NAME");
a_utf8_string = get_atom_from_string("UTF8_STRING");
- a_string = get_atom_from_string("STRING");
a_swm_iconic = get_atom_from_string("_SWM_ICONIC");
a_swm_ws = get_atom_from_string("_SWM_WS");
}
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win,
netwmcheck, XCB_ATOM_WINDOW, 32, 1, &win);
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win,
- a_netwmname, a_utf8_string, 8, strlen("LG3D"), "LG3D");
+ ewmh[_NET_WM_NAME].atom, a_utf8_string, 8, strlen("LG3D"),
+ "LG3D");
}
}