* Copyright (c) 2009 Pierre-Yves Ritschard <pyr@spootnik.org>
* Copyright (c) 2010 Tuukka Kataja <stuge@xor.fi>
* Copyright (c) 2011 Jason L. Wright <jason@thought.net>
- * Copyright (c) 2011-2015 Reginald Kennedy <rk@rejii.com>
+ * Copyright (c) 2011-2016 Reginald Kennedy <rk@rejii.com>
* Copyright (c) 2011-2012 Lawrence Teo <lteo@lteo.net>
* Copyright (c) 2011-2012 Tiago Cunha <tcunha@gmx.com>
* Copyright (c) 2012-2015 David Hill <dhill@mindcry.org>
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/*
- * Much code and ideas taken from dwm under the following license:
- * MIT/X Consortium License
- *
- * 2006-2008 Anselm R Garbe <garbeam at gmail dot com>
- * 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
- * 2006-2007 Jukka Salmi <jukka at salmi dot ch>
- * 2007 Premysl Hruby <dfenze at gmail dot com>
- * 2007 Szabolcs Nagy <nszabolcs at gmail dot com>
- * 2007 Christof Musik <christof at sendfax dot de>
- * 2007-2008 Enno Gottox Boland <gottox at s01 dot de>
- * 2007-2008 Peter Hartlich <sgkkr at hartlich dot com>
- * 2008 Martin Hurton <martin dot hurton at gmail dot com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
/* kernel includes */
#include <sys/types.h>
#define MOUSEMASK (BUTTONMASK|XCB_EVENT_MASK_POINTER_MOTION)
#define SWM_PROPLEN (16)
#define SWM_FUNCNAME_LEN (32)
-#define SWM_KEYS_LEN (255)
#define SWM_QUIRK_LEN (64)
#define X(r) ((r)->g.x)
#define Y(r) ((r)->g.y)
#define WIDTH(r) ((r)->g.w)
#define HEIGHT(r) ((r)->g.h)
-#define BORDER(w) ((w)->bordered ? border_width : 0)
#define MAX_X(r) ((r)->g.x + (r)->g.w)
#define MAX_Y(r) ((r)->g.y + (r)->g.h)
#define SH_MIN(w) ((w)->sh.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE)
#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)
#define SWM_FOCUS_FOLLOW (1)
#define SWM_FOCUS_MANUAL (2)
-#define SWM_CK_NONE (0)
#define SWM_CK_ALL (0xf)
#define SWM_CK_FOCUS (0x1)
#define SWM_CK_POINTER (0x2)
#define SWM_CK_FALLBACK (0x4)
#define SWM_CK_REGION (0x8)
-#define SWM_G_ALL (0xf)
-#define SWM_G_SIZE (0x1)
-#define SWM_G_POS (0x2)
-
#define SWM_CONF_DEFAULT (0)
#define SWM_CONF_KEYMAPPING (1)
xcb_atom_t a_state;
xcb_atom_t a_prot;
xcb_atom_t a_delete;
+xcb_atom_t a_net_frame_extents;
xcb_atom_t a_net_wm_check;
xcb_atom_t a_net_supported;
xcb_atom_t a_takefocus;
bool java_workaround = true;
bool verbose_layout = false;
#ifdef SWM_DEBUG
+bool debug_enabled;
time_t time_started;
#endif
pid_t bar_pid;
xcb_window_t id;
xcb_pixmap_t buffer;
struct swm_geometry g;
+ struct swm_region *r; /* Associated region. */
};
/* virtual "screens" */
};
TAILQ_HEAD(swm_region_list, swm_region);
+enum {
+ SWM_WIN_STATE_REPARENTING,
+ SWM_WIN_STATE_REPARENTED,
+ SWM_WIN_STATE_UNPARENTING,
+ SWM_WIN_STATE_UNPARENTED,
+};
+
struct ws_win {
TAILQ_ENTRY(ws_win) entry;
TAILQ_ENTRY(ws_win) stack_entry;
xcb_window_t id;
+ xcb_window_t frame;
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;
+ uint8_t state;
bool bordered;
uint32_t ewmh_flags;
int font_size_boundary[SWM_MAX_FONT_STEPS];
xcb_size_hints_t sh;
xcb_icccm_get_wm_class_reply_t ch;
xcb_icccm_wm_hints_t hints;
+#ifdef SWM_DEBUG
+ xcb_window_t debug;
+#endif
};
TAILQ_HEAD(ws_win_list, ws_win);
TAILQ_HEAD(ws_win_stack, ws_win);
struct pid_list pidlist = TAILQ_HEAD_INITIALIZER(pidlist);
/* layout handlers */
-void stack(void);
+void stack(struct swm_region *);
void vertical_config(struct workspace *, int);
void vertical_stack(struct workspace *, struct swm_geometry *);
void horizontal_config(struct workspace *, int);
#define SWM_ARG_ID_CYCLEWS_MOVE_DOWN (47)
#define SWM_ARG_ID_STACKINC (50)
#define SWM_ARG_ID_STACKDEC (51)
-#define SWM_ARG_ID_SS_ALL (60)
-#define SWM_ARG_ID_SS_WINDOW (61)
#define SWM_ARG_ID_DONTCENTER (70)
#define SWM_ARG_ID_CENTER (71)
#define SWM_ARG_ID_KILLWINDOW (80)
#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)
#define SWM_ARG_ID_CYCLERG_MOVE_UP (112)
_NET_DESKTOP_VIEWPORT,
_NET_MOVERESIZE_WINDOW,
_NET_NUMBER_OF_DESKTOPS,
+ _NET_REQUEST_FRAME_EXTENTS,
_NET_RESTACK_WINDOW,
_NET_WM_ACTION_ABOVE,
_NET_WM_ACTION_CLOSE,
{"_NET_DESKTOP_VIEWPORT", XCB_ATOM_NONE},
{"_NET_MOVERESIZE_WINDOW", XCB_ATOM_NONE},
{"_NET_NUMBER_OF_DESKTOPS", XCB_ATOM_NONE},
+ {"_NET_REQUEST_FRAME_EXTENTS", XCB_ATOM_NONE},
{"_NET_RESTACK_WINDOW", XCB_ATOM_NONE},
{"_NET_WM_ACTION_ABOVE", XCB_ATOM_NONE},
{"_NET_WM_ACTION_CLOSE", XCB_ATOM_NONE},
FN_WS_PREV_ALL,
FN_WS_PREV_MOVE,
FN_WS_PRIOR,
- FN_DUMPWINS, /* MUST BE LAST */
+ /* SWM_DEBUG actions MUST be here: */
+ FN_DEBUG_TOGGLE,
+ FN_DUMPWINS,
+ /* ALWAYS last: */
FN_INVALID
};
int bar_extra_update(void);
void bar_fmt(const char *, char *, struct swm_region *, size_t);
void bar_fmt_expand(char *, size_t);
-void bar_draw(void);
+void bar_draw(struct swm_bar *);
void bar_print(struct swm_region *, const char *);
void bar_print_legacy(struct swm_region *, const char *);
void bar_replace(char *, char *, struct swm_region *, size_t);
void cycle_layout(struct binding *, struct swm_region *, union arg *);
void cyclerg(struct binding *, struct swm_region *, union arg *);
void cyclews(struct binding *, struct swm_region *, union arg *);
+#ifdef SWM_DEBUG
+void debug_refresh(struct ws_win *);
+#endif
+void debug_toggle(struct binding *, struct swm_region *, union arg *);
void destroynotify(xcb_destroy_notify_event_t *);
void dumpwins(struct binding *, struct swm_region *, union arg *);
int enable_wm(void);
char *expand_tilde(const char *);
void expose(xcb_expose_event_t *);
void fake_keypress(struct ws_win *, xcb_keysym_t, uint16_t);
+struct swm_bar *find_bar(xcb_window_t);
+struct ws_win *find_frame_window(xcb_window_t);
struct pid_e *find_pid(pid_t);
+struct swm_region *find_region(xcb_window_t);
struct ws_win *find_unmanaged_window(xcb_window_t);
struct ws_win *find_window(xcb_window_t);
void floating_toggle(struct binding *, struct swm_region *, union arg *);
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 *);
void region_containment(struct ws_win *, struct swm_region *, int);
struct swm_region *region_under(struct swm_screen *, int, int);
void regionize(struct ws_win *, int, int);
+void reparent_window(struct ws_win *);
+void reparentnotify(xcb_reparent_notify_event_t *);
void resize(struct binding *, struct swm_region *, union arg *);
void resize_win(struct ws_win *, struct binding *, int);
void restart(struct binding *, struct swm_region *, union arg *);
void unmap_all(void);
void unmap_window(struct ws_win *);
void unmapnotify(xcb_unmap_notify_event_t *);
+void unparent_window(struct ws_win *);
void update_floater(struct ws_win *);
void update_modkey(uint16_t);
void update_win_stacking(struct ws_win *);
void update_window(struct ws_win *);
-void update_window_color(struct ws_win *);
+void draw_frame(struct ws_win *);
void update_wm_state(struct ws_win *win);
void updatenumlockmask(void);
void validate_spawns(void);
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win,
a_net_wm_check, XCB_ATOM_WINDOW, 32, 1, &win);
- /*
- * Impersonate LG3D non-reparenting WM, written by Sun, to
- * workaround a Java GUI rendering issue.
- */
- if (java_workaround)
- xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win,
- ewmh[_NET_WM_NAME].atom, a_utf8_string,
- 8, strlen("LG3D"), "LG3D");
- else
- xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win,
- ewmh[_NET_WM_NAME].atom, a_utf8_string,
- 8, strlen("spectrwm"), "spectrwm");
+ xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win,
+ ewmh[_NET_WM_NAME].atom, a_utf8_string,
+ 8, strlen("spectrwm"), "spectrwm");
/* Report supported atoms */
xcb_delete_property(conn, root, a_net_supported);
}
}
- update_window_color(win);
+ draw_frame(win);
raise_window(win);
}
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", w->id, wa->map_state,
+ DPRINTF("win %#x (%#x), map_state: %d, state: %u, "
+ "transient: %#x\n", w->frame, w->id, wa->map_state,
state, w->transient);
free(wa);
} else
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)),
+ DPRINTF("win %#x (%#x), fs: %s, maximized: %s, above: %s, "
+ "iconic: %s\n", w->frame, w->id, YESNO(FULLSCREEN(w)),
YESNO(MAXIMIZED(w)), YESNO(ABOVE(w)), YESNO(ICONIC(w)));
}
DPRINTF("=================================\n");
}
+
+void
+debug_toggle(struct binding *b, struct swm_region *r, union arg *s)
+{
+ struct ws_win *win;
+ int num_screens, i, j;
+
+ /* Suppress warnings. */
+ (void)b;
+ (void)r;
+ (void)s;
+
+ DNPRINTF(SWM_D_MISC, "debug_toggle\n");
+
+ debug_enabled = !debug_enabled;
+
+ num_screens = get_screen_count();
+ for (i = 0; i < num_screens; i++)
+ for (j = 0; j < workspace_limit; j++)
+ TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry)
+ debug_refresh(win);
+
+ xcb_flush(conn);
+}
+
+void
+debug_refresh(struct ws_win *win)
+{
+ struct ws_win *w;
+ XftDraw *draw;
+ XGlyphInfo info;
+ GC l_draw;
+ XGCValues l_gcv;
+ XRectangle l_ibox, l_lbox;
+ xcb_rectangle_t rect;
+ size_t len;
+ uint32_t wc[4], mask, width, height, gcv[1];
+ int widx, sidx;
+ char *s;
+ xcb_screen_t *screen;
+
+ if (debug_enabled) {
+ /* Create debug window if it doesn't exist. */
+ if (win->debug == XCB_WINDOW_NONE) {
+ if ((screen = get_screen(win->s->idx)) == NULL)
+ errx(1, "ERROR: can't get screen %d.",
+ win->s->idx);
+
+ win->debug = xcb_generate_id(conn);
+ wc[0] = win->s->c[SWM_S_COLOR_BAR].pixel;
+ wc[1] = win->s->c[SWM_S_COLOR_BAR_BORDER].pixel;
+ wc[2] = screen->default_colormap;
+
+ xcb_create_window(conn, screen->root_depth, win->debug,
+ win->frame, 0, 0, 10, 10, 1,
+ XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual,
+ XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL |
+ XCB_CW_COLORMAP, wc);
+
+ xcb_map_window(conn, win->debug);
+ }
+
+ /* Determine workspace window list index. */
+ widx = 0;
+ TAILQ_FOREACH(w, &win->ws->winlist, entry) {
+ ++widx;
+ if (w == win)
+ break;
+ }
+
+ /* Determine stacking index (top down). */
+ sidx = 0;
+ TAILQ_FOREACH(w, &win->ws->stack, stack_entry) {
+ ++sidx;
+ if (w == win)
+ break;
+ }
+
+ 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);
+
+ /* Update window to an appropriate dimension. */
+ if (bar_font_legacy) {
+ XmbTextExtents(bar_fs, s, len, &l_ibox, &l_lbox);
+ width = l_lbox.width + 4;
+ height = bar_fs_extents->max_logical_extent.height + 4;
+ } else {
+ XftTextExtentsUtf8(display, bar_font, (FcChar8 *)s, len,
+ &info);
+ width = info.width + 4;
+ height = bar_font->height + 4;
+ }
+
+ mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
+ XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
+ if (win->bordered)
+ wc[0] = wc[1] = border_width;
+ else
+ wc[0] = wc[1] = 0;
+
+ wc[2] = width;
+ wc[3] = height;
+
+ xcb_configure_window(conn, win->debug, mask, wc);
+
+ /* Draw a filled rectangle to 'clear' window. */
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = width;
+ rect.height = height;
+
+ gcv[0] = win->s->c[SWM_S_COLOR_BAR].pixel;
+ xcb_change_gc(conn, win->s->bar_gc, XCB_GC_FOREGROUND, gcv);
+ xcb_poly_fill_rectangle(conn, win->debug, win->s->bar_gc, 1,
+ &rect);
+
+ /* Draw text. */
+ if (bar_font_legacy) {
+ l_gcv.graphics_exposures = 0;
+ l_draw = XCreateGC(display, win->debug, 0, &l_gcv);
+
+ XSetForeground(display, l_draw,
+ win->s->c[SWM_S_COLOR_BAR_FONT].pixel);
+
+ DRAWSTRING(display, win->debug, bar_fs, l_draw, 2,
+ (bar_fs_extents->max_logical_extent.height -
+ l_lbox.height) / 2 - l_lbox.y, s, len);
+
+ XFreeGC(display, l_draw);
+ } else {
+ draw = XftDrawCreate(display, win->debug,
+ DefaultVisual(display, win->s->idx),
+ DefaultColormap(display, win->s->idx));
+
+ XftDrawStringUtf8(draw, &bar_font_color, bar_font, 2,
+ (bar_height + bar_font->height) / 2 -
+ bar_font->descent, (FcChar8 *)s, len);
+
+ XftDrawDestroy(draw);
+ }
+
+ free(s);
+ } else if (win->debug != XCB_WINDOW_NONE) {
+ xcb_destroy_window(conn, win->debug);
+ win->debug = XCB_WINDOW_NONE;
+ }
+}
#else
void
dumpwins(struct binding *b, struct swm_region *r, union arg *s)
(void)r;
(void)s;
}
+
+void
+debug_toggle(struct binding *b, struct swm_region *r, union arg *s)
+{
+ (void)b;
+ (void)r;
+ (void)s;
+}
#endif /* SWM_DEBUG */
void
#endif
}
-/* Redraws the bar; need to follow with xcb_flush() or focus_flush(). */
+/* Redraws a region bar; need to follow with xcb_flush() or focus_flush(). */
void
-bar_draw(void)
+bar_draw(struct swm_bar *bar)
{
+ struct swm_region *r;
char fmtexp[SWM_BAR_MAX], fmtnew[SWM_BAR_MAX];
char fmtrep[SWM_BAR_MAX];
- int i, num_screens;
- struct swm_region *r;
/* expand the format by first passing it through strftime(3) */
bar_fmt_expand(fmtexp, sizeof fmtexp);
- num_screens = get_screen_count();
- for (i = 0; i < num_screens; i++) {
- TAILQ_FOREACH(r, &screens[i].rl, entry) {
- if (r->bar == NULL)
- continue;
+ if (bar == NULL)
+ return;
- if (bar_enabled && r->ws->bar_enabled)
- xcb_map_window(conn, r->bar->id);
- else {
- xcb_unmap_window(conn, r->bar->id);
- continue;
- }
+ r = bar->r;
- if (startup_exception)
- snprintf(fmtrep, sizeof fmtrep, "total "
- "exceptions: %d, first exception: %s",
- nr_exceptions,
- startup_exception);
- else {
- bar_fmt(fmtexp, fmtnew, r, sizeof fmtnew);
- bar_replace(fmtnew, fmtrep, r, sizeof fmtrep);
- }
- if (bar_font_legacy)
- bar_print_legacy(r, fmtrep);
- else
- bar_print(r, fmtrep);
- }
+ if (bar_enabled && r->ws->bar_enabled)
+ xcb_map_window(conn, bar->id);
+ else {
+ xcb_unmap_window(conn, bar->id);
+ return;
+ }
+
+ if (startup_exception)
+ snprintf(fmtrep, sizeof fmtrep, "total "
+ "exceptions: %d, first exception: %s",
+ nr_exceptions,
+ startup_exception);
+ else {
+ bar_fmt(fmtexp, fmtnew, r, sizeof fmtnew);
+ bar_replace(fmtnew, fmtrep, r, sizeof fmtrep);
}
+
+ if (bar_font_legacy)
+ bar_print_legacy(r, fmtrep);
+ else
+ bar_print(r, fmtrep);
}
/*
xcb_unmap_window(conn, tmpr->bar->id);
}
- stack();
-
- /* must be after stack */
- bar_draw();
+ /* Restack all regions and redraw bar. */
+ num_screens = get_screen_count();
+ for (i = 0; i < num_screens; i++)
+ TAILQ_FOREACH(tmpr, &screens[i].rl, entry) {
+ stack(tmpr);
+ bar_draw(tmpr->bar);
+ }
focus_flush();
}
bar_fs = NULL;
}
- DNPRINTF(SWM_D_INIT, "fontset_init: loading bar_fonts: %s\n", bar_fonts);
+ DNPRINTF(SWM_D_INIT, "fontset_init: loading bar_fonts: %s\n",
+ bar_fonts);
bar_fs = XCreateFontSet(display, bar_fonts, &missing_charsets,
&num_missing_charsets, &default_string);
else
xft_init(r);
+ r->bar->r = r;
X(r->bar) = X(r);
Y(r->bar) = bar_at_bottom ? (Y(r) + HEIGHT(r) - bar_height) : Y(r);
WIDTH(r->bar) = WIDTH(r) - 2 * bar_border_width;
void
version(struct binding *bp, struct swm_region *r, union arg *args)
{
+ struct swm_region *tmpr;
+ int i, num_screens;
+
/* suppress unused warnings since vars are needed */
(void)bp;
(void)r;
else
strlcpy(bar_vertext, "", sizeof bar_vertext);
- bar_draw();
- xcb_flush(conn);
+ num_screens = get_screen_count();
+ for (i = 0; i < num_screens; i++) {
+ TAILQ_FOREACH(tmpr, &screens[i].rl, entry) {
+ bar_draw(tmpr->bar);
+ xcb_flush(conn);
+ }
+ }
}
void
ce.y = Y(win);
ce.width = WIDTH(win);
ce.height = HEIGHT(win);
+ ce.border_width = 0;
ce.override_redirect = 0;
if (ev == NULL) {
/* EWMH */
ce.event = win->id;
ce.window = win->id;
- ce.border_width = BORDER(win);
ce.above_sibling = XCB_WINDOW_NONE;
} else {
/* normal */
}
/* adjust x and y for requested border_width. */
- ce.x += BORDER(win) - ev->border_width;
- ce.y += BORDER(win) - ev->border_width;
- ce.border_width = ev->border_width;
+ ce.x += ev->border_width;
+ ce.y += ev->border_width;
+
ce.above_sibling = ev->sibling;
}
update_win_stacking(struct ws_win *win)
{
struct ws_win *sibling;
+#ifdef SWM_DEBUG
+ struct ws_win *w;
+#endif
struct swm_region *r;
uint32_t val[2];
if (win == NULL || (r = win->ws->r) == NULL)
return;
+ if (win->frame == XCB_WINDOW_NONE) {
+ DNPRINTF(SWM_D_EVENT, "update_window_stacking: win %#x not "
+ "reparented.\n", win->id);
+ return;
+ }
+
sibling = TAILQ_NEXT(win, stack_entry);
if (sibling != NULL && (FLOATING(win) == FLOATING(sibling) ||
(win->ws->always_raise && win->ws->focus == win)))
- val[0] = sibling->id;
+ val[0] = sibling->frame;
else if (FLOATING(win) || (win->ws->always_raise &&
win->ws->focus == win))
val[0] = r->bar->id;
else
val[0] = r->id;
- DNPRINTF(SWM_D_EVENT, "update_win_stacking: %#x, sibling %#x\n",
- win->id, val[0]);
+ DNPRINTF(SWM_D_EVENT, "update_win_stacking: win %#x (%#x), "
+ "sibling %#x\n", win->frame, win->id, val[0]);
val[1] = XCB_STACK_MODE_ABOVE;
- xcb_configure_window(conn, win->id, XCB_CONFIG_WINDOW_SIBLING |
+ xcb_configure_window(conn, win->frame, XCB_CONFIG_WINDOW_SIBLING |
XCB_CONFIG_WINDOW_STACK_MODE, val);
+
+#ifdef SWM_DEBUG
+ TAILQ_FOREACH(w, &win->ws->winlist, entry)
+ debug_refresh(w);
+#endif
}
void
if (win->mapped)
return;
+ xcb_map_window(conn, win->frame);
xcb_map_window(conn, win->id);
set_win_state(win, XCB_ICCCM_WM_STATE_NORMAL);
win->mapped = true;
return;
xcb_unmap_window(conn, win->id);
+ xcb_unmap_window(conn, win->frame);
set_win_state(win, XCB_ICCCM_WM_STATE_ICONIC);
win->mapped = false;
}
DNPRINTF(SWM_D_EVENT, "center_pointer: win %#x.\n", WINID(win));
if (win && win->mapped)
- xcb_warp_pointer(conn, XCB_NONE, win->id, 0, 0, 0, 0,
+ xcb_warp_pointer(conn, XCB_NONE, win->frame, 0, 0, 0, 0,
WIDTH(win) / 2, HEIGHT(win) / 2);
else
xcb_warp_pointer(conn, XCB_NONE, r->id, 0, 0, 0, 0,
return (r);
}
-struct ws_win *
-find_unmanaged_window(xcb_window_t id)
+struct swm_region *
+find_region(xcb_window_t id)
{
- struct ws_win *win;
- int i, j, num_screens;
+ struct swm_region *r;
+ int i, num_screens;
num_screens = get_screen_count();
for (i = 0; i < num_screens; i++)
- for (j = 0; j < workspace_limit; j++)
- TAILQ_FOREACH(win, &screens[i].ws[j].unmanagedlist,
- entry)
- if (id == win->id)
- return (win);
- return (NULL);
+ TAILQ_FOREACH(r, &screens[i].rl, entry)
+ if (r->id == id)
+ return r;
+
+ return NULL;
+}
+
+struct swm_bar *
+find_bar(xcb_window_t id)
+{
+ struct swm_region *r;
+ int i, num_screens;
+
+ num_screens = get_screen_count();
+ for (i = 0; i < num_screens; i++)
+ TAILQ_FOREACH(r, &screens[i].rl, entry)
+ if (r->bar && r->bar->id == id)
+ return r->bar;
+
+ return NULL;
+}
+
+struct ws_win *
+find_frame_window(xcb_window_t id) {
+ struct swm_region *r;
+ struct ws_win *w;
+ int i, num_screens;
+
+ num_screens = get_screen_count();
+ for (i = 0; i < num_screens; i++)
+ TAILQ_FOREACH(r, &screens[i].rl, entry)
+ TAILQ_FOREACH(w, &r->ws->winlist, entry)
+ if (w->frame == id)
+ return w;
+
+ return NULL;
}
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 *r;
+ 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++)
TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry)
- if (id == win->id)
+ if (id == win->id || id == win->frame)
return (win);
- r = xcb_query_tree_reply(conn, xcb_query_tree(conn, id), NULL);
- if (r == NULL)
- return (NULL);
- /* if we were looking for the parent return that window instead */
- if (r->parent == 0 || r->root == r->parent) {
- free(r);
- return (NULL);
+ /* If window isn't top-level, try to find managed ancestor. */
+ qtr = xcb_query_tree_reply(conn, xcb_query_tree(conn, id), NULL);
+ if (qtr) {
+ if (qtr->parent != XCB_WINDOW_NONE && qtr->parent != qtr->root)
+ win = find_window(qtr->parent);
+
+#ifdef SWM_DEBUG
+ if (win)
+ DNPRINTF(SWM_D_MISC, "find_window: found child %#x "
+ "of %#x.\n", win->id, qtr->parent);
+#endif
+
+ free(qtr);
}
- /* look for parent */
+ return (win);
+}
+
+struct ws_win *
+find_unmanaged_window(xcb_window_t id)
+{
+ struct ws_win *win;
+ int i, j, num_screens;
+
+ num_screens = get_screen_count();
for (i = 0; i < num_screens; i++)
for (j = 0; j < workspace_limit; j++)
- TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry)
- if (r->parent == win->id) {
- free(r);
+ TAILQ_FOREACH(win, &screens[i].ws[j].unmanagedlist,
+ entry)
+ if (id == win->id)
return (win);
- }
-
- free(r);
return (NULL);
}
ws->focus = NULL;
if (win == ws->focus_prev)
ws->focus_prev = NULL;
+ if (win == ws->focus_pending)
+ ws->focus_pending = NULL;
if (TRANS(win))
TAILQ_FOREACH(w, &ws->winlist, entry)
win->ws->focus_prev = NULL;
}
- update_window_color(win);
+ draw_frame(win);
/* Raise window to "top unfocused position." */
if (win->ws->always_raise)
{
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 = xcb_get_input_focus_reply(conn, xcb_get_input_focus(conn), NULL);
if (gifr) {
+ DNPRINTF(SWM_D_FOCUS, "focus_win: cur focus: %#x\n",
+ gifr->focus);
+
cfw = find_window(gifr->focus);
- if (cfw != NULL && cfw != win) {
- if (cfw->ws != ws && cfw->ws->r != NULL) {
- /* Change border to unfocused color. */
- xcb_change_window_attributes(conn, cfw->id,
- XCB_CW_BORDER_PIXEL,
- &cfw->s->c[(MAXIMIZED(cfw) ?
- SWM_S_COLOR_UNFOCUS_MAXIMIZED :
- SWM_S_COLOR_UNFOCUS)].pixel);
-
- /* Update border width */
- if (cfw->bordered &&
- (cfw->quirks & SWM_Q_MINIMALBORDER) &&
- FLOATING(cfw)) {
- cfw->bordered = 0;
- X(cfw) += border_width;
- Y(cfw) += border_width;
- update_window(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 {
- 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) {
parent->focus_child = win;
}
- if (cfw != win && ws->r != NULL) {
+ /* Update window border even if workspace is hidden. */
+ draw_frame(win);
+
+ if (cfw == win) {
+ DNPRINTF(SWM_D_FOCUS, "focus_win: already focused.\n");
+ goto out;
+ }
+
+ 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)
- xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT,
- win->id, last_event_time);
- else
- xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT,
+ 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);
+ xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT,
+ win->id, last_event_time);
+ } else if (!win->take_focus) {
+ DNPRINTF(SWM_D_FOCUS, "focus_win: set_input_focus: %#x,"
+ " revert-to: parent, time: 0\n", ws->r->id);
+ xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT,
ws->r->id, XCB_CURRENT_TIME);
+ }
/* Tell app it can adjust focus to a specific window. */
if (win->take_focus) {
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->s->root,
ewmh[_NET_ACTIVE_WINDOW].atom, XCB_ATOM_WINDOW, 32, 1,
&win->id);
- }
-
- if (cfw != win) {
- /* Update window border even if workspace is hidden. */
- update_window_color(win);
- /* Update border width */
- if (!win->bordered && WS_FOCUSED(win->ws) &&
- (win->quirks & SWM_Q_MINIMALBORDER) && FLOATING(win)) {
- win->bordered = 1;
- X(win) -= border_width;
- Y(win) -= border_width;
- update_window(win);
- }
+ bar_draw(ws->r->bar);
}
out:
- bar_draw();
-
+ free(gifr);
+ free(war);
DNPRINTF(SWM_D_FOCUS, "focus_win: done.\n");
}
focus_win(nfw);
} else {
/* New region is empty; need to manually unfocus win. */
- if (old_r)
+ if (old_r) {
unfocus_win(old_r->ws->focus);
+ /* Clear bar since empty. */
+ bar_draw(old_r->bar);
+ }
- xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT, r->id,
+ DNPRINTF(SWM_D_FOCUS, "focus_region: set_input_focus: %#x, "
+ "revert-to: parent, time: 0\n", r->id);
+ xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, r->id,
XCB_CURRENT_TIME);
- /* Clear bar since empty. */
- bar_draw();
}
}
int wsid = args->id;
bool unmap_old = false;
- (void)bp;
-
if (!(r && r->s))
return;
return;
other_r = new_ws->r;
- if (other_r && workspace_clamp) {
+ if (other_r && workspace_clamp &&
+ bp->action != FN_RG_MOVE_NEXT && bp->action != FN_RG_MOVE_PREV) {
DNPRINTF(SWM_D_WS, "switchws: ws clamped.\n");
if (warp_focus) {
}
if ((win = old_ws->focus) != NULL) {
- update_window_color(win);
+ draw_frame(win);
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->s->root,
ewmh[_NET_ACTIVE_WINDOW].atom, XCB_ATOM_WINDOW, 32, 1,
}
new_ws->state = SWM_WS_STATE_MAPPING;
- stack();
+
+ stack(other_r);
+ stack(this_r);
/* unmap old windows */
if (unmap_old) {
/* Clear bar and set focus on region input win if new ws is empty. */
if (new_ws->focus_pending == NULL && new_ws->focus == NULL) {
- xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT, r->id,
+ DNPRINTF(SWM_D_FOCUS, "switchws: set_input_focus: %#x, "
+ "revert-to: parent, time: 0\n", r->id);
+ xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, r->id,
XCB_CURRENT_TIME);
- bar_draw();
+ bar_draw(r->bar);
}
ewmh_update_current_desktop();
sort_windows(wl);
ewmh_update_client_list();
- stack();
+ stack(r);
center_pointer(r);
focus_flush();
out:
}
if (clear_maximized(ws) > 0)
- stack();
+ stack(r);
focus_win(get_focus_magic(winfocus));
center_pointer(r);
clear_maximized(ws);
- stack();
- bar_draw();
+ stack(r);
+ bar_draw(r->bar);
focus_win(get_region_focus(r));
args->id, ws->idx);
if (clear_maximized(ws) > 0)
- stack();
+ stack(r);
if (ws->cur_layout->l_config != NULL)
ws->cur_layout->l_config(ws, args->id);
if (args->id != SWM_ARG_ID_STACKINIT)
- stack();
- bar_draw();
+ stack(r);
+ bar_draw(r->bar);
center_pointer(r);
focus_flush();
}
void
-stack(void) {
+stack(struct swm_region *r) {
struct swm_geometry g;
- struct swm_region *r, *r_prev = NULL;
- int i, num_screens;
+ struct swm_region *r_prev;
uint32_t val[2];
-#ifdef SWM_DEBUG
- int j;
-#endif
- DNPRINTF(SWM_D_STACK, "stack: begin\n");
+ if (r == NULL)
+ return;
- num_screens = get_screen_count();
- for (i = 0; i < num_screens; i++) {
-#ifdef SWM_DEBUG
- j = 0;
-#endif
- TAILQ_FOREACH(r, &screens[i].rl, entry) {
- /* Adjust stack area for region bar and padding. */
- g = r->g;
- g.x += region_padding;
- g.y += region_padding;
- g.w -= 2 * border_width + 2 * region_padding;
- g.h -= 2 * border_width + 2 * region_padding;
- if (bar_enabled && r->ws->bar_enabled) {
- if (!bar_at_bottom)
- g.y += bar_height;
- g.h -= bar_height;
- }
+ DNPRINTF(SWM_D_STACK, "stack: begin\n");
- DNPRINTF(SWM_D_STACK, "stack: workspace: %d (screen: "
- "%d, region: %d), (x,y) WxH: (%d,%d) %d x %d\n",
- r->ws->idx, i, j++, g.x, g.y, g.w, g.h);
-
- if (r_prev) {
- /* Stack bar/input relative to prev. region. */
- val[1] = XCB_STACK_MODE_ABOVE;
-
- val[0] = r_prev->id;
- DNPRINTF(SWM_D_STACK, "stack: region input %#x "
- "relative to %#x.\n", r->id, val[0]);
- xcb_configure_window(conn, r->id,
- XCB_CONFIG_WINDOW_SIBLING |
- XCB_CONFIG_WINDOW_STACK_MODE, val);
-
- val[0] = r_prev->bar->id;
- DNPRINTF(SWM_D_STACK, "stack: region bar %#x "
- "relative to %#x.\n", r->bar->id, val[0]);
- xcb_configure_window(conn, r->bar->id,
- XCB_CONFIG_WINDOW_SIBLING |
- XCB_CONFIG_WINDOW_STACK_MODE, val);
- }
+ /* Adjust stack area for region bar and padding. */
+ g = r->g;
+ g.x += region_padding;
+ g.y += region_padding;
+ g.w -= 2 * border_width + 2 * region_padding;
+ g.h -= 2 * border_width + 2 * region_padding;
+ if (bar_enabled && r->ws->bar_enabled) {
+ if (!bar_at_bottom)
+ g.y += bar_height;
+ g.h -= bar_height;
+ }
+
+ DNPRINTF(SWM_D_STACK, "stack: workspace: %d (screen: "
+ "%d, region: %d), (x,y) WxH: (%d,%d) %d x %d\n",
+ r->ws->idx, r->s->idx, get_region_index(r), g.x, g.y, g.w, g.h);
+
+ r_prev = TAILQ_PREV(r, swm_region_list, entry);
+ if (r_prev) {
+ /* Stack bar/input relative to prev. region. */
+ val[1] = XCB_STACK_MODE_ABOVE;
+
+ val[0] = r_prev->id;
+ DNPRINTF(SWM_D_STACK, "stack: region input %#x "
+ "relative to %#x.\n", r->id, val[0]);
+ xcb_configure_window(conn, r->id,
+ XCB_CONFIG_WINDOW_SIBLING |
+ XCB_CONFIG_WINDOW_STACK_MODE, val);
- r->ws->cur_layout->l_stack(r->ws, &g);
- r->ws->cur_layout->l_string(r->ws);
- /* save r so we can track region changes */
- r->ws->old_r = r;
- r_prev = r;
- }
+ val[0] = r_prev->bar->id;
+ DNPRINTF(SWM_D_STACK, "stack: region bar %#x "
+ "relative to %#x.\n", r->bar->id, val[0]);
+ xcb_configure_window(conn, r->bar->id,
+ XCB_CONFIG_WINDOW_SIBLING |
+ XCB_CONFIG_WINDOW_STACK_MODE, val);
}
+
+ r->ws->cur_layout->l_stack(r->ws, &g);
+ r->ws->cur_layout->l_string(r->ws);
+ /* save r so we can track region changes */
+ r->ws->old_r = r;
+
if (font_adjusted)
font_adjusted--;
}
if (win->bordered) {
+ /* Window geometry excludes frame. */
+ X(win) += border_width;
+ Y(win) += border_width;
HEIGHT(win) -= 2 * border_width;
WIDTH(win) -= 2 * border_width;
}
* unless manually moved, resized or ANYWHERE
* quirk is set.
*/
- X(win) = X(r) + (WIDTH(r) - WIDTH(win)) / 2 -
- BORDER(win);
- Y(win) = Y(r) + (HEIGHT(r) - HEIGHT(win)) / 2 -
- BORDER(win);
+ X(win) = X(r) + (WIDTH(r) - WIDTH(win)) / 2;
+ Y(win) = Y(r) + (HEIGHT(r) - HEIGHT(win)) / 2;
store_float_geom(win);
}
}
void
stack_master(struct workspace *ws, struct swm_geometry *g, int rot, bool flip)
{
- struct swm_geometry win_g, r_g = *g;
+ struct swm_geometry cell, r_g = *g;
struct ws_win *win;
int i = 0, j = 0, s = 0, stacks = 0;
int w_inc = 1, h_inc, w_base = 1, h_base;
int remain, missing, v_slice, mscale;
bool bordered = true, reconfigure = false;
+ /*
+ * cell: geometry for window, including frame.
+ * mwin: # of windows in master area.
+ * mscale: size increment of master area.
+ * stacks: # of stack columns
+ */
+
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. */
mscale = ws->l_state.vertical_msize;
stacks = ws->l_state.vertical_stacks;
}
- win_g = r_g;
+
+ cell = r_g;
+ cell.x += border_width;
+ cell.y += border_width;
if (stacks > winno - mwin)
stacks = winno - mwin;
split = mwin;
colno = split;
- win_g.w = v_slice * mscale;
+ cell.w = v_slice * mscale;
if (w_inc > 1 && w_inc < v_slice) {
/* Adjust for requested size increment. */
- remain = (win_g.w - w_base) % w_inc;
- win_g.w -= remain;
+ remain = (cell.w - w_base) % w_inc;
+ cell.w -= remain;
}
- msize = win_g.w;
+ msize = cell.w;
if (flip)
- win_g.x += r_g.w - msize;
+ cell.x += r_g.w - msize;
} else {
msize = -2;
colno = split = winno / stacks;
- win_g.w = ((r_g.w - (stacks * 2 * border_width) +
+ cell.w = ((r_g.w - (stacks * 2 * border_width) +
2 * border_width) / stacks);
}
+
hrh = r_g.h / colno;
extra = r_g.h - (colno * hrh);
- win_g.h = hrh - 2 * border_width;
+ cell.h = hrh - 2 * border_width;
i = j = 0, s = stacks;
}
extra = r_g.h - (colno * hrh);
if (!flip)
- win_g.x += win_g.w + 2 * border_width +
+ cell.x += cell.w + 2 * border_width +
tile_gap;
- win_g.w = (r_g.w - msize -
+ cell.w = (r_g.w - msize -
(stacks * (2 * border_width + tile_gap))) / stacks;
if (s == 1)
- win_g.w += (r_g.w - msize -
+ cell.w += (r_g.w - msize -
(stacks * (2 * border_width + tile_gap))) %
stacks;
if (flip)
- win_g.x -= win_g.w + 2 * border_width +
+ cell.x -= cell.w + 2 * border_width +
tile_gap;
s--;
j = 0;
}
- win_g.h = hrh - 2 * border_width - tile_gap;
+ cell.h = hrh - 2 * border_width - tile_gap;
if (rot) {
h_inc = win->sh.width_inc;
}
if (j == colno - 1) {
- win_g.h = hrh + extra;
+ cell.h = hrh + extra;
} else if (h_inc > 1 && h_inc < h_slice) {
/* adjust for window's requested size increment */
- remain = (win_g.h - h_base) % h_inc;
+ remain = (cell.h - h_base) % h_inc;
missing = h_inc - remain;
if (missing <= extra || j == 0) {
extra -= missing;
- win_g.h += missing;
+ cell.h += missing;
} else {
- win_g.h -= remain;
+ cell.h -= remain;
extra += remain;
}
}
if (j == 0)
- win_g.y = r_g.y;
+ cell.y = r_g.y + border_width;
else
- win_g.y += last_h + 2 * border_width + tile_gap;
+ cell.y += last_h + 2 * border_width + tile_gap;
- if (disable_border && !(bar_enabled && ws->bar_enabled) &&
- winno == 1) {
- bordered = false;
- win_g.w += 2 * border_width;
- win_g.h += 2 * border_width;
- } else {
+ /* Window coordinates exclude frame. */
+
+ if (winno > 1 || !disable_border ||
+ (bar_enabled && ws->bar_enabled)) {
bordered = true;
+ } else {
+ bordered = false;
}
if (rot) {
- if (X(win) != win_g.y || Y(win) != win_g.x ||
- WIDTH(win) != win_g.h || HEIGHT(win) != win_g.w) {
+ if (X(win) != cell.y || Y(win) != cell.x ||
+ WIDTH(win) != cell.h || HEIGHT(win) != cell.w) {
reconfigure = true;
- X(win) = win_g.y;
- Y(win) = win_g.x;
- WIDTH(win) = win_g.h;
- HEIGHT(win) = win_g.w;
+ X(win) = cell.y;
+ Y(win) = cell.x;
+ WIDTH(win) = cell.h;
+ HEIGHT(win) = cell.w;
}
} else {
- if (X(win) != win_g.x || Y(win) != win_g.y ||
- WIDTH(win) != win_g.w || HEIGHT(win) != win_g.h) {
+ if (X(win) != cell.x || Y(win) != cell.y ||
+ WIDTH(win) != cell.w || HEIGHT(win) != cell.h) {
reconfigure = true;
- X(win) = win_g.x;
- Y(win) = win_g.y;
- WIDTH(win) = win_g.w;
- HEIGHT(win) = win_g.h;
+ X(win) = cell.x;
+ Y(win) = cell.y;
+ WIDTH(win) = cell.w;
+ HEIGHT(win) = cell.h;
}
}
+ if (!bordered) {
+ X(win) -= border_width;
+ Y(win) -= border_width;
+ WIDTH(win) += 2 * border_width;
+ HEIGHT(win) += 2 * border_width;
+ }
+
if (bordered != win->bordered) {
reconfigure = true;
win->bordered = bordered;
update_window(win);
}
- last_h = win_g.h;
+ last_h = cell.h;
i++;
j++;
}
HEIGHT(w) += 2 * border_width;
} else {
w->bordered = true;
+ X(w) += border_width;
+ Y(w) += border_width;
}
update_window(w);
win->ws->focus_pending = NULL;
if (win->ws->focus_prev)
- update_window_color(win->ws->focus_prev);
+ draw_frame(win->ws->focus_prev);
}
DNPRINTF(SWM_D_STACK, "send_to_ws: focus_pending: %#x, focus: %#x, "
ewmh_apply_flags(win, win->ewmh_flags & ~EWMH_F_MAXIMIZED);
ewmh_update_wm_state(win);
- /* Restack and set new focus on current ws. */
- if (FLOATING(win))
- load_float_geom(win);
+ /* Restack focused region. */
+ stack(r);
- stack();
+ /* If destination ws has a region, restack. */
+ if (win->ws->r) {
+ if (FLOATING(win))
+ load_float_geom(win);
+ stack(win->ws->r);
+ }
+
+ /* Set new focus on current ws. */
if (focus_mode != SWM_FOCUS_FOLLOW) {
if (r->ws->focus != NULL) {
focus_win(r->ws->focus);
} else {
- xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT, r->id,
- XCB_CURRENT_TIME);
- bar_draw();
+ DNPRINTF(SWM_D_FOCUS, "send_to_ws: set_input_focus: "
+ "%#x, revert-to: parent, time: 0\n", r->id);
+ xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT,
+ r->id, XCB_CURRENT_TIME);
+ bar_draw(r->bar);
}
}
ewmh_apply_flags(w, w->ewmh_flags | EWMH_F_HIDDEN);
ewmh_update_wm_state(w);
- stack();
+ stack(r);
focus_flush();
}
height = bar_font->height + 4;
}
- xcb_create_window(conn, screen->root_depth, w, win->id, 0, 0,
+ xcb_create_window(conn, screen->root_depth, w, win->frame, 0, 0,
width, height, 1, XCB_WINDOW_CLASS_INPUT_OUTPUT,
screen->root_visual, XCB_CW_BACK_PIXEL |
XCB_CW_BORDER_PIXEL | XCB_CW_COLORMAP, wa);
/* XXX this should be a callback to generalize */
ewmh_apply_flags(win, win->ewmh_flags & ~EWMH_F_HIDDEN);
ewmh_update_wm_state(win);
- stack();
+ stack(search_r);
free(s);
break;
}
ewmh_apply_flags(w, w->ewmh_flags ^ EWMH_F_MAXIMIZED);
ewmh_update_wm_state(w);
- stack();
+ stack(r);
if (w == w->ws->focus)
focus_win(w);
ewmh_apply_flags(w, w->ewmh_flags ^ EWMH_F_ABOVE);
ewmh_update_wm_state(w);
- stack();
+ stack(r);
if (w == w->ws->focus)
focus_win(w);
* side of the region boundary. Positive values indicate the side of
* the window has passed beyond the region boundary.
*/
- rt = opts & SWM_CW_RIGHT ? MAX_X(win) + BORDER(win) - MAX_X(r) : bw;
- lt = opts & SWM_CW_LEFT ? X(r) - X(win) + BORDER(win) : bw;
- bm = opts & SWM_CW_BOTTOM ? MAX_Y(win) + BORDER(win) - MAX_Y(r) : bw;
- tp = opts & SWM_CW_TOP ? Y(r) - Y(win) + BORDER(win) : bw;
+ rt = opts & SWM_CW_RIGHT ? MAX_X(win) - MAX_X(r) : bw;
+ lt = opts & SWM_CW_LEFT ? X(r) - X(win) : bw;
+ bm = opts & SWM_CW_BOTTOM ? MAX_Y(win) - MAX_Y(r) : bw;
+ tp = opts & SWM_CW_TOP ? Y(r) - Y(win) : bw;
DNPRINTF(SWM_D_MISC, "region_containment: win %#x, rt: %d, lt: %d, "
"bm: %d, tp: %d, SOFTBOUNDARY: %s, HARDBOUNDARY: %s\n", win->id, rt,
YESNO(*opts & SWM_CW_BOTTOM), YESNO(*opts & SWM_CW_TOP),
YESNO(*opts & SWM_CW_RESIZABLE));
- if ((*opts & SWM_CW_RIGHT) && MAX_X(win) + BORDER(win) > b->x + b->w) {
+ if ((*opts & SWM_CW_RIGHT) && MAX_X(win) > b->x + b->w) {
if (*opts & SWM_CW_RESIZABLE)
- WIDTH(win) = b->x + b->w - X(win) - BORDER(win);
+ WIDTH(win) = b->x + b->w - X(win);
else
- X(win) = b->x + b->w - WIDTH(win) - BORDER(win);
+ X(win) = b->x + b->w - WIDTH(win);
}
- if ((*opts & SWM_CW_LEFT) && X(win) + BORDER(win) < b->x) {
+ if ((*opts & SWM_CW_LEFT) && X(win) < b->x) {
if (*opts & SWM_CW_RESIZABLE)
- WIDTH(win) -= b->x - X(win) - BORDER(win);
+ WIDTH(win) -= b->x - X(win);
- X(win) = b->x - BORDER(win);
+ X(win) = b->x;
}
- if ((*opts & SWM_CW_BOTTOM) && MAX_Y(win) + BORDER(win) > b->y + b->h) {
+ if ((*opts & SWM_CW_BOTTOM) && MAX_Y(win) > b->y + b->h) {
if (*opts & SWM_CW_RESIZABLE)
- HEIGHT(win) = b->y + b->h - Y(win) - BORDER(win);
+ HEIGHT(win) = b->y + b->h - Y(win);
else
- Y(win) = b->y + b->h - HEIGHT(win) - BORDER(win);
+ Y(win) = b->y + b->h - HEIGHT(win);
}
- if ((*opts & SWM_CW_TOP) && Y(win) + BORDER(win) < b->y) {
+ if ((*opts & SWM_CW_TOP) && Y(win) < b->y) {
if (*opts & SWM_CW_RESIZABLE)
- HEIGHT(win) -= b->y - Y(win) - BORDER(win);
+ HEIGHT(win) -= b->y - Y(win);
- Y(win) = b->y - BORDER(win);
+ Y(win) = b->y;
}
if (*opts & SWM_CW_RESIZABLE) {
}
void
-update_window_color(struct ws_win *win)
+draw_frame(struct ws_win *win)
{
- uint32_t *pixel;
+ xcb_rectangle_t rect[4];
+ uint32_t *pixel;
+ int n = 0;
+
+ if (win->frame == XCB_WINDOW_NONE) {
+ DNPRINTF(SWM_D_EVENT, "draw_frame: win %#x not "
+ "reparented.\n", win->id);
+ return;
+ }
+
+ if (!win->bordered) {
+ DNPRINTF(SWM_D_EVENT, "draw_frame: win %#x frame "
+ "disabled\n", win->id);
+ }
if (WS_FOCUSED(win->ws) && win->ws->focus == win)
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);
+ /* Top (with corners) */
+ rect[n].x = 0;
+ rect[n].y = 0;
+ rect[n].width = WIDTH(win) + 2 * border_width;
+ rect[n].height = border_width;
+ /* Left (without corners) */
+ rect[++n].x = 0;
+ rect[n].y = border_width;
+ rect[n].width = border_width;
+ rect[n].height = HEIGHT(win);
+ /* Right (without corners) */
+ rect[++n].x = border_width + WIDTH(win);
+ rect[n].y = border_width;
+ rect[n].width = border_width;
+ rect[n].height = HEIGHT(win);
+ /* Bottom (with corners)*/
+ rect[++n].x = 0;
+ rect[n].y = border_width + HEIGHT(win);
+ rect[n].width = WIDTH(win) + 2 * border_width;
+ rect[n].height = border_width;
+
+ xcb_change_gc(conn, win->s->bar_gc, XCB_GC_FOREGROUND, pixel);
+ xcb_poly_fill_rectangle(conn, win->frame, win->s->bar_gc, 4, rect);
}
void
uint16_t mask;
uint32_t wc[5];
- mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
- XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT |
- XCB_CONFIG_WINDOW_BORDER_WIDTH;
- wc[0] = X(win);
- wc[1] = Y(win);
+ if (win->frame == XCB_WINDOW_NONE) {
+ DNPRINTF(SWM_D_EVENT, "update_window: skip win %#x; "
+ "not reparented.\n", win->id);
+ return;
+ }
+
+ mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
+ XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT |
+ XCB_CONFIG_WINDOW_BORDER_WIDTH;
+
+ /* Reconfigure frame. */
+ if (win->bordered) {
+ wc[0] = X(win) - border_width;
+ wc[1] = Y(win) - border_width;
+ wc[2] = WIDTH(win) + 2 * border_width;
+ wc[3] = HEIGHT(win) + 2 * border_width;
+ } else {
+ wc[0] = X(win);
+ wc[1] = Y(win);
+ wc[2] = WIDTH(win);
+ wc[3] = HEIGHT(win);
+ }
+
+ wc[4] = 0;
+
+ DNPRINTF(SWM_D_EVENT, "update_window: win %#x frame %#x, (x,y) w x h: "
+ "(%d,%d) %d x %d, bordered: %s\n", win->id, win->frame, wc[0],
+ wc[1], wc[2], wc[3], YESNO(win->bordered));
+
+ xcb_configure_window(conn, win->frame, mask, wc);
+
+ /* Reconfigure client window. */
+ wc[0] = wc[1] = win->bordered ? border_width : 0;
wc[2] = WIDTH(win);
wc[3] = HEIGHT(win);
- wc[4] = BORDER(win);
DNPRINTF(SWM_D_EVENT, "update_window: win %#x, (x,y) w x h: "
"(%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);
+
+ /* 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);
~EWMH_F_MAXIMIZED);
ewmh_update_wm_state(win);
- stack();
+ stack(r);
focus_flush();
r = region_under(win->s, X(win) + WIDTH(win) / 2,
Y(win) + HEIGHT(win) / 2);
- if (r != NULL && r != win->ws->r) {
- if (clear_maximized(r->ws) > 0)
- stack();
+ if (r && r != win->ws->r) {
+ clear_maximized(r->ws);
win_to_ws(win, r->ws->idx, false);
+ /* Stack old and new region. */
+ stack(r);
+ stack(win->ws->r);
+
/* Set focus on new ws. */
unfocus_win(r->ws->focus);
r->ws->focus = win;
ewmh_update_wm_state(win);
if (restack)
- stack();
+ stack(r);
focus_flush();
store_float_geom(win);
/* New region set to fullscreen layout. */
- if (win->ws->cur_layout == &layouts[SWM_MAX_STACK]) {
- stack();
+ if (win->ws->r && win->ws->cur_layout == &layouts[SWM_MAX_STACK]) {
+ stack(win->ws->r);
focus_flush();
}
/* move_* uses focus window. */
if (r->ws)
win = r->ws->focus;
+
+ /* Disallow move_ on tiled. */
+ if (win && !(TRANS(win) || ABOVE(win)))
+ return;
} else {
/* move uses window under pointer. */
qpr = xcb_query_pointer_reply(conn,
union arg *);
uint32_t flags;
union arg args;
-} actions[FN_INVALID + 1] = {
+} actions[FN_INVALID + 2] = {
/* name function argument */
{ "bar_toggle", bar_toggle, 0, {.id = SWM_ARG_ID_BAR_TOGGLE} },
{ "bar_toggle_ws", bar_toggle, 0, {.id = SWM_ARG_ID_BAR_TOGGLE_WS} },
{ "ws_prev_all", cyclews, 0, {.id = SWM_ARG_ID_CYCLEWS_DOWN_ALL} },
{ "ws_prev_move", cyclews, 0, {.id = SWM_ARG_ID_CYCLEWS_MOVE_DOWN} },
{ "ws_prior", priorws, 0, {0} },
- { "dumpwins", dumpwins, 0, {0} }, /* MUST BE LAST */
+ /* SWM_DEBUG actions MUST be here: */
+ { "debug_toggle", debug_toggle, 0, {0} },
+ { "dumpwins", dumpwins, 0, {0} },
+ /* ALWAYS last: */
{ "invalid action", NULL, 0, {0} },
};
BINDKEY(MODSHIFT, XK_Down, FN_WS_PREV_MOVE);
BINDKEY(MODKEY, XK_a, FN_WS_PRIOR);
#ifdef SWM_DEBUG
+ BINDKEY(MODKEY, XK_d, FN_DEBUG_TOGGLE);
BINDKEY(MODSHIFT, XK_d, FN_DUMPWINS);
#endif
#undef BINDKEY
return ws_idx;
}
-struct ws_win *
-manage_window(xcb_window_t id, int spawn_pos, bool mapped)
+void
+reparent_window(struct ws_win *win)
{
- struct ws_win *win, *ww;
- struct swm_region *r;
- struct pid_e *p;
- struct quirk *qp;
- xcb_get_geometry_reply_t *gr;
- xcb_window_t trans = XCB_WINDOW_NONE;
- uint32_t i, wa[2], new_flags;
- int ws_idx, force_ws = -1;
- char *class, *instance, *name;
+ xcb_void_cookie_t c;
+ xcb_generic_error_t *error;
+ uint32_t wa[2];
+
+ win->frame = xcb_generate_id(conn);
+
+ DNPRINTF(SWM_D_MISC, "reparent_window: win %#x, frame: %#x\n",
+ win->id, win->frame);
+
+ wa[0] =
+ XCB_EVENT_MASK_ENTER_WINDOW |
+ XCB_EVENT_MASK_STRUCTURE_NOTIFY |
+ XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
+ XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
+ XCB_EVENT_MASK_EXPOSURE;
+#ifdef SWM_DEBUG
+ wa[0] |= XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_FOCUS_CHANGE;
+#endif
+
+ xcb_create_window(conn, XCB_COPY_FROM_PARENT, win->frame, win->s->root,
+ X(win), Y(win), WIDTH(win), HEIGHT(win), 0,
+ XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT,
+ XCB_CW_EVENT_MASK, wa);
+
+ win->state = SWM_WIN_STATE_REPARENTING;
+ c = xcb_reparent_window_checked(conn, win->id, win->frame, 0, 0);
+ if ((error = xcb_request_check(conn, c))) {
+ DNPRINTF(SWM_D_MISC, "reparent_window: error:\n");
+ event_error(error);
+ free(error);
+
+ /* Abort. */
+ xcb_destroy_window(conn, win->frame);
+ win->frame = XCB_WINDOW_NONE;
+ } else {
+ xcb_change_save_set(conn, XCB_SET_MODE_INSERT, win->id);
+ }
+ DNPRINTF(SWM_D_MISC, "reparent_window: done.\n");
+}
+
+void
+unparent_window(struct ws_win *win)
+{
+ xcb_change_save_set(conn, XCB_SET_MODE_DELETE, win->id);
+ xcb_reparent_window(conn, win->id, win->s->root, X(win), Y(win));
+ xcb_destroy_window(conn, win->frame);
+ win->frame = XCB_WINDOW_NONE;
+ win->state = SWM_WIN_STATE_UNPARENTING;
+}
+
+struct ws_win *
+manage_window(xcb_window_t id, int spawn_pos, bool mapping)
+{
+ struct ws_win *win = NULL, *ww;
+ struct swm_region *r;
+ struct pid_e *p;
+ struct quirk *qp;
+ xcb_get_geometry_reply_t *gr;
+ xcb_get_window_attributes_reply_t *war = NULL;
+ xcb_window_t trans = XCB_WINDOW_NONE;
+ uint32_t i, wa[1], new_flags;
+ int ws_idx, force_ws = -1;
+ char *class, *instance, *name;
+
+ if (find_bar(id)) {
+ DNPRINTF(SWM_D_MISC, "manage_window: win %#x is region bar; "
+ "skipping.\n", id);
+ goto out;
+ }
+
+ if (find_region(id)) {
+ DNPRINTF(SWM_D_MISC, "manage_window: win %#x is region window; "
+ "skipping.\n", id);
+ goto out;
+ }
if ((win = find_window(id)) != NULL) {
DNPRINTF(SWM_D_MISC, "manage_window: win %#x already "
if (TRANS(win))
set_child_transient(win, &trans);
- goto out;
+ goto remanage;
} else {
DNPRINTF(SWM_D_MISC, "manage_window: win %#x is new.\n", id);
}
+ war = xcb_get_window_attributes_reply(conn,
+ xcb_get_window_attributes(conn, id), NULL);
+ if (war == NULL) {
+ DNPRINTF(SWM_D_EVENT, "manage_window: window lost.\n");
+ goto out;
+ }
+
+ if (war->override_redirect) {
+ DNPRINTF(SWM_D_EVENT, "manage_window: override_redirect; "
+ "skipping.\n");
+ goto out;
+ }
+
+ if (!mapping && war->map_state == XCB_MAP_STATE_UNMAPPED &&
+ get_win_state(id) == XCB_ICCCM_WM_STATE_WITHDRAWN) {
+ DNPRINTF(SWM_D_EVENT, "manage_window: window withdrawn; "
+ "skipping.\n");
+ goto out;
+ }
+
/* Try to get initial window geometry. */
gr = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, id), NULL);
if (gr == NULL) {
DNPRINTF(SWM_D_MISC, "manage_window: get geometry failed.\n");
- return (NULL);
+ goto out;
}
/* Create and initialize ws_win object. */
/* Ignore window border if there is one. */
WIDTH(win) = gr->width;
HEIGHT(win) = gr->height;
- X(win) = gr->x + gr->border_width - border_width;
- Y(win) = gr->y + gr->border_width - border_width;
- win->bordered = true;
- win->mapped = mapped;
+ X(win) = gr->x + gr->border_width;
+ Y(win) = gr->y + gr->border_width;
+ win->bordered = false;
+ win->mapped = (war->map_state != XCB_MAP_STATE_UNMAPPED);
win->s = r->s; /* this never changes */
free(gr);
/* 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 |
+ wa[0] = XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_PROPERTY_CHANGE |
XCB_EVENT_MASK_STRUCTURE_NOTIFY;
-#ifdef SWM_DEBUG
- wa[1] |= XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_FOCUS_CHANGE;
-#endif
- xcb_change_window_attributes(conn, win->id, XCB_CW_BORDER_PIXEL |
- XCB_CW_EVENT_MASK, wa);
+ xcb_change_window_attributes(conn, win->id, XCB_CW_EVENT_MASK, wa);
/* Get WM_SIZE_HINTS. */
xcb_icccm_get_wm_normal_hints_reply(conn,
#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. */
update_window(win);
}
-out:
+remanage:
/* Figure out where to insert the window in the workspace list. */
if (trans && (ww = find_window(trans)))
TAILQ_INSERT_AFTER(&win->ws->winlist, ww, win, entry);
/* Set initial _NET_WM_ALLOWED_ACTIONS */
ewmh_update_actions(win);
+ reparent_window(win);
+
DNPRINTF(SWM_D_MISC, "manage_window: done. win %#x, (x,y) w x h: "
"(%d,%d) %d x %d, ws: %d, iconic: %s, transient: %#x\n", win->id,
X(win), Y(win), WIDTH(win), HEIGHT(win), win->ws->idx,
YESNO(ICONIC(win)), win->transient);
-
+out:
+ free(war);
return (win);
}
void
unmanage_window(struct ws_win *win)
{
- struct ws_win *parent;
-
DNPRINTF(SWM_D_MISC, "unmanage_window: win %#x\n", WINID(win));
if (win == NULL)
return;
- if (TRANS(win)) {
- parent = find_window(win->transient);
- if (parent)
- parent->focus_child = NULL;
- }
+ kill_refs(win);
+ unparent_window(win);
TAILQ_REMOVE(&win->ws->stack, win, stack_entry);
TAILQ_REMOVE(&win->ws->winlist, win, entry);
void
expose(xcb_expose_event_t *e)
{
- int i, num_screens;
- struct swm_region *r;
+ struct ws_win *w;
+ struct swm_bar *b;
+#ifdef SWM_DEBUG
+ struct workspace *ws;
+#endif
- DNPRINTF(SWM_D_EVENT, "expose: win %#x\n", e->window);
+ DNPRINTF(SWM_D_EVENT, "expose: win %#x, count: %d\n", e->window,
+ e->count);
- num_screens = get_screen_count();
- for (i = 0; i < num_screens; i++)
- TAILQ_FOREACH(r, &screens[i].rl, entry)
- if (e->window == WINID(r->bar))
- bar_draw();
+ if (e->count > 0)
+ return;
- xcb_flush(conn);
+ if ((b = find_bar(e->window))) {
+ bar_draw(b);
+ xcb_flush(conn);
+ } else if ((w = find_window(e->window)) && w->frame == e->window) {
+ draw_frame(w);
+#ifdef SWM_DEBUG
+ ws = w->ws;
+ TAILQ_FOREACH(w, &ws->winlist, entry)
+ debug_refresh(w);
+#endif
+ xcb_flush(conn);
+ }
+
+ 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)
{
last_event_time = e->time;
+ keysym = xcb_key_release_lookup_keysym(syms, e, 0);
+
DNPRINTF(SWM_D_EVENT, "keyrelease: keysym: %u, win (x,y): %#x (%d,%d), "
"detail: %u, time: %u, root (x,y): %#x (%d,%d), child: %#x, "
"state: %u, same_screen: %s\n", keysym, e->event, e->event_x,
e->event_y, e->detail, e->time, e->root, e->root_x, e->root_y,
e->child, e->state, YESNO(e->same_screen));
- keysym = xcb_key_release_lookup_keysym(syms, e, 0);
-
bp = binding_lookup(CLEANMASK(e->state), KEYBIND, keysym);
if (bp == NULL)
/* Look for catch-all. */
DNPRINTF(SWM_D_EVENT, "keyrelease: replaying.\n");
} else {
xcb_allow_events(conn, XCB_ALLOW_SYNC_KEYBOARD, e->time);
+ DNPRINTF(SWM_D_EVENT, "keyrelease: unfreezing.\n");
}
xcb_flush(conn);
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;
if (old_r && old_r != r)
unfocus_win(old_r->ws->focus);
+ DNPRINTF(SWM_D_FOCUS, "buttonpress: "
+ "set_input_focus: %#x, revert-to: parent, "
+ "time: %#x\n", e->root, e->time);
xcb_set_input_focus(conn,
- XCB_INPUT_FOCUS_PARENT, e->root, e->time);
+ XCB_INPUT_FOCUS_POINTER_ROOT,
+ e->root, e->time);
/* Clear bar since empty. */
- bar_draw();
+ bar_draw(r->bar);
/* No need to replay event. */
replay = false;
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);
xcb_allow_events(conn, XCB_ALLOW_SYNC_POINTER, e->time);
}
- xcb_flush(conn);
+ focus_flush();
}
void
}
#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
win = find_window(e->window);
if (win) {
- xcb_icccm_get_wm_normal_hints_reply(conn,
- xcb_icccm_get_wm_normal_hints(conn, win->id),
- &win->sh, NULL);
adjust_font(win);
- if (font_adjusted) {
- stack();
+ if (font_adjusted && win->ws->r) {
+ stack(win->ws->r);
xcb_flush(conn);
}
}
destroynotify(xcb_destroy_notify_event_t *e)
{
struct ws_win *win;
+ struct workspace *ws;
DNPRINTF(SWM_D_EVENT, "destroynotify: win %#x\n", e->window);
- if ((win = find_window(e->window))) {
- /* Managed window cleanup. */
- if (focus_mode != SWM_FOCUS_FOLLOW) {
- /* If focused, focus on something else. */
- if (win == win->ws->focus)
- win->ws->focus_pending = get_focus_prev(win);
+ if ((win = find_window(e->window)) == NULL) {
+ if ((win = find_unmanaged_window(e->window)) == NULL)
+ goto out;
+ /* Window is on unmanaged list. */
+ TAILQ_REMOVE(&win->ws->unmanagedlist, win, entry);
+ free_window(win);
+ goto out;
+ }
+
+ ws = win->ws;
+
+ if (win->frame == e->window) {
+ DNPRINTF(SWM_D_EVENT, "destroynotify: frame for win %#x\n",
+ win->id);
+ win->frame = XCB_WINDOW_NONE;
+ goto out;
+ }
+
+ if (focus_mode != SWM_FOCUS_FOLLOW) {
+ /* If we were focused, make sure we focus on something else. */
+ if (win == ws->focus) {
+ ws->focus_pending = get_focus_prev(win);
+ if (ws->focus_pending == win)
+ ws->focus_pending = NULL;
}
+ }
- unmanage_window(win);
- stack();
+ unmanage_window(win);
+ TAILQ_REMOVE(&win->ws->unmanagedlist, win, entry);
+ free_window(win);
+ stack(ws->r);
- 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) {
- xcb_set_input_focus(conn,
- XCB_INPUT_FOCUS_PARENT, win->ws->r->id,
- XCB_CURRENT_TIME);
- }
+ if (focus_mode != SWM_FOCUS_FOLLOW && WS_FOCUSED(ws)) {
+ if (ws->focus_pending) {
+ focus_win(ws->focus_pending);
+ ws->focus_pending = NULL;
+ } else if (ws->focus == NULL) {
+ DNPRINTF(SWM_D_FOCUS, "destroynotify: set_input_focus: "
+ "%#x, revert-to: parent, time: 0\n", ws->r->id);
+ xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT,
+ ws->r->id, XCB_CURRENT_TIME);
}
- kill_refs(win);
focus_flush();
- } else {
- win = find_unmanaged_window(e->window);
- }
-
- if (win) {
- /* unmanage_window() puts win into unmanaged list. */
- TAILQ_REMOVE(&win->ws->unmanagedlist, win, entry);
- free_window(win);
}
+out:
DNPRINTF(SWM_D_EVENT, "destroynotify: done.\n");
}
YESNO(e->same_screen_focus), get_state_mask_label(e->state),
e->state);
+ if (e->event == e->root && e->child == XCB_WINDOW_NONE &&
+ e->mode == XCB_NOTIFY_MODE_GRAB &&
+ e->detail == XCB_NOTIFY_DETAIL_INFERIOR) {
+ DNPRINTF(SWM_D_EVENT, "enternotify: grab inferior; ignoring.\n");
+ return;
+ }
+
if (focus_mode == SWM_FOCUS_MANUAL &&
e->mode == XCB_NOTIFY_MODE_NORMAL) {
DNPRINTF(SWM_D_EVENT, "enternotify: manual focus; ignoring.\n");
focus_win(get_focus_magic(win));
}
+ DNPRINTF(SWM_D_EVENT, "enternotify: done\n");
+
xcb_flush(conn);
}
DNPRINTF(SWM_D_EVENT, "mapnotify: win %#x\n", e->window);
- if ((win = manage_window(e->window, spawn_position, true)) == NULL)
+ if ((win = manage_window(e->window, spawn_position, false)) == NULL)
return;
ws = win->ws;
+ if (win->state == SWM_WIN_STATE_REPARENTING)
+ return;
+
+ if (ws->r == NULL) {
+ unmap_window(win);
+ goto out;
+ }
+
/* Need to know if win was mapped due to ws switch. */
if (ws->state == SWM_WS_STATE_MAPPED) {
if (ws->focus_pending && TRANS(ws->focus_pending))
/* If window's parent is maximized, don't clear it. */
if ((parent == NULL) || !MAXIMIZED(parent))
if (clear_maximized(ws) > 0)
- stack();
+ stack(ws->r);
}
win->mapped = true;
if (ws->focus_pending == win) {
focus_win(win);
ws->focus_pending = NULL;
- center_pointer(win->ws->r);
+ center_pointer(ws->r);
focus_flush();
}
}
+out:
+ DNPRINTF(SWM_D_EVENT, "mapnotify: done\n");
+
xcb_flush(conn);
}
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,
- (war->map_state == XCB_MAP_STATE_VIEWABLE));
+ 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) {
}
/* All windows need to be mapped if they are in the current workspace.*/
- if (win->ws->r)
- stack();
+ stack(win->ws->r);
/* Ignore EnterNotify to handle the mapnotify without interference. */
if (focus_mode == SWM_FOCUS_DEFAULT)
event_drain(XCB_ENTER_NOTIFY);
out:
- free(war);
DNPRINTF(SWM_D_EVENT, "maprequest: done.\n");
}
if (e->state == XCB_PROPERTY_NEW_VALUE) {
if (focus_mode != SWM_FOCUS_FOLLOW && WS_FOCUSED(ws)) {
if (win->mapped &&
+ win->state == SWM_WIN_STATE_REPARENTED &&
ws->focus_pending == win) {
focus_win(ws->focus_pending);
ws->focus_pending = NULL;
}
} else if (e->atom == XCB_ATOM_WM_CLASS ||
e->atom == XCB_ATOM_WM_NAME) {
- bar_draw();
+ if (ws->r)
+ bar_draw(ws->r->bar);
} else if (e->atom == a_prot) {
get_wm_protocols(win);
+ } else if (e->atom == XCB_ATOM_WM_NORMAL_HINTS) {
+ xcb_icccm_get_wm_normal_hints_reply(conn,
+ xcb_icccm_get_wm_normal_hints(conn, win->id),
+ &win->sh, NULL);
}
xcb_flush(conn);
}
+void
+reparentnotify(xcb_reparent_notify_event_t *e)
+{
+ struct ws_win *win;
+
+ DNPRINTF(SWM_D_EVENT, "reparentnotify: event: %#x, win %#x, "
+ "parent: %#x, (x,y): (%u,%u), override_redirect: %u\n",
+ e->event, e->window, e->parent, e->x, e->y, e->override_redirect);
+
+ win = find_window(e->window);
+ if (win) {
+ if (win->state == SWM_WIN_STATE_REPARENTING) {
+ win->state = SWM_WIN_STATE_REPARENTED;
+
+ if (win->ws->r)
+ map_window(win);
+ else
+ unmap_window(win);
+
+ update_window(win);
+ update_win_stacking(win);
+ } else if (win->state == SWM_WIN_STATE_UNPARENTING) {
+ win->state = SWM_WIN_STATE_UNPARENTED;
+ }
+ }
+}
+
void
unmapnotify(xcb_unmap_notify_event_t *e)
{
/* If we aren't managing the window, then ignore. */
win = find_window(e->window);
- if (win == NULL || win->id != e->window)
+ if (win == NULL || win->id != e->window) {
+ DNPRINTF(SWM_D_EVENT, "unmapnotify: ignore unmanaged.\n");
return;
+ }
/* Do nothing if already withdrawn. */
- if (!win->mapped && !ICONIC(win))
+ if (!win->mapped && !ICONIC(win)) {
+ DNPRINTF(SWM_D_EVENT, "unmapnotify: ignore withdrawn.\n");
return;
+ }
ws = win->ws;
win->mapped = false;
+ /* Ignore if reparenting-related. */
+ if (win->state != SWM_WIN_STATE_REPARENTED) {
+ DNPRINTF(SWM_D_EVENT, "unmapnotify: ignore not reparented.\n");
+ return;
+ }
+
/* If win was focused, make sure to focus on something else. */
if (win == ws->focus) {
if (focus_mode != SWM_FOCUS_FOLLOW) {
if (ICONIC(win)) {
/* Iconify. */
+ DNPRINTF(SWM_D_EVENT, "unmapnotify: iconify.\n");
set_win_state(win, XCB_ICCCM_WM_STATE_ICONIC);
} else {
/* Withdraw. */
+ DNPRINTF(SWM_D_EVENT, "unmapnotify: withdraw.\n");
set_win_state(win, XCB_ICCCM_WM_STATE_WITHDRAWN);
unmanage_window(win);
}
- if (ws->r)
- stack();
+ stack(ws->r);
/* Update focus if ws is active. */
if (WS_FOCUSED(ws)) {
focus_win(ws->focus_pending);
ws->focus_pending = NULL;
} else if (ws->focus == NULL) {
- xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT,
+ DNPRINTF(SWM_D_FOCUS, "unmapnotify: set_input_focus: "
+ "%#x, revert-to: parent, time: 0\n",
+ ws->r->id);
+ xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT,
ws->r->id, XCB_CURRENT_TIME);
}
}
center_pointer(ws->r);
focus_flush();
+ DNPRINTF(SWM_D_EVENT, "unmapnotify: done.\n");
}
#ifdef SWM_DEBUG
struct ws_win *win;
struct swm_region *r = NULL;
union arg a;
- uint32_t val[2];
+ uint32_t vals[4];
int num_screens, i;
xcb_map_request_event_t mre;
#ifdef SWM_DEBUG
focus_flush();
}
+ return;
+ } else if (e->type == ewmh[_NET_REQUEST_FRAME_EXTENTS].atom) {
+ DNPRINTF(SWM_D_EVENT,
+ "clientmessage: set _NET_FRAME_EXTENTS on window.\n");
+ vals[0] = vals[1] = vals[2] = vals[3] = border_width;
+ xcb_change_property(conn, XCB_PROP_MODE_REPLACE, e->window,
+ a_net_frame_extents, XCB_ATOM_CARDINAL, 32, 4, vals);
+ xcb_flush(conn);
return;
}
}
} else if (e->type == ewmh[_NET_RESTACK_WINDOW].atom) {
DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_RESTACK_WINDOW\n");
- val[0] = e->data.data32[1]; /* Sibling window. */
- val[1] = e->data.data32[2]; /* Stack mode detail. */
+ vals[0] = e->data.data32[1]; /* Sibling window. */
+ vals[1] = e->data.data32[2]; /* Stack mode detail. */
- xcb_configure_window(conn, win->id, XCB_CONFIG_WINDOW_SIBLING |
- XCB_CONFIG_WINDOW_STACK_MODE, val);
+ if (win->frame != XCB_WINDOW_NONE)
+ xcb_configure_window(conn, win->frame,
+ XCB_CONFIG_WINDOW_SIBLING |
+ XCB_CONFIG_WINDOW_STACK_MODE, vals);
} else if (e->type == ewmh[_NET_WM_STATE].atom) {
DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_WM_STATE\n");
ewmh_change_wm_state(win, e->data.data32[1], e->data.data32[0]);
e->data.data32[0]);
ewmh_update_wm_state(win);
- stack();
+ stack(win->ws->r);
} 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], true);
- /* 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 source and destination ws, if mapped. */
+ if (r != win->ws->r) {
+ if (r)
+ stack(r);
- stack();
+ if (win->ws->r) {
+ if (FLOATING(win))
+ load_float_geom(win);
+
+ stack(win->ws->r);
+ }
}
}
{
int num_screens, i;
const uint32_t val = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
- XCB_EVENT_MASK_ENTER_WINDOW;
+ XCB_EVENT_MASK_ENTER_WINDOW |
+ XCB_EVENT_MASK_OWNER_GRAB_BUTTON |
+ XCB_EVENT_MASK_STRUCTURE_NOTIFY |
+ XCB_EVENT_MASK_ENTER_WINDOW |
+ XCB_EVENT_MASK_LEAVE_WINDOW |
+ XCB_EVENT_MASK_BUTTON_PRESS |
+ XCB_EVENT_MASK_BUTTON_RELEASE |
+ XCB_EVENT_MASK_KEY_PRESS |
+ XCB_EVENT_MASK_KEY_RELEASE |
+ XCB_EVENT_MASK_PROPERTY_CHANGE;
xcb_screen_t *sc;
xcb_void_cookie_t wac;
xcb_generic_error_t *error;
r->ws->r = NULL;
bar_cleanup(r);
xcb_destroy_window(conn, r->id);
+ r->id = XCB_WINDOW_NONE;
TAILQ_REMOVE(&s->rl, r, entry);
TAILQ_INSERT_TAIL(&s->orl, r, entry);
}
Y(r) = y;
WIDTH(r) = w;
HEIGHT(r) = h;
+ r->bar = NULL;
r->s = s;
r->ws = ws;
r->ws_prior = NULL;
r->ws->old_r = r->ws->r = NULL;
bar_cleanup(r);
xcb_destroy_window(conn, r->id);
+ r->id = XCB_WINDOW_NONE;
TAILQ_REMOVE(&screens[idx].rl, r, entry);
TAILQ_INSERT_TAIL(&screens[idx].orl, r, entry);
}
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();
+ /* 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);
}
- bar_draw();
focus_flush();
- /* Update workspace state on all regions. */
- for (i = 0; i < num_screens; i++)
- TAILQ_FOREACH(r, &screens[i].rl, entry)
- r->ws->state = SWM_WS_STATE_MAPPED;
+ /* Update workspace state and bar on all regions. */
+ TAILQ_FOREACH(r, &screens[i].rl, entry) {
+ r->ws->state = SWM_WS_STATE_MAPPED;
+ bar_draw(r->bar);
+ }
}
void
grab_windows(void)
{
- struct swm_region *r = NULL;
- xcb_window_t *wins = NULL, trans, *cwins = NULL;
- int i, j, k, n, no, num_screens;
- uint8_t state;
- bool manage, mapped;
-
- xcb_query_tree_cookie_t qtc;
- xcb_query_tree_reply_t *qtr;
- xcb_get_window_attributes_cookie_t gac;
- xcb_get_window_attributes_reply_t *gar;
- xcb_get_property_cookie_t pc;
- xcb_get_property_reply_t *pr;
+ struct swm_region *r = NULL;
+ xcb_query_tree_cookie_t qtc;
+ xcb_query_tree_reply_t *qtr;
+ xcb_get_property_cookie_t pc;
+ xcb_get_property_reply_t *pr;
+ xcb_window_t *wins = NULL, trans, *cwins = NULL;
+ int i, j, k, n, no, num_screens;
DNPRINTF(SWM_D_INIT, "grab_windows: begin\n");
num_screens = get_screen_count();
free(pr);
}
- /* attach windows to a region */
- /* normal windows */
- DNPRINTF(SWM_D_INIT, "grab_windows: grab top level windows.\n");
+ /* Manage top-level windows first, then transients. */
+ /* TODO: allow transients to be managed before leader. */
+ DNPRINTF(SWM_D_INIT, "grab_windows: grab top-level windows.\n");
for (j = 0; j < no; j++) {
TAILQ_FOREACH(r, &screens[i].rl, entry) {
if (r->id == wins[j]) {
if (r)
continue;
- gac = xcb_get_window_attributes(conn, wins[j]);
- gar = xcb_get_window_attributes_reply(conn, gac, NULL);
- if (gar == NULL) {
- DNPRINTF(SWM_D_INIT, "grab_windows: skip %#x; "
- "doesn't exist.\n", wins[j]);
- continue;
- }
-
- if (gar->override_redirect) {
- DNPRINTF(SWM_D_INIT, "grab_windows: skip %#x; "
- "override_redirect set.\n", wins[j]);
- free(gar);
- continue;
- }
-
pc = xcb_icccm_get_wm_transient_for(conn, wins[j]);
if (xcb_icccm_get_wm_transient_for_reply(conn, pc,
&trans, NULL)) {
DNPRINTF(SWM_D_INIT, "grab_windows: skip %#x; "
"is transient for %#x.\n", wins[j], trans);
- free(gar);
continue;
}
- state = get_win_state(wins[j]);
- manage = state != XCB_ICCCM_WM_STATE_WITHDRAWN;
- mapped = gar->map_state == XCB_MAP_STATE_VIEWABLE;
- if (mapped || manage)
- manage_window(wins[j], SWM_STACK_TOP, mapped);
- free(gar);
+ manage_window(wins[j], SWM_STACK_TOP, false);
}
- /* transient windows */
+
DNPRINTF(SWM_D_INIT, "grab_windows: grab transient windows.\n");
for (j = 0; j < no; j++) {
- gac = xcb_get_window_attributes(conn, wins[j]);
- gar = xcb_get_window_attributes_reply(conn, gac, NULL);
- if (gar == NULL) {
- DNPRINTF(SWM_D_INIT, "grab_windows: skip %#x; "
- "doesn't exist.\n", wins[j]);
- continue;
- }
-
- if (gar->override_redirect) {
- DNPRINTF(SWM_D_INIT, "grab_windows: skip %#x; "
- "override_redirect set.\n", wins[j]);
- free(gar);
- continue;
- }
-
- 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]);
if (xcb_icccm_get_wm_transient_for_reply(conn, pc,
- &trans, NULL) && manage)
- manage_window(wins[j], SWM_STACK_TOP, mapped);
- free(gar);
+ &trans, NULL))
+ manage_window(wins[j], SWM_STACK_TOP, false);
}
free(qtr);
}
a_state = get_atom_from_string("WM_STATE");
a_prot = get_atom_from_string("WM_PROTOCOLS");
a_delete = get_atom_from_string("WM_DELETE_WINDOW");
+ a_net_frame_extents = get_atom_from_string("_NET_FRAME_EXTENTS");
a_net_supported = get_atom_from_string("_NET_SUPPORTED");
a_net_wm_check = get_atom_from_string("_NET_SUPPORTING_WM_CHECK");
a_takefocus = get_atom_from_string("WM_TAKE_FOCUS");
for (i = 0; i < num_screens; ++i) {
int j;
+ DNPRINTF(SWM_D_FOCUS, "shutdown_cleanup: set_input_focus: "
+ "%#x, revert-to: root, time: 0\n", screens[i].root);
xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT,
screens[i].root, XCB_CURRENT_TIME);
xcb_key_symbols_free(syms);
xcb_flush(conn);
+ xcb_aux_sync(conn);
xcb_disconnect(conn);
}
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, );*/
EVENT(XCB_MOTION_NOTIFY, motionnotify);
/*EVENT(XCB_NO_EXPOSURE, );*/
EVENT(XCB_PROPERTY_NOTIFY, propertynotify);
- /*EVENT(XCB_REPARENT_NOTIFY, );*/
+ EVENT(XCB_REPARENT_NOTIFY, reparentnotify);
/*EVENT(XCB_RESIZE_REQUEST, );*/
/*EVENT(XCB_SELECTION_CLEAR, );*/
/*EVENT(XCB_SELECTION_NOTIFY, );*/
grabkeys();
grabbuttons();
- stack();
- bar_draw();
+
+ /* Stack all regions to trigger mapping. */
+ for (i = 0; i < num_screens; i++)
+ TAILQ_FOREACH(r, &screens[i].rl, entry)
+ stack(r);
xcb_ungrab_server(conn);
xcb_flush(conn);
- /* Update state of each newly mapped workspace. */
+ /* Update state and bar of each newly mapped workspace. */
for (i = 0; i < num_screens; i++)
- TAILQ_FOREACH(r, &screens[i].rl, entry)
+ TAILQ_FOREACH(r, &screens[i].rl, entry) {
r->ws->state = SWM_WS_STATE_MAPPED;
+ bar_draw(r->bar);
+ }
memset(&pfd, 0, sizeof(pfd));
pfd[0].fd = xfd;
bar_extra_update();
}
- bar_draw();
+ /* Need to ensure the bar(s) are always updated. */
+ for (i = 0; i < num_screens; i++)
+ TAILQ_FOREACH(r, &screens[i].rl, entry)
+ bar_draw(r->bar);
+
xcb_flush(conn);
}
done: