Add client frame

This commit is contained in:
Martin Duquesnoy 2011-10-16 12:32:48 +02:00
parent 6215f23f86
commit 67cb8cd5ba
11 changed files with 177 additions and 155 deletions

View File

@ -22,6 +22,7 @@
#define barwin_refresh(b) XCopyArea(W->dpy, b->dr, b->win, W->gc, 0, 0, b->geo.w, b->geo.h, 0, 0)
#define barwin_map(b) XMapWindow(W->dpy, b->win);
#define barwin_unmap(b) XUnmapWindow(W->dpy, b->win);
#define barwin_move(b, x, y) XMoveWindow(W->dpy, b->win, x, y);
struct barwin* barwin_new(Window parent, int x, int y, int w, int h, Color fg, Color bg, bool entermask);
void barwin_remove(struct barwin *b);

View File

@ -12,8 +12,10 @@
#include "barwin.h"
#include "ewmh.h"
#include "layout.h"
#include "barwin.h"
#include "draw.h"
#define CCOL(c) (c == c->tag->sel ? &c->scol : &c->ncol)
#define CLIENT_MOUSE_MOD Mod1Mask
#define CLIENT_RESIZE_DIR(D) \
@ -87,10 +89,10 @@ client_configure(struct client *c)
.type = ConfigureNotify,
.event = c->win,
.window = c->win,
.x = c->geo.x,
.y = c->geo.y,
.width = c->geo.w,
.height = c->geo.h,
.x = c->rgeo.x + c->border,
.y = c->rgeo.y + c->tbarw,
.width = c->wgeo.w,
.height = c->wgeo.h,
.above = None,
.border_width = 0,
.override_redirect = 0
@ -111,6 +113,17 @@ client_gb_win(Window w)
return c;
}
struct client*
client_gb_frame(Window w)
{
struct client *c = SLIST_FIRST(&W->h.client);
while(c && c->frame != w)
c = SLIST_NEXT(c, next);
return c;
}
struct client*
client_gb_pos(struct tag *t, int x, int y)
{
@ -164,8 +177,8 @@ client_swap2(struct client *c1, struct client *c2)
return;
/* are swapped geos compatible? */
if(client_winsize(c1, &c2->geo, &c1->wgeo)
|| client_winsize(c2, &c1->geo, &c2->wgeo))
if(client_winsize(c1, &c2->geo)
|| client_winsize(c2, &c1->geo))
return;
if(c1->screen != c2->screen)
@ -199,6 +212,8 @@ _swap_get(struct client *c, enum position p)
return ret;
}
#define _REV_SBORDER() \
draw_reversed_rect(W->root, W->rgc, &c2->geo);
void
client_swap(struct client *c, enum position p)
{
@ -207,13 +222,6 @@ client_swap(struct client *c, enum position p)
bool b = true;
XEvent ev;
KeySym keysym;
GC rgc;
XGCValues xgc =
{
.function = GXinvert,
.subwindow_mode = IncludeInferiors,
.line_width = THEME_DEFAULT->client_border_width
};
c2 = _swap_get(c, p);
@ -226,9 +234,7 @@ client_swap(struct client *c, enum position p)
*/
XGrabKeyboard(W->dpy, W->root, True, GrabModeAsync, GrabModeAsync, CurrentTime);
rgc = XCreateGC(W->dpy, c->tag->frame, GCFunction | GCSubwindowMode | GCLineWidth, &xgc);
draw_reversed_rect(c->tag->frame, rgc, c2->geo);
_REV_SBORDER();
do
{
@ -239,7 +245,7 @@ client_swap(struct client *c, enum position p)
XKeyPressedEvent *ke = &ev.xkey;
keysym = XKeycodeToKeysym(W->dpy, (KeyCode)ke->keycode, 0);
draw_reversed_rect(c->tag->frame, rgc, c2->geo);
_REV_SBORDER();
SLIST_FOREACH(k, &W->h.keybind, next)
if(k->keysym == keysym && KEYPRESS_MASK(k->mod) == KEYPRESS_MASK(ke->state)
@ -260,7 +266,7 @@ client_swap(struct client *c, enum position p)
}
}
draw_reversed_rect(c->tag->frame, rgc, c2->geo);
_REV_SBORDER();
/* Gtfo of this loop */
if(keysym == XK_Return)
@ -277,12 +283,11 @@ client_swap(struct client *c, enum position p)
} while(ev.type != KeyPress);
draw_reversed_rect(c->tag->frame, rgc, c2->geo);
_REV_SBORDER();
if(b)
client_swap2(c, c2);
XFreeGC(W->dpy, rgc);
XUngrabKeyboard(W->dpy, CurrentTime);
}
@ -314,33 +319,47 @@ client_grabbuttons(struct client *c, bool focused)
ButtonMask, GrabModeAsync, GrabModeSync, None, None);
}
static inline void
client_draw_bord(struct client *c)
static void
client_frame_update(struct client *c, struct colpair *cp)
{
struct geo ge = { 0, 0, c->screen->ugeo.w, c->screen->ugeo.h };
XSetWindowBackground(W->dpy, c->frame, cp->bg);
XClearWindow(W->dpy, c->frame);
draw_rect(c->tag->frame, ge, THEME_DEFAULT->client_n.bg);
if(c->titlebar && c->title)
{
int w = draw_textw(THEME_DEFAULT, c->title);
/* Selected client's border */
if(W->client)
draw_rect(W->client->tag->frame, W->client->tag->sel->geo, THEME_DEFAULT->client_s.bg);
c->titlebar->fg = cp->fg;
c->titlebar->bg = cp->bg;
barwin_move(c->titlebar, (c->geo.w >> 1) - (w >> 1) - PAD, 0);
barwin_resize(c->titlebar, w + (PAD << 1), c->tbarw);
barwin_refresh_color(c->titlebar);
draw_text(c->titlebar->dr, THEME_DEFAULT,
PAD, TEXTY(THEME_DEFAULT, c->tbarw), cp->fg,
c->title);
barwin_refresh(c->titlebar);
}
}
void
client_focus(struct client *c)
{
/* Unfocus selected */
if(W->client && W->client != c)
{
client_grabbuttons(W->client, false);
client_frame_update(W->client, &W->client->ncol);
}
/* Focus c */
if((W->client = c))
{
c->tag->sel = c;
client_draw_bord(c);
client_grabbuttons(c, true);
client_frame_update(c, &c->scol);
XSetInputFocus(W->dpy, c->win, RevertToPointerRoot, CurrentTime);
}
@ -370,6 +389,8 @@ client_get_name(struct client *c)
/* Still no title... */
if(!c->title)
XFetchName(W->dpy, c->win, &(c->title));
client_frame_update(c, CCOL(c));
}
/** Close a client
@ -477,6 +498,33 @@ client_get_sizeh(struct client *c)
c->flags |= CLIENT_HINT_FLAG;
}
static void
client_frame_new(struct client *c)
{
XSetWindowAttributes at =
{
.background_pixel = c->ncol.bg,
.override_redirect = true,
.background_pixmap = ParentRelative,
.event_mask = BARWIN_MASK | BARWIN_ENTERMASK
};
c->frame = XCreateWindow(W->dpy, W->root,
c->geo.x, c->geo.y,
c->geo.w, c->geo.h,
0, CopyFromParent,
InputOutput,
CopyFromParent,
(CWOverrideRedirect | CWBackPixmap
| CWBackPixel | CWEventMask), &at);
if(c->tbarw > c->border)
c->titlebar = barwin_new(c->frame, 0, 0, 1, c->tbarw,
c->ncol.fg, c->ncol.bg, true);
XReparentWindow(W->dpy, c->win, c->frame, c->border, c->tbarw);
}
struct client*
client_new(Window w, XWindowAttributes *wa)
{
@ -493,7 +541,22 @@ client_new(Window w, XWindowAttributes *wa)
c->geo.y = wa->y;
c->geo.w = wa->width;
c->geo.h = wa->height;
c->tgeo = c->wgeo = c->owgeo = c->geo;
c->tgeo = c->wgeo = c->rgeo = c->geo;
/*
* Conf option set per client, for possibility
* to config only one client
*/
c->border = THEME_DEFAULT->client_border_width;
if(!(c->tbarw = THEME_DEFAULT->client_titlebar_width))
c->tbarw = c->border;
c->ncol.fg = THEME_DEFAULT->client_n.fg;
c->ncol.bg = THEME_DEFAULT->client_n.bg;
c->scol.fg = THEME_DEFAULT->client_s.fg;
c->scol.bg = THEME_DEFAULT->client_s.bg;
client_frame_new(c);
/* Set tag */
client_get_sizeh(c);
@ -508,7 +571,10 @@ client_new(Window w, XWindowAttributes *wa)
SLIST_INSERT_HEAD(&W->h.client, c, next);
/* Map */
WIN_STATE(w, Map);
WIN_STATE(c->frame, Map);
if(c->titlebar)
barwin_map(c->titlebar);
ewmh_set_wm_state(w, NormalState);
client_get_name(c);
@ -555,32 +621,29 @@ client_geo_hints(struct geo *g, int *s)
}
bool
client_winsize(struct client *c, struct geo *g, struct geo *ret)
client_winsize(struct client *c, struct geo *g)
{
int ow, bord = THEME_DEFAULT->client_border_width;
c->owgeo = c->wgeo;
int ow;
struct geo og = c->wgeo;
/* Window geo */
ret->x = g->x + bord;
ret->y = g->y + bord;
ret->h = g->h - (bord << 1);
ret->w = ow = g->w - (bord << 1);
c->wgeo.x = c->border;
c->wgeo.y = c->tbarw;
c->wgeo.h = g->h - (c->border + c->tbarw);
c->wgeo.w = ow = g->w - (c->border << 1);
client_geo_hints(ret, (int*)c->sizeh);
client_geo_hints(&c->wgeo, (int*)c->sizeh);
/* Check possible problem for tile integration */
if(g->w < c->sizeh[MINW] || g->h < c->sizeh[MINH]
|| g->x < 0 || g->y < 0
|| ret->x < g->x || ret->y < g->y
|| ret->h > g->h || ret->w > g->w)
|| c->wgeo.h > g->h || c->wgeo.w > g->w)
{
*ret = c->wgeo;
c->wgeo = og;
return true;
}
/* Balance position with new size */
ret->x += (ow - ret->w) >> 1;
c->wgeo.x += (ow - c->wgeo.w) >> 1;
c->flags |= CLIENT_DID_WINSIZE;
@ -590,11 +653,24 @@ client_winsize(struct client *c, struct geo *g, struct geo *ret)
void
client_moveresize(struct client *c, struct geo *g)
{
c->tgeo = c->geo = *g;
c->tgeo = c->rgeo = c->geo = *g;
if(!(c->flags & CLIENT_DID_WINSIZE))
if(client_winsize(c, g, &c->wgeo))
return;
if(client_winsize(c, g))
{
/* TODO
* Window required size not compatible
* with frame window size in tile mode
*/
}
/* Real geo regarding full root size */
c->rgeo.x += c->screen->ugeo.x;
c->rgeo.y += c->screen->ugeo.y;
XMoveResizeWindow(W->dpy, c->frame,
c->rgeo.x, c->rgeo.y,
c->rgeo.w, c->rgeo.h);
XMoveResizeWindow(W->dpy, c->win,
c->wgeo.x, c->wgeo.y,
@ -602,18 +678,15 @@ client_moveresize(struct client *c, struct geo *g)
c->flags &= ~CLIENT_DID_WINSIZE;
client_draw_bord(c);
client_frame_update(c, CCOL(c));
client_configure(c);
}
void
client_maximize(struct client *c)
{
c->geo = c->tag->screen->ugeo;
c->geo.x = c->geo.y = 0; /* Frame x/y, not screen geo */
c->geo.w = c->tag->screen->ugeo.w;
c->geo.h = c->tag->screen->ugeo.h;
c->geo = c->screen->ugeo;
c->geo.x = c->geo.y = 0;
client_moveresize(c, &c->geo);
@ -684,7 +757,7 @@ _fac_resize(struct client *c, enum position p, int fac)
* clients in linked list.
*/
SLIST_FOREACH(gc, &c->tag->clients, tnext)
if(client_winsize(gc, &gc->tgeo, &gc->wgeo))
if(client_winsize(gc, &gc->tgeo))
{
/*
* Reverse back the flag and the window geo
@ -702,7 +775,7 @@ _fac_resize(struct client *c, enum position p, int fac)
#define _REV_BORDER() \
SLIST_FOREACH(gc, &c->tag->clients, tnext) \
draw_reversed_rect(c->tag->frame, rgc, gc->tgeo);
draw_reversed_rect(W->root, W->rgc, &gc->tgeo);
void
client_fac_resize(struct client *c, enum position p, int fac)
{
@ -711,13 +784,6 @@ client_fac_resize(struct client *c, enum position p, int fac)
bool b = true;
XEvent ev;
KeySym keysym;
GC rgc;
XGCValues xgc =
{
.function = GXinvert,
.subwindow_mode = IncludeInferiors,
.line_width = THEME_DEFAULT->client_border_width
};
/* Do it once before */
_fac_resize(c, p, fac);
@ -729,7 +795,6 @@ client_fac_resize(struct client *c, enum position p, int fac)
XGrabServer(W->dpy);
XGrabKeyboard(W->dpy, W->root, True, GrabModeAsync, GrabModeAsync, CurrentTime);
rgc = XCreateGC(W->dpy, c->tag->frame, GCFunction | GCSubwindowMode | GCLineWidth, &xgc);
_REV_BORDER();
@ -800,7 +865,6 @@ client_fac_resize(struct client *c, enum position p, int fac)
}
}
XFreeGC(W->dpy, rgc);
XUngrabServer(W->dpy);
XUngrabKeyboard(W->dpy, CurrentTime);
}
@ -811,6 +875,7 @@ client_remove(struct client *c)
XGrabServer(W->dpy);
XSetErrorHandler(wmfs_error_handler_dummy);
XReparentWindow(W->dpy, c->win, W->root, c->geo.x, c->geo.y);
XDestroyWindow(W->dpy, c->frame);
/* Remove from global client list */
SLIST_REMOVE(&W->h.client, c, client, next);

