wmii

git clone git://oldgit.suckless.org/wmii/
Log | Files | Refs | README | LICENSE

commit 3ee60cd19c70e9e05f9ab7a7df5072916d513edb
parent 967912b82bf32710b07b1f49937075c73306e95a
Author: Kris Maglione <jg@suckless.org>
Date:   Sat, 19 Jan 2008 22:30:37 -0500

Merge

Diffstat:
cmd/util.c | 31++++++++++++++++++++++++-------
cmd/wihack.sh | 1+
cmd/wmii/Makefile | 5++++-
cmd/wmii/area.c | 260+++++++++++--------------------------------------------------------------------
cmd/wmii/bar.c | 4++--
cmd/wmii/client.c | 182+++++++++++++++++++++++++++++++++++++++++--------------------------------------
cmd/wmii/column.c | 211+++++++++++++++++++++++++------------------------------------------------------
cmd/wmii/dat.h | 29++++++++++++++++++++++++-----
cmd/wmii/div.c | 163+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/wmii/event.c | 8++++----
cmd/wmii/ewmh.c | 30+++++++++---------------------
cmd/wmii/float.c | 144+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/wmii/fns.h | 89++++++++++++++++++++++++++++++++++++++-----------------------------------------
cmd/wmii/frame.c | 40++++++++++++++++++++++++++++++++--------
cmd/wmii/fs.c | 2+-
cmd/wmii/geom.c | 52++++++++++++++++++++++++++++++++++++++++------------
cmd/wmii/main.c | 9+++++++--
cmd/wmii/message.c | 64+++++++++++++++++++++++++++++++++++++++++++++++++++-------------
cmd/wmii/mouse.c | 212+++++++++++++++++++++++++++++++++++++++++--------------------------------------
cmd/wmii/rule.c | 67++++++++++++++++++++++++++++++++++++++++---------------------------
cmd/wmii/view.c | 153+++++++++++++++++++++++++++++++++++++++----------------------------------------
cmd/wmii/x11.c | 38+++++++++++++++++++++++++++++++++-----
cmd/wmii/xext.c | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
include/util.h | 3++-
include/x11.h | 35++++++++++++++++++++---------------
libwmii_hack/hack.c | 16++++++++++++++--
libwmii_hack/x11.c | 4----
libwmii_hack/x11.h | 2+-
man/wmiiloop.tex | 2+-
mk/hdr.mk | 8++++++--
mk/so.mk | 2+-
rc/rc.wmii.rc | 13++++++-------
32 files changed, 1125 insertions(+), 826 deletions(-)

