static void xbtnpress(XEvent* e)
{
+ XButtonEvent* ev = &(e->xbutton);
Client* c = client_get(e->xbutton.window);
- if (c && (e->xbutton.window == c->frame))
+ if (c && (ev->window == c->frame))
{
- 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);
+ if (ev->button == Button1) {
+ client_raise(c);
+ if (ev->y < (TITLE_HEIGHT + BORDER_WIDTH)) {
+ X.start_x = ev->x_root;
+ X.start_y = ev->y_root;
+ }
+ else
+ {
+ /* TODO: warp the pointer and resize the window*/
+ }
+ } else if (ev->button == Button2) {
+ client_close(c);
+ } else if (ev->button == Button3) {
+ client_lower(c);
}
}
}
(void)e;
}
+static void xbtnmotion(XEvent* e)
+{
+ XMotionEvent *ev = &e->xmotion;
+ Client* c = client_get(ev->window);
+ if (c && (ev->window == c->frame))
+ {
+ /* TODO: only move window if Button1 held */
+ client_move(c, ev->x_root - X.start_x, ev->y_root - X.start_y);
+ }
+ X.start_x = ev->x_root;
+ X.start_y = ev->y_root;
+}
+
+
static void xconfigrequest(XEvent* e)
{
(void)e;
static void xdestroynotify(XEvent* e)
{
- (void)e;
+ XDestroyWindowEvent* ev = &(e->xdestroywindow);
+ Client* c = client_get(ev->window);
+ if (c)
+ {
+ if (Focused == c)
+ {
+ Focused = NULL;
+ }
+ mons_delclient(c);
+ }
}
static void xclientmsg(XEvent* e)
static void xenternotify(XEvent* e)
{
- (void)e;
+ XCrossingEvent* ev = &(e->xcrossing);
+ Client* c = client_get(ev->window);
+ if (c)
+ {
+ client_focus(c);
+// XSetInputFocus(X.disp, c->win, RevertToPointerRoot, CurrentTime);
+// client_draw(c, 0);
+ }
}
static void xexpose(XEvent* e)
/* 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);
XAllocNamedColor(X.disp, DefaultColormap(X.disp, X.screen), "DimGray", &color, &exact);
X.gray = color.pixel;
check_for_wm();
-puts("locked WM");
mons_init();
-puts("setup monitors");
client_initall();
-puts("found existing clients");
/* setup event handlers */
X.eventfns[ButtonPress] = xbtnpress;
X.eventfns[ButtonRelease] = xbtnrelease;
+ X.eventfns[MotionNotify] = xbtnmotion;
X.eventfns[KeyPress] = xkeypress;
X.eventfns[ConfigureRequest] = xconfigrequest;
X.eventfns[MapRequest] = xmaprequest;
{
XEvent ev;
XNextEvent(X.disp, &ev);
-printf("event: %d\n", ev.type);
if (X.eventfns[ev.type])
{
X.eventfns[ev.type](&ev);
int screen;
Window root;
unsigned long black, white, gray;
+ int start_x, start_y;
void (*eventfns[LASTEvent])(XEvent*);
} XConf;
Workspace* cspace;
} Monitor;
+typedef struct Location {
+ Monitor* monitor;
+ Workspace* workspace;
+ Client* client;
+} Location;
+
#define BORDER_WIDTH 5
+#define TITLE_HEIGHT 10
/* anvil.c */
extern XConf X;
extern Monitor* Monitors;
void mons_init(void);
void mons_addclient(Client* c);
+void mons_delclient(Client* c);
+int mons_find(Window win, Location* loc);
/* client.c */
+extern Client* Focused;
void client_initall(void);
Client* client_add(Window win, XWindowAttributes* attr);
void client_draw(Client* c, int active);
Client* client_get(Window w);
+void client_raise(Client* c);
+void client_lower(Client* c);
+void client_move(Client* c, int xdiff, int ydiff);
+void client_close(Client* c);
+void client_focus(Client* c);
/* error.c */
extern int (*error_default)(Display* disp, XErrorEvent* ev);
#!/bin/sh
-cc -Wall -Wextra -Werror -o anvil *.c -lX11 -lXinerama
+cc -g -Wall -Wextra -Werror -o anvil *.c -lX11 -lXinerama
ctags *
grep -n 'TODO' *.c | sed -e 's/: \+/: /' -e 's/\/\* *//g' -e 's/ *\*\/$//' -e 's/TODO: *//'
\ No newline at end of file
#include "anvil.h"
-static int title_height(void)
-{
- return 10;
-}
+Client* Focused = NULL;
void client_initall(void)
{
/* Reparent the window if applicable */
c->frame = XCreateSimpleWindow(X.disp, X.root,
- c->x, c->y - title_height(),
- c->w, c->h + title_height(),
+ c->x - BORDER_WIDTH,
+ c->y - TITLE_HEIGHT - BORDER_WIDTH,
+ c->w + (2 * BORDER_WIDTH),
+ c->h + TITLE_HEIGHT + 2*BORDER_WIDTH,
1, X.black, X.white);
XSelectInput(X.disp, c->frame,
ExposureMask | EnterWindowMask |
- ButtonPressMask | ButtonReleaseMask |
- SubstructureRedirectMask | SubstructureNotifyMask |
- PointerMotionMask
+ ButtonPressMask | ButtonReleaseMask | ButtonMotionMask |
+ SubstructureRedirectMask | SubstructureNotifyMask
);
- 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());
+ 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);
Client* client_get(Window w)
{
- (void)w;
- /* TODO: Actually find the window correctly... */
- return NULL;
+ Client* c = NULL;
+ Location loc = {0};
+ if (mons_find(w, &loc))
+ {
+ c = loc.client;
+ }
+ return c;
+}
+
+void client_raise(Client* c)
+{
+ XRaiseWindow(X.disp, c->frame);
+ XRaiseWindow(X.disp, c->win);
+}
+
+void client_lower(Client* c)
+{
+ XLowerWindow(X.disp, c->win);
+ XLowerWindow(X.disp, c->frame);
}
+
+void client_move(Client* c, int xdiff, int ydiff)
+{
+ c->x += xdiff;
+ c->y += ydiff;
+ XMoveWindow(X.disp, c->frame,
+ c->x - BORDER_WIDTH,
+ c->y - TITLE_HEIGHT - BORDER_WIDTH);
+ XSync(X.disp, False);
+}
+
+void client_close(Client* c)
+{
+ /* TODO: handle wm_delete client message here */
+ XKillClient(X.disp, c->win);
+}
+
+void client_focus(Client* c)
+{
+ if (Focused != NULL)
+ {
+ client_draw(Focused, 0);
+ }
+ Focused = c;
+ XSetInputFocus(X.disp, c->win, RevertToPointerRoot, CurrentTime);
+ client_draw(Focused, 1);
+}
\ No newline at end of file
/* 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
+ /* TODO: use size and position to pick the "right" monitor */
+}
+
+Client* delclient(Client* list, Client* dead)
+{
+ if (list == dead)
+ {
+ list = list->next;
+ }
+ else
+ {
+ list->next = delclient(list->next, dead);
+ }
+ return list;
+}
+
+void mons_delclient(Client* c)
+{
+ Location loc = {0};
+ if (mons_find(c->win, &loc))
+ {
+ loc.workspace->floating = delclient(loc.workspace->floating, c);
+ xfree(c->name);
+ XDestroyWindow(X.disp, c->frame);
+ free(c);
+ }
+}
+
+int mons_find(Window win, Location* loc)
+{
+ Monitor* mons = Monitors;
+ for (Monitor* mon = Monitors; mon; mon = mon->next)
+ {
+ for (Workspace* wspace = mons->wspaces; wspace; wspace = wspace->next)
+ {
+ for (Client* client = wspace->floating; client; client = client->next)
+ {
+ if (client->frame == win || client->win == win)
+ {
+ loc->monitor = mon;
+ loc->workspace = wspace;
+ loc->client = client;
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}