#define SH_INC_H(w) ((w)->sh.height_inc)
#define SWM_MAX_FONT_STEPS (3)
#define WINID(w) ((w) ? (w)->id : XCB_WINDOW_NONE)
+#define ACCEPTS_FOCUS(w) (!((w)->hints.flags & XCB_ICCCM_WM_HINT_INPUT) \
+ || ((w)->hints.input))
#define WS_FOCUSED(ws) ((ws)->r && (ws)->r->s->r_focus == (ws)->r)
#define YESNO(x) ((x) ? "yes" : "no")
#define ICONIC(w) ((w)->ewmh_flags & EWMH_F_HIDDEN)
xcb_window_t transient;
struct ws_win *focus_child; /* focus on child transient */
struct swm_geometry g; /* current geometry */
+ struct swm_geometry g_prev; /* prev configured geometry */
struct swm_geometry g_float; /* region coordinates */
bool g_floatvalid; /* g_float geometry validity */
bool mapped;
void focus_pointer(struct binding *, struct swm_region *, union arg *);
void focus_region(struct swm_region *);
void focus_win(struct ws_win *);
-#ifdef SWM_DEBUG
void focusin(xcb_focus_in_event_t *);
+#ifdef SWM_DEBUG
void focusout(xcb_focus_out_event_t *);
#endif
void focusrg(struct binding *, struct swm_region *, union arg *);
#endif
int32_t get_swm_ws(xcb_window_t);
bool get_urgent(struct ws_win *);
+#ifdef SWM_DEBUG
+char *get_win_input_model(struct ws_win *);
+#endif
char *get_win_name(xcb_window_t);
uint8_t get_win_state(xcb_window_t);
void get_wm_protocols(struct ws_win *);
void priorws(struct binding *, struct swm_region *, union arg *);
#ifdef SWM_DEBUG
void print_win_geom(xcb_window_t);
-void print_win_input_model(struct ws_win *);
#endif
void propertynotify(xcb_property_notify_event_t *);
void put_back_event(xcb_generic_event_t *);
break;
}
- if (asprintf(&s, "%#x wl:%d s:%d", win->id, widx, sidx) == -1)
+ if (asprintf(&s, "%#x f:%#x wl:%d s:%d im:%s", win->id,
+ win->frame, widx, sidx, get_win_input_model(win)) == -1)
return;
len = strlen(s);
struct ws_win *
find_window(xcb_window_t id)
{
- struct ws_win *win;
+ struct ws_win *win = NULL;
int i, j, num_screens;
xcb_query_tree_reply_t *qtr;
+ DNPRINTF(SWM_D_MISC, "find_window: id: %#x\n", id);
+
num_screens = get_screen_count();
for (i = 0; i < num_screens; i++)
for (j = 0; j < workspace_limit; j++)
if (id == win->id || id == win->frame)
return (win);
- /* win NULL */
/* If window isn't top-level, try to find managed ancestor. */
qtr = xcb_query_tree_reply(conn, xcb_query_tree(conn, id), NULL);
{
struct ws_win *cfw = NULL, *parent = NULL, *w, *tmpw;
struct workspace *ws;
- xcb_get_input_focus_reply_t *gifr;
+ xcb_get_input_focus_reply_t *gifr = NULL;
+ xcb_get_window_attributes_reply_t *war = NULL;
DNPRINTF(SWM_D_FOCUS, "focus_win: win %#x\n", WINID(win));
gifr->focus);
cfw = find_window(gifr->focus);
- if (cfw != NULL && cfw != win) {
- if (cfw->ws != ws && cfw->ws->r != NULL &&
- cfw->frame != XCB_WINDOW_NONE) {
- draw_frame(cfw);
- } else {
- unfocus_win(cfw);
+ if (cfw) {
+ if (cfw != win) {
+ if (cfw->ws != ws && cfw->ws->r != NULL &&
+ cfw->frame != XCB_WINDOW_NONE) {
+ draw_frame(cfw);
+ } else {
+ unfocus_win(cfw);
+ }
+ }
+ } else {
+ war = xcb_get_window_attributes_reply(conn,
+ xcb_get_window_attributes(conn, gifr->focus), NULL);
+ if (war && war->override_redirect && ws->focus == win) {
+ DNPRINTF(SWM_D_FOCUS, "focus_win: skip refocus "
+ "from override_redirect.\n");
+ goto out;
}
}
- free(gifr);
}
if (ws->focus != win) {
if (ws->r) {
/* Set input focus if no input hint, or indicated by hint. */
- if (!(win->hints.flags & XCB_ICCCM_WM_HINT_INPUT) ||
- win->hints.input) {
+ if (ACCEPTS_FOCUS(win)) {
DNPRINTF(SWM_D_FOCUS, "focus_win: set_input_focus: %#x,"
" revert-to: parent, time: %#x\n", win->id,
last_event_time);
}
out:
+ free(gifr);
+ free(war);
DNPRINTF(SWM_D_FOCUS, "focus_win: done.\n");
}
DNPRINTF(SWM_D_STACK, "stack_master: workspace: %d, rot: %s, "
"flip: %s\n", ws->idx, YESNO(rot), YESNO(flip));
+ memset(&cell, 0, sizeof(cell));
+
/* Prepare tiling variables, if needed. */
if ((winno = count_win(ws, false)) > 0) {
/* Find first tiled window. */
"(%d,%d) %d x %d, bordered: %s\n", win->id, wc[0], wc[1], wc[2],
wc[3], YESNO(win->bordered));
xcb_configure_window(conn, win->id, mask, wc);
- config_win(win, NULL);
+
+ /* ICCCM 4.2.3 Synthetic ConfigureNotify when moved and not resized. */
+ if ((X(win) != win->g_prev.x || Y(win) != win->g_prev.y) &&
+ (win->java || (WIDTH(win) == win->g_prev.w &&
+ HEIGHT(win) == win->g_prev.h))) {
+ /* Java has special needs when moved together with a resize. */
+ config_win(win, NULL);
+ }
+
+ win->g_prev = win->g;
}
struct event {
SIMPLEQ_HEAD(event_queue, event) events = SIMPLEQ_HEAD_INITIALIZER(events);
xcb_generic_event_t *
-get_next_event(bool wait)
+get_next_event(bool dowait)
{
struct event *ep;
xcb_generic_event_t *evt;
evt = ep->ev;
SIMPLEQ_REMOVE_HEAD(&events, entry);
free(ep);
- } else if (wait)
+ } else if (dowait)
evt = xcb_wait_for_event(conn);
else
evt = xcb_poll_for_event(conn);
struct ws_win *
manage_window(xcb_window_t id, int spawn_pos, bool mapping)
{
- struct ws_win *win, *ww;
+ struct ws_win *win = NULL, *ww;
struct swm_region *r;
struct pid_e *p;
struct quirk *qp;
#ifdef SWM_DEBUG
/* Must be after getting WM_HINTS and WM_PROTOCOLS. */
- print_win_input_model(win);
+ DNPRINTF(SWM_D_FOCUS, "manage_window: input_model: %s\n",
+ get_win_input_model(win));
#endif
/* Set initial quirks based on EWMH. */
DNPRINTF(SWM_D_EVENT, "expose: done\n");
}
-#ifdef SWM_DEBUG
void
focusin(xcb_focus_in_event_t *e)
{
+ struct ws_win *win;
+
DNPRINTF(SWM_D_EVENT, "focusin: win %#x, mode: %s(%u), "
"detail: %s(%u)\n", e->event, get_notify_mode_label(e->mode),
e->mode, get_notify_detail_label(e->detail), e->detail);
+ if ((win = find_window(e->event)) && win != win->ws->focus &&
+ win != win->ws->focus_pending &&
+ e->mode == XCB_NOTIFY_MODE_NORMAL) {
+ win->ws->focus_prev = win->ws->focus;
+ win->ws->focus = win;
+ win->ws->focus_pending = NULL;
+
+ if (win->ws->focus_prev)
+ draw_frame(win->ws->focus_prev);
+ draw_frame(win);
+ raise_window(win);
+ }
}
+#ifdef SWM_DEBUG
void
focusout(xcb_focus_out_event_t *e)
{
void
buttonpress(xcb_button_press_event_t *e)
{
- struct ws_win *win = NULL;
+ struct ws_win *win = NULL, *newf;
struct swm_region *r, *old_r;
struct action *ap;
struct binding *bp;
win = find_window(e->event);
}
- if (win)
- focus_win(get_focus_magic(win));
+ if (win) {
+ newf = get_focus_magic(win);
+ if (win->ws->focus == newf && newf != win) {
+ if (win->focus_child == win)
+ win->focus_child = NULL;
+ newf = win;
+ }
+ focus_win(newf);
+ }
/* Handle any bound action. */
bp = binding_lookup(CLEANMASK(e->state), BTNBIND, e->detail);
}
#ifdef SWM_DEBUG
-void
-print_win_input_model(struct ws_win *win)
+char *
+get_win_input_model(struct ws_win *win)
{
char *inputmodel;
/*
* Globally Active False Present
*/
- if (!(win->hints.flags & XCB_ICCCM_WM_HINT_INPUT) || win->hints.input)
+ if (ACCEPTS_FOCUS(win))
inputmodel = (win->take_focus) ? "Locally Active" : "Passive";
else
inputmodel = (win->take_focus) ? "Globally Active" : "No Input";
- DNPRINTF(SWM_D_FOCUS, "print_win_input_model: win %#x, model: %s\n",
- win->id, inputmodel);
+ return inputmodel;
}
void
maprequest(xcb_map_request_event_t *e)
{
struct ws_win *win, *w = NULL;
- xcb_get_window_attributes_reply_t *war;
DNPRINTF(SWM_D_EVENT, "maprequest: win %#x\n",
e->window);
- war = xcb_get_window_attributes_reply(conn,
- xcb_get_window_attributes(conn, e->window),
- NULL);
- if (war == NULL) {
- DNPRINTF(SWM_D_EVENT, "maprequest: window lost.\n");
- goto out;
- }
-
- if (war->override_redirect) {
- DNPRINTF(SWM_D_EVENT, "maprequest: override_redirect; "
- "skipping.\n");
- goto out;
- }
-
win = manage_window(e->window, spawn_position, true);
if (win == NULL)
goto out;
/* The new window should get focus; prepare. */
if (focus_mode != SWM_FOCUS_FOLLOW &&
- !(win->quirks & SWM_Q_NOFOCUSONMAP) &&
- (!(win->hints.flags & XCB_ICCCM_WM_HINT_INPUT) ||
- (win->hints.flags & XCB_ICCCM_WM_HINT_INPUT &&
- win->hints.input))) {
+ !(win->quirks & SWM_Q_NOFOCUSONMAP) && ACCEPTS_FOCUS(win)) {
if (win->quirks & SWM_Q_FOCUSONMAP_SINGLE) {
/* See if other wins of same type are already mapped. */
TAILQ_FOREACH(w, &win->ws->winlist, entry) {
if (focus_mode == SWM_FOCUS_DEFAULT)
event_drain(XCB_ENTER_NOTIFY);
out:
- free(war);
DNPRINTF(SWM_D_EVENT, "maprequest: done.\n");
}
print_win_geom(e->root);
#endif
/* add bars to all regions */
- for (i = 0; i < num_screens; i++) {
- TAILQ_FOREACH(r, &screens[i].rl, entry)
- bar_setup(r);
- }
+ TAILQ_FOREACH(r, &screens[i].rl, entry)
+ bar_setup(r);
/* Stack all regions. */
TAILQ_FOREACH(r, &screens[i].rl, entry)
stack(r);
- /* Make sure a region has focus on each screen. */
- for (i = 0; i < num_screens; i++) {
- if (screens[i].r_focus == NULL) {
- r = TAILQ_FIRST(&screens[i].rl);
- if (r != NULL)
- focus_region(r);
- }
+ /* Make sure a region has focus. */
+ if (screens[i].r_focus == NULL) {
+ r = TAILQ_FIRST(&screens[i].rl);
+ if (r != NULL)
+ focus_region(r);
}
focus_flush();
/* Update workspace state and bar on all regions. */
- for (i = 0; i < num_screens; i++)
- TAILQ_FOREACH(r, &screens[i].rl, entry) {
- r->ws->state = SWM_WS_STATE_MAPPED;
- bar_draw(r->bar);
- }
+ TAILQ_FOREACH(r, &screens[i].rl, entry) {
+ r->ws->state = SWM_WS_STATE_MAPPED;
+ bar_draw(r->bar);
+ }
}
void
EVENT(XCB_DESTROY_NOTIFY, destroynotify);
EVENT(XCB_ENTER_NOTIFY, enternotify);
EVENT(XCB_EXPOSE, expose);
-#ifdef SWM_DEBUG
EVENT(XCB_FOCUS_IN, focusin);
+#ifdef SWM_DEBUG
EVENT(XCB_FOCUS_OUT, focusout);
#endif
/*EVENT(XCB_GRAPHICS_EXPOSURE, );*/