]> git.mdlowis.com Git - proto/anvil.git/commitdiff
started building out infrastructure for workspace and monitor handling
authorMike Lowis <mike.lowis@gentex.com>
Mon, 5 Aug 2024 17:55:50 +0000 (13:55 -0400)
committerMike Lowis <mike.lowis@gentex.com>
Mon, 5 Aug 2024 17:55:50 +0000 (13:55 -0400)
anvil.c
anvil.h
build.sh
client.c
error.c
keys.c
monitors.c [new file with mode: 0644]
mouse.c
util.c [deleted file]

diff --git a/anvil.c b/anvil.c
index ac5bc514acc9391f33bee7219986a2f5f98ee0a8..c7b1c41e2d0cf9c82b17e37e76f2403dcb0b7d88 100644 (file)
--- a/anvil.c
+++ b/anvil.c
@@ -1,6 +1,16 @@
 #include "anvil.h"
 #include <sys/wait.h>
 
+void check(intptr_t stat, char* msg)
+{
+    if (!stat)
+    {
+        printf("anvil: fatal error: %s\n", msg);
+        exit(1);
+    }
+}
+
+
 /*
 
     X11 Client Window State Management:
@@ -35,7 +45,12 @@ static void xmaprequest(XEvent* e)
     printf("MAP(w: 0x%lx)\n", ev->window);
 
     /* window request to be shown, let's place it now */
-    Client_Show(ev->window);
+    Client* c = Client_Find(ev->window);
+    if (!c) { c = Client_Create(ev->window); }
+    if (c)
+    {
+        Client_Show(c);
+    }
 }
 
 static void xunmapnotify(XEvent* e)
@@ -44,7 +59,11 @@ static void xunmapnotify(XEvent* e)
     printf("UNMAP(e: 0x%lx w: 0x%lx %d)\n", ev->event, ev->window, ev->from_configure);
 
     /* hide or shade the window */
-    Client_Hide(ev->window);
+    Client* c = Client_Find(ev->window);
+    if (c)
+    {
+        Client_Hide(c);
+    }
 }
 
 static void xdestroynotify(XEvent* e)
@@ -53,7 +72,11 @@ static void xdestroynotify(XEvent* e)
     printf("DESTROY(w: 0x%lx)\n", ev->window);
 
     /* remove the client altogether */
-    Client_Destroy(ev->window);
+    Client* c = Client_Find(ev->window);
+    if (c)
+    {
+        Client_Destroy(c);
+    }
 }
 
 
@@ -63,9 +86,9 @@ XConf X = {0};
 
 /* Anvil State */
 int PtrX = 0, PtrY = 0;
-//int Num_Monitors = 0;
-//Monitor Monitors[10] = {0};
-//Workspace Workspaces[10] = {0};
+int Num_Monitors = 0;
+Monitor Monitors[10] = {0};
+Workspace Workspaces[10] = {0};
 Client* AllClients = NULL;
 Client* Focused = NULL;
 
@@ -73,6 +96,7 @@ static void check_for_wm(void)
 {
     error_default = XSetErrorHandler(error_init);
     XSelectInput(X.disp, X.root, SubstructureRedirectMask|SubstructureNotifyMask);
+    XRRSelectInput(X.disp, X.root, RRScreenChangeNotifyMask);
     XSync(X.disp, False);
     XSetErrorHandler(error_panic);
     XSync(X.disp, False);
@@ -205,6 +229,13 @@ static void xkeypress(XEvent* e)
     Keys_Process(ev);
 }
 
