Add client_resize_<direction> function (New cfactor)

This commit is contained in:
Martin Duquesnoy 2011-09-17 18:14:03 +02:00
parent 961e57f876
commit 4321dc3aa8
9 changed files with 195 additions and 69 deletions

View File

@ -14,6 +14,19 @@
#define CLIENT_MOUSE_MOD Mod1Mask
#define CLIENT_RESIZE_DIR(d) \
void uicb_client_resize_##d(Uicb cmd) \
{ \
if(W->client) \
client_fac_resize(W->client, d, ATOI(cmd)); \
}
/* uicb_client_resize_dir() */
CLIENT_RESIZE_DIR(Right)
CLIENT_RESIZE_DIR(Left)
CLIENT_RESIZE_DIR(Top)
CLIENT_RESIZE_DIR(Bottom)
/** Send a ConfigureRequest event to the struct client
* \param c struct client pointer
*/
@ -245,7 +258,7 @@ client_new(Window w, XWindowAttributes *wa)
c->geo.y = wa->y;
c->geo.w = wa->width;
c->geo.h = wa->height;
c->cgeo = c->geo;
c->tgeo = c->geo;
/* Set tag */
tag_client(W->screen->seltag, c);
@ -272,10 +285,7 @@ client_new(Window w, XWindowAttributes *wa)
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;
c->geo = g;
XMoveResizeWindow(W->dpy, c->win, g.x, g.y, g.w, g.h);
}
@ -292,6 +302,36 @@ client_maximize(struct client *c)
client_moveresize(c, c->geo);
}
void
client_fac_resize(struct client *c, Position p, int fac)
{
struct client *gc = client_next_with_pos(c, p);
if(!gc || gc->screen != c->screen)
return;
/* Check futur size/pos */
if(!client_fac_geo(c, p, fac)
|| !client_fac_geo(gc, RPOS(p), -fac)
|| !client_fac_check_row(c, p, fac)
|| !client_fac_check_row(gc, RPOS(p), -fac))
return;
/* Simple resize with only c & gc */
if(GEO_CHECK2(c->geo, gc->geo, p))
{
client_moveresize(c, c->tgeo);
client_moveresize(gc, gc->tgeo);
}
/* Resize with row parents */
else
{
client_fac_arrange_row(c, p, fac);
client_fac_arrange_row(gc, RPOS(p), -fac);
}
}
void
client_remove(struct client *c)
{
@ -305,8 +345,6 @@ 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

@ -7,6 +7,7 @@
#define CLIENT_H
#include "wmfs.h"
#include "layout.h"
void client_configure(struct client *c);
struct client *client_gb_win(Window w);
@ -17,7 +18,76 @@ 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_fac_resize(struct client *c, Position p, int fac);
void client_remove(struct client *c);
void client_free(void);
void uicb_client_resize_Right(Uicb);
void uicb_client_resize_Left(Uicb);
void uicb_client_resize_Top(Uicb);
void uicb_client_resize_Bottom(Uicb);
static inline bool
client_fac_geo(struct client *c, Position p, int fac)
{
struct geo cg = c->geo;
switch(p)
{
default:
case Right:
cg.w += fac;
break;
case Left:
cg.x -= fac;
cg.w += fac;
break;
case Top:
cg.y -= fac;
cg.h += fac;
break;
case Bottom:
cg.h += fac;
break;
}
/* Check for incompatible geo */
if(cg.w > c->screen->ugeo.w || cg.h > c->screen->ugeo.h
|| cg.w < 1 || cg.h < 1)
return false;
/* Set transformed geo in tmp geo */
c->tgeo = cg;
return true;
}
static inline bool
client_fac_check_row(struct client *c, Position p, int fac)
{
struct geo g = c->geo;
struct client *cc;
/* Travel clients to search parents of row and check geos */
SLIST_FOREACH(cc, &c->tag->clients, tnext)
if(GEO_PARENTROW(g, cc->geo, p) && !client_fac_geo(cc, p, fac))
return false;
return true;
}
static inline void
client_fac_arrange_row(struct client *c, Position p, int fac)
{
struct geo g = c->geo;
struct client *cc;
/* Travel clients to search row parents and apply fac */
SLIST_FOREACH(cc, &c->tag->clients, tnext)
if(GEO_PARENTROW(g, cc->geo, p))
{
client_fac_geo(cc, p, fac);
client_moveresize(cc, cc->tgeo);
}
}
#endif /* CLIENT_H */

View File

@ -13,6 +13,7 @@
#include "wmfs.h"
#include "util.h"
#include "tag.h"
#include "client.h"
#define THEME_DEFAULT (SLIST_FIRST(&W->h.theme))
@ -28,6 +29,13 @@ static const struct { char *name; void (*func)(Uicb cmd); } uicb_list[] =
{ "tag", uicb_tag_set_with_name },
{ "tag_next", uicb_tag_next },
{ "tag_prev", uicb_tag_prev },
/* Client */
{ "client_resize_right", uicb_client_resize_Right },
{ "client_resize_left", uicb_client_resize_Left },
{ "client_resize_top", uicb_client_resize_Top },
{ "client_resize_bottom", uicb_client_resize_Bottom },
{ NULL, NULL }
};

