From: Michael D. Lowis Date: Fri, 16 Aug 2019 17:11:53 +0000 (-0400) Subject: detect dialog windows and float them instead of tile them X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=a912269902fdd65a57195eb261b46731dae4054d;p=projs%2Ftide.git detect dialog windows and float them instead of tile them --- diff --git a/TODO.md b/TODO.md index 14a70e9..bc124a8 100644 --- a/TODO.md +++ b/TODO.md @@ -4,10 +4,9 @@ ## STAGING -* anvil: search floating list as well as tiled list for clients -* anvil: support floating windows for dialogs -* anvil: add column support +* anvil: support moving floating windows * anvil: add support for multiple workspaces +* anvil: add column support * anvil: add support for multiple monitors ## BACKLOG diff --git a/src/anvil.c b/src/anvil.c index 6a57bed..f9364a5 100644 --- a/src/anvil.c +++ b/src/anvil.c @@ -14,13 +14,28 @@ #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; @@ -28,6 +43,11 @@ typedef struct Client { 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; @@ -35,8 +55,8 @@ typedef struct Column { } 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; @@ -75,23 +95,100 @@ int get_prop(XConf* x, Window w, Atom name, Atom* type, int* format, void** data 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) { @@ -107,12 +204,14 @@ 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) { @@ -175,26 +274,19 @@ void client_create(XConf* x, Window win) { 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); @@ -213,58 +305,34 @@ void client_destroy(XConf* x, Client* c) { } 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) { @@ -369,14 +437,14 @@ static void xdestroynotify(XConf* x, XEvent* e) { 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);