+static void xscreenchangenotify(XEvent* e)
+{
+    (void)e;
+    Monitors_Init();
+}
+
+
 static void init_cursors(void)
 {
     XColor csr_bdr, csr_fill;
@@ -269,9 +300,9 @@ int main(void)
     check_for_wm();
     init_cursors();
     init_font();
-//    mons_init();
     Client_InitAll();
     Keys_Init();
+    Monitors_Init();
     atoms_init();
 
     /* setup window life-cycle management event handlers */
@@ -290,6 +321,8 @@ int main(void)
     X.eventfns[PropertyNotify] = xpropnotify;
     X.eventfns[EnterNotify] = xenternotify;
     X.eventfns[Expose] = xexpose;
+    X.eventfns[RRScreenChangeNotify] = xscreenchangenotify;
+
 
     /* main event loop */
     XSync(X.disp, False);
diff --git a/anvil.h b/anvil.h
index ad32035169f55d2c50a41318454ebace0b909621..d097e2c65111fa3b2aaae380fa5e007a70f7e003 100644 (file)
--- a/anvil.h
+++ b/anvil.h
@@ -10,6 +10,7 @@
 #include <X11/Xproto.h>
 #include <X11/Xutil.h>
 #include <X11/extensions/Xinerama.h>
+#include <X11/extensions/Xrandr.h>
 #include <stdlib.h>
 #include <stdint.h>
 #include <stdio.h>
 #define min(a,b) (a < b ? a : b)
 #define max(a,b) (a > b ? a : b)
 
-#define BORDER_WIDTH     5
-#define TITLE_HEIGHT     (X.font_ext->max_logical_extent.height)
-#define MIN_HEIGHT       (TITLE_HEIGHT+BORDER_WIDTH)
-#define MIN_COL_FACT     0.20
-#define MAX_COL_COUNT    5
-#define FONT_NAME        "-*-lucida-bold-r-normal-sans-14-*-*-*-p-*-iso10646-1"
-#define MODKEY           Mod4Mask
-#define FRAME_HEIGHT_SUM (2*BORDER_WIDTH + TITLE_HEIGHT)
-#define FRAME_WIDTH_SUM  (2*BORDER_WIDTH)
-#define MAX_WSPACE_COUNT 10
+#define BORDER_WIDTH      5
+#define TITLE_HEIGHT      (X.font_ext->max_logical_extent.height)
+#define MIN_HEIGHT        (TITLE_HEIGHT+BORDER_WIDTH)
+#define MIN_COL_FACT      0.20
+#define MAX_COL_COUNT     5
+#define FONT_NAME         "-*-lucida-bold-r-normal-sans-14-*-*-*-p-*-iso10646-1"
+#define MODKEY            Mod4Mask
+#define FRAME_HEIGHT_SUM  (2*BORDER_WIDTH + TITLE_HEIGHT)
+#define FRAME_WIDTH_SUM   (2*BORDER_WIDTH)
+#define MAX_WSPACE_COUNT  10
+#define MAX_MONITOR_COUNT 10
 
 /* TODO: Add shortcuts to transfer windows between monitors */
 /* TODO: add floating addclient function */
@@ -78,7 +80,7 @@ typedef struct Client {
     struct Client* next;
     char* name;
     Window frame, win;
-    int state, flags, x, y, w, h;
+    int state, flags, wspace, x, y, w, h;
     long hint_flags, wm_flags;
     XWMHints hints;
     XSizeHints size_hints;
@@ -91,23 +93,16 @@ typedef struct Client {
 //    Client* clients;
 //} Column;
 //
-//typedef struct Workspace {
+typedef struct Workspace {
+    int monitor;
 //    Client* floating;
 //    Column columns[MAX_COL_COUNT];
 //    int ncolumns;
-//} Workspace;
-//
-//typedef struct Monitor {
-//    int x, y, w, h, midx, midy;
-//    Workspace* wspace;
-//} Monitor;
-//
-//typedef struct Location {
-//    Monitor* monitor;
-//    Workspace* workspace;
-//    Column* column;
-//    Client* client;
-//} Location;
+} Workspace;
+
+typedef struct Monitor {
+    int x, y, w, h, midx, midy, wspace;
+} Monitor;
 
 typedef union {
     int i;
@@ -121,19 +116,16 @@ typedef struct {
     Arg arg;
 } Key;
 
-
 /* anvil.c */
 extern XConf X;
-
 extern int PtrX;
 extern int PtrY;
-//extern int Num_Monitors;
-//extern Monitor Monitors[10];
-//extern Workspace Workspaces[10];
+extern int Num_Monitors;
+extern Monitor Monitors[MAX_MONITOR_COUNT];
+extern Workspace Workspaces[MAX_WSPACE_COUNT];
 extern Client* AllClients;
 extern Client* Focused;
 
-
 /* list.c */
 int list_length(void* list);
 void* list_del(void* list, void* node);
@@ -151,10 +143,10 @@ void Keys_Process(XKeyEvent* ev);
 /* client.c */
 Client* Client_Find(Window win);
 void Client_InitAll(void);
-void Client_Create(Window win);
-void Client_Destroy(Window win);
-void Client_Show(Window win);
-void Client_Hide(Window win);
+Client* Client_Create(Window win);
+void Client_Destroy(Client* c);
+void Client_Show(Client* c);
+void Client_Hide(Client* c);
 void Client_MoveResize(Client* c);
 void Client_Move(Client* c, int xdiff, int ydiff);
 void Client_Resize(Client* c, int xdiff, int ydiff);
@@ -163,37 +155,24 @@ void Client_Lower(Client* c);
 void Client_Update(Client* c);
 void Client_Focus(Client* client);
 void Client_Close(Client* client);
-
-//Client* client_add(Window win, XWindowAttributes* attr);
-//void client_draw(Client* c);
-//void client_move(Client* c, int xdiff, int ydiff);
-//void client_resize(Client* c, int xdiff, int ydiff);
-//void client_close(Client* c);
-//void client_focus(Client* c);
-//void client_show(Client* c, int show);
-//void client_readprops(Client* c);
-//void client_shade(Client* c);
-//void client_setshade(Client* c, int shade);
+void Client_UpdateAll(void);
+void Client_Place(Client* c);
 
 /* mouse.c */
 void Mouse_Down(XButtonEvent* ev);
 void Mouse_Up(XButtonEvent* ev);
 void Mouse_Drag(XMotionEvent* ev);
 void Mouse_ToCorner(Client* c);
+void Mouse_GetLocation(int* ptrx, int* ptry);
 
-//void mouse_totitle(Client* c);
-//void mouse_get(int* ptrx, int* ptry);
+/* monitors.c */
+void Monitors_Init(void);
+void Monitors_SetWorkspace(int id);
+void Monitors_SendToWorkspace(Client* c, int id);
 
 /* error.c */
 extern int (*error_default)(Display* disp, XErrorEvent* ev);
 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);
-void sendmsg(Window win, Atom proto, Atom type);
-
 #endif
index 85cab23debe5d08fbf7a3dd34f85e08786dbc3f4..57e3872b45f3d4788a6197dc40e7aad1751ff187 100755 (executable)
--- a/build.sh
+++ b/build.sh
@@ -2,7 +2,7 @@
 cflags="-g -Wall -Wextra -Werror"
 incpath="-I/usr/X11R6/include -Itest/"
 libpath="-L/usr/X11R6/lib"
-libs="-lX11 -lXinerama -lm"
+libs="-lX11 -lXinerama -lm -lXrandr"
 
 cc $cflags $incpath $libpath -o anvil ./*.c $libs \
     # && ./atf $incpath test/*.c
index ac423718a948cf93f2d6b81ea24dd173072765fb..9aae909de32629cdc51d7e99d5a714e3ad9cbf1a 100644 (file)
--- a/client.c
+++ b/client.c
@@ -4,6 +4,39 @@ static void ReadProps(Client* c);
 static void Redraw(Client* c);
 static void LayerWindows(void);
 
+void* ecalloc(size_t n, size_t sz)
+{
+    void* p = calloc(n, sz);
+    if (!p)
+    {
+        printf("anvil: fatal error: memory allocation failed\n");
+        exit(1);
+    }
+    return p;
+}
+
+void xfree(void* p)
+{
+    if (p)
+    {
+        XFree(p);
+    }
+}
+
+void sendmsg(Window win, Atom proto, Atom type)
+{
+    XEvent ev;
+    memset(&ev, 0, sizeof(ev));
+    ev.xclient.type = ClientMessage;
+    ev.xclient.window = win;
+    ev.xclient.message_type = proto;
+    ev.xclient.format = 32;
+    ev.xclient.data.l[0] = type;
+    ev.xclient.data.l[1] = CurrentTime;
+    XSendEvent(X.disp, win, False, 0, &ev);
+}
+
+
 void SetWMState(Client *c, int state)
 {
     CARD32 data[2] = {state, None};
@@ -46,7 +79,7 @@ Client* Client_Find(Window win)
     return curr;
 }
 
-static Client* Create(Window win)
+Client* Client_Create(Window win)
 {
     Client* c = NULL;
     XWindowAttributes attr;
@@ -95,60 +128,30 @@ static Client* Create(Window win)
     return c;
 }
 
-void Client_Show(Window win)
+void Client_Show(Client* c)
 {
-    /* find or create the client structure */
-    Client* c = Client_Find(win);
-    if (!c) { c = Create(win); }
-
-    /* if we have a calid client, show it */
-    if (c)
-    {
-        ReadProps(c);
-        XMapWindow(X.disp, c->frame);
-        XMapWindow(X.disp, c->win);
-        Redraw(c);
-    }
+    ReadProps(c);
+    XMapWindow(X.disp, c->frame);
+    XMapWindow(X.disp, c->win);
+    Redraw(c);
 }
 
-void Client_Hide(Window win)
+void Client_Hide(Client* c)
 {
-    (void)win;
-    /* TODO: hiding is complicated...
-        if window == frame and client_window == unmapped
-            unmap frame
-            move to withdrawn list
-        else if shaded
-
-    */
-
-//        if (ev->event == X.root && ev->window == loc.client->win)
-//        {
-////            mons_delclient(&loc);
-//        }
-//        else if ( !(loc.client->flags & F_SHADED) )
-//        {
-//            Client_Shade(ev->window);
-////            XUnmapWindow(X.disp, loc.client->frame);
-//        }
-
-
+    XUnmapWindow(X.disp, c->frame);
+    XUnmapWindow(X.disp, c->win);
 }
 
-void Client_Destroy(Window win)
+void Client_Destroy(Client* c)
 {
-    Client* c = Client_Find(win);
-    if (c)
+    if (Focused == c)
     {
-        if (Focused == c)
-        {
-            Focused = NULL;
-        }
-        AllClients = list_del(AllClients, c);
-        xfree(c->name);
-        XDestroyWindow(X.disp, c->frame);
-        free(c);
+        Focused = NULL;
     }
+    AllClients = list_del(AllClients, c);
+    xfree(c->name);
+    XDestroyWindow(X.disp, c->frame);
+    free(c);
 }
 
 void Client_MoveResize(Client* c)
@@ -169,7 +172,7 @@ void Client_MoveResize(Client* c)
         printf("XResize(0x%lx, %d, %d)\n", c->win, c->w, c->h);
         XResizeWindow(X.disp, c->win, child_w, child_h);
     }
-//    mons_place(c);
+    Client_Place(c);
     Redraw(c);
 }
 