View File

@ -11,6 +11,7 @@
inline void client_configure(struct client *c);
struct client *client_gb_win(Window w);
struct client *client_gb_frame(Window w);
struct client *client_gb_pos(struct tag *t, int x, int y);
struct client *client_next_with_pos(struct client *bc, enum position p);
void client_swap2(struct client *c1, struct client *c2);
@ -20,7 +21,7 @@ void client_get_name(struct client *c);
void client_close(struct client *c);
void uicb_client_close(Uicb cmd);
struct client *client_new(Window w, XWindowAttributes *wa);
bool client_winsize(struct client *c, struct geo *geo, struct geo *ret);
bool client_winsize(struct client *c, struct geo *geo);
void client_moveresize(struct client *c, struct geo *g);
void client_maximize(struct client *c);
void client_fac_resize(struct client *c, enum position p, int fac);

View File

@ -34,12 +34,16 @@ draw_rect(Drawable d, struct geo g, Color bg)
* For client use
*/
static inline void
draw_reversed_rect(Drawable dr, GC gc, struct geo g)
draw_reversed_rect(Drawable dr, GC gc, struct geo *g)
{
struct geo *ug = &W->screen->ugeo;
int i = THEME_DEFAULT->client_border_width;
XDrawRectangle(W->dpy, dr, gc, g.x + i, g.y + i,
g.w - (i << 1), g.h - (i << 1));
XDrawRectangle(W->dpy, dr, gc,
ug->x + g->x + i,
ug->y + g->y + i,
g->w - (i << 1),
g->h - (i << 1));
}
static inline unsigned short

