#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:
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)
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)
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);
+ }
}
/* 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;
{
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);
Keys_Process(ev);
}
+static void xscreenchangenotify(XEvent* e)
+{
+ (void)e;
+ Monitors_Init();
+}
+
+
static void init_cursors(void)
{
XColor csr_bdr, csr_fill;
check_for_wm();
init_cursors();
init_font();
-// mons_init();
Client_InitAll();
Keys_Init();
+ Monitors_Init();
atoms_init();
/* setup window life-cycle management event handlers */
X.eventfns[PropertyNotify] = xpropnotify;
X.eventfns[EnterNotify] = xenternotify;
X.eventfns[Expose] = xexpose;
+ X.eventfns[RRScreenChangeNotify] = xscreenchangenotify;
+
/* main event loop */
XSync(X.disp, False);
#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 */
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;
// 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;
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);
/* 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);
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
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
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};
return curr;
}
-static Client* Create(Window win)
+Client* Client_Create(Window win)
{
Client* c = NULL;
XWindowAttributes attr;
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)
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);
}
}
}
+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;
c->name, strlen(c->name));
}
}
-
- /* tell the window to redraw itself */
-\
}
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)
// {
// }
}
+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));
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;
}
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)
--- /dev/null
+#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;
+}
X.edge = E_NONE;
}
- Client_Raise(client);
+ Client_Raise(c);
ProcessMouseEvent(ev, c, Floating, sizeof(Floating)/sizeof(Floating[0]));
}
}
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);
+}
+++ /dev/null
-#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);
-}