View File

@ -40,6 +40,54 @@ layout_split(struct client *c, bool vertical)
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 + (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;
}
/* Use ghost client properties to fix holes in tile
* .--. ~ ~
* /xx \ ~ ~

View File

@ -7,8 +7,6 @@
#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)
@ -17,72 +15,22 @@
#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) \
#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) \
? (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)))
? ((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

@ -89,6 +89,8 @@ tag_client(struct tag *t, struct client *c)
if(c->tag == t)
return;
layout_split_arrange_closed(c);
SLIST_REMOVE(&c->tag->clients, c, client, tnext);
/* TODO: Focus next client */
if(c->tag->sel == c)
@ -105,6 +107,7 @@ tag_client(struct tag *t, struct client *c)
if(SLIST_EMPTY(&c->tag->clients))
WIN_STATE(c->tag->frame, Unmap);
return;
}

View File

@ -151,7 +151,7 @@ wmfs_grab_keys(void)
KeyCode c;
struct keybind *k;
wmfs_numlockmask();
/*wmfs_numlockmask();*/
XUngrabKey(W->dpy, AnyKey, AnyModifier, W->root);

View File

@ -104,7 +104,7 @@ struct client
struct tag *tag;
struct screen *screen;
struct barwin *titlebar;
struct geo geo, cgeo; /* Complete geo: + border */
struct geo geo, tgeo;
char *title;
Flags flags;
Window win;

View File

@ -113,4 +113,15 @@
[key] mod = {"Super"} key = "a" func = "tag_prev" [/key]
[key] mod = {"Super"} key = "z" func = "tag" cmd = "tag2" [/key]
# Resize selected tiled client with direction
[key] mod = {"Super"} key = "h" func = "client_resize_left" cmd = "20" [/key]
[key] mod = {"Super"} key = "l" func = "client_resize_right" cmd = "20" [/key]
[key] mod = {"Super"} key = "k" func = "client_resize_top" cmd = "20" [/key]
[key] mod = {"Super"} key = "j" func = "client_resize_bottom" cmd = "20" [/key]
[key] mod = {"Super", "Control"} key = "h" func = "client_resize_right" cmd = "-20" [/key]
[key] mod = {"Super", "Control"} key = "l" func = "client_resize_left" cmd = "-20" [/key]
[key] mod = {"Super", "Control"} key = "k" func = "client_resize_bottom" cmd = "-20" [/key]
[key] mod = {"Super", "Control"} key = "j" func = "client_resize_top" cmd = "-20" [/key]
[/keys]