#include <util.h>
#include <X11/cursorfont.h>
#include <X11/extensions/Xrandr.h>
+#include <X11/Xcursor/Xcursor.h>
#include <X11/Xft/Xft.h>
#include <X11/Xlib-xcb.h>
#include <xcb/xcb_atom.h>
#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
#define SWM_FOCUS_FOLLOW (1)
#define SWM_FOCUS_MANUAL (2)
+#define SWM_CK_NONE 0
+#define SWM_CK_ALL 0x7
+#define SWM_CK_FOCUS 0x1
+#define SWM_CK_POINTER 0x2
+#define SWM_CK_FALLBACK 0x4
+
#define SWM_CONF_DEFAULT (0)
#define SWM_CONF_KEYMAPPING (1)
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;
char *bar_argv[] = { NULL, NULL };
int bar_pipe[2];
-unsigned char bar_ext[SWM_BAR_MAX];
+char bar_ext[SWM_BAR_MAX];
char bar_vertext[SWM_BAR_MAX];
int bar_version = 0;
sig_atomic_t bar_alarm = 0;
int floatmaxed; /* whether maxed by max_stack */
int floating;
int manual;
+ int32_t mapped;
int32_t iconic;
int bordered;
unsigned int ewmh_flags;
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)
{"_SWM_WM_STATE_MANUAL", XCB_ATOM_NONE},
};
+/* Cursors */
+enum {
+ XC_FLEUR,
+ XC_LEFT_PTR,
+ XC_BOTTOM_LEFT_CORNER,
+ XC_BOTTOM_RIGHT_CORNER,
+ XC_SIZING,
+ XC_TOP_LEFT_CORNER,
+ XC_TOP_RIGHT_CORNER,
+ XC_MAX
+};
+
+struct cursors {
+ char *name; /* Name used by Xcursor .*/
+ uint8_t cf_char; /* cursorfont index. */
+ xcb_cursor_t cid;
+} cursors[XC_MAX] = {
+ {"fleur", XC_fleur, XCB_CURSOR_NONE},
+ {"left_ptr", XC_left_ptr, XCB_CURSOR_NONE},
+ {"bottom_left_corner", XC_bottom_left_corner, XCB_CURSOR_NONE},
+ {"bottom_right_corner", XC_bottom_right_corner, XCB_CURSOR_NONE},
+ {"sizing", XC_sizing, XCB_CURSOR_NONE},
+ {"top_left_corner", XC_top_left_corner, XCB_CURSOR_NONE},
+ {"top_right_corner", XC_top_right_corner, XCB_CURSOR_NONE},
+};
+
+/* spawn */
+struct spawn_prog {
+ TAILQ_ENTRY(spawn_prog) entry;
+ char *name;
+ int argc;
+ char **argv;
+};
+TAILQ_HEAD(spawn_list, spawn_prog);
+struct spawn_list spawns = TAILQ_HEAD_INITIALIZER(spawns);
+
+/* user/key callable function IDs */
+enum keyfuncid {
+ KF_BAR_TOGGLE,
+ KF_BUTTON2,
+ KF_CYCLE_LAYOUT,
+ KF_FLIP_LAYOUT,
+ KF_FLOAT_TOGGLE,
+ KF_FOCUS_MAIN,
+ KF_FOCUS_NEXT,
+ KF_FOCUS_PREV,
+ KF_HEIGHT_GROW,
+ KF_HEIGHT_SHRINK,
+ KF_ICONIFY,
+ KF_MASTER_SHRINK,
+ KF_MASTER_GROW,
+ KF_MASTER_ADD,
+ KF_MASTER_DEL,
+ KF_MOVE_DOWN,
+ KF_MOVE_LEFT,
+ KF_MOVE_RIGHT,
+ KF_MOVE_UP,
+ KF_MVWS_1,
+ KF_MVWS_2,
+ KF_MVWS_3,
+ KF_MVWS_4,
+ KF_MVWS_5,
+ KF_MVWS_6,
+ KF_MVWS_7,
+ KF_MVWS_8,
+ KF_MVWS_9,
+ KF_MVWS_10,
+ KF_MVWS_11,
+ KF_MVWS_12,
+ KF_MVWS_13,
+ KF_MVWS_14,
+ KF_MVWS_15,
+ KF_MVWS_16,
+ KF_MVWS_17,
+ KF_MVWS_18,
+ KF_MVWS_19,
+ KF_MVWS_20,
+ KF_MVWS_21,
+ KF_MVWS_22,
+ KF_NAME_WORKSPACE,
+ KF_QUIT,
+ KF_RAISE_TOGGLE,
+ KF_RESTART,
+ KF_SCREEN_NEXT,
+ KF_SCREEN_PREV,
+ KF_SEARCH_WIN,
+ KF_SEARCH_WORKSPACE,
+ KF_SPAWN_CUSTOM,
+ KF_STACK_INC,
+ KF_STACK_DEC,
+ KF_STACK_RESET,
+ KF_SWAP_MAIN,
+ KF_SWAP_NEXT,
+ KF_SWAP_PREV,
+ KF_UNICONIFY,
+ KF_VERSION,
+ KF_WIDTH_GROW,
+ KF_WIDTH_SHRINK,
+ KF_WIND_DEL,
+ KF_WIND_KILL,
+ KF_WS_1,
+ KF_WS_2,
+ KF_WS_3,
+ KF_WS_4,
+ KF_WS_5,
+ KF_WS_6,
+ KF_WS_7,
+ KF_WS_8,
+ KF_WS_9,
+ KF_WS_10,
+ KF_WS_11,
+ KF_WS_12,
+ KF_WS_13,
+ KF_WS_14,
+ KF_WS_15,
+ KF_WS_16,
+ KF_WS_17,
+ KF_WS_18,
+ KF_WS_19,
+ KF_WS_20,
+ KF_WS_21,
+ KF_WS_22,
+ KF_WS_NEXT,
+ KF_WS_NEXT_ALL,
+ KF_WS_PREV,
+ KF_WS_PREV_ALL,
+ KF_WS_PRIOR,
+ KF_DUMPWINS, /* MUST BE LAST */
+ KF_INVALID
+};
+
+struct key {
+ RB_ENTRY(key) entry;
+ unsigned int mod;
+ KeySym keysym;
+ enum keyfuncid funcid;
+ char *spawn_name;
+};
+RB_HEAD(key_tree, key);
+
/* function prototypes */
+void adjust_font(struct ws_win *);
+void bar_class_name(char *, size_t, struct swm_region *);
+void bar_class_title_name(char *, size_t, struct swm_region *);
+void bar_cleanup(struct swm_region *);
+void bar_extra_stop(void);
+void bar_fmt(const char *, char *, struct swm_region *, size_t);
+void bar_fmt_expand(char *, size_t);
+void bar_fmt_print(void);
+void bar_print(struct swm_region *, const char *);
+void bar_print_legacy(struct swm_region *, const char *);
+void bar_refresh(void);
+void bar_replace(char *, char *, struct swm_region *, size_t);
+void bar_replace_pad(char *, int *, size_t);
+char * bar_replace_seq(char *, char *, struct swm_region *, size_t *,
+ size_t);
+void bar_setup(struct swm_region *);
+void bar_signal(int);
+void bar_title_name(char *, size_t, struct swm_region *);
+void bar_toggle(struct swm_region *, union arg *);
+void bar_update(void);
+void bar_urgent(char *, size_t);
+void bar_window_float(char *, size_t, struct swm_region *);
+void bar_window_name(char *, size_t, struct swm_region *);
+void bar_workspace_name(char *, size_t, struct swm_region *);
void buttonpress(xcb_button_press_event_t *);
void check_conn(void);
+void clear_keys(void);
void clientmessage(xcb_client_message_event_t *);
-int conf_load(char *, int);
+void client_msg(struct ws_win *, xcb_atom_t, xcb_timestamp_t);
+int conf_load(const char *, int);
void configurenotify(xcb_configure_notify_event_t *);
void configurerequest(xcb_configure_request_event_t *);
+void config_win(struct ws_win *, xcb_configure_request_event_t *);
void constrain_window(struct ws_win *, struct swm_region *, int);
+int count_win(struct workspace *, int);
+void cursors_cleanup(void);
+void cursors_load(void);
+void custom_region(char *);
+void cyclescr(struct swm_region *, union arg *);
+void cyclews(struct swm_region *, union arg *);
+void cycle_layout(struct swm_region *, union arg *);
void destroynotify(xcb_destroy_notify_event_t *);
+void dumpwins(struct swm_region *, union arg *);
+int enable_wm(void);
void enternotify(xcb_enter_notify_event_t *);
void event_drain(uint8_t);
void event_error(xcb_generic_error_t *);
void event_handle(xcb_generic_event_t *);
-char *expand_tilde(char *);
+void ewmh_autoquirk(struct ws_win *);
+void ewmh_get_win_state(struct ws_win *);
+int ewmh_set_win_fullscreen(struct ws_win *, int);
+void ewmh_update_actions(struct ws_win *);
+void ewmh_update_win_state(struct ws_win *, xcb_atom_t, long);
+char *expand_tilde(const char *);
void expose(xcb_expose_event_t *);
+void fake_keypress(struct ws_win *, xcb_keysym_t, uint16_t);
+struct pid_e *find_pid(pid_t);
+struct ws_win *find_unmanaged_window(xcb_window_t);
struct ws_win *find_window(xcb_window_t);
+void floating_toggle(struct swm_region *, union arg *);
int floating_toggle_win(struct ws_win *);
void focus(struct swm_region *, union arg *);
-void focus_flush(void);
-struct ws_win *focus_magic(struct ws_win *);
#ifdef SWM_DEBUG
void focusin(xcb_focus_in_event_t *);
+void focusout(xcb_focus_out_event_t *);
#endif
+void focus_flush(void);
+void focus_win(struct ws_win *);
+void fontset_init(void);
+void free_window(struct ws_win *);
xcb_atom_t get_atom_from_string(const char *);
#ifdef SWM_DEBUG
char *get_atom_name(xcb_atom_t);
+#endif
+struct ws_win *get_focus_magic(struct ws_win *);
+struct ws_win *get_focus_prev(struct ws_win *);
+#ifdef SWM_DEBUG
char *get_notify_detail_label(uint8_t);
char *get_notify_mode_label(uint8_t);
#endif
+struct ws_win *get_pointer_win(xcb_window_t);
+struct ws_win *get_region_focus(struct swm_region *);
xcb_screen_t *get_screen(int);
+#ifdef SWM_DEBUG
+char *get_stack_mode_name(uint8_t);
+#endif
+int32_t get_swm_iconic(struct ws_win *);
char *get_win_name(xcb_window_t);
+int get_ws_idx(xcb_window_t);
uint32_t getstate(xcb_window_t);
-void grabbuttons(struct ws_win *, int);
+void grabbuttons(struct ws_win *);
+void grabkeys(void);
+void grab_windows(void);
+void iconify(struct swm_region *, union arg *);
+int isxlfd(char *);
void keypress(xcb_key_press_event_t *);
+int key_cmp(struct key *, struct key *);
+void key_insert(unsigned int, KeySym, enum keyfuncid, const char *);
+struct key *key_lookup(unsigned int, KeySym);
+void key_remove(struct key *);
+void key_replace(struct key *, unsigned int, KeySym, enum keyfuncid,
+ const char *);
+void kill_refs(struct ws_win *);
#ifdef SWM_DEBUG
void leavenotify(xcb_leave_notify_event_t *);
#endif
void load_float_geom(struct ws_win *, struct swm_region *);
-void map_window_raised(xcb_window_t);
+struct ws_win *manage_window(xcb_window_t, uint16_t);
+void map_window(struct ws_win *);
void mapnotify(xcb_map_notify_event_t *);
void mappingnotify(xcb_mapping_notify_event_t *);
void maprequest(xcb_map_request_event_t *);
+void move(struct ws_win *, union arg *);
+void move_step(struct swm_region *, union arg *);
+uint32_t name_to_pixel(const char *);
+void name_workspace(struct swm_region *, union arg *);
void new_region(struct swm_screen *, int, int, int, int);
+int parsekeys(char *, unsigned int, unsigned int *, KeySym *);
+int parsequirks(char *, unsigned long *);
int parse_rgb(const char *, uint16_t *, uint16_t *, uint16_t *);
+void pressbutton(struct swm_region *, union arg *);
+void priorws(struct swm_region *, union arg *);
+#ifdef SWM_DEBUG
+void print_win_geom(xcb_window_t);
+#endif
void propertynotify(xcb_property_notify_event_t *);
-void spawn_select(struct swm_region *, union arg *, char *, int *);
+void quirk_insert(const char *, const char *, unsigned long);
+void quirk_remove(struct quirk *);
+void quirk_replace(struct quirk *, const char *, const char *,
+ unsigned long);
+void quit(struct swm_region *, union arg *);
+void raise_toggle(struct swm_region *, union arg *);
+void resize(struct ws_win *, union arg *);
+void resize_step(struct swm_region *, union arg *);
+void restart(struct swm_region *, union arg *);
+struct swm_region *root_to_region(xcb_window_t, int);
void screenchange(xcb_randr_screen_change_notify_event_t *);
+void scan_xrandr(int);
+void search_do_resp(void);
+void search_resp_name_workspace(const char *, unsigned long);
+void search_resp_search_window(const char *);
+void search_resp_search_workspace(const char *);
+void search_resp_uniconify(const char *, unsigned long);
+void search_win(struct swm_region *, union arg *);
+void search_win_cleanup(void);
+void search_workspace(struct swm_region *, union arg *);
+void send_to_ws(struct swm_region *, union arg *);
+int setautorun(char *, char *, int);
+int setconfbinding(char *, char *, int);
+int setconfcolor(char *, char *, int);
+int setconfmodkey(char *, char *, int);
+int setconfquirk(char *, char *, int);
+int setconfregion(char *, char *, int);
+int setconfspawn(char *, char *, int);
+int setconfvalue(char *, char *, int);
+void setkeybinding(unsigned int, KeySym, enum keyfuncid, const char *);
+int setkeymapping(char *, char *, int);
+int setlayout(char *, char *, int);
+void setquirk(const char *, const char *, unsigned long);
+void setscreencolor(char *, int, int);
+void setspawn(const char *, const char *);
+void setup_ewmh(void);
+void setup_globals(void);
+void setup_keys(void);
+void setup_quirks(void);
+void setup_screens(void);
+void setup_spawn(void);
+void set_child_transient(struct ws_win *, xcb_window_t *);
+void set_swm_iconic(struct ws_win *, int);
+void set_win_state(struct ws_win *, uint16_t);
void shutdown_cleanup(void);
+void sighdlr(int);
+void socket_setnonblock(int);
+void sort_windows(struct ws_win_list *);
+void spawn(int, union arg *, int);
+void spawn_custom(struct swm_region *, union arg *, const char *);
+int spawn_expand(struct swm_region *, union arg *, const char *, char ***);
+void spawn_insert(const char *, const char *);
+void spawn_remove(struct spawn_prog *);
+void spawn_replace(struct spawn_prog *, const char *, const char *);
+void spawn_select(struct swm_region *, union arg *, const char *, int *);
+void stack_config(struct swm_region *, union arg *);
+void stack_floater(struct ws_win *, struct swm_region *);
+void stack_master(struct workspace *, struct swm_geometry *, int, int);
void store_float_geom(struct ws_win *, struct swm_region *);
+char * strdupsafe(const char *);
+void swapwin(struct swm_region *, union arg *);
+void switchws(struct swm_region *, union arg *);
+void teardown_ewmh(void);
+void unfocus_win(struct ws_win *);
+void uniconify(struct swm_region *, union arg *);
void unmanage_window(struct ws_win *);
void unmapnotify(xcb_unmap_notify_event_t *);
+void unmap_all(void);
+void unmap_window(struct ws_win *);
+void updatenumlockmask(void);
+void update_modkey(unsigned int);
void update_window(struct ws_win *);
+int validate_win(struct ws_win *);
+int validate_ws(struct workspace *);
/*void visibilitynotify(xcb_visibility_notify_event_t *);*/
+void version(struct swm_region *, union arg *);
+pid_t window_get_pid(xcb_window_t);
+void wkill(struct swm_region *, union arg *);
+void workaround(void);
+void xft_init(struct swm_region *);
+
+RB_PROTOTYPE(key_tree, key, entry, key_cmp);
+RB_GENERATE(key_tree, key, entry, key_cmp);
+struct key_tree keys;
+
+void
+cursors_load(void)
+{
+ xcb_font_t cf = XCB_NONE;
+ int i;
+
+ for (i = 0; i < LENGTH(cursors); ++i) {
+ /* try to load Xcursor first. */
+ cursors[i].cid = XcursorLibraryLoadCursor(display,
+ cursors[i].name);
+
+ /* fallback to cursorfont. */
+ if (cursors[i].cid == XCB_CURSOR_NONE) {
+ if (cf == XCB_NONE) {
+ cf = xcb_generate_id(conn);
+ xcb_open_font(conn, cf, strlen("cursor"),
+ "cursor");
+ }
+
+ cursors[i].cid = xcb_generate_id(conn);
+ xcb_create_glyph_cursor(conn, cursors[i].cid, cf, cf,
+ cursors[i].cf_char, cursors[i].cf_char + 1, 0, 0, 0,
+ 0xffff, 0xffff, 0xffff);
+
+ }
+ }
+
+ if (cf != XCB_NONE)
+ xcb_close_font(conn, cf);
+}
+
+void
+cursors_cleanup(void)
+{
+ int i;
+ for (i = 0; i < LENGTH(cursors); ++i)
+ xcb_free_cursor(conn, cursors[i].cid);
+}
char *
-expand_tilde(char *s)
+expand_tilde(const char *s)
{
struct passwd *ppwd;
- int i, max;
+ int i;
+ long max;
char *user;
const char *sc = s;
char *result;
s = &s[i];
ppwd = strlen(user) == 0 ? getpwuid(getuid()) : getpwnam(user);
+ free(user);
+
if (ppwd == NULL)
result = strdup(sc);
else
xcb_flush(conn);
}
-void
-map_window_raised(xcb_window_t win)
-{
- uint32_t val = XCB_STACK_MODE_ABOVE;
-
- xcb_configure_window(conn, win,
- XCB_CONFIG_WINDOW_STACK_MODE, &val);
-
- xcb_map_window(conn, win);
-}
-
xcb_atom_t
get_atom_from_string(const char *str)
{
}
void
-update_iconic(struct ws_win *win, int newv)
+set_swm_iconic(struct ws_win *win, int newv)
{
int32_t v = newv;
}
int32_t
-get_iconic(struct ws_win *win)
+get_swm_iconic(struct ws_win *win)
{
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);
kill(bar_pid, SIGTERM);
bar_pid = 0;
}
- strlcpy((char *)bar_ext, "", sizeof bar_ext);
+ strlcpy(bar_ext, "", sizeof bar_ext);
bar_extra = 0;
}
if (title_class_enabled) {
strlcat(fmtnew, "+C", sz);
- if (title_name_enabled == 0)
+ if (!title_name_enabled)
strlcat(fmtnew, "+4<", sz);
}
size_t len;
char *b;
- if (bar_enabled == 0)
+ if (!bar_enabled)
return;
if (bar_extra && bar_extra_running) {
/* ignore short reads; it'll correct itself */
while ((b = fgetln(stdin, &len)) != NULL)
if (b && b[len - 1] == '\n') {
b[len - 1] = '\0';
- strlcpy((char *)bar_ext, b, sizeof bar_ext);
+ strlcpy(bar_ext, b, sizeof bar_ext);
}
if (b == NULL && errno != EAGAIN) {
warn("bar_update: bar_extra failed");
bar_extra_stop();
}
} else
- strlcpy((char *)bar_ext, "", sizeof bar_ext);
+ strlcpy(bar_ext, "", sizeof bar_ext);
bar_fmt_print();
alarm(bar_delay);
for (i = 0; i < num_screens; i++)
TAILQ_FOREACH(tmpr, &screens[i].rl, entry)
if (tmpr->bar)
- map_window_raised(tmpr->bar->id);
+ xcb_map_window(conn, tmpr->bar->id);
}
bar_enabled = !bar_enabled;
int i, num_screens;
/* do this here because the conf file is in memory */
- if (bar_extra && bar_extra_running == 0 && bar_argv[0]) {
+ if (bar_extra && !bar_extra_running && bar_argv[0]) {
/* launch external status app */
bar_extra_running = 1;
if (pipe(bar_pipe) == -1)
}
void
-fontset_init()
+fontset_init(void)
{
char *default_string;
char **missing_charsets;
if (!XftColorAllocValue(display, DefaultVisual(display, r->s->idx),
DefaultColormap(display, r->s->idx), &color, &bar_font_color))
- warn("unable to allocate Xft color");
+ warn("Xft error: unable to allocate color.");
bar_height = bar_font->height + 2 * bar_border_width;
XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE);
if (bar_enabled)
- map_window_raised(r->bar->id);
+ xcb_map_window(conn, r->bar->id);
DNPRINTF(SWM_D_BAR, "bar_setup: window: 0x%x, (x,y) w x h: (%d,%d) "
"%d x %d\n", WINID(r->bar), X(r->bar), Y(r->bar), WIDTH(r->bar),
{
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;
}
void
-client_msg(struct ws_win *win, xcb_atom_t a)
+client_msg(struct ws_win *win, xcb_atom_t a, xcb_timestamp_t t)
{
xcb_client_message_event_t ev;
+#ifdef SWM_DEBUG
+ char *name;
+#endif
if (win == NULL)
return;
+#ifdef SWM_DEBUG
+ name = get_atom_name(a);
+ DNPRINTF(SWM_D_EVENT, "client_msg: window: 0x%x, atom: %s(%u), "
+ "time: %#x\n",
+ win->id, name, a, t);
+ free(name);
+#endif
bzero(&ev, sizeof ev);
ev.response_type = XCB_CLIENT_MESSAGE;
ev.type = a_prot;
ev.format = 32;
ev.data.data32[0] = a;
- ev.data.data32[1] = XCB_CURRENT_TIME;
+ ev.data.data32[1] = t;
xcb_send_event(conn, 0, win->id,
XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
int count = 0;
TAILQ_FOREACH(win, &ws->winlist, entry) {
- if (count_transient == 0 && win->floating)
+ if (!count_transient && win->floating)
continue;
- if (count_transient == 0 && win->transient)
+ if (!count_transient && win->transient)
continue;
if (win->iconic)
continue;
}
void
-unmap_window(struct ws_win *win)
+map_window(struct ws_win *win)
{
- DNPRINTF(SWM_D_EVENT, "unmap_window: window: 0x%x\n", win->id);
+ uint32_t val = XCB_STACK_MODE_ABOVE;
if (win == NULL)
return;
- /* don't unmap again */
- if (getstate(win->id) == XCB_ICCCM_WM_STATE_ICONIC)
+ DNPRINTF(SWM_D_EVENT, "map_window: win 0x%x, mapped: %s\n", win->id,
+ YESNO(win->mapped));
+
+ xcb_configure_window(conn, win->id,
+ XCB_CONFIG_WINDOW_STACK_MODE, &val);
+
+ if (win->mapped)
+ return;
+
+ xcb_map_window(conn, win->id);
+ set_win_state(win, XCB_ICCCM_WM_STATE_NORMAL);
+ win->mapped = 1;
+}
+
+void
+unmap_window(struct ws_win *win)
+{
+ if (win == NULL)
return;
- set_win_state(win, XCB_ICCCM_WM_STATE_ICONIC);
+ DNPRINTF(SWM_D_EVENT, "unmap_window: win 0x%x, mapped: %s\n", win->id,
+ YESNO(win->mapped));
+
+ if (!win->mapped)
+ return;
xcb_unmap_window(conn, win->id);
- xcb_change_window_attributes(conn, win->id,
- XCB_CW_BORDER_PIXEL, &win->s->c[SWM_S_COLOR_UNFOCUS].pixel);
+ set_win_state(win, XCB_ICCCM_WM_STATE_ICONIC);
+ win->mapped = 0;
}
void
quit(NULL, NULL);
}
+struct ws_win *
+get_pointer_win(xcb_window_t root)
+{
+ struct ws_win *win = NULL;
+ xcb_query_pointer_reply_t *r;
+
+ DNPRINTF(SWM_D_EVENT, "get_pointer_win: root: 0x%x.\n", root);
+
+ r = xcb_query_pointer_reply(conn, xcb_query_pointer(conn, root), NULL);
+ if (r) {
+ win = find_window(r->child);
+ if (win) {
+ DNPRINTF(SWM_D_EVENT, "get_pointer_win: 0x%x.\n",
+ win->id);
+ } else {
+ DNPRINTF(SWM_D_EVENT, "get_pointer_win: none.\n");
+ }
+ free(r);
+ }
+
+ return win;
+}
+
struct swm_region *
-root_to_region(xcb_window_t root)
+root_to_region(xcb_window_t root, int check)
{
+ struct ws_win *cfw;
struct swm_region *r = NULL;
int i, num_screens;
xcb_query_pointer_reply_t *qpr;
+ xcb_get_input_focus_reply_t *gifr;
DNPRINTF(SWM_D_MISC, "root_to_region: window: 0x%x\n", root);
if (screens[i].root == root)
break;
- qpr = xcb_query_pointer_reply(conn, xcb_query_pointer(conn,
- screens[i].root), NULL);
+ if (check & SWM_CK_FOCUS) {
+ /* Try to find an actively focused window */
+ gifr = xcb_get_input_focus_reply(conn,
+ xcb_get_input_focus(conn), NULL);
+ if (gifr) {
+ cfw = find_window(gifr->focus);
+ if (cfw && cfw->ws->r)
+ r = cfw->ws->r;
- if (qpr) {
- DNPRINTF(SWM_D_MISC, "root_to_region: pointer: (%d,%d)\n",
- qpr->root_x, qpr->root_y);
- /* choose a region based on pointer location */
- TAILQ_FOREACH(r, &screens[i].rl, entry)
- if (X(r) <= qpr->root_x && qpr->root_x < MAX_X(r) &&
- Y(r) <= qpr->root_y && qpr->root_y < MAX_Y(r))
- break;
- free(qpr);
+ free(gifr);
+ }
}
- if (r == NULL)
+ if (r == NULL && check & SWM_CK_POINTER) {
+ /* No region with an active focus; try to use pointer. */
+ qpr = xcb_query_pointer_reply(conn, xcb_query_pointer(conn,
+ screens[i].root), NULL);
+
+ if (qpr) {
+ DNPRINTF(SWM_D_MISC, "root_to_region: pointer: "
+ "(%d,%d)\n", qpr->root_x, qpr->root_y);
+ TAILQ_FOREACH(r, &screens[i].rl, entry)
+ if (X(r) <= qpr->root_x &&
+ qpr->root_x < MAX_X(r) &&
+ Y(r) <= qpr->root_y &&
+ qpr->root_y < MAX_Y(r))
+ break;
+ free(qpr);
+ }
+ }
+
+ /* Last resort. */
+ if (r == NULL && check & SWM_CK_FALLBACK)
r = TAILQ_FIRST(&screens[i].rl);
return (r);
if (win == NULL)
return;
- if (win->ws == NULL)
+ if (win->ws == NULL) {
+ DNPRINTF(SWM_D_FOCUS, "unfocus_win: NULL ws.\n");
return;
+ }
- if (validate_ws(win->ws))
- return; /* XXX this gets hit with thunderbird, needs fixing */
+ if (validate_ws(win->ws)) {
+ DNPRINTF(SWM_D_FOCUS, "unfocus_win: invalid ws.\n");
+ return;
+ }
- if (win->ws->r == NULL)
+ if (win->ws->r == NULL) {
+ DNPRINTF(SWM_D_FOCUS, "unfocus_win: NULL region.\n");
return;
+ }
if (validate_win(win)) {
+ DNPRINTF(SWM_D_FOCUS, "unfocus_win: invalid win.\n");
kill_refs(win);
return;
}
win->ws->focus_prev = NULL;
}
- grabbuttons(win, 0);
xcb_change_window_attributes(conn, win->id, XCB_CW_BORDER_PIXEL,
&win->ws->r->s->c[SWM_S_COLOR_UNFOCUS].pixel);
+
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->s->root,
ewmh[_NET_ACTIVE_WINDOW].atom, XCB_ATOM_WINDOW, 32, 1, &none);
-}
-
-void
-unfocus_all(void)
-{
- struct ws_win *win;
- int i, j, num_screens;
- DNPRINTF(SWM_D_FOCUS, "unfocus_all\n");
-
- num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
- for (i = 0; i < num_screens; i++)
- for (j = 0; j < workspace_limit; j++)
- TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry)
- unfocus_win(win);
+ DNPRINTF(SWM_D_FOCUS, "unfocus_win: done.\n");
}
void
focus_win(struct ws_win *win)
{
- struct ws_win *cfw = NULL;
+ struct ws_win *cfw = NULL, *parent = NULL, *w;
+ struct workspace *ws;
xcb_get_input_focus_reply_t *r;
- xcb_window_t cur_focus = XCB_WINDOW_NONE;
DNPRINTF(SWM_D_FOCUS, "focus_win: window: 0x%x\n", WINID(win));
- if (win == NULL) {
- /* Clear the status-bar. */
- bar_update();
- return;
- }
+ if (win == NULL)
+ goto out;
if (win->ws == NULL)
- return;
+ goto out;
+
+ ws = win->ws;
- if (validate_ws(win->ws))
- return; /* XXX this gets hit with thunderbird, needs fixing */
+ if (validate_ws(ws))
+ goto out;
if (validate_win(win)) {
kill_refs(win);
- return;
+ goto out;
}
r = xcb_get_input_focus_reply(conn, xcb_get_input_focus(conn), NULL);
if (r) {
- cur_focus = r->focus;
+ cfw = find_window(r->focus);
+ if (cfw != win)
+ unfocus_win(cfw);
free(r);
}
- if ((cfw = find_window(cur_focus)) != NULL)
- unfocus_win(cfw);
- win->ws->focus = win;
+ if (ws->focus != win) {
+ if (ws->focus && ws->focus != cfw)
+ unfocus_win(ws->focus);
+ ws->focus = win;
+ }
- /* Tell app it can set focus. */
- if (win->take_focus) {
- /* java is special; always tell parent */
- if (win->transient && win->java)
- client_msg(find_window(win->transient), a_takefocus);
- else
- client_msg(win, a_takefocus);
+ /* If this window directs focus to a child window, then clear. */
+ if (win->focus_child)
+ win->focus_child = NULL;
+
+ /* If transient, adjust parent's focus child for focus_magic. */
+ if (win->transient) {
+ parent = find_window(win->transient);
+ if (parent && parent->focus_child != win)
+ parent->focus_child = win;
}
- if (win->ws->r != NULL) {
- if (win->java == 0)
+ if (cfw != win && ws->r != NULL) {
+ /* Set input focus if no input hint, or indicated by hint. */
+ if (!(win->hints.flags & XCB_ICCCM_WM_HINT_INPUT) ||
+ (win->hints.flags & XCB_ICCCM_WM_HINT_INPUT &&
+ win->hints.input))
xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT,
- win->id, XCB_CURRENT_TIME);
- grabbuttons(win, 1);
- xcb_change_window_attributes(conn, win->id,
- XCB_CW_BORDER_PIXEL,
- &win->ws->r->s->c[SWM_S_COLOR_FOCUS].pixel);
- if (win->ws->cur_layout->flags & SWM_L_MAPONFOCUS ||
- win->ws->always_raise)
- map_window_raised(win->id);
+ win->id, last_event_time);
+
+ /* Tell app it can adjust focus to a specific window. */
+ if (win->take_focus) {
+ /* java is special; always tell parent */
+ if (win->transient && win->java)
+ client_msg(parent, a_takefocus,
+ last_event_time);
+ else
+ client_msg(win, a_takefocus, last_event_time);
+ }
+
+ xcb_change_window_attributes(conn, win->id, XCB_CW_BORDER_PIXEL,
+ &ws->r->s->c[SWM_S_COLOR_FOCUS].pixel);
+
+ if (ws->cur_layout->flags & SWM_L_MAPONFOCUS ||
+ ws->always_raise) {
+ /* If a parent exists, map it first. */
+ if (parent) {
+ map_window(parent);
+
+ /* Map siblings next. */
+ TAILQ_FOREACH(w, &ws->winlist, entry)
+ if (w != win && !w->iconic &&
+ w->transient == parent->id)
+ map_window(w);
+ }
+
+ /* Map focused window. */
+ map_window(win);
+
+ /* Finally, map children of focus window. */
+ TAILQ_FOREACH(w, &ws->winlist, entry)
+ if (w->transient == win->id && !w->iconic)
+ map_window(w);
+
+ }
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->s->root,
ewmh[_NET_ACTIVE_WINDOW].atom, XCB_ATOM_WINDOW, 32, 1,
&win->id);
}
+out:
bar_update();
+
+ DNPRINTF(SWM_D_FOCUS, "focus_win: done.\n");
}
/* If a child window should have focus instead, return it. */
struct ws_win *
-focus_magic(struct ws_win *win)
+get_focus_magic(struct ws_win *win)
{
struct ws_win *parent = NULL;
+ struct ws_win *child = NULL;
- DNPRINTF(SWM_D_FOCUS, "focus_magic: window: 0x%x\n", WINID(win));
+ DNPRINTF(SWM_D_FOCUS, "get_focus_magic: window: 0x%x\n", WINID(win));
if (win == NULL)
return win;
if (win->transient) {
parent = find_window(win->transient);
- /* If parent prefers focus elsewhere, then do so. */
- if (parent && parent->focus_child) {
- if (validate_win(parent->focus_child) == 0)
- win = parent->focus_child;
+ /* If parent prefers focus elsewhere, then try to do so. */
+ if (parent && (child = parent->focus_child)) {
+ if (validate_win(child) == 0 && child->mapped)
+ win = child;
else
parent->focus_child = NULL;
}
}
- /* If this window prefers focus elsewhere, then do so. */
- if (win->focus_child) {
- if (validate_win(win->focus_child) == 0)
- win = win->focus_child;
+ /* If this window prefers focus elsewhere, then try to do so. */
+ if ((child = win->focus_child)) {
+ if (validate_win(child) == 0 && child->mapped)
+ win = child;
else
win->focus_child = NULL;
}
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 */
this_r->ws = new_ws;
new_ws->r = this_r;
- /* this is needed so that we can click on a window after a restart */
- unfocus_all();
+ /* Set focus_pending before stacking. */
+ if (focus_mode != SWM_FOCUS_FOLLOW)
+ new_ws->focus_pending = get_region_focus(new_ws->r);
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);
+ /* if workspaces were swapped, then don't wait to set focus */
+ if (old_ws->r && focus_mode != SWM_FOCUS_FOLLOW) {
+ if (new_ws->focus_pending) {
+ focus_win(new_ws->focus_pending);
+ } else {
+ /* Empty region, focus on root. */
+ xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT,
+ new_ws->r->s[new_ws->r->s->idx].root,
+ XCB_CURRENT_TIME);
+ }
+ }
+
+ /* Clear bar if new ws is empty. */
+ if (new_ws->focus_pending == NULL)
+ bar_update();
+
focus_flush();
- DNPRINTF(SWM_D_WS, "switchws: done\n");
+ DNPRINTF(SWM_D_WS, "switchws: done.\n");
}
void
};
if (!cycle_all &&
- (cycle_empty == 0 && TAILQ_EMPTY(&s->ws[a.id].winlist)))
+ (!cycle_empty && TAILQ_EMPTY(&s->ws[a.id].winlist)))
continue;
- if (cycle_visible == 0 && s->ws[a.id].r != NULL)
+ if (!cycle_visible && s->ws[a.id].r != NULL)
continue;
switchws(r, &a);
void
cyclescr(struct swm_region *r, union arg *args)
{
+ struct ws_win *nfw;
struct swm_region *rr = NULL;
- union arg a;
- int i, x, y, num_screens;
+ int i, num_screens;
num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
/* do nothing if we don't have more than one screen */
if (rr == NULL)
return;
- /* move mouse to region */
- x = X(rr) + 1;
- y = Y(rr) + 1 + (bar_enabled ? bar_height : 0);
- 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);
+ nfw = get_region_focus(rr);
+ if (nfw) {
+ focus_win(nfw);
+ } else {
+ /* New region is empty; unfocus old region and warp pointer. */
+ unfocus_win(r->ws->focus);
+ xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT,
+ rr->s[i].root, XCB_CURRENT_TIME);
- if (rr->ws->focus) {
- /* move to focus window */
- x = X(rr->ws->focus) + 1;
- y = Y(rr->ws->focus) + 1;
- xcb_warp_pointer(conn, XCB_WINDOW_NONE, rr->s[i].root, 0, 0, 0,
- 0, x, y);
+ /* Clear bar since empty. */
+ bar_update();
}
+
+ focus_flush();
}
void
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);
focus_flush();
}
-void
-focus_prev(struct ws_win *win)
+struct ws_win *
+get_focus_prev(struct ws_win *win)
{
struct ws_win *winfocus = NULL;
struct ws_win *cur_focus = NULL;
struct workspace *ws = NULL;
if (!(win && win->ws))
- return;
+ return NULL;
ws = win->ws;
wl = &ws->winlist;
cur_focus = ws->focus;
- DNPRINTF(SWM_D_FOCUS, "focus_prev: window: 0x%x, cur_focus: 0x%x\n",
+ DNPRINTF(SWM_D_FOCUS, "get_focus_prev: window: 0x%x, cur_focus: 0x%x\n",
WINID(win), WINID(cur_focus));
/* pickle, just focus on whatever */
goto done;
}
- DNPRINTF(SWM_D_FOCUS, "focus_prev: focus_close: %d\n", focus_close);
+ DNPRINTF(SWM_D_FOCUS, "get_focus_prev: focus_close: %d\n", focus_close);
if (winfocus == NULL || winfocus == win) {
switch (focus_close) {
}
kill_refs(win);
- focus_win(focus_magic(winfocus));
+
+ 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;
-
- focus_win(focus_magic(winfocus));
- return;
- }
-
if ((cur_focus = r->ws->focus) == NULL)
return;
ws = r->ws;
/* make sure there is at least one uniconified window */
all_iconics = 1;
TAILQ_FOREACH(winfocus, wl, entry)
- if (winfocus->iconic == 0) {
+ if (!winfocus->iconic) {
all_iconics = 0;
break;
}
while (winfocus != cur_focus) {
if (winfocus == NULL)
winfocus = TAILQ_LAST(wl, ws_win_list);
- if (winfocus->iconic == 0)
+ if (!winfocus->iconic)
break;
winfocus = TAILQ_PREV(winfocus, ws_win_list,
entry);
while (winfocus != cur_focus) {
if (winfocus == NULL)
winfocus = TAILQ_FIRST(wl);
- if (winfocus->iconic == 0)
+ if (!winfocus->iconic)
break;
winfocus = TAILQ_NEXT(winfocus, entry);
}
return;
}
- focus_win(focus_magic(winfocus));
+ focus_win(get_focus_magic(winfocus));
- xcb_flush(conn);
+ focus_flush();
}
void
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(get_region_focus(r));
focus_flush();
}
if (args->id != SWM_ARG_ID_STACKINIT)
stack();
bar_update();
+
+ focus_flush();
}
void
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;
- xcb_get_window_attributes_reply_t *war;
DNPRINTF(SWM_D_STACK, "stack_master: workspace: %d, rot: %s, "
"flip: %s\n", ws->idx, YESNO(rot), YESNO(flip));
return;
TAILQ_FOREACH(win, &ws->winlist, entry)
- if (win->transient == 0 && win->floating == 0
- && win->iconic == 0)
+ if (!win->transient && !win->floating && !win->iconic)
break;
if (win == NULL)
/* stack all the tiled windows */
i = j = 0, s = stacks;
TAILQ_FOREACH(win, &ws->winlist, entry) {
- if (win->transient != 0 || win->floating != 0)
+ if (win->transient || win->floating)
continue;
- if (win->iconic != 0)
+ if (win->iconic)
continue;
if (win->ewmh_flags & EWMH_F_FULLSCREEN) {
else
win_g.y += last_h + 2 * border_width;
- if (disable_border && bar_enabled == 0 && winno == 1){
+ if (disable_border && !bar_enabled && winno == 1){
bordered = 0;
win_g.w += 2 * border_width;
win_g.h += 2 * border_width;
update_window(win);
}
- war = xcb_get_window_attributes_reply(conn,
- xcb_get_window_attributes(conn, win->id),
- NULL);
- if (war) {
- if (war->map_state == XCB_MAP_STATE_UNMAPPED)
- map_window_raised(win->id);
- free(war);
- }
+ map_window(win);
last_h = win_g.h;
i++;
notiles:
/* now, stack all the floaters and transients */
TAILQ_FOREACH(win, &ws->winlist, entry) {
- if (win->transient == 0 && win->floating == 0)
+ if (!win->transient && !win->floating)
continue;
- if (win->iconic == 1)
+ if (win->iconic)
continue;
if (win->ewmh_flags & EWMH_F_FULLSCREEN) {
fs_win = win;
}
stack_floater(win, ws->r);
- map_window_raised(win->id);
+ map_window(win);
}
+ /* Make sure fs_win is stacked last so it's on top. */
if (fs_win) {
stack_floater(fs_win, ws->r);
- map_window_raised(fs_win->id);
+ map_window(fs_win);
}
}
max_stack(struct workspace *ws, struct swm_geometry *g)
{
struct swm_geometry gg = *g;
- struct ws_win *win, *wintrans = NULL, *parent = NULL;
+ struct ws_win *w, *win = NULL, *parent = NULL;
int winno, num_screens;
DNPRINTF(SWM_D_STACK, "max_stack: workspace: %d\n", ws->idx);
if (winno == 0 && count_win(ws, 1) == 0)
return;
+ /* Figure out which top level window should be visible. */
+ if (ws->focus_pending)
+ win = ws->focus_pending;
+ else if (ws->focus)
+ win = ws->focus;
+ else
+ win = TAILQ_FIRST(&ws->winlist);
+
+ if (win->transient)
+ parent = find_window(win->transient);
+
+ DNPRINTF(SWM_D_STACK, "max_stack: win: 0x%x\n", win->id);
+
+ /* maximize all top level windows */
num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
- TAILQ_FOREACH(win, &ws->winlist, entry) {
- if (win->transient) {
- wintrans = win;
- parent = find_window(win->transient);
+ TAILQ_FOREACH(w, &ws->winlist, entry) {
+ if (w->transient || w->iconic)
continue;
- }
- if (win->floating && win->floatmaxed == 0 ) {
+ if (w->floating && !w->floatmaxed) {
/*
* retain geometry for retrieval on exit from
* max_stack mode
*/
- store_float_geom(win, ws->r);
- win->floatmaxed = 1;
+ store_float_geom(w, ws->r);
+ w->floatmaxed = 1;
}
/* only reconfigure if necessary */
- if (X(win) != gg.x || Y(win) != gg.y || WIDTH(win) != gg.w ||
- HEIGHT(win) != gg.h) {
- win->g = gg;
+ if (X(w) != gg.x || Y(w) != gg.y || WIDTH(w) != gg.w ||
+ HEIGHT(w) != gg.h) {
+ w->g = gg;
if (bar_enabled){
- win->bordered = 1;
+ w->bordered = 1;
} else {
- win->bordered = 0;
- WIDTH(win) += 2 * border_width;
- HEIGHT(win) += 2 * border_width;
+ w->bordered = 0;
+ WIDTH(w) += 2 * border_width;
+ HEIGHT(w) += 2 * border_width;
}
- update_window(win);
+ update_window(w);
}
- /* unmap only if we don't have multi screen */
- if (win != ws->focus)
- if (!(num_screens > 1 || outputs > 1))
- unmap_window(win);
+
+ /* Unmap unwanted windows if not multi-screen. */
+ if (!(num_screens > 1 || outputs > 1) && (w != win ||
+ w != parent || w->transient != win->id))
+ unmap_window(w);
}
- /* put the last transient on top */
- if (wintrans) {
- if (parent)
- map_window_raised(parent->id);
- stack_floater(wintrans, ws->r);
- focus_win(focus_magic(wintrans));
+ /* If a parent exists, map it first. */
+ if (parent) {
+ map_window(parent);
+
+ /* Map siblings next. */
+ TAILQ_FOREACH(w, &ws->winlist, entry)
+ if (w != win && !w->iconic &&
+ w->transient == parent->id) {
+ stack_floater(w, ws->r);
+ map_window(w);
+ }
}
+
+ /* Map focused window. */
+ map_window(win);
+
+ /* Finally, map children of focus window. */
+ TAILQ_FOREACH(w, &ws->winlist, entry)
+ if (w->transient == win->id && !w->iconic) {
+ stack_floater(w, ws->r);
+ map_window(w);
+ }
}
void
{
int wsid = args->id;
struct ws_win *win = NULL, *parent;
- struct workspace *ws, *nws;
+ struct workspace *ws, *nws, *pws;
char ws_idx_str[SWM_PROPLEN];
- union arg a;
if (wsid >= workspace_limit)
return;
win = r->ws->focus;
else
return;
- if (win == NULL)
- return;
+
if (win->ws->idx == wsid)
return;
- DNPRINTF(SWM_D_MOVE, "send_to_ws: window: 0x%x\n", win->id);
+ DNPRINTF(SWM_D_MOVE, "send_to_ws: win 0x%x, ws %d -> %d\n", win->id,
+ win->ws->idx, wsid);
ws = win->ws;
nws = &win->s->ws[wsid];
- a.id = SWM_ARG_ID_FOCUSPREV;
- focus(r, &a);
- if (win->transient) {
- parent = find_window(win->transient);
- if (parent) {
- unmap_window(parent);
- TAILQ_REMOVE(&ws->winlist, parent, entry);
- TAILQ_INSERT_TAIL(&nws->winlist, parent, entry);
- parent->ws = nws;
+ /* Update the window's workspace property: _SWM_WS */
+ if (snprintf(ws_idx_str, SWM_PROPLEN, "%d", nws->idx) < SWM_PROPLEN) {
+ if (focus_mode != SWM_FOCUS_FOLLOW)
+ ws->focus_pending = get_focus_prev(win);
+
+ /* Move the parent if this is a transient window. */
+ if (win->transient) {
+ parent = find_window(win->transient);
+ if (parent) {
+ pws = parent->ws;
+ /* Set new focus in parent's ws if needed. */
+ if (pws->focus == parent) {
+ if (focus_mode != SWM_FOCUS_FOLLOW)
+ pws->focus_pending =
+ get_focus_prev(parent);
+
+ unfocus_win(parent);
+
+ if (focus_mode != SWM_FOCUS_FOLLOW)
+ pws->focus = pws->focus_pending;
+
+ if (focus_mode != SWM_FOCUS_FOLLOW)
+ pws->focus_pending = NULL;
+ }
+
+ /* Don't unmap parent if new ws is visible */
+ if (nws->r == NULL)
+ unmap_window(parent);
+
+ /* Transfer */
+ TAILQ_REMOVE(&ws->winlist, parent, entry);
+ TAILQ_INSERT_TAIL(&nws->winlist, parent, entry);
+ parent->ws = nws;
+
+ DNPRINTF(SWM_D_PROP, "send_to_ws: set "
+ "property: _SWM_WS: %s\n", ws_idx_str);
+ xcb_change_property(conn, XCB_PROP_MODE_REPLACE,
+ parent->id, a_swm_ws, XCB_ATOM_STRING, 8,
+ strlen(ws_idx_str), ws_idx_str);
+ }
}
- }
- unmap_window(win);
- TAILQ_REMOVE(&ws->winlist, win, entry);
- TAILQ_INSERT_TAIL(&nws->winlist, win, entry);
- if (TAILQ_EMPTY(&ws->winlist))
- r->ws->focus = NULL;
- win->ws = nws;
- /* Try to update the window's workspace property */
- if (snprintf(ws_idx_str, SWM_PROPLEN, "%d", nws->idx) < SWM_PROPLEN) {
+ unfocus_win(win);
+
+ /* Don't unmap if new ws is visible */
+ if (nws->r == NULL)
+ unmap_window(win);
+
+ /* Transfer */
+ TAILQ_REMOVE(&ws->winlist, win, entry);
+ TAILQ_INSERT_TAIL(&nws->winlist, win, entry);
+ win->ws = nws;
+
+ /* Set focus on new ws. */
+ unfocus_win(nws->focus);
+ nws->focus = win;
+
DNPRINTF(SWM_D_PROP, "send_to_ws: set property: _SWM_WS: %s\n",
ws_idx_str);
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->id,
a_swm_ws, XCB_ATOM_STRING, 8, strlen(ws_idx_str),
ws_idx_str);
- }
- stack();
- bar_update();
+ /* Restack and set new focus. */
+ stack();
- focus_flush();
+ if (focus_mode != SWM_FOCUS_FOLLOW) {
+ focus_win(ws->focus_pending);
+ ws->focus_pending = NULL;
+ }
+
+ focus_flush();
+ }
+
+ DNPRINTF(SWM_D_MOVE, "send_to_ws: done.\n");
}
void
r->ws->always_raise = !r->ws->always_raise;
/* bring floaters back to top */
- if (r->ws->always_raise == 0)
+ if (!r->ws->always_raise)
stack();
focus_flush();
void
iconify(struct swm_region *r, union arg *args)
{
- union arg a;
-
/* suppress unused warning since var is needed */
(void)args;
if (r->ws->focus == NULL)
return;
- unmap_window(r->ws->focus);
- update_iconic(r->ws->focus, 1);
- stack();
- r->ws->focus = NULL;
- a.id = SWM_ARG_ID_FOCUSCUR;
- focus(r, &a);
+ set_swm_iconic(r->ws->focus, 1);
- focus_flush();
+ xcb_flush(conn);
}
char *
XCB_GET_PROPERTY_TYPE_ANY, 0, UINT_MAX);
r = xcb_get_property_reply(conn, c, NULL);
- if (!r || r->type == XCB_NONE) {
- free(r);
- /* Use WM_NAME instead; no UTF-8. */
- c = xcb_get_property(conn, 0, win, XCB_ATOM_WM_NAME,
- XCB_GET_PROPERTY_TYPE_ANY, 0, UINT_MAX);
- r = xcb_get_property_reply(conn, c, NULL);
-
- if(!r || r->type == XCB_NONE) {
+ if (r) {
+ if (r->type == XCB_NONE) {
free(r);
- return NULL;
+ /* Use WM_NAME instead; no UTF-8. */
+ c = xcb_get_property(conn, 0, win, XCB_ATOM_WM_NAME,
+ XCB_GET_PROPERTY_TYPE_ANY, 0, UINT_MAX);
+ r = xcb_get_property_reply(conn, c, NULL);
+
+ if (!r)
+ return (NULL);
+ if (r->type == XCB_NONE) {
+ free(r);
+ return (NULL);
+ }
}
- }
+ if (r->length > 0)
+ name = strndup(xcb_get_property_value(r),
+ xcb_get_property_value_length(r));
- if (r->length > 0)
- name = strndup(xcb_get_property_value(r),
- xcb_get_property_value_length(r));
+ free(r);
+ }
- free(r);
- return name;
+ return (name);
}
void
TAILQ_FOREACH(win, &r->ws->winlist, entry) {
if (win->ws == NULL)
continue; /* should never happen */
- if (win->iconic == 0)
+ if (!win->iconic)
continue;
count++;
}
TAILQ_FOREACH(win, &r->ws->winlist, entry) {
if (win->ws == NULL)
continue; /* should never happen */
- if (win->iconic == 0)
+ if (!win->iconic)
continue;
name = get_win_name(win->id);
}
fclose(lfile);
-
- xcb_flush(conn);
}
void
i = 1;
TAILQ_FOREACH(win, &r->ws->winlist, entry) {
- if (win->iconic == 1)
+ if (win->iconic)
continue;
sw = calloc(1, sizeof(struct search_window));
XCB_COPY_FROM_PARENT, XCB_CW_BACK_PIXEL |
XCB_CW_BORDER_PIXEL, wa);
- map_window_raised(w);
+ xcb_map_window(conn, w);
sw->indicator = w;
TAILQ_INSERT_TAIL(&search_wl, sw, entry);
}
void
-search_resp_uniconify(char *resp, unsigned long len)
+search_resp_uniconify(const char *resp, unsigned long len)
{
char *name;
struct ws_win *win;
DNPRINTF(SWM_D_MISC, "search_resp_uniconify: resp: %s\n", resp);
TAILQ_FOREACH(win, &search_r->ws->winlist, entry) {
- if (win->iconic == 0)
+ if (!win->iconic)
continue;
name = get_win_name(win->id);
if (name == NULL)
free(name);
if (strncmp(s, resp, len) == 0) {
/* XXX this should be a callback to generalize */
- update_iconic(win, 0);
+ set_swm_iconic(win, 0);
free(s);
break;
}
}
void
-search_resp_name_workspace(char *resp, unsigned long len)
+search_resp_name_workspace(const char *resp, unsigned long len)
{
struct workspace *ws;
}
void
-search_resp_search_workspace(char *resp)
+search_resp_search_workspace(const char *resp)
{
char *p, *q;
int ws_idx;
}
void
-search_resp_search_window(char *resp)
+search_resp_search_window(const char *resp)
{
char *s;
int idx;
search_resp_action = SWM_SEARCH_NONE;
close(select_resp_pipe[0]);
free(resp);
+
+ xcb_flush(conn);
}
void
xcb_kill_client(conn, r->ws->focus->id);
else
if (r->ws->focus->can_delete)
- client_msg(r->ws->focus, a_delete);
+ client_msg(r->ws->focus, a_delete, 0);
- xcb_flush(conn);
+ focus_flush();
}
-
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);
- }
+ if (win == win->ws->focus)
+ focus_win(win);
focus_flush();
}
{
xcb_timestamp_t timestamp = 0;
struct swm_region *r = NULL;
- int resize_step = 0;
+ int resize_stp = 0;
struct swm_geometry g;
int top = 0, left = 0, resizing;
int dx, dy;
- unsigned int shape; /* cursor style */
- xcb_cursor_t cursor;
- xcb_font_t cursor_font;
+ xcb_cursor_t cursor;
xcb_query_pointer_reply_t *xpr;
xcb_generic_event_t *evt;
xcb_motion_notify_event_t *mne;
"transient: 0x%x\n", win->id, YESNO(win->floating),
win->transient);
- if (!(win->transient != 0 || win->floating != 0))
+ if (!win->transient && !win->floating)
return;
/* reject resizes in max mode for floaters (transient ok) */
switch (args->id) {
case SWM_ARG_ID_WIDTHSHRINK:
WIDTH(win) -= SWM_RESIZE_STEPS;
- resize_step = 1;
+ resize_stp = 1;
break;
case SWM_ARG_ID_WIDTHGROW:
WIDTH(win) += SWM_RESIZE_STEPS;
- resize_step = 1;
+ resize_stp = 1;
break;
case SWM_ARG_ID_HEIGHTSHRINK:
HEIGHT(win) -= SWM_RESIZE_STEPS;
- resize_step = 1;
+ resize_stp = 1;
break;
case SWM_ARG_ID_HEIGHTGROW:
HEIGHT(win) += SWM_RESIZE_STEPS;
- resize_step = 1;
+ resize_stp = 1;
break;
default:
break;
}
- if (resize_step) {
+ if (resize_stp) {
constrain_window(win, r, 1);
update_window(win);
store_float_geom(win,r);
top = 1;
if (args->id == SWM_ARG_ID_CENTER)
- shape = XC_sizing;
+ cursor = cursors[XC_SIZING].cid;
else if (top)
- shape = (left) ? XC_top_left_corner : XC_top_right_corner;
+ cursor = cursors[left ? XC_TOP_LEFT_CORNER :
+ XC_TOP_RIGHT_CORNER].cid;
else
- shape = (left) ? XC_bottom_left_corner : XC_bottom_right_corner;
-
- cursor_font = xcb_generate_id(conn);
- xcb_open_font(conn, cursor_font, strlen("cursor"), "cursor");
-
- cursor = xcb_generate_id(conn);
- xcb_create_glyph_cursor(conn, cursor, cursor_font, cursor_font,
- shape, shape + 1, 0, 0, 0, 0xffff, 0xffff, 0xffff);
+ cursor = cursors[left ? XC_BOTTOM_LEFT_CORNER :
+ XC_BOTTOM_RIGHT_CORNER].cid;
xcb_grab_pointer(conn, 0, win->id, MOUSEMASK,
XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_WINDOW_NONE, cursor,
store_float_geom(win,r);
xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
- xcb_free_cursor(conn, cursor);
- xcb_close_font(conn, cursor_font);
free(xpr);
- DNPRINTF(SWM_D_EVENT, "resize: done\n");
+ DNPRINTF(SWM_D_EVENT, "resize: done.\n");
}
void
return;
resize(win, args);
+ focus_flush();
}
#define SWM_MOVE_STEPS (50)
move(struct ws_win *win, union arg *args)
{
xcb_timestamp_t timestamp = 0;
- int move_step = 0, moving;
+ int move_stp = 0, moving;
struct swm_region *r = NULL;
- xcb_font_t cursor_font;
- xcb_cursor_t cursor;
xcb_query_pointer_reply_t *qpr;
xcb_generic_event_t *evt;
xcb_motion_notify_event_t *mne;
return;
win->manual = 1;
- if (win->floating == 0 && !win->transient) {
+ if (!win->floating && !win->transient) {
store_float_geom(win, r);
ewmh_update_win_state(win, ewmh[_NET_WM_STATE_ABOVE].atom,
_NET_WM_STATE_ADD);
focus_flush();
- move_step = 0;
+ move_stp = 0;
switch (args->id) {
case SWM_ARG_ID_MOVELEFT:
X(win) -= (SWM_MOVE_STEPS - border_width);
- move_step = 1;
+ move_stp = 1;
break;
- case SWM_ARG_ID_MOVERIGHT:
- X(win) += (SWM_MOVE_STEPS - border_width);
- move_step = 1;
- break;
- case SWM_ARG_ID_MOVEUP:
- Y(win) -= (SWM_MOVE_STEPS - border_width);
- move_step = 1;
- break;
- case SWM_ARG_ID_MOVEDOWN:
- Y(win) += (SWM_MOVE_STEPS - border_width);
- move_step = 1;
- break;
- default:
- break;
- }
- if (move_step) {
- constrain_window(win, r, 0);
- update_window(win);
- store_float_geom(win, r);
- return;
- }
-
- cursor_font = xcb_generate_id(conn);
- xcb_open_font(conn, cursor_font, strlen("cursor"), "cursor");
-
- cursor = xcb_generate_id(conn);
- xcb_create_glyph_cursor(conn, cursor, cursor_font, cursor_font,
- XC_fleur, XC_fleur + 1, 0, 0, 0, 0xffff, 0xffff, 0xffff);
-
- xcb_grab_pointer(conn, 0, win->id, MOUSEMASK,
- XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC,
- XCB_WINDOW_NONE, cursor, XCB_CURRENT_TIME);
-
- /* get cursor offset from window root */
- qpr = xcb_query_pointer_reply(conn, xcb_query_pointer(conn, win->id),
- NULL);
- if (!qpr) {
- xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
- xcb_free_cursor(conn, cursor);
- xcb_close_font(conn, cursor_font);
- return;
- }
-
- xcb_flush(conn);
- moving = 1;
- while ((evt = xcb_wait_for_event(conn)) && moving) {
- switch (XCB_EVENT_RESPONSE_TYPE(evt)) {
- case XCB_BUTTON_RELEASE:
- DNPRINTF(SWM_D_EVENT, "move: BUTTON_RELEASE\n");
- moving = 0;
- break;
- case XCB_MOTION_NOTIFY:
- mne = (xcb_motion_notify_event_t *)evt;
- X(win) = mne->root_x - qpr->win_x - border_width;
- Y(win) = mne->root_y - qpr->win_y - border_width;
-
- constrain_window(win, r, 0);
-
- /* not free, don't sync more than 120 times / second */
- if ((mne->time - timestamp) > (1000 / 120) ) {
- timestamp = mne->time;
- update_window(win);
- xcb_flush(conn);
- }
- break;
- default:
- event_handle(evt);
- break;
- }
- free(evt);
- }
- if (timestamp) {
- update_window(win);
- xcb_flush(conn);
- }
- store_float_geom(win, r);
- free(qpr);
- xcb_free_cursor(conn, cursor);
- xcb_close_font(conn, cursor_font);
- xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
- DNPRINTF(SWM_D_EVENT, "move: done\n");
-}
-
-void
-move_step(struct swm_region *r, union arg *args)
-{
- struct ws_win *win = NULL;
-
- if (r && r->ws && r->ws->focus)
- win = r->ws->focus;
- else
- return;
-
- if (!(win->transient != 0 || win->floating != 0))
- return;
-
- move(win, args);
-}
-
-
-/* user/key callable function IDs */
-enum keyfuncid {
- KF_BAR_TOGGLE,
- KF_BUTTON2,
- KF_CYCLE_LAYOUT,
- KF_FLIP_LAYOUT,
- KF_FLOAT_TOGGLE,
- KF_FOCUS_MAIN,
- KF_FOCUS_NEXT,
- KF_FOCUS_PREV,
- KF_HEIGHT_GROW,
- KF_HEIGHT_SHRINK,
- KF_ICONIFY,
- KF_MASTER_SHRINK,
- KF_MASTER_GROW,
- KF_MASTER_ADD,
- KF_MASTER_DEL,
- KF_MOVE_DOWN,
- KF_MOVE_LEFT,
- KF_MOVE_RIGHT,
- KF_MOVE_UP,
- KF_MVWS_1,
- KF_MVWS_2,
- KF_MVWS_3,
- KF_MVWS_4,
- KF_MVWS_5,
- KF_MVWS_6,
- KF_MVWS_7,
- KF_MVWS_8,
- KF_MVWS_9,
- KF_MVWS_10,
- KF_MVWS_11,
- KF_MVWS_12,
- KF_MVWS_13,
- KF_MVWS_14,
- KF_MVWS_15,
- KF_MVWS_16,
- KF_MVWS_17,
- KF_MVWS_18,
- KF_MVWS_19,
- KF_MVWS_20,
- KF_MVWS_21,
- KF_MVWS_22,
- KF_NAME_WORKSPACE,
- KF_QUIT,
- KF_RAISE_TOGGLE,
- KF_RESTART,
- KF_SCREEN_NEXT,
- KF_SCREEN_PREV,
- KF_SEARCH_WIN,
- KF_SEARCH_WORKSPACE,
- KF_SPAWN_CUSTOM,
- KF_STACK_INC,
- KF_STACK_DEC,
- KF_STACK_RESET,
- KF_SWAP_MAIN,
- KF_SWAP_NEXT,
- KF_SWAP_PREV,
- KF_UNICONIFY,
- KF_VERSION,
- KF_WIDTH_GROW,
- KF_WIDTH_SHRINK,
- KF_WIND_DEL,
- KF_WIND_KILL,
- KF_WS_1,
- KF_WS_2,
- KF_WS_3,
- KF_WS_4,
- KF_WS_5,
- KF_WS_6,
- KF_WS_7,
- KF_WS_8,
- KF_WS_9,
- KF_WS_10,
- KF_WS_11,
- KF_WS_12,
- KF_WS_13,
- KF_WS_14,
- KF_WS_15,
- KF_WS_16,
- KF_WS_17,
- KF_WS_18,
- KF_WS_19,
- KF_WS_20,
- KF_WS_21,
- KF_WS_22,
- KF_WS_NEXT,
- KF_WS_NEXT_ALL,
- KF_WS_PREV,
- KF_WS_PREV_ALL,
- KF_WS_PRIOR,
- KF_DUMPWINS, /* MUST BE LAST */
- KF_INVALID
-};
+ case SWM_ARG_ID_MOVERIGHT:
+ X(win) += (SWM_MOVE_STEPS - border_width);
+ move_stp = 1;
+ break;
+ case SWM_ARG_ID_MOVEUP:
+ Y(win) -= (SWM_MOVE_STEPS - border_width);
+ move_stp = 1;
+ break;
+ case SWM_ARG_ID_MOVEDOWN:
+ Y(win) += (SWM_MOVE_STEPS - border_width);
+ move_stp = 1;
+ break;
+ default:
+ break;
+ }
+ if (move_stp) {
+ constrain_window(win, r, 0);
+ update_window(win);
+ store_float_geom(win, r);
+ return;
+ }
+
+ xcb_grab_pointer(conn, 0, win->id, MOUSEMASK,
+ XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC,
+ XCB_WINDOW_NONE, cursors[XC_FLEUR].cid, XCB_CURRENT_TIME);
+
+ /* get cursor offset from window root */
+ qpr = xcb_query_pointer_reply(conn, xcb_query_pointer(conn, win->id),
+ NULL);
+ if (!qpr) {
+ xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
+ return;
+ }
+
+ xcb_flush(conn);
+ moving = 1;
+ while ((evt = xcb_wait_for_event(conn)) && moving) {
+ switch (XCB_EVENT_RESPONSE_TYPE(evt)) {
+ case XCB_BUTTON_RELEASE:
+ DNPRINTF(SWM_D_EVENT, "move: BUTTON_RELEASE\n");
+ moving = 0;
+ break;
+ case XCB_MOTION_NOTIFY:
+ mne = (xcb_motion_notify_event_t *)evt;
+ X(win) = mne->root_x - qpr->win_x - border_width;
+ Y(win) = mne->root_y - qpr->win_y - border_width;
+
+ constrain_window(win, r, 0);
+
+ /* not free, don't sync more than 120 times / second */
+ if ((mne->time - timestamp) > (1000 / 120) ) {
+ timestamp = mne->time;
+ update_window(win);
+ xcb_flush(conn);
+ }
+ break;
+ default:
+ event_handle(evt);
+ break;
+ }
+ free(evt);
+ }
+ if (timestamp) {
+ update_window(win);
+ xcb_flush(conn);
+ }
+ store_float_geom(win, r);
+ free(qpr);
+ xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
+ DNPRINTF(SWM_D_EVENT, "move: done.\n");
+}
+
+void
+move_step(struct swm_region *r, union arg *args)
+{
+ struct ws_win *win = NULL;
+
+ if (r && r->ws && r->ws->focus)
+ win = r->ws->focus;
+ else
+ return;
+
+ if (!win->transient && !win->floating)
+ return;
+
+ move(win, args);
+ focus_flush();
+}
/* key definitions */
struct keyfunc {
{ "dumpwins", dumpwins, {0} }, /* MUST BE LAST */
{ "invalid key func", NULL, {0} },
};
-struct key {
- RB_ENTRY(key) entry;
- unsigned int mod;
- KeySym keysym;
- enum keyfuncid funcid;
- char *spawn_name;
-};
-RB_HEAD(key_tree, key);
int
key_cmp(struct key *kp1, struct key *kp2)
return (0);
}
-RB_GENERATE(key_tree, key, entry, key_cmp);
-struct key_tree keys;
-
/* mouse */
enum { client_click, root_click };
struct button {
} buttons[] = {
#define MODKEY_SHIFT MODKEY | XCB_MOD_MASK_SHIFT
/* action key mouse button func args */
- { client_click, MODKEY, Button3, resize, {.id = SWM_ARG_ID_DONTCENTER} },
- { client_click, MODKEY_SHIFT, Button3, resize, {.id = SWM_ARG_ID_CENTER} },
- { client_click, MODKEY, Button1, move, {0} },
+ { client_click, MODKEY, XCB_BUTTON_INDEX_3, resize, {.id = SWM_ARG_ID_DONTCENTER} },
+ { client_click, MODKEY_SHIFT, XCB_BUTTON_INDEX_3, resize, {.id = SWM_ARG_ID_CENTER} },
+ { client_click, MODKEY, XCB_BUTTON_INDEX_1, move, {0} },
#undef MODKEY_SHIFT
};
buttons[i].mask = mod;
}
-/* spawn */
-struct spawn_prog {
- TAILQ_ENTRY(spawn_prog) entry;
- char *name;
- int argc;
- char **argv;
-};
-TAILQ_HEAD(spawn_list, spawn_prog);
-struct spawn_list spawns = TAILQ_HEAD_INITIALIZER(spawns);
-
int
-spawn_expand(struct swm_region *r, union arg *args, char *spawn_name,
+spawn_expand(struct swm_region *r, union arg *args, const char *spawn_name,
char ***ret_args)
{
struct spawn_prog *prog = NULL;
}
void
-spawn_custom(struct swm_region *r, union arg *args, char *spawn_name)
+spawn_custom(struct swm_region *r, union arg *args, const char *spawn_name)
{
union arg a;
char **real_args;
}
void
-spawn_select(struct swm_region *r, union arg *args, char *spawn_name, int *pid)
+spawn_select(struct swm_region *r, union arg *args, const char *spawn_name,
+ int *pid)
{
union arg a;
char **real_args;
}
void
-spawn_insert(char *name, char *args)
+spawn_insert(const char *name, const char *args)
{
char *arg, *cp, *ptr;
struct spawn_prog *sp;
}
void
-spawn_replace(struct spawn_prog *sp, char *name, char *args)
+spawn_replace(struct spawn_prog *sp, const char *name, const char *args)
{
DNPRINTF(SWM_D_SPAWN, "spawn_replace: %s [%s]\n", sp->name, name);
}
void
-setspawn(char *name, char *args)
+setspawn(const char *name, const char *args)
{
struct spawn_prog *sp;
setspawn(selector, args);
free(args);
- DNPRINTF(SWM_D_SPAWN, "setconfspawn: done\n");
+ DNPRINTF(SWM_D_SPAWN, "setconfspawn: done.\n");
return (0);
}
}
char *
-strdupsafe(char *str)
+strdupsafe(const char *str)
{
if (str == NULL)
return (NULL);
}
void
-key_insert(unsigned int mod, KeySym ks, enum keyfuncid kfid, char *spawn_name)
+key_insert(unsigned int mod, KeySym ks, enum keyfuncid kfid,
+ const char *spawn_name)
{
struct key *kp;
void
key_replace(struct key *kp, unsigned int mod, KeySym ks, enum keyfuncid kfid,
- char *spawn_name)
+ const char *spawn_name)
{
DNPRINTF(SWM_D_KEY, "key_replace: %s [%s]\n", keyfuncs[kp->funcid].name,
spawn_name);
void
setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid,
- char *spawn_name)
+ const char *spawn_name)
{
struct key *kp;
return;
}
if (kfid == KF_INVALID) {
- warnx("error: setkeybinding: cannot find mod/key combination");
+ warnx("bind: Key combination already unbound.");
DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n");
return;
}
{
struct key *kp;
int num_screens, k, j;
- unsigned int modifiers[3];
+ unsigned int modifiers[4];
xcb_keycode_t *code;
DNPRINTF(SWM_D_MISC, "grabkeys\n");
modifiers[0] = 0;
modifiers[1] = numlockmask;
- modifiers[2] = numlockmask | XCB_MOD_MASK_LOCK;
+ modifiers[2] = XCB_MOD_MASK_LOCK;
+ modifiers[3] = numlockmask | XCB_MOD_MASK_LOCK;
num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
for (k = 0; k < num_screens; k++) {
XCB_MOD_MASK_ANY);
RB_FOREACH(kp, key_tree, &keys) {
if ((code = xcb_key_symbols_get_keycode(syms,
- kp->keysym)))
+ kp->keysym))) {
for (j = 0; j < LENGTH(modifiers); j++)
xcb_grab_key(conn, 1,
screens[k].root,
kp->mod | modifiers[j],
- *code, XCB_GRAB_MODE_ASYNC,
+ *code, XCB_GRAB_MODE_SYNC,
XCB_GRAB_MODE_ASYNC);
free(code);
+ }
}
}
}
void
-grabbuttons(struct ws_win *win, int focused)
+grabbuttons(struct ws_win *win)
{
- int i;
+ unsigned int modifiers[4];
+ int i, j;
- xcb_ungrab_button(conn, XCB_BUTTON_INDEX_ANY, win->id,
- XCB_BUTTON_MASK_ANY);
- if (focused) {
- for (i = 0; i < LENGTH(buttons); i++)
- if (buttons[i].action == client_click)
- xcb_grab_button(conn, 0, win->id,
- BUTTONMASK,
- XCB_GRAB_MODE_ASYNC,
- XCB_GRAB_MODE_SYNC,
- XCB_WINDOW_NONE,
- XCB_CURSOR_NONE,
- buttons[i].button,
- buttons[i].mask);
- } else
- xcb_grab_button(conn, 0, win->id, BUTTONMASK,
- XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_SYNC, XCB_WINDOW_NONE,
- XCB_CURSOR_NONE, XCB_BUTTON_INDEX_ANY, XCB_BUTTON_MASK_ANY);
+ DNPRINTF(SWM_D_MOUSE, "grabbuttons: win 0x%x\n", win->id);
+ updatenumlockmask();
+
+ modifiers[0] = 0;
+ modifiers[1] = numlockmask;
+ modifiers[2] = XCB_MOD_MASK_LOCK;
+ modifiers[3] = numlockmask | XCB_MOD_MASK_LOCK;
+
+ for (i = 0; i < LENGTH(buttons); i++)
+ if (buttons[i].action == client_click)
+ for (j = 0; j < LENGTH(modifiers); ++j)
+ xcb_grab_button(conn, 0, win->id, BUTTONMASK,
+ XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC,
+ XCB_WINDOW_NONE, XCB_CURSOR_NONE,
+ buttons[i].button, buttons[i].mask |
+ modifiers[j]);
}
const char *quirkname[] = {
DNPRINTF(SWM_D_QUIRK, "setquirk: enter %s:%s [%lu]\n", class, name,
quirk);
+ /* Remove/replace existing quirk. */
TAILQ_FOREACH(qp, &quirks, entry) {
if (!strcmp(qp->class, class) && !strcmp(qp->name, name)) {
if (!quirk)
return;
}
}
- if (!quirk) {
- warnx("error: setquirk: cannot find class/name combination");
- return;
- }
- quirk_insert(class, name, quirk);
+ /* Only insert if quirk is not NONE. */
+ if (quirk)
+ quirk_insert(class, name, quirk);
+
DNPRINTF(SWM_D_QUIRK, "setquirk: leave\n");
}
case SWM_S_FOCUS_MODE:
if (!strcmp(value, "default"))
focus_mode = SWM_FOCUS_DEFAULT;
- else if (!strcmp(value, "follow_cursor"))
+ else if (!strcmp(value, "follow") ||
+ !strcmp(value, "follow_cursor"))
focus_mode = SWM_FOCUS_FOLLOW;
else if (!strcmp(value, "manual"))
focus_mode = SWM_FOCUS_MANUAL;
{
int ws_id;
char s[1024];
- char *ap, *sp = s;
+ char *ap, *sp;
union arg a;
int argc = 0;
pid_t pid;
if (ws_id < 0 || ws_id >= workspace_limit)
errx(1, "autorun: invalid workspace %d", ws_id + 1);
+ sp = expand_tilde((char *)&s);
+
/*
* This is a little intricate
*
err(1, "setautorun: realloc");
a.argv[argc - 1] = ap;
}
+ free(sp);
if ((a.argv = realloc(a.argv, (argc + 1) * sizeof(char *))) == NULL)
err(1, "setautorun: realloc");
{ "layout", setlayout, 0 },
};
-
int
-conf_load(char *filename, int keymapping)
+conf_load(const char *filename, int keymapping)
{
FILE *config;
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;
DNPRINTF(SWM_D_MISC, "set_child_transient: parent doesn't exist"
" for 0x%x trans 0x%x\n", win->id, win->transient);
- r = root_to_region(win->wa->root);
+ r = root_to_region(win->wa->root, SWM_CK_ALL);
ws = r->ws;
/* parent doen't exist in our window list */
TAILQ_FOREACH(w, &ws->winlist, entry) {
}
struct ws_win *
-manage_window(xcb_window_t id)
+manage_window(xcb_window_t id, uint16_t mapped)
{
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) {
NULL);
/* Figure out which region the window belongs to. */
- r = root_to_region(win->wa->root);
+ r = root_to_region(win->wa->root, SWM_CK_ALL);
/* 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;
win->s = r->s; /* this never changes */
xcb_icccm_get_wm_protocols_reply_wipe(&wpr);
}
- win->iconic = get_iconic(win);
+ win->iconic = get_swm_iconic(win);
/* Figure out which workspace the window belongs to. */
if ((p = find_pid(window_get_pid(win->id))) != NULL) {
free(p);
p = NULL;
} else if ((ws_idx = get_ws_idx(win->id)) != -1 &&
- win->transient == 0) {
+ !win->transient) {
/* _SWM_WS is set; use that. */
win->ws = &r->s->ws[ws_idx];
} 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. */
/* Set initial _NET_WM_ALLOWED_ACTIONS */
ewmh_update_actions(win);
+ grabbuttons(win);
+
DNPRINTF(SWM_D_MISC, "manage_window: done. window: 0x%x, (x,y) w x h: "
"(%d,%d) %d x %d, ws: %d, iconic: %s, transient: 0x%x\n", win->id,
X(win), Y(win), WIDTH(win), HEIGHT(win), win->ws->idx,
memset(win, 0xff, sizeof *win); /* XXX kill later */
free(win);
- DNPRINTF(SWM_D_MISC, "free_window: done\n");
+ DNPRINTF(SWM_D_MISC, "free_window: done.\n");
}
void
unmanage_window(struct ws_win *win)
{
struct ws_win *parent;
- xcb_screen_t *screen;
if (win == NULL)
return;
parent->focus_child = NULL;
}
- /* focus on root just in case */
- screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
- xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT,
- screen->root, XCB_CURRENT_TIME);
-
- focus_prev(win);
-
TAILQ_REMOVE(&win->ws->winlist, win, entry);
TAILQ_INSERT_TAIL(&win->ws->unmanagedlist, win, entry);
}
"detail: %s(%u)\n", e->event, get_notify_mode_label(e->mode),
e->mode, get_notify_detail_label(e->detail), e->detail);
}
+
+void
+focusout(xcb_focus_out_event_t *e)
+{
+ DNPRINTF(SWM_D_EVENT, "focusout: window: 0x%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);
+}
#endif
void
if ((kp = key_lookup(CLEANMASK(e->state), keysym)) == NULL)
return;
+ last_event_time = e->time;
+
if (kp->funcid == KF_SPAWN_CUSTOM)
- spawn_custom(root_to_region(e->root),
+ spawn_custom(root_to_region(e->root, SWM_CK_ALL),
&(keyfuncs[kp->funcid].args), kp->spawn_name);
else if (keyfuncs[kp->funcid].func)
- keyfuncs[kp->funcid].func(root_to_region(e->root),
+ keyfuncs[kp->funcid].func(root_to_region(e->root, SWM_CK_ALL),
&(keyfuncs[kp->funcid].args));
}
void
buttonpress(xcb_button_press_event_t *e)
{
- struct ws_win *win;
+ struct ws_win *win = NULL;
+ struct swm_region *r, *old_r;
int i;
- unsigned int action;
+ int handled = 0;
+
+ DNPRINTF(SWM_D_EVENT, "buttonpress: win (x,y): 0x%x (%d,%d), "
+ "detail: %u, time: %u, root (x,y): 0x%x (%d,%d), child: 0x%x, "
+ "state: %u, same_screen: %s\n", 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));
+
+ if (e->event == e->root) {
+ if (e->child != 0) {
+ win = find_window(e->child);
+ /* Pass ButtonPress to window if it isn't managed. */
+ if (win == NULL)
+ goto out;
+ } else {
+ /* Focus on empty region */
+ /* If no windows on region if its empty. */
+ r = root_to_region(e->root, SWM_CK_POINTER);
+ if (r == NULL) {
+ DNPRINTF(SWM_D_EVENT, "buttonpress: "
+ "NULL region; ignoring.\n");
+ goto out;
+ }
+
+ if (TAILQ_EMPTY(&r->ws->winlist)) {
+ old_r = root_to_region(e->root, SWM_CK_FOCUS);
+ if (old_r && old_r != r)
+ unfocus_win(old_r->ws->focus);
+
+ xcb_set_input_focus(conn,
+ XCB_INPUT_FOCUS_PARENT, e->root, e->time);
+
+ /* Clear bar since empty. */
+ bar_update();
- DNPRINTF(SWM_D_EVENT, "buttonpress: window 0x%x, detail: %u\n",
- e->event, e->detail);
+ handled = 1;
+ goto out;
+ }
+ }
+ } else {
+ win = find_window(e->event);
+ }
- if ((win = find_window(e->event)) == NULL)
+ if (win == NULL)
return;
- focus_win(focus_magic(win));
- action = client_click;
+ last_event_time = e->time;
+
+ focus_win(get_focus_magic(win));
for (i = 0; i < LENGTH(buttons); i++)
- if (action == buttons[i].action && buttons[i].func &&
+ if (client_click == buttons[i].action && buttons[i].func &&
buttons[i].button == e->detail &&
- CLEANMASK(buttons[i].mask) == CLEANMASK(e->state))
+ CLEANMASK(buttons[i].mask) == CLEANMASK(e->state)) {
buttons[i].func(win, &buttons[i].args);
+ handled = 1;
+ }
+
+out:
+ if (!handled) {
+ DNPRINTF(SWM_D_EVENT, "buttonpress: passing to window.\n");
+ /* Replay event to event window */
+ xcb_allow_events(conn, XCB_ALLOW_REPLAY_POINTER, e->time);
+ } else {
+ DNPRINTF(SWM_D_EVENT, "buttonpress: handled.\n");
+ /* Unfreeze grab events. */
+ xcb_allow_events(conn, XCB_ALLOW_SYNC_POINTER, e->time);
+ }
xcb_flush(conn);
}
wc[i++] = e->stack_mode;
}
- if (mask != 0)
+ if (mask != 0) {
xcb_configure_window(conn, e->window, mask, wc);
+ xcb_flush(conn);
+ }
} else if ((!win->manual || win->quirks & SWM_Q_ANYWHERE) &&
!(win->ewmh_flags & EWMH_F_FULLSCREEN)) {
if (win->ws->r)
win->g_floatvalid = 1;
- if (win->floating && r) {
+ if (win->floating && r && (win->transient ||
+ win->ws->cur_layout != &layouts[SWM_MAX_STACK])) {
WIDTH(win) = win->g_float.w;
HEIGHT(win) = win->g_float.h;
- stack_floater(win, win->ws->r);
-
- focus_flush();
+ if (r) {
+ stack_floater(win, r);
+ focus_flush();
+ }
} else {
config_win(win, e);
xcb_flush(conn);
config_win(win, e);
xcb_flush(conn);
}
+
+ DNPRINTF(SWM_D_EVENT, "configurerequest: done.\n");
}
void
{
struct ws_win *win;
- DNPRINTF(SWM_D_EVENT, "configurenotify: window: 0x%x\n",
- e->window);
+ DNPRINTF(SWM_D_EVENT, "configurenotify: win 0x%x, event win: 0x%x, "
+ "(x,y) WxH: (%d,%d) %ux%u, border: %u, above_sibling: 0x%x, "
+ "override_redirect: %s\n", e->window, e->event, e->x, e->y,
+ e->width, e->height, e->border_width, e->above_sibling,
+ YESNO(e->override_redirect));
win = find_window(e->window);
if (win) {
return;
}
- /* make sure we focus on something */
- win->floating = 0;
+ if (focus_mode != SWM_FOCUS_FOLLOW) {
+ /* 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 (focus_mode != SWM_FOCUS_FOLLOW) {
+ if (win->ws->focus_pending) {
+ focus_win(win->ws->focus_pending);
+ win->ws->focus_pending = NULL;
+ }
+ }
+
+ free_window(win);
+
focus_flush();
}
enternotify(xcb_enter_notify_event_t *e)
{
struct ws_win *win;
+ struct swm_region *old_r, *r;
- DNPRINTF(SWM_D_FOCUS, "enternotify: window: 0x%x, mode: %s(%d), "
- "detail: %s(%d), root: 0x%x, subwindow: 0x%x, same_screen_focus: "
- "%s, state: %d\n", e->event, get_notify_mode_label(e->mode),
- e->mode, get_notify_detail_label(e->detail), e->detail, e->root,
- e->child, YESNO(e->same_screen_focus), e->state);
+ DNPRINTF(SWM_D_FOCUS, "enternotify: time: %u, win (x,y): 0x%x "
+ "(%d,%d), mode: %s(%d), detail: %s(%d), root (x,y): 0x%x (%d,%d), "
+ "child: 0x%x, same_screen_focus: %s, state: %d\n",
+ e->time, e->event, e->event_x, e->event_y,
+ get_notify_mode_label(e->mode), e->mode,
+ get_notify_detail_label(e->detail), e->detail,
+ e->root, e->root_x, e->root_y, e->child,
+ YESNO(e->same_screen_focus), e->state);
if (focus_mode == SWM_FOCUS_MANUAL &&
e->mode == XCB_NOTIFY_MODE_NORMAL) {
return;
}
+ last_event_time = e->time;
+
if ((win = find_window(e->event)) == NULL) {
- DNPRINTF(SWM_D_EVENT, "enternotify: window is NULL; ignoring\n");
+ if (e->event == e->root) {
+ /* If no windows on pointer region, then focus root. */
+ r = root_to_region(e->root, SWM_CK_POINTER);
+ if (r == NULL) {
+ DNPRINTF(SWM_D_EVENT, "enterntoify: "
+ "NULL region; ignoring.\n");
+ return;
+ }
+
+ if (TAILQ_EMPTY(&r->ws->winlist)) {
+ old_r = root_to_region(e->root, SWM_CK_FOCUS);
+ if (old_r && old_r != r)
+ unfocus_win(old_r->ws->focus);
+
+ xcb_set_input_focus(conn,
+ XCB_INPUT_FOCUS_PARENT, e->root, e->time);
+
+ /* Clear bar since empty. */
+ bar_update();
+
+ focus_flush();
+ }
+ } else {
+ DNPRINTF(SWM_D_EVENT, "enternotify: window is NULL; "
+ "ignoring\n");
+ }
return;
}
- focus_win(focus_magic(win));
+ focus_win(get_focus_magic(win));
xcb_flush(conn);
}
void
leavenotify(xcb_leave_notify_event_t *e)
{
- DNPRINTF(SWM_D_FOCUS, "leavenotify: window: 0x%x, mode: %s(%d), "
- "detail: %s(%d), root: 0x%x, subwindow: 0x%x, same_screen_focus: "
- "%s, state: %d\n", e->event, get_notify_mode_label(e->mode),
- e->mode, get_notify_detail_label(e->detail), e->detail, e->root,
- e->child, YESNO(e->same_screen_focus), e->state);
+ DNPRINTF(SWM_D_FOCUS, "leavenotify: time: %u, win (x,y): 0x%x "
+ "(%d,%d), mode: %s(%d), detail: %s(%d), root (x,y): 0x%x (%d,%d), "
+ "child: 0x%x, same_screen_focus: %s, state: %d\n",
+ e->time, e->event, e->event_x, e->event_y,
+ get_notify_mode_label(e->mode), e->mode,
+ get_notify_detail_label(e->detail), e->detail,
+ e->root, e->root_x, e->root_y, e->child,
+ YESNO(e->same_screen_focus), e->state);
}
#endif
-/* lets us use one switch statement for arbitrary mode/detail combinations */
-#define MERGE_MEMBERS(a,b) (((a & 0xffff) << 16) | (b & 0xffff))
-
void
mapnotify(xcb_map_notify_event_t *e)
{
DNPRINTF(SWM_D_EVENT, "mapnotify: window: 0x%x\n", e->window);
if ((win = find_window(e->window)) == NULL)
- win = manage_window(e->window);
+ win = manage_window(e->window, 1);
+ win->mapped = 1;
set_win_state(win, XCB_ICCCM_WM_STATE_NORMAL);
- /* Focus on window if it is selected. */
- if (win->ws->focus == win)
- focus_win(win);
+ if (focus_mode != SWM_FOCUS_FOLLOW) {
+ if (win->ws->focus_pending == win) {
+ focus_win(win);
+ win->ws->focus_pending = NULL;
+ focus_flush();
+ }
+ }
+
+ xcb_flush(conn);
}
void
goto out;
}
- win = manage_window(e->window);
+ win = manage_window(e->window,
+ (war->map_state == XCB_MAP_STATE_VIEWABLE));
+
+ /* The new window should get focus; prepare. */
+ if (focus_mode != SWM_FOCUS_FOLLOW)
+ win->ws->focus_pending = get_focus_magic(win);
/* All windows need to be mapped if they are in the current workspace.*/
if (win->ws->r)
stack();
- /* The new window should get focus. */
- win->ws->focus = focus_magic(win);
-
/* Ignore EnterNotify to handle the mapnotify without interference. */
if (focus_mode == SWM_FOCUS_DEFAULT)
event_drain(XCB_ENTER_NOTIFY);
char *name;
name = get_atom_name(e->atom);
- DNPRINTF(SWM_D_EVENT, "propertynotify: window: 0x%x, atom: %s(%u)\n",
- e->window, name, e->atom);
+ DNPRINTF(SWM_D_EVENT, "propertynotify: window: 0x%x, atom: %s(%u), "
+ "time: %#x, state: %u\n", e->window, name, e->atom, e->time,
+ e->state);
free(name);
#endif
- xcb_flush(conn);
-
win = find_window(e->window);
if (win == NULL)
return;
- if (e->state == XCB_PROPERTY_DELETE && e->atom == a_swm_iconic) {
- update_iconic(win, 0);
- map_window_raised(win->id);
- stack();
- focus_win(win);
- return;
- }
+ last_event_time = e->time;
+
+ if (e->atom == a_swm_iconic) {
+ if (e->state == XCB_PROPERTY_NEW_VALUE) {
+ if (focus_mode != SWM_FOCUS_FOLLOW)
+ win->ws->focus_pending = get_focus_prev(win);
+
+ unfocus_win(win);
+ unmap_window(win);
+
+ if (win->ws->r) {
+ stack();
+ if (focus_mode != SWM_FOCUS_FOLLOW) {
+ focus_win(win->ws->focus_pending);
+ win->ws->focus_pending = NULL;
+ }
+ focus_flush();
+ }
+ } else if (e->state == XCB_PROPERTY_DELETE) {
+ /* The window is no longer iconic, restack ws. */
+ if (focus_mode != SWM_FOCUS_FOLLOW)
+ win->ws->focus_pending = get_focus_magic(win);
+
+ stack();
- switch (e->atom) {
- case XCB_ATOM_WM_CLASS:
- case XCB_ATOM_WM_NAME:
+ /* Flush EnterNotify for mapnotify, if needed. */
+ focus_flush();
+ }
+ } else if (e->atom == a_state) {
+ /* State just changed, make sure it gets focused if mapped. */
+ if (e->state == XCB_PROPERTY_NEW_VALUE) {
+ if (focus_mode != SWM_FOCUS_FOLLOW) {
+ if (win->mapped &&
+ win->ws->focus_pending == win) {
+ focus_win(win->ws->focus_pending);
+ win->ws->focus_pending = NULL;
+ }
+ }
+ }
+ } else if (e->atom == XCB_ATOM_WM_CLASS ||
+ e->atom == XCB_ATOM_WM_NAME) {
bar_update();
- break;
- default:
- break;
}
+
+ xcb_flush(conn);
}
void
unmapnotify(xcb_unmap_notify_event_t *e)
{
struct ws_win *win;
+ struct workspace *ws;
DNPRINTF(SWM_D_EVENT, "unmapnotify: window: 0x%x\n", e->window);
- /* determine if we need to help unmanage this window */
+ /* If we aren't managing the window, then ignore. */
win = find_window(e->window);
if (win == NULL)
return;
- if (getstate(e->window) == XCB_ICCCM_WM_STATE_NORMAL) {
+ ws = win->ws;
+
+ if (getstate(e->window) != XCB_ICCCM_WM_STATE_ICONIC)
+ set_win_state(win, XCB_ICCCM_WM_STATE_ICONIC);
+
+ if (win->mapped) {
+ /* window unmapped itself */
+ /* do unmap/unfocus/restack and unmanage */
+ win->mapped = 0;
+
+ /* If win was focused, make sure to focus on something else. */
+ if (win == ws->focus) {
+ if (focus_mode != SWM_FOCUS_FOLLOW) {
+ ws->focus_pending = get_focus_prev(win);
+ DNPRINTF(SWM_D_EVENT, "unmapnotify: "
+ "focus_pending: 0x%x\n",
+ WINID(ws->focus_pending));
+ }
+
+ unfocus_win(win);
+ }
+
unmanage_window(win);
- stack();
- /* resend unmap because we ated it */
- xcb_unmap_window(conn, e->window);
- xcb_flush(conn);
+ if (ws->r)
+ stack();
+
+ if (focus_mode == SWM_FOCUS_FOLLOW) {
+ if (ws->r)
+ focus_win(get_pointer_win(ws->r->s->root));
+ } else {
+ if (ws->focus_pending) {
+ focus_win(ws->focus_pending);
+ ws->focus_pending = NULL;
+ }
+ }
}
+
+ if (getstate(e->window) == XCB_ICCCM_WM_STATE_NORMAL)
+ set_win_state(win, XCB_ICCCM_WM_STATE_ICONIC);
+
+ focus_flush();
}
#if 0
if (win == NULL) {
if (e->type == ewmh[_NET_ACTIVE_WINDOW].atom) {
+ /* Manage the window with maprequest. */
DNPRINTF(SWM_D_EVENT, "clientmessage: request focus on "
"unmanaged window.\n");
mre.window = e->window;
if (e->type == ewmh[_NET_CLOSE_WINDOW].atom) {
DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_CLOSE_WINDOW\n");
if (win->can_delete)
- client_msg(win, a_delete);
+ client_msg(win, a_delete, 0);
else
xcb_kill_client(conn, win->id);
}
stack();
}
- xcb_flush(conn);
+ focus_flush();
}
void
enable_wm(void)
{
int num_screens, i;
- const uint32_t val = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT;
+ const uint32_t val = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
+ XCB_EVENT_MASK_ENTER_WINDOW;
xcb_screen_t *sc;
xcb_void_cookie_t wac;
xcb_generic_error_t *error;
free(error);
return 1;
}
+
+ /* click to focus on empty region */
+ xcb_grab_button(conn, 1, sc->root, BUTTONMASK,
+ XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, XCB_WINDOW_NONE,
+ XCB_CURSOR_NONE, XCB_BUTTON_INDEX_1, XCB_BUTTON_MASK_ANY);
}
return 0;
xcb_randr_crtc_t *crtc;
xcb_screen_t *screen;
+ DNPRINTF(SWM_D_MISC, "scan_xrandr: screen: %d\n", i);
+
if ((screen = get_screen(i)) == NULL)
errx(1, "ERROR: can't get screen %d.", i);
new_region(&screens[i], 0, 0,
screen->width_in_pixels,
screen->height_in_pixels);
- return;
+ goto out;
} else
ncrtc = srr->num_crtcs;
free(cir);
}
free(srr);
- } else
+ }
#endif /* SWM_XRR_HAS_CRTC */
- {
+
+ /* If detection failed, create a single region that spans the screen. */
+ if (TAILQ_EMPTY(&screens[i].rl))
new_region(&screens[i], 0, 0, screen->width_in_pixels,
screen->height_in_pixels);
- }
+
+out:
+ DNPRINTF(SWM_D_MISC, "scan_xrandr: done.\n");
}
void
void
grab_windows(void)
{
- xcb_window_t *wins = NULL;
+ xcb_window_t *wins = NULL, trans;
int no;
int i, j, num_screens;
- uint16_t state, manage;
+ uint16_t state, manage, mapped;
xcb_query_tree_cookie_t qtc;
xcb_query_tree_reply_t *qtr;
no = xcb_query_tree_children_length(qtr);
/* attach windows to a region */
/* normal windows */
+ DNPRINTF(SWM_D_INIT, "grab_windows: grab top level windows.\n");
for (j = 0; j < no; j++) {
c = xcb_get_window_attributes(conn, wins[j]);
r = xcb_get_window_attributes_reply(conn, c, NULL);
- if (!r)
+ if (!r) {
+ DNPRINTF(SWM_D_INIT, "grab_windows: skip %#x; "
+ "doesn't exist.\n", wins[j]);
continue;
+ }
if (r->override_redirect) {
+ DNPRINTF(SWM_D_INIT, "grab_windows: skip %#x; "
+ "override_redirect set.\n", wins[j]);
free(r);
continue;
}
pc = xcb_icccm_get_wm_transient_for(conn, wins[j]);
if (xcb_icccm_get_wm_transient_for_reply(conn, pc,
- &wins[j], NULL)) {
+ &trans, NULL)) {
+ DNPRINTF(SWM_D_INIT, "grab_windows: skip %#x; "
+ "is transient for %#x.\n", wins[j], trans);
free(r);
continue;
}
state = getstate(wins[j]);
- manage = state == XCB_ICCCM_WM_STATE_ICONIC;
- if (r->map_state == XCB_MAP_STATE_VIEWABLE || manage)
- manage_window(wins[j]);
+ manage = state != XCB_ICCCM_WM_STATE_WITHDRAWN;
+ mapped = r->map_state != XCB_MAP_STATE_UNMAPPED;
+ if (mapped || manage)
+ manage_window(wins[j], mapped);
free(r);
}
/* transient windows */
+ DNPRINTF(SWM_D_INIT, "grab_windows: grab transient windows.\n");
for (j = 0; j < no; j++) {
c = xcb_get_window_attributes(conn, wins[j]);
r = xcb_get_window_attributes_reply(conn, c, NULL);
- if (!r)
+ if (!r) {
+ DNPRINTF(SWM_D_INIT, "grab_windows: skip %#x; "
+ "doesn't exist.\n", wins[j]);
continue;
+ }
if (r->override_redirect) {
+ DNPRINTF(SWM_D_INIT, "grab_windows: skip %#x; "
+ "override_redirect set.\n", wins[j]);
free(r);
continue;
}
- free(r);
state = getstate(wins[j]);
- manage = state == XCB_ICCCM_WM_STATE_ICONIC;
+ manage = state != XCB_ICCCM_WM_STATE_WITHDRAWN;
+ mapped = r->map_state != XCB_MAP_STATE_UNMAPPED;
pc = xcb_icccm_get_wm_transient_for(conn, wins[j]);
if (xcb_icccm_get_wm_transient_for_reply(conn, pc,
- &wins[j], NULL) && manage)
- manage_window(wins[j]);
+ &trans, NULL) && manage)
+ manage_window(wins[j], mapped);
+ free(r);
}
free(qtr);
}
- DNPRINTF(SWM_D_INIT, "grab_windows: done\n");
+ DNPRINTF(SWM_D_INIT, "grab_windows: done.\n");
}
void
uint32_t gcv[1], wa[1];
const xcb_query_extension_reply_t *qep;
xcb_screen_t *screen;
- xcb_cursor_t cursor;
- xcb_font_t cursor_font;
xcb_randr_query_version_cookie_t c;
xcb_randr_query_version_reply_t *r;
}
}
- cursor_font = xcb_generate_id(conn);
- xcb_open_font(conn, cursor_font, strlen("cursor"), "cursor");
-
- cursor = xcb_generate_id(conn);
- xcb_create_glyph_cursor(conn, cursor, cursor_font, cursor_font,
- XC_left_ptr, XC_left_ptr + 1, 0, 0, 0, 0xffff, 0xffff, 0xffff);
- wa[0] = cursor;
+ wa[0] = cursors[XC_LEFT_PTR].cid;
/* map physical screens */
for (i = 0; i < num_screens; i++) {
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);
xcb_randr_select_input(conn, screens[i].root,
XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE);
}
- xcb_free_cursor(conn, cursor);
- xcb_close_font(conn, cursor_font);
}
void
bar_extra = 1;
unmap_all();
+ cursors_cleanup();
+
teardown_ewmh();
num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
{
uint8_t type = XCB_EVENT_RESPONSE_TYPE(evt);
- DNPRINTF(SWM_D_EVENT, "XCB Event: %s(%d)\n",
+ DNPRINTF(SWM_D_EVENT, "XCB Event: %s(%d), seq %u\n",
xcb_event_get_label(XCB_EVENT_RESPONSE_TYPE(evt)),
- XCB_EVENT_RESPONSE_TYPE(evt));
+ XCB_EVENT_RESPONSE_TYPE(evt), evt->sequence);
switch (type) {
#define EVENT(type, callback) case type: callback((void *)evt); return
EVENT(XCB_EXPOSE, expose);
#ifdef SWM_DEBUG
EVENT(XCB_FOCUS_IN, focusin);
+ EVENT(XCB_FOCUS_OUT, focusout);
#endif
- /*EVENT(XCB_FOCUS_OUT, );*/
/*EVENT(XCB_GRAPHICS_EXPOSURE, );*/
/*EVENT(XCB_GRAVITY_NOTIFY, );*/
EVENT(XCB_KEY_PRESS, keypress);
{
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;
if (enable_wm() != 0)
errx(1, "another window manager is currently running");
+ /* Load Xcursors and/or cursorfont glyph cursors. */
+ cursors_load();
+
xcb_aux_sync(conn);
setup_globals();
bar_setup(r);
}
- //unfocus_all();
-
grabkeys();
stack();
while (running) {
while ((evt = xcb_poll_for_event(conn))) {
- if (running == 0)
+ if (!running)
goto done;
event_handle(evt);
free(evt);
}
- /* if we are being restarted go focus on first window */
- if (winfocus) {
+ /* If just (re)started, set default focus if needed. */
+ if (winfocus && focus_mode != SWM_FOCUS_FOLLOW) {
rr = winfocus->ws->r;
if (rr == NULL) {
/* not a visible window */
winfocus = NULL;
continue;
}
- /* move pointer to first screen if multi screen */
- if (num_screens > 1 || outputs > 1)
- xcb_warp_pointer(conn, XCB_WINDOW_NONE,
- 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(get_region_focus(rr));
+ focus_flush();
winfocus = NULL;
continue;
}
if (errno != EINTR) {
DNPRINTF(SWM_D_MISC, "select failed");
}
- if (restart_wm == 1)
+ if (restart_wm)
restart(NULL, NULL);
- if (search_resp == 1)
+ if (search_resp)
search_do_resp();
- if (running == 0)
+ if (!running)
goto done;
if (bar_alarm) {
bar_alarm = 0;