#define BARHEIGHT(x) \
((x)->font->height + 3)
+#define TCLIENT(c) \
+ container_of(c, Client, tnode)
+
+#define MCLIENT(c) \
+ container_of(c, Client, mnode)
+
enum {
TOO_SMALL = (1 << 0),
FLOATING = (1 << 1),
};
+typedef struct Node {
+ struct Node* next;
+ struct Node* prev;
+} Node;
+
+typedef void* (*Reducer)(Node* node, void* accum);
+
+typedef void (*Iterator)(Node* node);
+
typedef struct Client {
- struct Client *next, *prev;
+ Node mnode, tnode;
Window win;
Window frame;
char* name;
int flags, x, y, w, h;
} Client;
+typedef struct {
+ Client* c;
+ size_t nclients, nexty, sh;
+} GrowState;
+
typedef struct Column {
struct Column *next;
struct Client* clients;
} Column;
XConf X = {0};
-Client* Clients = NULL;
-Client* Floating = NULL;
+Node* All_Clients = NULL;
+Node* Tiled_Clients = NULL;
Cursor Move_Cursor;
Cursor Main_Cursor;
int StartY = 0;
x->display, w, name, 0, -1, False, AnyPropertyType, type, format, ndata, &nleft, (unsigned char**)data);
}
+/* List Handling
+ *****************************************************************************/
+void list_add(Node** list, Node* parent, Node* node) {
+ if (!parent) {
+ node->next = *list;
+ if (*list) (*list)->prev = node;
+ *list = node;
+ } else {
+ node->next = parent->next;
+ node->prev = parent;
+ parent->next = node;
+ if (node->next) node->next->prev = node;
+ }
+}
+
+void list_del(Node** list, Node* node) {
+ if (node->prev) node->prev->next = node->next;
+ if (node->next) node->next->prev = node->prev;
+ if (*list == node) *list = node->next;
+}
+
+void* list_reduce(Node* list, Reducer rfn, void* accum) {
+ return (list ? list_reduce(list->next, rfn, rfn(list, accum)) : accum);
+}
+
+void list_each(Node* list, Iterator ifn) {
+ if (!list) return;
+ ifn(list);
+ list_each(list->next, ifn);
+}
+
+size_t list_count(Node* curr) {
+ size_t nclients = 0;
+ for (; curr; curr = curr->next, nclients++);
+ return nclients;
+}
+
/* Client Handling
*****************************************************************************/
+void client_reconfig(XConf* xs, Client* c);
+
+void* biggest(Node* node, void* accum) {
+ if (!accum || TCLIENT(node)->h > ((Client*)accum)->h)
+ accum = TCLIENT(node);
+ return accum;
+}
+
+void* find_win(Node* n, void* env) {
+ struct { Window w; Client* c; }* state = env;
+ if ((MCLIENT(n)->frame == state->w) || (MCLIENT(n)->win == state->w))
+ state->c = MCLIENT(n);
+ return env;
+}
+
+void* grow_client(Node* node, void* env) {
+ GrowState* state = env;
+ Client* curr = TCLIENT(node);
+ state->nclients--;
+ curr->y = state->nexty;
+ if (curr == state->c)
+ curr->h = state->sh - state->nexty - (state->nclients * BARHEIGHT(&X));
+ else
+ curr->h = BARHEIGHT(&X);
+ client_reconfig(&X, curr);
+ state->nexty += curr->h;
+ return state;
+}
+
int client_flags(Client* c, int mask) {
return (c->flags & mask);
}
void client_add(Client* parent, Client* c) {
- c->next = parent->next;
- c->prev = parent;
- parent->next = c;
- if (c->next) c->next->prev = c;
+ list_add(&All_Clients, NULL, &(c->mnode));
+ if (!client_flags(c, FLOATING))
+ list_add(&Tiled_Clients, (parent ? &(parent->tnode) : NULL), &(c->tnode));
}
void client_del(Client* c) {
- if (c->prev) c->prev->next = c->next;
- if (c->next) c->next->prev = c->prev;
- if (Clients == c) Clients = c->next;
+ list_del(&All_Clients, &(c->mnode));
+ if (!client_flags(c, FLOATING))
+ list_del(&Tiled_Clients, &(c->tnode));
+}
+
+void client_redraw(XConf* x, Client* c) {
+ puts("redraw");
+ XftColor fgclr, bgclr;
+ if (!c->name) return;
+ xftcolor(x, &fgclr, -1);
+ xftcolor(x, &bgclr, BackgroundColor);
+ XftDrawRect(c->xft, &bgclr, 0, 0, c->w, BARHEIGHT(x));
+ XftDrawStringUtf8(c->xft, &fgclr, x->font, 0, x->font->ascent, (const FcChar8*)c->name, strlen(c->name));
+ XftColorFree(x->display, x->visual, x->colormap, &fgclr);
+ XftColorFree(x->display, x->visual, x->colormap, &bgclr);
}
void client_reconfig(XConf* xs, Client* c) {
XMapWindow(xs->display, c->win);
}
}
+ client_redraw(xs, c);
XSync(xs->display, False);
}
void client_config(XConf* xs, Client* c, int x, int y, int w, int h) {
c->x = x, c->y = y, c->w = w, c->h = h;
client_reconfig(xs, c);
+ client_redraw(xs, c);
}
void client_raise(XConf* x, Client* c) {
EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
/* position the window and frame */
+ Client* parent = NULL;
if (!client_flags(c, FLOATING)) {
- Client* biggy = Clients;
- for (Client* curr = Clients; curr; curr = curr->next)
- if (curr->h > biggy->h) biggy = curr;
- if (biggy) {
- c->h = (biggy->h - (biggy->h / 2));
- biggy->h /= 2;
- c->y = biggy->y + biggy->h;
- client_config(x, biggy, biggy->x, biggy->y, biggy->w, biggy->h);
- client_add(biggy, c);
- } else {
- Clients = c;
+ parent = list_reduce(Tiled_Clients, biggest, NULL);
+ if (parent) {
+ c->h = (parent->h - (parent->h / 2));
+ parent->h /= 2;
+ c->y = parent->y + parent->h;
+ client_config(x, parent, parent->x, parent->y, parent->w, parent->h);
}
- } else {
- if (Floating)
- client_add(c, Floating);
- else
- Floating = c;
}
+ client_add(parent, c);
client_config(x, c, c->x, c->y, c->w, c->h);
+ client_redraw(x, c);
client_raise(x, c);
XSync(x->display, False);
}
Client* client_find(Window win) {
- Client *c;
- for (c = Clients; c; c = c->next)
- if ((c->frame == win) || (c->win == win))
- return c;
-// for (c = Floating; c; c = c->next)
-// if ((c->frame == win) || (c->win == win))
-// return c;
- return NULL;
-}
-
-void client_redraw(XConf* x, Client* c) {
- puts("redraw");
- XftColor fgclr, bgclr;
- if (!c->name) return;
- xftcolor(x, &fgclr, -1);
- xftcolor(x, &bgclr, BackgroundColor);
- XftDrawRect(c->xft, &bgclr, 0, 0, c->w, BARHEIGHT(x));
- XftDrawStringUtf8(c->xft, &fgclr, x->font, 0, x->font->ascent, (const FcChar8*)c->name, strlen(c->name));
- XftColorFree(x->display, x->visual, x->colormap, &fgclr);
- XftColorFree(x->display, x->visual, x->colormap, &bgclr);
+ struct { Window w; Client* c; } state = { .w = win };
+ list_reduce(All_Clients, find_win, &state);
+ return state.c;
}
void client_resize(XConf* x, Client* c, int dir) {
- if (!c->prev) return;
- Client* prev = c->prev;
+ (void)x, (void)c, (void)dir;
+ if (!c->tnode.prev) return;
+ Client* prev = TCLIENT(c->tnode.prev);
dir = (!abs(dir) ? -BARHEIGHT(x) : dir);
int sh = HeightOfScreen(DefaultScreenOfDisplay(x->display));
int miny = prev->y + BARHEIGHT(x);
- int maxy = (c->next ? c->next->y : sh) - BARHEIGHT(x);
+ int maxy = (c->tnode.next ? TCLIENT(c->tnode.next)->y : sh) - BARHEIGHT(x);
int newy = min(max(miny, (c->y + dir)), maxy);
prev->h = newy - prev->y;
- c->h = (c->next ? (c->next->y - newy) : (sh - newy));
+ c->h = (c->tnode.next ? (TCLIENT(c->tnode.next)->y - newy) : (sh - newy));
c->y = newy;
client_reconfig(x, prev);
client_reconfig(x, c);
}
void client_grow(XConf* x, Client* c) {
- Client* curr;
- int nclients = 0, nexty = 0;
- int sh = HeightOfScreen(DefaultScreenOfDisplay(x->display));
- for (curr = Clients; curr; curr = curr->next, nclients++);
- for (curr = Clients; curr; curr = curr->next) {
- nclients--;
- curr->y = nexty;
- if (curr == c)
- curr->h = sh - nexty - (nclients * BARHEIGHT(x));
- else
- curr->h = BARHEIGHT(x);
- client_reconfig(x, curr);
- nexty += curr->h;
- }
+ GrowState state = {
+ .c = c,
+ .nclients = list_count(Tiled_Clients),
+ .sh = HeightOfScreen(DefaultScreenOfDisplay(x->display))
+ };
+ list_reduce(Tiled_Clients, grow_client, &state);
}
void client_maximize(XConf* xs, Client* c) {
if (c) {
if (!client_flags(c, FLOATING)) {
int y = c->y, h = c->h;
- if (c->prev) {
- c->prev->h += h;
- client_config(x, c->prev, c->prev->x, c->prev->y, c->prev->w, c->prev->h);
- client_raise(x, c->prev);
- } else if (c->next) {
- c->next->y = y, c->next->h += h;
- client_config(x, c->next, c->next->x, c->next->y, c->next->w, c->next->h);
- client_raise(x, c->next);
+ Node* nsucc = (c->tnode.prev ? c->tnode.prev : c->tnode.next);
+ if (nsucc) {
+ Client* succ = TCLIENT(nsucc);
+ succ->h += h;
+ if (nsucc == c->tnode.next)
+ succ->y = y;
+ client_config(x, succ, succ->x, succ->y, succ->w, succ->h);
+ client_raise(x, succ);
}
}
client_destroy(x, c);