static const char *cvstag = "$scrotwm$";
-#define SWM_VERSION "0.9.24"
+#define SWM_VERSION "0.9.25"
#include <stdio.h>
#include <stdlib.h>
Atom adelete;
Atom takefocus;
volatile sig_atomic_t running = 1;
+volatile sig_atomic_t restart_wm = 0;
int outputs = 0;
int last_focus_event = FocusOut;
int (*xerrorxlib)(Display *, XErrorEvent *);
int title_name_enabled = 0;
int title_class_enabled = 0;
int focus_mode = SWM_FOCUS_DEFAULT;
+int disable_border = 0;
pid_t bar_pid;
GC bar_gc;
XGCValues bar_gcv;
Window id;
Window transient;
struct ws_win *child_trans; /* transient child window */
- struct swm_geometry g;
+ struct swm_geometry g; /* current geometry */
+ struct swm_geometry g_float; /* geometry when floating */
+ struct swm_geometry rg_float; /* region geom when floating */
+ int g_floatvalid; /* flag: geometry in g_float is valid */
+ int floatmaxed; /* flag: floater was maxed in max_stack */
int floating;
int manual;
int font_size_boundary[SWM_MAX_FONT_STEPS];
{ NULL, NULL, 0, NULL },
};
+/* position of max_stack mode in the layouts array */
+#define SWM_MAX_STACK 2
+
#define SWM_H_SLICE (32)
#define SWM_V_SLICE (32)
#define SWM_ARG_ID_SWAPNEXT (10)
#define SWM_ARG_ID_SWAPPREV (11)
#define SWM_ARG_ID_SWAPMAIN (12)
+#define SWM_ARG_ID_MOVELAST (13)
#define SWM_ARG_ID_MASTERSHRINK (20)
#define SWM_ARG_ID_MASTERGROW (21)
#define SWM_ARG_ID_MASTERADD (22)
break;
}
break;
+ case SIGHUP:
+ restart_wm = 1;
+ break;
case SIGINT:
case SIGTERM:
- case SIGHUP:
case SIGQUIT:
running = 0;
break;
int i, x;
size_t len;
char s[SWM_BAR_MAX];
+ char cn[SWM_BAR_MAX];
char loc[SWM_BAR_MAX];
char *b;
char *stack = "";
for (i = 0; i < ScreenCount(display); i++) {
x = 1;
TAILQ_FOREACH(r, &screens[i].rl, entry) {
+ strlcpy(cn, "", sizeof cn);
if (r && r->ws)
- bar_class_name(s, sizeof s, r->ws->focus);
+ bar_class_name(cn, sizeof cn, r->ws->focus);
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,
+ snprintf(loc, sizeof loc, "%d:%d %s %s%s %s %s",
+ x++, r->ws->idx + 1, stack, s, cn, bar_ext,
bar_vertext);
bar_print(r, loc);
}
other_r = new_ws->r;
if (other_r == NULL) {
- /* if the other workspace is hidden, switch windows */
- if (old_ws->r != NULL)
- old_ws->old_r = old_ws->r;
+ /* the other workspace is hidden, hide this one */
old_ws->r = NULL;
unmap_old = 1;
} else {
+ /* the other ws is visible in another region, exchange them */
other_r->ws_prior = new_ws;
other_r->ws = old_ws;
old_ws->r = other_r;
TAILQ_REMOVE(wl, source, entry);
TAILQ_INSERT_HEAD(wl, source, entry);
break;
+ case SWM_ARG_ID_MOVELAST:
+ TAILQ_REMOVE(wl, source, entry);
+ TAILQ_INSERT_TAIL(wl, source, entry);
+ break;
default:
DNPRINTF(SWM_D_MOVE, "invalid id: %d\n", args->id);
return;
g.h -= bar_height;
}
r->ws->cur_layout->l_stack(r->ws, &g);
+ /* save r so we can track region changes */
+ r->ws->old_r = r;
}
}
if (font_adjusted)
}
void
+store_float_geom(struct ws_win *win, struct swm_region *r)
+{
+ /* retain window geom and region geom */
+ win->g_float.x = win->g.x;
+ win->g_float.y = win->g.y;
+ win->g_float.w = win->g.w;
+ win->g_float.h = win->g.h;
+ win->rg_float.x = r->g.x;
+ win->rg_float.y = r->g.y;
+ win->rg_float.w = r->g.w;
+ win->rg_float.h = r->g.h;
+ win->g_floatvalid = 1;
+}
+
+void
stack_floater(struct ws_win *win, struct swm_region *r)
{
unsigned int mask;
bzero(&wc, sizeof wc);
mask = CWX | CWY | CWBorderWidth | CWWidth | CWHeight;
+
+ /*
+ * to allow windows to change their size (e.g. mplayer fs) only retrieve
+ * geom on ws switches or return from max mode
+ */
+
+ if (win->floatmaxed || (r != r->ws->old_r && win->g_floatvalid) ) {
+ /*
+ * use stored g and rg to set relative position and size
+ * as in old region or before max stack mode
+ */
+ win->g.x = win->g_float.x - win->rg_float.x + r->g.x;
+ win->g.y = win->g_float.y - win->rg_float.y + r->g.y;
+ win->g.w = win->g_float.w;
+ win->g.h = win->g_float.h;
+ win->g_floatvalid = 0;
+ }
+
+ win->floatmaxed = 0;
+
if ((win->quirks & SWM_Q_FULLSCREEN) && (win->g.w >= WIDTH(r)) &&
(win->g.h >= HEIGHT(r)))
wc.border_width = 0;
win->g.w = (double)WIDTH(r) * dialog_ratio;
win->g.h = (double)HEIGHT(r) * dialog_ratio;
}
- wc.width = win->g.w;
- wc.height = win->g.h;
- if (win->manual) {
- wc.x = win->g.x;
- wc.y = win->g.y;
- } else {
- wc.x = (WIDTH(r) - win->g.w) / 2;
- wc.y = (HEIGHT(r) - win->g.h) / 2;
+
+ if (!win->manual) {
+ /*
+ * floaters and transients are auto-centred unless moved
+ * or resized
+ */
+ win->g.x = r->g.x + (WIDTH(r) - win->g.w) / 2;
+ win->g.y = r->g.y + (HEIGHT(r) - win->g.h) / 2;
}
- /* adjust for region */
- if (wc.x < r->g.x)
- wc.x += r->g.x;
- if (wc.y < r->g.y)
- wc.y += r->g.y;
+ /* win can be outside r if new r smaller than old r */
+ /* Ensure top left corner inside r (move probs otherwise) */
+ if (win->g.x < r->g.x )
+ win->g.x = r->g.x;
+ if (win->g.x > r->g.x + r->g.w - 1)
+ win->g.x = (win->g.w > r->g.w) ? r->g.x :
+ (r->g.x + r->g.w - win->g.w - 2);
+ if (win->g.y < r->g.y )
+ win->g.y = r->g.y;
+ if (win->g.y > r->g.y + r->g.h - 1)
+ win->g.y = (win->g.h > r->g.h) ? r->g.y :
+ (r->g.y + r->g.h - win->g.h - 2);
+
+ wc.x = win->g.x;
+ wc.y = win->g.y;
+ wc.width = win->g.w;
+ wc.height = win->g.h;
- win->g.x = wc.x;
- win->g.y = wc.y;
- win->g.w = wc.width;
- win->g.h = wc.height;
+ /*
+ * Retain floater and transient geometry for correct positioning
+ * when ws changes region
+ */
+ store_float_geom(win, r);
DNPRINTF(SWM_D_MISC, "stack_floater: win %lu x %d y %d w %d h %d\n",
win->id, wc.x, wc.y, wc.width, wc.height);
win_g.y += last_h + 2;
bzero(&wc, sizeof wc);
- wc.border_width = 1;
+ if (disable_border && bar_enabled == 0 && winno == 1){
+ wc.border_width = 0;
+ win_g.w += 2;
+ win_g.h += 2;
+ } else
+ wc.border_width = 1;
reconfigure = 0;
if (rot) {
if (win->g.x != win_g.y || win->g.y != win_g.x ||
void
horizontal_stack(struct workspace *ws, struct swm_geometry *g)
{
- DNPRINTF(SWM_D_STACK, "vertical_stack: workspace: %d\n", ws->idx);
+ DNPRINTF(SWM_D_STACK, "horizontal_stack: workspace: %d\n", ws->idx);
stack_master(ws, g, 1, 0);
}
continue;
}
+ if (win->floating && win->floatmaxed == 0 ) {
+ /*
+ * retain geometry for retrieval on exit from
+ * max_stack mode
+ */
+ store_float_geom(win, ws->r);
+ win->floatmaxed = 1;
+ }
+
/* only reconfigure if necessary */
if (win->g.x != gg.x || win->g.y != gg.y || win->g.w != gg.w ||
win->g.h != gg.h) {
bzero(&wc, sizeof wc);
- wc.border_width = 1;
win->g.x = wc.x = gg.x;
win->g.y = wc.y = gg.y;
- win->g.w = wc.width = gg.w;
- win->g.h = wc.height = gg.h;
+ if (bar_enabled){
+ wc.border_width = 1;
+ win->g.w = wc.width = gg.w;
+ win->g.h = wc.height = gg.h;
+ } else {
+ wc.border_width = 0;
+ win->g.w = wc.width = gg.w + 2;
+ win->g.h = wc.height = gg.h + 2;
+ }
mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
XConfigureWindow(display, win->id, mask, &wc);
configreq_win(win);
if (win == NULL)
return;
- win->floating = !win->floating;
- win->manual = 0;
+ /* reject floating toggles in max stack mode */
+ if (r->ws->cur_layout == &layouts[SWM_MAX_STACK])
+ return;
+
+ if (win->floating) {
+ if (!win->floatmaxed) {
+ /* retain position for refloat */
+ store_float_geom(win, r);
+ }
+ win->floating = 0;
+ } else {
+ if (win->g_floatvalid) {
+ /* refloat at last floating relative position */
+ win->g.x = win->g_float.x - win->rg_float.x + r->g.x;
+ win->g.y = win->g_float.y - win->rg_float.y + r->g.y;
+ win->g.w = win->g_float.w;
+ win->g.h = win->g_float.h;
+ }
+ win->floating = 1;
+ }
+
stack();
a.id = SWM_ARG_ID_FOCUSCUR;
focus(win->ws->r, &a);
XEvent ev;
Time time = 0;
struct swm_region *r = win->ws->r;
+ int relx, rely;
+ union arg a;
+
DNPRINTF(SWM_D_MOUSE, "resize: win %lu floating %d trans %lu\n",
win->id, win->floating, win->transient);
if (!(win->transient != 0 || win->floating != 0))
return;
+ /* reject resizes in max mode for floaters (transient ok) */
+ if (win->floatmaxed)
+ return;
+
+ win->manual = 1;
+ /* raise the window = move to last in window list */
+ a.id = SWM_ARG_ID_MOVELAST;
+ swapwin(r, &a);
+ stack();
+
if (XGrabPointer(display, win->id, False, MOUSEMASK, GrabModeAsync,
GrabModeAsync, None, None /* cursor */, CurrentTime) != GrabSuccess)
return;
- XWarpPointer(display, None, win->id, 0, 0, 0, 0, win->g.w, win->g.h);
+
+ /* place pointer at bottom left corner or nearest point inside r */
+ if ( win->g.x + win->g.w < r->g.x + r->g.w - 1)
+ relx = win->g.w;
+ else
+ relx = r->g.x + r->g.w - win->g.x - 2;
+
+ if ( win->g.y + win->g.h < r->g.y + r->g.h - 1)
+ rely = win->g.h;
+ else
+ rely = r->g.y + r->g.h - win->g.y - 2;
+
+ XWarpPointer(display, None, win->id, 0, 0, 0, 0, relx, rely);
do {
XMaskEvent(display, MOUSEMASK | ExposureMask |
SubstructureRedirectMask, &ev);
break;
case MotionNotify:
/* do not allow resize outside of region */
- if (ev.xmotion.y_root < r->g.y ||
- ev.xmotion.y_root >= r->g.y + r->g.h - 1)
- continue;
- if (ev.xmotion.x_root < r->g.x ||
- ev.xmotion.x_root >= r->g.x + r->g.w - 1)
+ if ( ev.xmotion.x_root < r->g.x ||
+ ev.xmotion.x_root > r->g.x + r->g.w - 1 ||
+ ev.xmotion.y_root < r->g.y ||
+ ev.xmotion.y_root > r->g.y + r->g.h - 1)
continue;
if (ev.xmotion.x <= 1)
XSync(display, False);
resize_window(win, args->id);
}
+ store_float_geom(win,r);
+
XWarpPointer(display, None, win->id, 0, 0, 0, 0, win->g.w - 1,
win->g.h - 1);
XUngrabPointer(display, CurrentTime);
{
XEvent ev;
Time time = 0;
- int restack = 0;
struct swm_region *r = win->ws->r;
+ union arg a;
DNPRINTF(SWM_D_MOUSE, "move: win %lu floating %d trans %lu\n",
win->id, win->floating, win->transient);
- if (win->floating == 0) {
+ /* in max_stack mode should only move transients */
+ if (win->ws->cur_layout == &layouts[SWM_MAX_STACK] && !win->transient)
+ return;
+
+ win->manual = 1;
+ if (win->floating == 0 && !win->transient) {
win->floating = 1;
- win->manual = 1;
- restack = 1;
}
+ /* raise the window = move to last in window list */
+ a.id = SWM_ARG_ID_MOVELAST;
+ swapwin(r, &a);
+ stack();
+
if (XGrabPointer(display, win->id, False, MOUSEMASK, GrabModeAsync,
GrabModeAsync, None, None /* cursor */, CurrentTime) != GrabSuccess)
return;
- XWarpPointer(display, None, win->id, 0, 0, 0, 0, 0, 0);
+ XWarpPointer(display, None, win->id, 0, 0, 0, 0, -1, -1);
do {
XMaskEvent(display, MOUSEMASK | ExposureMask |
SubstructureRedirectMask, &ev);
handler[ev.type](&ev);
break;
case MotionNotify:
- /* don't allow to move window out of region */
- if (ev.xmotion.y_root < r->g.y ||
- ev.xmotion.y_root + win->g.h >= r->g.y + r->g.h - 1)
- continue;
- if (ev.xmotion.x_root < r->g.x ||
- ev.xmotion.x_root + win->g.w >= r->g.x + r->g.w - 1)
+ /* don't allow to move window origin out of region */
+ if ( ev.xmotion.x_root < r->g.x ||
+ ev.xmotion.x_root > r->g.x + r->g.w - 1 ||
+ ev.xmotion.y_root < r->g.y ||
+ ev.xmotion.y_root > r->g.y + r->g.h - 1)
continue;
win->g.x = ev.xmotion.x_root;
XSync(display, False);
move_window(win);
}
+ store_float_geom(win,r);
XWarpPointer(display, None, win->id, 0, 0, 0, 0, 0, 0);
XUngrabPointer(display, CurrentTime);
- if (restack)
- stack();
/* drain events */
while (XCheckMaskEvent(display, EnterWindowMask, &ev));
SWM_S_CLOCK_ENABLED, SWM_S_CLOCK_FORMAT, 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_FOCUS_MODE, SWM_S_BAR_FONT, SWM_S_BAR_ACTION, SWM_S_SPAWN_TERM,
- SWM_S_SS_APP, SWM_S_DIALOG_RATIO
+ SWM_S_FOCUS_MODE, SWM_S_DISABLE_BORDER, SWM_S_BAR_FONT,
+ SWM_S_BAR_ACTION, SWM_S_SPAWN_TERM, SWM_S_SS_APP, SWM_S_DIALOG_RATIO
};
int
else
err(1, "focus_mode");
break;
+ case SWM_S_DISABLE_BORDER:
+ disable_border = atoi(value);
+ break;
case SWM_S_BAR_FONT:
free(bar_fonts[0]);
if ((bar_fonts[0] = strdup(value)) == NULL)
{ "title_class_enabled", setconfvalue, SWM_S_TITLE_CLASS_ENABLED },
{ "title_name_enabled", setconfvalue, SWM_S_TITLE_NAME_ENABLED },
{ "focus_mode", setconfvalue, SWM_S_FOCUS_MODE },
+ { "disable_border", setconfvalue, SWM_S_DISABLE_BORDER },
};
win->g.h = win->wa.height;
win->g.x = win->wa.x;
win->g.y = win->wa.y;
+ win->g_floatvalid = 0;
+ win->floatmaxed = 0;
/* Set window properties so we can remember this after reincarnation */
if (ws_idx_atom && prop == NULL &&
void
focusevent(XEvent *e)
{
- DNPRINTF(SWM_D_EVENT, "focusevent: %s window: %lu mode %d detail %d\n",
- ev->type == FocusIn ? "entering" : "leaving",
- ev->window, ev->mode, ev->detail);
#if 0
struct ws_win *win;
u_int32_t mode_detail;
(X(r) + WIDTH(r)) > x &&
Y(r) < (y + h) &&
(Y(r) + HEIGHT(r)) > y) {
+ if (r->ws->r != NULL)
+ r->ws->old_r = r->ws->r;
+ r->ws->r = NULL;
XDestroyWindow(display, r->bar_window);
TAILQ_REMOVE(&s->rl, r, entry);
TAILQ_INSERT_TAIL(&s->orl, r, entry);
if (select(xfd + 1, &rd, NULL, NULL, &tv) == -1)
if (errno != EINTR)
DNPRINTF(SWM_D_MISC, "select failed");
+ if (restart_wm == 1)
+ restart(NULL, NULL);
if (running == 0)
goto done;
if (bar_alarm) {