Add split layout

This commit is contained in:
Martin Duquesnoy 2011-09-15 00:01:28 +02:00
parent 60bd64e59e
commit 961e57f876
12 changed files with 299 additions and 19 deletions

View File

@ -98,9 +98,7 @@ barwin_resize(struct barwin *b, int w, int h)
void
barwin_mousebind_new(struct barwin *b, unsigned int button, bool u, struct geo a, void (*func)(Uicb), Uicb cmd)
{
struct mousebind *m;
m = xcalloc(1, sizeof(struct mousebind));
struct mousebind *m = (struct mousebind*)xcalloc(1, sizeof(struct mousebind));
m->button = button;
m->use_area = u;

View File

@ -10,6 +10,7 @@
#include "util.h"
#include "barwin.h"
#include "ewmh.h"
#include "layout.h"
#define CLIENT_MOUSE_MOD Mod1Mask
@ -47,6 +48,54 @@ client_gb_win(Window w)
return c;
}
static struct client*
client_gb_pos(struct tag *t, int x, int y)
{
struct client *c;
SLIST_FOREACH(c, &t->clients, tnext)
if(INAREA(x, y, c->geo))
return c;
return NULL;
}
/** Get client left/right/top/bottom of selected client
*\param bc Base client
*\param pos Position
*\return Client found or NULL
*/
struct client*
client_next_with_pos(struct client *bc, Position p)
{
struct client *c;
int x, y;
const static char scanfac[4][2] =
{
{ 2, 0 }, { -2, 0 }, /* Right, Left */
{ 0, -2 }, { 0, 2 } /* Top, Bottom */
};
/*
* Set start place of pointer (edge of base client)
* for faster scanning
*/
x = bc->geo.x + ((p == Right) ? bc->geo.w : 0);
y = bc->geo.y + ((p == Bottom) ? bc->geo.h : 0);
y += ((LDIR(p)) ? (bc->geo.h >> 1) : 0);
x += ((p > Left) ? (bc->geo.w >> 1) : 0);
/* Scan in right direction to next(p) physical client */
while((c = client_gb_pos(bc->tag, x, y)) == bc)
{
x += scanfac[p][0];
y += scanfac[p][1];
}
return c;
}
/** Map a client
* \param c struct client pointer
*/
@ -191,14 +240,15 @@ client_new(Window w, XWindowAttributes *wa)
c->flags = 0;
c->tag = NULL;
/* Set tag */
tag_client(W->screen->seltag, c);
/* struct geometry */
c->geo.x = wa->x;
c->geo.y = wa->y;
c->geo.w = wa->width;
c->geo.h = wa->height;
c->cgeo = c->geo;
/* Set tag */
tag_client(W->screen->seltag, c);
/* X window attributes */
XSelectInput(W->dpy, w, EnterWindowMask | FocusChangeMask
@ -219,6 +269,29 @@ client_new(Window w, XWindowAttributes *wa)
return c;
}
void
client_moveresize(struct client *c, struct geo g)
{
c->geo = c->cgeo = g;
c->cgeo.w += THEME_DEFAULT->client_border_width << 1;
c->cgeo.h += THEME_DEFAULT->client_border_width << 1;
XMoveResizeWindow(W->dpy, c->win, g.x, g.y, g.w, g.h);
}
void
client_maximize(struct client *c)
{
c->geo = c->tag->screen->ugeo;
c->geo.x = c->geo.y = 0; /* Frame x/y, not screen geo */
c->geo.w = c->tag->screen->ugeo.w - (THEME_DEFAULT->client_border_width << 1);
c->geo.h = c->tag->screen->ugeo.h - (THEME_DEFAULT->client_border_width << 1);
client_moveresize(c, c->geo);
}
void
client_remove(struct client *c)
{
@ -232,6 +305,8 @@ client_remove(struct client *c)
XSetInputFocus(W->dpy, W->root, RevertToPointerRoot, CurrentTime);
}
layout_split_arrange_closed(c);
/* Remove from global client list */
SLIST_REMOVE(&W->h.client, c, client, next);

View File

@ -10,10 +10,13 @@
void client_configure(struct client *c);
struct client *client_gb_win(Window w);
struct client *client_next_with_pos(struct client *bc, Position p);
void client_focus(struct client *c);
void client_get_name(struct client *c);
void client_close(struct client *c);
struct client *client_new(Window w, XWindowAttributes *wa);
void client_moveresize(struct client *c, struct geo g);
void client_maximize(struct client *c);
void client_remove(struct client *c);
void client_free(void);

View File

