commit d0a06fe945e8f0f424430ab370e2385ad9297afb
parent afe6a9b863d94d2ba854522ef4f4f62264dcea0a
Author: Kris Maglione <jg@suckless.org>
Date: Thu, 31 May 2007 21:05:59 -0400
Merge with wmii-test.
Diffstat:
66 files changed, 7125 insertions(+), 4215 deletions(-)
diff --git a/.hgsigs b/.hgsigs
@@ -0,0 +1,2 @@
+3b3ace9543175ecba98e5b3245ec39b103edc33b 0 iD8DBQBGXiI6seQZD8Aui4wRAmhLAJ4wf+TzWEk431kNN3CONMTVGK61YgCfVDWsjKlQDym+s30UMeE38hr9vv8=
+3ea520ff8668c297a5c6b667a68b3c3a1f44fec5 0 iD8DBQBGXiNCseQZD8Aui4wRAlAfAJ9jGmSOX0nZ9J8vnpnWj2bCb9/GngCfTCIKWJfcyHsmXBxniuys14ncRn8=
diff --git a/Makefile b/Makefile
@@ -6,9 +6,12 @@ PDIRS = \
rc \
man
-DIRS = libixp \
+DIRS = \
${PDIRS}
+config:
+ ROOT="${ROOT}" ${ROOT}/util/genconfig
+
include ${ROOT}/mk/dir.mk
INSTDIRS = ${PDIRS}
diff --git a/README b/README
@@ -9,21 +9,21 @@ the remote access utility.
Requirements
------------
-In order to build wmii you need the Xlib header files and libixp. Further
-dependencies are xmessage and dmenu. libixp and dmenu can be obtained from
-[1]. One of plan9port or 9base is also recommended.
+In order to build wmii you need the Xlib header files and libixp. xmessage
+and dmenu are used by the default scripts. libixp and dmenu can be obtained
+from http://suckless.org/. Either plan9port or 9base is recommended.
Installation
------------
-Edit config.mk to match your local setup. wmii is installed into
-the /usr/local hierarchy by default.
+First, edit config.mk to match your local setup, or to let us guess it, run:
+ make config
-Afterwards enter the following command to build and install wmii (if
-necessary as root):
-
- make clean install
+To build, simply run:
+ make
+To install, run the following, as root, if necessary:
+ make install
Running wmii
------------
@@ -33,12 +33,12 @@ Add the following line to your .xinitrc to start wmii using startx:
true
done
-In order to connect wmii or wmiir to a specific display, make sure that
-the DISPLAY environment variable is set correctly, e.g.:
+In order to connect wmii to a specific display, make sure that
+the DISPLAY environment variable is set correctly. For example:
- DISPLAY=foo.bar:1 wmii
+ DISPLAY=:1 wmii
-This will start wmii on display :1 of the host foo.bar.
+This will start wmii on display :1.
Configuration
@@ -49,8 +49,8 @@ The main rc.wmii script lives in PREFIX/etc/wmii-3.5/, while rc.wmii.local
goes in $HOME/.wmii-3.5/.
rc.wmii.local should contain a line containing just: '# Overrides'. You must
-set your MODKEY before this line, if you wish to change it, and define most
-functions after it.
+set your MODKEY and other configuration variables before this line, if you
+wish to change then, and define most functions after it.
Credits
-------
diff --git a/TODO b/TODO
@@ -4,11 +4,9 @@
* Switch to mk for building
4.0
-* Get rid of col modes
+* Get rid of colmodes
* (Multi line) Tag bars
-* Replace bar with master tag bar
-* New event system
* Resizable managed area
-* Sticky clients
+* Regex-based tag strings
* New dmenu(with real cursor and using Bio)
-* Depend on plan9-corelibs
+* Use libbio, libfmt, libregex9
diff --git a/cmd/Makefile b/cmd/Makefile
@@ -17,6 +17,8 @@ FILTER = sed "s|CONFPREFIX|${ETC}|g; \
s|P9PATHS|${P9PATHS}|g; \
s|AWKPATH|${AWKPATH}|g"
+CFLAGS += ${INCX11} -DVERSION=\"${VERSION}\"
+
include ${ROOT}/mk/many.mk
include ${ROOT}/mk/dir.mk
@@ -24,6 +26,5 @@ OWMIIR=wmiir.o ${OFILES} ${LIBIXP}
wmiir.O: ${OWMIIR}
${LINK} $@ ${STATIC} ${OWMIIR}
-EXCFLAGS=${INCX11}
wmii9menu.O: wmii9menu.o ${OFILES}
${LINK} $@ $*.o ${OFILES} ${LIBX11}
diff --git a/cmd/util.c b/cmd/util.c
@@ -29,7 +29,7 @@ fatal(const char *fmt, ...) {
}
/* Can't malloc */
-void
+static void
mfatal(char *name, uint size) {
const char
couldnot[] = ": fatal: Could not ",
diff --git a/cmd/wmii/Makefile b/cmd/wmii/Makefile
@@ -5,26 +5,30 @@ include ${ROOT}/mk/wmii.mk
main.c: ${ROOT}/mk/wmii.mk
TARG = wmii
-HFILES= dat.h fns.h
+HFILES= dat.h fns.h utf.h x11.h
LIB = ${LIBIXP}
-EXLDFLAGS = -lm ${LIBX11} -lXext
-EXCFLAGS = ${INCX11}
+LDFLAGS += -lm ${LIBX11} -lXext ${LIBICONV}
+CFLAGS += ${INCX11} ${INCICONV} -DVERSION=\"${VERSION}\"
OBJ = area \
bar \
client \
column \
- draw \
event \
frame \
- fs \
+ fs \
geom \
- key \
- main \
+ key \
+ main \
+ map \
+ message \
mouse \
- rule \
+ rule \
printevent\
- view \
+ utf \
+ view \
+ x11 \
../util
include ${ROOT}/mk/one.mk
+
diff --git a/cmd/wmii/area.c b/cmd/wmii/area.c
@@ -23,59 +23,70 @@ area_selclient(Area *a) {
Area *
create_area(View *v, Area *pos, uint w) {
static ushort id = 1;
- uint areanum, colnum, i;
+ uint areanum, i;
uint minwidth;
- Area *a, **p;
-
- minwidth = screen->rect.width/NCOL;
+ int colnum;
+ Area *a;
- p = &v->area;
- if(pos)
- p = &pos->next;
+ minwidth = Dx(screen->r)/NCOL;
- i = areanum = 0;
- a = v->area;
- for(; a != *p; a = a->next)
- areanum++, i++;
- for(; a; a = a->next)
+ i = 0;
+ for(a = v->area; a != pos; a = a->next)
+ i++;
+ areanum = 0;
+ for(a = v->area; a; a = a->next)
areanum++;
- colnum = max((areanum - 1), 0);
+ colnum = areanum - 1;
if(w == 0) {
- if(colnum) {
- w = newcolw_of_view(v, max(i-1, 0));
+ if(colnum >= 0) {
+ w = newcolw(v, i);
if (w == 0)
- w = screen->rect.width / (colnum + 1);
+ w = Dx(screen->r) / (colnum + 1);
}
- else w = screen->rect.width;
+ else
+ w = Dx(screen->r);
}
if(w < minwidth)
w = minwidth;
- if(colnum && (colnum * minwidth + w) > screen->rect.width)
+ if(colnum && (colnum * minwidth + w) > Dx(screen->r))
return nil;
+
if(pos)
- scale_view(v, screen->rect.width - w);
+ scale_view(v, Dx(screen->r) - w);
- a = emallocz(sizeof(Area));
+ a = emallocz(sizeof *a);
a->view = v;
a->id = id++;
- a->rect = screen->rect;
- a->rect.height = screen->rect.height - screen->brect.height;
a->mode = def.colmode;
- a->rect.width = w;
a->frame = nil;
a->sel = nil;
- a->next = *p;
- *p = a;
+
+ a->r = screen->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;
+ a->prev = pos;
+ }else {
+ a->next = v->area;
+ v->area = a;
+ }
+ if(a->prev)
+ a->prev->next = a;
+ if(a->next)
+ a->next->prev = a;
if(a == v->area)
a->floating = True;
- if((!v->sel) ||
- (v->sel->floating && v->area->next == a && a->next == nil))
+
+ if(v->sel == nil)
focus_area(a);
- if(i)
+ if(!a->floating)
write_event("CreateColumn %d\n", i);
return a;
}
@@ -91,38 +102,54 @@ destroy_area(Area *a) {
if(a->frame)
fatal("destroying non-empty area");
+
if(v->revert == a)
v->revert = nil;
+
for(c=client; c; c=c->next)
if(c->revert == a)
c->revert = nil;
- i = 1;
- for(ta=v->area; ta; ta=ta->next)
- if(ta->next == a) break;
- else i++;
- if(ta) {
- ta->next = a->next;
+ i = 0;
+ for(ta=v->area; ta != a; ta=ta->next)
+ i++;
+
+ if(a->prev)
+ ta = a->prev;
+ else
+ ta = a->next;
+
+ assert(a->prev || a->next == nil);
+ if(a->prev)
+ a->prev->next = a->next;
+ if(a->next)
+ a->next->prev = a->prev;
+
+ if(ta && v->sel == a) {
if(ta->floating && ta->next)
ta = ta->next;
- if(v->sel == a)
- focus_area(ta);
+ focus_area(ta);
}
- if(i) write_event("DestroyColumn %d\n", i);
+ write_event("DestroyColumn %d\n", i);
+
free(a);
}
void
send_to_area(Area *to, Frame *f) {
Area *from;
+
assert(to->view == f->view);
+
from = f->area;
+
if(to->floating != from->floating) {
- XRectangle temp = f->revert;
- f->revert = f->rect;
- f->rect = temp;
+ Rectangle temp = f->revert;
+ f->revert = f->r;
+ f->r = temp;
}
f->client->revert = from;
+
detach_from_area(f);
attach_to_area(to, f, True);
}
@@ -143,28 +170,27 @@ attach_to_area(Area *a, Frame *f, Bool send) {
n_frame = 0;
for(ft=a->frame; ft; ft=ft->anext)
n_frame++;
- if(n_frame == 0)
- n_frame = 1;
+ n_frame = max(n_frame, 1);
c->floating = a->floating;
- if(!a->floating)
- f->rect.height = a->rect.height / n_frame;
+ if(!a->floating) {
+ f->r = a->r;
+ f->r.max.y = Dy(a->r) / n_frame;
+ }
- insert_frame(a->sel, f, False);
+ insert_frame(a->sel, f);
- if(a->floating)
+ if(a->floating) {
place_frame(f);
+ resize_client(f->client, &f->r);
+ }
focus_frame(f, False);
- resize_frame(f, &f->rect);
restack_view(a->view);
if(!a->floating)
arrange_column(a, False);
- else
- resize_frame(f, &f->rect);
- update_client_grab(f->client);
if(a->frame)
assert(a->sel);
}
@@ -172,24 +198,21 @@ attach_to_area(Area *a, Frame *f, Bool send) {
void
detach_from_area(Frame *f) {
Frame *pr;
- Client *c;
+ Client *c, *cp;
Area *a;
View *v;
- Area *ta;
- uint i;
a = f->area;
v = a->view;
c = f->client;
- for(pr = a->frame; pr; pr = pr->anext)
- if(pr->anext == f) break;
+ pr = f->aprev;
remove_frame(f);
if(a->sel == f) {
if(!pr)
pr = a->frame;
- if((a->view->sel == a) && (pr))
+ if(pr && (v->sel == a))
focus_frame(pr, False);
else
a->sel = pr;
@@ -199,23 +222,18 @@ detach_from_area(Frame *f) {
if(a->frame)
arrange_column(a, False);
else {
- i = 0;
- for(ta=v->area; ta && ta != a; ta=ta->next)
- i++;
if(v->area->next->next)
destroy_area(a);
- else if(!a->frame && v->area->frame)
- /* focus floating area if it contains something */
+ else if((a->frame == nil) && (v->area->frame))
focus_area(v->area);
+
arrange_view(v);
}
- }
- else if(!a->frame) {
+ }else if(!a->frame) {
if(c->trans) {
- /* focus area of transient, if possible */
- Client *cl = win2client(c->trans);
- if(cl && cl->frame) {
- a = cl->sel->area;
+ cp = win2client(c->trans);
+ if(cp && cp->frame) {
+ a = cp->sel->area;
if(a->view == v)
focus_area(a);
}
@@ -227,12 +245,12 @@ detach_from_area(Frame *f) {
}
static void
-bit_twiddle(uint *field, uint width, uint x, uint y, Bool set) {
- enum { devisor = sizeof(uint) * 8 };
+bit_set(uint *field, uint width, uint x, uint y, Bool set) {
+ enum { divisor = sizeof(uint) * 8 };
uint bx, mask;
- bx = x / devisor;
- mask = 1 << x % devisor;
+ bx = x / divisor;
+ mask = 1 << x % divisor;
if(set)
field[y*width + bx] |= mask;
else
@@ -241,25 +259,26 @@ bit_twiddle(uint *field, uint width, uint x, uint y, Bool set) {
static Bool
bit_get(uint *field, uint width, uint x, uint y) {
- enum { devisor = sizeof(uint) * 8 };
+ enum { divisor = sizeof(uint) * 8 };
uint bx, mask;
- bx = x / devisor;
- mask = 1 << x % devisor;
+ bx = x / divisor;
+ mask = 1 << x % divisor;
return (field[y*width + bx] & mask) != 0;
}
static void
place_frame(Frame *f) {
- enum { devisor = sizeof(uint) * 8 };
+ enum { divisor = sizeof(uint) * 8 };
enum { dx = 8, dy = 8 };
+
static uint mwidth, mx, my;
static uint *field = nil;
- BlitzAlign align;
- XPoint p1 = {0, 0};
- XPoint p2 = {0, 0};
- XRectangle *rects;
+ Align align;
+ Point p1 = ZP;
+ Point p2 = ZP;
+ Rectangle *rects;
Frame *fr;
Client *c;
Area *a;
@@ -267,7 +286,7 @@ place_frame(Frame *f) {
uint i, j, x, y, cx, cy, maxx, maxy, diff, num;
int snap;
- snap = screen->rect.height / 66;
+ snap = Dy(screen->r) / 66;
num = 0;
fit = False;
align = CENTER;
@@ -277,43 +296,52 @@ place_frame(Frame *f) {
if(c->trans)
return;
- if(c->rect.width >= a->rect.width
- || c->rect.height >= a->rect.height
- || c->size.flags & USPosition
- || c->size.flags & PPosition)
+ if(c->fullscreen || c->w.hints->position || starting) {
+ f->r = gravclient(c, c->w.r);
return;
+ }
if(!field) {
- mx = screen->rect.width / dx;
- my = screen->rect.height / dy;
- mwidth = ceil((float)mx / devisor);
+ mx = Dx(screen->r) / dx;
+ my = Dy(screen->r) / dy;
+ mwidth = ceil((float)mx / divisor);
field = emallocz(sizeof(uint) * mwidth * my);
}
+
memset(field, ~0, (sizeof(uint) * mwidth * my));
for(fr=a->frame; fr; fr=fr->anext) {
if(fr == f) {
- cx = f->rect.width / dx;
- cy = f->rect.height / dy;
+ cx = Dx(f->r) / dx;
+ cy = Dx(f->r) / dy;
continue;
}
- if(fr->rect.x < 0)
+
+ if(fr->r.min.x < 0)
x = 0;
else
- x = fr->rect.x / dx;
- if(fr->rect.y < 0)
+ x = fr->r.min.x / dx;
+
+ if(fr->r.min.y < 0)
y = 0;
else
- y = fr->rect.y / dy;
- maxx = r_east(&fr->rect) / dx;
- maxy = r_south(&fr->rect) / dy;
+ 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_twiddle(field, mwidth, i, j, False);
+ 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) && bit_get(field, mwidth, i, y); i++);
- for(j = y; (j < my) && bit_get(field, mwidth, x, j); j++);
+ 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))
{
@@ -325,25 +353,27 @@ place_frame(Frame *f) {
}
}
}
+
if(fit) {
p1.x *= dx;
p1.y *= dy;
}
- if(fit && (p1.x + f->rect.width < r_south(&a->rect)))
- f->rect.x = p1.x;
- else {
- diff = a->rect.width - f->rect.width;
- f->rect.x = a->rect.x + (random() % (diff ? diff : 1));
+
+ 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 + f->rect.height < (r_south(&a->rect))))
- f->rect.y = p1.y;
- else {
- diff = a->rect.height - f->rect.height;
- f->rect.y = a->rect.y + (random() % (diff ? 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->rect, &align, snap);
+ snap_rect(rects, num, &f->r, &align, snap);
if(rects)
free(rects);
}
@@ -361,9 +391,8 @@ focus_area(Area *a) {
v->sel = a;
- if((old_a)
- && (a->floating != old_a->floating))
- v->revert = old_a;
+ if((old_a) && (a->floating != old_a->floating))
+ v->revert = old_a;
if(v != screen->sel)
return;
@@ -377,71 +406,9 @@ focus_area(Area *a) {
i = 0;
for(a = v->area; a != v->sel; a = a->next)
i++;
- if(i)
- write_event("ColumnFocus %d\n", i);
- else
+ if(a->floating)
write_event("FocusFloating\n");
- if(a->frame)
- write_event("ClientFocus 0x%x\n", a->sel->client->win);
- }
-}
-
-char *
-select_area(Area *a, char *arg) {
- Area *new;
- uint i;
- Frame *p, *f;
- View *v;
- static char Ebadvalue[] = "bad value";
-
- v = a->view;
- f = a->sel;
- if(!strncmp(arg, "toggle", 7)) {
- if(!a->floating)
- new = v->area;
- else if(v->revert)
- new = v->revert;
else
- new = v->area->next;
- } else if(!strncmp(arg, "left", 5)) {
- if(a->floating)
- return Ebadvalue;
- for(new=v->area->next; new->next; new=new->next)
- if(new->next == a) break;
- } else if(!strncmp(arg, "right", 5)) {
- if(a->floating)
- return Ebadvalue;
- new = a->next ? a->next : v->area->next;
- }
- else if(!strncmp(arg, "up", 3)) {
- if(!f)
- return Ebadvalue;
- for(p=a->frame; p->anext; p=p->anext)
- if(p->anext == f) break;
- goto focus_frame;
- }
- else if(!strncmp(arg, "down", 5)) {
- if(!f)
- return Ebadvalue;
- p = f->anext ? f->anext : a->frame;
- goto focus_frame;
- }
- else if(!strncmp(arg, "~", 2)) {
- new = v->area;
- }
- else {
- if(sscanf(arg, "%u", &i) != 1 || i == 0)
- return Ebadvalue;
- for(new=v->area->next; new->next; new=new->next)
- if(!--i) break;
+ write_event("ColumnFocus %d\n", i);
}
- focus_area(new);
- return nil;
-
-focus_frame:
- focus_frame(p, False);
- frame_to_top(p);
- if(v == screen->sel)
- restack_view(v);
- return nil;
}
diff --git a/cmd/wmii/bar.c b/cmd/wmii/bar.c
@@ -2,20 +2,49 @@
* Copyright ©2006-2007 Kris Maglione <fbsdaemon@gmail.com>
* See LICENSE file for license details.
*/
+#include <stdio.h>
#include <string.h>
#include <util.h>
#include "dat.h"
#include "fns.h"
-Bar *free_bars = nil;
+static Handlers handlers;
+static Bar *free_bars;
+
+void
+initbar(WMScreen *s) {
+ WinAttr wa;
+
+ s->brect = s->r;
+ s->brect.min.y = s->brect.max.y - labelh(def.font);
+
+ wa.override_redirect = 1;
+ wa.background_pixmap = ParentRelative;
+ wa.event_mask =
+ ExposureMask
+ | ButtonPressMask
+ | ButtonReleaseMask
+ | FocusChangeMask
+ | SubstructureRedirectMask
+ | SubstructureNotifyMask;
+
+ s->barwin = createwindow(&scr.root, s->brect, scr.depth, InputOutput, &wa,
+ CWOverrideRedirect
+ | CWBackPixmap
+ | CWEventMask);
+ sethandler(s->barwin, &handlers);
+ mapwin(s->barwin);
+}
Bar *
-create_bar(Bar **b_link, char *name) {
+create_bar(Bar **bp, char *name) {
static uint id = 1;
- Bar **i, *b = bar_of_name(*b_link, name);;
+ Bar *b;
+ b = bar_of_name(*bp, name);;
if(b)
return b;
+
if(free_bars) {
b = free_bars;
free_bars = b->next;
@@ -23,26 +52,28 @@ create_bar(Bar **b_link, char *name) {
}
else
b = emallocz(sizeof(Bar));
+
b->id = id++;
strncpy(b->name, name, sizeof(b->name));
- b->brush = screen->bbrush;
- b->brush.color = def.normcolor;
- for(i = b_link; *i; i = &(*i)->next)
- if(strcmp((*i)->name, name) >= 0)
+ b->col = def.normcolor;
+
+ for(; *bp; bp = &(*bp)->next)
+ if(strcmp((*bp)->name, name) >= 0)
break;
- b->next = *i;
- *i = b;
+ b->next = *bp;
+ *bp = b;
return b;
}
void
-destroy_bar(Bar **b_link, Bar *b) {
+destroy_bar(Bar **bp, Bar *b) {
Bar **p;
- for(p = b_link; *p; p = &(*p)->next)
+ for(p = bp; *p; p = &(*p)->next)
if(*p == b) break;
*p = b->next;
+
b->next = free_bars;
free_bars = b;
}
@@ -51,12 +82,12 @@ void
resize_bar(WMScreen *s) {
View *v;
- s->brect = s->rect;
- s->brect.height = labelh(&def.font);
- s->brect.y = s->rect.height - s->brect.height;
+ s->brect = s->r;
+ s->brect.min.y = s->brect.max.y - labelh(def.font);
+
+ reshapewin(s->barwin, s->brect);
- XMoveResizeWindow(blz.dpy, s->barwin, s->brect.x, s->brect.y, s->brect.width, s->brect.height);
- XSync(blz.dpy, False);
+ XSync(display, False);
draw_bar(s);
for(v = view; v; v = v->next)
arrange_view(v);
@@ -64,74 +95,127 @@ resize_bar(WMScreen *s) {
void
draw_bar(WMScreen *s) {
+ Bar *b, *tb, *largest, **pb;
+ Rectangle r;
+ Align align;
uint width, tw, nb, size;
float shrink;
- Bar *b, *tb, *largest, **pb;
-
- draw_tile(&s->bbrush);
- if(!s->bar[BarLeft] && !s->bar[BarRight])
- goto MapBar;
largest = b = tb = nil;
tw = width = nb = size = 0;
for(nb = 0; nb < nelem(s->bar); nb++)
for(b = s->bar[nb]; b; b=b->next) {
- b->brush.rect.x = b->brush.rect.y = 0;
- b->brush.rect.width = def.font.height & ~1;
+ b->r.min = ZP;
+ b->r.max.y = Dy(s->brect);
+ b->r.max.x = def.font->height & ~1;
if(b->text && strlen(b->text))
- b->brush.rect.width += textwidth(b->brush.font, b->text);
- b->brush.rect.height = s->brect.height;
- width += b->brush.rect.width;
+ b->r.max.x += textwidth(def.font, b->text);
+
+ width += Dx(b->r);
}
+
/* Not enough room. Shrink bars until they all fit */
- if(width > s->brect.width) {
+ if(width > Dx(s->brect)) {
for(nb = 0; nb < nelem(s->bar); nb++)
for(b = s->bar[nb]; b; b=b->next) {
for(pb = &largest; *pb; pb = &(*pb)->smaller)
- if((*pb)->brush.rect.width < b->brush.rect.width)
+ if(Dx((*pb)->r) < Dx(b->r))
break;
b->smaller = *pb;
*pb = b;
}
for(tb = largest; tb; tb = tb->smaller) {
- width -= tb->brush.rect.width;
- tw += tb->brush.rect.width;
- shrink = (s->brect.width - width) / (float)tw;
+ width -= Dx(tb->r);
+ tw += Dx(tb->r);
+ shrink = (Dx(s->brect) - width) / (float)tw;
if(tb->smaller)
- if(tb->brush.rect.width * shrink >= tb->smaller->brush.rect.width)
- break;
+ if(Dx(tb->r) * shrink >= Dx(tb->smaller->r))
+ break;
}
if(tb)
- for(b = largest; b != tb->smaller; b = b->smaller)
- b->brush.rect.width = (int)(b->brush.rect.width * shrink);
+ for(b = largest; b != tb->smaller; b = b->smaller)
+ b->r.max.x *= shrink;
width += tw * shrink;
tb = nil;
}
+
for(nb = 0; nb < nelem(s->bar); nb++)
for(b = s->bar[nb]; b; tb=b, b=b->next) {
if(b == s->bar[BarRight]) {
- b->brush.align = EAST;
- b->brush.rect.width += (s->brect.width - width);
+ align = EAST;
+ b->r.max.x += Dx(s->brect) - width;
}else
- b->brush.align = CENTER;
+ align = CENTER;
+
if(tb)
- b->brush.rect.x = tb->brush.rect.x + tb->brush.rect.width;
- draw_label(&b->brush, b->text);
- draw_border(&b->brush);
+ b->r = rectaddpt(b->r, Pt( tb->r.max.x, 0));
+ }
+
+ r = rectsubpt(s->brect, s->brect.min);
+ fill(screen->ibuf, r, def.normcolor.bg);
+ for(nb = 0; nb < nelem(s->bar); nb++)
+ for(b = s->bar[nb]; b; tb=b, b=b->next) {
+ 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);
}
-MapBar:
- XCopyArea(blz.dpy, s->bbrush.drawable, s->barwin, s->bbrush.gc, 0, 0,
- s->brect.width, s->brect.height, 0, 0);
- XSync(blz.dpy, False);
+ copyimage(s->barwin, r, screen->ibuf, ZP);
+ XSync(display, False);
}
Bar *
-bar_of_name(Bar *b_link, const char *name) {
- static char buf[256];
+bar_of_name(Bar *bp, const char *name) {
Bar *b;
- strncpy(buf, name, sizeof(buf));
- for(b = b_link; b; b = b->next)
- if(!strncmp(b->name, name, sizeof(b->name))) break;
+ for(b = bp; b; b = b->next)
+ if(!strncmp(b->name, name, sizeof(b->name)))
+ break;
return b;
}
+
+static void
+bdown_event(Window *w, XButtonPressedEvent *e) {
+ Bar *b;
+
+ /* Ungrab so a menu can receive events before the button is released */
+ XUngrabPointer(display, e->time);
+ XSync(display, False);
+
+ for(b=screen->bar[BarLeft]; b; b=b->next)
+ if(ptinrect(Pt(e->x, e->y), b->r)) {
+ write_event("LeftBarMouseDown %d %s\n", e->button, b->name);
+ return;
+ }
+ for(b=screen->bar[BarRight]; b; b=b->next)
+ if(ptinrect(Pt(e->x, e->y), b->r)) {
+ write_event("RightBarMouseDown %d %s\n", e->button, b->name);
+ return;
+ }
+}
+
+static void
+bup_event(Window *w, XButtonPressedEvent *e) {
+ Bar *b;
+
+ for(b=screen->bar[BarLeft]; b; b=b->next)
+ if(ptinrect(Pt(e->x, e->y), b->r)) {
+ write_event("LeftBarClick %d %s\n", e->button, b->name);
+ return;
+ }
+ for(b=screen->bar[BarRight]; b; b=b->next)
+ if(ptinrect(Pt(e->x, e->y), b->r)) {
+ write_event("RightBarClick %d %s\n", e->button, b->name);
+ return;
+ }
+}
+
+static void
+expose_event(Window *w, XExposeEvent *e) {
+ draw_bar(screen);
+}
+
+static Handlers handlers = {
+ .bdown = bdown_event,
+ .bup = bup_event,
+ .expose = expose_event,
+};
diff --git a/cmd/wmii/client.c b/cmd/wmii/client.c
@@ -2,6 +2,7 @@
* Copyright ©2006-2007 Kris Maglione <fbsdaemon@gmail.com>
* See LICENSE file for license details.
*/
+#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -10,10 +11,9 @@
#include "dat.h"
#include "fns.h"
-static void update_client_name(Client *c);
+#define Mbsearch(k, l, cmp) bsearch(k, l, nelem(l), sizeof(*l), cmp)
-static char Ebadcmd[] = "bad command",
- Ebadvalue[] = "bad value";
+static Handlers handlers;
enum {
ClientMask =
@@ -22,60 +22,57 @@ enum {
| EnterWindowMask
| FocusChangeMask,
ButtonMask =
- ButtonPressMask | ButtonReleaseMask
+ ButtonPressMask
+ | ButtonReleaseMask
};
Client *
-create_client(Window w, XWindowAttributes *wa) {
+create_client(XWindow w, XWindowAttributes *wa) {
Client **t, *c;
- XSetWindowAttributes fwa;
+ WinAttr fwa;
c = emallocz(sizeof(Client));
- c->win = w;
- c->rect.x = wa->x;
- c->rect.y = wa->y;
c->border = wa->border_width;
- c->rect.width = wa->width;
- c->rect.height = wa->height;
- c->proto = win_proto(c->win);
- prop_client(c, XA_WM_TRANSIENT_FOR);
- prop_client(c, XA_WM_NORMAL_HINTS);
- prop_client(c, XA_WM_HINTS);
- prop_client(c, XA_WM_NAME);
+ c->r.min = Pt(wa->x, wa->y);
+ c->r.max = addpt(c->r.min, Pt(wa->width, wa->height));
- XSetWindowBorderWidth(blz.dpy, c->win, 0);
- XAddToSaveSet(blz.dpy, c->win);
+ c->w.type = WWindow;
+ c->w.w = w;
+ c->w.r = c->r;
+
+ prop_client(c, xatom("WM_PROTOCOLS"));
+ prop_client(c, xatom("WM_TRANSIENT_FOR"));
+ prop_client(c, xatom("WM_NORMAL_HINTS"));
+ prop_client(c, xatom("WM_HINTS"));
+ prop_client(c, xatom("WM_CLASS"));
+ prop_client(c, xatom("WM_NAME"));
+ prop_client(c, xatom("_MOTIF_WM_HINTS"));
+
+ XSetWindowBorderWidth(display, w, 0);
+ XAddToSaveSet(display, w);
+ XSelectInput(display, c->w.w, ClientMask);
fwa.override_redirect = True;
- fwa.background_pixmap = ParentRelative;
- fwa.backing_store = Always;
+ fwa.background_pixmap = None;
fwa.event_mask =
- SubstructureRedirectMask
- | SubstructureNotifyMask
- | ExposureMask
- | EnterWindowMask
- | PointerMotionMask
- | KeyPressMask
- | ButtonPressMask
- | ButtonReleaseMask;
- c->framewin = XCreateWindow(
- /* display */ blz.dpy,
- /* parent */ blz.root,
- /* x */ c->rect.x,
- /* y */ c->rect.y,
- /* width */ c->rect.width + 2 * def.border,
- /* height */ c->rect.height + def.border + labelh(&def.font),
- /* border */ 0,
- /* depth */ DefaultDepth(blz.dpy, blz.screen),
- /* class */ CopyFromParent,
- /* visual */ DefaultVisual(blz.dpy, blz.screen),
- /* valuemask */ CWOverrideRedirect | CWEventMask | CWBackPixmap | CWBackingStore,
- /* attributes */&fwa
- );
-
- c->gc = XCreateGC(blz.dpy, c->framewin, 0, 0);
- XSync(blz.dpy, False);
+ SubstructureRedirectMask
+ | SubstructureNotifyMask
+ | ExposureMask
+ | EnterWindowMask
+ | PointerMotionMask
+ | ButtonPressMask
+ | ButtonReleaseMask;
+ c->framewin = createwindow(&scr.root, c->r, scr.depth, InputOutput, &fwa,
+ CWOverrideRedirect
+ | CWEventMask
+ | CWBackPixmap);
+ c->framewin->aux = c;
+ c->w.aux = c;
+ sethandler(c->framewin, &framehandler);
+ sethandler(&c->w, &handlers);
+
+ grab_button(c->framewin->w, AnyButton, AnyModifier);
for(t=&client ;; t=&(*t)->next)
if(!*t) {
@@ -84,24 +81,60 @@ create_client(Window w, XWindowAttributes *wa) {
break;
}
- write_event("CreateClient 0x%x\n", c->win);
+ write_event("CreateClient 0x%x\n", c->w.w);
+ manage_client(c);
return c;
}
+void
+manage_client(Client *c) {
+ Point p;
+ Client *trans;
+ char *tags;
+
+ tags = gettextproperty(&c->w, "_WIN_TAGS");
+
+ if((trans = win2client(c->trans)))
+ strncpy(c->tags, trans->tags, sizeof(c->tags));
+ else if(tags)
+ strncpy(c->tags, tags, sizeof(c->tags));
+
+ free(tags);
+
+ p.x = def.border;
+ p.y = labelh(def.font);
+
+ if(c->tags[0])
+ apply_tags(c, c->tags);
+ else
+ apply_rules(c);
+
+ reparentwindow(&c->w, c->framewin, p);
+
+ if(!starting)
+ update_views();
+
+ if(c->sel->view == screen->sel)
+ focus(c, True);
+ flushevents(EnterWindowMask, False);
+}
+
static int
-dummy_error_handler(Display *dpy, XErrorEvent *error) {
+ignoreerrors(Display *d, XErrorEvent *e) {
return 0;
}
void
destroy_client(Client *c) {
+ int (*handler)(Display*, XErrorEvent*);
+ Rectangle r;
char *dummy;
Client **tc;
- XEvent ev;
+ Bool hide;
- XGrabServer(blz.dpy);
- /* In case the client is already unmapped */
- XSetErrorHandler(dummy_error_handler);
+ Debug fprintf(stderr, "client.c:destroy_client(%p) %s\n", c, c->name);
+
+ unmapwin(c->framewin);
for(tc=&client; *tc; tc=&(*tc)->next)
if(*tc == c) {
@@ -109,298 +142,418 @@ destroy_client(Client *c) {
break;
}
- dummy = nil;
- update_client_views(c, &dummy);
-
- unmap_client(c, WithdrawnState);
- gravitate_client(c, True);
- reparent_client(c, blz.root, c->rect.x, c->rect.y);
+ r = c->w.r;
+ if(c->sel)
+ r = gravclient(c, ZR);
- XFreeGC(blz.dpy, c->gc);
- XDestroyWindow(blz.dpy, c->framewin);
- XSync(blz.dpy, False);
-
- XSetErrorHandler(wmii_error_handler);
- XUngrabServer(blz.dpy);
- flushevents(EnterWindowMask, False);
+ hide = False;
+ if(!c->sel || c->sel->view != screen->sel)
+ hide = True;
- while(XCheckMaskEvent(blz.dpy, StructureNotifyMask, &ev))
- if(ev.type != UnmapNotify || ev.xunmap.window != c->win)
- dispatch_event(&ev);
+ XGrabServer(display);
- write_event("DestroyClient 0x%x\n", c->win);
- free(c);
-}
-
-void
-manage_client(Client *c) {
- XTextProperty tags = { 0 };
- Client *trans;
-
- XGetTextProperty(blz.dpy, c->win, &tags, atom[TagsAtom]);
-
- if((trans = win2client(c->trans)))
- strncpy(c->tags, trans->tags, sizeof(c->tags));
- else if(tags.nitems)
- strncpy(c->tags, (char *)tags.value, sizeof(c->tags));
- XFree(tags.value);
+ /* In case the client is already unmapped */
+ handler = XSetErrorHandler(ignoreerrors);
- gravitate_client(c, False);
- reparent_client(c, c->framewin, def.border, labelh(&def.font));
+ dummy = nil;
+ update_client_views(c, &dummy);
+ unmap_client(c, IconicState);
+ sethandler(&c->w, nil);
- if(!strlen(c->tags))
- apply_rules(c);
+ if(hide)
+ reparentwindow(&c->w, &scr.root, screen->r.max);
else
- apply_tags(c, c->tags);
+ reparentwindow(&c->w, &scr.root, r.min);
+ destroywindow(c->framewin);
- if(!starting)
- update_views();
- XSync(blz.dpy, False);
+ XSync(display, False);
+ XSetErrorHandler(handler);
+ XUngrabServer(display);
+
+ write_event("DestroyClient 0x%x\n", clientwin(c));
- if(c->sel->view == screen->sel)
- focus(c, True);
flushevents(EnterWindowMask, False);
+ free(c);
}
+/* Convenience functions */
Client *
-selclient() {
- if(screen->sel && screen->sel->sel->sel)
+selclient(void) {
+ if(screen->sel->sel->sel)
return screen->sel->sel->sel->client;
return nil;
}
Client *
-win2client(Window w) {
+win2client(XWindow w) {
Client *c;
for(c=client; c; c=c->next)
- if(c->win == w) break;
+ if(c->w.w == w) break;
return c;
}
-Frame *
-win2frame(Window w) {
- Client *c;
- for(c=client; c; c=c->next)
- if(c->framewin == w) break;
+uint
+clientwin(Client *c) {
if(c)
- return c->sel;
- return nil;
+ return (uint)c->w.w;
+ return 0;
}
-static void
-update_client_name(Client *c) {
- XTextProperty name;
- XClassHint ch;
- int n;
- char **list = nil;
-
- name.nitems = 0;
- c->name[0] = 0;
- XGetTextProperty(blz.dpy, c->win, &name, atom[NetWMName]);
- if(!name.nitems)
- XGetWMName(blz.dpy, c->win, &name);
- if(!name.nitems)
- return;
- if(name.encoding == XA_STRING)
- strncpy(c->name, (char *)name.value, sizeof(c->name));
- else {
- if(XmbTextPropertyToTextList(blz.dpy, &name, &list, &n) >= Success
- && n > 0 && *list)
- {
- strncpy(c->name, *list, sizeof(c->name));
- XFreeStringList(list);
- }
- }
- XFree(name.value);
- if(XGetClassHint(blz.dpy, c->win, &ch)) {
- snprintf(c->props, sizeof(c->props),
- "%s:%s:%s",
- str_nil(ch.res_class),
- str_nil(ch.res_name),
- c->name);
- if(ch.res_class)
- XFree(ch.res_class);
- if(ch.res_name)
- XFree(ch.res_name);
- }
+char *
+clientname(Client *c) {
+ if(c)
+ return c->name;
+ return "<nil>";
}
-void
-update_client_grab(Client *c) {
- Frame *f;
- f = c->sel;
- if((f->client != selclient())
- || (f->area->floating && f != f->area->stack)) {
- if(verbose)
- fprintf(stderr, "update_client_grab(%p) AnyButton => %s\n", c, str_nil(c->name));
- grab_button(c->framewin, AnyButton, AnyModifier);
+Rectangle
+gravclient(Client *c, Rectangle rd) {
+ Rectangle r;
+ Point sp;
+ WinHints *h;
+
+ h = c->w.hints;
+ sp = Pt(def.border, labelh(def.font));
+
+ if(eqrect(rd, ZR)) {
+ if(c->sel->area->floating)
+ r = c->sel->r;
+ else
+ r = c->sel->revert;
+ r = gravitate(r, c->w.r, h->grav);
+ if(h->gravstatic)
+ r = rectaddpt(r, sp);
+ r = frame2client(nil, r);
}else {
- if(verbose)
- fprintf(stderr, "update_client_grab(%p) def.mod => %s\n", c, str_nil(c->name));
- XUngrabButton(blz.dpy, AnyButton, AnyModifier, c->framewin);
- grab_button(c->framewin, Button1, def.mod);
- grab_button(c->framewin, Button3, def.mod);
+ r = client2frame(c->sel, c->w.r);
+ r = gravitate(rd, r, h->grav);
+ if(h->gravstatic)
+ r = rectsubpt(r, sp);
+ r = client2frame(nil, r);
}
+ return r;
}
-void
+Rectangle
+frame_hints(Frame *f, Rectangle r, Align sticky) {
+ Rectangle or;
+ Point p;
+ Client *c;
+
+ c = f->client;
+ if(c->w.hints == nil)
+ return r;
+
+ or = r;
+ r = frame2client(f, r);
+ r = sizehint(c->w.hints, r);
+ r = client2frame(f, r);
+
+ if(!f->area->floating) {
+ /* Not allowed to grow */
+ if(Dx(r) > Dx(or))
+ r.max.x =r.min.x+Dx(or);
+ if(Dy(r) > Dy(or))
+ r.max.y = r.min.y+Dy(or);
+ }
+
+ p = ZP;
+ if((sticky&(EAST|WEST)) == EAST)
+ p.x = Dx(or) - Dx(r);
+ if((sticky&(NORTH|SOUTH)) == SOUTH)
+ p.y = Dy(or) - Dy(r);
+
+ return rectaddpt(r, p);
+}
+
+static void
set_client_state(Client * c, int state) {
long data[] = { state, None };
- XChangeProperty(
- /* display */ blz.dpy,
- /* parent */ c->win,
- /* property */ atom[WMState],
- /* type */ atom[WMState],
- /* format */ 32,
- /* mode */ PropModeReplace,
- /* data */ (uchar *) data,
- /* npositions */2
- );
+ changeprop(&c->w, "WM_STATE", "WM_STATE", data, nelem(data));
}
void
map_client(Client *c) {
- if(!c->mapped) {
- XSelectInput(blz.dpy, c->win, ClientMask & ~StructureNotifyMask);
- XMapWindow(blz.dpy, c->win);
- XSelectInput(blz.dpy, c->win, ClientMask);
+ if(!c->w.mapped) {
+ mapwin(&c->w);
set_client_state(c, NormalState);
- c->mapped = 1;
}
}
void
unmap_client(Client *c, int state) {
- if(c->mapped) {
- c->unmapped++;
- XSelectInput(blz.dpy, c->win, ClientMask & ~StructureNotifyMask);
- XUnmapWindow(blz.dpy, c->win);
- XSelectInput(blz.dpy, c->win, ClientMask);
+ if(c->w.mapped) {
+ unmapwin(&c->w);
set_client_state(c, state);
- c->mapped = 0;
}
}
-void
+int
map_frame(Client *c) {
- if(!c->frame_mapped) {
- XMapWindow(blz.dpy, c->framewin);
- c->frame_mapped = True;
- }
+ return mapwin(c->framewin);
}
-void
+int
unmap_frame(Client *c) {
- if(c->frame_mapped) {
- XUnmapWindow(blz.dpy, c->framewin);
- c->frame_mapped = False;
+ return unmapwin(c->framewin);
+}
+
+void
+focus(Client *c, Bool restack) {
+ View *v;
+ Frame *f;
+
+ f = c->sel;
+ if(!f)
+ return;
+
+ v = f->area->view;
+ if(v != screen->sel)
+ focus_view(screen, v);
+ focus_frame(c->sel, restack);
+}
+
+void
+focus_client(Client *c) {
+ flushevents(FocusChangeMask, True);
+
+ Debug fprintf(stderr, "focus_client(%p[%x]) => %s\n", c, clientwin(c), clientname(c));
+
+ if((c == nil || !c->noinput) && screen->focus != c) {
+ Debug fprintf(stderr, "\t%s => %s\n", clientname(screen->focus), clientname(c));
+
+ if(c)
+ setfocus(&c->w, RevertToParent);
+ else
+ setfocus(screen->barwin, RevertToParent);
+
+ write_event("ClientFocus 0x%x\n", clientwin(c));
+
+ XSync(display, False);
+ flushevents(FocusChangeMask, True);
}
}
void
-reparent_client(Client *c, Window w, int x, int y) {
- XSelectInput(blz.dpy, c->win, ClientMask & ~StructureNotifyMask);
- XReparentWindow(blz.dpy, c->win, w, x, y);
- XSelectInput(blz.dpy, c->win, ClientMask);
+resize_client(Client *c, Rectangle *r) {
+ Frame *f;
+
+ f = c->sel;
+ resize_frame(f, *r);
+
+ if(f->area->view != screen->sel) {
+ unmap_client(c, IconicState);
+ unmap_frame(c);
+ return;
+ }
+
+ c->r = rectaddpt(f->crect, f->r.min);
+
+ if((f->area->mode == Colmax) && (f->area->sel != f)) {
+ unmap_frame(c);
+ unmap_client(c, IconicState);
+ }else if(f->collapsed) {
+ reshapewin(c->framewin, f->r);
+ map_frame(c);
+ unmap_client(c, IconicState);
+ }else {
+ map_client(c);
+ reshapewin(c->framewin, f->r);
+ reshapewin(&c->w, f->crect);
+ map_frame(c);
+ configure_client(c);
+ }
+
+ flushevents(FocusChangeMask|ExposureMask, True);
}
void
set_cursor(Client *c, Cursor cur) {
- XSetWindowAttributes wa;
+ WinAttr wa;
if(c->cursor != cur) {
c->cursor = cur;
wa.cursor = cur;
- XChangeWindowAttributes(blz.dpy, c->framewin, CWCursor, &wa);
+ setwinattr(c->framewin, &wa, CWCursor);
}
}
void
configure_client(Client *c) {
XConfigureEvent e;
+ Rectangle r;
Frame *f;
f = c->sel;
if(!f)
return;
+ r = rectaddpt(f->crect, f->r.min);
+ r = insetrect(r, -c->border);
+
e.type = ConfigureNotify;
- e.event = c->win;
- e.window = c->win;
- e.x = f->crect.x + f->rect.x - c->border;
- e.y = f->crect.y + f->rect.y - c->border;
- e.width = f->crect.width;
- e.height = f->crect.height;
- e.border_width = c->border;
+ e.event = c->w.w;
+ e.window = c->w.w;
e.above = None;
e.override_redirect = False;
- XSendEvent(blz.dpy, c->win, False,
- StructureNotifyMask, (XEvent *) & e);
- XSync(blz.dpy, False);
+
+ e.x = r.min.x;
+ e.y = r.min.y;
+ e.width = Dx(r);
+ e.height = Dy(r);
+ e.border_width = c->border;
+
+ XSendEvent(display, c->w.w,
+ /*propegate*/ False,
+ StructureNotifyMask,
+ (XEvent*)&e);
}
static void
-send_client_message(Window w, Atom a, long value) {
+send_client_message(Client *c, char *name, char *value) {
XEvent e;
e.type = ClientMessage;
- e.xclient.window = w;
- e.xclient.message_type = a;
+ e.xclient.window = c->w.w;
+ e.xclient.message_type = xatom(name);
e.xclient.format = 32;
- e.xclient.data.l[0] = value;
+ e.xclient.data.l[0] = xatom(value);
e.xclient.data.l[1] = CurrentTime;
- XSendEvent(blz.dpy, w, False, NoEventMask, &e);
- XSync(blz.dpy, False);
+ XSendEvent(display, c->w.w, False, NoEventMask, &e);
+ XSync(display, False);
}
void
kill_client(Client * c) {
if(c->proto & WM_PROTOCOL_DELWIN)
- send_client_message(c->win, atom[WMProtocols], atom[WMDelete]);
+ send_client_message(c, "WM_PROTOCOLS", "WM_DELETE_WINDOW");
else
- XKillClient(blz.dpy, c->win);
+ XKillClient(display, c->w.w);
}
-static void
+void
+fullscreen(Client *c, Bool fullscreen) {
+ Frame *f;
+
+ c->fullscreen = fullscreen;
+ if((f = c->sel)) {
+ if(fullscreen) {
+ if(!f->area->floating)
+ send_to_area(f->view->area, f);
+ focus_client(c);
+ }
+ if(f->view == screen->sel)
+ focus_view(screen, f->view);
+ }
+}
+
+void
set_urgent(Client *c, Bool urgent, Bool write) {
XWMHints *wmh;
char *cwrite, *cnot;
Frame *f, *ff;
Area *a;
- cwrite = "Client";
- if(write)
- cwrite = "Manager";
- cnot = "Not";
- if(urgent)
- cnot = "";
+ cwrite = (write ? "Manager" : "Client");
+ cnot = (urgent ? "" : "Not");
if(urgent != c->urgent) {
- write_event("%sUrgent 0x%x %s\n", cnot, c->win, cwrite);
+ write_event("%sUrgent 0x%x %s\n", cnot, clientwin(c), cwrite);
c->urgent = urgent;
if(c->sel) {
if(c->sel->view == screen->sel)
draw_frame(c->sel);
- if(!urgent || c->sel->view != screen->sel)
- for(f=c->frame; f; f=f->cnext) {
+ for(f=c->frame; f; f=f->cnext) {
+ if(!urgent)
for(a=f->view->area; a; a=a->next)
for(ff=a->frame; ff; ff=ff->anext)
if(ff->client->urgent) break;
- if(!ff)
- write_event("%sUrgentTag %s %s\n", cnot, cwrite, f->view->name);
- }
+ if(urgent || ff == nil)
+ write_event("%sUrgentTag %s %s\n", cnot, cwrite, f->view->name);
+ }
}
}
if(write) {
- wmh = XGetWMHints(blz.dpy, c->win);
- if(wmh) {
- if(urgent)
- wmh->flags |= XUrgencyHint;
- else
- wmh->flags &= ~XUrgencyHint;
- XSetWMHints(blz.dpy, c->win, wmh);
- XFree(wmh);
+ wmh = XGetWMHints(display, c->w.w);
+ if(wmh == nil)
+ wmh = emallocz(sizeof *wmh);
+
+ wmh->flags &= ~XUrgencyHint;
+ if(urgent)
+ wmh->flags |= XUrgencyHint;
+ XSetWMHints(display, c->w.w, wmh);
+ XFree(wmh);
+ }
+}
+
+/* X11 stuff */
+void
+update_class(Client *c) {
+ char *str;
+
+ str = utfrune(c->props, L':');
+ if(str)
+ str = utfrune(str+1, L':');
+ if(str == nil) {
+ strcpy(c->props, "::");
+ str = c->props + 1;
+ }
+ utfecpy(str+1, c->props+sizeof(c->props), c->name);
+}
+
+static void
+update_client_name(Client *c) {
+ char *str;
+
+ c->name[0] = '\0';
+
+ str = gettextproperty(&c->w, "_NET_WM_NAME");
+ if(str == nil)
+ str = gettextproperty(&c->w, "WM_NAME");
+ if(str)
+ utfecpy(c->name, c->name+sizeof(c->name), str);
+ free(str);
+
+ update_class(c);
+ if(c->sel)
+ draw_frame(c->sel);
+}
+
+static void
+updatemwm(Client *c) {
+ enum {
+ All = 0x1,
+ Border = 0x2,
+ Title = 0x8,
+ };
+ Rectangle r;
+ ulong *ret, decor;
+ Atom real;
+ int n;
+
+ n = getproperty(&c->w, "_MOTIF_WM_HINTS", "_MOTIF_WM_HINTS", &real,
+ 2L, (uchar**)&ret, 1L);
+
+ if(n == 0) {
+ c->borderless = 0;
+ c->titleless = 0;
+ }else {
+ decor = *ret;
+ free(ret);
+
+ if(c->sel)
+ r = frame2client(c->sel, c->sel->r);
+
+ if(decor&All)
+ decor ^= ~0;
+ c->borderless = ((decor&Border)==0);
+ c->titleless = ((decor&Title)==0);
+
+ if(c->sel) {
+ r = client2frame(c->sel, c->sel->r);
+ resize_client(c, &r);
+ draw_frame(c->sel);
}
}
}
@@ -408,263 +561,205 @@ set_urgent(Client *c, Bool urgent, Bool write) {
void
prop_client(Client *c, Atom a) {
XWMHints *wmh;
- long msize;
+ char **class;
+ int n;
- if(a == atom[WMProtocols])
- c->proto = win_proto(c->win);
- else if(a== atom[NetWMName]) {
-wmname:
- update_client_name(c);
- if(c->frame)
- draw_frame(c->sel);
- }else switch (a) {
+ if(a == xatom("WM_PROTOCOLS")) {
+ c->proto = winprotocols(&c->w);
+ }
+ else if(a == xatom("_NET_WM_NAME")) {
+ goto wmname;
+ }
+ else if(a == xatom("_MOTIF_WM_HINTS")) {
+ updatemwm(c);
+ }
+ else switch (a) {
case XA_WM_TRANSIENT_FOR:
- XGetTransientForHint(blz.dpy, c->win, &c->trans);
+ XGetTransientForHint(display, c->w.w, &c->trans);
break;
case XA_WM_NORMAL_HINTS:
- if(!XGetWMNormalHints(blz.dpy, c->win, &c->size, &msize) || !c->size.flags)
- c->size.flags = PSize;
- c->fixedsize = False;
- if((c->size.flags & PMinSize) && (c->size.flags & PMaxSize)
- &&(c->size.min_width == c->size.max_width)
- &&(c->size.min_height == c->size.max_height))
- c->fixedsize = True;
+ sethints(&c->w);
+ if(c->w.hints)
+ c->fixedsize = eqpt(c->w.hints->min, c->w.hints->max);
break;
case XA_WM_HINTS:
- wmh = XGetWMHints(blz.dpy, c->win);
+ wmh = XGetWMHints(display, c->w.w);
if(wmh) {
+ c->noinput = !((wmh->flags&InputFocus) && wmh->input);
set_urgent(c, (wmh->flags & XUrgencyHint) != 0, False);
XFree(wmh);
}
break;
+ case XA_WM_CLASS:
+ n = gettextlistproperty(&c->w, "WM_CLASS", &class);
+ snprintf(c->props, sizeof(c->props), "%s:%s:",
+ (n > 0 ? class[0] : "<nil>"),
+ (n > 1 ? class[1] : "<nil>"));
+ freestringlist(class);
+ update_class(c);
+ break;
case XA_WM_NAME:
- goto wmname;
+wmname:
+ update_client_name(c);
+ break;
}
}
-void
-gravitate_client(Client *c, Bool invert) {
- int dx, dy;
- int gravity;
+/* Handlers */
+static void
+configreq_event(Window *w, XConfigureRequestEvent *e) {
+ Rectangle r;
+ Frame *f;
+ Client *c;
- gravity = NorthWestGravity;
- if(c->size.flags & PWinGravity) {
- gravity = c->size.win_gravity;
- }
+ c = w->aux;
+ f = c->sel;
- dy = 0;
- switch (gravity) {
- case StaticGravity:
- case NorthWestGravity:
- case NorthGravity:
- case NorthEastGravity:
- dy = labelh(&def.font);
- break;
- case EastGravity:
- case CenterGravity:
- case WestGravity:
- dy = -(c->rect.height / 2) + labelh(&def.font);
- break;
- case SouthEastGravity:
- case SouthGravity:
- case SouthWestGravity:
- dy = -c->rect.height;
- break;
- default:
- break;
- }
+ r = gravclient(c, ZR);
+ r.max = subpt(r.max, r.min);
- dx = 0;
- switch (gravity) {
- case StaticGravity:
- case NorthWestGravity:
- case WestGravity:
- case SouthWestGravity:
- dx = def.border;
- break;
- case NorthGravity:
- case CenterGravity:
- case SouthGravity:
- dx = -(c->rect.width / 2) + def.border;
- break;
- case NorthEastGravity:
- case EastGravity:
- case SouthEastGravity:
- dx = -(c->rect.width + def.border);
- break;
- default:
- break;
- }
+ if(e->value_mask&CWX)
+ r.min.x = e->x;
+ if(e->value_mask&CWY)
+ r.min.y = e->y;
+ if(e->value_mask&CWWidth)
+ r.max.x = e->width;
+ if(e->value_mask&CWHeight)
+ r.max.y = e->height;
- if(invert) {
- dx = -dx;
- dy = -dy;
+ if(e->value_mask&CWBorderWidth)
+ c->border = e->border_width;
+
+ r.max = addpt(r.min, r.max);
+ r = gravclient(c, r);
+
+ if((Dx(r) == Dx(screen->r)) && (Dy(r) == Dy(screen->r)))
+ fullscreen(c, True);
+
+ if(c->sel->area->floating)
+ resize_client(c, &r);
+ else {
+ c->sel->revert = r;
+ configure_client(c);
}
- c->rect.x += dx;
- c->rect.y += dy;
}
-void
-apply_sizehints(Client *c, XRectangle *r, Bool floating, Bool frame, BlitzAlign sticky) {
- XSizeHints *s;
- XRectangle orig;
- uint bw, bh;
+static void
+destroy_event(Window *w, XDestroyWindowEvent *e) {
+ Debug fprintf(stderr, "client.c:destroy_event(%x)\n", (uint)w->w);
+ destroy_client(w->aux);
+}
+
+static void
+enter_event(Window *w, XCrossingEvent *e) {
+ Client *c;
- s = &c->size;
- orig = *r;
- if(frame)
- frame2client(c->sel, r);
- bw = 0;
- bh = 0;
-
- if(s->flags & PMinSize) {
- bw = s->min_width;
- bh = s->min_height;
- if(floating) {
- if(r->width < s->min_width)
- r->width = s->min_width;
- if(r->height < s->min_height)
- r->height = s->min_height;
+ c = w->aux;
+ if(e->detail != NotifyInferior) {
+ if(screen->focus != c) {
+ Debug fprintf(stderr, "enter_notify(c) => %s\n", c->name);
+ focus(c, False);
}
- }
- if(s->flags & PMaxSize) {
- if(r->width > s->max_width)
- r->width = s->max_width;
- if(r->height > s->max_height)
- r->height = s->max_height;
- }
+ set_cursor(c, cursor[CurNormal]);
+ }else Debug
+ fprintf(stderr, "enter_notify(c[NotifyInferior]) => %s\n", c->name);
+}
- if(s->flags & PBaseSize) {
- bw = s->base_width;
- bh = s->base_height;
- }
+static void
+focusin_event(Window *w, XFocusChangeEvent *e) {
+ Client *c, *old;
- if(s->flags & PResizeInc) {
- if(s->width_inc > 0)
- r->width -= (r->width - bw) % s->width_inc;
- if(s->height_inc > 0)
- r->height -= (r->height - bh) % s->height_inc;
- }
+ c = w->aux;
- if((s->flags & (PBaseSize|PMinSize)) == PMinSize) {
- bw = 0;
- bh = 0;
- }
+ print_focus(c, c->name);
- if(s->flags & PAspect) {
- double min, max, initial;
+ if(e->mode == NotifyGrab)
+ screen->hasgrab = c;
- min = (double)s->min_aspect.x / s->min_aspect.y;
- max = (double)s->max_aspect.x / s->max_aspect.y;
- initial = (double)(r->width - bw) / (r->height - bh);
- if(initial < min)
- r->height = bh + (r->width - bw) / min;
- if(initial > max)
- r->width = bw + (r->height - bh) * max;
+ old = screen->focus;
+ screen->focus = c;
+ if(c != old) {
+ if(c->sel)
+ draw_frame(c->sel);
}
+}
- if(frame)
- client2frame(c->sel, r);
+static void
+focusout_event(Window *w, XFocusChangeEvent *e) {
+ Client *c;
- if(!(s->flags & PMinSize) || !floating) {
- if(r->width > orig.width)
- r->width = orig.width;
- if(r->height > orig.height)
- r->height = orig.height;
+ c = w->aux;
+ if((e->mode == NotifyWhileGrabbed) && (screen->hasgrab != &c_root)) {
+ if((screen->focus) && (screen->hasgrab != screen->focus))
+ screen->hasgrab = screen->focus;
+ if(screen->hasgrab == c)
+ return;
+ }else if(screen->focus == c) {
+ print_focus(&c_magic, "<magic>");
+ screen->focus = &c_magic;
+ if(c->sel)
+ draw_frame(c->sel);
}
-
- if((sticky & (EAST|WEST)) == EAST)
- r->x = r_east(&orig) - r->width;
- if((sticky & (NORTH|SOUTH)) == SOUTH)
- r->y = r_south(&orig) - r->height;
}
-void
-focus(Client *c, Bool restack) {
- View *v;
- Frame *f;
-
- f = c->sel;
- if(!f)
- return;
-
- v = f->area->view;
- if(v != screen->sel)
- focus_view(screen, v);
- focus_frame(c->sel, restack);
+static void
+unmap_event(Window *w, XUnmapEvent *e) {
+ Client *c;
+
+ c = w->aux;
+ if(!e->send_event)
+ c->unmapped--;
+ destroy_client(c);
}
-void
-focus_client(Client *c) {
- flushevents(FocusChangeMask, True);
-
- if(verbose)
- fprintf(stderr, "focus_client(%p) => %s\n", c, (c ? c->name : nil));
- if(screen->focus != c) {
- if(c && verbose)
- fprintf(stderr, "\t%s => %s\n", (screen->focus ? screen->focus->name : "<nil>"),
- (c ? c->name : "<nil>"));
- if(c) {
- XSetInputFocus(blz.dpy, c->win, RevertToParent, CurrentTime);
- update_client_grab(c);
- }else
- XSetInputFocus(blz.dpy, screen->barwin, RevertToParent, CurrentTime);
- }
-
- flushevents(FocusChangeMask, True);
+static void
+map_event(Window *w, XMapEvent *e) {
+ Client *c;
+
+ c = w->aux;
+ if(c == selclient())
+ focus_client(c);
}
-void
-resize_client(Client *c, XRectangle *r) {
- Frame *f;
-
- f = c->sel;
- resize_frame(f, r);
+static void
+property_event(Window *w, XPropertyEvent *e) {
+ Client *c;
- if(f->area->view != screen->sel) {
- unmap_client(c, IconicState);
- unmap_frame(c);
+ if(e->state == PropertyDelete)
return;
- }
- c->rect = f->crect;
- c->rect.x += f->rect.x;
- c->rect.y += f->rect.y;
- if((f->area->mode == Colmax)
- && (f->area->sel != f)) {
- unmap_frame(c);
- unmap_client(c, IconicState);
- }else if(f->collapsed) {
- XMoveResizeWindow(blz.dpy, c->framewin,
- f->rect.x, f->rect.y,
- f->rect.width, f->rect.height);
- map_frame(c);
- unmap_client(c, IconicState);
- }else {
- XMoveResizeWindow(blz.dpy, c->win,
- f->crect.x, f->crect.y,
- f->crect.width, f->crect.height);
- map_client(c);
- XMoveResizeWindow(blz.dpy, c->framewin,
- f->rect.x, f->rect.y,
- f->rect.width, f->rect.height);
- map_frame(c);
- configure_client(c);
- }
-
- flushevents(FocusChangeMask|ExposureMask, True);
+ c = w->aux;
+ prop_client(c, e->atom);
}
+static Handlers handlers = {
+ .configreq = configreq_event,
+ .destroy = destroy_event,
+ .enter = enter_event,
+ .focusin = focusin_event,
+ .focusout = focusout_event,
+ .map = map_event,
+ .unmap = unmap_event,
+ .property = property_event,
+};
+
+/* Other */
+#if 0 /* Not used at the moment */
void
newcol_client(Client *c, char *arg) {
- Frame *f = c->sel;
- Area *to, *a = f->area;
- View *v = a->view;
+ Frame *f;
+ Area *to, *a;
+ View *v;
+
+ f = c->sel;
+ a = f->area;
+ v = f->view;
if(a->floating)
return;
- if(!f->anext && f == a->frame)
+ if((f->anext == nil) && (f->aprev == nil))
return;
+
if(!strncmp(arg, "prev", 5)) {
for(to=v->area; to; to=to->next)
if(to->next == a) break;
@@ -679,94 +774,7 @@ newcol_client(Client *c, char *arg) {
return;
flushevents(EnterWindowMask, False);
}
-
-char *
-send_client(Frame *f, char *arg, Bool swap) {
- Area *to, *a;
- Client *c;
- Frame *tf;
- View *v;
- Bool before;
- int j;
-
- a = f->area;
- v = a->view;
- c = f->client;
- if(!strncmp(arg, "toggle", 7)) {
- if(!a->floating)
- to = v->area;
- else if(c->revert && !c->revert->floating)
- to = c->revert;
- else
- to = v->area->next;
- goto send_area;
- }else if(!a->floating) {
- if(!strncmp(arg, "left", 5)) {
- if(a->floating)
- return Ebadvalue;
- for(to=v->area->next; to; to=to->next)
- if(a == to->next) break;
- if(!to && !swap && (f->anext || f != a->frame))
- to=new_column(v, v->area, 0);
- goto send_area;
- }
- else if(!strncmp(arg, "right", 5)) {
- if(a->floating)
- return Ebadvalue;
- to = a->next;
- if(!to && !swap && (f->anext || f != a->frame))
- to = new_column(v, a, 0);
- goto send_area;
- }
- else if(!strncmp(arg, "up", 3)) {
- for(tf=a->frame; tf; tf=tf->anext)
- if(tf->anext == f) break;
- before = True;
- goto send_frame;
- }
- else if(!strncmp(arg, "down", 5)) {
- tf = f->anext;
- before = False;
- goto send_frame;
- }
- else {
- if(sscanf(arg, "%d", &j) != 1)
- return Ebadvalue;
- for(to=v->area; to; to=to->next)
- if(!--j) break;
- goto send_area;
- }
- }
- return Ebadvalue;
-
-send_frame:
- if(!tf)
- return Ebadvalue;
- if(!swap) {
- remove_frame(f);
- insert_frame(tf, f, before);
- }else
- swap_frames(f, tf);
- arrange_column(a, False);
-
- flushevents(EnterWindowMask, False);
- focus_frame(f, True);
- update_views();
- return nil;
-
-send_area:
- if(!to)
- return Ebadvalue;
- if(!swap)
- send_to_area(to, f);
- else if(to->sel)
- swap_frames(f, to->sel);
-
- flushevents(EnterWindowMask, False);
- focus_frame(f, True);
- update_views();
- return nil;
-}
+#endif
void
update_client_views(Client *c, char **tags) {
@@ -806,10 +814,21 @@ update_client_views(Client *c, char **tags) {
}
static int
-compare_tags(const void *a, const void *b) {
+bsstrcmp(const void *a, const void *b) {
+ return strcmp((char*)a, (char*)b);
+}
+
+static int
+strpcmp(const void *a, const void *b) {
return strcmp(*(char **)a, *(char **)b);
}
+static char *badtags[] = {
+ ".",
+ "..",
+ "sel",
+};
+
void
apply_tags(Client *c, const char *tags) {
uint i, j, k, n;
@@ -818,15 +837,18 @@ apply_tags(Client *c, const char *tags) {
char *toks[32], *cur;
buf[0] = 0;
+
for(n = 0; tags[n]; n++)
- if(tags[n] != ' ' && tags[n] != '\t') break;
+ if(!isspace(tags[n]))
+ break;
+
if(tags[n] == '+' || tags[n] == '-')
strncpy(buf, c->tags, sizeof(c->tags));
+
strlcat(buf, &tags[n], sizeof(buf));
trim(buf, " \t/");
n = 0;
- j = 0;
add = True;
if(buf[0] == '+')
n++;
@@ -834,24 +856,22 @@ apply_tags(Client *c, const char *tags) {
n++;
add = False;
}
+
+ 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';
cur = nil;
- if(!strncmp(&buf[n], "~", 2))
+ if(!strcmp(buf+n, "~"))
c->floating = add;
- else if(!strncmp(&buf[n], "!", 2))
- cur = view ? screen->sel->name : "nil";
- else if(strncmp(&buf[n], "sel", 4)
- && strncmp(&buf[n], ".", 2)
- && strncmp(&buf[n], "..", 3))
- cur = &buf[n];
+ else if(!strcmp(buf+n, "!"))
+ cur = screen->sel->name;
+ else if(!Mbsearch(buf+n, badtags, bsstrcmp))
+ cur = buf+n;
n = i + 1;
if(cur) {
@@ -878,14 +898,15 @@ apply_tags(Client *c, const char *tags) {
}
}
- c->tags[0] = '\0';
if(!j)
return;
- qsort(toks, j, sizeof(char *), compare_tags);
+ qsort(toks, j, sizeof(char *), strpcmp);
+
+ c->tags[0] = '\0';
for(i=0, n=0; i < j; i++)
- if(!n || strcmp(toks[i], toks[n-1])) {
- if(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));
toks[n++] = toks[i];
@@ -893,37 +914,25 @@ apply_tags(Client *c, const char *tags) {
toks[n] = nil;
update_client_views(c, toks);
- XChangeProperty(blz.dpy, c->win, atom[TagsAtom], XA_STRING, 8,
- PropModeReplace, (uchar *)c->tags, strlen(c->tags));
+
+ changeprop(&c->w, "_WIN_TAGS", "UTF8_STRING", c->tags, strlen(c->tags));
}
void
apply_rules(Client *c) {
Rule *r;
regmatch_t rm;
-
+
if(strlen(c->tags))
return;
+
if(def.tagrules.string)
for(r=def.tagrules.rule; r; r=r->next)
if(!regexec(&r->regex, c->props, 1, &rm, 0)) {
apply_tags(c, r->value);
- if(strlen(c->tags) && strcmp(c->tags, "nil"))
+ if(strcmp(c->tags, "nil"))
break;
}
- if(!strlen(c->tags))
+ if(c->tags[0] == '\0')
apply_tags(c, "nil");
}
-
-char *
-message_client(Client *c, char *message) {
- if(!strncmp(message, "kill", 5))
- kill_client(c);
- else if(!strncmp(message, "Urgent", 7))
- set_urgent(c, True, True);
- else if(!strncmp(message, "NotUrgent", 10))
- set_urgent(c, False, True);
- else
- return Ebadcmd;
- return nil;
-}
diff --git a/cmd/wmii/column.c b/cmd/wmii/column.c
@@ -6,14 +6,13 @@
#include <math.h>
#include <stdio.h>
#include <string.h>
-#include <X11/extensions/shape.h>
#include <util.h>
#include "dat.h"
#include "fns.h"
-int divw, divh;
-GC divgc;
-GC maskgc;
+static Image *divimg, *divmask;
+static CTuple divc;
+static Handlers divhandler;
char *modes[] = {
[Coldefault] = "default",
@@ -21,15 +20,6 @@ char *modes[] = {
[Colmax] = "max",
};
-Divide *
-win2div(Window w) {
- Divide *d;
-
- for(d = divs; d; d = d->next)
- if(d->w == w) return d;
- return nil;
-}
-
int
str2colmode(const char *str) {
int i;
@@ -40,61 +30,9 @@ str2colmode(const char *str) {
return -1;
}
-static void
-draw_pmap(Pixmap pm, GC gc, Bool color) {
- XPoint pt[4];
-
- pt[0] = (XPoint){ 0, 0 };
- pt[1] = (XPoint){ divw/2 - 1, divw/2 - 1 };
- pt[2] = (XPoint){ divw/2, divw/2 - 1 };
- pt[3] = (XPoint){ divw - 1, 0 };
-
- if(color)
- XSetForeground(blz.dpy, gc, def.normcolor.bg);
- else {
- XSetForeground(blz.dpy, gc, 0);
- XFillRectangle(blz.dpy, pm, gc, 0, 0, divw, divh);
- XSetForeground(blz.dpy, gc, 1);
- }
-
- XFillPolygon(blz.dpy, pm, gc, pt, nelem(pt), Convex, CoordModeOrigin);
-
- if(color)
- XSetForeground(blz.dpy, gc, def.normcolor.border);
-
- XDrawLines(blz.dpy, pm, gc, pt, nelem(pt), CoordModeOrigin);
- XDrawRectangle(blz.dpy, pm, gc, pt[1].x, pt[1].y, 1, screen->rect.height);
-}
-
-void
-update_dividers() {
- if(divmap) {
- XFreePixmap(blz.dpy, divmap);
- XFreePixmap(blz.dpy, divmask);
- XFreeGC(blz.dpy, divgc);
- XFreeGC(blz.dpy, maskgc);
- }
-
- divw = 2 * (labelh(&def.font) / 3);
- divw = max(divw, 10);
- divh = screen->rect.height;
-
- divmap = XCreatePixmap(blz.dpy, blz.root,
- divw, divh,
- DefaultDepth(blz.dpy, blz.screen));
- divmask = XCreatePixmap(blz.dpy, blz.root,
- divw, divh,
- 1);
- divgc = XCreateGC(blz.dpy, divmap, 0, 0);
- maskgc = XCreateGC(blz.dpy, divmask, 0, 0);
-
- draw_pmap(divmap, divgc, True);
- draw_pmap(divmask, maskgc, False);
-}
-
static Divide*
-get_div(Divide **dp) {
- XSetWindowAttributes wa;
+getdiv(Divide **dp) {
+ WinAttr wa;
Divide *d;
if(*dp)
@@ -103,100 +41,156 @@ get_div(Divide **dp) {
d = emallocz(sizeof *d);
wa.override_redirect = True;
- wa.background_pixmap = ParentRelative;
wa.cursor = cursor[CurDHArrow];
wa.event_mask =
- SubstructureRedirectMask
- | ExposureMask
+ ExposureMask
| EnterWindowMask
- | PointerMotionMask
| ButtonPressMask
| ButtonReleaseMask;
- d->w = XCreateWindow(
- /* display */ blz.dpy,
- /* parent */ blz.root,
- /* x, y */ 0, 0,
- /* w, h */ 1, 1,
- /* border */ 0,
- /* depth */ DefaultDepth(blz.dpy, blz.screen),
- /* class */ CopyFromParent,
- /* visual */ DefaultVisual(blz.dpy, blz.screen),
- /* valuemask */ CWOverrideRedirect | CWEventMask | CWBackPixmap | CWCursor,
- /* attributes */&wa
- );
+ 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;
}
static void
-map_div(Divide *d) {
- if(!d->mapped)
- XMapWindow(blz.dpy, d->w);
- d->mapped = 1;
+mapdiv(Divide *d) {
+ mapwin(d->w);
+}
+
+static void
+unmapdiv(Divide *d) {
+ unmapwin(d->w);
+}
+
+void
+setdiv(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
-unmap_div(Divide *d) {
- if(d->mapped)
- XUnmapWindow(blz.dpy, d->w);
- d->mapped = 0;
+drawdiv(Divide *d) {
+ copyimage(d->w, divimg->r, divimg, ZP);
+ setshapemask(d->w, divmask, ZP);
}
static void
-move_div(Divide *d, int x) {
- d->x = x - divw/2;
-
- XMoveResizeWindow(blz.dpy,
- d->w,
- d->x, 0,
- divw, divh);
- map_div(d);
+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
-update_divs() {
+update_divs(void) {
Divide **dp, *d;
Area *a;
View *v;
- update_dividers();
-
+ update_imgs();
+
v = screen->sel;
dp = &divs;
for(a = v->area->next; a; a = a->next) {
- d = get_div(dp);
+ d = getdiv(dp);
dp = &d->next;
- d->x = a->rect.x - divw/2;
- move_div(d, a->rect.x);
+ setdiv(d, a->r.min.x);
+
if(!a->next) {
- d = get_div(dp);
+ d = getdiv(dp);
dp = &d->next;
- move_div(d, r_east(&a->rect));
+ setdiv(d, a->r.max.x);
}
}
for(d = *dp; d; d = d->next)
- unmap_div(d);
+ unmapdiv(d);
}
-void
-draw_div(Divide *d) {
- XCopyArea(
- blz.dpy,
- divmap, d->w,
- divgc,
- /* x, y */ 0, 0,
- /* w, h */ divw, divh,
- /* dest x, y */ 0, 0
- );
- XShapeCombineMask (
- /* dpy */ blz.dpy,
- /* dst */ d->w,
- /* type */ ShapeBounding,
- /* off x, y */ 0, 0,
- /* src */ divmask,
- /* op */ ShapeSet
- );
+/* Div Handlers */
+static void
+bdown_event(Window *w, XButtonEvent *e) {
+ Divide *d;
+
+ d = w->aux;
+ mouse_resizecol(d);
+}
+
+static void
+expose_event(Window *w, XExposeEvent *e) {
+ Divide *d;
+
+ d = w->aux;
+ drawdiv(d);
+}
+
+static Handlers divhandler = {
+ .bdown = bdown_event,
+ .expose = expose_event,
+};
+
+Area *
+new_column(View *v, Area *pos, uint w) {
+ Area *a;
+
+ a = create_area(v, pos, w);
+ if(!a)
+ return nil;
+
+ arrange_view(v);
+ if(v == screen->sel)
+ focus_view(screen, v);
+ return a;
}
static void
@@ -210,37 +204,33 @@ scale_column(Area *a) {
if(!a->frame)
return;
- /* This works by comparing heights based on a surplus of their
- * minimum size. We start by subtracting the minimum size, then
- * scale the surplus, and add back the minimum size later. This
- * is based on the size of the client, rather than the frame, so
- * increment gaps can be equalized later */
- /* Frames that can't be accomodated are pushed to the floating layer */
-
- minh = labelh(&def.font);
- colh = labelh(&def.font);
- uncolh = minh + frame_delta_h();
+ minh = labelh(def.font);
+ colh = labelh(def.font);
+ uncolh = minh + colh +1;
ncol = 0;
nuncol = 0;
dy = 0;
- for(f=a->frame; f; f=f->anext)
+ for(f=a->frame; f; f=f->anext) {
+ resize_frame(f, f->r);
if(f->collapsed)
ncol++;
else
nuncol++;
+ }
+
+ surplus = Dy(a->r) - (ncol * colh) - (nuncol * uncolh);
- surplus = a->rect.height;
- surplus -= ncol * colh;
- surplus -= nuncol * uncolh;
+ /* Collapse until there is room */
if(surplus < 0) {
- i = ceil((float)(-surplus)/(uncolh - colh));
+ i = ceil((float)(-surplus) / (uncolh - colh));
if(i >= nuncol)
i = nuncol - 1;
nuncol -= i;
ncol += i;
surplus += i * (uncolh - colh);
}
+ /* Push to the floating layer until there is room */
if(surplus < 0) {
i = ceil((float)(-surplus)/colh);
if(i > ncol)
@@ -249,72 +239,81 @@ scale_column(Area *a) {
surplus += i * colh;
}
- i = ncol - 1;
j = nuncol - 1;
- for(f=a->frame; f; f=f->anext) {
- if(f == a->sel)
- j++;
- if(!f->collapsed) {
- if(j < 0 && f != a->sel)
- f->collapsed = True;
- else {
- if(f->crect.height <= minh)
- f->crect.height = 1;
- else
- f->crect.height -= minh;
- dy += f->crect.height;
- }
- j--;
- }
- }
+ i = ncol - 1;
+ /* Decide which to collapse, float */
for(fp=&a->frame; *fp;) {
f = *fp;
if(f == a->sel)
- i++;
+ i++, j++;
if(f->collapsed) {
- if(i < 0 && f != a->sel) {
+ if(i < 0 && (f != a->sel)) {
f->collapsed = False;
send_to_area(f->view->area, f);
continue;
}
i--;
+ }else {
+ if(j < 0 && (f != a->sel))
+ f->collapsed = True;
+ j--;
}
+ /* Doesn't change if we 'continue' */
fp=&f->anext;
}
- i = nuncol;
+ surplus = 0;
for(f=a->frame; f; f=f->anext) {
- f->rect.x = a->rect.x;
- f->rect.width = a->rect.width;
+ f->r = rectsubpt(f->r, f->r.min);
+ f->crect = rectsubpt(f->crect, f->crect.min);
+ f->r.max.x = Dx(a->r);
+
+ if(f->collapsed) {
+ f->r.max.y = colh;
+ }else {
+ f->r.max.y = uncolh;
+ dy += Dy(f->crect);
+ }
+ surplus += Dy(f->r);
+ }
+ for(f = a->frame; f; f = f->anext)
+ f->ratio = (float)Dy(f->crect)/dy;
+
+ j = 0;
+ surplus = Dy(a->r) - surplus;
+ while(surplus > 0 && surplus != j) {
+ j = surplus;
+ dy = 0;
+ for(f=a->frame; f; f=f->anext) {
+ if(!f->collapsed)
+ f->r.max.y += f->ratio * surplus;
+ resize_frame(f, f->r);
+ dy += Dy(f->r);
+ }
+ surplus = Dy(a->r) - dy;
+ }
+ for(f=a->frame; f && surplus > 0; f=f->anext) {
if(!f->collapsed) {
- i--;
- f->rect.height = (float)f->crect.height / dy * surplus;
- if(!i)
- f->rect.height = surplus;
- f->rect.height += minh + frame_delta_h();
- apply_sizehints(f->client, &f->rect, False, True, NWEST);
-
- dy -= f->crect.height;
- surplus -= f->rect.height - frame_delta_h() - minh;
- }else
- f->rect.height = labelh(&def.font);
+ dy = Dy(f->r);
+ f->r.max.y += surplus;
+ resize_frame(f, f->r);
+ f->r.max.y = Dy(f->crect) + labelh(def.font) + 1;
+ surplus -= Dy(f->r) - dy;
+ }
}
- yoff = a->rect.y;
+ yoff = a->r.min.y;
i = nuncol;
for(f=a->frame; f; f=f->anext) {
- f->rect.y = yoff;
- f->rect.x = a->rect.x;
- f->rect.width = a->rect.width;
- if(f->collapsed)
- yoff += f->rect.height;
- else{
+ f->r = rectaddpt(f->r, Pt(a->r.min.x, yoff));
+
+ if(!f->collapsed) {
i--;
- f->rect.height += surplus / nuncol;
+ f->r.max.y += surplus / nuncol;
if(!i)
- f->rect.height += surplus % nuncol;
- yoff += f->rect.height;
+ f->r.max.y += surplus % nuncol;
}
+ yoff = f->r.max.y;
}
}
@@ -327,11 +326,9 @@ arrange_column(Area *a, Bool dirty) {
switch(a->mode) {
case Coldefault:
- for(f=a->frame; f; f=f->anext) {
- f->collapsed = False;
- if(dirty)
- f->crect.height = 100;
- }
+ if(dirty)
+ for(f=a->frame; f; f=f->anext)
+ f->r = Rect(0, 0, 100, 100);
break;
case Colstack:
for(f=a->frame; f; f=f->anext)
@@ -340,7 +337,7 @@ arrange_column(Area *a, Bool dirty) {
case Colmax:
for(f=a->frame; f; f=f->anext) {
f->collapsed = False;
- f->rect = a->rect;
+ f->r = a->r;
}
goto resize;
default:
@@ -351,14 +348,14 @@ arrange_column(Area *a, Bool dirty) {
resize:
if(a->view == screen->sel) {
restack_view(a->view);
- resize_client(a->sel->client, &a->sel->rect);
+ resize_client(a->sel->client, &a->sel->r);
for(f=a->frame; f; f=f->anext)
if(!f->collapsed && f != a->sel)
- resize_client(f->client, &f->rect);
+ resize_client(f->client, &f->r);
for(f=a->frame; f; f=f->anext)
if(f->collapsed && f != a->sel)
- resize_client(f->client, &f->rect);
+ resize_client(f->client, &f->r);
}
}
@@ -370,60 +367,50 @@ resize_column(Area *a, int w) {
an = a->next;
assert(an != nil);
- dw = w - a->rect.width;
- a->rect.width += dw;
- an->rect.width -= dw;
+ dw = w - Dx(a->r);
+ a->r.max.x += dw;
+ an->r.min.x += dw;
arrange_view(a->view);
focus_view(screen, a->view);
}
static void
-resize_colframeh(Frame *f, XRectangle *r) {
+resize_colframeh(Frame *f, Rectangle *r) {
Area *a;
- Frame *fa, *fb;
+ Frame *fn, *fp;
uint minh;
- int dy, dh, maxy;
- a = f->area;
- maxy = r_south(r);
-
- minh = 2 * labelh(&def.font);
+ minh = 2 * labelh(def.font);
- fa = f->anext;
- for(fb = a->frame; fb; fb = fb->anext)
- if(fb->anext == f) break;
+ a = f->area;
+ fn = f->anext;
+ fp = f->aprev;
- if(fb)
- r->y = max(r->y, fb->rect.y + minh);
+ if(fp)
+ r->min.y = max(r->min.y, fp->r.min.y + minh);
else
- r->y = a->rect.y;
+ r->min.y = max(r->min.y, a->r.min.y);
- if(fa) {
- if(maxy > r_south(&fa->rect) - minh)
- maxy = r_south(&fa->rect) - minh;
- }
+ if(fn)
+ r->max.y = min(r->max.y, fn->r.max.y - minh);
else
- if(r_south(r) >= r_south(&a->rect))
- maxy = r_south(&a->rect) - 1;
-
- dy = f->rect.y - r->y;
- dh = maxy - r_south(&f->rect);
- if(fb) {
- fb->rect.height -= dy;
- resize_frame(fb, &fb->rect);
+ r->max.y = min(r->max.y, a->r.max.y);
+
+ if(fp) {
+ fp->r.max.y = r->min.y;
+ resize_frame(fp, fp->r);
}
- if(fa) {
- fa->rect.height -= dh;
- resize_frame(fa, &fa->rect);
+ if(fn) {
+ fn->r.min.y = r->max.y;
+ resize_frame(fn, fn->r);
}
- f->rect.height = maxy - r->y;
- resize_frame(f, &f->rect);
+ resize_frame(f, *r);
}
void
-resize_colframe(Frame *f, XRectangle *r) {
+resize_colframe(Frame *f, Rectangle *r) {
Area *a, *al, *ar;
View *v;
uint minw;
@@ -431,51 +418,43 @@ resize_colframe(Frame *f, XRectangle *r) {
a = f->area;
v = a->view;
- maxx = r_east(r);
+ maxx = r->max.x;
- minw = screen->rect.width/NCOL;
+ minw = Dx(screen->r) / NCOL;
+ al = a->prev;
ar = a->next;
for(al = v->area->next; al; al = al->next)
if(al->next == a) break;
if(al)
- r->x = max(r->x, al->rect.x + minw);
+ r->min.x = max(r->min.x, al->r.min.x + minw);
else
- r->x = max(r->x, 0);
+ r->min.x = max(r->min.x, 0);
if(ar) {
- if(maxx >= r_east(&ar->rect) - minw)
- maxx = r_east(&ar->rect) - minw;
+ if(maxx >= ar->r.max.x - minw)
+ maxx = ar->r.max.x - minw;
}
else
- if(maxx > screen->rect.width)
- maxx = screen->rect.width - 1;
+ if(maxx > screen->r.max.x)
+ maxx = screen->r.max.x;
- dx = a->rect.x - r->x;
- dw = maxx - r_east(&a->rect);
+ dx = a->r.min.x - r->min.x;
+ dw = maxx - a->r.max.x;
if(al) {
- al->rect.width -= dx;
+ al->r.max.x -= dx;
arrange_column(al, False);
}
if(ar) {
- ar->rect.width -= dw;
+ ar->r.max.x -= dw;
arrange_column(ar, False);
}
resize_colframeh(f, r);
- a->rect.width = maxx - r->x;
+ a->r.max.x = maxx;
arrange_view(a->view);
focus_view(screen, v);
}
-
-Area *
-new_column(View *v, Area *pos, uint w) {
- Area *a = create_area(v, pos, w);
- if(!a)
- return nil;
- arrange_view(v);
- return a;
-}
diff --git a/cmd/wmii/dat.h b/cmd/wmii/dat.h
@@ -2,27 +2,18 @@
* See LICENSE file for license details.
*/
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
#include <regex.h>
#include <ixp.h>
+#include <utf.h>
+#include "x11.h"
-#define BLITZ_FONT "-*-fixed-medium-r-normal-*-13-*-*-*-*-*-*-*"
-#define BLITZ_FOCUSCOLORS "#ffffff #335577 #447799"
-#define BLITZ_NORMCOLORS "#222222 #eeeeee #666666"
+#define FONT "-*-fixed-medium-r-*-*-13-*-*-*-*-*-*-*"
+#define FOCUSCOLORS "#ffffff #335577 #447799"
+#define NORMCOLORS "#222222 #eeeeee #666666"
-typedef struct Blitz Blitz;
-typedef struct BlitzColor BlitzColor;
-typedef struct BlitzFont BlitzFont;
-typedef struct BlitzBrush BlitzBrush;
+typedef struct CTuple CTuple;
-struct Blitz {
- Display *dpy;
- int screen;
- Window root;
-};
-
-enum BlitzAlign {
+enum Align {
NORTH = 0x01,
EAST = 0x02,
SOUTH = 0x04,
@@ -34,60 +25,31 @@ enum BlitzAlign {
CENTER = NEAST | SWEST
};
-typedef enum BlitzAlign BlitzAlign;
+typedef enum Align Align;
-struct BlitzColor {
- vlong bg;
- vlong fg;
- vlong border;
+struct CTuple {
+ ulong bg;
+ ulong fg;
+ ulong border;
char colstr[24]; /* #RRGGBB #RRGGBB #RRGGBB */
};
-struct BlitzFont {
- XFontStruct *xfont;
- XFontSet set;
- int ascent;
- int descent;
- uint height;
- char *fontstr;
-};
-
-struct BlitzBrush {
- Blitz *blitz;
- Drawable drawable;
- GC gc;
- int border;
- BlitzColor color;
- BlitzAlign align;
- BlitzFont *font;
- XRectangle rect; /* relative rect */
-};
-
enum {
-/* WM atom */
- WMState, WMProtocols, WMDelete,
-/* NET atom */
- NetSupported, NetWMName,
-/* Other */
- TagsAtom,
-/* Last atom */
- AtomLast
+ Coldefault, Colstack, Colmax
};
-/* Column modes */
-enum { Coldefault, Colstack, Colmax };
-
-/* Cursor */
enum {
CurNormal,
CurNECorner, CurNWCorner, CurSECorner, CurSWCorner,
- CurDHArrow, CurMove, CurInput,
+ CurDHArrow, CurMove, CurInput, CurSizing, CurIcon,
CurInvisible,
CurLast
};
-enum { NCOL = 16 };
-enum { WM_PROTOCOL_DELWIN = 1 };
+enum {
+ NCOL = 16,
+ WM_PROTOCOL_DELWIN = 1
+};
/* Data Structures */
typedef struct View View;
@@ -100,6 +62,20 @@ typedef struct Bar Bar;
typedef struct Rule Rule;
typedef struct Ruleset Ruleset;
typedef struct WMScreen WMScreen;
+typedef struct Map Map;
+typedef struct MapEnt MapEnt;
+
+struct Map {
+ MapEnt **bucket;
+ uint nhash;
+};
+
+struct MapEnt {
+ ulong hash;
+ char *key;
+ void *val;
+ MapEnt *next;
+};
struct View {
View *next;
@@ -111,7 +87,7 @@ struct View {
};
struct Area {
- Area *next;
+ Area *next, *prev;
Frame *frame;
Frame *stack;
Frame *sel;
@@ -119,23 +95,24 @@ struct Area {
Bool floating;
ushort id;
int mode;
- XRectangle rect;
+ Rectangle r;
};
struct Frame {
Frame *cnext;
- Frame *anext;
- Frame *snext;
+ Frame *anext, *aprev;
+ Frame *snext, *sprev;
View *view;
Area *area;
ushort id;
- XRectangle rect;
- XRectangle crect;
- XRectangle revert;
+ Rectangle r;
+ Rectangle crect;
+ Rectangle revert;
Client *client;
Bool collapsed;
- XRectangle grabbox;
- XRectangle titlebar;
+ Rectangle grabbox;
+ Rectangle titlebar;
+ float ratio;
};
struct Client {
@@ -152,21 +129,22 @@ struct Client {
Bool fixedsize;
Bool fullscreen;
Bool urgent;
- Bool mapped;
- Bool frame_mapped;
+ Bool borderless;
+ Bool titleless;
+ Bool noinput;
int unmapped;
- Window win;
- Window trans;
- Window framewin;
+ Window w;
+ XWindow trans;
+ Window *framewin;
Cursor cursor;
- XRectangle rect;
+ Rectangle r;
XSizeHints size;
GC gc;
};
struct Divide {
Divide *next;
- Window w;
+ Window *w;
Bool mapped;
int x;
};
@@ -188,7 +166,8 @@ struct Bar {
char text[256];
char name[256];
ushort id;
- BlitzBrush brush;
+ Rectangle r;
+ CTuple col;
};
struct Rule {
@@ -205,9 +184,9 @@ struct Ruleset {
/* global variables */
struct {
- BlitzColor focuscolor;
- BlitzColor normcolor;
- BlitzFont font;
+ CTuple focuscolor;
+ CTuple normcolor;
+ Font *font;
uint border;
uint snap;
char *keys;
@@ -219,18 +198,20 @@ struct {
int colmode;
} def;
-enum { BarLeft, BarRight };
+enum {
+ BarLeft, BarRight
+};
struct WMScreen {
Bar *bar[2];
View *sel;
Client *focus;
Client *hasgrab;
- Window barwin;
+ Window *barwin;
+ Image *ibuf;
- XRectangle rect;
- XRectangle brect;
- BlitzBrush bbrush;
+ Rectangle r;
+ Rectangle brect;
} *screens, *screen;
Client *client;
@@ -240,6 +221,8 @@ Divide *divs;
Client c_magic;
Client c_root;
+Handlers framehandler;
+
char buffer[8092];
/* IXP */
@@ -252,17 +235,17 @@ uint valid_mask;
uint num_lock_mask;
Bool sel_screen;
-Blitz blz;
-GC xorgc;
-Pixmap pmap;
-Pixmap divmap, divmask;
+Image xor;
-Atom atom[AtomLast];
Cursor cursor[CurLast];
void (*handler[LASTEvent]) (XEvent *);
/* Misc */
+Image *broken;
Bool starting;
Bool verbose;
char *user;
char *execstr;
+
+#define Debug if(verbose)
+
diff --git a/cmd/wmii/draw.c b/cmd/wmii/draw.c
@@ -1,244 +0,0 @@
-/* Copyright ©2004-2006 Anselm R. Garbe <garbeam at gmail dot com>
- * See LICENSE file for license details.
- */
-#include <ctype.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <util.h>
-#include "dat.h"
-#include "fns.h"
-
-uint
-textwidth_l(BlitzFont *font, char *text, uint len) {
- if(font->set) {
- XRectangle r;
- XmbTextExtents(font->set, text, len, &r, nil);
- return r.width;
- }
- return XTextWidth(font->xfont, text, len);
-}
-
-uint
-textwidth(BlitzFont *font, char *text) {
- return textwidth_l(font, text, strlen(text));
-}
-
-void
-loadfont(Blitz *blitz, BlitzFont *font) {
- char *fontname = font->fontstr;
- char **missing = nil, *def = "?";
- int n, i;
-
- if(font->set)
- XFreeFontSet(blitz->dpy, font->set);
- font->set = XCreateFontSet(blitz->dpy, fontname, &missing, &n, &def);
- if(missing) {
- fprintf(stderr, "%s: missing fontset%s for '%s':", argv0,
- (n > 1 ? "s":""), fontname);
- for(i = 0; i < n; i++)
- fprintf(stderr, "%s %s", (i ? ",":""), missing[i]);
- fprintf(stderr, "\n");
- XFreeStringList(missing);
- }
- if(font->set) {
- XFontSetExtents *font_extents;
- XFontStruct **xfonts;
- char **font_names;
-
- font->ascent = font->descent = 0;
- font_extents = XExtentsOfFontSet(font->set);
- XFontsOfFontSet(font->set, &xfonts, &font_names);
- font->ascent = xfonts[0]->ascent;
- font->descent = xfonts[0]->descent;
- }
- else {
- if(font->xfont)
- XFreeFont(blitz->dpy, font->xfont);
- font->xfont = nil;
- font->xfont = XLoadQueryFont(blitz->dpy, fontname);
- fprintf(stderr, "%s: cannot load font: %s\n", argv0, fontname);
- if(!font->xfont) {
- if(!strcmp(fontname, BLITZ_FONT))
- fatal("cannot load font: %s", BLITZ_FONT);
- free(font->fontstr);
- font->fontstr = estrdup(BLITZ_FONT);
- loadfont(blitz, font);
- return;
- }
- font->ascent = font->xfont->ascent;
- font->descent = font->xfont->descent;
- }
- font->height = font->ascent + font->descent;
-}
-
-uint
-labelh(BlitzFont *font) {
- return font->height + 2;
-}
-
-void
-draw_tile(BlitzBrush *b) {
- drawbg(b->blitz->dpy, b->drawable, b->gc, &b->rect,
- b->color, True, b->border);
-}
-
-void
-draw_border(BlitzBrush *b) {
- drawbg(b->blitz->dpy, b->drawable, b->gc, &b->rect,
- b->color, False, b->border);
-}
-
-void
-draw_label(BlitzBrush *b, char *text) {
- uint x, y, w, h, len;
- Bool shortened = False;
- static char buf[2048];
- XRectangle r = {0};
- XGCValues gcv;
-
- draw_tile(b);
- if(!text)
- return;
- shortened = 0;
- strncpy(buf, text, sizeof(buf));
- len = strlen(buf);
- gcv.foreground = b->color.fg;
- gcv.background = b->color.bg;
- h = b->font->ascent + b->font->descent;
- y = b->rect.y + b->rect.height / 2 - h / 2 + b->font->ascent;
- /* shorten text if necessary */
- while(len
- && (w = textwidth(b->font, buf)) > b->rect.width - (b->font->height & ~1)) {
- buf[--len] = 0;
- shortened = True;
- }
- if(!len)
- return;
- if(w > b->rect.width)
- return;
- /* mark shortened info in the string */
- if(shortened) {
- if (len > 3)
- buf[len - 3] = '.';
- if (len > 2)
- buf[len - 2] = '.';
- if (len > 1)
- buf[len - 1] = '.';
- }
-
- if(b->font->set)
- XmbTextExtents(b->font->set, text, len, &r, nil);
-
- switch (b->align) {
- case EAST:
- x = b->rect.x + b->rect.width - (w + (b->font->height / 2));
- break;
- default:
- x = b->rect.x + (b->font->height / 2) - r.x;
- break;
- }
- if(b->font->set) {
- XChangeGC(b->blitz->dpy, b->gc, GCForeground | GCBackground, &gcv);
- XmbDrawImageString(b->blitz->dpy, b->drawable, b->font->set, b->gc,
- x, y, buf, len);
- }
- else {
- gcv.font = b->font->xfont->fid;
- XChangeGC(b->blitz->dpy, b->gc, GCForeground | GCBackground | GCFont, &gcv);
- XDrawImageString(b->blitz->dpy, b->drawable, b->gc, x, y, buf, len);
- }
-}
-
-void
-drawbg(Display *dpy, Drawable drawable, GC gc, XRectangle *rect,
- BlitzColor c, Bool fill, int border)
-{
- if(fill) {
- XSetForeground(dpy, gc, c.bg);
- XFillRectangles(dpy, drawable, gc, rect, 1);
- }
- if(border) {
- XSetLineAttributes(dpy, gc, border, LineSolid, CapButt, JoinMiter);
- XSetForeground(dpy, gc, c.border);
- XDrawRectangle(dpy, drawable, gc,
- rect->x + border / 2,
- rect->y + border / 2,
- rect->width - border,
- rect->height - border);
- }
-}
-
-void
-drawcursor(Display *dpy, Drawable drawable, GC gc,
- int x, int y, uint h, BlitzColor c)
-{
- XSegment s[5];
-
- XSetForeground(dpy, gc, c.fg);
- XSetLineAttributes(dpy, gc, 1, LineSolid, CapButt, JoinMiter);
- s[0].x1 = x - 1;
- s[0].y1 = s[0].y2 = y;
- s[0].x2 = x + 2;
- s[1].x1 = x - 1;
- s[1].y1 = s[1].y2 = y + 1;
- s[1].x2 = x + 2;
- s[2].x1 = s[2].x2 = x;
- s[2].y1 = y;
- s[2].y2 = y + h;
- s[3].x1 = x - 1;
- s[3].y1 = s[3].y2 = y + h;
- s[3].x2 = x + 2;
- s[4].x1 = x - 1;
- s[4].y1 = s[4].y2 = y + h - 1;
- s[4].x2 = x + 2;
- XDrawSegments(dpy, drawable, gc, s, 5);
-}
-
-static ulong
-xloadcolor(Blitz *blitz, char *colstr) {
- XColor color;
- char col[8];
-
- strncpy(col, colstr, sizeof(col));
- col[7] = 0;
- XAllocNamedColor(blitz->dpy,
- DefaultColormap(blitz->dpy, blitz->screen), col, &color, &color);
- return color.pixel;
-}
-
-int
-loadcolor(Blitz *blitz, BlitzColor *c) {
- if(!c->colstr || strlen(c->colstr) != 23)
- return -1;
- c->fg = xloadcolor(blitz, &c->colstr[0]);
- c->bg = xloadcolor(blitz, &c->colstr[8]);
- c->border = xloadcolor(blitz, &c->colstr[16]);
- return 0;
-}
-
-char *
-parse_colors(char **buf, int *buflen, BlitzColor *col) {
- static regex_t reg;
- static Bool compiled;
-
- if(!compiled) {
- compiled = 1;
- regcomp(®, "^#[0-9a-f]{6} #[0-9a-f]{6} #[0-9a-f]{6}",
- REG_EXTENDED|REG_NOSUB|REG_ICASE);
- }
-
- if(*buflen < 23 || regexec(®, *buf, 0, 0, 0))
- return "bad value";
-
- memcpy(col->colstr, *buf, 23);
- loadcolor(&blz, col);
-
- *buf += 23;
- *buflen -= 23;
- if(isspace(**buf)) {
- (*buf)++;
- (*buflen)--;
- }
- return nil;
-}
diff --git a/cmd/wmii/event.c b/cmd/wmii/event.c
@@ -1,5 +1,4 @@
-/* Copyright ©2004-2006 Anselm R. Garbe <garbeam at gmail dot com>
- * Copyright ©2006-2007 Kris Maglione <fbsdaemon@gmail.com>
+/* Copyright ©2006-2007 Kris Maglione <fbsdaemon@gmail.com>
* See LICENSE file for license details.
*/
#include <stdio.h>
@@ -11,16 +10,19 @@
void
dispatch_event(XEvent *e) {
+ Debug printevent(e);
if(handler[e->type])
handler[e->type](e);
}
+#define handle(w, fn, ev) ((w)->handler->fn ? (w)->handler->fn((w), ev) : (void)0)
+
uint
flushevents(long event_mask, Bool dispatch) {
XEvent ev;
uint n = 0;
- while(XCheckMaskEvent(blz.dpy, event_mask, &ev)) {
+ while(XCheckMaskEvent(display, event_mask, &ev)) {
if(dispatch)
dispatch_event(&ev);
n++;
@@ -31,135 +33,35 @@ flushevents(long event_mask, Bool dispatch) {
static void
buttonrelease(XEvent *e) {
XButtonPressedEvent *ev;
- Frame *f;
- Bar *b;
+ Window *w;
ev = &e->xbutton;
- if(ev->window == screen->barwin) {
- for(b=screen->bar[BarLeft]; b; b=b->next)
- if(ptinrect(ev->x, ev->y, &b->brush.rect)) {
- write_event("LeftBarClick %d %s\n", ev->button, b->name);
- return;
- }
- for(b=screen->bar[BarRight]; b; b=b->next)
- if(ptinrect(ev->x, ev->y, &b->brush.rect)) {
- write_event("RightBarClick %d %s\n", ev->button, b->name);
- return;
- }
- }
- else if((f = win2frame(ev->window)))
- write_event("ClientClick 0x%x %d\n", f->client->win, ev->button);
+ if((w = findwin(ev->window)))
+ handle(w, bup, ev);
}
static void
buttonpress(XEvent *e) {
XButtonPressedEvent *ev;
- Divide *d;
- Frame *f;
+ Window *w;
ev = &e->xbutton;
- if((f = win2frame(ev->window))) {
- if((ev->state & def.mod) == def.mod) {
- switch(ev->button) {
- case Button1:
- do_mouse_resize(f->client, False, CENTER);
- focus(f->client, True);
- frame_to_top(f);
- focus(f->client, True);
- break;
- case Button3:
- do_mouse_resize(f->client, False,
- quadrant(&f->rect, ev->x_root, ev->y_root));
- frame_to_top(f);
- focus(f->client, True);
- break;
- default: break;
- XAllowEvents(blz.dpy, ReplayPointer, ev->time);
- }
- }else{
- if(ev->button == Button1) {
- if(frame_to_top(f))
- restack_view(f->view);
-
- else if(ptinrect(ev->x, ev->y, &f->grabbox))
- do_mouse_resize(f->client, True, CENTER);
- else if(f->area->floating)
- if(!ev->subwindow && !ptinrect(ev->x, ev->y, &f->titlebar))
- do_mouse_resize(f->client, False,
- quadrant(&f->rect, ev->x_root, ev->y_root));
-
- if(f->client != selclient())
- focus(f->client, True);
- }
- if(ev->subwindow)
- XAllowEvents(blz.dpy, ReplayPointer, ev->time);
- else {
- /* Ungrab so a menu can receive events before the button is released */
- XUngrabPointer(blz.dpy, ev->time);
- XSync(blz.dpy, False);
-
- write_event("ClientMouseDown 0x%x %d\n", f->client->win, ev->button);
- }
- }
- }
- else if((d = win2div(ev->window)))
- mouse_resizecol(d);
+ if((w = findwin(ev->window)))
+ handle(w, bdown, ev);
else
- XAllowEvents(blz.dpy, ReplayPointer, ev->time);
+ XAllowEvents(display, ReplayPointer, ev->time);
}
static void
configurerequest(XEvent *e) {
XConfigureRequestEvent *ev;
XWindowChanges wc;
- XRectangle *frect;
- Client *c;
- Frame *f;
+ Window *w;
ev = &e->xconfigurerequest;
- c = win2client(ev->window);
- if(c) {
- f = c->sel;
- gravitate_client(c, True);
- if(ev->value_mask & CWX)
- c->rect.x = ev->x;
- if(ev->value_mask & CWY)
- c->rect.y = ev->y;
- if(ev->value_mask & CWWidth)
- c->rect.width = ev->width;
- if(ev->value_mask & CWHeight)
- c->rect.height = ev->height;
- if(ev->value_mask & CWBorderWidth)
- c->border = ev->border_width;
- gravitate_client(c, False);
-
- if((c->rect.height == screen->rect.height)
- && (c->rect.width == screen->rect.width)) {
- c->fullscreen = True;
- if(c->sel) {
- if(!c->sel->area->floating)
- send_to_area(c->sel->view->area, c->sel);
- focus_client(c);
- restack_view(c->sel->view);
- }
- }
-
- if(c->sel->area->floating)
- frect=&c->sel->rect;
- else
- frect=&c->sel->revert;
-
- *frect = c->rect;
- frect->y -= labelh(&def.font);
- frect->x -= def.border;
- frect->width += 2 * def.border;
- frect->height += frame_delta_h();
-
- if(c->sel->area->floating || c->fullscreen)
- resize_client(c, frect);
- else
- configure_client(c);
- }else{
+ if((w = findwin(ev->window)))
+ handle(w, configreq, ev);
+ else{
wc.x = ev->x;
wc.y = ev->y;
wc.width = ev->width;
@@ -167,50 +69,39 @@ configurerequest(XEvent *e) {
wc.border_width = ev->border_width;
wc.sibling = ev->above;
wc.stack_mode = ev->detail;
- ev->value_mask &= ~(CWStackMode|CWSibling);
- XConfigureWindow(blz.dpy, ev->window, ev->value_mask, &wc);
- XSync(blz.dpy, False);
+ XConfigureWindow(display, ev->window, ev->value_mask, &wc);
}
}
static void
destroynotify(XEvent *e) {
XDestroyWindowEvent *ev;
+ Window *w;
Client *c;
ev = &e->xdestroywindow;
- if((c = win2client(ev->window)))
- destroy_client(c);
+ if((w = findwin(ev->window)))
+ handle(w, destroy, ev);
+ else {
+ Debug fprintf(stderr, "DestroyWindow(%x) (no handler)\n", (uint)ev->window);
+ if((c = win2client(ev->window)))
+ fprintf(stderr, "Badness: Unhandled DestroyNotify: "
+ "Client: %p, Window: %x, Name: %s\n", c, (uint)c->w.w, c->name);
+ }
}
static void
enternotify(XEvent *e) {
XCrossingEvent *ev;
- Client *c;
- Frame *f;
+ Window *w;
ev = &e->xcrossing;
if(ev->mode != NotifyNormal)
return;
- if((c = win2client(ev->window))) {
- if(ev->detail != NotifyInferior) {
- if(screen->focus != c) {
- if(verbose) fprintf(stderr, "enter_notify(c) => %s\n", c->name);
- focus(c, False);
- }
- set_cursor(c, cursor[CurNormal]);
- }else if(verbose) fprintf(stderr, "enter_notify(c[NotifyInferior]) => %s\n", c->name);
- }
- else if((f = win2frame(ev->window))) {
- if(screen->focus != c) {
- if(verbose) fprintf(stderr, "enter_notify(f) => %s\n", f->client->name);
- if(f->area->floating || !f->collapsed)
- focus(f->client, False);
- }
- set_frame_cursor(f, ev->x, ev->y);
- }
- else if(ev->window == blz.root) {
+ if((w = findwin(ev->window)))
+ handle(w, enter, ev);
+ else if(ev->window == scr.root.w) {
sel_screen = True;
draw_frames();
}
@@ -219,9 +110,11 @@ enternotify(XEvent *e) {
static void
leavenotify(XEvent *e) {
XCrossingEvent *ev;
+ Window *w;
ev = &e->xcrossing;
- if((ev->window == blz.root) && !ev->same_screen) {
+ w = findwin(ev->window);
+ if((ev->window == scr.root.w) && !ev->same_screen) {
sel_screen = True;
draw_frames();
}
@@ -229,25 +122,26 @@ leavenotify(XEvent *e) {
void
print_focus(Client *c, char *to) {
- if(verbose) {
- fprintf(stderr, "screen->focus: %p => %p\n",
- screen->focus, c);
- fprintf(stderr, "\t%s => %s\n",
- screen->focus ? screen->focus->name : "<nil>",
- to);
+ Debug {
+ fprintf(stderr, "screen->focus: %p[%x] => %p[%x]\n",
+ screen->focus, clientwin(screen->focus), c, clientwin(c));
+ fprintf(stderr, "\t%s => %s\n", clientname(screen->focus), to);
}
}
static void
focusin(XEvent *e) {
XFocusChangeEvent *ev;
- Client *c, *old;
+ Window *w;
+ Client *c;
XEvent me;
ev = &e->xfocus;
/* Yes, we're focusing in on nothing, here. */
if(ev->detail == NotifyDetailNone) {
- XSetInputFocus(blz.dpy, screen->barwin, RevertToParent, CurrentTime);
+ print_focus(&c_magic, "<magic[none]>");
+ screen->focus = &c_magic;
+ setfocus(screen->barwin, RevertToParent);
return;
}
@@ -257,34 +151,22 @@ focusin(XEvent *e) {
||(ev->detail == NotifyInferior)
||(ev->detail == NotifyAncestor)))
return;
- if((ev->mode == NotifyWhileGrabbed)
- && (screen->hasgrab != &c_root))
+ if((ev->mode == NotifyWhileGrabbed) && (screen->hasgrab != &c_root))
return;
- old = screen->focus;
- c = win2client(ev->window);
- if(c) {
- print_focus(c, c->name);
- if(ev->mode == NotifyGrab)
- screen->hasgrab = c;
- screen->focus = c;
- if(c != old) {
- update_client_grab(c);
- if(c->sel)
- draw_frame(c->sel);
- if(old && old->sel)
- draw_frame(old->sel);
- }
- }else if(ev->window == screen->barwin) {
+ if(ev->window == screen->barwin->w) {
print_focus(nil, "<nil>");
screen->focus = nil;
- }else if(ev->mode == NotifyGrab) {
- if(ev->window == blz.root)
- if(XCheckMaskEvent(blz.dpy, KeyPressMask, &me)) {
+ }
+ else if((w = findwin(ev->window)))
+ handle(w, focusin, ev);
+ else if(ev->mode == NotifyGrab) {
+ if(ev->window == scr.root.w)
+ if(XCheckMaskEvent(display, KeyPressMask, &me)) {
/* wmii has grabbed focus */
screen->hasgrab = &c_root;
+ flushevents(FocusChangeMask, True);
dispatch_event(&me);
- return;
}
/* Some unmanaged window has grabbed focus */
if((c = screen->focus)) {
@@ -299,61 +181,44 @@ focusin(XEvent *e) {
static void
focusout(XEvent *e) {
XFocusChangeEvent *ev;
- Client *c;
+ Window *w;
ev = &e->xfocus;
if(!((ev->detail == NotifyNonlinear)
- ||(ev->detail == NotifyNonlinearVirtual)))
+ ||(ev->detail == NotifyNonlinearVirtual)
+ ||(ev->detail == NotifyVirtual)
+ ||(ev->detail == NotifyInferior)
+ ||(ev->detail == NotifyAncestor)))
return;
if(ev->mode == NotifyUngrab)
screen->hasgrab = nil;
- c = win2client(ev->window);
- if(c) {
- if((ev->mode == NotifyWhileGrabbed)
- && (screen->hasgrab != &c_root)) {
- if((screen->focus)
- && (screen->hasgrab != screen->focus))
- screen->hasgrab = screen->focus;
- if(screen->hasgrab == c)
- return;
- }else if(ev->mode != NotifyGrab) {
- if(screen->focus == c) {
- print_focus(&c_magic, "<magic>");
- screen->focus = &c_magic;
- }
- update_client_grab(c);
- if(c->sel)
- draw_frame(c->sel);
- }
- }
+ if((w = findwin(ev->window)))
+ handle(w, focusout, ev);
}
static void
expose(XEvent *e) {
XExposeEvent *ev;
- Divide *d;
- Frame *f;
+ Window *w;
ev = &e->xexpose;
if(ev->count == 0) {
- if(ev->window == screen->barwin)
- draw_bar(screen);
- else if((f = win2frame(ev->window)))
- draw_frame(f);
- else if((d = win2div(ev->window)))
- draw_div(d);
+ if((w = findwin(ev->window)))
+ handle(w, expose, ev);
}
}
static void
keypress(XEvent *e) {
XKeyEvent *ev;
+ Window *w;
ev = &e->xkey;
+ w = findwin(ev->window);
ev->state &= valid_mask;
- if(ev->window == blz.root)
- kpress(blz.root, ev->state, (KeyCode) ev->keycode);
+ if(ev->window == scr.root.w)
+ kpress(scr.root.w, ev->state, (KeyCode) ev->keycode);
}
static void
@@ -369,93 +234,92 @@ mappingnotify(XEvent *e) {
static void
maprequest(XEvent *e) {
XMapRequestEvent *ev;
- static XWindowAttributes wa;
+ Window *w;
+ XWindowAttributes wa;
ev = &e->xmaprequest;
- if(!XGetWindowAttributes(blz.dpy, ev->window, &wa))
+ w = findwin(ev->window);
+
+ if(!XGetWindowAttributes(display, ev->window, &wa))
return;
+
if(wa.override_redirect) {
- XSelectInput(blz.dpy, ev->window,
+ XSelectInput(display, ev->window,
(StructureNotifyMask | PropertyChangeMask));
return;
}
if(!win2client(ev->window))
- manage_client(create_client(ev->window, &wa));
+ create_client(ev->window, &wa);
}
static void
motionnotify(XEvent *e) {
XMotionEvent *ev;
- Frame *f;
+ Window *w;
ev = &e->xmotion;
- if((f = win2frame(ev->window)))
- set_frame_cursor(f, ev->x, ev->y);
+ if((w = findwin(ev->window)))
+ handle(w, motion, ev);
}
static void
propertynotify(XEvent *e) {
XPropertyEvent *ev;
- Client *c;
+ Window *w;
ev = &e->xproperty;
- if(ev->state == PropertyDelete)
- return; /* ignore */
- if((c = win2client(ev->window)))
- prop_client(c, ev->atom);
+ if((w = findwin(ev->window)))
+ handle(w, property, ev);
}
static void
mapnotify(XEvent *e) {
XMapEvent *ev;
- Client *c;
+ Window *w;
ev = &e->xmap;
- if((c = win2client(ev->window)))
- if(c == selclient())
- focus_client(c);
+ if((w = findwin(ev->window)))
+ handle(w, map, ev);
}
static void
unmapnotify(XEvent *e) {
XUnmapEvent *ev;
- Client *c;
+ Window *w;
ev = &e->xunmap;
- if((c = win2client(ev->window)))
- if(ev->send_event || (c->unmapped-- == 0))
- destroy_client(c);
+ if((w = findwin(ev->window)) && (ev->event == w->parent->w)) {
+ if(ev->send_event || w->unmapped-- == 0)
+ handle(w, unmap, ev);
+ }
}
void (*handler[LASTEvent]) (XEvent *) = {
- [ButtonPress] = buttonpress,
- [ButtonRelease] = buttonrelease,
- [ConfigureRequest]=configurerequest,
- [DestroyNotify] = destroynotify,
- [EnterNotify] = enternotify,
- [Expose] = expose,
- [FocusIn] = focusin,
- [FocusOut] = focusout,
- [KeyPress] = keypress,
- [LeaveNotify] = leavenotify,
- [MapNotify] = mapnotify,
- [MapRequest] = maprequest,
- [MappingNotify] = mappingnotify,
- [MotionNotify] = motionnotify,
- [PropertyNotify]= propertynotify,
- [UnmapNotify] = unmapnotify,
-
+ [ButtonPress] = buttonpress,
+ [ButtonRelease] = buttonrelease,
+ [ConfigureRequest] = configurerequest,
+ [DestroyNotify] = destroynotify,
+ [EnterNotify] = enternotify,
+ [Expose] = expose,
+ [FocusIn] = focusin,
+ [FocusOut] = focusout,
+ [KeyPress] = keypress,
+ [LeaveNotify] = leavenotify,
+ [MapNotify] = mapnotify,
+ [MapRequest] = maprequest,
+ [MappingNotify] = mappingnotify,
+ [MotionNotify] = motionnotify,
+ [PropertyNotify] = propertynotify,
+ [UnmapNotify] = unmapnotify,
};
void
check_x_event(IxpConn *c) {
XEvent ev;
- while(XPending(blz.dpy)) {
- XNextEvent(blz.dpy, &ev);
- if(verbose)
- printevent(&ev);
+ while(XPending(display)) {
+ XNextEvent(display, &ev);
dispatch_event(&ev);
/* Hack to alleviate an apparant Xlib bug */
- XPending(blz.dpy);
+ XPending(display);
}
}
diff --git a/cmd/wmii/fns.h b/cmd/wmii/fns.h
@@ -2,106 +2,89 @@
* See LICENSE file for license details.
*/
-/* wm.c */
-char *message_root(char *message);
-
/* area.c */
Area *create_area(View*, Area *pos, uint w);
void destroy_area(Area*);
Area *area_of_id(View*, ushort id);
void focus_area(Area*);
-char *select_area(Area*, char *arg);
void send_to_area(Area*, Frame*);
void attach_to_area(Area*, Frame*, Bool send);
void detach_from_area(Frame*);
Client *area_selclient(Area*);
/* bar.c */
+void initbar(WMScreen *s);
Bar *create_bar(Bar **b_link, char *name);
void destroy_bar(Bar **b_link, Bar*);
void draw_bar(WMScreen *s);
-void draw_border(BlitzBrush*);
-void resize_bar();
+void resize_bar(WMScreen *s);
Bar *bar_of_name(Bar *b_link, const char *name);
/* client.c */
-Client *create_client(Window, XWindowAttributes*);
+Client *create_client(XWindow, XWindowAttributes*);
void destroy_client(Client*);
void configure_client(Client*);
+void update_class(Client *c);
void prop_client(Client *c, Atom);
void kill_client(Client*);
void gravitate_client(Client*, Bool invert);
void map_client(Client*);
void unmap_client(Client*, int state);
-void map_frame(Client*);
-void unmap_frame(Client*);
-void set_cursor(Client*, Cursor cur);
+int map_frame(Client*);
+int unmap_frame(Client*);
+Rectangle gravclient(Client*, Rectangle);
+void fullscreen(Client*, Bool);
+void set_urgent(Client *, Bool urgent, Bool write);
+void set_cursor(Client*, Cursor);
void focus_frame(Frame*, Bool restack);
-void reparent_client(Client*, Window w, int x, int y);
+void reparent_client(Client*, Window*, Point);
void manage_client(Client*);
void focus(Client*, Bool restack);
void focus_client(Client*);
-void resize_client(Client*, XRectangle*);
-void apply_sizehints(Client*, XRectangle*, Bool floating, Bool frame, BlitzAlign sticky);
-char *send_client(Frame*, char*, Bool swap);
-char * message_client(Client*, char*);
+void resize_client(Client*, Rectangle*);
+void apply_sizehints(Client*, Rectangle*, Bool floating, Bool frame, Align sticky);
void move_client(Client*, char *arg);
void size_client(Client*, char *arg);
-Client *selclient();
-Frame *win2frame(Window);
-Client *win2client(Window);
-void update_client_grab(Client*);
+Client *selclient(void);
+Client *win2client(XWindow);
+uint clientwin(Client *c);
+char *clientname(Client*);
void apply_rules(Client*);
void apply_tags(Client*, const char*);
/* column.c */
-Divide *win2div(Window);
-void update_dividers();
-void update_divs();
+void update_divs(void);
void draw_div(Divide*);
+void setdiv(Divide*, int x);
void arrange_column(Area*, Bool dirty);
void resize_column(Area*, int w);
-void resize_colframe(Frame*, XRectangle*);
+void resize_colframe(Frame*, Rectangle*);
int str2colmode(const char *str);
Area *new_column(View*, Area *pos, uint w);
-/* draw.c */
-int loadcolor(Blitz *, BlitzColor *);
-void draw_label(BlitzBrush *, char *text);
-void draw_tile(BlitzBrush *);
-void draw_rect(BlitzBrush *);
-
-void drawbg(Display*, Drawable, GC,
- XRectangle*, BlitzColor, Bool fill, Bool border);
-void drawcursor(Display*, Drawable, GC,
- int x, int y, uint h, BlitzColor);
-uint textwidth(BlitzFont*, char *text);
-uint textwidth_l(BlitzFont*, char *text, uint len);
-void loadfont(Blitz*, BlitzFont*);
-uint labelh(BlitzFont *font);
-char *parse_colors(char **buf, int *buflen, BlitzColor*);
-
/* event.c */
void dispatch_event(XEvent*);
void check_x_event(IxpConn*);
uint flushevents(long even_mask, Bool dispatch);
+void print_focus(Client *c, char *to);
/* frame.c */
Frame *create_frame(Client*, View*);
void remove_frame(Frame*);
-void insert_frame(Frame *pos, Frame*, Bool before);
-void resize_frame(Frame*, XRectangle*);
+void insert_frame(Frame *pos, Frame*);
+void resize_frame(Frame*, Rectangle);
Bool frame_to_top(Frame *f);
-void set_frame_cursor(Frame*, int x, int y);
+void set_frame_cursor(Frame*, Point);
void swap_frames(Frame*, Frame*);
-int frame_delta_h();
-void frame2client(Frame*, XRectangle*);
-void client2frame(Frame*, XRectangle*);
+int frame_delta_h(void);
+Rectangle frame_hints(Frame*, Rectangle, Align);
+Rectangle frame2client(Frame*, Rectangle);
+Rectangle client2frame(Frame*, Rectangle);
int ingrabbox(Frame*, int x, int y);
void draw_frame(Frame*);
-void draw_frames();
+void draw_frames(void);
void update_frame_widget_colors(Frame*);
-void check_frame_constraints(XRectangle*);
+Rectangle constrain(Rectangle);
/* fs.c */
void fs_attach(Ixp9Req*);
@@ -118,28 +101,41 @@ void fs_write(Ixp9Req*);
void write_event(char*, ...);
/* geom.c */
-Bool ptinrect(int x, int y, XRectangle*);
-BlitzAlign quadrant(XRectangle*, int x, int y);
-Cursor cursor_of_quad(BlitzAlign);
-int strtorect(XRectangle*, const char*);
-BlitzAlign get_sticky(XRectangle *src, XRectangle *dst);
-int r_east(XRectangle*);
-int r_south(XRectangle*);
+Bool ptinrect(Point, Rectangle);
+Align quadrant(Rectangle, Point);
+Cursor cursor_of_quad(Align);
+Align get_sticky(Rectangle src, Rectangle dst);
/* key.c */
-void kpress(Window, ulong mod, KeyCode);
-void update_keys();
-void init_lock_keys();
-ulong mod_key_of_str(char*);
+void kpress(XWindow, ulong mod, KeyCode);
+void update_keys(void);
+void init_lock_keys(void);
+ulong str2modmask(char*);
+
+/* map.c */
+MapEnt* mapget(Map*, ulong, int create);
+MapEnt* hashget(Map*, char*, int create);
+void* maprm(Map*, ulong);
+void* hashrm(Map*, char*);
+
+/* message.c */
+char * getword(Message*);
+Area * strarea(View*, char*);
+char * message_view(View*, Message*);
+char * parse_colors(Message*, CTuple*);
+char * message_root(void*, Message*);
+char * read_root_ctl(void);
+char * message_client(Client*, Message*);
+char *select_area(Area*, Message*);
+char *send_client(View*, Message*, Bool swap);
/* mouse.c */
void mouse_resizecol(Divide*);
-void do_mouse_resize(Client*, Bool opaque, BlitzAlign);
-void grab_mouse(Window, ulong mod, ulong button);
-void ungrab_mouse(Window, ulong mod, uint button);
-BlitzAlign snap_rect(XRectangle *rects, int num, XRectangle *current,
- BlitzAlign *mask, int snapw);
-void grab_button(Window, uint button, ulong mod);
+void do_mouse_resize(Client*, Bool opaque, Align);
+void grab_mouse(XWindow, ulong mod, ulong button);
+void ungrab_mouse(XWindow, ulong mod, uint button);
+Align snap_rect(Rectangle *rects, int num, Rectangle *current, Align *mask, int snapw);
+void grab_button(XWindow, uint button, ulong mod);
/* rule.c */
void update_rules(Rule**, const char*);
@@ -147,23 +143,110 @@ void trim(char *str, const char *chars);
/* view.c */
void arrange_view(View*);
-void scale_view(View*, float w);
+void scale_view(View*, int w);
View *get_view(const char*);
View *create_view(const char*);
void focus_view(WMScreen*, View*);
void update_client_views(Client*, char**);
-XRectangle *rects_of_view(View*, uint *num, Frame *ignore);
+Rectangle *rects_of_view(View*, uint *num, Frame *ignore);
View *view_of_id(ushort);
+Frame *view_clientframe(View *v, Client *c);
void select_view(const char*);
void attach_to_view(View*, Frame*);
Client *view_selclient(View*);
-char *message_view(View*, char*);
+char *message_view(View *v, Message *m);
void restack_view(View*);
uchar *view_index(View*);
void destroy_view(View*);
-void update_views();
-uint newcolw_of_view(View*, int i);
+void update_views(void);
+uint newcolw(View*, int i);
/* wm.c */
-int wmii_error_handler(Display*, XErrorEvent *error);
int win_proto(Window);
+
+/* x11.c */
+XRectangle XRect(Rectangle);
+int eqrect(Rectangle, Rectangle);
+int eqpt(Point, Point);
+Point addpt(Point, Point);
+Point subpt(Point, Point);
+Point mulpt(Point p, Point q);
+Point divpt(Point, Point);
+Rectangle insetrect(Rectangle, int);
+Rectangle rectaddpt(Rectangle, Point);
+Rectangle rectsubpt(Rectangle, Point);
+void initdisplay(void);
+Image * allocimage(int w, int h, int depth);
+void freeimage(Image *);
+Window *createwindow(Window *parent, Rectangle, int depth, uint class, WinAttr*, int valuemask);
+void reparentwindow(Window*, Window*, Point);
+void destroywindow(Window*);
+void setwinattr(Window*, WinAttr*, int valmask);
+void reshapewin(Window*, Rectangle);
+void movewin(Window*, Point);
+int mapwin(Window*);
+int unmapwin(Window*);
+void lowerwin(Window*);
+void raisewin(Window*);
+Handlers* sethandler(Window*, Handlers*);
+Window* findwin(XWindow);
+uint winprotocols(Window*);
+void setshapemask(Window *dst, Image *src, Point);
+void border(Image *dst, Rectangle, int w, ulong col);
+void fill(Image *dst, Rectangle, ulong col);
+void drawpoly(Image *dst, Point *pt, int np, int cap, int w, ulong col);
+void fillpoly(Image *dst, Point *pt, int np, ulong col);
+void drawline(Image *dst, Point p1, Point p2, int cap, int w, ulong col);
+void drawstring(Image *dst, Font *font, Rectangle, Align align, char *text, ulong col);
+void copyimage(Image *dst, Rectangle, Image *src, Point p);
+Bool namedcolor(char *name, ulong*);
+Bool loadcolor(CTuple*, char*);
+Font * loadfont(char*);
+void freefont(Font*);
+uint textwidth_l(Font*, char*, uint len);
+uint textwidth(Font*, char*);
+uint labelh(Font*);
+Atom xatom(char*);
+void freestringlist(char**);
+ulong getproperty(Window *w, char *prop, char *type, Atom *actual, ulong offset, uchar **ret, ulong length);
+char *gettextproperty(Window*, char*);
+int gettextlistproperty(Window *w, char *name, char **ret[]);
+void changeproperty(Window*, char *prop, char *type, int width, uchar *data, int n);
+void setfocus(Window*, int mode);
+Point querypointer(Window*);
+void warppointer(Point);
+Point translate(Window*, Window*, Point);
+int grabpointer(Window*, Window *confine, Cursor, int mask);
+void ungrabpointer(void);
+Rectangle gravitate(Rectangle dst, Rectangle src, Point grav);
+Rectangle sizehint(WinHints*, Rectangle);
+void sethints(Window*);
+
+/* utf.c */
+int chartorune(Rune*, char*);
+int fullrune(char*, int n);
+int runelen(long);
+int runenlen(Rune*, int nrune);
+Rune* runestrcat(Rune*, Rune*);
+Rune* runestrchr(Rune*, Rune);
+int runestrcmp(Rune*, Rune*);
+Rune* runestrcpy(Rune*, Rune*);
+Rune* runestrdup(Rune*) ;
+Rune* runestrecpy(Rune*, Rune *end, Rune*);
+long runestrlen(Rune*);
+Rune* runestrncat(Rune*, Rune*, long);
+int runestrncmp(Rune*, Rune*, long);
+Rune* runestrncpy(Rune*, Rune*, long);
+Rune* runestrrchr(Rune*, Rune);
+Rune* runestrstr(Rune*, Rune*);
+int runetochar(char*, Rune *rune);
+Rune totitlerune(Rune);
+char* utfecpy(char*, char *end, char*);
+int utflen(char*);
+int utfnlen(char*, long);
+char* utfrrune(char*, long);
+char* utfrune(char*, long);
+char* utfutf(char*, char*);
+char* toutf8n(char*, int);
+char* toutf8(char*);
+int isspacerune(Rune c);
diff --git a/cmd/wmii/frame.c b/cmd/wmii/frame.c
@@ -10,20 +10,21 @@
Frame *
create_frame(Client *c, View *v) {
static ushort id = 1;
- Frame *f = emallocz(sizeof(Frame));
-
+ Frame *f;
+
+ f = emallocz(sizeof *f);
f->id = id++;
f->client = c;
f->view = v;
+
if(c->sel) {
f->revert = c->sel->revert;
- f->rect = c->sel->rect;
+ f->r = c->sel->r;
}
else{
c->sel = f;
- f->revert = f->rect = c->rect;
- f->revert.width = f->rect.width += 2 * def.border;
- f->revert.height = f->rect.height += frame_delta_h();
+ f->r = client2frame(f, c->w.r);
+ f->revert = f->r;
}
f->collapsed = False;
@@ -33,194 +34,317 @@ create_frame(Client *c, View *v) {
void
remove_frame(Frame *f) {
Area *a;
- Frame **ft;
a = f->area;
- for(ft = &a->frame; *ft; ft=&(*ft)->anext)
- if(*ft == f) break;
- *ft = f->anext;
+ if(f->aprev)
+ f->aprev->anext = f->anext;
+ if(f->anext)
+ f->anext->aprev = f->aprev;
+ if(f == a->frame)
+ a->frame = f->anext;
if(a->floating) {
- for(ft = &a->stack; *ft; ft=&(*ft)->snext)
- if(*ft == f) break;
- *ft = f->snext;
+ if(f->sprev)
+ f->sprev->snext = f->snext;
+ if(f->snext)
+ f->snext->sprev = f->sprev;
+ if(f == a->stack)
+ a->stack = f->snext;
}
+ f->anext = f->aprev = f->snext = f->sprev = nil;
}
void
-insert_frame(Frame *pos, Frame *f, Bool before) {
- Frame *ft, **p;
+insert_frame(Frame *pos, Frame *f) {
Area *a;
a = f->area;
- if(before) {
- for(ft=a->frame; ft; ft=ft->anext)
- if(ft->anext == pos) break;
- pos=ft;
+ if(pos) {
+ f->aprev = pos;
+ f->anext = pos->anext;
+ }else {
+ f->anext = f->area->frame;
+ f->area->frame = f;
}
-
- p = &a->frame;
- if(pos)
- p = &pos->anext;
-
- f->anext = *p;
- *p = f;
+ if(f->aprev)
+ f->aprev->anext = f;
+ if(f->anext)
+ f->anext->aprev = f;
if(a->floating) {
f->snext = a->stack;
a->stack = f;
+ if(f->snext)
+ f->snext->sprev = f;
}
}
-void
-frame2client(Frame *f, XRectangle *r) {
- if(f->area->floating) {
- r->width = max(r->width - def.border * 2, 1);
- r->height = max(r->height - frame_delta_h(), 1);
+Bool
+frame_to_top(Frame *f) {
+ Area *a;
+
+ a = f->area;
+ if(!a->floating || f == a->stack)
+ return False;
+
+ if(f->sprev)
+ f->sprev->snext = f->snext;
+ if(f->snext)
+ f->snext->sprev = f->sprev;
+
+ f->snext = a->stack;
+ a->stack = f;
+ f->sprev = nil;
+ if(f->snext)
+ f->snext->sprev = f;
+
+ return True;
+}
+
+/* Handlers */
+static void
+bup_event(Window *w, XButtonEvent *e) {
+ write_event("ClientClick 0x%x %d\n", (uint)w->w, e->button);
+}
+
+static void
+bdown_event(Window *w, XButtonEvent *e) {
+ Frame *f;
+ Client *c;
+
+ c = w->aux;
+ f = c->sel;
+
+ if((e->state & def.mod) == def.mod) {
+ switch(e->button) {
+ case Button1:
+ do_mouse_resize(c, False, CENTER);
+ focus(c, True);
+ frame_to_top(f);
+ focus(c, True);
+ break;
+ case Button3:
+ do_mouse_resize(c, False, quadrant(f->r, Pt(e->x_root, e->y_root)));
+ frame_to_top(f);
+ focus(c, True);
+ break;
+ default:
+ XAllowEvents(display, ReplayPointer, e->time);
+ break;
+ }
+ XUngrabPointer(display, e->time);
+ }else{
+ if(e->button == Button1) {
+ if(frame_to_top(f))
+ restack_view(f->view);
+ else if(ptinrect(Pt(e->x, e->y), f->grabbox))
+ do_mouse_resize(c, True, CENTER);
+ else if(f->area->floating)
+ if(!e->subwindow && !ptinrect(Pt(e->x, e->y), f->titlebar))
+ do_mouse_resize(c, False, quadrant(f->r, Pt(e->x_root, e->y_root)));
+
+ if(f->client != selclient())
+ focus(c, True);
+ }
+ if(e->subwindow)
+ XAllowEvents(display, ReplayPointer, e->time);
+ else {
+ /* Ungrab so a menu can receive events before the button is released */
+ XUngrabPointer(display, e->time);
+ XSync(display, False);
+
+ write_event("ClientMouseDown 0x%x %d\n", f->client->w.w, e->button);
+ }
+ }
+}
+
+static void
+enter_event(Window *w, XCrossingEvent *e) {
+ Client *c;
+ Frame *f;
+
+ c = w->aux;
+ f = c->sel;
+ if(screen->focus != c) {
+ Debug fprintf(stderr, "enter_notify(f) => %s\n", f->client->name);
+ if(f->area->floating || !f->collapsed)
+ focus(f->client, False);
+ }
+ set_frame_cursor(f, Pt(e->x, e->y));
+}
+
+static void
+expose_event(Window *w, XExposeEvent *e) {
+ Client *c;
+
+ c = w->aux;
+ if(c->sel)
+ draw_frame(c->sel);
+ else
+ fprintf(stderr, "Badness: Expose event on a client frame which shouldn't be visible: %x\n",
+ (uint)c->w.w);
+}
+
+static void
+motion_event(Window *w, XMotionEvent *e) {
+ Client *c;
+
+ c = w->aux;
+ set_frame_cursor(c->sel, Pt(e->x, e->y));
+}
+
+Handlers framehandler = {
+ .bup = bup_event,
+ .bdown = bdown_event,
+ .enter = enter_event,
+ .expose = expose_event,
+ .motion = motion_event,
+};
+
+Rectangle
+frame2client(Frame *f, Rectangle r) {
+ if(f == nil || f->area == nil || f->area->floating) {
+ r.max.x -= def.border * 2;
+ r.max.y -= frame_delta_h();
+ if(f) {
+ if(f->client->borderless) {
+ r.max.x += 2 * def.border;
+ r.max.y += def.border;
+ }
+ if(f->client->titleless)
+ r.max.y += labelh(def.font);
+ }
}else {
- r->width = max(r->width - 2, 1);
- r->height = max(r->height - labelh(&def.font) - 1, 1);
+ r.max.x -= 2;
+ r.max.y -= labelh(def.font) + 1;
}
+ r.max.x = max(r.min.x+1, r.max.x);
+ r.max.y = max(r.min.y+1, r.max.y);
+ return r;
}
-void
-client2frame(Frame *f, XRectangle *r) {
- if(f->area->floating) {
- r->width += def.border * 2;
- r->height += frame_delta_h();
+Rectangle
+client2frame(Frame *f, Rectangle r) {
+ if(f == nil || f->area == nil || f->area->floating) {
+ r.max.x += def.border * 2;
+ r.max.y += frame_delta_h();
+ if(f) {
+ if(f->client->borderless) {
+ r.max.x -= 2 * def.border;
+ r.max.y -= def.border;
+ }
+ if(f->client->titleless)
+ r.max.y -= labelh(def.font);
+ }
}else {
- r->width += 2;
- r->height +=labelh(&def.font) + 1;
+ r.max.x += 2;
+ r.max.y += labelh(def.font) + 1;
}
+ return r;
}
void
-resize_frame(Frame *f, XRectangle *r) {
- BlitzAlign stickycorner;
+resize_frame(Frame *f, Rectangle r) {
+ Align stickycorner;
+ Point pt;
Client *c;
c = f->client;
- stickycorner = get_sticky(&f->rect, r);
+ stickycorner = get_sticky(f->r, r);
+
+ f->crect = frame_hints(f, r, stickycorner);
- f->rect = *r;
- f->crect = *r;
- apply_sizehints(c, &f->crect, f->area->floating, True, stickycorner);
+ if(Dx(r) <= 0 || Dy(r) <= 0)
+ fprintf(stderr, "Badness: Frame rect: %d,%d %dx%d\n",
+ r.min.x, r.min.y, Dx(r), Dy(r));
if(f->area->floating)
- f->rect = f->crect;
+ f->r = f->crect;
+ else
+ f->r = r;
- frame2client(f, &f->crect);
+ f->crect = frame2client(f, f->crect);
+ f->crect = rectsubpt(f->crect, f->crect.min);
- if(f->crect.height < labelh(&def.font))
- f->collapsed = True;
- else
- f->collapsed = False;
+ if(!f->area->floating && f->area->mode == Coldefault) {
+ if(Dy(f->r) < 2 * labelh(def.font))
+ f->collapsed = True;
+ else
+ f->collapsed = False;
+ }
- if(f->crect.width < labelh(&def.font)) {
- f->rect.width = frame_delta_h();
+ if(Dx(f->crect) < labelh(def.font)) {
+ f->r.max.x = f->r.min.x + frame_delta_h();
f->collapsed = True;
}
if(f->collapsed) {
- f->rect.height = labelh(&def.font);
- f->crect = f->rect;
+ f->r.max.y= f->r.min.y + labelh(def.font);
+ f->crect = f->r;
}
- f->crect.y = labelh(&def.font);
- f->crect.x = (f->rect.width - f->crect.width) / 2;
-
+
+ pt = ZP;
+ if(!f->client->borderless || !f->area->floating)
+ pt.y += 1;
+ if(!f->client->titleless || !f->area->floating)
+ pt.y += labelh(def.font) - 1;
if(f->area->floating) {
if(c->fullscreen) {
- f->crect.width = screen->rect.width;
- f->crect.height = screen->rect.height;
-
- f->rect = f->crect;
- f->rect.x = -def.border;
- f->rect.y = -labelh(&def.font);
- client2frame(f, &f->rect);
+ f->crect = screen->r;
+ f->r = client2frame(f, f->crect);
+ pt.x = (Dx(f->r) - Dx(f->crect)) / 2;
+ f->r = rectsubpt(f->r, pt);
}else
- check_frame_constraints(&f->rect);
+ f->r = constrain(f->r);
}
+ pt.x = (Dx(f->r) - Dx(f->crect)) / 2;
+ f->crect = rectaddpt(f->crect, pt);
}
void
-set_frame_cursor(Frame *f, int x, int y) {
- XRectangle r;
+set_frame_cursor(Frame *f, Point pt) {
+ Rectangle r;
Cursor cur;
if(f->area->floating
- && !ptinrect(x, y, &f->titlebar)
- && !ptinrect(x, y, &f->crect)
- && !ingrabbox(f, x, y)) {
- r = f->rect;
- r.x = 0;
- r.y = 0;
- cur = cursor_of_quad(quadrant(&r, x, y));
+ && !ptinrect(pt, f->titlebar)
+ && !ptinrect(pt, f->crect)) {
+ r = rectsubpt(f->r, f->r.min);
+ cur = cursor_of_quad(quadrant(r, pt));
set_cursor(f->client, cur);
} else
set_cursor(f->client, cursor[CurNormal]);
}
-Bool
-frame_to_top(Frame *f) {
- Frame **tf;
- Area *a;
-
- a = f->area;
- if(!a->floating || f == a->stack)
- return False;
- for(tf=&a->stack; *tf; tf=&(*tf)->snext)
- if(*tf == f) break;
- *tf = f->snext;
- f->snext = a->stack;
- a->stack = f;
- update_client_grab(f->client);
- return True;
-}
-
void
swap_frames(Frame *fa, Frame *fb) {
- XRectangle trect;
- Area *a;
- Frame **fp_a, **fp_b, *ft;
+ Frame **fp;
+ Client *c;
if(fa == fb) return;
- a = fa->area;
- for(fp_a = &a->frame; *fp_a; fp_a = &(*fp_a)->anext)
- if(*fp_a == fa) break;
- a = fb->area;
- for(fp_b = &a->frame; *fp_b; fp_b = &(*fp_b)->anext)
- if(*fp_b == fb) break;
-
- if(fa->anext == fb) {
- *fp_a = fb;
- fa->anext = fb->anext;
- fb->anext = fa;
- } else if(fb->anext == fa) {
- *fp_b = fa;
- fb->anext = fa->anext;
- fa->anext = fb;
- } else {
- *fp_a = fb;
- *fp_b = fa;
- ft = fb->anext;
- fb->anext = fa->anext;
- fa->anext = ft;
- }
+ for(fp = &fa->client->frame; *fp; fp = &(*fp)->cnext)
+ if(*fp == fa) break;
+ *fp = (*fp)->cnext;
+
+ for(fp = &fb->client->frame; *fp; fp = &(*fp)->cnext)
+ if(*fp == fb) break;
+ *fp = (*fp)->cnext;
- if(fb->area->sel == fb)
- fb->area->sel = fa;
- if(fa->area->sel == fa)
- fa->area->sel = fb;
+ c = fa->client;
+ fa->client = fb->client;
+ fb->client = c;
+ fb->cnext = c->frame;
+ c->frame = fb;
- fb->area = fa->area;
- fa->area = a;
+ c = fa->client;
+ fa->cnext = c->frame;
+ c->frame = fa;
- trect = fa->rect;
- fa->rect = fb->rect;
- fb->rect = trect;
+ if(c->sel && c->sel->view == screen->sel)
+ focus_view(screen, c->sel->view);
}
void
@@ -245,142 +369,75 @@ focus_frame(Frame *f, Bool restack) {
focus_client(f->client);
- if(!a->floating
- && ((a->mode == Colstack) || (a->mode == Colmax)))
+ if(!a->floating && ((a->mode == Colstack) || (a->mode == Colmax)))
arrange_column(a, False);
- if((f != old)
- && (f->area == old_a))
- write_event("ClientFocus 0x%x\n", f->client->win);
-
if(restack)
restack_view(v);
}
int
-frame_delta_h() {
- return def.border + labelh(&def.font);
-}
-
-int
-ingrabbox(Frame *f, int x, int y) {
- int dx, h;
-
- if(f->area->floating)
- return 0;
-
- h = labelh(&def.font) / 3;
- h = max(h, 4);
-
- if((f == f->area->frame) && f->area->next)
- if(x >= f->rect.width - h) {
- dx = x - (f->rect.width - h);
- if(y <= dx)
- return 1;
- }
- if((f == f->area->frame) && (f->area != f->view->area->next))
- if(x <= h && y <= h - x)
- return 1;
-
- return 0;
+frame_delta_h(void) {
+ return def.border + labelh(def.font);
}
void
draw_frame(Frame *f) {
- BlitzBrush br = { 0 };
+ Rectangle r, fr;
+ CTuple *col;
Frame *tf;
if(f->view != screen->sel)
return;
- br.blitz = &blz;
- br.font = &def.font;
- br.drawable = pmap;
- br.gc = f->client->gc;
if(f->client == screen->focus)
- br.color = def.focuscolor;
+ col = &def.focuscolor;
else
- br.color = def.normcolor;
+ col = &def.normcolor;
if(!f->area->floating && f->area->mode == Colmax)
for(tf = f->area->frame; tf; tf=tf->anext)
if(tf->client == screen->focus) {
- br.color = def.focuscolor;
+ col = &def.focuscolor;
break;
}
+ fr = f->client->framewin->r;
+ fr = rectsubpt(fr, fr.min);
+
+ /* background */
+ r = fr;
+ fill(screen->ibuf, r, col->bg);
+ border(screen->ibuf, r, 1, col->border);
+
+ r.max.y = r.min.y + labelh(def.font);
+ border(screen->ibuf, r, 1, col->border);
- br.rect = f->rect;
- br.rect.x = 0;
- br.rect.y = 0;
- draw_tile(&br);
-
- br.rect.x += def.font.height - 3;
- br.rect.width -= br.rect.x;
- br.rect.height = labelh(&def.font);
- draw_label(&br, f->client->name);
-
- br.border = 1;
- br.rect.width += br.rect.x;
- br.rect.x = 0;
- f->titlebar.x = br.rect.x + 3;
- f->titlebar.height = br.rect.height - 3;
- f->titlebar.y = br.rect.y + 3;
- f->titlebar.width = br.rect.width - 6;
- draw_border(&br);
- br.rect.height = f->rect.height;
- if(def.border)
- draw_border(&br);
+ f->titlebar = insetrect(r, 3);
+ f->titlebar.max.y += 3;
+
+ /* grabbox */
+ r.min = Pt(2, 2);
+ r.max.x = r.min.x + def.font->height - 3;
+ r.max.y -= 2;
+ f->grabbox = r;
if(f->client->urgent)
- br.color.bg = br.color.fg;
- br.rect.x = 2;
- br.rect.y = 2;
- br.rect.height = labelh(&def.font) - 4;
- br.rect.width = def.font.height - 3;
- f->grabbox = br.rect;
- draw_tile(&br);
-
-#if 0
- if(!f->area->floating) {
- XSetLineAttributes(blz.dpy, br.gc, 1, LineSolid, CapButt, JoinMiter);
- h = labelh(&def.font) / 3;
- h = max(h, 4);
- if((f == f->area->frame) && f->area->next) {
- pt[0] = (XPoint){ f->rect.width - h, 0 };
- pt[1] = (XPoint){ f->rect.width, h };
- pt[2] = (XPoint){ f->rect.width, 0 };
- XSetForeground(blz.dpy, br.gc, def.normcolor.bg);
- XFillPolygon(blz.dpy, br.drawable, br.gc, pt, 3, Convex, CoordModeOrigin);
- XSetForeground(blz.dpy, br.gc, br.color.border);
- XDrawLines(blz.dpy, br.drawable, br.gc, pt, 2, CoordModeOrigin);
- }
- if((f == f->area->frame) && (f->area != f->view->area->next)) {
- pt[0] = (XPoint){ h, 0 };
- pt[1] = (XPoint){ 0, h };
- pt[2] = (XPoint){ 0, 0 };
- XSetForeground(blz.dpy, br.gc, def.normcolor.bg);
- XFillPolygon(blz.dpy, br.drawable, br.gc, pt, 3, Convex, CoordModeOrigin);
- XSetForeground(blz.dpy, br.gc, br.color.border);
- XDrawLines(blz.dpy, br.drawable, br.gc, pt, 2, CoordModeOrigin);
- }
- }
-#endif
-
- XCopyArea(
- /* display */ blz.dpy,
- /* src */ pmap,
- /* dest */ f->client->framewin,
- /* gc */ f->client->gc,
- /* x, y */ 0, 0,
- /* width */ f->rect.width,
- /* height */ f->rect.height,
- /* dest_x */ 0,
- /* dest_y */ 0
- );
- XSync(blz.dpy, False);
+ fill(screen->ibuf, r, col->fg);
+ border(screen->ibuf, r, 1, col->border);
+
+ r.min.x = r.max.x;
+ r.max.x = fr.max.x;
+ r.min.y = 0;
+ r.max.y = labelh(def.font);
+ drawstring(screen->ibuf, def.font, r, WEST,
+ f->client->name, col->fg);
+
+ XSetWindowBackgroundPixmap(display, f->client->framewin->w, None);
+ copyimage(f->client->framewin, fr, screen->ibuf, ZP);
+ XSync(display, False);
}
void
-draw_frames() {
+draw_frames(void) {
Client *c;
for(c=client; c; c=c->next)
@@ -388,24 +445,24 @@ draw_frames() {
draw_frame(c->sel);
}
-void
-check_frame_constraints(XRectangle *rect) {
- int max_height;
- int barheight;
-
- barheight = screen->brect.height;
- max_height = screen->rect.height - barheight;
-
- if(rect->height > max_height)
- rect->height = max_height;
- if(rect->width > screen->rect.width)
- rect->width = screen->rect.width;
- if(rect->x + barheight > screen->rect.width)
- rect->x = screen->rect.width - barheight;
- if(rect->y + barheight > max_height)
- rect->y = max_height - barheight;
- if(r_east(rect) < barheight)
- rect->x = barheight - rect->width;
- if(r_south(rect) < barheight)
- rect->y = barheight - rect->height;
+Rectangle
+constrain(Rectangle r) {
+ Rectangle sr;
+ Point p;
+
+ sr = screen->r;
+ sr.max.y = screen->brect.min.y;
+
+ if(Dx(r) > Dx(sr))
+ r.max.x = r.min.x + Dx(sr);
+ if(Dy(r) > Dy(sr))
+ r.max.y = r.min.y + Dy(sr);
+
+ sr = insetrect(sr, Dy(screen->brect));
+ p = ZP;
+ p.x -= min(r.max.x - sr.min.x, 0);
+ p.x -= max(r.min.x - sr.max.x, 0);
+ p.y -= min(r.max.y - sr.min.y, 0);
+ p.y -= max(r.min.y - sr.max.y, 0);
+ return rectaddpt(r, p);
}
diff --git a/cmd/wmii/fs.c b/cmd/wmii/fs.c
@@ -2,6 +2,8 @@
* See LICENSE file for license details.
*/
#include <assert.h>
+#include <ctype.h>
+#include <regex.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -38,8 +40,8 @@ struct FileId {
View *view;
Client *client;
Ruleset *rule;
- BlitzColor *col;
- } content;
+ CTuple *col;
+ } p;
uint id;
uint index;
Dirtab tab;
@@ -62,8 +64,7 @@ static char
Enoperm[] = "permission denied",
Enofile[] = "file not found",
Ebadvalue[] = "bad value",
- Einterrupted[] = "interrupted",
- Ebadcmd[] = "bad command";
+ Einterrupted[] = "interrupted";
/* Macros */
#define QID(t, i) (((vlong)((t)&0xFF)<<32)|((i)&0xFFFFFFFF))
@@ -109,7 +110,7 @@ dirtab_clients[]={{".", QTDIR, FsDClients, 0500|P9_DMDIR },
{nil}},
dirtab_client[]= {{".", QTDIR, FsDClient, 0500|P9_DMDIR },
{"ctl", QTAPPEND, FsFCctl, 0600|P9_DMAPPEND },
- {"label", QTFILE, FsFClabel, 0600 },
+ {"label", QTFILE, FsFClabel, 0600 },
{"tags", QTFILE, FsFCtags, 0600 },
{"props", QTFILE, FsFprops, 0400 },
{nil}},
@@ -134,7 +135,7 @@ static Dirtab *dirtab[] = {
/* Utility Functions */
static FileId *
-get_file() {
+get_file(void) {
FileId *temp;
if(!free_fileid) {
uint i = 15;
@@ -182,7 +183,7 @@ write_buf(Ixp9Req *r, char *buf, uint len) {
}
/* This should be moved to libixp */
-void
+static void
write_to_buf(Ixp9Req *r, void *buf, uint *len, uint max) {
uint offset, count;
@@ -209,100 +210,38 @@ write_to_buf(Ixp9Req *r, void *buf, uint *len, uint max) {
}
/* This should be moved to libixp */
-void
+static void
data_to_cstring(Ixp9Req *r) {
+ char *p;
uint i;
i = r->ifcall.count;
- if(!i || r->ifcall.data[i - 1] != '\n')
- r->ifcall.data = erealloc(r->ifcall.data, ++i);
+ p = r->ifcall.data;
+ if(p[i - 1] == '\n')
+ i--;
+
+ r->ifcall.data = toutf8n(p, i);
assert(r->ifcall.data);
- r->ifcall.data[i - 1] = '\0';
+ free(p);
}
-char *
-message_root(char *message)
-{
- uint n;
-
- if(!strchr(message, ' ')) {
- snprintf(buffer, sizeof(buffer), "%s ", message);
- message = buffer;
- }
- if(!strcmp(message, "quit "))
- srv.running = 0;
- else if(!strncmp(message, "exec ", 5)) {
- srv.running = 0;
- execstr = emalloc(strlen(&message[5]) + sizeof("exec "));
- sprintf(execstr, "exec %s", &message[5]);
- message += strlen(message);
- }
- else if(!strncmp(message, "view ", 5))
- select_view(&message[5]);
- else if(!strncmp(message, "selcolors ", 10)) {
- fprintf(stderr, "wmii: warning: selcolors have been removed\n");
- return Ebadcmd;
- }
- else if(!strncmp(message, "focuscolors ", 12)) {
- message += 12;
- n = strlen(message);
- return parse_colors(&message, (int *)&n, &def.focuscolor);
- }
- else if(!strncmp(message, "normcolors ", 11)) {
- message += 11;
- n = strlen(message);
- return parse_colors(&message, (int *)&n, &def.normcolor);
- }
- else if(!strncmp(message, "font ", 5)) {
- message += 5;
- free(def.font.fontstr);
- def.font.fontstr = estrdup(message);
- loadfont(&blz, &def.font);
- resize_bar(screen);
- }
- else if(!strncmp(message, "border ", 7)) {
- message += 7;
- n = (uint)strtol(message, &message, 10);
- if(*message)
- return Ebadvalue;
- def.border = n;
- }
- else if(!strncmp(message, "grabmod ", 8)) {
- message += 8;
- ulong mod;
- mod = mod_key_of_str(message);
- if(!(mod & (Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)))
- return Ebadvalue;
- strncpy(def.grabmod, message, sizeof(def.grabmod));
- def.mod = mod;
- restack_view(screen->sel);
- }
- else
- return Ebadcmd;
- return nil;
-}
+typedef char* (*MsgFunc)(void*, Message*);
-char *
-read_root_ctl() {
- uint i = 0;
- if(screen->sel)
- i += snprintf(&buffer[i], (sizeof(buffer) - i), "view %s\n", screen->sel->name);
- i += snprintf(&buffer[i], (sizeof(buffer) - i), "focuscolors %s\n", def.focuscolor.colstr);
- i += snprintf(&buffer[i], (sizeof(buffer) - i), "normcolors %s\n", def.normcolor.colstr);
- i += snprintf(&buffer[i], (sizeof(buffer) - i), "font %s\n", def.font.fontstr);
- i += snprintf(&buffer[i], (sizeof(buffer) - i), "grabmod %s\n", def.grabmod);
- i += snprintf(&buffer[i], (sizeof(buffer) - i), "border %d\n", def.border);
- return buffer;
-}
+static char *
+message(Ixp9Req *r, MsgFunc fn) {
+ char *err, *s, *p, c;
+ FileId *f;
+ Message m;
+ f = r->fid->aux;
void
respond_event(Ixp9Req *r) {
FileId *f = r->fid->aux;
- if(f->content.buf) {
- r->ofcall.data = (void *)f->content.buf;
- r->ofcall.count = strlen(f->content.buf);
+ if(f->p.buf) {
+ r->ofcall.data = (void *)f->p.buf;
+ r->ofcall.count = strlen(f->p.buf);
respond(r, nil);
- f->content.buf = nil;
+ f->p.buf = nil;
}else{
r->aux = peventread;
peventread = r;
@@ -324,10 +263,10 @@ write_event(char *format, ...) {
return;
for(f=peventfid; f; f=f->next) {
fi = f->fid->aux;
- slen = fi->content.buf ? strlen(fi->content.buf) : 0;
- fi->content.buf = (char *) erealloc(fi->content.buf, slen + len + 1);
- (fi->content.buf)[slen] = '\0';
- strcat(fi->content.buf, buffer);
+ slen = fi->p.buf ? strlen(fi->p.buf) : 0;
+ fi->p.buf = (char *) erealloc(fi->p.buf, slen + len + 1);
+ (fi->p.buf)[slen] = '\0';
+ strcat(fi->p.buf, buffer);
}
oeventread = peventread;
peventread = nil;
@@ -381,9 +320,9 @@ lookup_file(FileId *parent, char *name)
file = get_file();
*last = file;
last = &file->next;
- file->content.client = c;
- file->id = c->win;
- file->index = c->win;
+ file->p.client = c;
+ file->id = c->w.w;
+ file->index = c->w.w;
file->tab = *dir;
file->tab.name = estrdup("sel");
}if(name) goto LastItem;
@@ -393,16 +332,16 @@ lookup_file(FileId *parent, char *name)
if(*name) goto NextItem;
}
for(c=client; c; c=c->next) {
- if(!name || c->win == id) {
+ if(!name || c->w.w == id) {
file = get_file();
*last = file;
last = &file->next;
- file->content.client = c;
- file->id = c->win;
- file->index = c->win;
+ file->p.client = c;
+ file->id = c->w.w;
+ file->index = c->w.w;
file->tab = *dir;
file->tab.name = emallocz(16);
- snprintf(file->tab.name, 16, "0x%x", (uint)c->win);
+ snprintf(file->tab.name, 16, "0x%x", (uint)c->w.w);
if(name) goto LastItem;
}
}
@@ -413,7 +352,7 @@ lookup_file(FileId *parent, char *name)
file = get_file();
*last = file;
last = &file->next;
- file->content.view = screen->sel;
+ file->p.view = screen->sel;
file->id = screen->sel->id;
file->tab = *dir;
file->tab.name = estrdup("sel");
@@ -424,7 +363,7 @@ lookup_file(FileId *parent, char *name)
file = get_file();
*last = file;
last = &file->next;
- file->content.view = v;
+ file->p.view = v;
file->id = v->id;
file->tab = *dir;
file->tab.name = estrdup(v->name);
@@ -433,12 +372,12 @@ lookup_file(FileId *parent, char *name)
}
break;
case FsDBars:
- for(b=*parent->content.bar_p; b; b=b->next) {
+ for(b=*parent->p.bar_p; b; b=b->next) {
if(!name || !strcmp(name, b->name)) {
file = get_file();
*last = file;
last = &file->next;
- file->content.bar = b;
+ file->p.bar = b;
file->id = b->id;
file->tab = *dir;
file->tab.name = estrdup(b->name);
@@ -453,7 +392,7 @@ lookup_file(FileId *parent, char *name)
*last = file;
last = &file->next;
file->id = 0;
- file->content.ref = parent->content.ref;
+ file->p.ref = parent->p.ref;
file->index = parent->index;
file->tab = *dir;
file->tab.name = estrdup(file->tab.name);
@@ -461,15 +400,15 @@ lookup_file(FileId *parent, char *name)
switch(file->tab.type) {
case FsDBars:
if(!strcmp(file->tab.name, "lbar"))
- file->content.bar_p = &screen[0].bar[BarLeft];
+ file->p.bar_p = &screen[0].bar[BarLeft];
else
- file->content.bar_p = &screen[0].bar[BarRight];
+ file->p.bar_p = &screen[0].bar[BarRight];
break;
case FsFColRules:
- file->content.rule = &def.colrules;
+ file->p.rule = &def.colrules;
break;
case FsFTagRules:
- file->content.rule = &def.tagrules;
+ file->p.rule = &def.tagrules;
break;
}
if(name) goto LastItem;
@@ -482,7 +421,7 @@ LastItem:
return ret;
}
-Bool
+static Bool
verify_file(FileId *f) {
FileId *nf;
@@ -504,7 +443,7 @@ fs_attach(Ixp9Req *r) {
FileId *f = get_file();
f->tab = dirtab[FsRoot][0];
f->tab.name = estrdup("/");
- f->content.ref = nil;
+ f->p.ref = nil;
r->fid->aux = f;
r->fid->qid.type = f->tab.qtype;
r->fid->qid.path = QID(f->tab.type, 0);
@@ -562,22 +501,22 @@ fs_walk(Ixp9Req *r) {
respond(r, nil);
}
-uint
+static uint
fs_size(FileId *f) {
switch(f->tab.type) {
default:
return 0;
case FsFColRules:
case FsFTagRules:
- return f->content.rule->size;
+ return f->p.rule->size;
case FsFKeys:
return def.keyssz;
- case FsFClabel:
- return strlen(f->content.client->name);
case FsFCtags:
- return strlen(f->content.client->tags);
+ return strlen(f->p.client->tags);
+ case FsFClabel:
+ return strlen(f->p.client->name);
case FsFprops:
- return strlen(f->content.client->props);
+ return strlen(f->p.client->props);
}
}
@@ -587,7 +526,9 @@ fs_stat(Ixp9Req *r) {
Stat s;
int size;
uchar *buf;
- FileId *f = r->fid->aux;
+ FileId *f;
+
+ f = r->fid->aux;
if(!verify_file(f)) {
respond(r, Enofile);
@@ -654,32 +595,32 @@ fs_read(Ixp9Req *r) {
else{
switch(f->tab.type) {
case FsFprops:
- write_buf(r, f->content.client->props, strlen(f->content.client->props));
+ write_buf(r, f->p.client->props, strlen(f->p.client->props));
respond(r, nil);
return;
case FsFColRules:
case FsFTagRules:
- write_buf(r, f->content.rule->string, f->content.rule->size);
+ write_buf(r, f->p.rule->string, f->p.rule->size);
respond(r, nil);
return;
case FsFKeys:
write_buf(r, def.keys, def.keyssz);
respond(r, nil);
return;
- case FsFClabel:
- write_buf(r, f->content.client->name, strlen(f->content.client->name));
+ case FsFCtags:
+ write_buf(r, f->p.client->tags, strlen(f->p.client->tags));
respond(r, nil);
return;
- case FsFCtags:
- write_buf(r, f->content.client->tags, strlen(f->content.client->tags));
+ case FsFClabel:
+ write_buf(r, f->p.client->name, strlen(f->p.client->name));
respond(r, nil);
return;
case FsFTctl:
- write_buf(r, f->content.view->name, strlen(f->content.view->name));
+ write_buf(r, f->p.view->name, strlen(f->p.view->name));
respond(r, nil);
return;
case FsFBar:
- write_buf(r, f->content.bar->buf, strlen(f->content.bar->buf));
+ write_buf(r, f->p.bar->buf, strlen(f->p.bar->buf));
respond(r, nil);
return;
case FsFRctl:
@@ -699,7 +640,7 @@ fs_read(Ixp9Req *r) {
respond(r, nil);
return;
case FsFTindex:
- buf = (char *)view_index(f->content.view);
+ buf = (char*)view_index(f->p.view);
n = strlen(buf);
write_buf(r, buf, n);
respond(r, nil);
@@ -718,9 +659,7 @@ fs_read(Ixp9Req *r) {
void
fs_write(Ixp9Req *r) {
FileId *f;
- Client *c;
char *errstr = nil;
- XClassHint ch;
uint i;
if(r->ifcall.count == 0) {
@@ -737,7 +676,7 @@ fs_write(Ixp9Req *r) {
switch(f->tab.type) {
case FsFColRules:
case FsFTagRules:
- write_to_buf(r, &f->content.rule->string, &f->content.rule->size, 0);
+ write_to_buf(r, &f->p.rule->string, &f->p.rule->size, 0);
respond(r, nil);
return;
case FsFKeys:
@@ -746,74 +685,38 @@ fs_write(Ixp9Req *r) {
return;
case FsFClabel:
data_to_cstring(r);
- c = f->content.client;
- strncpy(c->name, r->ifcall.data, sizeof(c->name));
- if(XGetClassHint(blz.dpy, c->win, &ch)) {
- snprintf(c->props, sizeof(c->props),
- "%s:%s:%s",
- str_nil(ch.res_class),
- str_nil(ch.res_name),
- c->name);
- if(ch.res_class)
- XFree(ch.res_class);
- if(ch.res_name)
- XFree(ch.res_name);
- }
- draw_frame(f->content.client->sel);
+ utfecpy(f->p.client->name, f->p.client->name+sizeof(client->name), r->ifcall.data);
+ draw_frame(f->p.client->sel);
+ update_class(f->p.client);
r->ofcall.count = r->ifcall.count;
respond(r, nil);
return;
case FsFCtags:
data_to_cstring(r);
- apply_tags(f->content.client, r->ifcall.data);
+ apply_tags(f->p.client, r->ifcall.data);
r->ofcall.count = r->ifcall.count;
respond(r, nil);
return;
case FsFBar:
- /* XXX: This should validate after each write */
- i = strlen(f->content.bar->buf);
- write_to_buf(r, &f->content.bar->buf, &i, 279);
+ i = strlen(f->p.bar->buf);
+ write_to_buf(r, &f->p.bar->buf, &i, 279);
r->ofcall.count = i - r->ifcall.offset;
respond(r, nil);
return;
case FsFCctl:
- data_to_cstring(r);
- if((errstr = message_client(f->content.client, r->ifcall.data))) {
- respond(r, errstr);
- return;
- }
+ errstr = message(r, (MsgFunc)message_client);
r->ofcall.count = r->ifcall.count;
- respond(r, nil);
+ respond(r, errstr);
return;
case FsFTctl:
- data_to_cstring(r);
- if((errstr = message_view(f->content.view, r->ifcall.data))) {
- respond(r, errstr);
- return;
- }
+ errstr = message(r, (MsgFunc)message_view);
r->ofcall.count = r->ifcall.count;
- respond(r, nil);
+ respond(r, errstr);
return;
case FsFRctl:
- data_to_cstring(r);
- { uint n;
- char *toks[32];
- n = tokenize(toks, 32, r->ifcall.data, '\n');
- for(i = 0; i < n; i++) {
- if(errstr)
- message_root(toks[i]);
- else
- errstr = message_root(toks[i]);
- }
- }
- if(screen->sel)
- focus_view(screen, screen->sel);
- if(errstr) {
- respond(r, errstr);
- return;
- }
+ errstr = message(r, (MsgFunc)message_root);
r->ofcall.count = r->ifcall.count;
- respond(r, nil);
+ respond(r, errstr);
return;
case FsFEvent:
if(r->ifcall.data[r->ifcall.count-1] == '\n')
@@ -879,7 +782,7 @@ fs_create(Ixp9Req *r) {
respond(r, Ebadvalue);
return;
}
- create_bar(f->content.bar_p, r->ifcall.name);
+ create_bar(f->p.bar_p, r->ifcall.name);
f = lookup_file(f, r->ifcall.name);
if(!f) {
respond(r, Enofile);
@@ -909,7 +812,7 @@ fs_remove(Ixp9Req *r) {
respond(r, Enoperm);
return;
case FsFBar:
- destroy_bar(f->next->content.bar_p, f->content.bar);
+ destroy_bar(f->next->p.bar_p, f->p.bar);
draw_bar(screen);
respond(r, nil);
break;
@@ -918,12 +821,13 @@ fs_remove(Ixp9Req *r) {
void
fs_clunk(Ixp9Req *r) {
- Client *c;
FidLink **fl, *ft;
- char *buf;
- int i;
- FileId *f = r->fid->aux;
-
+ FileId *f;
+ char *p, *q;
+ Client *c;
+ Message m;
+
+ f = r->fid->aux;
if(!verify_file(f)) {
respond(r, nil);
return;
@@ -931,10 +835,10 @@ fs_clunk(Ixp9Req *r) {
switch(f->tab.type) {
case FsFColRules:
- update_rules(&f->content.rule->rule, f->content.rule->string);
+ update_rules(&f->p.rule->rule, f->p.rule->string);
break;
case FsFTagRules:
- update_rules(&f->content.rule->rule, f->content.rule->string);
+ update_rules(&f->p.rule->rule, f->p.rule->string);
for(c=client; c; c=c->next)
apply_rules(c);
update_views();
@@ -943,12 +847,20 @@ fs_clunk(Ixp9Req *r) {
update_keys();
break;
case FsFBar:
- buf = f->content.bar->buf;
- i = strlen(f->content.bar->buf);
- parse_colors(&buf, &i, &f->content.bar->brush.color);
- while(i > 0 && buf[i - 1] == '\n')
- buf[--i] = '\0';
- strncpy(f->content.bar->text, buf, sizeof(f->content.bar->text));
+ p = toutf8(f->p.bar->buf);
+
+ m = ixp_message(p, strlen(p), 0);
+ parse_colors(&m, &f->p.bar->col);
+
+ q = m.end-1;
+ while(q >= (char*)m.pos && *q == '\n')
+ *q-- = '\0';
+
+ q = f->p.bar->text;
+ utfecpy(q, q+sizeof((Bar){}.text), m.pos);
+
+ free(p);
+
draw_bar(screen);
break;
case FsFEvent:
diff --git a/cmd/wmii/geom.c b/cmd/wmii/geom.c
@@ -1,4 +1,4 @@
-/* Copyright ©2004-2006 Anselm R. Garbe <garbeam at gmail dot com>
+/* Copyright ©2006-2007 Kris Maglione <fbsdaemon@gmail.com>
* See LICENSE file for license details.
*/
#include <stdio.h>
@@ -7,31 +7,32 @@
#include "fns.h"
Bool
-ptinrect(int x, int y, XRectangle * r) {
- return (x >= r->x) && (x < r_east(r))
- && (y >= r->y) && (y < r_south(r));
+ptinrect(Point pt, Rectangle r) {
+ return (pt.x >= r.min.x) && (pt.x < r.max.x)
+ && (pt.y >= r.min.y) && (pt.y < r.max.y);
}
-BlitzAlign
-quadrant(XRectangle *rect, int x, int y) {
- BlitzAlign ret = 0;
- x -= rect->x;
- y -= rect->y;
+Align
+quadrant(Rectangle r, Point pt) {
+ Align ret;
- if(x >= rect->width * .5)
+ pt = subpt(pt, r.min);
+ ret = 0;
+
+ if(pt.x >= Dx(r) * .5)
ret |= EAST;
- if(x <= rect->width * .5)
+ if(pt.x <= Dx(r) * .5)
ret |= WEST;
- if(y <= rect->height * .5)
+ if(pt.y <= Dy(r) * .5)
ret |= NORTH;
- if(y >= rect->height * .5)
+ if(pt.y >= Dy(r) * .5)
ret |= SOUTH;
return ret;
}
Cursor
-cursor_of_quad(BlitzAlign align) {
+cursor_of_quad(Align align) {
switch(align) {
case NEAST:
return cursor[CurNECorner];
@@ -46,39 +47,15 @@ cursor_of_quad(BlitzAlign align) {
}
}
-/* Syntax: <x> <y> <width> <height> */
-int
-strtorect(XRectangle *r, const char *val) {
- XRectangle new;
- if (!val)
- return -1;
-
- if(sscanf(val, "%hd %hd %hu %hu", &new.x, &new.y, &new.width, &new.height) != 4)
- return -1;
-
- *r = new;
- return 0;
-}
-
-int
-r_east(XRectangle *r) {
- return r->x + r->width;
-}
-
-int
-r_south(XRectangle *r) {
- return r->y + r->height;
-}
-
-BlitzAlign
-get_sticky(XRectangle *src, XRectangle *dst) {
- BlitzAlign stickycorner = 0;
+Align
+get_sticky(Rectangle src, Rectangle dst) {
+ Align stickycorner = 0;
- if(src->x != dst->x && r_east(src) == r_east(dst))
+ if(src.min.x != dst.min.x && src.max.x == dst.max.x)
stickycorner |= EAST;
else
stickycorner |= WEST;
- if(src->y != dst->y && r_south(src) == r_south(dst))
+ if(src.min.y != dst.min.y && src.max.y == dst.max.y)
stickycorner |= SOUTH;
else
stickycorner |= NORTH;
diff --git a/cmd/wmii/key.c b/cmd/wmii/key.c
@@ -9,7 +9,7 @@
#include "fns.h"
void
-init_lock_keys() {
+init_lock_keys(void) {
XModifierKeymap *modmap;
KeyCode num_lock;
static int masks[] = {
@@ -19,8 +19,8 @@ init_lock_keys() {
int i;
num_lock_mask = 0;
- modmap = XGetModifierMapping(blz.dpy);
- num_lock = XKeysymToKeycode(blz.dpy, XStringToKeysym("Num_Lock"));
+ modmap = XGetModifierMapping(display);
+ num_lock = XKeysymToKeycode(display, XStringToKeysym("Num_Lock"));
if(modmap && modmap->max_keypermod > 0) {
int max = (sizeof(masks) / sizeof(int)) * modmap->max_keypermod;
for(i = 0; i < max; i++)
@@ -32,7 +32,7 @@ init_lock_keys() {
}
ulong
-mod_key_of_str(char *val) {
+str2modmask(char *val) {
ulong mod = 0;
if (strstr(val, "Shift"))
@@ -54,25 +54,25 @@ mod_key_of_str(char *val) {
static void
grab_key(Key *k) {
- XGrabKey(blz.dpy, k->key, k->mod, blz.root,
+ XGrabKey(display, k->key, k->mod, scr.root.w,
True, GrabModeAsync, GrabModeAsync);
if(num_lock_mask) {
- XGrabKey(blz.dpy, k->key, k->mod | num_lock_mask, blz.root,
+ XGrabKey(display, k->key, k->mod | num_lock_mask, scr.root.w,
True, GrabModeAsync, GrabModeAsync);
- XGrabKey(blz.dpy, k->key, k->mod | num_lock_mask | LockMask, blz.root,
+ XGrabKey(display, k->key, k->mod | num_lock_mask | LockMask, scr.root.w,
True, GrabModeAsync, GrabModeAsync);
}
- XSync(blz.dpy, False);
+ XSync(display, False);
}
static void
ungrab_key(Key *k) {
- XUngrabKey(blz.dpy, k->key, k->mod, blz.root);
+ XUngrabKey(display, k->key, k->mod, scr.root.w);
if(num_lock_mask) {
- XUngrabKey(blz.dpy, k->key, k->mod | num_lock_mask, blz.root);
- XUngrabKey(blz.dpy, k->key, k->mod | num_lock_mask | LockMask, blz.root);
+ XUngrabKey(display, k->key, k->mod | num_lock_mask, scr.root.w);
+ XUngrabKey(display, k->key, k->mod | num_lock_mask | LockMask, scr.root.w);
}
- XSync(blz.dpy, False);
+ XSync(display, False);
}
static Key *
@@ -111,8 +111,8 @@ get_key(const char *name) {
kstr++;
else
kstr = seq[i];
- k->key = XKeysymToKeycode(blz.dpy, XStringToKeysym(kstr));
- k->mod = mod_key_of_str(seq[i]);
+ k->key = XKeysymToKeycode(display, XStringToKeysym(kstr));
+ k->mod = str2modmask(seq[i]);
}
if(r) {
r->id = id++;
@@ -130,30 +130,30 @@ next_keystroke(ulong *mod, KeyCode *code) {
*mod = 0;
do {
- XMaskEvent(blz.dpy, KeyPressMask, &e);
+ XMaskEvent(display, KeyPressMask, &e);
*mod |= e.xkey.state & valid_mask;
*code = (KeyCode) e.xkey.keycode;
- sym = XKeycodeToKeysym(blz.dpy, e.xkey.keycode, 0);
+ sym = XKeycodeToKeysym(display, e.xkey.keycode, 0);
} while(IsModifierKey(sym));
}
static void
emulate_key_press(ulong mod, KeyCode key) {
XEvent e;
- Window client_win;
+ XWindow client_win;
int revert;
- XGetInputFocus(blz.dpy, &client_win, &revert);
+ XGetInputFocus(display, &client_win, &revert);
e.xkey.type = KeyPress;
e.xkey.time = CurrentTime;
e.xkey.window = client_win;
- e.xkey.display = blz.dpy;
+ e.xkey.display = display;
e.xkey.state = mod;
e.xkey.keycode = key;
- XSendEvent(blz.dpy, client_win, True, KeyPressMask, &e);
+ XSendEvent(display, client_win, True, KeyPressMask, &e);
e.xkey.type = KeyRelease;
- XSendEvent(blz.dpy, client_win, True, KeyReleaseMask, &e);
- XSync(blz.dpy, False);
+ XSendEvent(display, client_win, True, KeyReleaseMask, &e);
+ XSync(display, False);
}
static Key *
@@ -172,7 +172,7 @@ match_keys(Key *k, ulong mod, KeyCode keycode, Bool seq) {
}
static void
-kpress_seq(Window w, Key *done) {
+kpress_seq(XWindow w, Key *done) {
ulong mod;
KeyCode key;
Key *found;
@@ -183,7 +183,7 @@ kpress_seq(Window w, Key *done) {
emulate_key_press(mod, key); /* double key */
else {
if(!found) {
- XBell(blz.dpy, 0);
+ XBell(display, 0);
} /* grabbed but not found */
else if(!found->tnext && !found->next)
write_event("Key %s\n", found->name);
@@ -193,27 +193,27 @@ kpress_seq(Window w, Key *done) {
}
void
-kpress(Window w, ulong mod, KeyCode keycode) {
+kpress(XWindow w, ulong mod, KeyCode keycode) {
Key *k, *found;
for(k=key; k; k=k->lnext)
k->tnext=k->lnext;
found = match_keys(key, mod, keycode, False);
if(!found) {
- XBell(blz.dpy, 0);
+ XBell(display, 0);
} /* grabbed but not found */
else if(!found->tnext && !found->next)
write_event("Key %s\n", found->name);
else {
- XGrabKeyboard(blz.dpy, w, True, GrabModeAsync, GrabModeAsync, CurrentTime);
+ XGrabKeyboard(display, w, True, GrabModeAsync, GrabModeAsync, CurrentTime);
kpress_seq(w, found);
- XUngrabKeyboard(blz.dpy, CurrentTime);
- XSync(blz.dpy, False);
+ XUngrabKeyboard(display, CurrentTime);
+ XSync(display, False);
}
}
void
-update_keys() {
+update_keys(void) {
Key *k, *n;
char *l, *p;
@@ -241,5 +241,5 @@ update_keys() {
if((k = get_key(l)))
grab_key(k);
}
- XSync(blz.dpy, False);
+ XSync(display, False);
}
diff --git a/cmd/wmii/main.c b/cmd/wmii/main.c
@@ -2,7 +2,6 @@
* Copyright ©2006-2007 Kris Maglione <fbsdaemon@gmail.com>
* See LICENSE file for license details.
*/
-#include <X11/Xatom.h>
#include <X11/Xproto.h>
#include <X11/cursorfont.h>
#include <errno.h>
@@ -22,7 +21,7 @@
static const char
version[] = "wmii-"VERSION", ©2007 Kris Maglione\n";
-static int (*x_error_handler) (Display *, XErrorEvent *);
+static int (*xlib_errorhandler) (Display*, XErrorEvent*);
static char *address, *ns_path;
static Bool check_other_wm;
static struct sigaction sa;
@@ -30,82 +29,41 @@ static struct passwd *passwd;
static int sleeperfd, sock, exitsignal;
static void
-usage() {
+usage(void) {
fatal("usage: wmii [-a <address>] [-r <wmiirc>] [-v]\n");
}
static void
-scan_wins() {
+scan_wins(void) {
int i;
uint num;
- Window *wins;
+ XWindow *wins;
XWindowAttributes wa;
- Window d1, d2;
+ XWindow d1, d2;
- if(XQueryTree(blz.dpy, blz.root, &d1, &d2, &wins, &num)) {
+ if(XQueryTree(display, scr.root.w, &d1, &d2, &wins, &num)) {
for(i = 0; i < num; i++) {
- if(!XGetWindowAttributes(blz.dpy, wins[i], &wa))
+ if(!XGetWindowAttributes(display, wins[i], &wa))
continue;
- if(wa.override_redirect || XGetTransientForHint(blz.dpy, wins[i], &d1))
+ if(wa.override_redirect || XGetTransientForHint(display, wins[i], &d1))
continue;
if(wa.map_state == IsViewable)
- manage_client(create_client(wins[i], &wa));
+ create_client(wins[i], &wa);
}
for(i = 0; i < num; i++) {
- if(!XGetWindowAttributes(blz.dpy, wins[i], &wa))
+ if(!XGetWindowAttributes(display, wins[i], &wa))
continue;
- if((XGetTransientForHint(blz.dpy, wins[i], &d1))
+ if((XGetTransientForHint(display, wins[i], &d1))
&& (wa.map_state == IsViewable))
- manage_client(create_client(wins[i], &wa));
+ create_client(wins[i], &wa);
}
}
if(wins)
XFree(wins);
}
-int
-win_proto(Window w) {
- Atom *protocols;
- Atom real;
- ulong nitems, extra;
- int i, format, status, protos;
-
- status = XGetWindowProperty(
- /* display */ blz.dpy,
- /* window */ w,
- /* property */ atom[WMProtocols],
- /* offset */ 0L,
- /* length */ 20L,
- /* delete */ False,
- /* req_type */ XA_ATOM,
- /* type_ret */ &real,
- /* format_ret */&format,
- /* nitems_ret */&nitems,
- /* extra_bytes */&extra,
- /* prop_return */(uchar**)&protocols
- );
-
- if(status != Success || protocols == 0) {
- return 0;
- }
-
- if(nitems == 0) {
- free(protocols);
- return 0;
- }
-
- protos = 0;
- for(i = 0; i < nitems; i++) {
- if(protocols[i] == atom[WMDelete])
- protos |= WM_PROTOCOL_DELWIN;
- }
-
- free(protocols);
- return protos;
-}
-
static char*
-ns_display() {
+ns_display(void) {
char *s, *disp;
disp = getenv("DISPLAY");
@@ -144,7 +102,7 @@ rmkdir(char *path, int mode) {
}
static void
-init_ns() {
+init_ns(void) {
struct stat st;
char *s;
@@ -173,7 +131,7 @@ init_ns() {
}
static void
-init_environment() {
+init_environment(void) {
init_ns();
if(address == nil) {
@@ -186,30 +144,19 @@ init_environment() {
}
static void
-intern_atom(int ident, char *name) {
- atom[ident] = XInternAtom(blz.dpy, name, False);
-}
+init_atoms(void) {
+ Atom net[] = { xatom("_NET_SUPPORTED"), xatom("_NET_WM_NAME") };
-static void
-init_atoms() {
- intern_atom(WMState, "WM_STATE");
- intern_atom(WMProtocols, "WM_PROTOCOLS");
- intern_atom(WMDelete, "WM_DELETE_WINDOW");
- intern_atom(NetSupported, "_NET_SUPPORTED");
- intern_atom(NetWMName, "_NET_WM_NAME");
- intern_atom(TagsAtom, "_WIN_TAGS");
-
- XChangeProperty(blz.dpy, blz.root, atom[NetSupported], XA_ATOM, 32,
- PropModeReplace, (uchar *)&atom[NetSupported], 2);
+ changeprop(&scr.root, "_NET_SUPPORTED", "ATOM", net, nelem(net));
}
static void
create_cursor(int ident, uint shape) {
- cursor[ident] = XCreateFontCursor(blz.dpy, shape);
+ cursor[ident] = XCreateFontCursor(display, shape);
}
static void
-init_cursors() {
+init_cursors(void) {
Pixmap pix;
XColor black, dummy;
@@ -221,24 +168,26 @@ init_cursors() {
create_cursor(CurMove, XC_fleur);
create_cursor(CurDHArrow, XC_sb_h_double_arrow);
create_cursor(CurInput, XC_xterm);
+ create_cursor(CurSizing, XC_sizing);
+ create_cursor(CurIcon, XC_icon);
- XAllocNamedColor(blz.dpy, DefaultColormap(blz.dpy, blz.screen),
- "black", &black,
- &dummy);
- pix = XCreateBitmapFromData(blz.dpy, blz.root,
+ XAllocNamedColor(display, scr.colormap,
+ "black", &black, &dummy);
+ pix = XCreateBitmapFromData(
+ display, scr.root.w,
(char[]){0}, 1, 1);
- cursor[CurInvisible] = XCreatePixmapCursor(blz.dpy,
+ cursor[CurInvisible] = XCreatePixmapCursor(display,
pix, pix,
&black, &black,
0, 0);
- XFreePixmap(blz.dpy, pix);
+ XFreePixmap(display, pix);
}
static void
init_screen(WMScreen *screen) {
- Window w;
+ XWindow w;
int ret;
unsigned mask;
XGCValues gcv;
@@ -248,7 +197,10 @@ init_screen(WMScreen *screen) {
gcv.foreground = def.normcolor.bg;
gcv.plane_mask = AllPlanes;
gcv.graphics_exposures = False;
- xorgc = XCreateGC(blz.dpy, blz.root,
+
+ xor.type = WImage;
+ xor.image = scr.root.w;
+ xor.gc = XCreateGC(display, scr.root.w,
GCForeground
| GCGraphicsExposures
| GCFunction
@@ -256,17 +208,23 @@ init_screen(WMScreen *screen) {
| GCPlaneMask,
&gcv);
- screen->rect.x = screen->rect.y = 0;
- screen->rect.width = DisplayWidth(blz.dpy, blz.screen);
- screen->rect.height = DisplayHeight(blz.dpy, blz.screen);
- def.snap = screen->rect.height / 63;
+ screen->r = scr.rect;
+ def.snap = Dy(scr.rect) / 63;
- sel_screen = XQueryPointer(blz.dpy, blz.root,
+ sel_screen = XQueryPointer(display, scr.root.w,
&w, &w,
&ret, &ret, &ret, &ret,
&mask);
}
+static void
+cleanup(void) {
+ while(client)
+ destroy_client(client);
+ ixp_server_close(&srv);
+ close(sleeperfd);
+}
+
struct {
uchar rcode, ecode;
} itab[] = {
@@ -281,12 +239,13 @@ struct {
/*
* There's no way to check accesses to destroyed windows, thus
- * those cases are ignored (especially on UnmapNotifies).
+ * those cases are ignored (especially on UnmapNotifys).
* Other types of errors call Xlib's default error handler, which
* calls exit().
*/
-int
-wmii_error_handler(Display *dpy, XErrorEvent *error) {
+static int
+errorhandler(Display *dpy, XErrorEvent *error) {
+ static Bool dead;
int i;
if(check_other_wm)
@@ -299,16 +258,11 @@ wmii_error_handler(Display *dpy, XErrorEvent *error) {
fprintf(stderr, "%s: fatal error: Xrequest code=%d, Xerror code=%d\n",
argv0, error->request_code, error->error_code);
- return x_error_handler(blz.dpy, error); /* calls exit() */
-}
-static void
-cleanup() {
- Client *c;
-
- for(c=client; c; c=c->next)
- reparent_client(c, blz.root, c->sel->rect.x, c->sel->rect.y);
- XSync(blz.dpy, False);
+ /* Try to cleanup, but only try once, in case we're called again */
+ if(!dead++)
+ cleanup();
+ return xlib_errorhandler(display, error); /* calls exit() */
}
static void
@@ -328,7 +282,7 @@ cleanup_handler(int signal) {
}
static void
-init_traps() {
+init_traps(void) {
char buf[1];
int fd[2];
@@ -341,18 +295,18 @@ init_traps() {
break; /* not reached */
case 0:
close(fd[1]);
- close(ConnectionNumber(blz.dpy));
+ close(ConnectionNumber(display));
setsid();
- blz.dpy = XOpenDisplay(0);
- if(!blz.dpy)
+ display = XOpenDisplay(0);
+ if(!display)
fatal("Can't open display");
/* Wait for parent to exit */
read(fd[0], buf, 1);
- XSetInputFocus(blz.dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
- XCloseDisplay(blz.dpy);
+ XSetInputFocus(display, PointerRoot, RevertToPointerRoot, CurrentTime);
+ XCloseDisplay(display);
exit(0);
default:
break;
@@ -389,7 +343,7 @@ spawn_command(const char *cmd) {
if(setsid() == -1)
fatal("Can't setsid:");
close(sock);
- close(ConnectionNumber(blz.dpy));
+ close(ConnectionNumber(display));
shell = passwd->pw_shell;
if(shell[0] != '/')
@@ -414,18 +368,24 @@ spawn_command(const char *cmd) {
}
}
-void
+static void
check_9pcon(IxpConn *c) {
serve_9pcon(c);
check_x_event(nil);
}
+static void
+closedisplay(IxpConn *c) {
+ XCloseDisplay(display);
+}
+
int
main(int argc, char *argv[]) {
- char *wmiirc;
+ char *wmiirc, *str;
WMScreen *s;
- XSetWindowAttributes wa;
+ WinAttr wa;
int i;
+ ulong col;
wmiirc = "wmiistartrc";
@@ -453,16 +413,16 @@ main(int argc, char *argv[]) {
setlocale(LC_CTYPE, "");
starting = True;
- blz.dpy = XOpenDisplay(0);
- if(!blz.dpy)
- fatal("Can't open display");
- blz.screen = DefaultScreen(blz.dpy);
- blz.root = RootWindow(blz.dpy, blz.screen);
+ initdisplay();
+
+ xlib_errorhandler = XSetErrorHandler(errorhandler);
check_other_wm = True;
- x_error_handler = XSetErrorHandler(wmii_error_handler);
- XSelectInput(blz.dpy, blz.root, SubstructureRedirectMask | EnterWindowMask);
- XSync(blz.dpy, False);
+ XSelectInput(display, scr.root.w,
+ SubstructureRedirectMask
+ | EnterWindowMask);
+ XSync(display, False);
+
check_other_wm = False;
passwd = getpwuid(getuid());
@@ -470,7 +430,6 @@ main(int argc, char *argv[]) {
init_environment();
- errstr = nil;
sock = ixp_announce(address);
if(sock < 0)
fatal("Can't create socket '%s': %s", address, errstr);
@@ -478,48 +437,39 @@ main(int argc, char *argv[]) {
if(wmiirc)
spawn_command(wmiirc);
- ixp_listen(&srv, sock, &p9srv, check_9pcon, nil);
- ixp_listen(&srv, ConnectionNumber(blz.dpy), nil, check_x_event, nil);
+ init_traps();
+ init_atoms();
+ init_cursors();
+ init_lock_keys();
- view = nil;
- client = nil;
- key = nil;
+ ixp_listen(&srv, sock, &p9srv, check_9pcon, nil);
+ ixp_listen(&srv, ConnectionNumber(display), nil, check_x_event, closedisplay);
- def.font.fontstr = estrdup(BLITZ_FONT);
+ def.font = loadfont(FONT);
def.border = 1;
def.colmode = Coldefault;
def.mod = Mod1Mask;
strncpy(def.grabmod, "Mod1", sizeof(def.grabmod));
- strncpy(def.focuscolor.colstr, BLITZ_FOCUSCOLORS, sizeof(def.focuscolor.colstr));
- strncpy(def.normcolor.colstr, BLITZ_NORMCOLORS, sizeof(def.normcolor.colstr));
- loadcolor(&blz, &def.focuscolor);
- loadcolor(&blz, &def.normcolor);
-
- init_traps();
- init_atoms();
- init_cursors();
- loadfont(&blz, &def.font);
- init_lock_keys();
+ loadcolor(&def.focuscolor, FOCUSCOLORS);
+ loadcolor(&def.normcolor, NORMCOLORS);
num_screens = 1;
screens = emallocz(num_screens * sizeof(*screens));
+ screen = &screens[0];
for(i = 0; i < num_screens; i++) {
s = &screens[i];
init_screen(s);
- pmap = XCreatePixmap(
- /* display */ blz.dpy,
- /* drawable */ blz.root,
- /* width */ s->rect.width,
- /* height */ s->rect.height,
- /* depth */ DefaultDepth(blz.dpy, blz.screen)
- );
+
+ s->ibuf = allocimage(Dx(s->r), Dy(s->r), scr.depth);
+
wa.event_mask =
- SubstructureRedirectMask
- | EnterWindowMask
- | LeaveWindowMask
- | FocusChangeMask;
+ SubstructureRedirectMask
+ | SubstructureNotifyMask
+ | EnterWindowMask
+ | LeaveWindowMask
+ | FocusChangeMask;
wa.cursor = cursor[CurNormal];
XChangeWindowAttributes(blz.dpy, blz.root, CWEventMask | CWCursor, &wa);
wa.override_redirect = 1;
@@ -561,12 +511,20 @@ main(int argc, char *argv[]) {
XMapRaised(blz.dpy, s->barwin);
}
- screen = &screens[0];
+ str = "This app is broken. Disable its transparency feature.";
+ i = textwidth(def.font, str) + labelh(def.font);
+ broken = allocimage(i, labelh(def.font), scr.depth);
+
+ namedcolor("#ff0000", &col);
+ fill(broken, broken->r, scr.black);
+ drawstring(broken, def.font, broken->r, EAST, str, col);
+
screen->focus = nil;
- XSetInputFocus(blz.dpy, screen->barwin, RevertToParent, CurrentTime);
+ setfocus(screen->barwin, RevertToParent);
scan_wins();
starting = False;
+
select_view("nil");
update_views();
write_event("FocusTag %s\n", screen->sel->name);
@@ -577,9 +535,6 @@ main(int argc, char *argv[]) {
fprintf(stderr, "%s: error: %s\n", argv0, errstr);
cleanup();
- XCloseDisplay(blz.dpy);
- ixp_server_close(&srv);
- close(sleeperfd);
if(exitsignal)
raise(exitsignal);
diff --git a/cmd/wmii/map.c b/cmd/wmii/map.c
@@ -0,0 +1,120 @@
+/* Written by Kris Maglione */
+/* Public domain */
+#include <stdlib.h>
+#include <string.h>
+#include <util.h>
+#include "dat.h"
+#include "fns.h"
+
+/* Edit s/^([a-zA-Z].*)\n([a-z].*) {/\1 \2;/g x/^([^a-zA-Z]|static|$)/-+d s/ (\*map|val|*str)//g */
+
+MapEnt *NM;
+
+/* By Dan Bernstein. Public domain. */
+static ulong
+hash(const char *str) {
+ ulong h;
+
+ h = 5381;
+ while (*str != '\0') {
+ h += h << 5; /* h *= 33 */
+ h ^= *str++;
+ }
+ return h;
+}
+
+static void
+insert(MapEnt **e, ulong val, char *key) {
+ MapEnt *te;
+
+ te = emallocz(sizeof *te);
+ te->hash = val;
+ te->key = key;
+ te->next = *e;
+ *e = te;
+}
+
+static MapEnt**
+mapgetp(Map *map, ulong val, int create) {
+ MapEnt **e;
+
+ e = &map->bucket[val%map->nhash];
+ for(; *e; e = &(*e)->next)
+ if((*e)->hash >= val) break;
+ if(*e == nil || (*e)->hash != val) {
+ if(create)
+ insert(e, val, nil);
+ else
+ e = &NM;
+ }
+ return e;
+}
+
+static MapEnt**
+hashgetp(Map *map, char *str, int create) {
+ MapEnt **e;
+ ulong h;
+ int cmp;
+
+ h = hash(str);
+ e = mapgetp(map, h, create);
+ if(*e && (*e)->key == nil)
+ (*e)->key = str;
+ else {
+ for(; *e; e = &(*e)->next)
+ if((*e)->hash > h || (cmp = strcmp((*e)->key, str)) >= 0)
+ break;
+ if(*e == nil || (*e)->hash > h || cmp > 0)
+ if(create)
+ insert(e, h, str);
+ }
+ return e;
+}
+
+MapEnt*
+mapget(Map *map, ulong val, int create) {
+ MapEnt **e;
+
+ e = mapgetp(map, val, create);
+ return *e;
+}
+
+MapEnt*
+hashget(Map *map, char *str, int create) {
+ MapEnt **e;
+
+ e = hashgetp(map, str, create);
+ return *e;
+}
+
+void*
+maprm(Map *map, ulong val) {
+ MapEnt **e, *te;
+ void *ret;
+
+ ret = nil;
+ e = mapgetp(map, val, 0);
+ if(*e) {
+ te = *e;
+ ret = te->val;
+ *e = te->next;
+ free(te);
+ }
+ return ret;
+}
+
+void*
+hashrm(Map *map, char *str) {
+ MapEnt **e, *te;
+ void *ret;
+
+ ret = nil;
+ e = hashgetp(map, str, 0);
+ if(*e) {
+ te = *e;
+ ret = te->val;
+ *e = te->next;
+ free(te);
+ }
+ return ret;
+}
diff --git a/cmd/wmii/message.c b/cmd/wmii/message.c
@@ -0,0 +1,583 @@
+/* Copyright ©2006-2007 Kris Maglione <fbsdaemon@gmail.com>
+ * See LICENSE file for license details.
+ */
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <util.h>
+#include "dat.h"
+#include "fns.h"
+
+static char
+ Ebadcmd[] = "bad command",
+ Ebadvalue[] = "bad value";
+
+/* Edit |sort Edit s/"([^"]+)"/L\1/g Edit |tr 'a-z' 'A-Z' */
+enum {
+ LFULLSCREEN,
+ LNOTFULLSCREEN,
+ LNOTURGENT,
+ LURGENT,
+ LBORDER,
+ LCOLMODE,
+ LDOWN,
+ LEXEC,
+ LFOCUSCOLORS,
+ LFONT,
+ LGRABMOD,
+ LKILL,
+ LLEFT,
+ LNORMCOLORS,
+ LQUIT,
+ LRIGHT,
+ LSELCOLORS,
+ LSELECT,
+ LSEND,
+ LSWAP,
+ LTOGGLE,
+ LUP,
+ LVIEW,
+ LTILDE,
+};
+char *symtab[] = {
+ "Fullscreen",
+ "NotFullscreen",
+ "NotUrgent",
+ "Urgent",
+ "border",
+ "colmode",
+ "down",
+ "exec",
+ "focuscolors",
+ "font",
+ "grabmod",
+ "kill",
+ "left",
+ "normcolors",
+ "quit",
+ "right",
+ "selcolors",
+ "select",
+ "send",
+ "swap",
+ "toggle",
+ "up",
+ "view",
+ "~",
+};
+
+/* Edit ,y/^[a-zA-Z].*\n.* {\n/d
+ * Edit s/^([a-zA-Z].*)\n(.*) {\n/\1 \2;\n/
+ * Edit ,x/^static.*\n/d
+ */
+
+static int
+getsym(char *s) {
+ int i, n, m, cmp;
+
+ n = nelem(symtab);
+ i = 0;
+ while(n) {
+ m = n/2;
+ cmp = strcmp(s, symtab[i+m]);
+ if(cmp == 0)
+ return i+m;
+ if(cmp < 0 || m == 0)
+ n = m;
+ else {
+ i += m;
+ n = n-m;
+ }
+ }
+ return -1;
+}
+
+static void
+eatrunes(Message *m, int (*p)(Rune), int val) {
+ Rune r;
+ int n;
+
+ while(m->pos < m->end) {
+ n = chartorune(&r, m->pos);
+ if(p(r) != val)
+ break;
+ m->pos += n;
+ }
+}
+
+char *
+getword(Message *m) {
+ char *ret;
+ Rune r;
+ int n;
+
+ eatrunes(m, isspacerune, 1);
+ ret = m->pos;
+ eatrunes(m, isspacerune, 0);
+ n = chartorune(&r, m->pos);
+ *m->pos = '\0';
+ m->pos += n;
+ eatrunes(m, isspacerune, 1);
+
+ return ret;
+}
+
+
+#define strbcmp(str, const) (strncmp((str), (const), sizeof(const)-1))
+static int
+getbase(char **s) {
+ char base[3];
+ char *p;
+
+ p = *s;
+ if(!strbcmp(p, "0x")) {
+ *s += 2;
+ return 16;
+ }
+ if(isdigit(p[0]) && p[1] == 'r') {
+ *s += 2;
+ return p[0] - '0';
+ }
+ if(isdigit(p[0]) && isdigit(p[1]) && p[2] == 'r') {
+ *s += 3;
+ strncpy(base, p, sizeof base);
+ return atoi(base);
+ }
+ if(!strbcmp(p, "0")) {
+ *s += 1;
+ return 8;
+ }
+ return 10;
+}
+
+static int
+getlong(char *s, long *ret) {
+ char *end, *rend;
+ int base;
+
+ end = s+strlen(s);
+ base = getbase(&s);
+
+ *ret = strtol(s, &rend, base);
+ return (end == rend);
+}
+
+static int
+getulong(char *s, ulong *ret) {
+ char *end, *rend;
+ int base;
+
+ end = s+strlen(s);
+ base = getbase(&s);
+
+ *ret = strtoul(s, &rend, base);
+ return (end == rend);
+}
+
+static Client *
+strclient(View *v, char *s) {
+ ulong id;
+
+ if(!strcmp(s, "sel"))
+ return view_selclient(v);
+ if(getulong(s, &id))
+ return win2client(id);
+
+ return nil;
+}
+
+Area *
+strarea(View *v, char *s) {
+ Area *a;
+ long i;
+
+ if(!strcmp(s, "sel"))
+ return v->sel;
+ if(!strcmp(s, "~"))
+ return v->area;
+ if(!getlong(s, &i) || i == 0)
+ return nil;
+
+ if(i > 0)
+ for(a = v->area; a; a = a->next) {
+ if(i-- == 0) break;
+ }
+ else {
+ for(a = v->area; a->next; a = a->next)
+ ;
+ for(; a != v->area; a = a->prev)
+ if(++i == 0) break;
+ if(a == v->area)
+ a = nil;
+ }
+ return a;
+}
+
+char *
+message_view(View *v, Message *m) {
+ Area *a;
+ char *s;
+ int i;
+
+ s = getword(m);
+
+ switch(getsym(s)) {
+ case LSEND:
+ return send_client(v, m, 0);
+ case LSWAP:
+ return send_client(v, m, 1);
+ case LSELECT:
+ return select_area(v->sel, m);
+ case LCOLMODE:
+ s = getword(m);
+ if((a = strarea(v, s)) == nil || a->floating)
+ return Ebadvalue;
+
+ s = getword(m);
+ if((i = str2colmode(s)) == -1)
+ return Ebadvalue;
+
+ a->mode = i;
+ arrange_column(a, True);
+ restack_view(v);
+
+ if(v == screen->sel)
+ focus_view(screen, v);
+ draw_frames();
+ return nil;
+ default:
+ return Ebadcmd;
+ }
+ assert(!"can't get here");
+}
+
+char *
+parse_colors(Message *m, CTuple *col) {
+ static regex_t reg;
+ static Bool compiled;
+ char c;
+
+ if(!compiled) {
+ compiled = 1;
+ regcomp(®, "^#[0-9a-f]{6} #[0-9a-f]{6} #[0-9a-f]{6}([[:space:]]|$)",
+ REG_EXTENDED|REG_NOSUB|REG_ICASE);
+ }
+
+ if(m->pos + 23 > m->end || regexec(®, m->pos, 0, 0, 0))
+ return "bad value";
+
+ c = m->pos[23];
+ m->pos[23] = '\0';
+ loadcolor(col, m->pos);
+ m->pos[23] = c;
+
+ m->pos += 23;
+ eatrunes(m, isspacerune, 1);
+ return nil;
+}
+
+char *
+message_root(void *p, Message *m) {
+ Font *fn;
+ char *s, *ret;
+ ulong n;
+
+ ret = nil;
+ s = getword(m);
+
+ switch(getsym(s)) {
+ case LQUIT:
+ srv.running = 0;
+ break;
+ case LEXEC:
+ execstr = emalloc(strlen(m->pos) + sizeof("exec "));
+ sprintf(execstr, "exec %s", m->pos);
+ srv.running = 0;
+ break;
+ case LVIEW:
+ select_view(m->pos);
+ break;
+ case LSELCOLORS:
+ fprintf(stderr, "%s: warning: selcolors have been removed\n", argv0);
+ return Ebadcmd;
+ case LFOCUSCOLORS:
+ ret = parse_colors(m, &def.focuscolor);
+ focus_view(screen, screen->sel);
+ break;
+ case LNORMCOLORS:
+ ret = parse_colors(m, &def.normcolor);
+ focus_view(screen, screen->sel);
+ break;
+ case LFONT:
+ fn = loadfont(m->pos);
+ if(fn) {
+ freefont(def.font);
+ def.font = fn;
+ resize_bar(screen);
+ }else
+ ret = "can't load font";
+ break;
+ case LBORDER:
+ if(!getulong(getword(m), &n))
+ return Ebadvalue;
+ def.border = n;
+ /* XXX: Apply the change */
+ break;
+ case LGRABMOD:
+ s = getword(m);
+ n = str2modmask(s);
+
+ if((n & (Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) == 0)
+ return Ebadvalue;
+
+ strncpy(def.grabmod, s, sizeof(def.grabmod));
+ def.mod = n;
+ break;
+ default:
+ return Ebadcmd;
+ }
+ return ret;
+}
+
+char *
+read_root_ctl(void) {
+ uint i = 0;
+ i += snprintf(&buffer[i], (sizeof(buffer) - i), "view %s\n", screen->sel->name);
+ i += snprintf(&buffer[i], (sizeof(buffer) - i), "focuscolors %s\n", def.focuscolor.colstr);
+ i += snprintf(&buffer[i], (sizeof(buffer) - i), "normcolors %s\n", def.normcolor.colstr);
+ i += snprintf(&buffer[i], (sizeof(buffer) - i), "font %s\n", def.font->name);
+ i += snprintf(&buffer[i], (sizeof(buffer) - i), "grabmod %s\n", def.grabmod);
+ i += snprintf(&buffer[i], (sizeof(buffer) - i), "border %d\n", def.border);
+ return buffer;
+}
+
+char *
+message_client(Client *c, Message *m) {
+ char *s;
+
+ s = getword(m);
+
+ switch(getsym(s)) {
+ case LKILL:
+ kill_client(c);
+ break;
+ case LURGENT:
+ set_urgent(c, True, True);
+ break;
+ case LNOTURGENT:
+ set_urgent(c, False, True);
+ break;
+ case LFULLSCREEN:
+ fullscreen(c, True);
+ break;
+ case LNOTFULLSCREEN:
+ fullscreen(c, False);
+ break;
+ default:
+ return Ebadcmd;
+ }
+ return nil;
+}
+
+static char*
+send_frame(Frame *f, int sym, Bool swap) {
+ Frame *fp;
+ Area *a;
+
+ a = f->area;
+
+ switch(sym) {
+ case LUP:
+ fp = f->aprev;
+ if(!fp)
+ return Ebadvalue;
+ fp = fp->aprev;
+ break;
+ case LDOWN:
+ fp = f->anext;
+ if(!fp)
+ return Ebadvalue;
+ break;
+ default:
+ assert(!"can't get here");
+ }
+
+ if(swap) {
+ if(!fp)
+ return Ebadvalue;
+ swap_frames(f, fp);
+ }else {
+ remove_frame(f);
+ insert_frame(fp, f);
+ }
+
+ arrange_view(f->view);
+
+ flushevents(EnterWindowMask, False);
+ focus_frame(f, True);
+ update_views();
+ return nil;
+}
+
+char *
+send_client(View *v, Message *m, Bool swap) {
+ Area *to, *a;
+ Frame *f;
+ Client *c;
+ char *s;
+ ulong i;
+ int sym;
+
+ s = getword(m);
+
+ c = strclient(v, s);
+ if(c == nil)
+ return Ebadvalue;
+
+ f = view_clientframe(v, c);
+ if(f == nil)
+ return Ebadvalue;
+
+ a = f->area;
+ to = nil;
+
+ s = getword(m);
+ sym = getsym(s);
+
+ switch(sym) {
+ case LTOGGLE:
+ if(!a->floating)
+ to = v->area;
+ else if(c->revert && !c->revert->floating)
+ to = c->revert;
+ else
+ to = v->area->next;
+ break;
+ case LUP:
+ case LDOWN:
+ return send_frame(f, sym, swap);
+ case LLEFT:
+ if(a->floating)
+ return Ebadvalue;
+
+ if(a->prev != v->area)
+ to = a->prev;
+ a = v->area;
+ break;
+ case LRIGHT:
+ if(a->floating)
+ return Ebadvalue;
+
+ to = a->next;
+ break;
+ default:
+ if(!getulong(s, &i) || i == 0)
+ return Ebadvalue;
+
+ for(to=v->area; to; to=to->next)
+ if(!i--) break;
+ break;
+ }
+
+ if(!to && !swap && (f->anext || f != a->frame))
+ to = new_column(v, a, 0);
+
+ if(!to)
+ return Ebadvalue;
+
+ if(!swap)
+ send_to_area(to, f);
+ else if(to->sel)
+ swap_frames(f, to->sel);
+ else
+ return Ebadvalue;
+
+ flushevents(EnterWindowMask, False);
+ focus_frame(f, True);
+ arrange_view(v);
+ update_views();
+ return nil;
+}
+
+static char*
+select_frame(Frame *f, int sym) {
+ Frame *fp;
+ Area *a;
+
+ if(!f)
+ return Ebadvalue;
+ a = f->area;
+
+ switch(sym) {
+ case LUP:
+ for(fp = a->frame; fp->anext; fp = fp->anext)
+ if(fp->anext == f) break;
+ break;
+ case LDOWN:
+ fp = f->anext;
+ if(fp == nil)
+ fp = a->frame;
+ break;
+ default:
+ assert(!"can't get here");
+ }
+
+ focus_frame(fp, False);
+ frame_to_top(fp);
+ if(f->view == screen->sel)
+ restack_view(f->view);
+ return nil;
+}
+
+char*
+select_area(Area *a, Message *m) {
+ Area *ap;
+ View *v;
+ char *s;
+ ulong i;
+ int sym;
+
+ v = a->view;
+ s = getword(m);
+ sym = getsym(s);
+
+ switch(sym) {
+ case LUP:
+ case LDOWN:
+ return select_frame(a->sel, sym);
+ case LTOGGLE:
+ if(!a->floating)
+ ap = v->area;
+ else if(v->revert && v->revert != a)
+ ap = v->revert;
+ else
+ ap = v->area->next;
+ break;
+ case LLEFT:
+ if(a->floating)
+ return Ebadvalue;
+ for(ap=v->area->next; ap->next; ap=ap->next)
+ if(ap->next == a) break;
+ break;
+ case LRIGHT:
+ if(a->floating)
+ return Ebadvalue;
+ ap = a->next;
+ if(ap == nil)
+ ap = v->area->next;
+ break;
+ case LTILDE:
+ ap = v->area;
+ break;
+ default:
+ if(!getulong(s, &i) || i == 0)
+ return Ebadvalue;
+ for(ap=v->area->next; ap; ap=ap->next)
+ if(!--i) break;
+ }
+
+ focus_area(ap);
+ return nil;
+}
diff --git a/cmd/wmii/mouse.c b/cmd/wmii/mouse.c
@@ -1,6 +1,7 @@
-/* Copyright ©2006 Kris Maglione <fbsdaemon@gmail.com>
+/* Copyright ©2006-2007 Kris Maglione <fbsdaemon@gmail.com>
* See LICENSE file for license details.
*/
+#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -15,355 +16,499 @@ enum {
ButtonMask | PointerMotionMask
};
-static void
-rect_morph_xy(XRectangle *rect, int dx, int dy, BlitzAlign *mask) {
- BlitzAlign nmask;
-
- nmask = 0;
- if(*mask & NORTH) {
- if(rect->height - dy >= 0 || *mask & SOUTH) {
- rect->y += dy;
- rect->height -= dy;
- }
- else {
- rect->y += rect->height;
- rect->height = dy - rect->height;
- nmask ^= NORTH|SOUTH;
- }
- }
- if(*mask & SOUTH) {
- if(rect->height + dy >= 0 || *mask & NORTH)
- rect->height += dy;
- else {
- rect->height = -dy - rect->height;
- rect->y -= rect->height;
- nmask ^= NORTH|SOUTH;
- }
- }
- if(*mask & EAST) {
- if(rect->width + dx >= 0 || *mask & WEST)
- rect->width += dx;
- else {
- rect->width = -dx - rect->width;
- rect->x -= rect->width;
- nmask ^= EAST|WEST;
- }
- }
- if(*mask & WEST) {
- if(rect->width - dx >= 0 || *mask & EAST) {
- rect->x += dx;
- rect->width -= dx;
- }
- else {
- rect->x += rect->width;
- rect->width = dx - rect->width;
- nmask ^= EAST|WEST;
- }
- }
- *mask ^= nmask;
-}
-
-typedef struct {
- XRectangle *rects;
- int num;
- int x1, y1;
- int x2, y2;
- int dx, dy;
- BlitzAlign mask;
-} SnapArgs;
-
-static void
-snap_line(SnapArgs *a) {
- int i, t_xy;
-
- /* horizontal */
- if(a->y1 == a->y2 && (a->mask & (NORTH|SOUTH))) {
- for(i=0; i < a->num; i++) {
- if(!(r_east(&a->rects[i]) < a->x1) ||
- (a->rects[i].x > a->x2)) {
+static Handlers handlers;
- if(abs(a->rects[i].y - a->y1) <= abs(a->dy))
- a->dy = a->rects[i].y - a->y1;
+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;
+};
- t_xy = r_south(&a->rects[i]);
- if(abs(t_xy - a->y1) < abs(a->dy))
- a->dy = t_xy - a->y1;
- }
- }
+static Rectangle
+framerect(Framewin *f) {
+ Rectangle r;
+ 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;
+ 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 = rectsubpt(r, Pt(Dx(r)/2, 0));
}
- else if (a->mask & (EAST|WEST)) {
- for(i=0; i < a->num; i++) {
- if(!(r_south(&a->rects[i]) < a->y1) ||
- (a->rects[i].y > a->y2)) {
-
- if(abs(a->rects[i].x - a->x1) <= abs(a->dx))
- a->dx = a->rects[i].x - a->x1;
+ r = rectaddpt(r, f->pt);
+
+ /* Keep onscreen */
+ p = ZP;
+ p.x -= min(r.min.x, 0);
+ p.x -= max(r.max.x - screen->r.max.x, 0);
+ p.y -= max(r.max.y - screen->brect.min.y - Dy(r)/2, 0);
+ return rectaddpt(r, p);
+}
- t_xy = r_east(&a->rects[i]);
- if(abs(t_xy - a->x1) < abs(a->dx))
- a->dx = t_xy - a->x1;
- }
- }
- }
+static void
+frameadjust(Framewin *f, Point pt, int or, int n) {
+ f->or = or;
+ f->n = n;
+ f->pt = pt;
}
-/* Returns a gravity for increment handling. It's normally the opposite of the mask
- * (the directions that we're resizing in), unless a snap occurs, in which case, it's the
- * direction of the snap.
- */
-BlitzAlign
-snap_rect(XRectangle *rects, int num, XRectangle *current, BlitzAlign *mask, int snap) {
- SnapArgs a = { 0, };
- BlitzAlign ret;
-
- a.rects = rects;
- a.num = num;
- a.mask = *mask;
- a.dx = snap + 1;
- a.dy = snap + 1;
-
- a.x1 = current->x;
- a.x2 = r_east(current);
- if(*mask & NORTH) {
- a.y2 = a.y1 = current->y;
- snap_line(&a);
- }
- if(*mask & SOUTH) {
- a.y2 = a.y1 = r_south(current);
- snap_line(&a);
- }
+static Framewin*
+framewin(Frame *f, Point pt, int or, int n) {
+ WinAttr wa;
+ Framewin *fw;
- a.y1 = current->y;
- a.y2 = r_south(current);
- if(*mask & EAST) {
- a.x1 = a.x2 = r_east(current);
- snap_line(&a);
- }
- if(*mask & WEST) {
- a.x1 = a.x2 = current->x;
- snap_line(&a);
- }
+ fw = emallocz(sizeof *fw);
+ wa.override_redirect = True;
+ wa.event_mask = ExposureMask;
+ fw->w = createwindow(&scr.root, Rect(0, 0, 1, 1), scr.depth, InputOutput, &wa, CWEventMask);
+ fw->w->aux = fw;
+ sethandler(fw->w, &handlers);
- ret = CENTER;
- if(abs(a.dx) > snap)
- a.dx = 0;
- else
- ret ^= EAST|WEST;
+ fw->f = f;
+ fw->gb = f->grabbox;
+ frameadjust(fw, pt, or, n);
+ reshapewin(fw->w, framerect(fw));
- if(abs(a.dy) > snap)
- a.dy = 0;
- else
- ret ^= NORTH|SOUTH;
+ mapwin(fw->w);
+ raisewin(fw->w);
- rect_morph_xy(current, a.dx, a.dy, mask);
+ return fw;
+}
return ret ^ *mask;
}
static void
-xorborder(XRectangle *r) {
- XRectangle xor;
-
- xor = *r;
- xor.x += 2;
- xor.y += 2;
- xor.width = xor.width > 4 ? xor.width - 4 : 0;
- xor.height = xor.height > 4 ? xor.height - 4 : 0;
-
- XSetLineAttributes(blz.dpy, xorgc, 1, LineSolid, CapNotLast, JoinMiter);
- XSetForeground(blz.dpy, xorgc, def.focuscolor.bg);
- if(xor.height > 4 && xor.width > 2)
- XDrawLine(blz.dpy, blz.root, xorgc,
- xor.x + 2,
- xor.y + xor.height / 2,
- r_east(&xor) - 2,
- xor.y + xor.height / 2);
- if(xor.width > 4 && xor.height > 2)
- XDrawLine(blz.dpy, blz.root, xorgc,
- xor.x + xor.width / 2,
- xor.y + 2,
- xor.x + xor.width / 2,
- r_south(&xor) - 2);
- XSetLineAttributes(blz.dpy, xorgc, 4, LineSolid, CapNotLast, JoinMiter);
- XDrawRectangles(blz.dpy, blz.root, xorgc, &xor, 1);
+expose_event(Window *w, XExposeEvent *e) {
+ Rectangle r;
+ Framewin *f;
+ Image *buf;
+ CTuple *c;
+
+ f = w->aux;
+ c = &def.focuscolor;
+ buf = screen->ibuf;
+
+ 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);
+
+ copyimage(w, r, buf, ZP);
}
-static void
-xorrect(XRectangle *r) {
- XSetLineAttributes(blz.dpy, xorgc, 1, LineSolid, CapNotLast, JoinMiter);
- XSetForeground(blz.dpy, xorgc, 0x00888888l);
- XFillRectangles(blz.dpy, blz.root, xorgc, r, 1);
+static Handlers handlers = {
+ .expose = expose_event,
+};
+
+static int
+_vsnap(Framewin *f, int y) {
+ if(abs(f->n - y) < Dy(f->w->r)) {
+ f->n = y;
+ return 1;
+ }
+ return 0;
}
static void
-find_droppoint(Frame *frame, int x, int y, XRectangle *rect, Bool do_move) {
- enum { Delta = 5 };
- View *v;
- Area *a, *a_prev;
+vplace(Framewin *fw, Point pt) {
+ Rectangle r;
Frame *f;
- Bool before;
+ Area *a;
+ View *v;
+ int hr;
- v = frame->view;
+ v = screen->sel;
- /* New column? */
- a_prev = v->area;
- for(a = a_prev->next; a && a->next; a = a->next) {
- if(x < r_east(&a->rect))
+ for(a = v->area->next; a->next; a = a->next)
+ if(pt.x < a->r.max.x)
break;
- a_prev = a;
- }
+ fw->ra = a;
- rect->y = 0;
- rect->height = screen->rect.height - screen->brect.height;
- rect->width = 2 * Delta;
- if(x < (a->rect.x + labelh(&def.font))) {
- rect->x = a->rect.x - Delta;
- if(do_move) {
- a = new_column(v, a_prev, 0);
- send_to_area(a, frame);
- focus(frame->client, False);
- focus_view(screen, v);
- }
- return;
- }
- if(x > (r_east(&a->rect) - labelh(&def.font))) {
- rect->x = r_east(&a->rect) - Delta;
- if(do_move) {
- a = new_column(v, a, 0);
- send_to_area(a, frame);
- focus(frame->client, False);
- focus_view(screen, v);
- }
- return;
- }
+ pt.x = a->r.min.x;
+ frameadjust(fw, pt, OHoriz, Dx(a->r));
- /* Over/under frame? */
- for(f = a->frame; f; f = f->anext) {
- if(y < f->rect.y)
- break;
- if(y < r_south(&f->rect))
+ r = fw->w->r;
+ hr = Dy(r)/2;
+ fw->n = pt.y;
+
+ for(f = a->frame; f->anext; f = f->anext)
+ if(pt.y < f->r.max.y)
break;
- }
- rect->x = a->rect.x;
- rect->width = a->rect.width;
- rect->height = 2 * Delta;
- if(y < (f->rect.y + labelh(&def.font))) {
- before = True;
- rect->y = f->rect.y - Delta;
- if(do_move)
- goto do_move;
- return;
- }
- if(y > r_south(&f->rect) - labelh(&def.font)) {
- before = False;
- rect->y = r_south(&f->rect) - Delta;
- if(do_move)
- goto do_move;
- return;
+ if(!f->collapsed) {
+ fw->fp = f;
+ fw->fr = fw->fp->r;
+
+ if(f == fw->f) {
+ fw->fp = f->aprev;
+ fw->fr.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);
+ goto done;
+ }
+ if(_vsnap(fw, f->r.min.y+Dy(r)+hr)) {
+ fw->fr.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;
+ goto done;
}
- /* No? Swap. */
- *rect = f->rect;
- if(do_move) {
- swap_frames(frame, f);
- focus(frame->client, False);
- focus_view(screen, f->view);
+ if(pt.y < f->r.min.y + hr) {
+ pt.y = f->r.min.y;
+ if(f->aprev && !f->aprev->collapsed)
+ pt.y -= hr;
+ }else {
+ pt.y = f->r.max.y;
+ if(f->anext == fw->f)
+ pt.y += hr;
}
- return;
-do_move:
- if(frame == f)
- return;
- if(a != frame->area)
- send_to_area(a, frame);
- remove_frame(frame);
- insert_frame(f, frame, before);
- arrange_column(f->area, False);
- focus(frame->client, True);
+done:
+ pt.x = a->r.min.x;
+ pt.y = fw->n;
+ frameadjust(fw, pt, OHoriz, Dx(a->r));
+ reshapewin(fw->w, framerect(fw));
}
-void
-querypointer(Window w, int *x, int *y) {
- Window dummy;
- uint ui;
- int i;
+static void
+hplace(Framewin *fw, Point pt) {
+ Area *a;
+ View *v;
+ int minw;
- XQueryPointer(blz.dpy, w, &dummy, &dummy, &i, &i, x, y, &ui);
-}
+ minw = Dx(screen->r)/NCOL;
+ v = screen->sel;
-void
-warppointer(int x, int y) {
- XWarpPointer(blz.dpy,
- /* src_w */ None,
- /* dest_w */ blz.root,
- /* src_rect */ 0, 0, 0, 0,
- /* target */ x, y
- );
+ for(a = v->area->next; a->next; a = a->next)
+ if(pt.x < a->r.max.x)
+ break;
+
+ fw->ra = nil;
+ if(abs(pt.x - a->r.min.x) < minw/2) {
+ pt.x = a->r.min.x;
+ fw->ra = a->prev;
+ }
+ else if(abs(pt.x - a->r.max.x) < minw/2) {
+ pt.x = a->r.max.x;
+ fw->ra = a;
+ }
+
+ pt.y = a->r.min.y;
+ frameadjust(fw, pt, OVert, Dy(a->r));
+ reshapewin(fw->w, framerect(fw));
}
static void
do_managed_move(Client *c) {
- XRectangle frect, ofrect;
+ Rectangle r;
+ WinAttr wa;
XEvent ev;
Frame *f;
- int x, y;
+ Point pt, pt2;
+ int y;
focus(c, False);
f = c->sel;
- XSync(blz.dpy, False);
- if(XGrabPointer(blz.dpy, c->framewin, False, MouseMask, GrabModeAsync, GrabModeAsync,
- None, cursor[CurMove], CurrentTime) != GrabSuccess)
- return;
- XGrabServer(blz.dpy);
+ pt = querypointer(&scr.root);
- querypointer(blz.root, &x, &y);
+ pt2.x = f->area->r.min.x;
+ pt2.y = pt.y;
+ fw = framewin(f, pt2, OHoriz, Dx(f->area->r));
- find_droppoint(f, x, y, &frect, False);
- xorrect(&frect);
+ r = screen->r;
+ r.min.y += fw->gb.min.y + Dy(fw->gb)/2;
+ r.max.y = r.min.y + 1;
+ cwin = createwindow(&scr.root, r, 0, InputOnly, &wa, 0);
+ mapwin(cwin);
+
+horiz:
+ XUngrabPointer(display, CurrentTime);
+ if(!grabpointer(&scr.root, nil, cursor[CurIcon], MouseMask))
+ goto done;
+ warppointer(pt);
+ vplace(fw, pt);
for(;;) {
- XMaskEvent(blz.dpy, MouseMask | ExposureMask, &ev);
+ XMaskEvent(display, MouseMask | ExposureMask, &ev);
switch (ev.type) {
+ default:
+ break;
+ case Expose:
+ dispatch_event(&ev);
+ break;
+ case MotionNotify:
+ pt.x = ev.xmotion.x_root;
+ pt.y = ev.xmotion.y_root;
+
+ vplace(fw, pt);
+ break;
case ButtonRelease:
- xorrect(&frect);
+ switch(ev.xbutton.button) {
+ case 1:
+ if((f->anext) && (!f->aprev || (fw->fp != f->aprev && fw->fp != f->aprev->aprev))) {
+ f->anext->r.min.y = f->r.min.y;
+ resize_frame(f->anext, f->anext->r);
+ }
+ else if(f->aprev) {
+ if(fw->fp == f->aprev->aprev) {
+ fw->fp = f->aprev->aprev;
+ f->aprev->r = f->r;
+ }else
+ f->aprev->r.max.y = f->r.max.y;
+ resize_frame(f->aprev, f->aprev->r);
+ }
+
+ remove_frame(f);
+ f->area = fw->ra;
+ insert_frame(fw->fp, f);
+
+ if(f->aprev) {
+ f->aprev->r.max.y = fw->fr.min.y;
+ resize_frame(f->aprev, f->aprev->r);
+ }
+ else
+ fw->fr.min.y = f->area->r.min.y;
+ if(f->anext)
+ fw->fr.max.y = f->anext->r.min.y;
+ else
+ fw->fr.max.y = f->area->r.max.y;
+ resize_frame(f, fw->fr);
+
+ arrange_view(f->view);
+ goto done;
+ }
+ break;
+ case ButtonPress:
+ switch(ev.xbutton.button) {
+ case 2:
+ goto vert;
+ }
+ break;
+ }
+ }
+vert:
+ y = pt.y;
+ XUngrabPointer(display, CurrentTime);
+ if(!grabpointer(&scr.root, cwin, cursor[CurIcon], MouseMask))
+ goto done;
+ hplace(fw, pt);
+ for(;;) {
+ XMaskEvent(display, MouseMask | ExposureMask, &ev);
+ switch (ev.type) {
+ default:
+ break;
+ case Expose:
+ dispatch_event(&ev);
+ break;
+ case MotionNotify:
+ pt.x = ev.xmotion.x_root;
+ pt.y = ev.xmotion.y_root;
- find_droppoint(f, x, y, &frect, True);
+ hplace(fw, pt);
+ break;
+ case ButtonRelease:
+ switch(ev.xbutton.button) {
+ case 1:
+ if(fw->ra) {
+ fw->ra = new_column(f->view, fw->ra, 0);
+ send_to_area(fw->ra, f);
+ }
+ goto done;
+ case 2:
+ pt.y = y;
+ goto horiz;
+ }
+ break;
+ }
+ }
+done:
+ XUngrabPointer(display, CurrentTime);
+ framedestroy(fw);
+ destroywindow(cwin);
+
+ pt = addpt(f->r.min, f->grabbox.min);
+ pt.x += Dx(f->grabbox)/2;
+ pt.y += Dy(f->grabbox)/2;
+ warppointer(pt);
+}
- XUngrabServer(blz.dpy);
- XUngrabPointer(blz.dpy, CurrentTime);
- XSync(blz.dpy, False);
- return;
- case MotionNotify:
- ofrect = frect;
- x = ev.xmotion.x_root;
- y = ev.xmotion.y_root;
+static Window *
+gethsep(Rectangle r) {
+ Window *w;
+ WinAttr wa;
+
+ wa.background_pixel = def.normcolor.border;
+ w = createwindow(&scr.root, r, scr.depth, InputOutput, &wa, CWBackPixel);
+ mapwin(w);
+ raisewin(w);
+ return w;
+}
- find_droppoint(f, x, y, &frect, False);
+static void
+mouse_resizecolframe(Frame *f, Align align) {
+ WinAttr wa;
+ XEvent ev;
+ Window *cwin, *hwin;
+ Divide *d;
+ View *v;
+ Area *a;
+ Rectangle r;
+ Point pt, min;
- if(memcmp(&frect, &ofrect, sizeof(frect))) {
- xorrect(&ofrect);
- xorrect(&frect);
- }
+ 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)
+ d = d->next;
+
+ min.x = Dx(screen->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;
+ }else {
+ r.min.y = a->r.min.y;
+ r.max.y = r.min.y + 1;
+ }
+ }else {
+ if(f->anext) {
+ r.max.y = f->anext->r.max.y - min.y;
+ r.min.y = f->r.min.y + min.y;
+ }else {
+ r.max.y = a->r.max.y;
+ r.min.y = r.max.y - 1;
+ }
+ }
+ 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;
+ }else {
+ r.min.x = a->r.min.x;
+ r.max.x = r.min.x + 1;
+ }
+ }else {
+ if(a->next) {
+ r.max.x = a->next->r.max.x - min.x;
+ r.min.x = a->r.min.x + min.x;
+ }else {
+ r.max.x = a->r.max.x;
+ r.min.x = r.max.x - 1;
+ }
+ }
+
+ cwin = createwindow(&scr.root, r, 0, InputOnly, &wa, 0);
+ mapwin(cwin);
+
+ r = f->r;
+ if(align&NORTH)
+ r.min.y--;
+ else
+ r.min.y = r.max.y - 1;
+ r.max.y = r.min.y + 2;
+
+ hwin = gethsep(r);
+
+ 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);
+ warppointer(pt);
+
+ for(;;) {
+ XMaskEvent(display, MouseMask | ExposureMask, &ev);
+ switch (ev.type) {
+ default:
break;
case Expose:
dispatch_event(&ev);
break;
- default: break;
+ case MotionNotify:
+ pt.x = ev.xmotion.x_root;
+ pt.y = ev.xmotion.y_root;
+
+ 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.max.y = r.min.y+2;
+
+ setdiv(d, pt.x);
+ reshapewin(hwin, r);
+ break;
+ case ButtonRelease:
+ r = f->r;
+ if(align&WEST)
+ r.min.x = pt.x;
+ else
+ r.max.x = pt.x;
+ if(align&NORTH)
+ r.min.y = pt.y;
+ else
+ r.max.y = pt.y;
+ resize_colframe(f, &r);
+
+ if(align&WEST)
+ pt.x = f->r.min.x + 4;
+ else
+ pt.x = f->r.max.x - 4;
+ if(align&NORTH)
+ pt.y = f->r.min.y + 4;
+ else
+ pt.y = f->r.max.y - 4;
+ warppointer(pt);
+ goto done;
}
}
+done:
+ XUngrabPointer(display, CurrentTime);
+ destroywindow(cwin);
+ destroywindow(hwin);
}
void
mouse_resizecol(Divide *d) {
XSetWindowAttributes wa;
XEvent ev;
- Window cwin;
+ Window *cwin;
Divide *dp;
View *v;
Area *a;
- uint w, minw;
- int x, y;
+ Rectangle r;
+ Point pt;
+ uint minw;
v = screen->sel;
@@ -374,233 +519,268 @@ mouse_resizecol(Divide *d) {
if(a == nil || a->next == nil)
return;
- minw = screen->rect.width/NCOL;
-
- querypointer(blz.root, &x, &y);
- x = a->rect.x + minw;
- w = r_east(&a->next->rect) - minw;
- w -= x;
-
- cwin = XCreateWindow(blz.dpy, blz.root,
- x, y, w, 1,
- /* border */ 0,
- /* depth */ CopyFromParent,
- /* class */ InputOnly,
- /* visual */ CopyFromParent,
- /* valuemask */ 0,
- /* attrib */ &wa
- );
- XMapWindow(blz.dpy, cwin);
-
- if(XGrabPointer(
- blz.dpy, blz.root,
- /* owner_events*/ False,
- /* event_mask */ MouseMask,
- /* kbd, mouse */ GrabModeAsync, GrabModeAsync,
- /* confine_to */ cwin,
- /* cursor */ cursor[CurInvisible],
- /* time */ CurrentTime
- ) != GrabSuccess)
+ pt = querypointer(&scr.root);
+
+ minw = Dx(screen->r)/NCOL;
+ r.min.x = a->r.min.x + minw;
+ r.max.x = a->next->r.max.x - minw;
+ r.min.y = pt.y;
+ r.max.y = pt.y+1;
+
+ cwin = createwindow(&scr.root, r, 0, InputOnly, &wa, 0);
+ mapwin(cwin);
+
+ if(!grabpointer(&scr.root, cwin, cursor[CurInvisible], MouseMask))
goto done;
for(;;) {
- XMaskEvent(blz.dpy, MouseMask | ExposureMask, &ev);
+ XMaskEvent(display, MouseMask | ExposureMask, &ev);
switch (ev.type) {
- case ButtonRelease:
- resize_column(a, x - a->rect.x);
-
- XUngrabPointer(blz.dpy, CurrentTime);
- XSync(blz.dpy, False);
- goto done;
- case MotionNotify:
- x = ev.xmotion.x_root;
- XMoveWindow(blz.dpy, d->w, x, 0);
+ default:
break;
case Expose:
dispatch_event(&ev);
break;
- default: break;
+ case MotionNotify:
+ pt.x = ev.xmotion.x_root;
+ setdiv(d, pt.x);
+ break;
+ case ButtonRelease:
+ resize_column(a, pt.x - a->r.min.x);
+ goto done;
}
}
done:
- XDestroyWindow(blz.dpy, cwin);
+ XUngrabPointer(display, CurrentTime);
+ destroywindow(cwin);
+}
+
+static void
+rect_morph_xy(Rectangle *r, Point d, Align *mask) {
+ int n;
+
+ if(*mask & NORTH)
+ r->min.y += d.y;
+ if(*mask & WEST)
+ r->min.x += d.x;
+ if(*mask & SOUTH)
+ r->max.y += d.y;
+ 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;
+ }
+ if(r->min.y > r->max.y) {
+ n = r->min.y;
+ r->min.y = r->max.y;
+ r->max.y = n;
+ *mask ^= NORTH|SOUTH;
+ }
+}
+
+static int
+snap_line(Rectangle *rects, int nrect, int d, int horiz, Rectangle *r, int x, int y) {
+ Rectangle *rp;
+ int i, tx, ty;
+
+ if(horiz) {
+ for(i=0; i < nrect; i++) {
+ rp = &rects[i];
+ if((rp->min.x <= r->max.x) && (rp->max.x >= r->min.x)) {
+ ty = rp->min.y;
+ if(abs(ty - y) <= abs(d))
+ d = ty - y;
+
+ ty = rp->max.y;
+ if(abs(ty - y) <= abs(d))
+ d = ty - y;
+ }
+ }
+ }else {
+ for(i=0; i < nrect; i++) {
+ rp = &rects[i];
+ if((rp->min.y <= r->max.y) && (rp->max.y >= r->min.y)) {
+ tx = rp->min.x;
+ if(abs(tx - x) <= abs(d))
+ d = tx - x;
+
+ tx = rp->max.x;
+ if(abs(tx - x) <= abs(d))
+ d = tx - x;
+ }
+ }
+ }
+ return d;
+}
+
+/* Returns a gravity for increment handling. It's normally the opposite of the mask
+ * (the directions that we're resizing in), unless a snap occurs, in which case, it's the
+ * direction of the snap.
+ */
+Align
+snap_rect(Rectangle *rects, int num, Rectangle *r, Align *mask, int snap) {
+ Align ret;
+ Point d;
+
+ d.x = snap+1;
+ d.y = snap+1;
+
+ if(*mask&NORTH)
+ d.y = snap_line(rects, num, d.y, True, r, 0, r->min.y);
+ if(*mask&SOUTH)
+ d.y = snap_line(rects, num, d.y, True, r, 0, r->max.y);
+
+ if(*mask&EAST)
+ d.x = snap_line(rects, num, d.x, False, r, r->max.x, 0);
+ if(*mask&WEST)
+ d.x = snap_line(rects, num, d.x, False, r, r->min.x, 0);
+
+ ret = CENTER;
+ if(abs(d.x) <= snap)
+ ret ^= EAST|WEST;
+ else
+ d.x = 0;
+
+ if(abs(d.y) <= snap)
+ ret ^= NORTH|SOUTH;
+ else
+ d.y = 0;
+
+ rect_morph_xy(r, d, mask);
+ return ret ^ *mask;
}
void
-do_mouse_resize(Client *c, Bool opaque, BlitzAlign align) {
- BlitzAlign grav;
- Window dummy;
- Cursor cur;
+do_mouse_resize(Client *c, Bool opaque, Align align) {
XEvent ev;
- XRectangle *rects, ofrect, frect, origin;
- int snap, dx, dy, pt_x, pt_y, hr_x, hr_y;
- uint num;
- Bool floating;
+ Rectangle *rects;
+ Rectangle frect, origin;
+ Align grav;
+ Cursor cur;
+ Point d, pt, hr;
float rx, ry, hrx, hry;
Frame *f;
f = c->sel;
- floating = f->area->floating;
- origin = frect = f->rect;
- cur = cursor_of_quad(align);
- if(floating) {
- rects = rects_of_view(f->area->view, &num, (opaque ? c->frame : nil));
- snap = screen->rect.height / 66;
- }else{
- rects = nil;
- snap = 0;
- }
- if(align == CENTER) {
- if(!opaque)
- cur = cursor[CurInvisible];
- if(!floating) {
+ if(!f->area->floating) {
+ if(align==CENTER)
do_managed_move(c);
- return;
- }
+ else
+ mouse_resizecolframe(f, align);
+ return;
}
- querypointer(c->framewin, &pt_x, &pt_y);
- rx = (float)pt_x / frect.width;
- ry = (float)pt_y / frect.height;
-
- if(XGrabPointer(
- /* display */ blz.dpy,
- /* window */ c->framewin,
- /* owner_events */ False,
- /* event_mask */ MouseMask,
- /* pointer_mode */ GrabModeAsync,
- /* keyboard_mode */ GrabModeAsync,
- /* confine_to */ None,
- /* cursor */ cur,
- /* time */ CurrentTime
- ) != GrabSuccess)
+ origin = frect = f->r;
+ rects = rects_of_view(f->area->view, &num, c->frame);
+
+ cur = cursor_of_quad(align);
+ if((align==CENTER) && !opaque)
+ cur = cursor[CurSizing];
+
+ pt = querypointer(c->framewin);
+ rx = (float)pt.x / Dx(frect);
+ ry = (float)pt.y /Dy(frect);
+
+ if(!grabpointer(c->framewin, nil, cur, MouseMask))
return;
- querypointer(blz.root, &pt_x, &pt_y);
+ pt = querypointer(&scr.root);
+
+ hr = subpt(frect.max, frect.min);
+ hr = divpt(hr, Pt(2, 2));
if(align != CENTER) {
- hr_x = dx = frect.width / 2;
- hr_y = dy = frect.height / 2;
- if(align&NORTH) dy -= hr_y;
- if(align&SOUTH) dy += hr_y;
- if(align&EAST) dx += hr_x;
- if(align&WEST) dx -= hr_x;
-
- XTranslateCoordinates(blz.dpy,
- /* src, dst */ c->framewin, blz.root,
- /* src x,y */ dx, dy,
- /* dest x,y */ &pt_x, &pt_y,
- /* child */ &dummy
- );
- warppointer(pt_x, pt_y);
+ 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;
+
+ pt = addpt(d, f->r.min);
+ warppointer(pt);
}
else if(f->client->fullscreen) {
- XUngrabPointer(blz.dpy, CurrentTime);
+ XUngrabPointer(display, CurrentTime);
return;
}
else if(!opaque) {
- hrx = (double)(screen->rect.width + frect.width - 2 * labelh(&def.font))
- / screen->rect.width;
- hry = (double)(screen->rect.height + frect.height - 3 * labelh(&def.font))
- / screen->rect.height;
- pt_x = r_east(&frect) - labelh(&def.font);
- pt_y = r_south(&frect) - labelh(&def.font);
- warppointer(pt_x / hrx, pt_y / hry);
+ 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))
+ / Dy(screen->r);
+
+ pt.x = frect.max.x - labelh(def.font);
+ pt.y = frect.max.y - labelh(def.font);
+ d.x = pt.x / hrx;
+ d.y = pt.y / hry;
+
+ warppointer(d);
flushevents(PointerMotionMask, False);
}
- XSync(blz.dpy, False);
- if(!opaque) {
- XGrabServer(blz.dpy);
- xorborder(&frect);
- }else
- unmap_client(c, IconicState);
-
for(;;) {
- XMaskEvent(blz.dpy, MouseMask | ExposureMask, &ev);
+ XMaskEvent(display, MouseMask | ExposureMask, &ev);
switch (ev.type) {
- case ButtonRelease:
- if(!opaque)
- xorborder(&frect);
-
- if(!floating)
- resize_colframe(f, &frect);
- else
- resize_client(c, &frect);
-
- if(!opaque) {
- XTranslateCoordinates(blz.dpy,
- /* src, dst */ c->framewin, blz.root,
- /* src_x */ (frect.width * rx),
- /* src_y */ (frect.height * ry),
- /* dest x,y */ &pt_x, &pt_y,
- /* child */ &dummy
- );
- if(pt_y > screen->brect.y)
- pt_y = screen->brect.y - 1;
- warppointer(pt_x, pt_y);
- XUngrabServer(blz.dpy);
- }else
- map_client(c);
-
- free(rects);
-
- XUngrabPointer(blz.dpy, CurrentTime);
- XSync(blz.dpy, False);
- return;
+ default:
+ break;
+ case Expose:
+ dispatch_event(&ev);
+ break;
case MotionNotify:
- ofrect = frect;
- dx = ev.xmotion.x_root;
- dy = ev.xmotion.y_root;
+ d.x = ev.xmotion.x_root;
+ d.y = ev.xmotion.y_root;
if(align == CENTER && !opaque) {
- dx = (dx * hrx) - pt_x;
- dy = (dy * hry) - pt_y;
- }else{
- dx -= pt_x;
- dy -= pt_y;
- }
- pt_x += dx;
- pt_y += dy;
+ d.x = (d.x * hrx) - pt.x;
+ d.y = (d.y * hry) - pt.y;
+ }else
+ d = subpt(d, pt);
+ pt = addpt(pt, d);
- rect_morph_xy(&origin, dx, dy, &align);
- check_frame_constraints(&origin);
+ rect_morph_xy(&origin, d, &align);
+ origin = constrain(origin);
frect = origin;
- if(floating)
- grav = snap_rect(rects, num, &frect, &align, snap);
- else
- grav = align ^ CENTER;
+ grav = snap_rect(rects, num, &frect, &align, def.snap);
- apply_sizehints(c, &frect, floating, True, grav);
- check_frame_constraints(&frect);
+ frect = frame_hints(f, frect, grav);
+ frect = constrain(frect);
- if(opaque) {
- XMoveWindow(blz.dpy, c->framewin, frect.x, frect.y);
- XSync(blz.dpy, False);
- } else {
- xorborder(&ofrect);
- xorborder(&frect);
- }
- break;
- case Expose:
- dispatch_event(&ev);
- break;
- default:
+ //reshapewin(c->framewin, frect);
+ resize_client(c, &frect);
break;
+ case ButtonRelease:
+ resize_client(c, &frect);
+
+ if(!opaque) {
+ pt = translate(c->framewin, &scr.root,
+ Pt(Dx(frect)*rx, Dy(frect)*ry));
+ if(pt.y > screen->brect.min.y)
+ pt.y = screen->brect.min.y - 1;
+ warppointer(pt);
+ }
+
+ free(rects);
+ XUngrabPointer(display, CurrentTime);
+ return;
}
}
}
void
-grab_button(Window w, uint button, ulong mod) {
- XGrabButton(blz.dpy, button, mod, w, False, ButtonMask,
+grab_button(XWindow w, uint button, ulong mod) {
+ XGrabButton(display, button, mod, w, False, ButtonMask,
GrabModeSync, GrabModeSync, None, None);
if((mod != AnyModifier) && (num_lock_mask != 0)) {
- XGrabButton(blz.dpy, button, mod | num_lock_mask, w, False, ButtonMask,
+ XGrabButton(display, button, mod | num_lock_mask, w, False, ButtonMask,
GrabModeSync, GrabModeAsync, None, None);
- XGrabButton(blz.dpy, button, mod | num_lock_mask | LockMask, w, False,
+ XGrabButton(display, button, mod | num_lock_mask | LockMask, w, False,
ButtonMask, GrabModeSync, GrabModeAsync, None, None);
}
}
diff --git a/cmd/wmii/printevent.c b/cmd/wmii/printevent.c
@@ -1,463 +1,559 @@
/*
* Original code posted to comp.sources.x
* Modifications by Russ Cox <rsc@swtch.com>.
+ * Further modifications by Kris Maglione <fbsdaemon@gmail.com>
*/
/*
-Path: uunet!wyse!mikew
-From: mikew@wyse.wyse.com (Mike Wexler)
-Newsgroups: comp.sources.x
-Subject: v02i056: subroutine to print events in human readable form, Part01/01
-Message-ID: <1935@wyse.wyse.com>
-Date: 22 Dec 88 19:28:25 GMT
-Organization: Wyse Technology, San Jose
-Lines: 1093
-Approved: mikew@wyse.com
-
-Submitted-by: richsun!darkstar!ken
-Posting-number: Volume 2, Issue 56
-Archive-name: showevent/part01
-
-
-There are times during debugging when it would be real useful to be able to
-print the fields of an event in a human readable form. Too many times I found
-myself scrounging around in section 8 of the Xlib manual looking for the valid
-fields for the events I wanted to see, then adding printf's to display the
-numeric values of the fields, and then scanning through X.h trying to decode
-the cryptic detail and state fields. After playing with xev, I decided to
-write a couple of standard functions that I could keep in a library and call
-on whenever I needed a little debugging verbosity. The first function,
-GetType(), is useful for returning the string representation of the type of
-an event. The second function, ShowEvent(), is used to display all the fields
-of an event in a readable format. The functions are not complicated, in fact,
-they are mind-numbingly boring - but that's just the point nobody wants to
-spend the time writing functions like this, they just want to have them when
-they need them.
-
-A simple, sample program is included which does little else but to demonstrate
-the use of these two functions. These functions have saved me many an hour
-during debugging and I hope you find some benefit to these. If you have any
-comments, suggestions, improvements, or if you find any blithering errors you
-can get it touch with me at the following location:
-
- ken@richsun.UUCP
-*/
+ * Path: uunet!wyse!mikew From: mikew@wyse.wyse.com (Mike Wexler) Newsgroups:
+ * comp.sources.x Subject: v02i056: subroutine to print events in human
+ * readable form, Part01/01 Message-ID: <1935@wyse.wyse.com> Date: 22 Dec 88
+ * 19:28:25 GMT Organization: Wyse Technology, San Jose Lines: 1093 Approved:
+ * mikew@wyse.com
+ *
+ * Submitted-by: richsun!darkstar!ken Posting-number: Volume 2, Issue 56
+ * Archive-name: showevent/part01
+ *
+ *
+ * There are times during debugging when it would be real useful to be able to
+ * print the fields of an event in a human readable form. Too many times I
+ * found myself scrounging around in section 8 of the Xlib manual looking for
+ * the valid fields for the events I wanted to see, then adding printf's to
+ * display the numeric values of the fields, and then scanning through X.h
+ * trying to decode the cryptic detail and state fields. After playing with
+ * xev, I decided to write a couple of standard functions that I could keep
+ * in a library and call on whenever I needed a little debugging verbosity.
+ * The first function, GetType(), is useful for returning the string
+ * representation of the type of an event. The second function, ShowEvent(),
+ * is used to display all the fields of an event in a readable format. The
+ * functions are not complicated, in fact, they are mind-numbingly boring -
+ * but that's just the point nobody wants to spend the time writing functions
+ * like this, they just want to have them when they need them.
+ *
+ * A simple, sample program is included which does little else but to
+ * demonstrate the use of these two functions. These functions have saved me
+ * many an hour during debugging and I hope you find some benefit to these.
+ * If you have any comments, suggestions, improvements, or if you find any
+ * blithering errors you can get it touch with me at the following location:
+ *
+ * ken@richsun.UUCP
+ */
+#include <stdarg.h>
#include <stdio.h>
+#include <stdlib.h>
#include <X11/Intrinsic.h>
#include <X11/Xproto.h>
#include <util.h>
-#include "dat.h"
-#include "fns.h"
+//#include "dat.h"
+//#include "fns.h"
#include "printevent.h"
+#define nil ((void*)0)
+
+typedef struct Pair Pair;
+
+struct Pair {
+ int key;
+ char *val;
+};
+
static char* sep = " ";
-/******************************************************************************/
-/**** Miscellaneous routines to convert values to their string equivalents ****/
-/******************************************************************************/
+static char *
+search(Pair *lst, int key, char *(*def)(int)) {
+ for(; lst->val; lst++)
+ if(lst->key == key)
+ return lst->val;
+ return def(key);
+}
+
+static char buffer[512];
-/* Returns the string equivalent of a boolean parameter */
static char*
-TorF(int bool)
+unmask(Pair * list, uint val)
{
- switch (bool) {
- case True:
- return ("True");
+ Pair *p;
+ char *s, *end;
+ Boolean first = True;
+
+ buffer[0] = '\0';
+ end = buffer + sizeof buffer;
+ s = buffer;
+
+ s += strlcat(s, "(", end - s);
+
+ for (p = list; p->val; p++)
+ if (val & p->key) {
+ if (!first)
+ s += strlcat(s, "|", end - s);
+ first = False;
+ s += strlcat(s, p->val, end - s);
+ }
- case False:
- return ("False");
+ s += strlcat(s, ")", end - s);
- default:
- return ("?");
- }
+ return buffer;
}
-/* Returns the string equivalent of a property notify state */
-static char*
-PropertyState(int state)
+static char *
+strhex(int key) {
+ sprintf(buffer, "0x%x", key);
+ return buffer;
+}
+
+static char *
+strdec(int key) {
+ sprintf(buffer, "%d", key);
+ return buffer;
+}
+
+static char *
+strign(int key) {
+ return "?";
+}
+
+/******************************************************************************/
+/**** Miscellaneous routines to convert values to their string equivalents ****/
+/******************************************************************************/
+
+static char *
+Self(char *str)
{
- switch (state) {
- case PropertyNewValue:
- return ("PropertyNewValue");
+ strncpy(buffer, str, sizeof buffer);
+ free(str);
+ return buffer;
+}
- case PropertyDelete:
- return ("PropertyDelete");
+/* Returns the string equivalent of a timestamp */
+static char *
+ServerTime(Time time)
+{
+ ulong msec;
+ ulong sec;
+ ulong min;
+ ulong hr;
+ ulong day;
+
+ msec = time % 1000;
+ time /= 1000;
+ sec = time % 60;
+ time /= 60;
+ min = time % 60;
+ time /= 60;
+ hr = time % 24;
+ time /= 24;
+ day = time;
+
+ if (0)
+ sprintf(buffer, "%lu day%s %02lu:%02lu:%02lu.%03lu",
+ day, day == 1 ? "" : "(s)", hr, min, sec, msec);
- default:
- return ("?");
- }
+ sprintf(buffer, "%lud%luh%lum%lu.%03lds", day, hr, min, sec, msec);
+ return buffer;
}
-/* Returns the string equivalent of a visibility notify state */
-static char*
-VisibilityState(int state)
+/* Returns the string equivalent of a boolean parameter */
+static char *
+TorF(int key)
{
- switch (state) {
- case VisibilityUnobscured:
- return ("VisibilityUnobscured");
+ static Pair list[] = {
+ {True, "True"},
+ {False, "False"},
+ {0, nil},
+ };
- case VisibilityPartiallyObscured:
- return ("VisibilityPartiallyObscured");
+ return search(list, key, strign);
+}
- case VisibilityFullyObscured:
- return ("VisibilityFullyObscured");
+/* Returns the string equivalent of a property notify state */
+static char *
+PropertyState(int key)
+{
+ static Pair list[] = {
+ {PropertyNewValue, "PropertyNewValue"},
+ {PropertyDelete, "PropertyDelete"},
+ {0, nil},
+ };
- default:
- return ("?");
- }
+ return search(list, key, strign);
}
-/* Returns the string equivalent of a timestamp */
-static char*
-ServerTime(Time time)
+/* Returns the string equivalent of a visibility notify state */
+static char *
+VisibilityState(int key)
{
- ulong msec;
- ulong sec;
- ulong min;
- ulong hr;
- ulong day;
- static char buffer[32];
-
- msec = time % 1000;
- time /= 1000;
- sec = time % 60;
- time /= 60;
- min = time % 60;
- time /= 60;
- hr = time % 24;
- time /= 24;
- day = time;
-
-if(0)
- sprintf(buffer, "%lu day%s %02lu:%02lu:%02lu.%03lu",
- day, day == 1 ? "" : "(s)", hr, min, sec, msec);
-
- sprintf(buffer, "%lud%luh%lum%lu.%03lds", day, hr, min, sec, msec);
- return (buffer);
-}
-
-/* Simple structure to ease the interpretation of masks */
-typedef struct MaskType MaskType;
-struct MaskType
-{
- uint value;
- char *string;
-};
+ static Pair list[] = {
+ {VisibilityUnobscured, "VisibilityUnobscured"},
+ {VisibilityPartiallyObscured, "VisibilityPartiallyObscured"},
+ {VisibilityFullyObscured, "VisibilityFullyObscured"},
+ {0, nil},
+ };
+
+ return search(list, key, strign);
+}
/* Returns the string equivalent of a mask of buttons and/or modifier keys */
-static char*
+static char *
ButtonAndOrModifierState(uint state)
{
- static char buffer[256];
- static MaskType masks[] = {
- {Button1Mask, "Button1Mask"},
- {Button2Mask, "Button2Mask"},
- {Button3Mask, "Button3Mask"},
- {Button4Mask, "Button4Mask"},
- {Button5Mask, "Button5Mask"},
- {ShiftMask, "ShiftMask"},
- {LockMask, "LockMask"},
- {ControlMask, "ControlMask"},
- {Mod1Mask, "Mod1Mask"},
- {Mod2Mask, "Mod2Mask"},
- {Mod3Mask, "Mod3Mask"},
- {Mod4Mask, "Mod4Mask"},
- {Mod5Mask, "Mod5Mask"},
- };
- int num_masks = sizeof(masks) / sizeof(MaskType);
- int i;
- Boolean first = True;
-
- buffer[0] = 0;
-
- for (i = 0; i < num_masks; i++)
- if (state & masks[i].value) {
- if (first) {
- first = False;
- strcpy(buffer, masks[i].string);
- } else {
- strcat(buffer, " | ");
- strcat(buffer, masks[i].string);
- }
- }
- return (buffer);
+ static Pair list[] = {
+ {Button1Mask, "Button1Mask"},
+ {Button2Mask, "Button2Mask"},
+ {Button3Mask, "Button3Mask"},
+ {Button4Mask, "Button4Mask"},
+ {Button5Mask, "Button5Mask"},
+ {ShiftMask, "ShiftMask"},
+ {LockMask, "LockMask"},
+ {ControlMask, "ControlMask"},
+ {Mod1Mask, "Mod1Mask"},
+ {Mod2Mask, "Mod2Mask"},
+ {Mod3Mask, "Mod3Mask"},
+ {Mod4Mask, "Mod4Mask"},
+ {Mod5Mask, "Mod5Mask"},
+ {0, nil},
+ };
+
+ return unmask(list, state);
}
/* Returns the string equivalent of a mask of configure window values */
-static char*
+static char *
ConfigureValueMask(uint valuemask)
{
- static char buffer[256];
- static MaskType masks[] = {
- {CWX, "CWX"},
- {CWY, "CWY"},
- {CWWidth, "CWWidth"},
- {CWHeight, "CWHeight"},
- {CWBorderWidth, "CWBorderWidth"},
- {CWSibling, "CWSibling"},
- {CWStackMode, "CWStackMode"},
- };
- int num_masks = sizeof(masks) / sizeof(MaskType);
- int i;
- Boolean first = True;
-
- buffer[0] = 0;
-
- for (i = 0; i < num_masks; i++)
- if (valuemask & masks[i].value) {
- if (first) {
- first = False;
- strcpy(buffer, masks[i].string);
- } else {
- strcat(buffer, " | ");
- strcat(buffer, masks[i].string);
- }
- }
+ static Pair list[] = {
+ {CWX, "CWX"},
+ {CWY, "CWY"},
+ {CWWidth, "CWWidth"},
+ {CWHeight, "CWHeight"},
+ {CWBorderWidth, "CWBorderWidth"},
+ {CWSibling, "CWSibling"},
+ {CWStackMode, "CWStackMode"},
+ {0, nil},
+ };
- return (buffer);
+ return unmask(list, valuemask);
}
/* Returns the string equivalent of a motion hint */
-static char*
-IsHint(char is_hint)
+#if 0
+static char *
+IsHint(char key)
{
- switch (is_hint) {
- case NotifyNormal:
- return ("NotifyNormal");
-
- case NotifyHint:
- return ("NotifyHint");
+ static Pair list[] = {
+ {NotifyNormal, "NotifyNormal"},
+ {NotifyHint, "NotifyHint"},
+ {0, nil},
+ };
- default:
- return ("?");
- }
+ return search(list, key, strign);
}
+#endif
/* Returns the string equivalent of an id or the value "None" */
-static char*
-MaybeNone(int value)
+static char *
+MaybeNone(int key)
{
- static char buffer[16];
+ static Pair list[] = {
+ {None, "None"},
+ {0, nil},
+ };
- if (value == None)
- return ("None");
- else {
- sprintf(buffer, "0x%x", value);
- return (buffer);
- }
+ return search(list, key, strhex);
}
/* Returns the string equivalent of a colormap state */
-static char*
-ColormapState(int state)
+static char *
+ColormapState(int key)
{
- switch (state) {
- case ColormapInstalled:
- return ("ColormapInstalled");
-
- case ColormapUninstalled:
- return ("ColormapUninstalled");
+ static Pair list[] = {
+ {ColormapInstalled, "ColormapInstalled"},
+ {ColormapUninstalled, "ColormapUninstalled"},
+ {0, nil},
+ };
- default:
- return ("?");
- }
+ return search(list, key, strign);
}
/* Returns the string equivalent of a crossing detail */
-static char*
-CrossingDetail(int detail)
+static char *
+CrossingDetail(int key)
{
- switch (detail) {
- case NotifyAncestor:
- return ("NotifyAncestor");
+ static Pair list[] = {
+ {NotifyAncestor, "NotifyAncestor"},
+ {NotifyInferior, "NotifyInferior"},
+ {NotifyVirtual, "NotifyVirtual"},
+ {NotifyNonlinear, "NotifyNonlinear"},
+ {NotifyNonlinearVirtual, "NotifyNonlinearVirtual"},
+ {0, nil},
+ };
- case NotifyInferior:
- return ("NotifyInferior");
-
- case NotifyVirtual:
- return ("NotifyVirtual");
-
- case NotifyNonlinear:
- return ("NotifyNonlinear");
-
- case NotifyNonlinearVirtual:
- return ("NotifyNonlinearVirtual");
-
- default:
- return ("?");
- }
+ return search(list, key, strign);
}
/* Returns the string equivalent of a focus change detail */
-static char*
-FocusChangeDetail(int detail)
+static char *
+FocusChangeDetail(int key)
{
- switch (detail) {
- case NotifyAncestor:
- return ("NotifyAncestor");
-
- case NotifyInferior:
- return ("NotifyInferior");
-
- case NotifyVirtual:
- return ("NotifyVirtual");
+ static Pair list[] = {
+ {NotifyAncestor, "NotifyAncestor"},
+ {NotifyInferior, "NotifyInferior"},
+ {NotifyVirtual, "NotifyVirtual"},
+ {NotifyNonlinear, "NotifyNonlinear"},
+ {NotifyNonlinearVirtual, "NotifyNonlinearVirtual"},
+ {NotifyPointer, "NotifyPointer"},
+ {NotifyPointerRoot, "NotifyPointerRoot"},
+ {NotifyDetailNone, "NotifyDetailNone"},
+ {0, nil},
+ };
- case NotifyNonlinear:
- return ("NotifyNonlinear");
-
- case NotifyNonlinearVirtual:
- return ("NotifyNonlinearVirtual");
-
- case NotifyPointer:
- return ("NotifyPointer");
-
- case NotifyPointerRoot:
- return ("NotifyPointerRoot");
-
- case NotifyDetailNone:
- return ("NotifyDetailNone");
-
- default:
- return ("?");
- }
+ return search(list, key, strign);
}
/* Returns the string equivalent of a configure detail */
-static char*
-ConfigureDetail(int detail)
+static char *
+ConfigureDetail(int key)
{
- switch (detail) {
- case Above:
- return ("Above");
-
- case Below:
- return ("Below");
+ static Pair list[] = {
+ {Above, "Above"},
+ {Below, "Below"},
+ {TopIf, "TopIf"},
+ {BottomIf, "BottomIf"},
+ {Opposite, "Opposite"},
+ {0, nil},
+ };
- case TopIf:
- return ("TopIf");
-
- case BottomIf:
- return ("BottomIf");
-
- case Opposite:
- return ("Opposite");
-
- default:
- return ("?");
- }
+ return search(list, key, strign);
}
/* Returns the string equivalent of a grab mode */
-static char*
-GrabMode(int mode)
+static char *
+GrabMode(int key)
{
- switch (mode) {
- case NotifyNormal:
- return ("NotifyNormal");
-
- case NotifyGrab:
- return ("NotifyGrab");
-
- case NotifyUngrab:
- return ("NotifyUngrab");
-
- case NotifyWhileGrabbed:
- return ("NotifyWhileGrabbed");
+ static Pair list[] = {
+ {NotifyNormal, "NotifyNormal"},
+ {NotifyGrab, "NotifyGrab"},
+ {NotifyUngrab, "NotifyUngrab"},
+ {NotifyWhileGrabbed, "NotifyWhileGrabbed"},
+ {0, nil},
+ };
- default:
- return ("?");
- }
+ return search(list, key, strign);
}
/* Returns the string equivalent of a mapping request */
-static char*
-MappingRequest(int request)
+static char *
+MappingRequest(int key)
{
- switch (request) {
- case MappingModifier:
- return ("MappingModifier");
-
- case MappingKeyboard:
- return ("MappingKeyboard");
-
- case MappingPointer:
- return ("MappingPointer");
+ static Pair list[] = {
+ {MappingModifier, "MappingModifier"},
+ {MappingKeyboard, "MappingKeyboard"},
+ {MappingPointer, "MappingPointer"},
+ {0, nil},
+ };
- default:
- return ("?");
- }
+ return search(list, key, strign);
}
/* Returns the string equivalent of a stacking order place */
-static char*
-Place(int place)
+static char *
+Place(int key)
{
- switch (place) {
- case PlaceOnTop:
- return ("PlaceOnTop");
-
- case PlaceOnBottom:
- return ("PlaceOnBottom");
+ static Pair list[] = {
+ {PlaceOnTop, "PlaceOnTop"},
+ {PlaceOnBottom, "PlaceOnBottom"},
+ {0, nil},
+ };
- default:
- return ("?");
- }
+ return search(list, key, strign);
}
/* Returns the string equivalent of a major code */
-static char*
-MajorCode(int code)
-{
- static char buffer[32];
-
- switch (code) {
- case X_CopyArea:
- return ("X_CopyArea");
-
- case X_CopyPlane:
- return ("X_CopyPlane");
-
- default:
- sprintf(buffer, "0x%x", code);
- return (buffer);
- }
+static char *
+MajorCode(int key)
+{
+ static Pair list[] = {
+ {X_CopyArea, "X_CopyArea"},
+ {X_CopyPlane, "X_CopyPlane"},
+ {0, nil},
+ };
+
+ return search(list, key, strhex);
+}
+
+static char *
+eventtype(int key)
+{
+ static Pair list[] = {
+ {ButtonPress, "ButtonPress"},
+ {ButtonRelease, "ButtonRelease"},
+ {CirculateNotify, "CirculateNotify"},
+ {CirculateRequest, "CirculateRequest"},
+ {ClientMessage, "ClientMessage"},
+ {ColormapNotify, "ColormapNotify"},
+ {ConfigureNotify, "ConfigureNotify"},
+ {ConfigureRequest, "ConfigureRequest"},
+ {CreateNotify, "CreateNotify"},
+ {DestroyNotify, "DestroyNotify"},
+ {EnterNotify, "EnterNotify"},
+ {Expose, "Expose"},
+ {FocusIn, "FocusIn"},
+ {FocusOut, "FocusOut"},
+ {GraphicsExpose, "GraphicsExpose"},
+ {GravityNotify, "GravityNotify"},
+ {KeyPress, "KeyPress"},
+ {KeyRelease, "KeyRelease"},
+ {KeymapNotify, "KeymapNotify"},
+ {LeaveNotify, "LeaveNotify"},
+ {MapNotify, "MapNotify"},
+ {MapRequest, "MapRequest"},
+ {MappingNotify, "MappingNotify"},
+ {MotionNotify, "MotionNotify"},
+ {NoExpose, "NoExpose"},
+ {PropertyNotify, "PropertyNotify"},
+ {ReparentNotify, "ReparentNotify"},
+ {ResizeRequest, "ResizeRequest"},
+ {SelectionClear, "SelectionClear"},
+ {SelectionNotify, "SelectionNotify"},
+ {SelectionRequest, "SelectionRequest"},
+ {UnmapNotify, "UnmapNotify"},
+ {VisibilityNotify, "VisibilityNotify"},
+ {0, nil},
+ };
+
+ return search(list, key, strdec);
}
-
/* Returns the string equivalent the keycode contained in the key event */
static char*
-Keycode(XKeyEvent *ev)
-{
- static char buffer[256];
- KeySym keysym_str;
- char *keysym_name;
- char string[256];
-
- XLookupString(ev, string, 64, &keysym_str, NULL);
-
- if (keysym_str == NoSymbol)
- keysym_name = "NoSymbol";
- else if (!(keysym_name = XKeysymToString(keysym_str)))
- keysym_name = "(no name)";
- sprintf(buffer, "%u (keysym 0x%x \"%s\")",
- (int)ev->keycode, (int)keysym_str, keysym_name);
- return (buffer);
-}
+Keycode(XKeyEvent * ev)
+{
+ KeySym keysym_str;
+ char *keysym_name;
+
+ XLookupString(ev, buffer, sizeof buffer, &keysym_str, NULL);
+
+ if (keysym_str == NoSymbol)
+ keysym_name = "NoSymbol";
+ else
+ keysym_name = XKeysymToString(keysym_str);
+ if(keysym_name == nil)
+ keysym_name = "(no name)";
+
+ snprintf(buffer, sizeof buffer, "%u (keysym 0x%x \"%s\")",
+ (int)ev->keycode, (int)keysym_str, keysym_name);
+ return buffer;
+}
+
+/* Returns the string equivalent of an atom or "None" */
+static char *
+AtomName(Atom atom)
+{
+ extern Display *display;
+ char *atom_name;
+
+ if (atom == None)
+ return "None";
+
+ atom_name = XGetAtomName(display, atom);
+ strncpy(buffer, atom_name, sizeof buffer);
+ XFree(atom_name);
+
+ return buffer;
+}
+
+#define _(m) #m, ev->m
+
+enum {
+ TEnd,
+ TAtom,
+ TBool,
+ TColMap,
+ TConfDetail,
+ TConfMask,
+ TFocus,
+ TGrabMode,
+ TInt,
+ TIntNone,
+ TMajor,
+ TMapping,
+ TModState,
+ TPlace,
+ TPropState,
+ TString,
+ TTime,
+ TVis,
+ TWindow,
+ TXing,
+};
-/* Returns the string equivalent of an atom or "None"*/
-static char*
-AtomName(Display *dpy, Atom atom)
-{
- static char buffer[256];
- char *atom_name;
+typedef struct TypeTab TypeTab;
+
+struct TypeTab {
+ int size;
+ char *(*fn)();
+} ttab[] = {
+ [TEnd] = {0, nil},
+ [TAtom] = {sizeof(Atom), AtomName},
+ [TBool] = {sizeof(Bool), TorF},
+ [TColMap] = {sizeof(int), ColormapState},
+ [TConfDetail] = {sizeof(int), ConfigureDetail},
+ [TConfMask] = {sizeof(int), ConfigureValueMask},
+ [TFocus] = {sizeof(int), FocusChangeDetail},
+ [TGrabMode] = {sizeof(int), GrabMode},
+ [TIntNone] = {sizeof(int), MaybeNone},
+ [TInt] = {sizeof(int), strdec},
+ [TMajor] = {sizeof(int), MajorCode},
+ [TMapping] = {sizeof(int), MappingRequest},
+ [TModState] = {sizeof(int), ButtonAndOrModifierState},
+ [TPlace] = {sizeof(int), Place},
+ [TPropState] = {sizeof(int), PropertyState},
+ [TString] = {sizeof(char*), Self},
+ [TTime] = {sizeof(Time), ServerTime},
+ [TVis] = {sizeof(int), VisibilityState},
+ [TWindow] = {sizeof(Window), strhex},
+ [TXing] = {sizeof(int), CrossingDetail},
+};
- if (atom == None)
- return ("None");
+static void
+pevent(void *ev, ...) {
+ static char buf[4096];
+ static char *bend = buf + sizeof(buf);
+ va_list ap;
+ TypeTab *t;
+ char *p, *key, *val;
+ int n, type, valint;
+
+ va_start(ap, ev);
+
+ p = buf;
+ *p = '\0';
+ n = 0;
+ for(;;) {
+ type = va_arg(ap, int);
+ if(type == TEnd)
+ break;
+ t = &ttab[type];
+
+ key = va_arg(ap, char*);
+ switch(t->size) {
+ default:
+ break; /* Can't continue */
+ case sizeof(int):
+ valint = va_arg(ap, int);
+ val = t->fn(valint);
+ break;
+ }
+
+ if(n++ != 0)
+ p += strlcat(p, sep, bend-p);
+ p += snprintf(p, bend-p, "%s=%s", key, val);
+
+ if(p >= bend)
+ break;
+ }
+ fprintf(stderr, "%s\n", buf);
- atom_name = XGetAtomName(dpy, atom);
- strncpy(buffer, atom_name, 256);
- XFree(atom_name);
- return (buffer);
+ va_end(ap);
}
/******************************************************************************/
@@ -467,533 +563,448 @@ AtomName(Display *dpy, Atom atom)
static void
VerbMotion(XMotionEvent *ev)
{
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "root=0x%x%s", (int)ev->root, sep);
- fprintf(stderr, "subwindow=0x%x%s", (int)ev->subwindow, sep);
- fprintf(stderr, "time=%s%s", ServerTime(ev->time), sep);
- fprintf(stderr, "x=%d y=%d%s", ev->x, ev->y, sep);
- fprintf(stderr, "x_root=%d y_root=%d%s", ev->x_root, ev->y_root, sep);
- fprintf(stderr, "state=%s%s", ButtonAndOrModifierState(ev->state), sep);
- fprintf(stderr, "is_hint=%s%s", IsHint(ev->is_hint), sep);
- fprintf(stderr, "same_screen=%s\n", TorF(ev->same_screen));
+ pevent(ev,
+ TWindow, _(window),
+ TWindow, _(root),
+ TWindow, _(subwindow),
+ TTime, _(time),
+ TInt, _(x), TInt, _(y),
+ TInt, _(x_root), TInt, _(y_root),
+ TModState, _(state),
+ TBool, _(same_screen),
+ TEnd
+ );
+ //fprintf(stderr, "is_hint=%s%s", IsHint(ev->is_hint), sep);
}
static void
VerbButton(XButtonEvent *ev)
{
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "root=0x%x%s", (int)ev->root, sep);
- fprintf(stderr, "subwindow=0x%x%s", (int)ev->subwindow, sep);
- fprintf(stderr, "time=%s%s", ServerTime(ev->time), sep);
- fprintf(stderr, "x=%d y=%d%s", ev->x, ev->y, sep);
- fprintf(stderr, "x_root=%d y_root=%d%s", ev->x_root, ev->y_root, sep);
- fprintf(stderr, "state=%s%s", ButtonAndOrModifierState(ev->state), sep);
- fprintf(stderr, "button=%s%s", ButtonAndOrModifierState(ev->button), sep);
- fprintf(stderr, "same_screen=%s\n", TorF(ev->same_screen));
+ pevent(ev,
+ TWindow, _(window),
+ TWindow, _(root),
+ TWindow, _(subwindow),
+ TTime, _(time),
+ TInt, _(x), TInt, _(y),
+ TInt, _(x_root), TInt, _(y_root),
+ TModState, _(state),
+ TModState, _(button),
+ TBool, _(same_screen),
+ TEnd
+ );
}
static void
VerbColormap(XColormapEvent *ev)
{
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "colormap=%s%s", MaybeNone(ev->colormap), sep);
- fprintf(stderr, "new=%s%s", TorF(ev->new), sep);
- fprintf(stderr, "state=%s\n", ColormapState(ev->state));
+ pevent(ev,
+ TWindow, _(window),
+ TIntNone, _(colormap),
+ TBool, _(new),
+ TColMap, _(state),
+ TEnd
+ );
}
static void
VerbCrossing(XCrossingEvent *ev)
{
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "root=0x%x%s", (int)ev->root, sep);
- fprintf(stderr, "subwindow=0x%x%s", (int)ev->subwindow, sep);
- fprintf(stderr, "time=%s%s", ServerTime(ev->time), sep);
- fprintf(stderr, "x=%d y=%d%s", ev->x, ev->y, sep);
- fprintf(stderr, "x_root=%d y_root=%d%s", ev->x_root, ev->y_root, sep);
- fprintf(stderr, "mode=%s%s", GrabMode(ev->mode), sep);
- fprintf(stderr, "detail=%s%s", CrossingDetail(ev->detail), sep);
- fprintf(stderr, "same_screen=%s%s", TorF(ev->same_screen), sep);
- fprintf(stderr, "focus=%s%s", TorF(ev->focus), sep);
- fprintf(stderr, "state=%s\n", ButtonAndOrModifierState(ev->state));
+ pevent(ev,
+ TWindow, _(window),
+ TWindow, _(root),
+ TWindow, _(subwindow),
+ TTime, _(time),
+ TInt, _(x), TInt, _(y),
+ TInt, _(x_root), TInt, _(y_root),
+ TGrabMode, _(mode),
+ TXing, _(detail),
+ TBool, _(same_screen),
+ TBool, _(focus),
+ TModState, _(state),
+ TEnd
+ );
}
static void
VerbExpose(XExposeEvent *ev)
{
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "x=%d y=%d%s", ev->x, ev->y, sep);
- fprintf(stderr, "width=%d height=%d%s", ev->width, ev->height, sep);
- fprintf(stderr, "count=%d\n", ev->count);
+ pevent(ev,
+ TWindow, _(window),
+ TInt, _(x), TInt, _(y),
+ TInt, _(width), TInt, _(height),
+ TInt, _(count),
+ TEnd
+ );
}
static void
VerbGraphicsExpose(XGraphicsExposeEvent *ev)
{
- fprintf(stderr, "drawable=0x%x%s", (int)ev->drawable, sep);
- fprintf(stderr, "x=%d y=%d%s", ev->x, ev->y, sep);
- fprintf(stderr, "width=%d height=%d%s", ev->width, ev->height, sep);
- fprintf(stderr, "major_code=%s%s", MajorCode(ev->major_code), sep);
- fprintf(stderr, "minor_code=%d\n", ev->minor_code);
+ pevent(ev,
+ TWindow, _(drawable),
+ TInt, _(x), TInt, _(y),
+ TInt, _(width), TInt, _(height),
+ TMajor, _(major_code),
+ TInt, _(minor_code),
+ TEnd
+ );
}
static void
VerbNoExpose(XNoExposeEvent *ev)
{
- fprintf(stderr, "drawable=0x%x%s", (int)ev->drawable, sep);
- fprintf(stderr, "major_code=%s%s", MajorCode(ev->major_code), sep);
- fprintf(stderr, "minor_code=%d\n", ev->minor_code);
+ pevent(ev,
+ TWindow, _(drawable),
+ TMajor, _(major_code),
+ TInt, _(minor_code),
+ TEnd
+ );
}
static void
VerbFocus(XFocusChangeEvent *ev)
{
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "mode=%s%s", GrabMode(ev->mode), sep);
- fprintf(stderr, "detail=%s\n", FocusChangeDetail(ev->detail));
+ pevent(ev,
+ TWindow, _(window),
+ TGrabMode, _(mode),
+ TFocus, _(detail),
+ TEnd
+ );
}
static void
-VerbKeymap(XKeymapEvent *ev)
+VerbKeymap(XKeymapEvent * ev)
{
- int i;
+ int i;
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "key_vector=");
- for (i = 0; i < 32; i++)
- fprintf(stderr, "%02x", ev->key_vector[i]);
- fprintf(stderr, "\n");
+ fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
+ fprintf(stderr, "key_vector=");
+ for (i = 0; i < 32; i++)
+ fprintf(stderr, "%02x", ev->key_vector[i]);
+ fprintf(stderr, "\n");
}
static void
VerbKey(XKeyEvent *ev)
{
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "root=0x%x%s", (int)ev->root, sep);
- if(ev->subwindow)
- fprintf(stderr, "subwindow=0x%x%s", (int)ev->subwindow, sep);
- fprintf(stderr, "time=%s%s", ServerTime(ev->time), sep);
- fprintf(stderr, "[%d,%d]%s", ev->x, ev->y, sep);
- fprintf(stderr, "root=[%d,%d]%s", ev->x_root, ev->y_root, sep);
- if(ev->state)
- fprintf(stderr, "state=%s%s", ButtonAndOrModifierState(ev->state), sep);
- fprintf(stderr, "keycode=%s%s", Keycode(ev), sep);
- if(!ev->same_screen)
- fprintf(stderr, "!same_screen");
- fprintf(stderr, "\n");
- return;
-
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "root=0x%x%s", (int)ev->root, sep);
- fprintf(stderr, "subwindow=0x%x%s", (int)ev->subwindow, sep);
- fprintf(stderr, "time=%s%s", ServerTime(ev->time), sep);
- fprintf(stderr, "x=%d y=%d%s", ev->x, ev->y, sep);
- fprintf(stderr, "x_root=%d y_root=%d%s", ev->x_root, ev->y_root, sep);
- fprintf(stderr, "state=%s%s", ButtonAndOrModifierState(ev->state), sep);
- fprintf(stderr, "keycode=%s%s", Keycode(ev), sep);
- fprintf(stderr, "same_screen=%s\n", TorF(ev->same_screen));
+ pevent(ev,
+ TWindow, _(window),
+ TWindow, _(root),
+ TWindow, _(subwindow),
+ TTime, _(time),
+ TInt, _(x), TInt, _(y),
+ TInt, _(x_root), TInt, _(y_root),
+ TModState, _(state),
+ TString, "keycode", estrdup(Keycode(ev)),
+ TBool, _(same_screen),
+ TEnd
+ );
}
static void
VerbProperty(XPropertyEvent *ev)
{
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "atom=%s%s", AtomName(ev->display, ev->atom), sep);
- fprintf(stderr, "time=%s%s", ServerTime(ev->time), sep);
- fprintf(stderr, "state=%s\n", PropertyState(ev->state));
+ pevent(ev,
+ TWindow, _(window),
+ TAtom, _(atom),
+ TTime, _(time),
+ TPropState, _(state),
+ TEnd
+ );
}
static void
VerbResizeRequest(XResizeRequestEvent *ev)
{
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "width=%d height=%d\n", ev->width, ev->height);
+ pevent(ev,
+ TWindow, _(window),
+ TInt, _(width), TInt, _(height),
+ TEnd
+ );
}
static void
VerbCirculate(XCirculateEvent *ev)
{
- fprintf(stderr, "event=0x%x%s", (int)ev->event, sep);
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "place=%s\n", Place(ev->place));
+ pevent(ev,
+ TWindow, _(event),
+ TWindow, _(window),
+ TPlace, _(place),
+ TEnd
+ );
}
static void
VerbConfigure(XConfigureEvent *ev)
{
- fprintf(stderr, "event=0x%x%s", (int)ev->event, sep);
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "x=%d y=%d%s", ev->x, ev->y, sep);
- fprintf(stderr, "width=%d height=%d%s", ev->width, ev->height, sep);
- fprintf(stderr, "border_width=%d%s", ev->border_width, sep);
- fprintf(stderr, "above=%s%s", MaybeNone(ev->above), sep);
- fprintf(stderr, "override_redirect=%s\n", TorF(ev->override_redirect));
+ pevent(ev,
+ TWindow, _(event),
+ TWindow, _(window),
+ TInt, _(x), TInt, _(y),
+ TInt, _(width), TInt, _(height),
+ TInt, _(border_width),
+ TIntNone, _(above),
+ TBool, _(override_redirect),
+ TEnd
+ );
}
static void
VerbCreateWindow(XCreateWindowEvent *ev)
{
- fprintf(stderr, "parent=0x%x%s", (int)ev->parent, sep);
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "x=%d y=%d%s", ev->x, ev->y, sep);
- fprintf(stderr, "width=%d height=%d%s", ev->width, ev->height, sep);
- fprintf(stderr, "border_width=%d%s", ev->border_width, sep);
- fprintf(stderr, "override_redirect=%s\n", TorF(ev->override_redirect));
+ pevent(ev,
+ TWindow, _(parent),
+ TWindow, _(window),
+ TInt, _(x), TInt, _(y),
+ TInt, _(width), TInt, _(height),
+ TInt, _(border_width),
+ TBool, _(override_redirect),
+ TEnd
+ );
}
static void
VerbDestroyWindow(XDestroyWindowEvent *ev)
{
- fprintf(stderr, "event=0x%x%s", (int)ev->event, sep);
- fprintf(stderr, "window=0x%x\n", (int)ev->window);
+ pevent(ev,
+ TWindow, _(event),
+ TWindow, _(window),
+ TEnd
+ );
}
static void
VerbGravity(XGravityEvent *ev)
{
- fprintf(stderr, "event=0x%x%s", (int)ev->event, sep);
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "x=%d y=%d\n", ev->x, ev->y);
+ pevent(ev,
+ TWindow, _(event),
+ TWindow, _(window),
+ TInt, _(x), TInt, _(y),
+ TEnd
+ );
}
static void
VerbMap(XMapEvent *ev)
{
- fprintf(stderr, "event=0x%x%s", (int)ev->event, sep);
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "override_redirect=%s\n", TorF(ev->override_redirect));
+ pevent(ev,
+ TWindow, _(event),
+ TWindow, _(window),
+ TBool, _(override_redirect),
+ TEnd
+ );
}
static void
VerbReparent(XReparentEvent *ev)
{
- fprintf(stderr, "event=0x%x%s", (int)ev->event, sep);
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "parent=0x%x%s", (int)ev->parent, sep);
- fprintf(stderr, "x=%d y=%d%s", ev->x, ev->y, sep);
- fprintf(stderr, "override_redirect=%s\n", TorF(ev->override_redirect));
+ pevent(ev,
+ TWindow, _(event),
+ TWindow, _(window),
+ TWindow, _(parent),
+ TInt, _(x), TInt, _(y),
+ TBool, _(override_redirect),
+ TEnd
+ );
}
static void
VerbUnmap(XUnmapEvent *ev)
{
- fprintf(stderr, "event=0x%x%s", (int)ev->event, sep);
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "from_configure=%s\n", TorF(ev->from_configure));
+ pevent(ev,
+ TWindow, _(event),
+ TWindow, _(window),
+ TBool, _(from_configure),
+ TEnd
+ );
}
static void
VerbCirculateRequest(XCirculateRequestEvent *ev)
{
- fprintf(stderr, "parent=0x%x%s", (int)ev->parent, sep);
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "place=%s\n", Place(ev->place));
+ pevent(ev,
+ TWindow, _(parent),
+ TWindow, _(window),
+ TPlace, _(place),
+ TEnd
+ );
}
static void
VerbConfigureRequest(XConfigureRequestEvent *ev)
{
- fprintf(stderr, "parent=0x%x%s", (int)ev->parent, sep);
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "x=%d y=%d%s", ev->x, ev->y, sep);
- fprintf(stderr, "width=%d height=%d%s", ev->width, ev->height, sep);
- fprintf(stderr, "border_width=%d%s", ev->border_width, sep);
- fprintf(stderr, "above=%s%s", MaybeNone(ev->above), sep);
- fprintf(stderr, "detail=%s%s", ConfigureDetail(ev->detail), sep);
- fprintf(stderr, "value_mask=%s\n", ConfigureValueMask(ev->value_mask));
+ pevent(ev,
+ TWindow, _(parent),
+ TWindow, _(window),
+ TInt, _(x), TInt, _(y),
+ TInt, _(width), TInt, _(height),
+ TInt, _(border_width),
+ TIntNone, _(above),
+ TConfDetail, _(detail),
+ TConfMask, _(value_mask),
+ TEnd
+ );
}
static void
VerbMapRequest(XMapRequestEvent *ev)
{
- fprintf(stderr, "parent=0x%x%s", (int)ev->parent, sep);
- fprintf(stderr, "window=0x%x\n", (int)ev->window);
+ pevent(ev,
+ TWindow, _(parent),
+ TWindow, _(window),
+ TEnd
+ );
}
static void
-VerbClient(XClientMessageEvent *ev)
+VerbClient(XClientMessageEvent * ev)
{
- int i;
+ int i;
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "message_type=%s%s", AtomName(ev->display, ev->message_type), sep);
- fprintf(stderr, "format=%d\n", ev->format);
- fprintf(stderr, "data (shown as longs)=");
- for (i = 0; i < 5; i++)
- fprintf(stderr, " 0x%08lx", ev->data.l[i]);
- fprintf(stderr, "\n");
+ fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
+ fprintf(stderr, "message_type=%s%s", AtomName(ev->message_type), sep);
+ fprintf(stderr, "format=%d\n", ev->format);
+ fprintf(stderr, "data (shown as longs)=");
+ for (i = 0; i < 5; i++)
+ fprintf(stderr, " 0x%08lx", ev->data.l[i]);
+ fprintf(stderr, "\n");
}
static void
VerbMapping(XMappingEvent *ev)
{
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "request=%s%s", MappingRequest(ev->request), sep);
- fprintf(stderr, "first_keycode=0x%x%s", ev->first_keycode, sep);
- fprintf(stderr, "count=0x%x\n", ev->count);
+ pevent(ev,
+ TWindow, _(window),
+ TMapping, _(request),
+ TWindow, _(first_keycode),
+ TWindow, _(count),
+ TEnd
+ );
}
static void
VerbSelectionClear(XSelectionClearEvent *ev)
{
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "selection=%s%s", AtomName(ev->display, ev->selection), sep);
- fprintf(stderr, "time=%s\n", ServerTime(ev->time));
+ pevent(ev,
+ TWindow, _(window),
+ TAtom, _(selection),
+ TTime, _(time),
+ TEnd
+ );
}
static void
VerbSelection(XSelectionEvent *ev)
{
- fprintf(stderr, "requestor=0x%x%s", (int)ev->requestor, sep);
- fprintf(stderr, "selection=%s%s", AtomName(ev->display, ev->selection), sep);
- fprintf(stderr, "target=%s%s", AtomName(ev->display, ev->target), sep);
- fprintf(stderr, "property=%s%s", AtomName(ev->display, ev->property), sep);
- fprintf(stderr, "time=%s\n", ServerTime(ev->time));
+ pevent(ev,
+ TWindow, _(requestor),
+ TAtom, _(selection),
+ TAtom, _(target),
+ TAtom, _(property),
+ TTime, _(time),
+ TEnd
+ );
}
static void
VerbSelectionRequest(XSelectionRequestEvent *ev)
{
- fprintf(stderr, "owner=0x%x%s", (int)ev->owner, sep);
- fprintf(stderr, "requestor=0x%x%s", (int)ev->requestor, sep);
- fprintf(stderr, "selection=%s%s", AtomName(ev->display, ev->selection), sep);
- fprintf(stderr, "target=%s%s", AtomName(ev->display, ev->target), sep);
- fprintf(stderr, "property=%s%s", AtomName(ev->display, ev->property), sep);
- fprintf(stderr, "time=%s\n", ServerTime(ev->time));
+ pevent(ev,
+ TWindow, _(owner),
+ TWindow, _(requestor),
+ TAtom, _(selection),
+ TAtom, _(target),
+ TAtom, _(property),
+ TTime, _(time),
+ TEnd
+ );
}
static void
VerbVisibility(XVisibilityEvent *ev)
{
- fprintf(stderr, "window=0x%x%s", (int)ev->window, sep);
- fprintf(stderr, "state=%s\n", VisibilityState(ev->state));
-}
-
-/******************************************************************************/
-/************ Return the string representation for type of an event ***********/
-/******************************************************************************/
-
-char *eventtype(XEvent *ev)
-{
- static char buffer[20];
-
- switch (ev->type) {
- case KeyPress:
- return ("KeyPress");
- case KeyRelease:
- return ("KeyRelease");
- case ButtonPress:
- return ("ButtonPress");
- case ButtonRelease:
- return ("ButtonRelease");
- case MotionNotify:
- return ("MotionNotify");
- case EnterNotify:
- return ("EnterNotify");
- case LeaveNotify:
- return ("LeaveNotify");
- case FocusIn:
- return ("FocusIn");
- case FocusOut:
- return ("FocusOut");
- case KeymapNotify:
- return ("KeymapNotify");
- case Expose:
- return ("Expose");
- case GraphicsExpose:
- return ("GraphicsExpose");
- case NoExpose:
- return ("NoExpose");
- case VisibilityNotify:
- return ("VisibilityNotify");
- case CreateNotify:
- return ("CreateNotify");
- case DestroyNotify:
- return ("DestroyNotify");
- case UnmapNotify:
- return ("UnmapNotify");
- case MapNotify:
- return ("MapNotify");
- case MapRequest:
- return ("MapRequest");
- case ReparentNotify:
- return ("ReparentNotify");
- case ConfigureNotify:
- return ("ConfigureNotify");
- case ConfigureRequest:
- return ("ConfigureRequest");
- case GravityNotify:
- return ("GravityNotify");
- case ResizeRequest:
- return ("ResizeRequest");
- case CirculateNotify:
- return ("CirculateNotify");
- case CirculateRequest:
- return ("CirculateRequest");
- case PropertyNotify:
- return ("PropertyNotify");
- case SelectionClear:
- return ("SelectionClear");
- case SelectionRequest:
- return ("SelectionRequest");
- case SelectionNotify:
- return ("SelectionNotify");
- case ColormapNotify:
- return ("ColormapNotify");
- case ClientMessage:
- return ("ClientMessage");
- case MappingNotify:
- return ("MappingNotify");
- }
- sprintf(buffer, "%d", ev->type);
- return buffer;
+ pevent(ev,
+ TWindow, _(window),
+ TVis, _(state),
+ TEnd
+ );
}
/******************************************************************************/
/**************** Print the values of all fields for any event ****************/
/******************************************************************************/
-void printevent(XEvent *e)
-{
- XAnyEvent *ev = (void*)e;
- char *name;
-
- if(ev->window) {
- XFetchName(blz.dpy, ev->window, &name);
- if(name) {
- fprintf(stderr, "\ttitle=%s\n", name);
- XFree(name);
- }
- }
- fprintf(stderr, "%3ld %-20s ", ev->serial, eventtype(e));
- if(ev->send_event)
- fprintf(stderr, "(sendevent) ");
- if(0){
- fprintf(stderr, "type=%s%s", eventtype(e), sep);
- fprintf(stderr, "serial=%lu%s", ev->serial, sep);
- fprintf(stderr, "send_event=%s%s", TorF(ev->send_event), sep);
- fprintf(stderr, "display=0x%p%s", ev->display, sep);
- }
-
- switch (ev->type) {
- case MotionNotify:
- VerbMotion((void*)ev);
- break;
-
- case ButtonPress:
- case ButtonRelease:
- VerbButton((void*)ev);
- break;
-
- case ColormapNotify:
- VerbColormap((void*)ev);
- break;
-
- case EnterNotify:
- case LeaveNotify:
- VerbCrossing((void*)ev);
- break;
-
- case Expose:
- VerbExpose((void*)ev);
- break;
-
- case GraphicsExpose:
- VerbGraphicsExpose((void*)ev);
- break;
-
- case NoExpose:
- VerbNoExpose((void*)ev);
- break;
-
- case FocusIn:
- case FocusOut:
- VerbFocus((void*)ev);
- break;
-
- case KeymapNotify:
- VerbKeymap((void*)ev);
- break;
-
- case KeyPress:
- case KeyRelease:
- VerbKey((void*)ev);
- break;
-
- case PropertyNotify:
- VerbProperty((void*)ev);
- break;
-
- case ResizeRequest:
- VerbResizeRequest((void*)ev);
- break;
-
- case CirculateNotify:
- VerbCirculate((void*)ev);
- break;
-
- case ConfigureNotify:
- VerbConfigure((void*)ev);
- break;
-
- case CreateNotify:
- VerbCreateWindow((void*)ev);
- break;
-
- case DestroyNotify:
- VerbDestroyWindow((void*)ev);
- break;
-
- case GravityNotify:
- VerbGravity((void*)ev);
- break;
-
- case MapNotify:
- VerbMap((void*)ev);
- break;
-
- case ReparentNotify:
- VerbReparent((void*)ev);
- break;
-
- case UnmapNotify:
- VerbUnmap((void*)ev);
- break;
-
- case CirculateRequest:
- VerbCirculateRequest((void*)ev);
- break;
-
- case ConfigureRequest:
- VerbConfigureRequest((void*)ev);
- break;
-
- case MapRequest:
- VerbMapRequest((void*)ev);
- break;
-
- case ClientMessage:
- VerbClient((void*)ev);
- break;
+typedef struct Handler Handler;
- case MappingNotify:
- VerbMapping((void*)ev);
- break;
-
- case SelectionClear:
- VerbSelectionClear((void*)ev);
- break;
+struct Handler {
+ int key;
+ void (*fn)();
+};
- case SelectionNotify:
- VerbSelection((void*)ev);
- break;
+void
+printevent(XEvent * e)
+{
+ extern Display *display;
+ XAnyEvent *ev = (void *)e;
+ char *name;
- case SelectionRequest:
- VerbSelectionRequest((void*)ev);
- break;
+ if (ev->window) {
+ XFetchName(display, ev->window, &name);
+ if (name)
+ fprintf(stderr, "\ttitle=%s\n", name);
+ XFree(name);
+ }
- case VisibilityNotify:
- VerbVisibility((void*)ev);
- break;
- }
+ fprintf(stderr, "%3ld %-20s ", ev->serial, eventtype(e->xany.type));
+ if (ev->send_event)
+ fprintf(stderr, "(sendevent) ");
+ if (0) {
+ fprintf(stderr, "type=%s%s", eventtype(e->xany.type), sep);
+ fprintf(stderr, "serial=%lu%s", ev->serial, sep);
+ fprintf(stderr, "send_event=%s%s", TorF(ev->send_event), sep);
+ fprintf(stderr, "display=0x%p%s", ev->display, sep);
+ }
+ static Handler fns[] = {
+ {MotionNotify, VerbMotion},
+ {ButtonPress, VerbButton},
+ {ButtonRelease, VerbButton},
+ {ColormapNotify, VerbColormap},
+ {EnterNotify, VerbCrossing},
+ {LeaveNotify, VerbCrossing},
+ {Expose, VerbExpose},
+ {GraphicsExpose, VerbGraphicsExpose},
+ {NoExpose, VerbNoExpose},
+ {FocusIn, VerbFocus},
+ {FocusOut, VerbFocus},
+ {KeymapNotify, VerbKeymap},
+ {KeyPress, VerbKey},
+ {KeyRelease, VerbKey},
+ {PropertyNotify, VerbProperty},
+ {ResizeRequest, VerbResizeRequest},
+ {CirculateNotify, VerbCirculate},
+ {ConfigureNotify, VerbConfigure},
+ {CreateNotify, VerbCreateWindow},
+ {DestroyNotify, VerbDestroyWindow},
+ {GravityNotify, VerbGravity},
+ {MapNotify, VerbMap},
+ {ReparentNotify, VerbReparent},
+ {UnmapNotify, VerbUnmap},
+ {CirculateRequest, VerbCirculateRequest},
+ {ConfigureRequest, VerbConfigureRequest},
+ {MapRequest, VerbMapRequest},
+ {ClientMessage, VerbClient},
+ {MappingNotify, VerbMapping},
+ {SelectionClear, VerbSelectionClear},
+ {SelectionNotify, VerbSelection},
+ {SelectionRequest, VerbSelectionRequest},
+ {VisibilityNotify, VerbVisibility},
+ {0, nil},
+ };
+ Handler *p;
+
+ for (p = fns; p->fn; p++)
+ if (p->key == ev->type)
+ break;
+ if (p->fn)
+ p->fn(ev);
}
-
diff --git a/cmd/wmii/printevent.h b/cmd/wmii/printevent.h
@@ -1,2 +1 @@
-char *eventtype(XEvent*);
void printevent(XEvent*);
diff --git a/cmd/wmii/utf.c b/cmd/wmii/utf.c
@@ -0,0 +1,399 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
+ * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <errno.h>
+#include <iconv.h>
+#include <stdarg.h>
+#include <string.h>
+#include <util.h>
+#include "dat.h"
+#include "fns.h"
+
+enum
+{
+ Bit1 = 7,
+ Bitx = 6,
+ Bit2 = 5,
+ Bit3 = 4,
+ Bit4 = 3,
+
+ T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */
+ Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */
+ T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */
+ T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */
+ T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */
+
+ Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0111 1111 */
+ Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0111 1111 1111 */
+ Rune3 = (1<<(Bit3+2*Bitx))-1, /* 1111 1111 1111 1111 */
+
+ Maskx = (1<<Bitx)-1, /* 0011 1111 */
+ Testx = Maskx ^ 0xFF, /* 1100 0000 */
+
+ Bad = Runeerror,
+};
+
+int
+chartorune(Rune *rune, char *str)
+{
+ int c, c1, c2;
+ long l;
+
+ /*
+ * one character sequence
+ * 00000-0007F => T1
+ */
+ c = *(uchar*)str;
+ if(c < Tx) {
+ *rune = c;
+ return 1;
+ }
+
+ /*
+ * two character sequence
+ * 0080-07FF => T2 Tx
+ */
+ c1 = *(uchar*)(str+1) ^ Tx;
+ if(c1 & Testx)
+ goto bad;
+ if(c < T3) {
+ if(c < T2)
+ goto bad;
+ l = ((c << Bitx) | c1) & Rune2;
+ if(l <= Rune1)
+ goto bad;
+ *rune = l;
+ return 2;
+ }
+
+ /*
+ * three character sequence
+ * 0800-FFFF => T3 Tx Tx
+ */
+ c2 = *(uchar*)(str+2) ^ Tx;
+ if(c2 & Testx)
+ goto bad;
+ if(c < T4) {
+ l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3;
+ if(l <= Rune2)
+ goto bad;
+ *rune = l;
+ return 3;
+ }
+
+ /*
+ * bad decoding
+ */
+bad:
+ *rune = Bad;
+ return 1;
+}
+
+int
+runetochar(char *str, Rune *rune)
+{
+ long c;
+
+ /*
+ * one character sequence
+ * 00000-0007F => 00-7F
+ */
+ c = *rune;
+ if(c <= Rune1) {
+ str[0] = c;
+ return 1;
+ }
+
+ /*
+ * two character sequence
+ * 0080-07FF => T2 Tx
+ */
+ if(c <= Rune2) {
+ str[0] = T2 | (c >> 1*Bitx);
+ str[1] = Tx | (c & Maskx);
+ return 2;
+ }
+
+ /*
+ * three character sequence
+ * 0800-FFFF => T3 Tx Tx
+ */
+ str[0] = T3 | (c >> 2*Bitx);
+ str[1] = Tx | ((c >> 1*Bitx) & Maskx);
+ str[2] = Tx | (c & Maskx);
+ return 3;
+}
+
+int
+runelen(long c)
+{
+ Rune rune;
+ char str[10];
+
+ rune = c;
+ return runetochar(str, &rune);
+}
+
+int
+runenlen(Rune *r, int nrune)
+{
+ int nb, c;
+
+ nb = 0;
+ while(nrune--) {
+ c = *r++;
+ if(c <= Rune1)
+ nb++;
+ else
+ if(c <= Rune2)
+ nb += 2;
+ else
+ nb += 3;
+ }
+ return nb;
+}
+
+int
+fullrune(char *str, int n)
+{
+ int c;
+
+ if(n > 0) {
+ c = *(uchar*)str;
+ if(c < Tx)
+ return 1;
+ if(n > 1)
+ if(c < T3 || n > 2)
+ return 1;
+ }
+ return 0;
+}
+
+char*
+utfecpy(char *to, char *e, char *from)
+{
+ char *end;
+
+ if(to >= e)
+ return to;
+ end = memccpy(to, from, '\0', e - to);
+ if(end == nil){
+ end = e-1;
+ while(end>to && (*--end&0xC0)==0x80)
+ ;
+ *end = '\0';
+ }else{
+ end--;
+ }
+ return end;
+}
+
+char*
+utfrune(char *s, long c)
+{
+ long c1;
+ Rune r;
+ int n;
+
+ if(c < Runesync) /* not part of utf sequence */
+ return strchr(s, c);
+
+ for(;;) {
+ c1 = *(uchar*)s;
+ if(c1 < Runeself) { /* one byte rune */
+ if(c1 == 0)
+ return 0;
+ if(c1 == c)
+ return s;
+ s++;
+ continue;
+ }
+ n = chartorune(&r, s);
+ if(r == c)
+ return s;
+ s += n;
+ }
+}
+
+int
+utflen(char *s)
+{
+ int c;
+ long n;
+ Rune rune;
+
+ n = 0;
+ for(;;) {
+ c = *(uchar*)s;
+ if(c < Runeself) {
+ if(c == 0)
+ return n;
+ s++;
+ } else
+ s += chartorune(&rune, s);
+ n++;
+ }
+}
+
+int
+utfnlen(char *s, long m)
+{
+ int c;
+ long n;
+ Rune rune;
+ char *es;
+
+ es = s + m;
+ for(n = 0; s < es; n++) {
+ c = *(uchar*)s;
+ if(c < Runeself){
+ if(c == '\0')
+ break;
+ s++;
+ continue;
+ }
+ if(!fullrune(s, es-s))
+ break;
+ s += chartorune(&rune, s);
+ }
+ return n;
+}
+
+char*
+utfrrune(char *s, long c)
+{
+ long c1;
+ Rune r;
+ char *s1;
+
+ if(c < Runesync) /* not part of utf sequence */
+ return strrchr(s, c);
+
+ s1 = 0;
+ for(;;) {
+ c1 = *(uchar*)s;
+ if(c1 < Runeself) { /* one byte rune */
+ if(c1 == 0)
+ return s1;
+ if(c1 == c)
+ s1 = s;
+ s++;
+ continue;
+ }
+ c1 = chartorune(&r, s);
+ if(r == c)
+ s1 = s;
+ s += c1;
+ }
+}
+
+/*
+ * Return pointer to first occurrence of s2 in s1,
+ * 0 if none
+ */
+char*
+utfutf(char *s1, char *s2)
+{
+ char *p;
+ long f, n1, n2;
+ Rune r;
+
+ n1 = chartorune(&r, s2);
+ f = r;
+ if(f <= Runesync) /* represents self */
+ return strstr(s1, s2);
+
+ n2 = strlen(s2);
+ for(p=s1; (p=utfrune(p, f)); p+=n1)
+ if(strncmp(p, s2, n2) == 0)
+ return p;
+ return 0;
+}
+
+char*
+toutf8n(char *str, int nstr) {
+ static iconv_t cd;
+ char *buf, *pos;
+ int nbuf, bsize;
+
+ if(cd == nil)
+ cd = iconv_open("UTF-8", "");
+ iconv(cd, nil, nil, nil, nil);
+
+ bsize = nstr * 1.25 + 4;
+ buf = emalloc(bsize);
+ pos = buf;
+ nbuf = bsize-1;
+ while(iconv(cd, (void*)&str, &nstr, &pos, &nbuf) == -1)
+ if(errno == E2BIG) {
+ bsize *= 1.25 + 4;
+ nbuf = pos - buf;
+ buf = erealloc(buf, bsize);
+ pos = buf + nbuf;
+ nbuf = bsize - nbuf - 1;
+ }else
+ break;
+ *pos = '\0';
+ return buf;
+}
+
+char*
+toutf8(char *str) {
+ return toutf8n(str, strlen(str));
+}
+
+/*
+ * space ranges
+ */
+static
+Rune __space2[] =
+{
+ 0x0009, 0x000a, /* tab and newline */
+ 0x0020, 0x0020, /* space */
+ 0x00a0, 0x00a0, /* */
+ 0x2000, 0x200b, /* - */
+ 0x2028, 0x2029, /*
-
*/
+ 0x3000, 0x3000, /* */
+ 0xfeff, 0xfeff, /* */
+};
+
+static Rune*
+bsearch(Rune c, Rune *t, int n, int ne)
+{
+ Rune *p;
+ int m;
+
+ while(n > 1) {
+ m = n/2;
+ p = t + m*ne;
+ if(c >= p[0]) {
+ t = p;
+ n = n-m;
+ } else
+ n = m;
+ }
+ if(n && c >= t[0])
+ return t;
+ return 0;
+}
+
+int
+isspacerune(Rune c)
+{
+ Rune *p;
+
+ p = bsearch(c, __space2, nelem(__space2)/2, 2);
+ if(p && c >= p[0] && c <= p[1])
+ return 1;
+ return 0;
+}
diff --git a/cmd/wmii/utf.h b/cmd/wmii/utf.h
@@ -0,0 +1,9 @@
+typedef ushort Rune; /* 16 bits */
+
+enum
+{
+ UTFmax = 3, /* maximum bytes per rune */
+ Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */
+ Runeself = 0x80, /* rune and UTF sequences are the same (<) */
+ Runeerror = 0xFFFD, /* decoding error in UTF */
+};
diff --git a/cmd/wmii/view.c b/cmd/wmii/view.c
@@ -19,8 +19,9 @@ is_empty(View *v) {
}
Frame *
-clientframe_of_view(View *v, Client *c) {
+view_clientframe(View *v, Client *c) {
Frame *f;
+
for(f=c->frame; f; f=f->cnext)
if(f->area->view == v)
break;
@@ -62,11 +63,14 @@ create_view(const char *name) {
v = emallocz(sizeof(View));
v->id = id++;
+
strncpy(v->name, name, sizeof(v->name));
write_event("CreateTag %s\n", v->name);
create_area(v, nil, 0);
- create_area(v, v->area, 0);
+ new_column(v, v->area, 0);
+
+ focus_area(v->area->next);
for(i=&view; *i; i=&(*i)->next)
if(strcmp((*i)->name, name) < 0) break;
@@ -83,17 +87,20 @@ destroy_view(View *v) {
Area *a;
View **i, *tv;
- while((a = v->area)) {
- v->area = a->next;
+ while((a = v->area->next))
destroy_area(a);
- };
+ destroy_area(v->area);
+
for(i=&view; *i; i=&(*i)->next)
if(*i == v) break;
*i = v->next;
+
write_event("DestroyTag %s\n", v->name);
if(v == screen->sel) {
- for(tv=view; tv && tv->next; tv=tv->next)
+ for(tv=view; tv; tv=tv->next)
if(tv->next == *i) break;
+ if(tv == nil)
+ tv = view;
if(tv)
focus_view(screen, tv);
}
@@ -117,16 +124,17 @@ focus_view(WMScreen *s, View *v) {
Client *c;
old = screen->sel;
- XGrabServer(blz.dpy);
+
+ XGrabServer(display);
+
assign_sel_view(v);
update_frame_selectors(v);
update_divs();
for(c=client; c; c=c->next)
if((f = c->sel)) {
- if(f->view == v) {
- resize_client(c, &f->rect);
- update_client_grab(c);
- } else {
+ if(f->view == v)
+ resize_client(c, &f->r);
+ else {
unmap_frame(c);
unmap_client(c, IconicState);
}
@@ -135,8 +143,9 @@ focus_view(WMScreen *s, View *v) {
restack_view(v);
focus_area(v->sel);
draw_frames();
- XSync(blz.dpy, False);
- XUngrabServer(blz.dpy);
+
+ XSync(display, False);
+ XUngrabServer(display);
flushevents(EnterWindowMask, False);
}
@@ -146,30 +155,33 @@ select_view(const char *arg) {
strncpy(buf, arg, sizeof(buf));
trim(buf, " \t+/");
- if(!strlen(buf))
+
+ if(strlen(buf) == 0)
return;
if(!strncmp(buf, ".", 2) || !strncmp(buf, "..", 3))
return;
+
assign_sel_view(get_view(buf));
update_views(); /* performs focus_view */
}
void
attach_to_view(View *v, Frame *f) {
- Client *c = f->client;
-
+ Client *c;
+
+ c = f->client;
c->revert = nil;
if(c->trans || c->floating || c->fixedsize || c->fullscreen)
- v->sel = v->area;
+ focus_area(v->area);
else if(starting && v->sel->floating)
- v->sel = v->area->next;
+ focus_area(v->area->next);
attach_to_area(v->sel, f, False);
}
void
restack_view(View *v) {
- static Window *wins = nil;
- static uint winssz = 0;
+ static XWindow *wins;
+ static uint winssz;
Divide *d;
Frame *f;
Client *c;
@@ -180,8 +192,6 @@ restack_view(View *v) {
return;
i = 0;
- n = 0;
-
for(c = client; c; c = c->next)
i++;
if(i == 0)
@@ -195,7 +205,8 @@ restack_view(View *v) {
wins = erealloc(wins, sizeof(Window) * winssz);
}
- wins[n++] = screen->barwin;
+ n = 0;
+ wins[n++] = screen->barwin->w;
for(f = v->area->frame; f; f = f->anext)
if(f->client->fullscreen) {
n--;
@@ -203,98 +214,114 @@ restack_view(View *v) {
}
for(f=v->area->stack; f; f=f->snext)
- wins[n++] = f->client->framewin;
+ wins[n++] = f->client->framewin->w;
- for(d = divs; d && d->mapped; d = d->next)
- wins[n++] = d->w;
+ for(d = divs; d && d->w->mapped; d = d->next)
+ wins[n++] = d->w->w;
for(a=v->area->next; a; a=a->next)
if(a->frame) {
- wins[n++] = a->sel->client->framewin;
+ wins[n++] = a->sel->client->framewin->w;
for(f=a->frame; f; f=f->anext)
if(f != a->sel)
- wins[n++] = f->client->framewin;
+ wins[n++] = f->client->framewin->w;
}
if(n) {
- XRaiseWindow(blz.dpy, wins[0]);
- XRestackWindows(blz.dpy, wins, n);
+ XRaiseWindow(display, wins[0]);
+ XRestackWindows(display, wins, n);
}
}
void
-scale_view(View *v, float w) {
- uint xoff, num_col;
- uint min_width;
+scale_view(View *v, int w) {
+ uint xoff, numcol;
+ uint minwidth;
Area *a;
- float scale, dx = 0;
- int wdiff = 0;
+ float scale;
+ int wdiff, dx;
- min_width = screen->rect.width/NCOL;
+ minwidth = Dx(screen->r)/NCOL;
if(!v->area->next)
return;
- num_col = 0;
- for(a=v->area->next; a; a=a->next)
- num_col++, dx += a->rect.width;
+ numcol = 0;
+ dx = 0;
+ for(a=v->area->next; a; a=a->next) {
+ numcol++;
+ dx += Dx(a->r);
+ }
- scale = w / dx;
+ scale = (float)w / dx;
xoff = 0;
for(a=v->area->next; a; a=a->next) {
- a->rect.width *= scale;
+ a->r.max.x = xoff + Dx(a->r) * scale;
+ a->r.min.x = xoff;
if(!a->next)
a->rect.width = w - xoff;
xoff += a->rect.width;
}
- /* min_width can only be respected when there is enough space;
+
+ /* minwidth can only be respected when there is enough space;
* the caller should guarantee this */
if(num_col * min_width > w)
return;
+
+ dx = numcol * minwidth;
xoff = 0;
- for(a=v->area->next, num_col--; a; a=a->next, num_col--) {
- if(a->rect.width < min_width)
- a->rect.width = min_width;
- else if((wdiff = xoff + a->rect.width - w + num_col * min_width) > 0)
- a->rect.width -= wdiff;
+ for(a=v->area->next, numcol--; a; a=a->next, numcol--) {
+ a->r.min.x = xoff;
+
+ if(Dx(a->r) < minwidth)
+ a->r.max.x = xoff + minwidth;
+ else if((wdiff = xoff + Dx(a->r) - w + dx) > 0)
+ a->r.max.x -= wdiff;
if(!a->next)
- a->rect.width = w - xoff;
- xoff += a->rect.width;
+ a->r.max.x = w;
+ xoff = a->r.max.x;
}
}
void
arrange_view(View *v) {
- uint xoff = 0;
+ uint xoff;
Area *a;
if(!v->area->next)
return;
- scale_view(v, screen->rect.width);
+
+ scale_view(v, Dx(screen->r));
+ xoff = 0;
for(a=v->area->next; a; a=a->next) {
- a->rect.x = xoff;
- a->rect.y = 0;
- a->rect.height = screen->rect.height - screen->brect.height;
- xoff += a->rect.width;
+ a->r.min.x = xoff;
+ a->r.min.y = 0;
+ a->r.max.y = screen->brect.min.y;
+ xoff = a->r.max.x;
arrange_column(a, False);
}
+ if(v == screen->sel)
+ update_divs();
}
XRectangle *
rects_of_view(View *v, uint *num, Frame *ignore) {
- XRectangle *result;
+ Rectangle *result;
Frame *f;
int i;
i = 2;
for(f=v->area->frame; f; f=f->anext)
i++;
- result = emallocz(i * sizeof(XRectangle));
+
+ result = emallocz(i * sizeof(Rectangle));
+
i = 0;
for(f=v->area->frame; f; f=f->anext)
if(f != ignore)
- result[i++] = f->rect;
- result[i++] = screen->rect;
+ result[i++] = f->r;
+ result[i++] = screen->r;
result[i++] = screen->brect;
+
*num = i;
return result;
}
@@ -302,132 +329,47 @@ rects_of_view(View *v, uint *num, Frame *ignore) {
/* XXX: This will need cleanup */
uchar *
view_index(View *v) {
- uint a_i, buf_i, n;
- int len;
Frame *f;
Area *a;
+ char *buf;
+ uint i, n;
+ int len;
len = sizeof(buffer);
- buf_i = 0;
- for((a = v->area), (a_i = 0); a && len > 0; (a=a->next), (a_i++)) {
+ buf = buffer;
+ for((a=v->area), (i=0); a && len > 0; (a=a->next), i++) {
if(a->floating)
- n = snprintf(&buffer[buf_i], len, "# ~ %d %d\n",
- a->rect.width, a->rect.height);
+ n = snprintf(buf, len, "# ~ %d %d\n",
+ Dx(a->r), Dy(a->r));
else
- n = snprintf(&buffer[buf_i], len, "# %d %d %d\n",
- a_i, a->rect.x, a->rect.width);
- buf_i += n;
+ n = snprintf(buf, len, "# %d %d %d\n",
+ i, a->r.min.x, Dx(a->r));
+
+ buf += n;
len -= n;
for(f=a->frame; f && len > 0; f=f->anext) {
- XRectangle *r = &f->rect;
+ Rectangle *r = &f->r;
if(a->floating)
- n = snprintf(&buffer[buf_i], len, "~ 0x%x %d %d %d %d %s\n",
- (uint)f->client->win,
- r->x, r->y, r->width, r->height,
+ n = snprintf(buf, len, "~ 0x%x %d %d %d %d %s\n",
+ (uint)f->client->w.w,
+ r->min.x, r->min.y, Dx(*r), Dy(*r),
f->client->props);
else
- n = snprintf(&buffer[buf_i], len, "%d 0x%x %d %d %s\n",
- a_i, (uint)f->client->win, r->y,
- r->height, f->client->props);
+ n = snprintf(buf, len, "%d 0x%x %d %d %s\n",
+ i, (uint)f->client->w.w,
+ r->min.y, Dy(*r),
+ f->client->props);
if(len - n < 0)
return (uchar*)buffer;
- buf_i += n;
+ buf += n;
len -= n;
}
}
- return (uchar *)buffer;
-}
-
-Client *
-client_of_message(View *v, char *message, uint *next) {
- ulong id = 0;
- Client *c;
-
- if(!strncmp(message, "sel ", 4)) {
- *next = 4;
- return view_selclient(v);
- }
- sscanf(message, "0x%lx %n", &id, next);
- if(!id)
- sscanf(message, "%lu %n", &id, next);
- if(!id)
- return nil;
- for(c=client; c && c->win!=id; c=c->next);
- return c;
-}
-
-Area *
-area_of_message(View *v, char *message, uint *next) {
- uint i;
- Area *a;
-
- if(!strncmp(message, "sel ", 4)) {
- *next = 4;
- return v->sel;
- }
- if(!strncmp(message, "~ ", 2)) {
- *next = 2;
- return v->area;
- }
- if(1 != sscanf(message, "%u %n", &i, next) || i == 0)
- return nil;
- for(a=v->area; i && a; a=a->next)
- i--;
- return a;
-}
-
-char *
-message_view(View *v, char *message) {
- int n, i;
- Client *c;
- Frame *f;
- Area *a;
- Bool swap;
- static char Ebadvalue[] = "bad value";
-
- if(!strncmp(message, "send ", 5)) {
- message += 5;
- swap = False;
- goto send;
- }
- if(!strncmp(message, "swap ", 5)) {
- message += 5;
- swap = True;
- goto send;
- }
- if(!strncmp(message, "select ", 7)) {
- message += 7;
- return select_area(v->sel, message);
- }
- if(!strncmp(message, "colmode ", 8)) {
- message += 8;
- if((a = area_of_message(v, message, &n)) == nil
- || a->floating)
- return Ebadvalue;
- if((i = str2colmode(&message[n])) == -1)
- return Ebadvalue;
-
- a->mode = i;
- arrange_column(a, True);
- restack_view(v);
-
- if(v == screen->sel)
- focus_view(screen, v);
- draw_frames();
- return nil;
- }
- return Ebadvalue;
-
-send:
- if(!(c = client_of_message(v, message, &n)))
- return Ebadvalue;
- if(!(f = clientframe_of_view(v, c)))
- return Ebadvalue;
- return send_client(f, &message[n], swap);
+ return (uchar*)buffer;
}
void
-update_views() {
+update_views(void) {
View *n, *v, *old;
Bool found;
@@ -439,9 +381,10 @@ update_views() {
for(v=view; v; v=n) {
n=v->next;
if(v != old) {
- found = True;
if(is_empty(v))
destroy_view(v);
+ else
+ found = True;
}
}
@@ -451,7 +394,7 @@ update_views() {
}
uint
-newcolw_of_view(View *v, int num) {
+newcolw(View *v, int num) {
regmatch_t regm;
Rule *r;
uint n;
@@ -461,11 +404,12 @@ newcolw_of_view(View *v, int num) {
char buf[sizeof r->value];
char *toks[16];
- strncpy(buf, r->value, sizeof(buf));
+ strcpy(buf, r->value);
+
n = tokenize(toks, 16, buf, '+');
if(n > num)
if(sscanf(toks[num], "%u", &n) == 1)
- return screen->rect.width * ((double)n / 100);
+ return Dx(screen->r) * (n / 100.0);
break;
}
return 0;
diff --git a/cmd/wmii/x11.c b/cmd/wmii/x11.c
@@ -0,0 +1,790 @@
+/* Copyright ©2007 Kris Maglione <fbsdaemon@gmail.com>
+ * See LICENSE file for license details.
+ */
+#include <assert.h>
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <util.h>
+#include "dat.h"
+#include "fns.h"
+
+Point ZP = {0, 0};
+Rectangle ZR = {{0, 0}, {0, 0}};
+
+Map wmap, amap;
+MapEnt *wbucket[137];
+MapEnt *abucket[137];
+
+XRectangle
+XRect(Rectangle r) {
+ XRectangle xr;
+
+ xr.x = r.min.x;
+ xr.y = r.min.y;
+ xr.width = Dx(r);
+ xr.height = Dy(r);
+ return xr;
+}
+
+int
+eqrect(Rectangle a, Rectangle b) {
+ return a.min.x==b.min.x && a.max.x==b.max.x
+ && a.min.y==b.min.y && a.max.y==b.max.y;
+}
+
+int
+eqpt(Point p, Point q) {
+ return p.x==q.x && p.y==q.y;
+}
+
+Point
+addpt(Point p, Point q) {
+ p.x += q.x;
+ p.y += q.y;
+ return p;
+}
+
+Point
+subpt(Point p, Point q) {
+ p.x -= q.x;
+ p.y -= q.y;
+ return p;
+}
+
+Point
+mulpt(Point p, Point q) {
+ p.x *= q.x;
+ p.y *= q.y;
+ return p;
+}
+
+Point
+divpt(Point p, Point q) {
+ p.x /= q.x;
+ p.y /= q.y;
+ return p;
+}
+
+Rectangle
+insetrect(Rectangle r, int n) {
+ r.min.x += n;
+ r.min.y += n;
+ r.max.x -= n;
+ r.max.y -= n;
+ return r;
+}
+
+Rectangle
+rectaddpt(Rectangle r, Point p) {
+ r.min.x += p.x;
+ r.max.x += p.x;
+ r.min.y += p.y;
+ r.max.y += p.y;
+ return r;
+}
+
+Rectangle
+rectsubpt(Rectangle r, Point p) {
+ r.min.x -= p.x;
+ r.max.x -= p.x;
+ r.min.y -= p.y;
+ r.max.y -= p.y;
+ return r;
+}
+
+/* Init */
+void
+initdisplay(void) {
+ display = XOpenDisplay(nil);
+ scr.screen = DefaultScreen(display);
+ scr.colormap = DefaultColormap(display, scr.screen);
+ scr.visual = DefaultVisual(display, scr.screen);
+ scr.gc = DefaultGC(display, scr.screen);
+ scr.depth = DefaultDepth(display, scr.screen);
+
+ scr.white = WhitePixel(display, scr.screen);
+ scr.black = BlackPixel(display, scr.screen);
+
+ scr.root.w = RootWindow(display, scr.screen);
+ scr.root.r = Rect(0, 0, DisplayWidth(display, scr.screen), DisplayHeight(display, scr.screen));
+ scr.rect = scr.root.r;
+
+ scr.root.parent = &scr.root;
+
+ wmap.bucket = wbucket;
+ wmap.nhash = nelem(wbucket);
+ amap.bucket = abucket;
+ amap.nhash = nelem(abucket);
+}
+
+/* Images */
+Image *
+allocimage(int w, int h, int depth) {
+ Image *img;
+
+ img = emallocz(sizeof *img);
+ img->type = WImage;
+ img->image = XCreatePixmap(display, scr.root.w, w, h, depth);
+ img->gc = XCreateGC(display, img->image, 0, nil);
+ img->depth = depth;
+ img->r = Rect(0, 0, w, h);
+ return img;
+}
+
+void
+freeimage(Image *img) {
+ assert(img->type == WImage);
+
+ XFreePixmap(display, img->image);
+ XFreeGC(display, img->gc);
+}
+
+/* Windows */
+Window *
+createwindow(Window *parent, Rectangle r, int depth, uint class,
+ WinAttr *wa, int valmask)
+ {
+ Window *w;
+
+ assert(parent->type == WWindow);
+
+ w = emallocz(sizeof *w);
+ w->type = WWindow;
+ w->parent = parent;
+
+ w->w = XCreateWindow(display, parent->w, r.min.x, r.min.y, Dx(r), Dy(r),
+ 0 /* border */, depth, class, scr.visual, valmask, wa);
+
+ if(class != InputOnly) {
+ w->gc = XCreateGC(display, w->w, 0, nil);
+ w->image = w->w;
+ }
+
+ w->r = r;
+ w->depth = depth;
+ return w;
+}
+
+void
+reparentwindow(Window *w, Window *par, Point p) {
+ XReparentWindow(display, w->w, par->w, p.x, p.y);
+ w->parent = par;
+ w->r = rectsubpt(w->r, w->r.min);
+ w->r = rectaddpt(w->r, p);
+}
+
+void
+destroywindow(Window *w) {
+ assert(w->type == WWindow);
+ sethandler(w, nil);
+ if(w->gc)
+ XFreeGC(display, w->gc);
+ XDestroyWindow(display, w->w);
+}
+
+void
+setwinattr(Window *w, WinAttr *wa, int valmask) {
+ assert(w->type == WWindow);
+ XChangeWindowAttributes(display, w->w, valmask, wa);
+}
+
+void
+reshapewin(Window *w, Rectangle r) {
+ assert(w->type == WWindow);
+ if(!eqrect(r, w->r))
+ XMoveResizeWindow(display, w->w, r.min.x, r.min.y, Dx(r), Dy(r));
+ w->r = r;
+}
+
+void
+movewin(Window *w, Point pt) {
+ Rectangle r;
+
+ assert(w->type == WWindow);
+ r = rectsubpt(w->r, w->r.min);
+ r = rectaddpt(r, pt);
+ reshapewin(w, r);
+}
+
+int
+mapwin(Window *w) {
+ if(!w->mapped) {
+ XMapWindow(display, w->w);
+ w->mapped = 1;
+ return 1;
+ }
+ return 0;
+}
+
+int
+unmapwin(Window *w) {
+ if(w->mapped) {
+ XUnmapWindow(display, w->w);
+ w->mapped = 0;
+ w->unmapped++;
+ return 1;
+ }
+ return 0;
+}
+
+void
+raisewin(Window *w) {
+ XRaiseWindow(display, w->w);
+}
+
+void
+lowerwin(Window *w) {
+ XLowerWindow(display, w->w);
+}
+
+Handlers*
+sethandler(Window *w, Handlers *new) {
+ Handlers *old;
+ MapEnt *e;
+
+ assert(w->type == WWindow);
+ assert((w->prev != nil && w->next != nil) || w->next == w->prev);
+
+ if(new == nil)
+ maprm(&wmap, (ulong)w->w);
+ else {
+ e = mapget(&wmap, (ulong)w->w, 1);
+ e->val = w;
+ }
+ old = w->handler;
+ w->handler = new;
+ return old;
+}
+
+Window*
+findwin(XWindow w) {
+ MapEnt *e;
+
+ e = mapget(&wmap, (ulong)w, 0);
+ if(e)
+ return e->val;
+ return nil;
+}
+
+uint
+winprotocols(Window *w) {
+ Atom *protocols;
+ Atom actual, delete;
+ int i, n, protos;
+
+ n = getproperty(w, "WM_PROTOCOLS", "ATOM", &actual, 0L, (uchar**)&protocols, 20L);
+ if(n == 0)
+ return 0;
+
+ protos = 0;
+ delete = xatom("WM_DELETE_WINDOW");
+ for(i = 0; i < n; i++) {
+ if(protocols[i] == delete)
+ protos |= WM_PROTOCOL_DELWIN;
+ }
+
+ free(protocols);
+ return protos;
+}
+
+/* Shape */
+void
+setshapemask(Window *dst, Image *src, Point pt) {
+ XShapeCombineMask (display, dst->w,
+ ShapeBounding, pt.x, pt.y, src->image, ShapeSet);
+}
+
+static void
+setgccol(Image *dst, ulong col) {
+ XSetForeground(display, dst->gc, col);
+}
+
+/* Drawing */
+void
+border(Image *dst, Rectangle r, int w, ulong col) {
+ if(w == 0)
+ return;
+
+ r = insetrect(r, w/2);
+ r.max.x -= w%2;
+ r.max.y -= w%2;
+
+ XSetLineAttributes(display, dst->gc, w, LineSolid, CapButt, JoinMiter);
+ setgccol(dst, col);
+ XDrawRectangle(display, dst->image, dst->gc,
+ r.min.x, r.min.y, Dx(r), Dy(r));
+}
+
+void
+fill(Image *dst, Rectangle r, ulong col) {
+ setgccol(dst, col);
+ XFillRectangle(display, dst->image, dst->gc,
+ r.min.x, r.min.y, Dx(r), Dy(r));
+}
+
+static XPoint*
+convpts(Point *pt, int np) {
+ XPoint *rp;
+ int i;
+
+ rp = emalloc(np * sizeof(*rp));
+ for(i = 0; i < np; i++) {
+ rp[i].x = pt[i].x;
+ rp[i].y = pt[i].y;
+ }
+ return rp;
+}
+
+void
+drawpoly(Image *dst, Point *pt, int np, int cap, int w, ulong col) {
+ XPoint *xp;
+
+ xp = convpts(pt, np);
+ XSetLineAttributes(display, dst->gc, w, LineSolid, cap, JoinMiter);
+ setgccol(dst, col);
+ XDrawLines(display, dst->image, dst->gc, xp, np, CoordModeOrigin);
+ free(xp);
+}
+
+void
+fillpoly(Image *dst, Point *pt, int np, ulong col) {
+ XPoint *xp;
+
+ xp = convpts(pt, np);
+ setgccol(dst, col);
+ XFillPolygon(display, dst->image, dst->gc, xp, np, Complex, CoordModeOrigin);
+ free(xp);
+}
+
+void
+drawline(Image *dst, Point p1, Point p2, int cap, int w, ulong col) {
+ XSetLineAttributes(display, dst->gc, w, LineSolid, cap, JoinMiter);
+ setgccol(dst, col);
+ XDrawLine(display, dst->image, dst->gc, p1.x, p1.y, p2.x, p2.y);
+}
+
+void
+drawstring(Image *dst, Font *font,
+ Rectangle r, Align align,
+ char *text, ulong col) {
+ char *buf;
+ uint x, y, w, h, len;
+ Bool shortened;
+
+ shortened = 0;
+
+ len = strlen(text);
+ buf = emalloc(len+1);
+ memcpy(buf, text, len+1);
+
+ h = font->ascent + font->descent;
+ y = r.min.y + Dy(r) / 2 - h / 2 + font->ascent;
+
+ /* shorten text if necessary */
+ while(len > 0) {
+ w = textwidth_l(font, buf, len + min(shortened, 3));
+ if(w <= Dx(r) - (font->height & ~1))
+ break;
+ while(len > 0 && (buf[--len]&0xC0) == 0x80)
+ buf[len] = '.';
+ buf[len] = '.';
+ shortened++;
+ }
+
+ if(len == 0 || w > Dx(r))
+ goto done;
+
+ /* mark shortened info in the string */
+ if(shortened)
+ len += min(shortened, 3);
+
+ switch (align) {
+ case EAST:
+ x = r.max.x - (w + (font->height / 2));
+ break;
+ default:
+ x = r.min.x + (font->height / 2);
+ break;
+ }
+
+ setgccol(dst, col);
+ if(font->set)
+ Xutf8DrawString(display, dst->image,
+ font->set, dst->gc,
+ x, y,
+ buf, len);
+ else {
+ XSetFont(display, dst->gc, font->xfont->fid);
+ XDrawString(display, dst->image, dst->gc,
+ x, y,
+ buf, len);
+ }
+
+done:
+ free(buf);
+}
+
+void
+copyimage(Image *dst, Rectangle r, Image *src, Point p) {
+ XCopyArea(display,
+ src->image, dst->image,
+ dst->gc,
+ r.min.x, r.min.y, Dx(r), Dy(r),
+ p.x, p.y);
+}
+
+/* Colors */
+Bool
+namedcolor(char *name, ulong *ret) {
+ XColor c, c2;
+
+ if(XAllocNamedColor(display, scr.colormap, name, &c, &c2)) {
+ *ret = c.pixel;
+ return 1;
+ }
+ return 0;
+}
+
+Bool
+loadcolor(CTuple *c, char *str) {
+ char buf[24];
+
+ strncpy(buf, str, sizeof buf);
+ memcpy(c->colstr, str, sizeof c->colstr);
+
+ buf[7] = buf[15] = buf[23] = '\0';
+ return namedcolor(buf, &c->fg)
+ && namedcolor(buf+8, &c->bg)
+ && namedcolor(buf+16, &c->border);
+}
+
+/* Fonts */
+Font *
+loadfont(char *name) {
+ Font *f;
+ char **missing = nil, *def = "?";
+ int n, i;
+
+ f = emallocz(sizeof *f);
+ f->name = estrdup(name);
+
+ f->set = XCreateFontSet(display, name, &missing, &n, &def);
+ if(missing) {
+ fprintf(stderr, "%s: missing fontset%s for '%s':", argv0,
+ (n > 1 ? "s":""), name);
+ for(i = 0; i < n; i++)
+ fprintf(stderr, "%s %s", (i ? ",":""), missing[i]);
+ fprintf(stderr, "\n");
+ freestringlist(missing);
+ }
+
+ if(f->set) {
+ XFontStruct **xfonts;
+ char **font_names;
+
+ XFontsOfFontSet(f->set, &xfonts, &font_names);
+ f->ascent = xfonts[0]->ascent;
+ f->descent = xfonts[0]->descent;
+ }
+ else {
+ f->xfont = XLoadQueryFont(display, name);
+ if(!f->xfont) {
+ fprintf(stderr, "%s: cannot load font: %s\n", argv0, name);
+ freefont(f);
+ return nil;
+ }
+
+ f->ascent = f->xfont->ascent;
+ f->descent = f->xfont->descent;
+ }
+ f->height = f->ascent + f->descent;
+ return f;
+}
+
+void
+freefont(Font *f) {
+ if(f->set)
+ XFreeFontSet(display, f->set);
+ if(f->xfont)
+ XFreeFont(display, f->xfont);
+ free(f->name);
+ free(f);
+}
+
+uint
+textwidth_l(Font *font, char *text, uint len) {
+ XRectangle r;
+
+ if(font->set) {
+ Xutf8TextExtents(font->set, text, len, &r, nil);
+ return r.width;
+ }
+ return XTextWidth(font->xfont, text, len);
+}
+
+uint
+textwidth(Font *font, char *text) {
+ return textwidth_l(font, text, strlen(text));
+}
+
+uint
+labelh(Font *font) {
+ return font->height + 2;
+}
+
+/* Misc */
+Atom
+xatom(char *name) {
+ MapEnt *e;
+
+ e = hashget(&amap, name, 1);
+ if(e->val == nil)
+ e->val = (void*)XInternAtom(display, name, False);
+ return (Atom)e->val;
+}
+
+void
+changeproperty(Window *w, char *prop, char *type, int width, uchar *data, int n) {
+ XChangeProperty(display, w->w, xatom(prop), xatom(type), width, PropModeReplace, data, n);
+}
+
+void
+freestringlist(char *list[]) {
+ XFreeStringList(list);
+}
+
+ulong
+getproperty(Window *w, char *prop, char *type, Atom *actual, ulong offset, uchar **ret, ulong length) {
+ Atom typea;
+ ulong n, extra;
+ int status, format;
+
+ typea = (type ? xatom(type) : 0L);
+
+ status = XGetWindowProperty(display, w->w,
+ xatom(prop), offset, length, False /* delete */,
+ typea, actual, &format, &n, &extra, ret);
+
+ if(status != Success)
+ return 0;
+ if(n == 0)
+ free(*ret);
+ return n;
+}
+
+int
+gettextlistproperty(Window *w, char *name, char **ret[]) {
+ XTextProperty prop;
+ char **list;
+ int n;
+
+ *ret = nil;
+ n = 0;
+
+ XGetTextProperty(display, w->w, &prop, xatom(name));
+ if(prop.nitems > 0) {
+ if(Xutf8TextPropertyToTextList(display, &prop, &list, &n) == Success)
+ *ret = list;
+ XFree(prop.value);
+ }
+ return n;
+}
+
+char *
+gettextproperty(Window *w, char *name) {
+ char **list, *str;
+ int n;
+
+ str = nil;
+
+ n = gettextlistproperty(w, name, &list);
+ if(n > 0)
+ str = estrdup(*list);
+ freestringlist(list);
+
+ return str;
+}
+
+void
+setfocus(Window *w, int mode) {
+ XSetInputFocus(display, w->w, mode, CurrentTime);
+}
+
+/* Mouse */
+Point
+querypointer(Window *w) {
+ XWindow dummy;
+ Point pt;
+ uint ui;
+ int i;
+
+ XQueryPointer(display, w->w, &dummy, &dummy, &i, &i, &pt.x, &pt.y, &ui);
+ return pt;
+}
+
+void
+warppointer(Point pt) {
+ XWarpPointer(display,
+ /* src, dest w */ None, scr.root.w,
+ /* src_rect */ 0, 0, 0, 0,
+ /* target */ pt.x, pt.y);
+}
+
+Point
+translate(Window *src, Window *dst, Point sp) {
+ Point pt;
+ XWindow w;
+
+ XTranslateCoordinates(display, src->w, dst->w, sp.x, sp.y, &pt.x, &pt.y, &w);
+ return pt;
+}
+
+int
+grabpointer(Window *w, Window *confine, Cursor cur, int mask) {
+ XWindow cw;
+
+ cw = None;
+ if(confine)
+ cw = confine->w;
+ return XGrabPointer(display, w->w, False /* owner events */, mask,
+ GrabModeAsync, GrabModeAsync, cw, cur, CurrentTime
+ ) == GrabSuccess;
+}
+
+void
+ungrabpointer(void) {
+ XUngrabPointer(display, CurrentTime);
+}
+
+/* Insanity */
+void
+sethints(Window *w) {
+ enum { MaxInt = ((uint)(1<<(8*sizeof(int)-1))-1) };
+ XSizeHints xs;
+ WinHints *h;
+ Point p;
+ long size;
+
+ if(w->hints == nil)
+ w->hints = emalloc(sizeof *h);
+
+ h = w->hints;
+ memset(h, 0, sizeof *h);
+
+ h->max = Pt(MaxInt, MaxInt);
+ h->inc = Pt(1,1);
+
+ if(!XGetWMNormalHints(display, w->w, &xs, &size))
+ return;
+
+ if(xs.flags&PMinSize) {
+ p.x = xs.min_width;
+ p.y = xs.min_height;
+ h->min = p;
+ }
+ if(xs.flags&PMaxSize) {
+ p.x = xs.max_width;
+ p.y = xs.max_height;
+ h->max = p;
+ }
+
+ h->base = h->min;
+ if(xs.flags&PBaseSize) {
+ p.x = xs.base_width;
+ p.y = xs.base_height;
+ h->base = p;
+ h->baspect = p;
+ }
+
+ if(xs.flags&PResizeInc) {
+ h->inc.x = max(xs.width_inc, 1);
+ h->inc.y = max(xs.height_inc, 1);
+ }
+
+ if(xs.flags&PAspect) {
+ p.x = xs.min_aspect.x;
+ p.y = xs.min_aspect.y;
+ h->aspect.min = p;
+ p.x = xs.max_aspect.x;
+ p.y = xs.max_aspect.y;
+ h->aspect.max = p;
+ }
+
+ h->position = ((xs.flags&(USPosition|PPosition)) != 0);
+
+ p = ZP;
+ if((xs.flags&PWinGravity) == 0)
+ xs.win_gravity = NorthWestGravity;
+
+ switch (xs.win_gravity) {
+ case EastGravity: case CenterGravity: case WestGravity:
+ p.y = 1;
+ break;
+ case SouthEastGravity: case SouthGravity: case SouthWestGravity:
+ p.y = 2;
+ break;
+ }
+ switch (xs.win_gravity) {
+ case NorthGravity: case CenterGravity: case SouthGravity:
+ p.x = 1;
+ break;
+ case NorthEastGravity: case EastGravity: case SouthEastGravity:
+ p.x = 2;
+ break;
+ }
+ h->grav = p;
+ h->gravstatic = (xs.win_gravity==StaticGravity);
+}
+
+Rectangle
+sizehint(WinHints *h, Rectangle r) {
+ Point p, p2, o;
+
+ if(h == nil)
+ return r;
+
+ o = r.min;
+ r = rectsubpt(r, o);
+
+ /* Min/max */
+ r.max.x = max(r.max.x, h->min.x);
+ r.max.y = max(r.max.y, h->min.y);
+ r.max.x = min(r.max.x, h->max.x);
+ r.max.y = min(r.max.y, h->max.y);
+
+ /* Increment */
+ p = subpt(r.max, h->base);
+ r.max.x -= p.x % h->inc.x;
+ r.max.y -= p.y % h->inc.y;
+
+ /* Aspect */
+ p = subpt(r.max, h->baspect);
+ p.y = max(p.y, 1);
+ p2 = h->aspect.min;
+ if(p.x * p2.y / p.y < p2.x)
+ r.max.y = h->baspect.y + p.x * p2.y / p2.x;
+ p2 = h->aspect.max;
+ if(p.x * p2.y / p.y > p2.x)
+ r.max.x = h->baspect.x + p.y * p2.x / p2.y;
+
+ return rectaddpt(r, o);
+}
+
+Rectangle
+gravitate(Rectangle rc, Rectangle rf, Point grav) {
+ Point d;
+
+ rf = rectsubpt(rf, rf.min);
+
+ /* Get delta between frame and client rectangles */
+ d = subpt(rc.max, rc.min);
+ d = subpt(rf.max, d);
+
+ /* Divide by 2 and apply gravity */
+ d = divpt(d, Pt(2, 2));
+ d = mulpt(d, grav);
+
+ return rectaddpt(rc, d);
+}
diff --git a/cmd/wmii/x11.h b/cmd/wmii/x11.h
@@ -0,0 +1,117 @@
+#define Window XWindow
+#define Font XFont
+#define Screen XScreen
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/shape.h>
+#undef Window
+#undef Font
+#undef Screen
+
+typedef struct Point Point;
+typedef struct Rectangle Rectangle;
+typedef struct Screen Screen;
+typedef struct Window Window;
+typedef struct WinHints WinHints;
+typedef struct Handlers Handlers;
+typedef struct Window Image;
+typedef struct Font Font;
+typedef XSetWindowAttributes WinAttr;
+
+struct Point {
+ int x, y;
+};
+
+struct Rectangle {
+ Point min, max;
+};
+
+struct Window {
+ int type;
+ XWindow w;
+ Window *parent;
+ Drawable image;
+ GC gc;
+ Rectangle r;
+ void *aux;
+ Handlers *handler;
+ Window *next, *prev;
+ WinHints *hints;
+ Bool mapped;
+ int unmapped;
+ int depth;
+};
+
+struct WinHints {
+ Point min, max;
+ Point base, baspect;
+ Point inc;
+ Rectangle aspect;
+ Point grav;
+ Bool gravstatic;
+ Bool position;
+};
+
+struct Handlers {
+ void (*bdown)(Window*, XButtonEvent*);
+ void (*bup)(Window*, XButtonEvent*);
+ void (*kdown)(Window*, XKeyEvent*);
+ void (*kup)(Window*, XKeyEvent*);
+ void (*focusin)(Window*, XFocusChangeEvent*);
+ void (*focusout)(Window*, XFocusChangeEvent*);
+ void (*enter)(Window*, XCrossingEvent*);
+ void (*leave)(Window*, XCrossingEvent*);
+ void (*motion)(Window*, XMotionEvent*);
+ void (*destroy)(Window*, XDestroyWindowEvent*);
+ void (*configreq)(Window*, XConfigureRequestEvent*);
+ void (*map)(Window*, XMapEvent*);
+ void (*unmap)(Window*, XUnmapEvent*);
+ void (*property)(Window*, XPropertyEvent*);
+ void (*expose)(Window*, XExposeEvent*);
+};
+
+struct Screen {
+ int screen;
+ Window root;
+ Colormap colormap;
+ Visual *visual;
+ Rectangle rect;
+ GC gc;
+ int depth;
+ int fd;
+ ulong black, white;
+};
+
+enum { WWindow, WImage };
+
+struct Font {
+ XFontStruct *xfont;
+ XFontSet set;
+ int ascent;
+ int descent;
+ uint height;
+ char *name;
+};
+
+Display *display;
+Screen scr;
+
+extern Point ZP;
+extern Rectangle ZR;
+
+Rectangle insetrect(Rectangle r, int n);
+
+Point Pt(int x, int y);
+Rectangle Rect(int x0, int y0, int x1, int y1);
+Rectangle Rpt(Point min, Point max);
+
+XRectangle XRect(Rectangle r);
+
+#define Dx(r) ((r).max.x - (r).min.x)
+#define Dy(r) ((r).max.y - (r).min.y)
+#define Pt(x, y) ((Point){(x), (y)})
+#define Rpt(p, q) ((Rectangle){p, q})
+#define Rect(x0, y0, x1, y1) ((Rectangle){Pt(x0, y0), Pt(x1, y1)})
+#define changeprop(w, prop, type, data, n) changeproperty(w, prop, type, (sizeof(*(data))*8), \
+ (uchar*)(data), n)
diff --git a/cmd/wmii9menu.c b/cmd/wmii9menu.c
@@ -86,13 +86,13 @@ char **labels; /* list of labels and commands */
char **commands;
int numitems;
-void usage();
-void run_menu();
-void create_window();
-void redraw();
-void warpmouse();
-void memory();
-int args();
+void usage(void);
+void run_menu(void);
+void create_window(int, int);
+void redraw(int, int);
+void warpmouse(int, int);
+void memory(void);
+int args(void);
/* args --- go through the argument list, set options */
@@ -110,7 +110,7 @@ struct {
{0, },
}, *ap;
-ulong
+static ulong
getcolor(char *name, ulong def) {
if((name != nil)
&& (XParseColor(dpy, defcmap, name, &color) != 0)
@@ -204,7 +204,7 @@ main(int argc, char **argv)
if(fontname != nil) {
font = XLoadQueryFont(dpy, fontname);
if(font == nil)
- fprintf(stderr, "%s: warning: can't load font %s\n",
+ fprintf(stderr, "%s: warning: can't load font '%s'\n",
progname, fontname);
}
@@ -238,7 +238,7 @@ main(int argc, char **argv)
/* usage --- print a usage message and die */
void
-usage()
+usage(void)
{
fprintf(stderr, "usage: %s [-display <displayname>] [-font <fontname>] ", progname);
fprintf(stderr, "[-{n,s}{f,b} <color>] [-br <color>] ");
@@ -249,7 +249,7 @@ usage()
/* run_menu --- put up the window, execute selected commands */
void
-run_menu()
+run_menu(void)
{
XEvent ev;
int i, old, wide, high, dx, dy;
diff --git a/cmd/wmii9rc.sh b/cmd/wmii9rc.sh
@@ -1,6 +1,7 @@
#!/bin/sh -f
RC=""
-for i in "$PLAN9" P9PATHS; do
+IFS=:
+for i in "$PLAN9" `echo P9PATHS`; do
if [ -d "$i" -a -x "$i/bin/rc" ]; then
export PLAN9="$i"
RC="$i/bin/rc"
@@ -13,7 +14,7 @@ if [ ! -n "$RC" ]; then
fi
if [ -n "$1" ]; then
- exec $RC "$@"
+ exec "$RC" "$@"
else
true
fi
diff --git a/cmd/wmiiloop.sh b/cmd/wmiiloop.sh
@@ -11,20 +11,17 @@ script() {
BEGIN {
arg[1] = "Nop"
body = "";
- writekeys = "wmiir write /keys"
- print "IFS=''"
}
-
function addevent() {
if(arg[1] == "Key")
keys[arg[2]] = 1;
var = arg[1] "s"
- print var "=\"$" var " " arg[2] "\""
+ printf "%s=\"$%s %s\"\n", var, var, arg[2]
gsub("[^a-zA-Z_0-9]", "_", arg[2]);
if(body != "")
- print arg[1] "_" arg[2] "() {" body "\n}"
+ printf "%s_%s() { %s\n }\n", arg[1], arg[2], body
}
/^(Event|Key|Action)[ \t]/ {
@@ -38,9 +35,6 @@ script() {
END {
addevent()
- for(key in keys)
- print key | writekeys;
- close(writekeys);
}
!
}
diff --git a/cmd/wmiir.c b/cmd/wmiir.c
@@ -12,9 +12,9 @@
static IxpClient *client;
static void
-usage() {
+usage(void) {
fprintf(stderr,
- "usage: %1$s [-a <address>] {create | read | ls [-ld] | remove | write} <file>\n"
+ "usage: %1$s [-a <address>] {create | read | ls [-ld] | remove | rm | write} <file>\n"
" %1$s [-a <address>] xwrite <file> <data>\n"
" %1$s -v\n", argv0);
exit(1);
@@ -24,12 +24,12 @@ usage() {
static void
write_data(IxpCFid *fid, char *name) {
void *buf;
- uint len;
+ int len;
buf = ixp_emalloc(fid->iounit);;
do {
len = read(0, buf, fid->iounit);
- if(len >= 0 && ixp_write(fid, buf, len) != len)
+ if(len > 0 && ixp_write(fid, buf, len) != len)
fatal("cannot write file '%s': %s\n", name, errstr);
} while(len > 0);
@@ -216,7 +216,8 @@ xls(int argc, char *argv[]) {
Message m;
Stat *stat;
IxpCFid *fid;
- char *file, *buf;
+ char *file;
+ uchar *buf;
int lflag, dflag, count, nstat, mstat, i;
lflag = dflag = 0;
@@ -258,7 +259,7 @@ xls(int argc, char *argv[]) {
while(m.pos < m.end) {
if(nstat == mstat) {
mstat <<= 1;
- stat = ixp_erealloc(stat, mstat);
+ stat = erealloc(stat, sizeof(*stat) * mstat);
}
ixp_pstat(&m, &stat[nstat++]);
}
@@ -286,6 +287,7 @@ struct exectab {
{"read", xread},
{"create", xcreate},
{"remove", xremove},
+ {"rm", xremove},
{"ls", xls},
{0, 0}
};
diff --git a/config.mk b/config.mk
@@ -9,26 +9,26 @@ LIBDIR = ${PREFIX}/lib
INCLUDE = ${PREFIX}/include
# Includes and libs
-INCS = -I. -I${ROOT}/include -I${INCLUDE} -I/usr/include
+INCPATH = .:${ROOT}/include:${INCLUDE}:/usr/include
LIBS = -L/usr/lib -lc
# Flags
-CFLAGS = -g -Wall ${INCS} -DVERSION=\"${VERSION}\"
-LDFLAGS = -g ${LIBS}
+include ${ROOT}/mk/gcc.mk
+CFLAGS += -g -O0
+LDFLAGS += -g ${LIBS}
STATIC = -static
# Compiler
CC = cc -c
# Linker (Under normal circumstances, this should *not* be 'ld')
LD = cc
-# Other
-AR = ar crs
-#AR = sh -c 'ar cr "$$@" && ranlib "$$@"'
-P9PATHS = /usr/local/plan9 /usr/local/9 /opt/plan9 /opt/9 /usr/plan9 /usr/9
+AWKPATH = $$(which awk)
+P9PATHS = ${PLAN9}:/usr/local/plan9:/usr/local/9:/opt/plan9:/opt/9:/usr/plan9:/usr/9
INCX11 = -I/usr/X11R6/include
LIBX11 = -L/usr/X11R6/lib -lX11
+LIBICONV = # Leave blank if your libc includes iconv (glibc does)
LIBIXP = ${ROOT}/libixp/libixp.a
# Solaris
@@ -36,5 +36,5 @@ LIBIXP = ${ROOT}/libixp/libixp.a
#LDFLAGS = ${LIBS} -R${PREFIX}/lib
#LDFLAGS += -lsocket -lnsl
#CFLAGS += -xtarget=ultra
-#FCALL_H_VERSION=.nounion
+
diff --git a/debian/changelog b/debian/changelog
@@ -0,0 +1,6 @@
+wmii (3.6pre~20070508) unstable; urgency=low
+
+ * First commit of debian directory.
+
+ -- Kris Maglione <jg@suckless.org> Tue, 8 May 2007 18:18:00 -0400
+
diff --git a/debian/control b/debian/control
@@ -0,0 +1,25 @@
+Source: wmii
+Section: x11
+Priority: optional
+Maintainer: Daniel Baumann <daniel@debian.org>
+Build-Depends: libx11-dev, libxext-dev, x11proto-xext-dev, debhelper (>= 4.0)
+Standards-Version: 3.7.2
+
+Package: wmii
+Architecture: any
+Depends: ${shlibs:Depends}, dwm-tools
+Conflicts: wmii2
+Replaces: wmii2
+Recommends: wmii-doc
+Provides: x-window-manager
+Description: lightweight tabbed and tiled X11 window manager
+ wmii is a dynamic window manager for X11, which is highly customizable and
+ usable with keyboard and mouse. It supports conventional, tabbed and tiled
+ window management with low memory usage. It is highly modularized and uses an
+ inter-process communication interface which is oriented on the 9p protocol of
+ plan9.
+ .
+ This package contains a pre-3.6 snapshot of the window manager; wmii2 contains
+ version 2.
+ .
+ Homepage: <http://wmii.suckless.org/>
diff --git a/debian/copyright b/debian/copyright
@@ -0,0 +1,279 @@
+Debian packaging based on that of Daniel Baumann <daniel.baumann@panthera-systems.net>,
+now maintained by the upstream author.
+
+It was downloaded from <http://wmii.suckless.org/>.
+Upstream Author: Kris Maglione <jg@suckless.org>
+
+The majority of this package is under the following license, with exceptions
+following.
+
+In the event that a file contains a copyright notice at the top, that is the
+copyright notice that this license refers to. Otherwise, it is:
+©2006-2007 Kris Maglione <bsdaemon at comcast dot net>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+Exceptions:
+
+cmd/util.c and include/util.h are in the Public Domain.
+
+Original debian packaging is (C) 2005-2007, Daniel Baumann <daniel@debian.org>
+and is licensed under the GPL, see `/usr/share/common-licenses/GPL'.
+Whether what remains is worthy of copyright is to be determined by the copyer.
+Portions by Kris Maglione are in the Public Domain.
+
+libixp/intmap.c falls under the Lucent Public License, as follows:
+
+Lucent Public License Version 1.02
+
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS PUBLIC
+LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE
+PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+ a. in the case of Lucent Technologies Inc. ("LUCENT"), the Original
+ Program, and
+ b. in the case of each Contributor,
+
+ i. changes to the Program, and
+ ii. additions to the Program;
+
+ where such changes and/or additions to the Program were added to the
+ Program by such Contributor itself or anyone acting on such
+ Contributor's behalf, and the Contributor explicitly consents, in
+ accordance with Section 3C, to characterization of the changes and/or
+ additions as Contributions.
+
+"Contributor" means LUCENT and any other entity that has Contributed a
+Contribution to the Program.
+
+"Distributor" means a Recipient that distributes the Program,
+modifications to the Program, or any part thereof.
+
+"Licensed Patents" mean patent claims licensable by a Contributor
+which are necessarily infringed by the use or sale of its Contribution
+alone or when combined with the Program.
+
+"Original Program" means the original version of the software
+accompanying this Agreement as released by LUCENT, including source
+code, object code and documentation, if any.
+
+"Program" means the Original Program and Contributions or any part
+thereof
+
+"Recipient" means anyone who receives the Program under this
+Agreement, including all Contributors.
+
+2. GRANT OF RIGHTS
+
+ a. Subject to the terms of this Agreement, each Contributor hereby
+ grants Recipient a non-exclusive, worldwide, royalty-free copyright
+ license to reproduce, prepare derivative works of, publicly display,
+ publicly perform, distribute and sublicense the Contribution of such
+ Contributor, if any, and such derivative works, in source code and
+ object code form.
+
+ b. Subject to the terms of this Agreement, each Contributor hereby
+ grants Recipient a non-exclusive, worldwide, royalty-free patent
+ license under Licensed Patents to make, use, sell, offer to sell,
+ import and otherwise transfer the Contribution of such Contributor, if
+ any, in source code and object code form. The patent license granted
+ by a Contributor shall also apply to the combination of the
+ Contribution of that Contributor and the Program if, at the time the
+ Contribution is added by the Contributor, such addition of the
+ Contribution causes such combination to be covered by the Licensed
+ Patents. The patent license granted by a Contributor shall not apply
+ to (i) any other combinations which include the Contribution, nor to
+ (ii) Contributions of other Contributors. No hardware per se is
+ licensed hereunder.
+
+ c. Recipient understands that although each Contributor grants the
+ licenses to its Contributions set forth herein, no assurances are
+ provided by any Contributor that the Program does not infringe the
+ patent or other intellectual property rights of any other entity. Each
+ Contributor disclaims any liability to Recipient for claims brought by
+ any other entity based on infringement of intellectual property rights
+ or otherwise. As a condition to exercising the rights and licenses
+ granted hereunder, each Recipient hereby assumes sole responsibility
+ to secure any other intellectual property rights needed, if any. For
+ example, if a third party patent license is required to allow
+ Recipient to distribute the Program, it is Recipient's responsibility
+ to acquire that license before distributing the Program.
+
+ d. Each Contributor represents that to its knowledge it has sufficient
+ copyright rights in its Contribution, if any, to grant the copyright
+ license set forth in this Agreement.
+
+3. REQUIREMENTS
+
+A. Distributor may choose to distribute the Program in any form under
+this Agreement or under its own license agreement, provided that:
+
+ a. it complies with the terms and conditions of this Agreement;
+
+ b. if the Program is distributed in source code or other tangible
+ form, a copy of this Agreement or Distributor's own license agreement
+ is included with each copy of the Program; and
+
+ c. if distributed under Distributor's own license agreement, such
+ license agreement:
+
+ i. effectively disclaims on behalf of all Contributors all warranties
+ and conditions, express and implied, including warranties or
+ conditions of title and non-infringement, and implied warranties or
+ conditions of merchantability and fitness for a particular purpose;
+ ii. effectively excludes on behalf of all Contributors all liability
+ for damages, including direct, indirect, special, incidental and
+ consequential damages, such as lost profits; and
+ iii. states that any provisions which differ from this Agreement are
+ offered by that Contributor alone and not by any other party.
+
+B. Each Distributor must include the following in a conspicuous
+ location in the Program:
+
+ Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights
+ Reserved.
+
+C. In addition, each Contributor must identify itself as the
+originator of its Contribution in a manner that reasonably allows
+subsequent Recipients to identify the originator of the Contribution.
+Also, each Contributor must agree that the additions and/or changes
+are intended to be a Contribution. Once a Contribution is contributed,
+it may not thereafter be revoked.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain
+responsibilities with respect to end users, business partners and the
+like. While this license is intended to facilitate the commercial use
+of the Program, the Distributor who includes the Program in a
+commercial product offering should do so in a manner which does not
+create potential liability for Contributors. Therefore, if a
+Distributor includes the Program in a commercial product offering,
+such Distributor ("Commercial Distributor") hereby agrees to defend
+and indemnify every Contributor ("Indemnified Contributor") against
+any losses, damages and costs (collectively"Losses") arising from
+claims, lawsuits and other legal actions brought by a third party
+against the Indemnified Contributor to the extent caused by the acts
+or omissions of such Commercial Distributor in connection with its
+distribution of the Program in a commercial product offering. The
+obligations in this section do not apply to any claims or Losses
+relating to any actual or alleged intellectual property infringement.
+In order to qualify, an Indemnified Contributor must: a) promptly
+notify the Commercial Distributor in writing of such claim, and b)
+allow the Commercial Distributor to control, and cooperate with the
+Commercial Distributor in, the defense and any related settlement
+negotiations. The Indemnified Contributor may participate in any such
+claim at its own expense.
+
+For example, a Distributor might include the Program in a commercial
+product offering, Product X. That Distributor is then a Commercial
+Distributor. If that Commercial Distributor then makes performance
+claims, or offers warranties related to Product X, those performance
+claims and warranties are such Commercial Distributor's responsibility
+alone. Under this section, the Commercial Distributor would have to
+defend claims against the Contributors related to those performance
+claims and warranties, and if a court requires any Contributor to pay
+any damages as a result, the Commercial Distributor must pay those
+damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
+PROVIDED ON AN"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
+WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
+OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
+responsible for determining the appropriateness of using and
+distributing the Program and assumes all risks associated with its
+exercise of rights under this Agreement, including but not limited to
+the risks and costs of program errors, compliance with applicable
+laws, damage to or loss of data, programs or equipment, and
+unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR
+ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
+WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR
+DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. EXPORT CONTROL
+
+Recipient agrees that Recipient alone is responsible for compliance
+with the United States export administration regulations (and the
+export control laws and regulation of any other countries).
+
+8. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under
+applicable law, it shall not affect the validity or enforceability of
+the remainder of the terms of this Agreement, and without further
+action by the parties hereto, such provision shall be reformed to the
+minimum extent necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against a Contributor with
+respect to a patent applicable to software (including a cross-claim or
+counterclaim in a lawsuit), then any patent licenses granted by that
+Contributor to such Recipient under this Agreement shall terminate as
+of the date such litigation is filed. In addition, if Recipient
+institutes patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Program
+itself (excluding combinations of the Program with other software or
+hardware) infringes such Recipient's patent(s), then such Recipient's
+rights granted under Section 2(b) shall terminate as of the date such
+litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it
+fails to comply with any of the material terms or conditions of this
+Agreement and does not cure such failure in a reasonable period of
+time after becoming aware of such noncompliance. If all Recipient's
+rights under this Agreement terminate, Recipient agrees to cease use
+and distribution of the Program as soon as reasonably practicable.
+However, Recipient's obligations under this Agreement and any licenses
+granted by Recipient relating to the Program shall continue and
+survive.
+
+LUCENT may publish new versions (including revisions) of this
+Agreement from time to time. Each new version of the Agreement will be
+given a distinguishing version number. The Program (including
+Contributions) may always be distributed subject to the version of the
+Agreement under which it was received. In addition, after a new
+version of the Agreement is published, Contributor may elect to
+distribute the Program (including its Contributions) under the new
+version. No one other than LUCENT has the right to modify this
+Agreement. Except as expressly stated in Sections 2(a) and 2(b) above,
+Recipient receives no rights or licenses to the intellectual property
+of any Contributor under this Agreement, whether expressly, by
+implication, estoppel or otherwise. All rights in the Program not
+expressly granted under this Agreement are reserved.
+
+This Agreement is governed by the laws of the State of New York and
+the intellectual property laws of the United States of America. No
+party to this Agreement will bring a legal action under this Agreement
+more than one year after the cause of action arose. Each party waives
+its rights to a jury trial in any resulting litigation.
+
diff --git a/debian/docs b/debian/docs
@@ -0,0 +1 @@
+README
diff --git a/debian/file/wmii.desktop b/debian/file/wmii.desktop
@@ -0,0 +1,7 @@
+[Desktop Entry]
+Encoding=UTF-8
+Name=wmii
+Comment=wmii pre-3.6 Development Snapshot
+Exec=wmii
+Icon=wmii.png
+Type=XSession
diff --git a/debian/patches/unx-terminal-emulater.awk b/debian/patches/unx-terminal-emulater.awk
@@ -0,0 +1,9 @@
+/^[ ]*WMII_TERM[ ]*=/ {
+ print "E " FILENAME
+ print FNR "c"
+ print
+ print "."
+ print "w"
+ nextfile
+}
+
diff --git a/debian/patches/x-terminal-emulater.ed b/debian/patches/x-terminal-emulater.ed
@@ -0,0 +1,3 @@
+/^[ ]*WMII_TERM[ ]*=/s/=.*/=x-terminal-emulator/
+w
+
diff --git a/debian/patches/x-terminal-emulater.list b/debian/patches/x-terminal-emulater.list
@@ -0,0 +1,3 @@
+rc/rc.wmii.rc
+rc/wmiirc.sh
+
diff --git a/debian/rules b/debian/rules
@@ -0,0 +1,97 @@
+#!/usr/bin/make -f
+
+#export DH_VERBOSE=1
+export DH_COMPAT=4
+
+PREFIX=/usr
+ETC=/etc/X11
+FAKE=$(CURDIR)/debian/wmii
+
+PATCHES=debian/patches
+UNPATCH=debian/unpatch.ed
+
+CFLAGS = -g -O0
+ifeq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
+ # wmii is IO, not CPU bound. Please do not use -O2 here.
+ CFLAGS += -O
+endif
+ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
+ DH_STRIP = dh_strip
+endif
+
+export CFLAGS
+
+clean: unpatch
+ dh_testdir
+ dh_testroot
+ rm -f build-stamp
+
+ # Cleaning package
+ -$(MAKE) clean
+
+ dh_clean
+
+build: build-stamp
+build-stamp: patch
+ dh_testdir
+
+ $(MAKE) PREFIX=$(PREFIX) ETC=$(ETC)
+
+ touch build-stamp
+
+install: build
+ dh_testdir
+ dh_testroot
+ dh_clean -k
+ dh_installdirs
+
+ $(MAKE) install PREFIX=$(FAKE)$(PREFIX) ETC=$(FAKE)$(ETC)
+
+ install -D -m 0644 debian/file/wmii.desktop $(FAKE)$(PREFIX)/share/xsessions/wmii.desktop
+ install -D -m 0644 img/icon.png $(FAKE)$(PREFIX)/share/icons/wmii.png
+
+patch:
+ set -e; \
+ if ! [ -e ${UNPATCH} ]; then \
+ patches=${PATCHES}/*.list; \
+ for i in $$patches; do \
+ files=$$(cat "$$i"); \
+ base=$${i%.list}; \
+ base=$${base##*/}; \
+ awk -f "${PATCHES}/un$$base.awk" $$files >>debian/unpatch.ed; \
+ for f in $$files; do \
+ cat <"${PATCHES}/$$base.ed"; \
+ ed $$f <"${PATCHES}/$$base.ed"; \
+ done; \
+ done; \
+ fi
+
+unpatch:
+ set -e; \
+ if [ -e ${UNPATCH} ]; then \
+ ed <${UNPATCH}; \
+ rm ${UNPATCH}; \
+ fi
+
+binary-indep: build install
+
+binary-arch: build install
+ dh_testdir
+ dh_testroot
+ dh_installchangelogs
+ dh_installdocs
+ dh_install
+ dh_installmenu
+ dh_installwm --priority=30
+ dh_link
+ $(DH_STRIP)
+ dh_compress
+ dh_fixperms
+ dh_installdeb
+ dh_shlibdeps
+ dh_gencontrol
+ dh_md5sums
+ dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install
diff --git a/debian/watch b/debian/watch
@@ -0,0 +1,2 @@
+version=3
+http://www.suckless.org/download/wmii-(.*)\.tar\.gz
diff --git a/debian/wmii.menu b/debian/wmii.menu
@@ -0,0 +1,3 @@
+?package(wmii):needs="wm" section="WindowManagers"\
+ title="wmii" longtitle="wmii pre-3.6 Development Snapshot"\
+ command="/usr/bin/wmii"
diff --git a/debian/wmii.wm b/debian/wmii.wm
@@ -0,0 +1 @@
+/usr/bin/wmii
diff --git a/img/icon.png b/img/icon.png
Binary files differ.
diff --git a/img/mkfile b/img/mkfile
@@ -0,0 +1,21 @@
+MKSHELL=rc
+path=$PLAN9/bin $path
+
+eps = wmii.eps
+
+epsbox = `{sed -n '/^%%BoundingBox:/{s/.*://p; q;}' $eps}
+iconwidth = 32
+iconscale = `{*=$epsbox; hoc -e $iconwidth/'('$3-' '$1')'}
+iconheight = `{*=$epsbox; hoc -e '('$4-' '$2')*'$iconscale}
+
+icon.png: $eps
+ x = `{hoc -e -'('$epsbox(1)^')'}
+ y = `{hoc -e -'('$epsbox(2)^')'}
+ gs -q -dBATCH -dNOPAUSE -sDEVICE=pngalpha -sOutputFile=$target -g^$iconwidth^x^$iconheight - <<!
+ $iconscale $iconscale scale
+ $x $y translate
+ ($eps) run
+ showpage
+ quit
+ !
+
diff --git a/man/Makefile b/man/Makefile
@@ -3,8 +3,7 @@ include ${ROOT}/mk/hdr.mk
TARG = wmii.1 \
wmiiloop.1 \
- wmiir.1 \
- wmiiwm.1
+ wmiir.1
FILTER = sed "s|CONFPREFIX|${ETC}|g; \
s|CONFVERSION|${CONFVERSION}|g; \
diff --git a/man/mkfile b/man/mkfile
@@ -0,0 +1,9 @@
+TARG = `{make -VTARG}
+
+default:V: all
+
+all:V: $TARG
+
+%.1: %.tex
+ latex2man -M $stem.tex $stem.1
+
diff --git a/man/wmii.1 b/man/wmii.1
@@ -1,205 +1,391 @@
-.TH WMII 1 wmii-VERSION
+'\" t
+.\" Manual page created with latex2man on Fri May 25 01:36:45 EDT 2007
+.\" NOTE: This file is generated, DO NOT EDIT.
+.de Vb
+.ft CW
+.nf
+..
+.de Ve
+.ft R
+
+.fi
+..
+.TH "WMII" "1" "25 May 2007" "" ""
.SH NAME
-wmii \(em window manager improved\(emimproved
+
+wmii\-VERSION
+.PP
.SH SYNOPSIS
-.B wmii
+
+wmii
+[\fB\-a\fP\fI<address>\fP]
+[\fB\-c\fP\fI<wmiirc>\fP]
+.br
+wmii
+\fB\-v\fP
+.PP
.SH DESCRIPTION
-.SS Overview
-.B wmii
-is a dynamic window manager for X11. See
-.BR wmiiwm (1)
-for more info.
-.SS Actions
-An action is a shell script in the default setup, but it can actually be
-any executable file. It is executed usually by selecting it from the
-actions menu.
-You can customize an action by copying it from the global action
-directory CONFPREFIX/wmii-3.5 to $HOME/.wmii-3.5 and then editing the copy to
-fit your needs. Of course you can also create your own actions there; make
-sure that they are executable.
-.P
-Here is a list of the default actions:
-.TP 2
-quit
-leave the window manager nicely
-.TP 2
-status
-periodically print date and load average to the bar
-.TP 2
-welcome
-display a welcome message that contains the wmii tutorial
-.TP 2
-wmiirc
-configure wmii
-.SS Default Key Bindings
-.PD 0
-.B Moving Around
-.RS 2
-.TP 16
-.I Key
-.I Action
-.TP
-.B Mod-h
-Move to a
-.B window
-to the
-.B left
-of the one currently focused
-.TP
-.B Mod-l
-Move to a
-.B window
-to the
-.B right
-of the one currently focused
-.TP
-.B Mod-j
-Move to a
-.B window below
-the one currently focused
-.TP
-.B Mod-k
-Move to a
-.B window above
-the one currently focused
-.TP
-.B Mod-space
-.B Toggle
-between the managed and floating
-.B layer
-.TP
-.BI Mod-t \ tag
-Move to the
-.B view
-of the given
-.I tag
-.TP
-.B Mod-[0-9]
-Move to the
-.B view
-with the given number
-.PD 1
-.P
-.RE
-.B Moving Things Around
-.RS 2
-.PD 0
-.TP 16
-.I Key
-.I Action
-.TP
-.B Mod-Shift-h
-Move the current window
-.B window
-to a column on the
-.B left
-.TP
-.B Mod-Shift-l
-Move the current window
-.B window
-to a column on the
-.B right
-.TP
-.B Mod-Shift-j
-Move the current
-.B window below
-the one beneath it
-.TP
-.B Mod-Shift-k
-Move the current
-.B window above
-the one above it
-.TP
-.B Mod-Shift-space
-.B Toggle
-the current
-.B window
-between the managed and floating
-.B layer
-.TP
-.BI Mod-Shift-t \ tag
-Move the current window to the
-.B view
-of the given
-.I tag
-.TP
-.B Mod-Shift-[0-9]
-Move to the current window to the
-.B view
-with the given number
-.PD 1
-.P
-.RE
-.B Miscellaneous
-.RS 2
-.PD 0
-.TP 16
-.I Key
-.I Action
-.TP
-.B Mod-m
-Switch the current column to
-.B max mode
-.TP
-.B Mod-s
-Switch the current column to
-.B stack mode
-.TP
-.B Mod-d
-Switch the current column to
-.B default mode
-.TP
-.B Mod-Shift-c
-.B Kill
-the selected client
-.TP
-.BI Mod-p \ program
-.B Execute
-.I program
-.TP
-.BI Mod-a \ action
-Execute the
-.B named action
-.TP
-.B Mod-Enter
-Start an
-.B xterm
-.SS Configuration
-If you feel the need to change the default configuration, then customize (as
-described above) the
-.B wmiirc
-action. This action is executed at the end of the
-.B wmii
-script and does all the work of setting up the window manager, the key
-bindings, the bar labels, etc.
+.PP
+.SS OVERVIEW
+.PP
+wmii
+is a dynamic window manager for X11. In contrast to
+static window management the user rarely has to think about how to
+organize windows, no matter what he is doing or how many
+applications are used at the same time. The window manager adapts
+to the current environment and fits to the needs of the user, rather
+than forcing him to use a preset, fixed layout and trying to
+shoehorn all windows and applications into it.
+.PP
+wmii
+supports classic and tiled window management with
+extended keyboard and mouse control. The classic window management
+arranges windows in a floating layer in which windows can be moved
+and resized freely. The tiled window management is based on columns
+which split up the screen horizontally. Each column handles
+arbitrary windows and arranges them vertically in a nonoverlapping
+way. They can then be moved and resized between and within columns
+at will.
+.PP
+wmii
+provides a virtual filesystem which represents the
+internal state similar to the procfs of Unix operating systems.
+Modifying this virtual filesystem results in changing the state of
+the window manager. The virtual filesystem service can be accessed
+through 9Pcapable client programs, like \fIwmiir\fP(1)\&.
+This
+allows simple and powerful remote control of the core window
+manager.
+.PP
+wmii
+basically consists of clients, columns, views, and the
+bar, which are described in detail in the \fBTerminology\fP
+section.
+.PP
+.SS TERMINOLOGY
+.PP
+.TP
+Display
+A running X server instance consisting of input devices
+and screens.
+.TP
+Screen
+A physical or virtual (Xinerama or \fIXnest\fP(1))
+screen
+of an X display. A screen displays a bar window and a view at a time.
+.TP
+Window
+A (rectangular) drawable X object which is displayed on a
+screen, usually an application window.
+.TP
+Client
+An application window surrounded by a frame window containing
+a border and a titlebar.
+.TP
+Floating layer
+A screen layer of wmii
+on top of all other
+layers, where clients are arranged in a classic (floating) way.
+They can be resized or moved freely.
+.TP
+Managed layer
+A screen layer of wmii
+behind the floating layer,
+where clients are arranged in a nonoverlapping (managed) way. Here,
+the window manager dynamically assigns each client a size and position.
+The managed layer consists of columns.
+.TP
+Tag
+Alphanumeric strings which can be assigned to a client. This provides
+a mechanism to group clients with similar properties. Clients can have one
+tag, e.g. \fIwork\fP,
+or several tags, e.g. \fIwork+mail\fP\&.
+.PP
+Tags are separated with the \fI+\fP
+character.
+.TP
+View
+A set of clients containing a specific tag, quite similiar to a
+workspace in other window managers. It consists of the floating and
+managed layers.
+.TP
+Column
+A column is a screen area which arranges clients vertically in a
+non\-overlapping way. Columns provide three different modes, which
+arrange clients with equal size, stacked, or maximized respectively.
+Clients can be moved and resized between and within columns freely.
+.TP
+Bar
+The bar at the bottom of the screen displays a label for each view and
+allows the creation of arbitrary userdefined labels.
+.TP
+Event
+An event is a message which can be read from a special file in the
+filesystem of wmii,
+such as a mouse button press, a key press, or
+a message written by a different 9P\-client.
+.PP
+.SS BASIC WINDOW MANAGEMENT
+.PP
+Running a raw wmii
+process without a \fIwmiirc\fP(1)
+script
+provides basic window management capabilities already. However, to
+use it effectively, remote control through its filesystem interface
+is necessary. By default it is only usable with the mouse in
+conjunction with the \fIMod1 (Alt)\fP
+modifier key. Other
+interactions, such as customizing the style, killing or retagging
+clients, and grabbing keys, cannot be achieved without accessing the
+filesystem.
+.PP
+The filesystem can be accessed by connecting to the \fIaddress\fP
+of wmii
+with any 9P\-capable client, such as \fIwmiir\fP(1)
+.PP
+.SS ACTIONS
+.PP
+An action is a shell script in the default setup, but it can
+actually be any executable file. It is executed usually by
+selecting it from the actions menu. You can customize an action by
+copying it from the global action directory
+CONFPREFIX/wmii\-3.5
+to $HOME/.wmii\-3.5
+and then
+editing the copy to fit your needs. Of course you can also create
+your own actions there; make sure that they are executable.
+.PP
+Here is a list of the default actions:
+.PP
+.TS
+tab(&) expand;
+l lS.
+T{
+quit
+T}&T{
+leave the window manager nicely
+T}
+T{
+status
+T}&T{
+periodically print date and load average to the bar
+T}
+T{
+welcome
+T}&T{
+display a welcome message that contains the wmii tutorial
+T}
+T{
+wmiirc
+T}&T{
+configure wmii
+T}
+.TE
+.PP
+.SS DEFAULT KEY BINDINGS
+.SS Moving Around
+.PP
+.TS
+tab(&) expand;
+l lS.
+T{
+\fBKey\fP
+T}&T{
+\fBAction\fP
+T}
+T{
+Mod\-h
+T}&T{
+Move to a window to the \fIleft\fP
+of the one currently
+focused
+T}
+T{
+Mod\-l
+T}&T{
+Move to a window to the \fIright\fP
+of the one currently
+focused
+T}
+T{
+Mod\-j
+T}&T{
+Move to the window \fIbelow\fP
+the one currently focused
+T}
+T{
+Mod\-k
+T}&T{
+Move to a window \fIabove\fP
+the one currently focused
+T}
+T{
+Mod\-space
+T}&T{
+Toggle between the managed and floating layers
+T}
+T{
+Mod\-t \fItag\fP
+T}&T{
+Move to the view of the given \fItag\fP
+T}
+T{
+Mod\-\fI[0\-9]\fP
+T}&T{
+Move to the view with the given number
+T}
+.TE
+.PP
+.SS Moving Things Around
+.PP
+.TS
+tab(&) expand;
+l lS.
+T{
+\fBKey\fP
+T}&T{
+\fBAction\fP
+T}
+T{
+Mod\-Shift\-h
+T}&T{
+Move the current window \fIwindow\fP
+to a
+column on the \fIleft\fP
+T}
+T{
+Mod\-Shift\-l
+T}&T{
+Move the current window to a column
+on the \fIright\fP
+T}
+T{
+Mod\-Shift\-j
+T}&T{
+Move the current window below the window
+beneath it.
+T}
+T{
+Mod\-Shift\-k
+T}&T{
+Move the current window above the window
+above it.
+T}
+T{
+Mod\-Shift\-space
+T}&T{
+Toggle the current window between the
+managed and floating layer
+T}
+T{
+Mod\-Shift\-t \fItag\fP
+T}&T{
+Move the current window to the
+view of the given \fItag\fP
+T}
+T{
+Mod\-Shift\-\fI[0\-9]\fP
+T}&T{
+Move to the current window to the
+view with the given number
+T}
+.TE
+.PP
+.SS Miscellaneous
+.PP
+.TS
+tab(&) expand;
+l lS.
+T{
+\fBKey\fP
+T}&T{
+\fBAction\fP
+T}
+T{
+Mod\-m
+T}&T{
+Switch the current column to \fImax mode\fP
+T}
+T{
+Mod\-s
+T}&T{
+Switch the current column to \fIstack mode\fP
+T}
+T{
+Mod\-d
+T}&T{
+Switch the current column to \fIdefault mode\fP
+T}
+T{
+Mod\-Shift\-c
+T}&T{
+Kill
+the selected client
+T}
+T{
+Mod\-p \fIprogram\fP
+T}&T{
+Execute
+\fIprogram\fP
+T}
+T{
+Mod\-a \fIaction\fP
+T}&T{
+Execute
+the named \fIaction\fP
+T}
+T{
+Mod\-Enter
+T}&T{
+Execute
+an xterm
+T}
+.TE
+.PP
+.SH CONFIGURATION
+
+.PP
+If you feel the need to change the default configuration, then
+customize (as described above) the wmiirc
+action. This
+action is executed at the end of the wmii
+script and does all
+the work of setting up the window manager, the key bindings, the bar
+labels, etc.
+.PP
.SH FILES
+
+.PP
.TP
-/tmp/ns.$USER.${DISPLAY%.0}/wmii
-The wmii socket file which provides a 9P service.
+/tmp/ns.USER.{DISPLAY%\&.0}/wmii
+The wmii socket file which provides a 9P service.
.TP
-CONFPREFIX/wmii-3.5
-Global action directory.
+CONFPREFIX/wmii\-3.5
+Global action directory.
.TP
-$HOME/.wmii-3.5
-User-specific action directory. Actions are first searched here.
+$HOME/.wmii\-3.5
+User\-specific action directory. Actions are first searched here.
+.PP
.SH ENVIRONMENT
+
+.PP
.TP
-HOME, DISPLAY
-See the section
-.B FILES
-above.
-.P
-The following variables are set and exported within
-.B wmii
-and thus can be used in actions:
-.TP
-WMII_ADDRESS
-Socket file of
-.BR wmiiwm (1).
-Used by
-.BR wmiir (1).
+HOME, DISPLAY
+See the section \fBFILES\fP
+above.
+.PP
+The following variables are set and exported within wmii
+and
+thus can be used in actions:
+.PP
+.TP
+WMII_ADDRESS
+Socket file of Used by \fIwmiir\fP(1)\&.
+.PP
.SH SEE ALSO
-.BR wmiiwm (1),
-.BR dmenu (1),
-.BR wmiir (1)
+
+\fIdmenu\fP(1),
+\fIwmiir\fP(1)
+.PP
+.\" NOTE: This file is generated, DO NOT EDIT.
diff --git a/man/wmii.tex b/man/wmii.tex
@@ -0,0 +1,189 @@
+\begin{Name}{1}{wmii}{Kris Maglione}{}{wmii - window manager improved, improved}
+ \Prog{wmii}-VERSION
+\end{Name}
+
+\section{SYNOPSIS}
+\Prog{wmii} \oOptArg{-a}{<address>} \oOptArg{-c}{<wmiirc>} \\
+\Prog{wmii} \Opt{-v}
+
+\section{DESCRIPTION}
+
+\subsection{Overview}
+
+\Prog{wmii} is a dynamic window manager for X11. In contrast to
+static window management the user rarely has to think about how to
+organize windows, no matter what he is doing or how many
+applications are used at the same time. The window manager adapts
+to the current environment and fits to the needs of the user, rather
+than forcing him to use a preset, fixed layout and trying to
+shoehorn all windows and applications into it.
+
+\Prog{wmii} supports classic and tiled window management with
+extended keyboard and mouse control. The classic window management
+arranges windows in a floating layer in which windows can be moved
+and resized freely. The tiled window management is based on columns
+which split up the screen horizontally. Each column handles
+arbitrary windows and arranges them vertically in a non\-overlapping
+way. They can then be moved and resized between and within columns
+at will.
+
+\Prog{wmii} provides a virtual filesystem which represents the
+internal state similar to the procfs of Unix operating systems.
+Modifying this virtual filesystem results in changing the state of
+the window manager. The virtual filesystem service can be accessed
+through 9P\-capable client programs, like \Cmd{wmiir}{1}. This
+allows simple and powerful remote control of the core window
+manager.
+
+\Prog{wmii} basically consists of clients, columns, views, and the
+bar, which are described in detail in the \textbf{Terminology}
+section.
+
+\subsection{Terminology}
+
+\begin{description}
+\item[Display] A running X server instance consisting of input devices
+ and screens.
+\item[Screen] A physical or virtual (Xinerama or \Cmd{Xnest}{1}) screen
+ of an X display. A screen displays a bar window and a view at a time.
+\item[Window] A (rectangular) drawable X object which is displayed on a
+ screen, usually an application window.
+\item[Client] An application window surrounded by a frame window containing
+ a border and a titlebar.
+\item[Floating layer] A screen layer of \Prog{wmii} on top of all other
+ layers, where clients are arranged in a classic (floating) way.
+ They can be resized or moved freely.
+\item[Managed layer] A screen layer of \Prog{wmii} behind the floating layer,
+ where clients are arranged in a non\-overlapping (managed) way. Here,
+ the window manager dynamically assigns each client a size and position.
+ The managed layer consists of columns.
+\item[Tag] Alphanumeric strings which can be assigned to a client. This provides
+ a mechanism to group clients with similar properties. Clients can have one
+ tag, e.g. \emph{work}, or several tags, e.g. \emph{work+mail}.
+
+ Tags are separated with the \emph{+} character.
+\item[View] A set of clients containing a specific tag, quite similiar to a
+ workspace in other window managers. It consists of the floating and
+ managed layers.
+\item[Column] A column is a screen area which arranges clients vertically in a
+ non-overlapping way. Columns provide three different modes, which
+ arrange clients with equal size, stacked, or maximized respectively.
+ Clients can be moved and resized between and within columns freely.
+\item[Bar] The bar at the bottom of the screen displays a label for each view and
+ allows the creation of arbitrary user\-defined labels.
+\item[Event] An event is a message which can be read from a special file in the
+ filesystem of \Prog{wmii}, such as a mouse button press, a key press, or
+ a message written by a different 9P-client.
+\end{description}
+
+\subsection{Basic window management}
+
+Running a raw \Prog{wmii} process without a \Cmd{wmiirc}{1} script
+provides basic window management capabilities already. However, to
+use it effectively, remote control through its filesystem interface
+is necessary. By default it is only usable with the mouse in
+conjunction with the \emph{Mod1 (Alt)} modifier key. Other
+interactions, such as customizing the style, killing or retagging
+clients, and grabbing keys, cannot be achieved without accessing the
+filesystem.
+
+The filesystem can be accessed by connecting to the \emph{address}
+of \Prog{wmii} with any 9P-capable client, such as \Cmd{wmiir}{1}
+
+\subsection{Actions}
+
+An action is a shell script in the default setup, but it can
+actually be any executable file. It is executed usually by
+selecting it from the actions menu. You can customize an action by
+copying it from the global action directory
+\File{CONFPREFIX/wmii-3.5} to \File{\$HOME/.wmii-3.5} and then
+editing the copy to fit your needs. Of course you can also create
+your own actions there; make sure that they are executable.
+
+Here is a list of the default actions:
+
+\begin{Table}[]{2}
+quit & leave the window manager nicely \\
+status & periodically print date and load average to the bar \\
+welcome & display a welcome message that contains the wmii tutorial \\
+wmiirc & configure wmii \\
+\end{Table}
+
+\subsection{Default Key Bindings}
+\subsubsection{Moving Around}
+\begin{Table}[]{2}
+\textbf{Key} & \textbf{Action} \\
+Mod-h & Move to a window to the \emph{left} of the one currently
+ focused \\
+Mod-l & Move to a window to the \emph{right} of the one currently
+ focused \\
+Mod-j & Move to the window \emph{below} the one currently focused \\
+Mod-k & Move to a window \emph{above} the one currently focused \\
+Mod-space & Toggle between the managed and floating layers \\
+Mod-t \emph{tag} & Move to the view of the given \emph{tag} \\
+Mod-\emph{[0-9]} & Move to the view with the given number \\
+\end{Table}
+
+\subsubsection{Moving Things Around}
+\begin{Table}[]{2}
+\textbf{Key} & \textbf{Action} \\
+Mod-Shift-h & Move the current window \emph{window} to a
+ column on the \emph{left} \\
+Mod-Shift-l & Move the current window to a column
+ on the \emph{right} \\
+Mod-Shift-j & Move the current window below the window
+ beneath it. \\
+Mod-Shift-k & Move the current window above the window
+ above it. \\
+Mod-Shift-space & Toggle the current window between the
+ managed and floating layer \\
+Mod-Shift-t \emph{tag} & Move the current window to the
+ view of the given \emph{tag} \\
+Mod-Shift-\emph{[0-9]} & Move to the current window to the
+ view with the given number \\
+\end{Table}
+
+\subsubsection{Miscellaneous}
+\begin{Table}[]{2}
+\textbf{Key} & \textbf{Action} \\
+Mod-m & Switch the current column to \emph{max mode} \\
+Mod-s & Switch the current column to \emph{stack mode} \\
+Mod-d & Switch the current column to \emph{default mode} \\
+Mod-Shift-c & \Prog{Kill} the selected client \\
+Mod-p \emph{program} & \Prog{Execute} \emph{program} \\
+Mod-a \emph{action} & \Prog{Execute} the named \emph{action} \\
+Mod-Enter & \Prog{Execute} an \Prog{xterm} \\
+\end{Table}
+
+\section{Configuration}
+
+If you feel the need to change the default configuration, then
+customize (as described above) the \Prog{wmiirc} action. This
+action is executed at the end of the \Prog{wmii} script and does all
+the work of setting up the window manager, the key bindings, the bar
+labels, etc.
+
+\section{FILES}
+
+\begin{description}
+\item[/tmp/ns.$USER.${DISPLAY\%.0}/wmii] The wmii socket file which provides a 9P service.
+\item[CONFPREFIX/wmii-3.5] Global action directory.
+\item[\$HOME/.wmii-3.5] User-specific action directory. Actions are first searched here.
+\end{description}
+
+\section{ENVIRONMENT}
+
+\begin{description}
+\item[HOME, DISPLAY] See the section \textbf{FILES} above.
+\end{description}
+
+The following variables are set and exported within \Prog{wmii} and
+thus can be used in actions:
+
+\begin{description}
+\item[WMII\_ADDRESS] Socket file of Used by \Cmd{wmiir}{1}.
+\end{description}
+
+\section{SEE ALSO}
+\Cmd{dmenu}{1}, \Cmd{wmiir}{1}
+
diff --git a/man/wmiiloop.1 b/man/wmiiloop.1
@@ -1,79 +1,75 @@
-.TH WMIIR 1 wmii\-VERSION
-.SH NAME
-wmiiloop \(em wmii event loop processor
-.SH SYNOPSIS
-.B cat
-.I events
-|
-.B wmiiloop
-|
-.B sh
-.br
-.SH DESCRIPTION
-.SS Overview
-.B wmiiloop
-is an awk script which preprocesses
-.BR sh (1)
-syntax to simplify writing a wmii event loop.
+'\" t
+.\" Manual page created with latex2man on Fri May 25 01:36:45 EDT 2007
+.\" NOTE: This file is generated, DO NOT EDIT.
+.de Vb
+.ft CW
+.nf
+..
+.de Ve
+.ft R
-.br
-.B eventloop
-sends any text up to the first line containing
-.I #
-.IR Events|Actions|Key ,
-and any text after any other line begining with
-.IR # ,
-directly to its standard output. Any other line is processed based
-on its first word, with every indented line after it taken as its
-.IR body .
-.TP 2
-.BI "Key " sequence
-The key sequence
-.I sequence
-is bound to its
-.IR body .
-.I sequence
-is written to
-.I /keys
-and
-.I body
-is executed, with
-.I $key
-set to
-.I sequence
-whenever the key is pressed.
+.fi
+..
+.TH "WMIILOOP" "1" "25 May 2007" "" ""
+.SH NAME
-.TP 2
-.BI "Event " name
-Whenever an event with
-.I name
-is read from
-.IR /event ,
-.I body
-is executed, with
-.I $event
-set to
-.IR name ,
-and
-.I $[1\-9]
-set to further arguments.
+wmiiloop\-VERSION
+.PP
+.SH SYNOPSIS
-.TP 2
-.BI "Action " name
-A function called
-.BI Action_ name
-is created with
-.I body
-as its body, and
-.I name
-is added to the
-.I $ACTIONS
-variable.
+eval
+"$(wmiiloop
+<events)"
+.PP
+.SH DESCRIPTION
+.PP
+wmiiloop
+is an awk and sh script which preprocesses \fIsh\fP(1)
+syntax
+to simplify writing a wmii event loop.
+.PP
+wmiiloop
+associates lines begining with \fIEvent\fP,
+\fIAction\fP,
+or
+\fIKey\fP
+(henceforth known as \fB$keyword\fP),
+followed by arbitrary
+text (henceforth known as \fB$args\fP),
+with functions which call any
+indented lines which follow. In the function names, all non\-alphanumeric
+characters in \fB$args\fP
+are replaced with underscores (_). The
+functions are named \fB$keyword\fP\&'_\&'\fB$args\fP\&.
+.PP
+Any variables in the unintented lines are interpolated by the shell.
+.PP
+Additionally, each declaration\&'s \fB$args\fP
+are assigned to a variable
+named \fB$keyword\fP\&'s\&'\&.
+In this case, no transliteration occurs. For
+instance, the following declaration:
+.PP
+.Vb
+Key $MODKEY\-j
+ echo Got $@
+.Ve
+yields (assuming \fI$MODKEY\fP
+is set to \fIMod1\fP):
+.PP
+.Vb
+Keys=" $Keys Mod1\-j"
+Mod1_j() {
+ echo Got $@
+}
+.Ve
+.PP
.SH SEE ALSO
-.BR wmii (1),
-.BR wmiir (1),
-.BR wmiiwm (1)
-.B PREFIX/etc/wmiirc
-http://www.cs.bell\-labs.com/sys/man/5/INDEX.html
+\fIwmii\fP(1),
+\fIwmii\fP(1)\&.
+\fIwmiir\fP(1),
+PREFX/etc/wmiirc
+.PP
+.\" NOTE: This file is generated, DO NOT EDIT.
diff --git a/man/wmiiloop.tex b/man/wmiiloop.tex
@@ -0,0 +1,42 @@
+\begin{Name}{1}{wmiiloop}{Kris Maglione}{}{wmiir}
+ \Prog{wmiiloop}-VERSION
+\end{Name}
+
+\section{Synopsis}
+\Prog{eval} "\$(\Prog{wmiiloop} <\File{events})"
+
+\section{Description}
+
+\Prog{wmiiloop} is an awk and sh script which preprocesses \Cmd{sh}{1} syntax
+to simplify writing a wmii event loop.
+
+\Prog{wmiiloop} associates lines begining with \emph{Event}, \emph{Action}, or
+\emph{Key} (henceforth known as \textbf{\$keyword}), followed by arbitrary
+text (henceforth known as \textbf{\$args}), with functions which call any
+indented lines which follow. In the function names, all non-alphanumeric
+characters in \textbf{\$args} are replaced with underscores (\_). The
+functions are named \textbf{\$keyword}'_'\textbf{\$args}.
+
+Any variables in the unintented lines are interpolated by the shell.
+
+Additionally, each declaration's \textbf{\$args} are assigned to a variable
+named \textbf{\$keyword}'s'. In this case, no transliteration occurs. For
+instance, the following declaration:
+
+\begin{verbatim}
+Key $MODKEY-j
+ echo Got $@
+\end{verbatim}
+yields (assuming \emph{\$MODKEY} is set to \emph{Mod1}):
+
+\begin{verbatim}
+Keys=" $Keys Mod1-j"
+Mod1_j() {
+ echo Got $@
+}
+\end{verbatim}
+
+\section{SEE ALSO}
+\Cmd{wmii}{1}, \Cmd{wmii}{1}. \Cmd{wmiir}{1},
+\File{PREFX/etc/wmiirc}
+
diff --git a/man/wmiiwm.1 b/man/wmiiwm.1
@@ -1,150 +0,0 @@
-.TH WMIIWM 1 wmii-VERSION
-.SH NAME
-wmiiwm \(em window manager improved\(emimproved (core)
-.SH SYNOPSIS
-.B wmiiwm
-.B \-a
-.I <address>
-.RB [ \-c ]
-.RB [ \-v ]
-.SH DESCRIPTION
-
-.PD 0
-.SS Overview
-.BR wmiiwm (1)
-is the core of window manager improved\(emimproved.
-.P
-.B wmii
-is a dynamic window manager for X11. In contrast to static window management
-the user rarely has to think about how to organize windows, no matter what he
-is doing or how many applications are used at the same time. The window manager
-adapts to the current environment and fits to the needs of the user, rather
-than forcing him to use a preset, fixed layout and trying to shoehorn all
-windows and applications into it.
-.P
-.B wmii
-supports classic and tiled window management with extended keyboard and mouse
-control. The classic window management arranges windows in a floating layer
-in which windows can be moved and resized freely. The tiled window management
-is based on columns which split up the screen horizontally. Each column handles
-arbitrary windows and arranges them vertically in a non\-overlapping way. They
-can then be moved and resized between and within columns at will.
-.P
-.B wmii
-provides a virtual filesystem which represents the internal state similar to
-the procfs of Unix operating systems. Modifying this virtual filesystem results
-in changing the state of the window manager. The virtual filesystem service can
-be accessed through 9P\-capable client programs, like
-.BR wmiir (1) .
-This allows simple and powerful remote control of the core window manager.
-.P
-.B wmii
-basically consists of clients, columns, views, and the bar, which are described
-in detail in the
-.B Terminology
-section.
-.SS Options
-.TP
-.BI \-a " address"
-Lets you specify the address which
-.B wmiiwm
-uses to listen for connections. The syntax for
-.I address
-is taken (along with many other profound ideas) from the Plan 9 operating
-system and has the form
-.B unix!/path/to/socket
-for unix socket files, and
-.B tcp!hostname!port
-for tcp sockets.
-.TP
-.B \-c
-Checks if another window manager is running. If not it exits with termination code
-0.
-.TP
-.B \-v
-Prints version information to stdout, then exits.
-.SS Terminology
-.TP 2
-Display
-A running X server instance consisting of input devices and screens.
-.TP 2
-Screen
-A physical or virtual (Xinerama or
-.BR Xnest (1))
-screen of an X display. A screen displays a bar window and a view at a time.
-.TP 2
-Window
-A (rectangular) drawable X object which is displayed on a screen, usually an
-application window.
-.TP 2
-Client
-An application window surrounded by a frame window containing a border and a
-title\-bar.
-.TP 2
-Floating layer
-A screen layer of
-.B wmii
-on top of all other layers, where clients are arranged in a classic (floating)
-way. They can be resized or moved freely.
-.TP 2
-Managed layer
-A screen layer of
-.B wmii
-behind the floating layer, where clients are arranged in a non\-overlapping
-(managed) way. Here, the window manager dynamically assigns each client a
-size and position. The managed layer consists of columns.
-.TP 2
-Tag
-Alphanumeric strings which can be assigned to a client. This provides a
-mechanism to group clients with similar properties. Clients can have one
-tag, e.g.
-.IR work ,
-or several tags, e.g.
-.IR work+mail .
-Tags are separated with the
-.I +
-character.
-.TP 2
-View
-A set of clients containing a specific tag, quite similiar to a workspace in
-other window managers. It consists of the floating and managed layers.
-.TP 2
-Column
-A column is a screen area which arranges clients vertically in a
-non\-overlapping way. Columns provide three different modes, which arrange
-clients with equal size, stacked, or maximized respectively. Clients can be
-moved and resized between and within columns freely.
-.TP 2
-Bar
-The bar at the bottom of the screen displays a label for each view and
-allows the creation of arbitrary user\-defined labels.
-.TP 2
-Event
-An event is a message which can be read from a special file in the filesystem
-of
-.BR wmiiwm ,
-such as a mouse button press, a key press, or a message written by a different
-9P\-client.
-.SS Basic window management
-Running a raw
-.B wmiiwm
-process without the
-.BR wmii (1)
-script provides basic window management capabilities already. However to use
-it effectively, remote control through its filesystem interface is necessary.
-By default it is only usable with the mouse in conjunction with the
-.I Mod1 (Alt)
-modifier key. Other interactions like customizing the style, killing or
-retagging clients, or grabbing keys cannot be achieved without accessing the
-filesystem.
-.P
-The filesystem can be accessed by connecting to the
-.I address
-of
-.B wmiiwm
-with any 9P\-capable client, like
-.BR wmiir (1).
-.SH SEE ALSO
-.BR wmii (1),
-.BR dmenu (1),
-.BR wmiir (1)
diff --git a/mk/common.mk b/mk/common.mk
@@ -1,7 +1,6 @@
all:
install: all
-depend: cleandep
MANDIRS=${MAN}/man1
mkdirs:
@@ -11,6 +10,11 @@ mkdirs:
done
cleandep:
+ echo CLEANDEP
rm .depend 2>/dev/null || true
+DEP:=${shell if test -f .depend;then echo .depend;else echo /dev/null; fi}
+DEP!=echo /dev/null
+include ${DEP}
+
.PHONY: all options clean dist install uninstall depend cleandep
diff --git a/mk/gcc.mk b/mk/gcc.mk
@@ -0,0 +1,17 @@
+CFLAGS += \
+ -std=gnu99 \
+ -pipe \
+ -Wall \
+ -Wno-parentheses \
+ -Wno-missing-braces \
+ -Wno-switch \
+ -Wno-comment \
+ -Wno-sign-compare \
+ -Wno-uninitialized \
+ -Wno-unused-parameter \
+ -Wimplicit \
+ -Wreturn-type \
+ -Wtrigraphs \
+ -Wstrict-prototypes \
+ -Wmissing-prototypes \
+ -Wpointer-arith \
diff --git a/mk/hdr.mk b/mk/hdr.mk
@@ -3,7 +3,8 @@
all:
.c.depend:
- ${DEPEND} $< >>.depend
+ echo MKDEP $<
+ ${MKDEP} ${FULLCFLAGS} $< >>.depend
.c.o:
${COMPILE} $@ $<
@@ -63,18 +64,21 @@ all:
rm -f ${MAN}/man1/$<
.O.clean:
- rm $< || true 2>/dev/null
- rm $*.o || true 2>/dev/null
+ rm -f $< || true 2>/dev/null
+ rm -f $*.o || true 2>/dev/null
.o.clean:
- rm $< || true 2>/dev/null
+ rm -f $< || true 2>/dev/null
printinstall:
mkdirs:
clean:
install: printinstall mkdirs
+depend: cleandep
FILTER = cat
-COMPILE= CC="${CC}" CFLAGS="${CFLAGS} ${EXCFLAGS}" ${ROOT}/util/compile
-LINK= LD="${LD}" LDFLAGS="${LDFLAGS} ${EXLDFLAGS}" ${ROOT}/util/link
+COMPILE= CC="${CC}" CFLAGS="${CFLAGS}" ${ROOT}/util/compile
+LINK= LD="${LD}" LDFLAGS="${LDFLAGS}" ${ROOT}/util/link
include ${ROOT}/config.mk
+CFLAGS += -I$$(echo ${INCPATH}|sed 's/:/ -I/g')
+
diff --git a/mk/lib.mk b/mk/lib.mk
@@ -10,7 +10,7 @@ depend: ${OBJ:=.depend}
libclean:
for i in ${LIB} ${OFILES}; do \
- rm $$i; \
+ rm -f $$i; \
done 2>/dev/null || true
printinstall:
@@ -20,5 +20,6 @@ printinstall:
${LIB}: ${OFILES}
@echo AR $@
@${AR} $@ ${OFILES}
+ @${RANLIB} $@
include ${ROOT}/mk/common.mk
diff --git a/mk/many.mk b/mk/many.mk
@@ -12,7 +12,7 @@ printinstall:
manyclean:
for i in ${TARG:=.o} ${TARG:=.O} ${OFILES}; do \
- rm $$i; \
+ rm -f $$i; \
done 2>/dev/null || true
include ${ROOT}/mk/common.mk
diff --git a/mk/one.mk b/mk/one.mk
@@ -14,7 +14,7 @@ printinstall:
oneclean:
for i in ${PROG} ${OFILES}; do \
- rm $$i; \
+ rm -f $$i; \
done 2>/dev/null || true
${OFILES}: ${HFILES}
diff --git a/rc/rc.wmii.rc b/rc/rc.wmii.rc
@@ -10,7 +10,7 @@ DOWN=j
LEFT=h
RIGHT=l
-WMII_FONT='fixed'
+WMII_FONT='-*-fixed-medium-r-*-*-13-*-*-*-*-*-*-*'
WMII_NORMCOLORS=('#222222' '#5FBF77' '#2A7F3F')
WMII_FOCUSCOLORS=('#ffffff' '#153F1F' '#2A7F3F')
WMII_BACKGROUND='#333333'
@@ -74,7 +74,6 @@ fn status {
echo -n `{uptime | sed 's/.*://; s/,//g'} '|' `{date}
}
-# View Titles
fn viewtitle { echo $* }
# Events
@@ -101,10 +100,12 @@ menulast = ''
fn Event-ClientMouseDown {
client = $1; button = $2
if(~ $button 3) {
- do=`{9menu -initial $menulast Nop Delete}
+ do=`{9menu -initial $menulast Nop Delete Fullscreen}
switch($do) {
case Delete
wmiir xwrite /client/$client/ctl kill
+ case Fullscreen
+ wmiir xwrite /client/$client/ctl Fullscreen
}
if(! ~ $#do 0)
menulast = $do;
diff --git a/rc/sh.wmii b/rc/sh.wmii
@@ -0,0 +1,243 @@
+#!sh
+# WMII Configuration
+load std
+load string
+load regex
+
+mount -Aa {os dial unix!/tmp/ns.kris.:1/wmii >[1=0]} / || exit
+#mount -Aa {os rc -c 'dial $WMII_ADDRESS' >[1=0]} /
+
+MODKEY=Mod1
+UP=k
+DOWN=j
+LEFT=h
+RIGHT=l
+
+WMII_FONT=fixed
+WMII_NORMCOLORS=('#222222' '#5FBF77' '#2A7F3F')
+WMII_FOCUSCOLORS=('#ffffff' '#153F1F' '#2A7F3F')
+WMII_BACKGROUND='#333333'
+
+WMII_TERM=urxvt
+
+fn wmiimenu {
+ run_command ${re sg '#' '"#"' (dmenu -b -fn $WMII_FONT
+ -nf ${hd $WMII_NORMCOLORS} -nb ${index 2 $WMII_NORMCOLORS}
+ -sf ${hd $WMII_FOCUSCOLORS} -sb ${index 2 $WMII_FOCUSCOLORS})}
+}
+
+fn 9menu {
+ run_command (wmii9menu -font $WMII_FONT
+ -^(nf nb br)^$WMII_NORMCOLORS
+ -^(sf sb br)^$WMII_FOCUSCOLORS $*)
+}
+
+# Column Rules
+echo '/./ -> 60+40' >/colrules
+
+# Tagging Rules
+{ echo '/Firefox/ -> www
+/XMMS.*/ -> ~
+/MPlayer.*/ -> ~
+/.*/ -> !
+/.*/ -> 1
+' } >/tagrules
+
+subfn seq {
+ arg := $*
+ result=`{os seq $arg}
+}
+
+subfn hostenv {
+ arg := $"*
+ result="{os sh -c ${quote eval echo -n '$'$arg}}
+}
+
+# Status Bar Info
+fn status {
+ echo ${re mg '[0-9]+\.[0-9]+' "{os uptime}} '|' `{date}
+}
+
+# Events
+fn Event-Start {
+ if { ~ $1 wmiirc } {
+ rm -f $progs_file
+ exit
+ }
+}
+
+fn Event-Key {
+ echo Key-$1
+ Key-$1 $1
+}
+
+fn Event-CreateTag { echo $WMII_NORMCOLORS $* >> /lbar/$"* }
+fn Event-DestroyTag { rm /lbar/$"* }
+fn Event-FocusTag { echo $WMII_FOCUSCOLORS $* > /lbar/$"* }
+fn Event-UnfocusTag { echo $WMII_NORMCOLORS $* > /lbar/$"* }
+fn Event-UrgentTag { echo '*'${tl $*} > ${quote /lbar/${tl $*} } }
+fn Event-NotUrgentTag { echo ${tl $*} > ${quote /lbar/${tl $*} } }
+
+fn Event-LeftBarClick { echo view ${tl $*} >/ctl }
+lastcmd=''
+fn Event-ClientMouseDown {
+ (client button) := $*
+ if { ~ $button 3 } {
+ lastcmd = `{9menu -initial $lastcmd Nop Delete}
+ cmp := {~ $do $1}
+ or {and {$cmp Nop} {echo Do nothing}
+ } {and {$cmp Delete} {echo kill >/client/$client/ctl}}
+ }
+}
+
+# Actions
+fn Action {
+ (action args) := $*
+ if {whatis Action-$action | grep -s '^load std; fn '} {
+ Action-$action $args
+ } {
+ run_command ${config_whatis $action} $args </dev/null
+ }
+}
+fn Action-quit { echo quit >>/ctl }
+fn Action-rehash {
+ flag x -
+ proglist ${hostenv PATH} >$progs_file
+}
+fn Action-status {
+ if {rm /rbar/status >[2]/dev/null} {
+ sleep 2
+ }
+ echo $WMII_NORMCOLORS >/rbar/status
+ while {status >/rbar/status} {
+ sleep 1
+ }
+}
+
+# Key Bindings
+fn Key-$MODKEY-Control-t {
+ if { ~ `{wc -l /keys} 0 1} {
+ initkeys
+ grabmod $MODKEY >/ctl
+ } {
+ echo $MODKEY-Control-t >/keys
+ echo grabmod Mod3 >/ctl
+ }
+}
+
+fn Key-$MODKEY-$LEFT { echo select left >/tag/sel/ctl }
+fn Key-$MODKEY-$RIGHT { echo select right >/tag/sel/ctl }
+fn Key-$MODKEY-$DOWN { echo select down >/tag/sel/ctl }
+fn Key-$MODKEY-$UP { echo select up >/tag/sel/ctl }
+
+fn Key-$MODKEY-Shift-$LEFT { echo send sel left >/tag/sel/ctl }
+fn Key-$MODKEY-Shift-$RIGHT { echo send sel right >/tag/sel/ctl }
+fn Key-$MODKEY-Shift-$DOWN { echo send sel down >/tag/sel/ctl }
+fn Key-$MODKEY-Shift-$UP { echo send sel up >/tag/sel/ctl }
+
+fn Key-$MODKEY-space { echo select toggle >/tag/sel/ctl }
+fn Key-$MODKEY-Shift-space { echo send sel toggle >/tag/sel/ctl }
+
+fn Key-$MODKEY-d { echo colmode sel default >/tag/sel/ctl }
+fn Key-$MODKEY-s { echo colmode sel stack >/tag/sel/ctl }
+fn Key-$MODKEY-m { echo colmode sel max >/tag/sel/ctl }
+
+fn Key-$MODKEY-Shift-c { echo kill >/client/sel/ctl }
+
+fn Key-$MODKEY-a { Action `{actionlist | wmiimenu} & }
+fn Key-$MODKEY-p { run_command `{wmiimenu <$progs_file} </dev/null & }
+fn Key-$MODKEY-Return { run_command $WMII_TERM & }
+fn Key-$MODKEY-t { echo view `{read_tags | wmiimenu} >/ctl & }
+fn Key-$MODKEY-Shift-t {
+ sel := "{cat /client/sel/ctl}
+ read_tags | wmiimenu >/client/$sel/tags
+}
+
+for(i in ${seq 0 9}) {
+ fn Key-$MODKEY-$i { echo view ${tl ${splitr $1 -}} >/ctl }
+ fn Key-Shift-$MODKEY-$i { echo ${tl ${splitr $1 -}} >/client/sel/tags}
+}
+
+# Functions
+fn proglist {
+ apply {ls -lp $*} /n/local^${split : $"*} |
+ grep '^[^d][^ ]*x' |
+ getlines {
+ echo ${index 10 ${split ' ' $line}}
+ } | sort | uniq
+}
+
+fn getfuns {
+ ls -p /env | grep '^fn-' ^ $1 ^ '-' | getlines {
+ echo ${re s '^fn-[^-]+-' '' $line}
+ }
+}
+
+fn actionlist {
+ { rescue '*' {} {
+ proglist ${hostenv WMII_CONFPATH}
+ }
+ getfuns Action
+ } | sort | uniq
+}
+
+fn initkeys {
+ getfuns Key >/keys
+}
+
+fn read_tags {
+ ls -p /tag | grep -v '^sel$'
+}
+
+subfn config_whatis {
+ result="{os sh -c ${quote eval PATH'='${hostenv WMII_CONFPATH} which $*}}
+}
+
+fn run_command {
+ @{ pctl newpgrp
+ vars := 'DISPLAY=:1' 'PATH=/home/kris/wmiiinst/bin:$PATH'
+ os sh -c ${quote eval $vars $*}
+ } $*
+}
+
+# WM Configuration
+{
+ echo grabmod $MODKEY
+ echo border 2
+ echo font $WMII_FONT
+ echo focuscolors $WMII_FOCUSCOLORS
+ echo normcolors $WMII_NORMCOLORS
+} >/ctl
+
+# Misc Setup
+os xsetroot -solid $WMII_BACKGROUND
+Action status &
+progs_file=/tmp/proglist.${pid}
+Action rehash &
+
+# Tag Bar Setup
+seltag="{cat /tag/sel/ctl}
+comm -2 ${pipe read_tags} ${pipe ls -p /lbar/*} | getlines {
+ rm /lbar/$line
+}
+read_tags | getlines {
+ if {~ $line $seltag} {
+ echo $WMII_FOCUSCOLORS $line >/lbar/$line
+ } {
+ echo $WMII_NORMCOLORS $line >/lbar/$line
+ }
+}
+
+# Keygrab Setup
+initkeys
+
+echo Start wmiirc >/event
+
+# Event Loop
+getlines {
+ (event args) := ${split ' ' $line}
+ echo Event-$event: $args
+ rescue '*' { echo Exception: $exception } {
+ Event-$event $args
+ }
+} </event
diff --git a/rc/wmiirc.sh b/rc/wmiirc.sh
@@ -72,6 +72,8 @@ eventstuff() {
# Actions
Action quit
wmiir xwrite /ctl quit
+ Action exec
+ wmiir xwrite /ctl exec "$@"
Action rehash
proglist $PATH >$progsfile
Action status
@@ -162,8 +164,13 @@ grabmod $MODKEY
border 1
EOF
+export WMII_MENU WMII_9MENU WMII_FONT WMII_TERM
+export WMII_FOCUSCOLORS WMII_SELCOLORS WMII_NORMCOLORS
+
# Feed events to `wmiiloop' for processing
-eval "$(eventstuff | sed 's/^[ ]//' | wmiiloop)"
+eval "$(eventstuff | sed 's/^[ ]//' | { . wmiiloop; })"
+
+echo "$Keys" | tr ' ' '\n' | wmiir write /keys
# Functions
Action() {
@@ -188,9 +195,6 @@ proglist $PATH >$progsfile &
xsetroot -solid "$WMII_BACKGROUND" &
-export WMII_MENU WMII_9MENU WMII_FONT WMII_TERM
-export WMII_FOCUSCOLORS WMII_SELCOLORS WMII_NORMCOLORS
-
# Setup Tag Bar
seltag="$(wmiir read /tag/sel/ctl 2>/dev/null)"
wmiir ls /lbar |
diff --git a/util/genconfig b/util/genconfig
@@ -0,0 +1,125 @@
+#!/bin/sh -f
+
+CONFIG="$ROOT/config.mk"
+CONFSTR='# Generated by "make config"'
+
+#XXX Ignores lines ending in \
+parseconfig() {
+ cat <<!
+ /^$CONFSTR/ {exit}
+ /^( *#| )/ {next}
+!
+ cat <<'!'
+ /=/ {
+ gsub(/'/, "'\"'\"'")
+ sub(/[ ]*=[ ]*/, "='")
+ print $0"'"
+ sub(/=.*/, "")
+ print $0"_orig=\"$"$0"\""
+ }
+!
+}
+
+findinc() {
+ var="$1"; file="$2"; shift 2
+ for d in "$@"; do
+ if [ -d "$d" -a -f "$d/$file" ]; then
+ eval "$var=\"-I$d\""; break; fi
+ done
+}
+findlib() {
+ var="$1"; lib="$2"; shift 2
+ for d in "$@"; do
+ if [ -d "$d" -a -f "$d/$lib.so" -o -f "$d/lib$lib.a" ]; then
+ eval "$var=\"-L$d -l$lib\""; break; fi
+ done
+}
+
+prompt() {
+ var=$1; shift
+ eval "def=\$$var; orig=\$${var}_orig"
+
+ unset val
+ if [ -z "$def" -o -n "$force" ]; then
+ echo "$@"
+ read -p "$var[$def]= " val
+ echo
+ fi
+
+ if [ -z "$val" ]; then
+ val="$def"; fi
+ if [ "$val" != "$orig" ]; then
+ CFG="$CFG
+$var=$val"; fi
+}
+
+eval "$(awk "`parseconfig`" <"$CONFIG")"
+CFG="$(sed -n "/^$CONFSTR/q; p" "$CONFIG"; echo "$CONFSTR")"
+
+cat <<!
+Configuring for the wmii build.
+
+You'll be prompted for a number of settings which wmii needs to build,
+install, and run properly. In most cases, the defaults will be sufficient,
+in which case, you may simply press return to accept them.
+
+!
+
+# Guess...
+AWKPATH=`which awk`
+
+prompt AWKPATH "Full path to your system's 'awk' program"
+prompt PLAN9 "Path of a Plan 9 Port or 9base installation"
+
+force=1
+prompt PREFIX Installation prefix
+
+echo "Compilation details (if you don't understand these, just leave the defaults)"
+prompt CC C object compiler
+prompt LD 'Linker (this should normally not be "ld")'
+
+prompt INCPATH Search path for include files
+prompt LIBS Libraries to be linked with every executable
+
+prompt CFLAGS Flags for the C compiler
+prompt LDFLAGS Flags for the linker
+prompt STATIC Extra linker flags to produce a static executable
+unset force
+
+# Make some guesses
+
+#for i in LIBX11 LIBICONV LIBIXP INCX11; do
+# eval "unset $i ${i}_orig"; done
+
+libs="$LIBDIR:$(echo "$INCPATH"|sed 's,/include\(:\|$\),/lib\1,g')"
+libs="$libs$(echo "$LDFLAGS"|sed 's,-L\([^ ]*\),:\1,g')"
+libs="$libs:/usr/local/lib:/opt/local/lib"
+eval "libs=\"$libs\""
+LIBIXP=${LIBIXP%/libixp.a}
+INCPATH="$INCPATH:/usr/local/include:/opt/local/include"
+
+oifs="$IFS"
+IFS=:
+findinc INCX11 X11/Xlib.h $INCPATH /usr/X11R6/include /usr/x11/include /usr/x11/include /usr/X11/include \
+ /usr/openwin/include /opt/x11/include /opt/X11/include
+findinc INCICONV iconv.h $INCPATH
+
+findlib LIBX11 X11 $libs /usr/X11R6/lib /usr/X11/lib /usr/openwin/lib /usr/x11/lib /opt/X11 /opt/x11 \
+ /usr/local/lib /opt/local/lib
+findlib LIBICONV iconv $libs
+findlib LIBIXP ixp ${ROOT}/libixp $libs
+LIBIXP=$(echo "$LIBIXP"|sed 's,^-L\([^ ]*\) -l\([^ ]*\)$,\1/lib\2.a,')
+IFS="$oifs"
+
+# Back to prompting
+echo Library paths...
+prompt INCX11 Compiler flags to find X11 includes
+prompt LIBX11 Linker flags to link against libX11
+prompt LIBICONV Linker flags to link agains libiconv '(may be left blank if iconv is part of your system libc)'
+prompt INCICONV Compiler flags to find iconv.h
+prompt LIBIXP Path to libixp.a
+
+echo Writing config.mk
+echo "$CFG
+" >config.mk
+echo Done.