@@ -232,6 +235,39 @@ void Client_Close(Client* client)
     }
 }
 
+void Client_Place(Client* c)
+{
+    /* caclulate client boundaries */
+    int cleft  = (c->x - BORDER_WIDTH);
+    int cright = (c->x + c->w + 2*BORDER_WIDTH);
+    int ctop   = (c->y - BORDER_WIDTH);
+    int cbot   = (c->y + c->h + 2*BORDER_WIDTH + TITLE_HEIGHT);
+
+    /* now find the most appropriate monitor to own it */
+    int maxarea = 0;
+    int monitor = 0;
+    for (int i = 0; i < Num_Monitors; i++)
+    {
+        Monitor* mon = &Monitors[i];
+        int left  = max(cleft, mon->x);
+        int right = min(cright, mon->x + mon->w);
+        int top   = max(ctop, mon->y);
+        int bot   = min(cbot, mon->y + mon->h);
+        if (left < right && top < bot)
+        {
+            int area = (right - left) * (bot - top);
+            if (area > maxarea)
+            {
+                maxarea = area;
+                monitor = i;
+            }
+        }
+    }
+
+    /* update the workspace this client is mapped to */
+    c->wspace = Monitors[monitor].wspace;
+}
+
 static void ReadProps(Client* c)
 {
     Atom *protos = NULL, actual_type, *wintype;
@@ -338,9 +374,6 @@ static void Redraw(Client* c)
                 c->name, strlen(c->name));
         }
     }
