From: Michael D. Lowis Date: Tue, 28 May 2019 03:13:11 +0000 (-0400) Subject: started implementing acme-like window manager X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=3306fa5e0b7e77942aceaa132de3f02c65811c8d;p=projs%2Ftide.git started implementing acme-like window manager --- diff --git a/Makefile b/Makefile index 71764a0..284a617 100644 --- 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 index 0000000..7222d53 --- /dev/null +++ b/src/anvil.c @@ -0,0 +1,231 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +}