#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)
{
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)
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)
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;
{
XEvent ev;
XNextEvent(X.disp, &ev);
+printf("event: %d\n", ev.type);
if (X.eventfns[ev.type])
{
X.eventfns[ev.type](&ev);
}
return 0;
-}
\ No newline at end of file
+}
typedef struct {
Display* disp;
+ int screen;
Window root;
+ unsigned long black, white, gray;
void (*eventfns[LASTEvent])(XEvent*);
} XConf;
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);
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);
#!/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
--- /dev/null
+#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;
+}
--- /dev/null
+#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
#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);