--- /dev/null
+#include <stdc.h>
+#include <utf.h>
+#include <edit.h>
+#include <win.h>
+#include <x11.h>
+#include <draw.h>
+#include <locale.h>
+#include <sys/wait.h>
+
+#define INCLUDE_DEFS
+#include "config.h"
+
+typedef struct Client {
+ struct Client* next;
+ Window win;
+ Window frame;
+ char* name;
+ XftDraw* xft;
+ int x, y, w, h;
+} Client;
+
+XConf X = {0};
+Client* Clients = NULL;
+
+/* Utility Functions
+ *****************************************************************************/
+void dbg(char* fmt, ...) {
+ static FILE* dbgf = NULL;
+ if (!dbgf) { dbgf = fopen("w", "~/.anvil.log"); }
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(dbgf, fmt, args);
+ fflush(dbgf);
+ va_end(args);
+}
+
+void die(char* errstr) {
+ fprintf(stderr, "error: %s\n", errstr);
+ exit(1);
+}
+
+Atom atom(XConf* x, char* s) {
+ return XInternAtom(x->display, s, False);
+}
+
+void xfree(void* p) {
+ if (p) XFree(p);
+}
+
+/* Client Handling
+ *****************************************************************************/
+void client_setstate(XConf* x, Client* c, int state) {
+ uint32_t data[2] = { state, None };
+ Atom wm_state = atom(x, "WM_STATE");
+ XChangeProperty(x->display, c->win, wm_state, wm_state, 32, PropModeReplace, (unsigned char *)data, 2);
+}
+
+void client_config(XConf* x, Client *c) {
+ XConfigureEvent e = {0};
+ e.type = ConfigureNotify;
+ e.event = c->win;
+ e.window = c->win;
+ e.x = c->x;
+ e.y = c->y;
+ e.width = c->w;
+ e.height = c->h;
+ e.border_width = 0;
+ e.above = None;
+ e.override_redirect = 0;
+ XSendEvent(x->display, c->win, False, StructureNotifyMask, (XEvent *)&e);
+}
+
+void client_add(XConf* x, Window win) {
+ Client* c = calloc(1, sizeof(Client));
+ c->win = win;
+ c->next = Clients;
+ Clients = c;
+ XGrabServer(x->display);
+ XFetchName(x->display, win, &c->name);
+
+ XWindowAttributes attr;
+ XGetWindowAttributes(x->display, win, &attr);
+ c->x = attr.x, c->y = attr.y;
+ c->w = attr.width, c->h = attr.height;
+ client_setstate(x, c, NormalState);
+ XSetWindowAttributes pattr = {0};
+ pattr.override_redirect = True;
+ c->frame = XCreateWindow(
+ x->display, x->root, 0, 0, 1, 1, 0,
+ x->depth, CopyFromParent, x->visual,
+ CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWEventMask, &pattr);
+ XSelectInput(x->display, c->win, PropertyChangeMask);
+
+#if 0
+ XSetWindowBorderWidth(x->display, c->win, 0);
+ XResizeWindow(x->display, c->win, c->w, c->h);
+ XReparentWindow(x->display, c->win, c->frame, 0, 20);
+ client_config(x, c);
+ c->xft = XftDrawCreate(x->display, (Drawable) c->frame, x->visual, x->colormap);
+ XMapWindow(x->display, c->win);
+ XMapRaised(x->display, c->frame);
+#else
+ XSetWindowBorderWidth(x->display, c->win, 0);
+ XMoveResizeWindow(x->display, c->frame, 100, 100 - x->font->height, c->w, x->font->height);
+ XMoveResizeWindow(x->display, c->win, 100, 100, c->w, c->h);
+ client_config(x, c);
+ XMapWindow(x->display, c->frame);
+ XMapRaised(x->display, c->win);
+#endif
+
+ XSync(x->display, False);
+ XUngrabServer(x->display);
+}
+
+Client* client_del(XConf* x, Client* curr, Client* c) {
+ dbg("%p == %p\n", curr, c);
+ if (!curr) {
+ return NULL;
+ } else if (curr == c) {
+ dbg("destroy\n", curr, c);
+ Client* next = c->next;
+ XGrabServer(x->display);
+ client_setstate(x, c, WithdrawnState);
+ XftDrawDestroy(c->xft);
+ XDestroyWindow(x->display, c->frame);
+ xfree(c->name);
+ free(c);
+ XSync(x->display, False);
+ XUngrabServer(x->display);
+ return next;
+ } else {
+ curr->next = client_del(x, curr->next, c);
+ return curr;
+ }
+}
+
+Client* client_find(Window win) {
+ Client *c = Clients;
+ for (; c; c = c->next)
+ if ((c->frame == win) || (c->win == win))
+ return c;
+ return NULL;
+}
+
+/* X11 Event Handling
+ *****************************************************************************/
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
+static void xbtnpress(XConf* x, XEvent* e) {
+}
+
+static void xconfigrequest(XConf* x, XEvent* e) {
+ dbg("config\n");
+ Client* c = client_find(e->xconfigurerequest.window);
+ XWindowChanges wc;
+ if (c != NULL) {
+ wc.x = c->x;
+ wc.y = c->y - 20;
+ wc.width = c->w;
+ wc.height = c->h + 20;
+ wc.border_width = 1;
+ XConfigureWindow(x->display, c->frame, e->xconfigurerequest.value_mask, &wc);
+ client_config(x, c);
+ wc.x = 0;
+ wc.y = 20;
+ } else {
+ wc.x = e->xconfigurerequest.x;
+ wc.y = e->xconfigurerequest.y;
+ }
+ wc.width = e->xconfigurerequest.width;
+ wc.height = e->xconfigurerequest.height;
+ XConfigureWindow(x->display, e->xconfigurerequest.window, e->xconfigurerequest.value_mask, &wc);
+ XSync(x->display, False);
+}
+
+static void xmaprequest(XConf* x, XEvent* e) {
+ dbg("map\n");
+ static XWindowAttributes attr = {0};
+ if (XGetWindowAttributes(x->display, e->xmaprequest.window, &attr)) {
+ if (attr.override_redirect) return; /* ??? */
+ if (!client_find(e->xmaprequest.window))
+ client_add(x, e->xmaprequest.window);
+ }
+}
+
+static void xunmapnotify(XConf* x, XEvent* e) {
+ dbg("unmap\n");
+ Client* c = client_find(e->xunmap.window);
+ if (c) Clients = client_del(x, Clients, c);
+}
+
+static void xdestroynotify(XConf* x, XEvent* e) {
+}
+
+static void xclientmsg(XConf* x, XEvent* e) {
+}
+
+static void xpropnotify(XConf* x, XEvent* e) {
+}
+
+static void xenternotify(XConf* x, XEvent* e) {
+}
+
+static void xexpose(XConf* x, XEvent* e) {
+}
+
+#pragma GCC diagnostic pop
+
+int main(void) {
+// dbg("start\n");
+ x11_init(&X);
+ X.font = x11_font_load(&X, Fonts[0]);
+ XSelectInput(X.display, X.root, SubstructureRedirectMask);
+ XSync(X.display, False);
+ if (x11_error_get())
+ die("Could not start. Is another WM running?\n");
+ X.eventfns[ButtonPress] = xbtnpress;
+ X.eventfns[ConfigureRequest] = xconfigrequest;
+ X.eventfns[MapRequest] = xmaprequest;
+ X.eventfns[UnmapNotify] = xunmapnotify;
+ X.eventfns[DestroyNotify] = xdestroynotify;
+ X.eventfns[ClientMessage] = xclientmsg;
+ X.eventfns[PropertyNotify] = xpropnotify;
+ X.eventfns[EnterNotify] = xenternotify;
+ X.eventfns[Expose] = xexpose;
+// dbg("loop\n");
+ x11_event_loop(&X, 0);
+ return 0;
+}