diff --git a/src/cfactor.c b/src/cfactor.c index dafd370..1fb00d1 100644 --- a/src/cfactor.c +++ b/src/cfactor.c @@ -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; diff --git a/src/client.c b/src/client.c index 36ee205..cda9d48 100644 --- a/src/client.c +++ b/src/client.c @@ -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) { diff --git a/src/init.c b/src/init.c index 6514125..b67b875 100644 --- a/src/init.c +++ b/src/init.c @@ -52,6 +52,7 @@ const func_name_list_t layout_list[] = {"maxlayout", maxlayout }, {"freelayout", freelayout }, {"free", freelayout }, + {"split", split }, { NULL, NULL } }; diff --git a/src/layout.c b/src/layout.c index 46474fc..ea4bef7 100644 --- a/src/layout.c +++ b/src/layout.c @@ -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) { diff --git a/src/structs.h b/src/structs.h index 5d03d83..bb0a973 100644 --- a/src/structs.h +++ b/src/structs.h @@ -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); diff --git a/src/wmfs.h b/src/wmfs.h index 7b80cd9..b26a25b 100644 --- a/src/wmfs.h +++ b/src/wmfs.h @@ -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); diff --git a/wmfsrc b/wmfsrc index 9ed070c..bd204d2 100644 --- a/wmfsrc +++ b/wmfsrc @@ -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]