-
-    /* tell the window to redraw itself */
-\
 }
 
 void LayerWindows(void)
@@ -353,15 +386,6 @@ void LayerWindows(void)
         wins = realloc(wins, ++nwins * sizeof(Window));
         wins[nwins-1] = c->frame;
     }
-//    /* add in the monocled windows first */
-//    LIST_FOR_EACH(col, mon->cspace->columns)
-//    {
-//        if (col->focused)
-//        {
-//            wins = realloc(wins, ++nwins * sizeof(Window));
-//            wins[nwins-1] = col->focused->frame;
-//        }
-//    }
 //    /* now lower all of the tiled windows */
 //    LIST_FOR_EACH(col, mon->cspace->columns)
 //    {
@@ -412,6 +436,34 @@ void Client_InitAll(void)
 //    }
 }
 
+void Client_UpdateAll(void)
+{
+    int wspace_mask = 0;
+    for (int i = 0; i < Num_Monitors; i++)
+    {
+        wspace_mask |= (1 << Monitors[i].wspace);
+    }
+
+    Client* c;
+    LIST_FOR_EACH(c, AllClients)
+    {
+        int wspace_active = ((wspace_mask & (1 << c->wspace)) != 0);
+        if (wspace_active && (c->state != WithdrawnState))
+        {
+            Client_Show(c);
+        }
+        else
+        {
+            Client_Hide(c);
+        }
+    }
+}
+
+
+
+
+
+
 //Client* client_add(Window win, XWindowAttributes* attr)
 //{
 //    Client* c = ecalloc(1, sizeof(Client));
