Layout Split: Add split layout.

This commit is contained in:
Martin Duquesnoy 2011-05-16 20:38:54 +02:00
parent 7eb15d595f
commit 911ac2f74a
7 changed files with 180 additions and 70 deletions

View File

@ -32,14 +32,6 @@
#include "wmfs.h"
#define RPOS(x) (x % 2 ? x - 1 : x + 1)
char scanfac[4][2] =
{
{ 1, 0 }, { -1, 0 }, /* Right, Left */
{ 0, -1 }, { 0, 1 } /* Top, Bottom */
};
/** Clean client tile factors
*\param c Client pointer
*/
@ -99,7 +91,7 @@ cfactor_geo(XRectangle geo, int fact[4], int *err)
*\param ccg Second geo
*\param p Direction of resizing
*/
static Bool
Bool
cfactor_parentrow(XRectangle cg, XRectangle ccg, Position p)
{
Bool ret;
@ -179,7 +171,7 @@ cfactor_arrange_two(Client *c1, Client *c2, Position p, int fac)
*\param p Direction of resizing
*\returm 1/0
*/
static Bool
Bool
cfactor_check_2pc(XRectangle g1, XRectangle g2, Position p)
{
if(p < Top)
@ -244,19 +236,12 @@ void
cfactor_set(Client *c, Position p, int fac)
{
Client *gc = NULL;
int x, y;
if(!c || !(c->flags & TileFlag) || p > Bottom)
return;
/* Start place of pointer for faster scanning */
x = c->geo.x + ((p == Right) ? c->geo.width : 0);
y = c->geo.y + ((p == Bottom) ? c->geo.height : 0);
y += ((p < Top) ? c->geo.height / 2 : 0);
x += ((p > Left) ? c->geo.width / 2 : 0);
/* Scan in right direction to next(p) physical client */
for(; (gc = client_gb_pos(c, x, y)) == c; x += scanfac[p][0], y += scanfac[p][1]);
/* Get next client with direction of resize */
gc = client_get_next_with_direction(c, p);
if(!gc || c->screen != gc->screen)
return;

View File

@ -132,46 +132,34 @@ client_get_prev(void)
}
/** Get client left/right/top/bottom of selected client
*\param bc Base client
*\param pos Position (Left/Right/Top/Bottom
*\return Client found
*/
static Client*
client_get_next_with_direction(Position pos)
Client*
client_get_next_with_direction(Client *bc, Position pos)
{
Client *c = NULL;
Client *ret = NULL;
Client *c;
int x, y;
char scanfac[4][2] =
{
{ 1, 0 }, { -1, 0 }, /* Right, Left */
{ 0, -1 }, { 0, 1 } /* Top, Bottom */
};
if(!sel || ishide(sel, selscreen))
if(!bc || ishide(bc, selscreen))
return NULL;
for(c = clients; c; c = c->next)
if(c != sel && !ishide(c, sel->screen))
switch(pos)
{
default:
case Right:
if(c->geo.x > sel->geo.x
&& (!ret || (ret && ret->geo.x > sel->geo.x && c->geo.x < ret->geo.x)))
ret = c;
break;
case Left:
if(c->geo.x < sel->geo.x
&& (!ret || (ret && ret->geo.x < sel->geo.x && c->geo.x > ret->geo.x)))
ret = c;
break;
case Top:
if(c->geo.y < sel->geo.y
&& (!ret || (ret && ret->geo.y < sel->geo.y && c->geo.y > ret->geo.y)))
ret = c;
break;
case Bottom:
if(c->geo.y > sel->geo.y
&& (!ret || (ret && ret->geo.y > sel->geo.y && c->geo.y < ret->geo.y)))
ret = c;
break;
}
/* Start place of pointer for faster scanning */
x = bc->geo.x + ((pos == Right) ? bc->geo.width : 0);
y = bc->geo.y + ((pos == Bottom) ? bc->geo.height : 0);
y += ((pos < Top) ? bc->geo.height / 2 : 0);
x += ((pos > Left) ? bc->geo.width / 2 : 0);
return ret;
/* Scan in right direction to next(p) physical client */
for(; (c = client_gb_pos(bc, x, y)) == bc; x += scanfac[pos][0], y += scanfac[pos][1]);
return c;
}
/** Switch to the previous client
@ -255,7 +243,7 @@ uicb_client_focus_right(uicb_t cmd)
Client *c;
(void)cmd;
if((c = client_get_next_with_direction(Right)))
if((c = client_get_next_with_direction(sel, Right)))
{
client_focus(c);
client_raise(c);
@ -274,7 +262,7 @@ uicb_client_focus_left(uicb_t cmd)
Client *c;
(void)cmd;
if((c = client_get_next_with_direction(Left)))
if((c = client_get_next_with_direction(sel, Left)))
{
client_focus(c);
client_raise(c);
@ -292,7 +280,7 @@ uicb_client_focus_top(uicb_t cmd)
Client *c;
(void)cmd;
if((c = client_get_next_with_direction(Top)))
if((c = client_get_next_with_direction(sel, Top)))
{
client_focus(c);
client_raise(c);
@ -310,7 +298,7 @@ uicb_client_focus_bottom(uicb_t cmd)
Client *c;
(void)cmd;
if((c = client_get_next_with_direction(Bottom)))
if((c = client_get_next_with_direction(sel, Bottom)))
{
client_focus(c);
client_raise(c);
@ -1021,7 +1009,7 @@ void
client_moveresize(Client *c, XRectangle geo, Bool r)
{
int os, e;
int rhx = 0, rhy = 0;
int rhx = 0;
if(!c)
return;
@ -1056,8 +1044,7 @@ client_moveresize(Client *c, XRectangle geo, Bool r)
/* To balance position of window in frame */
rhx = ((c->wrgeo.width) - geo.width) / 2;
rhy = ((c->wrgeo.height) - geo.height) / 2;
}
}
c->geo = geo;
@ -1073,7 +1060,7 @@ client_moveresize(Client *c, XRectangle geo, Bool r)
frame_moveresize(c, c->wrgeo);
XMoveResizeWindow(dpy, c->win, BORDH + rhx, TBARH + rhy, c->geo.width, c->geo.height);
XMoveResizeWindow(dpy, c->win, BORDH + rhx, TBARH, c->geo.width, c->geo.height);
client_update_attributes(c);
client_configure(c);
@ -1093,7 +1080,7 @@ client_maximize(Client *c)
c->screen = screen_get_with_geo(c->geo.x, c->geo.y);
c->geo.x = sgeo[c->screen].x;
c->geo.y = sgeo[c->screen].y;
c->geo.y = sgeo[c->screen].y ;
c->geo.width = sgeo[c->screen].width - BORDH * 2;
c->geo.height = sgeo[c->screen].height - BORDH;
@ -1213,8 +1200,8 @@ client_swap(Client *c1, Client *c2)
client_size_hints(c2);
/* Resize the windows */
client_moveresize(c1, c1->geo, False);
client_moveresize(c2, c2->geo, False);
client_moveresize(c1, c1->geo, tags[c1->screen][c1->tag].resizehint);
client_moveresize(c2, c2->geo, tags[c2->screen][c2->tag].resizehint);
/* Get the new client name */
client_get_name(c1);
@ -1339,7 +1326,7 @@ client_unmanage(Client *c)
ewmh_get_client_list();
if(c->flags & TileFlag)
tags[c->screen][c->tag].cleanfact = True;
tags[c->screen][c->tag].layout.ghost = *c;
if(c->tag == MAXTAG + 1)
{

View File

@ -52,6 +52,7 @@ const func_name_list_t layout_list[] =
{"maxlayout", maxlayout },
{"freelayout", freelayout },
{"free", freelayout },
{"split", split },
{ NULL, NULL }
};

