* 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>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/wait.h>
+#ifdef __OSX__
+#include "queue.h"
+#else
#include <sys/queue.h>
+#endif
#include <sys/param.h>
#include <sys/select.h>
#if defined(__linux__)
#define LENGTH(x) (int)(sizeof (x) / sizeof (x)[0])
#define MODKEY XCB_MOD_MASK_1
-#define CLEANMASK(mask) ((mask) & ~(numlockmask | XCB_MOD_MASK_LOCK))
+#define ANYMOD XCB_MOD_MASK_ANY
+#define CLEANMASK(mask) ((mask) & (XCB_KEY_BUT_MASK_SHIFT | \
+ XCB_KEY_BUT_MASK_CONTROL | XCB_KEY_BUT_MASK_MOD_1 | \
+ XCB_KEY_BUT_MASK_MOD_2 | XCB_KEY_BUT_MASK_MOD_3 | \
+ XCB_KEY_BUT_MASK_MOD_4 | XCB_KEY_BUT_MASK_MOD_5) & ~(numlockmask))
#define BUTTONMASK (XCB_EVENT_MASK_BUTTON_PRESS | \
XCB_EVENT_MASK_BUTTON_RELEASE)
#define MOUSEMASK (BUTTONMASK|XCB_EVENT_MASK_POINTER_MOTION)
#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)
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 cycle_visible = false;
int term_width = 0;
int font_adjusted = 0;
-unsigned int mod_key = MODKEY;
+uint16_t mod_key = MODKEY;
bool warp_focus = false;
bool warp_pointer = false;
bool workspace_clamp = false;
bool bar_extra = false;
int bar_height = 0;
int bar_justify = SWM_BAR_JUSTIFY_LEFT;
-char *bar_format = NULL;
+char *bar_format = NULL;
bool stack_enabled = true;
bool clock_enabled = true;
bool iconic_enabled = false;
bool java_workaround = true;
bool verbose_layout = false;
#ifdef SWM_DEBUG
+bool debug_enabled;
time_t time_started;
#endif
pid_t bar_pid;
-XFontSet bar_fs;
+XFontSet bar_fs = NULL;
XFontSetExtents *bar_fs_extents;
-XftFont *bar_font;
+XftFont *bar_font = NULL;
bool bar_font_legacy = true;
-char *bar_fonts;
+char *bar_fonts = NULL;
XftColor bar_font_color;
XftColor search_font_color;
-struct passwd *pwd;
-char *startup_exception;
+char *startup_exception = NULL;
unsigned int nr_exceptions = 0;
/* layout manager data */
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);
regex_t regex_name;
uint32_t quirk;
int ws; /* Initial workspace. */
-#define SWM_Q_FLOAT (1<<0) /* float this window */
-#define SWM_Q_TRANSSZ (1<<1) /* transiend window size too small */
-#define SWM_Q_ANYWHERE (1<<2) /* don't position this window */
-#define SWM_Q_XTERM_FONTADJ (1<<3) /* adjust xterm fonts when resizing */
-#define SWM_Q_FULLSCREEN (1<<4) /* remove border when fullscreen */
-#define SWM_Q_FOCUSPREV (1<<5) /* focus on caller */
+#define SWM_Q_FLOAT (1<<0) /* Float this window. */
+#define SWM_Q_TRANSSZ (1<<1) /* Transient window size too small. */
+#define SWM_Q_ANYWHERE (1<<2) /* Don't position this window */
+#define SWM_Q_XTERM_FONTADJ (1<<3) /* Adjust xterm fonts when resizing. */
+#define SWM_Q_FULLSCREEN (1<<4) /* Remove border when fullscreen. */
+#define SWM_Q_FOCUSPREV (1<<5) /* Focus on caller. */
#define SWM_Q_NOFOCUSONMAP (1<<6) /* Don't focus on window when mapped. */
#define SWM_Q_FOCUSONMAP_SINGLE (1<<7) /* Only focus if single win of type. */
#define SWM_Q_OBEYAPPFOCUSREQ (1<<8) /* Focus when applications ask. */
#define SWM_Q_IGNOREPID (1<<9) /* Ignore PID when determining ws. */
#define SWM_Q_IGNORESPAWNWS (1<<10) /* Ignore _SWM_WS when managing win. */
#define SWM_Q_NOFOCUSCYCLE (1<<11) /* Remove from normal focus cycle. */
-#define SWM_Q_MINIMALBORDER (1<<12) /* Remove border when floating/unfocused */
+#define SWM_Q_MINIMALBORDER (1<<12) /* No border when floating/unfocused. */
};
TAILQ_HEAD(quirk_list, quirk);
struct quirk_list quirks = TAILQ_HEAD_INITIALIZER(quirks);
_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},
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_BAR_TOGGLE_WS,
- KF_BUTTON2,
- KF_CYCLE_LAYOUT,
- KF_FLIP_LAYOUT,
- KF_FLOAT_TOGGLE,
- KF_FOCUS_MAIN,
- KF_FOCUS_NEXT,
- KF_FOCUS_PREV,
- KF_FOCUS_URGENT,
- KF_MAXIMIZE_TOGGLE,
- 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_MVRG_1,
- KF_MVRG_2,
- KF_MVRG_3,
- KF_MVRG_4,
- KF_MVRG_5,
- KF_MVRG_6,
- KF_MVRG_7,
- KF_MVRG_8,
- KF_MVRG_9,
- 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_RG_1,
- KF_RG_2,
- KF_RG_3,
- KF_RG_4,
- KF_RG_5,
- KF_RG_6,
- KF_RG_7,
- KF_RG_8,
- KF_RG_9,
- KF_RG_MOVE_NEXT,
- KF_RG_MOVE_PREV,
- KF_RG_NEXT,
- KF_RG_PREV,
- KF_SCREEN_NEXT,
- KF_SCREEN_PREV,
- KF_SEARCH_WIN,
- KF_SEARCH_WORKSPACE,
- KF_SPAWN_CUSTOM,
- KF_STACK_BALANCE,
- 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_NEXT_MOVE,
- KF_WS_PREV,
- KF_WS_PREV_ALL,
- KF_WS_PREV_MOVE,
- KF_WS_PRIOR,
- KF_DUMPWINS, /* MUST BE LAST */
- KF_INVALID
+enum {
+ FN_F_NOREPLAY = 0x1,
+};
+
+/* User callable function IDs. */
+enum actionid {
+ FN_BAR_TOGGLE,
+ FN_BAR_TOGGLE_WS,
+ FN_BUTTON2,
+ FN_CYCLE_LAYOUT,
+ FN_FLIP_LAYOUT,
+ FN_FLOAT_TOGGLE,
+ FN_FOCUS,
+ FN_FOCUS_MAIN,
+ FN_FOCUS_NEXT,
+ FN_FOCUS_PREV,
+ FN_FOCUS_URGENT,
+ FN_MAXIMIZE_TOGGLE,
+ FN_HEIGHT_GROW,
+ FN_HEIGHT_SHRINK,
+ FN_ICONIFY,
+ FN_MASTER_SHRINK,
+ FN_MASTER_GROW,
+ FN_MASTER_ADD,
+ FN_MASTER_DEL,
+ FN_MOVE,
+ FN_MOVE_DOWN,
+ FN_MOVE_LEFT,
+ FN_MOVE_RIGHT,
+ FN_MOVE_UP,
+ FN_MVRG_1,
+ FN_MVRG_2,
+ FN_MVRG_3,
+ FN_MVRG_4,
+ FN_MVRG_5,
+ FN_MVRG_6,
+ FN_MVRG_7,
+ FN_MVRG_8,
+ FN_MVRG_9,
+ FN_MVWS_1,
+ FN_MVWS_2,
+ FN_MVWS_3,
+ FN_MVWS_4,
+ FN_MVWS_5,
+ FN_MVWS_6,
+ FN_MVWS_7,
+ FN_MVWS_8,
+ FN_MVWS_9,
+ FN_MVWS_10,
+ FN_MVWS_11,
+ FN_MVWS_12,
+ FN_MVWS_13,
+ FN_MVWS_14,
+ FN_MVWS_15,
+ FN_MVWS_16,
+ FN_MVWS_17,
+ FN_MVWS_18,
+ FN_MVWS_19,
+ FN_MVWS_20,
+ FN_MVWS_21,
+ FN_MVWS_22,
+ FN_NAME_WORKSPACE,
+ FN_QUIT,
+ FN_RAISE_TOGGLE,
+ FN_RESIZE,
+ FN_RESIZE_CENTERED,
+ FN_RESTART,
+ FN_RG_1,
+ FN_RG_2,
+ FN_RG_3,
+ FN_RG_4,
+ FN_RG_5,
+ FN_RG_6,
+ FN_RG_7,
+ FN_RG_8,
+ FN_RG_9,
+ FN_RG_MOVE_NEXT,
+ FN_RG_MOVE_PREV,
+ FN_RG_NEXT,
+ FN_RG_PREV,
+ FN_SCREEN_NEXT,
+ FN_SCREEN_PREV,
+ FN_SEARCH_WIN,
+ FN_SEARCH_WORKSPACE,
+ FN_SPAWN_CUSTOM,
+ FN_STACK_BALANCE,
+ FN_STACK_INC,
+ FN_STACK_DEC,
+ FN_STACK_RESET,
+ FN_SWAP_MAIN,
+ FN_SWAP_NEXT,
+ FN_SWAP_PREV,
+ FN_UNICONIFY,
+ FN_VERSION,
+ FN_WIDTH_GROW,
+ FN_WIDTH_SHRINK,
+ FN_WIND_DEL,
+ FN_WIND_KILL,
+ FN_WS_1,
+ FN_WS_2,
+ FN_WS_3,
+ FN_WS_4,
+ FN_WS_5,
+ FN_WS_6,
+ FN_WS_7,
+ FN_WS_8,
+ FN_WS_9,
+ FN_WS_10,
+ FN_WS_11,
+ FN_WS_12,
+ FN_WS_13,
+ FN_WS_14,
+ FN_WS_15,
+ FN_WS_16,
+ FN_WS_17,
+ FN_WS_18,
+ FN_WS_19,
+ FN_WS_20,
+ FN_WS_21,
+ FN_WS_22,
+ FN_WS_NEXT,
+ FN_WS_NEXT_ALL,
+ FN_WS_NEXT_MOVE,
+ FN_WS_PREV,
+ FN_WS_PREV_ALL,
+ FN_WS_PREV_MOVE,
+ FN_WS_PRIOR,
+ /* SWM_DEBUG actions MUST be here: */
+ FN_DEBUG_TOGGLE,
+ FN_DUMPWINS,
+ /* ALWAYS last: */
+ FN_INVALID
+};
+
+enum binding_type {
+ KEYBIND,
+ BTNBIND
+};
+
+enum {
+ BINDING_F_REPLAY = 0x1,
};
-struct key {
- RB_ENTRY(key) entry;
- unsigned int mod;
- KeySym keysym;
- enum keyfuncid funcid;
- char *spawn_name;
+struct binding {
+ RB_ENTRY(binding) entry;
+ uint16_t mod; /* Modifier Mask. */
+ enum binding_type type; /* Key or Button. */
+ uint32_t value; /* KeySym or Button Index. */
+ enum actionid action; /* Action Identifier. */
+ uint32_t flags;
+ char *spawn_name;
};
-RB_HEAD(key_tree, key);
+RB_HEAD(binding_tree, binding);
/* function prototypes */
void adjust_font(struct ws_win *);
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 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_toggle(struct swm_region *, union arg *);
+void bar_toggle(struct binding *, struct swm_region *, union arg *);
void bar_urgent(char *, size_t);
void bar_window_class(char *, size_t, struct swm_region *);
void bar_window_class_instance(char *, size_t, struct swm_region *);
void bar_window_name(char *, size_t, struct swm_region *);
void bar_window_state(char *, size_t, struct swm_region *);
void bar_workspace_name(char *, size_t, struct swm_region *);
+int binding_cmp(struct binding *, struct binding *);
+void binding_insert(uint16_t, enum binding_type, uint32_t, enum actionid,
+ uint32_t, const char *);
+struct binding *binding_lookup(uint16_t, enum binding_type, uint32_t);
+void binding_remove(struct binding *);
void buttonpress(xcb_button_press_event_t *);
+void buttonrelease(xcb_button_release_event_t *);
void center_pointer(struct swm_region *);
void check_conn(void);
-void clear_keys(void);
+void clear_bindings(void);
+void clear_keybindings(void);
int clear_maximized(struct workspace *);
void clear_quirks(void);
void clear_spawns(void);
void cursors_cleanup(void);
void cursors_load(void);
void custom_region(const char *);
-void cyclerg(struct swm_region *, union arg *);
-void cyclews(struct swm_region *, union arg *);
-void cycle_layout(struct swm_region *, union arg *);
+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 swm_region *, union arg *);
+void dumpwins(struct binding *, struct swm_region *, union arg *);
int enable_wm(void);
void enternotify(xcb_enter_notify_event_t *);
void event_drain(uint8_t);
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 swm_region *, union arg *);
-void focus(struct swm_region *, union arg *);
-#ifdef SWM_DEBUG
-void focusin(xcb_focus_in_event_t *);
-void focusout(xcb_focus_out_event_t *);
-#endif
+void floating_toggle(struct binding *, struct swm_region *, union arg *);
+void focus(struct binding *, struct swm_region *, union arg *);
void focus_flush(void);
+void focus_pointer(struct binding *, struct swm_region *, union arg *);
void focus_region(struct swm_region *);
-void focusrg(struct swm_region *, union arg *);
void focus_win(struct ws_win *);
+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 *);
void fontset_init(void);
void free_window(struct ws_win *);
xcb_atom_t get_atom_from_string(const char *);
#endif
struct ws_win *get_focus_magic(struct ws_win *);
struct ws_win *get_focus_prev(struct ws_win *);
+xcb_generic_event_t *get_next_event(bool);
#ifdef SWM_DEBUG
char *get_notify_detail_label(uint8_t);
char *get_notify_mode_label(uint8_t);
#ifdef SWM_DEBUG
char *get_source_type_label(uint32_t);
char *get_stack_mode_name(uint8_t);
+char *get_state_mask_label(uint16_t);
#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 *);
int get_ws_idx(struct ws_win *);
-void grabbuttons(struct ws_win *);
-void grabkeys(void);
void grab_windows(void);
-void iconify(struct swm_region *, union arg *);
+void grabbuttons(void);
+void grabkeys(void);
+void iconify(struct binding *, struct swm_region *, union arg *);
bool isxlfd(char *);
+bool keybindreleased(struct binding *, xcb_key_release_event_t *);
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 keyrelease(xcb_key_release_event_t *);
+bool keyrepeating(xcb_key_release_event_t *);
void kill_bar_extra_atexit(void);
void kill_refs(struct ws_win *);
#ifdef SWM_DEBUG
void mapnotify(xcb_map_notify_event_t *);
void mappingnotify(xcb_mapping_notify_event_t *);
void maprequest(xcb_map_request_event_t *);
-void maximize_toggle(struct swm_region *, union arg *);
+void maximize_toggle(struct binding *, struct swm_region *, union arg *);
void motionnotify(xcb_motion_notify_event_t *);
-void move(struct ws_win *, union arg *);
-void move_step(struct swm_region *, union arg *);
+void move(struct binding *, struct swm_region *, union arg *);
+void move_win(struct ws_win *, struct binding *, int);
uint32_t name_to_pixel(int, const char *);
-void name_workspace(struct swm_region *, union arg *);
+void name_workspace(struct binding *, struct swm_region *, union arg *);
void new_region(struct swm_screen *, int, int, int, int);
-int parsekeys(const char *, unsigned int, unsigned int *, KeySym *);
-int parsequirks(const char *, uint32_t *, int *);
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 *);
+int parsebinding(const char *, uint16_t *, enum binding_type *, uint32_t *,
+ uint32_t *);
+int parsequirks(const char *, uint32_t *, int *);
+void pressbutton(struct binding *, struct swm_region *, union arg *);
+void priorws(struct binding *, struct swm_region *, union arg *);
#ifdef SWM_DEBUG
void print_win_geom(xcb_window_t);
#endif
void propertynotify(xcb_property_notify_event_t *);
+void put_back_event(xcb_generic_event_t *);
void quirk_free(struct quirk *);
void quirk_insert(const char *, const char *, const char *, uint32_t, int);
void quirk_remove(struct quirk *);
void quirk_replace(struct quirk *, const char *, const char *, const char *,
uint32_t, int);
-void quit(struct swm_region *, union arg *);
-void raise_toggle(struct swm_region *, union arg *);
+void quit(struct binding *, struct swm_region *, union arg *);
+void raise_toggle(struct binding *, struct swm_region *, union arg *);
void raise_window(struct ws_win *);
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 resize(struct ws_win *, union arg *);
-void resize_step(struct swm_region *, union arg *);
-void restart(struct swm_region *, union arg *);
+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 *);
struct swm_region *root_to_region(xcb_window_t, int);
void screenchange(xcb_randr_screen_change_notify_event_t *);
void scan_randr(int);
void search_resp_search_window(const char *);
void search_resp_search_workspace(const char *);
void search_resp_uniconify(const char *, size_t);
-void search_win(struct swm_region *, union arg *);
+void search_win(struct binding *, struct swm_region *, union arg *);
void search_win_cleanup(void);
-void search_workspace(struct swm_region *, union arg *);
-void send_to_rg(struct swm_region *, union arg *);
-void send_to_ws(struct swm_region *, union arg *);
+void search_workspace(struct binding *, struct swm_region *, union arg *);
+void send_to_rg(struct binding *, struct swm_region *, union arg *);
+void send_to_ws(struct binding *, struct swm_region *, union arg *);
void set_region(struct swm_region *);
int setautorun(const char *, const char *, int);
+void setbinding(uint16_t, enum binding_type, uint32_t, enum actionid,
+ uint32_t, const char *);
int setconfbinding(const char *, const char *, int);
int setconfcolor(const char *, const char *, int);
int setconfmodkey(const char *, const char *, int);
int setconfregion(const char *, const char *, int);
int setconfspawn(const char *, const char *, int);
int setconfvalue(const char *, const char *, int);
-void setkeybinding(unsigned int, KeySym, enum keyfuncid, const char *);
int setkeymapping(const char *, const char *, int);
int setlayout(const char *, const char *, int);
void setquirk(const char *, const char *, const char *, uint32_t, int);
void setscreencolor(const char *, int, int);
void setspawn(const char *, const char *, int);
+void setup_btnbindings(void);
void setup_ewmh(void);
void setup_globals(void);
-void setup_keys(void);
+void setup_keybindings(void);
void setup_quirks(void);
void setup_screens(void);
void setup_spawn(void);
void spawn_remove(struct spawn_prog *);
void spawn_replace(struct spawn_prog *, const char *, const char *, int);
void spawn_select(struct swm_region *, union arg *, const char *, int *);
-void stack_config(struct swm_region *, union arg *);
+void stack_config(struct binding *, struct swm_region *, union arg *);
void stack_master(struct workspace *, struct swm_geometry *, int, bool);
void store_float_geom(struct ws_win *);
char *strdupsafe(const char *);
-void swapwin(struct swm_region *, union arg *);
-void switchws(struct swm_region *, union arg *);
+void swapwin(struct binding *, struct swm_region *, union arg *);
+void switchws(struct binding *, struct swm_region *, union arg *);
void teardown_ewmh(void);
void unescape_selector(char *);
void unfocus_win(struct ws_win *);
-void uniconify(struct swm_region *, union arg *);
+void uniconify(struct binding *, 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 unmapnotify(xcb_unmap_notify_event_t *);
+void unparent_window(struct ws_win *);
void update_floater(struct ws_win *);
-void update_modkey(unsigned int);
+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);
int validate_win(struct ws_win *);
int validate_ws(struct workspace *);
-void version(struct swm_region *, union arg *);
+void version(struct binding *, struct swm_region *, union arg *);
void win_to_ws(struct ws_win *, int, bool);
pid_t window_get_pid(xcb_window_t);
-void wkill(struct swm_region *, union arg *);
+void wkill(struct binding *, struct swm_region *, union arg *);
void update_ws_stack(struct workspace *);
void xft_init(struct swm_region *);
void _add_startup_exception(const char *, va_list);
void add_startup_exception(const char *, ...);
-RB_PROTOTYPE(key_tree, key, entry, key_cmp);
-RB_GENERATE(key_tree, key, entry, key_cmp);
-struct key_tree keys;
+RB_PROTOTYPE(binding_tree, binding, entry, binding_cmp);
+RB_GENERATE(binding_tree, binding, entry, binding_cmp);
+struct binding_tree bindings;
void
cursors_load(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);
}
/* events */
#ifdef SWM_DEBUG
void
-dumpwins(struct swm_region *r, union arg *args)
+dumpwins(struct binding *bp, struct swm_region *r, union arg *args)
{
struct ws_win *w;
uint32_t state;
xcb_get_window_attributes_reply_t *wa;
/* suppress unused warning since var is needed */
+ (void)bp;
(void)args;
if (r->ws == NULL) {
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 swm_region *r, union arg *s)
+dumpwins(struct binding *b, struct swm_region *r, union arg *s)
+{
+ (void)b;
+ (void)r;
+ (void)s;
+}
+
+void
+debug_toggle(struct binding *b, struct swm_region *r, union arg *s)
{
+ (void)b;
(void)r;
(void)s;
}
int sidx, num_screens;
xcb_screen_t *screen;
+ DNPRINTF(SWM_D_CONF, "custom_region: %s\n", val);
+
num_screens = get_screen_count();
if (sscanf(val, "screen[%d]:%ux%u+%u+%u", &sidx, &w, &h, &x, &y) != 5)
errx(1, "invalid custom region, "
/* bar_urgent already adds the space before the last asterisk */
if (urgent_enabled)
- strlcat(fmtnew, "* +U*+4<", sz);
+ strlcat(fmtnew, (urgent_collapse ? "*+U*+4<" : "* +U*+4<"), sz);
if (window_class_enabled) {
strlcat(fmtnew, "+C", sz);
#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);
}
/*
}
void
-bar_toggle(struct swm_region *r, union arg *args)
+bar_toggle(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;
(void)args;
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);
void
xft_init(struct swm_region *r)
{
- char *font, *d, *search;
+ char *font, *str, *search;
XRenderColor color;
if (bar_font == NULL) {
- if ((d = strdup(bar_fonts)) == NULL)
+ if ((search = str = strdup(bar_fonts)) == NULL)
errx(1, "insufficient memory.");
- search = d;
+
while ((font = strsep(&search, ",")) != NULL) {
if (*font == '\0')
continue;
break;
}
}
- free(d);
+ free(str);
}
if (bar_font == NULL)
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;
uint16_t data[2] = { state, XCB_ATOM_NONE };
DNPRINTF(SWM_D_EVENT, "set_win_state: win %#x, state: %u\n",
- win->id, state);
+ WINID(win), state);
if (win == NULL)
return;
}
void
-version(struct swm_region *r, union arg *args)
+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;
(void)args;
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;
}
}
void
-quit(struct swm_region *r, union arg *args)
+quit(struct binding *bp, struct swm_region *r, union arg *args)
{
/* suppress unused warnings since vars are needed */
+ (void)bp;
(void)r;
(void)args;
struct ws_win *target = NULL;
struct workspace *ws;
+ DNPRINTF(SWM_D_EVENT, "lower_window: win %#x\n", WINID(win));
+
if (win == NULL)
return;
ws = win->ws;
- DNPRINTF(SWM_D_EVENT, "lower_window: win %#x\n", win->id);
-
TAILQ_FOREACH(target, &ws->stack, stack_entry) {
if (target == win || ICONIC(target))
continue;
struct ws_win *target = NULL;
struct workspace *ws;
+ DNPRINTF(SWM_D_EVENT, "raise_window: win %#x\n", WINID(win));
+
if (win == NULL)
return;
- ws = win->ws;
- DNPRINTF(SWM_D_EVENT, "raise_window: win %#x\n", win->id);
+ ws = win->ws;
TAILQ_FOREACH(target, &ws->stack, stack_entry) {
if (target == win || ICONIC(target))
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;
}
}
void
-restart(struct swm_region *r, union arg *args)
+restart(struct binding *bp, struct swm_region *r, union arg *args)
{
/* suppress unused warning since var is needed */
+ (void)bp;
(void)r;
(void)args;
execvp(start_argv[0], start_argv);
warn("execvp failed");
- quit(NULL, NULL);
+ quit(NULL, NULL, NULL);
}
struct ws_win *
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);
}
void
kill_refs(struct ws_win *win)
{
- int i, x, num_screens;
- struct swm_region *r;
struct workspace *ws;
+ struct ws_win *w;
+ int i, j, num_screens;
if (win == NULL)
return;
num_screens = get_screen_count();
- for (i = 0; i < num_screens; i++)
- TAILQ_FOREACH(r, &screens[i].rl, entry)
- for (x = 0; x < workspace_limit; x++) {
- ws = &r->s->ws[x];
- if (win == ws->focus)
- ws->focus = NULL;
- if (win == ws->focus_prev)
- ws->focus_prev = NULL;
- }
+ for (i = 0; i < num_screens; i++) {
+ for (j = 0; j < workspace_limit; j++) {
+ ws = &screens[i].ws[j];
+
+ if (win == ws->focus)
+ 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)
+ if (win == w->focus_child)
+ w->focus_child = NULL;
+ }
+ }
}
int
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);
- } else {
- unfocus_win(cfw);
+ if (cfw) {
+ if (cfw != win) {
+ if (cfw->ws != ws && cfw->ws->r != NULL &&
+ cfw->frame != XCB_WINDOW_NONE) {
+ draw_frame(cfw);
+ } else {
+ unfocus_win(cfw);
+ }
+ }
+ } else {
+ war = xcb_get_window_attributes_reply(conn,
+ xcb_get_window_attributes(conn, gifr->focus), NULL);
+ if (war && war->override_redirect && ws->focus == win) {
+ DNPRINTF(SWM_D_FOCUS, "focus_win: skip refocus "
+ "from override_redirect.\n");
+ goto out;
}
}
- free(gifr);
}
if (ws->focus != win) {
ws->focus = win;
}
- /* If this window directs focus to a child window, then clear. */
- if (win->focus_child)
- win->focus_child = NULL;
+ /* Clear focus child redirect. */
+ win->focus_child = NULL;
/* If transient, adjust parent's focus child for focus_magic. */
if (TRANS(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.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");
}
/* ensure all pending requests have been processed before filtering. */
xcb_aux_sync(conn);
- while ((evt = xcb_poll_for_event(conn))) {
+ while ((evt = get_next_event(false))) {
if (XCB_EVENT_RESPONSE_TYPE(evt) != rt)
event_handle(evt);
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();
}
}
void
-switchws(struct swm_region *r, union arg *args)
+switchws(struct binding *bp, struct swm_region *r, union arg *args)
{
struct swm_region *this_r, *other_r;
struct ws_win *win;
int wsid = args->id;
bool unmap_old = false;
+ (void)bp;
+
if (!(r && r->s))
return;
}
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();
}
void
-cyclews(struct swm_region *r, union arg *args)
+cyclews(struct binding *bp, struct swm_region *r, union arg *args)
{
union arg a;
struct swm_screen *s = r->s;
continue;
if (mv)
- send_to_ws(r, &a);
+ send_to_ws(bp, r, &a);
- switchws(r, &a);
+ switchws(bp, r, &a);
} while (a.id != r->ws->idx);
DNPRINTF(SWM_D_FOCUS, "cyclews: done\n");
}
void
-priorws(struct swm_region *r, union arg *args)
+priorws(struct binding *bp, struct swm_region *r, union arg *args)
{
union arg a;
return;
a.id = r->ws_prior->idx;
- switchws(r, &a);
+ switchws(bp, r, &a);
DNPRINTF(SWM_D_FOCUS, "priorws: done\n");
}
void
-focusrg(struct swm_region *r, union arg *args)
+focusrg(struct binding *bp, struct swm_region *r, union arg *args)
{
int ridx = args->id, i, num_screens;
struct swm_region *rr = NULL;
+ (void)bp;
+
num_screens = get_screen_count();
/* do nothing if we don't have more than one screen */
if (!(num_screens > 1 || outputs > 1))
}
void
-cyclerg(struct swm_region *r, union arg *args)
+cyclerg(struct binding *bp, struct swm_region *r, union arg *args)
{
union arg a;
struct swm_region *rr = NULL;
case SWM_ARG_ID_CYCLERG_MOVE_UP:
case SWM_ARG_ID_CYCLERG_MOVE_DOWN:
a.id = rr->ws->idx;
- switchws(r, &a);
+ switchws(bp, r, &a);
break;
default:
return;
}
void
-swapwin(struct swm_region *r, union arg *args)
+swapwin(struct binding *bp, struct swm_region *r, union arg *args)
{
struct ws_win *target, *source;
struct ws_win *cur_focus;
struct ws_win_list *wl;
+ (void)bp;
+
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);
sort_windows(wl);
ewmh_update_client_list();
- stack();
+ stack(r);
center_pointer(r);
focus_flush();
out:
}
void
-focus(struct swm_region *r, union arg *args)
+focus(struct binding *bp, struct swm_region *r, union arg *args)
{
struct ws_win *head, *cur_focus = NULL, *winfocus = NULL;
struct ws_win_list *wl = NULL;
/* Switch ws if new focus is on a different ws. */
if (winfocus && winfocus->ws != ws) {
a.id = winfocus->ws->idx;
- switchws(r, &a);
+ switchws(bp, r, &a);
}
break;
default:
}
if (clear_maximized(ws) > 0)
- stack();
+ stack(r);
focus_win(get_focus_magic(winfocus));
center_pointer(r);
}
void
-cycle_layout(struct swm_region *r, union arg *args)
+focus_pointer(struct binding *bp, struct swm_region *r, union arg *args)
+{
+ (void)args;
+
+ /* Not needed for buttons since this is already done in buttonpress. */
+ if (bp->type == KEYBIND) {
+ focus_win(get_pointer_win(r->s->root));
+ focus_flush();
+ }
+}
+
+void
+cycle_layout(struct binding *bp, struct swm_region *r, union arg *args)
{
struct workspace *ws = r->ws;
/* suppress unused warning since var is needed */
+ (void)bp;
(void)args;
DNPRINTF(SWM_D_EVENT, "cycle_layout: workspace: %d\n", ws->idx);
clear_maximized(ws);
- stack();
- bar_draw();
+ stack(r);
+ bar_draw(r->bar);
focus_win(get_region_focus(r));
}
void
-stack_config(struct swm_region *r, union arg *args)
+stack_config(struct binding *bp, struct swm_region *r, union arg *args)
{
struct workspace *ws = r->ws;
+ (void)bp;
+
DNPRINTF(SWM_D_STACK, "stack_config: id: %d workspace: %d\n",
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--;
struct workspace *ws;
struct swm_region *r;
+ DNPRINTF(SWM_D_MISC, "update_floater: win %#x\n", WINID(win));
+
if (win == NULL)
return;
if ((r = ws->r) == NULL)
return;
- DNPRINTF(SWM_D_MISC, "update_floater: win %#x\n", win->id);
-
win->bordered = true;
if (FULLSCREEN(win)) {
}
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, j, s, stacks;
+ int i = 0, j = 0, s = 0, stacks = 0;
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;
+ int hrh = 0, extra = 0, h_slice = 0, last_h = 0;
+ int split = 0, colno = 0;
+ int winno, mwin = 0, msize = 0;
+ 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);
}
void
-send_to_rg(struct swm_region *r, union arg *args)
+send_to_rg(struct binding *bp, struct swm_region *r, union arg *args)
{
int ridx = args->id, i, num_screens;
struct swm_region *rr = NULL;
a.id = rr->ws->idx;
- send_to_ws(r, &a);
+ send_to_ws(bp, r, &a);
}
struct swm_region *
/* Transfer focused window to target workspace and focus. */
void
-send_to_ws(struct swm_region *r, union arg *args)
+send_to_ws(struct binding *bp, struct swm_region *r, union arg *args)
{
int wsid = args->id;
struct ws_win *win = NULL;
+ (void)bp;
+
if (r && r->ws && r->ws->focus)
win = r->ws->focus;
else
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);
+
+ /* If destination ws has a region, restack. */
+ if (win->ws->r) {
+ if (FLOATING(win))
+ load_float_geom(win);
- stack();
+ 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);
}
}
}
void
-pressbutton(struct swm_region *r, union arg *args)
+pressbutton(struct binding *bp, struct swm_region *r, union arg *args)
{
/* suppress unused warning since var is needed */
+ (void)bp;
(void)r;
xcb_test_fake_input(conn, XCB_BUTTON_PRESS, args->id,
}
void
-raise_toggle(struct swm_region *r, union arg *args)
+raise_toggle(struct binding *bp, struct swm_region *r, union arg *args)
{
/* Suppress warning. */
+ (void)bp;
(void)args;
if (r == NULL || r->ws == NULL)
}
void
-iconify(struct swm_region *r, union arg *args)
+iconify(struct binding *bp, struct swm_region *r, union arg *args)
{
struct ws_win *w;
/* Suppress warning. */
+ (void)bp;
(void)args;
if ((w = r->ws->focus) == NULL)
ewmh_apply_flags(w, w->ewmh_flags | EWMH_F_HIDDEN);
ewmh_update_wm_state(w);
- stack();
+ stack(r);
focus_flush();
}
}
void
-uniconify(struct swm_region *r, union arg *args)
+uniconify(struct binding *bp, struct swm_region *r, union arg *args)
{
struct ws_win *win;
FILE *lfile;
char *name;
int count = 0;
+ (void)bp;
+
DNPRINTF(SWM_D_MISC, "uniconify\n");
if (r == NULL || r->ws == NULL)
}
void
-name_workspace(struct swm_region *r, union arg *args)
+name_workspace(struct binding *bp, struct swm_region *r, union arg *args)
{
FILE *lfile;
+ (void)bp;
+
DNPRINTF(SWM_D_MISC, "name_workspace\n");
if (r == NULL)
}
void
-search_workspace(struct swm_region *r, union arg *args)
+search_workspace(struct binding *bp, struct swm_region *r, union arg *args)
{
int i;
struct workspace *ws;
FILE *lfile;
+ (void)bp;
+
DNPRINTF(SWM_D_MISC, "search_workspace\n");
if (r == NULL)
}
void
-search_win(struct swm_region *r, union arg *args)
+search_win(struct binding *bp, struct swm_region *r, union arg *args)
{
struct ws_win *win = NULL;
struct search_window *sw = NULL;
XGCValues l_gcv;
XRectangle l_ibox, l_lbox;
+ (void)bp;
+
DNPRINTF(SWM_D_MISC, "search_win\n");
search_r = r;
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;
}
}
free(q);
a.id = ws_idx - 1;
- switchws(search_r, &a);
+ switchws(NULL, search_r, &a);
}
void
}
void
-wkill(struct swm_region *r, union arg *args)
+wkill(struct binding *bp, struct swm_region *r, union arg *args)
{
+ (void)bp;
+
DNPRINTF(SWM_D_MISC, "wkill: win %#x, id: %d\n", WINID(r->ws->focus),
args->id);
}
void
-maximize_toggle(struct swm_region *r, union arg *args)
+maximize_toggle(struct binding *bp, struct swm_region *r, union arg *args)
{
struct ws_win *w = r->ws->focus;
/* suppress unused warning since var is needed */
+ (void)bp;
(void)args;
if (w == NULL)
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);
}
void
-floating_toggle(struct swm_region *r, union arg *args)
+floating_toggle(struct binding *bp, struct swm_region *r, union arg *args)
{
struct ws_win *w = r->ws->focus;
/* suppress unused warning since var is needed */
+ (void)bp;
(void)args;
if (w == NULL)
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];
+ 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;
- wc[0] = X(win);
- wc[1] = Y(win);
+
+ /* 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_ENTRY(event) entry;
+ xcb_generic_event_t *ev;
+};
+SIMPLEQ_HEAD(event_queue, event) events = SIMPLEQ_HEAD_INITIALIZER(events);
+
+xcb_generic_event_t *
+get_next_event(bool dowait)
+{
+ struct event *ep;
+ xcb_generic_event_t *evt;
+
+ /* Try queue first. */
+ if ((ep = SIMPLEQ_FIRST(&events))) {
+ evt = ep->ev;
+ SIMPLEQ_REMOVE_HEAD(&events, entry);
+ free(ep);
+ } else if (dowait)
+ evt = xcb_wait_for_event(conn);
+ else
+ evt = xcb_poll_for_event(conn);
+
+ return evt;
+}
+
+void
+put_back_event(xcb_generic_event_t *evt)
+{
+ struct event *ep;
+ if ((ep = malloc(sizeof (struct event))) == NULL)
+ err(1, "put_back_event: failed to allocate memory.");
+ ep->ev = evt;
+ SIMPLEQ_INSERT_HEAD(&events, ep, entry);
+}
+
+/* Peeks at next event to detect auto-repeat. */
+bool
+keyrepeating(xcb_key_release_event_t *kre)
+{
+ xcb_generic_event_t *evt;
+
+ /* Ensure repeating keypress is finished processing. */
+ xcb_aux_sync(conn);
+
+ if ((evt = get_next_event(false))) {
+ put_back_event(evt);
+
+ if (XCB_EVENT_RESPONSE_TYPE(evt) == XCB_KEY_PRESS &&
+ kre->sequence == evt->sequence &&
+ kre->detail == ((xcb_key_press_event_t *)evt)->detail)
+ return true;
+ }
+
+ return false;
+}
+
+bool
+keybindreleased(struct binding *bp, xcb_key_release_event_t *kre)
+{
+ if (bp->type == KEYBIND && !keyrepeating(kre) &&
+ bp->value == xcb_key_press_lookup_keysym(syms, kre, 0))
+ return true;
+
+ return false;
}
#define SWM_RESIZE_STEPS (50)
void
-resize(struct ws_win *win, union arg *args)
+resize_win(struct ws_win *win, struct binding *bp, int opt)
{
xcb_timestamp_t timestamp = 0;
struct swm_region *r = NULL;
struct swm_geometry g;
- int resize_stp = 0;
int top = 0, left = 0;
int dx, dy;
xcb_cursor_t cursor;
xcb_query_pointer_reply_t *xpr = NULL;
xcb_generic_event_t *evt;
xcb_motion_notify_event_t *mne;
- bool resizing;
+ bool resizing, step = false;
if (win == NULL)
return;
~EWMH_F_MAXIMIZED);
ewmh_update_wm_state(win);
- stack();
+ stack(r);
focus_flush();
goto out;
}
- switch (args->id) {
+ switch (opt) {
case SWM_ARG_ID_WIDTHSHRINK:
WIDTH(win) -= SWM_RESIZE_STEPS;
- resize_stp = 1;
+ step = true;
break;
case SWM_ARG_ID_WIDTHGROW:
WIDTH(win) += SWM_RESIZE_STEPS;
- resize_stp = 1;
+ step = true;
break;
case SWM_ARG_ID_HEIGHTSHRINK:
HEIGHT(win) -= SWM_RESIZE_STEPS;
- resize_stp = 1;
+ step = true;
break;
case SWM_ARG_ID_HEIGHTGROW:
HEIGHT(win) += SWM_RESIZE_STEPS;
- resize_stp = 1;
+ step = true;
break;
default:
break;
}
- if (resize_stp) {
+ if (step) {
region_containment(win, r, SWM_CW_ALLSIDES | SWM_CW_RESIZABLE |
SWM_CW_HARDBOUNDARY);
update_window(win);
if (xpr->win_y < HEIGHT(win) / 2)
top = 1;
- if (args->id == SWM_ARG_ID_CENTER)
+ if (opt == SWM_ARG_ID_CENTER)
cursor = cursors[XC_SIZING].cid;
else if (top)
cursor = cursors[left ? XC_TOP_LEFT_CORNER :
xcb_grab_pointer(conn, 0, win->id, MOUSEMASK,
XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_WINDOW_NONE, cursor,
- XCB_CURRENT_TIME),
+ XCB_CURRENT_TIME);
+
+ /* Release keyboard freeze if called via keybind. */
+ if (bp->type == KEYBIND)
+ xcb_allow_events(conn, XCB_ALLOW_ASYNC_KEYBOARD,
+ XCB_CURRENT_TIME);
xcb_flush(conn);
resizing = true;
- while (resizing && (evt = xcb_wait_for_event(conn))) {
+ while (resizing && (evt = get_next_event(true))) {
switch (XCB_EVENT_RESPONSE_TYPE(evt)) {
case XCB_BUTTON_RELEASE:
- DNPRINTF(SWM_D_EVENT, "resize: BUTTON_RELEASE\n");
- resizing = false;
+ if (bp->type == BTNBIND && bp->value ==
+ ((xcb_button_release_event_t *)evt)->detail)
+ resizing = false;
+ break;
+ case XCB_KEY_RELEASE:
+ if (keybindreleased(bp, (xcb_key_release_event_t *)evt))
+ resizing = false;
break;
case XCB_MOTION_NOTIFY:
mne = (xcb_motion_notify_event_t *)evt;
+ DNPRINTF(SWM_D_EVENT, "resize: MOTION_NOTIFY: "
+ "root: %#x\n", mne->root);
+
/* cursor offset/delta from start of the operation */
dx = mne->root_x - xpr->root_x;
dy = mne->root_y - xpr->root_y;
if (top)
dy = -dy;
- if (args->id == SWM_ARG_ID_CENTER) {
+ if (opt == SWM_ARG_ID_CENTER) {
if (g.h / 2 + dy < 1)
dy = 1 - g.h / 2;
if (left)
dx = -dx;
- if (args->id == SWM_ARG_ID_CENTER) {
+ if (opt == SWM_ARG_ID_CENTER) {
if (g.w / 2 + dx < 1)
dx = 1 - g.w / 2;
xcb_flush(conn);
}
break;
+ case XCB_BUTTON_PRESS:
+ /* Ignore. */
+ DNPRINTF(SWM_D_EVENT, "resize: BUTTON_PRESS ignored\n");
+ xcb_allow_events(conn, XCB_ALLOW_ASYNC_POINTER,
+ ((xcb_button_press_event_t *)evt)->time);
+ xcb_flush(conn);
+ break;
case XCB_KEY_PRESS:
/* Ignore. */
+ DNPRINTF(SWM_D_EVENT, "resize: KEY_PRESS ignored\n");
xcb_allow_events(conn, XCB_ALLOW_ASYNC_KEYBOARD,
((xcb_key_press_event_t *)evt)->time);
xcb_flush(conn);
}
void
-resize_step(struct swm_region *r, union arg *args)
+resize(struct binding *bp, struct swm_region *r, union arg *args)
{
struct ws_win *win = NULL;
+ xcb_query_pointer_reply_t *qpr = NULL;
- if (r && r->ws && r->ws->focus)
- win = r->ws->focus;
- else
+ if (r == NULL)
return;
- resize(win, args);
- center_pointer(r);
+ if (args->id != SWM_ARG_ID_DONTCENTER &&
+ args->id != SWM_ARG_ID_CENTER) {
+ /* {height,width}_{grow,shrink} use the focus window. */
+ if (r->ws)
+ win = r->ws->focus;
+ } else {
+ /* resize uses window under pointer. */
+ qpr = xcb_query_pointer_reply(conn,
+ xcb_query_pointer(conn, r->s->root), NULL);
+ if (qpr)
+ win = find_window(qpr->child);
+ }
+
+ if (win == NULL)
+ return;
+
+ resize_win(win, bp, args->id);
+
+ if (args->id && bp->type == KEYBIND)
+ center_pointer(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;
#define SWM_MOVE_STEPS (50)
void
-move(struct ws_win *win, union arg *args)
+move_win(struct ws_win *win, struct binding *bp, int opt)
{
struct swm_region *r;
xcb_timestamp_t timestamp = 0;
- int move_stp = 0;
xcb_query_pointer_reply_t *qpr = NULL;
xcb_generic_event_t *evt;
xcb_motion_notify_event_t *mne;
- bool moving, restack = false;
+ bool moving, restack = false, step = false;
if (win == NULL)
return;
ewmh_update_wm_state(win);
if (restack)
- stack();
+ stack(r);
focus_flush();
goto out;
}
- move_stp = 0;
- switch (args->id) {
+ switch (opt) {
case SWM_ARG_ID_MOVELEFT:
X(win) -= (SWM_MOVE_STEPS - border_width);
- move_stp = 1;
+ step = true;
break;
case SWM_ARG_ID_MOVERIGHT:
X(win) += (SWM_MOVE_STEPS - border_width);
- move_stp = 1;
+ step = true;
break;
case SWM_ARG_ID_MOVEUP:
Y(win) -= (SWM_MOVE_STEPS - border_width);
- move_stp = 1;
+ step = true;
break;
case SWM_ARG_ID_MOVEDOWN:
Y(win) += (SWM_MOVE_STEPS - border_width);
- move_stp = 1;
+ step = true;
break;
default:
break;
}
- if (move_stp) {
+ if (step) {
regionize(win, -1, -1);
region_containment(win, win->ws->r, SWM_CW_ALLSIDES);
update_window(win);
return;
}
+ /* Release keyboard freeze if called via keybind. */
+ if (bp->type == KEYBIND)
+ xcb_allow_events(conn, XCB_ALLOW_ASYNC_KEYBOARD,
+ XCB_CURRENT_TIME);
+
regionize(win, qpr->root_x, qpr->root_y);
region_containment(win, win->ws->r, SWM_CW_ALLSIDES |
SWM_CW_SOFTBOUNDARY);
update_window(win);
xcb_flush(conn);
moving = true;
- while (moving && (evt = xcb_wait_for_event(conn))) {
+ while (moving && (evt = get_next_event(true))) {
switch (XCB_EVENT_RESPONSE_TYPE(evt)) {
case XCB_BUTTON_RELEASE:
- DNPRINTF(SWM_D_EVENT, "move: BUTTON_RELEASE\n");
- moving = false;
+ if (bp->type == BTNBIND && bp->value ==
+ ((xcb_button_release_event_t *)evt)->detail)
+ moving = false;
+
+ xcb_allow_events(conn, XCB_ALLOW_ASYNC_POINTER,
+ ((xcb_button_release_event_t *)evt)->time);
+ xcb_flush(conn);
+ break;
+ case XCB_KEY_RELEASE:
+ if (keybindreleased(bp, (xcb_key_release_event_t *)evt))
+ moving = false;
+
+ xcb_allow_events(conn, XCB_ALLOW_ASYNC_KEYBOARD,
+ ((xcb_key_release_event_t *)evt)->time);
+ xcb_flush(conn);
break;
case XCB_MOTION_NOTIFY:
mne = (xcb_motion_notify_event_t *)evt;
- DNPRINTF(SWM_D_EVENT, "motion: root: %#x\n", mne->root);
+ DNPRINTF(SWM_D_EVENT, "move: MOTION_NOTIFY: "
+ "root: %#x\n", mne->root);
X(win) = mne->root_x - qpr->win_x - border_width;
Y(win) = mne->root_y - qpr->win_y - border_width;
xcb_flush(conn);
}
break;
+ case XCB_BUTTON_PRESS:
+ /* Thaw and ignore. */
+ xcb_allow_events(conn, XCB_ALLOW_ASYNC_POINTER,
+ ((xcb_button_press_event_t *)evt)->time);
+ xcb_flush(conn);
+ break;
case XCB_KEY_PRESS:
/* Ignore. */
xcb_allow_events(conn, XCB_ALLOW_ASYNC_KEYBOARD,
default:
event_handle(evt);
- /* It's possible for win to have been freed above. */
+ /* It's possible for win to have been freed. */
if (validate_win(win)) {
DNPRINTF(SWM_D_EVENT, "move: invalid win.\n");
goto out;
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();
}
}
void
-move_step(struct swm_region *r, union arg *args)
+move(struct binding *bp, struct swm_region *r, union arg *args)
{
- struct ws_win *win = NULL;
+ struct ws_win *win = NULL;
+ xcb_query_pointer_reply_t *qpr = NULL;
- if (r && r->ws && r->ws->focus)
- win = r->ws->focus;
- else
+ if (r == NULL)
return;
- if (!TRANS(win) && !ABOVE(win))
- return;
+ if (args->id) {
+ /* move_* uses focus window. */
+ if (r->ws)
+ win = r->ws->focus;
- move(win, args);
- center_pointer(r);
- focus_flush();
-}
+ /* Disallow move_ on tiled. */
+ if (win && !(TRANS(win) || ABOVE(win)))
+ return;
+ } else {
+ /* move uses window under pointer. */
+ qpr = xcb_query_pointer_reply(conn,
+ xcb_query_pointer(conn, r->s->root), NULL);
+ if (qpr)
+ win = find_window(qpr->child);
+ }
-/* key definitions */
-struct keyfunc {
- char name[SWM_FUNCNAME_LEN];
- void (*func)(struct swm_region *r, union arg *);
- union arg args;
-} keyfuncs[KF_INVALID + 1] = {
- /* name function argument */
- { "bar_toggle", bar_toggle, {.id = SWM_ARG_ID_BAR_TOGGLE} },
- { "bar_toggle_ws", bar_toggle, {.id = SWM_ARG_ID_BAR_TOGGLE_WS} },
- { "button2", pressbutton, {2} },
- { "cycle_layout", cycle_layout, {0} },
- { "flip_layout", stack_config, {.id = SWM_ARG_ID_FLIPLAYOUT} },
- { "float_toggle", floating_toggle,{0} },
- { "focus_main", focus, {.id = SWM_ARG_ID_FOCUSMAIN} },
- { "focus_next", focus, {.id = SWM_ARG_ID_FOCUSNEXT} },
- { "focus_prev", focus, {.id = SWM_ARG_ID_FOCUSPREV} },
- { "focus_urgent", focus, {.id = SWM_ARG_ID_FOCUSURGENT} },
- { "maximize_toggle", maximize_toggle,{0} },
- { "height_grow", resize_step, {.id = SWM_ARG_ID_HEIGHTGROW} },
- { "height_shrink", resize_step, {.id = SWM_ARG_ID_HEIGHTSHRINK} },
- { "iconify", iconify, {0} },
- { "master_shrink", stack_config, {.id = SWM_ARG_ID_MASTERSHRINK} },
- { "master_grow", stack_config, {.id = SWM_ARG_ID_MASTERGROW} },
- { "master_add", stack_config, {.id = SWM_ARG_ID_MASTERADD} },
- { "master_del", stack_config, {.id = SWM_ARG_ID_MASTERDEL} },
- { "move_down", move_step, {.id = SWM_ARG_ID_MOVEDOWN} },
- { "move_left", move_step, {.id = SWM_ARG_ID_MOVELEFT} },
- { "move_right", move_step, {.id = SWM_ARG_ID_MOVERIGHT} },
- { "move_up", move_step, {.id = SWM_ARG_ID_MOVEUP} },
- { "mvrg_1", send_to_rg, {.id = 0} },
- { "mvrg_2", send_to_rg, {.id = 1} },
- { "mvrg_3", send_to_rg, {.id = 2} },
- { "mvrg_4", send_to_rg, {.id = 3} },
- { "mvrg_5", send_to_rg, {.id = 4} },
- { "mvrg_6", send_to_rg, {.id = 5} },
- { "mvrg_7", send_to_rg, {.id = 6} },
- { "mvrg_8", send_to_rg, {.id = 7} },
- { "mvrg_9", send_to_rg, {.id = 8} },
- { "mvws_1", send_to_ws, {.id = 0} },
- { "mvws_2", send_to_ws, {.id = 1} },
- { "mvws_3", send_to_ws, {.id = 2} },
- { "mvws_4", send_to_ws, {.id = 3} },
- { "mvws_5", send_to_ws, {.id = 4} },
- { "mvws_6", send_to_ws, {.id = 5} },
- { "mvws_7", send_to_ws, {.id = 6} },
- { "mvws_8", send_to_ws, {.id = 7} },
- { "mvws_9", send_to_ws, {.id = 8} },
- { "mvws_10", send_to_ws, {.id = 9} },
- { "mvws_11", send_to_ws, {.id = 10} },
- { "mvws_12", send_to_ws, {.id = 11} },
- { "mvws_13", send_to_ws, {.id = 12} },
- { "mvws_14", send_to_ws, {.id = 13} },
- { "mvws_15", send_to_ws, {.id = 14} },
- { "mvws_16", send_to_ws, {.id = 15} },
- { "mvws_17", send_to_ws, {.id = 16} },
- { "mvws_18", send_to_ws, {.id = 17} },
- { "mvws_19", send_to_ws, {.id = 18} },
- { "mvws_20", send_to_ws, {.id = 19} },
- { "mvws_21", send_to_ws, {.id = 20} },
- { "mvws_22", send_to_ws, {.id = 21} },
- { "name_workspace", name_workspace, {0} },
- { "quit", quit, {0} },
- { "raise_toggle", raise_toggle, {0} },
- { "restart", restart, {0} },
- { "rg_1", focusrg, {.id = 0} },
- { "rg_2", focusrg, {.id = 1} },
- { "rg_3", focusrg, {.id = 2} },
- { "rg_4", focusrg, {.id = 3} },
- { "rg_5", focusrg, {.id = 4} },
- { "rg_6", focusrg, {.id = 5} },
- { "rg_7", focusrg, {.id = 6} },
- { "rg_8", focusrg, {.id = 7} },
- { "rg_9", focusrg, {.id = 8} },
- { "rg_move_next", cyclerg, {.id = SWM_ARG_ID_CYCLERG_MOVE_UP} },
- { "rg_move_prev", cyclerg, {.id = SWM_ARG_ID_CYCLERG_MOVE_DOWN} },
- { "rg_next", cyclerg, {.id = SWM_ARG_ID_CYCLERG_UP} },
- { "rg_prev", cyclerg, {.id = SWM_ARG_ID_CYCLERG_DOWN} },
- { "screen_next", cyclerg, {.id = SWM_ARG_ID_CYCLERG_UP} },
- { "screen_prev", cyclerg, {.id = SWM_ARG_ID_CYCLERG_DOWN} },
- { "search_win", search_win, {0} },
- { "search_workspace", search_workspace, {0} },
- { "spawn_custom", NULL, {0} },
- { "stack_balance", stack_config, {.id = SWM_ARG_ID_STACKBALANCE} },
- { "stack_inc", stack_config, {.id = SWM_ARG_ID_STACKINC} },
- { "stack_dec", stack_config, {.id = SWM_ARG_ID_STACKDEC} },
- { "stack_reset", stack_config, {.id = SWM_ARG_ID_STACKRESET} },
- { "swap_main", swapwin, {.id = SWM_ARG_ID_SWAPMAIN} },
- { "swap_next", swapwin, {.id = SWM_ARG_ID_SWAPNEXT} },
- { "swap_prev", swapwin, {.id = SWM_ARG_ID_SWAPPREV} },
- { "uniconify", uniconify, {0} },
- { "version", version, {0} },
- { "width_grow", resize_step, {.id = SWM_ARG_ID_WIDTHGROW} },
- { "width_shrink", resize_step, {.id = SWM_ARG_ID_WIDTHSHRINK} },
- { "wind_del", wkill, {.id = SWM_ARG_ID_DELETEWINDOW} },
- { "wind_kill", wkill, {.id = SWM_ARG_ID_KILLWINDOW} },
- { "ws_1", switchws, {.id = 0} },
- { "ws_2", switchws, {.id = 1} },
- { "ws_3", switchws, {.id = 2} },
- { "ws_4", switchws, {.id = 3} },
- { "ws_5", switchws, {.id = 4} },
- { "ws_6", switchws, {.id = 5} },
- { "ws_7", switchws, {.id = 6} },
- { "ws_8", switchws, {.id = 7} },
- { "ws_9", switchws, {.id = 8} },
- { "ws_10", switchws, {.id = 9} },
- { "ws_11", switchws, {.id = 10} },
- { "ws_12", switchws, {.id = 11} },
- { "ws_13", switchws, {.id = 12} },
- { "ws_14", switchws, {.id = 13} },
- { "ws_15", switchws, {.id = 14} },
- { "ws_16", switchws, {.id = 15} },
- { "ws_17", switchws, {.id = 16} },
- { "ws_18", switchws, {.id = 17} },
- { "ws_19", switchws, {.id = 18} },
- { "ws_20", switchws, {.id = 19} },
- { "ws_21", switchws, {.id = 20} },
- { "ws_22", switchws, {.id = 21} },
- { "ws_next", cyclews, {.id = SWM_ARG_ID_CYCLEWS_UP} },
- { "ws_next_all", cyclews, {.id = SWM_ARG_ID_CYCLEWS_UP_ALL} },
- { "ws_next_move", cyclews, {.id = SWM_ARG_ID_CYCLEWS_MOVE_UP} },
- { "ws_prev", cyclews, {.id = SWM_ARG_ID_CYCLEWS_DOWN} },
- { "ws_prev_all", cyclews, {.id = SWM_ARG_ID_CYCLEWS_DOWN_ALL} },
- { "ws_prev_move", cyclews, {.id = SWM_ARG_ID_CYCLEWS_MOVE_DOWN} },
- { "ws_prior", priorws, {0} },
- { "dumpwins", dumpwins, {0} }, /* MUST BE LAST */
- { "invalid key func", NULL, {0} },
-};
+ if (win == NULL)
+ return;
-int
-key_cmp(struct key *kp1, struct key *kp2)
-{
- if (kp1->keysym < kp2->keysym)
- return (-1);
- if (kp1->keysym > kp2->keysym)
- return (1);
+ move_win(win, bp, args->id);
- if (kp1->mod < kp2->mod)
- return (-1);
- if (kp1->mod > kp2->mod)
- return (1);
+ if (args->id && bp->type == KEYBIND)
+ center_pointer(r);
- return (0);
+ focus_flush();
}
-/* mouse */
-enum { client_click, root_click };
-struct button {
- unsigned int action;
- unsigned int mask;
- unsigned int button;
- void (*func)(struct ws_win *, union arg *);
+/* action definitions */
+struct action {
+ char name[SWM_FUNCNAME_LEN];
+ void (*func)(struct binding *, struct swm_region *,
+ union arg *);
+ uint32_t flags;
union arg args;
-} buttons[] = {
-#define MODKEY_SHIFT MODKEY | XCB_MOD_MASK_SHIFT
- /* action key mouse button func args */
- { 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
+} 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} },
+ { "button2", pressbutton, 0, {.id = 2} },
+ { "cycle_layout", cycle_layout, 0, {0} },
+ { "flip_layout", stack_config, 0, {.id = SWM_ARG_ID_FLIPLAYOUT} },
+ { "float_toggle", floating_toggle,0, {0} },
+ { "focus", focus_pointer, 0, {0} },
+ { "focus_main", focus, 0, {.id = SWM_ARG_ID_FOCUSMAIN} },
+ { "focus_next", focus, 0, {.id = SWM_ARG_ID_FOCUSNEXT} },
+ { "focus_prev", focus, 0, {.id = SWM_ARG_ID_FOCUSPREV} },
+ { "focus_urgent", focus, 0, {.id = SWM_ARG_ID_FOCUSURGENT} },
+ { "maximize_toggle", maximize_toggle,0, {0} },
+ { "height_grow", resize, 0, {.id = SWM_ARG_ID_HEIGHTGROW} },
+ { "height_shrink", resize, 0, {.id = SWM_ARG_ID_HEIGHTSHRINK} },
+ { "iconify", iconify, 0, {0} },
+ { "master_shrink", stack_config, 0, {.id = SWM_ARG_ID_MASTERSHRINK} },
+ { "master_grow", stack_config, 0, {.id = SWM_ARG_ID_MASTERGROW} },
+ { "master_add", stack_config, 0, {.id = SWM_ARG_ID_MASTERADD} },
+ { "master_del", stack_config, 0, {.id = SWM_ARG_ID_MASTERDEL} },
+ { "move", move, FN_F_NOREPLAY, {0} },
+ { "move_down", move, 0, {.id = SWM_ARG_ID_MOVEDOWN} },
+ { "move_left", move, 0, {.id = SWM_ARG_ID_MOVELEFT} },
+ { "move_right", move, 0, {.id = SWM_ARG_ID_MOVERIGHT} },
+ { "move_up", move, 0, {.id = SWM_ARG_ID_MOVEUP} },
+ { "mvrg_1", send_to_rg, 0, {.id = 0} },
+ { "mvrg_2", send_to_rg, 0, {.id = 1} },
+ { "mvrg_3", send_to_rg, 0, {.id = 2} },
+ { "mvrg_4", send_to_rg, 0, {.id = 3} },
+ { "mvrg_5", send_to_rg, 0, {.id = 4} },
+ { "mvrg_6", send_to_rg, 0, {.id = 5} },
+ { "mvrg_7", send_to_rg, 0, {.id = 6} },
+ { "mvrg_8", send_to_rg, 0, {.id = 7} },
+ { "mvrg_9", send_to_rg, 0, {.id = 8} },
+ { "mvws_1", send_to_ws, 0, {.id = 0} },
+ { "mvws_2", send_to_ws, 0, {.id = 1} },
+ { "mvws_3", send_to_ws, 0, {.id = 2} },
+ { "mvws_4", send_to_ws, 0, {.id = 3} },
+ { "mvws_5", send_to_ws, 0, {.id = 4} },
+ { "mvws_6", send_to_ws, 0, {.id = 5} },
+ { "mvws_7", send_to_ws, 0, {.id = 6} },
+ { "mvws_8", send_to_ws, 0, {.id = 7} },
+ { "mvws_9", send_to_ws, 0, {.id = 8} },
+ { "mvws_10", send_to_ws, 0, {.id = 9} },
+ { "mvws_11", send_to_ws, 0, {.id = 10} },
+ { "mvws_12", send_to_ws, 0, {.id = 11} },
+ { "mvws_13", send_to_ws, 0, {.id = 12} },
+ { "mvws_14", send_to_ws, 0, {.id = 13} },
+ { "mvws_15", send_to_ws, 0, {.id = 14} },
+ { "mvws_16", send_to_ws, 0, {.id = 15} },
+ { "mvws_17", send_to_ws, 0, {.id = 16} },
+ { "mvws_18", send_to_ws, 0, {.id = 17} },
+ { "mvws_19", send_to_ws, 0, {.id = 18} },
+ { "mvws_20", send_to_ws, 0, {.id = 19} },
+ { "mvws_21", send_to_ws, 0, {.id = 20} },
+ { "mvws_22", send_to_ws, 0, {.id = 21} },
+ { "name_workspace", name_workspace, 0, {0} },
+ { "quit", quit, 0, {0} },
+ { "raise_toggle", raise_toggle, 0, {0} },
+ { "resize", resize, FN_F_NOREPLAY, {.id = SWM_ARG_ID_DONTCENTER} },
+ { "resize_centered", resize, FN_F_NOREPLAY, {.id = SWM_ARG_ID_CENTER} },
+ { "restart", restart, 0, {0} },
+ { "rg_1", focusrg, 0, {.id = 0} },
+ { "rg_2", focusrg, 0, {.id = 1} },
+ { "rg_3", focusrg, 0, {.id = 2} },
+ { "rg_4", focusrg, 0, {.id = 3} },
+ { "rg_5", focusrg, 0, {.id = 4} },
+ { "rg_6", focusrg, 0, {.id = 5} },
+ { "rg_7", focusrg, 0, {.id = 6} },
+ { "rg_8", focusrg, 0, {.id = 7} },
+ { "rg_9", focusrg, 0, {.id = 8} },
+ { "rg_move_next", cyclerg, 0, {.id = SWM_ARG_ID_CYCLERG_MOVE_UP} },
+ { "rg_move_prev", cyclerg, 0, {.id = SWM_ARG_ID_CYCLERG_MOVE_DOWN} },
+ { "rg_next", cyclerg, 0, {.id = SWM_ARG_ID_CYCLERG_UP} },
+ { "rg_prev", cyclerg, 0, {.id = SWM_ARG_ID_CYCLERG_DOWN} },
+ { "screen_next", cyclerg, 0, {.id = SWM_ARG_ID_CYCLERG_UP} },
+ { "screen_prev", cyclerg, 0, {.id = SWM_ARG_ID_CYCLERG_DOWN} },
+ { "search_win", search_win, 0, {0} },
+ { "search_workspace", search_workspace, 0, {0} },
+ { "spawn_custom", NULL, 0, {0} },
+ { "stack_balance", stack_config, 0, {.id = SWM_ARG_ID_STACKBALANCE} },
+ { "stack_inc", stack_config, 0, {.id = SWM_ARG_ID_STACKINC} },
+ { "stack_dec", stack_config, 0, {.id = SWM_ARG_ID_STACKDEC} },
+ { "stack_reset", stack_config, 0, {.id = SWM_ARG_ID_STACKRESET} },
+ { "swap_main", swapwin, 0, {.id = SWM_ARG_ID_SWAPMAIN} },
+ { "swap_next", swapwin, 0, {.id = SWM_ARG_ID_SWAPNEXT} },
+ { "swap_prev", swapwin, 0, {.id = SWM_ARG_ID_SWAPPREV} },
+ { "uniconify", uniconify, 0, {0} },
+ { "version", version, 0, {0} },
+ { "width_grow", resize, 0, {.id = SWM_ARG_ID_WIDTHGROW} },
+ { "width_shrink", resize, 0, {.id = SWM_ARG_ID_WIDTHSHRINK} },
+ { "wind_del", wkill, 0, {.id = SWM_ARG_ID_DELETEWINDOW} },
+ { "wind_kill", wkill, 0, {.id = SWM_ARG_ID_KILLWINDOW} },
+ { "ws_1", switchws, 0, {.id = 0} },
+ { "ws_2", switchws, 0, {.id = 1} },
+ { "ws_3", switchws, 0, {.id = 2} },
+ { "ws_4", switchws, 0, {.id = 3} },
+ { "ws_5", switchws, 0, {.id = 4} },
+ { "ws_6", switchws, 0, {.id = 5} },
+ { "ws_7", switchws, 0, {.id = 6} },
+ { "ws_8", switchws, 0, {.id = 7} },
+ { "ws_9", switchws, 0, {.id = 8} },
+ { "ws_10", switchws, 0, {.id = 9} },
+ { "ws_11", switchws, 0, {.id = 10} },
+ { "ws_12", switchws, 0, {.id = 11} },
+ { "ws_13", switchws, 0, {.id = 12} },
+ { "ws_14", switchws, 0, {.id = 13} },
+ { "ws_15", switchws, 0, {.id = 14} },
+ { "ws_16", switchws, 0, {.id = 15} },
+ { "ws_17", switchws, 0, {.id = 16} },
+ { "ws_18", switchws, 0, {.id = 17} },
+ { "ws_19", switchws, 0, {.id = 18} },
+ { "ws_20", switchws, 0, {.id = 19} },
+ { "ws_21", switchws, 0, {.id = 20} },
+ { "ws_22", switchws, 0, {.id = 21} },
+ { "ws_next", cyclews, 0, {.id = SWM_ARG_ID_CYCLEWS_UP} },
+ { "ws_next_all", cyclews, 0, {.id = SWM_ARG_ID_CYCLEWS_UP_ALL} },
+ { "ws_next_move", cyclews, 0, {.id = SWM_ARG_ID_CYCLEWS_MOVE_UP} },
+ { "ws_prev", cyclews, 0, {.id = SWM_ARG_ID_CYCLEWS_DOWN} },
+ { "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} },
+ /* SWM_DEBUG actions MUST be here: */
+ { "debug_toggle", debug_toggle, 0, {0} },
+ { "dumpwins", dumpwins, 0, {0} },
+ /* ALWAYS last: */
+ { "invalid action", NULL, 0, {0} },
};
void
-update_modkey(unsigned int mod)
+update_modkey(uint16_t mod)
{
- int i;
- struct key *kp;
+ struct binding *bp;
+ /* Replace all instances of the old mod key. */
+ RB_FOREACH(bp, binding_tree, &bindings)
+ if (bp->mod & mod_key)
+ bp->mod = (bp->mod & ~mod_key) | mod;
mod_key = mod;
- RB_FOREACH(kp, key_tree, &keys)
- if (kp->mod & XCB_MOD_MASK_SHIFT)
- kp->mod = mod | XCB_MOD_MASK_SHIFT;
- else
- kp->mod = mod;
-
- for (i = 0; i < LENGTH(buttons); i++)
- if (buttons[i].mask & XCB_MOD_MASK_SHIFT)
- buttons[i].mask = mod | XCB_MOD_MASK_SHIFT;
- else
- buttons[i].mask = mod;
}
int
void
validate_spawns(void)
{
+ struct binding *bp;
struct spawn_prog *sp;
char which[PATH_MAX];
size_t i;
- struct key *kp;
-
- RB_FOREACH(kp, key_tree, &keys) {
- if (kp->funcid != KF_SPAWN_CUSTOM)
+ RB_FOREACH(bp, binding_tree, &bindings) {
+ if (bp->action != FN_SPAWN_CUSTOM)
continue;
/* find program */
- sp = spawn_find(kp->spawn_name);
+ sp = spawn_find(bp->spawn_name);
if (sp == NULL || sp->flags & SWM_SPAWN_OPTIONAL)
continue;
setconfspawn("initscr", "initscreen.sh", SWM_SPAWN_OPTIONAL);
}
-/* key bindings */
+/* bindings */
#define SWM_MODNAME_SIZE 32
#define SWM_KEY_WS "\n+ \t"
int
-parsekeys(const char *keystr, unsigned int currmod, unsigned int *mod, KeySym *ks)
+parsebinding(const char *bindstr, uint16_t *mod, enum binding_type *type,
+ uint32_t *val, uint32_t *flags)
{
char *str, *cp, *name;
- KeySym uks;
+ KeySym ks, lks, uks;
- DNPRINTF(SWM_D_KEY, "parsekeys: enter [%s]\n", keystr);
- if (mod == NULL || ks == NULL) {
- DNPRINTF(SWM_D_KEY, "parsekeys: no mod or key vars\n");
+ DNPRINTF(SWM_D_KEY, "parsebinding: enter [%s]\n", bindstr);
+ if (mod == NULL || val == NULL) {
+ DNPRINTF(SWM_D_KEY, "parsebinding: no mod or key vars\n");
return (1);
}
- if (keystr == NULL || strlen(keystr) == 0) {
- DNPRINTF(SWM_D_KEY, "parsekeys: no keystr\n");
+ if (bindstr == NULL || strlen(bindstr) == 0) {
+ DNPRINTF(SWM_D_KEY, "parsebinding: no bindstr\n");
return (1);
}
- if ((cp = str = strdup(keystr)) == NULL)
- err(1, "parsekeys: strdup");
+ if ((cp = str = strdup(bindstr)) == NULL)
+ err(1, "parsebinding: strdup");
- *ks = XCB_NO_SYMBOL;
+ *val = XCB_NO_SYMBOL;
*mod = 0;
+ *flags = 0;
+ *type = KEYBIND;
while ((name = strsep(&cp, SWM_KEY_WS)) != NULL) {
- DNPRINTF(SWM_D_KEY, "parsekeys: key [%s]\n", name);
+ DNPRINTF(SWM_D_KEY, "parsebinding: entry [%s]\n", name);
if (cp)
cp += (long)strspn(cp, SWM_KEY_WS);
if (strncasecmp(name, "MOD", SWM_MODNAME_SIZE) == 0)
- *mod |= currmod;
+ *mod |= mod_key;
else if (strncasecmp(name, "Mod1", SWM_MODNAME_SIZE) == 0)
*mod |= XCB_MOD_MASK_1;
else if (strncasecmp(name, "Mod2", SWM_MODNAME_SIZE) == 0)
- *mod += XCB_MOD_MASK_2;
+ *mod |= XCB_MOD_MASK_2;
else if (strncmp(name, "Mod3", SWM_MODNAME_SIZE) == 0)
*mod |= XCB_MOD_MASK_3;
else if (strncmp(name, "Mod4", SWM_MODNAME_SIZE) == 0)
*mod |= XCB_MOD_MASK_SHIFT;
else if (strncasecmp(name, "CONTROL", SWM_MODNAME_SIZE) == 0)
*mod |= XCB_MOD_MASK_CONTROL;
- else {
- *ks = XStringToKeysym(name);
- XConvertCase(*ks, ks, &uks);
- if (ks == XCB_NO_SYMBOL) {
+ else if (strncasecmp(name, "ANYMOD", SWM_MODNAME_SIZE) == 0)
+ *mod |= XCB_MOD_MASK_ANY;
+ else if (strncasecmp(name, "REPLAY", SWM_MODNAME_SIZE) == 0)
+ *flags |= BINDING_F_REPLAY;
+ else if (sscanf(name, "Button%u", val) == 1) {
+ DNPRINTF(SWM_D_KEY, "parsebinding: button %u\n", *val);
+ *type = BTNBIND;
+ if (*val > 255 || *val == 0) {
+ DNPRINTF(SWM_D_KEY,
+ "parsebinding: invalid button %u\n", *val);
+ return (1);
+ }
+ } else {
+ /* TODO: do this without Xlib. */
+ ks = XStringToKeysym(name);
+ if (ks == NoSymbol) {
DNPRINTF(SWM_D_KEY,
- "parsekeys: invalid key %s\n",
- name);
+ "parsebinding: invalid key %s\n", name);
free(str);
return (1);
}
+
+ XConvertCase(ks, &lks, &uks);
+ *val = (uint32_t)lks;
}
}
+ /* If ANYMOD was specified, ignore the rest. */
+ if (*mod & XCB_MOD_MASK_ANY)
+ *mod = XCB_MOD_MASK_ANY;
+
free(str);
- DNPRINTF(SWM_D_KEY, "parsekeys: leave ok\n");
+ DNPRINTF(SWM_D_KEY, "parsebinding: leave ok\n");
return (0);
}
return (strdup(str));
}
-void
-key_insert(unsigned int mod, KeySym ks, enum keyfuncid kfid,
- const char *spawn_name)
+int
+binding_cmp(struct binding *bp1, struct binding *bp2)
{
- struct key *kp;
-
- DNPRINTF(SWM_D_KEY, "key_insert: enter %s [%s]\n",
- keyfuncs[kfid].name, spawn_name);
+ if (bp1->type < bp2->type)
+ return (-1);
+ if (bp1->type > bp2->type)
+ return (1);
- if ((kp = malloc(sizeof *kp)) == NULL)
- err(1, "key_insert: malloc");
+ if (bp1->value < bp2->value)
+ return (-1);
+ if (bp1->value > bp2->value)
+ return (1);
- kp->mod = mod;
- kp->keysym = ks;
- kp->funcid = kfid;
- kp->spawn_name = strdupsafe(spawn_name);
- RB_INSERT(key_tree, &keys, kp);
+ if (bp1->mod < bp2->mod)
+ return (-1);
+ if (bp1->mod > bp2->mod)
+ return (1);
- DNPRINTF(SWM_D_KEY, "key_insert: leave\n");
+ return (0);
}
-struct key *
-key_lookup(unsigned int mod, KeySym ks)
+void
+binding_insert(uint16_t mod, enum binding_type type, uint32_t val,
+ enum actionid aid, uint32_t flags, const char *spawn_name)
{
- struct key kp;
+ struct binding *bp;
- kp.keysym = ks;
- kp.mod = mod;
+ DNPRINTF(SWM_D_KEY, "binding_insert: mod: %u, type: %d, val: %u, "
+ "action: %s(%d), spawn_name: %s\n", mod, type, val,
+ actions[aid].name, aid, spawn_name);
- return (RB_FIND(key_tree, &keys, &kp));
+ if ((bp = malloc(sizeof *bp)) == NULL)
+ err(1, "binding_insert: malloc");
+
+ bp->mod = mod;
+ bp->type = type;
+ bp->value = val;
+ bp->action = aid;
+ bp->flags = flags;
+ bp->spawn_name = strdupsafe(spawn_name);
+ RB_INSERT(binding_tree, &bindings, bp);
+
+ DNPRINTF(SWM_D_KEY, "binding_insert: leave\n");
}
-void
-key_remove(struct key *kp)
+struct binding *
+binding_lookup(uint16_t mod, enum binding_type type, uint32_t val)
{
- DNPRINTF(SWM_D_KEY, "key_remove: %s\n", keyfuncs[kp->funcid].name);
+ struct binding bp;
- RB_REMOVE(key_tree, &keys, kp);
- free(kp->spawn_name);
- free(kp);
+ bp.mod = mod;
+ bp.type = type;
+ bp.value = val;
- DNPRINTF(SWM_D_KEY, "key_remove: leave\n");
+ return (RB_FIND(binding_tree, &bindings, &bp));
}
void
-key_replace(struct key *kp, unsigned int mod, KeySym ks, enum keyfuncid kfid,
- const char *spawn_name)
+binding_remove(struct binding *bp)
{
- DNPRINTF(SWM_D_KEY, "key_replace: %s [%s]\n", keyfuncs[kp->funcid].name,
- spawn_name);
+ DNPRINTF(SWM_D_KEY, "binding_remove: mod: %u, type: %d, val: %u, "
+ "action: %s(%d), spawn_name: %s\n", bp->mod, bp->type, bp->value,
+ actions[bp->action].name, bp->action, bp->spawn_name);
- key_remove(kp);
- key_insert(mod, ks, kfid, spawn_name);
+ RB_REMOVE(binding_tree, &bindings, bp);
+ free(bp->spawn_name);
+ free(bp);
- DNPRINTF(SWM_D_KEY, "key_replace: leave\n");
+ DNPRINTF(SWM_D_KEY, "binding_remove: leave\n");
}
void
-setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid,
- const char *spawn_name)
+setbinding(uint16_t mod, enum binding_type type, uint32_t val,
+ enum actionid aid, uint32_t flags, const char *spawn_name)
{
- struct key *kp;
+ struct binding *bp;
- DNPRINTF(SWM_D_KEY, "setkeybinding: enter %s [%s]\n",
- keyfuncs[kfid].name, spawn_name);
+ DNPRINTF(SWM_D_KEY, "setbinding: enter %s [%s]\n",
+ actions[aid].name, spawn_name);
- if ((kp = key_lookup(mod, ks)) != NULL) {
- if (kfid == KF_INVALID)
- key_remove(kp);
- else
- key_replace(kp, mod, ks, kfid, spawn_name);
- DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n");
- return;
- }
- if (kfid == KF_INVALID) {
- warnx("bind: Key combination already unbound.");
- DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n");
- return;
- }
+ /* Unbind any existing. Loop is to handle MOD_MASK_ANY. */
+ while ((bp = binding_lookup(mod, type, val)))
+ binding_remove(bp);
- key_insert(mod, ks, kfid, spawn_name);
- DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n");
+ if (aid != FN_INVALID)
+ binding_insert(mod, type, val, aid, flags, spawn_name);
+
+ DNPRINTF(SWM_D_KEY, "setbinding: leave\n");
}
int
setconfbinding(const char *selector, const char *value, int flags)
{
- enum keyfuncid kfid;
- unsigned int mod;
- KeySym ks;
struct spawn_prog *sp;
+ uint32_t keybtn, opts;
+ uint16_t mod;
+ enum actionid aid;
+ enum binding_type type;
/* suppress unused warning since var is needed */
(void)flags;
"value: [%s]\n", selector, value);
if (selector == NULL || strlen(selector) == 0) {
DNPRINTF(SWM_D_KEY, "setconfbinding: unbind %s\n", value);
- if (parsekeys(value, mod_key, &mod, &ks) == 0) {
- kfid = KF_INVALID;
- setkeybinding(mod, ks, kfid, NULL);
+ if (parsebinding(value, &mod, &type, &keybtn, &opts) == 0) {
+ setbinding(mod, type, keybtn, FN_INVALID, opts, NULL);
return (0);
} else
return (1);
}
/* search by key function name */
- for (kfid = 0; kfid < KF_INVALID; (kfid)++) {
- if (strncasecmp(selector, keyfuncs[kfid].name,
+ for (aid = 0; aid < FN_INVALID; aid++) {
+ if (strncasecmp(selector, actions[aid].name,
SWM_FUNCNAME_LEN) == 0) {
DNPRINTF(SWM_D_KEY, "setconfbinding: %s: match "
- "keyfunc\n", selector);
- if (parsekeys(value, mod_key, &mod, &ks) == 0) {
- setkeybinding(mod, ks, kfid, NULL);
+ "action\n", selector);
+ if (parsebinding(value, &mod, &type, &keybtn,
+ &opts) == 0) {
+ setbinding(mod, type, keybtn, aid, opts, NULL);
return (0);
} else
return (1);
if ((sp = spawn_find(selector)) != NULL) {
DNPRINTF(SWM_D_KEY, "setconfbinding: %s: match "
"spawn\n", selector);
- if (parsekeys(value, mod_key, &mod, &ks) == 0) {
- setkeybinding(mod, ks, KF_SPAWN_CUSTOM,
+ if (parsebinding(value, &mod, &type, &keybtn, &opts) == 0) {
+ setbinding(mod, type, keybtn, FN_SPAWN_CUSTOM, opts,
sp->name);
return (0);
} else
return (1);
}
-void
-setup_keys(void)
-{
-#define MODKEY_SHIFT MODKEY | XCB_MOD_MASK_SHIFT
- setkeybinding(MODKEY, XK_b, KF_BAR_TOGGLE, NULL);
- setkeybinding(MODKEY_SHIFT, XK_b, KF_BAR_TOGGLE_WS,NULL);
- setkeybinding(MODKEY, XK_v, KF_BUTTON2, NULL);
- setkeybinding(MODKEY, XK_space, KF_CYCLE_LAYOUT,NULL);
- setkeybinding(MODKEY_SHIFT, XK_backslash, KF_FLIP_LAYOUT, NULL);
- setkeybinding(MODKEY, XK_t, KF_FLOAT_TOGGLE,NULL);
- setkeybinding(MODKEY, XK_m, KF_FOCUS_MAIN, NULL);
- setkeybinding(MODKEY, XK_j, KF_FOCUS_NEXT, NULL);
- setkeybinding(MODKEY, XK_Tab, KF_FOCUS_NEXT, NULL);
- setkeybinding(MODKEY, XK_k, KF_FOCUS_PREV, NULL);
- setkeybinding(MODKEY_SHIFT, XK_Tab, KF_FOCUS_PREV, NULL);
- setkeybinding(MODKEY, XK_u, KF_FOCUS_URGENT,NULL);
- setkeybinding(MODKEY, XK_e, KF_MAXIMIZE_TOGGLE,NULL);
- setkeybinding(MODKEY_SHIFT, XK_equal, KF_HEIGHT_GROW,NULL);
- setkeybinding(MODKEY_SHIFT, XK_minus, KF_HEIGHT_SHRINK,NULL);
- setkeybinding(MODKEY, XK_w, KF_ICONIFY, NULL);
- setkeybinding(MODKEY, XK_h, KF_MASTER_SHRINK, NULL);
- setkeybinding(MODKEY, XK_l, KF_MASTER_GROW, NULL);
- setkeybinding(MODKEY, XK_comma, KF_MASTER_ADD, NULL);
- setkeybinding(MODKEY, XK_period, KF_MASTER_DEL, NULL);
- setkeybinding(MODKEY_SHIFT, XK_bracketright,KF_MOVE_DOWN,NULL);
- setkeybinding(MODKEY, XK_bracketleft, KF_MOVE_LEFT,NULL);
- setkeybinding(MODKEY, XK_bracketright,KF_MOVE_RIGHT,NULL);
- setkeybinding(MODKEY_SHIFT, XK_bracketleft, KF_MOVE_UP, NULL);
- setkeybinding(MODKEY_SHIFT, XK_KP_End, KF_MVRG_1, NULL);
- setkeybinding(MODKEY_SHIFT, XK_KP_Down, KF_MVRG_2, NULL);
- setkeybinding(MODKEY_SHIFT, XK_KP_Next, KF_MVRG_3, NULL);
- setkeybinding(MODKEY_SHIFT, XK_KP_Left, KF_MVRG_4, NULL);
- setkeybinding(MODKEY_SHIFT, XK_KP_Begin, KF_MVRG_5, NULL);
- setkeybinding(MODKEY_SHIFT, XK_KP_Right, KF_MVRG_6, NULL);
- setkeybinding(MODKEY_SHIFT, XK_KP_Home, KF_MVRG_7, NULL);
- setkeybinding(MODKEY_SHIFT, XK_KP_Up, KF_MVRG_8, NULL);
- setkeybinding(MODKEY_SHIFT, XK_KP_Prior, KF_MVRG_9, NULL);
- setkeybinding(MODKEY_SHIFT, XK_1, KF_MVWS_1, NULL);
- setkeybinding(MODKEY_SHIFT, XK_2, KF_MVWS_2, NULL);
- setkeybinding(MODKEY_SHIFT, XK_3, KF_MVWS_3, NULL);
- setkeybinding(MODKEY_SHIFT, XK_4, KF_MVWS_4, NULL);
- setkeybinding(MODKEY_SHIFT, XK_5, KF_MVWS_5, NULL);
- setkeybinding(MODKEY_SHIFT, XK_6, KF_MVWS_6, NULL);
- setkeybinding(MODKEY_SHIFT, XK_7, KF_MVWS_7, NULL);
- setkeybinding(MODKEY_SHIFT, XK_8, KF_MVWS_8, NULL);
- setkeybinding(MODKEY_SHIFT, XK_9, KF_MVWS_9, NULL);
- setkeybinding(MODKEY_SHIFT, XK_0, KF_MVWS_10, NULL);
- setkeybinding(MODKEY_SHIFT, XK_F1, KF_MVWS_11, NULL);
- setkeybinding(MODKEY_SHIFT, XK_F2, KF_MVWS_12, NULL);
- setkeybinding(MODKEY_SHIFT, XK_F3, KF_MVWS_13, NULL);
- setkeybinding(MODKEY_SHIFT, XK_F4, KF_MVWS_14, NULL);
- setkeybinding(MODKEY_SHIFT, XK_F5, KF_MVWS_15, NULL);
- setkeybinding(MODKEY_SHIFT, XK_F6, KF_MVWS_16, NULL);
- setkeybinding(MODKEY_SHIFT, XK_F7, KF_MVWS_17, NULL);
- setkeybinding(MODKEY_SHIFT, XK_F8, KF_MVWS_18, NULL);
- setkeybinding(MODKEY_SHIFT, XK_F9, KF_MVWS_19, NULL);
- setkeybinding(MODKEY_SHIFT, XK_F10, KF_MVWS_20, NULL);
- setkeybinding(MODKEY_SHIFT, XK_F11, KF_MVWS_21, NULL);
- setkeybinding(MODKEY_SHIFT, XK_F12, KF_MVWS_22, NULL);
- setkeybinding(MODKEY_SHIFT, XK_slash, KF_NAME_WORKSPACE,NULL);
- setkeybinding(MODKEY_SHIFT, XK_q, KF_QUIT, NULL);
- setkeybinding(MODKEY_SHIFT, XK_r, KF_RAISE_TOGGLE,NULL);
- setkeybinding(MODKEY, XK_q, KF_RESTART, NULL);
- setkeybinding(MODKEY, XK_KP_End, KF_RG_1, NULL);
- setkeybinding(MODKEY, XK_KP_Down, KF_RG_2, NULL);
- setkeybinding(MODKEY, XK_KP_Next, KF_RG_3, NULL);
- setkeybinding(MODKEY, XK_KP_Left, KF_RG_4, NULL);
- setkeybinding(MODKEY, XK_KP_Begin, KF_RG_5, NULL);
- setkeybinding(MODKEY, XK_KP_Right, KF_RG_6, NULL);
- setkeybinding(MODKEY, XK_KP_Home, KF_RG_7, NULL);
- setkeybinding(MODKEY, XK_KP_Up, KF_RG_8, NULL);
- setkeybinding(MODKEY, XK_KP_Prior, KF_RG_9, NULL);
- setkeybinding(MODKEY_SHIFT, XK_Right, KF_RG_NEXT, NULL);
- setkeybinding(MODKEY_SHIFT, XK_Left, KF_RG_PREV, NULL);
- setkeybinding(MODKEY, XK_f, KF_SEARCH_WIN, NULL);
- setkeybinding(MODKEY, XK_slash, KF_SEARCH_WORKSPACE,NULL);
- setkeybinding(MODKEY_SHIFT, XK_i, KF_SPAWN_CUSTOM,"initscr");
- setkeybinding(MODKEY_SHIFT, XK_Delete, KF_SPAWN_CUSTOM,"lock");
- setkeybinding(MODKEY, XK_p, KF_SPAWN_CUSTOM,"menu");
- setkeybinding(MODKEY, XK_s, KF_SPAWN_CUSTOM,"screenshot_all");
- setkeybinding(MODKEY_SHIFT, XK_s, KF_SPAWN_CUSTOM,"screenshot_wind");
- setkeybinding(MODKEY_SHIFT, XK_Return, KF_SPAWN_CUSTOM,"term");
- setkeybinding(MODKEY_SHIFT, XK_comma, KF_STACK_INC, NULL);
- setkeybinding(MODKEY_SHIFT, XK_period, KF_STACK_DEC, NULL);
- setkeybinding(MODKEY_SHIFT, XK_space, KF_STACK_RESET, NULL);
- setkeybinding(MODKEY, XK_Return, KF_SWAP_MAIN, NULL);
- setkeybinding(MODKEY_SHIFT, XK_j, KF_SWAP_NEXT, NULL);
- setkeybinding(MODKEY_SHIFT, XK_k, KF_SWAP_PREV, NULL);
- setkeybinding(MODKEY_SHIFT, XK_w, KF_UNICONIFY, NULL);
- setkeybinding(MODKEY_SHIFT, XK_v, KF_VERSION, NULL);
- setkeybinding(MODKEY, XK_equal, KF_WIDTH_GROW, NULL);
- setkeybinding(MODKEY, XK_minus, KF_WIDTH_SHRINK,NULL);
- setkeybinding(MODKEY, XK_x, KF_WIND_DEL, NULL);
- setkeybinding(MODKEY_SHIFT, XK_x, KF_WIND_KILL, NULL);
- setkeybinding(MODKEY, XK_1, KF_WS_1, NULL);
- setkeybinding(MODKEY, XK_2, KF_WS_2, NULL);
- setkeybinding(MODKEY, XK_3, KF_WS_3, NULL);
- setkeybinding(MODKEY, XK_4, KF_WS_4, NULL);
- setkeybinding(MODKEY, XK_5, KF_WS_5, NULL);
- setkeybinding(MODKEY, XK_6, KF_WS_6, NULL);
- setkeybinding(MODKEY, XK_7, KF_WS_7, NULL);
- setkeybinding(MODKEY, XK_8, KF_WS_8, NULL);
- setkeybinding(MODKEY, XK_9, KF_WS_9, NULL);
- setkeybinding(MODKEY, XK_0, KF_WS_10, NULL);
- setkeybinding(MODKEY, XK_F1, KF_WS_11, NULL);
- setkeybinding(MODKEY, XK_F2, KF_WS_12, NULL);
- setkeybinding(MODKEY, XK_F3, KF_WS_13, NULL);
- setkeybinding(MODKEY, XK_F4, KF_WS_14, NULL);
- setkeybinding(MODKEY, XK_F5, KF_WS_15, NULL);
- setkeybinding(MODKEY, XK_F6, KF_WS_16, NULL);
- setkeybinding(MODKEY, XK_F7, KF_WS_17, NULL);
- setkeybinding(MODKEY, XK_F8, KF_WS_18, NULL);
- setkeybinding(MODKEY, XK_F9, KF_WS_19, NULL);
- setkeybinding(MODKEY, XK_F10, KF_WS_20, NULL);
- setkeybinding(MODKEY, XK_F11, KF_WS_21, NULL);
- setkeybinding(MODKEY, XK_F12, KF_WS_22, NULL);
- setkeybinding(MODKEY, XK_Right, KF_WS_NEXT, NULL);
- setkeybinding(MODKEY, XK_Left, KF_WS_PREV, NULL);
- setkeybinding(MODKEY, XK_Up, KF_WS_NEXT_ALL, NULL);
- setkeybinding(MODKEY, XK_Down, KF_WS_PREV_ALL, NULL);
- setkeybinding(MODKEY_SHIFT, XK_Up, KF_WS_NEXT_MOVE,NULL);
- setkeybinding(MODKEY_SHIFT, XK_Down, KF_WS_PREV_MOVE,NULL);
- setkeybinding(MODKEY, XK_a, KF_WS_PRIOR, NULL);
+#define MODSHIFT MODKEY | XCB_MOD_MASK_SHIFT
+void
+setup_keybindings(void)
+{
+#define BINDKEY(m, k, a) setbinding(m, KEYBIND, k, a, 0, NULL)
+#define BINDKEYSPAWN(m, k, s) setbinding(m, KEYBIND, k, FN_SPAWN_CUSTOM, 0, s)
+ BINDKEY(MODKEY, XK_b, FN_BAR_TOGGLE);
+ BINDKEY(MODSHIFT, XK_b, FN_BAR_TOGGLE_WS);
+ BINDKEY(MODKEY, XK_b, FN_BAR_TOGGLE);
+ BINDKEY(MODSHIFT, XK_b, FN_BAR_TOGGLE_WS);
+ BINDKEY(MODKEY, XK_v, FN_BUTTON2);
+ BINDKEY(MODKEY, XK_space, FN_CYCLE_LAYOUT);
+ BINDKEY(MODSHIFT, XK_backslash, FN_FLIP_LAYOUT);
+ BINDKEY(MODKEY, XK_t, FN_FLOAT_TOGGLE);
+ BINDKEY(MODKEY, XK_m, FN_FOCUS_MAIN);
+ BINDKEY(MODKEY, XK_j, FN_FOCUS_NEXT);
+ BINDKEY(MODKEY, XK_Tab, FN_FOCUS_NEXT);
+ BINDKEY(MODKEY, XK_k, FN_FOCUS_PREV);
+ BINDKEY(MODSHIFT, XK_Tab, FN_FOCUS_PREV);
+ BINDKEY(MODKEY, XK_u, FN_FOCUS_URGENT);
+ BINDKEY(MODKEY, XK_e, FN_MAXIMIZE_TOGGLE);
+ BINDKEY(MODSHIFT, XK_equal, FN_HEIGHT_GROW);
+ BINDKEY(MODSHIFT, XK_minus, FN_HEIGHT_SHRINK);
+ BINDKEY(MODKEY, XK_w, FN_ICONIFY);
+ BINDKEY(MODKEY, XK_h, FN_MASTER_SHRINK);
+ BINDKEY(MODKEY, XK_l, FN_MASTER_GROW);
+ BINDKEY(MODKEY, XK_comma, FN_MASTER_ADD);
+ BINDKEY(MODKEY, XK_period, FN_MASTER_DEL);
+ BINDKEY(MODSHIFT, XK_bracketright, FN_MOVE_DOWN);
+ BINDKEY(MODKEY, XK_bracketleft, FN_MOVE_LEFT);
+ BINDKEY(MODKEY, XK_bracketright, FN_MOVE_RIGHT);
+ BINDKEY(MODSHIFT, XK_bracketleft, FN_MOVE_UP);
+ BINDKEY(MODSHIFT, XK_KP_End, FN_MVRG_1);
+ BINDKEY(MODSHIFT, XK_KP_Down, FN_MVRG_2);
+ BINDKEY(MODSHIFT, XK_KP_Next, FN_MVRG_3);
+ BINDKEY(MODSHIFT, XK_KP_Left, FN_MVRG_4);
+ BINDKEY(MODSHIFT, XK_KP_Begin, FN_MVRG_5);
+ BINDKEY(MODSHIFT, XK_KP_Right, FN_MVRG_6);
+ BINDKEY(MODSHIFT, XK_KP_Home, FN_MVRG_7);
+ BINDKEY(MODSHIFT, XK_KP_Up, FN_MVRG_8);
+ BINDKEY(MODSHIFT, XK_KP_Prior, FN_MVRG_9);
+ BINDKEY(MODSHIFT, XK_1, FN_MVWS_1);
+ BINDKEY(MODSHIFT, XK_2, FN_MVWS_2);
+ BINDKEY(MODSHIFT, XK_3, FN_MVWS_3);
+ BINDKEY(MODSHIFT, XK_4, FN_MVWS_4);
+ BINDKEY(MODSHIFT, XK_5, FN_MVWS_5);
+ BINDKEY(MODSHIFT, XK_6, FN_MVWS_6);
+ BINDKEY(MODSHIFT, XK_7, FN_MVWS_7);
+ BINDKEY(MODSHIFT, XK_8, FN_MVWS_8);
+ BINDKEY(MODSHIFT, XK_9, FN_MVWS_9);
+ BINDKEY(MODSHIFT, XK_0, FN_MVWS_10);
+ BINDKEY(MODSHIFT, XK_F1, FN_MVWS_11);
+ BINDKEY(MODSHIFT, XK_F2, FN_MVWS_12);
+ BINDKEY(MODSHIFT, XK_F3, FN_MVWS_13);
+ BINDKEY(MODSHIFT, XK_F4, FN_MVWS_14);
+ BINDKEY(MODSHIFT, XK_F5, FN_MVWS_15);
+ BINDKEY(MODSHIFT, XK_F6, FN_MVWS_16);
+ BINDKEY(MODSHIFT, XK_F7, FN_MVWS_17);
+ BINDKEY(MODSHIFT, XK_F8, FN_MVWS_18);
+ BINDKEY(MODSHIFT, XK_F9, FN_MVWS_19);
+ BINDKEY(MODSHIFT, XK_F10, FN_MVWS_20);
+ BINDKEY(MODSHIFT, XK_F11, FN_MVWS_21);
+ BINDKEY(MODSHIFT, XK_F12, FN_MVWS_22);
+ BINDKEY(MODSHIFT, XK_slash, FN_NAME_WORKSPACE);
+ BINDKEY(MODSHIFT, XK_q, FN_QUIT);
+ BINDKEY(MODSHIFT, XK_r, FN_RAISE_TOGGLE);
+ BINDKEY(MODKEY, XK_q, FN_RESTART);
+ BINDKEY(MODKEY, XK_KP_End, FN_RG_1);
+ BINDKEY(MODKEY, XK_KP_Down, FN_RG_2);
+ BINDKEY(MODKEY, XK_KP_Next, FN_RG_3);
+ BINDKEY(MODKEY, XK_KP_Left, FN_RG_4);
+ BINDKEY(MODKEY, XK_KP_Begin, FN_RG_5);
+ BINDKEY(MODKEY, XK_KP_Right, FN_RG_6);
+ BINDKEY(MODKEY, XK_KP_Home, FN_RG_7);
+ BINDKEY(MODKEY, XK_KP_Up, FN_RG_8);
+ BINDKEY(MODKEY, XK_KP_Prior, FN_RG_9);
+ BINDKEY(MODSHIFT, XK_Right, FN_RG_NEXT);
+ BINDKEY(MODSHIFT, XK_Left, FN_RG_PREV);
+ BINDKEY(MODKEY, XK_f, FN_SEARCH_WIN);
+ BINDKEY(MODKEY, XK_slash, FN_SEARCH_WORKSPACE);
+ BINDKEYSPAWN(MODSHIFT, XK_i, "initscr");
+ BINDKEYSPAWN(MODSHIFT, XK_Delete, "lock");
+ BINDKEYSPAWN(MODKEY, XK_p, "menu");
+ BINDKEYSPAWN(MODKEY, XK_s, "screenshot_all");
+ BINDKEYSPAWN(MODSHIFT, XK_s, "screenshot_wind");
+ BINDKEYSPAWN(MODSHIFT, XK_Return, "term");
+ BINDKEY(MODSHIFT, XK_comma, FN_STACK_INC);
+ BINDKEY(MODSHIFT, XK_period, FN_STACK_DEC);
+ BINDKEY(MODSHIFT, XK_space, FN_STACK_RESET);
+ BINDKEY(MODKEY, XK_Return, FN_SWAP_MAIN);
+ BINDKEY(MODSHIFT, XK_j, FN_SWAP_NEXT);
+ BINDKEY(MODSHIFT, XK_k, FN_SWAP_PREV);
+ BINDKEY(MODSHIFT, XK_w, FN_UNICONIFY);
+ BINDKEY(MODSHIFT, XK_v, FN_VERSION);
+ BINDKEY(MODKEY, XK_equal, FN_WIDTH_GROW);
+ BINDKEY(MODKEY, XK_minus, FN_WIDTH_SHRINK);
+ BINDKEY(MODKEY, XK_x, FN_WIND_DEL);
+ BINDKEY(MODSHIFT, XK_x, FN_WIND_KILL);
+ BINDKEY(MODKEY, XK_1, FN_WS_1);
+ BINDKEY(MODKEY, XK_2, FN_WS_2);
+ BINDKEY(MODKEY, XK_3, FN_WS_3);
+ BINDKEY(MODKEY, XK_4, FN_WS_4);
+ BINDKEY(MODKEY, XK_5, FN_WS_5);
+ BINDKEY(MODKEY, XK_6, FN_WS_6);
+ BINDKEY(MODKEY, XK_7, FN_WS_7);
+ BINDKEY(MODKEY, XK_8, FN_WS_8);
+ BINDKEY(MODKEY, XK_9, FN_WS_9);
+ BINDKEY(MODKEY, XK_0, FN_WS_10);
+ BINDKEY(MODKEY, XK_F1, FN_WS_11);
+ BINDKEY(MODKEY, XK_F2, FN_WS_12);
+ BINDKEY(MODKEY, XK_F3, FN_WS_13);
+ BINDKEY(MODKEY, XK_F4, FN_WS_14);
+ BINDKEY(MODKEY, XK_F5, FN_WS_15);
+ BINDKEY(MODKEY, XK_F6, FN_WS_16);
+ BINDKEY(MODKEY, XK_F7, FN_WS_17);
+ BINDKEY(MODKEY, XK_F8, FN_WS_18);
+ BINDKEY(MODKEY, XK_F9, FN_WS_19);
+ BINDKEY(MODKEY, XK_F10, FN_WS_20);
+ BINDKEY(MODKEY, XK_F11, FN_WS_21);
+ BINDKEY(MODKEY, XK_F12, FN_WS_22);
+ BINDKEY(MODKEY, XK_Right, FN_WS_NEXT);
+ BINDKEY(MODKEY, XK_Left, FN_WS_PREV);
+ BINDKEY(MODKEY, XK_Up, FN_WS_NEXT_ALL);
+ BINDKEY(MODKEY, XK_Down, FN_WS_PREV_ALL);
+ BINDKEY(MODSHIFT, XK_Up, FN_WS_NEXT_MOVE);
+ BINDKEY(MODSHIFT, XK_Down, FN_WS_PREV_MOVE);
+ BINDKEY(MODKEY, XK_a, FN_WS_PRIOR);
#ifdef SWM_DEBUG
- setkeybinding(MODKEY_SHIFT, XK_d, KF_DUMPWINS, NULL);
+ BINDKEY(MODKEY, XK_d, FN_DEBUG_TOGGLE);
+ BINDKEY(MODSHIFT, XK_d, FN_DUMPWINS);
#endif
-#undef MODKEY_SHIFT
+#undef BINDKEY
+#undef BINDKEYSPAWN
+}
+
+void
+setup_btnbindings(void)
+{
+ setbinding(ANYMOD, BTNBIND, XCB_BUTTON_INDEX_1, FN_FOCUS,
+ BINDING_F_REPLAY, NULL);
+ setbinding(MODKEY, BTNBIND, XCB_BUTTON_INDEX_3, FN_RESIZE, 0, NULL);
+ setbinding(MODSHIFT, BTNBIND, XCB_BUTTON_INDEX_3, FN_RESIZE_CENTERED, 0,
+ NULL);
+ setbinding(MODKEY, BTNBIND, XCB_BUTTON_INDEX_1, FN_MOVE, 0, NULL);
+}
+#undef MODSHIFT
+
+void
+clear_bindings(void)
+{
+ struct binding *bp;
+
+ while ((bp = RB_ROOT(&bindings)))
+ binding_remove(bp);
}
void
-clear_keys(void)
+clear_keybindings(void)
{
- struct key *kp;
+ struct binding *bp, *bptmp;
- while (RB_EMPTY(&keys) == 0) {
- kp = RB_ROOT(&keys);
- key_remove(kp);
+ RB_FOREACH_SAFE(bp, binding_tree, &bindings, bptmp) {
+ if (bp->type != KEYBIND)
+ continue;
+ binding_remove(bp);
}
}
keymapping_file = expand_tilde(value);
- clear_keys();
+ clear_keybindings();
/* load new key bindings; if it fails, revert to default bindings */
if (conf_load(keymapping_file, SWM_CONF_KEYMAPPING)) {
- clear_keys();
- setup_keys();
+ clear_keybindings();
+ setup_keybindings();
}
free(keymapping_file);
void
grabkeys(void)
{
- struct key *kp;
+ struct binding *bp;
int num_screens, k, j;
- unsigned int modifiers[4];
+ uint16_t modifiers[4];
xcb_keycode_t *code;
DNPRINTF(SWM_D_MISC, "grabkeys\n");
continue;
xcb_ungrab_key(conn, XCB_GRAB_ANY, screens[k].root,
XCB_MOD_MASK_ANY);
- RB_FOREACH(kp, key_tree, &keys) {
- /* Skip unused ws binds. */
- if ((int)kp->funcid > KF_WS_1 + workspace_limit - 1 &&
- kp->funcid <= KF_WS_22)
+ RB_FOREACH(bp, binding_tree, &bindings) {
+ if (bp->type != KEYBIND)
continue;
- /* Skip unused mvws binds. */
- if ((int)kp->funcid > KF_MVWS_1 + workspace_limit - 1 &&
- kp->funcid <= KF_MVWS_22)
+ /* If there is a catch-all, only bind that. */
+ if ((binding_lookup(ANYMOD, KEYBIND, bp->value)) &&
+ bp->mod != ANYMOD)
continue;
- if ((code = xcb_key_symbols_get_keycode(syms,
- kp->keysym))) {
- for (j = 0; j < LENGTH(modifiers); j++)
+ /* Skip unused ws binds. */
+ if ((int)bp->action > FN_WS_1 + workspace_limit - 1 &&
+ bp->action <= FN_WS_22)
+ continue;
+
+ /* Skip unused mvws binds. */
+ if ((int)bp->action > FN_MVWS_1 + workspace_limit - 1 &&
+ bp->action <= FN_MVWS_22)
+ continue;
+
+ if ((code = xcb_key_symbols_get_keycode(syms,
+ bp->value)) == NULL)
+ continue;
+
+ if (bp->mod == XCB_MOD_MASK_ANY) {
+ /* All modifiers are grabbed in one pass. */
+ DNPRINTF(SWM_D_MOUSE, "grabkeys: grab, "
+ "key: %u, modifiers: %d\n", bp->value,
+ bp->mod);
+ xcb_grab_key(conn, 1, screens[k].root,
+ bp->mod, *code, XCB_GRAB_MODE_ASYNC,
+ XCB_GRAB_MODE_SYNC);
+ } else {
+ /* Need to grab each modifier permutation. */
+ for (j = 0; j < LENGTH(modifiers); j++) {
+ DNPRINTF(SWM_D_MOUSE, "grabkeys: grab, "
+ "key: %u, modifiers: %d\n",
+ bp->value, bp->mod | modifiers[j]);
xcb_grab_key(conn, 1,
screens[k].root,
- kp->mod | modifiers[j],
- *code, XCB_GRAB_MODE_SYNC,
+ bp->mod | modifiers[j],
+ *code, XCB_GRAB_MODE_ASYNC,
XCB_GRAB_MODE_SYNC);
- free(code);
+ }
}
+ free(code);
}
}
}
void
-grabbuttons(struct ws_win *win)
+grabbuttons(void)
{
- unsigned int modifiers[4];
- int i, j;
+ struct binding *bp;
+ int num_screens, i, k;
+ uint16_t modifiers[4];
- DNPRINTF(SWM_D_MOUSE, "grabbuttons: win %#x\n", win->id);
+ DNPRINTF(SWM_D_MOUSE, "grabbuttons\n");
updatenumlockmask();
modifiers[0] = 0;
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]);
+ num_screens = get_screen_count();
+ for (k = 0; k < num_screens; k++) {
+ if (TAILQ_EMPTY(&screens[k].rl))
+ continue;
+ xcb_ungrab_button(conn, XCB_BUTTON_INDEX_ANY, screens[k].root,
+ XCB_MOD_MASK_ANY);
+ RB_FOREACH(bp, binding_tree, &bindings) {
+ if (bp->type != BTNBIND)
+ continue;
+
+ /* If there is a catch-all, only bind that. */
+ if ((binding_lookup(ANYMOD, BTNBIND, bp->value)) &&
+ bp->mod != ANYMOD)
+ continue;
+
+ /* Skip unused ws binds. */
+ if ((int)bp->action > FN_WS_1 + workspace_limit - 1 &&
+ bp->action <= FN_WS_22)
+ continue;
+
+ /* Skip unused mvws binds. */
+ if ((int)bp->action > FN_MVWS_1 + workspace_limit - 1 &&
+ bp->action <= FN_MVWS_22)
+ continue;
+
+ if (bp->mod == XCB_MOD_MASK_ANY) {
+ /* All modifiers are grabbed in one pass. */
+ DNPRINTF(SWM_D_MOUSE, "grabbuttons: grab, "
+ "button: %u, modifiers: %d\n", bp->value,
+ bp->mod);
+ xcb_grab_button(conn, 0, screens[k].root,
+ BUTTONMASK, XCB_GRAB_MODE_SYNC,
+ XCB_GRAB_MODE_ASYNC, XCB_WINDOW_NONE,
+ XCB_CURSOR_NONE, bp->value, bp->mod);
+ } else {
+ /* Need to grab each modifier permutation. */
+ for (i = 0; i < LENGTH(modifiers); ++i) {
+ DNPRINTF(SWM_D_MOUSE, "grabbuttons: "
+ "grab, button: %u, modifiers: %u\n",
+ bp->value, bp->mod | modifiers[i]);
+ xcb_grab_button(conn, 0,
+ screens[k].root, BUTTONMASK,
+ XCB_GRAB_MODE_SYNC,
+ XCB_GRAB_MODE_ASYNC,
+ XCB_WINDOW_NONE,
+ XCB_CURSOR_NONE, bp->value,
+ bp->mod | modifiers[i]);
+ }
+ }
+ }
+ }
}
const char *quirkname[] = {
if (quirk == NULL || qstr == NULL)
return (1);
- if ((str = strdup(qstr)) == NULL)
+ if ((cp = str = strdup(qstr)) == NULL)
err(1, "parsequirks: strdup");
- cp = str;
*quirk = 0;
while ((name = strsep(&cp, SWM_Q_DELIM)) != NULL) {
if (cp)
{
struct workspace *ws;
int i, ws_id, num_screens;
- char *b, *str, s[1024];
+ char *b, *str, *sp, s[1024];
switch (flags) {
case SWM_S_BAR_ACTION:
if (!bar_font_legacy)
break;
- if ((str = strdup(value)) == NULL)
+ if ((sp = str = strdup(value)) == NULL)
err(1, "setconfvalue: strdup");
/* If there are any non-XLFD entries, switch to Xft mode. */
- while ((b = strsep(&str, ",")) != NULL) {
+ while ((b = strsep(&sp, ",")) != NULL) {
if (*b == '\0')
continue;
if (!isxlfd(b)) {
{
int ws_id;
char s[1024];
- char *ap, *sp;
+ char *ap, *sp, *str;
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);
+ sp = str = 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");
_exit(1);
}
free(a.argv);
+ free(str);
/* parent */
p = find_pid(pid);
if (line)
free(line);
fclose(config);
+
DNPRINTF(SWM_D_CONF, "conf_load: end\n");
return (0);
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,
/* Get WM_PROTOCOLS. */
get_wm_protocols(win);
+#ifdef SWM_DEBUG
+ /* Must be after getting WM_HINTS and WM_PROTOCOLS. */
+ DNPRINTF(SWM_D_FOCUS, "manage_window: input_model: %s\n",
+ get_win_input_model(win));
+#endif
+
/* Set initial quirks based on EWMH. */
ewmh_autoquirk(win);
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);
- grabbuttons(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
free_window(struct ws_win *win)
{
- DNPRINTF(SWM_D_MISC, "free_window: win %#x\n", win->id);
+ DNPRINTF(SWM_D_MISC, "free_window: win %#x\n", WINID(win));
if (win == NULL)
return;
- TAILQ_REMOVE(&win->ws->unmanagedlist, win, entry);
-
xcb_icccm_get_wm_class_reply_wipe(&win->ch);
- kill_refs(win);
-
/* paint memory */
memset(win, 0xff, sizeof *win); /* XXX kill later */
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;
- DNPRINTF(SWM_D_MISC, "unmanage_window: win %#x\n", win->id);
-
- 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)
{
void
keypress(xcb_key_press_event_t *e)
{
+ struct action *ap;
+ struct binding *bp;
xcb_keysym_t keysym;
- struct key *kp;
+ bool replay = true;
+
+ last_event_time = e->time;
keysym = xcb_key_press_lookup_keysym(syms, e, 0);
DNPRINTF(SWM_D_EVENT, "keypress: 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));
+ "state: %u, cleaned: %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, CLEANMASK(e->state),
+ YESNO(e->same_screen));
+
+ bp = binding_lookup(CLEANMASK(e->state), KEYBIND, keysym);
+ if (bp == NULL) {
+ /* Look for catch-all. */
+ if ((bp = binding_lookup(ANYMOD, KEYBIND, keysym)) == NULL)
+ goto out;
+ }
+
+ replay = bp->flags & BINDING_F_REPLAY;
- if ((kp = key_lookup(CLEANMASK(e->state), keysym)) == NULL)
+ if ((ap = &actions[bp->action]) == NULL)
goto out;
- last_event_time = e->time;
+ if (bp->action == FN_SPAWN_CUSTOM)
+ spawn_custom(root_to_region(e->root, SWM_CK_ALL), &ap->args,
+ bp->spawn_name);
+ else if (ap->func)
+ ap->func(bp, root_to_region(e->root, SWM_CK_ALL), &ap->args);
- if (kp->funcid == KF_SPAWN_CUSTOM)
- 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, SWM_CK_ALL),
- &(keyfuncs[kp->funcid].args));
+ replay = replay && !(ap->flags & FN_F_NOREPLAY);
out:
- /* Unfreeze grab events. */
- xcb_allow_events(conn, XCB_ALLOW_ASYNC_KEYBOARD, e->time);
+ if (replay) {
+ DNPRINTF(SWM_D_EVENT, "keypress: replaying.\n");
+ /* Pass keypress to event window and unfreeze keyboard queue. */
+ xcb_allow_events(conn, XCB_ALLOW_REPLAY_KEYBOARD, e->time);
+ } else {
+ /* Release freeze. */
+ xcb_allow_events(conn, XCB_ALLOW_SYNC_KEYBOARD, e->time);
+ }
xcb_flush(conn);
DNPRINTF(SWM_D_EVENT, "keypress: done.\n");
}
+void
+keyrelease(xcb_key_release_event_t *e)
+{
+ struct action *ap;
+ struct binding *bp;
+ xcb_keysym_t keysym;
+
+ 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));
+
+ bp = binding_lookup(CLEANMASK(e->state), KEYBIND, keysym);
+ if (bp == NULL)
+ /* Look for catch-all. */
+ bp = binding_lookup(ANYMOD, KEYBIND, keysym);
+
+ if (bp && (ap = &actions[bp->action]) && !(ap->flags & FN_F_NOREPLAY) &&
+ bp->flags & BINDING_F_REPLAY) {
+ xcb_allow_events(conn, XCB_ALLOW_REPLAY_KEYBOARD, e->time);
+ 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);
+
+ DNPRINTF(SWM_D_EVENT, "keyrelease: done.\n");
+}
+
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;
- int i;
- bool handled = false;
+ struct action *ap;
+ struct binding *bp;
+ bool replay = true;
+
+ last_event_time = e->time;
DNPRINTF(SWM_D_EVENT, "buttonpress: win (x,y): %#x (%d,%d), "
"detail: %u, time: %u, root (x,y): %#x (%d,%d), child: %#x, "
e->state, YESNO(e->same_screen));
if (e->event == e->root) {
- if (e->child != 0) {
+ if (e->child) {
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)) {
+ if (r && 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);
+ 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);
- handled = true;
- goto out;
+ /* No need to replay event. */
+ replay = false;
}
}
} else {
win = find_window(e->event);
}
- if (win == NULL)
- goto out;
+ 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);
+ }
- last_event_time = e->time;
+ /* Handle any bound action. */
+ bp = binding_lookup(CLEANMASK(e->state), BTNBIND, e->detail);
+ if (bp == NULL) {
+ /* Look for catch-all. */
+ if ((bp = binding_lookup(ANYMOD, BTNBIND, e->detail)) == NULL)
+ goto out;
- focus_win(get_focus_magic(win));
+ }
- for (i = 0; i < LENGTH(buttons); i++)
- if (client_click == buttons[i].action && buttons[i].func &&
- buttons[i].button == e->detail &&
- CLEANMASK(buttons[i].mask) == CLEANMASK(e->state)) {
- buttons[i].func(win, &buttons[i].args);
- handled = true;
- }
+ replay = bp->flags & BINDING_F_REPLAY;
+
+ if ((ap = &actions[bp->action]) == NULL)
+ goto out;
+
+ if (bp->action == FN_SPAWN_CUSTOM)
+ spawn_custom(root_to_region(e->root, SWM_CK_ALL), &ap->args,
+ bp->spawn_name);
+ else if (ap->func)
+ ap->func(bp, root_to_region(e->root, SWM_CK_ALL), &ap->args);
+
+ replay = replay && !(ap->flags & FN_F_NOREPLAY);
out:
- if (!handled) {
- DNPRINTF(SWM_D_EVENT, "buttonpress: passing to window.\n");
+ if (replay) {
+ DNPRINTF(SWM_D_EVENT, "buttonpress: replaying.\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);
}
+ focus_flush();
+}
+
+void
+buttonrelease(xcb_button_release_event_t *e)
+{
+ struct action *ap;
+ struct binding *bp;
+
+ last_event_time = e->time;
+
+ DNPRINTF(SWM_D_EVENT, "buttonrelease: win (x,y): %#x (%d,%d), "
+ "detail: %u, time: %u, root (x,y): %#x (%d,%d), child: %#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));
+
+ bp = binding_lookup(CLEANMASK(e->state), BTNBIND, e->detail);
+ if (bp == NULL)
+ /* Look for catch-all. */
+ bp = binding_lookup(ANYMOD, BTNBIND, e->detail);
+
+ if (bp && (ap = &actions[bp->action]) && !(ap->flags & FN_F_NOREPLAY) &&
+ bp->flags & BINDING_F_REPLAY) {
+ DNPRINTF(SWM_D_EVENT, "buttonrelease: replaying.\n");
+ xcb_allow_events(conn, XCB_ALLOW_REPLAY_POINTER, e->time);
+ } else {
+ xcb_allow_events(conn, XCB_ALLOW_SYNC_POINTER, e->time);
+ }
+
xcb_flush(conn);
}
#ifdef SWM_DEBUG
+char *
+get_win_input_model(struct ws_win *win)
+{
+ char *inputmodel;
+ /*
+ * Input Model Input Field WM_TAKE_FOCUS
+ * No Input False Absent
+ * Passive True Absent
+ * Locally Active True Present
+ * Globally Active False Present
+ */
+
+ if (ACCEPTS_FOCUS(win))
+ inputmodel = (win->take_focus) ? "Locally Active" : "Passive";
+ else
+ inputmodel = (win->take_focus) ? "Globally Active" : "No Input";
+
+ return inputmodel;
+}
+
void
print_win_geom(xcb_window_t w)
{
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)) == NULL) {
if ((win = find_unmanaged_window(e->window)) == NULL)
- return;
+ goto out;
+ /* Window is on unmanaged list. */
+ TAILQ_REMOVE(&win->ws->unmanagedlist, win, entry);
free_window(win);
- return;
+ 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 == win->ws->focus)
- win->ws->focus_pending = get_focus_prev(win);
+ if (win == ws->focus) {
+ ws->focus_pending = get_focus_prev(win);
+ if (ws->focus_pending == win)
+ ws->focus_pending = NULL;
+ }
}
unmanage_window(win);
- stack();
+ 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);
}
- }
- free_window(win);
+ focus_flush();
+ }
- focus_flush();
+out:
+ DNPRINTF(SWM_D_EVENT, "destroynotify: done.\n");
}
#ifdef SWM_DEBUG
return label;
}
+
+char *
+get_state_mask_label(uint16_t state)
+{
+ char *label;
+
+ switch (state) {
+ case XCB_KEY_BUT_MASK_SHIFT:
+ label = "ShiftMask";
+ break;
+ case XCB_KEY_BUT_MASK_LOCK:
+ label = "LockMask";
+ break;
+ case XCB_KEY_BUT_MASK_CONTROL:
+ label = "ControlMask";
+ break;
+ case XCB_KEY_BUT_MASK_MOD_1:
+ label = "Mod1Mask";
+ break;
+ case XCB_KEY_BUT_MASK_MOD_2:
+ label = "Mod2Mask";
+ break;
+ case XCB_KEY_BUT_MASK_MOD_3:
+ label = "Mod3Mask";
+ break;
+ case XCB_KEY_BUT_MASK_MOD_4:
+ label = "Mod4Mask";
+ break;
+ case XCB_KEY_BUT_MASK_MOD_5:
+ label = "Mod5Mask";
+ break;
+ case XCB_KEY_BUT_MASK_BUTTON_1:
+ label = "Button1Mask";
+ break;
+ case XCB_KEY_BUT_MASK_BUTTON_2:
+ label = "Button2Mask";
+ break;
+ case XCB_KEY_BUT_MASK_BUTTON_3:
+ label = "Button3Mask";
+ break;
+ case XCB_KEY_BUT_MASK_BUTTON_4:
+ label = "Button4Mask";
+ break;
+ case XCB_KEY_BUT_MASK_BUTTON_5:
+ label = "Button5Mask";
+ break;
+ case 0:
+ label = "None";
+ break;
+ default:
+ label = "Unknown";
+ }
+
+ return label;
+}
#endif
void
struct ws_win *win;
struct swm_region *r;
+ last_event_time = e->time;
+
DNPRINTF(SWM_D_FOCUS, "enternotify: time: %u, win (x,y): %#x "
"(%d,%d), mode: %s(%d), detail: %s(%d), root (x,y): %#x (%d,%d), "
- "child: %#x, same_screen_focus: %s, state: %d\n",
+ "child: %#x, same_screen_focus: %s, state: %s(%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);
+ 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) {
}
if (focus_mode != SWM_FOCUS_FOLLOW &&
- e->mode == XCB_NOTIFY_MODE_UNGRAB) {
+ e->mode == XCB_NOTIFY_MODE_UNGRAB &&
+ e->detail != XCB_NOTIFY_DETAIL_ANCESTOR) {
DNPRINTF(SWM_D_EVENT, "enternotify: ungrab; ignoring.\n");
return;
}
- last_event_time = e->time;
-
if ((win = find_window(e->event)) == NULL) {
if (e->event == e->root) {
/* If no windows on pointer region, then focus root. */
focus_win(get_focus_magic(win));
}
+ DNPRINTF(SWM_D_EVENT, "enternotify: done\n");
+
xcb_flush(conn);
}
void
leavenotify(xcb_leave_notify_event_t *e)
{
+ last_event_time = e->time;
+
DNPRINTF(SWM_D_FOCUS, "leavenotify: time: %u, win (x,y): %#x "
"(%d,%d), mode: %s(%d), detail: %s(%d), root (x,y): %#x (%d,%d), "
- "child: %#x, same_screen_focus: %s, state: %d\n",
+ "child: %#x, same_screen_focus: %s, state: %s(%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);
+ YESNO(e->same_screen_focus), get_state_mask_label(e->state),
+ e->state);
}
#endif
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);
}
void
mappingnotify(xcb_mapping_notify_event_t *e)
{
- struct ws_win *w;
- int i, j, num_screens;
-
- xcb_refresh_keyboard_mapping(syms, e);
-
- if (e->request == XCB_MAPPING_KEYBOARD) {
+ if (e->request != XCB_MAPPING_POINTER) {
+ xcb_refresh_keyboard_mapping(syms, e);
grabkeys();
-
- /* Regrab buttons on all managed windows. */
- num_screens = get_screen_count();
- for (i = 0; i < num_screens; i++)
- for (j = 0; j < workspace_limit; j++)
- TAILQ_FOREACH(w, &screens[i].ws[j].winlist,
- entry)
- grabbuttons(w);
}
+
+ grabbuttons();
}
void
maprequest(xcb_map_request_event_t *e)
{
struct ws_win *win, *w = NULL;
- xcb_get_window_attributes_reply_t *war;
DNPRINTF(SWM_D_EVENT, "maprequest: win %#x\n",
e->window);
- war = xcb_get_window_attributes_reply(conn,
- xcb_get_window_attributes(conn, e->window),
- NULL);
- if (war == NULL) {
- DNPRINTF(SWM_D_EVENT, "maprequest: window lost.\n");
- goto out;
- }
-
- if (war->override_redirect) {
- DNPRINTF(SWM_D_EVENT, "maprequest: override_redirect; "
- "skipping.\n");
- goto out;
- }
-
- win = manage_window(e->window, spawn_position,
- (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");
}
struct swm_region *r = NULL;
int i, num_screens;
+ last_event_time = e->time;
+
DNPRINTF(SWM_D_FOCUS, "motionnotify: time: %u, win (x,y): %#x "
"(%d,%d), detail: %s(%d), root (x,y): %#x (%d,%d), "
"child: %#x, same_screen_focus: %s, state: %d\n",
e->root, e->root_x, e->root_y, e->child,
YESNO(e->same_screen), e->state);
- last_event_time = e->time;
-
if (focus_mode == SWM_FOCUS_MANUAL)
return;
e->state);
free(name);
#endif
+ last_event_time = e->time;
+
win = find_window(e->window);
if (win == NULL)
return;
ws = win->ws;
- last_event_time = e->time;
-
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 && 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
if (r && e->data.data32[0] < (uint32_t)workspace_limit) {
a.id = e->data.data32[0];
- switchws(r, &a);
+ switchws(NULL, r, &a);
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);
+
+ if (win->ws->r) {
+ if (FLOATING(win))
+ load_float_geom(win);
- stack();
+ 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;
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;
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);
}
xcb_randr_query_version_reply_t *r;
num_screens = get_screen_count();
- if ((screens = calloc(num_screens,
- sizeof(struct swm_screen))) == NULL)
+ if ((screens = calloc(num_screens, sizeof(struct swm_screen))) == NULL)
err(1, "setup_screens: calloc: failed to allocate memory for "
"screens");
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");
void
shutdown_cleanup(void)
{
+ struct swm_region *r;
+ struct ws_win *w;
+ struct workspace *ws;
int i, num_screens;
/* disable alarm because the following code may not be interrupted */
clear_quirks();
clear_spawns();
- clear_keys();
+ clear_bindings();
teardown_ewmh();
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);
free(screens[i].c[j].name);
}
+ /* Free window memory. */
for (j = 0; j < SWM_WS_MAX; ++j) {
- free(screens[i].ws[j].name);
+ ws = &screens[i].ws[j];
+ free(ws->name);
+
+ while ((w = TAILQ_FIRST(&ws->winlist)) != NULL) {
+ TAILQ_REMOVE(&ws->winlist, w, entry);
+ free_window(w);
+ }
+
+ while ((w = TAILQ_FIRST(&ws->unmanagedlist)) != NULL) {
+ TAILQ_REMOVE(&ws->unmanagedlist, w, entry);
+ free_window(w);
+ }
+ }
+
+ /* Free region memory. */
+ while ((r = TAILQ_FIRST(&screens[i].rl)) != NULL) {
+ TAILQ_REMOVE(&screens[i].rl, r, entry);
+ free(r->bar);
+ free(r);
+ }
+
+ while ((r = TAILQ_FIRST(&screens[i].orl)) != NULL) {
+ TAILQ_REMOVE(&screens[i].rl, r, entry);
+ free(r->bar);
+ free(r);
}
}
free(screens);
free(bar_format);
+ free(bar_fonts);
free(clock_format);
+ free(startup_exception);
- if (bar_font_legacy)
+ if (bar_fs)
XFreeFontSet(display, bar_fs);
- else {
+ if (bar_font)
XftFontClose(display, bar_font);
- }
xcb_key_symbols_free(syms);
xcb_flush(conn);
+ xcb_aux_sync(conn);
xcb_disconnect(conn);
}
#define EVENT(type, callback) case type: callback((void *)evt); return
EVENT(0, event_error);
EVENT(XCB_BUTTON_PRESS, buttonpress);
- /*EVENT(XCB_BUTTON_RELEASE, buttonpress);*/
+ EVENT(XCB_BUTTON_RELEASE, buttonrelease);
/*EVENT(XCB_CIRCULATE_NOTIFY, );*/
/*EVENT(XCB_CIRCULATE_REQUEST, );*/
EVENT(XCB_CLIENT_MESSAGE, clientmessage);
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_GRAVITY_NOTIFY, );*/
EVENT(XCB_KEY_PRESS, keypress);
- /*EVENT(XCB_KEY_RELEASE, keypress);*/
+ EVENT(XCB_KEY_RELEASE, keyrelease);
/*EVENT(XCB_KEYMAP_NOTIFY, );*/
#ifdef SWM_DEBUG
EVENT(XCB_LEAVE_NOTIFY, leavenotify);
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, );*/
int
main(int argc, char *argv[])
{
- struct swm_region *r;
- char conf[PATH_MAX], *cfile = NULL;
- struct stat sb;
- int xfd, i, num_screens;
+ struct pollfd pfd[2];
struct sigaction sact;
+ struct stat sb;
+ struct passwd *pwd;
+ struct swm_region *r;
xcb_generic_event_t *evt;
- int num_readable;
- struct pollfd pfd[2];
+ int xfd, i, num_screens, num_readable;
+ char conf[PATH_MAX], *cfile = NULL;
bool stdin_ready = false, startup = true;
/* suppress unused warning since var is needed */
xcb_aux_sync(conn);
/* flush all events */
- while ((evt = xcb_poll_for_event(conn))) {
+ while ((evt = get_next_event(false))) {
if (XCB_EVENT_RESPONSE_TYPE(evt) == 0)
event_handle(evt);
free(evt);
setup_globals();
setup_screens();
setup_ewmh();
- setup_keys();
+ setup_keybindings();
+ setup_btnbindings();
setup_quirks();
setup_spawn();
grab_windows();
grabkeys();
- stack();
- bar_draw();
+ grabbuttons();
+
+ /* 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;
pfd[1].events = POLLIN;
while (running) {
- while ((evt = xcb_poll_for_event(conn))) {
+ while ((evt = get_next_event(false))) {
if (!running)
goto done;
event_handle(evt);
}
}
+ if (search_resp)
+ search_do_resp();
+
num_readable = poll(pfd, bar_extra ? 2 : 1, 1000);
if (num_readable == -1) {
- DNPRINTF(SWM_D_MISC, "poll failed: %s", strerror(errno));
- } else if (num_readable > 0 && bar_extra && pfd[1].revents & POLLIN) {
+ DNPRINTF(SWM_D_MISC, "poll failed: %s",
+ strerror(errno));
+ } else if (num_readable > 0 && bar_extra &&
+ pfd[1].revents & POLLIN) {
stdin_ready = true;
}
if (restart_wm)
- restart(NULL, NULL);
-
- if (search_resp)
- search_do_resp();
+ restart(NULL, NULL, NULL);
if (!running)
goto done;
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: