wmii

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

commit 967912b82bf32710b07b1f49937075c73306e95a
parent f6c2a49d34a1bb0b74fee7f0805182f8f9b5fd9c
Author: Kris Maglione <jg@suckless.org>
Date:   Fri, 18 Jan 2008 15:57:54 -0500

Merge.

Diffstat:
Makefile | 13+++++++------
cmd/Makefile | 40++++++++++++++++++++++++----------------
cmd/util.c | 15+++++++++++++++
cmd/wihack.sh | 43+++++++++++++++++++++++++++++++++++++++++++
cmd/wmii.rc.rc | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/wmii/Makefile | 22++++++++++++----------
cmd/wmii/area.c | 152+++++++++++++++++++++++++++++++++++++++++--------------------------------------
cmd/wmii/bar.c | 47+++++++++++++++++++++++------------------------
cmd/wmii/client.c | 443++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
cmd/wmii/column.c | 71++++++++++++++++++++++++++++++++++-------------------------------------
cmd/wmii/dat.h | 316+++++++++++++++++++++++++++++++++++++++++++------------------------------------
cmd/wmii/event.c | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
cmd/wmii/ewmh.c | 500+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/wmii/fns.h | 297++++++++++++++++++++++++++++++++++++-------------------------------------------
cmd/wmii/frame.c | 179+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
cmd/wmii/fs.c | 55+++++++++++++++++++++++++++----------------------------
cmd/wmii/geom.c | 8++++----
cmd/wmii/key.c | 114++++++++++++++++++++++++++++++++++++++++++-------------------------------------
cmd/wmii/main.c | 55++++++++++++++++++++-----------------------------------
cmd/wmii/map.c | 26++++++++++++--------------
cmd/wmii/message.c | 547+++++++++++++++++++++++++++++++++++++++++--------------------------------------
cmd/wmii/mouse.c | 148+++++++++++++++++++++++++++++++++++++++++--------------------------------------
cmd/wmii/printevent.c | 2--
cmd/wmii/rule.c | 7++-----
cmd/wmii/utf.c | 14++++++++++++--
cmd/wmii/view.c | 246++++++++++++++++++++++++++++++++++++-------------------------------------------
cmd/wmii/x11.c | 196++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
cmd/wmii/x11.h | 121-------------------------------------------------------------------------------
cmd/wmii9rc.sh | 4++--
cmd/wmiir.c | 2+-
config.mk | 43+++++++++++++++++++++++--------------------
include/util.h | 4++++
include/x11.h | 231+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
libfmt/fmtvprint.c | 2+-
libwmii_hack/Makefile | 14++++++++++++++
libwmii_hack/hack.c | 132+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
libwmii_hack/hack.h | 28++++++++++++++++++++++++++++
libwmii_hack/util.c | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
libwmii_hack/x11.c | 193+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
libwmii_hack/x11.h | 18++++++++++++++++++
man/Makefile | 1+
mk/common.mk | 6+++---
mk/dir.mk | 16++++++++--------
mk/gcc.mk | 8++++++--
mk/hdr.mk | 78+++++++++++++++++++++++++++++++++++++++++++-----------------------------------
mk/lib.mk | 27++++++++++++++++-----------
mk/man.mk | 3+--
mk/many.mk | 8+++-----
mk/one.mk | 19+++++++++----------
mk/so.mk | 27+++++++++++++++++++++++++++
rc/rc.wmii.rc | 206+++++++++++++++++++++++++++++--------------------------------------------------
rc/sh.wmii | 6+++---
rc/wmiirc.sh | 8+++++---
util/compile | 41++++++++++++++++++++++++++++++++++++++++-
util/genconfig | 17+++++++++++++----
util/link | 2+-
56 files changed, 3364 insertions(+), 1759 deletions(-)

