#endif /* XINERAMA */
/* macros */
+#define D if(1)
#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask))
#define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH))
} Layout;
struct Monitor {
- const char *ltsymbol;
+ char ltsymbol[16];
float mfact;
int num;
int by; /* bar geometry */
/* function declarations */
static void applyrules(Client *c);
static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact);
-static void arrange(void);
+static void arrange(Monitor *m);
+static void arrangemon(Monitor *m);
static void attach(Client *c);
static void attachstack(Client *c);
static void buttonpress(XEvent *e);
static void checkotherwm(void);
static void cleanup(void);
-static void cleanupmons(void);
+static void cleanupmon(Monitor *mon);
static void clearurgent(Client *c);
static void configure(Client *c);
static void configurenotify(XEvent *e);
static void configurerequest(XEvent *e);
+static Monitor *createmon(void);
static void destroynotify(XEvent *e);
static void detach(Client *c);
static void detachstack(Client *c);
}
void
-arrange(void) {
- Monitor *m;
-
- for(m = mons; m; m = m->next)
+arrange(Monitor *m) {
+ if(m)
+ showhide(m->stack);
+ else for(m = mons; m; m = m->next)
showhide(m->stack);
focus(NULL);
- for(m = mons; m; m = m->next) {
- m->ltsymbol = m->lt[m->sellt]->symbol;
- if(m->lt[m->sellt]->arrange)
- m->lt[m->sellt]->arrange(m);
- restack(m);
- }
+ if(m)
+ arrangemon(m);
+ else for(m = mons; m; m = m->next)
+ arrangemon(m);
+}
+
+void
+arrangemon(Monitor *m) {
+ strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol);
+ if(m->lt[m->sellt]->arrange)
+ m->lt[m->sellt]->arrange(m);
+ restack(m);
}
void
XFreeCursor(dpy, cursor[CurNormal]);
XFreeCursor(dpy, cursor[CurResize]);
XFreeCursor(dpy, cursor[CurMove]);
- cleanupmons();
+ while(mons)
+ cleanupmon(mons);
XSync(dpy, False);
XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
}
void
-cleanupmons(void) {
+cleanupmon(Monitor *mon) {
Monitor *m;
- while(mons) {
- m = mons->next;
- XUnmapWindow(dpy, mons->barwin);
- XDestroyWindow(dpy, mons->barwin);
- free(mons);
- mons = m;
+ if(mon == mons)
+ mons = mons->next;
+ else {
+ for(m = mons; m && m->next != mon; m = m->next);
+ m->next = mon->next;
}
+ XUnmapWindow(dpy, mon->barwin);
+ XDestroyWindow(dpy, mon->barwin);
+ free(mon);
}
void
updatebars();
for(m = mons; m; m = m->next)
XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
- arrange();
+ arrange(NULL);
}
}
}
XSync(dpy, False);
}
+Monitor *
+createmon(void) {
+ Monitor *m;
+
+ if(!(m = (Monitor *)calloc(1, sizeof(Monitor))))
+ die("fatal: could not malloc() %u bytes\n", sizeof(Monitor));
+ m->tagset[0] = m->tagset[1] = 1;
+ m->mfact = mfact;
+ m->showbar = showbar;
+ m->topbar = topbar;
+ m->lt[0] = &layouts[0];
+ m->lt[1] = &layouts[1 % LENGTH(layouts)];
+ strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
+ return m;
+}
+
void
destroynotify(XEvent *e) {
Client *c;
focus(Client *c) {
if(!c || !ISVISIBLE(c))
for(c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
- if(selmon->sel)
- unfocus(selmon->sel);
+// if(selmon->sel)
+// unfocus(selmon->sel);
if(c) {
if(c->mon != selmon)
selmon = c->mon;
return ret;
}
+#ifdef XINERAMA
+static Bool
+isuniquegeom(XineramaScreenInfo *unique, size_t len, XineramaScreenInfo *info) {
+ unsigned int i;
+
+ for(i = 0; i < len; i++)
+ if(unique[i].x_org == info->x_org && unique[i].y_org == info->y_org
+ && unique[i].width == info->width && unique[i].height == info->height)
+ return False;
+ return True;
+}
+#endif /* XINERAMA */
+
void
keypress(XEvent *e) {
unsigned int i;
XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
XMapWindow(dpy, c->win);
setclientstate(c, NormalState);
- arrange();
+ arrange(c->mon);
}
void
void
monocle(Monitor *m) {
- static char ntext[8];
unsigned int n = 0;
Client *c;
for(c = m->clients; c; c = c->next)
if(ISVISIBLE(c))
n++;
- if(n > 0) { /* override layout symbol */
- snprintf(ntext, sizeof ntext, "[%d]", n);
- m->ltsymbol = ntext;
- }
+ if(n > 0) /* override layout symbol */
+ snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n);
for(c = nexttiled(m->clients); c; c = nexttiled(c->next))
resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, False);
}
case XA_WM_TRANSIENT_FOR:
XGetTransientForHint(dpy, c->win, &trans);
if(!c->isfloating && (c->isfloating = (wintoclient(trans) != NULL)))
- arrange();
+ arrange(c->mon);
break;
case XA_WM_NORMAL_HINTS:
updatesizehints(c);
XEvent ev;
XWindowChanges wc;
- drawbars();
+ drawbar(m);
if(!m->sel)
return;
if(m->sel->isfloating || !m->lt[m->sellt]->arrange)
void
run(void) {
XEvent ev;
-
+ static const char *evname[LASTEvent] = {
+ [ButtonPress] = "buttonpress",
+ [ConfigureRequest] = "configurerequest",
+ [ConfigureNotify] = "configurenotify",
+ [DestroyNotify] = "destroynotify",
+ [EnterNotify] = "enternotify",
+ [Expose] = "expose",
+ [FocusIn] = "focusin",
+ [KeyPress] = "keypress",
+ [MappingNotify] = "mappingnotify",
+ [MapRequest] = "maprequest",
+ [PropertyNotify] = "propertynotify",
+ [UnmapNotify] = "unmapnotify"
+ };
/* main event loop */
XSync(dpy, False);
- while(running && !XNextEvent(dpy, &ev))
+ while(running && !XNextEvent(dpy, &ev)) {
+ D fprintf(stderr, "run event %s\n", evname[ev.type]);
if(handler[ev.type])
handler[ev.type](&ev); /* call handler */
+ }
}
void
attach(c);
attachstack(c);
focus(NULL);
- arrange();
+ arrange(NULL);
}
void
selmon->sellt ^= 1;
if(arg && arg->v)
selmon->lt[selmon->sellt] = (Layout *)arg->v;
+ strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
if(selmon->sel)
- arrange();
+ arrange(selmon);
else
- drawbars();
+ drawbar(selmon);
}
/* arg > 1.0 will set mfact absolutly */
if(f < 0.1 || f > 0.9)
return;
selmon->mfact = f;
- arrange();
+ arrange(selmon);
}
void
tag(const Arg *arg) {
if(selmon->sel && arg->ui & TAGMASK) {
selmon->sel->tags = arg->ui & TAGMASK;
- arrange();
+ arrange(selmon);
}
}
selmon->showbar = !selmon->showbar;
updatebarpos(selmon);
XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
- arrange();
+ arrange(selmon);
}
void
if(selmon->sel->isfloating)
resize(selmon->sel, selmon->sel->x, selmon->sel->y,
selmon->sel->w, selmon->sel->h, False);
- arrange();
+ arrange(selmon);
}
void
newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
if(newtags) {
selmon->sel->tags = newtags;
- arrange();
+ arrange(selmon);
}
}
if(newtagset) {
selmon->tagset[selmon->seltags] = newtagset;
- arrange();
+ arrange(selmon);
}
}
void
unmanage(Client *c, Bool destroyed) {
+ Monitor *m = c->mon;
XWindowChanges wc;
/* The server grab construct avoids race conditions. */
}
free(c);
focus(NULL);
- arrange();
+ arrange(m);
}
void
Bool
updategeom(void) {
- int i, j, nn = 1, n = 1;
- Client *c;
- Monitor *newmons = NULL, *m = NULL, *tm;
-
- /* TODO:
- * This function needs to be seriously re-designed:
- *
- * #ifdef XINERAMA
- * 1. Determine number of already existing monitors n
- * 2. Determine number of monitors Xinerama reports nn
- * 3. if(n <= nn) {
- * if(n < nn) {
- * append nn-n monitors to current struct
- * flag dirty
- * }
- * for(i = 0; i < nn; i++) {
- * if(oldgeom != newgeom) {
- * apply newgeom;
- * flag dirty;
- * }
- * }
- * }
- * else {
- * detach all clients
- * destroy current monitor struct
- * create new monitor struct
- * attach all clients to first monitor
- * flag dirty;
- * }
- * return dirty flag to caller
- * if dirty is seen by caller:
- * re-arrange bars/pixmaps
- * arrange()
- * #else
- * don't share between XINERAMA and non-XINERAMA handling if it gets
- * too ugly
- * #endif
- */
+ Bool dirty = False;
+
#ifdef XINERAMA
- XineramaScreenInfo *info = NULL;
- Bool *flags = NULL;
-
- if(XineramaIsActive(dpy))
- info = XineramaQueryScreens(dpy, &n);
- flags = (Bool *)malloc(sizeof(Bool) * n);
- for(i = 0; i < n; i++)
- flags[i] = False;
- /* next double-loop seeks any combination of retrieved Xinerama info
- * with existing monitors, this is used to avoid unnecessary
- * re-allocations of monitor structs */
- for(i = 0, nn = n; i < n; i++)
- for(j = 0, m = mons; m; m = m->next, j++)
- if(!flags[j]) {
- if((flags[j] = (
- info[i].x_org == m->mx
- && info[i].y_org == m->my
- && info[i].width == m->mw
- && info[i].height == m->mh)
- ))
- --nn;
- }
- if(nn == 0) { /* no need to re-allocate monitors */
- j = 0;
- for(i = 0, m = mons; m; m = m->next, i++) {
- m->num = info[i].screen_number;
- if(info[i].x_org != m->mx
- || info[i].y_org != m->my
- || info[i].width != m->mw
- || info[i].height != m->mh)
- {
- m->mx = m->wx = info[i].x_org;
- m->my = m->wy = info[i].y_org;
- m->mw = m->ww = info[i].width;
- m->mh = m->wh = info[i].height;
- updatebarpos(m);
- j++;
- }
- }
+ if(XineramaIsActive(dpy)) {
+ int i, j, n, nn;
+ Client *c;
+ Monitor *m;
+ XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn);
+ XineramaScreenInfo *unique = NULL;
+
+ info = XineramaQueryScreens(dpy, &nn);
+ for(n = 0, m = mons; m; m = m->next, n++);
+ /* only consider unique geometries as separate screens */
+ if(!(unique = (XineramaScreenInfo *)malloc(sizeof(XineramaScreenInfo) * nn)))
+ die("fatal: could not malloc() %u bytes\n", sizeof(XineramaScreenInfo) * nn);
+ for(i = 0, j = 0; i < nn; i++)
+ if(isuniquegeom(unique, j, &info[i]))
+ memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo));
XFree(info);
- free(flags);
- return j > 0;
- }
- /* next algorithm only considers unique geometries as separate screens */
- for(i = 0; i < n; i++)
- flags[i] = False; /* used for ignoring certain monitors */
- for(i = 0, nn = n; i < n; i++)
- for(j = 0; j < n; j++)
- if(i != j && !flags[i]) {
- if((flags[i] = (
- info[i].x_org == info[j].x_org
- && info[i].y_org == info[j].y_org
- && info[i].width == info[j].width
- && info[i].height == info[j].height)
- ))
- --nn;
+ nn = j;
+ if(n <= nn) {
+ for(i = 0; i < (nn - n); i++) { /* new monitors available */
+ for(m = mons; m && m->next; m = m->next);
+ if(m)
+ m->next = createmon();
+ else
+ mons = createmon();
}
-#endif /* XINERAMA */
- /* allocate monitor(s) for the new geometry setup */
- for(i = 0; i < nn; i++) {
- if(!(m = (Monitor *)malloc(sizeof(Monitor))))
- die("fatal: could not malloc() %u bytes\n", sizeof(Monitor));
- m->next = newmons;
- newmons = m;
- }
- /* initialise monitor(s) */
-#ifdef XINERAMA
- if(XineramaIsActive(dpy)) {
- for(i = 0, m = newmons; m && i < n; i++) {
- if(!flags[i]) { /* only use screens that aren't dublettes */
- m->num = info[i].screen_number;
- m->mx = m->wx = info[i].x_org;
- m->my = m->wy = info[i].y_org;
- m->mw = m->ww = info[i].width;
- m->mh = m->wh = info[i].height;
- m = m->next;
+ for(i = 0, m = mons; i < nn && m; m = m->next, i++)
+ if(i >= n
+ || (unique[i].x_org != m->mx || unique[i].y_org != m->my
+ || unique[i].width != m->mw || unique[i].height != m->mh))
+ {
+ dirty = True;
+ m->num = i;
+ m->mx = m->wx = unique[i].x_org;
+ m->my = m->wy = unique[i].y_org;
+ m->mw = m->ww = unique[i].width;
+ m->mh = m->wh = unique[i].height;
+ updatebarpos(m);
+ }
+ }
+ else { /* less monitors available nn < n */
+ for(i = nn; i < n; i++) {
+ for(m = mons; m && m->next; m = m->next);
+ while(m->clients) {
+ dirty = True;
+ c = m->clients;
+ m->clients = c->next;
+ detachstack(c);
+ c->mon = mons;
+ attach(c);
+ attachstack(c);
+ }
+ if(m == selmon)
+ selmon = mons;
+ cleanupmon(m);
}
}
- XFree(info);
- free(flags);
+ free(unique);
}
else
#endif /* XINERAMA */
/* default monitor setup */
{
- m->num = 0;
- m->mx = m->wx = 0;
- m->my = m->wy = 0;
- m->mw = m->ww = sw;
- m->mh = m->wh = sh;
- }
- /* bar geometry setup */
- for(m = newmons; m; m = m->next) {
- m->sel = m->stack = m->clients = NULL;
- m->seltags = 0;
- m->sellt = 0;
- m->tagset[0] = m->tagset[1] = 1;
- m->mfact = mfact;
- m->showbar = showbar;
- m->topbar = topbar;
- m->lt[0] = &layouts[0];
- m->lt[1] = &layouts[1 % LENGTH(layouts)];
- m->ltsymbol = layouts[0].symbol;
- updatebarpos(m);
- }
- /* reassign left over clients of disappeared monitors */
- for(tm = mons; tm; tm = tm->next)
- while(tm->clients) {
- c = tm->clients;
- tm->clients = c->next;
- detachstack(c);
- c->mon = newmons;
- attach(c);
- attachstack(c);
+ if(!mons)
+ mons = createmon();
+ if(mons->mw != sw || mons->mh != sh) {
+ dirty = True;
+ mons->mw = mons->ww = sw;
+ mons->mh = mons->wh = sh;
+ updatebarpos(mons);
}
- /* select focused monitor */
- cleanupmons();
- selmon = mons = newmons;
- selmon = wintomon(root);
- return True;
+ }
+ if(dirty) {
+ selmon = mons;
+ selmon = wintomon(root);
+ }
+ return dirty;
}
void
selmon->seltags ^= 1; /* toggle sel tagset */
if(arg->ui & TAGMASK)
selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
- arrange();
+ arrange(selmon);
}
Client *
detach(c);
attach(c);
focus(c);
- arrange();
+ arrange(c->mon);
}
int