]> git.mdlowis.com Git - projs/tide.git/commitdiff
started implementing acme-like window manager
authorMichael D. Lowis <mike@mdlowis.com>
Tue, 28 May 2019 03:13:11 +0000 (23:13 -0400)
committerMichael D. Lowis <mike@mdlowis.com>
Tue, 28 May 2019 03:13:11 +0000 (23:13 -0400)
Makefile
src/anvil.c [new file with mode: 0644]

index 71764a07ad41f2ce37024cf2523557c6b4c748e4..284a617f3943e5e33e9a02e91a1b9788cd7b1373 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 CC = ./acc
 INCS = -Iinc/
-BINS = bin/tide bin/registrar bin/edit bin/fetch bin/pick bin/tsed bin/tframe
+BINS = bin/tide bin/registrar bin/edit bin/fetch bin/pick bin/tsed bin/tframe bin/anvil
 TEST_BINS =  tests/libedit
 MAN1 = docs/tide.1
 
diff --git a/src/anvil.c b/src/anvil.c
new file mode 100644 (file)
index 0000000..7222d53
--- /dev/null
@@ -0,0 +1,231 @@
+#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;
+}