diff --git a/Makefile b/Makefile @@ -2,15 +2,16 @@ ROOT=. include ${ROOT}/mk/hdr.mk PDIRS = \ - cmd \ - rc \ + cmd \ + libwmii_hack \ + rc \ man DIRS = \ - libutf \ - libfmt \ - libbio \ - libregexp\ + libbio \ + libfmt \ + libregexp \ + libutf \ ${PDIRS} config: diff --git a/cmd/Makefile b/cmd/Makefile @@ -1,31 +1,39 @@ ROOT=.. -include ${ROOT}/mk/hdr.mk -include ${ROOT}/mk/wmii.mk +include $(ROOT)/mk/hdr.mk +include $(ROOT)/mk/wmii.mk -wmiir.c: ${ROOT}/mk/wmii.mk +wmiir.c: $(ROOT)/mk/wmii.mk DIRS = wmii -TARG = wmii9menu \ +TARG = wihack \ + wmii.rc \ + wmii9menu \ wmii9rc \ wmiiloop \ wmiir \ wmiistartrc OFILES = util.o -FILTER = sed "s|CONFPREFIX|${ETC}|g; \ - s|CONFVERSION|${CONFVERSION}|g; \ - s|P9PATHS|${P9PATHS}|g; \ - s|AWKPATH|${AWKPATH}|g" +FILTER = sed "s|CONFPREFIX|$(ETC)|g; \ + s|CONFVERSION|$(CONFVERSION)|g; \ + s|P9PATHS|$(P9PATHS)|g; \ + s|LIBDIR|$(LIBDIR)|g; \ + s|AWKPATH|$(AWKPATH)|g" LDFLAGS += -lfmt -lutf -CFLAGS += ${INCX11} -DVERSION=\"${VERSION}\" +CFLAGS += $(INCX11) -DVERSION=\"$(VERSION)\" -include ${ROOT}/mk/many.mk -include ${ROOT}/mk/dir.mk +include $(ROOT)/mk/many.mk +include $(ROOT)/mk/dir.mk -OWMIIR=wmiir.o ${OFILES} ${LIBIXP} -wmiir.O: ${OWMIIR} - ${LINK} $@ ${STATIC} ${OWMIIR} +OWMIIR=wmiir.o $(OFILES) $(LIBIXP) +wmiir.O: $(OWMIIR) + $(LINK) $@ $(STATIC) $(OWMIIR) + +OMENU=menu.o wmii/x11.o $(OFILES) $(LIBIXP) +menu.O: $(OMENU) dall + $(LINK) $@ $(OMENU) + +wmii9menu.O: wmii9menu.o $(OFILES) + $(LINK) $@ $*.o $(OFILES) $(LIBX11) -wmii9menu.O: wmii9menu.o ${OFILES} - ${LINK} $@ $*.o ${OFILES} ${LIBX11} diff --git a/cmd/util.c b/cmd/util.c @@ -1,6 +1,8 @@ /* Written by Kris Maglione <fbsdaemon at gmail dot com> */ /* Public domain */ #include <errno.h> +#include <sys/types.h> +#include <signal.h> #include <stdarg.h> #include <stdlib.h> #include <stdio.h> @@ -44,6 +46,19 @@ fatal(const char *fmt, ...) { exit(1); } +void +_die(char *file, int line, char *msg) { + fprint(2, "%s: dieing at %s:%d: %s\n", + file, line, msg); + kill(getpid(), SIGABRT); + abort(); /* Adds too many frames: + * _die() + * abort() + * raise(SIGABRT) + * kill(getpid(), SIGABRT) + */ +} + /* Can't malloc */ static void mfatal(char *name, uint size) { diff --git a/cmd/wihack.sh b/cmd/wihack.sh @@ -0,0 +1,43 @@ +#!/bin/sh -f + +usage() { + echo 1>&2 Usage: \ + "$0 [-transient <window>] [-type <window_type>[,...]] [-tags <tags>] <command> [<arg> ...]" + exit 1 +} + +checkarg='[ ${#@} -gt 0 ] || usage' + +while [ ${#@} -gt 0 ] +do + case $1 in + -transient) + shift; eval $checkarg + export WMII_HACK_TRANSIENT=$1 + shift;; + -type) + shift; eval $checkarg + export WMII_HACK_TYPE=$1 + shift;; + -tags) + shift; eval $checkarg + export WMII_HACK_TAGS=$1 + shift;; + -*) + usage;; + *) + break;; + esac +done + +eval $checkarg + +if [ ! -u "`which $1`" -a ! -g "`which $1`" ] +then + export LD_PRELOAD=libwmii_hack.so + export LD_LIBRARY_PATH="LIBDIR${LD_LIBRARY_PATH:+:}${LD_LIBRARY_PATH}" +else + unset WMII_HACK_TRANSIENT WMII_HACK_TYPE WMII_HACK_TAGS +fi +exec "$@" + diff --git a/cmd/wmii.rc.rc b/cmd/wmii.rc.rc @@ -0,0 +1,127 @@ + +wmiiscript=$1 +wmiikeys=() + +echo Start $wmiiscript | wmiir write /event >[2]/dev/null \ + || exit write + +if(~ $scriptname '') + scriptname=$wmiiscript + +# Blech. +if(! test -x $PLAN9/bin/read) + fn read { sh -c 'read -r x || exit 1; echo $x' } + +fn wi_atexit {} +fn sigexit { + wi_atexit +} + +fn Event-Start { + if(~ $1 $wmiiscript) + exit +} + +fn Event-Key { Key-$1 $1 } + +fn wi_fatal { + echo $scriptname: Fatal: $* + exit fatal +} + +fn wi_notice { + xmessage $scriptname: Notice: $* +} + +fn wi_readctl { wmiir read /ctl | sed -n 's/^'$1' (.*)/\1/p' } + +wmiifont=`{wi_readctl font} +wmiinormcol=`{wi_readctl normcolors} +wmiifocuscol=`{wi_readctl focuscolors} + +fn wi_menu { + dmenu -b -fn $wmiifont \ + -nf $wmiinormcol(1) -nb $wmiinormcol(2) \ + -sf $wmiifocuscol(1) -sb $wmiifocuscol(2) +} + +fn wi_9menu { + wmii9menu -font `{echo $wmiifont | sed 's/,.*//'} \ + -^(nf nb br)^$wmiinormcol \ + -^(sf sb br)^$wmiifocuscol $* +} + +fn wi_proglist { + /bin/ls -lL `{echo $* | sed 'y/:/ /'} >[2]/dev/null \ + | awk '$1 ~ /^[^d].*x/ { print $NF }' \ + | sort | uniq +} + +fn wi_actions { + { wi_proglist $WMII_CONFPATH + wi_getfuns Action + } | sort | uniq +} + +fn wi_script { + prog = `{@{path=$confpath whatis $1} | + grep -v '^fn|= ' || echo /dev/null} + shift; echo $prog $* +} + + +fn wi_initkeys { + ifs=() { + wmiikeys = `{wmiir read /keys} { + mykeys = `{comm -23 \ + <{wi_getfuns Key | sort | uniq} \ + <{echo $wmiikeys | sort | uniq}} + {echo $wmiikeys; wi_getfuns Key} \ + | sort | uniq \ + | wmiir write /keys + } + } + fn wi_atexit { + wi_cleankeys + } +} + +fn wi_cleankeys { + ifs=() { + wmiikeys = `{wmiir read /keys} { + comm -23 <{echo $wmiikeys | sort | uniq} \ + <{echo $mykeys} \ + | wmiir write /keys + } + } +} + +fn wi_runcmd { @{ + rfork ns + path=$oldpath + if(~ $1 -t) { + shift + * = (wihack -tags `{wmiir read /tag/sel/ctl | sed 1q} $*) + } + eval exec $* & + } +} + +fn wi_getfuns { + env | sed -n 's/^fn#'^$1^'-([^=]+).*/\1/p' +} + +fn wi_tags { + wmiir ls /tag | sed 's,/,,; /^sel$/d' +} + +fn wi_eventloop { + wi_initkeys + + wmiir read /event | + while(*=`{read}) { + event = $1; shift + Event-$event $* + } >[2]/dev/null </dev/null +} + diff --git a/cmd/wmii/Makefile b/cmd/wmii/Makefile @@ -5,29 +5,31 @@ include ${ROOT}/mk/wmii.mk main.c: ${ROOT}/mk/wmii.mk TARG = wmii -HFILES= dat.h fns.h x11.h +HFILES= dat.h fns.h LIB = ${LIBIXP} LDFLAGS += -lm ${LIBX11} -lXext ${LIBICONV} -lregexp9 -lbio -lfmt -lutf -CFLAGS += ${INCX11} ${INCICONV} -DVERSION=\"${VERSION}\" +CFLAGS += ${INCX11} ${INCICONV} -DVERSION=\"${VERSION}\" \ + -DIXP_NEEDAPI=86 OBJ = area \ bar \ client \ column \ event \ + ewmh \ frame \ - fs \ + fs \ geom \ - key \ - main \ - map \ + key \ + main \ + map \ message \ mouse \ - rule \ + rule \ printevent\ - utf \ - view \ - x11 \ + utf \ + view \ + x11 \ ../util include ${ROOT}/mk/one.mk diff --git a/cmd/wmii/area.c b/cmd/wmii/area.c @@ -5,13 +5,11 @@ #include "dat.h" #include <assert.h> #include <math.h> -#include <stdlib.h> -#include <string.h> #include "fns.h" static void place_frame(Frame *f); -Client * +Client* area_selclient(Area *a) { if(a && a->sel) return a->sel->client; @@ -40,8 +38,8 @@ area_name(Area *a) { return buf; } -Area * -create_area(View *v, Area *pos, uint w) { +Area* +area_create(View *v, Area *pos, uint w) { static ushort id = 1; uint areanum, i; uint minwidth; @@ -60,7 +58,7 @@ create_area(View *v, Area *pos, uint w) { colnum = areanum - 1; if(w == 0) { if(colnum >= 0) { - w = newcolw(v, i); + w = view_newcolw(v, i); if (w == 0) w = Dx(screen->r) / (colnum + 1); } @@ -74,7 +72,7 @@ create_area(View *v, Area *pos, uint w) { return nil; if(pos) - scale_view(v, Dx(screen->r) - w); + view_scale(v, Dx(screen->r) - w); a = emallocz(sizeof *a); a->view = v; @@ -104,24 +102,24 @@ create_area(View *v, Area *pos, uint w) { a->floating = True; if(v->sel == nil) - focus_area(a); + area_focus(a); if(!a->floating) - write_event("CreateColumn %ud\n", i); + event("CreateColumn %ud\n", i); return a; } void -destroy_area(Area *a) { +area_destroy(Area *a) { Client *c; Area *ta; View *v; - uint i; + int idx; v = a->view; if(a->frame) - fatal("destroying non-empty area"); + die("destroying non-empty area"); if(v->revert == a) v->revert = nil; @@ -130,15 +128,19 @@ destroy_area(Area *a) { if(c->revert == a) c->revert = nil; - i = 0; - for(ta=v->area; ta != a; ta=ta->next) - i++; + idx = area_idx(a); - if(a->prev) + if(a->prev && !a->prev->floating) ta = a->prev; else ta = a->next; + if(a == v->colsel) + v->colsel = ta; + + /* Can only destroy the floating area when destroying a + * view---after destroying all columns. + */ assert(a->prev || a->next == nil); if(a->prev) a->prev->next = a->next; @@ -146,17 +148,17 @@ destroy_area(Area *a) { a->next->prev = a->prev; if(ta && v->sel == a) { - if(ta->floating && ta->next) - ta = ta->next; - focus_area(ta); + area_focus(ta); } - write_event("DestroyColumn %ud\n", i); + event("DestroyArea %d\n", idx); + /* Deprecated */ + event("DestroyColumn %d\n", idx); free(a); } void -send_to_area(Area *to, Frame *f) { +area_moveto(Area *to, Frame *f) { Area *from; assert(to->view == f->view); @@ -164,19 +166,32 @@ send_to_area(Area *to, Frame *f) { from = f->area; if(to->floating != from->floating) { - Rectangle temp = f->revert; + Rectangle tr; + + tr = f->revert; f->revert = f->r; f->r = temp; } f->client->revert = from; - detach_from_area(f); - attach_to_area(to, f); + area_detach(f); + area_attach(to, f); } void -attach_to_area(Area *a, Frame *f) { - uint n_frame; +area_setsel(Area *a, Frame *f) { + View *v; + + v = a->view; + if(a == v->sel && f) + frame_focus(f); + else + a->sel = f; +} + +void +area_attach(Area *a, Frame *f) { + uint nframe; Frame *ft; Client *c; @@ -184,10 +199,10 @@ attach_to_area(Area *a, Frame *f) { f->area = a; - n_frame = 0; + nframe = 0; for(ft=a->frame; ft; ft=ft->anext) - n_frame++; - n_frame = max(n_frame, 1); + nframe++; + nframe = max(nframe, 1); c->floating = a->floating; if(!a->floating) { @@ -195,27 +210,28 @@ attach_to_area(Area *a, Frame *f) { f->r.max.y = Dy(a->r) / n_frame; } - insert_frame(a->sel, f); + frame_insert(a->sel, f); if(a->floating) { place_frame(f); - resize_frame(f, f->r); + client_resize(f->client, f->r); } - focus_frame(f, False); - restack_view(a->view); + if(!a->sel) + area_setsel(a, f); + view_restack(a->view); if(!a->floating) - arrange_column(a, False); + column_arrange(a, False); if(a->frame) assert(a->sel); } void -detach_from_area(Frame *f) { +area_detach(Frame *f) { Frame *pr; - Client *c, *cp; + Client *c; Area *a; View *v; @@ -224,43 +240,31 @@ detach_from_area(Frame *f) { c = f->client; pr = f->aprev; - remove_frame(f); - - if(a->sel == f) { - if(!pr) - pr = a->frame; - if(pr && (v->sel == a)) - focus_frame(pr, False); - else - a->sel = pr; - } + frame_remove(f); if(!a->floating) { if(a->frame) - arrange_column(a, False); + column_arrange(a, False); else { if(v->area->next->next) - destroy_area(a); + area_destroy(a); else if((a->frame == nil) && (v->area->frame)) - focus_area(v->area); - - arrange_view(v); - } - }else if(!a->frame) { - if(c->trans) { - cp = win2client(c->trans); - if(cp && cp->frame) { - a = cp->sel->area; - if(a->view == v) { - focus_area(a); - return; - } - } + area_focus(v->area); + view_arrange(v); } - if(v->area->next->frame) - focus_area(v->area->next); + }else if(v->oldsel) + area_focus(v->oldsel); + else if(!a->frame) { + if(v->colsel->frame) + area_focus(v->colsel); }else assert(a->sel); + + if(a->sel == f) { + if(!pr) + pr = a->frame; + area_setsel(a, pr); + } } static void @@ -305,7 +309,7 @@ place_frame(Frame *f) { Frame *fr; Client *c; Area *a; - Bool fit; + bool fit; uint i, j, x, y, cx, cy, maxx, maxy, diff, num; int snap; @@ -404,11 +408,10 @@ place_frame(Frame *f) { } void -focus_area(Area *a) { +area_focus(Area *a) { Frame *f; View *v; Area *old_a; - int i; v = a->view; f = a->sel; @@ -422,18 +425,19 @@ focus_area(Area *a) { if(v != screen->sel) return; + move_focus(old_a->sel, f); + if(f) - focus_client(f->client); + client_focus(f->client); else - focus_client(nil); + client_focus(nil); if(a != old_a) { - i = 0; - for(a = v->area; a != v->sel; a = a->next) - i++; + event("AreaFocus %s\n", area_name(a)); + /* Deprecated */ if(a->floating) - write_event("FocusFloating\n"); + event("FocusFloating\n"); else - write_event("ColumnFocus %d\n", i); + event("ColumnFocus %d\n", area_idx(a)); } } diff --git a/cmd/wmii/bar.c b/cmd/wmii/bar.c @@ -1,16 +1,15 @@ /* Copyright ©2004-2006 Anselm R. Garbe <garbeam at gmail dot com> - * Copyright ©2006-2007 Kris Maglione <fbsdaemon@gmail.com> + * Copyright ©2006-2008 Kris Maglione <fbsdaemon@gmail.com> * See LICENSE file for license details. */ #include "dat.h" -#include <string.h> #include "fns.h" static Handlers handlers; static Bar *free_bars; void -initbar(WMScreen *s) { +bar_init(WMScreen *s) { WinAttr wa; s->brect = s->r; @@ -34,12 +33,12 @@ initbar(WMScreen *s) { mapwin(s->barwin); } -Bar * -create_bar(Bar **bp, char *name) { +Bar* +bar_create(Bar **bp, const char *name) { static uint id = 1; Bar *b; - b = bar_of_name(*bp, name);; + b = bar_find(*bp, name);; if(b) return b; @@ -65,7 +64,7 @@ create_bar(Bar **bp, char *name) { } void -destroy_bar(Bar **bp, Bar *b) { +bar_destroy(Bar **bp, Bar *b) { Bar **p; for(p = bp; *p; p = &p[0]->next) @@ -77,7 +76,7 @@ destroy_bar(Bar **bp, Bar *b) { } void -resize_bar(WMScreen *s) { +bar_resize(WMScreen *s) { View *v; s->brect = s->r; @@ -85,14 +84,14 @@ resize_bar(WMScreen *s) { reshapewin(s->barwin, s->brect); - XSync(display, False); - draw_bar(s); + sync(); + bar_draw(s); for(v = view; v; v = v->next) - arrange_view(v); + view_arrange(v); } void -draw_bar(WMScreen *s) { +bar_draw(WMScreen *s) { Bar *b, *tb, *largest, **pb; Rectangle r; Align align; @@ -158,11 +157,11 @@ draw_bar(WMScreen *s) { border(screen->ibuf, b->r, 1, b->col.border); } copyimage(s->barwin, r, screen->ibuf, ZP); - XSync(display, False); + sync(); } Bar* -bar_of_name(Bar *bp, const char *name) { +bar_find(Bar *bp, const char *name) { Bar *b; for(b = bp; b; b = b->next) @@ -179,16 +178,16 @@ bdown_event(Window *w, XButtonPressedEvent *e) { /* Ungrab so a menu can receive events before the button is released */ XUngrabPointer(display, e->time); - XSync(display, False); + sync(); 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); + if(rect_haspoint_p(Pt(e->x, e->y), b->r)) { + 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); + if(rect_haspoint_p(Pt(e->x, e->y), b->r)) { + event("RightBarMouseDown %d %s\n", e->button, b->name); return; } } @@ -200,13 +199,13 @@ bup_event(Window *w, XButtonPressedEvent *e) { USED(w, e); 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); + if(rect_haspoint_p(Pt(e->x, e->y), b->r)) { + 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); + if(rect_haspoint_p(Pt(e->x, e->y), b->r)) { + event("RightBarClick %d %s\n", e->button, b->name); return; } } @@ -214,7 +213,7 @@ bup_event(Window *w, XButtonPressedEvent *e) { static void expose_event(Window *w, XExposeEvent *e) { USED(w, e); - draw_bar(screen); + bar_draw(screen); } static Handlers handlers = { diff --git a/cmd/wmii/client.c b/cmd/wmii/client.c @@ -1,5 +1,5 @@ /* Copyright ©2004-2006 Anselm R. Garbe <garbeam at gmail dot com> - * Copyright ©2006-2007 Kris Maglione <fbsdaemon@gmail.com> + * Copyright ©2006-2008 Kris Maglione <fbsdaemon@gmail.com> * See LICENSE file for license details. */ #include "dat.h" @@ -24,8 +24,71 @@ enum { | ButtonReleaseMask }; -Client * -create_client(XWindow w, XWindowAttributes *wa) { +static Group* group; + +static void +group_init(Client *c) { + Group *g; + long *ret; + XWindow w; + long n; + + n = getprop_long(&c->w, "WM_CLIENT_LEADER", "WINDOW", 0L, &ret, 1L); + if(n == 0) + return; + w = *ret; + + for(g=group; g; g=g->next) + if(g->leader == w) + break; + if(g == nil) { + g = emallocz(sizeof *g); + g->leader = w; + g->next = group; + group = g; + } + c->group = g; + g->ref++; +} + +static void +group_remove(Client *c) { + Group **gp; + Group *g; + + g = c->group; + if(g == nil) + return; + if(g->client == c) + g->client = nil; + g->ref--; + if(g->ref == 0) { + for(gp=&group; *gp; gp=&gp[0]->next) + if(*gp == g) + break; + assert(*gp == g); + gp[0] = gp[0]->next; + } +} + +static Client* +group_leader(Group *g) { + Client *c; + + c = win2client(g->leader); + if(c) + return c; + if(g->client) + return g->client; + /* Could do better. */ + for(c=client; c; c=c->next) + if(c->frame && c->group == g) + break; + return c; +} + +Client* +client_create(XWindow w, XWindowAttributes *wa) { Client **t, *c; WinAttr fwa; @@ -38,17 +101,14 @@ create_client(XWindow w, XWindowAttributes *wa) { c->w.type = WWindow; c->w.w = w; c->w.r = c->r; - - if((Dx(c->r) == Dx(screen->r)) && (Dy(c->r) == Dy(screen->r))) - fullscreen(c, True); - 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")); + client_prop(c, xatom("WM_PROTOCOLS")); + client_prop(c, xatom("WM_TRANSIENT_FOR")); + client_prop(c, xatom("WM_NORMAL_HINTS")); + client_prop(c, xatom("WM_HINTS")); + client_prop(c, xatom("WM_CLASS")); + client_prop(c, xatom("WM_NAME")); + client_prop(c, xatom("_MOTIF_WM_HINTS")); XSetWindowBorderWidth(display, w, 0); XAddToSaveSet(display, w); @@ -73,6 +133,13 @@ create_client(XWindow w, XWindowAttributes *wa) { sethandler(c->framewin, &framehandler); sethandler(&c->w, &handlers); + p.x = def.border; + p.y = labelh(def.font); + reparentwindow(&c->w, c->framewin, p); + + ewmh_initclient(c); + group_init(c); + grab_button(c->framewin->w, AnyButton, AnyModifier); for(t=&client ;; t=&t[0]->next) @@ -82,44 +149,55 @@ create_client(XWindow w, XWindowAttributes *wa) { break; } - write_event("CreateClient %C\n", c); - manage_client(c); + event("CreateClient %C\n", c); + client_manage(c); return c; } void -manage_client(Client *c) { - Point p; +client_manage(Client *c) { Client *trans; + Frame *f; char *tags; - tags = gettextproperty(&c->w, "_WMII_TAGS"); - if(tags == nil) - tags = gettextproperty(&c->w, "_WIN_TAGS"); + tags = getprop_string(&c->w, "_WMII_TAGS"); - if((trans = win2client(c->trans))) - utflcpy(c->tags, trans->tags, sizeof(c->tags)); - else if(tags) - utflcpy(c->tags, tags, sizeof(c->tags)); + trans = win2client(c->trans); + if(trans == nil && c->group) + trans = group_leader(c->group); + if(tags) + utflcpy(c->tags, tags, sizeof(c->tags)); + else if(trans) + utflcpy(c->tags, trans->tags, sizeof(c->tags)); free(tags); - p.x = def.border; - p.y = labelh(def.font); - - reparentwindow(&c->w, c->framewin, p); - if(c->tags[0]) apply_tags(c, c->tags); else apply_rules(c); if(!starting) - update_views(); + view_update_all(); + + bool newgroup = !c->group + || c->group->ref == 1 + || selclient() && (selclient()->group == c->group); + + f = c->sel; + if((f->view == screen->sel) + && (!(c->w.ewmh.type & TypeSplash)) + && newgroup) { + if(f->area != f->view->sel) + f->view->oldsel = f->view->sel; + focus(c, false); + } + else { + frame_restack(c->sel, c->sel->area->sel); + view_restack(c->sel->view); + } - if(c->sel->view == screen->sel) - focus(c, True); - flushevents(EnterWindowMask, False); + flushenterevents(); } static int /* Temporary Xlib error handler */ @@ -129,14 +207,12 @@ ignoreerrors(Display *d, XErrorEvent *e) { } void -destroy_client(Client *c) { +client_destroy(Client *c) { int (*handler)(Display*, XErrorEvent*); Rectangle r; char *dummy; Client **tc; - Bool hide; - - Dprint("client.c:destroy_client(%p) %s\n", c, c->name); + bool hide; unmapwin(c->framewin); @@ -146,7 +222,7 @@ destroy_client(Client *c) { break; } - r = gravclient(c, ZR); + r = client_grav(c, ZR); hide = False; if(!c->sel || c->sel->view != screen->sel) @@ -158,8 +234,8 @@ destroy_client(Client *c) { handler = XSetErrorHandler(ignoreerrors); dummy = nil; - update_client_views(c, &dummy); - unmap_client(c, IconicState); + client_setviews(c, &dummy); + client_unmap(c, IconicState); sethandler(&c->w, nil); if(hide) @@ -168,26 +244,38 @@ destroy_client(Client *c) { reparentwindow(&c->w, &scr.root, r.min); destroywindow(c->framewin); - XSync(display, False); + sync(); XSetErrorHandler(handler); XUngrabServer(display); - write_event("DestroyClient %C\n", c); + ewmh_destroyclient(c); + group_remove(c); + event("DestroyClient %C\n", c); - flushevents(EnterWindowMask, False); + flushenterevents(); free(c->w.hints); free(c); } /* Convenience functions */ -Client * +Frame* +client_viewframe(Client *c, View *v) { + Frame *f; + + for(f=c->frame; f; f=f->cnext) + if(f->area->view == v) + break; + return f; +} + +Client* selclient(void) { if(screen->sel->sel->sel) return screen->sel->sel->sel->client; return nil; } -Client * +Client* win2client(XWindow w) { Client *c; for(c=client; c; c=c->next) @@ -205,7 +293,7 @@ Cfmt(Fmt *f) { return fmtprint(f, "<nil>"); } -char * +char* clientname(Client *c) { if(c) return c->name; @@ -213,7 +301,7 @@ clientname(Client *c) { } Rectangle -gravclient(Client *c, Rectangle rd) { +client_grav(Client *c, Rectangle rd) { Rectangle r; Point sp; WinHints *h; @@ -228,17 +316,17 @@ gravclient(Client *c, Rectangle rd) { else r = c->sel->revert; }else - r = client2frame(nil, c->r); + r = frame_client2rect(nil, c->r); r = gravitate(r, c->r, h->grav); if(h->gravstatic) r = rectaddpt(r, sp); - return frame2client(nil, r); + return frame_rect2client(nil, r); }else { - r = client2frame(nil, rd); + r = frame_client2rect(nil, rd); r = gravitate(rd, r, h->grav); if(h->gravstatic) r = rectsubpt(r, sp); - return client2frame(nil, r); + return frame_client2rect(nil, r); } } @@ -253,9 +341,9 @@ frame_hints(Frame *f, Rectangle r, Align sticky) { return r; or = r; - r = frame2client(f, r); + r = frame_rect2client(f, r); r = sizehint(c->w.hints, r); - r = client2frame(f, r); + r = frame_client2rect(f, r); if(!f->area->floating) { /* Not allowed to grow */ @@ -275,25 +363,25 @@ frame_hints(Frame *f, Rectangle r, Align sticky) { } static void -set_client_state(Client * c, int state) { +client_setstate(Client *c, int state) { long data[] = { state, None }; changeprop_long(&c->w, "WM_STATE", "WM_STATE", data, nelem(data)); } void -map_client(Client *c) { +client_map(Client *c) { if(!c->w.mapped) { mapwin(&c->w); - set_client_state(c, NormalState); + client_setstate(c, NormalState); } } void -unmap_client(Client *c, int state) { +client_unmap(Client *c, int state) { if(c->w.mapped) { unmapwin(&c->w); - set_client_state(c, state); + client_setstate(c, state); } } @@ -308,33 +396,42 @@ unmap_frame(Client *c) { } void -focus(Client *c, Bool restack) { +focus(Client *c, bool user) { View *v; Frame *f; f = c->sel; if(!f) return; + if(!user && c->noinput) + return; - v = f->area->view; + v = f->view; if(v != screen->sel) - focus_view(screen, v); - focus_frame(c->sel, restack); + view_focus(screen, v); + frame_focus(c->sel); } void -focus_client(Client *c) { +client_focus(Client *c) { flushevents(FocusChangeMask, True); - Dprint("focus_client(%p[%C]) => %s\n", c, c, clientname(c)); + Dprint(DFocus, "client_focus(%p[%C]) => %s\n", c, c, clientname(c)); - if((c == nil || !c->noinput) && screen->focus != c) { - Dprint("\t%s => %s\n", clientname(screen->focus), clientname(c)); + if(c) { + if(c->noinput) + return; + if(c->group) + c->group->client = c; + } + if(screen->focus != c) { + Dprint(DFocus, "\t%s => %s\n", clientname(screen->focus), clientname(c)); if(c) setfocus(&c->w, RevertToParent); else setfocus(screen->barwin, RevertToParent); + event("ClientFocus %C\n", c); write_event("ClientFocus %C\n", c); @@ -344,14 +441,14 @@ focus_client(Client *c) { } void -resize_client(Client *c, Rectangle r) { +client_resize(Client *c, Rectangle r) { Frame *f; f = c->sel; - resize_frame(f, r); + frame_resize(f, r); if(f->area->view != screen->sel) { - unmap_client(c, IconicState); + client_unmap(c, IconicState); unmap_frame(c); return; } @@ -360,24 +457,25 @@ resize_client(Client *c, Rectangle r) { if((f->area->mode == Colmax) && (f->area->sel != f)) { unmap_frame(c); - unmap_client(c, IconicState); + client_unmap(c, IconicState); }else if(f->collapsed) { reshapewin(c->framewin, f->r); map_frame(c); - unmap_client(c, IconicState); + client_unmap(c, IconicState); }else { - map_client(c); + client_map(c); reshapewin(c->framewin, f->r); reshapewin(&c->w, f->crect); map_frame(c); - configure_client(c); + client_configure(c); + ewmh_framesize(c); } flushevents(FocusChangeMask|ExposureMask, True); } void -set_cursor(Client *c, Cursor cur) { +client_setcursor(Client *c, Cursor cur) { WinAttr wa; if(c->cursor != cur) { @@ -388,7 +486,7 @@ set_cursor(Client *c, Cursor cur) { } void -configure_client(Client *c) { +client_configure(Client *c) { XConfigureEvent e; Rectangle r; @@ -406,30 +504,29 @@ configure_client(Client *c) { e.height = Dy(r); e.border_width = c->border; - XSendEvent(display, c->w.w, - /*propegate*/ False, - StructureNotifyMask, - (XEvent*)&e); + sendevent(&c->w, false, StructureNotifyMask, (XEvent*)&e); } static void -send_client_message(Client *c, char *name, char *value) { - XEvent e; +client_sendmessage(Client *c, char *name, char *value) { + XClientMessageEvent e; e.type = ClientMessage; - e.xclient.window = c->w.w; - e.xclient.message_type = xatom(name); - e.xclient.format = 32; - e.xclient.data.l[0] = xatom(value); - e.xclient.data.l[1] = CurrentTime; - XSendEvent(display, c->w.w, False, NoEventMask, &e); - XSync(display, False); + e.window = c->w.w; + e.message_type = xatom(name); + e.format = 32; + e.data.l[0] = xatom(value); + e.data.l[1] = xtime; + sendevent(&c->w, false, NoEventMask, (XEvent*)&e); + sync(); } void -kill_client(Client * c) { - if(c->proto & WM_PROTOCOL_DELWIN) - send_client_message(c, "WM_PROTOCOLS", "WM_DELETE_WINDOW"); +client_kill(Client *c, bool nice) { + if(nice && (c->proto & ProtoDelete)) { + client_sendmessage(c, "WM_PROTOCOLS", "WM_DELETE_WINDOW"); + ewmh_pingclient(c); + } else XKillClient(display, c->w.w); } @@ -443,8 +540,9 @@ fullscreen(Client *c, int fullscreen) { if(fullscreen == c->fullscreen) return; - write_event("Fullscreen %C %s\n", c, (fullscreen ? "on" : "off")); + event("Fullscreen %C %s\n", c, (fullscreen ? "on" : "off")); c->fullscreen = fullscreen; + ewmh_updatestate(c); if((f = c->sel)) { if(fullscreen) { @@ -452,18 +550,18 @@ fullscreen(Client *c, int fullscreen) { f->revert = f->r; else { f->r = f->revert; - send_to_area(f->view->area, f); + area_moveto(f->view->area, f); } - focus_client(c); + focus(c, true); }else - resize_frame(f, f->revert); + frame_resize(f, f->revert); if(f->view == screen->sel) - focus_view(screen, f->view); + view_focus(screen, f->view); } } void -set_urgent(Client *c, int urgent, Bool write) { +client_seturgent(Client *c, int urgent, bool write) { XWMHints *wmh; char *cwrite, *cnot; Frame *f, *ff; @@ -476,11 +574,12 @@ set_urgent(Client *c, int urgent, Bool write) { cnot = (urgent ? "" : "Not"); if(urgent != c->urgent) { - write_event("%sUrgent %C %s\n", cnot, c, cwrite); + event("%sUrgent %C %s\n", cnot, c, cwrite); c->urgent = urgent; + ewmh_updatestate(c); if(c->sel) { if(c->sel->view == screen->sel) - draw_frame(c->sel); + frame_draw(c->sel); for(f=c->frame; f; f=f->cnext) { SET(ff); if(!urgent) @@ -488,7 +587,7 @@ set_urgent(Client *c, int urgent, Bool write) { for(ff=a->frame; ff; ff=ff->anext) if(ff->client->urgent) break; if(urgent || ff == nil) - write_event("%sUrgentTag %s %s\n", cnot, cwrite, f->view->name); + event("%sUrgentTag %s %s\n", cnot, cwrite, f->view->name); } } } @@ -522,21 +621,21 @@ update_class(Client *c) { } static void -update_client_name(Client *c) { +client_updatename(Client *c) { char *str; c->name[0] = '\0'; - str = gettextproperty(&c->w, "_NET_WM_NAME"); + str = getprop_string(&c->w, "_NET_WM_NAME"); if(str == nil) - str = gettextproperty(&c->w, "WM_NAME"); + str = getprop_string(&c->w, "WM_NAME"); if(str) utflcpy(c->name, str, sizeof(c->name)); free(str); update_class(c); if(c->sel) - draw_frame(c->sel); + frame_draw(c->sel); } static void @@ -544,42 +643,40 @@ updatemwm(Client *c) { enum { All = 0x1, Border = 0x2, - Title = 0x8, - FlagDecor = 0x2, - Flags = 0, - Decor = 2, + Title = 0x8, + FlagDecor = 0x2, + Flags = 0, + Decor = 2, }; Rectangle r; ulong *ret; - Atom real; int n; - n = getproperty(&c->w, "_MOTIF_WM_HINTS", "_MOTIF_WM_HINTS", &real, - 0L, (void*)&ret, 3L); + n = getprop_long(&c->w, "_MOTIF_WM_HINTS", "_MOTIF_WM_HINTS", + 0L, (long**)&ret, 3L); if(c->sel) - r = frame2client(c->sel, c->sel->r); + r = frame_rect2client(c->sel, c->sel->r); + c->borderless = 0; + c->titleless = 0; if(n >= 3 && (ret[Flags]&FlagDecor)) { if(ret[Decor]&All) ret[Decor] ^= ~0; - c->borderless = ((ret[Decor]&Border)==0); - c->titleless = ((ret[Decor]&Title)==0); - }else { - c->borderless = 0; - c->titleless = 0; + c->borderless = !(ret[Decor]&Border); + c->titleless = !(ret[Decor]&Title); } free(ret); if(c->sel) { - r = client2frame(c->sel, r); - resize_client(c, r); - draw_frame(c->sel); + r = frame_client2rect(c->sel, r); + client_resize(c, r); + frame_draw(c->sel); } } void -prop_client(Client *c, Atom a) { +client_prop(Client *c, Atom a) { XWMHints *wmh; char **class; int n; @@ -594,6 +691,9 @@ prop_client(Client *c, Atom a) { updatemwm(c); } else switch (a) { + default: + ewmh_prop(c, a); + break; case XA_WM_TRANSIENT_FOR: XGetTransientForHint(display, c->w.w, &c->trans); break; @@ -606,12 +706,12 @@ prop_client(Client *c, Atom a) { wmh = XGetWMHints(display, c->w.w); if(wmh) { c->noinput = !((wmh->flags&InputFocus) && wmh->input); - set_urgent(c, (wmh->flags & XUrgencyHint) != 0, False); + client_seturgent(c, (wmh->flags & XUrgencyHint) != 0, False); XFree(wmh); } break; case XA_WM_CLASS: - n = gettextlistproperty(&c->w, "WM_CLASS", &class); + n = getprop_textlist(&c->w, "WM_CLASS", &class); snprint(c->props, sizeof(c->props), "%s:%s:", (n > 0 ? class[0] : "<nil>"), (n > 1 ? class[1] : "<nil>")); @@ -620,7 +720,7 @@ prop_client(Client *c, Atom a) { break; case XA_WM_NAME: wmname: - update_client_name(c); + client_updatename(c); break; } } @@ -633,33 +733,36 @@ configreq_event(Window *w, XConfigureRequestEvent *e) { c = w->aux; - r = gravclient(c, ZR); + r = client_grav(c, ZR); r.max = subpt(r.max, r.min); - if(e->value_mask&CWX) + if(e->value_mask & CWX) r.min.x = e->x; - if(e->value_mask&CWY) + if(e->value_mask & CWY) r.min.y = e->y; - if(e->value_mask&CWWidth) + if(e->value_mask & CWWidth) r.max.x = e->width; - if(e->value_mask&CWHeight) + if(e->value_mask & CWHeight) r.max.y = e->height; - if(e->value_mask&CWBorderWidth) + if(e->value_mask & CWBorderWidth) c->border = e->border_width; r.max = addpt(r.min, r.max); cr = r; - r = gravclient(c, r); + r = client_grav(c, r); if((Dx(cr) == Dx(screen->r)) && (Dy(cr) == Dy(screen->r))) fullscreen(c, True); - if(c->sel->area->floating) - resize_client(c, r); + if(c->sel->area->floating) { + client_resize(c, r); + sync(); + flushenterevents(); + } else { c->sel->revert = r; - configure_client(c); + client_configure(c); } } @@ -667,8 +770,7 @@ static void destroy_event(Window *w, XDestroyWindowEvent *e) { USED(w, e); - Dprint("client.c:destroy_event(%W)\n", w); - destroy_client(w->aux); + client_destroy(w->aux); } static void @@ -678,11 +780,12 @@ enter_event(Window *w, XCrossingEvent *e) { c = w->aux; if(e->detail != NotifyInferior) { if(screen->focus != c) { - Dprint("enter_notify(c) => %s\n", c->name); - focus(c, False); + Dprint(DGeneric, "enter_notify(c) => %s\n", c->name); + focus(c, false); } - set_cursor(c, cursor[CurNormal]); - }else Dprint("enter_notify(c[NotifyInferior]) => %s\n", c->name); + client_setcursor(c, cursor[CurNormal]); + }else + Dprint(DGeneric, "enter_notify(c[NotifyInferior]) => %s\n", c->name); } static void @@ -700,7 +803,7 @@ focusin_event(Window *w, XFocusChangeEvent *e) { screen->focus = c; if(c != old) { if(c->sel) - draw_frame(c->sel); + frame_draw(c->sel); } } @@ -716,7 +819,7 @@ focusout_event(Window *w, XFocusChangeEvent *e) { print_focus(&c_magic, "<magic>"); screen->focus = &c_magic; if(c->sel) - draw_frame(c->sel); + frame_draw(c->sel); } } @@ -727,7 +830,7 @@ unmap_event(Window *w, XUnmapEvent *e) { c = w->aux; if(!e->send_event) c->unmapped--; - destroy_client(c); + client_destroy(c); } static void @@ -738,7 +841,7 @@ map_event(Window *w, XMapEvent *e) { c = w->aux; if(c == selclient()) - focus_client(c); + client_focus(c); } static void @@ -749,7 +852,7 @@ property_event(Window *w, XPropertyEvent *e) { return; c = w->aux; - prop_client(c, e->atom); + client_prop(c, e->atom); } static Handlers handlers = { @@ -764,40 +867,8 @@ static Handlers handlers = { }; /* Other */ -#if 0 /* Not used at the moment */ -void -newcol_client(Client *c, char *arg) { - Frame *f; - Area *to, *a; - View *v; - - f = c->sel; - a = f->area; - v = f->view; - - if(a->floating) - return; - 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; - to = new_column(v, to, 0); - send_to_area(to, f); - } - else if(!strncmp(arg, "next", 5)) { - to = new_column(v, a, 0); - send_to_area(to, f); - } - else - return; - flushevents(EnterWindowMask, False); -} -#endif - void -update_client_views(Client *c, char **tags) { +client_setviews(Client *c, char **tags) { Frame **fp, *f; int cmp; @@ -812,7 +883,7 @@ update_client_views(Client *c, char **tags) { } f = *fp; - detach_from_area(f); + area_detach(f); *fp = f->cnext; if(c->sel == f) c->sel = *fp; @@ -820,10 +891,10 @@ update_client_views(Client *c, char **tags) { } if(*tags) { if(!*fp || cmp > 0) { - f = create_frame(c, get_view(*tags)); + f = frame_create(c, view_create(*tags)); if(f->view == screen->sel || !c->sel) c->sel = f; - attach_to_view(f->view, f); + view_attach(f->view, f); f->cnext = *fp; *fp = f; } @@ -831,7 +902,7 @@ update_client_views(Client *c, char **tags) { tags++; } } - update_views(); + view_update_all(); } static int @@ -843,7 +914,7 @@ static int strpcmp(const void *ap, const void *bp) { char **a, **b; - a = (char**)ap; /* gcc wants this case. *sigh* */ + a = (char**)ap; b = (char**)bp; return strcmp(*a, *b); } @@ -857,7 +928,7 @@ static char *badtags[] = { void apply_tags(Client *c, const char *tags) { uint i, j, k, n; - Bool add; + bool add; char buf[512], last; char *toks[32], *cur; @@ -938,9 +1009,9 @@ apply_tags(Client *c, const char *tags) { } toks[n] = nil; - update_client_views(c, toks); + client_setviews(c, toks); - changeprop_char(&c->w, "_WMII_TAGS", "UTF8_STRING", c->tags, strlen(c->tags)); + changeprop_string(&c->w, "_WMII_TAGS", c->tags); } void diff --git a/cmd/wmii/column.c b/cmd/wmii/column.c @@ -75,7 +75,7 @@ unmapdiv(Divide *d) { } void -setdiv(Divide *d, int x) { +div_set(Divide *d, int x) { Rectangle r; d->x = x; @@ -139,7 +139,7 @@ update_imgs(void) { } void -update_divs(void) { +div_update_all(void) { Divide **dp, *d; Area *a; View *v; @@ -151,12 +151,12 @@ update_divs(void) { for(a = v->area->next; a; a = a->next) { d = getdiv(dp); dp = &d->next; - setdiv(d, a->r.min.x); + div_set(d, a->r.min.x); if(!a->next) { d = getdiv(dp); dp = &d->next; - setdiv(d, a->r.max.x); + div_set(d, a->r.max.x); } } for(d = *dp; d; d = d->next) @@ -189,17 +189,17 @@ static Handlers divhandler = { .expose = expose_event, }; -Area * -new_column(View *v, Area *pos, uint w) { +Area* +column_new(View *v, Area *pos, uint w) { Area *a; - a = create_area(v, pos, w); + a = area_create(v, pos, w); if(!a) return nil; - arrange_view(v); + view_arrange(v); if(v == screen->sel) - focus_view(screen, v); + view_focus(screen, v); return a; } @@ -222,7 +222,7 @@ scale_column(Area *a) { nuncol = 0; dy = 0; for(f=a->frame; f; f=f->anext) { - resize_frame(f, f->r); + frame_resize(f, f->r); if(f->collapsed) ncol++; else @@ -259,7 +259,7 @@ scale_column(Area *a) { if(f->collapsed) { if(i < 0 && (f != a->sel)) { f->collapsed = False; - send_to_area(f->view->area, f); + area_moveto(f->view->area, f); continue; } i--; @@ -269,7 +269,7 @@ scale_column(Area *a) { j--; } /* Doesn't change if we 'continue' */ - fp=&f->anext; + fp = &f->anext; } surplus = 0; @@ -297,7 +297,7 @@ scale_column(Area *a) { for(f=a->frame; f; f=f->anext) { if(!f->collapsed) f->r.max.y += f->ratio * surplus; - resize_frame(f, f->r); + frame_resize(f, f->r); dy += Dy(f->r); } surplus = Dy(a->r) - dy; @@ -306,7 +306,7 @@ scale_column(Area *a) { if(!f->collapsed) { dy = Dy(f->r); f->r.max.y += surplus; - resize_frame(f, f->r); + frame_resize(f, f->r); f->r.max.y = Dy(f->crect) + labelh(def.font) + 1; surplus -= Dy(f->r) - dy; } @@ -328,7 +328,7 @@ scale_column(Area *a) { } void -arrange_column(Area *a, Bool dirty) { +column_arrange(Area *a, bool dirty) { Frame *f; if(a->floating || !a->frame) @@ -351,26 +351,26 @@ arrange_column(Area *a, Bool dirty) { } goto resize; default: - assert(!"Can't happen"); + die("can't get here"); break; } scale_column(a); resize: if(a->view == screen->sel) { - restack_view(a->view); - resize_client(a->sel->client, a->sel->r); + view_restack(a->view); + client_resize(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->r); + client_resize(f->client, f->r); for(f=a->frame; f; f=f->anext) if(f->collapsed && f != a->sel) - resize_client(f->client, f->r); + client_resize(f->client, f->r); } } void -resize_column(Area *a, int w) { +column_resize(Area *a, int w) { Area *an; int dw; @@ -381,8 +381,8 @@ resize_column(Area *a, int w) { a->r.max.x += dw; an->r.min.x += dw; - arrange_view(a->view); - focus_view(screen, a->view); + view_arrange(a->view); + view_focus(screen, a->view); } static void @@ -409,18 +409,18 @@ resize_colframeh(Frame *f, Rectangle *r) { if(fp) { fp->r.max.y = r->min.y; - resize_frame(fp, fp->r); + frame_resize(fp, fp->r); } if(fn) { fn->r.min.y = r->max.y; - resize_frame(fn, fn->r); + frame_resize(fn, fn->r); } - resize_frame(f, *r); + frame_resize(f, *r); } void -resize_colframe(Frame *f, Rectangle *r) { +column_resizeframe(Frame *f, Rectangle *r) { Area *a, *al, *ar; View *v; uint minw; @@ -440,29 +440,26 @@ resize_colframe(Frame *f, Rectangle *r) { else r->min.x = max(r->min.x, 0); - if(ar) { - if(maxx >= ar->r.max.x - minw) - maxx = ar->r.max.x - minw; - } + if(ar) + maxx = min(maxx, a->r.max.x - minw); else - if(maxx > screen->r.max.x) - maxx = screen->r.max.x; + maxx = min(maxx, screen->r.max.x); dx = a->r.min.x - r->min.x; dw = maxx - a->r.max.x; if(al) { al->r.max.x -= dx; - arrange_column(al, False); + column_arrange(al, False); } if(ar) { ar->r.max.x -= dw; - arrange_column(ar, False); + column_arrange(ar, False); } resize_colframeh(f, r); a->r.max.x = maxx; - arrange_view(a->view); + view_arrange(a->view); - focus_view(screen, v); + view_focus(screen, v); } diff --git a/cmd/wmii/dat.h b/cmd/wmii/dat.h @@ -17,32 +17,30 @@ #define FOCUSCOLORS "#ffffff #335577 #447799" #define NORMCOLORS "#222222 #eeeeee #666666" -enum Align { - NORTH = 0x01, - EAST = 0x02, - SOUTH = 0x04, - WEST = 0x08, - NEAST = NORTH | EAST, - NWEST = NORTH | WEST, - SEAST = SOUTH | EAST, - SWEST = SOUTH | WEST, - CENTER = NEAST | SWEST, +enum { + PingTime = 10000, }; -typedef struct CTuple CTuple; -typedef enum Align Align; - -struct CTuple { - ulong bg; - ulong fg; - ulong border; - char colstr[24]; /* #RRGGBB #RRGGBB #RRGGBB */ +enum EWMHType { + TypeDesktop = 1<<0, + TypeDock = 1<<1, + TypeToolbar = 1<<2, + TypeMenu = 1<<3, + TypeUtility = 1<<4, + TypeSplash = 1<<5, + TypeDialog = 1<<6, + TypeNormal = 1<<7, }; enum { Coldefault, Colstack, Colmax, }; +#define TOGGLE(x) \ + (x == On ? "On" : \ + x == Off ? "Off" : \ + x == Toggle ? "Toggle" : \ + "<toggle>") enum { Off, On, @@ -59,136 +57,171 @@ enum { enum { NCOL = 16, - WM_PROTOCOL_DELWIN = 1, +}; + +enum Protocols { + ProtoDelete = 1<<0, + ProtoTakeFocus = 1<<1, + ProtoPing = 1<<2, +}; + +enum DebugOpt { + DEvent = 1<<0, + DEwmh = 1<<1, + DFocus = 1<<2, + DGeneric= 1<<3, }; /* Data Structures */ -typedef struct View View; typedef struct Area Area; -typedef struct Frame Frame; +typedef struct Bar Bar; typedef struct Client Client; typedef struct Divide Divide; +typedef struct Frame Frame; +typedef struct Group Group; typedef struct Key Key; -typedef struct Bar Bar; +typedef struct Map Map; +typedef struct MapEnt MapEnt; typedef struct Rule Rule; typedef struct Ruleset Ruleset; +typedef struct Strut Strut; +typedef struct View View; typedef struct WMScreen WMScreen; -typedef struct Map Map; -typedef struct MapEnt MapEnt; -struct Map { - MapEnt **bucket; - uint nhash; +struct Area { + Area* next; + Area* prev; + Frame* frame; + Frame* stack; + Frame* sel; + View* view; + bool floating; + ushort id; + int mode; + Rectangle r; }; -struct MapEnt { - ulong hash; - char *key; - void *val; - MapEnt *next; +struct Bar { + Bar* next; + Bar* smaller; + char buf[280]; + char text[256]; + char name[256]; + ushort id; + Rectangle r; + CTuple col; }; -struct View { - View *next; - char name[256]; - ushort id; - Area *area; - Area *sel; - Area *revert; +struct Client { + Client* next; + Area* revert; + Frame* frame; + Frame* sel; + Window w; + Window* framewin; + XWindow trans; + Group* group; + Strut* strut; + Cursor cursor; + Rectangle r; + char name[256]; + char tags[256]; + char props[512]; + uint border; + long proto; + char floating; + char fixedsize; + char fullscreen; + char urgent; + char borderless; + char titleless; + char noinput; + int unmapped; }; -struct Area { - Area *next, *prev; - Frame *frame; - Frame *stack; - Frame *sel; - View *view; - Bool floating; - ushort id; - int mode; - Rectangle r; +struct Divide { + Divide* next; + Window* w; + bool mapped; + int x; }; struct Frame { - Frame *cnext; - Frame *anext, *aprev; - Frame *snext, *sprev; - View *view; - Area *area; - ushort id; - Rectangle r; - Rectangle crect; - Rectangle revert; - Client *client; - Bool collapsed; - Rectangle grabbox; - Rectangle titlebar; - float ratio; + Frame* cnext; + Frame* anext; + Frame* aprev; + Frame* snext; + Frame* sprev; + View* view; + Area* area; + Client* client; + ushort id; + bool collapsed; + float ratio; + Rectangle r; + Rectangle crect; + Rectangle revert; + Rectangle grabbox; + Rectangle titlebar; }; -struct Client { - Client *next; - Area *revert; - Frame *frame; - Frame *sel; - Window w; - Window *framewin; - XWindow trans; - Cursor cursor; - Rectangle r; - char name[256]; - char tags[256]; - char props[512]; - uint border; - int proto; - char floating; - char fixedsize; - char fullscreen; - char urgent; - char borderless; - char titleless; - char noinput; - int unmapped; +struct Group { + Group* next; + XWindow leader; + Client *client; + int ref; }; -struct Divide { - Divide *next; - Window *w; - Bool mapped; - int x; +struct Key { + Key* next; + Key* lnext; + Key* tnext; + ushort id; + char name[128]; + ulong mod; + KeyCode key; }; -struct Key { - Key *next; - Key *lnext; - Key *tnext; - ushort id; - char name[128]; - ulong mod; - KeyCode key; +struct Map { + MapEnt**bucket; + uint nhash; }; -struct Bar { - Bar *next; - Bar *smaller; - char buf[280]; - char text[256]; - char name[256]; - ushort id; - Rectangle r; - CTuple col; +struct MapEnt { + ulong hash; + const char* key; + void* val; + MapEnt* next; }; struct Rule { - Rule *next; - Reprog *regex; - char value[256]; + Rule* next; + Reprog* regex; + char value[256]; }; struct Ruleset { - Rule *rule; - char *string; - uint size; + Rule* rule; + char* string; + uint size; +}; + +struct Strut { + Rectangle left; + Rectangle right; + Rectangle top; + Rectangle bottom; +}; + +struct View { + View* next; + char name[256]; + ushort id; + Area* area; + Area* sel; + Area* colsel; + Area* oldsel; + Area* revert; }; #ifndef EXTERN @@ -197,31 +230,33 @@ struct Ruleset { /* global variables */ EXTERN struct { - CTuple focuscolor; - CTuple normcolor; - Font *font; - char *keys; + CTuple focuscolor; + CTuple normcolor; + Font* font; + char* keys; + uint keyssz; Ruleset tagrules; Ruleset colrules; - char grabmod[5]; - ulong mod; - uint border; - uint snap; - uint keyssz; - int colmode; + char grabmod[5]; + ulong mod; + uint border; + uint snap; + int colmode; } def; enum { BarLeft, BarRight }; +#define BLOCK(x) do { x; }while(0) + EXTERN struct WMScreen { - Bar *bar[2]; - View *sel; - Client *focus; - Client *hasgrab; - Window *barwin; - Image *ibuf; + Bar* bar[2]; + View* sel; + Client* focus; + Client* hasgrab; + Window* barwin; + Image* ibuf; Rectangle r; Rectangle brect; @@ -237,6 +272,13 @@ EXTERN Client c_root; EXTERN Handlers framehandler; EXTERN char buffer[8092]; +EXTERN char* _buffer; +static char* const _buf_end = buffer + sizeof buffer; + +#define bufclear() \ + BLOCK( _buffer = buffer; _buffer[0] = '\0' ) +#define bufprint(...) \ + _buffer = seprint(_buffer, _buf_end, __VA_ARGS__) /* IXP */ EXTERN IxpServer srv; @@ -245,8 +287,8 @@ EXTERN Ixp9Srv p9srv; /* X11 */ EXTERN uint num_screens; EXTERN uint valid_mask; -EXTERN uint num_lock_mask; -EXTERN Bool sel_screen; +EXTERN uint numlock_mask; +EXTERN bool sel_screen; EXTERN Cursor cursor[CurLast]; @@ -254,14 +296,4 @@ typedef void (*XHandler)(XEvent*); EXTERN XHandler handler[LASTEvent]; /* Misc */ -EXTERN Image* broken; -EXTERN Bool starting; -EXTERN Bool verbose; -EXTERN char* user; -EXTERN char* execstr; - -#define BLOCK(x) do { x; }while(0) - -#define Debug if(verbose) -#define Dprint(...) BLOCK( Debug fprint(2, __VA_ARGS__) ) diff --git a/cmd/wmii/event.c b/cmd/wmii/event.c @@ -1,4 +1,4 @@ -/* Copyright ©2006-2007 Kris Maglione <fbsdaemon@gmail.com> +/* Copyright ©2006-2008 Kris Maglione <fbsdaemon@gmail.com> * See LICENSE file for license details. */ #include "dat.h" @@ -8,15 +8,17 @@ void dispatch_event(XEvent *e) { - Debug printevent(e); + Debug(DEvent) + printevent(e); if(handler[e->type]) handler[e->type](e); } -#define handle(w, fn, ev) if(!(w)->handler->fn) {}else (w)->handler->fn((w), ev) +#define handle(w, fn, ev) \ + BLOCK(if((w)->handler->fn) (w)->handler->fn((w), ev)) uint -flushevents(long event_mask, Bool dispatch) { +flushevents(long event_mask, bool dispatch) { XEvent ev; uint n = 0; @@ -28,6 +30,37 @@ flushevents(long event_mask, Bool dispatch) { return n; } +static Bool +findenter(Display *d, XEvent *e, XPointer v) { + long *l; + + l = (long*)v; + if(*l) + return False; + if(e->type == EnterNotify) + return True; + if(e->type == MotionNotify) + (*l)++; + return False; +} + +/* This isn't perfect. If there were motion events in the queue + * before this was called, then it flushes nothing. If we don't + * check for them, we might lose a legitamate enter event. + */ +uint +flushenterevents(void) { + XEvent e; + long l; + int n; + + l = 0; + n = 0; + while(XCheckIfEvent(display, &e, findenter, (void*)&l)) + n++; + return n; +} + static void buttonrelease(XEvent *e) { XButtonPressedEvent *ev; @@ -72,6 +105,14 @@ configurerequest(XEvent *e) { } static void +clientmessage(XEvent *e) { + XClientMessageEvent *ev; + + ev = &e->xclient; + ewmh_clientmessage(ev); +} + +static void destroynotify(XEvent *e) { XDestroyWindowEvent *ev; Window *w; @@ -81,7 +122,7 @@ destroynotify(XEvent *e) { if((w = findwin(ev->window))) handle(w, destroy, ev); else { - Dprint("DestroyWindow(%ux) (no handler)\n", (uint)ev->window); + Dprint(DGeneric, "DestroyWindow(%ux) (no handler)\n", (uint)ev->window); if((c = win2client(ev->window))) fprint(2, "Badness: Unhandled DestroyNotify: " "Client: %p, Window: %W, Name: %s\n", c, &c->w, c->name); @@ -94,6 +135,7 @@ enternotify(XEvent *e) { Window *w; ev = &e->xcrossing; + xtime = ev->time; if(ev->mode != NotifyNormal) return; @@ -101,7 +143,7 @@ enternotify(XEvent *e) { handle(w, enter, ev); else if(ev->window == scr.root.w) { sel_screen = True; - draw_frames(); + frame_draw_all(); } } @@ -110,17 +152,18 @@ leavenotify(XEvent *e) { XCrossingEvent *ev; ev = &e->xcrossing; + xtime = ev->time; if((ev->window == scr.root.w) && !ev->same_screen) { sel_screen = True; - draw_frames(); + frame_draw_all(); } } void -print_focus(Client *c, char *to) { - Dprint("screen->focus: %p[%C] => %p[%C]\n", +print_focus(Client *c, const char *to) { + Dprint(DFocus, "screen->focus: %p[%C] => %p[%C]\n", screen->focus, screen->focus, c, c); - Dprint("\t%s => %s\n", clientname(screen->focus), to); + Dprint(DFocus, "\t%s => %s\n", clientname(screen->focus), to); } static void @@ -161,7 +204,7 @@ focusin(XEvent *e) { print_focus(&c_magic, "<magic>"); screen->focus = &c_magic; if(c->sel) - draw_frame(c->sel); + frame_draw(c->sel); } } } @@ -206,6 +249,7 @@ keypress(XEvent *e) { XKeyEvent *ev; ev = &e->xkey; + xtime = ev->time; ev->state &= valid_mask; if(ev->window == scr.root.w) kpress(scr.root.w, ev->state, (KeyCode) ev->keycode); @@ -227,17 +271,16 @@ maprequest(XEvent *e) { XWindowAttributes wa; ev = &e->xmaprequest; - if(!XGetWindowAttributes(display, ev->window, &wa)) return; - if(wa.override_redirect) { + /* Do I really want these? */ XSelectInput(display, ev->window, (StructureNotifyMask | PropertyChangeMask)); return; } if(!win2client(ev->window)) - create_client(ev->window, &wa); + client_create(ev->window, &wa); } static void @@ -246,6 +289,7 @@ motionnotify(XEvent *e) { Window *w; ev = &e->xmotion; + xtime = ev->time; if((w = findwin(ev->window))) handle(w, motion, ev); } @@ -256,6 +300,7 @@ propertynotify(XEvent *e) { Window *w; ev = &e->xproperty; + xtime = ev->time; if((w = findwin(ev->window))) handle(w, property, ev); } @@ -286,6 +331,7 @@ void (*handler[LASTEvent]) (XEvent *) = { [ButtonPress] = buttonpress, [ButtonRelease] = buttonrelease, [ConfigureRequest] = configurerequest, + [ClientMessage] = clientmessage, [DestroyNotify] = destroynotify, [EnterNotify] = enternotify, [Expose] = expose, diff --git a/cmd/wmii/ewmh.c b/cmd/wmii/ewmh.c @@ -0,0 +1,500 @@ +/* Copyright ©2007-2008 Kris Maglione <fbsdaemon@gmail.com> + * See LICENSE file for license details. + */ +#include "dat.h" +#include <assert.h> +#include <sys/limits.h> +#include "fns.h" + +Window *ewmhwin; + +#define Net(x) ("_NET_" x) +#define Action(x) ("_NET_WM_ACTION_" x) +#define State(x) ("_NET_WM_STATE_" x) +#define Type(x) ("_NET_WM_WINDOW_TYPE_" x) +#define NET(x) xatom(Net(x)) +#define ACTION(x) xatom(Action(x)) +#define STATE(x) xatom(State(x)) +#define TYPE(x) xatom(Type(x)) + +static void +senemessage(Window *w, char *name, char *value, long l2, long l3, long l4) { + XClientMessageEvent e; + + e.type = ClientMessage; + e.window = w->w; + e.message_type = xatom(name); + e.format = 32; + e.data.l[0] = xatom(value); + e.data.l[1] = xtime; + e.data.l[2] = l2; + e.data.l[3] = l3; + e.data.l[4] = l4; + sendevent(w, false, NoEventMask, (XEvent*)&e); +} + +void +ewmh_init(void) { + WinAttr wa; + char myname[] = "wmii"; + long win[1]; + + ewmhwin = createwindow(&scr.root, + Rect(0, 0, 1, 1), 0 /*depth*/, + InputOnly, &wa, 0); + + win[0] = ewmhwin->w; + changeprop_long(&scr.root, Net("SUPPORTING_WM_CHECK"), "WINDOW", win, 1); + changeprop_long(ewmhwin, Net("SUPPORTING_WM_CHECK"), "WINDOW", win, 1); + changeprop_string(ewmhwin, Net("WM_NAME"), myname); + changeprop_long(&scr.root, Net("DESKTOP_VIEWPORT"), "CARDINAL", + (long[]){0, 0}, 2); + + long supported[] = { + /* Misc */ + NET("SUPPORTED"), + /* Root Properties */ + NET("ACTIVE_WINDOW"), + NET("CURRENT_DESKTOP"), + /* Client Properties */ + NET("WM_NAME"), + NET("WM_STRUT_PARTIAL"), + NET("WM_DESKTOP"), + NET("FRAME_EXTENTS"), + /* States */ + NET("WM_STATE"), + STATE("DEMANDS_ATTENTION"), + STATE("FULLSCREEN"), + STATE("SHADED"), + /* Window Types */ + NET("WM_WINDOW_TYPE"), + TYPE("DIALOG"), + TYPE("DOCK"), + TYPE("NORMAL"), + TYPE("SPLASH"), + /* Actions */ + NET("WM_ALLOWED_ACTIONS"), + ACTION("FULLSCREEN"), + /* Desktops */ + NET("DESKTOP_NAMES"), + NET("NUMBER_OF_DESKTOPS"), + /* Client List */ + NET("CLIENT_LIST"), + NET("CLIENT_LIST_STACKING"), + }; + changeprop_long(&scr.root, Net("SUPPORTED"), "ATOM", supported, nelem(supported)); +} + +void +ewmh_updateclientlist(void) { + Client *c; + long *list; + int i; + + i = 0; + for(c=client; c; c=c->next) + i++; + list = emalloc(i * sizeof *list); + for(c=client, i=0; c; c=c->next) + list[i++] = c->w.w; + changeprop_long(&scr.root, Net("CLIENT_LIST"), "WINDOW", list, i); +} + +void +ewmh_updatestacking(void) { + Vector_long vec; + Frame *f; + Area *a; + View *v; + + vector_linit(&vec); + + for(v=view; v; v=v->next) + for(f=v->area->stack; f; f=f->snext) + if(f->client->sel == f) + vector_lpush(&vec, f->client->w.w); + for(v=view; v; v=v->next) + for(a=v->area->next; a; a=a->next) + for(f=a->frame; f; f=f->anext) + if(f->client->sel == f) + vector_lpush(&vec, f->client->w.w); + + changeprop_long(&scr.root, Net("CLIENT_LIST_STACKING"), "WINDOW", vec.ary, vec.n); + vector_lfree(&vec); +} + +void +ewmh_initclient(Client *c) { + long allowed[] = { + ACTION("FULLSCREEN"), + }; + + changeprop_long(&c->w, Net("WM_ALLOWED_ACTIONS"), "ATOM", + allowed, nelem(allowed)); + ewmh_getwintype(c); + ewmh_updateclientlist(); +} + +void +ewmh_destroyclient(Client *c) { + Ewmh *e; + + ewmh_updateclientlist(); + + e = &c->w.ewmh; + if(e->timer) + ixp_unsettimer(&srv, e->timer); +} + +static void +pingtimeout(long id, void *v) { + Client *c; + + c = v; + event("Unresponsive %C\n", c); + c->w.ewmh.ping = 0; + c->w.ewmh.timer = 0; +} + +void +ewmh_pingclient(Client *c) { + Ewmh *e; + + if(!(c->proto & ProtoPing)) + return; + + e = &c->w.ewmh; + if(e->ping) + return; + + senemessage(&c->w, "WM_PROTOCOLS", Net("WM_PING"), c->w.w, 0, 0); + e->ping = xtime++; + e->timer = ixp_settimer(&srv, PingTime, pingtimeout, c); +} + +void +ewmh_prop(Client *c, Atom a) { + if(a == NET("WM_WINDOW_TYPE")) + ewmh_getwintype(c); + else + if(a == NET("WM_STRUT_PARTIAL")) + ewmh_getstrut(c); +} + +typedef struct Prop Prop; +struct Prop { + char* name; + long mask; + Atom atom; +}; + +static long +getmask(Prop *props, long *vals, int n) { + Prop *p; + long ret; + + if(props[0].atom == 0) + for(p=props; p->name; p++) + p->atom = xatom(p->name); + + ret = 0; + while(n--) { + Dprint(DEwmh, "\tvals[%d] = \"%A\"\n", n, vals[n]); + for(p=props; p->name; p++) + if(p->atom == vals[n]) { + ret |= p->mask; + break; + } + } + return ret; +} + +void +ewmh_getwintype(Client *c) { + static Prop props[] = { + {Type("DESKTOP"), TypeDesktop}, + {Type("DOCK"), TypeDock}, + {Type("TOOLBAR"), TypeToolbar}, + {Type("MENU"), TypeMenu}, + {Type("UTILITY"), TypeUtility}, + {Type("SPLASH"), TypeSplash}, + {Type("DIALOG"), TypeDialog}, + {Type("NORMAL"), TypeNormal}, + {0, } + }; + long *types; + long n, mask; + + n = getprop_long(&c->w, Net("WM_WINDOW_TYPE"), "ATOM", + 0L, &types, 16); + Dprint(DEwmh, "ewmh_getwintype(%C) n = %ld\n", c, n); + mask = getmask(props, types, n); + free(types); + + c->w.ewmh.type = mask; + if(mask & TypeDock) { + c->borderless = 1; + c->titleless = 1; + } +} + +long +ewmh_protocols(Window *w) { + static Prop props[] = { + {"WM_DELETE_WINDOW", ProtoDelete}, + {"WM_TAKE_FOCUS", ProtoTakeFocus}, + {Net("WM_PING"), ProtoPing}, + {0, } + }; + long *protos; + long n, mask; + + n = getprop_long(w, "WM_PROTOCOLS", "ATOM", + 0L, &protos, 16); + Dprint(DEwmh, "ewmh_protocols(%W) n = %ld\n", w, n); + mask = getmask(props, protos, n); + free(protos); + return mask; +} + +void +ewmh_getstrut(Client *c) { + enum { + Left, Right, Top, Bottom, + LeftMin, LeftMax, + RightMin, RightMax, + TopMin, TopMax, + BottomMin, BottomMax, + Last = BottomMax + }; + long *strut; + ulong n; + + if(c->strut) + free(c->strut); + c->strut = nil; + + n = getprop_long(&c->w, Net("WM_STRUT_PARTIAL"), "CARDINAL", + 0L, &strut, Last); + if(n != nelem(strut)) { + free(strut); + n = getprop_long(&c->w, Net("WM_STRUT"), "CARDINAL", + 0L, &strut, 4L); + if(n != 4) { + free(strut); + return; + } + strut = erealloc(strut, Last * sizeof *strut); + strut[LeftMin] = strut[RightMin] = 0; + strut[LeftMax] = strut[RightMax] = INT_MAX; + strut[TopMin] = strut[BottomMin] = 0; + strut[TopMax] = strut[BottomMax] = INT_MAX; + } + c->strut = emalloc(sizeof *c->strut); + c->strut->left = Rect(0, strut[LeftMin], strut[Left], strut[LeftMax]); + c->strut->right = Rect(-strut[Right], strut[RightMin], 0, strut[RightMax]); + c->strut->top = Rect(strut[TopMin], 0, strut[TopMax], strut[Top]); + c->strut->bottom = Rect(strut[BottomMin], -strut[Bottom], strut[BottomMax], 0); + free(strut); +} + +int +ewmh_clientmessage(XClientMessageEvent *e) { + Client *c; + View *v; + long *l; + int msg, action, i; + + l = e->data.l; + msg = e->message_type; + Dprint(DEwmh, "ClientMessage: %A\n", msg); + + if(msg == NET("WM_STATE")) { + enum { + StateUnset, + StateSet, + StateToggle, + }; + if(e->format != 32) + return -1; + c = win2client(e->window); + if(c == nil) + return 0; + switch(l[0]) { + case StateUnset: action = Off; break; + case StateSet: action = On; break; + case StateToggle: action = Toggle; break; + default: + return -1; + } + Dprint(DEwmh, "\tAction: %s\n", TOGGLE(action)); + for(i = 1; i <= 2; i++) { + if(l[i] == 0) + break; + Dprint(DEwmh, "\tl[%d] = %A\n", i, l[i]); + if(l[i] == STATE("FULLSCREEN")) + fullscreen(c, action); + else + if(l[i] == STATE("DEMANDS_ATTENTION")) + client_seturgent(c, action, false); + } + return 1; + }else + if(msg == NET("ACTIVE_WINDOW")) { + if(e->format != 32) + return -1; + Dprint(DEwmh, "\tsource: %ld\n", l[0]); + Dprint(DEwmh, "\twindow: 0x%lx\n", e->window); + c = win2client(e->window); + if(c == nil) + return 1; + Dprint(DEwmh, "\tclient: %s\n", clientname(c)); + if(l[0] != 2) + return 1; + focus(c, true); + return 1; + }else + if(msg == NET("CURRENT_DESKTOP")) { + if(e->format != 32) + return -1; + for(v=view, i=l[0]; v; v=v->next, i--) + if(i == 0) + break; + Dprint(DEwmh, "\t%s\n", v->name); + if(i == 0) + view_select(v->name); + return 1; + }else + if(msg == xatom("WM_PROTOCOLS")) { + Dprint(DEwmh, "\t%A\n", l[0]); + if(l[0] == NET("WM_PING")) { + if(e->format != 32) + return -1; + if(e->window != scr.root.w) + return -1; + c = win2client(l[2]); + if(c == nil) + return 1; + Dprint(DEwmh, "\tclient = [%C]\"%s\"\n", c, clientname(c)); + Dprint(DEwmh, "\ttimer = %ld, ping = %ld\n", + c->w.ewmh.timer, c->w.ewmh.ping); + if(c->w.ewmh.timer) + ixp_unsettimer(&srv, c->w.ewmh.timer); + c->w.ewmh.timer = 0; + c->w.ewmh.ping = 0; + return 1; + } + } + + return 0; +} + +void +ewmh_framesize(Client *c) { + Rectangle r; + Frame *f; + + f = c->sel; + r.min.x = f->crect.min.x; + r.min.y = f->crect.min.y; + r.max.x = f->r.max.x - f->crect.max.x; + r.max.y = f->r.max.y - f->crect.max.y; + + long extents[] = { + r.min.x, r.max.x, + r.min.y, r.max.y, + }; + changeprop_long(&c->w, Net("FRAME_EXTENTS"), "CARDINAL", + extents, nelem(extents)); +} + +void +ewmh_updatestate(Client *c) { + long state[16]; + Frame *f; + int i; + + f = c->sel; + if(f->view != screen->sel) + return; + + i = 0; + if(f->collapsed) + state[i++] = STATE("SHADED"); + if(c->fullscreen) + state[i++] = STATE("FULLSCREEN"); + if(c->urgent) + state[i++] = STATE("DEMANDS_ATTENTION"); + + if(i > 0) + changeprop_long(&c->w, Net("WM_STATE"), "ATOM", state, i); + else + delproperty(&c->w, Net("WM_STATE")); +} + +/* Views */ +void +ewmh_updateviews(void) { + View *v; + char **tags; + long i; + + if(starting) + return; + + for(v=view, i=0; v; v=v->next) + i++; + tags = emalloc((i + 1) * sizeof *tags); + for(v=view, i=0; v; v=v->next) + tags[i++] = v->name; + tags[i] = nil; + changeprop_textlist(&scr.root, Net("DESKTOP_NAMES"), "UTF8_STRING", tags); + changeprop_long(&scr.root, Net("NUMBER_OF_DESKTOPS"), "CARDINAL", &i, 1); + ewmh_updateview(); + ewmh_updateclients(); +} + +static int +viewidx(View *v) { + View *vp; + int i; + + for(vp=view, i=0; vp; vp=vp->next, i++) + if(vp == v) + break; + assert(vp); + return i; +} + +void +ewmh_updateview(void) { + long i; + + if(starting) + return; + + i = viewidx(screen->sel); + changeprop_long(&scr.root, Net("CURRENT_DESKTOP"), "CARDINAL", &i, 1); +} + +void +ewmh_updateclient(Client *c) { + long i; + + i = -1; + if(c->sel) + i = viewidx(c->sel->view); + changeprop_long(&c->w, Net("WM_DESKTOP"), "CARDINAL", &i, 1); +} + +void +ewmh_updateclients(void) { + Client *c; + + if(starting) + return; + + for(c=client; c; c=c->next) + ewmh_updateclient(c); +} + diff --git a/cmd/wmii/fns.h b/cmd/wmii/fns.h @@ -1,101 +1,156 @@ -/* © 2004-2006 Anselm R. Garbe <garbeam at gmail dot com> +/* Copyright ©2007-2008 Kris Maglione <jg@suckless.org> * See LICENSE file for license details. */ #ifdef VARARGCK -# pragma varargck argpos write_event 1 +# pragma varargck argpos event 1 # # pragma varargck type "C" Client* -# pragma varargck type "W" Window* -# pragma varargck type "P" Point -# pragma varargck type "R" Rectangle # pragma varargck type "r" void #endif +/* XXX: These don't belong here. */ + +typedef struct Vector_long Vector_long; +struct Vector_long { + long* ary; + long n; + long size; +}; + +static void +vector_linit(Vector_long *v) { + memset(v, 0, sizeof *v); +} + +static void +vector_lfree(Vector_long *v) { + free(v->ary); + memset(v, 0, sizeof *v); +} + +static void +vector_lpush(Vector_long *v, long val) { + if(v->n == v->size) { + if(v->size == 0) + v->size = 2; + v->size <<= 2; + v->ary = erealloc(v->ary, v->size * sizeof *v->ary); + } + v->ary[v->n++] = val; +} + +static inline void +__grr__(void) { + vector_linit(nil); + vector_lfree(nil); + vector_lpush(nil, 0); +} + /* area.c */ +void area_attach(Area*, Frame*); +Area* area_create(View*, Area *pos, uint w); +void area_destroy(Area*); +void area_detach(Frame*); +void area_focus(Area*); uint area_idx(Area*); +void area_moveto(Area*, Frame*); char* area_name(Area*); Client* area_selclient(Area*); -void attach_to_area(Area*, Frame*); -Area* create_area(View*, Area *pos, uint w); -void destroy_area(Area*); -void detach_from_area(Frame*); -void focus_area(Area*); -void send_to_area(Area*, Frame*); +void area_setsel(Area*, Frame*); /* bar.c */ -Bar* bar_of_name(Bar*, const char*); -Bar* create_bar(Bar**, char*); -void destroy_bar(Bar**, Bar*); -void draw_bar(WMScreen*); -void initbar(WMScreen*); -void resize_bar(WMScreen*); +Bar* bar_create(Bar**, const char*); +void bar_destroy(Bar**, Bar*); +void bar_draw(WMScreen*); +Bar* bar_find(Bar*, const char*); +void bar_init(WMScreen*); +void bar_resize(WMScreen*); /* client.c */ int Cfmt(Fmt *f); void apply_rules(Client*); void apply_tags(Client*, const char*); +void client_configure(Client*); +Client* client_create(XWindow, XWindowAttributes*); +void client_destroy(Client*); +void client_focus(Client*); +void client_kill(Client*, bool); +void client_manage(Client*); +void client_map(Client*); +void client_prop(Client*, Atom); +void client_reparent(Client*, Window*, Point); +void client_resize(Client*, Rectangle); +void client_setcursor(Client*, Cursor); +void client_seturgent(Client*, int urgent, bool write); +void client_unmap(Client*, int state); +Frame* client_viewframe(Client *c, View *v); char* clientname(Client*); -void configure_client(Client*); -Client* create_client(XWindow, XWindowAttributes*); -void destroy_client(Client*); -void focus(Client*, Bool restack); -void focus_client(Client*); -void focus_frame(Frame*, Bool restack); -void fullscreen(Client*, Bool); -void kill_client(Client*); -void manage_client(Client*); -void map_client(Client*); +void focus(Client*, bool restack); +void fullscreen(Client*, int); int map_frame(Client*); -void move_client(Client*, char*); -void prop_client(Client*, Atom); -void reparent_client(Client*, Window*, Point); -void resize_client(Client*, Rectangle); Client* selclient(void); -void set_cursor(Client*, Cursor); -void set_urgent(Client *, Bool urgent, Bool write); -void size_client(Client*, char*); -void unmap_client(Client*, int state); int unmap_frame(Client*); void update_class(Client*); Client* win2client(XWindow); -Rectangle gravclient(Client*, Rectangle); +Rectangle client_grav(Client*, Rectangle); /* column.c */ -void arrange_column(Area*, Bool dirty); char* colmode2str(int); -void draw_div(Divide*); -Area* new_column(View*, Area *, uint); -void resize_colframe(Frame*, Rectangle*); -void resize_column(Area*, int); -void setdiv(Divide*, int x); int str2colmode(const char*); -void update_divs(void); +void column_arrange(Area*, bool dirty); +Area* column_new(View*, Area *, uint); +void column_resize(Area*, int); +void column_resizeframe(Frame*, Rectangle*); +void div_draw(Divide*); +void div_set(Divide*, int x); +void div_update_all(void); /* event.c */ void check_x_event(IxpConn*); void dispatch_event(XEvent*); -uint flushevents(long, Bool dispatch); -void print_focus(Client*, char*); +uint flushenterevents(void); +uint flushevents(long, bool dispatch); +void print_focus(Client*, const char*); + +/* ewmh.c */ +int ewmh_clientmessage(XClientMessageEvent*); +void ewmh_destroyclient(Client*); +void ewmh_framesize(Client*); +void ewmh_getstrut(Client*); +void ewmh_getwintype(Client*); +void ewmh_init(void); +void ewmh_initclient(Client*); +void ewmh_pingclient(Client*); +void ewmh_prop(Client*, Atom); +long ewmh_protocols(Window*); +void ewmh_updateclient(Client*); +void ewmh_updateclientlist(void); +void ewmh_updateclients(void); +void ewmh_updatestacking(void); +void ewmh_updatestate(Client*); +void ewmh_updateview(void); +void ewmh_updateviews(void); /* frame.c */ -Frame* create_frame(Client*, View*); -void draw_frame(Frame*); -void draw_frames(void); +Frame* frame_create(Client*, View*); int frame_delta_h(void); +void frame_draw(Frame*); +void frame_draw_all(void); +void frame_focus(Frame*); uint frame_idx(Frame*); -Bool frame_to_top(Frame*); -int ingrabbox(Frame*, int x, int y); -void insert_frame(Frame *pos, Frame*); -void remove_frame(Frame*); -void resize_frame(Frame*, Rectangle); -void set_frame_cursor(Frame*, Point); -void swap_frames(Frame*, Frame*); -void update_frame_widget_colors(Frame*); +void frame_insert(Frame *pos, Frame*); +void frame_remove(Frame*); +void frame_resize(Frame*, Rectangle); +bool frame_restack(Frame*, Frame*); +void frame_setcursor(Frame*, Point); +void frame_swap(Frame*, Frame*); +int ingrabbox_p(Frame*, int x, int y); +void move_focus(Frame*, Frame*); Rectangle constrain(Rectangle); -Rectangle client2frame(Frame*, Rectangle); -Rectangle frame2client(Frame*, Rectangle); +Rectangle frame_client2rect(Frame*, Rectangle); Rectangle frame_hints(Frame*, Rectangle, Align); +Rectangle frame_rect2client(Frame*, Rectangle); /* fs.c */ void fs_attach(Ixp9Req*); @@ -109,136 +164,52 @@ void fs_remove(Ixp9Req*); void fs_stat(Ixp9Req*); void fs_walk(Ixp9Req*); void fs_write(Ixp9Req*); -void write_event(char*, ...); +void event(const char*, ...); /* geom.c */ -Cursor cursor_of_quad(Align); +Cursor quad_cursor(Align); Align get_sticky(Rectangle src, Rectangle dst); -Bool ptinrect(Point, Rectangle); +bool rect_haspoint_p(Point, Rectangle); Align quadrant(Rectangle, Point); /* key.c */ void init_lock_keys(void); void kpress(XWindow, ulong mod, KeyCode); -ulong str2modmask(char*); +ulong str2modmask(const char*); void update_keys(void); /* map.c */ -MapEnt* hashget(Map*, char*, int create); -void* hashrm(Map*, char*); -MapEnt* mapget(Map*, ulong, int create); -void* maprm(Map*, ulong); +MapEnt* hash_get(Map*, const char*, int create); +void* hash_rm(Map*, const char*); +MapEnt* map_get(Map*, ulong, int create); +void* map_rm(Map*, ulong); /* message.c */ -int getlong(char*, long*); -int getulong(char*, ulong*); -char* getword(IxpMsg*); +int getlong(const char*, long*); +int getulong(const char*, ulong*); char* message_client(Client*, IxpMsg*); char* message_root(void*, IxpMsg*); char* message_view(View*, IxpMsg*); -char* parse_colors(IxpMsg*, CTuple*); -char* read_root_ctl(void); -char* select_area(Area*, IxpMsg*); -char* send_client(View*, IxpMsg*, Bool swap); -Area* strarea(View*, char*); +char* msg_getword(IxpMsg*); +char* msg_parsecolors(IxpMsg*, CTuple*); +char* msg_selectarea(Area*, IxpMsg*); +char* msg_sendclient(View*, IxpMsg*, bool swap); +char* root_readctl(void); +Area* strarea(View*, const char*); /* mouse.c */ -void do_mouse_resize(Client*, Bool opaque, Align); -void grab_button(XWindow, uint button, ulong mod); -void grab_mouse(XWindow, ulong mod, ulong button); +void mouse_resize(Client*, bool opaque, Align); void mouse_resizecol(Divide*); +void grab_button(XWindow, uint button, ulong mod); Align snap_rect(Rectangle *rects, int num, Rectangle *current, Align *mask, int snapw); -void ungrab_mouse(XWindow, ulong mod, uint button); /* rule.c */ void trim(char *str, const char *chars); void update_rules(Rule**, const char*); /* view.c */ -View *get_view(const char*); -void arrange_view(View*); -void attach_to_view(View*, Frame*); -View* create_view(const char*); -void destroy_view(View*); -void focus_view(WMScreen*, View*); -char* message_view(View *v, IxpMsg *m); -uint newcolw(View*, int i); -void restack_view(View*); -void scale_view(View*, int w); -void select_view(const char*); -void update_client_views(Client*, char**); -void update_views(void); -Frame* view_clientframe(View *v, Client *c); -uchar* view_ctl(View *v); -uchar* view_index(View*); -View* view_of_id(ushort); -Client* view_selclient(View*); -Rectangle* rects_of_view(View*, uint *num, Frame *ignore); - -/* wm.c */ -int win_proto(Window); - -/* x11.c */ -Window *createwindow(Window *parent, Rectangle, int depth, uint class, WinAttr*, int valuemask); -char *gettextproperty(Window*, char*); -Point addpt(Point, Point); -Image* allocimage(int w, int h, int depth); -void border(Image *dst, Rectangle, int w, ulong col); -void changeprop_char(Window *w, char *prop, char *type, char data[], int len); -void changeprop_long(Window *w, char *prop, char *type, long data[], int len); -void changeprop_short(Window *w, char *prop, char *type, short data[], int len); -void changeproperty(Window*, char *prop, char *type, int width, uchar *data, int n); -void copyimage(Image *dst, Rectangle, Image *src, Point p); -void destroywindow(Window*); -Point divpt(Point, Point); -void drawline(Image *dst, Point p1, Point p2, int cap, int w, ulong col); -void drawpoly(Image *dst, Point *pt, int np, int cap, int w, ulong col); -void drawstring(Image *dst, Font *font, Rectangle, Align align, char *text, ulong col); -int eqpt(Point, Point); -int eqrect(Rectangle, Rectangle); -void fill(Image *dst, Rectangle, ulong col); -void fillpoly(Image *dst, Point *pt, int np, ulong col); -Window* findwin(XWindow); -void freefont(Font*); -void freeimage(Image *); -void freestringlist(char**); -ulong getproperty(Window *w, char *prop, char *type, Atom *actual, ulong offset, uchar **ret, ulong length); -int gettextlistproperty(Window *w, char *name, char **ret[]); -int grabpointer(Window*, Window *confine, Cursor, int mask); -void initdisplay(void); -uint labelh(Font*); -Bool loadcolor(CTuple*, char*); -Font* loadfont(char*); -void lowerwin(Window*); -int mapwin(Window*); -void movewin(Window*, Point); -Point mulpt(Point p, Point q); -Bool namedcolor(char *name, ulong*); -Point querypointer(Window*); -void raisewin(Window*); -void reparentwindow(Window*, Window*, Point); -void reshapewin(Window*, Rectangle); -void setfocus(Window*, int mode); -void sethints(Window*); -void setshapemask(Window *dst, Image *src, Point); -void setwinattr(Window*, WinAttr*, int valmask); -Point subpt(Point, Point); -uint textwidth(Font*, char*); -uint textwidth_l(Font*, char*, uint len); -Point translate(Window*, Window*, Point); -void ungrabpointer(void); -int unmapwin(Window*); -void warppointer(Point); -uint winprotocols(Window*); -Atom xatom(char*); -Handlers* sethandler(Window*, Handlers*); -XRectangle XRect(Rectangle); -Rectangle gravitate(Rectangle dst, Rectangle src, Point grav); -Rectangle insetrect(Rectangle, int); -Rectangle rectaddpt(Rectangle, Point); -Rectangle rectsubpt(Rectangle, Point); -Rectangle sizehint(WinHints*, Rectangle); /* utf.c */ -char* toutf8(char*); -char* toutf8n(char*, size_t); +char* toutf8(const char*); +char* toutf8n(const char*, size_t); + diff --git a/cmd/wmii/frame.c b/cmd/wmii/frame.c @@ -1,4 +1,4 @@ -/* Copyright ©2006-2007 Kris Maglione <fbsdaemon@gmail.com> +/* Copyright ©2006-2008 Kris Maglione <fbsdaemon@gmail.com> * See LICENSE file for license details. */ #include "dat.h" @@ -16,8 +16,8 @@ frame_idx(Frame *f) { return i; } -Frame * -create_frame(Client *c, View *v) { +Frame* +frame_create(Client *c, View *v) { static ushort id = 1; Frame *f; @@ -31,7 +31,7 @@ create_frame(Client *c, View *v) { f->r = c->sel->r; } else{ - f->r = client2frame(f, gravclient(c, ZR)); + f->r = frame_client2rect(f, client_grav(c, ZR)); f->revert = f->r; c->sel = f; } @@ -41,7 +41,7 @@ create_frame(Client *c, View *v) { } void -remove_frame(Frame *f) { +frame_remove(Frame *f) { Area *a; a = f->area; @@ -64,7 +64,7 @@ remove_frame(Frame *f) { } void -insert_frame(Frame *pos, Frame *f) { +frame_insert(Frame *pos, Frame *f) { Area *a; a = f->area; @@ -89,32 +89,42 @@ insert_frame(Frame *pos, Frame *f) { } } -Bool -frame_to_top(Frame *f) { +bool +frame_restack(Frame *f, Frame *above) { Area *a; a = f->area; - if(!a->floating || f == a->stack) - return False; + if(!a->floating) + return false; + if(above && above->area != a) + return false; if(f->sprev) f->sprev->snext = f->snext; + else + a->stack = f->snext; if(f->snext) f->snext->sprev = f->sprev; - f->snext = a->stack; - a->stack = f; - f->sprev = nil; + f->sprev = above; + if(above == nil) { + f->snext = a->stack; + a->stack = f; + } + else { + f->snext = above->snext; + above->snext = f; + } if(f->snext) f->snext->sprev = f; - return True; + return true; } /* Handlers */ static void bup_event(Window *w, XButtonEvent *e) { - write_event("ClientClick %C %d\n", w->aux, e->button); + event("ClientClick %C %d\n", w->aux, e->button); } static void @@ -128,15 +138,15 @@ bdown_event(Window *w, XButtonEvent *e) { 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); + mouse_resize(c, False, CENTER); + focus(c, false); + frame_restack(f, nil); + focus(c, false); /* Blech */ 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); + mouse_resize(c, False, quadrant(f->r, Pt(e->x_root, e->y_root))); + frame_restack(f, nil); + focus(c, false); break; default: XAllowEvents(display, ReplayPointer, e->time); @@ -146,25 +156,25 @@ bdown_event(Window *w, XButtonEvent *e) { 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); + if(frame_restack(f, nil)) + view_restack(f->view); + else if(rect_haspoint_p(Pt(e->x, e->y), f->grabbox)) + mouse_resize(c, True, CENTER); 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(!e->subwindow && !rect_haspoint_p(Pt(e->x, e->y), f->titlebar)) + mouse_resize(c, False, quadrant(f->r, Pt(e->x_root, e->y_root))); if(f->client != selclient()) - focus(c, True); + focus(c, false); } 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); + sync(); - write_event("ClientMouseDown %C %d\n", f->client, e->button); + event("ClientMouseDown %C %d\n", f->client, e->button); } } } @@ -176,12 +186,12 @@ enter_event(Window *w, XCrossingEvent *e) { c = w->aux; f = c->sel; - if(screen->focus != c) { - Dprint("enter_notify(f) => %s\n", f->client->name); + if(screen->focus != c || selclient() != c) { + Dprint(DGeneric, "enter_notify(f) => %s\n", f->client->name); if(f->area->floating || !f->collapsed) - focus(f->client, False); + focus(f->client, false); } - set_frame_cursor(f, Pt(e->x, e->y)); + frame_setcursor(f, Pt(e->x, e->y)); } static void @@ -192,7 +202,7 @@ expose_event(Window *w, XExposeEvent *e) { c = w->aux; if(c->sel) - draw_frame(c->sel); + frame_draw(c->sel); else fprint(2, "Badness: Expose event on a client frame which shouldn't be visible: %C\n", c); @@ -203,7 +213,7 @@ motion_event(Window *w, XMotionEvent *e) { Client *c; c = w->aux; - set_frame_cursor(c->sel, Pt(e->x, e->y)); + frame_setcursor(c->sel, Pt(e->x, e->y)); } Handlers framehandler = { @@ -215,7 +225,7 @@ Handlers framehandler = { }; Rectangle -frame2client(Frame *f, Rectangle r) { +frame_rect2client(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(); @@ -237,7 +247,7 @@ frame2client(Frame *f, Rectangle r) { } Rectangle -client2frame(Frame *f, Rectangle r) { +frame_client2rect(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(); @@ -257,10 +267,11 @@ client2frame(Frame *f, Rectangle r) { } void -resize_frame(Frame *f, Rectangle r) { +frame_resize(Frame *f, Rectangle r) { Align stickycorner; Point pt; Client *c; + int collapsed; c = f->client; stickycorner = get_sticky(f->r, r); @@ -275,9 +286,11 @@ resize_frame(Frame *f, Rectangle r) { else f->r = r; - f->crect = frame2client(f, f->crect); + f->crect = frame_rect2client(f, f->crect); f->crect = rectsubpt(f->crect, f->crect.min); + collapsed = f->collapsed; + if(!f->area->floating && f->area->mode == Coldefault) { if(Dy(f->r) < 2 * labelh(def.font)) f->collapsed = True; @@ -295,6 +308,9 @@ resize_frame(Frame *f, Rectangle r) { f->crect = f->r; } + if(collapsed != f->collapsed) + ewmh_updatestate(c); + pt = ZP; if(!f->client->borderless || !f->area->floating) pt.y += 1; @@ -304,7 +320,7 @@ resize_frame(Frame *f, Rectangle r) { if(f->area->floating) { if(c->fullscreen) { f->crect = screen->r; - f->r = client2frame(f, f->crect); + f->r = frame_client2rect(f, f->crect); pt.x = (Dx(f->r) - Dx(f->crect)) / 2; f->r = rectsubpt(f->r, pt); }else @@ -315,22 +331,22 @@ resize_frame(Frame *f, Rectangle r) { } void -set_frame_cursor(Frame *f, Point pt) { +frame_setcursor(Frame *f, Point pt) { Rectangle r; Cursor cur; if(f->area->floating - && !ptinrect(pt, f->titlebar) - && !ptinrect(pt, f->crect)) { + && !rect_haspoint_p(pt, f->titlebar) + && !rect_haspoint_p(pt, f->crect)) { r = rectsubpt(f->r, f->r.min); - cur = cursor_of_quad(quadrant(r, pt)); - set_cursor(f->client, cur); + cur = quad_cursor(quadrant(r, pt)); + client_setcursor(f->client, cur); } else - set_cursor(f->client, cursor[CurNormal]); + client_setcursor(f->client, cursor[CurNormal]); } void -swap_frames(Frame *fa, Frame *fb) { +frame_swap(Frame *fa, Frame *fb) { Frame **fp; Client *c; @@ -355,33 +371,52 @@ swap_frames(Frame *fa, Frame *fb) { c->frame = fa; if(c->sel && c->sel->view == screen->sel) - focus_view(screen, c->sel->view); + view_focus(screen, c->sel->view); } void -focus_frame(Frame *f, Bool restack) { +move_focus(Frame *old_f, Frame *f) { + int noinput; + + noinput = (old_f && old_f->client->noinput) || + (f && f->client->noinput) || + screen->hasgrab != &c_root; + if(noinput) { + if(old_f) + frame_draw(old_f); + if(f) + frame_draw(f); + } +} + +void +frame_focus(Frame *f) { + Client *c; + Frame *old_f; View *v; Area *a, *old_a; - a = f->area; + c = f->client; v = f->view; + a = f->area; old_a = v->sel; + old_f = old_a->sel; a->sel = f; if(a != old_a) - focus_area(f->area); + area_focus(f->area); + if(old_a != v->oldsel && f != old_f) + v->oldsel = nil; - if(v != screen->sel) + if(v != screen->sel || a != v->sel) return; - focus_client(f->client); + move_focus(old_f, f); + client_focus(f->client); if(!a->floating && ((a->mode == Colstack) || (a->mode == Colmax))) - arrange_column(a, False); - - if(restack) - restack_view(v); + column_arrange(a, False); } int @@ -390,15 +425,17 @@ frame_delta_h(void) { } void -draw_frame(Frame *f) { +frame_draw(Frame *f) { Rectangle r, fr; CTuple *col; Frame *tf; + uint w; if(f->view != screen->sel) return; - if(f->client == screen->focus) + if(f->client == screen->focus + || f->client == selclient()) col = &def.focuscolor; else col = &def.normcolor; @@ -422,6 +459,11 @@ draw_frame(Frame *f) { f->titlebar = insetrect(r, 3); f->titlebar.max.y += 3; + /* Odd state of focus. */ + if(f->client != selclient() && col == &def.focuscolor) + border(screen->ibuf, insetrect(r, 1), + 1, def.normcolor.bg); + /* grabbox */ r.min = Pt(2, 2); r.max.x = r.min.x + def.font->height - 3; @@ -432,25 +474,34 @@ draw_frame(Frame *f) { fill(screen->ibuf, r, col->fg); border(screen->ibuf, r, 1, col->border); + /* Odd state of focus. */ + if(f->client != screen->focus && col == &def.focuscolor) + border(screen->ibuf, insetrect(r, -1), + 1, def.normcolor.bg); + + /* Label */ 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, + if(f->client->floating) + r.max.x -= Dx(f->grabbox); + w = 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(void) { +frame_draw_all(void) { Client *c; for(c=client; c; c=c->next) if(c->sel && c->sel->view == screen->sel) - draw_frame(c->sel); + frame_draw(c->sel); } Rectangle diff --git a/cmd/wmii/fs.c b/cmd/wmii/fs.c @@ -1,12 +1,10 @@ -/* Copyright ©2006 Kris Maglione <fbsdaemon at gmail dot com> +/* Copyright ©2006-2008 Kris Maglione <fbsdaemon at gmail dot com> * See LICENSE file for license details. */ #include "dat.h" #include <assert.h> #include <ctype.h> #include <stdarg.h> -#include <stdlib.h> -#include <string.h> #include <time.h> #include "fns.h" @@ -109,7 +107,7 @@ dirtab_clients[]={{".", QTDIR, FsDClients, 0500|DMDIR }, {nil}}, dirtab_client[]= {{".", QTDIR, FsDClient, 0500|DMDIR }, {"ctl", QTAPPEND, FsFCctl, 0600|DMAPPEND }, - {"label", QTFILE, FsFClabel, 0600 }, + {"label", QTFILE, FsFClabel, 0600 }, {"tags", QTFILE, FsFCtags, 0600 }, {"props", QTFILE, FsFprops, 0400 }, {nil}}, @@ -200,7 +198,7 @@ write_to_buf(Ixp9Req *r, char **buf, uint *len, uint max) { *len = offset + count; if(max == 0) - *buf = erealloc((void*)*buf, *len + 1); + *buf = erealloc(*buf, *len + 1); p = *buf; @@ -227,7 +225,7 @@ data_to_cstring(Ixp9Req *r) { typedef char* (*MsgFunc)(void*, IxpMsg*); -static char * +static char* message(Ixp9Req *r, MsgFunc fn) { char *err, *s, *p, c; FileId *f; @@ -249,7 +247,7 @@ message(Ixp9Req *r, MsgFunc fn) { c = *p; *p = '\0'; - m = ixp_message((uchar*)s, p-s, 0); + m = ixp_message(s, p-s, 0); s = fn(f->p.ref, &m); if(s) err = s; @@ -273,7 +271,7 @@ respond_event(Ixp9Req *r) { } void -write_event(char *format, ...) { +event(const char *format, ...) { uint len, slen; va_list ap; FidLink *f; @@ -457,7 +455,7 @@ LastItem: return ret; } -static Bool +static bool verify_file(FileId *f) { FileId *nf; int ret; @@ -565,7 +563,7 @@ fs_stat(Ixp9Req *r) { IxpMsg m; Stat s; int size; - uchar *buf; + char *buf; FileId *f; f = r->fid->aux; @@ -591,7 +589,7 @@ fs_read(Ixp9Req *r) { char *buf; FileId *f, *tf; int n, offset; - int size; + ulong size; f = r->fid->aux; @@ -606,8 +604,10 @@ fs_read(Ixp9Req *r) { offset = 0; size = r->ifcall.count; + if(size > r->fid->iounit) + size = r->fid->iounit; buf = emallocz(size); - m = ixp_message((uchar*)buf, size, MsgPack); + m = ixp_message(buf, size, MsgPack); tf = f = lookup_file(f, nil); /* Note: f->tab.name == "." so we skip it */ @@ -659,7 +659,7 @@ fs_read(Ixp9Req *r) { respond(r, nil); return; case FsFRctl: - buf = read_root_ctl(); + buf = root_readctl(); write_buf(r, buf, strlen(buf)); respond(r, nil); return; @@ -673,13 +673,13 @@ fs_read(Ixp9Req *r) { respond(r, nil); return; case FsFTindex: - buf = (char*)view_index(f->p.view); + buf = view_index(f->p.view); n = strlen(buf); write_buf(r, buf, n); respond(r, nil); return; case FsFTctl: - buf = (char*)view_ctl(f->p.view); + buf = view_ctl(f->p.view); n = strlen(buf); write_buf(r, buf, n); respond(r, nil); @@ -693,7 +693,7 @@ fs_read(Ixp9Req *r) { * This is an assert because this should this should not be called if * the file is not open for reading. */ - assert(!"Read called on an unreadable file"); + die("Read called on an unreadable file"); } void @@ -727,7 +727,7 @@ fs_write(Ixp9Req *r) { case FsFClabel: data_to_cstring(r); utfecpy(f->p.client->name, f->p.client->name+sizeof(client->name), r->ifcall.data); - draw_frame(f->p.client->sel); + frame_draw(f->p.client->sel); update_class(f->p.client); r->ofcall.count = r->ifcall.count; respond(r, nil); @@ -740,7 +740,6 @@ fs_write(Ixp9Req *r) { return; case FsFBar: i = strlen(f->p.bar->buf); - /* Why the explicit cast? Ask gcc. */ p = f->p.bar->buf; write_to_buf(r, &p, &i, 279); r->ofcall.count = i - r->ifcall.offset; @@ -763,9 +762,9 @@ fs_write(Ixp9Req *r) { return; case FsFEvent: if(r->ifcall.data[r->ifcall.count-1] == '\n') - write_event("%.*s", (int)r->ifcall.count, r->ifcall.data); + event("%.*s", (int)r->ifcall.count, r->ifcall.data); else - write_event("%.*s\n", (int)r->ifcall.count, r->ifcall.data); + event("%.*s\n", (int)r->ifcall.count, r->ifcall.data); r->ofcall.count = r->ifcall.count; respond(r, nil); return; @@ -774,7 +773,7 @@ fs_write(Ixp9Req *r) { * This is an assert because this function should not be called if * the file is not open for writing. */ - assert(!"Write called on an unwritable file"); + die("Write called on an unwritable file"); } void @@ -827,7 +826,7 @@ fs_create(Ixp9Req *r) { respond(r, Ebadvalue); return; } - create_bar(f->p.bar_p, r->ifcall.name); + bar_create(f->p.bar_p, r->ifcall.name); f = lookup_file(f, r->ifcall.name); if(!f) { respond(r, Enofile); @@ -857,8 +856,8 @@ fs_remove(Ixp9Req *r) { respond(r, Enoperm); return; case FsFBar: - destroy_bar(f->next->p.bar_p, f->p.bar); - draw_bar(screen); + bar_destroy(f->next->p.bar_p, f->p.bar); + bar_draw(screen); respond(r, nil); break; } @@ -886,7 +885,7 @@ fs_clunk(Ixp9Req *r) { update_rules(&f->p.rule->rule, f->p.rule->string); for(c=client; c; c=c->next) apply_rules(c); - update_views(); + view_update_all(); break; case FsFKeys: update_keys(); @@ -894,8 +893,8 @@ fs_clunk(Ixp9Req *r) { case FsFBar: p = toutf8(f->p.bar->buf); - m = ixp_message((uchar*)p, strlen(p), 0); - parse_colors(&m, &f->p.bar->col); + m = ixp_message(p, strlen(p), 0); + msg_parsecolors(&m, &f->p.bar->col); q = (char*)m.end-1; while(q >= (char*)m.pos && *q == '\n') @@ -906,7 +905,7 @@ fs_clunk(Ixp9Req *r) { free(p); - draw_bar(screen); + bar_draw(screen); break; case FsFEvent: for(fl=&peventfid; *fl; fl=&fl[0]->next) diff --git a/cmd/wmii/geom.c b/cmd/wmii/geom.c @@ -1,11 +1,11 @@ -/* Copyright ©2006-2007 Kris Maglione <fbsdaemon@gmail.com> +/* Copyright ©2006-2008 Kris Maglione <fbsdaemon@gmail.com> * See LICENSE file for license details. */ #include "dat.h" #include "fns.h" -Bool -ptinrect(Point pt, Rectangle r) { +bool +rect_haspoint_p(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); } @@ -30,7 +30,7 @@ quadrant(Rectangle r, Point pt) { } Cursor -cursor_of_quad(Align align) { +quad_cursor(Align align) { switch(align) { case NEAST: return cursor[CurNECorner]; diff --git a/cmd/wmii/key.c b/cmd/wmii/key.c @@ -2,36 +2,38 @@ * See LICENSE file for license details. */ #include "dat.h" -#include <string.h> -#include <stdlib.h> #include <X11/keysym.h> #include "fns.h" void init_lock_keys(void) { XModifierKeymap *modmap; - KeyCode num_lock; + KeyCode numlock; static int masks[] = { - ShiftMask, LockMask, ControlMask, Mod1Mask, - Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask + ShiftMask, LockMask, ControlMask, + Mod1Mask, Mod2Mask, Mod3Mask, + Mod4Mask, Mod5Mask }; int i; - num_lock_mask = 0; + numlock_mask = 0; modmap = XGetModifierMapping(display); - num_lock = XKeysymToKeycode(display, XStringToKeysym("Num_Lock")); + numlock = keycode("Num_Lock"); + if(numlock) if(modmap && modmap->max_keypermod > 0) { - int max = (sizeof(masks) / sizeof(int)) * modmap->max_keypermod; + int max; + + max = nelem(masks) * modmap->max_keypermod; for(i = 0; i < max; i++) - if(num_lock && (modmap->modifiermap[i] == num_lock)) - num_lock_mask = masks[i / modmap->max_keypermod]; + if(modmap->modifiermap[i] == numlock) + numlock_mask = masks[i / modmap->max_keypermod]; } XFreeModifiermap(modmap); - valid_mask = 255 & ~(num_lock_mask | LockMask); + valid_mask = 255 & ~(numlock_mask | LockMask); } ulong -str2modmask(char *val) { +str2modmask(const char *val) { ulong mod = 0; if (strstr(val, "Shift")) @@ -52,38 +54,40 @@ str2modmask(char *val) { } static void -grab_key(Key *k) { +grabkey(Key *k) { XGrabKey(display, k->key, k->mod, scr.root.w, True, GrabModeAsync, GrabModeAsync); - if(num_lock_mask) { - XGrabKey(display, k->key, k->mod | num_lock_mask, scr.root.w, + if(numlock_mask) { + XGrabKey(display, k->key, k->mod | numlock_mask, scr.root.w, True, GrabModeAsync, GrabModeAsync); - XGrabKey(display, k->key, k->mod | num_lock_mask | LockMask, scr.root.w, + XGrabKey(display, k->key, k->mod | numlock_mask | LockMask, scr.root.w, True, GrabModeAsync, GrabModeAsync); } - XSync(display, False); + sync(); } static void -ungrab_key(Key *k) { +ungrabkey(Key *k) { XUngrabKey(display, k->key, k->mod, scr.root.w); - if(num_lock_mask) { - 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); + if(numlock_mask) { + XUngrabKey(display, k->key, k->mod | numlock_mask, scr.root.w); + XUngrabKey(display, k->key, k->mod | numlock_mask | LockMask, scr.root.w); } - XSync(display, False); + sync(); } static Key * name2key(const char *name) { Key *k; + for(k=key; k; k=k->lnext) - if(!strncmp(k->name, name, sizeof(k->name))) break; - return k; + if(!strncmp(k->name, name, sizeof(k->name))) + return k; + return nil; } static Key * -get_key(const char *name) { +getkey(const char *name) { char buf[128]; char *seq[8]; char *kstr; @@ -94,7 +98,7 @@ get_key(const char *name) { r = nil; if((k = name2key(name))) { - ungrab_key(k); + ungrabkey(k); return k; } utflcpy(buf, name, sizeof(buf)); @@ -139,26 +143,30 @@ next_keystroke(ulong *mod, KeyCode *code) { } static void -emulate_key_press(ulong mod, KeyCode key) { - XEvent e; - XWindow client_win; - int revert; - - XGetInputFocus(display, &client_win, &revert); - e.xkey.type = KeyPress; - e.xkey.time = CurrentTime; - e.xkey.window = client_win; - e.xkey.display = display; - e.xkey.state = mod; - e.xkey.keycode = key; - XSendEvent(display, client_win, True, KeyPressMask, &e); - e.xkey.type = KeyRelease; - XSendEvent(display, client_win, True, KeyReleaseMask, &e); - XSync(display, False); +fake_keypress(ulong mod, KeyCode key) { + XKeyEvent e; + Client *c; + + c = screen->focus; + if(c == nil || c->w.w == 0) + return; + + e.time = CurrentTime; + e.window = c->w.w; + e.display = display; + e.state = mod; + e.keycode = key; + + e.type = KeyPress; + sendevent(&c->w, true, KeyPressMask, (XEvent*)&e); + e.type = KeyRelease; + sendevent(&c->w, true, KeyReleaseMask, (XEvent*)&e); + + sync(); } static Key * -match_keys(Key *k, ulong mod, KeyCode keycode, Bool seq) { +match_keys(Key *k, ulong mod, KeyCode keycode, bool seq) { Key *ret = nil, *next; for(next = k->tnext; k; (k=next) && (next=k->tnext)) { @@ -181,12 +189,12 @@ kpress_seq(XWindow w, Key *done) { next_keystroke(&mod, &key); found = match_keys(done, mod, key, True); if((done->mod == mod) && (done->key == key)) - emulate_key_press(mod, key); /* double key */ + fake_keypress(mod, key); /* double key */ else { if(!found) XBell(display, 0); else if(!found->tnext && !found->next) - write_event("Key %s\n", found->name); + event("Key %s\n", found->name); else kpress_seq(w, found); } @@ -202,13 +210,13 @@ kpress(XWindow w, ulong mod, KeyCode keycode) { if(!found) /* grabbed but not found */ XBell(display, 0); else if(!found->tnext && !found->next) - write_event("Key %s\n", found->name); + event("Key %s\n", found->name); else { XGrabKeyboard(display, w, True, GrabModeAsync, GrabModeAsync, CurrentTime); flushevents(FocusChangeMask, True); kpress_seq(w, found); XUngrabKeyboard(display, CurrentTime); - XSync(display, False); + sync(); } } @@ -220,7 +228,7 @@ update_keys(void) { init_lock_keys(); while((k = key)) { key = key->lnext; - ungrab_key(k); + ungrabkey(k); while((n = k)) { k = k->next; free(n); @@ -229,8 +237,8 @@ update_keys(void) { for(l = p = def.keys; p && *p;) { if(*p == '\n') { *p = 0; - if((k = get_key(l))) - grab_key(k); + if((k = getkey(l))) + grabkey(k); *p = '\n'; l = ++p; } @@ -238,8 +246,8 @@ update_keys(void) { p++; } if(l < p && strlen(l)) { - if((k = get_key(l))) - grab_key(k); + if((k = getkey(l))) + grabkey(k); } - XSync(display, False); + sync(); } diff --git a/cmd/wmii/main.c b/cmd/wmii/main.c @@ -1,5 +1,5 @@ /* Copyright ©2004-2006 Anselm R. Garbe <garbeam at gmail dot com> - * Copyright ©2006-2007 Kris Maglione <fbsdaemon@gmail.com> + * Copyright ©2006-2008 Kris Maglione <fbsdaemon@gmail.com> * See LICENSE file for license details. */ #define EXTERN @@ -11,15 +11,11 @@ #include <locale.h> #include <pwd.h> #include <signal.h> -#include <stdlib.h> -#include <string.h> #include <sys/stat.h> #include <sys/wait.h> #include <unistd.h> #include "fns.h" -enum { false, true }; - static const char version[] = "wmii-"VERSION", ©2007 Kris Maglione\n"; @@ -52,17 +48,19 @@ scan_wins(void) { for(i = 0; i < num; i++) { if(!XGetWindowAttributes(display, wins[i], &wa)) continue; + /* Skip transients. */ if(wa.override_redirect || XGetTransientForHint(display, wins[i], &d1)) continue; if(wa.map_state == IsViewable) - create_client(wins[i], &wa); + client_create(wins[i], &wa); } + /* Manage transients. */ for(i = 0; i < num; i++) { if(!XGetWindowAttributes(display, wins[i], &wa)) continue; if((XGetTransientForHint(display, wins[i], &d1)) && (wa.map_state == IsViewable)) - create_client(wins[i], &wa); + client_create(wins[i], &wa); } } if(wins) @@ -150,13 +148,6 @@ init_environment(void) { } static void -init_atoms(void) { - Atom net[] = { xatom("_NET_SUPPORTED"), xatom("_NET_WM_NAME") }; - - changeprop_long(&scr.root, "_NET_SUPPORTED", "ATOM", (long*)net, nelem(net)); -} - -static void create_cursor(int ident, uint shape) { cursor[ident] = XCreateFontCursor(display, shape); } @@ -194,23 +185,17 @@ init_cursors(void) { static void init_screen(WMScreen *screen) { - XWindow w; - int ret; - unsigned mask; screen->r = scr.rect; def.snap = Dy(scr.rect) / 63; - sel_screen = XQueryPointer(display, scr.root.w, - &w, &w, - &ret, &ret, &ret, &ret, - &mask); + sel_screen = pointerscreen(); } static void cleanup(void) { while(client) - destroy_client(client); + client_destroy(client); ixp_server_close(&srv); close(sleeperfd); } @@ -225,6 +210,7 @@ struct { { X_PolySegment, BadDrawable }, { X_ConfigureWindow, BadMatch }, { X_GrabKey, BadAccess }, + { X_GetAtomName, BadAtom }, }; /* @@ -322,7 +308,7 @@ init_traps(void) { /* Wait for parent to exit */ read(fd[0], buf, 1); - XSetInputFocus(display, PointerRoot, RevertToPointerRoot, CurrentTime); + setfocus(pointerwin, RevertToPointerRoot); XCloseDisplay(display); exit(0); } @@ -388,15 +374,12 @@ main(int argc, char *argv[]) { wmiirc = "wmiistartrc"; ARGBEGIN{ - case 'v': - print("%s", version); - exit(0); - case 'V': - verbose = true; - break; case 'a': address = EARGF(usage()); break; + case 'G': + debug |= DGeneric; + break; case 'r': wmiirc = EARGF(usage()); break; @@ -420,7 +403,7 @@ main(int argc, char *argv[]) { XSelectInput(display, scr.root.w, SubstructureRedirectMask | EnterWindowMask); - XSync(display, False); + sync(); check_other_wm = false; @@ -438,9 +421,9 @@ main(int argc, char *argv[]) { spawn_command(wmiirc); init_traps(); - init_atoms(); init_cursors(); init_lock_keys(); + ewmh_init(); srv.preselect = check_preselect; ixp_listen(&srv, sock, &p9srv, serve_9pcon, nil); @@ -475,7 +458,7 @@ main(int argc, char *argv[]) { setwinattr(&scr.root, &wa, CWEventMask | CWCursor); - initbar(s); + bar_init(s); } screen->focus = nil; @@ -484,9 +467,11 @@ main(int argc, char *argv[]) { scan_wins(); starting = false; - select_view("nil"); - update_views(); - write_event("FocusTag %s\n", screen->sel->name); + view_select("nil"); + view_update_all(); + ewmh_updateviews(); + + event("FocusTag %s\n", screen->sel->name); i = ixp_serverloop(&srv); if(i) diff --git a/cmd/wmii/map.c b/cmd/wmii/map.c @@ -1,8 +1,6 @@ /* Written by Kris Maglione */ /* Public domain */ #include "dat.h" -#include <stdlib.h> -#include <string.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 */ @@ -23,7 +21,7 @@ hash(const char *str) { } static void -insert(MapEnt **e, ulong val, char *key) { +insert(MapEnt **e, ulong val, const char *key) { MapEnt *te; te = emallocz(sizeof *te); @@ -34,7 +32,7 @@ insert(MapEnt **e, ulong val, char *key) { } static MapEnt** -mapgetp(Map *map, ulong val, int create) { +map_getp(Map *map, ulong val, int create) { MapEnt **e; e = &map->bucket[val%map->nhash]; @@ -50,13 +48,13 @@ mapgetp(Map *map, ulong val, int create) { } static MapEnt** -hashgetp(Map *map, char *str, int create) { +hash_getp(Map *map, const char *str, int create) { MapEnt **e; ulong h; int cmp; h = hash(str); - e = mapgetp(map, h, create); + e = map_getp(map, h, create); if(*e && (*e)->key == nil) (*e)->key = str; else { @@ -72,28 +70,28 @@ hashgetp(Map *map, char *str, int create) { } MapEnt* -mapget(Map *map, ulong val, int create) { +map_get(Map *map, ulong val, int create) { MapEnt **e; - e = mapgetp(map, val, create); + e = map_getp(map, val, create); return *e; } MapEnt* -hashget(Map *map, char *str, int create) { +hash_get(Map *map, const char *str, int create) { MapEnt **e; - e = hashgetp(map, str, create); + e = hash_getp(map, str, create); return *e; } void* -maprm(Map *map, ulong val) { +map_rm(Map *map, ulong val) { MapEnt **e, *te; void *ret; ret = nil; - e = mapgetp(map, val, 0); + e = map_getp(map, val, 0); if(*e) { te = *e; ret = te->val; @@ -104,12 +102,12 @@ maprm(Map *map, ulong val) { } void* -hashrm(Map *map, char *str) { +hash_rm(Map *map, const char *str) { MapEnt **e, *te; void *ret; ret = nil; - e = hashgetp(map, str, 0); + e = hash_getp(map, str, 0); if(*e) { te = *e; ret = te->val; diff --git a/cmd/wmii/message.c b/cmd/wmii/message.c @@ -1,13 +1,15 @@ -/* Copyright ©2006-2007 Kris Maglione <fbsdaemon@gmail.com> +/* Copyright ©2006-2008 Kris Maglione <fbsdaemon@gmail.com> * See LICENSE file for license details. */ #include "dat.h" #include <assert.h> #include <ctype.h> -#include <stdlib.h> -#include <string.h> #include "fns.h" +static char* msg_debug(IxpMsg*); +static char* msg_selectframe(Frame*, IxpMsg*, int); +static char* msg_sendframe(Frame*, int, bool); + static char Ebadcmd[] = "bad command", Ebadvalue[] = "bad value", @@ -20,6 +22,7 @@ enum { LBORDER, LCLIENT, LCOLMODE, + LDEBUG, LDOWN, LEXEC, LFOCUSCOLORS, @@ -35,6 +38,7 @@ enum { LSELCOLORS, LSELECT, LSEND, + LSLAY, LSWAP, LTOGGLE, LUP, @@ -47,6 +51,7 @@ char *symtab[] = { "border", "client", "colmode", + "debug", "down", "exec", "focuscolors", @@ -62,6 +67,7 @@ char *symtab[] = { "selcolors", "select", "send", + "slay", "swap", "toggle", "up", @@ -69,23 +75,30 @@ char *symtab[] = { "~", }; +char *debugtab[] = { + "event", + "ewmh", + "focus", + "generic", +}; + /* 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) { +_bsearch(char *s, char **tab, int ntab) { int i, n, m, cmp; if(s == nil) return -1; - n = nelem(symtab); + n = ntab; i = 0; while(n) { m = n/2; - cmp = strcmp(s, symtab[i+m]); + cmp = strcmp(s, tab[i+m]); if(cmp == 0) return i+m; if(cmp < 0 || m == 0) @@ -99,8 +112,18 @@ getsym(char *s) { } static int +getsym(char *s) { + return _bsearch(s, symtab, nelem(symtab)); +} + +static int +getdebug(char *s) { + return _bsearch(s, debugtab, nelem(debugtab)); +} + +static int gettoggle(IxpMsg *m) { - switch(getsym(getword(m))) { + switch(getsym(msg_getword(m))) { case LON: return On; case LOFF: @@ -127,8 +150,8 @@ eatrunes(IxpMsg *m, int (*p)(Rune), int val) { m->pos = m->end; } -char * -getword(IxpMsg *m) { +char* +msg_getword(IxpMsg *m) { char *ret; Rune r; int n; @@ -148,21 +171,23 @@ getword(IxpMsg *m) { #define strbcmp(str, const) (strncmp((str), (const), sizeof(const)-1)) static int -getbase(char **s) { - char *p; +getbase(const char **s) { + const 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; - return 10*(p[0]-'0') + (p[1]-'0'); + if(isdigit(p[0])) { + if(p[1] == 'r') { + *s += 2; + return p[0] - '0'; + } + if(isdigit(p[1]) && p[2] == 'r') { + *s += 3; + return 10*(p[0]-'0') + (p[1]-'0'); + } } if(p[0] == '0') { *s += 1; @@ -172,8 +197,9 @@ getbase(char **s) { } int -getlong(char *s, long *ret) { - char *end, *rend; +getlong(const char *s, long *ret) { + const char *end; + char *rend; int base; end = s+strlen(s); @@ -184,8 +210,9 @@ getlong(char *s, long *ret) { } int -getulong(char *s, ulong *ret) { - char *end, *rend; +getulong(const char *s, ulong *ret) { + const char *end; + char *rend; int base; end = s+strlen(s); @@ -195,7 +222,7 @@ getulong(char *s, ulong *ret) { return (end == rend); } -static Client * +static Client* strclient(View *v, char *s) { ulong id; @@ -207,8 +234,8 @@ strclient(View *v, char *s) { return nil; } -Area * -strarea(View *v, char *s) { +Area* +strarea(View *v, const char *s) { Area *a; long i; @@ -234,40 +261,139 @@ strarea(View *v, char *s) { return a; } -char * +char* +message_client(Client *c, IxpMsg *m) { + char *s; + int i; + + s = msg_getword(m); + + switch(getsym(s)) { + case LFULLSCREEN: + i = gettoggle(m); + if(i == -1) + return Ebadusage; + fullscreen(c, i); + break; + case LKILL: + client_kill(c, true); + break; + case LSLAY: + client_kill(c, false); + break; + case LURGENT: + i = gettoggle(m); + if(i == -1) + return Ebadusage; + client_seturgent(c, i, True); + break; + default: + return Ebadcmd; + } + return nil; +} + +char* +message_root(void *p, IxpMsg *m) { + Font *fn; + char *s, *ret; + ulong n; + + USED(p); + ret = nil; + s = msg_getword(m); + + switch(getsym(s)) { + case LBORDER: + if(!getulong(msg_getword(m), &n)) + return Ebadvalue; + def.border = n; + view_focus(screen, screen->sel); + break; + case LDEBUG: + ret = msg_debug(m); + break; + case LEXEC: + execstr = smprint("exec %s", m->pos); + srv.running = 0; + break; + case LFOCUSCOLORS: + ret = msg_parsecolors(m, &def.focuscolor); + view_focus(screen, screen->sel); + break; + case LFONT: + fn = loadfont(m->pos); + if(fn) { + freefont(def.font); + def.font = fn; + bar_resize(screen); + }else + ret = "can't load font"; + view_focus(screen, screen->sel); + break; + case LGRABMOD: + s = msg_getword(m); + n = str2modmask(s); + + if((n & (Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) == 0) + return Ebadvalue; + + utflcpy(def.grabmod, s, sizeof(def.grabmod)); + def.mod = n; + break; + case LNORMCOLORS: + ret = msg_parsecolors(m, &def.normcolor); + view_focus(screen, screen->sel); + break; + case LSELCOLORS: + fprint(2, "%s: warning: selcolors have been removed\n", argv0); + return Ebadcmd; + case LVIEW: + view_select(m->pos); + break; + case LQUIT: + srv.running = 0; + break; + default: + return Ebadcmd; + } + return ret; +} + +char* message_view(View *v, IxpMsg *m) { Area *a; char *s; int i; - s = getword(m); + s = msg_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); + s = msg_getword(m); a = strarea(v, s); if(a == nil || a->floating) return Ebadvalue; - s = getword(m); + s = msg_getword(m); i = str2colmode(s); if(i == -1) return Ebadvalue; a->mode = i; - arrange_column(a, True); - restack_view(v); + column_arrange(a, True); + view_restack(v); if(v == screen->sel) - focus_view(screen, v); - draw_frames(); + view_focus(screen, v); + frame_draw_all(); return nil; + case LSELECT: + return msg_selectarea(v->sel, m); + case LSEND: + return msg_sendclient(v, m, 0); + case LSWAP: + return msg_sendclient(v, m, 1); default: return Ebadcmd; } @@ -309,155 +435,123 @@ parse_colors(IxpMsg *m, CTuple *col) { return nil; } -char * -message_root(void *p, IxpMsg *m) { - Font *fn; - char *s, *ret; - ulong n; +char* +msg_selectarea(Area *a, IxpMsg *m) { + Frame *f; + Area *ap; + View *v; + char *s; + ulong i; + int sym; - USED(p); - ret = nil; - s = getword(m); + v = a->view; + s = msg_getword(m); + sym = getsym(s); - switch(getsym(s)) { - case LQUIT: - srv.running = 0; - break; - case LEXEC: - execstr = smprint("exec %s", m->pos); - srv.running = 0; - break; - case LVIEW: - select_view(m->pos); - break; - case LSELCOLORS: - fprint(2, "%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"; - focus_view(screen, screen->sel); + switch(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 LBORDER: - if(!getulong(getword(m), &n)) + case LUP: + case LDOWN: + case LCLIENT: + return msg_selectframe(a->sel, m, sym); + case LLEFT: + if(a->floating) return Ebadvalue; - def.border = n; - focus_view(screen, screen->sel); + for(ap=v->area->next; ap->next; ap=ap->next) + if(ap->next == a) break; break; - case LGRABMOD: - s = getword(m); - n = str2modmask(s); - - if((n & (Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) == 0) + case LRIGHT: + if(a->floating) return Ebadvalue; - - utflcpy(def.grabmod, s, sizeof(def.grabmod)); - def.mod = n; - break; - default: - return Ebadcmd; - } - return ret; -} - -char * -read_root_ctl(void) { - char *b, *e; - - b = buffer; - e = b + sizeof(buffer) - 1; - b = seprint(b, e, "view %s\n", screen->sel->name); - b = seprint(b, e, "focuscolors %s\n", def.focuscolor.colstr); - b = seprint(b, e, "normcolors %s\n", def.normcolor.colstr); - b = seprint(b, e, "font %s\n", def.font->name); - b = seprint(b, e, "grabmod %s\n", def.grabmod); - b = seprint(b, e, "border %d\n", def.border); - USED(b); - return buffer; -} - -char * -message_client(Client *c, IxpMsg *m) { - char *s; - int i; - - s = getword(m); - - switch(getsym(s)) { - case LKILL: - kill_client(c); - break; - case LURGENT: - i = gettoggle(m); - if(i == -1) - return Ebadusage; - set_urgent(c, i, True); + ap = a->next; + if(ap == nil) + ap = v->area->next; break; - case LFULLSCREEN: - i = gettoggle(m); - if(i == -1) - return Ebadusage; - fullscreen(c, i); + case LTILDE: + ap = v->area; break; default: - return Ebadcmd; + if(!strcmp(s, "sel")) + ap = v->sel; + else { + if(!getulong(s, &i) || i == 0) + return Ebadvalue; + for(ap=v->area->next; ap; ap=ap->next) + if(--i == 0) break; + if(i != 0) + return Ebadvalue; + } + if((s = msg_getword(m))) { + if(!getulong(s, &i)) + return Ebadvalue; + for(f = ap->frame; f; f = f->anext) + if(--i == 0) break; + if(i != 0) + return Ebadvalue; + frame_focus(f); + return nil; + } } + + area_focus(ap); return nil; } static char* -send_frame(Frame *f, int sym, Bool swap) { +msg_selectframe(Frame *f, IxpMsg *m, int sym) { Frame *fp; + Client *c; + Area *a; + char *s; + ulong i; + + if(!f) + return Ebadvalue; + a = f->area; SET(fp); switch(sym) { case LUP: - fp = f->aprev; - if(!fp) - return Ebadvalue; - fp = fp->aprev; + for(fp=a->frame; fp->anext; fp=fp->anext) + if(fp->anext == f) break; break; case LDOWN: fp = f->anext; - if(!fp) - return Ebadvalue; + if(fp == nil) + fp = a->frame; + break; + case LCLIENT: + s = msg_getword(m); + if(s == nil || !getulong(s, &i)) + return "usage: select client <client>"; + c = win2client(i); + if(c == nil) + return "unknown client"; + fp = client_viewframe(c, f->view); break; default: - assert(!"can't get here"); - } - - if(swap) { - if(!fp) - return Ebadvalue; - swap_frames(f, fp); - }else { - remove_frame(f); - insert_frame(fp, f); + die("can't get here"); } - arrange_view(f->view); + if(fp == nil) + return "invalid selection"; - flushevents(EnterWindowMask, False); - focus_frame(f, True); - update_views(); + frame_focus(fp); + frame_restack(fp, nil); + if(f->view == screen->sel) + view_restack(f->view); return nil; } -char * -send_client(View *v, IxpMsg *m, Bool swap) { +char* +msg_sendclient(View *v, IxpMsg *m, bool swap) { Area *to, *a; Frame *f; Client *c; @@ -465,26 +559,26 @@ send_client(View *v, IxpMsg *m, Bool swap) { ulong i; int sym; - s = getword(m); + s = msg_getword(m); c = strclient(v, s); if(c == nil) return Ebadvalue; - f = view_clientframe(v, c); + f = client_viewframe(c, v); if(f == nil) return Ebadvalue; a = f->area; to = nil; - s = getword(m); + s = msg_getword(m); sym = getsym(s); switch(sym) { case LUP: case LDOWN: - return send_frame(f, sym, swap); + return msg_sendframe(f, sym, swap); case LLEFT: if(a->floating) return Ebadvalue; @@ -517,136 +611,59 @@ send_client(View *v, IxpMsg *m, Bool swap) { } if(!to && !swap && (f->anext || f != f->area->frame)) - to = new_column(v, a, 0); + to = column_new(v, a, 0); if(!to) return Ebadvalue; if(!swap) - send_to_area(to, f); + area_moveto(to, f); else if(to->sel) - swap_frames(f, to->sel); + frame_swap(f, to->sel); else return Ebadvalue; - flushevents(EnterWindowMask, False); - focus_frame(f, True); - arrange_view(v); - update_views(); + flushenterevents(); + frame_focus(f); + view_arrange(v); + view_update_all(); return nil; } static char* -select_frame(Frame *f, IxpMsg *m, int sym) { +msg_sendframe(Frame *f, int sym, bool swap) { Frame *fp; - Client *c; - Area *a; - char *s; - ulong i; - - if(!f) - return Ebadvalue; - a = f->area; SET(fp); switch(sym) { case LUP: - for(fp = a->frame; fp->anext; fp = fp->anext) - if(fp->anext == f) break; + fp = f->aprev; + if(!fp) + return Ebadvalue; + fp = fp->aprev; break; case LDOWN: fp = f->anext; - if(fp == nil) - fp = a->frame; - break; - case LCLIENT: - s = getword(m); - if(s == nil || !getulong(s, &i)) - return "usage: select client <client>"; - c = win2client(i); - if(c == nil) - return "unknown client"; - fp = view_clientframe(f->view, c); + if(!fp) + return Ebadvalue; break; default: - assert(!"can't get here"); + die("can't get here"); } - if(fp == nil) - return "invalid selection"; - - focus_frame(fp, False); - frame_to_top(fp); - if(f->view == screen->sel) - restack_view(f->view); - return nil; -} - -char* -select_area(Area *a, IxpMsg *m) { - Frame *f; - Area *ap; - View *v; - char *s; - ulong i; - int sym; - - v = a->view; - s = getword(m); - sym = getsym(s); - - switch(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 LUP: - case LDOWN: - case LCLIENT: - return select_frame(a->sel, m, sym); - 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) + if(swap) { + if(!fp) return Ebadvalue; - ap = a->next; - if(ap == nil) - ap = v->area->next; - break; - case LTILDE: - ap = v->area; - break; - default: - if(!strcmp(s, "sel")) - ap = v->sel; - else { - if(!getulong(s, &i) || i == 0) - return Ebadvalue; - for(ap=v->area->next; ap; ap=ap->next) - if(--i == 0) break; - if(i != 0) - return Ebadvalue; - } - if((s = getword(m))) { - if(!getulong(s, &i)) - return Ebadvalue; - for(f = ap->frame; f; f = f->anext) - if(--i == 0) break; - if(i != 0) - return Ebadvalue; - focus_frame(f, True); - return nil; - } + frame_swap(f, fp); + }else { + frame_remove(f); + frame_insert(fp, f); } - focus_area(ap); + view_arrange(f->view); + + flushenterevents(); + frame_focus(f); + view_update_all(); return nil; } diff --git a/cmd/wmii/mouse.c b/cmd/wmii/mouse.c @@ -1,10 +1,8 @@ -/* Copyright ©2006-2007 Kris Maglione <fbsdaemon@gmail.com> +/* Copyright ©2006-2008 Kris Maglione <fbsdaemon@gmail.com> * See LICENSE file for license details. */ #include "dat.h" #include <assert.h> -#include <stdlib.h> -#include <string.h> #include "fns.h" enum { @@ -49,9 +47,9 @@ framerect(Framewin *f) { /* 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); + p.x -= min(0, r.min.x); + p.x -= max(0, r.max.x - screen->r.max.x); + p.y -= max(0, r.max.y - screen->brect.min.y - Dy(r)/2); return rectaddpt(r, p); } @@ -237,7 +235,7 @@ do_managed_move(Client *c) { Point pt, pt2; int y; - focus(c, False); + focus(c, false); f = c->sel; pt = querypointer(&scr.root); @@ -253,7 +251,7 @@ do_managed_move(Client *c) { mapwin(cwin); horiz: - XUngrabPointer(display, CurrentTime); + ungrabpointer(); if(!grabpointer(&scr.root, nil, cursor[CurIcon], MouseMask)) goto done; warppointer(pt); @@ -275,9 +273,10 @@ horiz: case ButtonRelease: switch(ev.xbutton.button) { case 1: + /* TODO: Fix... Tangled, broken mess. */ if((f->anext) && (!f->aprev || (fw->fp != f->aprev && fw->fp != f->aprev->aprev))) { f->anext->r.min.y = f->r.min.y; - resize_frame(f->anext, f->anext->r); + frame_resize(f->anext, f->anext->r); } else if(f->aprev) { if(fw->fp == f->aprev->aprev) { @@ -285,16 +284,16 @@ horiz: f->aprev->r = f->r; }else f->aprev->r.max.y = f->r.max.y; - resize_frame(f->aprev, f->aprev->r); + frame_resize(f->aprev, f->aprev->r); } - remove_frame(f); + frame_remove(f); f->area = fw->ra; - insert_frame(fw->fp, f); + frame_insert(fw->fp, f); if(f->aprev) { f->aprev->r.max.y = fw->fr.min.y; - resize_frame(f->aprev, f->aprev->r); + frame_resize(f->aprev, f->aprev->r); } else fw->fr.min.y = f->area->r.min.y; @@ -302,9 +301,9 @@ horiz: fw->fr.max.y = f->anext->r.min.y; else fw->fr.max.y = f->area->r.max.y; - resize_frame(f, fw->fr); + frame_resize(f, fw->fr); - arrange_view(f->view); + view_arrange(f->view); goto done; } break; @@ -318,7 +317,7 @@ horiz: } vert: y = pt.y; - XUngrabPointer(display, CurrentTime); + ungrabpointer(); if(!grabpointer(&scr.root, cwin, cursor[CurIcon], MouseMask)) goto done; hplace(fw, pt); @@ -340,8 +339,8 @@ vert: switch(ev.xbutton.button) { case 1: if(fw->ra) { - fw->ra = new_column(f->view, fw->ra, 0); - send_to_area(fw->ra, f); + fw->ra = column_new(f->view, fw->ra, 0); + area_moveto(fw->ra, f); } goto done; case 2: @@ -352,7 +351,7 @@ vert: } } done: - XUngrabPointer(display, CurrentTime); + ungrabpointer(); framedestroy(fw); destroywindow(cwin); @@ -362,7 +361,7 @@ done: warppointer(pt); } -static Window * +static Window* gethsep(Rectangle r) { Window *w; WinAttr wa; @@ -470,7 +469,7 @@ mouse_resizecolframe(Frame *f, Align align) { r.min.y = ((align&SOUTH) ? pt.y : pt.y-1); r.max.y = r.min.y+2; - setdiv(d, pt.x); + div_set(d, pt.x); reshapewin(hwin, r); break; case ButtonRelease: @@ -483,8 +482,9 @@ mouse_resizecolframe(Frame *f, Align align) { r.min.y = pt.y; else r.max.y = pt.y; - resize_colframe(f, &r); + column_resizeframe(f, &r); + /* XXX: Magic number... */ if(align&WEST) pt.x = f->r.min.x + 4; else @@ -498,7 +498,7 @@ mouse_resizecolframe(Frame *f, Align align) { } } done: - XUngrabPointer(display, CurrentTime); + ungrabpointer(); destroywindow(cwin); destroywindow(hwin); } @@ -548,20 +548,20 @@ mouse_resizecol(Divide *d) { break; case MotionNotify: pt.x = ev.xmotion.x_root; - setdiv(d, pt.x); + div_set(d, pt.x); break; case ButtonRelease: - resize_column(a, pt.x - a->r.min.x); + column_resize(a, pt.x - a->r.min.x); goto done; } } done: - XUngrabPointer(display, CurrentTime); + ungrabpointer(); destroywindow(cwin); } static void -rect_morph_xy(Rectangle *r, Point d, Align *mask) { +rect_morph(Rectangle *r, Point d, Align *mask) { int n; if(*mask & NORTH) @@ -588,38 +588,43 @@ rect_morph_xy(Rectangle *r, Point d, Align *mask) { } static int -snap_line(Rectangle *rects, int nrect, int d, int horiz, Rectangle *r, int x, int y) { +snap_hline(Rectangle *rects, int nrect, int dy, Rectangle *r, 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; - } + int i, ty; + + 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(dy)) + dy = ty - y; + + ty = rp->max.y; + if(abs(ty - y) <= abs(dy)) + dy = 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 dy; +} + +static int +snap_vline(Rectangle *rects, int nrect, int dx, Rectangle *r, int x) { + Rectangle *rp; + int i, tx; + + 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(dx)) + dx = tx - x; + + tx = rp->max.x; + if(abs(tx - x) <= abs(dx)) + dx = tx - x; } } - return d; + return dx; } /* Returns a gravity for increment handling. It's normally the opposite of the mask @@ -635,14 +640,14 @@ snap_rect(Rectangle *rects, int num, Rectangle *r, Align *mask, int snap) { d.y = snap+1; if(*mask&NORTH) - d.y = snap_line(rects, num, d.y, True, r, 0, r->min.y); + d.y = snap_hline(rects, num, d.y, r, r->min.y); if(*mask&SOUTH) - d.y = snap_line(rects, num, d.y, True, r, 0, r->max.y); + d.y = snap_hline(rects, num, d.y, r, r->max.y); if(*mask&EAST) - d.x = snap_line(rects, num, d.x, False, r, r->max.x, 0); + d.x = snap_vline(rects, num, d.x, r, r->max.x); if(*mask&WEST) - d.x = snap_line(rects, num, d.x, False, r, r->min.x, 0); + d.x = snap_vline(rects, num, d.x, r, r->min.x); ret = CENTER; if(abs(d.x) <= snap) @@ -655,10 +660,11 @@ snap_rect(Rectangle *rects, int num, Rectangle *r, Align *mask, int snap) { else d.y = 0; - rect_morph_xy(r, d, mask); + rect_morph(r, d, mask); return ret ^ *mask; } +/* Grumble... Messy... TODO: Rewrite. */ void do_mouse_resize(Client *c, Bool opaque, Align align) { XEvent ev; @@ -683,9 +689,9 @@ do_mouse_resize(Client *c, Bool opaque, Align align) { origin = f->r; frect = f->r; - rects = rects_of_view(f->area->view, &num, c->frame); + rects = view_rects(f->area->view, &num, c->frame); - cur = cursor_of_quad(align); + cur = quad_cursor(align); if((align==CENTER) && !opaque) cur = cursor[CurSizing]; @@ -703,7 +709,6 @@ do_mouse_resize(Client *c, Bool opaque, Align align) { if(align != CENTER) { d = hr; - if(align&NORTH) d.y -= hr.y; if(align&SOUTH) d.y += hr.y; if(align&EAST) d.x += hr.x; @@ -713,7 +718,7 @@ do_mouse_resize(Client *c, Bool opaque, Align align) { warppointer(pt); } else if(f->client->fullscreen) { - XUngrabPointer(display, CurrentTime); + ungrabpointer(); return; } else if(!opaque) { @@ -752,7 +757,7 @@ do_mouse_resize(Client *c, Bool opaque, Align align) { d = subpt(d, pt); pt = addpt(pt, d); - rect_morph_xy(&origin, d, &align); + rect_morph(&origin, d, &align); origin = constrain(origin); frect = origin; @@ -762,10 +767,10 @@ do_mouse_resize(Client *c, Bool opaque, Align align) { frect = constrain(frect); //reshapewin(c->framewin, frect); - resize_client(c, frect); + client_resize(c, frect); break; case ButtonRelease: - resize_client(c, frect); + client_resize(c, frect); if(!opaque) { pt = translate(c->framewin, &scr.root, @@ -776,20 +781,21 @@ do_mouse_resize(Client *c, Bool opaque, Align align) { } free(rects); - XUngrabPointer(display, CurrentTime); + ungrabpointer(); return; } } } +/* Doesn't belong here */ void 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(display, button, mod | num_lock_mask, w, False, ButtonMask, + if((mod != AnyModifier) && (numlock_mask != 0)) { + XGrabButton(display, button, mod | numlock_mask, w, False, ButtonMask, GrabModeSync, GrabModeAsync, None, None); - XGrabButton(display, button, mod | num_lock_mask | LockMask, w, False, + XGrabButton(display, button, mod | numlock_mask | LockMask, w, False, ButtonMask, GrabModeSync, GrabModeAsync, None, None); } } diff --git a/cmd/wmii/printevent.c b/cmd/wmii/printevent.c @@ -41,8 +41,6 @@ #include "dat.h" #include <stdarg.h> -#include <stdlib.h> -#include <string.h> #include <bio.h> //#include "fns.h" #include "printevent.h" diff --git a/cmd/wmii/rule.c b/cmd/wmii/rule.c @@ -1,12 +1,9 @@ -/* - * Copyright ©2006 Anselm R. Garbe <garbeam at gmail dot com> +/* Copyright ©2006 Anselm R. Garbe <garbeam at gmail dot com> * See LICENSE file for license details. */ #include "dat.h" #include <assert.h> -#include <string.h> -#include <stdlib.h> #include "fns.h" /* basic rule matching language /regex/ -> value @@ -88,6 +85,6 @@ update_rules(Rule **rule, const char *data) { *v++ = *p; break; default: /* can't happen */ - assert(!"invalid state"); + die("invalid state"); } } diff --git a/cmd/wmii/utf.c b/cmd/wmii/utf.c @@ -9,14 +9,24 @@ char* toutf8n(char *str, size_t nstr) { static iconv_t cd; + static bool haveiconv; char *buf, *pos; size_t nbuf, bsize; if(cd == nil) { cd = iconv_open("UTF-8", nl_langinfo(CODESET)); - if(cd == (iconv_t)-1) - fatal("Can't convert from native codeset to UTF-8"); + if((int)cd == -1) + warning("Can't convert from local character encoding to UTF-8"); + else + haveiconv = true; } + if(!haveiconv) { + buf = emalloc(nstr+1); + memcpy(buf, str, nstr); + buf[nstr+1] = '\0'; + return buf; + } + iconv(cd, nil, nil, nil, nil); bsize = nstr * 1.25 + 4; diff --git a/cmd/wmii/view.c b/cmd/wmii/view.c @@ -1,14 +1,12 @@ /* Copyright ©2004-2006 Anselm R. Garbe <garbeam at gmail dot com> - * Copyright ©2006-2007 Kris Maglione <fbsdaemon@gmail.com> + * Copyright ©2006-2008 Kris Maglione <fbsdaemon@gmail.com> * See LICENSE file for license details. */ #include "dat.h" -#include <stdlib.h> -#include <string.h> #include "fns.h" -static Bool -is_empty(View *v) { +static bool +empty_p(View *v) { Area *a; for(a=v->area; a; a=a->next) if(a->frame) @@ -16,86 +14,78 @@ is_empty(View *v) { return True; } -Frame * -view_clientframe(View *v, Client *c) { - Frame *f; - - for(f=c->frame; f; f=f->cnext) - if(f->area->view == v) - break; - return f; -} - static void -assign_sel_view(View *v) { +_view_select(View *v) { if(screen->sel != v) { if(screen->sel) - write_event("UnfocusTag %s\n",screen->sel->name); + event("UnfocusTag %s\n",screen->sel->name); screen->sel = v; - write_event("FocusTag %s\n", screen->sel->name); + event("FocusTag %s\n", screen->sel->name); + ewmh_updateview(); } } -Client * +Client* view_selclient(View *v) { return v->sel && v->sel->sel ? v->sel->sel->client : nil; } -View * -get_view(const char *name) { - View *v; - int cmp; +bool +view_fullscreen_p(View *v) { + Frame *f; - SET(cmp); - for(v = view; v; v=v->next) - if((cmp=strcmp(name, v->name)) >= 0) - break; - if(!v || cmp != 0) - v = create_view(name); - return v; + for(f=v->area->frame; f; f=f->anext) + if(f->client->fullscreen) + return true; + return false; } -View * -create_view(const char *name) { +View* +view_create(const char *name) { static ushort id = 1; View **i, *v; + for(v=view; v; v=v->next) + if(!strcmp(name, v->name)) + return v; + v = emallocz(sizeof(View)); v->id = id++; utflcpy(v->name, name, sizeof(v->name)); - write_event("CreateTag %s\n", v->name); - create_area(v, nil, 0); - new_column(v, v->area, 0); + event("CreateTag %s\n", v->name); + area_create(v, nil, 0); + column_new(v, v->area, 0); - focus_area(v->area->next); + area_focus(v->area->next); for(i=&view; *i; i=&(*i)->next) - if(strcmp((*i)->name, name) < 0) + if(strcmp((*i)->name, name) >= 0) break; v->next = *i; *i = v; if(!screen->sel) - assign_sel_view(v); + _view_select(v); + ewmh_updateviews(); return v; } void -destroy_view(View *v) { +view_destroy(View *v) { Area *a; View **i, *tv; while((a = v->area->next)) - destroy_area(a); - destroy_area(v->area); + area_destroy(a); + area_destroy(v->area); for(i=&view; *i; i=&(*i)->next) if(*i == v) break; *i = v->next; - write_event("DestroyTag %s\n", v->name); + event("DestroyTag %s\n", v->name); if(v == screen->sel) { for(tv=view; tv; tv=tv->next) @@ -103,9 +93,10 @@ destroy_view(View *v) { if(tv == nil) tv = view; if(tv) - focus_view(screen, tv); + view_focus(screen, tv); } free(v); + ewmh_updateviews(); } static void @@ -119,7 +110,7 @@ update_frame_selectors(View *v) { } void -focus_view(WMScreen *s, View *v) { +view_focus(WMScreen *s, View *v) { Frame *f; Client *c; @@ -127,117 +118,110 @@ focus_view(WMScreen *s, View *v) { XGrabServer(display); - assign_sel_view(v); + _view_select(v); update_frame_selectors(v); - update_divs(); + div_update_all(); for(c=client; c; c=c->next) if((f = c->sel)) { if(f->view == v) - resize_client(c, f->r); + client_resize(c, f->r); else { unmap_frame(c); - unmap_client(c, IconicState); + client_unmap(c, IconicState); } + ewmh_updatestate(c); + ewmh_updateclient(c); } restack_view(v); focus_area(v->sel); draw_frames(); - XSync(display, False); + sync(); XUngrabServer(display); - flushevents(EnterWindowMask, False); + flushenterevents(); } void -select_view(const char *arg) { +view_select(const char *arg) { char buf[256]; utflcpy(buf, arg, sizeof(buf)); trim(buf, " \t+/"); - if(strlen(buf) == 0) + if(buf[0] == '\0') return; if(!strcmp(buf, ".") || !strcmp(buf, "..")) return; - assign_sel_view(get_view(buf)); - update_views(); /* performs focus_view */ + _view_select(view_create(buf)); + view_update_all(); /* performs view_focus */ } void -attach_to_view(View *v, Frame *f) { +view_attach(View *v, Frame *f) { Client *c; + Frame *ff; + Area *a; c = f->client; c->revert = nil; + + a = v->sel; if(c->trans || c->floating || c->fixedsize - || c->titleless || c->borderless || c->fullscreen) - focus_area(v->area); + || c->titleless || c->borderless || c->fullscreen + || (c->w.ewmh.type & (TypeDialog|TypeSplash|TypeDock))) + a = v->area; + else if(c->group && c->group->client + && (ff = client_viewframe(c->group->client, v))) + a = ff->area; else if(starting && v->sel->floating) - focus_area(v->area->next); - attach_to_area(v->sel, f); + a = v->area->next; + + area_attach(a, f); } void -restack_view(View *v) { - static XWindow *wins; - static uint winssz; +view_restack(View *v) { + static Vector_long wins; Divide *d; Frame *f; - Client *c; Area *a; - uint n, i, fscrn; + bool fscrn; if(v != screen->sel) return; - i = 1; - for(c = client; c; c = c->next) - i++; - if(i == 1) - return; + wins.n = 0; + fscrn = view_fullscreen_p(v); - for(a = v->area; a; a = a->next) - i++; - - if(i >= winssz) { - winssz = 2 * i; - wins = erealloc(wins, sizeof(Window) * winssz); - } - - n = 0; - fscrn = 0; - wins[n++] = screen->barwin->w; - for(f=v->area->frame; f; f=f->anext) - if(f->client->fullscreen) { - n--; - fscrn++; - break; - } + if(!fscrn) + vector_lpush(&wins, screen->barwin->w); for(f=v->area->stack; f; f=f->snext) - wins[n++] = f->client->framewin->w; + vector_lpush(&wins, f->client->framewin->w); if(fscrn) - wins[n++] = screen->barwin->w; + vector_lpush(&wins, screen->barwin->w); for(d = divs; d && d->w->mapped; d = d->next) - wins[n++] = d->w->w; + vector_lpush(&wins, d->w->w); for(a=v->area->next; a; a=a->next) if(a->frame) { - wins[n++] = a->sel->client->framewin->w; + vector_lpush(&wins, a->sel->client->framewin->w); for(f=a->frame; f; f=f->anext) if(f != a->sel) - wins[n++] = f->client->framewin->w; + vector_lpush(&wins, f->client->framewin->w); } - if(n) - XRestackWindows(display, wins, n); + + ewmh_updatestacking(); + if(wins.n) + XRestackWindows(display, (ulong*)wins.ary, wins.n); } void -scale_view(View *v, int w) { +view_scale(View *v, int w) { uint xoff, numcol; uint minwidth; Area *a; @@ -287,28 +271,28 @@ scale_view(View *v, int w) { } void -arrange_view(View *v) { +view_arrange(View *v) { uint xoff; Area *a; if(!v->area->next) return; - scale_view(v, Dx(screen->r)); + view_scale(v, Dx(screen->r)); xoff = 0; for(a=v->area->next; a; a=a->next) { 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); + column_arrange(a, False); } if(v == screen->sel) - update_divs(); + div_update_all(); } -Rectangle * -rects_of_view(View *v, uint *num, Frame *ignore) { +Rectangle* +view_rects(View *v, uint *num, Frame *ignore) { Rectangle *result; Frame *f; int i; @@ -330,72 +314,63 @@ rects_of_view(View *v, uint *num, Frame *ignore) { return result; } -uchar * +char* view_index(View *v) { Rectangle *r; Frame *f; Area *a; - char *buf, *end; int i; - buf = buffer; - end = buffer+sizeof(buffer)-1; - for((a=v->area), (i=0); a && buf < end-1; (a=a->next), i++) { + bufclear(); + for((a=v->area), (i=0); a; (a=a->next), i++) { if(a->floating) - buf = seprint(buf, end, "# ~ %d %d\n", - Dx(a->r), Dy(a->r)); + bufprint("# ~ %d %d\n", Dx(a->r), Dy(a->r)); else - buf = seprint(buf, end, "# %d %d %d\n", - i, a->r.min.x, Dx(a->r)); + bufprint("# %d %d %d\n", i, a->r.min.x, Dx(a->r)); - for(f=a->frame; f && buf < end-1; f=f->anext) { + for(f=a->frame; f; f=f->anext) { r = &f->r; if(a->floating) - buf = seprint(buf, end, "~ %C %d %d %d %d %s\n", + bufprint("~ %C %d %d %d %d %s\n", f->client, r->min.x, r->min.y, Dx(*r), Dy(*r), f->client->props); else - buf = seprint(buf, end, "%d %C %d %d %s\n", + bufprint("%d %C %d %d %s\n", i, f->client, r->min.y, Dy(*r), f->client->props); } } - return (uchar*)buffer; + return buffer; } -uchar * +char* view_ctl(View *v) { Area *a; - char *buf, *end; uint i; - buf = buffer; - end = buffer+sizeof(buffer)-1; - - buf = seprint(buf, end, "%s\n", v->name); + bufclear(); + bufprint("%s\n", v->name); /* select <area>[ <frame>] */ - buf = seprint(buf, end, "select %s", area_name(v->sel)); + bufprint("select %s", area_name(v->sel)); if(v->sel->sel) - buf = seprint(buf, end, " %d", frame_idx(v->sel->sel)); - buf = seprint(buf, end, "\n"); + bufprint(" %d", frame_idx(v->sel->sel)); + bufprint("\n"); /* select client <client> */ if(v->sel->sel) - buf = seprint(buf, end, "select client %C\n", v->sel->sel->client); + bufprint("select client %C\n", v->sel->sel->client); - for(a = v->area->next, i = 1; a && buf < end-1; a = a->next, i++) { - buf = seprint(buf, end, "colmode %d %s\n", - i, colmode2str(a->mode)); - } - return (uchar*)buffer; + for(a = v->area->next, i = 1; a; a = a->next, i++) + bufprint("colmode %d %s\n", i, colmode2str(a->mode)); + return buffer; } void -update_views(void) { +view_update_all(void) { View *n, *v, *old; int found; @@ -407,20 +382,20 @@ update_views(void) { for(v=view; v; v=n) { n=v->next; if(v != old) { - if(is_empty(v)) - destroy_view(v); + if(empty_p(v)) + view_destroy(v); else found++; } } - if(found && !strcmp(old->name, "nil") && is_empty(old)) - destroy_view(old); - focus_view(screen, screen->sel); + if(found && !strcmp(old->name, "nil") && empty_p(old)) + view_destroy(old); + view_focus(screen, screen->sel); } uint -newcolw(View *v, int num) { +view_newcolw(View *v, int num) { Rule *r; ulong n; @@ -439,3 +414,4 @@ newcolw(View *v, int num) { } return 0; } + diff --git a/cmd/wmii/x11.c b/cmd/wmii/x11.c @@ -1,7 +1,10 @@ -/* Copyright ©2007 Kris Maglione <fbsdaemon@gmail.com> +/* Copyright ©2007-2008 Kris Maglione <fbsdaemon@gmail.com> * See LICENSE file for license details. */ #define _X11_VISIBLE +#define ZP _ZP +#define ZR _ZR +#define pointerwin __pointerwin #include "dat.h" #include <assert.h> #include <math.h> @@ -10,13 +13,23 @@ #include <unistd.h> #include <bio.h> #include "fns.h" +#undef ZP /* These should be allocated in read-only memory, */ +#undef ZR /* but declaring them const causes too much trouble + * elsewhere. */ +#undef pointerwin -Point ZP = {0, 0}; -Rectangle ZR = {{0, 0}, {0, 0}}; +const Point ZP = {0, 0}; +const Rectangle ZR = {{0, 0}, {0, 0}}; + +const Window _pointerwin = { + .w = PointerRoot +}; +Window *const pointerwin = (Window*)&_pointerwin; static Map wmap, amap; -static MapEnt *wbucket[137]; -static MapEnt *abucket[137]; +static MapEnt* wbucket[137]; +static MapEnt* abucket[137]; + XRectangle XRect(Rectangle r) { @@ -95,6 +108,20 @@ rectsubpt(Rectangle r, Point p) { return r; } +/* Formatters */ +static int +Afmt(Fmt *f) { + Atom a; + char *s; + int i; + + a = va_arg(f->args, Atom); + s = XGetAtomName(display, a); + i = fmtprint(f, "%s", s); + free(s); + return i; +} + static int Rfmt(Fmt *f) { Rectangle r; @@ -143,13 +170,14 @@ initdisplay(void) { amap.bucket = abucket; amap.nhash = nelem(abucket); + fmtinstall('A', Afmt); fmtinstall('R', Rfmt); fmtinstall('P', Pfmt); fmtinstall('W', Wfmt); } /* Images */ -Image * +Image* allocimage(int w, int h, int depth) { Image *img; @@ -172,7 +200,7 @@ freeimage(Image *img) { } /* Windows */ -Window * +Window* createwindow(Window *parent, Rectangle r, int depth, uint class, WinAttr *wa, int valmask) { @@ -197,6 +225,15 @@ createwindow(Window *parent, Rectangle r, int depth, uint class, return w; } +Window* +window(XWindow w) { + static Window win; + + win.type = WWindow; + win.w = w; + return &win; +} + void reparentwindow(Window *w, Window *par, Point p) { XReparentWindow(display, w->w, par->w, p.x, p.y); @@ -279,9 +316,9 @@ sethandler(Window *w, Handlers *new) { assert((w->prev != nil && w->next != nil) || w->next == w->prev); if(new == nil) - maprm(&wmap, (ulong)w->w); + map_rm(&wmap, (ulong)w->w); else { - e = mapget(&wmap, (ulong)w->w, 1); + e = map_get(&wmap, (ulong)w->w, 1); e->val = w; } old = w->handler; @@ -293,31 +330,15 @@ Window* findwin(XWindow w) { MapEnt *e; - e = mapget(&wmap, (ulong)w, 0); + e = map_get(&wmap, (ulong)w, 0); if(e) return e->val; return nil; } -uint +long winprotocols(Window *w) { - Atom *protocols; - Atom actual, delete; - int i, n, protos; - - n = getproperty(w, "WM_PROTOCOLS", "ATOM", &actual, 0L, (void*)&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; + return ewmh_protocols(w); } /* Shape */ @@ -396,7 +417,7 @@ drawline(Image *dst, Point p1, Point p2, int cap, int w, ulong col) { XDrawLine(display, dst->image, dst->gc, p1.x, p1.y, p2.x, p2.y); } -void +uint drawstring(Image *dst, Font *font, Rectangle r, Align align, char *text, ulong col) { @@ -456,6 +477,7 @@ drawstring(Image *dst, Font *font, done: free(buf); + return w; } void @@ -468,7 +490,7 @@ copyimage(Image *dst, Rectangle r, Image *src, Point p) { } /* Colors */ -Bool +bool namedcolor(char *name, ulong *ret) { XColor c, c2; @@ -479,7 +501,7 @@ namedcolor(char *name, ulong *ret) { return 0; } -Bool +bool loadcolor(CTuple *c, char *str) { char buf[24]; @@ -493,7 +515,7 @@ loadcolor(CTuple *c, char *str) { } /* Fonts */ -Font * +Font* loadfont(char *name) { Biobuf *b; Font *f; @@ -572,18 +594,44 @@ Atom xatom(char *name) { MapEnt *e; - e = hashget(&amap, name, 1); + e = hash_get(&amap, name, 1); if(e->val == nil) e->val = (void*)XInternAtom(display, name, False); return (Atom)e->val; } void +sendevent(Window *w, bool propegate, long mask, XEvent *e) { + XSendEvent(display, w->w, propegate, mask, e); +} + +KeyCode +keycode(char *name) { + return XKeysymToKeycode(display, XStringToKeysym(name)); +} + +void +sync(void) { + XSync(display, False); +} + +/* Properties */ +void +delproperty(Window *w, char *prop) { + XDeleteProperty(display, w->w, xatom(prop)); +} + +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 +changeprop_string(Window *w, char *prop, char *string) { + changeprop_char(w, prop, "UTF8_STRING", string, strlen(string)); +} + +void changeprop_char(Window *w, char *prop, char *type, char data[], int len) { changeproperty(w, prop, type, 8, (uchar*)data, len); } @@ -599,21 +647,40 @@ changeprop_long(Window *w, char *prop, char *type, long data[], int len) { } void +changeprop_textlist(Window *w, char *prop, char *type, char *data[]) { + char **p, *s, *t; + int len, n; + + len = 0; + for(p=data; *p; p++) + len += strlen(*p) + 1; + s = emalloc(len); + t = s; + for(p=data; *p; p++) { + n = strlen(*p) + 1; + memcpy(t, *p, n); + t += n; + } + changeprop_char(w, prop, type, s, len); + free(s); +} + +void freestringlist(char *list[]) { XFreeStringList(list); } -ulong -getproperty(Window *w, char *prop, char *type, Atom *actual, ulong offset, uchar **ret, ulong length) { +static ulong +getprop(Window *w, char *prop, char *type, Atom *actual, int *format, ulong offset, uchar **ret, ulong length) { Atom typea; ulong n, extra; - int status, format; + int status; typea = (type ? xatom(type) : 0L); status = XGetWindowProperty(display, w->w, xatom(prop), offset, length, False /* delete */, - typea, actual, &format, &n, &extra, ret); + typea, actual, format, &n, &extra, ret); if(status != Success) { *ret = nil; @@ -626,6 +693,29 @@ getproperty(Window *w, char *prop, char *type, Atom *actual, ulong offset, uchar return n; } +ulong +getproperty(Window *w, char *prop, char *type, Atom *actual, ulong offset, uchar **ret, ulong length) { + int format; + + return getprop(w, prop, type, actual, &format, offset, ret, length); +} + +ulong +getprop_long(Window *w, char *prop, char *type, ulong offset, long **ret, ulong length) { + Atom actual; + ulong n; + int format; + + n = getprop(w, prop, type, &actual, &format, offset, (uchar**)ret, length); + if(n == 0 || format == 32 && xatom(type) == actual) + return n; + Dprint(DGeneric, "getprop_long(%W, %s, %s) format=%d, actual=\"%A\"\n", + w, prop, type, format, actual); + free(*ret); + *ret = 0; + return 0; +} + char** strlistdup(char *list[], int n) { char **p, *q; @@ -648,7 +738,7 @@ strlistdup(char *list[], int n) { } int -gettextlistproperty(Window *w, char *name, char **ret[]) { +getprop_textlist(Window *w, char *name, char **ret[]) { XTextProperty prop; char **list; int n; @@ -665,14 +755,14 @@ gettextlistproperty(Window *w, char *name, char **ret[]) { return n; } -char * -gettextproperty(Window *w, char *name) { +char* +getprop_string(Window *w, char *name) { char **list, *str; int n; str = nil; - n = gettextlistproperty(w, name, &list); + n = getprop_textlist(w, name, &list); if(n > 0) str = estrdup(*list); freestringlist(list); @@ -688,15 +778,25 @@ setfocus(Window *w, int mode) { /* Mouse */ Point querypointer(Window *w) { - XWindow dummy; + XWindow win; Point pt; uint ui; int i; - XQueryPointer(display, w->w, &dummy, &dummy, &i, &i, &pt.x, &pt.y, &ui); + XQueryPointer(display, w->w, &win, &win, &i, &i, &pt.x, &pt.y, &ui); return pt; } +int +pointerscreen(void) { + XWindow win; + Point pt; + uint ui; + int i; + + return XQueryPointer(display, scr.root.w, &win, &win, &i, &i, &pt.x, &pt.y, &ui); +} + void warppointer(Point pt) { XWarpPointer(display, @@ -792,7 +892,9 @@ sethints(Window *w) { xs.win_gravity = NorthWestGravity; switch (xs.win_gravity) { - case EastGravity: case CenterGravity: case WestGravity: + case EastGravity: + case CenterGravity: + case WestGravity: p.y = 1; break; case SouthEastGravity: case SouthGravity: case SouthWestGravity: @@ -800,7 +902,9 @@ sethints(Window *w) { break; } switch (xs.win_gravity) { - case NorthGravity: case CenterGravity: case SouthGravity: + case NorthGravity: + case CenterGravity: + case SouthGravity: p.x = 1; break; case NorthEastGravity: case EastGravity: case SouthEastGravity: @@ -841,7 +945,7 @@ sizehint(WinHints *h, Rectangle r) { 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); } diff --git a/cmd/wmii/x11.h b/cmd/wmii/x11.h @@ -1,121 +0,0 @@ -#define Window XWindow -#define Font XFont -#define Screen XScreen -#include <X11/Xlib.h> -#include <X11/Xutil.h> -#ifdef _X11_VISIBLE -# include <X11/Xatom.h> -# include <X11/extensions/shape.h> -#endif -#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 ? 4 : sizeof(*(data))) * 8), \ - (uchar*)(data), n) diff --git a/cmd/wmii9rc.sh b/cmd/wmii9rc.sh @@ -1,7 +1,7 @@ #!/bin/sh -f RC="" IFS=: -for i in "$PLAN9" `echo P9PATHS`; do +for i in "$PLAN9" `echo "P9PATHS"`; do if [ -d "$i" -a -x "$i/bin/rc" ]; then export PLAN9="$i" RC="$i/bin/rc" @@ -9,7 +9,7 @@ for i in "$PLAN9" `echo P9PATHS`; do fi done -if [ -n "$RC" ]; then +if [ -z "$RC" ]; then exit 1 fi diff --git a/cmd/wmiir.c b/cmd/wmiir.c @@ -239,7 +239,7 @@ xls(int argc, char *argv[]) { Stat *stat; IxpCFid *fid; char *file; - uchar *buf; + char *buf; int lflag, dflag, count, nstat, mstat, i; lflag = dflag = 0; diff --git a/config.mk b/config.mk @@ -2,26 +2,26 @@ # paths PREFIX = /usr/local -BIN = ${PREFIX}/bin -MAN = ${PREFIX}/share/man -ETC = ${PREFIX}/etc -LIBDIR = ${PREFIX}/lib -INCLUDE = ${PREFIX}/include + BIN = $(PREFIX)/bin + MAN = $(PREFIX)/share/man + ETC = $(PREFIX)/etc + LIBDIR = $(PREFIX)/lib + INCLUDE = $(PREFIX)/include # Includes and libs -INCPATH = .:${ROOT}/include:${INCLUDE}:/usr/include -LIBS = -L/usr/lib -lc -L${ROOT}/lib +INCPATH = .:$(ROOT)/include:$(INCLUDE):/usr/include +LIBS = -L/usr/lib -lc -L$(ROOT)/lib # Flags -include ${ROOT}/mk/gcc.mk -CFLAGS += -g -O0 -DIXPlint -LDFLAGS += -g ${LIBS} +include $(ROOT)/mk/gcc.mk +CFLAGS += $(DEBUGCFLAGS) +LDFLAGS += -g $(LIBS) +SOLDFLAGS += $(LDFLAGS) STATIC = -static MKDEP = cpp -M -# Compiler +# Compiler, Linker. Linker should usually *not* be ld. CC = cc -c -# Linker (Under normal circumstances, this should *not* be 'ld') LD = cc # Archiver AR = ar crs @@ -32,15 +32,18 @@ P9PATHS = ${PLAN9}:"'$${HOME}/plan9'":/usr/local/plan9:/usr/local/9:/opt/plan9:/ 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 -LIBIXP = ${LIBDIR}/libixp.a +LIBIXP = $(ROOT)/libixp/libixp.a +LIBIXP = $(LIBDIR)/libixp.a + +# Operating System Configurations + +# *BSD +#LIBICONV = -liconv +# +Darwin +#STATIC = # Darwon doesn't like static linking # Solaris -#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\" -#LDFLAGS = ${LIBS} -R${PREFIX}/lib -#LDFLAGS += -lsocket -lnsl +#CFLAGS = -fast $(INCS) +#LDFLAGS = $(LIBS) -R$(PREFIX)/lib -lsocket -lnsl #CFLAGS += -xtarget=ultra -# Darwin -#STATIC = # This space intentionally left blank -#LIBICONV = -liconv diff --git a/include/util.h b/include/util.h @@ -25,6 +25,7 @@ typedef long long vlong; #define strlcat wmii_strlcat /* util.c */ +void _die(char*, int, char*); void* emalloc(uint); void* emallocz(uint); void* erealloc(void*, uint); @@ -37,6 +38,9 @@ uint strlcat(char*, const char*, uint); uint tokenize(char **, uint, char*, char); int utflcpy(char*, const char*, int); +#define die(x) \ + _die(__FILE__, __LINE__, x) + char *argv0; #undef ARGBEGIN #undef ARGEND diff --git a/include/x11.h b/include/x11.h @@ -0,0 +1,231 @@ +#define Window XWindow +#define Font XFont +#define Screen XScreen +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#ifdef _X11_VISIBLE +# include <X11/Xatom.h> +# include <X11/extensions/shape.h> +#endif +#undef Window +#undef Font +#undef Screen + +enum Align { + NORTH = 0x01, + EAST = 0x02, + SOUTH = 0x04, + WEST = 0x08, + NEAST = NORTH | EAST, + NWEST = NORTH | WEST, + SEAST = SOUTH | EAST, + SWEST = SOUTH | WEST, + CENTER = NEAST | SWEST, +}; + +typedef enum Align Align; + +typedef struct CTuple CTuple; +typedef struct Point Point; +typedef struct Rectangle Rectangle; +typedef struct Screen Screen; +typedef struct Ewmh Ewmh; +typedef struct Window Window; +typedef struct WinHints WinHints; +typedef struct Handlers Handlers; +typedef struct Window Image; +typedef struct Font Font; +typedef XSetWindowAttributes WinAttr; + +struct CTuple { + ulong bg; + ulong fg; + ulong border; + char colstr[24]; /* #RRGGBB #RRGGBB #RRGGBB */ +}; + +struct Point { + int x, y; +}; + +struct Rectangle { + Point min, max; +}; + +struct Ewmh { + long type; + long ping; + long timer; +}; + +struct Window { + int type; + XWindow w; + Window *parent; + Drawable image; + GC gc; + Rectangle r; + void *aux; + Handlers *handler; + Window *next, *prev; + WinHints *hints; + Ewmh ewmh; + 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; +}; + +#ifdef VARARGCK +# pragma varargck type "A" Atom +# pragma varargck type "W" Window* +# pragma varargck type "P" Point +# pragma varargck type "R" Rectangle +#endif + +Display *display; +Screen scr; + +extern Point ZP; +extern Rectangle ZR; +extern Window* pointerwin; + +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 ? 4 : sizeof(*(data))) * 8), \ + (uchar*)(data), n) + +/* x11.c */ +Point addpt(Point, Point); +Image* allocimage(int w, int h, int depth); +void border(Image *dst, Rectangle, int w, ulong col); +void changeprop_char(Window*, char*, char*, char[], int); +void changeprop_long(Window*, char*, char*, long[], int); +void changeprop_short(Window*, char*, char*, short[], int); +void changeprop_string(Window*, char*, char*); +void changeprop_textlist(Window*, char*, char*, char*[]); +void changeproperty(Window*, char*, char*, int width, uchar*, int); +void copyimage(Image*, Rectangle, Image*, Point); +Window* createwindow(Window *parent, Rectangle, int depth, uint class, WinAttr*, int valuemask); +void delproperty(Window*, char*); +void destroywindow(Window*); +Point divpt(Point, Point); +void drawline(Image*, Point, Point, int cap, int w, ulong col); +void drawpoly(Image*, Point*, int, int cap, int w, ulong col); +uint drawstring(Image*, Font*, Rectangle, Align, char*, ulong col); +int eqpt(Point, Point); +int eqrect(Rectangle, Rectangle); +void fill(Image*, Rectangle, ulong col); +void fillpoly(Image*, Point*, int, ulong col); +Window* findwin(XWindow); +void freefont(Font*); +void freeimage(Image *); +void freestringlist(char**); +ulong getprop_long(Window*, char*, char*, ulong, long**, ulong); +char* getprop_string(Window*, char*); +int getprop_textlist(Window *w, char *name, char **ret[]); +ulong getproperty(Window*, char *prop, char *type, Atom *actual, ulong offset, uchar **ret, ulong length); +int grabpointer(Window*, Window *confine, Cursor, int mask); +void initdisplay(void); +KeyCode keycode(char*); +uint labelh(Font*); +bool loadcolor(CTuple*, char*); +Font* loadfont(char*); +void lowerwin(Window*); +int mapwin(Window*); +void movewin(Window*, Point); +Point mulpt(Point p, Point q); +bool namedcolor(char *name, ulong*); +int pointerscreen(void); +Point querypointer(Window*); +void raisewin(Window*); +void reparentwindow(Window*, Window*, Point); +void reshapewin(Window*, Rectangle); +void sendevent(Window*, bool propegate, long mask, XEvent*); +void setfocus(Window*, int mode); +void sethints(Window*); +void setshapemask(Window *dst, Image *src, Point); +void setwinattr(Window*, WinAttr*, int valmask); +char** strlistdup(char**, int); +Point subpt(Point, Point); +void sync(void); +uint textwidth(Font*, char*); +uint textwidth_l(Font*, char*, uint len); +Point translate(Window*, Window*, Point); +void ungrabpointer(void); +int unmapwin(Window*); +void warppointer(Point); +Window* window(XWindow); +long winprotocols(Window*); +Atom xatom(char*); +XRectangle XRect(Rectangle); +Rectangle gravitate(Rectangle dst, Rectangle src, Point grav); +Rectangle insetrect(Rectangle, int); +Rectangle rectaddpt(Rectangle, Point); +Rectangle rectsubpt(Rectangle, Point); +Handlers* sethandler(Window*, Handlers*); +Rectangle sizehint(WinHints*, Rectangle); + diff --git a/libfmt/fmtvprint.c b/libfmt/fmtvprint.c @@ -24,7 +24,7 @@ * but ignore any width flags */ int -fmtvprint(Fmt *f, const char *fmt, va_list args) +fmtvprint(Fmt *f, const char *fmt, va_list args) { va_list va; int n; diff --git a/libwmii_hack/Makefile b/libwmii_hack/Makefile @@ -0,0 +1,14 @@ +ROOT= .. +include ${ROOT}/mk/hdr.mk + +hack.o hack.o_pic: util.c x11.c hack.h x11.h + +CFLAGS += $(INCX11) + +TARG = libwmii_hack +OBJ = hack +# util \ +# x11 + +include ${ROOT}/mk/so.mk + diff --git a/libwmii_hack/hack.c b/libwmii_hack/hack.c @@ -0,0 +1,132 @@ +/* Copyright ©2008 Kris Maglione <fbsdaemon@gmail.com> + * See LICENSE file for license details. + */ +#include "hack.h" +#include <dlfcn.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> + +#include "util.c" +#include "x11.c" + +enum { + Timeout = 10000, +}; + +static void* xlib; + +static long transient; +static Atom types[32]; +static long ntypes; +static char* tags[32]; +static long ntags; +static long pid; +static char hostname[256]; +static long nmsec; + +typedef Window (*mapfn)(Display*, Window); + +static Window (*mapwindow)(Display*, Window); +static Window (*mapraised)(Display*, Window); + +static long +msec(void) { + struct timeval tv; + + if(!gettimeofday(&tv, 0)) + return 0; + return tv.tv_sec*1000 + tv.tv_usec/1000; +} + +static void +init(Display *d) { /* Hrm... assumes one display... */ + char *toks[nelem(types)]; + char *s, *p; + long n; + int i; + + xlib = dlopen("libX11.so", RTLD_GLOBAL | RTLD_LAZY); + if(xlib == nil) + return; + mapwindow = (mapfn)(uintptr_t)dlsym(xlib, "XMapWindow"); + mapraised = (mapfn)(uintptr_t)dlsym(xlib, "XMapRaised"); + + unsetenv("LD_PRELOAD"); + + if((s = getenv("WMII_HACK_TRANSIENT"))) { + if(getlong(s, &n)) + transient = n; + unsetenv("WMII_HACK_TRANSIENT"); + } + if((s = getenv("WMII_HACK_TYPE"))) { + s = strdup(s); + unsetenv("WMII_HACK_TYPE"); + + n = tokenize(toks, nelem(toks), s, ','); + for(i=0; i < n; i++) { + for(p=toks[i]; *p; p++) + if(*p >= 'a' && *p <= 'z') + *p += 'A' - 'a'; + toks[i] = smprint("_NET_WM_WINDOW_TYPE_%s", toks[i]); + } + XInternAtoms(d, toks, n, False, types); + ntypes = n; + for(i=0; i < n; i++) + free(toks[i]); + free(s); + } + if((s = getenv("WMII_HACK_TAGS"))) { + s = strdup(s); + unsetenv("WMII_HACK_TAGS"); + + n = tokenize(toks, nelem(toks)-1, s, '+'); + for(i=0; i < n; i++) + tags[i] = strdup(toks[i]); + ntags = n; + free(s); + } + + pid = getpid(); + gethostname(hostname, sizeof hostname); +} + +static void +setprops(Display *d, Window w) { + + if(!xlib) + init(d); + + changeprop_long(d, w, "_NET_WM_PID", "CARDINAL", &pid, 1); + changeprop_string(d, w, "_NET_WM_CLIENT_MACHINE", hostname); + + /* Kludge. */ + if(nmsec == 0) + nmsec = msec(); + if(msec() > nmsec + Timeout) + return; + + if(transient) + changeprop_long(d, w, "WM_TRANSIENT_FOR", "WINDOW", &transient, 1); + if(ntypes) + changeprop_long(d, w, "_NET_WM_WINDOW_TYPE", "ATOM", (long*)types, ntypes); + if(ntags) + changeprop_textlist(d, w, "_WMII_TAGS", "UTF8_STRING", tags); +} + +int +XMapWindow(Display *d, Window w) { + + setprops(d, w); + return mapwindow(d, w); +} + +int +XMapRaised(Display *d, Window w) { + + setprops(d, w); + return mapraised(d, w); +} + diff --git a/libwmii_hack/hack.h b/libwmii_hack/hack.h @@ -0,0 +1,28 @@ + +typedef unsigned long ulong; +typedef unsigned int uint; +typedef unsigned char uchar; + +#define _XOPEN_SOURCE 600 +#define IXP_P9_STRUCTS +#define IXP_NO_P9_ +#include <assert.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <x11.h> +#include <X11/Xlib.h> + +#define strdup my_strdup + +static int getlong(const char*, long*); +static uint tokenize(char*[], uint, char*, char); +static char* smprint(const char*, ...); +static char* vsmprint(const char*, va_list); +static char* strdup(const char*); + +#define nil ((void*)0) +#define nelem(ary) (sizeof(ary) / sizeof(*ary)) + diff --git a/libwmii_hack/util.c b/libwmii_hack/util.c @@ -0,0 +1,101 @@ +#include <ctype.h> +#include <stdio.h> +#include <string.h> + +#define strbcmp(str, const) (strncmp((str), (const), sizeof(const)-1)) +static int +getbase(const char **s) { + const char *p; + + p = *s; + if(!strbcmp(p, "0x")) { + *s += 2; + return 16; + } + if(isdigit(p[0])) { + if(p[1] == 'r') { + *s += 2; + return p[0] - '0'; + } + if(isdigit(p[1]) && p[2] == 'r') { + *s += 3; + return 10*(p[0]-'0') + (p[1]-'0'); + } + } + if(p[0] == '0') { + *s += 1; + return 8; + } + return 10; +} + +static int +getlong(const char *s, long *ret) { + const char *end; + char *rend; + int base; + + end = s+strlen(s); + base = getbase(&s); + + *ret = strtol(s, &rend, base); + return (end == rend); +} + +static uint +tokenize(char *res[], uint reslen, char *str, char delim) { + char *s; + uint i; + + i = 0; + s = str; + while(i < reslen && *s) { + while(*s == delim) + *(s++) = '\0'; + if(*s) + res[i++] = s; + while(*s && *s != delim) + s++; + } + return i; +} + +static char* +vsmprint(const char *fmt, va_list ap) { + va_list al; + char *buf = ""; + int n; + + va_copy(al, ap); + n = vsnprintf(buf, 0, fmt, al); + va_end(al); + + buf = malloc(++n); + if(buf) + vsnprintf(buf, n, fmt, ap); + return buf; +} + +static char* +smprint(const char *fmt, ...) { + va_list ap; + char *ret; + + va_start(ap, fmt); + ret = vsmprint(fmt, ap); + va_end(ap); + return ret; +} + +static char* +strdup(const char *s) { + char *ret; + int len; + + len = strlen(s)+1; + ret = malloc(len); + if(ret) + memcpy(ret, s, len); + return ret; +} + diff --git a/libwmii_hack/x11.c b/libwmii_hack/x11.c @@ -0,0 +1,193 @@ +/* Copyright ©2007 Kris Maglione <fbsdaemon@gmail.com> + * See LICENSE file for license details. + */ +#include <assert.h> + +/* Misc */ +static Atom +xatom(Display *display, char *name) { + /* Blech. I don't trust Xlib's cacheing. + MapEnt *e; + + e = hash_get(&amap, name, 1); + if(e->val == nil) + e->val = (void*)XInternAtom(display, name, False); + return (Atom)e->val; + */ + return XInternAtom(display, name, False); +} +/* Properties */ +#if 0 +static void +delproperty(Display *display, Window w, char *prop) { + XDeleteProperty(display, w, xatom(display, prop)); +} +#endif + +static void +changeproperty(Display *display, Window w, char *prop, char *type, int width, uchar data[], int n) { + XChangeProperty(display, w, xatom(display, prop), xatom(display, type), width, PropModeReplace, data, n); +} + +static void +changeprop_string(Display *display, Window w, char *prop, char *string) { + changeprop_char(display, w, prop, "UTF8_STRING", string, strlen(string)); +} + +static void +changeprop_char(Display *display, Window w, char *prop, char *type, char data[], int len) { + changeproperty(display, w, prop, type, 8, (uchar*)data, len); +} + +#if 0 +static void +changeprop_short(Display *display, Window w, char *prop, char *type, short data[], int len) { + changeproperty(display, w, prop, type, 16, (uchar*)data, len); +} +#endif + +static void +changeprop_long(Display *display, Window w, char *prop, char *type, long data[], int len) { + changeproperty(display, w, prop, type, 32, (uchar*)data, len); +} + +static void +changeprop_textlist(Display *display, Window w, char *prop, char *type, char *data[]) { + char **p, *s, *t; + int len, n; + + len = 0; + for(p=data; *p; p++) + len += strlen(*p) + 1; + s = malloc(len); + if(s == nil) + return; + t = s; + for(p=data; *p; p++) { + n = strlen(*p) + 1; + memcpy(t, *p, n); + t += n; + } + changeprop_char(display, w, prop, type, s, len); + free(s); +} + +#if 0 +static void +freestringlist(char *list[]) { + XFreeStringList(list); +} +#endif + +#if 0 +static ulong +getprop(Display *display, Window w, char *prop, char *type, Atom *actual, int *format, ulong offset, uchar **ret, ulong length) { + Atom typea; + ulong n, extra; + int status; + + typea = (type ? xatom(display, type) : 0L); + + status = XGetWindowProperty(display, w, + xatom(display, prop), offset, length, False /* delete */, + typea, actual, format, &n, &extra, ret); + + if(status != Success) { + *ret = nil; + return 0; + } + if(n == 0) { + free(*ret); + *ret = nil; + } + return n; +} +#endif + +#if 0 +static ulong +getproperty(Display *display, Window w, char *prop, char *type, Atom *actual, ulong offset, uchar **ret, ulong length) { + int format; + + return getprop(display, w, prop, type, actual, &format, offset, ret, length); +} +#endif + +#if 0 +static ulong +getprop_long(Display *display, Window w, char *prop, char *type, ulong offset, long **ret, ulong length) { + Atom actual; + ulong n; + int format; + + n = getprop(display, w, prop, type, &actual, &format, offset, (uchar**)ret, length); + if(n == 0 || format == 32 && xatom(display, type) == actual) + return n; + free(*ret); + *ret = 0; + return 0; +} +#endif + +#ifdef notdef +static char** +strlistdup(char *list[], int n) { + char **p, *q; + int i, m; + + for(i=0, m=0; i < n; i++) + m += strlen(list[i])+1; + + p = malloc((n+1)*sizeof(char*) + m); + if(p == nil) + return nil; + q = (char*)&p[n+1]; + + for(i=0; i < n; i++) { + p[i] = q; + m = strlen(list[i])+1; + memcpy(q, list[i], m); + q += m; + } + p[n] = nil; + return p; +} +#endif + +#if 0 +static int +getprop_textlist(Display *display, Window w, char *name, char **ret[]) { + XTextProperty prop; + char **list; + int n; + + *ret = nil; + n = 0; + + XGetTextProperty(display, w, &prop, xatom(display, name)); + if(prop.nitems > 0) { + if(Xutf8TextPropertyToTextList(display, &prop, &list, &n) == Success) + *ret = list; + XFree(prop.value); + } + return n; +} +#endif + +#if 0 +static char* +getprop_string(Display *display, Window w, char *name) { + char **list, *str; + int n; + + str = nil; + + n = getprop_textlist(display, w, name, &list); + if(n > 0) + str = strdup(*list); + freestringlist(list); + + return str; +} +#endif + diff --git a/libwmii_hack/x11.h b/libwmii_hack/x11.h @@ -0,0 +1,18 @@ +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> + +static void changeprop_char(Display*, Window, char*, char*, char[], int); +static void changeprop_long(Display*, Window, char*, char*, long[], int); +/* static void changeprop_short(Display*, Window, char*, char*, short[], int); */ +static void changeprop_string(Display*, Window, char*, char*); +static void changeprop_textlist(Display*, Window, char*, char*, char*[]); +static void changeproperty(Display*, Window, char*, char*, int width, uchar*, int); +/* static void delproperty(Display*, Window, char*); */ +/* static void freestringlist(char**); */ +/* static ulong getprop_long(Display*, Window, char*, char*, ulong, long**, ulong); */ +/* static char* getprop_string(Display*, Window, char*); */ +/* static int getprop_textlist(Display*, Window, char*, char**[]); */ +/* static ulong getproperty(Display*, Window, char*, char*, Atom*, ulong, uchar**, ulong); */ +static Atom xatom(Display*, char*); + diff --git a/man/Makefile b/man/Makefile @@ -11,3 +11,4 @@ FILTER = sed "s|CONFPREFIX|${ETC}|g; \ s|AWKPATH|${AWKPATH}|g" include ${ROOT}/mk/man.mk + diff --git a/mk/common.mk b/mk/common.mk @@ -2,9 +2,9 @@ all: install: all -MANDIRS=${MAN}/man1 +MANDIRS=$(MAN)/man1 mkdirs: - for i in ${BIN} ${ETC} ${LIBDIR} ${MANDIRS} ${INCLUDE} ${DIRS}; do \ + for i in $(BIN) $(ETC) $(LIBDIR) $(MANDIRS) $(INCLUDE) $(DIRS); do \ test -d $$i || echo MKDIR $$i; \ mkdir -pm 0755 $$i; \ done @@ -15,6 +15,6 @@ cleandep: DEP:=${shell if test -f .depend;then echo .depend;else echo /dev/null; fi} DEP!=echo /dev/null -include ${DEP} +include $(DEP) .PHONY: all options clean dist install uninstall depend cleandep diff --git a/mk/dir.mk b/mk/dir.mk @@ -3,21 +3,21 @@ MKSUBDIR = targ=$@; \ if [ ! -d $$i ]; then \ echo Skipping nonexistent directory: $$i 1>&2; \ else \ - echo MAKE $${targ\#d} ${BASE}$$i/; \ - (cd $$i && ${MAKE} BASE="${BASE}$$i/" $${targ\#d}) || exit $?; \ + echo MAKE $${targ\#d} $(BASE)$$i/; \ + (cd $$i && $(MAKE) BASE="$(BASE)$$i/" $${targ\#d}) || exit $?; \ fi; \ done dall: - dirs="${DIRS}"; ${MKSUBDIR} + dirs="$(DIRS)"; $(MKSUBDIR) dclean: - dirs="${DIRS}"; ${MKSUBDIR} + dirs="$(DIRS)"; $(MKSUBDIR) dinstall: - dirs="${INSTDIRS}"; ${MKSUBDIR} + dirs="$(INSTDIRS)"; $(MKSUBDIR) duninstall: - dirs="${INSTDIRS}"; ${MKSUBDIR} + dirs="$(INSTDIRS)"; $(MKSUBDIR) ddepend: - dirs="${DIRS}"; ${MKSUBDIR} + dirs="$(DIRS)"; $(MKSUBDIR) all: dall clean: dclean @@ -25,5 +25,5 @@ install: dinstall uninstall: duninstall depend: ddepend -INSTDIRS = ${DIRS} +INSTDIRS = $(DIRS) diff --git a/mk/gcc.mk b/mk/gcc.mk @@ -1,7 +1,7 @@ CFLAGS += \ -std=c99 \ - -pipe \ -pedantic \ + -pipe \ -Wall \ -Wimplicit \ -Wmissing-prototypes \ @@ -13,4 +13,8 @@ CFLAGS += \ -Wpointer-arith \ -Wreturn-type \ -Wstrict-prototypes \ - -Wtrigraphs \ + -Wtrigraphs +MKDEP = cpp -M +SOCFLAGS += -fPIC +SOLDFLAGS += -shared -soname $(SONAME) + diff --git a/mk/hdr.mk b/mk/hdr.mk @@ -1,65 +1,69 @@ .SILENT: -.SUFFIXES: .O .o .c .sh .rc .awk .1 .depend .install .uninstall .clean +.SUFFIXES: .O .o .o_pic .c .sh .rc .so .awk .1 .depend .install .uninstall .clean all: .c.depend: echo MKDEP $< - ${MKDEP} ${CFLAGS} $< >>.depend + $(MKDEP) $(CFLAGS) $< >>.depend .sh.depend .rc.depend .1.depend .awk.depend: : .c.o: - ${COMPILE} $@ $< + $(COMPILE) $@ $< + +.c.o_pic: + $(COMPILEPIC) $@ $< .o.O: - ${LINK} $@ $< + $(LINK) $@ $< .c.O: - ${COMPILE} $@ $< - ${LINK} $@ $< + ${COMPILE} ${<:.c=.o} $< + ${LINK} $@ ${<:.c=.o} + .rc.O .sh.O .awk.O: - echo FILTER ${BASE}$< - ${FILTER} $< >$@ + echo FILTER $(BASE)$< + $(FILTER) $< >$@ chmod 0755 $@ .O.install: - echo INSTALL ${BASE}$* - cp -f $< ${BIN}/$* - chmod 0755 ${BIN}/$* + echo INSTALL $$($(CLEANNAME) $(BASE)$*) + cp -f $< $(BIN)/$* + chmod 0755 $(BIN)/$* .O.uninstall: - echo UNINSTALL ${BASE}$* - rm -f ${BIN}/$* + echo UNINSTALL $$($(CLEANNAME) $(BASE)$*) + rm -f $(BIN)/$* -.a.install: - echo INSTALL ${BASE}$< - cp -f $< ${LIBDIR}/$< - chmod 0644 ${LIBDIR}/$< -.a.uninstall: - echo UNINSTALL ${BASE}$< - rm -f ${LIBDIR}/$< +.a.install .so.install: + echo INSTALL $$($(CLEANNAME) $(BASE)$<) + cp -f $< $(LIBDIR)/$< + chmod 0644 $(LIBDIR)/$< +.a.uninstall .so.uninstall: + echo UNINSTALL $$($(CLEANNAME) $(BASE)$<) + rm -f $(LIBDIR)/$< .h.install: - echo INSTALL ${BASE}$< - cp -f $< ${INCLUDE}/$< - chmod 0644 ${INCLUDE}/$< + echo INSTALL $$($(CLEANNAME) $(BASE)$<) + cp -f $< $(INCLUDE)/$< + chmod 0644 $(INCLUDE)/$< .h.uninstall: - echo UNINSTALL ${BASE}$< - rm -f ${INCLUDE}/$< + echo UNINSTALL $$($(CLEANNAME) $(BASE)$<) + rm -f $(INCLUDE)/$< .1.install: - echo INSTALL man $*'(1)' - ${FILTER} $< >${MAN}/man1/$< - chmod 0644 ${MAN}/man1/$< + echo INSTALL man $$($(CLEANNAME) $*'(1)') + $(FILTER) $< >$(MAN)/man1/$< + chmod 0644 $(MAN)/man1/$< .1.uninstall: - echo UNINSTALL man $*'(1)' - rm -f ${MAN}/man1/$< + echo UNINSTALL man $$($(CLEANNAME) $*'(1)') + rm -f $(MAN)/man1/$< .O.clean: rm -f $< || true 2>/dev/null rm -f $*.o || true 2>/dev/null -.o.clean: +.o.clean .o_pic.clean: rm -f $< || true 2>/dev/null printinstall: @@ -69,9 +73,13 @@ install: printinstall mkdirs depend: cleandep FILTER = cat -COMPILE= CC="${CC}" CFLAGS="${CFLAGS}" ${ROOT}/util/compile -LINK= LD="${LD}" LDFLAGS="${LDFLAGS}" ${ROOT}/util/link +COMPILE= CC="$(CC)" CFLAGS="$(CFLAGS)" $(ROOT)/util/compile +COMPILEPIC= CC="$(CC)" CFLAGS="$(CFLAGS) $(SOCFLAGS)" $(ROOT)/util/compile +LINK= LD="$(LD)" LDFLAGS="$(LDFLAGS)" $(ROOT)/util/link +LINKSO= LD="$(LD)" LDFLAGS="$(SOLDFLAGS)" $(ROOT)/util/link +CLEANNAME=$(ROOT)/util/cleanname -include ${ROOT}/config.mk -CFLAGS += -I$$(echo ${INCPATH}|sed 's/:/ -I/g') +include $(ROOT)/config.mk +CFLAGS += -I$$(echo $(INCPATH)|sed 's/:/ -I/g') +include $(ROOT)/mk/common.mk diff --git a/mk/lib.mk b/mk/lib.mk @@ -1,25 +1,30 @@ -LIB = ${ROOT}/lib/${TARG}.a +PTARG = $(ROOT)/lib/$(TARG) +LIB = $(PTARG).a OFILES = ${OBJ:=.o} -all: ${HFILES} ${LIB} +all: $(HFILES) $(LIB) -install: ${TARG}.install -uninstall: ${TARG}.uninstall +install: $(PTARG).install +uninstall: $(PTARG).uninstall clean: libclean depend: ${OBJ:=.depend} libclean: - for i in ${LIB} ${OFILES}; do \ + for i in $(LIB) $(OFILES); do \ rm -f $$i; \ done 2>/dev/null || true printinstall: echo 'Install directories:' - echo ' Lib: ${LIBDIR}' + echo ' Lib: $(LIBDIR)' -${LIB}: ${OFILES} - echo AR $$($(ROOT)/util/cleanname $(BASE)/$@) - mkdir ${ROOT}/lib 2>/dev/null || true - ${AR} $@ ${OFILES} +$(LIB): $(OFILES) + echo AR $$($(CLEANNAME) $(BASE)/$@) + mkdir $(ROOT)/lib 2>/dev/null || true + $(AR) $@ $(OFILES) + +SOMKSH=case "$(MAKESO)" in 1|[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]) echo $(ROOT)/mk/so.mk;; *) echo /dev/null;; esac +SOMK:=${shell $(SOMKSH)} +SOMK!=$(SOMKSH) +include $(SOMK) -include ${ROOT}/mk/common.mk diff --git a/mk/man.mk b/mk/man.mk @@ -3,6 +3,5 @@ uninstall: ${TARG:.1=.uninstall} printinstall: echo 'Install directories:' - echo ' Man: ${MAN}' + echo ' Man: $(MAN)' -include ${ROOT}/mk/common.mk diff --git a/mk/many.mk b/mk/many.mk @@ -1,6 +1,6 @@ PROGS = ${TARG:=.O} -all: ${OFILES} ${PROGS} +all: $(OFILES) $(PROGS) install: ${TARG:=.install} uninstall: ${TARG:=.uninstall} @@ -9,12 +9,10 @@ clean: manyclean printinstall: echo 'Install directories:' - echo ' Bin: ${BIN}' + echo ' Bin: $(BIN)' manyclean: - for i in ${TARG:=.o} ${TARG:=.O} ${OFILES}; do \ + for i in ${TARG:=.o} ${TARG:=.O} $(OFILES); do \ rm -f $$i; \ done 2>/dev/null || true -include ${ROOT}/mk/common.mk - diff --git a/mk/one.mk b/mk/one.mk @@ -1,25 +1,24 @@ -PROG = ${TARG}.O +PROG = $(TARG).O OFILES = ${OBJ:=.o} -all: ${PROG} +all: $(PROG) -install: ${TARG}.install -uninstall: ${TARG}.uninstall +install: $(TARG).install +uninstall: $(TARG).uninstall clean: oneclean depend: ${OBJ:=.depend} printinstall: echo 'Install directories:' - echo ' Bin: ${BIN}' + echo ' Bin: $(BIN)' oneclean: - for i in ${PROG} ${OFILES}; do \ + for i in $(PROG) $(OFILES); do \ rm -f $$i; \ done 2>/dev/null || true -${OFILES}: ${HFILES} +$(OFILES): $(HFILES) -${PROG}: ${OFILES} ${LIB} - ${LINK} $@ ${OFILES} ${LIB} +$(PROG): $(OFILES) $(LIB) + $(LINK) $@ $(OFILES) $(LIB) -include ${ROOT}/mk/common.mk diff --git a/mk/so.mk b/mk/so.mk @@ -0,0 +1,27 @@ +SOPTARG = $(ROOT)/lib/$(TARG) +SO = $(PTARG).so +SONAME = $(TARG).so +OFILES_PIC = ${OBJ:=.o_pic} + +all: $(HFILES) $(SO) + +install: $(SOPTARG).install +uninstall: $(SOPTARG).uninstall +clean: soclean +depend: ${OBJ:=.depend} + +soclean: + for i in $(SO) $(OFILES_PIC); do \ + rm -f $$i; \ + done 2>/dev/null || true + +printsoinstall: + echo 'Install directories:' + echo ' Lib: $(LIBDIR)' + +printinstall: printsoinstall + +$(SO): $(OFILES_PIC) + mkdir $(ROOT)/lib 2>/dev/null || true + $(LINKSO) $@ $(OFILES_PIC) + diff --git a/rc/rc.wmii.rc b/rc/rc.wmii.rc @@ -1,30 +1,25 @@ #!/usr/bin/env wmii9rc -# WMII Configuration - -ifs='' {nl=`{echo}} - -confpath=`{echo $WMII_CONFPATH | sed 'y/:/ /'} -oldpath=$path -path=($PLAN9/bin $path) +scriptname=$0 +oldpath=$path; path=($PLAN9/bin $path) +. wmii.rc wmiirc # Include utility functions -# Sanity checks -if(echo $0 | grep -s '(^|/)rc\.wmii\.local$') { - echo >[1=2] Fatal: This file must not be named rc.wmii.local - exit badname -} +# WMII Configuration -# Configurables +# Keys MODKEY=Mod1 UP=k DOWN=j LEFT=h RIGHT=l -WMII_FONT='-*-fixed-medium-r-*-*-13-*-*-*-*-*-*-*' -WMII_NORMCOLORS=('#222222' '#5FBF77' '#2A7F3F') -WMII_FOCUSCOLORS=('#ffffff' '#153F1F' '#2A7F3F') -WMII_BACKGROUND='#333333' +# Theme +wmiifont='drift,-*-fixed-*-*-*-*-9-*-*-*-*-*-*-*' +wmiifont='-*-fixed-medium-r-*-*-13-*-*-*-*-*-*-*' +wmiinormcol=`{echo '#222222 #5FBF77 #2A7F3F'} +wmiifocuscol=`{echo '#ffffff #153F1F #2A7F3F'} +wmiibackground='#333333' +# Programs WMII_TERM=(xterm) # Column Rules @@ -34,117 +29,85 @@ wmiir write /colrules <<! # Tagging Rules wmiir write /tagrules <<! +/VLC/ -> ~ /XMMS.*/ -> ~ /MPlayer.*/ -> ~ /.*/ -> sel -/.*/ -> 1 ! # Status Bar Info -fn status { echo -n `{uptime | sed 's/.*://; s/,//g'} '|' `{date} } -fn viewtitle { echo $* } - -# Convenience Functions -fn wmiimenu { - dmenu -b -fn $WMII_FONT \ - -nf $WMII_NORMCOLORS(1) -nb $WMII_NORMCOLORS(2) \ - -sf $WMII_FOCUSCOLORS(1) -sb $WMII_FOCUSCOLORS(2) +fn status { + echo -n `{uptime | sed 's/.*://; s/,//g'} \ + '|' `{date} } -fn 9menu { - wmii9menu -font $WMII_FONT \ - -^(nf nb br)^$WMII_NORMCOLORS \ - -^(sf sb br)^$WMII_FOCUSCOLORS $* -} - -fn proglist { - /bin/ls -lL `{echo $* | sed 'y/:/ /'} >[2]/dev/null \ - | awk '$1 ~ /^[^d].*x/ && NF > 2 { print $NF }' \ - | sort | uniq -} - -fn actionlist { - { proglist $WMII_CONFPATH - getfuns Action - } | sort | uniq -} - -fn config_whatis { - prog = `{@{path=$confpath whatis $1} | grep -v '^fn|= ' || echo /dev/null} - shift; echo $prog $* -} - -fn run_command { @{ - rfork ns - path=$oldpath - eval exec $* & - } -} - -fn getfuns { - env | sed -n 's/^fn#'^$1^'-([^=]+).*/\1/p' -} -fn initkeys { - getfuns Key | wmiir write /keys -} -fn read_tags { - wmiir ls /tag | sed 's,/,,; /^sel$/d' -} +# End Configuration -fn 'fn?' {rc -c 'whatis '$1 >[2]/dev/null | grep -s '^fn ' } +ifs='' {nl=`{echo}} +confpath=`{echo $WMII_CONFPATH | sed 'y/:/ /'} # Events -fn Event-Start { - switch($1) { - case wmiirc - rm -f $progs_file - exit - } +fn sigexit { + rm -f $progs_file + wi_cleankeys } -fn Event-Key { Key-$1 $1 } -fn Event-CreateTag { echo $WMII_NORMCOLORS `{viewtitle $*} | wmiir create /lbar/$"* } +fn Event-CreateTag { echo $wmiinormcol $* | wmiir create /lbar/$"* } fn Event-DestroyTag { wmiir remove /lbar/$"* } -fn Event-FocusTag { wmiir xwrite /lbar/$"* $WMII_FOCUSCOLORS `{viewtitle $*} } -fn Event-UnfocusTag { wmiir xwrite /lbar/$"* $WMII_NORMCOLORS `{viewtitle $*} } +fn Event-FocusTag { wmiir xwrite /lbar/$"* $wmiifocuscol $* } +fn Event-UnfocusTag { wmiir xwrite /lbar/$"* $wmiinormcol $* } fn Event-UrgentTag { shift; wmiir xwrite /lbar/$"* '*'$"* } fn Event-NotUrgentTag { shift; wmiir xwrite /lbar/$"* $"* } -fn Event-LeftBarClick { shift; wmiir xwrite /ctl view $* } +fn Event-Unresponsive { + client = $1; shift + @{ + msg = 'The following client is not responding. What would you like to do?' + resp = `{wihack -transient $client \ + xmessage -nearmouse -buttons Kill,Wait -print \ + $msg $nl '' `{wmiir read /client/sel/label}} + if(~ $resp Kill) + wmiir xwrite /client/$client/ctl slay + }& +} +fn Event-LeftBarClick { shift; wmiir xwrite /ctl view $* } fn Event-ClientMouseDown { client = $1; button = $2 if(~ $button 3) { - do=`{9menu -initial $menulast Nop Delete Fullscreen} + do=`{wi_9menu -initial $menulast Nop Delete Fullscreen} switch($do) { case Delete wmiir xwrite /client/$client/ctl kill case Fullscreen wmiir xwrite /client/$client/ctl Fullscreen on } - if(! ~ $#do 0) + if(! ~ $do '') menulast = $do; } } menulast = Nop +# Utility +fn 'fn?' {rc -c 'whatis '$1 >[2]/dev/null | grep -s '^fn ' } + +# Actions fn Action { cmd=$1 action=Action-$cmd { shift if('fn?' $action) $action $* if not - run_command `{config_whatis $cmd} $* + wi_runcmd `{wi_script $cmd} $* } & } # Actions fn Action-rehash { - if(test -d /proc/$pid) - for(i in $WMII_NS_DIR/proglist.*) { - id=`{echo $i | sed 's/.*\.(.*)/\1/'} \ - if(! test -d /proc/$id) rm $i - } - proglist $PATH >$progs_file + comm -23 <{ls $WMII_NS_DIR/proglist.* | awk -F'\.' '{print $NF}'} \ + <{ps | awk '{print $2}'} | + while(id=`{read}) + rm $WMII_NS_DIR/proglist.$id + wi_proglist $PATH >$progs_file } fn Action-quit { wmiir xwrite /ctl quit } fn Action-exec { wmiir xwrite /ctl exec $* } @@ -152,24 +115,16 @@ fn Action-status { flag x -; flag r - if(wmiir remove /rbar/status >[2]/dev/null) sleep 2 - echo $WMII_NORMCOLORS | wmiir create /rbar/status + echo $wmiinormcol | wmiir create /rbar/status while(status | wmiir write /rbar/status) sleep 1 } # Source Variables, &c -local = `{config_whatis rc.wmii.local} -. <{awk '//; - /^# Overrides/ { - print "xmessage -file - <<!" - print "rc.wmii: Warning:" - print " Your rc.wmii.local contains an ''# Overrides'' line." - print " This line has a deprecated special meaning. Functions" - print " you wish to override should be defined in a function" - print " called Action-overridekeys" - print "!" - exit - }' $local </dev/null} +if(~ $0 rc.wmii.local */rc.wmii.local) + wi_notice This file should not be named rc.wmii.local +if not + . `{wi_script rc.wmii.local} /dev/null # Key Bindings fn key { @@ -178,12 +133,15 @@ fn key { ~ $#key 0 } +# This is... ugly. + key $MODKEY-Control-t || fn $key { switch(`{wmiir read /keys | wc -l}) { case 0 1 - initkeys + wmiir xwrite /ctl $keys wmiir xwrite /ctl grabmod $MODKEY case * + ifs=() { keys=`{wmiir read /keys} } wmiir xwrite /keys $MODKEY-Control-t wmiir xwrite /ctl grabmod Mod3 } @@ -209,37 +167,36 @@ key $MODKEY-m || fn $key { wmiir xwrite /tag/sel/ctl colmode sel max } key $MODKEY-Shift-c || fn $key { wmiir xwrite /client/sel/ctl kill } -key $MODKEY-a || fn $key { Action `{actionlist | wmiimenu} & } -key $MODKEY-p || fn $key { ifs=() { run_command `{wmiimenu <$progs_file} & } } -key $MODKEY-Return || fn $key { run_command $WMII_TERM & } +key $MODKEY-a || fn $key { Action `{wi_actions | wi_menu} & } +key $MODKEY-p || fn $key { ifs=() { wi_runcmd -t `{wi_menu <$progs_file} & } } +key $MODKEY-Return || fn $key { wi_runcmd $WMII_TERM & } -key $MODKEY-t || fn $key { wmiir xwrite /ctl view `{read_tags | wmiimenu} & } +key $MODKEY-t || fn $key { wmiir xwrite /ctl view `{wi_tags | wi_menu} & } key $MODKEY-Shift-t || fn $key { sel = `{wmiir read /client/sel/ctl | sed 1q} \ - wmiir xwrite /client/$sel/tags `{read_tags | wmiimenu} & + wmiir xwrite /client/$sel/tags `{wi_tags | wi_menu} & } -key $MODKEY-^`{seq 0 9}|| fn $key { wmiir xwrite /ctl view `{echo $1 | sed 's/.*-//'} } +key $MODKEY-^`{seq 0 9} || fn $key { + wmiir xwrite /ctl view `{echo $1 | sed 's/.*-//'} +} key Shift-$MODKEY-^`{seq 0 9} || fn $key { wmiir xwrite /client/sel/tags `{echo $1 | sed 's/.*-//'} } # WM Configuration wmiir write /ctl <<! + view 1 grabmod $MODKEY border 2 - font $WMII_FONT - focuscolors $WMII_FOCUSCOLORS - normcolors $WMII_NORMCOLORS + font $wmiifont + focuscolors $wmiifocuscol + normcolors $wmiinormcol ! xsetroot -solid $WMII_BACKGROUND # Source Overrides -. <{awk '/^# Overrides/, 0' $local </dev/null} -if('fn?' Action-overridekeys) - Action-overridekeys -if not - . `{config_whatis overridekeys} +Action overridekeys # Misc Setup progs_file=$WMII_NS_DIR/proglist.$pid @@ -248,26 +205,15 @@ Action rehash # Tag Bar Setup ifs=$nl{ - wmiir rm `{comm -23 <{wmiir ls /lbar} <{read_tags}} + wmiir rm `{comm -23 <{wmiir ls /lbar} <{wi_tags}} seltag=`{wmiir read /tag/sel/ctl | sed 1q} - for(tag in `{read_tags}) { + for(tag in `{wi_tags}) { if(~ $tag $seltag) - echo $WMII_FOCUSCOLORS `{viewtitle $tag} | wmiir create /lbar/$tag + echo $wmiifocuscol $tag | wmiir create /lbar/$tag if not - echo $WMII_NORMCOLORS `{viewtitle $tag} | wmiir create /lbar/$tag + echo $wmiinormcol $tag | wmiir create /lbar/$tag } } -# Keygrab Setup -initkeys - -if(echo Start wmiirc | ! wmiir write /event >[2]/dev/null) - exit write - -# Event Loop -wmiir read /event | - while(*=`{read}) { - event = $1; shift - Event-$event $* - } >[2]/dev/null </dev/null +wi_eventloop diff --git a/rc/sh.wmii b/rc/sh.wmii @@ -45,8 +45,7 @@ echo ' /Firefox/ -> www /XMMS.*/ -> ~ /MPlayer.*/ -> ~ -/.*/ -> ! -/.*/ -> 1 +/.*/ -> sel ' >/tagrules subfn seq { @@ -139,6 +138,7 @@ Event ClientMouseDown { (client button) := $* if {~ $button 3} { lastcmd = `{9menu -initial $lastcmd Nop Delete Fullscreen} + if{~ $#lastcmd 0} {lastcmd=''} cmp := {~ $lastcmd $*} if {$cmp Nop} { } {$cmp Delete} { echo kill >/client/$client/ctl @@ -174,7 +174,7 @@ fn Action { Key $MODKEY-Control-t { if { ~ `{wc -l /keys} 0 1} { initkeys - grabmod $MODKEY >/ctl + echo grabmod $MODKEY >/ctl } { echo $MODKEY-Control-t >/keys echo grabmod Mod3 >/ctl diff --git a/rc/wmiirc.sh b/rc/wmiirc.sh @@ -201,8 +201,9 @@ xsetroot -solid "$WMII_BACKGROUND" & # Setup Tag Bar (IFS="$(echo)"; wmiir rm $(wmiir ls /lbar)) -seltag="$(wmiir read /tag/sel/ctl 2>/dev/null | sed 1q)" -wmiir ls /tag | sed -e 's|/||; /^sel$/d' | while read tag; do +seltag="$(wmiir read /tag/sel/ctl | sed 1q)" +wmiir ls /tag | sed -e 's|/||; /^sel$/d' | while read tag +do if [ "$tag" = "$seltag" ]; then echo "$WMII_FOCUSCOLORS" "$tag" else @@ -230,7 +231,8 @@ conf_which() { # Stop any running instances of wmiirc echo Start wmiirc | wmiir write /event || exit 1 -wmiir read /event | while read event; do +wmiir read /event | while read event +do set -- $event event=$1; shift Event_$event $@ diff --git a/util/compile b/util/compile @@ -15,10 +15,49 @@ status=$? base=$(echo $BASE | sed 's/,/\\,/g') re='\([^[:space:]/]*\..:[0-9]\)' +undup() { # GCC is crap. + awk ' + function shift() { + for(n=1; n<=3; n++) + if(2*n <= nl) + for(i=1; i<=n; i++) { + if(l[i] != l[i+n]) + break; + if(i == n) { + for(i=1; i<=n; i++) + print l[i] + nl -= 2*n; + for(i=1; i<=nl; i++) + l[i] = l[i+2*n]; + return; + } + } + if(nl == 0) + return + print l[1] + for(i=1; i<nl; i++) + l[i] = l[i+1] + nl-- + } + BEGIN{ + nl=0 + maxl=6 + } + { + if(nl == maxl) + shift() + l[++nl] = $0 + } + END{ + while(nl > 0) + shift(); + }' +} + cat $xtmp | sed "s,^$re,$base&,g; s,\([[:space:]]\)$re,\1$base\2,g" | egrep -v ': error: .Each undeclared identifier|: error: for each function it appears|is dangerous, better use|is almost always misused|: In function |: At top level:|support .long long.|use of C99 long long|ISO C forbids conversion' | sed 's/ .first use in this function.$//; s/\"\([^\"][^\"]*\)\", line \([0-9][0-9]*\)/\1:\2/g' | - uniq 1>&2 + undup 1>&2 rm -f $xtmp exit $status diff --git a/util/genconfig b/util/genconfig @@ -100,14 +100,17 @@ 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 \ +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 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 +findlib LIBIXP ixp "$ROOT/lib" $libs +[ -e "$ROOT/libixp" ] && LIBIXP="$ROOT/lib/libixp.a" LIBIXP=$(echo "$LIBIXP"|sed 's,^-L\([^ ]*\) -l\([^ ]*\)$,\1/lib\2.a,') IFS="$oifs" @@ -115,6 +118,12 @@ IFS="$oifs" echo Library paths... prompt INCX11 Compiler flags to find X11 includes prompt LIBX11 Linker flags to link against libX11 +# Yuck... +if nm -D `ldd /bin/sh | awk '$1 ~ /^libc\.so/ {print $3}'` | + awk '$2 == "T" && $3 == "iconv" {exit 0}; END {exit 1}' +then + echo "Your system's libc appears to contain iconv" +fi 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 diff --git a/util/link b/util/link @@ -9,7 +9,7 @@ args="" for i do case "$i" in - *.[ao]) + *.[ao]|*.o_pic) ofiles="$ofiles $i" ;; *)