Add wistrut. Undocumented, not built by default.

This commit is contained in:
Kris Maglione 2008-03-21 13:41:30 -04:00
parent 86059e16d2
commit a95494a9f7
13 changed files with 816 additions and 4 deletions

26
cmd/strut/Makefile Normal file
View File

@ -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

77
cmd/strut/_util.c Normal file
View File

@ -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);
}

33
cmd/strut/dat.h Normal file
View File

@ -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__)

309
cmd/strut/event.c Normal file
View File

@ -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);
}
}

84
cmd/strut/ewmh.c Normal file
View File

@ -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));
}

18
cmd/strut/fns.h Normal file
View File

@ -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);

144
cmd/strut/main.c Normal file
View File

@ -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;
}

View File

@ -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);
}

103
cmd/strut/win.c Normal file
View File

@ -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,
};

View File

@ -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);

View File

@ -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;

View File

@ -278,6 +278,11 @@ setwinattr(Window *w, WinAttr *wa, int valmask) {
XChangeWindowAttributes(display, w->w, valmask, wa);
}
void
selectinput(Window *w, long mask) {
XSelectInput(display, w->w, mask);
}
void
setborder(Window *w, int width, long pixel) {
Rectangle r;

View File

@ -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);