/*
- * Copyright (c) 2009-2012 Marco Peereboom <marco@peereboom.us>
+ * Copyright (c) 2009-2015 Marco Peereboom <marco@peereboom.us>
* Copyright (c) 2009-2011 Ryan McBride <mcbride@countersiege.com>
* Copyright (c) 2009 Darrin Chandler <dwchandler@stilyagin.com>
* 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-2014 Reginald Kennedy <rk@rejii.com>
+ * Copyright (c) 2011-2015 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-2013 David Hill <dhill@mindcry.org>
+ * Copyright (c) 2012-2015 David Hill <dhill@mindcry.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
#include <ctype.h>
#include <err.h>
#include <errno.h>
+#include <poll.h>
#include <fcntl.h>
#include <locale.h>
#include <paths.h>
int term_width = 0;
int font_adjusted = 0;
unsigned int mod_key = MODKEY;
+bool warp_pointer = false;
+unsigned int mouse_button_move = XCB_BUTTON_INDEX_1;
+unsigned int mouse_button_resize = XCB_BUTTON_INDEX_3;
/* dmenu search */
struct swm_region *search_r;
bool clock_enabled = true;
bool iconic_enabled = false;
bool urgent_enabled = false;
+bool urgent_collapse = false;
char *clock_format = NULL;
bool window_class_enabled = false;
bool window_instance_enabled = false;
bool can_delete;
bool take_focus;
bool java;
- unsigned long quirks;
+ uint32_t quirks;
struct workspace *ws; /* always valid */
struct swm_screen *s; /* always valid, never changes */
xcb_size_hints_t sh;
#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_DOWN (41)
#define SWM_ARG_ID_CYCLERG_UP (42)
regex_t regex_class;
regex_t regex_instance;
regex_t regex_name;
- unsigned long quirk;
+ 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_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. */
};
TAILQ_HEAD(quirk_list, quirk);
struct quirk_list quirks = TAILQ_HEAD_INITIALIZER(quirks);
KF_STACK_INC,
KF_STACK_DEC,
KF_STACK_RESET,
+ KF_STACK_BALANCE,
KF_SWAP_MAIN,
KF_SWAP_NEXT,
KF_SWAP_PREV,
void bar_window_state(char *, size_t, struct swm_region *);
void bar_workspace_name(char *, size_t, struct swm_region *);
void buttonpress(xcb_button_press_event_t *);
+void center_pointer(struct swm_region *);
void check_conn(void);
void clear_keys(void);
int clear_maximized(struct workspace *);
char *get_stack_mode_name(uint8_t);
#endif
int32_t get_swm_ws(xcb_window_t);
+bool get_urgent(struct ws_win *);
char *get_win_name(xcb_window_t);
uint8_t get_win_state(xcb_window_t);
void get_wm_protocols(struct ws_win *);
void leavenotify(xcb_leave_notify_event_t *);
#endif
void load_float_geom(struct ws_win *);
+void lower_window(struct ws_win *);
struct ws_win *manage_window(xcb_window_t, int, bool);
void map_window(struct ws_win *);
void mapnotify(xcb_map_notify_event_t *);
void name_workspace(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 *, unsigned long *);
+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 *);
#endif
void propertynotify(xcb_property_notify_event_t *);
void quirk_free(struct quirk *);
-void quirk_insert(const char *, const char *, const char *,unsigned long);
+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 *,
- unsigned long);
+ uint32_t, int);
void quit(struct swm_region *, union arg *);
void raise_toggle(struct swm_region *, union arg *);
void raise_window(struct ws_win *);
int setconfbinding(const char *, const char *, int);
int setconfcolor(const char *, const char *, int);
int setconfmodkey(const char *, const char *, int);
+int setconfmousebuttonmove(const char *, const char *, int);
+int setconfmousebuttonresize(const char *, const char *, int);
int setconfquirk(const char *, const char *, int);
int setconfregion(const char *, const char *, int);
int setconfspawn(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 *,unsigned long);
+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_ewmh(void);
void updatenumlockmask(void);
void update_floater(struct ws_win *);
void update_modkey(unsigned int);
+unsigned char update_mousebutton(unsigned char, unsigned int);
void update_win_stacking(struct ws_win *);
void update_window(struct ws_win *);
void update_window_color(struct ws_win *);
free(title);
}
+bool
+get_urgent(struct ws_win *win)
+{
+ xcb_icccm_wm_hints_t hints;
+ xcb_get_property_cookie_t c;
+ bool urgent = false;
+
+ if (win) {
+ c = xcb_icccm_get_wm_hints(conn, win->id);
+ if (xcb_icccm_get_wm_hints_reply(conn, c, &hints, NULL))
+ urgent = xcb_icccm_wm_hints_get_urgency(&hints);
+ }
+
+ return urgent;
+}
+
void
bar_urgent(char *s, size_t sz)
{
int i, j, num_screens;
bool urgent[SWM_WS_MAX];
char b[8];
- xcb_get_property_cookie_t c;
- xcb_icccm_wm_hints_t hints;
for (i = 0; i < workspace_limit; i++)
urgent[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) {
- c = xcb_icccm_get_wm_hints(conn, win->id);
- if (xcb_icccm_get_wm_hints_reply(conn, c,
- &hints, NULL) == 0)
- continue;
- if (hints.flags & XCB_ICCCM_WM_HINT_X_URGENCY)
+ TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry)
+ if (get_urgent(win))
urgent[j] = true;
- }
for (i = 0; i < workspace_limit; i++) {
- if (urgent[i])
+ if (urgent[i]) {
snprintf(b, sizeof b, "%d ", i + 1);
- else
- snprintf(b, sizeof b, "- ");
- strlcat(s, b, sz);
+ strlcat(s, b, sz);
+ } else if (!urgent_collapse) {
+ strlcat(s, "- ", sz);
+ }
}
}
running = 0;
}
+void
+lower_window(struct ws_win *win)
+{
+ struct ws_win *target = NULL;
+ struct workspace *ws;
+
+ 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;
+ if (ws->cur_layout == &layouts[SWM_MAX_STACK])
+ break;
+ if (TRANS(win)) {
+ if (win->transient == target->transient)
+ continue;
+ if (win->transient == target->id)
+ break;
+ }
+ if (FULLSCREEN(target))
+ continue;
+ if (FULLSCREEN(win))
+ break;
+ if (MAXIMIZED(target))
+ continue;
+ if (MAXIMIZED(win))
+ break;
+ if (ABOVE(target) || TRANS(target))
+ continue;
+ if (ABOVE(win) || TRANS(win))
+ break;
+ }
+
+ /* Change stack position. */
+ TAILQ_REMOVE(&ws->stack, win, stack_entry);
+ if (target)
+ TAILQ_INSERT_BEFORE(target, win, stack_entry);
+ else
+ TAILQ_INSERT_TAIL(&ws->stack, win, stack_entry);
+
+ update_win_stacking(win);
+
+#ifdef SWM_DEBUG
+ if (swm_debug & SWM_D_STACK) {
+ DPRINTF("=== stacking order (top down) === \n");
+ TAILQ_FOREACH(target, &ws->stack, stack_entry) {
+ DPRINTF("win %#x, fs: %s, maximized: %s, above: %s, "
+ "iconic: %s\n", target->id, YESNO(FULLSCREEN(target)),
+ YESNO(MAXIMIZED(target)), YESNO(ABOVE(target)),
+ YESNO(ICONIC(target)));
+ }
+ }
+#endif
+ DNPRINTF(SWM_D_EVENT, "lower_window: done\n");
+}
+
void
raise_window(struct ws_win *win)
{
struct ws_win *target = NULL;
- struct swm_region *r;
struct workspace *ws;
- if (win == NULL || (r = win->ws->r) == NULL)
+ if (win == NULL)
return;
ws = win->ws;
break;
if (MAXIMIZED(target))
continue;
- if (ABOVE(win) || TRANS(win))
+ if (ABOVE(win) || TRANS(win) ||
+ (win->ws->focus == win && ws->always_raise))
break;
if (!ABOVE(target) && !TRANS(target))
break;
}
- if (target != NULL) {
- /* Change stack position. */
- TAILQ_REMOVE(&ws->stack, win, stack_entry);
+ TAILQ_REMOVE(&ws->stack, win, stack_entry);
+ if (target)
TAILQ_INSERT_BEFORE(target, win, stack_entry);
- update_win_stacking(win);
- }
+ else
+ TAILQ_INSERT_TAIL(&ws->stack, win, stack_entry);
+
+ update_win_stacking(win);
#ifdef SWM_DEBUG
if (swm_debug & SWM_D_STACK) {
DPRINTF("=== stacking order (top down) === \n");
- TAILQ_FOREACH(target, &r->ws->stack, stack_entry) {
+ TAILQ_FOREACH(target, &ws->stack, stack_entry) {
DPRINTF("win %#x, fs: %s, maximized: %s, above: %s, "
"iconic: %s\n", target->id, YESNO(FULLSCREEN(target)),
YESNO(MAXIMIZED(target)), YESNO(ABOVE(target)),
return;
sibling = TAILQ_NEXT(win, stack_entry);
- if (sibling != NULL && FLOATING(win) == FLOATING(sibling))
+ 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))
+ val[0] = r->bar->id;
else
- val[0] = FLOATING(win) ? r->bar->id : r->id;
+ val[0] = r->id;
DNPRINTF(SWM_D_EVENT, "update_win_stacking: %#x, sibling %#x\n",
win->id, val[0]);
return win;
}
+void
+center_pointer(struct swm_region *r)
+{
+ struct ws_win *win;
+
+ if (!warp_pointer || r == NULL)
+ return;
+
+ win = r->ws->focus;
+
+ 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,
+ WIDTH(win) / 2, HEIGHT(win) / 2);
+ else
+ xcb_warp_pointer(conn, XCB_NONE, r->id, 0, 0, 0, 0,
+ WIDTH(r) / 2, HEIGHT(r) / 2);
+}
+
struct swm_region *
root_to_region(xcb_window_t root, int check)
{
update_window_color(win);
+ /* Raise window to "top unfocused position." */
+ if (win->ws->always_raise)
+ raise_window(win);
+
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->s->root,
ewmh[_NET_ACTIVE_WINDOW].atom, XCB_ATOM_WINDOW, 32, 1, &none);
ewmh_update_current_desktop();
+ center_pointer(r);
focus_flush();
new_ws->state = SWM_WS_STATE_MAPPED;
return;
focus_region(rr);
+ center_pointer(rr);
focus_flush();
DNPRINTF(SWM_D_FOCUS, "focusrg: done\n");
}
return;
focus_region(rr);
+ center_pointer(rr);
focus_flush();
DNPRINTF(SWM_D_FOCUS, "cyclerg: done\n");
}
ewmh_update_client_list();
stack();
+ center_pointer(r);
focus_flush();
out:
DNPRINTF(SWM_D_MOVE, "swapwin: done\n");
struct workspace *ws = NULL;
union arg a;
int i;
- xcb_icccm_wm_hints_t hints;
if (!(r && r->ws))
goto out;
} while (winfocus && (ICONIC(winfocus) ||
winfocus->id == cur_focus->transient ||
(cur_focus->transient != XCB_WINDOW_NONE &&
- winfocus->transient == cur_focus->transient)));
+ winfocus->transient == cur_focus->transient) ||
+ (winfocus->quirks & SWM_Q_NOFOCUSCYCLE)));
break;
case SWM_ARG_ID_FOCUSNEXT:
if (cur_focus == NULL)
} while (winfocus && (ICONIC(winfocus) ||
winfocus->id == cur_focus->transient ||
(cur_focus->transient != XCB_WINDOW_NONE &&
- winfocus->transient == cur_focus->transient)));
+ winfocus->transient == cur_focus->transient) ||
+ (winfocus->quirks & SWM_Q_NOFOCUSCYCLE)));
break;
case SWM_ARG_ID_FOCUSMAIN:
if (cur_focus == NULL)
head = TAILQ_FIRST(&r->s->ws[(ws->idx + i) %
workspace_limit].winlist);
- while (head != NULL &&
- (head = TAILQ_NEXT(head, entry)) != NULL) {
+ while (head) {
if (head == cur_focus) {
- winfocus = cur_focus;
- break;
- }
- if (xcb_icccm_get_wm_hints_reply(conn,
- xcb_icccm_get_wm_hints(conn, head->id),
- &hints, NULL) != 0 &&
- xcb_icccm_wm_hints_get_urgency(&hints)) {
+ if (i > 0) {
+ winfocus = cur_focus;
+ break;
+ }
+ } else if (get_urgent(head)) {
winfocus = head;
break;
}
+
+ head = TAILQ_NEXT(head, entry);
}
- if (winfocus != NULL)
+ if (winfocus)
break;
}
/* Switch ws if new focus is on a different ws. */
- if (winfocus != NULL && winfocus->ws != ws) {
+ if (winfocus && winfocus->ws != ws) {
a.id = winfocus->ws->idx;
switchws(r, &a);
}
stack();
focus_win(get_focus_magic(winfocus));
+ center_pointer(r);
focus_flush();
out:
focus_win(get_region_focus(r));
+ center_pointer(r);
focus_flush();
}
stack();
bar_draw();
+ center_pointer(r);
focus_flush();
}
win_g.y += last_h + 2 * border_width + tile_gap;
if (disable_border && !(bar_enabled && ws->bar_enabled) &&
- winno == 1){
+ winno == 1) {
bordered = false;
win_g.w += 2 * border_width;
win_g.h += 2 * border_width;
ws->l_state.vertical_mwin = 1;
ws->l_state.vertical_stacks = 1;
break;
+ case SWM_ARG_ID_STACKBALANCE:
+ ws->l_state.vertical_msize = SWM_V_SLICE / (ws->l_state.vertical_stacks + 1);
+ break;
case SWM_ARG_ID_MASTERSHRINK:
if (ws->l_state.vertical_msize > 1)
ws->l_state.vertical_msize--;
ws->l_state.horizontal_msize = SWM_H_SLICE / 2;
ws->l_state.horizontal_stacks = 1;
break;
+ case SWM_ARG_ID_STACKBALANCE:
+ ws->l_state.horizontal_msize = SWM_H_SLICE / (ws->l_state.horizontal_stacks + 1);
+ break;
case SWM_ARG_ID_MASTERSHRINK:
if (ws->l_state.horizontal_msize > 1)
ws->l_state.horizontal_msize--;
if (X(w) != gg.x || Y(w) != gg.y || WIDTH(w) != gg.w ||
HEIGHT(w) != gg.h) {
w->g = gg;
- if (bar_enabled && ws->bar_enabled){
- w->bordered = true;
- } else {
+
+ if (disable_border && !(bar_enabled && ws->bar_enabled)) {
w->bordered = false;
WIDTH(w) += 2 * border_width;
HEIGHT(w) += 2 * border_width;
+ } else {
+ w->bordered = true;
}
update_window(w);
}
}
+ center_pointer(r);
focus_flush();
}
void
raise_toggle(struct swm_region *r, union arg *args)
{
- /* suppress unused warning since var is needed */
+ /* Suppress warning. */
(void)args;
if (r == NULL || r->ws == NULL)
r->ws->always_raise = !r->ws->always_raise;
- /* bring floaters back to top */
- if (!r->ws->always_raise)
- stack();
+ /* Update focused win stacking order based on new always_raise value. */
+ raise_window(r->ws->focus);
focus_flush();
}
iconify(struct swm_region *r, union arg *args)
{
struct ws_win *w;
- /* suppress unused warning since var is needed */
+
+ /* Suppress warning. */
(void)args;
if ((w = r->ws->focus) == NULL)
if (w == w->ws->focus)
focus_win(w);
+ center_pointer(r);
focus_flush();
DNPRINTF(SWM_D_MISC, "maximize_toggle: done\n");
}
if (w == w->ws->focus)
focus_win(w);
+ center_pointer(r);
focus_flush();
DNPRINTF(SWM_D_MISC, "floating_toggle: done\n");
}
return;
resize(win, args);
+ center_pointer(r);
focus_flush();
}
return;
move(win, args);
+ center_pointer(r);
focus_flush();
}
{ "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} },
+ { "stack_balance", stack_config, {.id = SWM_ARG_ID_STACKBALANCE} },
{ "swap_main", swapwin, {.id = SWM_ARG_ID_SWAPMAIN} },
{ "swap_next", swapwin, {.id = SWM_ARG_ID_SWAPNEXT} },
{ "swap_prev", swapwin, {.id = SWM_ARG_ID_SWAPPREV} },
buttons[i].mask = mod;
}
+unsigned char
+update_mousebutton(unsigned char type, unsigned int but)
+{
+ int i;
+
+ switch (type) {
+ case 0:
+ mouse_button_move = but;
+ break;
+ case 1:
+ mouse_button_resize = but;
+ break;
+ }
+
+ for (i = 0; i < LENGTH(buttons); i++) {
+ if (buttons[i].func == move)
+ buttons[i].button = mouse_button_move;
+
+ if (buttons[i].func == resize)
+ buttons[i].button = mouse_button_resize;
+ }
+
+ return(1);
+}
+
int
spawn_expand(struct swm_region *r, union arg *args, const char *spawn_name,
char ***ret_args)
*mod |= XCB_MOD_MASK_3;
else if (strncmp(name, "Mod4", SWM_MODNAME_SIZE) == 0)
*mod |= XCB_MOD_MASK_4;
+ else if (strncmp(name, "Mod5", SWM_MODNAME_SIZE) == 0)
+ *mod |= XCB_MOD_MASK_5;
else if (strncasecmp(name, "SHIFT", SWM_MODNAME_SIZE) == 0)
*mod |= XCB_MOD_MASK_SHIFT;
else if (strncasecmp(name, "CONTROL", SWM_MODNAME_SIZE) == 0)
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_SHIFT, XK_h, KF_STACK_BALANCE, 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);
"OBEYAPPFOCUSREQ",
"IGNOREPID",
"IGNORESPAWNWS",
+ "NOFOCUSCYCLE",
};
-/* SWM_Q_WS: retain '|' for back compat for now (2009-08-11) */
-#define SWM_Q_WS "\n|+ \t"
+/* SWM_Q_DELIM: retain '|' for back compat for now (2009-08-11) */
+#define SWM_Q_DELIM "\n|+ \t"
int
-parsequirks(const char *qstr, unsigned long *quirk)
+parsequirks(const char *qstr, uint32_t *quirk, int *ws)
{
char *str, *cp, *name;
int i;
cp = str;
*quirk = 0;
- while ((name = strsep(&cp, SWM_Q_WS)) != NULL) {
+ while ((name = strsep(&cp, SWM_Q_DELIM)) != NULL) {
if (cp)
- cp += (long)strspn(cp, SWM_Q_WS);
+ cp += (long)strspn(cp, SWM_Q_DELIM);
+
+ if (sscanf(name, "WS[%d]", ws) == 1) {
+ if (*ws > 0)
+ *ws -= 1;
+ continue;
+ }
+
for (i = 0; i < LENGTH(quirkname); i++) {
if (strncasecmp(name, quirkname[i],
SWM_QUIRK_LEN) == 0) {
void
quirk_insert(const char *class, const char *instance, const char *name,
- unsigned long quirk)
+ uint32_t quirk, int ws)
{
struct quirk *qp;
char *str;
bool failed = false;
DNPRINTF(SWM_D_QUIRK, "quirk_insert: class: %s, instance: %s, name: %s,"
- " value: %lu\n", class, instance, name, quirk);
+ " value: %u, ws: %d\n", class, instance, name, quirk, ws);
if ((qp = malloc(sizeof *qp)) == NULL)
err(1, "quirk_insert: malloc");
quirk_free(qp);
} else {
qp->quirk = quirk;
+ qp->ws = ws;
TAILQ_INSERT_TAIL(&quirks, qp, entry);
}
DNPRINTF(SWM_D_QUIRK, "quirk_insert: leave\n");
void
quirk_remove(struct quirk *qp)
{
- DNPRINTF(SWM_D_QUIRK, "quirk_remove: %s:%s [%lu]\n", qp->class,
+ DNPRINTF(SWM_D_QUIRK, "quirk_remove: %s:%s [%u]\n", qp->class,
qp->name, qp->quirk);
TAILQ_REMOVE(&quirks, qp, entry);
void
quirk_replace(struct quirk *qp, const char *class, const char *instance,
- const char *name, unsigned long quirk)
+ const char *name, uint32_t quirk, int ws)
{
- DNPRINTF(SWM_D_QUIRK, "quirk_replace: %s:%s:%s [%lu]\n", qp->class,
- qp->instance, qp->name, qp->quirk);
+ DNPRINTF(SWM_D_QUIRK, "quirk_replace: %s:%s:%s [%u], ws: %d\n", qp->class,
+ qp->instance, qp->name, qp->quirk, qp->ws);
quirk_remove(qp);
- quirk_insert(class, instance, name, quirk);
+ quirk_insert(class, instance, name, quirk, ws);
DNPRINTF(SWM_D_QUIRK, "quirk_replace: leave\n");
}
void
setquirk(const char *class, const char *instance, const char *name,
- unsigned long quirk)
+ uint32_t quirk, int ws)
{
struct quirk *qp;
- DNPRINTF(SWM_D_QUIRK, "setquirk: enter %s:%s:%s [%lu]\n", class,
- instance, name, quirk);
+ DNPRINTF(SWM_D_QUIRK, "setquirk: enter %s:%s:%s [%u], ws: %d\n", class,
+ instance, name, quirk, ws);
/* Remove/replace existing quirk. */
TAILQ_FOREACH(qp, &quirks, entry) {
if (strcmp(qp->class, class) == 0 &&
strcmp(qp->instance, instance) == 0 &&
strcmp(qp->name, name) == 0) {
- if (quirk == 0)
+ if (quirk == 0 && ws == -1)
quirk_remove(qp);
else
- quirk_replace(qp, class, instance, name, quirk);
+ quirk_replace(qp, class, instance, name, quirk,
+ ws);
DNPRINTF(SWM_D_QUIRK, "setquirk: leave\n");
return;
}
}
- /* Only insert if quirk is not NONE. */
- if (quirk)
- quirk_insert(class, instance, name, quirk);
+ /* Only insert if quirk is not NONE or forced ws is set. */
+ if (quirk || ws != -1)
+ quirk_insert(class, instance, name, quirk, ws);
DNPRINTF(SWM_D_QUIRK, "setquirk: leave\n");
}
{
char *str, *cp, *class;
char *instance = NULL, *name = NULL;
- int retval, count = 0;
- unsigned long qrks;
+ int retval, count = 0, ws = -1;
+ uint32_t qrks;
/* suppress unused warning since var is needed */
(void)flags;
DNPRINTF(SWM_D_CONF, "setconfquirk: class: %s, instance: %s, "
"name: %s\n", class, instance, name);
- if ((retval = parsequirks(value, &qrks)) == 0)
- setquirk(class, instance, name, qrks);
+ if ((retval = parsequirks(value, &qrks, &ws)) == 0)
+ setquirk(class, instance, name, qrks, ws);
free(str);
return (retval);
void
setup_quirks(void)
{
- setquirk("MPlayer", "xv", ".*", SWM_Q_FLOAT | SWM_Q_FULLSCREEN | SWM_Q_FOCUSPREV);
- setquirk("OpenOffice.org 3.2", "VCLSalFrame", ".*", SWM_Q_FLOAT);
- setquirk("Firefox-bin", "firefox-bin", ".*", SWM_Q_TRANSSZ);
- setquirk("Firefox", "Dialog", ".*", SWM_Q_FLOAT);
- setquirk("Gimp", "gimp", ".*", SWM_Q_FLOAT | SWM_Q_ANYWHERE);
- setquirk("XTerm", "xterm", ".*", SWM_Q_XTERM_FONTADJ);
- setquirk("xine", "Xine Window", ".*", SWM_Q_FLOAT | SWM_Q_ANYWHERE);
- setquirk("Xitk", "Xitk Combo", ".*", SWM_Q_FLOAT | SWM_Q_ANYWHERE);
- setquirk("xine", "xine Panel", ".*", SWM_Q_FLOAT | SWM_Q_ANYWHERE);
- setquirk("Xitk", "Xine Window", ".*", SWM_Q_FLOAT | SWM_Q_ANYWHERE);
- setquirk("xine", "xine Video Fullscreen Window", ".*", SWM_Q_FULLSCREEN | SWM_Q_FLOAT);
- setquirk("pcb", "pcb", ".*", SWM_Q_FLOAT);
- setquirk("SDL_App", "SDL_App", ".*", SWM_Q_FLOAT | SWM_Q_FULLSCREEN);
+ setquirk("MPlayer", "xv", ".*",
+ SWM_Q_FLOAT | SWM_Q_FULLSCREEN | SWM_Q_FOCUSPREV, -1);
+ setquirk("OpenOffice.org 3.2", "VCLSalFrame", ".*",
+ SWM_Q_FLOAT, -1);
+ setquirk("Firefox-bin", "firefox-bin", ".*",
+ SWM_Q_TRANSSZ, -1);
+ setquirk("Firefox", "Dialog", ".*",
+ SWM_Q_FLOAT, -1);
+ setquirk("Gimp", "gimp", ".*",
+ SWM_Q_FLOAT | SWM_Q_ANYWHERE, -1);
+ setquirk("XTerm", "xterm", ".*",
+ SWM_Q_XTERM_FONTADJ, -1);
+ setquirk("xine", "Xine Window", ".*",
+ SWM_Q_FLOAT | SWM_Q_ANYWHERE, -1);
+ setquirk("Xitk", "Xitk Combo", ".*",
+ SWM_Q_FLOAT | SWM_Q_ANYWHERE, -1);
+ setquirk("xine", "xine Panel", ".*",
+ SWM_Q_FLOAT | SWM_Q_ANYWHERE, -1);
+ setquirk("Xitk", "Xine Window", ".*",
+ SWM_Q_FLOAT | SWM_Q_ANYWHERE, -1);
+ setquirk("xine", "xine Video Fullscreen Window", ".*",
+ SWM_Q_FULLSCREEN | SWM_Q_FLOAT, -1);
+ setquirk("pcb", "pcb", ".*",
+ SWM_Q_FLOAT, -1);
+ setquirk("SDL_App", "SDL_App", ".*",
+ SWM_Q_FLOAT | SWM_Q_FULLSCREEN, -1);
}
/* conf file stuff */
SWM_S_STACK_ENABLED,
SWM_S_TERM_WIDTH,
SWM_S_TILE_GAP,
+ SWM_S_URGENT_COLLAPSE,
SWM_S_URGENT_ENABLED,
SWM_S_VERBOSE_LAYOUT,
+ SWM_S_WARP_POINTER,
SWM_S_WINDOW_CLASS_ENABLED,
SWM_S_WINDOW_INSTANCE_ENABLED,
SWM_S_WINDOW_NAME_ENABLED,
case SWM_S_TILE_GAP:
tile_gap = atoi(value);
break;
+ case SWM_S_URGENT_COLLAPSE:
+ urgent_collapse = (atoi(value) != 0);
+ break;
case SWM_S_URGENT_ENABLED:
urgent_enabled = (atoi(value) != 0);
break;
layouts[i].l_string = plain_stacker;
}
break;
+ case SWM_S_WARP_POINTER:
+ warp_pointer = (atoi(value) != 0);
+ break;
case SWM_S_WINDOW_CLASS_ENABLED:
window_class_enabled = (atoi(value) != 0);
break;
update_modkey(XCB_MOD_MASK_3);
else if (strncasecmp(value, "Mod4", strlen("Mod4")) == 0)
update_modkey(XCB_MOD_MASK_4);
+ else if (strncasecmp(value, "Mod5", strlen("Mod5")) == 0)
+ update_modkey(XCB_MOD_MASK_5);
else
return (1);
return (0);
}
+int
+setconfmousebuttonmove(const char *selector, const char *value, int flags)
+{
+ /* suppress unused warnings since vars are needed */
+ (void)selector;
+ (void)flags;
+
+ if (strncasecmp(value, "But1", strlen("But1")) == 0) {
+ if (!update_mousebutton(0, XCB_BUTTON_INDEX_1))
+ return (1);
+ } else if (strncasecmp(value, "But2", strlen("But2")) == 0) {
+ if (!update_mousebutton(0, XCB_BUTTON_INDEX_2))
+ return (1);
+ } else if (strncasecmp(value, "But3", strlen("But3")) == 0) {
+ if (!update_mousebutton(0, XCB_BUTTON_INDEX_3))
+ return (1);
+ } else
+ return (1);
+ return (0);
+}
+
+int
+setconfmousebuttonresize(const char *selector, const char *value, int flags)
+{
+ /* suppress unused warnings since vars are needed */
+ (void)selector;
+ (void)flags;
+
+ if (strncasecmp(value, "But1", strlen("But1")) == 0) {
+ if (!update_mousebutton(1, XCB_BUTTON_INDEX_1))
+ return (1);
+ } else if (strncasecmp(value, "But2", strlen("But2")) == 0) {
+ if (!update_mousebutton(1, XCB_BUTTON_INDEX_2))
+ return (1);
+ } else if (strncasecmp(value, "But3", strlen("But3")) == 0) {
+ if (!update_mousebutton(1, XCB_BUTTON_INDEX_3))
+ return (1);
+ } else
+ return (1);
+ return (0);
+}
+
int
setconfcolor(const char *selector, const char *value, int flags)
{
{ "keyboard_mapping", setkeymapping, 0 },
{ "layout", setlayout, 0 },
{ "modkey", setconfmodkey, 0 },
+ { "move_button", setconfmousebuttonmove, 0 },
+ { "resize_button", setconfmousebuttonresize, 0 },
{ "program", setconfspawn, 0 },
{ "quirk", setconfquirk, 0 },
{ "region", setconfregion, 0 },
{ "tile_gap", setconfvalue, SWM_S_TILE_GAP },
{ "title_class_enabled", setconfvalue, SWM_S_WINDOW_CLASS_ENABLED }, /* For backwards compat. */
{ "title_name_enabled", setconfvalue, SWM_S_WINDOW_INSTANCE_ENABLED }, /* For backwards compat. */
+ { "urgent_collapse", setconfvalue, SWM_S_URGENT_COLLAPSE },
{ "urgent_enabled", setconfvalue, SWM_S_URGENT_ENABLED },
{ "verbose_layout", setconfvalue, SWM_S_VERBOSE_LAYOUT },
+ { "warp_pointer", setconfvalue, SWM_S_WARP_POINTER },
{ "window_class_enabled", setconfvalue, SWM_S_WINDOW_CLASS_ENABLED },
{ "window_instance_enabled", setconfvalue, SWM_S_WINDOW_INSTANCE_ENABLED },
{ "window_name_enabled", setconfvalue, SWM_S_WINDOW_NAME_ENABLED },
if (line)
free(line);
fclose(config);
+
+ if (mouse_button_move == mouse_button_resize) {
+ add_startup_exception("%s: move and resize mouse buttons match",
+ filename);
+ }
+
DNPRINTF(SWM_D_CONF, "conf_load: end\n");
return (0);
xcb_get_geometry_reply_t *gr;
xcb_window_t trans = XCB_WINDOW_NONE;
uint32_t i, wa[2], new_flags;
- int ws_idx;
+ int ws_idx, force_ws = -1;
char *class, *instance, *name;
if ((win = find_window(id)) != NULL) {
regexec(&qp->regex_instance, instance, 0, NULL, 0) == 0 &&
regexec(&qp->regex_name, name, 0, NULL, 0) == 0) {
DNPRINTF(SWM_D_CLASS, "manage_window: matched "
- "quirk: %s:%s:%s mask: %#lx\n", qp->class,
- qp->instance, qp->name, qp->quirk);
+ "quirk: %s:%s:%s mask: %#x, ws: %d\n", qp->class,
+ qp->instance, qp->name, qp->quirk, qp->ws);
win->quirks = qp->quirk;
+ if (qp->ws >= 0 && qp->ws < workspace_limit)
+ force_ws = qp->ws;
}
}
win->ws = r->ws;
}
+ if (force_ws != -1)
+ win->ws = &r->s->ws[force_ws];
+
/* Set the _NET_WM_DESKTOP atom. */
DNPRINTF(SWM_D_PROP, "manage_window: set _NET_WM_DESKTOP: %d\n",
win->ws->idx);
}
out:
- /* Figure out where to stack the window in the workspace. */
+ /* 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);
else if (win->ws->focus && spawn_pos == SWM_STACK_ABOVE)
ewmh_update_client_list();
- TAILQ_INSERT_TAIL(&win->ws->stack, win, stack_entry);
+ TAILQ_INSERT_HEAD(&win->ws->stack, win, stack_entry);
+ lower_window(win);
/* Get/apply initial _NET_WM_STATE */
ewmh_get_wm_state(win);
return;
}
+ if (focus_mode != SWM_FOCUS_FOLLOW &&
+ e->mode == XCB_NOTIFY_MODE_UNGRAB) {
+ DNPRINTF(SWM_D_EVENT, "enternotify: ungrab; ignoring.\n");
+ return;
+ }
+
last_event_time = e->time;
if ((win = find_window(e->event)) == NULL) {
if (ws->focus_pending == win) {
focus_win(win);
ws->focus_pending = NULL;
+ center_pointer(win->ws->r);
focus_flush();
}
}
}
}
+ center_pointer(ws->r);
focus_flush();
}
int xfd, i, num_screens;
struct sigaction sact;
xcb_generic_event_t *evt;
- struct timeval tv;
- fd_set rd;
- int rd_max;
int num_readable;
+ struct pollfd pfd[2];
bool stdin_ready = false, startup = true;
/* suppress unused warning since var is needed */
TAILQ_FOREACH(r, &screens[i].rl, entry)
r->ws->state = SWM_WS_STATE_MAPPED;
- rd_max = xfd > STDIN_FILENO ? xfd : STDIN_FILENO;
+ memset(&pfd, 0, sizeof(pfd));
+ pfd[0].fd = xfd;
+ pfd[0].events = POLLIN;
+ pfd[1].fd = STDIN_FILENO;
+ pfd[1].events = POLLIN;
while (running) {
while ((evt = xcb_poll_for_event(conn))) {
}
}
- FD_ZERO(&rd);
-
- if (bar_extra)
- FD_SET(STDIN_FILENO, &rd);
-
- FD_SET(xfd, &rd);
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- num_readable = select(rd_max + 1, &rd, NULL, NULL, &tv);
- if (num_readable == -1 && errno != EINTR) {
- DNPRINTF(SWM_D_MISC, "select failed");
- } else if (num_readable > 0 && FD_ISSET(STDIN_FILENO, &rd)) {
+ 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) {
stdin_ready = true;
}