diff options
author | Andrew Shadura <bugzilla@tut.by> | 2012-08-10 17:28:37 +0200 |
---|---|---|
committer | Andrew Shadura <bugzilla@tut.by> | 2012-08-10 17:28:37 +0200 |
commit | 73a0b1b034b50c3356b51e389daa8bfd5f113853 (patch) | |
tree | 89f259da840cdf6a7aad11b983942e7926c70d59 /cmd/wmii/client.c | |
parent | 79e6dfc63311b132887889a6f4f582480575e80a (diff) |
Synchronise to the latest hg tip.
Diffstat (limited to 'cmd/wmii/client.c')
-rw-r--r-- | cmd/wmii/client.c | 655 |
1 files changed, 317 insertions, 338 deletions
diff --git a/cmd/wmii/client.c b/cmd/wmii/client.c index 5f82455..c119bd0 100644 --- a/cmd/wmii/client.c +++ b/cmd/wmii/client.c @@ -5,6 +5,7 @@ #include "dat.h" #include <ctype.h> #include <strings.h> +#include <signal.h> #include <X11/Xatom.h> #include "fns.h" @@ -23,7 +24,7 @@ enum { static Group* group; -static void +void group_init(Client *c) { Group *g; long *ret; @@ -53,12 +54,13 @@ group_init(Client *c) { g->ref++; } -static void +void group_remove(Client *c) { Group **gp; Group *g; g = c->group; + c->group = nil; if(g == nil) return; if(g->client == c) @@ -92,32 +94,23 @@ group_leader(Group *g) { Client* client_create(XWindow w, XWindowAttributes *wa) { Client **t, *c; - WinAttr fwa; - Point p; - Visual *vis; - int depth; + char **host = nil; + ulong *pid = nil; c = emallocz(sizeof *c); c->fullscreen = -1; c->border = wa->border_width; - c->r.min = Pt(wa->x, wa->y); - c->r.max = addpt(c->r.min, - Pt(wa->width, wa->height)); + c->r = rectsetorigin(Rect(0, 0, wa->width, wa->height), + Pt(wa->x, wa->y)); c->w.type = WWindow; + c->w.visual = wa->visual; c->w.xid = w; c->w.r = c->r; + c->w.aux = c; - depth = scr.depth; - vis = scr.visual; - /* XXX: Multihead. */ - c->ibuf = &ibuf; - if(render_argb_p(wa->visual)) { - depth = 32; - vis = render_visual; - c->ibuf = &ibuf32; - } + setborder(&c->w, 0, &(Color){0}); client_prop(c, xatom("WM_PROTOCOLS")); client_prop(c, xatom("WM_TRANSIENT_FOR")); @@ -127,43 +120,21 @@ client_create(XWindow w, XWindowAttributes *wa) { client_prop(c, xatom("WM_NAME")); client_prop(c, xatom("_MOTIF_WM_HINTS")); - XSetWindowBorderWidth(display, w, 0); - XAddToSaveSet(display, w); + gethostname(hostname, sizeof(hostname) - 1); + if(getprop_textlist(&c->w, "WM_CLIENT_MACHINE", &host) && + getprop_ulong(&c->w, Net("WM_PID"), "CARDINAL", 0, &pid, 1) && + !strcmp(hostname, *host)) + c->pid = (int)*pid; + freestringlist(host); + free(pid); - fwa.background_pixmap = None; - fwa.bit_gravity = NorthWestGravity; - fwa.border_pixel = 0; - fwa.colormap = XCreateColormap(display, scr.root.xid, vis, AllocNone); - fwa.event_mask = SubstructureRedirectMask - | SubstructureNotifyMask - | StructureNotifyMask - | ExposureMask - | EnterWindowMask - | PointerMotionMask - | ButtonPressMask - | ButtonReleaseMask; - fwa.override_redirect = true; - c->framewin = createwindow_visual(&scr.root, c->r, - depth, vis, InputOutput, - &fwa, CWBackPixmap - | CWBitGravity - /* These next two matter for ARGB windows. Donno why. */ - | CWBorderPixel - | CWColormap - | CWEventMask - | CWOverrideRedirect); - XFreeColormap(display, fwa.colormap); + c->rgba = render_argb_p(c->w.visual); + client_reparent(c); - c->framewin->aux = c; - c->w.aux = c; - sethandler(c->framewin, &framehandler); sethandler(&c->w, &handlers); selectinput(&c->w, ClientMask); - p.x = def.border; - p.y = labelh(def.font); - group_init(c); grab_button(c->framewin->xid, AnyButton, AnyModifier); @@ -176,14 +147,14 @@ client_create(XWindow w, XWindowAttributes *wa) { } - /* + /* * It's actually possible for a window to be destroyed * before we get a chance to reparent it. Check for that * now, because otherwise we'll wind up mapping a * perceptibly empty frame before it's destroyed. */ traperrors(true); - reparentwindow(&c->w, c->framewin, p); + XAddToSaveSet(display, w); if(traperrors(false)) { client_destroy(c); return nil; @@ -191,46 +162,115 @@ client_create(XWindow w, XWindowAttributes *wa) { ewmh_initclient(c); - event("CreateClient %C\n", c); + event("CreateClient %#C\n", c); client_manage(c); return c; } +void +client_reparent(Client *c) { + Window *fw; + WinAttr wa; + bool rgba; + + rgba = c->rgba | RGBA_P(def.normcolor) | RGBA_P(def.focuscolor); + + fw = c->framewin; + if(fw && (fw->depth == 32) == rgba) + return; + + wa.background_pixmap = None; + wa.bit_gravity = NorthWestGravity; + wa.event_mask = ButtonPressMask + | ButtonReleaseMask + | EnterWindowMask + | ExposureMask + | PointerMotionMask + | StructureNotifyMask + | SubstructureNotifyMask + | SubstructureRedirectMask; + wa.override_redirect = true; + if(rgba) + c->framewin = createwindow_rgba(&scr.root, c->r, + &wa, CWBackPixmap + | CWBitGravity + | CWEventMask + | CWOverrideRedirect); + else + c->framewin = createwindow(&scr.root, c->r, scr.depth, InputOutput, + &wa, CWBackPixmap + | CWBitGravity + | CWEventMask + | CWOverrideRedirect); + + c->framewin->aux = c; + sethandler(c->framewin, &framehandler); + reparentwindow(&c->w, c->framewin, ZP); + if(fw) + destroywindow(fw); +} + static bool apply_rules(Client *c) { + IxpMsg m; Rule *r; - - if(def.tagrules.string) - for(r=def.tagrules.rule; r; r=r->next) - if(regexec(r->regex, c->props, nil, 0)) - return client_applytags(c, r->value); - return false; + Ruleval *rv; + bool ret, more; + + ret = true; + more = true; + for(r=def.rules.rule; r && more; r=r->next) + if(regexec(r->regex, c->props, nil, 0)) { + more = false; + for(rv=r->values; rv; rv=rv->next) { + if(!strcmp(rv->key, "continue")) + more = true; + else if(!strcmp(rv->key, "tags")) + utflcpy(c->tags, rv->value, sizeof c->tags); + else if(!strcmp(rv->key, "force-tags")) { + utflcpy(c->tags, rv->value, sizeof c->tags); + ret = false; + }else { + bufclear(); + bufprint("%s %s", rv->key, rv->value); + m = ixp_message(buffer, _buf_end - buffer, MsgPack); + if(waserror()) + warning("processing rule %q=%q: %r", rv->key, rv->value); + else { + message_client(c, &m); + poperror(); + } + } + } + } + return ret; } void client_manage(Client *c) { Client *leader; - Frame *f; char *tags; - bool rules; + bool dotags; if(Dx(c->r) == Dx(screen->r)) if(Dy(c->r) == Dy(screen->r)) if(c->w.ewmh.type == 0) fullscreen(c, true, -1); - tags = getprop_string(&c->w, "_WMII_TAGS"); - rules = apply_rules(c); + dotags = apply_rules(c); - leader = win2client(c->trans); - if(leader == nil && c->group) - leader = group_leader(c->group); + if(!c->tags[0] || dotags) { + leader = win2client(c->trans); + if(leader == nil && c->group) + leader = group_leader(c->group); - if(tags) // && (!leader || leader == c || starting)) - utflcpy(c->tags, tags, sizeof c->tags); - else if(leader && !rules) - utflcpy(c->tags, leader->tags, sizeof c->tags); - free(tags); + tags = getprop_string(&c->w, "_WMII_TAGS"); + if(tags) + utflcpy(c->tags, tags, sizeof c->tags); + else if(leader) + utflcpy(c->tags, leader->tags, sizeof c->tags); + free(tags); + } if(c->tags[0]) client_applytags(c, c->tags); @@ -247,17 +287,17 @@ client_manage(Client *c) { && !client_viewframe(group_leader(c->group), c->sel->view); - f = c->sel; + /* f = c->sel; */ if(!(c->w.ewmh.type & TypeSplash)) - if(newgroup) { - /* XXX: Look over this. - if(f->area != f->view->sel) - f->view->oldsel = f->view->sel; - */ - }else { - frame_restack(c->sel, c->sel->area->sel); - view_restack(c->sel->view); - } + if(newgroup) { + /* XXX: Look over this. + if(f->area != f->view->sel) + f->view->oldsel = f->view->sel; + */ + }else { + frame_restack(c->sel, c->sel->area->sel); + view_restack(c->sel->view); + } } void @@ -278,11 +318,7 @@ client_destroy(Client *c) { r = client_grav(c, ZR); - hide = false; - if(!c->sel || c->sel->view != selview) - hide = true; - - XGrabServer(display); + hide = (!c->sel || c->sel->view != selview); /* In case the client is already destroyed. */ traperrors(true); @@ -293,29 +329,30 @@ client_destroy(Client *c) { else reparentwindow(&c->w, &scr.root, r.min); - if(starting > -1) + if(starting >= 0) XRemoveFromSaveSet(display, c->w.xid); - traperrors(false); - XUngrabServer(display); - none = nil; client_setviews(c, &none); - if(starting > -1) + if(starting >= 0) { client_unmap(c, WithdrawnState); + delproperty(&c->w, "_WMII_TAGS"); + } refree(&c->tagre); refree(&c->tagvre); free(c->retags); + traperrors(false); + destroywindow(c->framewin); ewmh_destroyclient(c); group_remove(c); - if(starting > -1) - event("DestroyClient %C\n", c); + if(starting >= 0) + event("DestroyClient %#C\n", c); - flushevents(FocusChangeMask, true); - free(c->w.hints); + event_flush(FocusChangeMask, true); + cleanupwindow(&c->w); free(c); } @@ -351,17 +388,13 @@ Cfmt(Fmt *f) { c = va_arg(f->args, Client*); if(c) - return fmtprint(f, "%W", &c->w); + if(f->flags & FmtSharp) + return fmtprint(f, "%W", &c->w); + else + return fmtprint(f, "%s", c->name); return fmtprint(f, "<nil>"); } -char* -clientname(Client *c) { - if(c) - return c->name; - return "<nil>"; -} - Rectangle client_grav(Client *c, Rectangle rd) { Rectangle r, cr; @@ -396,13 +429,15 @@ client_grav(Client *c, Rectangle rd) { bool client_floats_p(Client *c) { + if(c->floating == Never) + return false; return c->trans || c->floating || c->fixedsize || c->titleless || c->borderless || c->fullscreen >= 0 - || (c->w.ewmh.type & (TypeDialog|TypeSplash|TypeDock)); + || (c->w.ewmh.type & (TypeDialog|TypeSplash|TypeDock|TypeMenu|TypeToolbar)); } Frame* @@ -466,12 +501,12 @@ client_unmap(Client *c, int state) { } int -map_frame(Client *c) { +client_mapframe(Client *c) { return mapwin(c->framewin); } int -unmap_frame(Client *c) { +client_unmapframe(Client *c) { return unmapwin(c->framewin); } @@ -480,19 +515,15 @@ focus(Client *c, bool user) { View *v; Frame *f; - USED(user); - f = c->sel; - if(!f) - return; - /* - if(!user && c->noinput) - return; - */ - - v = f->view; - if(v != selview) - view_focus(screen, v); - frame_focus(c->sel); + Dprint(DFocus, "focus(%#C, %d)\n", c, user); + if(!c->nofocus || user) + if((f = c->sel)) { + v = f->view; + if(v != selview) + view_focus(screen, v); + frame_focus(c->sel); + view_restack(c->sel->view); + } } void @@ -503,26 +534,26 @@ client_focus(Client *c) { c->group->client = c; sync(); - flushevents(FocusChangeMask, true); + event_flush(FocusChangeMask, true); + + Dprint(DFocus, "client_focus([%#C]%C) collapsed=%s\n", + c, c, c && c->sel->collapsed ? "true" : "false"); + Dprint(DFocus, "\t[%#C]%C\n\t=> [%#C]%C\n", + disp.focus, disp.focus, c, c); - Dprint(DFocus, "client_focus([%C]%s)\n", c, clientname(c)); - Dprint(DFocus, "\t[%C]%s\n\t=> [%C]%s\n", - disp.focus, clientname(disp.focus), - c, clientname(c)); if(disp.focus != c) { - if(c) { + if(c && !c->sel->collapsed) { if(!c->noinput) setfocus(&c->w, RevertToParent); else if(c->proto & ProtoTakeFocus) { - xtime_kludge(); + event_updatextime(); client_message(c, "WM_TAKE_FOCUS", 0); } }else setfocus(screen->barwin, RevertToParent); - event("ClientFocus %C\n", c); sync(); - flushevents(FocusChangeMask, true); + event_flush(FocusChangeMask, true); } } @@ -535,7 +566,7 @@ client_resize(Client *c, Rectangle r) { if(f->view != selview) { client_unmap(c, IconicState); - unmap_frame(c); + client_unmapframe(c); return; } @@ -543,19 +574,20 @@ client_resize(Client *c, Rectangle r) { if(f->collapsed) { if(f->area->max && !resizing) - unmap_frame(c); + client_unmapframe(c); else { reshapewin(c->framewin, f->r); movewin(&c->w, f->crect.min); - map_frame(c); + client_mapframe(c); } client_unmap(c, IconicState); }else { client_map(c); reshapewin(c->framewin, f->r); reshapewin(&c->w, f->crect); - map_frame(c); - client_configure(c); + client_mapframe(c); + if(!eqrect(c->r, c->configr)) + client_configure(c); ewmh_framesize(c); } } @@ -573,37 +605,44 @@ client_setcursor(Client *c, Cursor cur) { void client_configure(Client *c) { - XConfigureEvent e; Rectangle r; + c->configr = c->r; r = rectsubpt(c->r, Pt(c->border, c->border)); - e.type = ConfigureNotify; - e.event = c->w.xid; - e.window = c->w.xid; - e.above = None; - e.override_redirect = false; - - e.x = r.min.x; - e.y = r.min.y; - e.width = Dx(r); - e.height = Dy(r); - e.border_width = c->border; - - sendevent(&c->w, false, StructureNotifyMask, (XEvent*)&e); + sendevent(&c->w, false, StructureNotifyMask, + &(XConfigureEvent) { + .type = ConfigureNotify, + .event = c->w.xid, + .window = c->w.xid, + + .x = r.min.x, + .y = r.min.y, + .width = Dx(r), + .height = Dy(r), + .border_width = c->border, + }); } void client_message(Client *c, char *msg, long l2) { - sendmessage(&c->w, "WM_PROTOCOLS", xatom(msg), xtime, l2, 0, 0); + sendmessage(&c->w, "WM_PROTOCOLS", xatom(msg), event_xtime, l2, 0, 0); } void client_kill(Client *c, bool nice) { - if(nice && (c->proto & ProtoDelete)) { + + if(!nice) { + if(c->pid) + kill(c->pid, SIGKILL); + XKillClient(display, c->w.xid); + } + else if(c->proto & ProtoDelete) { + c->dead = 1; client_message(c, "WM_DELETE_WINDOW", 0); - ewmh_pingclient(c); - }else + ewmh_checkresponsive(c); + } + else XKillClient(display, c->w.xid); } @@ -618,8 +657,7 @@ fullscreen(Client *c, int fullscreen, long screen) { if(fullscreen == (c->fullscreen >= 0)) return; - event("Fullscreen %C %s\n", c, (fullscreen ? "on" : "off")); - ewmh_updatestate(c); + event("Fullscreen %#C %s\n", c, (fullscreen ? "on" : "off")); c->fullscreen = -1; if(!fullscreen) @@ -654,15 +692,14 @@ fullscreen(Client *c, int fullscreen, long screen) { if((f = c->sel)) view_update(f->view); } + ewmh_updatestate(c); } void client_seturgent(Client *c, int urgent, int from) { XWMHints *wmh; char *cfrom, *cnot; - Frame *f, *ff; - Area *a; - int s; + Frame *f; if(urgent == Toggle) urgent = c->urgent ^ On; @@ -671,22 +708,14 @@ client_seturgent(Client *c, int urgent, int from) { cnot = (urgent ? "" : "Not"); if(urgent != c->urgent) { - event("%sUrgent %C %s\n", cnot, c, cfrom); + event("%sUrgent %#C %s\n", cnot, c, cfrom); c->urgent = urgent; ewmh_updatestate(c); - if(c->sel) { - if(c->sel->view == selview) - frame_draw(c->sel); - for(f=c->frame; f; f=f->cnext) { - SET(ff); - if(!urgent) - foreach_frame(f->view, s, a, ff) - if(ff->client->urgent) break; - if(urgent || ff == nil) - event("%sUrgentTag %s %s\n", - cnot, cfrom, f->view->name); - } - } + if(c->sel) + frame_draw(c->sel); + + for(f=c->frame; f; f=f->cnext) + view_update_urgency(f->view, cfrom); } if(from == UrgManager) { @@ -705,16 +734,8 @@ client_seturgent(Client *c, int urgent, int from) { /* X11 stuff */ void update_class(Client *c) { - char *str; - str = utfrune(c->props, L':'); - if(str) - str = utfrune(str+1, L':'); - if(str == nil) { - strcpy(c->props, "::"); - str = c->props + 1; - } - utflcpy(str+1, c->name, sizeof c->props); + snprint(c->props, sizeof c->props, "%s:%s", c->class, c->name); } static void @@ -722,13 +743,10 @@ client_updatename(Client *c) { char *str; c->name[0] = '\0'; - - str = getprop_string(&c->w, "_NET_WM_NAME"); - if(str == nil) - str = getprop_string(&c->w, "WM_NAME"); - if(str) + if((str = windowname(&c->w))) { utflcpy(c->name, str, sizeof c->name); - free(str); + free(str); + } update_class(c); if(c->sel) @@ -776,7 +794,7 @@ updatemwm(Client *c) { } free(ret); - if(c->sel && false) { + if(false && c->sel) { c->sel->floatr = client_grav(c, r); if(c->sel->area->floating) { client_resize(c, c->sel->floatr); @@ -785,7 +803,7 @@ updatemwm(Client *c) { } } -void +bool client_prop(Client *c, Atom a) { WinHints h; XWMHints *wmh; @@ -803,8 +821,7 @@ client_prop(Client *c, Atom a) { else switch (a) { default: - ewmh_prop(c, a); - break; + return true; case XA_WM_TRANSIENT_FOR: XGetTransientForHint(display, c->w.xid, &c->trans); break; @@ -812,12 +829,12 @@ client_prop(Client *c, Atom a) { memset(&h, 0, sizeof h); if(c->w.hints) bcopy(c->w.hints, &h, sizeof h); - sethints(&c->w); + gethints(&c->w); if(c->w.hints) c->fixedsize = eqpt(c->w.hints->min, c->w.hints->max); if(memcmp(&h, c->w.hints, sizeof h)) - if(c->sel) - view_update(c->sel->view); + if(c->sel) + view_update(c->sel->view); break; case XA_WM_HINTS: wmh = XGetWMHints(display, c->w.xid); @@ -829,9 +846,9 @@ client_prop(Client *c, Atom a) { break; case XA_WM_CLASS: n = getprop_textlist(&c->w, "WM_CLASS", &class); - snprint(c->props, sizeof c->props, "%s:%s:", - (n > 0 ? class[0] : "<nil>"), - (n > 1 ? class[1] : "<nil>")); + snprint(c->class, sizeof c->class, "%s:%s", + (n > 0 ? class[0] : "<nil>"), + (n > 1 ? class[1] : "<nil>")); freestringlist(class); update_class(c); break; @@ -840,15 +857,16 @@ client_prop(Client *c, Atom a) { client_updatename(c); break; } + return false; } /* Handlers */ -static void -configreq_event(Window *w, XConfigureRequestEvent *e) { - Rectangle r, cr; +static bool +configreq_event(Window *w, void *aux, XConfigureRequestEvent *e) { + Rectangle r; Client *c; - c = w->aux; + c = aux; r = client_grav(c, ZR); r.max = subpt(r.max, r.min); @@ -866,45 +884,47 @@ configreq_event(Window *w, XConfigureRequestEvent *e) { c->border = e->border_width; r.max = addpt(r.min, r.max); - cr = r; r = client_grav(c, r); - if(c->sel->area->floating) { + if(c->sel->area->floating) client_resize(c, r); - }else { + else { c->sel->floatr = r; client_configure(c); } + return false; } -static void -destroy_event(Window *w, XDestroyWindowEvent *e) { +static bool +destroy_event(Window *w, void *aux, XDestroyWindowEvent *e) { USED(w, e); - client_destroy(w->aux); + client_destroy(aux); + return false; } -static void -enter_event(Window *w, XCrossingEvent *e) { +static bool +enter_event(Window *w, void *aux, XCrossingEvent *e) { Client *c; - - c = w->aux; + + c = aux; if(e->detail != NotifyInferior) { if(e->detail != NotifyVirtual) - if(e->serial != ignoreenter && disp.focus != c) { - Dprint(DFocus, "enter_notify([%C]%s)\n", c, c->name); + if(e->serial > event_lastconfigure && disp.focus != c) { + Dprint(DFocus, "enter_notify([%#C]%s)\n", c, c->name); focus(c, false); } client_setcursor(c, cursor[CurNormal]); }else - Dprint(DFocus, "enter_notify(%C[NotifyInferior]%s)\n", c, c->name); + Dprint(DFocus, "enter_notify(%#C[NotifyInferior]%s)\n", c, c->name); + return false; } -static void -focusin_event(Window *w, XFocusChangeEvent *e) { +static bool +focusin_event(Window *w, void *aux, XFocusChangeEvent *e) { Client *c, *old; - c = w->aux; + c = aux; print_focus("focusin_event", c, c->name); @@ -914,16 +934,18 @@ focusin_event(Window *w, XFocusChangeEvent *e) { old = disp.focus; disp.focus = c; if(c != old) { + event("ClientFocus %#C\n", c); if(c->sel) frame_draw(c->sel); } + return false; } -static void -focusout_event(Window *w, XFocusChangeEvent *e) { +static bool +focusout_event(Window *w, void *aux, XFocusChangeEvent *e) { Client *c; - c = w->aux; + c = aux; if((e->mode == NotifyWhileGrabbed) && (disp.hasgrab != &c_root)) { if(disp.focus) disp.hasgrab = disp.focus; @@ -933,38 +955,39 @@ focusout_event(Window *w, XFocusChangeEvent *e) { if(c->sel) frame_draw(c->sel); } + return false; } -static void -unmap_event(Window *w, XUnmapEvent *e) { +static bool +unmap_event(Window *w, void *aux, XUnmapEvent *e) { Client *c; - - c = w->aux; - if(!e->send_event) - c->unmapped--; - client_destroy(c); + + c = aux; + if(!e->send_event && w->parent != c->framewin) + c->w.unmapped++; + if(e->send_event || c->w.unmapped < 0) + client_destroy(c); + return false; } -static void -map_event(Window *w, XMapEvent *e) { +static bool +map_event(Window *w, void *aux, XMapEvent *e) { Client *c; USED(e); - - c = w->aux; + + c = aux; if(c == selclient()) client_focus(c); + return true; } -static void -property_event(Window *w, XPropertyEvent *e) { - Client *c; +static bool +property_event(Window *w, void *aux, XPropertyEvent *e) { if(e->state == PropertyDelete) /* FIXME */ - return; - - c = w->aux; - client_prop(c, e->atom); + return true; + return client_prop(aux, e->atom); } static Handlers handlers = { @@ -1004,6 +1027,7 @@ client_setviews(Client *c, char **tags) { if(*tags) { if(!*fp || cmp > 0) { f = frame_create(c, view_create(*tags)); + Dprint(DGeneric, "%#C %p %R %R %R %C\n", c, c->sel, c->r, f->floatr, c->sel ? c->sel->floatr : ZR, c); if(f->view == selview || !c->sel) c->sel = f; kludge = c; /* FIXME */ @@ -1030,7 +1054,7 @@ bsstrcmp(const void *a, const void *b) { static int strpcmp(const void *ap, const void *bp) { char **a, **b; - + a = (char**)ap; b = (char**)bp; return strcmp(*a, *b); @@ -1044,10 +1068,10 @@ static char *badtags[] = { char* client_extratags(Client *c) { + Fmt fmt; Frame *f; char *toks[32]; char **tags; - char *s, *s2; int i; i = 0; @@ -1058,137 +1082,92 @@ client_extratags(Client *c) { toks[i] = nil; tags = comm(CLeft, toks, c->retags); - s = nil; + if(i == 1 && !c->tagre.regex && !c->tagvre.regex) { + free(tags); + return nil; + } + + fmtstrinit(&fmt); if(i > 1) - s = join(tags, "+"); + join(tags, "+", &fmt); free(tags); - if(!c->tagre.regex && !c->tagvre.regex) - return s; - if(c->tagre.regex) { - s2 = s; - s = smprint("%s+/%s/", s ? s : "", c->tagre.regex); - free(s2); - } - if(c->tagvre.regex) { - s2 = s; - s = smprint("%s-/%s/", s ? s : "", c->tagvre.regex); - free(s2); - } - return s; + if(c->tagre.regex) + fmtprint(&fmt, "+/%s/", c->tagre.regex); + if(c->tagvre.regex) + fmtprint(&fmt, "-/%s/", c->tagvre.regex); + return fmtstrflush(&fmt); } bool client_applytags(Client *c, const char *tags) { - uint i, j, k, n; - bool add, found; - char buf[512], last; + Fmt fmt; + uint i, j, k; + char buf[512]; char *toks[32]; char **p; char *cur, *s; + int add, old; buf[0] = 0; - - for(n = 0; tags[n]; n++) - if(!isspace(tags[n])) - break; - - if(tags[n] == '+' || tags[n] == '-') + if(memchr("+-^", tags[0], 4)) utflcpy(buf, c->tags, sizeof c->tags); else { refree(&c->tagre); refree(&c->tagvre); } - strlcat(buf, &tags[n], sizeof buf); - - n = 0; - add = true; - if(buf[0] == '+') - n++; - else if(buf[0] == '-') { - n++; - add = false; - } - - found = false; + strlcat(buf, tags, sizeof buf); j = 0; - while(buf[n] && n < sizeof(buf) && j < 32) { + s = buf; + old = '+'; + while((cur = mask(&s, &add, &old))) { /* Check for regex. */ - if(buf[n] == '/') { - for(i=n+1; i < sizeof(buf) - 1; i++) - if(buf[i] == '/') break; - if(buf[i] == '/') { - i++; - if(buf[i] == '+' - || buf[i] == '-' - || buf[i] == '\0') { /* Don't be lenient */ - buf[i-1] = '\0'; - if(add) - reinit(&c->tagre, buf+n+1); - else - reinit(&c->tagvre, buf+n+1); - last = buf[i]; - buf[i] = '\0'; - - found = true; - goto next; - } - } + if(cur[0] == '/') { + cur++; + *strrchr(cur, '/') = '\0'; + if(add == '+') + reinit(&c->tagre, cur); + else if(add == '-') + reinit(&c->tagvre, cur); } - - for(i = n; i < sizeof(buf) - 1; i++) - if(buf[i] == '+' - || buf[i] == '-' - || buf[i] == '\0') - break; - last = buf[i]; - buf[i] = '\0'; - - trim(buf+n, " \t/"); - - cur = nil; - if(!strcmp(buf+n, "~")) - c->floating = add; - else - if(!strcmp(buf+n, "!") || !strcmp(buf+n, "sel")) - cur = selview->name; - else - if(!Mbsearch(buf+n, badtags, bsstrcmp)) - cur = buf+n; - - if(cur && j < nelem(toks)-1) { - if(add) { - found = true; - toks[j++] = cur; - }else { - for(i = 0, k = 0; i < j; i++) - if(strcmp(toks[i], cur)) - toks[k++] = toks[i]; - j = k; + else if(!strcmp(cur, "~")) + c->floating = add ? On : Never; + else { + trim(cur, " \t\r\n"); + if(!strcmp(cur, "sel")) + cur = selview->name; + else if(Mbsearch(cur, badtags, bsstrcmp)) + continue; + + if(j < nelem(toks)-1) { + if(add == '^') + add = bsearch(cur, toks, j, sizeof *toks, bsstrcmp) ? '-' : '+'; + if(add == '+') + toks[j++] = cur; + else { + for(i = 0, k = 0; i < j; i++) + if(strcmp(toks[i], cur)) + toks[k++] = toks[i]; + j = k; + } } } - - next: - n = i + 1; - if(last == '+') - add = true; - if(last == '-') - add = false; - if(last == '\0') - break; } toks[j] = nil; qsort(toks, j, sizeof *toks, strpcmp); uniq(toks); - s = join(toks, "+"); - utflcpy(c->tags, s, sizeof c->tags); + fmtstrinit(&fmt); + join(toks, "+", &fmt); if(c->tagre.regex) - strlcatprint(c->tags, sizeof c->tags, "+/%s/", c->tagre.regex); + fmtprint(&fmt, "+/%s/", c->tagre.regex); if(c->tagvre.regex) - strlcatprint(c->tags, sizeof c->tags, "-/%s/", c->tagvre.regex); + fmtprint(&fmt, "-/%s/", c->tagvre.regex); + + s = fmtstrflush(&fmt); + utflcpy(c->tags, s, sizeof c->tags); changeprop_string(&c->w, "_WMII_TAGS", c->tags); free(s); @@ -1207,6 +1186,6 @@ client_applytags(Client *c, const char *tags) { p = comm(~0, c->retags, toks); client_setviews(c, p); free(p); - return found; + return true; } |