diff --git a/cmd/util.c b/cmd/util.c @@ -46,6 +46,30 @@ fatal(const char *fmt, ...) { exit(1); } +char* +vsxprint(const char *fmt, va_list ap) { + static char* bufs[16]; + static long nbuf; + int id; + + id = nbuf++ % nelem(bufs); + if(bufs[id]) + free(bufs[id]); + bufs[id] = vsmprint(fmt, ap); + return bufs[id]; +} + +char* +sxprint(const char *fmt, ...) { + va_list ap; + char *ret; + + va_start(ap, fmt); + ret = vsxprint(fmt, ap); + va_end(ap); + return ret; +} + void _die(char *file, int line, char *msg) { fprint(2, "%s: dieing at %s:%d: %s\n", @@ -150,13 +174,6 @@ min(int a, int b) { return b; } -char * -str_nil(char *s) { - if(s) - return s; - return "<nil>"; -} - int utflcpy(char *to, const char *from, int l) { char *p; diff --git a/cmd/wihack.sh b/cmd/wihack.sh @@ -7,6 +7,7 @@ usage() { } checkarg='[ ${#@} -gt 0 ] || usage' +export WMII_HACK_TIME=$(date +%s) while [ ${#@} -gt 0 ] do diff --git a/cmd/wmii/Makefile b/cmd/wmii/Makefile @@ -8,15 +8,17 @@ TARG = wmii HFILES= dat.h fns.h LIB = ${LIBIXP} -LDFLAGS += -lm ${LIBX11} -lXext ${LIBICONV} -lregexp9 -lbio -lfmt -lutf +LDFLAGS += -lm ${LIBX11} -lXext -lXrandr ${LIBICONV} -lregexp9 -lbio -lfmt -lutf CFLAGS += ${INCX11} ${INCICONV} -DVERSION=\"${VERSION}\" \ -DIXP_NEEDAPI=86 OBJ = area \ bar \ client \ column \ + div \ event \ ewmh \ + float \ frame \ fs \ geom \ @@ -30,6 +32,7 @@ OBJ = area \ utf \ view \ x11 \ + xext \ ../util include ${ROOT}/mk/one.mk diff --git a/cmd/wmii/area.c b/cmd/wmii/area.c @@ -30,12 +30,12 @@ area_idx(Area *a) { char* area_name(Area *a) { - static char buf[16]; - + + if(a == nil) + return "<nil>"; if(a->floating) return "~"; - snprint(buf, sizeof(buf), "%d", area_idx(a)); - return buf; + return sxprint("%d", area_idx(a)); } Area* @@ -46,13 +46,13 @@ area_create(View *v, Area *pos, uint w) { int colnum; Area *a; - minwidth = Dx(screen->r)/NCOL; + minwidth = Dx(v->r)/NCOL; i = 0; - for(a = v->area; a != pos; a = a->next) - i++; + if(pos) + i = area_idx(pos); areanum = 0; - for(a = v->area; a; a = a->next) + for(a=v->area; a; a=a->next) areanum++; colnum = areanum - 1; @@ -60,19 +60,19 @@ area_create(View *v, Area *pos, uint w) { if(colnum >= 0) { w = view_newcolw(v, i); if (w == 0) - w = Dx(screen->r) / (colnum + 1); + w = Dx(v->r) / (colnum + 1); } else - w = Dx(screen->r); + w = Dx(v->r); } if(w < minwidth) w = minwidth; - if(colnum && (colnum * minwidth + w) > Dx(screen->r)) + if(colnum && (colnum * minwidth + w) > Dx(v->r)) return nil; if(pos) - view_scale(v, Dx(screen->r) - w); + view_scale(v, Dx(v->r) - w); a = emallocz(sizeof *a); a->view = v; @@ -81,10 +81,9 @@ area_create(View *v, Area *pos, uint w) { a->frame = nil; a->sel = nil; - a->r = screen->r; + a->r = v->r; a->r.min.x = 0; a->r.max.x = w; - a->r.max.y = screen->brect.min.y; if(pos) { a->next = pos->next; @@ -111,7 +110,6 @@ area_create(View *v, Area *pos, uint w) { void area_destroy(Area *a) { - Client *c; Area *ta; View *v; int idx; @@ -124,10 +122,6 @@ area_destroy(Area *a) { if(v->revert == a) v->revert = nil; - for(c=client; c; c=c->next) - if(c->revert == a) - c->revert = nil; - idx = area_idx(a); if(a->prev && !a->prev->floating) @@ -135,9 +129,6 @@ area_destroy(Area *a) { else ta = a->next; - if(a == v->colsel) - v->colsel = ta; - /* Can only destroy the floating area when destroying a * view---after destroying all columns. */ @@ -147,9 +138,9 @@ area_destroy(Area *a) { if(a->next) a->next->prev = a->prev; - if(ta && v->sel == a) { + if(ta && v->sel == a) area_focus(ta); - } + view_arrange(v); event("DestroyArea %d\n", idx); /* Deprecated */ event("DestroyColumn %d\n", idx); @@ -159,6 +150,7 @@ area_destroy(Area *a) { void area_moveto(Area *to, Frame *f) { + Rectangle tr; Area *from; assert(to->view == f->view); @@ -166,16 +158,18 @@ area_moveto(Area *to, Frame *f) { from = f->area; if(to->floating != from->floating) { - Rectangle tr; - + /* XXX: This must be changed. */ tr = f->revert; f->revert = f->r; - f->r = temp; + f->r = tr; } - f->client->revert = from; area_detach(f); area_attach(to, f); + + /* Temporary kludge. */ + if(!to->floating && to->floating != from->floating) + column_resizeframe(f, &tr); } void @@ -191,220 +185,29 @@ area_setsel(Area *a, Frame *f) { void area_attach(Area *a, Frame *f) { - uint nframe; - Frame *ft; - Client *c; - - c = f->client; f->area = a; + if(a->floating) + float_attach(a, f); + else + column_attach(a, f); - nframe = 0; - for(ft=a->frame; ft; ft=ft->anext) - nframe++; - nframe = max(nframe, 1); - - c->floating = a->floating; - if(!a->floating) { - f->r = a->r; - f->r.max.y = Dy(a->r) / n_frame; - } - - frame_insert(a->sel, f); - - if(a->floating) { - place_frame(f); - client_resize(f->client, f->r); - } - - if(!a->sel) - area_setsel(a, f); view_restack(a->view); - if(!a->floating) - column_arrange(a, False); - if(a->frame) assert(a->sel); } void area_detach(Frame *f) { - Frame *pr; - Client *c; Area *a; - View *v; a = f->area; - v = a->view; - c = f->client; - - pr = f->aprev; - frame_remove(f); - - if(!a->floating) { - if(a->frame) - column_arrange(a, False); - else { - if(v->area->next->next) - area_destroy(a); - else if((a->frame == nil) && (v->area->frame)) - area_focus(v->area); - view_arrange(v); - } - }else if(v->oldsel) - area_focus(v->oldsel); - else if(!a->frame) { - if(v->colsel->frame) - area_focus(v->colsel); - }else - assert(a->sel); - - if(a->sel == f) { - if(!pr) - pr = a->frame; - area_setsel(a, pr); - } -} -static void -bit_set(uint *field, uint width, uint x, uint y, int set) { - enum { divisor = sizeof(uint) * 8 }; - uint bx, mask; - div_t d; - - d = div(x, divisor); - bx = d.quot; - mask = 1 << d.rem; - if(set) - field[y*width + bx] |= mask; + if(a->floating) + float_detach(f); else - field[y*width + bx] &= ~mask; -} - -static Bool -bit_get(uint *field, uint width, uint x, uint y) { - enum { divisor = sizeof(uint) * 8 }; - uint bx, mask; - div_t d; - - d = div(x, divisor); - bx = d.quot; - mask = 1 << d.rem; - - return (field[y*width + bx] & mask) != 0; -} - -static void -place_frame(Frame *f) { - enum { divisor = sizeof(uint) * 8 }; - enum { dx = 8, dy = 8 }; - - static uint mwidth, mx, my; - static uint *field = nil; - Align align; - Point p1 = ZP; - Point p2 = ZP; - Rectangle *rects; - Frame *fr; - Client *c; - Area *a; - bool fit; - uint i, j, x, y, cx, cy, maxx, maxy, diff, num; - int snap; - - snap = Dy(screen->r) / 66; - num = 0; - fit = False; - align = CENTER; - - a = f->area; - c = f->client; - - if(c->trans) - return; - if(c->fullscreen || c->w.hints->position || starting) { - f->r = gravclient(c, c->r); - return; - } - if(!field) { - mx = Dx(screen->r) / dx; - my = Dy(screen->r) / dy; - mwidth = ceil((float)mx / divisor); - field = emallocz(sizeof(uint) * mwidth * my); - } - - SET(cx); - SET(cy); - memset(field, ~0, (sizeof(uint) * mwidth * my)); - for(fr=a->frame; fr; fr=fr->anext) { - if(fr == f) { - cx = Dx(f->r) / dx; - cy = Dx(f->r) / dy; - continue; - } - - if(fr->r.min.x < 0) - x = 0; - else - x = fr->r.min.x / dx; - - if(fr->r.min.y < 0) - y = 0; - else - y = fr->r.min.y / dy; - - maxx = fr->r.max.x / dx; - maxy = fr->r.max.y / dy; - for(j = y; j < my && j < maxy; j++) - for(i = x; i < mx && i < maxx; i++) - bit_set(field, mwidth, i, j, False); - } - - for(y = 0; y < my; y++) - for(x = 0; x < mx; x++) { - if(bit_get(field, mwidth, x, y)) { - for(i = x; i < mx; i++) - if(bit_get(field, mwidth, i, y) == 0) - break; - for(j = y; j < my; j++) - if(bit_get(field, mwidth, x, j) == 0) - break; - - if(((i - x) * (j - y) > (p2.x - p1.x) * (p2.y - p1.y)) - && (i - x > cx) && (j - y > cy)) - { - fit = True; - p1.x = x; - p1.y = y; - p2.x = i; - p2.y = j; - } - } - } - - if(fit) { - p1.x *= dx; - p1.y *= dy; - } - - if(!fit || (p1.x + Dx(f->r) > a->r.max.x)) { - diff = Dx(a->r) - Dx(f->r); - p1.x = a->r.min.x + (random() % max(diff, 1)); - } - - if(!fit && (p1.y + Dy(f->r) > a->r.max.y)) { - diff = Dy(a->r) - Dy(f->r); - p1.y = a->r.min.y + (random() % max(diff, 1)); - } - - p1 = subpt(p1, f->r.min); - f->r = rectaddpt(f->r, p1); - - rects = rects_of_view(a->view, &num, nil); - snap_rect(rects, num, &f->r, &align, snap); - if(rects) - free(rects); + column_detach(f); } void @@ -417,7 +220,12 @@ area_focus(Area *a) { f = a->sel; old_a = v->sel; + if(view_fullscreen_p(v) && !a->floating) + return; + v->sel = a; + if(!a->floating) + v->selcol = area_idx(a); if((old_a) && (a->floating != old_a->floating)) v->revert = old_a; diff --git a/cmd/wmii/bar.c b/cmd/wmii/bar.c @@ -149,9 +149,9 @@ bar_draw(WMScreen *s) { fill(screen->ibuf, r, def.normcolor.bg); for(nb = 0; nb < nelem(s->bar); nb++) for(b = s->bar[nb]; b; b=b->next) { - align = CENTER; + align = Center; if(b == s->bar[BarRight]) - align = EAST; + align = East; fill(screen->ibuf, b->r, b->col.bg); drawstring(screen->ibuf, def.font, b->r, align, b->text, b->col.fg); border(screen->ibuf, b->r, 1, b->col.border); diff --git a/cmd/wmii/client.c b/cmd/wmii/client.c @@ -3,9 +3,8 @@ * See LICENSE file for license details. */ #include "dat.h" +#include <assert.h> #include <ctype.h> -#include <stdlib.h> -#include <string.h> #include <X11/Xatom.h> #include "fns.h" @@ -33,10 +32,14 @@ group_init(Client *c) { XWindow w; long n; - n = getprop_long(&c->w, "WM_CLIENT_LEADER", "WINDOW", 0L, &ret, 1L); - if(n == 0) - return; - w = *ret; + w = c->w.hints->group; + if(w == 0) { + /* Not quite ICCCM compliant, but it seems to work. */ + n = getprop_long(&c->w, "WM_CLIENT_LEADER", "WINDOW", 0L, &ret, 1L); + if(n == 0) + return; + w = *ret; + } for(g=group; g; g=g->next) if(g->leader == w) @@ -91,6 +94,7 @@ Client* client_create(XWindow w, XWindowAttributes *wa) { Client **t, *c; WinAttr fwa; + Point p; c = emallocz(sizeof(Client)); c->border = wa->border_width; @@ -160,6 +164,10 @@ client_manage(Client *c) { Frame *f; char *tags; + if(Dx(c->r) == Dx(screen->r)) + if(Dy(c->r) == Dy(screen->r)) + fullscreen(c, true); + tags = getprop_string(&c->w, "_WMII_TAGS"); trans = win2client(c->trans); @@ -167,15 +175,15 @@ client_manage(Client *c) { trans = group_leader(c->group); if(tags) - utflcpy(c->tags, tags, sizeof(c->tags)); + utflcpy(c->tags, tags, sizeof c->tags); else if(trans) - utflcpy(c->tags, trans->tags, sizeof(c->tags)); + utflcpy(c->tags, trans->tags, sizeof c->tags); free(tags); - if(c->tags[0]) - apply_tags(c, c->tags); - else + /* Maybe not the best idea... */ + if(!trans || !c->tags[0]) apply_rules(c); + apply_tags(c, c->tags); if(!starting) view_update_all(); @@ -185,9 +193,9 @@ client_manage(Client *c) { || selclient() && (selclient()->group == c->group); f = c->sel; - if((f->view == screen->sel) - && (!(c->w.ewmh.type & TypeSplash)) - && newgroup) { + if(f->view == screen->sel) + if(!(c->w.ewmh.type & TypeSplash)) + if(newgroup) { if(f->area != f->view->sel) f->view->oldsel = f->view->sel; focus(c, false); @@ -210,7 +218,7 @@ void client_destroy(Client *c) { int (*handler)(Display*, XErrorEvent*); Rectangle r; - char *dummy; + char *none; Client **tc; bool hide; @@ -233,9 +241,8 @@ client_destroy(Client *c) { /* In case the client is already unmapped */ handler = XSetErrorHandler(ignoreerrors); - dummy = nil; - client_setviews(c, &dummy); - client_unmap(c, IconicState); + none = nil; + client_setviews(c, &none); sethandler(&c->w, nil); if(hide) @@ -330,6 +337,24 @@ client_grav(Client *c, Rectangle rd) { } } +bool +client_floats_p(Client *c) { + return c->trans + || c->floating + || c->fixedsize + || c->titleless + || c->borderless + || c->fullscreen + || (c->w.ewmh.type & (TypeDialog|TypeSplash|TypeDock)); +} + +Frame* +client_groupframe(Client *c, View *v) { + if(c->group && c->group->client) + return client_viewframe(c->group->client, v); + return nil; +} + Rectangle frame_hints(Frame *f, Rectangle r, Align sticky) { Rectangle or; @@ -354,16 +379,16 @@ frame_hints(Frame *f, Rectangle r, Align sticky) { } p = ZP; - if((sticky&(EAST|WEST)) == EAST) + if((sticky&(East|West)) == East) p.x = Dx(or) - Dx(r); - if((sticky&(NORTH|SOUTH)) == SOUTH) + if((sticky&(North|South)) == South) p.y = Dy(or) - Dy(r); return rectaddpt(r, p); } static void -client_setstate(Client *c, int state) { +client_setstate(Client * c, int state) { long data[] = { state, None }; changeprop_long(&c->w, "WM_STATE", "WM_STATE", data, nelem(data)); @@ -403,8 +428,10 @@ focus(Client *c, bool user) { f = c->sel; if(!f) return; + /* if(!user && c->noinput) return; + */ v = f->view; if(v != screen->sel) @@ -433,9 +460,7 @@ client_focus(Client *c) { setfocus(screen->barwin, RevertToParent); event("ClientFocus %C\n", c); - write_event("ClientFocus %C\n", c); - - XSync(display, False); + sync(); flushevents(FocusChangeMask, True); } } @@ -507,24 +532,10 @@ client_configure(Client *c) { sendevent(&c->w, false, StructureNotifyMask, (XEvent*)&e); } -static void -client_sendmessage(Client *c, char *name, char *value) { - XClientMessageEvent e; - - e.type = ClientMessage; - e.window = c->w.w; - e.message_type = xatom(name); - e.format = 32; - e.data.l[0] = xatom(value); - e.data.l[1] = xtime; - sendevent(&c->w, false, NoEventMask, (XEvent*)&e); - sync(); -} - void client_kill(Client *c, bool nice) { if(nice && (c->proto & ProtoDelete)) { - client_sendmessage(c, "WM_PROTOCOLS", "WM_DELETE_WINDOW"); + sendmessage(&c->w, "WM_PROTOCOLS", "WM_DELETE_WINDOW", 0, 0, 0); ewmh_pingclient(c); } else @@ -534,6 +545,7 @@ client_kill(Client *c, bool nice) { void fullscreen(Client *c, int fullscreen) { Frame *f; + bool wassel; if(fullscreen == Toggle) fullscreen = c->fullscreen ^ On; @@ -544,37 +556,42 @@ fullscreen(Client *c, int fullscreen) { c->fullscreen = fullscreen; ewmh_updatestate(c); - if((f = c->sel)) { - if(fullscreen) { - if(f->area->floating) - f->revert = f->r; - else { - f->r = f->revert; - area_moveto(f->view->area, f); + if(!fullscreen) + for(f=c->frame; f; f=f->cnext) { + if(f->oldarea == 0) + frame_resize(f, f->oldr); /* XXX: oldr Replace with floatr */ + else if(f->oldarea > 0) { + wassel = (f == f->area->sel); + area_moveto(view_findarea(f->view, f->oldarea, true), f); + f->revert = f->oldr; /* XXX: oldr */ + if(wassel) + frame_focus(f); } - focus(c, true); - }else - frame_resize(f, f->revert); - if(f->view == screen->sel) - view_focus(screen, f->view); + } + else { + for(f=c->frame; f; f=f->cnext) + f->oldarea = -1; + if((f = c->sel)) + if(f->view == screen->sel) + view_focus(screen, f->view); } } void -client_seturgent(Client *c, int urgent, bool write) { +client_seturgent(Client *c, bool urgent, int from) { XWMHints *wmh; - char *cwrite, *cnot; + char *cfrom, *cnot; Frame *f, *ff; Area *a; if(urgent == Toggle) urgent = c->urgent ^ On; - cwrite = (write ? "Manager" : "Client"); + cfrom = (from == UrgManager ? "Manager" : "Client"); cnot = (urgent ? "" : "Not"); if(urgent != c->urgent) { - event("%sUrgent %C %s\n", cnot, c, cwrite); + event("%sUrgent %C %s\n", cnot, c, cfrom); c->urgent = urgent; ewmh_updatestate(c); if(c->sel) { @@ -587,12 +604,12 @@ client_seturgent(Client *c, int urgent, bool write) { for(ff=a->frame; ff; ff=ff->anext) if(ff->client->urgent) break; if(urgent || ff == nil) - event("%sUrgentTag %s %s\n", cnot, cwrite, f->view->name); + event("%sUrgentTag %s %s\n", cnot, cfrom, f->view->name); } } } - if(write) { + if(from == UrgManager) { wmh = XGetWMHints(display, c->w.w); if(wmh == nil) wmh = emallocz(sizeof *wmh); @@ -681,16 +698,16 @@ client_prop(Client *c, Atom a) { char **class; int n; - if(a == xatom("WM_PROTOCOLS")) { + if(a == xatom("WM_PROTOCOLS")) c->proto = winprotocols(&c->w); - } - else if(a == xatom("_NET_WM_NAME")) { + else + if(a == xatom("_NET_WM_NAME")) goto wmname; - } - else if(a == xatom("_MOTIF_WM_HINTS")) { + else + if(a == xatom("_MOTIF_WM_HINTS")) updatemwm(c); - } - else switch (a) { + else + switch (a) { default: ewmh_prop(c, a); break; @@ -706,7 +723,7 @@ client_prop(Client *c, Atom a) { wmh = XGetWMHints(display, c->w.w); if(wmh) { c->noinput = !((wmh->flags&InputFocus) && wmh->input); - client_seturgent(c, (wmh->flags & XUrgencyHint) != 0, False); + client_seturgent(c, (wmh->flags & XUrgencyHint) != 0, UrgClient); XFree(wmh); } break; @@ -752,9 +769,6 @@ configreq_event(Window *w, XConfigureRequestEvent *e) { cr = r; r = client_grav(c, r); - if((Dx(cr) == Dx(screen->r)) && (Dy(cr) == Dy(screen->r))) - fullscreen(c, True); - if(c->sel->area->floating) { client_resize(c, r); sync(); @@ -956,7 +970,9 @@ apply_tags(Client *c, const char *tags) { j = 0; while(buf[n] && n < sizeof(buf) && j < 32) { for(i = n; i < sizeof(buf) - 1; i++) - if(buf[i] == '+' || buf[i] == '-' || buf[i] == '\0') + if(buf[i] == '+' + || buf[i] == '-' + || buf[i] == '\0') break; last = buf[i]; buf[i] = '\0'; @@ -964,7 +980,8 @@ apply_tags(Client *c, const char *tags) { cur = nil; if(!strcmp(buf+n, "~")) c->floating = add; - else if(!strcmp(buf+n, "!") || !strcmp(buf+n, "sel")) + else + if(!strcmp(buf+n, "!") || !strcmp(buf+n, "sel")) cur = screen->sel->name; else if(!Mbsearch(buf+n, badtags, bsstrcmp)) cur = buf+n; @@ -981,30 +998,25 @@ apply_tags(Client *c, const char *tags) { } } - switch(last) { - case '+': + if(last == '+') add = True; - break; - case '-': + if(last == '-') add = False; - break; - case '\0': + if(last == '\0') buf[n] = '\0'; - break; - } } if(!j) return; - qsort(toks, j, sizeof(char *), strpcmp); + qsort(toks, j, sizeof *toks, strpcmp); c->tags[0] = '\0'; for(i=0, n=0; i < j; i++) if(n == 0 || strcmp(toks[i], toks[n-1])) { if(i > 0) - strlcat(c->tags, "+", sizeof(c->tags)); - strlcat(c->tags, toks[i], sizeof(c->tags)); + strlcat(c->tags, "+", sizeof c->tags); + strlcat(c->tags, toks[i], sizeof c->tags); toks[n++] = toks[i]; } toks[n] = nil; @@ -1018,17 +1030,13 @@ void apply_rules(Client *c) { Rule *r; - if(strlen(c->tags)) - return; - if(def.tagrules.string) for(r=def.tagrules.rule; r; r=r->next) if(regexec(r->regex, c->props, nil, 0)) { apply_tags(c, r->value); - if(c->tags[0] && strcmp(c->tags, "nil")) - break; + break; } if(c->tags[0] == '\0') - apply_tags(c, "nil"); + apply_tags(c, "sel"); } diff --git a/cmd/wmii/column.c b/cmd/wmii/column.c @@ -1,18 +1,13 @@ /* Copyright ©2004-2006 Anselm R. Garbe <garbeam at gmail dot com> - * Copyright ©2006-2007 Kris Maglione <fbsdaemon@gmail.com> + * Copyright ©2006-2008 Kris Maglione <fbsdaemon@gmail.com> * See LICENSE file for license details. */ #include "dat.h" #include <assert.h> #include <math.h> -#include <string.h> #include <strings.h> #include "fns.h" -static Image *divimg, *divmask; -static CTuple divc; -static Handlers divhandler; - char *modes[] = { [Coldefault] = "default", [Colstack] = "stack", @@ -30,158 +25,87 @@ str2colmode(const char *str) { } char* -colmode2str(int i) { +colmode2str(uint i) { if(i < nelem(modes)) return modes[i]; return nil; } -static Divide* -getdiv(Divide **dp) { - WinAttr wa; - Divide *d; - - if(*dp) - return *dp; - - d = emallocz(sizeof *d); - - wa.override_redirect = True; - wa.cursor = cursor[CurDHArrow]; - wa.event_mask = - ExposureMask - | EnterWindowMask - | ButtonPressMask - | ButtonReleaseMask; - d->w = createwindow(&scr.root, Rect(0, 0, 1, 1), scr.depth, InputOutput, &wa, - CWOverrideRedirect - | CWEventMask - | CWCursor); - d->w->aux = d; - sethandler(d->w, &divhandler); - - *dp = d; - return d; -} +Area* +column_new(View *v, Area *pos, uint w) { + Area *a; -static void -mapdiv(Divide *d) { - mapwin(d->w); -} + a = area_create(v, pos, w); + if(!a) + return nil; -static void -unmapdiv(Divide *d) { - unmapwin(d->w); + view_arrange(v); + if(v == screen->sel) + view_focus(screen, v); + return a; } void -div_set(Divide *d, int x) { - Rectangle r; - - d->x = x; - r = rectaddpt(divimg->r, Pt(x - Dx(divimg->r)/2, 0)); - r.max.y = screen->brect.min.y; - - reshapewin(d->w, r); - mapdiv(d); -} - -static void -drawimg(Image *img, ulong cbg, ulong cborder) { - Point pt[6]; +column_insert(Area *a, Frame *f, Frame *pos) { - pt[0] = Pt(0, 0); - pt[1] = Pt(Dx(img->r)/2 - 1, Dx(img->r)/2 - 1); - - pt[2] = Pt(pt[1].x, Dy(img->r)); - pt[3] = Pt(Dx(img->r)/2, pt[2].y); - - pt[4] = Pt(pt[3].x, Dx(img->r)/2 - 1); - pt[5] = Pt(Dx(img->r) - 1, 0); - - fillpoly(img, pt, nelem(pt), cbg); - drawpoly(img, pt, nelem(pt), CapNotLast, 1, cborder); -} - -static void -drawdiv(Divide *d) { - copyimage(d->w, divimg->r, divimg, ZP); - setshapemask(d->w, divmask, ZP); + f->area = a; + f->client->floating = false; + f->column = area_idx(a); + frame_insert(f, pos); } -static void -update_imgs(void) { - Divide *d; - int w, h; - - w = 2 * (labelh(def.font) / 3); - w = max(w, 10); - h = Dy(screen->r); - - if(divimg) { - if(w == Dx(divimg->r) && h == Dy(divimg->r) - && !memcmp(&divc, &def.normcolor, sizeof(divc))) - return; - freeimage(divimg); - freeimage(divmask); - } - - divimg = allocimage(w, h, scr.depth); - divmask = allocimage(w, h, 1); - divc = def.normcolor; - - fill(divmask, divmask->r, 0); - drawimg(divmask, 1, 1); - drawimg(divimg, divc.bg, divc.border); - - for(d = divs; d && d->w->mapped; d = d->next) - drawdiv(d); +void +column_attach(Area *a, Frame *f) { + uint nframe; + Frame *ft; + + nframe = 0; + for(ft=a->frame; ft; ft=ft->anext) + nframe++; + nframe = max(nframe, 1); + + f->r = a->r; + f->r.max.y = Dy(a->r) / nframe; + + column_insert(a, f, a->sel); + if(a->sel == nil) + area_setsel(a, f); + column_arrange(a, false); } void -div_update_all(void) { - Divide **dp, *d; +column_remove(Frame *f, bool arrange) { + Client *c; + Frame *pr; Area *a; View *v; - update_imgs(); - - v = screen->sel; - dp = &divs; - for(a = v->area->next; a; a = a->next) { - d = getdiv(dp); - dp = &d->next; - div_set(d, a->r.min.x); + a = f->area; + v = a->view; + c = f->client; - if(!a->next) { - d = getdiv(dp); - dp = &d->next; - div_set(d, a->r.max.x); - } - } - for(d = *dp; d; d = d->next) - unmapdiv(d); -} + pr = f->aprev; -/* Div Handlers */ -static void -bdown_event(Window *w, XButtonEvent *e) { - Divide *d; + frame_remove(f); - USED(e); - - d = w->aux; - mouse_resizecol(d); -} + f->area = nil; + if(a->sel == f) { + if(!pr) + pr = a->frame; + a->sel = nil; + area_setsel(a, pr); + } -static void -expose_event(Window *w, XExposeEvent *e) { - Divide *d; - - USED(e); - - d = w->aux; - drawdiv(d); + if(a->frame) { + if(arrange) + column_arrange(a, False); + } + else { + if(v->area->next->next) + area_destroy(a); + else if(v->area->frame) + area_focus(v->area); + } } static Handlers divhandler = { @@ -197,14 +121,11 @@ column_new(View *v, Area *pos, uint w) { if(!a) return nil; - view_arrange(v); - if(v == screen->sel) - view_focus(screen, v); - return a; + column_remove(f, true); } static void -scale_column(Area *a) { +column_scale(Area *a) { Frame *f, **fp; uint minh, yoff, dy; uint ncol, nuncol; @@ -354,7 +275,7 @@ column_arrange(Area *a, bool dirty) { die("can't get here"); break; } - scale_column(a); + column_scale(a); resize: if(a->view == screen->sel) { view_restack(a->view); @@ -386,7 +307,7 @@ column_resize(Area *a, int w) { } static void -resize_colframeh(Frame *f, Rectangle *r) { +column_resizeframe_h(Frame *f, Rectangle *r) { Area *a; Frame *fn, *fp; uint minh; @@ -430,7 +351,7 @@ column_resizeframe(Frame *f, Rectangle *r) { v = a->view; maxx = r->max.x; - minw = Dx(screen->r) / NCOL; + minw = Dx(v->r) / NCOL; al = a->prev; ar = a->next; @@ -443,7 +364,7 @@ column_resizeframe(Frame *f, Rectangle *r) { if(ar) maxx = min(maxx, a->r.max.x - minw); else - maxx = min(maxx, screen->r.max.x); + maxx = min(maxx, v->r.max.x); dx = a->r.min.x - r->min.x; dw = maxx - a->r.max.x; @@ -456,7 +377,7 @@ column_resizeframe(Frame *f, Rectangle *r) { column_arrange(ar, False); } - resize_colframeh(f, r); + column_resizeframe_h(f, r); a->r.max.x = maxx; view_arrange(a->view); diff --git a/cmd/wmii/dat.h b/cmd/wmii/dat.h @@ -1,4 +1,4 @@ -/* © 2004-2006 Anselm R. Garbe <garbeam at gmail dot com> +/* Copyright ©2007-2008 Kris Maglione <jg@suckless.org> * See LICENSE file for license details. */ @@ -6,12 +6,15 @@ #define IXP_P9_STRUCTS #define IXP_NO_P9_ #include <regexp9.h> +#include <stdbool.h> #include <stdint.h> +#include <stdlib.h> +#include <string.h> #include <ixp.h> #include <util.h> #include <utf.h> #include <fmt.h> -#include "x11.h" +#include <x11.h> #define FONT "-*-fixed-medium-r-*-*-13-*-*-*-*-*-*-*" #define FOCUSCOLORS "#ffffff #335577 #447799" @@ -21,6 +24,11 @@ enum { PingTime = 10000, }; +enum { + UrgManager, + UrgClient, +}; + enum EWMHType { TypeDesktop = 1<<0, TypeDock = 1<<1, @@ -114,7 +122,6 @@ struct Bar { struct Client { Client* next; - Area* revert; Frame* frame; Frame* sel; Window w; @@ -152,13 +159,16 @@ struct Frame { Frame* aprev; Frame* snext; Frame* sprev; + Client* client; View* view; Area* area; - Client* client; + int oldarea; + int column; ushort id; bool collapsed; float ratio; Rectangle r; + Rectangle oldr; Rectangle crect; Rectangle revert; Rectangle grabbox; @@ -219,9 +229,10 @@ struct View { ushort id; Area* area; Area* sel; - Area* colsel; Area* oldsel; Area* revert; + int selcol; + Rectangle r; }; #ifndef EXTERN @@ -296,4 +307,12 @@ typedef void (*XHandler)(XEvent*); EXTERN XHandler handler[LASTEvent]; /* Misc */ +EXTERN bool starting; +EXTERN char* user; +EXTERN char* execstr; +EXTERN int debug; +EXTERN long xtime; + +#define Debug(x) if(debug&(x)) +#define Dprint(x, ...) BLOCK( Debug(x) fprint(2, __VA_ARGS__) ) diff --git a/cmd/wmii/div.c b/cmd/wmii/div.c @@ -0,0 +1,163 @@ +/* Copyright ©2006-2008 Kris Maglione <fbsdaemon@gmail.com> + * See LICENSE file for license details. + */ +#include "dat.h" +#include "fns.h" + +static Image *divimg, *divmask; +static CTuple divc; +static Handlers handlers; + +static Divide* +getdiv(Divide **dp) { + WinAttr wa; + Divide *d; + + if(*dp) + return *dp; + + d = emallocz(sizeof *d); + + wa.override_redirect = True; + wa.cursor = cursor[CurDHArrow]; + wa.event_mask = + ExposureMask + | EnterWindowMask + | ButtonPressMask + | ButtonReleaseMask; + d->w = createwindow(&scr.root, Rect(0, 0, 1, 1), scr.depth, InputOutput, &wa, + CWOverrideRedirect + | CWEventMask + | CWCursor); + d->w->aux = d; + sethandler(d->w, &handlers); + + *dp = d; + return d; +} + +static void +mapdiv(Divide *d) { + mapwin(d->w); +} + +static void +unmapdiv(Divide *d) { + unmapwin(d->w); +} + +void +div_set(Divide *d, int x) { + Rectangle r; + + d->x = x; + r = rectaddpt(divimg->r, Pt(x - Dx(divimg->r)/2, 0)); + r.max.y = screen->brect.min.y; + + reshapewin(d->w, r); + mapdiv(d); +} + +static void +drawimg(Image *img, ulong cbg, ulong cborder) { + Point pt[6]; + + pt[0] = Pt(0, 0); + pt[1] = Pt(Dx(img->r)/2 - 1, Dx(img->r)/2 - 1); + + pt[2] = Pt(pt[1].x, Dy(img->r)); + pt[3] = Pt(Dx(img->r)/2, pt[2].y); + + pt[4] = Pt(pt[3].x, Dx(img->r)/2 - 1); + pt[5] = Pt(Dx(img->r) - 1, 0); + + fillpoly(img, pt, nelem(pt), cbg); + drawpoly(img, pt, nelem(pt), CapNotLast, 1, cborder); +} + +static void +drawdiv(Divide *d) { + copyimage(d->w, divimg->r, divimg, ZP); + setshapemask(d->w, divmask, ZP); +} + +static void +update_imgs(void) { + Divide *d; + int w, h; + + w = 2 * (labelh(def.font) / 3); + w = max(w, 10); + h = Dy(screen->sel->r); + + if(divimg) { + if(w == Dx(divimg->r) && h == Dy(divimg->r) + && !memcmp(&divc, &def.normcolor, sizeof(divc))) + return; + freeimage(divimg); + freeimage(divmask); + } + + divimg = allocimage(w, h, scr.depth); + divmask = allocimage(w, h, 1); + divc = def.normcolor; + + fill(divmask, divmask->r, 0); + drawimg(divmask, 1, 1); + drawimg(divimg, divc.bg, divc.border); + + for(d = divs; d && d->w->mapped; d = d->next) + drawdiv(d); +} + +void +div_update_all(void) { + Divide **dp, *d; + Area *a; + View *v; + + update_imgs(); + + v = screen->sel; + dp = &divs; + for(a = v->area->next; a; a = a->next) { + d = getdiv(dp); + dp = &d->next; + div_set(d, a->r.min.x); + + if(!a->next) { + d = getdiv(dp); + dp = &d->next; + div_set(d, a->r.max.x); + } + } + for(d = *dp; d; d = d->next) + unmapdiv(d); +} + +/* Div Handlers */ +static void +bdown_event(Window *w, XButtonEvent *e) { + Divide *d; + + USED(e); + + d = w->aux; + mouse_resizecol(d); +} + +static void +expose_event(Window *w, XExposeEvent *e) { + Divide *d; + + USED(e); + + d = w->aux; + drawdiv(d); +} + +static Handlers handlers = { + .bdown = bdown_event, + .expose = expose_event, +}; + diff --git a/cmd/wmii/event.c b/cmd/wmii/event.c @@ -10,8 +10,10 @@ void dispatch_event(XEvent *e) { Debug(DEvent) printevent(e); - if(handler[e->type]) + if(e->type < nelem(handler) && handler[e->type]) handler[e->type](e); + else + xext_event(e); } #define handle(w, fn, ev) \ @@ -276,7 +278,7 @@ maprequest(XEvent *e) { if(wa.override_redirect) { /* Do I really want these? */ XSelectInput(display, ev->window, - (StructureNotifyMask | PropertyChangeMask)); + (StructureNotifyMask | PropertyChangeMask)); return; } if(!win2client(ev->window)) @@ -356,7 +358,5 @@ check_x_event(IxpConn *c) { while(XPending(display)) { XNextEvent(display, &ev); dispatch_event(&ev); - /* Hack to alleviate an apparant Xlib bug */ - XPending(display); } } diff --git a/cmd/wmii/ewmh.c b/cmd/wmii/ewmh.c @@ -17,22 +17,6 @@ Window *ewmhwin; #define STATE(x) xatom(State(x)) #define TYPE(x) xatom(Type(x)) -static void -senemessage(Window *w, char *name, char *value, long l2, long l3, long l4) { - XClientMessageEvent e; - - e.type = ClientMessage; - e.window = w->w; - e.message_type = xatom(name); - e.format = 32; - e.data.l[0] = xatom(value); - e.data.l[1] = xtime; - e.data.l[2] = l2; - e.data.l[3] = l3; - e.data.l[4] = l4; - sendevent(w, false, NoEventMask, (XEvent*)&e); -} - void ewmh_init(void) { WinAttr wa; @@ -143,7 +127,8 @@ ewmh_destroyclient(Client *c) { e = &c->w.ewmh; if(e->timer) - ixp_unsettimer(&srv, e->timer); + if(!ixp_unsettimer(&srv, e->timer)) + fprint(2, "Badness: %C: Can't unset timer\n", c); } static void @@ -167,18 +152,21 @@ ewmh_pingclient(Client *c) { if(e->ping) return; - senemessage(&c->w, "WM_PROTOCOLS", Net("WM_PING"), c->w.w, 0, 0); + sendmessage(&c->w, "WM_PROTOCOLS", Net("WM_PING"), c->w.w, 0, 0); e->ping = xtime++; e->timer = ixp_settimer(&srv, PingTime, pingtimeout, c); } -void +int ewmh_prop(Client *c, Atom a) { if(a == NET("WM_WINDOW_TYPE")) ewmh_getwintype(c); else if(a == NET("WM_STRUT_PARTIAL")) ewmh_getstrut(c); + else + return 0; + return 1; } typedef struct Prop Prop; @@ -336,7 +324,7 @@ ewmh_clientmessage(XClientMessageEvent *e) { fullscreen(c, action); else if(l[i] == STATE("DEMANDS_ATTENTION")) - client_seturgent(c, action, false); + client_seturgent(c, action, UrgClient); } return 1; }else @@ -415,7 +403,7 @@ ewmh_updatestate(Client *c) { int i; f = c->sel; - if(f->view != screen->sel) + if(f == nil || f->view != screen->sel) return; i = 0; diff --git a/cmd/wmii/float.c b/cmd/wmii/float.c @@ -0,0 +1,144 @@ +/* Copyright ©2006-2008 Kris Maglione <fbsdaemon@gmail.com> + * See LICENSE file for license details. + */ +#include "dat.h" +#include <sys/limits.h> +#include "fns.h" + +static void float_placeframe(Frame*); + +void +float_attach(Area *a, Frame *f) { + + f->client->floating = true; + + float_placeframe(f); + frame_insert(f, a->sel); + + if(a->sel == nil) + area_setsel(a, f); +} + +void +float_detach(Frame *f) { + Frame *pr; + Area *a, *sel; + View *v; + + v = f->view; + a = f->area; + sel = view_findarea(v, v->selcol, false); + pr = f->aprev; + + frame_remove(f); + + f->area = nil; + if(a->sel == f) { + if(!pr) + pr = a->frame; + a->sel = nil; + area_setsel(a, pr); + } + + if(v->oldsel) + area_focus(v->oldsel); + else if(!a->frame) + if(sel->frame) + area_focus(sel); +} + +static void +rect_push(Vector_rect *vec, Rectangle r) { + Rectangle *rp; + int i; + + for(i=0; i < vec->n; i++) { + rp = &vec->ary[i]; + if(rect_contains_p(*rp, r)) + return; + if(rect_contains_p(r, *rp)) { + *rp = r; + return; + } + } + vector_rpush(vec, r); +} + +static void +float_placeframe(Frame *f) { + static Vector_rect rvec, rvec2; + Vector_rect *vp, *vp2, *vptemp; + Rectangle *rp; + Rectangle r, fr; + Point dim, p; + Client *c; + Frame *ff; + Area *a; + long area, l; + int i; + + a = f->area; + c = f->client; + + if(c->trans) + return; + if(c->fullscreen || c->w.hints->position || starting) { + f->r = client_grav(c, c->r); + return; + } + + dim.x = Dx(f->r); + dim.y = Dy(f->r); + + rvec.n = 0; + rvec2.n = 0; + vp = &rvec; + vp2 = &rvec2; + + /* Find all rectangles on the floating layer into which + * the new frame would fit. (Please ignore the man behind + * the curtain). + */ + vector_rpush(vp, a->r); + for(ff=a->frame; ff; ff=ff->anext) { + fr = ff->r; + vp2->n = 0; + for(i=0; i < vp->n; i++) { + r = vp->ary[i]; + if(!rect_intersect_p(fr, r)) { + rect_push(vp2, r); + continue; + } + if(r.min.x < fr.min.x && fr.min.x - r.min.x >= dim.x) + rect_push(vp2, Rect(r.min.x, r.min.y, fr.min.x, r.max.y)); + if(r.max.x > fr.max.x && r.max.x - fr.max.x >= dim.x) + rect_push(vp2, Rect(fr.max.x, r.min.y, r.max.x, r.max.y)); + if(r.min.y < fr.min.y && fr.min.y - r.min.y >= dim.y) + rect_push(vp2, Rect(r.min.x, r.min.y, r.max.x, fr.min.y)); + if(r.max.y > fr.max.y && r.max.y - fr.max.y >= dim.y) + rect_push(vp2, Rect(r.min.x, fr.max.y, r.max.x, r.max.y)); + } + vptemp = vp; + vp = vp2; + vp2 = vptemp; + } + + if(vp->n == 0) { + p.x = random() % max(0, Dx(a->r) - dim.x); + p.y = random() % max(0, Dy(a->r) - dim.y); + }else { + area = LONG_MAX; + for(i=0; i < vp->n; i++) { + rp = &vp->ary[i]; + l = Dx(*rp) * Dy(*rp); + if(l < area) { + area = l; + p = rp->min; + } + } + } + + fr = rectsubpt(f->r, f->r.min); + f->r = rectaddpt(fr, p); +} + diff --git a/cmd/wmii/fns.h b/cmd/wmii/fns.h @@ -9,44 +9,6 @@ # pragma varargck type "r" void #endif -/* XXX: These don't belong here. */ - -typedef struct Vector_long Vector_long; -struct Vector_long { - long* ary; - long n; - long size; -}; - -static void -vector_linit(Vector_long *v) { - memset(v, 0, sizeof *v); -} - -static void -vector_lfree(Vector_long *v) { - free(v->ary); - memset(v, 0, sizeof *v); -} - -static void -vector_lpush(Vector_long *v, long val) { - if(v->n == v->size) { - if(v->size == 0) - v->size = 2; - v->size <<= 2; - v->ary = erealloc(v->ary, v->size * sizeof *v->ary); - } - v->ary[v->n++] = val; -} - -static inline void -__grr__(void) { - vector_linit(nil); - vector_lfree(nil); - vector_lpush(nil, 0); -} - /* area.c */ void area_attach(Area*, Frame*); Area* area_create(View*, Area *pos, uint w); @@ -74,6 +36,7 @@ void apply_tags(Client*, const char*); void client_configure(Client*); Client* client_create(XWindow, XWindowAttributes*); void client_destroy(Client*); +bool client_floats_p(Client*); void client_focus(Client*); void client_kill(Client*, bool); void client_manage(Client*); @@ -82,7 +45,7 @@ void client_prop(Client*, Atom); void client_reparent(Client*, Window*, Point); void client_resize(Client*, Rectangle); void client_setcursor(Client*, Cursor); -void client_seturgent(Client*, int urgent, bool write); +void client_seturgent(Client*, bool, int); void client_unmap(Client*, int state); Frame* client_viewframe(Client *c, View *v); char* clientname(Client*); @@ -96,15 +59,19 @@ Client* win2client(XWindow); Rectangle client_grav(Client*, Rectangle); /* column.c */ -char* colmode2str(int); -int str2colmode(const char*); +char* colmode2str(uint); void column_arrange(Area*, bool dirty); +void column_attach(Area*, Frame*); +void column_detach(Frame*); +void column_insert(Area*, Frame*, Frame*); Area* column_new(View*, Area *, uint); +void column_remove(Frame*, bool); void column_resize(Area*, int); void column_resizeframe(Frame*, Rectangle*); void div_draw(Divide*); void div_set(Divide*, int x); void div_update_all(void); +int str2colmode(const char*); /* event.c */ void check_x_event(IxpConn*); @@ -122,7 +89,7 @@ void ewmh_getwintype(Client*); void ewmh_init(void); void ewmh_initclient(Client*); void ewmh_pingclient(Client*); -void ewmh_prop(Client*, Atom); +int ewmh_prop(Client*, Atom); long ewmh_protocols(Window*); void ewmh_updateclient(Client*); void ewmh_updateclientlist(void); @@ -132,6 +99,10 @@ void ewmh_updatestate(Client*); void ewmh_updateview(void); void ewmh_updateviews(void); +/* float.c */ +void float_attach(Area*, Frame*); +void float_detach(Frame*); + /* frame.c */ Frame* frame_create(Client*, View*); int frame_delta_h(void); @@ -139,7 +110,7 @@ void frame_draw(Frame*); void frame_draw_all(void); void frame_focus(Frame*); uint frame_idx(Frame*); -void frame_insert(Frame *pos, Frame*); +void frame_insert(Frame*, Frame *pos); void frame_remove(Frame*); void frame_resize(Frame*, Rectangle); bool frame_restack(Frame*, Frame*); @@ -167,10 +138,13 @@ void fs_write(Ixp9Req*); void event(const char*, ...); /* geom.c */ -Cursor quad_cursor(Align); Align get_sticky(Rectangle src, Rectangle dst); -bool rect_haspoint_p(Point, Rectangle); +Cursor quad_cursor(Align); Align quadrant(Rectangle, Point); +bool rect_contains_p(Rectangle, Rectangle); +bool rect_haspoint_p(Point, Rectangle); +bool rect_intersect_p(Rectangle, Rectangle); +Rectangle rect_intersection(Rectangle, Rectangle); /* key.c */ void init_lock_keys(void); @@ -194,7 +168,8 @@ char* msg_getword(IxpMsg*); char* msg_parsecolors(IxpMsg*, CTuple*); char* msg_selectarea(Area*, IxpMsg*); char* msg_sendclient(View*, IxpMsg*, bool swap); -char* root_readctl(void); +char* readctl_root(void); +char* readctl_view(View*); Area* strarea(View*, const char*); /* mouse.c */ @@ -208,8 +183,30 @@ void trim(char *str, const char *chars); void update_rules(Rule**, const char*); /* view.c */ +void view_arrange(View*); +void view_attach(View*, Frame*); +View* view_create(const char*); +void view_destroy(View*); +Area* view_findarea(View*, int, bool); +void view_focus(WMScreen*, View*); +bool view_fullscreen_p(View*); +char* view_index(View*); +uint view_newcolw(View*, int i); +void view_restack(View*); +void view_scale(View*, int w); +Client* view_selclient(View*); +void view_select(const char*); +void client_setviews(Client*, char**); +void view_update_all(void); +Rectangle* view_rects(View*, uint *num, Frame *ignore); /* utf.c */ char* toutf8(const char*); char* toutf8n(const char*, size_t); +/* xext.c */ +void randr_event(XEvent*); +void randr_init(void); +void xext_event(XEvent*); +void xext_init(void); + diff --git a/cmd/wmii/frame.c b/cmd/wmii/frame.c @@ -35,7 +35,8 @@ frame_create(Client *c, View *v) { f->revert = f->r; c->sel = f; } - f->collapsed = False; + f->collapsed = false; + f->oldarea = -1; return f; } @@ -64,7 +65,7 @@ frame_remove(Frame *f) { } void -frame_insert(Frame *pos, Frame *f) { +frame_insert(Frame *f, Frame *pos) { Area *a; a = f->area; @@ -138,13 +139,13 @@ bdown_event(Window *w, XButtonEvent *e) { if((e->state & def.mod) == def.mod) { switch(e->button) { case Button1: - mouse_resize(c, False, CENTER); + mouse_resize(c, false, Center); focus(c, false); frame_restack(f, nil); focus(c, false); /* Blech */ break; case Button3: - mouse_resize(c, False, quadrant(f->r, Pt(e->x_root, e->y_root))); + mouse_resize(c, false, quadrant(f->r, Pt(e->x_root, e->y_root))); frame_restack(f, nil); focus(c, false); break; @@ -159,10 +160,10 @@ bdown_event(Window *w, XButtonEvent *e) { if(frame_restack(f, nil)) view_restack(f->view); else if(rect_haspoint_p(Pt(e->x, e->y), f->grabbox)) - mouse_resize(c, True, CENTER); + mouse_resize(c, true, Center); else if(f->area->floating) if(!e->subwindow && !rect_haspoint_p(Pt(e->x, e->y), f->titlebar)) - mouse_resize(c, False, quadrant(f->r, Pt(e->x_root, e->y_root))); + mouse_resize(c, false, quadrant(f->r, Pt(e->x_root, e->y_root))); if(f->client != selclient()) focus(c, false); @@ -433,6 +434,8 @@ frame_draw(Frame *f) { if(f->view != screen->sel) return; + if(f->area == nil) /* Blech. */ + return; if(f->client == screen->focus || f->client == selclient()) @@ -486,13 +489,34 @@ frame_draw(Frame *f) { r.max.y = labelh(def.font); if(f->client->floating) r.max.x -= Dx(f->grabbox); - w = drawstring(screen->ibuf, def.font, r, WEST, + w = drawstring(screen->ibuf, def.font, r, West, f->client->name, col->fg); + if(f->area->floating) { + r.min.x = r.min.x + w + 10; + r.max.x = f->titlebar.max.x + 1; + r.min.y = f->grabbox.min.y; + r.max.y = f->grabbox.max.y; + border(screen->ibuf, r, 1, col->border); + } + + /* Border increment gaps... */ + r.min.y = f->crect.min.y; + r.min.x = max(1, f->crect.min.x - 1); + r.max.x = min(fr.max.x - 1, f->crect.max.x + 1); + r.max.y = min(fr.max.y - 1, f->crect.max.y + 1); + border(screen->ibuf, r, 1, col->border); + + /* Why? Because some non-ICCCM-compliant apps feel the need to + * change the background properties of all of their ancestor windows + * in order to implement pseudo-transparency. + * What's more, the designers of X11 felt that it would be unfair to + * implementers to make it possible to detect, or forbid, such changes. + */ XSetWindowBackgroundPixmap(display, f->client->framewin->w, None); copyimage(f->client->framewin, fr, screen->ibuf, ZP); - XSync(display, False); + sync(); } void diff --git a/cmd/wmii/fs.c b/cmd/wmii/fs.c @@ -679,7 +679,7 @@ fs_read(Ixp9Req *r) { respond(r, nil); return; case FsFTctl: - buf = view_ctl(f->p.view); + buf = readctl_view(f->p.view); n = strlen(buf); write_buf(r, buf, n); respond(r, nil); diff --git a/cmd/wmii/geom.c b/cmd/wmii/geom.c @@ -10,6 +10,34 @@ rect_haspoint_p(Point pt, Rectangle r) { && (pt.y >= r.min.y) && (pt.y < r.max.y); } +bool +rect_intersect_p(Rectangle r, Rectangle r2) { + return r.min.x <= r2.max.x + && r.max.x >= r2.min.x + && r.min.y <= r2.max.y + && r.max.y >= r2.min.y; +} + +Rectangle +rect_intersection(Rectangle r, Rectangle r2) { + Rectangle ret; + + /* canonrect(ret) != ret if not intersection */ + ret.min.x = max(r.min.x, r2.min.x); + ret.max.x = min(r.max.x, r2.max.x); + ret.min.y = max(r.min.y, r2.min.y); + ret.max.y = min(r.max.y, r2.max.y); + return ret; +} + +bool +rect_contains_p(Rectangle r, Rectangle r2) { + return r2.min.x >= r.min.x + && r2.max.x <= r.max.x + && r2.min.y >= r.min.y + && r2.max.y <= r.max.y; +} + Align quadrant(Rectangle r, Point pt) { Align ret; @@ -18,13 +46,13 @@ quadrant(Rectangle r, Point pt) { ret = 0; if(pt.x >= Dx(r) * .5) - ret |= EAST; + ret |= East; if(pt.x <= Dx(r) * .5) - ret |= WEST; + ret |= West; if(pt.y <= Dy(r) * .5) - ret |= NORTH; + ret |= North; if(pt.y >= Dy(r) * .5) - ret |= SOUTH; + ret |= South; return ret; } @@ -32,13 +60,13 @@ quadrant(Rectangle r, Point pt) { Cursor quad_cursor(Align align) { switch(align) { - case NEAST: + case NEast: return cursor[CurNECorner]; - case NWEST: + case NWest: return cursor[CurNWCorner]; - case SEAST: + case SEast: return cursor[CurSECorner]; - case SWEST: + case SWest: return cursor[CurSWCorner]; default: return cursor[CurMove]; @@ -50,13 +78,13 @@ get_sticky(Rectangle src, Rectangle dst) { Align stickycorner = 0; if(src.min.x != dst.min.x && src.max.x == dst.max.x) - stickycorner |= EAST; + stickycorner |= East; else - stickycorner |= WEST; + stickycorner |= West; if(src.min.y != dst.min.y && src.max.y == dst.max.y) - stickycorner |= SOUTH; + stickycorner |= South; else - stickycorner |= NORTH; + stickycorner |= North; return stickycorner; } diff --git a/cmd/wmii/main.c b/cmd/wmii/main.c @@ -133,7 +133,8 @@ init_ns(void) { if(getuid() != st.st_uid) fatal("ns_path '%s' exists but is not owned by you", ns_path); if(st.st_mode & 077) - fatal("ns_path '%s' exists, but has group or world permissions", ns_path); + if(chmod(ns_path, st.st_mode & ~077)) + fatal("ns_path '%s' exists, but has group or world permissions", ns_path); } static void @@ -383,6 +384,9 @@ main(int argc, char *argv[]) { case 'r': wmiirc = EARGF(usage()); break; + case 'v': + print("%s", version); + exit(0); default: usage(); break; @@ -424,6 +428,7 @@ main(int argc, char *argv[]) { init_cursors(); init_lock_keys(); ewmh_init(); + xext_init(); srv.preselect = check_preselect; ixp_listen(&srv, sock, &p9srv, serve_9pcon, nil); @@ -463,11 +468,11 @@ main(int argc, char *argv[]) { screen->focus = nil; setfocus(screen->barwin, RevertToParent); + view_select("1"); scan_wins(); starting = false; - view_select("nil"); view_update_all(); ewmh_updateviews(); diff --git a/cmd/wmii/message.c b/cmd/wmii/message.c @@ -156,13 +156,13 @@ msg_getword(IxpMsg *m) { Rune r; int n; - eatrunes(m, isspacerune, 1); + eatrunes(m, isspacerune, true); ret = m->pos; - eatrunes(m, isspacerune, 0); + eatrunes(m, isspacerune, false); n = chartorune(&r, m->pos); *m->pos = '\0'; m->pos += n; - eatrunes(m, isspacerune, 1); + eatrunes(m, isspacerune, true); if(ret == m->end) return nil; @@ -285,7 +285,7 @@ message_client(Client *c, IxpMsg *m) { i = gettoggle(m); if(i == -1) return Ebadusage; - client_seturgent(c, i, True); + client_seturgent(c, i, UrgManager); break; default: return Ebadcmd; @@ -391,17 +391,55 @@ message_view(View *v, IxpMsg *m) { case LSELECT: return msg_selectarea(v->sel, m); case LSEND: - return msg_sendclient(v, m, 0); + return msg_sendclient(v, m, false); case LSWAP: - return msg_sendclient(v, m, 1); + return msg_sendclient(v, m, true); default: return Ebadcmd; } /* not reached */ } -char * -parse_colors(IxpMsg *m, CTuple *col) { +static void +printdebug(void) { + int i, j; + + for(i=0, j=0; i < nelem(debugtab); i++) + Debug(1<<i) { + if(j++ > 0) + bufprint(" "); + bufprint("%s", debugtab[i]); + } +} + +static char* +msg_debug(IxpMsg *m) { + char *opt; + int d; + char add; + + bufclear(); + while((opt = msg_getword(m))) { + add = '+'; + if(opt[0] == '+' || opt[0] == '-') + add = *opt++; + d = getdebug(opt); + if(d == -1) { + bufprint(", %s", opt); + continue; + } + if(add == '+') + debug |= 1<<d; + else + debug &= ~(1<<d); + } + if(buffer[0] != '\0') + return sxprint("Bad debug options: %s", buffer+2); + return nil; +} + +char* +msg_parsecolors(IxpMsg *m, CTuple *col) { static char Ebad[] = "bad color string"; Rune r; char c, *p; @@ -431,7 +469,7 @@ parse_colors(IxpMsg *m, CTuple *col) { *p = c; m->pos = p; - eatrunes(m, isspacerune, 1); + eatrunes(m, isspacerune, true); return nil; } @@ -596,10 +634,10 @@ msg_sendclient(View *v, IxpMsg *m, bool swap) { case LTOGGLE: if(!a->floating) to = v->area; - else if(c->revert && !c->revert->floating) - to = c->revert; + else if(f->column) + to = view_findarea(v, f->column, true); else - to = v->area->next; + to = view_findarea(v, v->selcol, true); break; default: if(!getulong(s, &i) || i == 0) @@ -657,7 +695,7 @@ msg_sendframe(Frame *f, int sym, bool swap) { frame_swap(f, fp); }else { frame_remove(f); - frame_insert(fp, f); + frame_insert(f, fp); } view_arrange(f->view); diff --git a/cmd/wmii/mouse.c b/cmd/wmii/mouse.c @@ -5,6 +5,8 @@ #include <assert.h> #include "fns.h" +/* Here be dragons. */ + enum { ButtonMask = ButtonPressMask | ButtonReleaseMask, @@ -17,15 +19,16 @@ static Handlers handlers; enum { OHoriz, OVert }; typedef struct Framewin Framewin; struct Framewin { - Window *w; - Frame *f; - Frame *fp; - Rectangle fr; - Area *ra; - Rectangle gb; - Point pt; - int or; - int n; + /* Todo... give these better names. */ + Window* w; + Rectangle grabbox; + Rectangle fprev_r; + Frame* fprev; + Frame* f; + Area* ra; + Point pt; + int orientation; + int xy; }; static Rectangle @@ -34,13 +37,13 @@ framerect(Framewin *f) { Point p; r.min = ZP; - if(f->or == OHoriz) { - r.max.x = f->n; - r.max.y = f->gb.max.y + f->gb.min.y; + if(f->orientation == OHoriz) { + r.max.x = f->xy; + r.max.y = f->grabbox.max.y + f->grabbox.min.y; r = rectsubpt(r, Pt(0, Dy(r)/2)); }else { - r.max.x = f->gb.max.x + f->gb.min.x; - r.max.y = f->n; + r.max.x = f->grabbox.max.x + f->grabbox.min.x; + r.max.y = f->xy; r = rectsubpt(r, Pt(Dx(r)/2, 0)); } r = rectaddpt(r, f->pt); @@ -54,14 +57,14 @@ framerect(Framewin *f) { } static void -frameadjust(Framewin *f, Point pt, int or, int n) { - f->or = or; - f->n = n; +frameadjust(Framewin *f, Point pt, int orientation, int xy) { + f->orientation = orientation; + f->xy = xy; f->pt = pt; } static Framewin* -framewin(Frame *f, Point pt, int or, int n) { +framewin(Frame *f, Point pt, int orientation, int n) { WinAttr wa; Framewin *fw; @@ -73,8 +76,8 @@ framewin(Frame *f, Point pt, int or, int n) { sethandler(fw->w, &handlers); fw->f = f; - fw->gb = f->grabbox; - frameadjust(fw, pt, or, n); + fw->grabbox = f->grabbox; + frameadjust(fw, pt, orientation, n); reshapewin(fw->w, framerect(fw)); mapwin(fw->w); @@ -105,8 +108,8 @@ expose_event(Window *w, XExposeEvent *e) { r = rectsubpt(w->r, w->r.min); fill(buf, r, c->bg); border(buf, r, 1, c->border); - border(buf, f->gb, 1, c->border); - border(buf, insetrect(f->gb, -f->gb.min.x), 1, c->border); + border(buf, f->grabbox, 1, c->border); + border(buf, insetrect(f->grabbox, -f->grabbox.min.x), 1, c->border); copyimage(w, r, buf, ZP); } @@ -117,8 +120,8 @@ static Handlers handlers = { static int _vsnap(Framewin *f, int y) { - if(abs(f->n - y) < Dy(f->w->r)) { - f->n = y; + if(abs(f->xy - y) < Dy(f->w->r)) { + f->xy = y; return 1; } return 0; @@ -144,38 +147,38 @@ vplace(Framewin *fw, Point pt) { r = fw->w->r; hr = Dy(r)/2; - fw->n = pt.y; + fw->xy = pt.y; for(f = a->frame; f->anext; f = f->anext) if(pt.y < f->r.max.y) break; if(!f->collapsed) { - fw->fp = f; - fw->fr = fw->fp->r; + fw->fprev = f; + fw->fprev_r = f->r; if(f == fw->f) { - fw->fp = f->aprev; - fw->fr.max = f->r.max; + fw->fprev = f->aprev; + fw->fprev_r.max = f->r.max; if(_vsnap(fw, f->r.min.y+hr)) goto done; } if(_vsnap(fw, f->r.max.y - hr)) { - fw->fr.min.y = f->r.max.y - labelh(def.font); + fw->fprev_r.min.y = f->r.max.y - labelh(def.font); goto done; } if(_vsnap(fw, f->r.min.y+Dy(r)+hr)) { - fw->fr.min.y = f->r.min.y + labelh(def.font); + fw->fprev_r.min.y = f->r.min.y + labelh(def.font); goto done; } if(f->aprev == nil || f->aprev->collapsed) _vsnap(fw, f->r.min.y); else if(_vsnap(fw, f->r.min.y-hr)) - fw->fp = f->aprev; - fw->fr.min.y = pt.y - hr; - if(fw->fp && fw->fp->anext == fw->f) - fw->fr.max = fw->f->r.max; + fw->fprev = f->aprev; + fw->fprev_r.min.y = pt.y - hr; + if(fw->fprev && fw->fprev->anext == fw->f) + fw->fprev_r.max = fw->f->r.max; goto done; } @@ -191,7 +194,7 @@ vplace(Framewin *fw, Point pt) { done: pt.x = a->r.min.x; - pt.y = fw->n; + pt.y = fw->xy; frameadjust(fw, pt, OHoriz, Dx(a->r)); reshapewin(fw->w, framerect(fw)); } @@ -202,8 +205,8 @@ hplace(Framewin *fw, Point pt) { View *v; int minw; - minw = Dx(screen->r)/NCOL; v = screen->sel; + minw = Dx(v->r)/NCOL; for(a = v->area->next; a->next; a = a->next) if(pt.x < a->r.max.x) @@ -231,7 +234,7 @@ do_managed_move(Client *c) { XEvent ev; Framewin *fw; Window *cwin; - Frame *f; + Frame *f, *fprev, *fnext; Point pt, pt2; int y; @@ -245,7 +248,7 @@ do_managed_move(Client *c) { fw = framewin(f, pt2, OHoriz, Dx(f->area->r)); r = screen->r; - r.min.y += fw->gb.min.y + Dy(fw->gb)/2; + r.min.y += fw->grabbox.min.y + Dy(fw->grabbox)/2; r.max.y = r.min.y + 1; cwin = createwindow(&scr.root, r, 0, InputOnly, &wa, 0); mapwin(cwin); @@ -274,34 +277,39 @@ horiz: switch(ev.xbutton.button) { case 1: /* TODO: Fix... Tangled, broken mess. */ - if((f->anext) && (!f->aprev || (fw->fp != f->aprev && fw->fp != f->aprev->aprev))) { - f->anext->r.min.y = f->r.min.y; - frame_resize(f->anext, f->anext->r); + fprev = f->aprev; + fnext = f->anext; + column_remove(f, false); + if(fnext + && (!fprev || (fw->fprev != fprev) + && (fw->fprev != fprev->aprev))) { + fnext->r.min.y = f->r.min.y; + frame_resize(fnext, fnext->r); } - else if(f->aprev) { - if(fw->fp == f->aprev->aprev) { - fw->fp = f->aprev->aprev; - f->aprev->r = f->r; + else if(fprev) { + if(fw->fprev == fprev->aprev) { + fw->fprev = fprev->aprev; + fprev->r = f->r; }else - f->aprev->r.max.y = f->r.max.y; - frame_resize(f->aprev, f->aprev->r); + fprev->r.max.y = f->r.max.y; + frame_resize(fprev, fprev->r); } - frame_remove(f); - f->area = fw->ra; - frame_insert(fw->fp, f); + column_insert(fw->ra, f, fw->fprev); + r = fw->fprev_r; if(f->aprev) { f->aprev->r.max.y = fw->fr.min.y; frame_resize(f->aprev, f->aprev->r); - } - else - fw->fr.min.y = f->area->r.min.y; + }else + r.min.y = f->area->r.min.y; + if(f->anext) - fw->fr.max.y = f->anext->r.min.y; + r.max.y = f->anext->r.min.y; else - fw->fr.max.y = f->area->r.max.y; - frame_resize(f, fw->fr); + r.max.y = f->area->r.max.y; + + frame_resize(f, fw->fprev_r); view_arrange(f->view); goto done; @@ -341,6 +349,7 @@ vert: if(fw->ra) { fw->ra = column_new(f->view, fw->ra, 0); area_moveto(fw->ra, f); + view_arrange(f->view); /* I hate this. */ } goto done; case 2: @@ -384,19 +393,19 @@ mouse_resizecolframe(Frame *f, Align align) { Rectangle r; Point pt, min; - assert((align&(EAST|WEST)) != (EAST|WEST)); - assert((align&(NORTH|SOUTH)) != (NORTH|SOUTH)); + assert((align&(East|West)) != (East|West)); + assert((align&(North|South)) != (North|South)); v = screen->sel; for(a = v->area->next, d = divs; a; a = a->next, d = d->next) if(a == f->area) break; - if(align&EAST) + if(align&East) d = d->next; - min.x = Dx(screen->r)/NCOL; - min.y = frame_delta_h() + labelh(def.font); - if(align&NORTH) { + min.x = Dx(v->r)/NCOL; + min.y = /*frame_delta_h() +*/ labelh(def.font); + if(align&North) { if(f->aprev) { r.min.y = f->aprev->r.min.y + min.y; r.max.y = f->r.max.y - min.y; @@ -413,7 +422,7 @@ mouse_resizecolframe(Frame *f, Align align) { r.min.y = r.max.y - 1; } } - if(align&WEST) { + if(align&West) { if(a->prev != v->area) { r.min.x = a->prev->r.min.x + min.x; r.max.x = a->r.max.x - min.x; @@ -435,7 +444,7 @@ mouse_resizecolframe(Frame *f, Align align) { mapwin(cwin); r = f->r; - if(align&NORTH) + if(align&North) r.min.y--; else r.min.y = r.max.y - 1; @@ -446,8 +455,8 @@ mouse_resizecolframe(Frame *f, Align align) { if(!grabpointer(&scr.root, cwin, cursor[CurSizing], MouseMask)) goto done; - pt.x = ((align&WEST) ? f->r.min.x : f->r.max.x); - pt.y = ((align&NORTH) ? f->r.min.y : f->r.max.y); + pt.x = ((align&West) ? f->r.min.x : f->r.max.x); + pt.y = ((align&North) ? f->r.min.y : f->r.max.y); warppointer(pt); for(;;) { @@ -462,11 +471,11 @@ mouse_resizecolframe(Frame *f, Align align) { pt.x = ev.xmotion.x_root; pt.y = ev.xmotion.y_root; - if(align&WEST) + if(align&West) r.min.x = pt.x; else r.max.x = pt.x; - r.min.y = ((align&SOUTH) ? pt.y : pt.y-1); + r.min.y = ((align&South) ? pt.y : pt.y-1); r.max.y = r.min.y+2; div_set(d, pt.x); @@ -474,22 +483,22 @@ mouse_resizecolframe(Frame *f, Align align) { break; case ButtonRelease: r = f->r; - if(align&WEST) + if(align&West) r.min.x = pt.x; else r.max.x = pt.x; - if(align&NORTH) + if(align&North) r.min.y = pt.y; else r.max.y = pt.y; column_resizeframe(f, &r); /* XXX: Magic number... */ - if(align&WEST) + if(align&West) pt.x = f->r.min.x + 4; else pt.x = f->r.max.x - 4; - if(align&NORTH) + if(align&North) pt.y = f->r.min.y + 4; else pt.y = f->r.max.y - 4; @@ -526,7 +535,7 @@ mouse_resizecol(Divide *d) { pt = querypointer(&scr.root); - minw = Dx(screen->r)/NCOL; + minw = Dx(v->r)/NCOL; r.min.x = a->r.min.x + minw; r.max.x = a->next->r.max.x - minw; r.min.y = pt.y; @@ -564,26 +573,26 @@ static void rect_morph(Rectangle *r, Point d, Align *mask) { int n; - if(*mask & NORTH) + if(*mask & North) r->min.y += d.y; - if(*mask & WEST) + if(*mask & West) r->min.x += d.x; - if(*mask & SOUTH) + if(*mask & South) r->max.y += d.y; - if(*mask & EAST) + if(*mask & East) r->max.x += d.x; if(r->min.x > r->max.x) { n = r->min.x; r->min.x = r->max.x; r->max.x = n; - *mask ^= EAST|WEST; + *mask ^= East|West; } if(r->min.y > r->max.y) { n = r->min.y; r->min.y = r->max.y; r->max.y = n; - *mask ^= NORTH|SOUTH; + *mask ^= North|South; } } @@ -639,24 +648,24 @@ snap_rect(Rectangle *rects, int num, Rectangle *r, Align *mask, int snap) { d.x = snap+1; d.y = snap+1; - if(*mask&NORTH) + if(*mask&North) d.y = snap_hline(rects, num, d.y, r, r->min.y); - if(*mask&SOUTH) + if(*mask&South) d.y = snap_hline(rects, num, d.y, r, r->max.y); - if(*mask&EAST) + if(*mask&East) d.x = snap_vline(rects, num, d.x, r, r->max.x); - if(*mask&WEST) + if(*mask&West) d.x = snap_vline(rects, num, d.x, r, r->min.x); - ret = CENTER; + ret = Center; if(abs(d.x) <= snap) - ret ^= EAST|WEST; + ret ^= East|West; else d.x = 0; if(abs(d.y) <= snap) - ret ^= NORTH|SOUTH; + ret ^= North|South; else d.y = 0; @@ -666,7 +675,7 @@ snap_rect(Rectangle *rects, int num, Rectangle *r, Align *mask, int snap) { /* Grumble... Messy... TODO: Rewrite. */ void -do_mouse_resize(Client *c, Bool opaque, Align align) { +mouse_resize(Client *c, bool grabbox, Align align) { XEvent ev; Rectangle *rects; Rectangle frect, origin; @@ -679,8 +688,11 @@ do_mouse_resize(Client *c, Bool opaque, Align align) { f = c->sel; + if(f->client->fullscreen) + return; + if(!f->area->floating) { - if(align==CENTER) + if(align==Center) do_managed_move(c); else mouse_resizecolframe(f, align); @@ -692,7 +704,7 @@ do_mouse_resize(Client *c, Bool opaque, Align align) { rects = view_rects(f->area->view, &num, c->frame); cur = quad_cursor(align); - if((align==CENTER) && !opaque) + if((align==Center) && !grabbox) cur = cursor[CurSizing]; pt = querypointer(c->framewin); @@ -707,21 +719,17 @@ do_mouse_resize(Client *c, Bool opaque, Align align) { hr = subpt(frect.max, frect.min); hr = divpt(hr, Pt(2, 2)); - if(align != CENTER) { + if(align != Center) { d = hr; - if(align&NORTH) d.y -= hr.y; - if(align&SOUTH) d.y += hr.y; - if(align&EAST) d.x += hr.x; - if(align&WEST) d.x -= hr.x; + if(align&North) d.y -= hr.y; + if(align&South) d.y += hr.y; + if(align&East) d.x += hr.x; + if(align&West) d.x -= hr.x; pt = addpt(d, f->r.min); warppointer(pt); } - else if(f->client->fullscreen) { - ungrabpointer(); - return; - } - else if(!opaque) { + else if(!grabbox) { hrx = (double)(Dx(screen->r) + Dx(frect) - 2 * labelh(def.font)) / Dx(screen->r); hry = (double)(Dy(screen->r) + Dy(frect) - 3 * labelh(def.font)) @@ -748,7 +756,7 @@ do_mouse_resize(Client *c, Bool opaque, Align align) { d.x = ev.xmotion.x_root; d.y = ev.xmotion.y_root; - if(align == CENTER && !opaque) { + if(align == Center && !grabbox) { SET(hrx); SET(hry); d.x = (d.x * hrx) - pt.x; @@ -772,7 +780,7 @@ do_mouse_resize(Client *c, Bool opaque, Align align) { case ButtonRelease: client_resize(c, frect); - if(!opaque) { + if(!grabbox) { pt = translate(c->framewin, &scr.root, Pt(Dx(frect)*rx, Dy(frect)*ry)); if(pt.y > screen->brect.min.y) diff --git a/cmd/wmii/rule.c b/cmd/wmii/rule.c @@ -6,34 +6,40 @@ #include <assert.h> #include "fns.h" -/* basic rule matching language /regex/ -> value - * regex might contain POSIX regex syntax defined in regex(3) */ -enum { - IGNORE, - REGEX, - VALUE -}; - void trim(char *str, const char *chars) { const char *cp; char *p, *q; char c; - for(cp = chars; (c = *cp); cp++) { - q = str; - for(p = q; *p; p++) - if(*p != c) - *q++ = *p; - *q = '\0'; + q = str; + for(p = str; *p; p++) { + for(cp = chars; (c = *cp); cp++) + if(*p == c) + goto nextchar; + *q++ = *p; + nextchar: + continue; } + *q = '\0'; } +/* XXX: I hate this. --KM */ void update_rules(Rule **rule, const char *data) { - int state = IGNORE; + /* basic rule matching language /regex/ -> value + * regex might contain POSIX regex syntax defined in regex(3) */ + enum { + IGNORE, + REGEX, + VALUE, + COMMENT, + }; + int state; Rule *rul; char regex[256], value[256]; + char *regex_end = regex + sizeof(regex) - 1; + char *value_end = value + sizeof(value) - 1; char *r, *v; const char *p; @@ -47,42 +53,49 @@ update_rules(Rule **rule, const char *data) { free(rul->regex); free(rul); } - for(p = data; *p; p++) + state = IGNORE; + for(p = data; (c = *p); p++) switch(state) { case IGNORE: - if(*p == '/') { + if(c == '#') + state = COMMENT; + else if(c == '/') { r = regex; state = REGEX; } - else if(*p == '>') { + else if(c == '>') { value[0] = 0; v = value; state = VALUE; } break; case REGEX: - if(*p == '/') { + if(c == '\\' && p[1] == '/') + p++; + else if(c == '/') { *r = 0; state = IGNORE; } - else - *r++ = *p; + if(r < regex_end) + *r++ = c; break; case VALUE: - if(*p == '\n' || *p == 0) { - *rule = emallocz(sizeof(Rule)); + if(c == '\n' || c == '#' || c == 0) { *v = 0; trim(value, " \t/"); + *rule = emallocz(sizeof *rule); (*rule)->regex = regcomp(regex); if((*rule)->regex) { utflcpy((*rule)->value, value, sizeof(rul->value)); rule = &(*rule)->next; - } - else free(*rule); + }else + free(*rule); state = IGNORE; + if(c == '#') + state = COMMENT; } - else - *v++ = *p; + else if(v < value_end) + *v++ = c; break; default: /* can't happen */ die("invalid state"); diff --git a/cmd/wmii/view.c b/cmd/wmii/view.c @@ -51,6 +51,8 @@ view_create(const char *name) { v = emallocz(sizeof(View)); v->id = id++; + v->r = screen->r; + v->r.max.y = screen->barwin->r.min.y; utflcpy(v->name, name, sizeof(v->name)); @@ -99,6 +101,16 @@ view_destroy(View *v) { ewmh_updateviews(); } +Area* +view_findarea(View *v, int idx, bool create) { + Area *a; + + for(a=v->area->next; a && --idx > 0; a=a->next) + if(create && a->next == nil) + return area_create(v, a, 0); + return a; +} + static void update_frame_selectors(View *v) { Area *a; @@ -111,8 +123,10 @@ update_frame_selectors(View *v) { void view_focus(WMScreen *s, View *v) { - Frame *f; Client *c; + Frame *f; + Area *a; + bool fscrn; USED(s); @@ -121,6 +135,21 @@ view_focus(WMScreen *s, View *v) { _view_select(v); update_frame_selectors(v); div_update_all(); + fscrn = false; + for(a=v->area; a; a=a->next) + for(f=a->frame; f; f=f->anext) + if(f->client->fullscreen) { + fscrn = true; + if(!f->area->floating) { + f->oldr = f->revert; + f->oldarea = area_idx(f->area); + area_moveto(v->area, f); + area_setsel(v->area, f); + }else if(f->oldarea == -1) { + f->oldr = f->r; /* XXX: oldr */ + f->oldarea = 0; + } + } for(c=client; c; c=c->next) if((f = c->sel)) { if(f->view == v) @@ -133,9 +162,12 @@ view_focus(WMScreen *s, View *v) { ewmh_updateclient(c); } - restack_view(v); - focus_area(v->sel); - draw_frames(); + view_restack(v); + if(fscrn) + area_focus(v->area); + else + area_focus(v->sel); + frame_draw_all(); sync(); XUngrabServer(display); @@ -165,15 +197,11 @@ view_attach(View *v, Frame *f) { Area *a; c = f->client; - c->revert = nil; a = v->sel; - if(c->trans || c->floating || c->fixedsize - || c->titleless || c->borderless || c->fullscreen - || (c->w.ewmh.type & (TypeDialog|TypeSplash|TypeDock))) + if(client_floats_p(c)) a = v->area; - else if(c->group && c->group->client - && (ff = client_viewframe(c->group->client, v))) + else if((ff = client_groupframe(c, v))) a = ff->area; else if(starting && v->sel->floating) a = v->area->next; @@ -228,7 +256,7 @@ view_scale(View *v, int w) { float scale; int wdiff, dx; - minwidth = Dx(screen->r)/NCOL; + minwidth = Dx(v->r)/NCOL; if(!v->area->next) return; @@ -278,7 +306,7 @@ view_arrange(View *v) { if(!v->area->next) return; - view_scale(v, Dx(screen->r)); + view_scale(v, Dx(v->r)); xoff = 0; for(a=v->area->next; a; a=a->next) { a->r.min.x = xoff; @@ -314,83 +342,20 @@ view_rects(View *v, uint *num, Frame *ignore) { return result; } -char* -view_index(View *v) { - Rectangle *r; - Frame *f; - Area *a; - int i; - - bufclear(); - for((a=v->area), (i=0); a; (a=a->next), i++) { - if(a->floating) - bufprint("# ~ %d %d\n", Dx(a->r), Dy(a->r)); - else - bufprint("# %d %d %d\n", i, a->r.min.x, Dx(a->r)); - - for(f=a->frame; f; f=f->anext) { - r = &f->r; - if(a->floating) - bufprint("~ %C %d %d %d %d %s\n", - f->client, - r->min.x, r->min.y, - Dx(*r), Dy(*r), - f->client->props); - else - bufprint("%d %C %d %d %s\n", - i, f->client, - r->min.y, Dy(*r), - f->client->props); - } - } - return buffer; -} - -char* -view_ctl(View *v) { - Area *a; - uint i; - - bufclear(); - bufprint("%s\n", v->name); - - /* select <area>[ <frame>] */ - bufprint("select %s", area_name(v->sel)); - if(v->sel->sel) - bufprint(" %d", frame_idx(v->sel->sel)); - bufprint("\n"); - - /* select client <client> */ - if(v->sel->sel) - bufprint("select client %C\n", v->sel->sel->client); - - for(a = v->area->next, i = 1; a; a = a->next, i++) - bufprint("colmode %d %s\n", i, colmode2str(a->mode)); - return buffer; -} - void view_update_all(void) { View *n, *v, *old; - int found; old = screen->sel; for(v=view; v; v=v->next) update_frame_selectors(v); - found = 0; for(v=view; v; v=n) { n=v->next; - if(v != old) { - if(empty_p(v)) - view_destroy(v); - else - found++; - } + if(v != old && empty_p(v)) + view_destroy(v); } - if(found && !strcmp(old->name, "nil") && empty_p(old)) - view_destroy(old); view_focus(screen, screen->sel); } @@ -409,9 +374,41 @@ view_newcolw(View *v, int num) { n = tokenize(toks, 16, buf, '+'); if(num < n) if(getulong(toks[num], &n)) - return Dx(screen->r) * (n / 100.0); + return Dx(v->r) * (n / 100.0); break; } return 0; } +char* +view_index(View *v) { + Rectangle *r; + Frame *f; + Area *a; + int i; + + bufclear(); + for((a=v->area), (i=0); a; (a=a->next), i++) { + if(a->floating) + bufprint("# ~ %d %d\n", Dx(a->r), Dy(a->r)); + else + bufprint("# %d %d %d\n", i, a->r.min.x, Dx(a->r)); + + for(f=a->frame; f; f=f->anext) { + r = &f->r; + if(a->floating) + bufprint("~ %C %d %d %d %d %s\n", + f->client, + r->min.x, r->min.y, + Dx(*r), Dy(*r), + f->client->props); + else + bufprint("%d %C %d %d %s\n", + i, f->client, + r->min.y, Dy(*r), + f->client->props); + } + } + return buffer; +} + diff --git a/cmd/wmii/x11.c b/cmd/wmii/x11.c @@ -8,8 +8,6 @@ #include "dat.h" #include <assert.h> #include <math.h> -#include <stdlib.h> -#include <string.h> #include <unistd.h> #include <bio.h> #include "fns.h" @@ -31,6 +29,7 @@ static MapEnt* wbucket[137]; static MapEnt* abucket[137]; +/* Rectangles/Points */ XRectangle XRect(Rectangle r) { XRectangle xr; @@ -344,6 +343,7 @@ winprotocols(Window *w) { /* Shape */ void setshapemask(Window *dst, Image *src, Point pt) { + /* Assumes that we have the shape extension... */ XShapeCombineMask (display, dst->w, ShapeBounding, pt.x, pt.y, src->image, ShapeSet); } @@ -454,7 +454,7 @@ drawstring(Image *dst, Font *font, len += min(shortened, 3); switch (align) { - case EAST: + case East: x = r.max.x - (w + (font->height / 2)); break; default: @@ -601,6 +601,22 @@ xatom(char *name) { } void +sendmessage(Window *w, char *name, char *value, long l2, long l3, long l4) { + XClientMessageEvent e; + + e.type = ClientMessage; + e.window = w->w; + e.message_type = xatom(name); + e.format = 32; + e.data.l[0] = xatom(value); + e.data.l[1] = xtime; + e.data.l[2] = l2; + e.data.l[3] = l3; + e.data.l[4] = l4; + sendevent(w, false, NoEventMask, (XEvent*)&e); +} + +void sendevent(Window *w, bool propegate, long mask, XEvent *e) { XSendEvent(display, w->w, propegate, mask, e); } @@ -836,6 +852,7 @@ void sethints(Window *w) { enum { MaxInt = ((uint)(1<<(8*sizeof(int)-1))-1) }; XSizeHints xs; + XWMHints *wmh; WinHints *h; Point p; long size; @@ -849,6 +866,13 @@ sethints(Window *w) { h->max = Pt(MaxInt, MaxInt); h->inc = Pt(1,1); + wmh = XGetWMHints(display, w->w); + if(wmh) { + if(wmh->flags&WindowGroupHint) + h->group = wmh->window_group; + free(wmh); + } + if(!XGetWMNormalHints(display, w->w, &xs, &size)) return; @@ -897,7 +921,9 @@ sethints(Window *w) { case WestGravity: p.y = 1; break; - case SouthEastGravity: case SouthGravity: case SouthWestGravity: + case SouthEastGravity: + case SouthGravity: + case SouthWestGravity: p.y = 2; break; } @@ -907,7 +933,9 @@ sethints(Window *w) { case SouthGravity: p.x = 1; break; - case NorthEastGravity: case EastGravity: case SouthEastGravity: + case NorthEastGravity: + case EastGravity: + case SouthEastGravity: p.x = 2; break; } diff --git a/cmd/wmii/xext.c b/cmd/wmii/xext.c @@ -0,0 +1,72 @@ +/* Copyright ©2008 Kris Maglione <fbsdaemon@gmail.com> + * See LICENSE file for license details. + */ +#define _X11_VISIBLE +#include "dat.h" +#include "fns.h" + +#if RANDR_MAJOR < 1 +# error XRandR versions less than 1.0 are not supported +#endif + +static void randr_screenchange(XRRScreenChangeNotifyEvent*); + +bool have_RandR; +int randr_eventbase; + +void +xext_init(void) { + randr_init(); +} + +void +xext_event(XEvent *e) { + + if(have_RandR && (ulong)(e->type - randr_eventbase) < RRNumberEvents) { + e->type -= randr_eventbase; + randr_event(e); + } +} + +void +randr_init(void) { + int errorbase, major, minor; + + have_RandR = XRRQueryExtension(display, &randr_eventbase, &errorbase); + if(have_RandR) + if(XRRQueryVersion(display, &major, &minor) && major < 1) + have_RandR = false; + if(!have_RandR) + return; + XRRSelectInput(display, scr.root.w, RRScreenChangeNotifyMask); +} + +static void +randr_screenchange(XRRScreenChangeNotifyEvent *ev) { + View *v; + Point d; + + XRRUpdateConfiguration((XEvent*)ev); + + d.x = ev->width - Dx(screen->r); + d.y = ev->height - Dy(screen->r); + for(v=view; v; v=v->next) { + v->r.max.x += d.x; + v->r.max.y += d.y; + } + screen->r = Rect(0, 0, ev->width, ev->height); + bar_resize(screen); +} + +void +randr_event(XEvent *e) { + + switch(e->type) { + default: + break; + case RRScreenChangeNotify: /* Yuck. */ + randr_screenchange((XRRScreenChangeNotifyEvent*)e); + break; + } +} + diff --git a/include/util.h b/include/util.h @@ -33,10 +33,11 @@ char* estrdup(const char*); void fatal(const char*, ...); int max(int, int); int min(int, int); -char* str_nil(char*); uint strlcat(char*, const char*, uint); +char* sxprint(const char*, ...); uint tokenize(char **, uint, char*, char); int utflcpy(char*, const char*, int); +char* vsxprint(const char*, va_list); #define die(x) \ _die(__FILE__, __LINE__, x) diff --git a/include/x11.h b/include/x11.h @@ -6,21 +6,22 @@ #ifdef _X11_VISIBLE # include <X11/Xatom.h> # include <X11/extensions/shape.h> +# include <X11/extensions/Xrandr.h> #endif #undef Window #undef Font #undef Screen enum Align { - NORTH = 0x01, - EAST = 0x02, - SOUTH = 0x04, - WEST = 0x08, - NEAST = NORTH | EAST, - NWEST = NORTH | WEST, - SEAST = SOUTH | EAST, - SWEST = SOUTH | WEST, - CENTER = NEAST | SWEST, + North = 0x01, + East = 0x02, + South = 0x04, + West = 0x08, + NEast = North | East, + NWest = North | West, + SEast = South | East, + SWest = South | West, + Center = NEast | SWest, }; typedef enum Align Align; @@ -76,13 +77,16 @@ struct Window { }; struct WinHints { - Point min, max; - Point base, baspect; - Point inc; + Point min; + Point max; + Point base; + Point baspect; + Point inc; + Point grav; Rectangle aspect; - Point grav; - bool gravstatic; - bool position; + XWindow group; + bool gravstatic; + bool position; }; struct Handlers { @@ -221,6 +225,7 @@ void warppointer(Point); Window* window(XWindow); long winprotocols(Window*); Atom xatom(char*); +void sendmessage(Window*, char*, char*, long, long, long); XRectangle XRect(Rectangle); Rectangle gravitate(Rectangle dst, Rectangle src, Point grav); Rectangle insetrect(Rectangle, int); diff --git a/libwmii_hack/hack.c b/libwmii_hack/hack.c @@ -24,6 +24,7 @@ static long ntypes; static char* tags[32]; static long ntags; static long pid; +static long stime; static char hostname[256]; static long nmsec; @@ -88,6 +89,10 @@ init(Display *d) { /* Hrm... assumes one display... */ ntags = n; free(s); } + if((s = getenv("WMII_HACK_TIME"))) { + getlong(s, &stime); + unsetenv("WMII_HACK_TIME"); + } pid = getpid(); gethostname(hostname, sizeof hostname); @@ -95,12 +100,17 @@ init(Display *d) { /* Hrm... assumes one display... */ static void setprops(Display *d, Window w) { + long *l; if(!xlib) init(d); - changeprop_long(d, w, "_NET_WM_PID", "CARDINAL", &pid, 1); - changeprop_string(d, w, "_NET_WM_CLIENT_MACHINE", hostname); + if(getprop_long(d, w, "_NET_WM_PID", "CARDINAL", 0L, &l, 1L)) + free(l); + else { + changeprop_long(d, w, "_NET_WM_PID", "CARDINAL", &pid, 1); + changeprop_string(d, w, "WM_CLIENT_MACHINE", hostname); + } /* Kludge. */ if(nmsec == 0) @@ -114,6 +124,8 @@ setprops(Display *d, Window w) { changeprop_long(d, w, "_NET_WM_WINDOW_TYPE", "ATOM", (long*)types, ntypes); if(ntags) changeprop_textlist(d, w, "_WMII_TAGS", "UTF8_STRING", tags); + if(stime) + changeprop_long(d, w, "_WMII_LAUNCH_TIME", "CARDINAL", &stime, 1); } int diff --git a/libwmii_hack/x11.c b/libwmii_hack/x11.c @@ -79,7 +79,6 @@ freestringlist(char *list[]) { } #endif -#if 0 static ulong getprop(Display *display, Window w, char *prop, char *type, Atom *actual, int *format, ulong offset, uchar **ret, ulong length) { Atom typea; @@ -102,7 +101,6 @@ getprop(Display *display, Window w, char *prop, char *type, Atom *actual, int *f } return n; } -#endif #if 0 static ulong @@ -113,7 +111,6 @@ getproperty(Display *display, Window w, char *prop, char *type, Atom *actual, ul } #endif -#if 0 static ulong getprop_long(Display *display, Window w, char *prop, char *type, ulong offset, long **ret, ulong length) { Atom actual; @@ -127,7 +124,6 @@ getprop_long(Display *display, Window w, char *prop, char *type, ulong offset, l *ret = 0; return 0; } -#endif #ifdef notdef static char** diff --git a/libwmii_hack/x11.h b/libwmii_hack/x11.h @@ -10,7 +10,7 @@ static void changeprop_textlist(Display*, Window, char*, char*, char*[]); static void changeproperty(Display*, Window, char*, char*, int width, uchar*, int); /* static void delproperty(Display*, Window, char*); */ /* static void freestringlist(char**); */ -/* static ulong getprop_long(Display*, Window, char*, char*, ulong, long**, ulong); */ +static ulong getprop_long(Display*, Window, char*, char*, ulong, long**, ulong); /* static char* getprop_string(Display*, Window, char*); */ /* static int getprop_textlist(Display*, Window, char*, char**[]); */ /* static ulong getproperty(Display*, Window, char*, char*, Atom*, ulong, uchar**, ulong); */ diff --git a/man/wmiiloop.tex b/man/wmiiloop.tex @@ -1,4 +1,4 @@ -\begin{Name}{1}{wmiiloop}{Kris Maglione}{}{wmiir} +\begin{Name}{1}{wmiiloop}{Kris Maglione}{}{wmiiloop} \Prog{wmiiloop}-VERSION \end{Name} diff --git a/mk/hdr.mk b/mk/hdr.mk @@ -22,8 +22,12 @@ all: ${COMPILE} ${<:.c=.o} $< ${LINK} $@ ${<:.c=.o} - -.rc.O .sh.O .awk.O: +.sh.O: + echo FILTER $(BASE)$< + $(FILTER) $< >$@ + sh -n $@ + chmod 0755 $@ +.rc.O .awk.O: echo FILTER $(BASE)$< $(FILTER) $< >$@ chmod 0755 $@ diff --git a/mk/so.mk b/mk/so.mk @@ -1,5 +1,5 @@ SOPTARG = $(ROOT)/lib/$(TARG) -SO = $(PTARG).so +SO = $(SOPTARG).so SONAME = $(TARG).so OFILES_PIC = ${OBJ:=.o_pic} diff --git a/rc/rc.wmii.rc b/rc/rc.wmii.rc @@ -15,8 +15,8 @@ RIGHT=l # Theme wmiifont='drift,-*-fixed-*-*-*-*-9-*-*-*-*-*-*-*' wmiifont='-*-fixed-medium-r-*-*-13-*-*-*-*-*-*-*' -wmiinormcol=`{echo '#222222 #5FBF77 #2A7F3F'} -wmiifocuscol=`{echo '#ffffff #153F1F #2A7F3F'} +wmiinormcol=`{echo '#000000 #c1c48b #81654f'} +wmiifocuscol=`{echo '#000000 #81654f #000000'} wmiibackground='#333333' # Programs @@ -24,7 +24,8 @@ WMII_TERM=(xterm) # Column Rules wmiir write /colrules <<! -/./ -> 60+40 +/gimp/ -> 17+83+41 +/./ -> 62+38 # Golden Ratio ! # Tagging Rules @@ -32,7 +33,6 @@ wmiir write /tagrules <<! /VLC/ -> ~ /XMMS.*/ -> ~ /MPlayer.*/ -> ~ -/.*/ -> sel ! # Status Bar Info @@ -101,9 +101,8 @@ fn Action { } & } -# Actions fn Action-rehash { - comm -23 <{ls $WMII_NS_DIR/proglist.* | awk -F'\.' '{print $NF}'} \ + comm -23 <{ls $WMII_NS_DIR/proglist.* >[2]/dev/null | awk -F'\.' '{print $NF}'} \ <{ps | awk '{print $2}'} | while(id=`{read}) rm $WMII_NS_DIR/proglist.$id @@ -193,7 +192,7 @@ wmiir write /ctl <<! focuscolors $wmiifocuscol normcolors $wmiinormcol ! -xsetroot -solid $WMII_BACKGROUND +xsetroot -solid $wmiibackground # Source Overrides Action overridekeys