From ad5c4101ee0f6baf15054447022a24831ae7416e Mon Sep 17 00:00:00 2001 From: Martin Duquesnoy Date: Thu, 6 Oct 2011 23:41:38 +0200 Subject: [PATCH] Add client size hints support --- src/client.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/layout.c | 23 +++++++----- src/wmfs.h | 13 +++++++ 3 files changed, 130 insertions(+), 9 deletions(-) diff --git a/src/client.c b/src/client.c index 839db03..91d57f7 100644 --- a/src/client.c +++ b/src/client.c @@ -295,6 +295,69 @@ uicb_client_close(Uicb cmd) client_close(W->client); } +static void +client_get_sizeh(struct client *c) +{ + long msize; + XSizeHints size; + + memset(c->sizeh, 0, SHLAST); + + if(!XGetWMNormalHints(W->dpy, c->win, &size, &msize) || !size.flags) + size.flags = PSize; + + /* base */ + if(size.flags & PBaseSize) + { + c->sizeh[BASEW] = size.base_width; + c->sizeh[BASEH] = size.base_height; + } + else if(size.flags & PMinSize) + { + c->sizeh[BASEW] = size.min_width; + c->sizeh[BASEH] = size.min_height; + } + + /* inc */ + if(size.flags & PResizeInc) + { + c->sizeh[INCW] = size.width_inc; + c->sizeh[INCH] = size.height_inc; + } + + /* max */ + if(size.flags & PMaxSize) + { + c->sizeh[MAXW] = size.max_width; + c->sizeh[MAXH] = size.max_height; + } + + /* min */ + if(size.flags & PMinSize) + { + c->sizeh[MINW] = (size.min_width ? size.min_width : 1); + c->sizeh[MINH] = (size.min_height ? size.min_height: 1); + } + else if(size.flags & PBaseSize) + { + c->sizeh[MINW] = (size.base_width ? size.base_width : 1); + c->sizeh[MINH] = (size.base_height ? size.base_height : 1); + } + + /* aspect */ + if(size.flags & PAspect) + { + c->sizeh[MINAX] = size.min_aspect.x; + c->sizeh[MAXAX] = size.max_aspect.x; + c->sizeh[MINAY] = size.min_aspect.y; + c->sizeh[MAXAY] = size.max_aspect.y; + } + + if(c->sizeh[MAXW] && c->sizeh[MINW] && c->sizeh[MAXH] && c->sizeh[MINH] + && c->sizeh[MAXW] == c->sizeh[MINW] && c->sizeh[MAXH] == c->sizeh[MINH]) + c->flags |= CLIENT_HINT_FLAG; +} + struct client* client_new(Window w, XWindowAttributes *wa) { @@ -314,6 +377,7 @@ client_new(Window w, XWindowAttributes *wa) c->tgeo = c->wgeo = c->geo; /* Set tag */ + client_get_sizeh(c); tag_client(W->screen->seltag, c); /* X window attributes */ @@ -335,6 +399,43 @@ client_new(Window w, XWindowAttributes *wa) return c; } +static void +client_geo_hints(struct geo *g, int *s) +{ + /* base */ + g->w -= s[BASEW]; + g->h -= s[BASEH]; + + /* aspect */ + if((s[MINAY] | s[MAXAY] | s[MINAX] | s[MAXAX]) > 0) + { + if(g->w * s[MAXAY] > g->h * s[MAXAX]) + g->w = g->h * s[MAXAX] / s[MAXAY]; + else if(g->w * s[MINAY] < g->h * s[MINAX]) + g->h = g->w * s[MINAY] / s[MINAX]; + } + + /* incremental */ + if(s[INCW]) + g->w -= g->w % s[INCW]; + if(s[INCH]) + g->h -= g->h % s[INCH]; + + /* base dimension */ + g->w += s[BASEW]; + g->h += s[BASEH]; + + if(s[MINW] > 0 && g->w < s[MINW]) + g->w = s[MINW]; + if(s[MINH] > 0 && g->h < s[MINH]) + g->h = s[MINH]; + if(s[MAXW] > 0 && g->w > s[MAXW]) + g->w = s[MAXW]; + if(s[MAXH] > 0 && g->h > s[MAXH]) + g->h = s[MAXH]; +} + + void client_moveresize(struct client *c, struct geo *g) { @@ -348,6 +449,8 @@ client_moveresize(struct client *c, struct geo *g) c->wgeo.w = g->w - (bord << 1); c->wgeo.h = g->h - (bord << 1); + client_geo_hints(&c->wgeo, (int*)c->sizeh); + XMoveResizeWindow(W->dpy, c->win, c->wgeo.x, c->wgeo.y, c->wgeo.w, c->wgeo.h); diff --git a/src/layout.c b/src/layout.c index 15ffe24..14b7980 100644 --- a/src/layout.c +++ b/src/layout.c @@ -93,6 +93,15 @@ layout_split_check_row_dir(struct client *c, struct client *g, enum position p) * '-.__ _.' ~ * ````` ~ */ +#define _ARRANGE_SINGLE_PARENT(p) \ + do { \ + 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; \ + } \ + } while(/* CONSTCOND */ 0); void layout_split_arrange_closed(struct client *ghost) { @@ -110,15 +119,11 @@ layout_split_arrange_closed(struct client *ghost) * | | 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; - } - } + _ARRANGE_SINGLE_PARENT(Right); + _ARRANGE_SINGLE_PARENT(Left); + _ARRANGE_SINGLE_PARENT(Top); + _ARRANGE_SINGLE_PARENT(Bottom); + /* Check row parents for full resize * Example case: diff --git a/src/wmfs.h b/src/wmfs.h index a38acdb..84fb80f 100644 --- a/src/wmfs.h +++ b/src/wmfs.h @@ -49,6 +49,17 @@ enum position PositionLast }; +enum size_hints +{ + BASEW, BASEH, + INCW, INCH, + MAXW, MAXH, + MINW, MINH, + MINAX, MINAY, + MAXAX, MAXAY, + SHLAST +}; + /* * Structures */ @@ -122,7 +133,9 @@ struct client struct screen *screen; struct barwin *titlebar; struct geo geo, tgeo, wgeo; + int sizeh[SHLAST]; char *title; +#define CLIENT_HINT_FLAG 0x01 Flags flags; Window win; SLIST_ENTRY(client) next; /* Global list */