View File

@ -46,8 +46,9 @@ event_enternotify(XEvent *e)
&& ev->window != W->root)
return;
if((c = client_gb_win(ev->window)))
{
if((c = client_gb_win(ev->window))
|| (c = client_gb_frame(ev->window)))
{
if(c->flags & CLIENT_IGNORE_ENTER)
c->flags ^= CLIENT_IGNORE_ENTER;
else
@ -193,14 +194,13 @@ event_motionnotify(XEvent *e)
{
XMotionEvent *ev = &e->xmotion;
struct client *c;
struct tag *t = W->screen->seltag;
/*
* Check client window and tag frame to get focused
* window with mouse motion
*/
if((c = client_gb_win(ev->subwindow))
|| (ev->window == t->frame && ((c = client_gb_pos(t, ev->x, ev->y)))))
|| (c = client_gb_frame(ev->subwindow)))
if(c != c->tag->sel)
client_focus(c);
}

View File

@ -53,8 +53,6 @@ infobar_placement(struct infobar *i, enum barpos p)
return false;
}
tag_update_frame_geo(i->screen);
return true;
}

View File

@ -46,7 +46,7 @@ static void
layout_apply_set(struct tag *t, struct layout_set *l)
{
struct geo_list *g;
struct client *c, cc;
struct client *c;
int nc = 1;
SLIST_FOREACH(c, &t->clients, tnext)
@ -105,7 +105,7 @@ layout_free_set(struct tag *t)
#define _REV_BORDER() \
SLIST_FOREACH(g, &l->geos, next) \
draw_reversed_rect(t->frame, rgc, g->geo);
draw_reversed_rect(W->root, W->rgc, &g->geo);
static void
_historic_set(struct tag *t, bool prev)
{
@ -115,13 +115,6 @@ _historic_set(struct tag *t, bool prev)
bool b = true;
XEvent ev;
KeySym keysym;
GC rgc;
XGCValues xgc =
{
.function = GXinvert,
.subwindow_mode = IncludeInferiors,
.line_width = THEME_DEFAULT->client_border_width
};
if(TAILQ_EMPTY(&t->sets))
return;
@ -142,7 +135,6 @@ _historic_set(struct tag *t, bool prev)
*/
XGrabKeyboard(W->dpy, W->root, True, GrabModeAsync, GrabModeAsync, CurrentTime);
rgc = XCreateGC(W->dpy, t->frame, GCFunction | GCSubwindowMode | GCLineWidth, &xgc);
_REV_BORDER();
@ -203,7 +195,6 @@ _historic_set(struct tag *t, bool prev)
if(b)
layout_apply_set(t, l);
XFreeGC(W->dpy, rgc);
XUngrabServer(W->dpy);
XUngrabKeyboard(W->dpy, CurrentTime);
}
@ -339,7 +330,6 @@ layout_split_arrange_closed(struct client *ghost)
_ARRANGE_SINGLE_PARENT(Top);
_ARRANGE_SINGLE_PARENT(Bottom);
/* Check row parents for full resize
* Example case:
* ___________ ___________
@ -460,16 +450,17 @@ static void
layout_rotate(struct tag *t, void (*pfunc)(struct geo*, struct geo*, struct geo*))
{
struct client *c;
struct geo g;
struct geo g, *ug = &t->screen->ugeo;
float f1 = (float)t->screen->ugeo.w / (float)t->screen->ugeo.h;
float f2 = 1 / f1;
SLIST_FOREACH(c, &t->clients, tnext)
{
pfunc(&g, &t->screen->ugeo, &c->geo);
pfunc(&g, ug, &c->geo);
g.x *= f1;
g.y *= f2;
g.w = c->geo.h * f1;
g.h = c->geo.w * f2;

View File

@ -18,13 +18,6 @@ struct tag*
tag_new(struct screen *s, char *name)
{
struct tag *t;
XSetWindowAttributes at =
{
.background_pixel = THEME_DEFAULT->frame_bg,
.override_redirect = true,
.background_pixmap = ParentRelative,
.event_mask = BARWIN_MASK
};
t = xcalloc(1, sizeof(struct tag));
@ -33,17 +26,6 @@ tag_new(struct screen *s, char *name)
t->flags = 0;
t->sel = NULL;
/* Frame window */
t->frame = XCreateWindow(W->dpy, W->root,
s->ugeo.x, s->ugeo.y,
s->ugeo.w, s->ugeo.h,
0, CopyFromParent,
InputOutput,
CopyFromParent,
(CWOverrideRedirect | CWBackPixmap
| CWBackPixel | CWEventMask),
&at);
SLIST_INIT(&t->clients);
TAILQ_INIT(&t->sets);
@ -58,9 +40,11 @@ tag_screen(struct screen *s, struct tag *t)
struct client *c;
/* Unmap previous tag's frame */
WIN_STATE(s->seltag->frame, Unmap);
SLIST_FOREACH(c, &s->seltag->clients, tnext)
{
WIN_STATE(c->frame, Unmap);
ewmh_set_wm_state(c->win, IconicState);
}
/*
* Map selected tag's frame, only if there is
@ -68,9 +52,11 @@ tag_screen(struct screen *s, struct tag *t)
*/
if(!SLIST_EMPTY(&t->clients))
{
WIN_STATE(t->frame, Map);
SLIST_FOREACH(c, &t->clients, tnext)
{
WIN_STATE(c->frame, Map);
ewmh_set_wm_state(c->win, NormalState);
}
client_focus(t->sel);
}
@ -98,24 +84,9 @@ tag_client(struct tag *t, struct client *c)
client_focus(client_next(c));
}
/*
* Case of client removing: umap frame if empty
*/
/* Client remove */
if(!t)
{
/* Unmap frame if tag is now empty */
if(SLIST_EMPTY(&c->tag->clients))
WIN_STATE(c->tag->frame, Unmap);
return;
}
/* Reparent client win in frame win */
XReparentWindow(W->dpy, c->win, t->frame, 0, 0);
/* Map frame if tag was empty */
if(SLIST_EMPTY(&t->clients))
WIN_STATE(t->frame, Map);
c->tag = t;
@ -184,8 +155,6 @@ tag_remove(struct tag *t)
{
free(t->name);
XDestroyWindow(W->dpy, t->frame);
layout_free_set(t);
free(t);

View File

@ -17,22 +17,4 @@ void uicb_tag_set_with_name(Uicb cmd);
void uicb_tag_next(Uicb cmd);
void uicb_tag_prev(Uicb cmd);
/*
* Update frames size with screen usable geo
*/
static inline void
tag_update_frame_geo(struct screen *s)
{
struct tag *t;
TAILQ_FOREACH(t, &s->tags, next)
XMoveResizeWindow(W->dpy,
t->frame,
s->ugeo.x,
s->ugeo.y,
s->ugeo.w,
s->ugeo.h);
}
#endif /* TAG_H */

View File

@ -101,6 +101,13 @@ wmfs_init_font(char *font, struct theme *t)
static void
wmfs_xinit(void)
{
XGCValues xgc =
{
.function = GXinvert,
.subwindow_mode = IncludeInferiors,
.line_width = 1
};
XSetWindowAttributes at =
{
.event_mask = (KeyMask | ButtonMask | MouseMask
@ -131,6 +138,8 @@ wmfs_xinit(void)
*/
W->root = RootWindow(W->dpy, W->xscreen);
XChangeWindowAttributes(W->dpy, W->root, CWEventMask | CWCursor, &at);
W->rgc = XCreateGC(W->dpy, W->root, GCFunction | GCSubwindowMode | GCLineWidth, &xgc);
/*
* Locale (font encode)
@ -261,6 +270,7 @@ wmfs_quit(void)
*/
screen_free();
XFreeGC(W->dpy, W->rgc);
XCloseDisplay(W->dpy);
/* Conf stuffs */

View File

@ -75,6 +75,11 @@ struct geo_list
SLIST_ENTRY(geo_list) next;
};
struct colpair
{
Color fg, bg;
};
struct barwin
{
struct geo geo;
@ -128,7 +133,6 @@ struct tag
struct client *prevsel;
char *name;
Flags flags;
Window frame;
SLIST_HEAD(, client) clients;
TAILQ_HEAD(ssub, layout_set) sets;
TAILQ_ENTRY(tag) next;
@ -139,14 +143,16 @@ struct client
struct tag *tag;
struct screen *screen;
struct barwin *titlebar;
struct geo geo, tgeo, wgeo, owgeo;
struct geo geo, wgeo, tgeo, rgeo;
struct colpair ncol, scol;
int sizeh[SHLAST];
char *title;
int border, tbarw;
#define CLIENT_HINT_FLAG 0x01
#define CLIENT_IGNORE_ENTER 0x02
#define CLIENT_DID_WINSIZE 0x04
Flags flags;
Window win;
Window win, frame;
SLIST_ENTRY(client) next; /* Global list */
SLIST_ENTRY(client) tnext; /* struct tag list */
};
@ -177,11 +183,6 @@ struct mousebind
SLIST_ENTRY(mousebind) next;
};
struct colpair
{
Color fg, bg;
};
struct theme
{
char *name;
@ -218,7 +219,7 @@ struct wmfs
Window root;
int xscreen, xdepth;
Flags numlockmask;
GC gc;
GC gc, rgc;
Atom *net_atom;
bool running;