123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- /*
- * wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
- * For license, see COPYING.
- */
- #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;
- geo = og = c->geo;
- if(vertical)
- {
- c->geo.w >>= 1;
- geo.x = c->geo.x + c->geo.w;
- geo.w >>= 1;
- /* Remainder */
- geo.w += (og.x + og.w) - (geo.x + geo.w);
- }
- else
- {
- c->geo.h >>= 1;
- geo.y = c->geo.y + c->geo.h;
- geo.h >>= 1;
- /* Remainder */
- geo.h += (og.y + og.h) - (geo.y + geo.h);
- }
- client_moveresize(c, c->geo);
- return geo;
- }
- static inline void
- layout_split_arrange_size(struct geo g, struct client *c, Position p)
- {
- if(LDIR(p))
- {
- c->geo.w += g.w;
- if(p == Right)
- c->geo.x = g.x;
- }
- else
- {
- c->geo.h += g.h;
- 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 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 : cc->geo.w);
- if(s == cs)
- return true;
- if(s > cs)
- return false;
- }
- return false;
- }
- /* 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 = false;
- 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);
- }
- /* Arrange inter-clients holes:
- * ___________ ___________
- * | || | -> | | |
- * | A || B | -> | A >| B |
- * | || | -> | >| |
- * |_____||____| -> |______|____|
- * ^ void
- *
- * and client-screen edge holes
- * ___________ ___________
- * | | || -> | | |
- * | A | B || -> | A | B >|
- * | | || -> | | >|
- * |_____|----'| -> |_____|__v__|
- * ^^^ void
- */
- static inline void
- layout_fix_hole(struct client *c)
- {
- struct client *cr = client_next_with_pos(c, Right);
- struct client *cb = client_next_with_pos(c, Bottom);
- c->geo.w += (cr ? cr->geo.x : c->screen->ugeo.w) - (c->geo.x + c->geo.w);
- c->geo.h += (cb ? cb->geo.y : c->screen->ugeo.h) - (c->geo.y + c->geo.h);
- client_moveresize(c, c->geo);
- }
- /* Layout rotation: Rotate 90° all client to right or left.
- * Avoid if(left) condition in layout_rotate loop; use func ptr
- *
- * Left rotation
- * ____________ ____________
- * | | B | -> | | A |
- * | A |_______| -> |__|_________|
- * |____| C | D | -> |_____| B |
- * |____|___|___| -> |_____|______|
- *
- * Right rotation
- * ____________ ____________
- * | | B | -> | B |_____|
- * | A |_______| -> |______|_____|
- * |____| C | D | -> | A | |
- * |____|___|___| -> |_________|__|
- *
- */
- static inline void
- _pos_rotate_left(struct geo *g, struct geo ug, struct geo og)
- {
- g->x = (ug.h - (og.y + og.h));
- g->y = og.x;
- }
- static inline void
- _pos_rotate_right(struct geo *g, struct geo ug, struct geo og)
- {
- g->x = og.y;
- g->y = (ug.w - (og.x + og.w));
- }
- static void
- layout_rotate(struct tag *t, bool left)
- {
- struct client *c;
- struct geo g;
- float f1 = (float)t->screen->ugeo.w / (float)t->screen->ugeo.h;
- float f2 = 1 / f1;
- void (*pos)(struct geo*, struct geo, struct geo) =
- (left ? _pos_rotate_left : _pos_rotate_right);
- SLIST_FOREACH(c, &t->clients, tnext)
- {
- pos(&g, t->screen->ugeo, c->geo);
- g.x *= f1;
- g.y *= f2;
- g.w = c->geo.h * f1;
- g.h = c->geo.w * f2;
- client_moveresize(c, g);
- }
- /* Rotate sometimes do not set back perfect size.. */
- SLIST_FOREACH(c, &t->clients, tnext)
- layout_fix_hole(c);
- }
- void
- uicb_layout_rotate_left(Uicb cmd)
- {
- (void)cmd;
- layout_rotate(W->screen->seltag, true);
- }
- void
- uicb_layout_rotate_right(Uicb cmd)
- {
- (void)cmd;
- layout_rotate(W->screen->seltag, false);
- }
- /*
- * Really simple functions, don't need static no-uicb backend
- * so we avoid the use of if(vertical) .. else
- *
- * Vertical mirror
- * ____________ ____________
- * | | B | -> | B | |
- * | A |_______| -> |_______| A |
- * | | C | D | -> | D | C | |
- * |____|___|___| -> |___|___|____|
- *
- * Horizontal mirror
- * ____________ ____________
- * | | B | -> | | C | D |
- * | A |_______| -> | A |___|___|
- * | | C | D | -> | | B |
- * |____|___|___| -> |____|_______|
- */
- void
- uicb_layout_vmirror(Uicb cmd)
- {
- (void)cmd;
- struct client *c;
- SLIST_FOREACH(c, &W->screen->seltag->clients, tnext)
- {
- c->geo.x = W->screen->ugeo.w - (c->geo.x + c->geo.w);
- client_moveresize(c, c->geo);
- }
- }
- void
- uicb_layout_hmirror(Uicb cmd)
- {
- (void)cmd;
- struct client *c;
- SLIST_FOREACH(c, &W->screen->seltag->clients, tnext)
- {
- c->geo.y = W->screen->ugeo.h - (c->geo.y + c->geo.h);
- client_moveresize(c, c->geo);
- }
- }
|