@ -16,7 +16,7 @@
static void
config_theme(void)
{
struct theme *t;
struct theme *t, *p;
size_t i, n;
struct conf_sec *sec, **ks;
@ -63,7 +63,13 @@ config_theme(void)
t->client_titlebar_width = fetch_opt_first(ks[i], "12", "client_titlebar_width").num;
t->client_border_width = fetch_opt_first(ks[i], "1", "client_border_width").num;
SLIST_INSERT_HEAD(&W->h.theme, t, next);
/* insert_tail with SLIST */
if(SLIST_EMPTY(&W->h.theme))
SLIST_INSERT_HEAD(&W->h.theme, t, next);
else
SLIST_INSERT_AFTER(p, t, next);
p = t;
}
free(ks);
@ -162,7 +168,7 @@ config_keybind(void)
/* mod = {} */
opt = fetch_opt(ks[i], "", "mod");
for(j = 0; j < fetch_opt_count(opt); ++j)
for(j = k->mod = 0; j < fetch_opt_count(opt); ++j)
k->mod |= modkey_keysym(opt[j].str);
free(opt);

View File

@ -1,4 +1,4 @@
/*
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/

View File

@ -4,5 +4,125 @@
*/
#include "layout.h"
#include "config.h"
#include "client.h"
#include "util.h"
static struct geo
layout_split(struct client *c, bool vertical)
{
struct geo og, geo;
int bord = THEME_DEFAULT->client_border_width;
geo = og = c->geo;
if(vertical)
{
c->geo.w >>= 1;
geo.x = (c->geo.x + bord) + (c->geo.w + bord);
geo.w >>= 1;
/* Remainder */
geo.w += (og.x + og.w) - (geo.x + geo.w);
}
else
{
c->geo.h >>= 1;
geo.y = (c->geo.y + bord) + (c->geo.h + bord);
geo.h >>= 1;
/* Remainder */
geo.h += (og.y + og.h) - (geo.y + geo.h);
}
client_moveresize(c, c->geo);
return geo;
}
/* Use ghost client properties to fix holes in tile
* .--. ~ ~
* /xx \ ~ ~
* ~~\O _ (____ ~
* __.| .--'-==~ ~
* '---\ '. ~ , ~
* '. '-.___.-'/ ~
* '-.__ _.' ~
* ````` ~
*/
void
layout_split_arrange_closed(struct client *ghost)
{
struct client *c, *cc;
struct geo g;
bool b;
Position p;
/* Search for single parent for easy resize
* Example case:
* ___________ ___________
* | | B | -> -> | | |
* | A |_____| -> Close -> | A | B |
* | | C | -> C -> | |v v v|
* |_____|_____| -> -> |_____|_____|
*/
for(p = Right; p < Center; ++p) /* Check every direction */
{
if((c = client_next_with_pos(ghost, p)))
if(GEO_CHECK2(ghost->geo, c->geo, p))
{
layout_split_arrange_size(ghost->geo, c, p);
return;
}
}
/* Check row parents for full resize
* Example case:
* ___________ ___________
* | | B | -> -> | << B |
* | A |_____| -> Close -> |___________|
* | | C | -> A -> | << C |
* |_____|_____| -> -> |___________|
*/
for(p = Right; p < Center && !b; ++p)
{
if((c = client_next_with_pos(ghost, p))
&& layout_split_check_row_dir(c, ghost, p))
{
g = c->geo;
SLIST_FOREACH(cc, &c->tag->clients, tnext)
if(GEO_PARENTROW(g, cc->geo, RPOS(p))
&& GEO_CHECK_ROW(cc->geo, ghost->geo, p))
{
layout_split_arrange_size(ghost->geo, cc, p);
b = true;
}
}
}
}
/* Integrate a client in split layout: split sc and fill c in new geo */
void
layout_split_integrate(struct client *c, struct client *sc)
{
struct geo g;
/* No sc */
if(!sc || sc == c || sc->tag != c->tag)
{
/*
* Not even a first client in list, then
* maximize the lonely client
*/
if(!(sc = SLIST_FIRST(&c->tag->clients)))
{
client_maximize(c);
return;
}
}
g = layout_split(sc, (sc->geo.h < sc->geo.w));
client_moveresize(c, g);
}

View File

