#include "anvil.h"
-Client* Focused = NULL;
-
void client_initall(void)
{
+ /* TODO: Find all top-level windows and register them correctly
+
+ * Find all root children with override_redirect set False
+ * Add them to withdrawn list if WM_STATE = withdrawn
+ * Add them as floating and unshaded if WM_STATE = Normal
+ * Add them as floating ad shaded if WM_STATE = Iconic
+
+ */
+
unsigned int nwins;
Window d1, d2, *wins = NULL;
XWindowAttributes attr;
{
for (unsigned int i = 0; i < nwins; i++)
{
- if (XGetWindowAttributes(X.disp, wins[i], &attr) && !attr.override_redirect)
+ if (XGetWindowAttributes(X.disp, wins[i], &attr) && (attr.override_redirect == False))
{
Client* c = client_add(wins[i], &attr);
c->flags |= F_FLOATING;
int format, nprotos = 0;
unsigned long n, extra;
- /* get window title */
+ /* WM_NAME - window title */
xfree(c->name);
c->name = NULL;
XGetWindowProperty(
X.disp, c->win, XA_WM_NAME, 0, -1, False, AnyPropertyType, &actual_type, &format, &n, &extra, (unsigned char **)&c->name);
- /* check if the window is a dialog */
- XGetWindowProperty(
- X.disp, c->win, _NET_WM_WINDOW_TYPE, 0L, -1, False, XA_ATOM, &actual_type, &format, &n, &extra, (unsigned char **)&wintype);
- if (wintype && *wintype == _NET_WM_WINDOW_TYPE_DIALOG)
+ /* WM_HINTS - other non-dimensional attributes of the window */
+ XWMHints* hints = XGetWMHints(X.disp, c->win);
+ if (hints)
{
- c->flags |= F_DIALOG|F_FLOATING;
+ int ignored = (Focused == c ? XUrgencyHint : 0);
+ c->wm_flags = (hints->flags & ~ignored);
+ c->hints = *hints;
}
- xfree(wintype);
+ xfree(hints);
+
+ /* WM_NORMAL_HINTS - desired dimensional attributes of the window */
+ XGetWMNormalHints(X.disp, c->win, &(c->size_hints), &(c->hint_flags));
- /* get the other hints and protocols */
- XGetWMNormalHints(X.disp, c->win, &(c->hints), &(c->hint_flags));
+ /* WM_PROTOCOLS - list of client message protocols this window responds to */
XGetWMProtocols(X.disp, c->win, &protos, &nprotos);
for (int i = 0; i < nprotos; i++)
{
{
c->flags |= F_WM_DELETE;
}
+
+ // TODO: handle WM_TAKE_FOCUS
}
xfree(protos);
+ /* WM_CLASS - instance and class names of the window. informs WM about behavior of window */
+ // TODO: Read the class and instance of the window
- XWMHints* hints = XGetWMHints(X.disp, c->win);
- if (hints)
+ /* WM_TRANSIENT_FOR - marks the window as a pop-up for another window */
+ // TODO: read the transient_for property and use ti to handle pop-ups better
+
+ /* WM_CLIENT_MACHINE - */
+ // TODO: read client machine property
+
+ /* check if the window is a dialog */
+ XGetWindowProperty(
+ X.disp, c->win, _NET_WM_WINDOW_TYPE, 0L, -1, False, XA_ATOM, &actual_type, &format, &n, &extra, (unsigned char **)&wintype);
+ if (wintype && *wintype == _NET_WM_WINDOW_TYPE_DIALOG)
{
- int ignored = (Focused == c ? XUrgencyHint : 0);
- c->wm_flags = (hints->flags & ~ignored);
+ c->flags |= F_DIALOG|F_FLOATING;
}
- xfree(hints);
+ xfree(wintype);
+
+ /* The following properties are unused currently */
+ /* WM_ICON_NAME - window title when iconified */
+ /* WM_COLORMAP_WINDOWS - */
}
void client_shade(Client* c)
#include "anvil.h"
#include <math.h>
-int PtrX = 0, PtrY = 0;
static Monitor* pickmon(void);
-static Column* pickcol(Column* cols, int relx);
-static Workspace* pickws(Monitor* mon, int wsid);
+static Column* pickcol(Workspace* wspace, int relx);
static void client_visibility(Workspace* wspace, int show);
static Client* client_find(Client* clients, Window win);
static void add_client(Monitor* mon, Client* c, int ptrx);
static void remove_client(Location* loc, Client* c);
-static void adjust_all(Column* col, int xoff);
+//static void adjust_all(Column* col, int xoff);
static void change_wspace(Monitor* mon, Workspace* wspace);
-Monitor* Monitors = NULL;
-
-static int min_col_width(Monitor* mon)
-{
- return (int)(mon->w * MIN_COL_FACT);
-}
+//static int min_col_width(Monitor* mon)
+//{
+// return (int)(mon->w * MIN_COL_FACT);
+//}
void mons_init(void)
{
XineramaScreenInfo* mons = XineramaQueryScreens(X.disp, &nmons);
for (int i = 0; i < nmons; i++)
{
- Monitor* m = ecalloc(1, sizeof(Monitor));
+ 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->next = Monitors;
- Monitors = m;
- for (int i = 0; i < 10; i++)
- {
- Column* col = ecalloc(1, sizeof(Column));
- col->width = m->w;
- Workspace* wspace = ecalloc(1, sizeof(Workspace));
- wspace->columns = col;
- wspace->next = m->wspaces;
- m->wspaces = wspace;
- }
- m->cspace = m->wspaces;
+ m->wspace = &Workspaces[i];
+ m->wspace->ncolumns = 1;
}
+ Num_Monitors = nmons;
xfree(mons);
-
- Monitor* m = Monitors;
- while (m)
- {
- printf("x: %d y: %d w: %d h: %d\n", m->x, m->y, m->w, m->h);
- Workspace* w = m->wspaces;
- while (w)
- {
- printf(" wspace %p\n", (void*)w);
- Column* c = w->columns;
- while (c)
- {
- printf(" col %p %d\n", (void*)c, c->width);
- c = c->next;
- }
- w = w->next;
- }
- m = m->next;
- }
-
}
void mons_layer(Monitor* mon)
int nwins = 0;
Window* wins = NULL;
Client* c;
- Column* col;
- LIST_FOR_EACH(c, mon->cspace->floating)
+ Workspace* wspace = mon->wspace;
+
+ /* add all of the floating windows */
+ LIST_FOR_EACH(c, wspace->floating)
{
wins = realloc(wins, ++nwins * sizeof(Window));
wins[nwins-1] = c->frame;
}
+
/* now lower all of the tiled windows */
- LIST_FOR_EACH(col, mon->cspace->columns)
+ for (int i = 0; i < wspace->ncolumns; i++)
{
- LIST_FOR_EACH(c, col->clients)
+ LIST_FOR_EACH(c, wspace->columns[i].clients)
{
- if (col->focused != c)
- {
- wins = realloc(wins, ++nwins * sizeof(Window));
- wins[nwins-1] = c->frame;
- }
+ wins = realloc(wins, ++nwins * sizeof(Window));
+ wins[nwins-1] = c->frame;
}
}
+
+ /* restack them and free the array */
if (nwins)
{
XRestackWindows(X.disp, wins, nwins);
int mons_find(Window win, Location* loc)
{
- Monitor* mon;
- Workspace* wspace;
- LIST_FOR_EACH(mon, Monitors)
+ Monitor* mon = NULL;
+ Workspace* wspace = NULL;
+ Column* column = NULL;
+ Client* client = NULL;
+
+ /* check if the window is withdrawn */
+ client = client_find(Withdrawn, win);
+
+ /* otherwise, check if it is on a workspace */
+ if (!client)
{
- LIST_FOR_EACH(wspace, mon->wspaces)
+ for (int i = 0; i < MAX_WSPACE_COUNT; i++)
{
- Column* column = NULL;
- Client* client = client_find(wspace->floating, win);
+ wspace = &Workspaces[i];
+
+ /* check if the window is floating first */
+ client = client_find(wspace->floating, win);
+
+ /* if not found, find the window in the columns */
if (!client)
{
- LIST_FOR_EACH(column, wspace->columns)
+ for (int c = 0; c < wspace->ncolumns; c++)
{
- if ( (client = client_find(column->clients, win)) )
+ Column* col = &(wspace->columns[c]);
+ if ( (client = client_find(col->clients, win)) )
{
+ column = col;
break;
}
}
}
- /* return the client location if we found it */
- if (client)
- {
- loc->monitor = mon;
- loc->workspace = wspace;
- loc->column = column;
- loc->client = client;
- return 1;
- }
}
}
+
+ /* return the client location if we found it */
+ if (client)
+ {
+ loc->monitor = mon;
+ loc->workspace = wspace;
+ loc->column = column;
+ loc->client = client;
+ return 1;
+ }
+
return 0;
}
{
int maxarea = 0;
Monitor *mon = NULL, *closest = NULL;
- LIST_FOR_EACH(mon, Monitors)
+ for (int i =0; i < Num_Monitors; i++)
{
+ mon = &Monitors[i];
int left = max(cleft, mon->x);
int right = min(cright, mon->x + mon->w);
int top = max(ctop, mon->y);
if (closest && loc.monitor != closest)
{
loc.workspace->floating = list_del(loc.workspace->floating, c);
- c->next = closest->cspace->floating;
- closest->cspace->floating = c;
+ c->next = closest->wspace->floating;
+ closest->wspace->floating = c;
}
}
}
void mons_wspace(int wsid)
{
Monitor* mon = pickmon();
- change_wspace(mon, pickws(mon, wsid));
+ change_wspace(mon, &Workspaces[wsid]);
}
void mons_towspace(Client* c, int wsid)
{
- Location loc = {0};
- if (mons_find(c->win, &loc))
- {
- mouse_get(&PtrX, &PtrY);
- Workspace* wspace = pickws(loc.monitor, wsid);
- if (wspace != loc.workspace)
- {
- remove_client(&loc, c);
- client_show(c, 0);
- Workspace* prev = loc.monitor->cspace;
- loc.monitor->cspace = wspace;
- add_client(loc.monitor, c, PtrX);
- loc.monitor->cspace = prev;
- }
- }
+ (void)c;
+ (void)wsid;
+// TODO: rework how towspace works
+// Location loc = {0};
+// if (mons_find(c->win, &loc))
+// {
+// mouse_get(&PtrX, &PtrY);
+// Workspace* wspace = &Workspaces[wsid];
+// if (wspace != loc.workspace)
+// {
+// remove_client(&loc, c);
+// client_show(c, 0);
+// Workspace* prev = &Workspaces[loc.monitor->wspace];
+// loc.monitor->wspace = wspace;
+// add_client(loc.monitor, c, PtrX);
+// loc.monitor->wspace = prev;
+// }
+// }
}
void mons_raise(Monitor* mon, Client* c)
{
- mon->cspace->floating = list_del(mon->cspace->floating, c);
- c->next = mon->cspace->floating;
- mon->cspace->floating = c;
+ mon->wspace->floating = list_del(mon->wspace->floating, c);
+ c->next = mon->wspace->floating;
+ mon->wspace->floating = c;
mons_layer(mon);
}
void mons_lower(Monitor* mon, Client* c)
{
- mon->cspace->floating = list_del(mon->cspace->floating, c);
+ mon->wspace->floating = list_del(mon->wspace->floating, c);
c->next = NULL;
- if (mon->cspace->floating)
+ if (mon->wspace->floating)
{
- Client* curr = list_last(mon->cspace->floating);
+ Client* curr = list_last(mon->wspace->floating);
curr->next = c;
}
else
{
- mon->cspace->floating = c;
+ mon->wspace->floating = c;
}
mons_layer(mon);
}
void mons_colsplit(void)
{
- Monitor* mon = pickmon();
- Column* col = pickcol(mon->cspace->columns, PtrX - mon->x);
- int next_empty = (col->next && !col->next->clients);
- if (col->clients && !next_empty && col->width >= 2*min_col_width(mon))
- {
- Column* newcol = ecalloc(1, sizeof(Column));
- newcol->width = col->width/2;
- col->width -= newcol->width;
- newcol->next = col->next;
- col->next = newcol;
- adjust_all(col, 0);
- }
+// TODO: implement column splitting
+// Monitor* mon = pickmon();
+// Column* col = pickcol(mon->wspace, PtrX - mon->x);
+// int next_empty = (col->next && !col->next->clients);
+// if (col->clients && !next_empty && col->width >= 2*min_col_width(mon))
+// {
+// Column* newcol = ecalloc(1, sizeof(Column));
+// newcol->width = col->width/2;
+// col->width -= newcol->width;
+// newcol->next = col->next;
+// col->next = newcol;
+// adjust_all(col, 0);
+// }
}
void mons_coljoin(void)
{
- Monitor* mon = pickmon();
- Column* dest = pickcol(mon->cspace->columns, PtrX - mon->x);
- Column* dead = dest->next;
- if (!dead)
- {
- dead = dest;
- dest = list_prev(mon->cspace->columns, dead);
- }
-
- if (dest && dead)
- {
- /* add the clients to the current col */
- for (Client* c = dead->clients; c;)
- {
- Client* next = c->next;
- stacked_add(&(Location){mon, NULL, dest, c});
- c = next;
- }
- dest->next = dead->next;
- dest->width += dead->width;
- free(dead);
- adjust_all(dest, 0);
- }
+// TODO: implement column joining
+// Monitor* mon = pickmon();
+// Column* dest = pickcol(mon->wspace, PtrX - mon->x);
+// Column* dead = dest->next;
+// if (!dead)
+// {
+// dead = dest;
+// dest = list_prev(mon->wspace->columns, dead);
+// }
+//
+// if (dest && dead)
+// {
+// /* add the clients to the current col */
+// for (Client* c = dead->clients; c;)
+// {
+// Client* next = c->next;
+// stacked_add(&(Location){mon, NULL, dest, c});
+// c = next;
+// }
+// dest->next = dead->next;
+// dest->width += dead->width;
+// free(dead);
+// adjust_all(dest, 0);
+// }
}
void mons_coladjust(Monitor* mon, Column* col, int wdiff)
{
- Column* neighbor = col->next;
- int minwidth = min_col_width(mon);
- if (X.edge == E_LEFT && mon->cspace->columns != col)
- {
- for (neighbor = mon->cspace->columns; neighbor && neighbor->next != col; neighbor = neighbor->next);
- int minadj = -(neighbor->width - minwidth);
- int maxadj = (col->width - minwidth);
- wdiff = min(max(minadj, wdiff), maxadj);
- neighbor->width += wdiff;
- col->width -= wdiff;
- adjust_all(col, wdiff);
- adjust_all(neighbor, 0);
- }
- else if (X.edge == E_RIGHT && col->next)
- {
- int minadj = -(col->width - minwidth);
- int maxadj = (neighbor->width - minwidth);
- wdiff = min(max(minadj, wdiff), maxadj);
- col->width += wdiff;
- neighbor->width -= wdiff;
- adjust_all(col, 0);
- adjust_all(neighbor, wdiff);
- }
- else
- {
- /* invalid edge */
- }
+ (void)mon;
+ (void)col;
+ (void)wdiff;
+// TODO: implement column resizing
+// Column* neighbor = col->next;
+// int minwidth = min_col_width(mon);
+// if (X.edge == E_LEFT && mon->wspace->columns != col)
+// {
+// for (neighbor = mon->wspace->columns; neighbor && neighbor->next != col; neighbor = neighbor->next);
+// int minadj = -(neighbor->width - minwidth);
+// int maxadj = (col->width - minwidth);
+// wdiff = min(max(minadj, wdiff), maxadj);
+// neighbor->width += wdiff;
+// col->width -= wdiff;
+// adjust_all(col, wdiff);
+// adjust_all(neighbor, 0);
+// }
+// else if (X.edge == E_RIGHT && col->next)
+// {
+// int minadj = -(col->width - minwidth);
+// int maxadj = (neighbor->width - minwidth);
+// wdiff = min(max(minadj, wdiff), maxadj);
+// col->width += wdiff;
+// neighbor->width -= wdiff;
+// adjust_all(col, 0);
+// adjust_all(neighbor, wdiff);
+// }
+// else
+// {
+// /* invalid edge */
+// }
}
void mons_tilemove(Location* loc, int hdiff)
{
Monitor* mon = pickmon();
- Column* col = pickcol(mon->cspace->columns, PtrX - mon->x);
+ Column* col = pickcol(mon->wspace, PtrX - mon->x);
if (loc->monitor != mon || loc->column != col)
{
remove_client(loc, loc->client);
static Monitor* pickmon(void)
{
mouse_get(&PtrX, &PtrY);
- Monitor* mon;
- LIST_FOR_EACH_UNTIL(mon, Monitors,
- (mon->x <= PtrX && PtrX < mon->x+mon->w) &&
- (mon->y <= PtrY && PtrY < mon->y+mon->h)
- );
- mon = (mon ? mon : Monitors);
- return mon;
+ Monitor* monitor = NULL;
+ 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 = mon;
+ break;
+ }
+ }
+ monitor = (monitor ? monitor : &Monitors[0]);
+ return monitor;
}
-static Column* pickcol(Column* cols, int relx)
+static Column* pickcol(Workspace* wspace, int relx)
{
Column* col;
int left = 0, right = 0;
- printf("cols %p\n", cols);
- LIST_FOR_EACH(col, cols)
+ for (int i = 0; i < wspace->ncolumns; i++)
{
- printf("curr = %p\n", col);
- left = right, right += col->width;
- printf("%d <= %d < %d\n", left, relx, right);
+ left = right, right += wspace->columns[i].width;
if (left <= relx && relx < right)
{
+ col = &wspace->columns[i];
break; /* we found the column holding the mouse */
}
}
- printf("%p\n", (void*)col);
-// if (!col) col = cols;
return col;
}
-static Workspace* pickws(Monitor* mon, int wsid)
-{
- Workspace* wspace;
- int i = 0;
- LIST_FOR_EACH_UNTIL(wspace, mon->wspaces, (i++ == wsid));
- return wspace;
-}
-
static void client_visibility(Workspace* wspace, int show)
{
Column* col;
{
client_show(client, show);
}
- LIST_FOR_EACH(col, wspace->columns)
+ for (int i = 0; i < wspace->ncolumns; i++)
{
+ col = &(wspace->columns[i]);
LIST_FOR_EACH(client, col->clients)
{
client_show(client, show);
{
if (X.mode == M_INIT || c->flags & (F_DIALOG|F_FLOATING))
{
- c->next = mon->cspace->floating;
- mon->cspace->floating = c;
+ c->next = mon->wspace->floating;
+ mon->wspace->floating = c;
c->x = mon->midx - c->w/2;
c->y = mon->midy - c->h/2;
client_adjust(c);
}
else
{
- /* find first empty column, and fill that first */
Column* col = NULL;
- LIST_FOR_EACH_UNTIL(col, mon->cspace->columns, col->clients == NULL);
+ /* find first empty column, and fill that first */
+ for (int i = 0; i < mon->wspace->ncolumns; i++)
+ {
+ if (mon->wspace->columns[i].clients == NULL)
+ {
+ col = &mon->wspace->columns[i];
+ break;
+ }
+ }
+
+ /* otherwise pick the column to the right of the current column */
if (!col)
{
- /* otherwise pick the column to the right or the current column */
- col = pickcol(mon->cspace->columns, ptrx - mon->x);
- if (col->next)
+ Column* c = pickcol(mon->wspace, ptrx - mon->x);
+ int cid = (c - mon->wspace->columns);
+ if (cid < (mon->wspace->ncolumns - 1))
{
- col = col->next;
+ cid++;
}
+ col = &mon->wspace->columns[cid];
}
- /* add in monocled or stacked mode */
+
+ /* add the client to the stack */
stacked_add(&(Location){mon, NULL, col, c});
}
mons_layer(mon);
}
}
-static void adjust_all(Column* col, int xoff)
-{
- Client* c;
- LIST_FOR_EACH(c, col->clients)
- {
- c->x += xoff;
- c->w = col->width;
- client_adjust(c);
- }
-}
+//static void adjust_all(Column* col, int xoff)
+//{
+// (void)col;
+// (void)xoff;
+//// Client* c;
+//// LIST_FOR_EACH(c, col->clients)
+//// {
+//// c->x += xoff;
+//// c->w = col->width;
+//// client_adjust(c);
+//// }
+//}
static void change_wspace(Monitor* mon, Workspace* wspace)
{
- if (mon->cspace != wspace)
+ if (mon->wspace != wspace)
{
- client_visibility(mon->cspace, 0);
+ client_visibility(mon->wspace, 0);
client_visibility(wspace, 1);
- mon->cspace = wspace;
+ mon->wspace = wspace;
}
}