From c2d3eb7adf87e4ebfeea4d7cc2484b1070587e80 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Sun, 19 Oct 2008 18:46:02 -0400 Subject: [PATCH] Beginnings of better ordinal selections with Xinerama --- cmd/menu/menu.c | 8 ++++ cmd/wmii/area.c | 21 ++++++++++ cmd/wmii/column.c | 75 ++++++++++++++++++++++++++++++++-- cmd/wmii/fns.h | 13 ++++-- cmd/wmii/message.c | 100 +++++++++++++++------------------------------ cmd/wmii/screen.c | 49 ++++++++++++++++++++++ cmd/wmii/view.c | 2 +- cmd/wmii/x11.c | 8 ++++ include/x11.h | 1 + 9 files changed, 203 insertions(+), 74 deletions(-) diff --git a/cmd/menu/menu.c b/cmd/menu/menu.c index ebc4abe7..44833eab 100644 --- a/cmd/menu/menu.c +++ b/cmd/menu/menu.c @@ -251,6 +251,14 @@ kdown_event(Window *w, XKeyEvent *e) { case XK_M: menu_cmd(ACCEPT, e->state&ShiftMask); return; + case XK_a: + case XK_A: + menu_cmd(BACKWARD, LINE); + return; + case XK_e: + case XK_E: + menu_cmd(FORWARD, LINE); + return; case XK_n: case XK_N: menu_cmd(HIST, FORWARD); diff --git a/cmd/wmii/area.c b/cmd/wmii/area.c index 26e4600c..3c1e72d5 100644 --- a/cmd/wmii/area.c +++ b/cmd/wmii/area.c @@ -28,6 +28,27 @@ area_idx(Area *a) { return i; } +static Rectangle +area_rect(void *v) { + Area *a; + + a = v; + return a->r; +} + +Area* +area_find(View *v, Rectangle r, int dir) { + static Vector_ptr vec; + Area *a; + int s; + + vec.n = 0; + foreach_column(v, s, a) + vector_ppush(&vec, a); + + return findthing(r, dir, &vec, area_rect); +} + int afmt(Fmt *f) { Area *a; diff --git a/cmd/wmii/column.c b/cmd/wmii/column.c index 4947e062..b63b75b6 100644 --- a/cmd/wmii/column.c +++ b/cmd/wmii/column.c @@ -7,6 +7,8 @@ #include #include "fns.h" +static void column_resizeframe_h(Frame*, Rectangle); + char *modes[] = { [Coldefault] = "default", [Colstack] = "stack", @@ -130,13 +132,15 @@ stack_scale(Frame *first, int height) { } static void -stack_info(Frame *f, Frame **firstp, int *dyp, int *nframep) { - Frame *ft, *first; +stack_info(Frame *f, Frame **firstp, Frame **lastp, int *dyp, int *nframep) { + Frame *ft, *first, *last; int dy, nframe; nframe = 0; dy = 0; first = f; + last = f; + for(ft=f; ft && ft->collapsed; ft=ft->anext) ; if(ft && ft != f) { @@ -151,11 +155,13 @@ stack_info(Frame *f, Frame **firstp, int *dyp, int *nframep) { for(ft=f->anext; ft && !ft->collapsed; ft=ft->anext) { if(first == nil) first = ft; + last = ft; nframe++; dy += Dy(ft->colr); } if(nframep) *nframep = nframe; if(firstp) *firstp = first; + if(lastp) *lastp = last; if(dyp) *dyp = dy; } @@ -174,6 +180,66 @@ stack_count(Frame *f, int *mp) { return n; } +Frame* +stack_find(Area *a, Frame *f, int dir) { + Frame *fp; + + switch (dir) { + default: + die("not reached"); + case North: + if(f) + for(f=f->aprev; f && f->collapsed; f=f->aprev) + ; + else { + f = nil; + for(fp=a->frame; fp; fp=fp->anext) + if(!fp->collapsed) + f = fp; + } + break; + case South: + if(f) + for(f=f->anext; f && f->collapsed; f=f->anext) + ; + else + for(f=a->frame; f && f->collapsed; f=f->anext) + ; + break; + } + return f; +} + +/* TODO: Move elsewhere. */ +bool +find(Area **ap, Frame **fp, int dir) { + Rectangle r; + Frame *f; + Area *a; + + f = *fp; + a = *ap; + r = f ? f->r : a->r; + + if(dir == North || dir == South) { + *fp = stack_find(a, f, dir); + if(*fp) + return true; + *ap = area_find(a->view, r, dir); + if(!*ap) + return false; + *fp = stack_find(*ap, *fp, dir); + return *fp; + } + if(dir != East && dir != West) + die("not reached"); + *ap = area_find(a->view, r, dir); + if(!*ap) + return false; + *fp = ap[0]->sel; + return true; +} + void column_attach(Area *a, Frame *f) { Frame *first; @@ -182,7 +248,7 @@ column_attach(Area *a, Frame *f) { f->colr = a->r; if(a->sel) { - stack_info(a->sel, &first, &dy, &nframe); + stack_info(a->sel, &first, nil, &dy, &nframe); h = dy / (nframe+1); f->colr.max.y = f->colr.min.y + h; stack_scale(first, dy - h); @@ -199,7 +265,7 @@ column_detach(Frame *f) { int dy; a = f->area; - stack_info(f, &first, &dy, nil); + stack_info(f, &first, nil, &dy, nil); if(first && first == f) first = f->anext; column_remove(f); @@ -235,6 +301,7 @@ column_attachrect(Area *a, Frame *f, Rectangle r) { } column_insert(a, f, pos); column_scale(a); + column_resizeframe_h(f, r); } void diff --git a/cmd/wmii/fns.h b/cmd/wmii/fns.h index 845227e8..bb532968 100644 --- a/cmd/wmii/fns.h +++ b/cmd/wmii/fns.h @@ -13,18 +13,21 @@ # pragma varargck type "r" void #endif +#define with(type, var) \ + for(type *var=(void*)-1; var == (void*)-1; var=nil) + #define foreach_area(v, s, a) \ - Area *__anext; /* Getting ugly... */ \ + with(Area, __anext) \ for(s=0; s <= nscreens; s++) \ for((a)=(s < nscreens ? (v)->areas[s] : v->floating), __anext=(a)->next; (a); (void)(((a)=__anext) && (__anext=(a)->next))) #define foreach_column(v, s, a) \ - Area *__anext; /* Getting ugly... */ \ + with(Area, __anext) \ for(s=0; s < nscreens; s++) \ for((a)=(v)->areas[s], __anext=(a)->next; (a); (void)(((a)=__anext) && (__anext=(a)->next))) #define foreach_frame(v, s, a, f) \ - Frame *__fnext; \ + with(Frame, __fnext) \ foreach_area(v, s, a) \ for((void)(((f)=(a)->frame) && (__fnext=(f)->anext)); (f); (void)(((f)=__fnext) && (__fnext=(f)->anext))) @@ -37,6 +40,7 @@ void area_attach(Area*, Frame*); Area* area_create(View*, Area *pos, int scrn, uint w); void area_destroy(Area*); void area_detach(Frame*); +Area* area_find(View*, Rectangle, int); void area_focus(Area*); int area_idx(Area*); void area_moveto(Area*, Frame*); @@ -105,7 +109,9 @@ void column_settle(Area*); void div_draw(Divide*); void div_set(Divide*, int x); void div_update_all(void); +bool find(Area**, Frame**, int); int stack_count(Frame*, int*); +Frame* stack_find(Area*, Frame*, int); /* event.c */ void check_x_event(IxpConn*); @@ -241,6 +247,7 @@ void printevent(XEvent*); void root_init(void); /* screen.c */ +void* findthing(Rectangle, int, Vector_ptr*, Rectangle(*)(void*)); int ownerscreen(Rectangle); /* rule.c */ diff --git a/cmd/wmii/message.c b/cmd/wmii/message.c index fe64ff6e..6e037930 100644 --- a/cmd/wmii/message.c +++ b/cmd/wmii/message.c @@ -7,9 +7,16 @@ static char* msg_grow(View*, IxpMsg*); static char* msg_nudge(View*, IxpMsg*); -static char* msg_selectframe(Frame*, IxpMsg*, int); +static char* msg_selectframe(Area*, IxpMsg*, int); static char* msg_sendframe(Frame*, int, bool); +#define DIR(s) (\ + s == LUP ? North : \ + s == LDOWN ? South : \ + s == LLEFT ? West : \ + s == LRIGHT ? East : \ + (abort(), 0)) + static char Ebadcmd[] = "bad command", Ebadvalue[] = "bad value", @@ -359,6 +366,7 @@ getframe(View *v, int scrn, IxpMsg *m) { return client_viewframe(c, v); } + /* XXX: Multihead */ a = strarea(v, scrn, s); if(a == nil) { fprint(2, "a == nil\n"); @@ -601,6 +609,7 @@ message_view(View *v, IxpMsg *m) { switch(getsym(s)) { case LCOLMODE: s = msg_getword(m); + /* XXX: Multihead */ a = strarea(v, screen->idx, s); if(a == nil) /* || a->floating) */ return Ebadvalue; @@ -845,29 +854,17 @@ msg_selectarea(Area *a, IxpMsg *m) { else ap = v->firstarea; break; + case LLEFT: + case LRIGHT: case LUP: case LDOWN: case LCLIENT: - return msg_selectframe(a->sel, m, sym); - case LLEFT: - /* XXX: Multihead. */ - if(a->floating) - return Ebadvalue; - for(ap=v->firstarea; ap->next; ap=ap->next) - if(ap->next == a) break; - break; - case LRIGHT: - /* XXX: Multihead. */ - if(a->floating) - return Ebadvalue; - ap = a->next; - if(ap == nil) - ap = v->firstarea; - break; + return msg_selectframe(a, m, sym); case LTILDE: ap = v->floating; break; default: + /* XXX: Multihead */ ap = strarea(v, a->screen, s); if(!ap || ap->floating) return Ebadvalue; @@ -888,17 +885,15 @@ msg_selectarea(Area *a, IxpMsg *m) { } static char* -msg_selectframe(Frame *f, IxpMsg *m, int sym) { - Frame *fp; +msg_selectframe(Area *a, IxpMsg *m, int sym) { Client *c; - Area *a; + Frame *f, *fp; char *s; bool stack; ulong i, dy; - if(!f) - return Ebadvalue; - a = f->area; + f = a->sel; + fp = f; stack = false; if(sym == LUP || sym == LDOWN) { @@ -910,65 +905,38 @@ msg_selectframe(Frame *f, IxpMsg *m, int sym) { return Ebadvalue; } - SET(fp); - switch(sym) { - case LUP: - /* XXX: Stack. */ - if(stack) { - for(; f->aprev && f->aprev->collapsed; f=f->aprev) - ; - for(fp=a->frame; fp->anext; fp=fp->anext) - if(fp->anext == f) break; - for(; fp->aprev && fp->collapsed; fp=fp->aprev) - ; - }else - for(fp=a->frame; fp->anext; fp=fp->anext) - if(fp->anext == f) break; - break; - case LDOWN: - /* XXX: Stack. */ - if(stack) { - for(fp=f->anext; fp && fp->collapsed; fp=fp->anext) - ; - if(fp == nil) - for(fp=a->frame; fp->collapsed; fp=fp->anext) - ; - }else { - fp = f->anext; - if(fp == nil) - fp = a->frame; - } - break; - case LCLIENT: + if(sym == LCLIENT) { s = msg_getword(m); if(s == nil || !getulong(s, &i)) return "usage: select client "; c = win2client(i); if(c == nil) return "unknown client"; - fp = client_viewframe(c, f->view); - break; - default: - die("can't get here"); + f = client_viewframe(c, f->view); + if(!f) + return Ebadvalue; + } + else { + if(!find(&a, &f, DIR(sym))) + return Ebadvalue; } - if(fp == nil) - return "invalid selection"; - if(fp == f) + area_focus(a); + + if(!f) return nil; + /* XXX */ - if(fp->collapsed && !f->area->floating && f->area->mode == Coldefault) { + if(a == fp->area && f->collapsed && !f->area->floating && f->area->mode == Coldefault) { dy = Dy(f->colr); f->colr.max.y = f->colr.min.y + Dy(fp->colr); fp->colr.max.y = fp->colr.min.y + dy; column_arrange(a, false); } - if(!f->area->floating) - frame_draw_all(); - frame_focus(fp); - frame_restack(fp, nil); - if(fp->view == selview) + frame_focus(f); + frame_restack(f, nil); + if(f->view == selview) view_restack(fp->view); return nil; } diff --git a/cmd/wmii/screen.c b/cmd/wmii/screen.c index 632ae1f7..ccd9d2ce 100644 --- a/cmd/wmii/screen.c +++ b/cmd/wmii/screen.c @@ -79,6 +79,55 @@ findscreen(Rectangle rect, int direction) { } #endif +void* +findthing(Rectangle rect, int direction, Vector_ptr *vec, Rectangle (*key)(void*)) { + Rectangle isect; + Rectangle r, bestisect, bestr; + void *best, *p; + int i, n; + + best = nil; +#define frob(min, max, LT, x, y) \ + if(D##y(isect) > 0) /* If they intersect at some point on this axis */ \ + if(r.min.x LT rect.min.x) { \ + n = abs(r.max.x - rect.min.x) - abs(bestr.max.x - rect.min.x); \ + if(best == nil \ + || n == 0 && D##y(isect) > D##y(bestisect) \ + || n < 0 \ + ) { \ + best = p; \ + bestr = r; \ + bestisect = isect; \ + } \ + } + + /* Variable hell? Certainly. */ + for(i=0; i < vec->n; i++) { + p = vec->ary[i]; + r = key(p); + isect = rect_intersection(rect, r); + switch(direction) { + default: + die("not reached"); + /* Not reached */ + case West: + frob(min, max, <, x, y); + break; + case East: + frob(max, min, >, x, y); + break; + case North: + frob(min, max, <, y, x); + break; + case South: + frob(max, min, >, y, x); + break; + } + } +#undef frob + return best; +} + int ownerscreen(Rectangle r) { Rectangle isect; diff --git a/cmd/wmii/view.c b/cmd/wmii/view.c index 0d9abb8d..8be553cd 100644 --- a/cmd/wmii/view.c +++ b/cmd/wmii/view.c @@ -373,7 +373,7 @@ view_attach(View *v, Frame *f) { || group_leader(c->group) && !client_viewframe(group_leader(c->group), c->sel->view); if(!(c->w.ewmh.type & (TypeSplash|TypeDock))) { - if(newgroup) + if(newgroup && !(c->tagre.regex && regexec(c->tagre.regc, v->name, nil, 0))) frame_focus(f); else if(c->group && f->area->sel->client->group == c->group) /* XXX: Stack. */ diff --git a/cmd/wmii/x11.c b/cmd/wmii/x11.c index 1ab136f5..d259ac88 100644 --- a/cmd/wmii/x11.c +++ b/cmd/wmii/x11.c @@ -903,6 +903,14 @@ setfocus(Window *w, int mode) { XSetInputFocus(display, w->w, mode, CurrentTime); } +XWindow +getfocus(void) { + XWindow ret, revert; + + XGetInputFocus(display, &ret, &revert); + return ret; +} + /* Mouse */ Point querypointer(Window *w) { diff --git a/include/x11.h b/include/x11.h index 26ee4659..038ca2f7 100644 --- a/include/x11.h +++ b/include/x11.h @@ -208,6 +208,7 @@ Window* findwin(XWindow); void freefont(Font*); void freeimage(Image *); void freestringlist(char**); +XWindow getfocus(void); ulong getprop_long(Window*, char*, char*, ulong, long**, ulong); char* getprop_string(Window*, char*); int getprop_textlist(Window *w, char *name, char **ret[]);