@ -7,6 +7,82 @@
#define LAYOUT_H
#include "wmfs.h"
#include "config.h"
#include "client.h"
/* Check lateral direction (if p is Right or Left) */
#define LDIR(P) (P < Top)
/* Reverse position */
#define RPOS(P) (P & 1 ? P - 1 : P + 1)
/* geo comparaison */
#define GEO_CHECK2(g1, g2, p) (LDIR(p) ? (g1.h == g2.h) : (g1.w == g2.w))
#define GEO_CHECK_ROW(g1, g2, p) \
(LDIR(p) \
? (g1.y >= g2.y && (g1.y + g1.h) <= (g2.y + g2.h)) \
: (g1.x >= g2.x && (g1.x + g1.w) <= (g2.x + g2.w)))
#define GEO_PARENTROW(g1, g2, p) \
(LDIR(p) \
? (p == Left ? (g1.x == g2.x) : (g1.x + g1.w == g2.x + g2.w)) \
: (p == Top ? (g1.y == g2.y) : (g1.y + g1.h == g2.y + g2.h)))
/* Debug */
#define DGEO(G) printf(": %d %d %d %d\n", G.x, G.y, G.w, G.h)
void layout_split_integrate(struct client *c, struct client *sc);
void layout_split_arrange_closed(struct client *ghost);
static inline void
layout_split_arrange_size(struct geo g, struct client *c, Position p)
{
if(LDIR(p))
{
c->geo.w += g.w + (THEME_DEFAULT->client_border_width << 1);
if(p == Right)
c->geo.x = g.x;
}
else
{
c->geo.h += g.h + (THEME_DEFAULT->client_border_width << 1);
if(p == Bottom)
c->geo.y = g.y;
}
client_moveresize(c, c->geo);
}
static inline bool
layout_split_check_row_dir(struct client *c, struct client *g, Position p)
{
struct geo cgeo = c->geo;
struct client *cc;
int bord = THEME_DEFAULT->client_border_width;
int i = 0, s = 0, cs = (LDIR(p) ? g->geo.h : g->geo.w );
SLIST_FOREACH(cc, &c->tag->clients, tnext)
if(GEO_PARENTROW(cgeo, cc->geo, RPOS(p))
&& GEO_CHECK_ROW(cc->geo, g->geo, p))
{
s += (LDIR(p)
? cc->geo.h + bord
: cc->geo.w + bord) + (i > 1 ? bord : 0);;
if(s == cs)
return true;
if(s > cs)
return false;
++i;
}
return false;
}
#endif /* LAYOUT_H */

View File

@ -12,6 +12,7 @@
#include "config.h"
#include "barwin.h"
#include "ewmh.h"
#include "layout.h"
struct tag*
tag_new(struct screen *s, char *name)
@ -89,7 +90,6 @@ tag_client(struct tag *t, struct client *c)
return;
SLIST_REMOVE(&c->tag->clients, c, client, tnext);
/* TODO: Focus next client */
if(c->tag->sel == c)
c->tag->sel = NULL;
@ -117,7 +117,7 @@ tag_client(struct tag *t, struct client *c)
/* Reparent client win in frame win */
XReparentWindow(W->dpy, c->win, t->frame, 0, 0);
/* tag_frame_client */
layout_split_integrate(c, t->sel);
/* Insert in new tag list */
SLIST_INSERT_HEAD(&t->clients, c, tnext);
@ -178,7 +178,9 @@ static void
tag_remove(struct tag *t)
{
free(t->name);
XDestroyWindow(W->dpy, t->frame);
free(t);
}

View File

@ -11,11 +11,11 @@
/* Todo FREE_LIST(type, head, function_remove) */
#define FREE_LIST(type, head) \
do { \
struct type *t; \
struct type *Z; \
while(!SLIST_EMPTY(&head)) { \
t = SLIST_FIRST(&head); \
Z = SLIST_FIRST(&head); \
SLIST_REMOVE_HEAD(&head, next); \
free(t); /* function_remove(t)*/ \
free(Z); /* function_remove(t)*/ \
} \
} while(/* CONSTCOND */ 0);
@ -33,7 +33,6 @@
#define ABS(j) (j < 0 ? -j : j)
#define INAREA(i, j, a) ((i) >= (a).x && (i) <= (a).x + (a).w && (j) >= (a).y && (j) <= (a).y + (a).h)
/*
* "#RRGGBB" -> 0xRRGGBB
*/

View File

@ -292,7 +292,7 @@ void
uicb_reload(Uicb cmd)
{
(void)cmd;
/* TODO */
}
void

View File

@ -104,7 +104,7 @@ struct client
struct tag *tag;
struct screen *screen;
struct barwin *titlebar;
struct geo geo;
struct geo geo, cgeo; /* Complete geo: + border */
char *title;
Flags flags;
Window win;
@ -124,7 +124,7 @@ struct keybind
struct mousebind
{
struct geo area;
unsigned int button;
int button;
bool use_area;
void (*func)(Uicb);
Uicb cmd;

View File

@ -4,6 +4,7 @@
[themes]
[theme]
# name = "default"