]> git.mdlowis.com Git - proto/anvil.git/commitdiff
added basic window controls and focus handling
authorMichael D. Lowis <mike.lowis@gentex.com>
Wed, 11 Mar 2020 15:57:28 +0000 (11:57 -0400)
committerMichael D. Lowis <mike.lowis@gentex.com>
Wed, 11 Mar 2020 15:57:28 +0000 (11:57 -0400)
anvil.c
anvil.h
build.sh
client.c
mons.c

diff --git a/anvil.c b/anvil.c
index f0bcc560a832a85c2d7d6564f33d85d79f57b5fb..1bc075ea7c38c39010971e732149ae550dc560ab 100644 (file)
--- a/anvil.c
+++ b/anvil.c
@@ -13,19 +13,24 @@ static void check_for_wm(void)
 
 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);
         }
     }
 }
@@ -35,6 +40,20 @@ static void xbtnrelease(XEvent* e)
     (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;
@@ -52,7 +71,16 @@ static void xunmapnotify(XEvent* 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)
@@ -67,7 +95,14 @@ static void xpropnotify(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)
@@ -94,7 +129,6 @@ int main(void)
     /* 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);
@@ -102,15 +136,13 @@ puts("opened display");
     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;
@@ -127,7 +159,6 @@ puts("found existing clients");
     {
         XEvent ev;
         XNextEvent(X.disp, &ev);
-printf("event: %d\n", ev.type);
         if (X.eventfns[ev.type])
         {
             X.eventfns[ev.type](&ev);
diff --git a/anvil.h b/anvil.h
index 42c860de27662db5f0ce87836859f9d3b3a650b7..3988f323ea77fb426cd6f9e358adbba53f43699b 100644 (file)
--- a/anvil.h
+++ b/anvil.h
@@ -19,6 +19,7 @@ typedef struct {
     int screen;
     Window root;
     unsigned long black, white, gray;
+    int start_x, start_y;
     void (*eventfns[LASTEvent])(XEvent*);
 } XConf;
 
@@ -41,7 +42,14 @@ typedef struct Monitor {
     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;
@@ -50,12 +58,20 @@ 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);
index 7ce3e681827d30bbbbbca5aa1bfd1d04d0d3f93f..6b0dfdce956a62c8e82942ff3a74c9e50dfdd533 100755 (executable)
--- a/build.sh
+++ b/build.sh
@@ -1,4 +1,4 @@
 #!/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
index 3c38e1d28bdeb82b111ce1f51dc597dbba00aa50..fe98ed5a9b80a1c8feb21c7920dd0b2ebec9f3a1 100644 (file)
--- a/client.c
+++ b/client.c
@@ -1,9 +1,6 @@
 #include "anvil.h"
 
-static int title_height(void)
-{
-    return 10;
-}
+Client* Focused = NULL;
 
 void client_initall(void)
 {
@@ -43,22 +40,22 @@ Client* client_add(Window win, XWindowAttributes* attr)
 
     /* 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);
@@ -91,7 +88,50 @@ void client_draw(Client* c, int active)
 
 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
diff --git a/mons.c b/mons.c
index af35b63e6caf67e8a3d096de80274d16a8220ce1..8a909b3e4140219993da496dbde7863d5b2c5bbe 100644 (file)
--- a/mons.c
+++ b/mons.c
@@ -28,5 +28,52 @@ 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
+    /* 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;
+}