/* #define SWM_DEBUG */
#ifdef SWM_DEBUG
-#define DPRINTF(x...) do { if (swm_debug) fprintf(stderr, x); } while(0)
-#define DNPRINTF(n,x...) do { if (swm_debug & n) fprintf(stderr, x); } while(0)
+#define DPRINTF(x...) do { if (swm_debug) fprintf(stderr, x); } while (0)
+#define DNPRINTF(n,x...) do { if (swm_debug & n) fprintf(stderr, x); } while (0)
#define SWM_D_MISC 0x0001
#define SWM_D_EVENT 0x0002
#define SWM_D_WS 0x0004
#define WIDTH(r) (r)->g.w
#define HEIGHT(r) (r)->g.h
#define SWM_MAX_FONT_STEPS (3)
+#define SWM_EV_PROLOGUE(x) do { XGrabServer(x); } while (0)
+#define SWM_EV_EPILOGUE(x) do { XUngrabServer(x); XFlush(x); } while (0)
#ifndef SWM_LIB
#define SWM_LIB "/usr/local/lib/libswmhack.so"
int bar_extra_running = 0;
int bar_verbose = 1;
int bar_height = 0;
+int stack_enabled = 1;
int clock_enabled = 1;
int title_name_enabled = 0;
int title_class_enabled = 0;
struct layout {
void (*l_stack)(struct workspace *, struct swm_geometry *);
void (*l_config)(struct workspace *, int);
+ u_int32_t flags;
+#define SWM_L_FOCUSPREV (1<<0)
+#define SWM_L_MAPONFOCUS (1<<1)
+ char *name;
} layouts[] = {
/* stack, configure */
- { vertical_stack, vertical_config},
- { horizontal_stack, horizontal_config},
- { max_stack, NULL},
- { NULL, NULL},
+ { vertical_stack, vertical_config, 0, "[|]" },
+ { horizontal_stack, horizontal_config, 0, "[-]" },
+ { max_stack, NULL,
+ SWM_L_FOCUSPREV | SWM_L_MAPONFOCUS, "[ ]"},
+ { NULL, NULL, 0},
};
#define SWM_H_SLICE (32)
char s[SWM_BAR_MAX];
char loc[SWM_BAR_MAX];
char *b;
+ char *stack = "";
if (bar_enabled == 0)
return;
if (r && r->ws)
bar_class_name(s, sizeof s, r->ws->focus);
- snprintf(loc, sizeof loc, "%d:%d %s %s %s",
- x++, r->ws->idx + 1, s, bar_ext, bar_vertext);
+ if (stack_enabled)
+ stack = r->ws->cur_layout->name;
+
+ snprintf(loc, sizeof loc, "%d:%d %s %s %s %s",
+ x++, r->ws->idx + 1, stack, s, bar_ext,
+ bar_vertext);
bar_print(r, loc);
}
}
- XSync(display, False);
alarm(bar_delay);
}
XSetWindowBorder(display, win->id,
win->ws->r->s->c[SWM_S_COLOR_FOCUS].color);
grabbuttons(win, 1);
+ if (win->ws->cur_layout->flags & SWM_L_MAPONFOCUS)
+ XMapRaised(display, win->id);
XSetInputFocus(display, win->id,
RevertToPointerRoot, CurrentTime);
XSync(display, False);
struct swm_region *rr;
int i;
+ /* do nothing if we don't have more than one screen */
+ if (!(ScreenCount(display) > 1 || outputs > 1))
+ return;
+
i = r->s->idx;
switch (args->id) {
case SWM_ARG_ID_CYCLESC_UP:
};
unfocus_all();
XSetInputFocus(display, PointerRoot, RevertToPointerRoot, CurrentTime);
- XWarpPointer(display, None, rr->s[i].root, 0, 0, 0, 0, rr->g.x,
- rr->g.y + bar_enabled ? bar_height : 0);
+ XWarpPointer(display, None, rr->s[i].root, 0, 0, 0, 0, rr->g.x + 1,
+ rr->g.y + bar_enabled + 1 ? bar_height : 0);
}
void
if (winfocus == winlostfocus || winfocus == NULL)
return;
- XMapRaised(display, winfocus->id);
focus_win(winfocus);
- XSync(display, False);
}
void
if (ws->cur_layout->l_stack == NULL)
ws->cur_layout = &layouts[0];
- /*
- * do the ignore enter dance but undo or sometimes an unwanted
- * enter gets discarded
- */
ignore_enter = 1;
-
stack();
focus_win(winfocus);
-
ignore_enter = 0;
}
DNPRINTF(SWM_D_STACK, "max_stack: workspace: %d\n", ws->idx);
+ if (ws == NULL)
+ return;
+
winno = count_win(ws, 0);
if (winno == 0 && count_win(ws, 1) == 0)
return;
win->g.h = wc.height = gg.h;
mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
XConfigureWindow(display, win->id, mask, &wc);
+
+ /* unmap only if we don't have multi screen */
if (win != ws->focus)
- unmap_window(win);
+ if (!(ScreenCount(display) > 1 || outputs > 1))
+ unmap_window(win);
}
}
/* put the last transient on top */
if (wintrans) {
stack_floater(wintrans, ws->r);
- XMapRaised(display, wintrans->id);
focus_win(wintrans); /* override */
}
}
send_to_ws(struct swm_region *r, union arg *args)
{
int wsid = args->id;
- struct ws_win *win = r->ws->focus, *winfocus = NULL;
+ struct ws_win *win = win, *winfocus = NULL;
struct workspace *ws, *nws;
Atom ws_idx_atom = 0;
unsigned char ws_idx_str[SWM_PROPLEN];
+ if (r && r->ws)
+ win = r->ws->focus;
+ else
+ return;
if (win == NULL)
return;
if (TAILQ_FIRST(&ws->winlist) == win)
winfocus = TAILQ_NEXT(win, entry);
else {
- winfocus = TAILQ_PREV(ws->focus, ws_win_list, entry);
+ winfocus = TAILQ_PREV(win, ws_win_list, entry);
if (winfocus == NULL)
winfocus = TAILQ_LAST(&ws->winlist, ws_win_list);
}
- /* out of windows in ws so focus on nws instead */
+ /* out of windows in ws so focus on nws instead if we multi screen */
if (winfocus == NULL)
- winfocus = win;
+ if (ScreenCount(display) > 1 || outputs > 1)
+ winfocus = win;
- unmap_window(win);
+ unmap_window(win);
TAILQ_REMOVE(&ws->winlist, win, entry);
-
TAILQ_INSERT_TAIL(&nws->winlist, win, entry);
win->ws = nws;
nws->restack = 1;
stack();
- focus_win(winfocus);
+ if (winfocus)
+ focus_win(winfocus);
}
void
}
/* key definitions */
-void dummykeyfunc(struct swm_region *r, union arg *args) {};
-void legacyfunc(struct swm_region *r, union arg *args) {};
+void
+dummykeyfunc(struct swm_region *r, union arg *args)
+{
+};
+
+void
+legacyfunc(struct swm_region *r, union arg *args)
+{
+};
struct keyfunc {
char name[SWM_FUNCNAME_LEN];
BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
}
-void
-expose(XEvent *e)
-{
- DNPRINTF(SWM_D_EVENT, "expose: window: %lu\n", e->xexpose.window);
-}
-
-void
-keypress(XEvent *e)
-{
- unsigned int i;
- KeySym keysym;
- XKeyEvent *ev = &e->xkey;
-
- DNPRINTF(SWM_D_EVENT, "keypress: window: %lu\n", ev->window);
-
- keysym = XKeycodeToKeysym(display, (KeyCode)ev->keycode, 0);
- for (i = 0; i < keys_length; i++)
- if (keysym == keys[i].keysym
- && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
- && keyfuncs[keys[i].funcid].func) {
- if (keys[i].funcid == kf_spawn_custom)
- spawn_custom(
- root_to_region(ev->root),
- &(keyfuncs[keys[i].funcid].args),
- keys[i].spawn_name
- );
- else
- keyfuncs[keys[i].funcid].func(
- root_to_region(ev->root),
- &(keyfuncs[keys[i].funcid].args)
- );
- }
-}
-
-void
-buttonpress(XEvent *e)
-{
- XButtonPressedEvent *ev = &e->xbutton;
-
- struct ws_win *win;
- int i, action;
-
- DNPRINTF(SWM_D_EVENT, "buttonpress: window: %lu\n", ev->window);
-
- action = root_click;
- if ((win = find_window(ev->window)) == NULL)
- return;
- else {
- focus_win(win);
- action = client_click;
- }
-
- for (i = 0; i < LENGTH(buttons); i++)
- if (action == buttons[i].action && buttons[i].func &&
- buttons[i].button == ev->button &&
- CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
- buttons[i].func(win, &buttons[i].args);
-}
-
const char *quirkname[] = {
"NONE", /* config string for "no value" */
"FLOAT",
{
char *cp, *name;
int i;
+
if (quirk == NULL)
return (1);
+
cp = qstr;
*quirk = 0;
while ((name = strsep(&cp, SWM_Q_WS)) != NULL) {
setquirk(const char *class, const char *name, const int quirk)
{
int i, j;
+
/* find existing */
for (i = 0; i < quirks_length; i++) {
if (!strcmp(quirks[i].class, class) &&
/* conf file stuff */
#define SWM_CONF_FILE "scrotwm.conf"
-enum { SWM_S_BAR_DELAY, SWM_S_BAR_ENABLED, SWM_S_CLOCK_ENABLED,
- SWM_S_CYCLE_EMPTY, SWM_S_CYCLE_VISIBLE, SWM_S_SS_ENABLED,
- SWM_S_TERM_WIDTH, SWM_S_TITLE_CLASS_ENABLED, SWM_S_TITLE_NAME_ENABLED,
- SWM_S_BAR_FONT, SWM_S_BAR_ACTION, SWM_S_SPAWN_TERM, SWM_S_SS_APP,
- SWM_S_DIALOG_RATIO };
+enum { SWM_S_BAR_DELAY, SWM_S_BAR_ENABLED, SWM_S_STACK_ENABLED,
+ SWM_S_CLOCK_ENABLED, SWM_S_CYCLE_EMPTY, SWM_S_CYCLE_VISIBLE,
+ SWM_S_SS_ENABLED, SWM_S_TERM_WIDTH, SWM_S_TITLE_CLASS_ENABLED,
+ SWM_S_TITLE_NAME_ENABLED, SWM_S_BAR_FONT, SWM_S_BAR_ACTION,
+ SWM_S_SPAWN_TERM, SWM_S_SS_APP, SWM_S_DIALOG_RATIO };
int
setconfvalue(char *selector, char *value, int flags)
case SWM_S_BAR_ENABLED:
bar_enabled = atoi(value);
break;
+ case SWM_S_STACK_ENABLED:
+ stack_enabled = atoi(value);
+ break;
case SWM_S_CLOCK_ENABLED:
clock_enabled = atoi(value);
break;
{ "bar_action", setconfvalue, SWM_S_BAR_ACTION },
{ "bar_delay", setconfvalue, SWM_S_BAR_DELAY },
{ "bind", setconfbinding, 0 },
+ { "stack_enabled", setconfvalue, SWM_S_STACK_ENABLED },
{ "clock_enabled", setconfvalue, SWM_S_CLOCK_ENABLED },
{ "color_focus", setconfcolor, SWM_S_COLOR_FOCUS },
{ "color_unfocus", setconfcolor, SWM_S_COLOR_UNFOCUS },
}
void
+expose(XEvent *e)
+{
+ DNPRINTF(SWM_D_EVENT, "expose: window: %lu\n", e->xexpose.window);
+}
+
+void
+keypress(XEvent *e)
+{
+ unsigned int i;
+ KeySym keysym;
+ XKeyEvent *ev = &e->xkey;
+
+ DNPRINTF(SWM_D_EVENT, "keypress: window: %lu\n", ev->window);
+
+ keysym = XKeycodeToKeysym(display, (KeyCode)ev->keycode, 0);
+ for (i = 0; i < keys_length; i++)
+ if (keysym == keys[i].keysym
+ && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
+ && keyfuncs[keys[i].funcid].func) {
+ if (keys[i].funcid == kf_spawn_custom)
+ spawn_custom(
+ root_to_region(ev->root),
+ &(keyfuncs[keys[i].funcid].args),
+ keys[i].spawn_name
+ );
+ else
+ keyfuncs[keys[i].funcid].func(
+ root_to_region(ev->root),
+ &(keyfuncs[keys[i].funcid].args)
+ );
+ }
+}
+
+void
+buttonpress(XEvent *e)
+{
+ XButtonPressedEvent *ev = &e->xbutton;
+
+ struct ws_win *win;
+ int i, action;
+
+ DNPRINTF(SWM_D_EVENT, "buttonpress: window: %lu\n", ev->window);
+
+ action = root_click;
+ if ((win = find_window(ev->window)) == NULL)
+ return;
+ else {
+ focus_win(win);
+ action = client_click;
+ }
+
+ for (i = 0; i < LENGTH(buttons); i++)
+ if (action == buttons[i].action && buttons[i].func &&
+ buttons[i].button == ev->button &&
+ CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
+ buttons[i].func(win, &buttons[i].args);
+}
+
+void
configurerequest(XEvent *e)
{
XConfigureRequestEvent *ev = &e->xconfigurerequest;
DNPRINTF(SWM_D_EVENT, "destroynotify: window %lu\n", ev->window);
+ SWM_EV_PROLOGUE(display);
+
if ((win = find_window(ev->window)) != NULL) {
/* find a window to focus */
ws = win->ws;
wl = &ws->winlist;
- if (ws->focus == win) {
- if (TAILQ_FIRST(wl) == win)
- winfocus = TAILQ_NEXT(win, entry);
- else {
- winfocus = TAILQ_PREV(ws->focus, ws_win_list, entry);
- if (winfocus == NULL)
- winfocus = TAILQ_LAST(wl, ws_win_list);
+
+ /* if we are transient give focus to parent */
+ if (win->transient)
+ winfocus = find_window(win->transient);
+ else if (ws->focus == win) {
+ /* if in max_stack try harder */
+ if (ws->cur_layout->flags & SWM_L_FOCUSPREV)
+ if (win != ws->focus && win != ws->focus_prev)
+ winfocus = ws->focus_prev;
+
+ /* fallback and normal handling */
+ if (winfocus == NULL) {
+ if (TAILQ_FIRST(wl) == win)
+ winfocus = TAILQ_NEXT(win, entry);
+ else {
+ winfocus = TAILQ_PREV(ws->focus,
+ ws_win_list, entry);
+ if (winfocus == NULL)
+ winfocus = TAILQ_LAST(wl,
+ ws_win_list);
+ }
}
}
if (winfocus)
focus_win(winfocus);
}
+
+ SWM_EV_EPILOGUE(display);
}
void
if (ignore_enter) {
/* eat event(r) to prevent autofocus */
- ignore_enter--;
+ ignore_enter = 0;
return;
}
/*
DNPRINTF(SWM_D_EVENT, "mapnotify: window: %lu\n", ev->window);
+ SWM_EV_PROLOGUE(display);
+
win = find_window(ev->window);
if (win)
set_win_state(win, NormalState);
XRefreshKeyboardMapping(ev);
if (ev->request == MappingKeyboard)
grabkeys();
+
+ SWM_EV_EPILOGUE(display);
}
void
DNPRINTF(SWM_D_EVENT, "maprequest: window: %lu\n",
e->xmaprequest.window);
+ SWM_EV_PROLOGUE(display);
+
if (!XGetWindowAttributes(display, ev->window, &wa))
- return;
+ goto done;
if (wa.override_redirect)
- return;
+ goto done;
manage_window(e->xmaprequest.window);
if (win->ws == r->ws)
focus_win(win);
+
+done:
+ SWM_EV_EPILOGUE(display);
}
void
void
unmapnotify(XEvent *e)
{
- struct ws_win *win, *winfocus;
+ struct ws_win *win, *winfocus = NULL;
struct workspace *ws;
DNPRINTF(SWM_D_EVENT, "unmapnotify: window: %lu\n", e->xunmap.window);
+ SWM_EV_PROLOGUE(display);
+
/* determine if we need to help unmanage this window */
win = find_window(e->xunmap.window);
if (win == NULL)
- return;
+ goto done;
if (win->transient)
- return;
+ goto done;
if (getstate(e->xunmap.window) == NormalState) {
/*
* longer visible due to the app unmapping it so unmanage it
*/
- /* find something to focus */
ws = win->ws;
- winfocus = TAILQ_PREV(win, ws_win_list, entry);
- if (TAILQ_FIRST(&ws->winlist) == win)
- winfocus = TAILQ_NEXT(win, entry);
- else {
- winfocus = TAILQ_PREV(ws->focus, ws_win_list, entry);
- if (winfocus == NULL)
- winfocus = TAILQ_LAST(&ws->winlist, ws_win_list);
+ /* if we are max_stack try harder to focus on something */
+ if (ws->cur_layout->flags & SWM_L_FOCUSPREV)
+ if (win != ws->focus && win != ws->focus_prev)
+ winfocus = ws->focus_prev;
+
+ /* normal and fallback if haven't found anything to focus on */
+ if (winfocus == NULL) {
+ winfocus = TAILQ_PREV(win, ws_win_list, entry);
+ if (TAILQ_FIRST(&ws->winlist) == win)
+ winfocus = TAILQ_NEXT(win, entry);
+ else {
+ winfocus = TAILQ_PREV(ws->focus, ws_win_list,
+ entry);
+ if (winfocus == NULL)
+ winfocus = TAILQ_LAST(&ws->winlist,
+ ws_win_list);
+ }
}
/* trash window and refocus */
stack();
focus_win(winfocus);
}
+
+done:
+ SWM_EV_EPILOGUE(display);
}
void
screenchange(XEvent *e) {
XRRScreenChangeNotifyEvent *xe = (XRRScreenChangeNotifyEvent *)e;
struct swm_region *r;
- struct ws_win *win;
int i;
DNPRINTF(SWM_D_EVENT, "screenchange: %lu\n", xe->root);
/* brute force for now, just re-enumerate the regions */
scan_xrandr(i);
- /* hide any windows that went away */
- TAILQ_FOREACH(r, &screens[i].rl, entry)
- TAILQ_FOREACH(win, &r->ws->winlist, entry)
- unmap_window(win);
-
/* add bars to all regions */
for (i = 0; i < ScreenCount(display); i++)
TAILQ_FOREACH(r, &screens[i].rl, entry)