wmii

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

commit d0a06fe945e8f0f424430ab370e2385ad9297afb
parent afe6a9b863d94d2ba854522ef4f4f62264dcea0a
Author: Kris Maglione <jg@suckless.org>
Date:   Thu, 31 May 2007 21:05:59 -0400

Merge with wmii-test.

Diffstat:
.hgsigs | 2++
Makefile | 5++++-
README | 30+++++++++++++++---------------
TODO | 8+++-----
cmd/Makefile | 3++-
cmd/util.c | 2+-
cmd/wmii/Makefile | 22+++++++++++++---------
cmd/wmii/area.c | 319+++++++++++++++++++++++++++++++++++--------------------------------------------
cmd/wmii/bar.c | 184+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
cmd/wmii/client.c | 1129++++++++++++++++++++++++++++++++++++++++---------------------------------------
cmd/wmii/column.c | 477++++++++++++++++++++++++++++++++++++++-----------------------------------------
cmd/wmii/dat.h | 155+++++++++++++++++++++++++++++++++++--------------------------------------------
cmd/wmii/draw.c | 244-------------------------------------------------------------------------------
cmd/wmii/event.c | 348++++++++++++++++++++++++-------------------------------------------------------
cmd/wmii/fns.h | 223++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
cmd/wmii/frame.c | 565+++++++++++++++++++++++++++++++++++++++++++------------------------------------
cmd/wmii/fs.c | 298++++++++++++++++++++++++++++---------------------------------------------------
cmd/wmii/geom.c | 63++++++++++++++++++++-------------------------------------------
cmd/wmii/key.c | 62+++++++++++++++++++++++++++++++-------------------------------
cmd/wmii/main.c | 253+++++++++++++++++++++++++++++++++----------------------------------------------
cmd/wmii/map.c | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/wmii/message.c | 583+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/wmii/mouse.c | 1086++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
cmd/wmii/printevent.c | 1493++++++++++++++++++++++++++++++++++++++++---------------------------------------
cmd/wmii/printevent.h | 1-
cmd/wmii/utf.c | 399+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/wmii/utf.h | 9+++++++++
cmd/wmii/view.c | 284++++++++++++++++++++++++++++++++-----------------------------------------------
cmd/wmii/x11.c | 790+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/wmii/x11.h | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/wmii9menu.c | 22+++++++++++-----------
cmd/wmii9rc.sh | 5+++--
cmd/wmiiloop.sh | 10++--------
cmd/wmiir.c | 14++++++++------
config.mk | 16++++++++--------
debian/changelog | 6++++++
debian/control | 25+++++++++++++++++++++++++
debian/copyright | 279+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
debian/docs | 1+
debian/file/wmii.desktop | 7+++++++
debian/patches/unx-terminal-emulater.awk | 9+++++++++
debian/patches/x-terminal-emulater.ed | 3+++
debian/patches/x-terminal-emulater.list | 3+++
debian/rules | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
debian/watch | 2++
debian/wmii.menu | 3+++
debian/wmii.wm | 1+
img/icon.png | 0
img/mkfile | 21+++++++++++++++++++++
man/Makefile | 3+--
man/mkfile | 9+++++++++
man/wmii.1 | 574++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
man/wmii.tex | 189+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
man/wmiiloop.1 | 142++++++++++++++++++++++++++++++++++++++-----------------------------------------
man/wmiiloop.tex | 42++++++++++++++++++++++++++++++++++++++++++
man/wmiiwm.1 | 150-------------------------------------------------------------------------------
mk/common.mk | 6+++++-
mk/gcc.mk | 17+++++++++++++++++
mk/hdr.mk | 16++++++++++------
mk/lib.mk | 3++-
mk/many.mk | 2+-
mk/one.mk | 2+-
rc/rc.wmii.rc | 7++++---
rc/sh.wmii | 243+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
rc/wmiirc.sh | 12++++++++----
util/genconfig | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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(&reg, "^#[0-9a-f]{6} #[0-9a-f]{6} #[0-9a-f]{6}", - REG_EXTENDED|REG_NOSUB|REG_ICASE); - } - - if(*buflen < 23 || regexec(&reg, *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(&reg, "^#[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(&reg, 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.