* Copyright (c) 2009 Pierre-Yves Ritschard <pyr@spootnik.org>
* Copyright (c) 2010 Tuukka Kataja <stuge@xor.fi>
* Copyright (c) 2011 Jason L. Wright <jason@thought.net>
- * Copyright (c) 2011-2015 Reginald Kennedy <rk@rejii.com>
+ * Copyright (c) 2011-2016 Reginald Kennedy <rk@rejii.com>
* Copyright (c) 2011-2012 Lawrence Teo <lteo@lteo.net>
* Copyright (c) 2011-2012 Tiago Cunha <tcunha@gmx.com>
* Copyright (c) 2012-2015 David Hill <dhill@mindcry.org>
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/*
- * Much code and ideas taken from dwm under the following license:
- * MIT/X Consortium License
- *
- * 2006-2008 Anselm R Garbe <garbeam at gmail dot com>
- * 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
- * 2006-2007 Jukka Salmi <jukka at salmi dot ch>
- * 2007 Premysl Hruby <dfenze at gmail dot com>
- * 2007 Szabolcs Nagy <nszabolcs at gmail dot com>
- * 2007 Christof Musik <christof at sendfax dot de>
- * 2007-2008 Enno Gottox Boland <gottox at s01 dot de>
- * 2007-2008 Peter Hartlich <sgkkr at hartlich dot com>
- * 2008 Martin Hurton <martin dot hurton at gmail dot com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
/* kernel includes */
#include <sys/types.h>
#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__)
#include <X11/Xcursor/Xcursor.h>
#include <X11/Xft/Xft.h>
#include <X11/Xlib-xcb.h>
+#include <xcb/xcb.h>
#include <xcb/xcb_atom.h>
#include <xcb/xcb_aux.h>
#include <xcb/xcb_event.h>
#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 SWM_PROPLEN (16)
#define SWM_FUNCNAME_LEN (32)
-#define SWM_KEYS_LEN (255)
#define SWM_QUIRK_LEN (64)
#define X(r) ((r)->g.x)
#define Y(r) ((r)->g.y)
#define WIDTH(r) ((r)->g.w)
#define HEIGHT(r) ((r)->g.h)
-#define BORDER(w) ((w)->bordered ? border_width : 0)
#define MAX_X(r) ((r)->g.x + (r)->g.w)
#define MAX_Y(r) ((r)->g.y + (r)->g.h)
#define SH_MIN(w) ((w)->sh.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE)
#define SH_INC_H(w) ((w)->sh.height_inc)
#define SWM_MAX_FONT_STEPS (3)
#define WINID(w) ((w) ? (w)->id : XCB_WINDOW_NONE)
+#define ACCEPTS_FOCUS(w) (!((w)->hints.flags & XCB_ICCCM_WM_HINT_INPUT) \
+ || ((w)->hints.input))
#define WS_FOCUSED(ws) ((ws)->r && (ws)->r->s->r_focus == (ws)->r)
#define YESNO(x) ((x) ? "yes" : "no")
#define ICONIC(w) ((w)->ewmh_flags & EWMH_F_HIDDEN)
#define SWM_FOCUS_FOLLOW (1)
#define SWM_FOCUS_MANUAL (2)
-#define SWM_CK_NONE (0)
#define SWM_CK_ALL (0xf)
#define SWM_CK_FOCUS (0x1)
#define SWM_CK_POINTER (0x2)
#define SWM_CK_FALLBACK (0x4)
#define SWM_CK_REGION (0x8)
-#define SWM_G_ALL (0xf)
-#define SWM_G_SIZE (0x1)
-#define SWM_G_POS (0x2)
-
#define SWM_CONF_DEFAULT (0)
#define SWM_CONF_KEYMAPPING (1)
xcb_atom_t a_state;
xcb_atom_t a_prot;
xcb_atom_t a_delete;
+xcb_atom_t a_net_frame_extents;
xcb_atom_t a_net_wm_check;
xcb_atom_t a_net_supported;
xcb_atom_t a_takefocus;
bool 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;
int tile_gap = 0;
bool java_workaround = true;
bool verbose_layout = false;
+bool track_pid_ws = true;
#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);
void horizontal_stack(struct workspace *, struct swm_geometry *);
void max_stack(struct workspace *, struct swm_geometry *);
+void max_config(struct workspace *, int);
void plain_stacker(struct workspace *);
void fancy_stacker(struct workspace *);
/* stack, configure */
{ vertical_stack, vertical_config, 0, plain_stacker },
{ horizontal_stack, horizontal_config, 0, plain_stacker },
- { max_stack, NULL,
+ { max_stack, max_config,
SWM_L_MAPONFOCUS | SWM_L_FOCUSPREV, plain_stacker },
{ NULL, NULL, 0, NULL },
};
struct ws_win *focus; /* may be NULL */
struct ws_win *focus_prev; /* may be NULL */
struct ws_win *focus_pending; /* may be NULL */
+ struct ws_win *focus_raise; /* may be NULL */
struct swm_region *r; /* may be NULL */
struct swm_region *old_r; /* may be NULL */
struct ws_win_list winlist; /* list of windows in ws */
};
struct swm_screen *screens;
+struct layout_config {
+ bool configured;
+ int layout;
+ int master_grow;
+ int master_add;
+ int stack_inc;
+ int always_raise;
+ bool apply_flip;
+} initial_layouts[SWM_WS_MAX];
+
/* args to functions */
union arg {
int id;
#define SWM_ARG_ID_MASTERADD (22)
#define SWM_ARG_ID_MASTERDEL (23)
#define SWM_ARG_ID_FLIPLAYOUT (24)
-#define SWM_ARG_ID_STACKRESET (30)
#define SWM_ARG_ID_STACKINIT (31)
#define SWM_ARG_ID_STACKBALANCE (32)
#define SWM_ARG_ID_CYCLEWS_UP (40)
#define SWM_ARG_ID_CYCLEWS_MOVE_DOWN (47)
#define SWM_ARG_ID_STACKINC (50)
#define SWM_ARG_ID_STACKDEC (51)
-#define SWM_ARG_ID_SS_ALL (60)
-#define SWM_ARG_ID_SS_WINDOW (61)
#define SWM_ARG_ID_DONTCENTER (70)
#define SWM_ARG_ID_CENTER (71)
#define SWM_ARG_ID_KILLWINDOW (80)
#define SWM_ARG_ID_MOVEDOWN (101)
#define SWM_ARG_ID_MOVELEFT (102)
#define SWM_ARG_ID_MOVERIGHT (103)
-#define SWM_ARG_ID_RAISE (105)
-#define SWM_ARG_ID_LOWER (106)
#define SWM_ARG_ID_BAR_TOGGLE (110)
#define SWM_ARG_ID_BAR_TOGGLE_WS (111)
#define SWM_ARG_ID_CYCLERG_MOVE_UP (112)
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_WM_STATE_SKIP_PAGER,
_NET_WM_STATE_SKIP_TASKBAR,
_NET_WM_WINDOW_TYPE,
+ _NET_WM_WINDOW_TYPE_DESKTOP,
_NET_WM_WINDOW_TYPE_DIALOG,
_NET_WM_WINDOW_TYPE_DOCK,
_NET_WM_WINDOW_TYPE_NORMAL,
{"_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},
{"_NET_WM_STATE_SKIP_PAGER", XCB_ATOM_NONE},
{"_NET_WM_STATE_SKIP_TASKBAR", XCB_ATOM_NONE},
{"_NET_WM_WINDOW_TYPE", XCB_ATOM_NONE},
+ {"_NET_WM_WINDOW_TYPE_DESKTOP", XCB_ATOM_NONE},
{"_NET_WM_WINDOW_TYPE_DIALOG", XCB_ATOM_NONE},
{"_NET_WM_WINDOW_TYPE_DOCK", XCB_ATOM_NONE},
{"_NET_WM_WINDOW_TYPE_NORMAL", 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_FULLSCREEN_TOGGLE,
+ 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,
+ KF_MVRG_NEXT,
+ KF_MVRG_PREV,
+ 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,
+ 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_INIT,
+ 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_float(char *, size_t, struct swm_region *);
+void bar_window_index_count(char *, size_t, struct swm_region *);
void bar_window_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 *);
+void bar_workspace_state(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);
void ewmh_autoquirk(struct ws_win *);
void ewmh_get_desktop_names(void);
void ewmh_get_wm_state(struct ws_win *);
+int ewmh_handle_special_types(xcb_window_t, struct swm_region *);
void ewmh_update_actions(struct ws_win *);
void ewmh_update_client_list(void);
void ewmh_update_current_desktop(void);
char *expand_tilde(const char *);
void expose(xcb_expose_event_t *);
void fake_keypress(struct ws_win *, xcb_keysym_t, uint16_t);
+struct swm_bar *find_bar(xcb_window_t);
+struct ws_win *find_frame_window(xcb_window_t);
struct pid_e *find_pid(pid_t);
+struct swm_region *find_region(xcb_window_t);
struct ws_win *find_unmanaged_window(xcb_window_t);
struct ws_win *find_window(xcb_window_t);
-void floating_toggle(struct 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 *);
+void fullscreen_toggle(struct binding *, struct swm_region *, union arg *);
xcb_atom_t get_atom_from_string(const char *);
#ifdef SWM_DEBUG
char *get_atom_name(xcb_atom_t);
#endif
struct ws_win *get_focus_magic(struct ws_win *);
struct ws_win *get_focus_prev(struct ws_win *);
+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 *);
+void initlayout(struct workspace *);
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_focus(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_rg_relative(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);
}
}
+int
+ewmh_handle_special_types(xcb_window_t id, struct swm_region *region)
+{
+ xcb_get_property_reply_t *r;
+ xcb_get_property_cookie_t c;
+ xcb_atom_t *type;
+ int i, n;
+ uint16_t configure_mask = 0;
+ uint32_t wa[2];
+
+ c = xcb_get_property(conn, 0, id,
+ ewmh[_NET_WM_WINDOW_TYPE].atom, XCB_ATOM_ATOM, 0, UINT32_MAX);
+ r = xcb_get_property_reply(conn, c, NULL);
+ if (r == NULL)
+ return 0;
+
+ type = xcb_get_property_value(r);
+ n = xcb_get_property_value_length(r) / sizeof(xcb_atom_t);
+
+ for (i = 0; i < n; i++) {
+ if (type[i] == ewmh[_NET_WM_WINDOW_TYPE_DESKTOP].atom) {
+ configure_mask = XCB_CONFIG_WINDOW_STACK_MODE |
+ XCB_CONFIG_WINDOW_SIBLING;
+ wa[0] = region->id;
+ wa[1] = XCB_STACK_MODE_ABOVE;
+ break;
+ }
+
+ if (type[i] == ewmh[_NET_WM_WINDOW_TYPE_DOCK].atom) {
+ configure_mask = XCB_CONFIG_WINDOW_STACK_MODE;
+ wa[0] = XCB_STACK_MODE_ABOVE;
+ break;
+ }
+ }
+ free(r);
+
+ if (configure_mask != 0) {
+ xcb_map_window(conn, id);
+ xcb_configure_window (conn, id, configure_mask, wa);
+ return 1;
+ }
+
+ return 0;
+}
+
void
ewmh_autoquirk(struct ws_win *win)
{
for (i = 0; i < n; i++) {
if (type[i] == ewmh[_NET_WM_WINDOW_TYPE_NORMAL].atom)
break;
- if (type[i] == ewmh[_NET_WM_WINDOW_TYPE_DOCK].atom ||
- type[i] == ewmh[_NET_WM_WINDOW_TYPE_TOOLBAR].atom ||
+ if (type[i] == ewmh[_NET_WM_WINDOW_TYPE_TOOLBAR].atom ||
type[i] == ewmh[_NET_WM_WINDOW_TYPE_UTILITY].atom) {
win->quirks = SWM_Q_FLOAT | SWM_Q_ANYWHERE;
break;
}
}
free(r);
+
+
+ c = xcb_get_property(conn, 0, win->id,
+ ewmh[_NET_WM_STATE].atom, XCB_ATOM_ATOM, 0, UINT32_MAX);
+ r = xcb_get_property_reply(conn, c, NULL);
+ if (r == NULL)
+ return;
+
+ type = xcb_get_property_value(r);
+ n = xcb_get_property_value_length(r) / sizeof(xcb_atom_t);
+
+ for (i = 0; i < n; i++) {
+ if (type[i] == ewmh[_NET_WM_STATE_SKIP_PAGER].atom ||
+ type[i] == ewmh[_NET_WM_STATE_SKIP_TASKBAR].atom) {
+ win->quirks = SWM_Q_FLOAT | SWM_Q_ANYWHERE;
+ break;
+ }
+ }
+ free(r);
}
void
}
}
- 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_window_instance(s, sz, r);
}
+void
+bar_window_index_count(char *s, size_t sz, struct swm_region *r)
+{
+ struct ws_win *w;
+ int count, index;
+
+ if (r == NULL || r->ws == NULL || r->ws->focus == NULL) {
+ strlcat(s, "0/0", sz);
+ return;
+ }
+
+ count = 0;
+ index = 0;
+
+ TAILQ_FOREACH(w, &r->ws->winlist, entry) {
+ ++count;
+ if (w->id == r->ws->focus->id) {
+ index = count;
+ }
+ }
+
+ snprintf(s, sz, "%d/%d", index, count);
+}
+
void
bar_window_state(char *s, size_t sz, struct swm_region *r)
{
strlcat(s, "- ", sz);
}
}
- if(urgent_collapse && s[0])
+ if (urgent_collapse && s[0])
s[strlen(s) - 1] = 0;
}
strlcat(s, r->ws->name, sz);
}
+void
+bar_workspace_state(char *s, size_t sz, struct swm_region *r)
+{
+ struct ws_win *win;
+ int i, j, num_screens;
+ bool used_workspaces[SWM_WS_MAX];
+ char tmp[8];
+ int first = 1;
+ char *fmt;
+
+ if (r == NULL || r->ws == NULL)
+ return;
+
+ for (i = 0; i < SWM_WS_MAX; ++i)
+ used_workspaces[i] = false;
+
+ 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)
+ ++used_workspaces[win->ws->idx];
+
+ for (i = 0; i < SWM_WS_MAX; ++i) {
+ fmt = NULL;
+ if (i == r->ws->idx) {
+ fmt = " [%d]";
+ } else if (used_workspaces[i]) {
+ fmt = " %d";
+ }
+ if (fmt) {
+ fmt = fmt + first;
+ first = 0;
+ snprintf(tmp, sizeof tmp, fmt, i + 1);
+ strlcat(s, tmp, sz);
+ }
+ }
+}
+
/* build the default bar format according to the defined enabled options */
void
bar_fmt(const char *fmtexp, char *fmtnew, struct swm_region *r, size_t sz)
/* 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);
case 'I':
snprintf(tmp, sizeof tmp, "%d", r->ws->idx + 1);
break;
+ case 'i':
+ bar_workspace_state(tmp, sizeof tmp, r);
+ break;
case 'M':
count = 0;
TAILQ_FOREACH(w, &r->ws->winlist, entry)
case 'N':
snprintf(tmp, sizeof tmp, "%d", r->s->idx + 1);
break;
+ case 'p':
+ bar_window_index_count(tmp, sizeof tmp, r);
+ break;
case 'P':
bar_window_class_instance(tmp, sizeof tmp, r);
break;
#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);
-}
-
-void
+ 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
client_msg(struct ws_win *win, xcb_atom_t a, xcb_timestamp_t t)
{
xcb_client_message_event_t ev;
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;
- else if (FLOATING(win) || (win->ws->always_raise &&
- win->ws->focus == win))
+ (win->ws->always_raise && win->ws->focus == win))) {
+ val[0] = sibling->frame;
+ val[1] = XCB_STACK_MODE_ABOVE;
+ } 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]);
+ val[1] = XCB_STACK_MODE_ABOVE;
+ } else {
+ val[0] = r->bar->id;
+ val[1] = XCB_STACK_MODE_BELOW;
+ }
- val[1] = XCB_STACK_MODE_ABOVE;
+ DNPRINTF(SWM_D_EVENT, "update_win_stacking: win %#x (%#x), "
+ "sibling %#x mode %#x\n", win->frame, win->id, val[0], val[1]);
- 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);
}
close(xcb_get_file_descriptor(conn));
- setenv("LD_PRELOAD", SWM_LIB, 1);
+ if (track_pid_ws) {
+ if ((ret = getenv("LD_PRELOAD"))) {
+ if (asprintf(&ret, "%s:%s", SWM_LIB, ret) == -1) {
+ warn("spawn: asprintf LD_PRELOAD");
+ _exit(1);
+ }
+ setenv("LD_PRELOAD", ret, 1);
+ free(ret);
+ } else {
+ setenv("LD_PRELOAD", SWM_LIB, 1);
+ }
- if (asprintf(&ret, "%d", ws_idx) == -1) {
- warn("spawn: asprintf SWM_WS");
- _exit(1);
- }
- setenv("_SWM_WS", ret, 1);
- free(ret);
- ret = NULL;
+ if (asprintf(&ret, "%d", ws_idx) == -1) {
+ warn("spawn: asprintf SWM_WS");
+ _exit(1);
+ }
+ setenv("_SWM_WS", ret, 1);
+ free(ret);
+ ret = NULL;
- if (asprintf(&ret, "%d", getpid()) == -1) {
- warn("spawn: asprintf _SWM_PID");
- _exit(1);
+ if (asprintf(&ret, "%d", getpid()) == -1) {
+ warn("spawn: asprintf _SWM_PID");
+ _exit(1);
+ }
+ setenv("_SWM_PID", ret, 1);
+ free(ret);
+ ret = NULL;
}
- setenv("_SWM_PID", ret, 1);
- free(ret);
- ret = NULL;
if (setsid() == -1) {
warn("spawn: setsid");
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;
- &nbs