#include <X11/Xlib.h>
#include <X11/Xproto.h>
#include <X11/Xutil.h>
+#ifdef XINERAMA
+#include <X11/extensions/Xinerama.h>
+#endif
/* macros */
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
-#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask))
-#define LENGTH(x) (sizeof x / sizeof x[0])
-#define MAXTAGLEN 16
-#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
+#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask))
+#define LENGTH(x) (sizeof x / sizeof x[0])
+#define MAXTAGLEN 16
+#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
/* enums */
-enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
-enum { ColBorder, ColFG, ColBG, ColLast }; /* color */
-enum { NetSupported, NetWMName, NetLast }; /* EWMH atoms */
+enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
+enum { ColBorder, ColFG, ColBG, ColLast }; /* color */
+enum { NetSupported, NetWMName, NetLast }; /* EWMH atoms */
enum { WMProtocols, WMDelete, WMName, WMState, WMLast };/* default atoms */
/* typedefs */
void run(void);
void scan(void);
void setclientstate(Client *c, long state);
+void setmfact(const char *arg);
void setup(void);
void spawn(const char *arg);
void tag(const char *arg);
unsigned int textnw(const char *text, unsigned int len);
unsigned int textw(const char *text);
+void tile(void);
+void tileresize(Client *c, int x, int y, int w, int h);
+void togglebar(const char *arg);
void togglefloating(const char *arg);
void togglelayout(const char *arg);
void toggletag(const char *arg);
void updatebar(void);
void updategeom(void);
void updatesizehints(Client *c);
+void updatetilegeom(void);
void updatetitle(Client *c);
void updatewmhints(Client *c);
void view(const char *arg);
-void viewprevtag(const char *arg); /* views previous selected tags */
+void viewprevtag(const char *arg);
int xerror(Display *dpy, XErrorEvent *ee);
int xerrordummy(Display *dpy, XErrorEvent *ee);
int xerrorstart(Display *dpy, XErrorEvent *ee);
/* variables */
char stext[256];
int screen, sx, sy, sw, sh;
-int (*xerrorxlib)(Display *, XErrorEvent *);
int bx, by, bw, bh, blw, wx, wy, ww, wh;
+int mx, my, mw, mh, tx, ty, tw, th;
int seltags = 0;
+int (*xerrorxlib)(Display *, XErrorEvent *);
unsigned int numlockmask = 0;
void (*handler[LASTEvent]) (XEvent *) = {
[ButtonPress] = buttonpress,
restack();
movemouse(c);
}
- else if(ev->button == Button2) {
- if(lt->arrange && c->isfloating)
- togglefloating(NULL);
- }
+ else if(ev->button == Button2)
+ togglefloating(NULL);
else if(ev->button == Button3 && !c->isfixed) {
restack();
resizemouse(c);
c->bw = wa->border_width;
}
else {
- if(c->x + c->w + 2 * c->bw > wx + ww)
- c->x = wx + ww - c->w - 2 * c->bw;
- if(c->y + c->h + 2 * c->bw > wy + wh)
- c->y = wy + wh - c->h - 2 * c->bw;
- c->x = MAX(c->x, wx);
- c->y = MAX(c->y, wy);
- c->bw = BORDERPX;
+ if(c->x + c->w + 2 * c->bw > sx + sw)
+ c->x = sx + sw - c->w - 2 * c->bw;
+ if(c->y + c->h + 2 * c->bw > sy + sh)
+ c->y = sy + sh - c->h - 2 * c->bw;
+ c->x = MAX(c->x, sx);
+ c->y = MAX(c->y, by == 0 ? bh : sy);
+ c->bw = borderpx;
}
wc.border_width = c->bw;
XSync(dpy, False);
nx = ocx + (ev.xmotion.x - x1);
ny = ocy + (ev.xmotion.y - y1);
- if(abs(wx - nx) < SNAP)
- nx = wx;
- else if(abs((wx + ww) - (nx + c->w + 2 * c->bw)) < SNAP)
- nx = wx + ww - c->w - 2 * c->bw;
- if(abs(wy - ny) < SNAP)
- ny = wy;
- else if(abs((wy + wh) - (ny + c->h + 2 * c->bw)) < SNAP)
- ny = wy + wh - c->h - 2 * c->bw;
- if(!c->isfloating && lt->arrange && (abs(nx - c->x) > SNAP || abs(ny - c->y) > SNAP))
- togglefloating(NULL);
+ if(snap && nx >= wx && nx <= wx + ww
+ && ny >= wy && ny <= wy + wh) {
+ if(abs(wx - nx) < snap)
+ nx = wx;
+ else if(abs((wx + ww) - (nx + c->w + 2 * c->bw)) < snap)
+ nx = wx + ww - c->w - 2 * c->bw;
+ if(abs(wy - ny) < snap)
+ ny = wy;
+ else if(abs((wy + wh) - (ny + c->h + 2 * c->bw)) < snap)
+ ny = wy + wh - c->h - 2 * c->bw;
+ if(!c->isfloating && lt->arrange && (abs(nx - c->x) > snap || abs(ny - c->y) > snap))
+ togglefloating(NULL);
+ }
if(!lt->arrange || c->isfloating)
resize(c, nx, ny, c->w, c->h, False);
break;
XSync(dpy, False);
nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
- if(!c->isfloating && lt->arrange && (abs(nw - c->w) > SNAP || abs(nh - c->h) > SNAP)) {
- togglefloating(NULL);
+
+ if(snap && nw >= wx && nw <= wx + ww
+ && nh >= wy && nh <= wy + wh) {
+ if(!c->isfloating && lt->arrange
+ && (abs(nw - c->w) > snap || abs(nh - c->h) > snap))
+ togglefloating(NULL);
}
if(!lt->arrange || c->isfloating)
resize(c, c->x, c->y, nw, nh, True);
PropModeReplace, (unsigned char *)data, 2);
}
+void
+setmfact(const char *arg) {
+ double d;
+
+ if(!arg || lt->arrange != tile)
+ return;
+ else {
+ d = strtod(arg, NULL);
+ if(arg[0] == '-' || arg[0] == '+')
+ d += mfact;
+ if(d < 0.1 || d > 0.9)
+ return;
+ mfact = d;
+ }
+ updatetilegeom();
+ arrange();
+}
+
void
setup(void) {
unsigned int i, w;
return textnw(text, strlen(text)) + dc.font.height;
}
+void
+tile(void) {
+ int x, y, h, w;
+ unsigned int i, n;
+ Client *c;
+
+ for(n = 0, c = nextunfloating(clients); c; c = nextunfloating(c->next), n++);
+ if(n == 0)
+ return;
+
+ /* master */
+ c = nextunfloating(clients);
+
+ if(n == 1)
+ tileresize(c, wx, wy, ww - 2 * c->bw, wh - 2 * c->bw);
+ else
+ tileresize(c, mx, my, mw - 2 * c->bw, mh - 2 * c->bw);
+
+ if(--n == 0)
+ return;
+
+ /* tile stack */
+ x = (tx > c->x + c->w) ? c->x + c->w + 2 * c->bw : tw;
+ y = ty;
+ w = (tx > c->x + c->w) ? wx + ww - x : tw;
+ h = th / n;
+ if(h < bh)
+ h = th;
+
+ for(i = 0, c = nextunfloating(c->next); c; c = nextunfloating(c->next), i++) {
+ if(i + 1 == n) /* remainder */
+ tileresize(c, x, y, w - 2 * c->bw, (ty + th) - y - 2 * c->bw);
+ else
+ tileresize(c, x, y, w - 2 * c->bw, h - 2 * c->bw);
+ if(h != th)
+ y = c->y + c->h + 2 * c->bw;
+ }
+}
+
+void
+tileresize(Client *c, int x, int y, int w, int h) {
+ resize(c, x, y, w, h, resizehints);
+ if(resizehints && ((c->h < bh) || (c->h > h) || (c->w < bh) || (c->w > w)))
+ /* client doesn't accept size constraints */
+ resize(c, x, y, w, h, False);
+}
+
+void
+togglebar(const char *arg) {
+ showbar = !showbar;
+ updategeom();
+ updatebar();
+ arrange();
+}
+
void
togglefloating(const char *arg) {
if(!sel)
void
updategeom(void) {
- unsigned int i;
-
- /* bar geometry */
- bx = 0;
- by = 0;
- bw = sw;
+ int i;
+#ifdef XINERAMA
+ XineramaScreenInfo *info = NULL;
/* window area geometry */
- wx = sx;
- wy = sy + bh;
- ww = sw;
- wh = sh - bh;
+ if(XineramaIsActive(dpy)) {
+ info = XineramaQueryScreens(dpy, &i);
+ wx = info[0].x_org;
+ wy = showbar && topbar ? info[0].y_org + bh : info[0].y_org;
+ ww = info[0].width;
+ wh = showbar ? info[0].height - bh : info[0].height;
+ XFree(info);
+ }
+ else
+#endif
+ {
+ wx = sx;
+ wy = showbar && topbar ? sy + bh : sy;
+ ww = sw;
+ wh = showbar ? sh - bh : sh;
+ }
+
+ /* bar geometry*/
+ bx = wx;
+ by = showbar ? (topbar ? 0 : wy + wh) : -bh;
+ bw = ww;
/* update layout geometries */
for(i = 0; i < LENGTH(layouts); i++)
&& c->maxw == c->minw && c->maxh == c->minh);
}
+void
+updatetilegeom(void) {
+ /* master area geometry */
+ mx = wx;
+ my = wy;
+ mw = mfact * ww;
+ mh = wh;
+
+ /* tile area geometry */
+ tx = mx + mw;
+ ty = wy;
+ tw = ww - mw;
+ th = wh;
+}
+
void
updatetitle(Client *c) {
if(!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
return -1;
}
+void
+zoom(const char *arg) {
+ Client *c = sel;
+
+ if(c == nextunfloating(clients))
+ if(!c || !(c = nextunfloating(c->next)))
+ return;
+ if(lt->arrange == tile && !sel->isfloating) {
+ detach(c);
+ attach(c);
+ focus(c);
+ }
+ arrange();
+}
+
int
main(int argc, char *argv[]) {
if(argc == 2 && !strcmp("-v", argv[1]))