#define XCB_ICCCM_SIZE_HINT_P_MIN_SIZE XCB_SIZE_HINT_P_MIN_SIZE
#define XCB_ICCCM_SIZE_HINT_P_MAX_SIZE XCB_SIZE_HINT_P_MAX_SIZE
#define XCB_ICCCM_SIZE_HINT_P_RESIZE_INC XCB_SIZE_HINT_P_RESIZE_INC
+#define XCB_ICCCM_WM_HINT_INPUT XCB_WM_HINT_INPUT
#define XCB_ICCCM_WM_HINT_X_URGENCY XCB_WM_HINT_X_URGENCY
#define XCB_ICCCM_WM_STATE_ICONIC XCB_WM_STATE_ICONIC
#define XCB_ICCCM_WM_STATE_WITHDRAWN XCB_WM_STATE_WITHDRAWN
xcb_atom_t a_swm_ws;
volatile sig_atomic_t running = 1;
volatile sig_atomic_t restart_wm = 0;
+xcb_timestamp_t last_event_time = 0;
int outputs = 0;
-/*int last_focus_event = FocusOut;*/
int other_wm;
int ss_enabled = 0;
int xrandr_support;
Display *display;
xcb_connection_t *conn;
xcb_key_symbols_t *syms;
-xcb_timestamp_t last_event_time;
int cycle_empty = 0;
int cycle_visible = 0;
struct layout *cur_layout; /* current layout handlers */
struct ws_win *focus; /* may be NULL */
struct ws_win *focus_prev; /* may be NULL */
+ struct ws_win *focus_pending; /* may be NULL */
struct swm_region *r; /* may be NULL */
struct swm_region *old_r; /* may be NULL */
struct ws_win_list winlist; /* list of windows in ws */
#define SWM_ARG_ID_FOCUSNEXT (0)
#define SWM_ARG_ID_FOCUSPREV (1)
#define SWM_ARG_ID_FOCUSMAIN (2)
-#define SWM_ARG_ID_FOCUSCUR (4)
#define SWM_ARG_ID_SWAPNEXT (10)
#define SWM_ARG_ID_SWAPPREV (11)
#define SWM_ARG_ID_SWAPMAIN (12)
char *get_notify_detail_label(uint8_t);
char *get_notify_mode_label(uint8_t);
#endif
+struct ws_win *get_region_focus(struct swm_region *);
xcb_screen_t *get_screen(int);
char *get_win_name(xcb_window_t);
uint32_t getstate(xcb_window_t);
int32_t v = 0;
xcb_get_property_reply_t *pr = NULL;
-
pr = xcb_get_property_reply(conn,
xcb_get_property(conn, 0, win->id, a_swm_iconic,
XCB_ATOM_INTEGER, 0, 1), NULL);
{
uint16_t data[2] = { state, XCB_ATOM_NONE };
- DNPRINTF(SWM_D_EVENT, "set_win_state: window: 0x%x\n", win->id);
+ DNPRINTF(SWM_D_EVENT, "set_win_state: window: 0x%x, state: %u\n",
+ win->id, state);
if (win == NULL)
return;
struct swm_region *this_r, *other_r;
struct ws_win *win;
struct workspace *new_ws, *old_ws;
- union arg a;
if (!(r && r->s))
return;
if (new_ws == old_ws)
return;
+ unfocus_win(old_ws->focus);
+
other_r = new_ws->r;
if (other_r == NULL) {
/* the other workspace is hidden, hide this one */
stack();
- a.id = SWM_ARG_ID_FOCUSCUR;
- focus(new_ws->r, &a);
-
/* unmap old windows */
if (unmap_old)
TAILQ_FOREACH(win, &old_ws->winlist, entry)
unmap_window(win);
- /* make sure bar gets updated if ws is empty */
- if (!new_ws->focus)
+ new_ws->focus_pending = get_region_focus(new_ws->r);
+
+ if (new_ws->focus_pending) {
+ /* if workspaces were swapped, then don't wait to set focus */
+ if (old_ws->r)
+ focus_win(new_ws->focus);
+ } else {
+ /* make sure bar gets updated if ws is empty */
bar_update();
+ }
focus_flush();
cyclescr(struct swm_region *r, union arg *args)
{
struct swm_region *rr = NULL;
- union arg a;
int i, x, y, num_screens;
num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
xcb_warp_pointer(conn, XCB_WINDOW_NONE, rr->s[i].root, 0, 0, 0, 0,
x, y);
- a.id = SWM_ARG_ID_FOCUSCUR;
- focus(rr, &a);
+ rr->ws->focus = get_region_focus(rr);
if (rr->ws->focus) {
/* move to focus window */
struct ws_win *cur_focus;
struct ws_win_list *wl;
-
DNPRINTF(SWM_D_WS, "swapwin: 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);
return get_focus_magic(winfocus);
}
+struct ws_win *
+get_region_focus(struct swm_region *r)
+{
+ struct ws_win *winfocus = NULL;
+
+ if (!(r && r->ws))
+ return NULL;
+
+ if (r->ws->focus && !r->ws->focus->iconic)
+ winfocus = r->ws->focus;
+ else if (r->ws->focus_prev && !r->ws->focus_prev->iconic)
+ winfocus = r->ws->focus_prev;
+ else
+ TAILQ_FOREACH(winfocus, &r->ws->winlist, entry)
+ if (!winfocus->iconic)
+ break;
+
+ return get_focus_magic(winfocus);
+}
+
void
focus(struct swm_region *r, union arg *args)
{
- struct ws_win *winfocus = NULL, *head;
- struct ws_win *cur_focus = NULL;
+ struct ws_win *head, *cur_focus = NULL, *winfocus = NULL;
struct ws_win_list *wl = NULL;
struct workspace *ws = NULL;
int all_iconics;
DNPRINTF(SWM_D_FOCUS, "focus: id: %d\n", args->id);
- /* treat FOCUS_CUR special */
- if (args->id == SWM_ARG_ID_FOCUSCUR) {
- if (r->ws->focus && r->ws->focus->iconic == 0)
- winfocus = r->ws->focus;
- else if (r->ws->focus_prev && r->ws->focus_prev->iconic == 0)
- winfocus = r->ws->focus_prev;
- else
- TAILQ_FOREACH(winfocus, &r->ws->winlist, entry)
- if (winfocus->iconic == 0)
- break;
-
- r->ws->focus = get_focus_magic(winfocus);
- return;
- }
-
if ((cur_focus = r->ws->focus) == NULL)
return;
ws = r->ws;
cycle_layout(struct swm_region *r, union arg *args)
{
struct workspace *ws = r->ws;
- union arg a;
/* suppress unused warning since var is needed */
(void)args;
stack();
bar_update();
- a.id = SWM_ARG_ID_FOCUSCUR;
- focus(r, &a);
- focus_win(r->ws->focus);
+ focus_win(get_region_focus(r));
focus_flush();
}
int w_inc = 1, h_inc, w_base = 1, h_base;
int hrh, extra = 0, h_slice, last_h = 0;
int split, colno, winno, mwin, msize, mscale;
- int remain, missing, v_slice, reconfigure;
+ int remain, missing, v_slice, reconfigure = 0;
int bordered = 1;
DNPRINTF(SWM_D_STACK, "stack_master: workspace: %d, rot: %s, "
xcb_flush(conn);
}
-
int
floating_toggle_win(struct ws_win *win)
{
floating_toggle(struct swm_region *r, union arg *args)
{
struct ws_win *win = r->ws->focus;
- union arg a;
/* suppress unused warning since var is needed */
(void)args;
stack();
- if (win == win->ws->focus) {
- a.id = SWM_ARG_ID_FOCUSCUR;
- focus(win->ws->r, &a);
- focus_win(win->ws->focus);
- }
+ if (win == win->ws->focus)
+ focus_win(win);
focus_flush();
}
move(win, args);
}
-
/* user/key callable function IDs */
enum keyfuncid {
KF_BAR_TOGGLE,
{ "layout", setlayout, 0 },
};
-
int
conf_load(char *filename, int keymapping)
{
char *line, *cp, *optsub, *optval;
size_t linelen, lineno = 0;
int wordlen, i, optidx;
- struct config_option *opt;
+ struct config_option *opt = NULL;
DNPRINTF(SWM_D_CONF, "conf_load: begin\n");
filename, lineno, wordlen, cp);
goto out;
}
- if (keymapping && strcmp(opt->optname, "bind")) {
+ if (keymapping && opt && strcmp(opt->optname, "bind")) {
warnx("%s: line %zd: invalid option %.*s",
filename, lineno, wordlen, cp);
goto out;
{
xcb_window_t trans = XCB_WINDOW_NONE;
struct ws_win *win, *ww;
- int ws_idx, border_me = 0;
+ int ws_idx;
char ws_idx_str[SWM_PROPLEN];
struct swm_region *r;
struct pid_e *p;
struct quirk *qp;
- uint32_t event_mask, i;
+ uint32_t i, wa[2];
xcb_icccm_get_wm_protocols_reply_t wpr;
if ((win = find_window(id)) != NULL) {
/* Ignore window border if there is one. */
WIDTH(win) = win->wa->width;
HEIGHT(win) = win->wa->height;
- X(win) = win->wa->x + win->wa->border_width;
- Y(win) = win->wa->y + win->wa->border_width;
- win->bordered = 0;
+ X(win) = win->wa->x + win->wa->border_width - border_width;
+ Y(win) = win->wa->y + win->wa->border_width - border_width;
+ win->bordered = 1;
win->mapped = mapped;
win->floatmaxed = 0;
win->ewmh_flags = 0;
} else if (trans && (ww = find_window(trans)) != NULL) {
/* Launch transients in the same ws as parent. */
win->ws = ww->ws;
- border_me = 1;
} else {
win->ws = r->ws;
}
DNPRINTF(SWM_D_CLASS, "manage_window: java window "
"detected.\n");
win->java = 1;
- border_me = 1;
}
TAILQ_FOREACH(qp, &quirks, entry) {
!strcmp(win->ch.instance_name, qp->name)) {
DNPRINTF(SWM_D_CLASS, "manage_window: on quirks"
"list; mask: 0x%lx\n", qp->quirk);
- if (qp->quirk & SWM_Q_FLOAT) {
+ if (qp->quirk & SWM_Q_FLOAT)
win->floating = 1;
- border_me = 1;
- }
win->quirks = qp->quirk;
}
}
}
/* Alter window position if quirky */
- if (win->quirks & SWM_Q_ANYWHERE) {
+ if (win->quirks & SWM_Q_ANYWHERE)
win->manual = 1;
- border_me = 1;
- }
/* Reset font sizes (the bruteforce way; no default keybinding). */
if (win->quirks & SWM_Q_XTERM_FONTADJ) {
fake_keypress(win, XK_KP_Add, XCB_MOD_MASK_SHIFT);
}
- if (border_me) {
- win->bordered = 1;
- X(win) -= border_width;
- Y(win) -= border_width;
- }
-
/* Make sure window is positioned inside its region, if its active. */
- if (win->ws->r)
+ if (win->ws->r) {
constrain_window(win, win->ws->r, 0);
-
- if (win->ws->r || border_me)
update_window(win);
+ }
- /* Select which X events to monitor. */
- event_mask = XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_FOCUS_CHANGE |
- XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_STRUCTURE_NOTIFY;
+ /* Select which X events to monitor and set border pixel color. */
+ wa[0] = win->s->c[SWM_S_COLOR_UNFOCUS].pixel;
+ wa[1] = XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_PROPERTY_CHANGE |
+ XCB_EVENT_MASK_STRUCTURE_NOTIFY;
#ifdef SWM_DEBUG
- event_mask |= XCB_EVENT_MASK_LEAVE_WINDOW;
+ wa[1] |= XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_FOCUS_CHANGE;
#endif
- xcb_change_window_attributes(conn, win->id, XCB_CW_EVENT_MASK,
- &event_mask);
+ xcb_change_window_attributes(conn, win->id, XCB_CW_BORDER_PIXEL |
+ XCB_CW_EVENT_MASK, wa);
out:
/* Figure out where to stack the window in the workspace. */
parent->focus_child = NULL;
}
- focus_win(get_focus_prev(win));
-
TAILQ_REMOVE(&win->ws->winlist, win, entry);
TAILQ_INSERT_TAIL(&win->ws->unmanagedlist, win, entry);
}
return;
}
- /* make sure we focus on something */
- win->floating = 0;
+ /* If we were focused, make sure we focus on something else. */
+ if (win == win->ws->focus)
+ win->ws->focus_pending = get_focus_prev(win);
unmanage_window(win);
- free_window(win);
-
stack();
+ if (win->ws->focus_pending) {
+ focus_win(win->ws->focus_pending);
+ win->ws->focus_pending = NULL;
+ }
+
+ free_window(win);
+
focus_flush();
}
win->mapped = 1;
set_win_state(win, XCB_ICCCM_WM_STATE_NORMAL);
- /* Focus on window if it is selected. */
- if (win->ws->focus == win)
+ if (win->ws->focus_pending == win) {
focus_win(win);
+ win->ws->focus_pending = NULL;
+ }
xcb_flush(conn);
}
stack();
/* The new window should get focus. */
- win->ws->focus = get_focus_magic(win);
+ win->ws->focus_pending = get_focus_magic(win);
/* Ignore EnterNotify to handle the mapnotify without interference. */
if (focus_mode == SWM_FOCUS_DEFAULT)
if (e->atom == a_swm_iconic) {
if (e->state == XCB_PROPERTY_DELETE) {
/* The window is no longer iconic, restack ws. */
+ win->ws->focus_pending = get_focus_magic(win);
stack();
- /* The window should get focus. */
- win->ws->focus = get_focus_magic(win);
-
/* Flush EnterNotify for mapnotify, if needed. */
focus_flush();
return;
} else if (e->state == XCB_PROPERTY_NEW_VALUE) {
- win->ws->focus = NULL;
-
+ win->ws->focus_pending = get_focus_prev(win);
unfocus_win(win);
unmap_window(win);
if (win->ws->r) {
- focus_win(get_focus_prev(win));
stack();
+ focus_win(win->ws->focus_pending);
+ win->ws->focus_pending = NULL;
focus_flush();
}
}
} else if (e->atom == a_state && e->state == XCB_PROPERTY_NEW_VALUE) {
- /* Focus on window if it is selected. */
- if (win->ws->focus == win)
+ /* State just changed, make sure it gets focused if mapped. */
+ if (win->mapped && win->ws->focus_pending == win) {
+ win->ws->focus_pending = NULL;
focus_win(win);
+ }
}
switch (e->atom) {
return;
if (getstate(e->window) == XCB_ICCCM_WM_STATE_NORMAL) {
+ /* If we were focused, make sure we focus on something else. */
+ if (win == win->ws->focus)
+ win->ws->focus_pending = get_focus_prev(win);
+
+ win->mapped = 0;
+ set_win_state(win, XCB_ICCCM_WM_STATE_ICONIC);
+
unmanage_window(win);
stack();
+
+ if (win->ws->focus_pending) {
+ focus_win(win->ws->focus_pending);
+ win->ws->focus_pending = NULL;
+ }
+
focus_flush();
}
}
ws->idx = j;
ws->name = NULL;
ws->focus = NULL;
+ ws->focus_prev = NULL;
+ ws->focus_pending = NULL;
ws->r = NULL;
ws->old_r = NULL;
TAILQ_INIT(&ws->winlist);
{
struct swm_region *r, *rr;
struct ws_win *winfocus = NULL;
- union arg a;
char conf[PATH_MAX], *cfile = NULL;
struct stat sb;
int xfd, i, num_screens;
rr->s[0].root, 0, 0, 0, 0, X(rr),
Y(rr) + (bar_enabled ? bar_height : 0));
- a.id = SWM_ARG_ID_FOCUSCUR;
- focus(rr, &a);
- focus_win(rr->ws->focus);
+ focus_win(get_region_focus(rr));
focus_flush();
winfocus = NULL;
continue;