diff --git a/error.c b/error.c
index bf2662372274aa296cb6371e575c51fdd84ce00c..35fb456c62c8774a549aee32046cb0aa7e42879a 100644 (file)
--- a/error.c
+++ b/error.c
@@ -5,7 +5,8 @@ int (*error_default)(Display* disp, XErrorEvent* ev) = NULL;
 int error_init(Display* disp, XErrorEvent* ev)
 {
     (void)disp, (void)ev;
-    die("another window manager is active");
+    printf("anvil: fatal error: another window manager is active");
+    exit(1);
     return -1;
 }
 
diff --git a/keys.c b/keys.c
index 8fc45bf5377b0967a98dea0e57e5645491411913..1092b28791bca2545f45f6a838d17965381eb642 100644 (file)
--- a/keys.c
+++ b/keys.c
@@ -25,14 +25,12 @@ static void quit(Arg* arg)
 
 static void set_workspace(Arg* arg)
 {
-    (void)arg;
-//    mons_wspace(arg->i);
+    Monitors_SetWorkspace(arg->i);
 }
 
 static void to_workspace(Arg* arg)
 {
-    (void)arg;
-//    mons_towspace(Focused, arg->i);
+    Monitors_SendToWorkspace(Focused, arg->i);
 }
 
 static void runcmd(Arg *arg)