View File

@ -238,6 +238,46 @@ uicb_set_nmaster(uicb_t cmd)
return;
}
/** Split layout function
*/
void
split(int screen)
{
Client *c, *last;
unsigned int n, on;
on = tags[screen][seltag[screen]].nclients;
for(n = 0, c = tiled_client(screen, clients); c; c = tiled_client(screen, c->next), ++n);
CHECK((tags[screen][seltag[screen]].nclients = n));
if(!(last = tiled_client(screen, clients)))
return;
/* New client (After manage) */
if(on && n > on)
{
layout_split_client(sel, (sel->frame_geo.height < sel->frame_geo.width));
layout_split_apply(last);
}
/* Client in less (After unmanage) */
else if(on && n < on)
layout_split_arrange_closed(screen);
/* First or the only client is maximized */
if(n == 1)
{
client_maximize(last);
last->flags &= ~(MaxFlag | LMaxFlag);
last->flags |= TileFlag;
}
ewmh_update_current_tag_prop();
return;
}
/** Grid layout function
*/
static void
@ -249,7 +289,7 @@ grid(int screen, Bool horizontal)
unsigned int i, n, temp, cols, rows, cpcols = 0;
for(n = 0, c = tiled_client(screen, clients); c; c = tiled_client(screen, c->next), ++n);
CHECK(n);
CHECK((tags[screen][seltag[screen]].nclients = n));
for(rows = 0; rows <= n / 2; ++rows)
if(rows * rows >= n)
@ -319,7 +359,7 @@ multi_tile(int screen, Position type)
uint i, n, tilesize = 0, mwfact, nmaster = tags[screen][seltag[screen]].nmaster;
for(n = 0, c = tiled_client(screen, clients); c; c = tiled_client(screen, c->next), ++n);
CHECK(n);
CHECK((tags[screen][seltag[screen]].nclients = n));
/* FIX NMASTER */
nmaster = (n < nmaster) ? n : nmaster;
@ -458,7 +498,7 @@ mirror(int screen, Bool horizontal)
memset(nextg, 0, sizeof(nextg));
for(n = 0, c = tiled_client(screen, clients); c; c = tiled_client(screen, c->next), ++n);
CHECK(n);
CHECK((tags[screen][seltag[screen]].nclients = n));
/* Fix nmaster */
nmaster = (n < nmaster) ? n : nmaster;
@ -875,7 +915,7 @@ layout_set_client_master(Client *c)
*\param c Client pointer
*\param p True = Vertical, False = Horizontal
*/
static void
void
layout_split_client(Client *c, Bool p)
{
XRectangle geo, sgeo;
@ -940,6 +980,91 @@ layout_split_apply(Client *c)
return;
}
static void
_layout_split_arrange_size(XRectangle g, XRectangle *cg, Position p)
{
if(p < Top)
cg->width += FRAMEW(g.width);
else
cg->height += FRAMEH(g.height);
if(p == Right)
cg->x -= FRAMEW(g.width);
if(p == Bottom)
cg->y -= FRAMEH(g.height);
return;
}
static Bool
_layout_split_check_row(XRectangle g1, XRectangle g2, Position p)
{
if(p < Top)
return (g1.y >= g2.y && (g1.y + g1.height) <= (g2.y + g2.height));
else
return (g1.x >= g2.x && (g1.x + g1.width) <= (g2.x + g2.width));
}
/* Arrange clients after a client close
*\param screen Screen
*/
void
layout_split_arrange_closed(int screen)
{
Position p;
Bool b = False;
XRectangle cgeo;
Client *c, *cc, ghost;
/* Set GHOST client
* .--. ~ ~
* /.. \ ~ ~
* \ø _ (____ ~
* __.| .--' ~ ~
* '---\ '. ~ , ~
* '. '-.___.-'/ ~
* '-.__ _.' ~
* ````` ~
*/
ghost = tags[screen][seltag[screen]].layout.ghost;
tags[screen][seltag[screen]].split = True;
/* Search for individual parent for easy resize */
for(p = Right; p < Bottom + 1; ++p)
if((c = client_get_next_with_direction(&ghost, p)))
if(cfactor_check_2pc(ghost.frame_geo, c->frame_geo, p))
{
_layout_split_arrange_size(ghost.wrgeo, &c->wrgeo, p);
cfactor_clean(c);
client_moveresize(c, (c->pgeo = c->wrgeo), tags[screen][c->tag].resizehint);
tags[screen][seltag[screen]].split = False;
return;
}
/* Check row parent for full resize */
for(p = Right; p < Bottom + 1 && !b; ++p)
if((c = client_get_next_with_direction(&ghost, p)))
for(cgeo = c->frame_geo, cc = tiled_client(c->screen, clients);
cc; cc = tiled_client(c->screen, cc->next))
{
if(cfactor_parentrow(cgeo, cc->frame_geo, RPOS(p))
&& _layout_split_check_row(cc->frame_geo, ghost.frame_geo, p))
{
_layout_split_arrange_size(ghost.wrgeo, &cc->wrgeo, p);
cfactor_clean(cc);
client_moveresize(cc, (cc->pgeo = cc->wrgeo), tags[screen][cc->tag].resizehint);
b = True;
}
}
tags[screen][seltag[screen]].split = False;
return;
}
void
uicb_split_client_vertical(uicb_t cmd)
{

View File

@ -37,7 +37,7 @@
#define NBUTTON 8
#define MAXTAG 36
#define NUM_OF_LAYOUT 10
#define NUM_OF_LAYOUT 11
#define HISTOLEN 128
/* Clients flags definition */
@ -196,6 +196,8 @@ struct Client
XRectangle free_geo; /* Free window attribute */
/* Tile size factors */
int tilefact[4];
/* Split direction */
Bool splitd;
/* For resizehint usage */
int basew, baseh, incw, inch;
int maxw, maxh, minw, minh;
@ -221,6 +223,8 @@ struct Client
/* Struct in chains */
Client *next;
Client *prev;
/* Split parents */
Client *parent, *child;
};
/* Keybind Structure */
@ -257,8 +261,8 @@ typedef struct
/* Layout Structure */
typedef struct
{
XRectangle sgeo;
int sfact[4];
XRectangle sgeo; /* Last splitted geo */
Client ghost;
char *symbol;
char *type;
void (*func)(int screen);

View File

@ -109,6 +109,7 @@
#define CHECK(x) if(!(x)) return
#define LEN(x) (sizeof(x) / sizeof((x)[0]))
#define MAXCLIST (64)
#define RPOS(x) (x % 2 ? x - 1 : x + 1)
/* barwin.c */
BarWindow *barwin_create(Window parent,
@ -155,6 +156,8 @@ void uicb_toggle_tagautohide(uicb_t);
/* cfactor.c */
void cfactor_clean(Client *c);
XRectangle cfactor_geo(XRectangle geo, int fact[4], int *err);
Bool cfactor_check_2pc(XRectangle g1, XRectangle g2, Position p);
Bool cfactor_parentrow(XRectangle cg, XRectangle ccg, Position p);
void cfactor_set(Client *c, Position p, int fac);
void cfactor_multi_set(Client *c, int fac[4]);
void uicb_client_resize_right(uicb_t cmd);
@ -193,6 +196,7 @@ void client_unmanage(Client *c);
void client_unmap(Client *c);
void client_update_attributes(Client *c);
void client_urgent(Client *c, Bool u);
Client* client_get_next_with_direction(Client *bc, Position pos);
void uicb_client_raise(uicb_t);
void uicb_client_next(uicb_t);
void uicb_client_prev(uicb_t);
@ -345,6 +349,7 @@ Client *tiled_client(int screen, Client *c);
void freelayout(int screen);
void layoutswitch(Bool b);
void maxlayout(int screen);
void split(int screen);
/* tile {{{ */
void tile(int screen);
void tile_left(int screen);
@ -365,7 +370,9 @@ void uicb_set_layout(uicb_t);
void uicb_toggle_resizehint(uicb_t);
void uicb_toggle_abovefc(uicb_t cmd);
void layout_set_client_master(Client *c);
void layout_split_client(Client *c, Bool p);
void layout_split_apply(Client *c);
void layout_split_arrange_closed(int screen);
void uicb_split_client_vertical(uicb_t);
void uicb_split_client_horizontal(uicb_t);
Bool uicb_checkmax(uicb_t);

1
wmfsrc
View File

@ -88,6 +88,7 @@
[layout] type = "tile_grid_vertical" symbol = "GRID_V" [/layout]
[layout] type = "mirror_vertical" symbol = "MIRROR_V" [/layout]
[layout] type = "mirror_horizontal" symbol = "MIRROR_H" [/layout]
[layout] type = "split" symbol = "$PLIT" [/layout]
# Other layouts.
[layout] type = "max" symbol = "MAX" [/layout]