diff --git a/src/client.c b/src/client.c index ca9c439..f883027 100644 --- a/src/client.c +++ b/src/client.c @@ -136,12 +136,13 @@ client_gb_pos(struct tag *t, int x, int y) { struct client *c = SLIST_FIRST(&t->clients); - while(c) + FOREACH_NFCLIENT(c, &t->clients, tnext) { + if(c->flags & CLIENT_FREE) + continue; + if(INAREA(x, y, c->geo)) return c; - - c = SLIST_NEXT(c, tnext); } return NULL; @@ -579,6 +580,10 @@ client_focus(struct client *c) client_grabbuttons(c, true); client_tab_focus(c); client_frame_update(c, CCOL(c)); + + if(c->flags & CLIENT_FREE) + XRaiseWindow(W->dpy, c->frame); + XSetInputFocus(W->dpy, c->win, RevertToPointerRoot, CurrentTime); } else @@ -825,7 +830,7 @@ client_apply_rule(struct client *c) c->theme = r->theme; if(r->flags & RULE_FREE) - { /* TODO */ } + c->flags |= CLIENT_FREE; if(r->flags & RULE_MAX) { /* TODO */ } @@ -833,7 +838,7 @@ client_apply_rule(struct client *c) if(r->flags & RULE_IGNORE_TAG) { /* TODO */ } - c->flags = r->flags | CLIENT_RULED; + c->flags |= CLIENT_RULED; } flags = 0; } @@ -863,7 +868,7 @@ client_new(Window w, XWindowAttributes *wa, bool scan) c->geo.y = wa->y; c->geo.w = wa->width; c->geo.h = wa->height; - c->tgeo = c->wgeo = c->rgeo = c->geo; + c->tgeo = c->wgeo = c->rgeo = c->fgeo = c->geo; c->tbgeo = NULL; client_apply_rule(c); @@ -1021,7 +1026,10 @@ client_moveresize(struct client *c, struct geo *g) if(c->flags & CLIENT_TABBED) return false; - c->ttgeo = c->tgeo = c->rgeo = c->geo = *g; + if(c->flags & CLIENT_FREE) + c->fgeo = c->rgeo = c->geo = *g; + else + c->ttgeo = c->tgeo = c->rgeo = c->geo = *g; if(!(c->flags & CLIENT_DID_WINSIZE)) if(client_winsize(c, g)) @@ -1099,7 +1107,7 @@ _fac_arrange_row(struct client *c, enum position p, int fac) struct client *cc; /* Travel clients to search row parents and apply fac */ - SLIST_FOREACH(cc, &c->tag->clients, tnext) + FOREACH_NFCLIENT(cc, &c->tag->clients, tnext) if(GEO_PARENTROW(g, cc->tgeo, p)) _fac_apply(cc, p, fac); } @@ -1115,7 +1123,7 @@ _fac_check_to_reverse(struct client *c) * resize client because of possible error with next * clients in linked list. */ - SLIST_FOREACH(gc, &c->tag->clients, tnext) + FOREACH_NFCLIENT(gc, &c->tag->clients, tnext) if(gc->flags & CLIENT_FAC_APPLIED && client_winsize(gc, &gc->tgeo)) { @@ -1142,7 +1150,7 @@ _fac_resize(struct client *c, enum position p, int fac) if(!gc || gc->screen != c->screen) return; - SLIST_FOREACH(cc, &c->tag->clients, tnext) + FOREACH_NFCLIENT(cc, &c->tag->clients, tnext) cc->ttgeo = cc->tgeo; if(GEO_CHECK2(c->tgeo, gc->tgeo, p)) @@ -1164,17 +1172,17 @@ client_apply_tgeo(struct tag *t) { struct client *c; - SLIST_FOREACH(c, &t->clients, tnext) + FOREACH_NFCLIENT(c, &t->clients, tnext) { client_moveresize(c, &c->tgeo); c->flags &= ~CLIENT_FAC_APPLIED; } } -#define _REV_BORDER() \ - do { \ - SLIST_FOREACH(gc, &c->tag->clients, tnext) \ - draw_reversed_rect(W->root, gc, true); \ +#define _REV_BORDER() \ + do { \ + FOREACH_NFCLIENT(gc, &c->tag->clients, tnext) \ + draw_reversed_rect(W->root, gc, true); \ } while(/* CONSTCOND */ 0); void client_fac_resize(struct client *c, enum position p, int fac) @@ -1256,7 +1264,7 @@ client_fac_resize(struct client *c, enum position p, int fac) /* Aborted with escape, Set back original geos */ else { - SLIST_FOREACH(gc, &c->tag->clients, tnext) + FOREACH_NFCLIENT(gc, &c->tag->clients, tnext) { gc->tgeo = gc->geo; gc->flags &= ~CLIENT_DID_WINSIZE; diff --git a/src/client.h b/src/client.h index 9401f5d..1c01e44 100644 --- a/src/client.h +++ b/src/client.h @@ -13,6 +13,11 @@ #define TCLIENT_CHECK(C) (C->flags & CLIENT_TABBED && !(C->flags & CLIENT_TABMASTER)) +/* SLIST_FOREACH for client with no free client */ +#define FOREACH_NFCLIENT(V, H, F) \ + SLIST_FOREACH(V, H, F) \ + if(!(V->flags & CLIENT_FREE)) + inline void client_configure(struct client *c); struct client *client_gb_win(Window w); struct client *client_gb_frame(Window w); diff --git a/src/config.h b/src/config.h index 36220aa..836c49c 100644 --- a/src/config.h +++ b/src/config.h @@ -46,6 +46,7 @@ static const struct { char *name; void (*func)(Uicb cmd); } uicb_list[] = { "layout_rotate_right", uicb_layout_rotate_right }, { "layout_prev_set", uicb_layout_prev_set }, { "layout_next_set", uicb_layout_next_set }, + { "layout_toggle_free", uicb_layout_toggle_free }, /* Client */ { "client_close", uicb_client_close }, diff --git a/src/layout.c b/src/layout.c index d19132c..d57d51b 100644 --- a/src/layout.c +++ b/src/layout.c @@ -23,7 +23,7 @@ layout_save_set(struct tag *t) l = xcalloc(1, sizeof(struct layout_set)); SLIST_INIT(&l->geos); - SLIST_FOREACH(c, &t->clients, tnext) + FOREACH_NFCLIENT(c, &t->clients, tnext) { g = xcalloc(1, sizeof(struct geo_list)); g->geo = c->geo; @@ -49,7 +49,7 @@ layout_apply_set(struct tag *t, struct layout_set *l) struct client *c; int nc = 1; - SLIST_FOREACH(c, &t->clients, tnext) + FOREACH_NFCLIENT(c, &t->clients, tnext) ++nc; /* TODO: Adapt different client number case */ @@ -275,7 +275,7 @@ layout_split_check_row_dir(struct client *c, struct client *g, enum position p) struct client *cc; int s = 0, cs = (LDIR(p) ? g->geo.h : g->geo.w); - SLIST_FOREACH(cc, &c->tag->clients, tnext) + FOREACH_NFCLIENT(cc, &c->tag->clients, tnext) if(GEO_PARENTROW(cgeo, cc->geo, RPOS(p)) && GEO_CHECK_ROW(cc->geo, g->geo, p)) { @@ -347,7 +347,7 @@ layout_split_arrange_closed(struct client *ghost) && layout_split_check_row_dir(c, ghost, p)) { g = c->geo; - SLIST_FOREACH(cc, &c->tag->clients, tnext) + FOREACH_NFCLIENT(cc, &c->tag->clients, tnext) if(GEO_PARENTROW(g, cc->geo, RPOS(p)) && GEO_CHECK_ROW(cc->geo, ghost->geo, p)) { @@ -366,14 +366,16 @@ layout_split_integrate(struct client *c, struct client *sc) { struct geo g; - /* No sc */ - if(!sc || sc == c || sc->tag != c->tag) + /* No sc or not compatible sc */ + if(!sc || sc == c || sc->tag != c->tag + || sc->flags & CLIENT_FREE) { /* * Not even a first client in list, then * maximize the lonely client */ - if(!(sc = SLIST_NEXT(SLIST_FIRST(&c->tag->clients), tnext))) + if(!(sc = SLIST_NEXT(SLIST_FIRST(&c->tag->clients), tnext)) + || sc->flags & CLIENT_FREE) { client_maximize(c); return; @@ -460,7 +462,7 @@ layout_rotate(struct tag *t, void (*pfunc)(struct geo*, struct geo*, struct geo* float f1 = (float)t->screen->ugeo.w / (float)t->screen->ugeo.h; float f2 = 1 / f1; - SLIST_FOREACH(c, &t->clients, tnext) + FOREACH_NFCLIENT(c, &t->clients, tnext) { pfunc(&g, ug, &c->geo); @@ -474,7 +476,7 @@ layout_rotate(struct tag *t, void (*pfunc)(struct geo*, struct geo*, struct geo* } /* Rotate sometimes do not set back perfect size.. */ - SLIST_FOREACH(c, &t->clients, tnext) + FOREACH_NFCLIENT(c, &t->clients, tnext) layout_fix_hole(c); layout_save_set(t); @@ -518,7 +520,7 @@ uicb_layout_vmirror(Uicb cmd) (void)cmd; struct client *c; - SLIST_FOREACH(c, &W->screen->seltag->clients, tnext) + FOREACH_NFCLIENT(c, &W->screen->seltag->clients, tnext) { c->geo.x = W->screen->ugeo.w - (c->geo.x + c->geo.w); client_moveresize(c, &c->geo); @@ -533,7 +535,7 @@ uicb_layout_hmirror(Uicb cmd) (void)cmd; struct client *c; - SLIST_FOREACH(c, &W->screen->seltag->clients, tnext) + FOREACH_NFCLIENT(c, &W->screen->seltag->clients, tnext) { c->geo.y = W->screen->ugeo.h - (c->geo.y + c->geo.h); client_moveresize(c, &c->geo); @@ -541,3 +543,36 @@ uicb_layout_hmirror(Uicb cmd) layout_save_set(W->screen->seltag); } + +void +layout_client(struct client *c) +{ + if(c->flags & CLIENT_IGNORE_LAYOUT) + { + c->flags ^= CLIENT_IGNORE_LAYOUT; + return; + } + + if(c->flags & CLIENT_FREE) + { + layout_split_arrange_closed(c); + client_moveresize(c, &c->fgeo); + XRaiseWindow(W->dpy, c->frame); + } + else if(!(c->flags & CLIENT_TABBED)) + layout_split_integrate(c, c->tag->sel); +} + +void +uicb_layout_toggle_free(Uicb cmd) +{ + (void)cmd; + + if(!(W->client)) + return; + + W->client->flags ^= CLIENT_FREE; + layout_client(W->client); +} + + diff --git a/src/layout.h b/src/layout.h index a03148a..fb675da 100644 --- a/src/layout.h +++ b/src/layout.h @@ -34,12 +34,14 @@ void layout_free_set(struct tag *t); void layout_split_integrate(struct client *c, struct client *sc); void layout_split_arrange_closed(struct client *ghost); inline void layout_fix_hole(struct client *c); +void layout_client(struct client *c); void uicb_layout_vmirror(Uicb cmd); void uicb_layout_hmirror(Uicb cmd); void uicb_layout_rotate_left(Uicb cmd); void uicb_layout_rotate_right(Uicb cmd); void uicb_layout_prev_set(Uicb cmd); void uicb_layout_next_set(Uicb cmd); +void uicb_layout_toggle_free(Uicb cmd); #endif /* LAYOUT_H */ diff --git a/src/mouse.c b/src/mouse.c index 1785518..3272bc9 100644 --- a/src/mouse.c +++ b/src/mouse.c @@ -9,11 +9,15 @@ #include "client.h" #include "draw.h" -#define _REV_BORDER() \ - do { \ - SLIST_FOREACH(gc, &c->tag->clients, tnext) \ - draw_reversed_rect(W->root, gc, true); \ + +#define _REV_SBORDER(c) draw_reversed_rect(W->root, c, false); + +#define _REV_BORDER() \ + do { \ + FOREACH_NFCLIENT(gc, &c->tag->clients, tnext) \ + draw_reversed_rect(W->root, gc, true); \ } while(/* CONSTCOND */ 0); + static void mouse_resize(struct client *c) { @@ -25,7 +29,12 @@ mouse_resize(struct client *c) XQueryPointer(W->dpy, W->root, &w, &w, &ox, &oy, &d, &d, (uint *)&u); XGrabServer(W->dpy); - _REV_BORDER(); + if(c->flags & CLIENT_FREE) + { + _REV_SBORDER(c); + } + else + _REV_BORDER(); if(c->flags & CLIENT_TABBED && !(c->flags & CLIENT_TABMASTER)) c = c->tabmaster; @@ -40,31 +49,54 @@ mouse_resize(struct client *c) if(ev.type != MotionNotify) continue; - _REV_BORDER(); + if(c->flags & CLIENT_FREE) + { + _REV_SBORDER(c); - if(ix >= c->geo.x + (c->geo.w >> 1)) - _fac_resize(c, Right, ev.xmotion.x_root - ox); + c->geo.w = ((ev.xmotion.x_root - c->geo.x < c->sizeh[MINW]) + ? c->sizeh[MINW] + : ev.xmotion.x_root - c->geo.x); + c->geo.h = ((ev.xmotion.y_root - c->geo.y < c->sizeh[MINH]) + ? c->sizeh[MINH] + : ev.xmotion.y_root - c->geo.y); + + _REV_SBORDER(c); + } else - _fac_resize(c, Left, ox - ev.xmotion.x_root); + { + _REV_BORDER(); - if(iy >= c->geo.y + (c->geo.h >> 1)) - _fac_resize(c, Bottom, ev.xmotion.y_root - oy); - else - _fac_resize(c, Top, oy - ev.xmotion.y_root); + if(ix >= c->geo.x + (c->geo.w >> 1)) + _fac_resize(c, Right, ev.xmotion.x_root - ox); + else + _fac_resize(c, Left, ox - ev.xmotion.x_root); - ox = ev.xmotion.x_root; - oy = ev.xmotion.y_root; + if(iy >= c->geo.y + (c->geo.h >> 1)) + _fac_resize(c, Bottom, ev.xmotion.y_root - oy); + else + _fac_resize(c, Top, oy - ev.xmotion.y_root); - _REV_BORDER(); + ox = ev.xmotion.x_root; + oy = ev.xmotion.y_root; + + _REV_BORDER(); + } XSync(W->dpy, false); } while(ev.type != ButtonRelease); - _REV_BORDER(); - - client_apply_tgeo(c->tag); - layout_save_set(c->tag); + if(c->flags & CLIENT_FREE) + { + _REV_SBORDER(c); + client_moveresize(c, &c->geo); + } + else + { + _REV_BORDER(); + client_apply_tgeo(c->tag); + layout_save_set(c->tag); + } XUngrabServer(W->dpy); } @@ -88,7 +120,6 @@ mouse_drag_tag(struct client *c, Window w) return NULL; } -#define _REV_SBORDER(c) draw_reversed_rect(W->root, c, false); void mouse_move(struct client *c, void (*func)(struct client*, struct client*)) { @@ -96,11 +127,17 @@ mouse_move(struct client *c, void (*func)(struct client*, struct client*)) struct tag *t = NULL; XEvent ev; Window w; - int d, u; + int d, u, ox, oy; + int ocx, ocy; + + ocx = c->geo.x; + ocy = c->geo.y; if(c->flags & CLIENT_TABBED && !(c->flags & CLIENT_TABMASTER)) c = c->tabmaster; + XQueryPointer(W->dpy, W->root, &w, &w, &ox, &oy, &d, &d, (uint *)&u); + _REV_SBORDER(c); do @@ -110,23 +147,35 @@ mouse_move(struct client *c, void (*func)(struct client*, struct client*)) if(ev.type != MotionNotify) continue; - XQueryPointer(W->dpy, W->root, &w, &w, &d, &d, &d, &d, (uint *)&u); - - if(!(c2 = client_gb_win(w))) - if(!(c2 = client_gb_frame(w))) - c2 = client_gb_titlebar(w); - - if(c2) + if(c->flags & CLIENT_FREE) { - if(c2 != last) - { - _REV_SBORDER(last); - _REV_SBORDER(c2); - last = c2; - } + _REV_SBORDER(c); + + c->geo.x = (ocx + (ev.xmotion.x_root - ox)); + c->geo.y = (ocy + (ev.xmotion.y_root - oy)); + + _REV_SBORDER(c); } else - t = mouse_drag_tag(c, w); + { + XQueryPointer(W->dpy, W->root, &w, &w, &d, &d, &d, &d, (uint *)&u); + + if(!(c2 = client_gb_win(w))) + if(!(c2 = client_gb_frame(w))) + c2 = client_gb_titlebar(w); + + if(c2) + { + if(c2 != last) + { + _REV_SBORDER(last); + _REV_SBORDER(c2); + last = c2; + } + } + else + t = mouse_drag_tag(c, w); + } XSync(W->dpy, false); @@ -137,7 +186,13 @@ mouse_move(struct client *c, void (*func)(struct client*, struct client*)) else if(t && t != (struct tag*)c) tag_client(t, c); else + { + /* No func mean free client resize */ + if(!func) + client_moveresize(c, &c->geo); + _REV_SBORDER(c); + } } void @@ -155,7 +210,7 @@ uicb_mouse_move(Uicb cmd) (void)cmd; if(W->client && mouse_check_client(W->client)) - mouse_move(W->client, client_swap2); + mouse_move(W->client, (W->client->flags & CLIENT_FREE ? NULL : client_swap2)); } void diff --git a/src/tag.c b/src/tag.c index 8f86433..d749aa0 100644 --- a/src/tag.c +++ b/src/tag.c @@ -74,7 +74,7 @@ tag_client(struct tag *t, struct client *c) if(c->tag == t) return; - if(!(c->flags & CLIENT_IGNORE_LAYOUT)) + if(!(c->flags & (CLIENT_IGNORE_LAYOUT | CLIENT_FREE))) layout_split_arrange_closed(c); if(!(c->flags & CLIENT_REMOVEALL)) @@ -98,18 +98,11 @@ tag_client(struct tag *t, struct client *c) client_update_props(c, CPROP_LOC); - /* - * Insert in new tag list before - * layout_split_integrate, because of set historic. - */ SLIST_INSERT_HEAD(&t->clients, c, tnext); infobar_elem_screen_update(t->screen, ElemTag); - if(c->flags & CLIENT_IGNORE_LAYOUT) - c->flags ^= CLIENT_IGNORE_LAYOUT; - else if(!(c->flags & CLIENT_TABBED)) - layout_split_integrate(c, t->sel); + layout_client(c); if(c->flags & CLIENT_TABMASTER && c->prevtag) { diff --git a/src/wmfs.h b/src/wmfs.h index 2ac62ef..bb6bf2d 100644 --- a/src/wmfs.h +++ b/src/wmfs.h @@ -177,7 +177,7 @@ struct client struct tag *tag, *prevtag; struct screen *screen; struct barwin *titlebar; - struct geo geo, wgeo, tgeo, ttgeo, rgeo, *tbgeo; + struct geo geo, wgeo, tgeo, ttgeo, rgeo, *tbgeo, fgeo; struct colpair ncol, scol; struct theme *theme; struct client *tabmaster; @@ -196,6 +196,7 @@ struct client #define CLIENT_REMOVEALL 0x200 #define CLIENT_MAPPED 0x400 #define CLIENT_FULLSCREEN 0x800 +#define CLIENT_FREE 0x1000 Flags flags; Window win, frame, tmp; SLIST_ENTRY(client) next; /* Global list */