#define SWM_D_BAR 0x4000
#define SWM_D_INIT 0x8000
-u_int32_t swm_debug = 0
+uint32_t swm_debug = 0
| SWM_D_MISC
| SWM_D_EVENT
| SWM_D_WS
struct swm_geometry g; /* current geometry */
struct swm_geometry g_float; /* region coordinates */
int g_floatvalid; /* g_float geometry validity */
- int32_t mapped;
+ int mapped;
int bordered;
uint32_t ewmh_flags;
int font_size_boundary[SWM_MAX_FONT_STEPS];
struct layout {
void (*l_stack)(struct workspace *, struct swm_geometry *);
void (*l_config)(struct workspace *, int);
- u_int32_t flags;
+ uint32_t flags;
#define SWM_L_FOCUSPREV (1<<0)
#define SWM_L_MAPONFOCUS (1<<1)
void (*l_string)(struct workspace *);
struct ws_win_list winlist; /* list of windows in ws */
struct ws_win_list unmanagedlist; /* list of dead windows in ws */
struct ws_win_stack stack; /* stacking order */
- int32_t state; /* mapping state */
+ int state; /* mapping state */
char stacker[10]; /* display stacker and layout */
/* stacker state */
SWM_S_COLOR_BAR_BORDER_UNFOCUS,
SWM_S_COLOR_BAR_FONT,
SWM_S_COLOR_FOCUS,
+ SWM_S_COLOR_FOCUS_MAXIMIZED,
SWM_S_COLOR_UNFOCUS,
+ SWM_S_COLOR_UNFOCUS_MAXIMIZED,
SWM_S_COLOR_MAX
};
struct {
uint32_t pixel;
char *name;
+ int manual;
} c[SWM_S_COLOR_MAX];
xcb_gcontext_t bar_gc;
#define SWM_ARG_ID_MOVEDOWN (101)
#define SWM_ARG_ID_MOVELEFT (102)
#define SWM_ARG_ID_MOVERIGHT (103)
+#define SWM_ARG_ID_RAISE (105)
+#define SWM_ARG_ID_LOWER (106)
#define SWM_ARG_ID_BAR_TOGGLE (110)
#define SWM_ARG_ID_BAR_TOGGLE_WS (111)
char **argv;
#define SWM_Q_FOCUSPREV (1<<5) /* focus on caller */
#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. */
};
TAILQ_HEAD(quirk_list, quirk);
struct quirk_list quirks = TAILQ_HEAD_INITIALIZER(quirks);
_NET_CLIENT_LIST,
_NET_CLOSE_WINDOW,
_NET_CURRENT_DESKTOP,
+ _NET_DESKTOP_GEOMETRY,
_NET_DESKTOP_NAMES,
+ _NET_DESKTOP_VIEWPORT,
_NET_MOVERESIZE_WINDOW,
_NET_NUMBER_OF_DESKTOPS,
_NET_RESTACK_WINDOW,
{"_NET_CLIENT_LIST", XCB_ATOM_NONE},
{"_NET_CLOSE_WINDOW", XCB_ATOM_NONE},
{"_NET_CURRENT_DESKTOP", XCB_ATOM_NONE},
+ {"_NET_DESKTOP_GEOMETRY", XCB_ATOM_NONE},
{"_NET_DESKTOP_NAMES", XCB_ATOM_NONE},
+ {"_NET_DESKTOP_VIEWPORT", XCB_ATOM_NONE},
{"_NET_MOVERESIZE_WINDOW", XCB_ATOM_NONE},
{"_NET_NUMBER_OF_DESKTOPS", XCB_ATOM_NONE},
{"_NET_RESTACK_WINDOW", XCB_ATOM_NONE},
void ewmh_update_client_list(void);
void ewmh_update_current_desktop(void);
void ewmh_update_desktop_names(void);
+void ewmh_update_desktops(void);
void ewmh_change_wm_state(struct ws_win *, xcb_atom_t, long);
void ewmh_update_wm_state(struct ws_win *);
char *expand_tilde(const char *);
xcb_screen_t *get_screen(int);
int get_screen_count(void);
#ifdef SWM_DEBUG
+char *get_source_type_label(uint32_t);
char *get_stack_mode_name(uint8_t);
#endif
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);
-uint32_t getstate(xcb_window_t);
void grabbuttons(struct ws_win *);
void grabkeys(void);
void grab_windows(void);
void leavenotify(xcb_leave_notify_event_t *);
#endif
void load_float_geom(struct ws_win *);
-struct ws_win *manage_window(xcb_window_t, uint16_t);
+struct ws_win *manage_window(xcb_window_t, int);
void map_window(struct ws_win *);
void mapnotify(xcb_map_notify_event_t *);
void mappingnotify(xcb_mapping_notify_event_t *);
void setup_screens(void);
void setup_spawn(void);
void set_child_transient(struct ws_win *, xcb_window_t *);
-void set_win_state(struct ws_win *, uint16_t);
+void set_win_state(struct ws_win *, uint8_t);
void shutdown_cleanup(void);
void sighdlr(int);
void socket_setnonblock(int);
void update_modkey(unsigned int);
void update_win_stacking(struct ws_win *);
void update_window(struct ws_win *);
+void update_window_color(struct ws_win *);
void update_wm_state(struct ws_win *win);
void validate_spawns(void);
int validate_win(struct ws_win *);
a_net_supported, XCB_ATOM_ATOM, 32, 1,
&ewmh[j].atom);
- xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root,
- ewmh[_NET_NUMBER_OF_DESKTOPS].atom, XCB_ATOM_CARDINAL, 32,
- 1, &workspace_limit);
}
+
+ ewmh_update_desktops();
+ ewmh_get_desktop_names();
}
void
void
ewmh_autoquirk(struct ws_win *win)
{
- uint32_t i, n;
- xcb_atom_t *type;
- xcb_get_property_cookie_t c;
xcb_get_property_reply_t *r;
+ xcb_get_property_cookie_t c;
+ xcb_atom_t *type;
+ int i, n;
c = xcb_get_property(conn, 0, win->id,
ewmh[_NET_WM_WINDOW_TYPE].atom, XCB_ATOM_ATOM, 0, UINT32_MAX);
ws->focus_pending = win;
}
}
+
+ update_window_color(win);
raise_window(win);
}
void
dumpwins(struct swm_region *r, union arg *args)
{
- struct ws_win *win;
+ struct ws_win *w;
uint32_t state;
xcb_get_window_attributes_cookie_t c;
xcb_get_window_attributes_reply_t *wa;
}
DPRINTF("=== managed window list ws %02d ===\n", r->ws->idx);
- TAILQ_FOREACH(win, &r->ws->winlist, entry) {
- state = getstate(win->id);
- c = xcb_get_window_attributes(conn, win->id);
+ TAILQ_FOREACH(w, &r->ws->winlist, entry) {
+ state = get_win_state(w->id);
+ c = xcb_get_window_attributes(conn, w->id);
wa = xcb_get_window_attributes_reply(conn, c, NULL);
if (wa) {
DPRINTF("win %#x, map_state: %d, state: %u, "
- "transient: %#x\n", win->id, wa->map_state,
- state, win->transient);
+ "transient: %#x\n", w->id, wa->map_state,
+ state, w->transient);
free(wa);
} else
DPRINTF("win %#x, failed xcb_get_window_attributes\n",
- win->id);
+ w->id);
+ }
+
+ DPRINTF("=== stacking order (top down) === \n");
+ TAILQ_FOREACH(w, &r->ws->stack, stack_entry) {
+ DPRINTF("win %#x, fs: %s, maximized: %s, above: %s, "
+ "iconic: %s\n", w->id, YESNO(FULLSCREEN(w)),
+ YESNO(MAXIMIZED(w)), YESNO(ABOVE(w)), YESNO(ICONIC(w)));
}
DPRINTF("===== unmanaged window list =====\n");
- TAILQ_FOREACH(win, &r->ws->unmanagedlist, entry) {
- state = getstate(win->id);
- c = xcb_get_window_attributes(conn, win->id);
+ TAILQ_FOREACH(w, &r->ws->unmanagedlist, entry) {
+ state = get_win_state(w->id);
+ c = xcb_get_window_attributes(conn, w->id);
wa = xcb_get_window_attributes_reply(conn, c, NULL);
if (wa) {
DPRINTF("win %#x, map_state: %d, state: %u, "
- "transient: %#x\n", win->id, wa->map_state,
- state, win->transient);
+ "transient: %#x\n", w->id, wa->map_state,
+ state, w->transient);
free(wa);
} else
DPRINTF("win %#x, failed xcb_get_window_attributes\n",
- win->id);
+ w->id);
}
DPRINTF("=================================\n");
void
setscreencolor(const char *val, int i, int c)
{
- int num_screens;
+ if (i < 0 || i >= get_screen_count())
+ return;
- num_screens = get_screen_count();
- if (i > 0 && i <= num_screens) {
- screens[i - 1].c[c].pixel = name_to_pixel(i - 1, val);
- free(screens[i - 1].c[c].name);
- if ((screens[i - 1].c[c].name = strdup(val)) == NULL)
- err(1, "strdup");
- } else if (i == -1) {
- for (i = 0; i < num_screens; i++) {
- screens[i].c[c].pixel = name_to_pixel(0, val);
- free(screens[i].c[c].name);
- if ((screens[i].c[c].name = strdup(val)) == NULL)
- err(1, "strdup");
- }
- } else
- errx(1, "invalid screen index: %d out of bounds (maximum %d)",
- i, num_screens);
+ screens[i].c[c].pixel = name_to_pixel(i, val);
+ free(screens[i].c[c].name);
+ if ((screens[i].c[c].name = strdup(val)) == NULL)
+ err(1, "strdup");
}
void
}
void
-set_win_state(struct ws_win *win, uint16_t state)
+set_win_state(struct ws_win *win, uint8_t state)
{
uint16_t data[2] = { state, XCB_ATOM_NONE };
a_state, 32, 2, data);
}
-uint32_t
-getstate(xcb_window_t w)
+uint8_t
+get_win_state(xcb_window_t w)
{
- uint32_t result = 0;
- xcb_get_property_cookie_t c;
xcb_get_property_reply_t *r;
+ xcb_get_property_cookie_t c;
+ uint32_t result = 0;
c = xcb_get_property(conn, 0, w, a_state, a_state, 0L, 2L);
r = xcb_get_property_reply(conn, c, NULL);
free(r);
}
- DNPRINTF(SWM_D_MISC, "getstate property: win %#x state %u\n", w,
+ DNPRINTF(SWM_D_MISC, "get_win_state property: win %#x state %u\n", w,
result);
return (result);
}
continue;
if (ws->cur_layout == &layouts[SWM_MAX_STACK])
break;
+ if (TRANS(win) && (win->transient == target->transient ||
+ win->transient == target->id))
+ break;
if (FULLSCREEN(win))
break;
if (FULLSCREEN(target))
update_win_stacking(win);
}
+#ifdef SWM_DEBUG
+ if (swm_debug & SWM_D_STACK) {
+ DPRINTF("=== stacking order (top down) === \n");
+ TAILQ_FOREACH(target, &r->ws->stack, stack_entry) {
+ DPRINTF("win %#x, fs: %s, maximized: %s, above: %s, "
+ "iconic: %s\n", target->id, YESNO(FULLSCREEN(target)),
+ YESNO(MAXIMIZED(target)), YESNO(ABOVE(target)),
+ YESNO(ICONIC(target)));
+ }
+ }
+#endif
DNPRINTF(SWM_D_EVENT, "raise_window: done\n");
}
win->ws->focus_prev = NULL;
}
- xcb_change_window_attributes(conn, win->id, XCB_CW_BORDER_PIXEL,
- &win->ws->r->s->c[SWM_S_COLOR_UNFOCUS].pixel);
+ update_window_color(win);
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->s->root,
ewmh[_NET_ACTIVE_WINDOW].atom, XCB_ATOM_WINDOW, 32, 1, &none);
DNPRINTF(SWM_D_FOCUS, "focus_win: win %#x\n", WINID(win));
- if (win == NULL)
- goto out;
-
- if (win->ws == NULL)
- goto out;
-
- if (!win->mapped)
+ if (win == NULL || win->ws == NULL || !win->mapped)
goto out;
ws = win->ws;
/* Change border to unfocused color. */
xcb_change_window_attributes(conn, cfw->id,
XCB_CW_BORDER_PIXEL,
- &cfw->ws->r->s->c[SWM_S_COLOR_UNFOCUS].pixel);
+ &cfw->s->c[(MAXIMIZED(cfw) ?
+ SWM_S_COLOR_UNFOCUS_MAXIMIZED :
+ SWM_S_COLOR_UNFOCUS)].pixel);
} else {
unfocus_win(cfw);
}
client_msg(win, a_takefocus, last_event_time);
}
- xcb_change_window_attributes(conn, win->id, XCB_CW_BORDER_PIXEL,
- &ws->r->s->c[SWM_S_COLOR_FOCUS].pixel);
-
if (ws->cur_layout->flags & SWM_L_MAPONFOCUS ||
ws->always_raise) {
/* If a parent exists, map it first. */
set_region(ws->r);
+ update_window_color(win);
+
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->s->root,
ewmh[_NET_ACTIVE_WINDOW].atom, XCB_ATOM_WINDOW, 32, 1,
&win->id);
set_region(struct swm_region *r)
{
struct swm_region *rf;
+ int vals[2];
if (r == NULL)
return;
rf = r->s->r_focus;
/* Unfocus old region bar. */
- if (rf) {
+ if (rf != NULL) {
if (rf == r)
return;
&r->s->c[SWM_S_COLOR_BAR_BORDER_UNFOCUS].pixel);
}
+ if (rf != NULL && rf != r && (X(rf) != X(r) || Y(rf) != Y(r) ||
+ WIDTH(rf) != WIDTH(r) || HEIGHT(rf) != HEIGHT(r))) {
+ /* Set _NET_DESKTOP_GEOMETRY. */
+ vals[0] = WIDTH(r);
+ vals[1] = HEIGHT(r);
+ xcb_change_property(conn, XCB_PROP_MODE_REPLACE, r->s->root,
+ ewmh[_NET_DESKTOP_GEOMETRY].atom, XCB_ATOM_CARDINAL, 32, 2,
+ &vals);
+ }
+
/* Set region bar border to focus_color. */
xcb_change_window_attributes(conn, r->bar->id,
XCB_CW_BORDER_PIXEL, &r->s->c[SWM_S_COLOR_BAR_BORDER].pixel);
return;
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);
+ update_window_color(win);
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->s->root,
ewmh[_NET_ACTIVE_WINDOW].atom, XCB_ATOM_WINDOW, 32, 1,
union arg a;
struct swm_screen *s = r->s;
int cycle_all = 0;
- int move = 0;
+ int mv = 0;
DNPRINTF(SWM_D_WS, "cyclews: id: %d, screen[%d]:%dx%d+%d+%d, ws: %d\n",
args->id, r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r), r->ws->idx);
do {
switch (args->id) {
case SWM_ARG_ID_CYCLEWS_MOVE_UP:
- move = 1;
+ mv = 1;
/* FALLTHROUGH */
case SWM_ARG_ID_CYCLEWS_UP_ALL:
cycle_all = 1;
a.id = (a.id < workspace_limit - 1) ? a.id + 1 : 0;
break;
case SWM_ARG_ID_CYCLEWS_MOVE_DOWN:
- move = 1;
+ mv = 1;
/* FALLTHROUGH */
case SWM_ARG_ID_CYCLEWS_DOWN_ALL:
cycle_all = 1;
if (!cycle_visible && s->ws[a.id].r != NULL)
continue;
- if (move)
+ if (mv)
send_to_ws(r, &a);
switchws(r, &a);
args->id, r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r), r->ws->idx);
cur_focus = r->ws->focus;
- if (cur_focus == NULL || ABOVE(cur_focus) || FULLSCREEN(cur_focus))
+ if (cur_focus == NULL || FULLSCREEN(cur_focus))
return;
+ /* Adjust stacking in floating layer. */
+ if (ABOVE(cur_focus)) {
+ switch (args->id) {
+ case SWM_ARG_ID_SWAPPREV:
+ target = TAILQ_PREV(cur_focus, ws_win_stack,
+ stack_entry);
+ if (target != NULL && FLOATING(target)) {
+ TAILQ_REMOVE(&cur_focus->ws->stack, cur_focus,
+ stack_entry);
+ TAILQ_INSERT_BEFORE(target, cur_focus,
+ stack_entry);
+ update_win_stacking(cur_focus);
+ focus_flush();
+ }
+ break;
+ case SWM_ARG_ID_SWAPNEXT:
+ target = TAILQ_NEXT(cur_focus, stack_entry);
+ if (target != NULL && FLOATING(target)) {
+ TAILQ_REMOVE(&cur_focus->ws->stack, cur_focus,
+ stack_entry);
+ TAILQ_INSERT_AFTER(&cur_focus->ws->stack,
+ target, cur_focus, stack_entry);
+ update_win_stacking(cur_focus);
+ focus_flush();
+ }
+ break;
+ }
+ goto out;
+ }
+
if (r->ws->cur_layout == &layouts[SWM_MAX_STACK])
return;
}
sort_windows(wl);
-
ewmh_update_client_list();
stack();
-
focus_flush();
+out:
+ DNPRINTF(SWM_D_MOVE, "swapwin: done\n");
}
struct ws_win *
else
win = TAILQ_FIRST(&ws->winlist);
- DNPRINTF(SWM_D_STACK, "max_stack: win: %#x\n", win->id);
+ DNPRINTF(SWM_D_STACK, "max_stack: focus_pending: %#x, focus: %#x, "
+ "focus_prev: %#x, first: %#x, win: %#x\n", WINID(ws->focus_pending),
+ WINID(ws->focus), WINID(ws->focus_prev),
+ WINID(TAILQ_FIRST(&ws->winlist)), win->id);
/* Update window geometry. */
TAILQ_FOREACH(w, &ws->winlist, entry) {
return (NULL);
}
+/* Transfer focused window to target workspace and focus. */
void
send_to_ws(struct swm_region *r, union arg *args)
{
DNPRINTF(SWM_D_MOVE, "send_to_ws: win %#x, ws %d\n", win->id, wsid);
- if (wsid >= workspace_limit)
+ if (wsid < 0 || wsid >= workspace_limit)
return;
if (win->ws->idx == wsid)
win_to_ws(win, wsid, 1);
+ /* Set window to be focus on target ws. */
+ if (focus_mode != SWM_FOCUS_FOLLOW) {
+ win->ws->focus = win;
+ win->ws->focus_pending = NULL;
+ }
+
+ DNPRINTF(SWM_D_STACK, "send_to_ws: focus_pending: %#x, focus: %#x, "
+ "focus_prev: %#x, first: %#x, win: %#x\n",
+ WINID(r->ws->focus_pending), WINID(r->ws->focus),
+ WINID(r->ws->focus_prev), WINID(TAILQ_FIRST(&r->ws->winlist)),
+ win->id);
+
ewmh_apply_flags(win, win->ewmh_flags & ~EWMH_F_MAXIMIZED);
ewmh_update_wm_state(win);
/* Restack and set new focus. */
+ if (FLOATING(win))
+ load_float_geom(win);
+
stack();
if (focus_mode != SWM_FOCUS_FOLLOW) {
- if (r->ws->focus_pending) {
- focus_win(r->ws->focus_pending);
- r->ws->focus_pending = NULL;
+ if (r->ws->focus != NULL) {
+ focus_win(r->ws->focus);
} else {
- xcb_set_input_focus(conn,
- XCB_INPUT_FOCUS_PARENT, r->id,
+ xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT, r->id,
XCB_CURRENT_TIME);
+ bar_draw();
}
}
struct ws_win *parent;
struct workspace *ws, *nws, *pws;
- if (wsid >= workspace_limit)
+ if (wsid < 0 || wsid >= workspace_limit)
return;
if (win->ws->idx == wsid)
DNPRINTF(SWM_D_MOVE, "win_to_ws: win %#x, ws %d -> %d\n", win->id,
ws->idx, wsid);
- if (focus_mode != SWM_FOCUS_FOLLOW)
+ /* Cleanup focus on source ws. */
+ if (focus_mode != SWM_FOCUS_FOLLOW &&
+ (ws->focus == win || ws->focus_pending == win))
ws->focus_pending = get_focus_prev(win);
/* Move the parent if this is a transient window. */
if (unfocus)
unfocus_win(win);
+ if (ws->focus_prev == win)
+ ws->focus_prev = NULL;
+
+ if (focus_mode != SWM_FOCUS_FOLLOW && ws->focus_pending != NULL) {
+ ws->focus = ws->focus_pending;
+ ws->focus_pending = NULL;
+ }
+
/* Don't unmap if new ws is visible */
if (nws->r == NULL)
unmap_window(win);
TAILQ_INSERT_TAIL(&nws->stack, win, stack_entry);
win->ws = nws;
- /* Set focus on new ws. */
- unfocus_win(nws->focus);
- nws->focus = win;
-
/* Update the window's workspace property: _NET_WM_DESKTOP */
DNPRINTF(SWM_D_PROP, "win_to_ws: set property: "
"_NET_WM_DESKTOP: %d\n", wsid);
++len;
}
- if((name_list = calloc(sizeof(char *), len)) == NULL)
+ if((name_list = calloc(len, sizeof(char))) == NULL)
err(1, "update_desktop_names: calloc: failed to "
"allocate memory.");
if (count == 0)
continue;
- wins = calloc(sizeof(xcb_window_t), count);
+ wins = calloc(count, sizeof(xcb_window_t));
if (wins == NULL)
err(1, "ewmh_update_client_list: calloc: failed to "
"allocate memory.");
}
void
+ewmh_update_desktops(void)
+{
+ int num_screens, i, j;
+ uint32_t *vals;
+
+ vals = calloc(workspace_limit * 2, sizeof(uint32_t));
+ if (vals == NULL)
+ err(1, "ewmh_update_desktops: calloc: failed to allocate "
+ "memory.");
+
+ num_screens = get_screen_count();
+ for (i = 0; i < num_screens; i++) {
+ xcb_change_property(conn, XCB_PROP_MODE_REPLACE,
+ screens[i].root, ewmh[_NET_NUMBER_OF_DESKTOPS].atom,
+ XCB_ATOM_CARDINAL, 32, 1, &workspace_limit);
+
+ for (j = 0; j < workspace_limit; ++j) {
+ if (screens[i].ws[j].r != NULL) {
+ vals[j * 2] = X(screens[i].ws[j].r);
+ vals[j * 2 + 1] = Y(screens[i].ws[j].r);
+ } else if (screens[i].ws[j].old_r != NULL) {
+ vals[j * 2] = X(screens[i].ws[j].old_r);
+ vals[j * 2 + 1] = Y(screens[i].ws[j].old_r);
+ } else {
+ vals[j * 2] = vals[j * 2 + 1] = 0;
+ }
+ }
+
+ xcb_change_property(conn, XCB_PROP_MODE_REPLACE,
+ screens[i].root, ewmh[_NET_DESKTOP_VIEWPORT].atom,
+ XCB_ATOM_CARDINAL, 32, workspace_limit * 2, vals);
+ }
+
+ free(vals);
+}
+
+void
search_resp_search_workspace(const char *resp)
{
char *p, *q;
void
floating_toggle(struct swm_region *r, union arg *args)
{
- struct ws_win *win = r->ws->focus;
+ struct ws_win *w = r->ws->focus;
/* suppress unused warning since var is needed */
(void)args;
- if (win == NULL)
+ if (w == NULL)
+ return;
+
+ DNPRINTF(SWM_D_MISC, "floating_toggle: win %#x\n", w->id);
+
+ if (FULLSCREEN(w) || TRANS(w))
return;
- if (FULLSCREEN(win) || TRANS(win))
+ if (w->ws->cur_layout == &layouts[SWM_MAX_STACK])
return;
- ewmh_apply_flags(win, win->ewmh_flags ^ EWMH_F_ABOVE);
- ewmh_update_wm_state(win);
+ ewmh_apply_flags(w, w->ewmh_flags ^ EWMH_F_ABOVE);
+ ewmh_update_wm_state(w);
stack();
- if (win == win->ws->focus)
- focus_win(win);
+ if (w == w->ws->focus)
+ focus_win(w);
focus_flush();
+ DNPRINTF(SWM_D_MISC, "floating_toggle: done\n");
}
void
}
void
+update_window_color(struct ws_win *win)
+{
+ uint32_t *pixel;
+
+ if (WS_FOCUSED(win->ws) && win->ws->focus == win)
+ pixel = MAXIMIZED(win) ?
+ &win->s->c[SWM_S_COLOR_FOCUS_MAXIMIZED].pixel :
+ &win->s->c[SWM_S_COLOR_FOCUS].pixel;
+ else
+ pixel = MAXIMIZED(win) ?
+ &win->s->c[SWM_S_COLOR_UNFOCUS_MAXIMIZED].pixel :
+ &win->s->c[SWM_S_COLOR_UNFOCUS].pixel;
+
+ xcb_change_window_attributes(conn, win->id,
+ XCB_CW_BORDER_PIXEL, pixel);
+}
+
+void
update_window(struct ws_win *win)
{
uint16_t mask;
xcb_flush(conn);
}
break;
+ case XCB_KEY_PRESS:
+ /* Ignore. */
+ xcb_allow_events(conn, XCB_ALLOW_ASYNC_KEYBOARD,
+ ((xcb_key_press_event_t *)evt)->time);
+ xcb_flush(conn);
+ break;
default:
event_handle(evt);
r = region_under(win->s, X(win) + WIDTH(win) / 2,
Y(win) + HEIGHT(win) / 2);
- if (r && r != win->ws->r) {
+ if (r != NULL && r != win->ws->r) {
+ if (clear_maximized(r->ws) > 0)
+ stack();
+
win_to_ws(win, r->ws->idx, 0);
+
+ /* Set focus on new ws. */
+ unfocus_win(r->ws->focus);
+ r->ws->focus = win;
+
set_region(r);
+ raise_window(win);
}
}
xcb_flush(conn);
}
break;
+ case XCB_KEY_PRESS:
+ /* Ignore. */
+ xcb_allow_events(conn, XCB_ALLOW_ASYNC_KEYBOARD,
+ ((xcb_key_press_event_t *)evt)->time);
+ xcb_flush(conn);
+ break;
default:
event_handle(evt);
xcb_flush(conn);
}
store_float_geom(win);
+
+ /* New region set to fullscreen layout. */
+ if (win->ws->cur_layout == &layouts[SWM_MAX_STACK]) {
+ stack();
+ focus_flush();
+ }
+
out:
free(qpr);
xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
strdup(r->s->c[SWM_S_COLOR_FOCUS].name))
== NULL)
err(1, "spawn_custom color focus");
+ } else if (strcasecmp(ap, "$color_focus_maximized") == 0) {
+ if ((real_args[c] =
+ strdup(r->s->c[SWM_S_COLOR_FOCUS_MAXIMIZED].name))
+ == NULL)
+ err(1, "spawn_custom color focus maximized");
} else if (strcasecmp(ap, "$color_unfocus") == 0) {
if ((real_args[c] =
strdup(r->s->c[SWM_S_COLOR_UNFOCUS].name))
== NULL)
err(1, "spawn_custom color unfocus");
+ } else if (strcasecmp(ap, "$color_unfocus_maximized") == 0) {
+ if ((real_args[c] =
+ strdup(r->s->c[SWM_S_COLOR_UNFOCUS_MAXIMIZED].name))
+ == NULL)
+ err(1, "spawn_custom color unfocus maximized");
} else if (strcasecmp(ap, "$region_index") == 0) {
if (asprintf(&real_args[c], "%d",
get_region_index(r) + 1) < 1)
spawn_insert(const char *name, const char *args, int flags)
{
struct spawn_prog *sp;
- char *arg, *dup, *ptr;
+ char *arg, *cp, *ptr;
DNPRINTF(SWM_D_SPAWN, "spawn_insert: %s[%s]\n", name, args);
err(1, "spawn_insert: strdup");
/* Convert the arguments to an argument list. */
- if ((ptr = dup = strdup(args)) == NULL)
+ if ((ptr = cp = strdup(args)) == NULL)
err(1, "spawn_insert: strdup");
while ((arg = argsep(&ptr)) != NULL) {
/* Null argument; skip it. */
if ((sp->argv[sp->argc - 1] = strdup(arg)) == NULL)
err(1, "spawn_insert: strdup");
}
- free(dup);
+ free(cp);
sp->flags = flags;
"FOCUSPREV",
"NOFOCUSONMAP",
"FOCUSONMAP_SINGLE",
+ "OBEYAPPFOCUSREQ",
};
/* SWM_Q_WS: retain '|' for back compat for now (2009-08-11) */
SWM_S_WINDOW_CLASS_ENABLED,
SWM_S_WINDOW_INSTANCE_ENABLED,
SWM_S_WINDOW_NAME_ENABLED,
- SWM_S_WORKSPACE_LIMIT
+ SWM_S_WORKSPACE_LIMIT,
+ SWM_S_WORKSPACE_NAME,
};
int
{
struct workspace *ws;
int i, ws_id, num_screens;
- char *b, *str;
+ char *b, *str, s[1024];
switch (flags) {
case SWM_S_BAR_ACTION:
else if (workspace_limit < 1)
workspace_limit = 1;
+ ewmh_update_desktops();
+ break;
+ case SWM_S_WORKSPACE_NAME:
+ if (getenv("SWM_STARTED") != NULL)
+ return (0);
+
+ bzero(s, sizeof s);
+ if (sscanf(value, "ws[%d]:%1023c", &ws_id, s) != 2)
+ errx(1, "invalid entry, should be 'ws[<idx>]:name'");
+ ws_id--;
+ if (ws_id < 0 || ws_id >= workspace_limit)
+ errx(1, "setconfvalue: workspace_name: invalid "
+ "workspace %d.", ws_id + 1);
+
num_screens = get_screen_count();
- for (i = 0; i < num_screens; i++) {
- xcb_change_property(conn, XCB_PROP_MODE_REPLACE,
- screens[i].root, ewmh[_NET_NUMBER_OF_DESKTOPS].atom,
- XCB_ATOM_CARDINAL, 32, 1, &workspace_limit);
+ for (i = 0; i < num_screens; ++i) {
+ ws = (struct workspace *)&screens[i].ws;
+
+ if (strlen(s) > 0) {
+ free(ws[ws_id].name);
+ if ((ws[ws_id].name = strdup(s)) == NULL)
+ err(1, "setconfvalue: workspace_name.");
+
+ ewmh_update_desktop_names();
+ ewmh_get_desktop_names();
+ }
}
break;
default:
int
setconfcolor(const char *selector, const char *value, int flags)
{
- setscreencolor(value,
- (selector == NULL || strlen(selector) == 0) ? -1 : atoi(selector),
- flags);
+ int first, last, i = 0, num_screens;
+
+ num_screens = get_screen_count();
+
+ /* conf screen indices begin at 1; treat vals <= 0 as 'all screens.' */
+ if (selector == NULL || strlen(selector) == 0 ||
+ (last = atoi(selector) - 1) < 0) {
+ first = 0;
+ last = num_screens - 1;
+ } else {
+ first = last;
+ }
+
+ if (last >= num_screens) {
+ add_startup_exception("invalid screen index: %d out of bounds "
+ "(maximum %d)", last + 1, num_screens);
+ return (1);
+ }
+
+ for (i = first; i <= last; ++i) {
+ setscreencolor(value, i, flags);
+
+ /*
+ * When setting focus/unfocus colors, we need to also
+ * set maximize colors to match if they haven't been customized.
+ */
+ if (flags == SWM_S_COLOR_FOCUS &&
+ !screens[i].c[SWM_S_COLOR_FOCUS_MAXIMIZED].manual)
+ setscreencolor(value, i, SWM_S_COLOR_FOCUS_MAXIMIZED);
+ else if (flags == SWM_S_COLOR_UNFOCUS &&
+ !screens[i].c[SWM_S_COLOR_UNFOCUS_MAXIMIZED].manual)
+ setscreencolor(value, i, SWM_S_COLOR_UNFOCUS_MAXIMIZED);
+
+ screens[i].c[flags].manual = 1;
+ }
+
return (0);
}
{ "clock_enabled", setconfvalue, SWM_S_CLOCK_ENABLED },
{ "clock_format", setconfvalue, SWM_S_CLOCK_FORMAT },
{ "color_focus", setconfcolor, SWM_S_COLOR_FOCUS },
+ { "color_focus_maximized", setconfcolor, SWM_S_COLOR_FOCUS_MAXIMIZED },
{ "color_unfocus", setconfcolor, SWM_S_COLOR_UNFOCUS },
+ { "color_unfocus_maximized", setconfcolor, SWM_S_COLOR_UNFOCUS_MAXIMIZED },
{ "cycle_empty", setconfvalue, SWM_S_CYCLE_EMPTY },
{ "cycle_visible", setconfvalue, SWM_S_CYCLE_VISIBLE },
{ "dialog_ratio", setconfvalue, SWM_S_DIALOG_RATIO },
{ "window_instance_enabled", setconfvalue, SWM_S_WINDOW_INSTANCE_ENABLED },
{ "window_name_enabled", setconfvalue, SWM_S_WINDOW_NAME_ENABLED },
{ "workspace_limit", setconfvalue, SWM_S_WORKSPACE_LIMIT },
+ { "name", setconfvalue, SWM_S_WORKSPACE_NAME },
};
void
}
struct ws_win *
-manage_window(xcb_window_t id, uint16_t mapped)
+manage_window(xcb_window_t id, int mapped)
{
- xcb_window_t trans = XCB_WINDOW_NONE;
struct ws_win *win, *ww;
- int ws_idx;
- char *class, *instance, *name;
struct swm_region *r;
struct pid_e *p;
struct quirk *qp;
- uint32_t i, wa[2], new_flags;
xcb_get_geometry_reply_t *gr;
+ xcb_window_t trans = XCB_WINDOW_NONE;
+ uint32_t i, wa[2], new_flags;
+ int ws_idx;
+ char *class, *instance, *name;
if ((win = find_window(id)) != NULL) {
DNPRINTF(SWM_D_MISC, "manage_window: win %#x already "
win->g_floatvalid = 1;
- if (ABOVE(win) && r && !MAXIMIZED(win) && (TRANS(win) ||
- win->ws->cur_layout != &layouts[SWM_MAX_STACK])) {
+ if (!MAXIMIZED(win) && !FULLSCREEN(win) &&
+ (TRANS(win) || (ABOVE(win) &&
+ win->ws->cur_layout != &layouts[SWM_MAX_STACK]))) {
WIDTH(win) = win->g_float.w;
HEIGHT(win) = win->g_float.h;
- if (r) {
+ if (r != NULL) {
update_floater(win);
focus_flush();
+ } else {
+ config_win(win, e);
+ xcb_flush(conn);
}
} else {
config_win(win, e);
focus_flush();
}
+#ifdef SWM_DEBUG
+char *
+get_source_type_label(uint32_t type)
+{
+ char *label;
+
+ switch (type) {
+ case EWMH_SOURCE_TYPE_NONE:
+ label = "None";
+ break;
+ case EWMH_SOURCE_TYPE_NORMAL:
+ label = "Normal";
+ break;
+ case EWMH_SOURCE_TYPE_OTHER:
+ label = "Other";
+ break;
+ default:
+ label = "Invalid";
+ }
+
+ return label;
+}
+#endif
+
void
clientmessage(xcb_client_message_event_t *e)
{
break;
}
- if (r && e->data.data32[0] <
- (uint32_t)workspace_limit) {
+ if (r && e->data.data32[0] < (uint32_t)workspace_limit) {
a.id = e->data.data32[0];
switchws(r, &a);
focus_flush();
}
if (e->type == ewmh[_NET_ACTIVE_WINDOW].atom) {
- DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_ACTIVE_WINDOW\n");
- if (WS_FOCUSED(win->ws))
- focus_win(win);
- else
- win->ws->focus_pending = win;
+ DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_ACTIVE_WINDOW, "
+ "source_type: %s(%d)\n",
+ get_source_type_label(e->data.data32[0]),
+ e->data.data32[0]);
+
+ /*
+ * Allow focus changes that are a result of direct user
+ * action and from applications that use the old EWMH spec.
+ */
+ if (e->data.data32[0] != EWMH_SOURCE_TYPE_NORMAL ||
+ win->quirks & SWM_Q_OBEYAPPFOCUSREQ) {
+ if (WS_FOCUSED(win->ws))
+ focus_win(win);
+ else
+ win->ws->focus_pending = win;
+ }
} else if (e->type == ewmh[_NET_CLOSE_WINDOW].atom) {
DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_CLOSE_WINDOW\n");
if (win->can_delete)
update_window(win);
} else {
- /* TODO: Change stack sizes */
- /* notify no change was made. */
+ /* Notify no change was made. */
config_win(win, NULL);
+ /* TODO: Change stack sizes */
}
} else if (e->type == ewmh[_NET_RESTACK_WINDOW].atom) {
DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_RESTACK_WINDOW\n");
ewmh_update_wm_state(win);
stack();
+ } else if (e->type == ewmh[_NET_WM_DESKTOP].atom) {
+ DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_WM_DESKTOP\n");
+ r = win->ws->r;
+
+ win_to_ws(win, e->data.data32[0], 1);
+
+ /* Restack if either the source or destination ws is mapped. */
+ if (r != NULL || win->ws->r != NULL) {
+ if (FLOATING(win))
+ load_float_geom(win);
+
+ stack();
+ }
}
focus_flush();
"skip %#x; region input window.\n",
wins[j]);
break;
+ } else if (r->bar->id == wins[j]) {
+ DNPRINTF(SWM_D_INIT, "grab_windows: "
+ "skip %#x; region bar.\n",
+ wins[j]);
+ break;
}
}
continue;
}
- state = getstate(wins[j]);
+ state = get_win_state(wins[j]);
manage = state != XCB_ICCCM_WM_STATE_WITHDRAWN;
mapped = gar->map_state == XCB_MAP_STATE_VIEWABLE;
if (mapped || manage)
continue;
}
- state = getstate(wins[j]);
+ state = get_win_state(wins[j]);
manage = state != XCB_ICCCM_WM_STATE_WITHDRAWN;
mapped = gar->map_state == XCB_MAP_STATE_VIEWABLE;
pc = xcb_icccm_get_wm_transient_for(conn, wins[j]);
screens[i].root = screen->root;
/* set default colors */
- setscreencolor("red", i + 1, SWM_S_COLOR_FOCUS);
- setscreencolor("rgb:88/88/88", i + 1, SWM_S_COLOR_UNFOCUS);
- setscreencolor("rgb:00/80/80", i + 1, SWM_S_COLOR_BAR_BORDER);
- setscreencolor("rgb:00/40/40", i + 1,
+ setscreencolor("red", i, SWM_S_COLOR_FOCUS);
+ setscreencolor("rgb:88/88/88", i, SWM_S_COLOR_UNFOCUS);
+ setscreencolor("rgb:00/80/80", i, SWM_S_COLOR_BAR_BORDER);
+ setscreencolor("rgb:00/40/40", i,
SWM_S_COLOR_BAR_BORDER_UNFOCUS);
- setscreencolor("black", i + 1, SWM_S_COLOR_BAR);
- setscreencolor("rgb:a0/a0/a0", i + 1, SWM_S_COLOR_BAR_FONT);
+ setscreencolor("black", i, SWM_S_COLOR_BAR);
+ setscreencolor("rgb:a0/a0/a0", i, SWM_S_COLOR_BAR_FONT);
+ setscreencolor("red", i, SWM_S_COLOR_FOCUS_MAXIMIZED);
+ setscreencolor("rgb:88/88/88", i,
+ SWM_S_COLOR_UNFOCUS_MAXIMIZED);
/* create graphics context on screen */
screens[i].bar_gc = xcb_generate_id(conn);
validate_spawns();
- /* grab existing windows (before we build the bars) */
- grab_windows();
-
if (getenv("SWM_STARTED") == NULL)
setenv("SWM_STARTED", "YES", 1);
TAILQ_FOREACH(r, &screens[i].rl, entry)
bar_setup(r);
+ /* Manage existing windows. */
+ grab_windows();
+
grabkeys();
stack();
bar_draw();