Beginnings of better ordinal selections with Xinerama

This commit is contained in:
Kris Maglione 2008-10-19 18:46:02 -04:00
parent ffed603830
commit c2d3eb7adf
9 changed files with 203 additions and 74 deletions

View File

@ -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);

View File

@ -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;

View File

@ -7,6 +7,8 @@
#include <strings.h>
#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

View File

@ -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 */

View File

@ -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 <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;
}

View File

@ -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;

View File

@ -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. */

View File

@ -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) {

View File

@ -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[]);