static const char *cvstag = "$scrotwm$";
-#define SWM_VERSION "0.6"
+#define SWM_VERSION "0.7"
#include <stdio.h>
#include <stdlib.h>
char *bar_argv[] = { NULL, NULL };
int bar_pipe[2];
char bar_ext[SWM_BAR_MAX];
+char bar_vertext[SWM_BAR_MAX];
+int bar_version = 0;
sig_atomic_t bar_alarm = 0;
int bar_delay = 30;
int bar_enabled = 1;
/* terminal + args */
char *spawn_term[] = { "xterm", NULL };
char *spawn_screenshot[] = { "screenshot.sh", NULL, NULL };
+char *spawn_lock[] = { "xlock", NULL };
char *spawn_menu[] = { "dmenu_run", "-fn", NULL, "-nb", NULL,
"-nf", NULL, "-sb", NULL, "-sf", NULL, NULL };
int got_focus;
int floating;
int transient;
+ int manual;
struct workspace *ws; /* always valid */
struct swm_screen *s; /* always valid, never changes */
XWindowAttributes wa;
#define SWM_ARG_ID_CYCLESC_DOWN (15)
#define SWM_ARG_ID_SS_ALL (0)
#define SWM_ARG_ID_SS_WINDOW (1)
+#define SWM_ARG_ID_DONTCENTER (0)
+#define SWM_ARG_ID_CENTER (1)
char **argv;
};
for (i = 0; i < ScreenCount(display); i++) {
x = 1;
TAILQ_FOREACH(r, &screens[i].rl, entry) {
- snprintf(loc, sizeof loc, "%s %d:%d %s",
- s, x++, r->ws->idx + 1, bar_ext);
+ snprintf(loc, sizeof loc, "%s %d:%d %s %s",
+ s, x++, r->ws->idx + 1, bar_ext, bar_vertext);
bar_print(r, loc);
}
}
}
void
+version(struct swm_region *r, union arg *args)
+{
+ bar_version = !bar_version;
+ if (bar_version)
+ strlcpy(bar_vertext, cvstag, sizeof bar_vertext);
+ else
+ strlcpy(bar_vertext, "", sizeof bar_vertext);
+ bar_update();
+}
+
+void
config_win(struct ws_win *win)
{
XConfigureEvent ce;
}
wc.width = win->g.w;
wc.height = win->g.h;
- wc.x = (WIDTH(r) - win->g.w) / 2;
- wc.y = (HEIGHT(r) - win->g.h) / 2;
+ 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;
+ }
DNPRINTF(SWM_D_STACK, "stack_floater: win %lu x %d y %d w %d h %d\n",
win->id, wc.x, wc.y, wc.width, wc.height);
extra = r_g.h - (colno * hrh);
win_g.h = hrh - 2;
+ /* stack all the tiled windows */
i = j = 0;
TAILQ_FOREACH(win, &ws->winlist, entry) {
+ if (win->transient != 0 || win->floating != 0)
+ continue;
+
if (split && i == split) {
colno = winno - split;
hrh = (r_g.h / colno);
else
win_g.y += last_h + 2;
- if (win->transient != 0 || win->floating != 0)
- stack_floater(win, ws->r);
- else {
- bzero(&wc, sizeof wc);
- wc.border_width = 1;
- if (rot) {
- win->g.x = wc.x = win_g.y;
- win->g.y = wc.y = win_g.x;
- win->g.w = wc.width = win_g.h;
- win->g.h = wc.height = win_g.w;
- } else {
- win->g.x = wc.x = win_g.x;
- win->g.y = wc.y = win_g.y;
- win->g.w = wc.width = win_g.w;
- win->g.h = wc.height = win_g.h;
- }
- mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
- XConfigureWindow(display, win->id, mask, &wc);
- /*
- fprintf(stderr, "vertical_stack: win %d x %d y %d w %d h %d bw %d\n", win->id, win->g.x, win->g.y, win->g.w , win->g.h, wc.border_width);
- */
+ bzero(&wc, sizeof wc);
+ wc.border_width = 1;
+ if (rot) {
+ win->g.x = wc.x = win_g.y;
+ win->g.y = wc.y = win_g.x;
+ win->g.w = wc.width = win_g.h;
+ win->g.h = wc.height = win_g.w;
+ } else {
+ win->g.x = wc.x = win_g.x;
+ win->g.y = wc.y = win_g.y;
+ win->g.w = wc.width = win_g.w;
+ win->g.h = wc.height = win_g.h;
}
-
+ mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
+ XConfigureWindow(display, win->id, mask, &wc);
XMapRaised(display, win->id);
+ /*
+ fprintf(stderr, "vertical_stack: win %d x %d y %d w %d h %d bw %d\n", win->id, win->g.x, win->g.y, win->g.w , win->g.h, wc.border_width);
+ */
+
last_h = win_g.h;
i++;
j++;
}
+ /* now, stack all the floaters and transients */
+ TAILQ_FOREACH(win, &ws->winlist, entry) {
+ if (win->transient == 0 && win->floating == 0)
+ continue;
+
+ stack_floater(win, ws->r);
+ XMapRaised(display, win->id);
+ }
+
if (winfocus)
focus_win(winfocus); /* has to be done outside of the loop */
}
Atom ws_idx_atom = 0;
unsigned char ws_idx_str[SWM_PROPLEN];
+ if (win == NULL)
+ return;
+
DNPRINTF(SWM_D_MOVE, "send_to_ws: win: %lu\n", win->id);
ws = win->ws;
spawn(r, &a);
}
+void
+floating_toggle(struct swm_region *r, union arg *args)
+{
+ struct ws_win *win = cur_focus;
+
+ if (win == NULL)
+ return;
+
+ win->floating = !win->floating;
+ win->manual = 0;
+ stack();
+ focus_win(win);
+}
+
/* key definitions */
struct key {
unsigned int mod;
{ MODKEY | ShiftMask, XK_x, wkill, {0} },
{ MODKEY, XK_s, screenshot, {.id = SWM_ARG_ID_SS_ALL} },
{ MODKEY | ShiftMask, XK_s, screenshot, {.id = SWM_ARG_ID_SS_WINDOW} },
+ { MODKEY, XK_t, floating_toggle,{0} },
+ { MODKEY | ShiftMask, XK_v, version, {0} },
+ { MODKEY | ShiftMask, XK_Delete, spawn, {.argv = spawn_lock} },
};
void
-resize_window(struct ws_win *win)
+resize_window(struct ws_win *win, int center)
{
unsigned int mask;
XWindowChanges wc;
r = root_to_region(win->wa.root);
bzero(&wc, sizeof wc);
- mask = CWX | CWY | CWBorderWidth | CWWidth | CWHeight;
+ mask = CWBorderWidth | CWWidth | CWHeight;
wc.border_width = 1;
wc.width = win->g.w;
wc.height = win->g.h;
- wc.x = (WIDTH(r) - win->g.w) / 2;
- wc.y = (HEIGHT(r) - win->g.h) / 2;
+ if (center == SWM_ARG_ID_CENTER) {
+ wc.x = (WIDTH(r) - win->g.w) / 2;
+ wc.y = (HEIGHT(r) - win->g.h) / 2;
+ mask |= CWX | CWY;
+ }
DNPRINTF(SWM_D_STACK, "resize_window: win %lu x %d y %d w %d h %d\n",
win->id, wc.x, wc.y, wc.width, wc.height);
}
void
-resize(struct ws_win *win)
+resize(struct ws_win *win, union arg *args)
{
XEvent ev;
- int nw, nh;
+ Time time = 0;
- DNPRINTF(SWM_D_MOUSE, "resize: win %d floating %d trans %d\n",
+ DNPRINTF(SWM_D_MOUSE, "resize: win %lu floating %d trans %d\n",
win->id, win->floating, win->transient);
if (!(win->transient != 0 || win->floating != 0))
handler[ev.type](&ev);
break;
case MotionNotify:
- XSync(display, False);
- win->g.w = nw = ev.xmotion.x;
- win->g.h = nh = ev.xmotion.y;
- resize_window(win);
+ if (ev.xmotion.x < 0)
+ ev.xmotion.x = 0;
+ if (ev.xmotion.y < 0)
+ ev.xmotion.y = 0;
+ win->g.w = ev.xmotion.x;
+ win->g.h = ev.xmotion.y;
+
+ /* not free, don't sync more than 60 times / second */
+ if ((ev.xmotion.time - time) > (1000 / 60) ) {
+ time = ev.xmotion.time;
+ XSync(display, False);
+ resize_window(win, args->id);
+ }
break;
}
} while (ev.type != ButtonRelease);
+ if (time) {
+ XSync(display, False);
+ resize_window(win, args->id);
+ }
XWarpPointer(display, None, win->id, 0, 0, 0, 0, win->g.w - 1,
win->g.h - 1);
XUngrabPointer(display, CurrentTime);
}
void
-click(struct ws_win *win, union arg *args)
+move_window(struct ws_win *win)
{
- DNPRINTF(SWM_D_MOUSE, "click: button: %d\n", args->id);
+ unsigned int mask;
+ XWindowChanges wc;
+ struct swm_region *r;
- switch (args->id) {
- case Button1:
- break;
- case Button2:
- break;
- case Button3:
- resize(win);
- break;
- default:
+ r = root_to_region(win->wa.root);
+ bzero(&wc, sizeof wc);
+ mask = CWX | CWY;
+ wc.x = win->g.x;
+ wc.y = win->g.y;
+
+ DNPRINTF(SWM_D_STACK, "move_window: win %lu x %d y %d w %d h %d\n",
+ win->id, wc.x, wc.y, wc.width, wc.height);
+
+ XConfigureWindow(display, win->id, mask, &wc);
+ config_win(win);
+}
+
+void
+move(struct ws_win *win, union arg *args)
+{
+ XEvent ev;
+ Time time = 0;
+ int restack = 0;
+
+ DNPRINTF(SWM_D_MOUSE, "move: win %lu floating %d trans %d\n",
+ win->id, win->floating, win->transient);
+
+ if (win->floating == 0) {
+ win->floating = 1;
+ win->manual = 1;
+ restack = 1;
+ }
+
+ 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);
+ do {
+ XMaskEvent(display, MOUSEMASK | ExposureMask |
+ SubstructureRedirectMask, &ev);
+ switch(ev.type) {
+ case ConfigureRequest:
+ case Expose:
+ case MapRequest:
+ handler[ev.type](&ev);
+ break;
+ case MotionNotify:
+ win->g.x = ev.xmotion.x_root;
+ win->g.y = ev.xmotion.y_root;
+
+ /* not free, don't sync more than 60 times / second */
+ if ((ev.xmotion.time - time) > (1000 / 60) ) {
+ time = ev.xmotion.time;
+ XSync(display, False);
+ move_window(win);
+ }
+ break;
+ }
+ } while (ev.type != ButtonRelease);
+ if (time) {
+ XSync(display, False);
+ move_window(win);
}
+ XWarpPointer(display, None, win->id, 0, 0, 0, 0, 0, 0);
+ XUngrabPointer(display, CurrentTime);
+ if (restack)
+ stack();
+
+ /* drain events */
+ while (XCheckMaskEvent(display, EnterWindowMask, &ev));
}
/* mouse */
union arg args;
} buttons[] = {
/* action key mouse button func args */
- { client_click, MODKEY, Button3, click, {.id=Button3} },
+ { client_click, MODKEY, Button3, resize, {.id = SWM_ARG_ID_DONTCENTER} },
+ { client_click, MODKEY | ShiftMask, Button3, resize, {.id = SWM_ARG_ID_CENTER} },
+ { client_click, MODKEY, Button1, move, {0} },
};
void
if ((win = calloc(1, sizeof(struct ws_win))) == NULL)
errx(1, "calloc: failed to allocate memory for new window");
+ /* Get all the window data in one shot */
ws_idx_atom = XInternAtom(display, "_SWM_WS", False);
if (ws_idx_atom)
XGetWindowProperty(display, id, ws_idx_atom, 0, SWM_PROPLEN,
False, XA_STRING, &type, &format, &nitems, &bytes, &prop);
-
XGetWindowAttributes(display, id, &win->wa);
+ XGetTransientForHint(display, id, &trans);
+ XGetWMNormalHints(display, id, &win->sh, &mask); /* XXX function? */
+ if (trans) {
+ win->transient = trans;
+ DNPRINTF(SWM_D_MISC, "manage_window: win %u transient %u\n",
+ (unsigned)win->id, win->transient);
+ }
+
+ /*
+ * Figure out where to put the window. If it was previously assigned to
+ * a workspace (either by spawn() or manually moving), and isn't
+ * transient, * put it in the same workspace
+ */
r = root_to_region(win->wa.root);
- /* If the window was managed before, put it in the same workspace */
- if (prop) {
+ if (prop && win->transient == 0) {
DNPRINTF(SWM_D_PROP, "got property _SWM_WS=%s\n", prop);
ws_idx = strtonum(prop, 0, 9, &errstr);
- if (errstr)
+ if (errstr) {
DNPRINTF(SWM_D_EVENT, "window idx is %s: %s",
errstr, prop);
+ }
ws = &r->s->ws[ws_idx];
} else
ws = r->ws;
+ /* set up the window layout */
win->id = id;
win->ws = ws;
win->s = r->s; /* this never changes */
TAILQ_INSERT_TAIL(&ws->winlist, win, entry);
- XGetTransientForHint(display, win->id, &trans);
- if (trans) {
- win->transient = trans;
- DNPRINTF(SWM_D_MISC, "manage_window: win %u transient %u\n",
- (unsigned)win->id, win->transient);
- }
win->g.w = win->wa.width;
win->g.h = win->wa.height;
win->g.x = win->wa.x;
win->g.y = win->wa.y;
- XGetWMNormalHints(display, win->id, &win->sh, &mask); /* XXX function? */
-
+ /* Set window properties so we can remember this after reincarnation */
if (ws_idx_atom && prop == NULL &&
snprintf(ws_idx_str, SWM_PROPLEN, "%d", ws->idx) < SWM_PROPLEN) {
DNPRINTF(SWM_D_PROP, "setting property _SWM_WS to %s\n",