From 1d3b40ad86865ba7b5749296f9394b77849a2e8c Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Tue, 10 Mar 2020 16:50:41 -0400 Subject: [PATCH] sketched out enough that i will reframe windows that exist when the WM launches --- anvil.c | 93 +++++++++++++++++++++-------------------------------- anvil.h | 15 +++++++++ build.sh | 2 +- client.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ mons.c | 32 +++++++++++++++++++ util.c | 8 +++++ 6 files changed, 189 insertions(+), 58 deletions(-) create mode 100644 client.c create mode 100644 mons.c diff --git a/anvil.c b/anvil.c index b27d691..f0bcc56 100644 --- a/anvil.c +++ b/anvil.c @@ -1,15 +1,6 @@ #include "anvil.h" XConf X = {0}; -Monitor* Monitors = NULL; - -static void check(intptr_t stat, char* msg) -{ - if (!stat) - { - die(msg); - } -} static void check_for_wm(void) { @@ -20,54 +11,23 @@ static void check_for_wm(void) XSync(X.disp, False); } -static void find_clients(void) +static void xbtnpress(XEvent* e) { - unsigned int nwins; - Window d1, d2, *wins = NULL; -// XWindowAttributes wa; - if (XQueryTree(X.disp, X.root, &d1, &d2, &wins, &nwins)) + Client* c = client_get(e->xbutton.window); + if (c && (e->xbutton.window == c->frame)) { - for (unsigned int i = 0; i < nwins; i++) - { -// if (!XGetWindowAttributes(dpy, wins[i], &wa) || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) -// continue; -// if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) -// manage(wins[i], &wa); + if (e->xbutton.button == Button1) { + /* TODO: handle move and resize */ +// XMapWindow(X.disp, c->frame); +// client_raise(c); + } else if (e->xbutton.button == Button2) { + /* TODO: handle close */ +// client_close(c); + } else if (e->xbutton.button == Button3) { + /* TODO: handle lowering */ +// client_lower(c); } - for (unsigned int i = 0; i < nwins; i++) { /* now the transients */ -// if (!XGetWindowAttributes(dpy, wins[i], &wa)) -// continue; -// if (XGetTransientForHint(dpy, wins[i], &d1) -// && (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)) -// manage(wins[i], &wa); - } - xfree(wins); - } -} - -static void setup_monitors(void) -{ - int nmons; - check( XineramaIsActive(X.disp), "Xinerama extension is required"); - XineramaScreenInfo* mons = XineramaQueryScreens(X.disp, &nmons); - for (int i = 0; i < nmons; i++) - { - Monitor* m = ecalloc(1, sizeof(Monitor)); - m->wspaces = ecalloc(1, sizeof(Workspace)); - m->cspace = m->wspaces; - m->x = mons[i].x_org; - m->y = mons[i].y_org; - m->w = mons[i].width; - m->h = mons[i].height; - m->next = Monitors; - Monitors = m; } - xfree(mons); -} - -static void xbtnpress(XEvent* e) -{ - (void)e; } static void xbtnrelease(XEvent* e) @@ -112,7 +72,14 @@ static void xenternotify(XEvent* e) static void xexpose(XEvent* e) { - (void)e; + if (e->xexpose.count == 0) + { + Client* c = client_get(e->xexpose.window); + if (c) + { + client_draw(c, 0); + } + } } static void xkeypress(XEvent* e) @@ -122,13 +89,24 @@ static void xkeypress(XEvent* e) int main(void) { + XColor color, exact; + /* Initialize X server*/ check( (X.disp = XOpenDisplay(0)) != NULL, "could not open display"); +puts("opened display"); X.root = DefaultRootWindow(X.disp); + X.screen = DefaultScreen(X.disp); + X.black = BlackPixel(X.disp, X.screen); + X.white = WhitePixel(X.disp, X.screen); + XAllocNamedColor(X.disp, DefaultColormap(X.disp, X.screen), "DimGray", &color, &exact); + X.gray = color.pixel; check_for_wm(); - setup_monitors(); - find_clients(); +puts("locked WM"); + mons_init(); +puts("setup monitors"); + client_initall(); +puts("found existing clients"); /* setup event handlers */ X.eventfns[ButtonPress] = xbtnpress; @@ -149,6 +127,7 @@ int main(void) { XEvent ev; XNextEvent(X.disp, &ev); +printf("event: %d\n", ev.type); if (X.eventfns[ev.type]) { X.eventfns[ev.type](&ev); @@ -156,4 +135,4 @@ int main(void) } return 0; -} \ No newline at end of file +} diff --git a/anvil.h b/anvil.h index 35d5ca3..42c860d 100644 --- a/anvil.h +++ b/anvil.h @@ -16,7 +16,9 @@ Management Notes: typedef struct { Display* disp; + int screen; Window root; + unsigned long black, white, gray; void (*eventfns[LASTEvent])(XEvent*); } XConf; @@ -39,9 +41,21 @@ typedef struct Monitor { Workspace* cspace; } Monitor; +#define BORDER_WIDTH 5 + /* anvil.c */ extern XConf X; + +/* mons.c */ extern Monitor* Monitors; +void mons_init(void); +void mons_addclient(Client* c); + +/* client.c */ +void client_initall(void); +Client* client_add(Window win, XWindowAttributes* attr); +void client_draw(Client* c, int active); +Client* client_get(Window w); /* error.c */ extern int (*error_default)(Display* disp, XErrorEvent* ev); @@ -50,6 +64,7 @@ int error_init(Display* disp, XErrorEvent* ev); int error_panic(Display* disp, XErrorEvent* ev); /* util.c */ +void check(intptr_t stat, char* msg); void die(char* str); void* ecalloc(size_t n, size_t sz); void xfree(void* p); diff --git a/build.sh b/build.sh index f54eaac..7ce3e68 100755 --- a/build.sh +++ b/build.sh @@ -1,4 +1,4 @@ #!/bin/sh cc -Wall -Wextra -Werror -o anvil *.c -lX11 -lXinerama ctags * -printf "done\n" \ No newline at end of file +grep -n 'TODO' *.c | sed -e 's/: \+/: /' -e 's/\/\* *//g' -e 's/ *\*\/$//' -e 's/TODO: *//' \ No newline at end of file diff --git a/client.c b/client.c new file mode 100644 index 0000000..3c38e1d --- /dev/null +++ b/client.c @@ -0,0 +1,97 @@ +#include "anvil.h" + +static int title_height(void) +{ + return 10; +} + +void client_initall(void) +{ + unsigned int nwins; + Window d1, d2, *wins = NULL; + XWindowAttributes attr; + if (XQueryTree(X.disp, X.root, &d1, &d2, &wins, &nwins)) + { + for (unsigned int i = 0; i < nwins; i++) + { + if (XGetWindowAttributes(X.disp, wins[i], &attr) && !attr.override_redirect) + { + (void)client_add(wins[i], &attr); + } + } + xfree(wins); + } +} + +Client* client_add(Window win, XWindowAttributes* attr) +{ + Client* c = ecalloc(1, sizeof(Client)); + c->win = win; + c->x = attr->x; + c->y = attr->y; + c->w = attr->width; + c->h = attr->height; + mons_addclient(c); + + /* get window name */ + /* get normal hints ? */ + /* get registered protocols */ + /* get transient_for property ? */ + /* set client flags appropriately */ + /* get size and position */ + /* Find monitor, add to that monitors cspace */ + + /* Reparent the window if applicable */ + c->frame = XCreateSimpleWindow(X.disp, X.root, + c->x, c->y - title_height(), + c->w, c->h + title_height(), + 1, X.black, X.white); + XSelectInput(X.disp, c->frame, + ExposureMask | EnterWindowMask | + ButtonPressMask | ButtonReleaseMask | + SubstructureRedirectMask | SubstructureNotifyMask | + PointerMotionMask + ); + XResizeWindow(X.disp, c->win, c->w - 2 * BORDER_WIDTH, c->h - 2 * BORDER_WIDTH); + XSetWindowAttributes wa; + wa.event_mask = EnterWindowMask | PropertyChangeMask | FocusChangeMask; + wa.win_gravity = StaticGravity; + wa.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask; + XChangeWindowAttributes(X.disp, c->win, CWEventMask | CWWinGravity | CWDontPropagate, &wa); + XReparentWindow(X.disp, c->win, c->frame, BORDER_WIDTH, BORDER_WIDTH + title_height()); + + /* Map the window and draw the frame */ + XAddToSaveSet(X.disp, c->win); + XMapWindow(X.disp, c->frame); + XMapWindow(X.disp, c->win); + client_draw(c, 0); + + /* Set focus and state? */ + + return c; +} + +void client_draw(Client* c, int active) +{ + if (c->frame) + { + XSetWindowBackground(X.disp, c->frame, active ? X.black : X.gray); + XClearWindow(X.disp, c->frame); + + // int quarter = (border + titleHeight()) / 4; + // /* Draw window title. */ + // if (c->name != 0) { + // Xutf8DrawString(dpy, c->parent, font_set, + // gc, border + 2 + (3 * quarter), + // 2 + ascent(font_set_ext), + // c->name, c->namelen); + // } + } +} + +Client* client_get(Window w) +{ + (void)w; + /* TODO: Actually find the window correctly... */ + return NULL; +} diff --git a/mons.c b/mons.c new file mode 100644 index 0000000..af35b63 --- /dev/null +++ b/mons.c @@ -0,0 +1,32 @@ +#include "anvil.h" + +Monitor* Monitors = NULL; + +void mons_init(void) +{ + int nmons; + check( XineramaIsActive(X.disp), "Xinerama extension is required"); + XineramaScreenInfo* mons = XineramaQueryScreens(X.disp, &nmons); + for (int i = 0; i < nmons; i++) + { + Monitor* m = ecalloc(1, sizeof(Monitor)); + m->wspaces = ecalloc(1, sizeof(Workspace)); + m->cspace = m->wspaces; + m->x = mons[i].x_org; + m->y = mons[i].y_org; + m->w = mons[i].width; + m->h = mons[i].height; + m->next = Monitors; + Monitors = m; + } + xfree(mons); +} + +/* adds a new client to the most appropriate monitor */ +void mons_addclient(Client* c) +{ + /* for now just add it to the first monitor in the list */ + c->next = Monitors->cspace->floating; + Monitors->cspace->floating = c; + /* TODO: using size and position to pick the "right" monitor */ +} \ No newline at end of file diff --git a/util.c b/util.c index b43b6df..6396ea4 100644 --- a/util.c +++ b/util.c @@ -1,5 +1,13 @@ #include "anvil.h" +void check(intptr_t stat, char* msg) +{ + if (!stat) + { + die(msg); + } +} + void die(char* str) { printf("anvil: fatal error: %s\n", str); -- 2.52.0