diff --git a/monitors.c b/monitors.c
new file mode 100644 (file)
index 0000000..83641fa
--- /dev/null
@@ -0,0 +1,74 @@
+#include "anvil.h"
+
+int GetActiveMonitor(void)
+{
+    int monitor = 0;
+    Mouse_GetLocation(&PtrX, &PtrY);
+    for (int i = 0; i < Num_Monitors; i++)
+    {
+        Monitor* mon = &Monitors[i];
+        if ((mon->x <= PtrX && PtrX < mon->x+mon->w) &&
+            (mon->y <= PtrY && PtrY < mon->y+mon->h))
+        {
+            monitor = i;
+            break;
+        }
+    }
+    return monitor;
+}
+
+void Monitors_Init(void)
+{
+    XGrabServer(X.disp);
+    int nmons;
+    XineramaScreenInfo* mons = XineramaQueryScreens(X.disp, &nmons);
+    nmons = min(MAX_MONITOR_COUNT, nmons);
+    for (int i = 0; i < nmons; i++)
+    {
+        Monitor* m = &Monitors[i];
+        m->x = mons[i].x_org;
+        m->y = mons[i].y_org;
+        m->w = mons[i].width;
+        m->h = mons[i].height;
+        m->midx = m->x + m->w/2;
+        m->midy = m->y + m->h/2;
+        m->wspace = i;
+        Workspaces[i].monitor = i;
+        printf("x: %d y: %d w: %d h: %d ws: %d\n", m->x, m->y, m->w, m->h, m->wspace);
+    }
+    Num_Monitors = nmons;
+    if (mons)
+    {
+        XFree(mons);
+    }
+    Client_UpdateAll();
+    XUngrabServer(X.disp);
+}
+
+void Monitors_SetWorkspace(int ws_id)
+{
+    printf("WORKSPACE %d\n", ws_id);
+
+    XGrabServer(X.disp);
+    int mon_id = GetActiveMonitor();
+    int other_mon_id = Workspaces[ws_id].monitor;
+    printf("MONITORS %d %d\n", mon_id, other_mon_id);
+
+    if (mon_id != other_mon_id)
+    {
+        int prev_ws = Monitors[mon_id].wspace;
+        printf("SWAPPING %d %d\n", prev_ws, ws_id);
+        Monitors[mon_id].wspace = ws_id;
+        Monitors[other_mon_id].wspace = prev_ws;
+
+
+        Client_UpdateAll();
+    }
+    XUngrabServer(X.disp);
+}
+
+void Monitors_SendToWorkspace(Client* c, int id)
+{
+    (void)c;
+    (void)id;
+}
diff --git a/mouse.c b/mouse.c
index 4931d7c45b608f38e5b64f02c7dfe18faab38819..531528fad2fc5cea045be9d8e5f458a4160b889a 100644 (file)
--- a/mouse.c
+++ b/mouse.c
@@ -147,7 +147,7 @@ void Mouse_Down(XButtonEvent* ev)
             X.edge = E_NONE;
         }
 
-        Client_Raise(client);
+        Client_Raise(c);
         ProcessMouseEvent(ev, c, Floating, sizeof(Floating)/sizeof(Floating[0]));
     }
 }
@@ -202,3 +202,10 @@ void Mouse_ToCorner(Client* c)
     X.last_x = c->x + new_w;
     X.last_y = c->y + new_h;
 }
+
+void Mouse_GetLocation(int* ptrx, int* ptry)
+{
+    Window root = 0, child = 0;
+    int winx = 0, winy = 0, mask = 0;
+    XQueryPointer(X.disp, X.root, &root, &child, ptrx, ptry, &winx, &winy, (unsigned int*)&mask);
+}
diff --git a/util.c b/util.c
deleted file mode 100644 (file)
index e33a086..0000000
--- a/util.c
+++ /dev/null
@@ -1,46 +0,0 @@
-#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);
-    exit(1);
-}
-
-void* ecalloc(size_t n, size_t sz)
-{
-    void* p = calloc(n, sz);
-    if (!p)
-    {
-        die("out of memory");
-    }
-    return p;
-}
-
-void xfree(void* p)
-{
-    if (p)
-    {
-        XFree(p);
-    }
-}
-
-void sendmsg(Window win, Atom proto, Atom type)
-{
-    XEvent ev;
-    memset(&ev, 0, sizeof(ev));
-    ev.xclient.type = ClientMessage;
-    ev.xclient.window = win;
-    ev.xclient.message_type = proto;
-    ev.xclient.format = 32;
-    ev.xclient.data.l[0] = type;
-    ev.xclient.data.l[1] = CurrentTime;
-    XSendEvent(X.disp, win, False, 0, &ev);
-}