wmii

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

commit a95494a9f736377e9c30c62fda61efce6f4f87a2
parent 86059e16d2f518d9c8cd3c594d1d590d6850ccad
Author: Kris Maglione <jg@suckless.org>
Date:   Fri, 21 Mar 2008 13:41:30 -0400

Add wistrut. Undocumented, not built by default.

Diffstat:
cmd/strut/Makefile | 26++++++++++++++++++++++++++
cmd/strut/_util.c | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/strut/dat.h | 33+++++++++++++++++++++++++++++++++
cmd/strut/event.c | 309+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/strut/ewmh.c | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/strut/fns.h | 18++++++++++++++++++
cmd/strut/main.c | 144+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/strut/printevent_kludge.c | 12++++++++++++
cmd/strut/win.c | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/wmii/client.c | 2+-
cmd/wmii/main.c | 5++---
cmd/wmii/x11.c | 5+++++
include/x11.h | 2++
13 files changed, 816 insertions(+), 4 deletions(-)

diff --git a/cmd/strut/Makefile b/cmd/strut/Makefile @@ -0,0 +1,26 @@ +ROOT= ../.. +include ${ROOT}/mk/hdr.mk +include ${ROOT}/mk/wmii.mk + +main.c: ${ROOT}/mk/wmii.mk + +TARG = wistrut +HFILES= dat.h fns.h + +LIB = ${LIBIXP} +LDFLAGS += -lm ${LIBX11} -lXext -lXrandr -lregexp9 -lbio -lfmt -lutf +CFLAGS += ${INCX11} -DVERSION=\"${VERSION}\" \ + -DIXP_NEEDAPI=86 +OBJ = main \ + event \ + ewmh \ + win \ + _util \ + ../wmii/map \ + ../wmii/printevent \ + printevent_kludge \ + ../wmii/x11 \ + ../util + +include ${ROOT}/mk/one.mk + diff --git a/cmd/strut/_util.c b/cmd/strut/_util.c @@ -0,0 +1,77 @@ +/* Copyright ©2008 Kris Maglione <fbsdaemon@gmail.com> + * See LICENSE file for license details. + */ +#include "dat.h" +#include <ctype.h> +#include <string.h> +#include "fns.h" + +#define strbcmp(str, const) (strncmp((str), (const), sizeof(const)-1)) +static int +getbase(const char **s, long *sign) { + const char *p; + int ret; + + ret = 10; + *sign = 1; + if(**s == '-') { + *sign = -1; + *s += 1; + }else if(**s == '+') + *s += 1; + + p = *s; + if(!strbcmp(p, "0x")) { + *s += 2; + ret = 16; + } + else if(isdigit(p[0])) { + if(p[1] == 'r') { + *s += 2; + ret = p[0] - '0'; + } + else if(isdigit(p[1]) && p[2] == 'r') { + *s += 3; + ret = 10*(p[0]-'0') + (p[1]-'0'); + } + } + else if(p[0] == '0') { + ret = 8; + } + if(ret != 10 && (**s == '-' || **s == '+')) + *sign = 0; + return ret; +} + +bool +getlong(const char *s, long *ret) { + const char *end; + char *rend; + int base; + long sign; + + end = s+strlen(s); + base = getbase(&s, &sign); + if(sign == 0) + return false; + + *ret = sign * strtol(s, &rend, base); + return (end == rend); +} + +bool +getulong(const char *s, ulong *ret) { + const char *end; + char *rend; + int base; + long sign; + + end = s+strlen(s); + base = getbase(&s, &sign); + if(sign < 1) + return false; + + *ret = strtoul(s, &rend, base); + return (end == rend); +} + diff --git a/cmd/strut/dat.h b/cmd/strut/dat.h @@ -0,0 +1,33 @@ +#include <fmt.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdlib.h> +#include <unistd.h> +#include <util.h> +#include <ixp.h> +#include <x11.h> + +#define BLOCK(x) do { x; }while(0) + +#ifndef EXTERN +# define EXTERN extern +#endif + +extern Handlers handlers; + +EXTERN bool running; + +EXTERN Window win; +EXTERN Window frame; +EXTERN long xtime; + +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__) + diff --git a/cmd/strut/event.c b/cmd/strut/event.c @@ -0,0 +1,309 @@ +/* Copyright ©2006-2008 Kris Maglione <fbsdaemon@gmail.com> + * See LICENSE file for license details. + */ +#include "dat.h" +#include "fns.h" + +static void (*handler[LASTEvent])(XEvent*); + +void +dispatch_event(XEvent *e) { + /* printevent(e); */ + if(e->type < nelem(handler) && handler[e->type]) + handler[e->type](e); +} + +#define handle(w, fn, ev) \ + BLOCK(if((w)->handler->fn) (w)->handler->fn((w), ev)) + +#ifdef notdef +uint +flushevents(long event_mask, bool dispatch) { + XEvent ev; + uint n = 0; + + while(XCheckMaskEvent(display, event_mask, &ev)) { + if(dispatch) + dispatch_event(&ev); + n++; + } + return n; +} + +static int +findenter(Display *d, XEvent *e, XPointer v) { + long *l; + + USED(d); + 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; +} +#endif + +static int +findtime(Display *d, XEvent *e, XPointer v) { + Window *w; + + w = (Window*)v; + if(e->type == PropertyNotify && e->xproperty.window == w->w) { + xtime = e->xproperty.time; + return true; + } + return false; +} + +void +xtime_kludge(void) { + Window *w; + WinAttr wa; + XEvent e; + long l; + + w = createwindow(&scr.root, Rect(0, 0, 1, 1), 0, InputOnly, &wa, 0); + + XSelectInput(display, w->w, PropertyChangeMask); + changeprop_long(w, "ATOM", "ATOM", &l, 0); + XIfEvent(display, &e, findtime, (void*)w); + + destroywindow(w); +} + +static void +buttonrelease(XEvent *e) { + XButtonPressedEvent *ev; + Window *w; + + ev = &e->xbutton; + if((w = findwin(ev->window))) + handle(w, bup, ev); +} + +static void +buttonpress(XEvent *e) { + XButtonPressedEvent *ev; + Window *w; + + ev = &e->xbutton; + if((w = findwin(ev->window))) + handle(w, bdown, ev); + else + XAllowEvents(display, ReplayPointer, ev->time); +} + +static void +clientmessage(XEvent *e) { + XClientMessageEvent *ev; + + ev = &e->xclient; + USED(ev); +} + +static void +configurenotify(XEvent *e) { + XConfigureEvent *ev; + Window *w; + + ev = &e->xconfigure; + if((w = findwin(ev->window))) + handle(w, config, ev); +} + +static void +destroynotify(XEvent *e) { + XDestroyWindowEvent *ev; + Window *w; + + ev = &e->xdestroywindow; + if((w = findwin(ev->window))) + handle(w, destroy, ev); +} + +static void +enternotify(XEvent *e) { + XCrossingEvent *ev; + Window *w; + + ev = &e->xcrossing; + xtime = ev->time; + if(ev->mode != NotifyNormal) + return; + + if((w = findwin(ev->window))) + handle(w, enter, ev); +} + +static void +leavenotify(XEvent *e) { + XCrossingEvent *ev; + + ev = &e->xcrossing; + xtime = ev->time; +} + +static void +focusin(XEvent *e) { + XFocusChangeEvent *ev; + Window *w; + + ev = &e->xfocus; + /* Yes, we're focusing in on nothing, here. */ + if(ev->detail == NotifyDetailNone) { + /* FIXME: Do something. */ + return; + } + + if(!((ev->detail == NotifyNonlinear) + ||(ev->detail == NotifyNonlinearVirtual) + ||(ev->detail == NotifyVirtual) + ||(ev->detail == NotifyInferior) + ||(ev->detail == NotifyAncestor))) + return; + if((ev->mode == NotifyWhileGrabbed)) + return; + + if((w = findwin(ev->window))) + handle(w, focusin, ev); +} + +static void +focusout(XEvent *e) { + XFocusChangeEvent *ev; + Window *w; + + ev = &e->xfocus; + if(!((ev->detail == NotifyNonlinear) + ||(ev->detail == NotifyNonlinearVirtual) + ||(ev->detail == NotifyVirtual) + ||(ev->detail == NotifyInferior) + ||(ev->detail == NotifyAncestor))) + return; + + if((w = findwin(ev->window))) + handle(w, focusout, ev); +} + +static void +expose(XEvent *e) { + XExposeEvent *ev; + Window *w; + + ev = &e->xexpose; + if(ev->count == 0) { + if((w = findwin(ev->window))) + handle(w, expose, ev); + } +} + +static void +keypress(XEvent *e) { + XKeyEvent *ev; + + ev = &e->xkey; + xtime = ev->time; +} + +static void +mappingnotify(XEvent *e) { + XMappingEvent *ev; + + ev = &e->xmapping; + /* Why do you need me to tell you this? */ + XRefreshKeyboardMapping(ev); +} + +static void +motionnotify(XEvent *e) { + XMotionEvent *ev; + Window *w; + + ev = &e->xmotion; + xtime = ev->time; + if((w = findwin(ev->window))) + handle(w, motion, ev); +} + +static void +propertynotify(XEvent *e) { + XPropertyEvent *ev; + Window *w; + + ev = &e->xproperty; + xtime = ev->time; + if((w = findwin(ev->window))) + handle(w, property, ev); +} + +static void +mapnotify(XEvent *e) { + XMapEvent *ev; + Window *w; + + ev = &e->xmap; + if((w = findwin(ev->window))) + handle(w, map, ev); +} + +static void +unmapnotify(XEvent *e) { + XUnmapEvent *ev; + Window *w; + + ev = &e->xunmap; + if((w = findwin(ev->window)) && w->parent && (ev->event == w->parent->w)) { + if(ev->send_event || w->unmapped-- == 0) + handle(w, unmap, ev); + } +} + +static void (*handler[LASTEvent])(XEvent*) = { + [ButtonPress] = buttonpress, + [ButtonRelease] = buttonrelease, + [ClientMessage] = clientmessage, + [ConfigureNotify] = configurenotify, + [DestroyNotify] = destroynotify, + [EnterNotify] = enternotify, + [Expose] = expose, + [FocusIn] = focusin, + [FocusOut] = focusout, + [KeyPress] = keypress, + [LeaveNotify] = leavenotify, + [MapNotify] = mapnotify, + [MappingNotify] = mappingnotify, + [MotionNotify] = motionnotify, + [PropertyNotify] = propertynotify, + [UnmapNotify] = unmapnotify, +}; + +void +xevent_loop(void) { + XEvent ev; + + while(running) { + XNextEvent(display, &ev); + dispatch_event(&ev); + } +} + diff --git a/cmd/strut/ewmh.c b/cmd/strut/ewmh.c @@ -0,0 +1,84 @@ +/* Copyright ©2007-2008 Kris Maglione <fbsdaemon@gmail.com> + * See LICENSE file for license details. + */ +#include "dat.h" +#include <limits.h> +#include <string.h> +#include "fns.h" + +#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)) + +enum { + Left, Right, Top, Bottom, + LeftMin, LeftMax, + RightMin, RightMax, + TopMin, TopMax, + BottomMin, BottomMax, + Last +}; + +void +ewmh_getstrut(Window *w, Rectangle struts[4]) { + long *strut; + ulong n; + + memset(struts, 0, sizeof struts); + + n = getprop_long(w, Net("WM_STRUT_PARTIAL"), "CARDINAL", + 0L, &strut, Last); + if(n != Last) { + free(strut); + n = getprop_long(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; + } + struts[Left] = Rect(0, strut[LeftMin], strut[Left], strut[LeftMax]); + struts[Right] = Rect(-strut[Right], strut[RightMin], 0, strut[RightMax]); + struts[Top] = Rect(strut[TopMin], 0, strut[TopMax], strut[Top]); + struts[Bottom] = Rect(strut[BottomMin], -strut[Bottom], strut[BottomMax], 0); + free(strut); +} + +void +ewmh_setstrut(Window *w, Rectangle struts[4]) { + long strut[Last]; + int i; + + strut[LeftMin] = struts[Left].min.y; + strut[Left] = struts[Left].max.x; + strut[LeftMax] = struts[Left].max.y; + + strut[RightMin] = struts[Right].min.y; + strut[Right] = -struts[Right].min.x; + strut[RightMax] = struts[Right].max.y; + + strut[TopMin] = struts[Top].min.x; + strut[Top] = struts[Top].max.y; + strut[TopMax] = struts[Top].max.x; + + strut[BottomMin] = struts[Bottom].min.x; + strut[Bottom] = -struts[Bottom].min.y; + strut[BottomMax] = struts[Bottom].max.x; + + for(i=0; i<Last; i++) + if(strut[i] < 0) + strut[i] = 0; + + changeprop_long(w, Net("WM_STRUT_PARTIAL"), "CARDINAL", strut, nelem(strut)); +} + diff --git a/cmd/strut/fns.h b/cmd/strut/fns.h @@ -0,0 +1,18 @@ + +void debug(int, const char*, ...); +void dispatch_event(XEvent*); +uint flushevents(long, bool); +uint flushenterevents(void); +void xevent_loop(void); +void xtime_kludge(void); + +void restrut(void); + +bool getlong(const char*, long*); +bool getulong(const char*, ulong*); + +void ewmh_getstrut(Window*, Rectangle[4]); +void ewmh_setstrut(Window*, Rectangle[4]); + +void printevent(XEvent *e); + diff --git a/cmd/strut/main.c b/cmd/strut/main.c @@ -0,0 +1,144 @@ +/* Copyright ©2006-2008 Kris Maglione <fbsdaemon@gmail.com> + * See LICENSE file for license details. + */ +#define EXTERN +#include "dat.h" +#include <X11/Xproto.h> +#include <locale.h> +#include <string.h> +#include "fns.h" + +static const char version[] = "witray-"VERSION", ©2007 Kris Maglione\n"; + +static int (*xlib_errorhandler) (Display*, XErrorEvent*); + +static void +usage(void) { + fatal("usage: %s <window>\n", argv0); +} + +static int +errfmt(Fmt *f) { + return fmtstrcpy(f, ixp_errbuf()); +} + +void +debug(int flag, const char *fmt, ...) { + va_list ap; + + USED(flag); + va_start(ap, fmt); + vfprint(2, fmt, ap); + va_end(ap); +} + +/* + * There's no way to check accesses to destroyed windows, thus + * those cases are ignored (especially on UnmapNotifies). + * Other types of errors call Xlib's default error handler, which + * calls exit(). + */ +struct { + uchar rcode; + uchar ecode; +} itab[] = { + { 0, BadWindow }, + { X_SetInputFocus, BadMatch }, + { X_PolyText8, BadDrawable }, + { X_PolyFillRectangle, BadDrawable }, + { X_PolySegment, BadDrawable }, + { X_ConfigureWindow, BadMatch }, + { X_GrabKey, BadAccess }, + { X_GetAtomName, BadAtom }, +}; + +static int +errorhandler(Display *dpy, XErrorEvent *error) { + int i; + + USED(dpy); + + if(error->request_code == X_QueryTree + && error->error_code == BadWindow + && error->resourceid == win.w) + fatal("%W: window does not exist", &win); + + for(i = 0; i < nelem(itab); i++) + if((itab[i].rcode == 0 || itab[i].rcode == error->request_code) + && (itab[i].ecode == 0 || itab[i].ecode == error->error_code)) + return 0; + + fprint(2, "%s: fatal error: Xrequest code=%d, Xerror code=%d\n", + argv0, error->request_code, error->error_code); + + return xlib_errorhandler(display, error); /* calls exit() */ +} + +static Window +findframe(Window *w) { + XWindow *children; + XWindow xw, par, root; + Window ret = {0, }; + uint n; + + for(par=w->w; par != scr.root.w; ) { + xw = par; + XQueryTree(display, xw, &root, &par, &children, &n); + XFree(children); + } + ret.w = xw; + ret.parent = &scr.root; + return ret; +} + +static void +getwinsize(Window *win) { + int x, y; + uint w, h; + /* ignored */ + XWindow root; + uint border, depth; + + XGetGeometry(display, win->w, &root, + &x, &y, &w, &h, + &border, &depth); + win->r = rectaddpt(Rect(0, 0, w, h), + Pt(x, y)); +} + +int +main(int argc, char *argv[]) { + char *s; + + fmtinstall('r', errfmt); + + ARGBEGIN{ + default: + usage(); + }ARGEND; + + s = EARGF(usage()); + if(!getulong(s, &win.w)) + usage(); + + if(argc) + usage(); + + setlocale(LC_CTYPE, ""); + + initdisplay(); + xlib_errorhandler = XSetErrorHandler(errorhandler); + + frame = findframe(&win); + getwinsize(&frame); + restrut(); + sethandler(&frame, &handlers); + selectinput(&frame, StructureNotifyMask); + + running = true; + xevent_loop(); + + XCloseDisplay(display); + return 0; +} + diff --git a/cmd/strut/printevent_kludge.c b/cmd/strut/printevent_kludge.c @@ -0,0 +1,12 @@ +#include "dat.h" + +void dprint(const char *fmt, ...); +void +dprint(const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + vfprint(2, fmt, ap); + va_end(ap); +} + diff --git a/cmd/strut/win.c b/cmd/strut/win.c @@ -0,0 +1,103 @@ +/* Copyright ©2008 Kris Maglione <fbsdaemon@gmail.com> + * See LICENSE file for license details. + */ +#include "dat.h" +#include <string.h> +#include "fns.h" + +void +restrut(void) { + enum { Left, Right, Top, Bottom }; + Rectangle strut[4]; + Rectangle r; + + r = frame.r; + memset(strut, 0, sizeof strut); + if(Dx(r) < Dx(scr.rect)/2) { + if(r.min.x <= scr.rect.min.x) { + strut[Left] = r; + strut[Left].min.x = 0; + strut[Left].max.x -= scr.rect.min.x; + } + if(r.max.x >= scr.rect.max.x) { + strut[Right] = r; + strut[Right].min.x -= scr.rect.max.x; + strut[Right].max.x = 0; + } + } + if(Dy(r) < Dy(scr.rect)/2) { + if(r.min.y <= scr.rect.min.y) { + strut[Top] = r; + strut[Top].min.y = 0; + strut[Top].max.y -= scr.rect.min.y; + } + if(r.max.y >= scr.rect.max.y) { + strut[Bottom] = r; + strut[Bottom].min.y -= scr.rect.max.y; + strut[Bottom].max.y = 0; + } + } + +#define pstrut(name) \ + if(!eqrect(strut[name], ZR)) \ + fprint(2, "strut["#name"] = %R\n", strut[name]) + /* Choose the struts which take up the least space. + * Not ideal. + */ + if(Dy(strut[Top])) { + if(strut[Top].min.x <= scr.rect.min.x) + if(Dy(strut[Top]) < Dx(strut[Left])) + strut[Left] = ZR; + else + strut[Top] = ZR; + if(strut[Top].max.x >= scr.rect.max.x) + if(Dy(strut[Top]) < Dx(strut[Right])) + strut[Right] = ZR; + else + strut[Top] = ZR; + } + if(Dy(strut[Bottom])) { + if(strut[Bottom].min.x <= scr.rect.min.x) + if(Dy(strut[Bottom]) < Dx(strut[Left])) + strut[Left] = ZR; + else + strut[Bottom] = ZR; + if(strut[Bottom].max.x >= scr.rect.max.x) + if(Dy(strut[Bottom]) < Dx(strut[Right])) + strut[Right] = ZR; + else + strut[Bottom] = ZR; + } + +#if 0 + pstrut(Left); + pstrut(Right); + pstrut(Top); + pstrut(Bottom); +#endif + + ewmh_setstrut(&win, strut); +} + +static void +config(Window *w, XConfigureEvent *ev) { + + USED(w); + + frame.r = rectaddpt(Rect(0, 0, ev->width, ev->height), + Pt(ev->x, ev->y)); + restrut(); + +} + +static void +destroy(Window *w, XDestroyWindowEvent *ev) { + USED(w, ev); + running = false; +} + +Handlers handlers = { + .config = config, + .destroy = destroy, +}; + diff --git a/cmd/wmii/client.c b/cmd/wmii/client.c @@ -152,7 +152,7 @@ client_create(XWindow w, XWindowAttributes *wa) { sethandler(c->framewin, &framehandler); sethandler(&c->w, &handlers); - XSelectInput(display, c->w.w, ClientMask); + selectinput(&c->w, ClientMask); p.x = def.border; p.y = labelh(def.font); diff --git a/cmd/wmii/main.c b/cmd/wmii/main.c @@ -328,9 +328,8 @@ main(int argc, char *argv[]) { xlib_errorhandler = XSetErrorHandler(errorhandler); check_other_wm = true; - XSelectInput(display, scr.root.w, - SubstructureRedirectMask - | EnterWindowMask); + selectinput(&scr.root, SubstructureRedirectMask + | EnterWindowMask); sync(); check_other_wm = false; diff --git a/cmd/wmii/x11.c b/cmd/wmii/x11.c @@ -279,6 +279,11 @@ setwinattr(Window *w, WinAttr *wa, int valmask) { } void +selectinput(Window *w, long mask) { + XSelectInput(display, w->w, mask); +} + +void setborder(Window *w, int width, long pixel) { Rectangle r; diff --git a/include/x11.h b/include/x11.h @@ -82,6 +82,7 @@ struct Handlers { Rectangle (*dndmotion)(Window*, Point); void (*bdown)(Window*, XButtonEvent*); void (*bup)(Window*, XButtonEvent*); + void (*config)(Window*, XConfigureEvent*); void (*configreq)(Window*, XConfigureRequestEvent*); void (*destroy)(Window*, XDestroyWindowEvent*); void (*enter)(Window*, XCrossingEvent*); @@ -221,6 +222,7 @@ Point querypointer(Window*); void raisewin(Window*); void reparentwindow(Window*, Window*, Point); void reshapewin(Window*, Rectangle); +void selectinput(Window*, long); void sendevent(Window*, bool propegate, long mask, XEvent*); void setborder(Window*, int, long); void setfocus(Window*, int mode);