diff options
author | Andrew Shadura <bugzilla@tut.by> | 2012-08-10 17:28:37 +0200 |
---|---|---|
committer | Andrew Shadura <bugzilla@tut.by> | 2012-08-10 17:28:37 +0200 |
commit | 73a0b1b034b50c3356b51e389daa8bfd5f113853 (patch) | |
tree | 89f259da840cdf6a7aad11b983942e7926c70d59 /cmd | |
parent | 79e6dfc63311b132887889a6f4f582480575e80a (diff) |
Synchronise to the latest hg tip.
Diffstat (limited to 'cmd')
81 files changed, 4575 insertions, 7717 deletions
diff --git a/cmd/Makefile b/cmd/Makefile index ea8690b..7df1ccb 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -4,30 +4,18 @@ include $(ROOT)/mk/wmii.mk wmiir.c: $(ROOT)/mk/wmii.mk -DIRS = wmii \ - menu +DIRS = menu \ + strut \ + tray \ + wmii \ + x11 TARG = wihack \ wmii.rc \ wmii.sh \ - wmii9menu \ wmiir -OFILES = util.o - -LIBS += $(LIBS9) -CFLAGS += $(INCX11) +LIBS += $(LIBS9) $(LIBIXP) include $(ROOT)/mk/many.mk include $(ROOT)/mk/dir.mk -OWMIIR=wmiir.o $(OFILES) $(LIBIXP) -wmiir.out: $(OWMIIR) - $(LINK) $@ $(OWMIIR) - -wmii/x11.o wmii/xext.o wmii/geom.o wmii/map.o: dall - true - -O9MENU=wmii9menu.o clientutil.o wmii/x11.o wmii/xext.o wmii/geom.o wmii/map.o $(OFILES) $(LIBIXP) -wmii9menu.out: $(O9MENU) - $(LINK) $@ $(O9MENU) $$(pkg-config --libs $(X11PACKAGES) xrandr xinerama) -lXext - diff --git a/cmd/click/Makefile b/cmd/click/Makefile deleted file mode 100644 index 1abf6cb..0000000 --- a/cmd/click/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -ROOT= ../.. -include ${ROOT}/mk/hdr.mk -include ${ROOT}/mk/wmii.mk - -main.c: ${ROOT}/mk/wmii.mk - -TARG = click -HFILES= dat.h fns.h - -PACKAGES += $(X11PACKAGES) xext xrandr xrender xinerama - -LIB = $(LIBIXP) -LIBS += -lm -lXtst $(LIBS9) -CFLAGS += -DVERSION=\"$(VERSION)\" -DIXP_NEEDAPI=86 -OBJ = main \ - _util \ - ../wmii/map \ - ../wmii/x11 \ - ../util - -include ${ROOT}/mk/one.mk - diff --git a/cmd/click/_util.c b/cmd/click/_util.c deleted file mode 100644 index 364ff81..0000000 --- a/cmd/click/_util.c +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright ©2008-2010 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/click/dat.h b/cmd/click/dat.h deleted file mode 100644 index 5096865..0000000 --- a/cmd/click/dat.h +++ /dev/null @@ -1,27 +0,0 @@ -#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 Window win; - -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/click/fns.h b/cmd/click/fns.h deleted file mode 100644 index d41b840..0000000 --- a/cmd/click/fns.h +++ /dev/null @@ -1,4 +0,0 @@ - -bool getlong(const char*, long*); -bool getulong(const char*, ulong*); - diff --git a/cmd/click/main.c b/cmd/click/main.c deleted file mode 100644 index 3ddc8ef..0000000 --- a/cmd/click/main.c +++ /dev/null @@ -1,62 +0,0 @@ -/* Copyright ©2006-2010 Kris Maglione <fbsdaemon@gmail.com> - * See LICENSE file for license details. - */ -#define EXTERN -#include "dat.h" -#include <X11/Xproto.h> -#include <X11/extensions/XTest.h> -#include <locale.h> -#include <string.h> -#include "fns.h" - -static const char version[] = "click-"VERSION", ©2010 Kris Maglione\n"; - -static void -usage(void) { - fatal("usage: %s [window]\n", argv0); -} - -static void -click(Window *w, Point p) { - Rectangle r; - Point rp; - - r = getwinrect(w); - rp = subpt(r.max, p); - - XTestFakeMotionEvent(display, 0, rp.x, rp.y, 0); - - XTestFakeButtonEvent(display, 1, true, 0); - XTestFakeButtonEvent(display, 1, false, 0); - - XTestFakeMotionEvent(display, 0, r.max.x, r.max.y, 0); -} - -int -main(int argc, char *argv[]) { - char *s; - - ARGBEGIN{ - default: - usage(); - }ARGEND; - - setlocale(LC_CTYPE, ""); - - initdisplay(); - - s = ARGF(); - if(s && !getulong(s, &win.w)) - usage(); - if (!s) - win.w = getfocus(); - - if(argc) - usage(); - - click(&win, Pt(1, 1)); - - XCloseDisplay(display); - return 0; -} - diff --git a/cmd/clientutil.c b/cmd/clientutil.c deleted file mode 100644 index 411fe67..0000000 --- a/cmd/clientutil.c +++ /dev/null @@ -1,50 +0,0 @@ -#define IXP_NO_P9_ -#define IXP_P9_STRUCTS -#define CLIENTEXTERN -#include <string.h> -#include <ixp.h> -#include <clientutil.h> -#include <util.h> - -static IxpCFid* ctlfid; -static char ctl[1024]; -static char* ectl; - -char* -readctl(char *key) { - char *s, *p; - int nkey, n; - - if(ctlfid == nil) { - ctlfid = ixp_open(client, "ctl", OREAD); - n = ixp_read(ctlfid, ctl, 1023); - ectl = ctl + n; - ixp_close(ctlfid); - } - - nkey = strlen(key); - p = ctl - 1; - do { - p++; - if(!strncmp(p, key, nkey)) { - p += nkey; - s = strchr(p, '\n'); - n = (s ? s : ectl) - p; - s = freelater(emalloc(n + 1)); - s[n] = '\0'; - return strncpy(s, p, n); - } - } while((p = strchr(p, '\n'))); - return ""; -} - -void -client_init(char* address) { - if(address && *address) - client = ixp_mount(address); - else - client = ixp_nsmount("wmii"); - if(client == nil) - fatal("can't mount: %r\n"); -} - diff --git a/cmd/menu/Makefile b/cmd/menu/Makefile index a2fc9ad..d8524c8 100644 --- a/cmd/menu/Makefile +++ b/cmd/menu/Makefile @@ -5,32 +5,24 @@ include $(ROOT)/mk/wmii.mk main.c: $(ROOT)/mk/wmii.mk bindings.c: keys.txt Makefile - ( echo "char binding_spec[] = "; \ + ( echo "char binding_spec[] ="; \ sed 's/.*/ "&\\n"/' keys.txt; \ - echo " ;" ) >bindings.c + echo " ;" ) >$@ TARG = wimenu HFILES= dat.h fns.h +TAGFILES= dat.h $(ROOT)/include/*.h $(ROOT)/include/stuff/*.h -PACKAGES += $(X11PACKAGES) xext xrandr xrender xinerama +PACKAGES += $(X11PACKAGES) -LIB = $(LIBIXP) -LIBS += -lm $(LIBS9) -CFLAGS += -DIXP_NEEDAPI=86 +LIB = $(LIBS9) $(LIBIXP) +LIBS += -lm OBJ = main \ caret \ history \ - event \ menu \ keys \ - bindings \ - ../wmii/geom \ - ../wmii/map \ - ../wmii/printevent \ - ../wmii/x11 \ - ../wmii/xext \ - ../clientutil \ - ../util + bindings include $(ROOT)/mk/one.mk diff --git a/cmd/menu/bindings.c b/cmd/menu/bindings.c deleted file mode 100644 index 28aad75..0000000 --- a/cmd/menu/bindings.c +++ /dev/null @@ -1,51 +0,0 @@ -char binding_spec[] = - "Control-j Accept\n" - "Control-m Accept\n" - "Return Accept\n" - "Control-Shift-j Accept literal\n" - "Control-Shift-m Accept literal\n" - "Shift-Return Accept literal\n" - "\n" - "Escape Reject\n" - "Control-Bracketleft Reject\n" - "\n" - "Left Backward char\n" - "Control-b Backward char\n" - "Right Forward char\n" - "Control-f Forward char\n" - "\n" - "Mod1-b Backward word\n" - "Mod1-f Forward word\n" - "\n" - "Control-a Backward line\n" - "Control-e Forward line\n" - "\n" - "Control-p History backward\n" - "Up History backward\n" - "Control-n History forward\n" - "Down History forward\n" - "\n" - "Backspace Kill char\n" - "Control-h Kill char\n" - "Control-Backspace Kill word\n" - "Control-w Kill word\n" - "Control-u Kill line\n" - "\n" - "Tab Complete next\n" - "Control-i Complete next\n" - "Mod1-l Complete next\n" - "\n" - "Shift-Tab Complete prev\n" - "Control-Shift-i Complete prev\n" - "Mod1-h Complete prev\n" - "\n" - "Prior Complete prevpage\n" - "Mod1-k Complete prevpage\n" - "Next Complete nextpage\n" - "Mod1-j Complete nextpage\n" - "Home Complete first\n" - "Mod1-g Complete first\n" - "End Complete last\n" - "Mod1-Shift-g Complete last\n" - "\n" - ; diff --git a/cmd/menu/caret.c b/cmd/menu/caret.c index c0380e3..ed203a9 100644 --- a/cmd/menu/caret.c +++ b/cmd/menu/caret.c @@ -69,9 +69,7 @@ caret_find(int dir, int type) { p = next; return p; case CHAR: - if(p < end) - return p+1; - return p; + return next_rune(p, &r); } } else if(dir == BACKWARD) { @@ -88,9 +86,7 @@ caret_find(int dir, int type) { p = next; return p; case CHAR: - if(p > end) - return p-1; - return end; + return prev_rune(end, p, &r); } } input.pos_end = nil; diff --git a/cmd/menu/dat.h b/cmd/menu/dat.h index 1d805fa..e980479 100644 --- a/cmd/menu/dat.h +++ b/cmd/menu/dat.h @@ -7,11 +7,9 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> -#include <util.h> #include <ixp.h> -#include <x11.h> - -#define BLOCK(x) do { x; }while(0) +#include <stuff/x.h> +#include <stuff/util.h> #ifndef EXTERN # define EXTERN extern @@ -31,6 +29,7 @@ enum { LBACKWARD, LCHAR, LCOMPLETE, + LDELETE, LFIRST, LFORWARD, LHISTORY, @@ -40,6 +39,7 @@ enum { LLITERAL, LNEXT, LNEXTPAGE, + LPASTE, LPREV, LPREVPAGE, LREJECT, @@ -69,48 +69,40 @@ EXTERN struct { int filter_start; } input; -extern char binding_spec[]; - -EXTERN int numlock; - -EXTERN long xtime; -EXTERN Image* ibuf; -EXTERN Font* font; -EXTERN CTuple cnorm, csel; -EXTERN bool ontop; +EXTERN struct { + Window* win; + Image* buf; + char* prompt; + int height; + int rows; + bool ontop; + Rectangle itemr; + Point arrow; +} menu; -EXTERN Cursor cursor[1]; -EXTERN Visual* render_visual; +extern char binding_spec[]; EXTERN IxpServer srv; -EXTERN Window* barwin; - -EXTERN Item* items; -EXTERN Item* matchfirst; -EXTERN Item* matchstart; -EXTERN Item* matchend; -EXTERN Item* matchidx; +EXTERN struct { + Item* all; + Item* first; + Item* start; + Item* end; + Item* sel; + int maxwidth; +} match; + +Font* font; +CTuple cnorm; +CTuple csel; EXTERN Item hist; -EXTERN Item* histidx; +EXTERN Item* histsel; -EXTERN int maxwidth; +EXTERN int itempad; EXTERN int result; -EXTERN char* (*find)(const char*, const char*); -EXTERN int (*compare)(const char*, const char*, size_t); - -EXTERN char* prompt; -EXTERN int promptw; - -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__) +EXTERN char* (*find)(const char*, const char*); +EXTERN int (*compare)(const char*, const char*, size_t); diff --git a/cmd/menu/event.c b/cmd/menu/event.c deleted file mode 100644 index fd524f9..0000000 --- a/cmd/menu/event.c +++ /dev/null @@ -1,334 +0,0 @@ -/* Copyright ©2006-2010 Kris Maglione <fbsdaemon@gmail.com> - * See LICENSE file for license details. - */ -#include "dat.h" -#include "fns.h" - -typedef void (*EvHandler)(XEvent*); -static EvHandler handler[LASTEvent]; - -void -dispatch_event(XEvent *e) { - if(e->type < nelem(handler)) { - if(handler[e->type]) - handler[e->type](e); - }else - xext_event(e); -} - -#define handle(w, fn, ev) \ - BLOCK(if((w)->handler->fn) (w)->handler->fn((w), ev)) - -static int -findtime(Display *d, XEvent *e, XPointer v) { - Window *w; - - w = (Window*)v; - if(e->type == PropertyNotify && e->xproperty.window == w->xid) { - xtime = e->xproperty.time; - return true; - } - return false; -} - -void -xtime_kludge(void) { - /* Round trip. */ - static Window *w; - WinAttr wa; - XEvent e; - long l; - - if(w == nil) { - w = createwindow(&scr.root, Rect(0, 0, 1, 1), 0, InputOnly, &wa, 0); - selectinput(w, PropertyChangeMask); - } - changeprop_long(w, "ATOM", "ATOM", &l, 0); - sync(); - XIfEvent(display, &e, findtime, (void*)w); -} - -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; -} - -static void -buttonrelease(XButtonPressedEvent *ev) { - Window *w; - - if((w = findwin(ev->window))) - handle(w, bup, ev); -} - -static void -buttonpress(XButtonPressedEvent *ev) { - Window *w; - - if((w = findwin(ev->window))) - handle(w, bdown, ev); - else - XAllowEvents(display, ReplayPointer, ev->time); -} - -static void -configurerequest(XConfigureRequestEvent *ev) { - XWindowChanges wc; - Window *w; - - if((w = findwin(ev->window))) - handle(w, configreq, ev); - else{ - wc.x = ev->x; - wc.y = ev->y; - wc.width = ev->width; - wc.height = ev->height; - wc.border_width = ev->border_width; - wc.sibling = ev->above; - wc.stack_mode = ev->detail; - XConfigureWindow(display, ev->window, ev->value_mask, &wc); - } -} - -static void -configurenotify(XConfigureEvent *ev) { - Window *w; - - USED(ev); - if((w = findwin(ev->window))) - handle(w, config, ev); -} - -static void -clientmessage(XClientMessageEvent *ev) { - - USED(ev); -} - -static void -destroynotify(XDestroyWindowEvent *ev) { - Window *w; - - if((w = findwin(ev->window))) - handle(w, destroy, ev); -} - -static void -enternotify(XCrossingEvent *ev) { - Window *w; - static int sel_screen; - - xtime = ev->time; - if(ev->mode != NotifyNormal) - return; - - if((w = findwin(ev->window))) - handle(w, enter, ev); - else if(ev->window == scr.root.xid) - sel_screen = true; -} - -static void -leavenotify(XCrossingEvent *ev) { - - xtime = ev->time; -#if 0 - if((ev->window == scr.root.xid) && !ev->same_screen) - sel_screen = true; -#endif -} - -static void -focusin(XFocusChangeEvent *ev) { - Window *w; - - /* 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)) /* && (screen->hasgrab != &c_root)) */ - return; - - if((w = findwin(ev->window))) - handle(w, focusin, ev); -#if 0 - else if(ev->mode == NotifyGrab) { - if(ev->window == scr.root.xid) - screen->hasgrab = &c_root; - /* Some unmanaged window has grabbed focus */ - else if((c = screen->focus)) { - print_focus("focusin", &c_magic, "<magic>"); - screen->focus = &c_magic; - if(c->sel) - frame_draw(c->sel); - } - } -#endif -} - -static void -focusout(XFocusChangeEvent *ev) { - Window *w; - - if(!((ev->detail == NotifyNonlinear) - ||(ev->detail == NotifyNonlinearVirtual) - ||(ev->detail == NotifyVirtual) - ||(ev->detail == NotifyInferior) - ||(ev->detail == NotifyAncestor))) - return; -#if 0 - if(ev->mode == NotifyUngrab) - screen->hasgrab = nil; -#endif - - if((w = findwin(ev->window))) - handle(w, focusout, ev); -} - -static void -expose(XExposeEvent *ev) { - Window *w; - - if(ev->count == 0) { - if((w = findwin(ev->window))) - handle(w, expose, ev); - } -} - -static void -keypress(XKeyEvent *ev) { - Window *w; - - xtime = ev->time; - if((w = findwin(ev->window))) - handle(w, kdown, ev); -} - -static void -mappingnotify(XMappingEvent *ev) { - - /* Why do you need me to tell you this? */ - XRefreshKeyboardMapping(ev); -} - -static void -maprequest(XMapRequestEvent *ev) { - - USED(ev); -} - -static void -motionnotify(XMotionEvent *ev) { - Window *w; - - xtime = ev->time; - if((w = findwin(ev->window))) - handle(w, motion, ev); -} - -static void -propertynotify(XPropertyEvent *ev) { - Window *w; - - xtime = ev->time; - if((w = findwin(ev->window))) - handle(w, property, ev); -} - -static void -mapnotify(XMapEvent *ev) { - Window *w; - - if((w = findwin(ev->window))) - handle(w, map, ev); -} - -static void -unmapnotify(XUnmapEvent *ev) { - Window *w; - - if((w = findwin(ev->window)) && (ev->event == w->parent->xid)) { - w->mapped = false; - if(ev->send_event || w->unmapped-- == 0) - handle(w, unmap, ev); - } -} - -static EvHandler handler[LASTEvent] = { - [ButtonPress] = (EvHandler)buttonpress, - [ButtonRelease] = (EvHandler)buttonrelease, - [ConfigureRequest] = (EvHandler)configurerequest, - [ConfigureNotify] = (EvHandler)configurenotify, - [ClientMessage] = (EvHandler)clientmessage, - [DestroyNotify] = (EvHandler)destroynotify, - [EnterNotify] = (EvHandler)enternotify, - [Expose] = (EvHandler)expose, - [FocusIn] = (EvHandler)focusin, - [FocusOut] = (EvHandler)focusout, - [KeyPress] = (EvHandler)keypress, - [LeaveNotify] = (EvHandler)leavenotify, - [MapNotify] = (EvHandler)mapnotify, - [MapRequest] = (EvHandler)maprequest, - [MappingNotify] = (EvHandler)mappingnotify, - [MotionNotify] = (EvHandler)motionnotify, - [PropertyNotify] = (EvHandler)propertynotify, - [UnmapNotify] = (EvHandler)unmapnotify, -}; - -void -check_x_event(IxpConn *c) { - XEvent ev; - - USED(c); - while(XCheckMaskEvent(display, ~0, &ev)) - dispatch_event(&ev); -} - diff --git a/cmd/menu/fns.h b/cmd/menu/fns.h index d95ab7f..0d221d4 100644 --- a/cmd/menu/fns.h +++ b/cmd/menu/fns.h @@ -1,10 +1,4 @@ -void check_x_event(IxpConn*); -void dispatch_event(XEvent*); -uint flushenterevents(void); -uint flushevents(long, bool); -void xtime_kludge(void); - /* caret.c */ void caret_delete(int, int); char* caret_find(int, int); @@ -19,7 +13,6 @@ char* history_search(int, char*, int); /* main.c */ void debug(int, const char*, ...); Item* filter_list(Item*, char*); -void init_screens(int); void update_filter(bool); void update_input(void); @@ -33,19 +26,3 @@ void parse_keys(char*); char** find_key(char*, long); int getsym(char*); -/* geom.c */ -Align get_sticky(Rectangle src, Rectangle dst); -Cursor quad_cursor(Align); -Align quadrant(Rectangle, Point); -bool rect_contains_p(Rectangle, Rectangle); -bool rect_haspoint_p(Point, Rectangle); -bool rect_intersect_p(Rectangle, Rectangle); -Rectangle rect_intersection(Rectangle, Rectangle); - -/* xext.c */ -void randr_event(XEvent*); -bool render_argb_p(Visual*); -void xext_event(XEvent*); -void xext_init(void); -Rectangle* xinerama_screens(int*); - diff --git a/cmd/menu/history.c b/cmd/menu/history.c index 38b0598..991fb47 100644 --- a/cmd/menu/history.c +++ b/cmd/menu/history.c @@ -8,7 +8,7 @@ static void splice(Item *i) { - if(i->next != nil) + if(i->next != nil) i->next->prev = i->prev; if(i->prev != nil) i->prev->next = i->next; @@ -19,25 +19,25 @@ history_search(int dir, char *string, int n) { Item *i; if(dir == FORWARD) { - if(histidx == &hist) + if(histsel == &hist) return hist.string; - for(i=histidx->next; i != hist.next; i=i->next) + for(i=histsel->next; i != hist.next; i=i->next) if(!i->string || !compare(i->string, string, n)) { - histidx = i; + histsel = i; return i->string; } return string; } assert(dir == BACKWARD); - if(histidx == &hist) { + if(histsel == &hist) { free(hist.string); hist.string = estrdup(input.string); } - for(i=histidx->prev; i != &hist; i=i->prev) + for(i=histsel->prev; i != &hist; i=i->prev) if(!compare(i->string, string, n)) { - histidx = i; + histsel = i; return i->string; } return string; @@ -59,7 +59,7 @@ history_dump(const char *path, int max) { fd = mkstemp(tmp); if(fd < 0) { fprint(2, "%s: Can't create temporary history file %q: %r\n", argv0, path); - return; + _exit(1); } hist.string = input.string; @@ -82,9 +82,13 @@ history_dump(const char *path, int max) { Binit(&b, fd, OWRITE); hist.next = nil; for(h=first; h; h=h->next) - Bprint(&b, "%s\n", h->string); + if(Bprint(&b, "%s\n", h->string) < 0) { + unlink(tmp); + fprint(2, "%s: Can't write temporary history file %q: %r\n", argv0, path); + _exit(1); + } Bterm(&b); rename(tmp, path); - exit(0); + _exit(0); } diff --git a/cmd/menu/keys.c b/cmd/menu/keys.c index e99f061..46fd6ec 100644 --- a/cmd/menu/keys.c +++ b/cmd/menu/keys.c @@ -13,29 +13,8 @@ struct Key { char** action; }; -static Key* bindings; - -static void -init_numlock(void) { - static int masks[] = { - ShiftMask, LockMask, ControlMask, Mod1Mask, - Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask - }; - XModifierKeymap *modmap; - KeyCode kcode; - int i, max; - - modmap = XGetModifierMapping(display); - kcode = keycode("Num_Lock"); - if(kcode) - if(modmap && modmap->max_keypermod > 0) { - max = nelem(masks) * modmap->max_keypermod; - for(i = 0; i < max; i++) - if(modmap->modifiermap[i] == kcode) - numlock = masks[i / modmap->max_keypermod]; - } - XFreeModifiermap(modmap); -} +static Key* bindings; +static int numlock; /* * To do: Find my red black tree implementation. @@ -50,7 +29,7 @@ parse_keys(char *spec) { int i, nlines, nwords; if(!numlock) - init_numlock(); + numlock = numlockmask(); nlines = tokenize(lines, nelem(lines), spec, '\n'); for(i=0; i < nlines; i++) { @@ -96,6 +75,7 @@ char *symtab[] = { "backward", "char", "complete", + "delete", "first", "forward", "history", @@ -105,6 +85,7 @@ char *symtab[] = { "literal", "next", "nextpage", + "paste", "prev", "prevpage", "reject", diff --git a/cmd/menu/keys.txt b/cmd/menu/keys.txt index d16a6c6..84d25b9 100644 --- a/cmd/menu/keys.txt +++ b/cmd/menu/keys.txt @@ -1,49 +1,52 @@ -Control-j Accept -Control-m Accept -Return Accept -Control-Shift-j Accept literal -Control-Shift-m Accept literal -Shift-Return Accept literal +Control-j Accept +Control-m Accept +Return Accept +Control-Shift-j Accept literal +Control-Shift-m Accept literal +Shift-Return Accept literal Escape Reject Control-Bracketleft Reject -Left Backward char -Control-b Backward char -Right Forward char -Control-f Forward char - -Mod1-b Backward word -Mod1-f Forward word - -Control-a Backward line -Control-e Forward line - -Control-p History backward -Up History backward -Control-n History forward -Down History forward - -Backspace Kill char -Control-h Kill char -Control-Backspace Kill word -Control-w Kill word -Control-u Kill line - -Tab Complete next -Control-i Complete next -Mod1-l Complete next - -Shift-Tab Complete prev -Control-Shift-i Complete prev -Mod1-h Complete prev - -Prior Complete prevpage -Mod1-k Complete prevpage -Next Complete nextpage -Mod1-j Complete nextpage -Home Complete first -Mod1-g Complete first -End Complete last -Mod1-Shift-g Complete last +Left Backward char +Control-b Backward char +Right Forward char +Control-f Forward char + +Mod1-b Backward word +Mod1-f Forward word + +Control-a Backward line +Control-e Forward line + +Control-p History backward +Up History backward +Control-n History forward +Down History forward + +Backspace Kill char +Control-h Kill char +Control-Backspace Kill word +Control-w Kill word +Control-u Kill line +Control-k Delete line + +Tab Complete next +Control-i Complete next +Mod1-l Complete next + +Mod1-p Paste PRIMARY + +Shift-Tab Complete prev +Control-Shift-i Complete prev +Mod1-h Complete prev + +Prior Complete prevpage +Mod1-k Complete prevpage +Next Complete nextpage +Mod1-j Complete nextpage +Home Complete first +Mod1-g Complete first +End Complete last +Mod1-Shift-g Complete last diff --git a/cmd/menu/main.c b/cmd/menu/main.c index aaab27d..605eda6 100644 --- a/cmd/menu/main.c +++ b/cmd/menu/main.c @@ -1,8 +1,6 @@ -/* Copyright ©2006-2010 Kris Maglione <fbsdaemon@gmail.com> +/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail> * See LICENSE file for license details. */ -#define IXP_NO_P9_ -#define IXP_P9_STRUCTS #define EXTERN #include "dat.h" #include <X11/Xproto.h> @@ -10,7 +8,7 @@ #include <strings.h> #include <unistd.h> #include <bio.h> -#include <clientutil.h> +#include <stuff/clientutil.h> #include "fns.h" #define link _link @@ -19,10 +17,13 @@ static Biobuf* cmplbuf; static Biobuf* inbuf; static bool alwaysprint; static char* cmdsep; +static int screen_hint; static void usage(void) { - fatal("usage: wimenu -i [-h <history>] [-a <address>] [-p <prompt>] [-s <screen>]\n"); + fprint(2, "usage: %s -i [-a <address>] [-h <history>] [-p <prompt>] [-r <rows>] [-s <screen>]\n", argv0); + fprint(2, " See manual page for full usage details.\n"); + exit(1); } static int @@ -30,27 +31,6 @@ errfmt(Fmt *f) { return fmtstrcpy(f, ixp_errbuf()); } -/* Stubs. */ -void -debug(int flag, const char *fmt, ...) { - va_list ap; - - USED(flag); - va_start(ap, fmt); - vfprint(2, fmt, ap); - va_end(ap); -} - -void dprint(long, char*, ...); -void dprint(long mask, char *fmt, ...) { - va_list ap; - - USED(mask); - va_start(ap, fmt); - vfprint(2, fmt, ap); - va_end(ap); -} - static inline void splice(Item *i) { i->next->prev = i->prev; @@ -70,13 +50,13 @@ populate_list(Biobuf *buf, bool hist) { bool stop; stop = !hist && !isatty(buf->fid); + ret.next_link = nil; i = &ret; while((p = Brdstr(buf, '\n', true))) { if(stop && p[0] == '\0') break; - link(i, emallocz(sizeof *i)); - i->next_link = i->next; - i = i->next; + i->next_link = emallocz(sizeof *i); + i = i->next_link; i->string = p; i->retstring = p; if(cmdsep && (p = strstr(p, cmdsep))) { @@ -85,15 +65,12 @@ populate_list(Biobuf *buf, bool hist) { } if(!hist) { i->len = strlen(i->string); - i->width = textwidth_l(font, i->string, i->len); - if(i->width > maxwidth) - maxwidth = i->width; + i->width = textwidth_l(font, i->string, i->len) + itempad; + match.maxwidth = max(i->width, match.maxwidth); } } - link(i, &ret); - splice(&ret); - return ret.next != &ret ? ret.next : nil; + return ret.next_link; } static void @@ -106,7 +83,7 @@ check_competions(IxpConn *c) { return; } input.filter_start = strtol(s, nil, 10); - items = populate_list(cmplbuf, false); + match.all = populate_list(cmplbuf, false); update_filter(false); menu_draw(); } @@ -163,41 +140,22 @@ update_filter(bool print) { if(input.pos < input.end) filter = freelater(estrndup(filter, input.pos - filter)); - matchidx = nil; - matchfirst = matchstart = filter_list(items, filter); + match.sel = nil; + match.first = match.start = filter_list(match.all, filter); if(print) update_input(); } -ErrorCode ignored_xerrors[] = { - { 0, } -}; - -static void -end(IxpConn *c) { - - USED(c); - srv.running = 0; -} - -static void -preselect(IxpServer *s) { - - USED(s); - check_x_event(nil); -} - enum { PointerScreen = -1 }; void -init_screens(int screen_hint) { +init_screens(void) { Rectangle *rects; Point p; int i, n; rects = xinerama_screens(&n); - if (screen_hint >= 0 && screen_hint < n) - /* We were given a valid screen index, use that. */ + if(screen_hint >= 0 && screen_hint < n) i = screen_hint; else { /* Pick the screen with the pointer, for now. Later, @@ -205,7 +163,7 @@ init_screens(int screen_hint) { */ p = querypointer(&scr.root); for(i=0; i < n; i++) - if(rect_haspoint_p(p, rects[i])) + if(rect_haspoint_p(rects[i], p)) break; if(i == n) i = 0; @@ -214,21 +172,26 @@ init_screens(int screen_hint) { menu_show(); } +ErrorCode ignored_xerrors[] = { + { 0, BadWindow }, + { X_GetAtomName, BadAtom }, +}; + int main(int argc, char *argv[]) { - Item *item; static char *address; static char *histfile; static char *keyfile; static bool nokeys; + Item *item; int i; long ndump; - int screen; - quotefmtinstall(); + setlocale(LC_ALL, ""); fmtinstall('r', errfmt); - address = getenv("WMII_ADDRESS"); - screen = PointerScreen; + quotefmtinstall(); + + screen_hint = PointerScreen; find = strstr; compare = strncmp; @@ -258,16 +221,19 @@ main(int argc, char *argv[]) { ndump = strtol(EARGF(usage()), nil, 10); break; case 'p': - prompt = EARGF(usage()); + menu.prompt = EARGF(usage()); + break; + case 'r': + menu.rows = strtol(EARGF(usage()), nil, 10); break; case 's': - screen = strtol(EARGF(usage()), nil, 10); + screen_hint = strtol(EARGF(usage()), nil, 10); break; case 'S': cmdsep = EARGF(usage()); break; case 'v': - print("%s", version); + lprint(1, "%s", version); return 0; default: usage(); @@ -276,8 +242,6 @@ main(int argc, char *argv[]) { if(argc) usage(); - setlocale(LC_CTYPE, ""); - initdisplay(); xext_init(); @@ -286,20 +250,16 @@ main(int argc, char *argv[]) { client_init(address); - srv.preselect = preselect; - ixp_listen(&srv, ConnectionNumber(display), nil, check_x_event, end); + srv.preselect = event_preselect; + ixp_listen(&srv, ConnectionNumber(display), nil, event_fdready, event_fdclosed); + + menu.ontop = !strcmp(readctl("/ctl", "bar "), "on top"); + client_readconfig(&cnorm, &csel, &font); - ontop = !strcmp(readctl("bar on "), "top"); - loadcolor(&cnorm, readctl("normcolors ")); - loadcolor(&csel, readctl("focuscolors ")); - font = loadfont(readctl("font ")); - sscanf(readctl("fontpad "), "%d %d %d %d", &font->pad.min.x, &font->pad.max.x, - &font->pad.min.x, &font->pad.max.y); - if(!font) - fatal("Can't load font %q", readctl("font ")); + itempad = (font->height & ~1) + font->pad.min.x + font->pad.max.x; cmplbuf = Bfdopen(0, OREAD); - items = populate_list(cmplbuf, false); + match.all = populate_list(cmplbuf, false); if(!isatty(cmplbuf->fid)) ixp_listen(&srv, cmplbuf->fid, inbuf, check_competions, nil); @@ -314,24 +274,21 @@ main(int argc, char *argv[]) { parse_keys(buffer); } - histidx = &hist; + histsel = &hist; link(&hist, &hist); - if(histfile) { - inbuf = Bopen(histfile, OREAD); - if(inbuf) { - item = populate_list(inbuf, true); - if(item) { - link(item->prev, &hist); - link(&hist, item); - } - Bterm(inbuf); + if(histfile && (inbuf = Bopen(histfile, OREAD))) { + item = filter_list(populate_list(inbuf, true), ""); + if(item->string) { + link(item->prev, &hist); + link(&hist, item); } + Bterm(inbuf); } - if(barwin == nil) + if(menu.win == nil) menu_init(); - init_screens(screen); + init_screens(); i = ixp_serverloop(&srv); if(i) diff --git a/cmd/menu/menu.c b/cmd/menu/menu.c index c947ec4..29ee250 100644 --- a/cmd/menu/menu.c +++ b/cmd/menu/menu.c @@ -4,283 +4,260 @@ #include <unistd.h> #include "fns.h" -static Handlers handlers; - -static int ltwidth; - -static void _menu_draw(bool); - -enum { - ACCEPT = CARET_LAST, - REJECT, - HIST, - KILL, - CMPL_NEXT, - CMPL_PREV, - CMPL_FIRST, - CMPL_LAST, - CMPL_NEXT_PAGE, - CMPL_PREV_PAGE, -}; +static Handlers handlers; +static int promptw; void menu_init(void) { WinAttr wa; - wa.override_redirect = 1; - wa.background_pixmap = ParentRelative; wa.event_mask = ExposureMask | KeyPressMask; - barwin = createwindow(&scr.root, Rect(-1, -1, 1, 1), scr.depth, InputOutput, - &wa, CWOverrideRedirect - | CWBackPixmap - | CWEventMask); - sethandler(barwin, &handlers); - mapwin(barwin); + menu.win = createwindow(&scr.root, Rect(-1, -1, 1, 1), scr.depth, InputOutput, + &wa, CWEventMask); + if(scr.xim) + menu.win->xic = XCreateIC(scr.xim, + XNInputStyle, XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, menu.win->xid, + XNFocusWindow, menu.win->xid, + nil); + + changeprop_long(menu.win, Net("WM_WINDOW_TYPE"), "ATOM", (long[]){ TYPE("MENU") }, 1); + changeprop_string(menu.win, "_WMII_TAGS", "sel"); + changeprop_textlist(menu.win, "WM_CLASS", "STRING", (char*[3]){ "wimenu", "wimenu" }); + + sethandler(menu.win, &handlers); + mapwin(menu.win); int i = 0; - while(!grabkeyboard(barwin)) { + while(!grabkeyboard(menu.win)) { if(i++ > 1000) fatal("can't grab keyboard"); usleep(1000); } } -static void -menu_unmap(long id, void *p) { +void +menu_show(void) { + Rectangle r; - USED(id, p); - unmapwin(barwin); - XFlush(display); -} + if(menu.prompt) + promptw = textwidth(font, menu.prompt) + itempad; -static void -selectitem(Item *i) { - if(i != matchidx) { - caret_set(input.filter_start, input.pos - input.string); - caret_insert(i->string, 0); - matchidx = i; - } -} + r = textextents_l(font, "<", 1, nil); + menu.arrow = Pt(Dy(r) + itempad/2, Dx(r) + itempad/2); -static void -menu_cmd(int op, int motion) { - int n; - - switch(op) { - case HIST: - n = input.pos - input.string; - caret_insert(history_search(motion, input.string, n), true); - input.pos = input.string + n; - break; - case KILL: - caret_delete(BACKWARD, motion); - break; - default: - goto next; - } - update_filter(true); -next: - switch(op) { - case ACCEPT: - srv.running = false; - if(!matchidx && matchfirst->retstring && !motion) - if(input.filter_start == 0 && input.pos == input.end) - menu_cmd(CMPL_FIRST, 0); - if(!motion && matchidx && !strcmp(input.string, matchidx->string)) - print("%s", matchidx->retstring); - else - print("%s", input.string); - break; - case REJECT: - srv.running = false; - result = 1; - break; - case BACKWARD: - case FORWARD: - caret_move(op, motion); - update_input(); - break; - case CMPL_NEXT: - selectitem(matchidx ? matchidx->next : matchfirst); - break; - case CMPL_PREV: - selectitem((matchidx ? matchidx : matchstart)->prev); - break; - case CMPL_FIRST: - matchstart = matchfirst; - matchend = nil; - selectitem(matchstart); - break; - case CMPL_LAST: - selectitem(matchfirst->prev); - break; - case CMPL_NEXT_PAGE: - if(matchend) - selectitem(matchend->next); - break; - case CMPL_PREV_PAGE: - matchend = matchstart->prev; - matchidx = nil; - _menu_draw(false); - selectitem(matchstart); - break; - } + menu.height = labelh(font); + + freeimage(menu.buf); + menu.buf = allocimage(Dx(scr.rect), + !!menu.rows * 2 * menu.arrow.y + (menu.rows + 1) * menu.height, + menu.win->depth); + + mapwin(menu.win); + raisewin(menu.win); menu_draw(); } +/* I'd prefer to use ⌃ and ⌄, but few fonts support them. */ static void -_menu_draw(bool draw) { - Rectangle r, rd, rp, r2, extent; - CTuple *c; - Item *i; - int inputw, itemoff, end, pad, n, offset; - - r = barwin->r; - r = rectsetorigin(r, ZP); - - pad = (font->height & ~1) + font->pad.min.x + font->pad.max.x; - - rd = r; - rp = ZR; // SET(rp) - if (prompt) { - if (!promptw) - promptw = textwidth(font, prompt) + 2 * ltwidth + pad; - rd.min.x += promptw; - - rp = r; - rp.max.x = promptw; - } +drawarrow(Image *img, Rectangle r, int up, Color *col) { + Point p[3], pt; - inputw = min(Dx(rd) / 3, maxwidth); - inputw = max(inputw, textwidth(font, input.string)) + pad; - itemoff = inputw + 2 * ltwidth; - end = Dx(rd) - ltwidth; - - fill(ibuf, r, cnorm.bg); - - if(matchend && matchidx == matchend->next) - matchstart = matchidx; - else if(matchidx == matchstart->prev) - matchend = matchidx; - if (matchend == nil) - matchend = matchstart; - - if(matchend == matchstart->prev && matchstart != matchidx) { - n = itemoff; - matchstart = matchend; - for(i=matchend; ; i=i->prev) { - n += i->width + pad; - if(n > end) - break; - matchstart = i; - if(i == matchfirst) - break; - } - } - - if(!draw) - return; + pt = Pt(menu.arrow.x - itempad/2, menu.arrow.y - itempad/2 & ~1); - r2 = rd; - for(i=matchstart; i->string; i=i->next) { - r2.min.x = promptw + itemoff; - itemoff = itemoff + i->width + pad; - r2.max.x = promptw + min(itemoff, end); - if(i != matchstart && itemoff > end) - break; - - c = (i == matchidx) ? &csel : &cnorm; - fill(ibuf, r2, c->bg); - drawstring(ibuf, font, r2, Center, i->string, c->fg); - matchend = i; - if(i->next == matchfirst) - break; - } - - r2 = rd; - r2.min.x = promptw + inputw; - if(matchstart != matchfirst) - drawstring(ibuf, font, r2, West, "<", cnorm.fg); - if(matchend->next != matchfirst) - drawstring(ibuf, font, r2, East, ">", cnorm.fg); + p[1] = Pt(r.min.x + Dx(r)/2, up ? r.min.y + itempad/4 : r.max.y - itempad/4); + p[0] = Pt(p[1].x - pt.x/2, up ? p[1].y + pt.y : p[1].y - pt.y); + p[2] = Pt(p[1].x + pt.x/2, p[0].y); + drawpoly(img, p, nelem(p), CapProjecting, 1, col); +} - r2 = rd; - r2.max.x = promptw + inputw; - drawstring(ibuf, font, r2, West, input.string, cnorm.fg); +static Rectangle +slice(Rectangle *rp, int x, int y) { + Rectangle r; - extent = textextents_l(font, input.string, input.pos - input.string, &offset); - r2.min.x = promptw + offset + font->pad.min.x - extent.min.x + pad/2 - 1; - r2.max.x = r2.min.x + 2; - r2.min.y++; - r2.max.y--; - border(ibuf, r2, 1, cnorm.border); + r = *rp; + if(x) rp->min.x += x, r.max.x = min(rp->min.x, rp->max.x); + if(y) rp->min.y += y, r.max.y = min(rp->min.y, rp->max.y); + return r; +} - if (prompt) - drawstring(ibuf, font, rp, West, prompt, cnorm.fg); +static bool +nextrect(Item *i, Rectangle *rp, Rectangle *src) { + Rectangle r; - border(ibuf, rd, 1, cnorm.border); - copyimage(barwin, r, ibuf, ZP); + if(menu.rows) + r = slice(src, 0, menu.height); + else + r = slice(src, i->width, 0); + return (Dx(*src) >= 0 && Dy(*src) >= 0) && (*rp = r, 1); } void menu_draw(void) { - _menu_draw(true); -} + Rectangle barr, extent, itemr, inputr, r, r2; + Item *item; + int inputw, offset; + + barr = r2 = Rect(0, 0, Dx(menu.win->r), menu.height); + + inputw = max(match.maxwidth + textwidth_l(font, input.string, min(input.filter_start, strlen(input.string))), + max(itempad + textwidth(font, input.string), + Dx(barr) / 3)); + + /* Calculate items box, w/ and w/o arrows */ + if(menu.rows) { + menu.itemr = barr; + menu.itemr.max.y += Dy(barr) * (menu.rows - 1); + if(menu.ontop) + menu.itemr = rectaddpt(menu.itemr, Pt(0, Dy(barr))); + itemr = menu.itemr; + if(match.start != match.first) + menu.itemr = rectaddpt(menu.itemr, Pt(0, menu.arrow.y)); + } + else { + itemr = r2; + slice(&itemr, inputw + promptw, 0); + menu.itemr = Rect(itemr.min.x + menu.arrow.x, itemr.min.y, + itemr.max.x - menu.arrow.x, itemr.max.y); + } -void -menu_show(void) { - Rectangle r; - int height, pad; + fill(menu.buf, menu.buf->r, &cnorm.bg); + + /* Draw items */ + item = match.start, r2 = menu.itemr; + nextrect(item, &r, &r2); + do { + match.end = item; + if(item->string) + fillstring(menu.buf, font, r, West, item->string, + (item == match.sel ? &csel : &cnorm), 0); + item = item->next; + } while(item != match.first && nextrect(item, &r, &r2)); + + /* Adjust dimensions for arrows/number of items */ + if(menu.rows) + itemr.max.y = r.max.y + (match.end->next != match.first ? menu.arrow.y : 0); + else + itemr.max.x = r.max.x + menu.arrow.x; + if(menu.rows && !menu.ontop) + barr = rectaddpt(barr, Pt(0, itemr.max.y)); + + /* Draw indicators */ + if(!menu.rows && match.start != match.first) + drawstring(menu.buf, font, itemr, West, "<", &cnorm.fg); + if(!menu.rows && match.end->next != match.first) + drawstring(menu.buf, font, itemr, East, ">", &cnorm.fg); + + if(menu.rows && match.start != match.first) + drawarrow(menu.buf, itemr, 1, &cnorm.fg); + if(menu.rows && match.end->next != match.first) + drawarrow(menu.buf, itemr, 0, &cnorm.fg); + + /* Draw prompt */ + r2 = barr; + if(menu.prompt) + drawstring(menu.buf, font, slice(&r2, promptw, 0), + West, menu.prompt, &cnorm.fg); + + /* Border input/horizontal items */ + border(menu.buf, r2, 1, &cnorm.border); + + /* Draw input */ + inputr = slice(&r2, inputw, 0); + drawstring(menu.buf, font, inputr, West, input.string, &cnorm.fg); + + /* Draw cursor */ + extent = textextents_l(font, input.string, input.pos - input.string, &offset); + r2 = insetrect(inputr, 2); + r2.min.x = inputr.min.x - extent.min.x + offset + font->pad.min.x + itempad/2 - 1; + r2.max.x = r2.min.x + 1; + fill(menu.buf, r2, &cnorm.border); - USED(menu_unmap); + /* Reshape window */ + r = scr.rect; + if(menu.ontop) + r.max.y = r.min.y + itemr.max.y; + else + r.min.y = r.max.y - barr.max.y; + reshapewin(menu.win, r); - ltwidth = textwidth(font, "<"); + /* Border window */ + r = rectsubpt(r, r.min); + border(menu.buf, r, 1, &cnorm.border); + copyimage(menu.win, r, menu.buf, ZP); +} - pad = (font->height & ~1)/2; - height = labelh(font); +static Item* +pagestart(Item *i) { + Rectangle r, r2; - r = scr.rect; - if(ontop) - r.max.y = r.min.y + height; - else - r.min.y = r.max.y - height; - reshapewin(barwin, r); + r = menu.itemr; + nextrect(i, &r2, &r); + while(i->prev != match.first->prev && nextrect(i->prev, &r2, &r)) + i = i->prev; + return i; +} - freeimage(ibuf); - ibuf = allocimage(Dx(r), Dy(r), scr.depth); +static void +selectitem(Item *i) { + if(i != match.sel) { + caret_set(input.filter_start, input.pos - input.string); + caret_insert(i->string, 0); + match.sel = i; + if(i == match.start->prev) + match.start = pagestart(i); + if(i == match.end->next) + match.start = i; + } +} - mapwin(barwin); - raisewin(barwin); +static void +paste(void *aux, char *str) { + if(str) + caret_insert(str, false); menu_draw(); } -static void -kdown_event(Window *w, XKeyEvent *e) { +static bool +kdown_event(Window *w, void *aux, XKeyEvent *e) { char **action, **p; char *key; - char buf[32]; - int num; + char buf[128]; + int num, status; KeySym ksym; - buf[0] = 0; - num = XLookupString(e, buf, sizeof buf, &ksym, 0); - key = XKeysymToString(ksym); - if(IsKeypadKey(ksym)) - if(ksym == XK_KP_Enter) - ksym = XK_Return; - else if(ksym >= XK_KP_0 && ksym <= XK_KP_9) - ksym = (ksym - XK_KP_0) + XK_0; - - if(IsFunctionKey(ksym) - || IsMiscFunctionKey(ksym) - || IsKeypadKey(ksym) - || IsPrivateKeypadKey(ksym) - || IsPFKey(ksym)) - return; - - action = find_key(key, e->state); - if(action == nil || action[0] == nil) { + if(XFilterEvent((XEvent*)e, w->xid)) + return false; + + status = XLookupBoth; + if(w->xic) + num = Xutf8LookupString(w->xic, e, buf, sizeof buf - 1, &ksym, &status); + else + num = XLookupString(e, buf, sizeof buf - 1, &ksym, nil); + + if(status != XLookupChars && status != XLookupKeySym && status != XLookupBoth) + return false; + + if(status == XLookupKeySym || status == XLookupBoth) { + key = XKeysymToString(ksym); + if(IsKeypadKey(ksym)) + if(ksym == XK_KP_Enter) + ksym = XK_Return; + else if(ksym >= XK_KP_0 && ksym <= XK_KP_9) + ksym = (ksym - XK_KP_0) + XK_0; + + if(IsFunctionKey(ksym) + || IsMiscFunctionKey(ksym) + || IsKeypadKey(ksym) + || IsPrivateKeypadKey(ksym) + || IsPFKey(ksym)) + return false; + action = find_key(key, e->state); + } + + if(status == XLookupChars || action == nil || action[0] == nil) { if(num && !iscntrl(buf[0])) { + buf[num] = '\0'; caret_insert(buf, false); update_filter(true); menu_draw(); @@ -296,45 +273,82 @@ kdown_event(Window *w, XKeyEvent *e) { have(LWORD) ? WORD : have(LLINE) ? LINE : -1); + switch(getsym(action[0])) { + default: + return false; + case LHISTORY: + num = input.pos - input.string; + amount = have(LBACKWARD) ? BACKWARD : FORWARD; + caret_insert(history_search(amount, input.string, num), true); + input.pos = input.string + num; + update_filter(true); + break; + case LKILL: + caret_delete(BACKWARD, amount); + update_filter(true); + break; + case LDELETE: + caret_delete(FORWARD, amount); + update_filter(true); + break; + case LACCEPT: - menu_cmd(ACCEPT, have(LLITERAL)); + srv.running = false; + if(!have(LLITERAL) && !match.sel && match.start->retstring) + if(input.filter_start == 0 && input.pos == input.end) + selectitem(match.start); + + if(!have(LLITERAL) && match.sel && !strcmp(input.string, match.sel->string)) + lprint(1, "%s", match.sel->retstring); + else + lprint(1, "%s", input.string); break; case LBACKWARD: - menu_cmd(BACKWARD, amount); + caret_move(BACKWARD, amount); + update_input(); break; case LCOMPLETE: - amount = ( - have(LNEXT) ? CMPL_NEXT : - have(LPREV) ? CMPL_PREV : - have(LNEXTPAGE) ? CMPL_NEXT_PAGE : - have(LPREVPAGE) ? CMPL_PREV_PAGE : - have(LFIRST) ? CMPL_FIRST : - have(LLAST) ? CMPL_LAST : - CMPL_NEXT); - menu_cmd(amount, 0); + if(have(LNEXT)) + selectitem(match.sel ? match.sel->next : match.first); + else if(have(LPREV)) + selectitem((match.sel ? match.sel : match.start)->prev); + else if(have(LFIRST)) { + match.start = match.first; + selectitem(match.start); + } + else if(have(LLAST)) + selectitem(match.first->prev); + else if(have(LNEXTPAGE)) + selectitem(match.end->next); + else if(have(LPREVPAGE)) { + match.start = pagestart(match.start->prev); + selectitem(match.start); + } break; case LFORWARD: - menu_cmd(FORWARD, amount); + caret_move(FORWARD, amount); + update_input(); break; - case LHISTORY: - menu_cmd(HIST, have(LBACKWARD) ? BACKWARD : FORWARD); - break; - case LKILL: - menu_cmd(KILL, amount); + case LPASTE: + getselection(action[1] ? action[1] : "PRIMARY", paste, nil); break; case LREJECT: - menu_cmd(REJECT, 0); + srv.running = false; + result = 1; break; } + menu_draw(); } + return false; } -static void -expose_event(Window *w, XExposeEvent *e) { +static bool +expose_event(Window *w, void *aux, XExposeEvent *e) { USED(w); menu_draw(); + return false; } static Handlers handlers = { diff --git a/cmd/strut/Makefile b/cmd/strut/Makefile index fca4bd2..9be2a69 100644 --- a/cmd/strut/Makefile +++ b/cmd/strut/Makefile @@ -1,27 +1,19 @@ ROOT= ../.. -include ${ROOT}/mk/hdr.mk -include ${ROOT}/mk/wmii.mk +include $(ROOT)/mk/hdr.mk +include $(ROOT)/mk/wmii.mk -main.c: ${ROOT}/mk/wmii.mk +main.c: $(ROOT)/mk/wmii.mk TARG = wistrut HFILES= dat.h fns.h -PACKAGES += $(X11PACKAGES) xext xrandr xinerama +PACKAGES += $(X11PACKAGES) -LIB = $(LIBIXP) -LIBS += -lm $(LIBS9) -CFLAGS += -DIXP_NEEDAPI=86 +LIB = $(LIBS9) +LIBS += -lm OBJ = main \ - event \ ewmh \ - win \ - _util \ - ../wmii/map \ - ../wmii/printevent \ - printevent_kludge \ - ../wmii/x11 \ - ../util + win -include ${ROOT}/mk/one.mk +include $(ROOT)/mk/one.mk diff --git a/cmd/strut/_util.c b/cmd/strut/_util.c deleted file mode 100644 index 364ff81..0000000 --- a/cmd/strut/_util.c +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright ©2008-2010 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 index 810d384..50b539d 100644 --- a/cmd/strut/dat.h +++ b/cmd/strut/dat.h @@ -3,31 +3,15 @@ #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) +#include <stuff/x.h> +#include <stuff/util.h> #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; +enum { DAuto, DHorizontal, DVertical }; -#define bufclear() \ - BLOCK( _buffer = buffer; _buffer[0] = '\0' ) -#define bufprint(...) \ - _buffer = seprint(_buffer, _buf_end, __VA_ARGS__) +EXTERN Handlers handlers; +EXTERN int direction; diff --git a/cmd/strut/event.c b/cmd/strut/event.c deleted file mode 100644 index aebd8ba..0000000 --- a/cmd/strut/event.c +++ /dev/null @@ -1,309 +0,0 @@ -/* Copyright ©2006-2010 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) { - /* print("%E\n", 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->xid) { - 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->xid, 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->xid)) { - 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 index b56923c..b965546 100644 --- a/cmd/strut/ewmh.c +++ b/cmd/strut/ewmh.c @@ -1,4 +1,4 @@ -/* Copyright ©2007-2010 Kris Maglione <fbsdaemon@gmail.com> +/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail> * See LICENSE file for license details. */ #include "dat.h" @@ -6,15 +6,6 @@ #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, diff --git a/cmd/strut/fns.h b/cmd/strut/fns.h index af6383e..8b70f3f 100644 --- a/cmd/strut/fns.h +++ b/cmd/strut/fns.h @@ -1,18 +1,6 @@ -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 restrut(Window*); 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 index ef9d27f..652b375 100644 --- a/cmd/strut/main.c +++ b/cmd/strut/main.c @@ -1,4 +1,4 @@ -/* Copyright ©2006-2010 Kris Maglione <fbsdaemon@gmail.com> +/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail> * See LICENSE file for license details. */ #define EXTERN @@ -6,32 +6,49 @@ #include <X11/Xproto.h> #include <locale.h> #include <string.h> +#include <time.h> #include "fns.h" -static const char version[] = "witray-"VERSION", ©2007 Kris Maglione\n"; +static Window* testwin; +static ulong testtime[2]; + +static const char version[] = "wistrut-"VERSION", "COPYRIGHT"\n"; + +static void manage(ulong); static void usage(void) { - fatal("usage: %s <window>\n", argv0); -} - -static int -errfmt(Fmt *f) { - return fmtstrcpy(f, ixp_errbuf()); + fatal("usage: %s [-HV] <window|class>...\n", argv0); } -void -debug(int flag, const char *fmt, ...) { - va_list ap; - - USED(flag); - va_start(ap, fmt); - vfprint(2, fmt, ap); - va_end(ap); +static void +search_wins(char *pattern) { + ulong *wins; + ulong n, num; + int i; + char **class; + Reprog *regexp; + Window *win; + + regexp = regcomp(pattern); + + num = getprop_ulong(&scr.root, "_NET_CLIENT_LIST", "WINDOW", 0L, &wins, 1024L); + for(i = 0; i < num; i++) { + win = window(wins[i]); + + n = getprop_textlist(win, "WM_CLASS", &class); + bufclear(); + bufprint("%s:%s:%s", + (n > 0 ? class[0] : "<nil>"), + (n > 1 ? class[1] : "<nil>"), + freelater(windowname(win))); + freestringlist(class); + if(regexec(regexp, buffer, nil, 0)) + manage(wins[i]); + } + free(wins); } -ErrorCode ignored_xerrors[] = { {0,} }; - static Window findframe(Window *w) { XWindow *children; @@ -39,11 +56,13 @@ findframe(Window *w) { Window ret = {0, }; uint n; + xw = w->xid; for(par=w->xid; par != scr.root.xid; ) { xw = par; XQueryTree(display, xw, &root, &par, &children, &n); XFree(children); } + ret.type = WWindow; ret.xid = xw; ret.parent = &scr.root; return ret; @@ -63,38 +82,90 @@ getwinsize(Window *win) { Pt(x+border, y+border)); } +static bool +managable(ulong xid) { + ulong *ret; + ulong n; + bool retval; + + n = getprop_ulong(window(xid), "_WMII_STRUT", "WINDOW", 0L, &ret, 1L); + if(n < 0) + retval = true; + else { + if(ret[0] == xid) + retval = ret[0] != testtime[0] || ret[1] != testtime[1]; + else + retval = managable(ret[0]); + } + free(ret); + return retval; +} + +static void +manage(ulong xid) { + Window *frame; + Window *win; + + if(!managable(xid)) + return; + + win = emallocz(sizeof *win); + frame = emalloc(sizeof *frame); + + win->type = WWindow; + win->xid = xid; + *frame = findframe(win); + frame->aux = win; + + getwinsize(frame); + restrut(frame); + sethandler(frame, &handlers); + selectinput(frame, StructureNotifyMask); + + changeprop_ulong(frame, "_WMII_STRUT", "WINDOW", testtime, nelem(testtime)); +} + int main(int argc, char *argv[]) { + ulong win; char *s; - fmtinstall('r', errfmt); -extern int fmtevent(Fmt*); + setlocale(LC_CTYPE, ""); fmtinstall('E', fmtevent); ARGBEGIN{ + case 'H': + direction = DHorizontal; + break; + case 'V': + direction = DVertical; + break; + case 'v': + lprint(1, "%s", version); + return 0; default: usage(); }ARGEND; - s = EARGF(usage()); - if(!getulong(s, &win.xid)) - usage(); - - if(argc) - usage(); - - setlocale(LC_CTYPE, ""); - initdisplay(); - frame = findframe(&win); - getwinsize(&frame); - restrut(); - sethandler(&frame, &handlers); - selectinput(&frame, StructureNotifyMask); + testwin = createwindow(&scr.root, Rect(0, 0, 1, 1), 0, + InputOnly, nil, 0); + testtime[0] = testwin->xid; + testtime[1] = time(nil); + + while(argc) { + s = ARGF(); + if(getulong(s, &win)) + manage(win); + else + search_wins(s); + } + + changeprop_ulong(testwin, "_WMII_STRUT", "WINDOW", testtime, nelem(testtime)); - running = true; - xevent_loop(); + if(windowmap.nmemb > 0) + event_loop(); XCloseDisplay(display); return 0; diff --git a/cmd/strut/printevent_kludge.c b/cmd/strut/printevent_kludge.c deleted file mode 100644 index c5e53cb..0000000 --- a/cmd/strut/printevent_kludge.c +++ /dev/null @@ -1,12 +0,0 @@ -#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 index ba607cf..b4810d2 100644 --- a/cmd/strut/win.c +++ b/cmd/strut/win.c @@ -1,4 +1,4 @@ -/* Copyright ©2008-2010 Kris Maglione <fbsdaemon@gmail.com> +/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail> * See LICENSE file for license details. */ #include "dat.h" @@ -6,14 +6,14 @@ #include "fns.h" void -restrut(void) { +restrut(Window *frame) { enum { Left, Right, Top, Bottom }; Rectangle strut[4]; Rectangle r; - r = frame.r; + r = frame->r; memset(strut, 0, sizeof strut); - if(Dx(r) < Dx(scr.rect)/2) { + if(Dx(r) < Dx(scr.rect)/2 && direction != DVertical) { if(r.min.x <= scr.rect.min.x) { strut[Left] = r; strut[Left].min.x = 0; @@ -25,7 +25,7 @@ restrut(void) { strut[Right].max.x = 0; } } - if(Dy(r) < Dy(scr.rect)/2) { + if(Dy(r) < Dy(scr.rect)/2 && direction != DHorizontal) { if(r.min.y <= scr.rect.min.y) { strut[Top] = r; strut[Top].min.y = 0; @@ -38,9 +38,6 @@ restrut(void) { } } -#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. */ @@ -70,33 +67,38 @@ restrut(void) { } #if 0 +#define pstrut(name) \ + if(!eqrect(strut[name], ZR)) \ + fprint(2, "strut["#name"] = %R\n", strut[name]) pstrut(Left); pstrut(Right); pstrut(Top); pstrut(Bottom); #endif - ewmh_setstrut(&win, strut); + ewmh_setstrut(frame->aux, strut); } -static void -config(Window *w, XConfigureEvent *ev) { +static bool +config_event(Window *frame, void *aux, XConfigureEvent *ev) { - USED(w); - - frame.r = rectaddpt(Rect(0, 0, ev->width, ev->height), - Pt(ev->x+ev->border_width, ev->y+ev->border_width)); - restrut(); + frame->r = rectaddpt(Rect(ev->x, ev->y, ev->width, ev->height), + Pt(ev->border_width, ev->border_width)); + restrut(frame); + return false; } -static void -destroy(Window *w, XDestroyWindowEvent *ev) { - USED(w, ev); - running = false; +static bool +destroy_event(Window *w, void *aux, XDestroyWindowEvent *ev) { + + USED(ev); + sethandler(w, nil); + event_looprunning = windowmap.nmemb > 0; + return false; } Handlers handlers = { - .config = config, - .destroy = destroy, + .config = config_event, + .destroy = destroy_event, }; diff --git a/cmd/tray/Makefile b/cmd/tray/Makefile new file mode 100644 index 0000000..2789c5d --- /dev/null +++ b/cmd/tray/Makefile @@ -0,0 +1,23 @@ +ROOT= ../.. +include $(ROOT)/mk/hdr.mk +include $(ROOT)/mk/wmii.mk + +main.c: $(ROOT)/mk/wmii.mk + +TARG = witray +HFILES= dat.h fns.h selection.h + +PACKAGES += $(X11PACKAGES) + +LIB = $(LIBS9) $(LIBIXP) +LIBS += -lm +OBJ = \ + client \ + ewmh \ + main \ + selection \ + tray \ + xembed + +include $(ROOT)/mk/one.mk + diff --git a/cmd/tray/client.c b/cmd/tray/client.c new file mode 100644 index 0000000..e90e625 --- /dev/null +++ b/cmd/tray/client.c @@ -0,0 +1,206 @@ +/* Copyright ©2010 Kris Maglione <maglione.k at Gmail> + * See LICENSE file for license details. + */ +#include "dat.h" +#include "fns.h" +#include <string.h> + +static Handlers handlers; + +static void client_cleanup(XEmbed*); + +void +client_manage(XWindow w) { + Client **cp; + Client *c; + WinAttr wa; + int size; + + c = emallocz(sizeof *c); + c->w.type = WWindow; + c->w.xid = w; + c->w.aux = c; + + Dprint("client_manage(%W)\n", &c->w); + + traperrors(true); + XAddToSaveSet(display, w); + c->xembed = xembed_swallow(tray.win, &c->w, client_cleanup); + if(traperrors(false)) { + fprint(2, "client_manage(0x%ulx): Caught error.\n", w); + xembed_disown(c->xembed); + return; + } + + wa.background_pixel = pixelvalue(&scr.root, &tray.selcolors.bg); + size = max(tray.iconsize / 4, 4); + + c->indicator = createwindow(tray.win, Rect(0, 0, size, size), scr.depth, + InputOutput, &wa, CWBackPixel); + setborder(c->indicator, 1, &tray.selcolors.border); + + sethandler(&c->w, &handlers); + + for(cp=&tray.clients; *cp; cp=&(*cp)->next) + ; + *cp = c; + + tray_update(); +} + +void +client_disown(Client *c) { + + Dprint("client_disown(%W)\n", &c->w); + xembed_disown(c->xembed); +} + +static void +client_cleanup(XEmbed *e) { + Client **cp; + Client *c; + + c = e->w->aux; + if (c->indicator) + destroywindow(c->indicator); + + for(cp=&tray.clients; *cp; cp=&(*cp)->next) + if(*cp == c) { + *cp = c->next; + break; + } + cleanupwindow(&c->w); + free(c); + tray_update(); +} + +Client* +client_find(Window *w) { + Client *c; + + for(c=tray.clients; c; c=c->next) + if(&c->w == w) + return c; + return nil; +} + +void +message_cancel(Client *c, long id) { + Message *m, **mp; + + for(mp=&c->message; (m = *mp) && m->id != id; mp=&m->next) + ; + + if(m) { + *mp = m->next; + free(m->msg.data); + free(m); + } +} + +bool +client_hasmessage(Client *c) { + Message *m; + + for(m=c->message; m; m=m->next) + if(m->msg.pos == m->msg.end) + return true; + return false; +} + +void +client_opcode(Client *c, long message, long l1, long l2, long l3) { + Message *m, **mp; + + Dprint("client_opcode(%p, %s, %ulx, %ulx, %ulx)\n", + c, + message == TrayRequestDock ? "TrayRequestDock" : + message == TrayBeginMessage ? "TrayBeginMessage" : + message == TrayCancelMessage ? "TrayCancelMessage" : + sxprint("%lx", message), + l1, l2, l3); + + if(message == TrayBeginMessage) + message_cancel(c, l1); + else if(message == TrayBeginMessage) { + if(l2 > 5 * 1024) /* Don't bother with absurdly large messages. */ + return; + + m = emallocz(sizeof *m); + m->timeout = l1; + m->msg = ixp_message(emallocz(l2), l2, MsgPack); + m->id = l3; + + /* Add the message to the end of the queue. */ + for(mp=&c->message; *mp; mp=&(*mp)->next) + ; + *mp = m; + } +} + +void +client_message(Client *c, long type, int format, ClientMessageData* data) { + Message *m; + + if(format == 8 && type == NET("SYSTEM_TRAY_MESSAGE_DATA")) { + /* Append the data to the last incomplete message. */ + for(m = c->message; m && m->msg.pos >= m->msg.end; m++) + ; + if(m) { + memcpy(m->msg.pos, data, min(20, m->msg.end - m->msg.pos)); + m->msg.pos += min(20, m->msg.end - m->msg.pos); + } + } +} + +static bool +config_event(Window *w, void *aux, XConfigureEvent *e) { + Client *c; + + c = aux; + if(false) + movewin(c->indicator, addpt(w->r.min, Pt(1, 1))); + return false; +} + +static bool +configreq_event(Window *w, void *aux, XConfigureRequestEvent *e) { + + Dprint("configreq_event(%W)\n", w); + /* This seems, sadly, to be necessary. */ + tray_update(); + return false; +} + +static bool +map_event(Window *w, void *aux, XMapEvent *e) { + + Dprint("client map_event(%W)\n", w); + w->mapped = true; + tray_update(); + return false; +} + +static bool +unmap_event(Window *w, void *aux, XUnmapEvent *e) { + + Dprint("client map_event(%W)\n", w); + tray_update(); + return false; +} + +static bool +reparent_event(Window *w, void *aux, XReparentEvent *e) { + + Dprint("client reparent_event(%W)\n", w); + return false; +} + +static Handlers handlers = { + .config = config_event, + .configreq = configreq_event, + .map = map_event, + .unmap = unmap_event, + .reparent = reparent_event, +}; + diff --git a/cmd/tray/dat.h b/cmd/tray/dat.h new file mode 100644 index 0000000..feebe24 --- /dev/null +++ b/cmd/tray/dat.h @@ -0,0 +1,73 @@ +#include <fmt.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdlib.h> +#include <unistd.h> +#include <ixp.h> +#include <stuff/x.h> +#include <stuff/util.h> +#include "selection.h" + +#ifndef EXTERN +# define EXTERN extern +#endif + +enum { OAuto, OHorizontal, OVertical }; + +enum XEmbedFlags { + XEmbedMapped = (1 << 0), +}; + +enum TrayOpcodes { + TrayRequestDock, + TrayBeginMessage, + TrayCancelMessage, +}; + +typedef struct Client Client; +typedef struct Message Message; +typedef struct XEmbed XEmbed; + +struct Client { + Client* next; + XEmbed* xembed; + Window w; + Window* indicator; + Message* message; +}; + +struct Message { + Message* next; + long id; + ulong timeout; + IxpMsg msg; +}; + +struct XEmbed { + Window* w; + Window* owner; + void (*cleanup)(XEmbed*); + int version; + ulong flags; +}; + +EXTERN IxpServer srv; +EXTERN char** program_args; +EXTERN int debug; + +EXTERN struct { + Window* win; + Image* pixmap; + Client* clients; + Selection* selection; + char* tags; + Rectangle r; + ulong iconsize; + ulong padding; + long edge; + int orientation; + Font* font; + CTuple selcolors; + CTuple normcolors; +} tray; + diff --git a/cmd/tray/ewmh.c b/cmd/tray/ewmh.c new file mode 100644 index 0000000..1bded02 --- /dev/null +++ b/cmd/tray/ewmh.c @@ -0,0 +1,45 @@ +/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail> + * See LICENSE file for license details. + */ +#include "dat.h" +#include <limits.h> +#include <string.h> +#include "fns.h" + +enum { + Left, Right, Top, Bottom, + LeftMin, LeftMax, + RightMin, RightMax, + TopMin, TopMax, + BottomMin, BottomMax, + Last +}; + +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/tray/fns.h b/cmd/tray/fns.h new file mode 100644 index 0000000..7f3614d --- /dev/null +++ b/cmd/tray/fns.h @@ -0,0 +1,22 @@ + +void cleanup(Selection*); +Client* client_find(Window*); +bool client_hasmessage(Client*); +void client_disown(Client*); +void client_manage(XWindow); +void client_message(Client*, long, int, ClientMessageData*); +void client_opcode(Client*, long, long, long, long); +void ewmh_setstrut(Window*, Rectangle[4]); +int main(int, char*[]); +void message(Selection*, XClientMessageEvent*); +void message_cancel(Client*, long); +void restrut(Window*, int); +void tray_init(void); +void tray_resize(Rectangle); +void tray_update(void); +void xembed_disown(XEmbed*); +XEmbed* xembed_swallow(Window*, Window*, void (*)(XEmbed*)); + +#define Debug if(debug) +#define Dprint Debug print + diff --git a/cmd/tray/main.c b/cmd/tray/main.c new file mode 100644 index 0000000..5e4e22f --- /dev/null +++ b/cmd/tray/main.c @@ -0,0 +1,218 @@ +/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail> + * See LICENSE file for license details. + */ +#define EXTERN +#include "dat.h" +#include <X11/Xproto.h> +#include <locale.h> +#include <stdio.h> +#include <string.h> +#include <stuff/clientutil.h> +#include <sys/signal.h> +#include "fns.h" + +static const char version[] = "witray-"VERSION", "COPYRIGHT"\n"; + +static int exitsignal; +static struct sigaction sa; + +static void +usage(void) { + fprint(2, "usage: %s [-a <address>] [-NESW] [-HVn] [-p <padding>] [-s <iconsize>] [-t tags]\n" + " %s -v\n", argv0, argv0); + exit(1); +} + +static int +errfmt(Fmt *f) { + return fmtstrcpy(f, ixp_errbuf()); +} + +static void +cleanup_handler(int signal) { + sa.sa_handler = SIG_DFL; + sigaction(signal, &sa, nil); + + selection_release(tray.selection); + srv.running = false; + + switch(signal) { + case SIGINT: + case SIGTERM: + sa.sa_handler = cleanup_handler; + sigaction(SIGALRM, &sa, nil); + alarm(1); + default: + exitsignal = signal; + break; + case SIGALRM: + raise(SIGTERM); + } +} + +static void +init_traps(void) { + + sa.sa_flags = 0; + sa.sa_handler = cleanup_handler; + sigaction(SIGINT, &sa, nil); + sigaction(SIGTERM, &sa, nil); + sigaction(SIGQUIT, &sa, nil); + sigaction(SIGHUP, &sa, nil); + sigaction(SIGUSR1, &sa, nil); + sigaction(SIGUSR2, &sa, nil); +} + +void +cleanup(Selection *s) { + USED(s); + + while(tray.clients) + client_disown(tray.clients); + tray.selection = nil; + srv.running = false; +} + +void +message(Selection *s, XClientMessageEvent *ev) { + Window *w; + Client *c; + + USED(s); + + Dprint("message(%A) 0x%lx\n", ev->message_type, ev->window); + Dprint("\t0x%lx, 0x%lx, 0x%ulx, 0x%ulx, 0x%ulx\n", + ev->data.l[0], ev->data.l[1], ev->data.l[2], ev->data.l[3], ev->data.l[4]); + + w = findwin(ev->window); + if(w == nil) + return; + + if(w == tray.selection->owner) { + if(ev->message_type == NET("SYSTEM_TRAY_OPCODE") && ev->format == 32) + if(ev->data.l[1] == TrayRequestDock) + client_manage(ev->data.l[2]); + return; + } + + if((c = client_find(w))) { + if(ev->message_type == NET("SYSTEM_TRAY_OPCODE") && ev->format == 32) + client_opcode(w->aux, ev->data.l[1], ev->data.l[2], ev->data.l[3], ev->data.l[4]); + else + client_message(w->aux, ev->message_type, ev->format, (ClientMessageData*)&ev->data); + return; + } +} + +ErrorCode ignored_xerrors[] = { + { 0, BadWindow }, + { X_GetAtomName, BadAtom }, +}; + +int +main(int argc, char *argv[]) { + static char* address; + bool steal; + + program_args = argv; + + setlocale(LC_CTYPE, ""); + fmtinstall('r', errfmt); + fmtinstall('E', fmtevent); + + steal = true; + tray.orientation = OHorizontal; + tray.tags = "/./"; + tray.padding = 1; + + ARGBEGIN{ + case 'N': + tray.edge = (tray.edge & ~South) | North; + break; + case 'S': + tray.edge = (tray.edge & ~North) | South; + break; + case 'E': + tray.edge = (tray.edge & ~West) | East; + break; + case 'W': + tray.edge = (tray.edge & ~East) | West; + break; + case 'H': + tray.orientation = OHorizontal; + break; + case 'V': + tray.orientation = OVertical; + break; + case 'n': + steal = false; + break; + case 'p': + if(!getulong(EARGF(usage()), &tray.padding)) + usage(); + tray.padding = max(1, min(10, (int)tray.padding)); + break; + case 's': + if(!getulong(EARGF(usage()), &tray.iconsize)) + usage(); + tray.iconsize = max(1, (int)tray.iconsize); + break; + case 't': + tray.tags = EARGF(usage()); + break; + case 'a': + address = EARGF(usage()); + break; + case 'D': + debug++; + break; + case 'v': + lprint(1, "%s", version); + return 0; + default: + usage(); + }ARGEND; + + if(argc) + usage(); + + init_traps(); + initdisplay(); + + srv.preselect = event_preselect; + ixp_listen(&srv, ConnectionNumber(display), nil, event_fdready, event_fdclosed); + + event_updatextime(); + tray.selection = selection_manage(sxprint(Net("SYSTEM_TRAY_S%d"), scr.screen), + event_xtime, message, cleanup, steal); + if(tray.selection == nil) + fatal("Another system tray is already running."); + if(tray.selection->oldowner) + lprint(1, "%s: Replacing currently running system tray.\n", argv0); + + xext_init(); + tray_init(); + + client_init(address); + + if(tray.edge == 0) + tray.edge = West | (!strcmp(readctl("/ctl", "bar on "), "top") ? North : South); + + client_readconfig(&tray.normcolors, &tray.selcolors, &tray.font); + + if(tray.iconsize == 0) /* Default to wmii's bar size. */ + tray.iconsize = labelh(tray.font) - 2 * tray.padding; + + srv.running = true; + ixp_serverloop(&srv); + + if(tray.selection) + selection_release(tray.selection); + + XCloseDisplay(display); + + if(exitsignal) + raise(exitsignal); + return 0; +} + diff --git a/cmd/tray/selection.c b/cmd/tray/selection.c new file mode 100644 index 0000000..55bd6b5 --- /dev/null +++ b/cmd/tray/selection.c @@ -0,0 +1,229 @@ +/* Copyright ©2010 Kris Maglione <maglione.k at Gmail> + * See LICENSE file for license details. + */ +#include "dat.h" +#include "fns.h" + +static Handlers selection_handlers; +static Handlers steal_handlers; + +static Selection* +_selection_create(char *selection, ulong time, + void (*request)(Selection*, XSelectionRequestEvent*), + void (*cleanup)(Selection*), + bool lazy) { + Selection *s; + + if(time == 0) + time = event_xtime; + + s = emallocz(sizeof *s); + s->owner = createwindow(&scr.root, Rect(0, 0, 1, 1), 0, + InputOnly, nil, 0); + s->owner->aux = s; + s->request = request; + s->cleanup = cleanup; + s->time_start = time; + + sethandler(s->owner, &selection_handlers); + + if (!lazy) { + XSetSelectionOwner(display, xatom(selection), s->owner->xid, time); + + /* + * There is a race here that ICCCM doesn't mention. It's + * possible that we've gained and lost the selection in this + * time, and a client's sent us a selection request. We're + * required to reply to it, but since we're destroying the + * window, we'll never hear about it. Since ICCCM doesn't + * mention it, we assume that other clients behave likewise, + * and therefore clients must be prepared to deal with such + * behavior regardless. + */ + if(XGetSelectionOwner(display, xatom(selection)) != s->owner->xid) { + destroywindow(s->owner); + free(s); + return nil; + } + } + + s->selection = estrdup(selection); + return s; +} + +Selection* +selection_create(char *selection, ulong time, + void (*request)(Selection*, XSelectionRequestEvent*), + void (*cleanup)(Selection*)) { + return _selection_create(selection, time, request, cleanup, false); +} + +static void +_selection_manage(Selection *s) { + + if (s->oldowner) { + Dprint("[selection] Grabbing.\n"); + XSetSelectionOwner(display, xatom(s->selection), s->owner->xid, s->time_start); + if(XGetSelectionOwner(display, xatom(s->selection)) != s->owner->xid) { + selection_release(s); + return; + } + } + + Dprint("[selection] Notifying.\n"); + clientmessage(&scr.root, "MANAGER", SubstructureNotifyMask|StructureNotifyMask, 32, + (ClientMessageData){ .l = {s->time_start, xatom(s->selection), s->owner->xid} }); +} + +static void +timeout(long timer, void *v) { + Selection *s; + + s = v; + Dprint("[selection] Done waiting. Killing 0x%ulx.\n", s->oldowner); + s->timer = 0; + XKillClient(display, s->oldowner); + sync(); +} + +Selection* +selection_manage(char *selection, ulong time, + void (*message)(Selection*, XClientMessageEvent*), + void (*cleanup)(Selection*), + bool steal) { + Selection *s; + Window *w; + XWindow old; + + if((old = XGetSelectionOwner(display, xatom(selection)))) { + if (!steal) + return nil; + + w = emallocz(sizeof *w); + w->type = WWindow; + w->xid = old; + selectinput(w, StructureNotifyMask); + + /* Hack for broken Qt systray implementation. If it + * finds a new system tray running when the old one + * dies, it never selects the StructureNotify mask + * on it, and therefore never disassociates from it, + * and completely ignores any future MANAGER + * messages it receives. + */ + XSetSelectionOwner(display, xatom(selection), 0, time); + } + + s = _selection_create(selection, time, nil, cleanup, old); + if(s) { + s->message = message; + s->oldowner = old; + if(!old) + _selection_manage(s); + else { + Dprint("[selection] Waiting for old owner %W to die...\n", w); + pushhandler(w, &steal_handlers, s); + s->timer = ixp_settimer(&srv, 2000, timeout, s); + } + } + + return s; +} + +void +selection_release(Selection *s) { + if(s->cleanup) + s->cleanup(s); + if(!s->time_end) + XSetSelectionOwner(display, xatom(s->selection), None, s->time_start); + destroywindow(s->owner); + free(s->selection); + free(s); +} + +static void +selection_notify(Selection *s, XSelectionRequestEvent *ev, bool success) { + XSelectionEvent notify; + + notify.type = SelectionNotify; + notify.requestor = ev->requestor; + notify.selection = ev->selection; + notify.target = ev->target; + notify.property = success ? ev->property : None; + notify.time = ev->time; + + sendevent(window(ev->requestor), false, 0L, ¬ify); +} + +static bool +message_event(Window *w, void *aux, XClientMessageEvent *ev) { + Selection *s; + + s = aux; + if(s->message) + s->message(s, ev); + return false; +} + +static bool +selectionclear_event(Window *w, void *aux, XSelectionClearEvent *ev) { + Selection *s; + + USED(w, ev); + Dprint("[selection] Lost selection\n"); + s = aux; + s->time_end = ev->time; + selection_release(s); + return false; +} + +static bool +selectionrequest_event(Window *w, void *aux, XSelectionRequestEvent *ev) { + Selection *s; + + s = aux; + if(ev->property == None) + ev->property = ev->target; /* Per ICCCM §2.2. */ + + Dprint("[selection] Request: %A\n", ev->target); + if(ev->target == xatom("TIMESTAMP")) { + /* Per ICCCM §2.6.2. */ + changeprop_ulong(window(ev->requestor), + atomname(ev->property), "TIMESTAMP", + &s->time_start, 1); + selection_notify(s, ev, true); + return false; + } + + if(s->request) + s->request(s, ev); + else + selection_notify(s, ev, false); + return false; +} + +static Handlers selection_handlers = { + .message = message_event, + .selectionclear = selectionclear_event, + .selectionrequest = selectionrequest_event, +}; + +static bool +destroy_event(Window *w, void *aux, XDestroyWindowEvent *e) { + Selection *s; + + Dprint("[selection] Old owner is dead.\n"); + s = aux; + if(s->timer) + ixp_unsettimer(&srv, s->timer); + s->timer = 0; + + _selection_manage(s); + s->oldowner = 0; + return false; +} + +static Handlers steal_handlers = { + .destroy = destroy_event, +}; + diff --git a/cmd/tray/selection.h b/cmd/tray/selection.h new file mode 100644 index 0000000..944836e --- /dev/null +++ b/cmd/tray/selection.h @@ -0,0 +1,18 @@ +typedef struct Selection Selection; + +struct Selection { + Window* owner; + char* selection; + ulong time_start; + ulong time_end; + void (*cleanup)(Selection*); + void (*message)(Selection*, XClientMessageEvent*); + void (*request)(Selection*, XSelectionRequestEvent*); + long timer; + ulong oldowner; +}; + +Selection* selection_create(char*, ulong, void (*)(Selection*, XSelectionRequestEvent*), void (*)(Selection*)); +Selection* selection_manage(char*, ulong, void (*)(Selection*, XClientMessageEvent*), void (*)(Selection*), bool); +void selection_release(Selection*); + diff --git a/cmd/tray/tray.c b/cmd/tray/tray.c new file mode 100644 index 0000000..dece602 --- /dev/null +++ b/cmd/tray/tray.c @@ -0,0 +1,423 @@ +/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail> + * See LICENSE file for license details. + */ +#include "dat.h" +#include <string.h> +#include <strings.h> +#include "fns.h" + +static Handlers handlers; +static Handlers root_handlers; + +void +restrut(Window *w, int orientation) { + enum { Left, Right, Top, Bottom }; + Rectangle strut[4]; + Rectangle r; + + r = w->r; + memset(strut, 0, sizeof strut); + if(Dx(r) < Dx(scr.rect)/2 && orientation != OHorizontal) { + 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 && orientation != OVertical) { + 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; + } + } + +#if 0 +#define pstrut(name) \ + if(!eqrect(strut[name], ZR)) \ + fprint(2, "strut["#name"] = %R\n", strut[name]) + pstrut(Left); + pstrut(Right); + pstrut(Top); + pstrut(Bottom); +#endif + + ewmh_setstrut(w, strut); +} + +void +tray_init(void) { + WinAttr wa; + XWMHints hints = { 0, }; + + wa.background_pixmap = None; + wa.bit_gravity = NorthEastGravity; + wa.border_pixel = 0; + wa.event_mask = ExposureMask + | ButtonPressMask + | ButtonReleaseMask + | StructureNotifyMask + | SubstructureNotifyMask + /* Disallow clients reconfiguring themselves. */ + | SubstructureRedirectMask; + tray.win = createwindow(&scr.root, Rect(0, 0, 1, 1), scr.depth, InputOutput, + &wa, CWBackPixmap + | CWBitGravity + | CWEventMask); + + sethandler(tray.win, &handlers); + pushhandler(&scr.root, &root_handlers, nil); + selectinput(&scr.root, scr.root.eventmask | PropertyChangeMask); + + + changeprop_string(tray.win, "_WMII_TAGS", tray.tags); + + changeprop_ulong(tray.win, "XdndAware", "ATOM", (ulong[1]){ 5 }, 1); + + changeprop_ulong(tray.selection->owner, Net("SYSTEM_TRAY_VISUAL"), "VISUALID", + &scr.visual->visualid, 1); + changeprop_long(tray.win, Net("WM_WINDOW_TYPE"), "ATOM", + (long[1]){ TYPE("DOCK") }, 1); + + changeprop_string(tray.win, Net("WM_NAME"), "witray"); + changeprop_textlist(tray.win, "WM_NAME", "STRING", + (char*[2]){ "witray", nil }); + changeprop_textlist(tray.win, "WM_CLASS", "STRING", + (char*[3]){ "witray", "witray", nil }); + changeprop_textlist(tray.win, "WM_COMMAND", "STRING", program_args); + + hints.flags = InputHint; + hints.input = false; + XSetWMHints(display, tray.win->xid, &hints); + tray_resize(tray.win->r); +} + +static void +tray_unmap(void) { + unmapwin(tray.win); + sendevent(&scr.root, false, SubstructureNotifyMask, + &(XUnmapEvent){ + .type = UnmapNotify, + .event = scr.root.xid, + .window = tray.win->xid + }); +} + +static void +tray_draw(Rectangle r) { + int borderwidth; + + if(!tray.pixmap) + return; + + borderwidth = 1; + + r = rectsetorigin(r, ZP); + border(tray.pixmap, r, borderwidth, &tray.selcolors.border); + r = insetrect(r, borderwidth); + fill(tray.pixmap, r, &tray.selcolors.bg); + XClearWindow(display, tray.win->xid); +} + +void +tray_resize(Rectangle r) { + WinHints hints; + Image *oldimage; + WinAttr wa; + + hints = ZWinHints; + hints.position = true; + hints.min = hints.max = Pt(Dx(r), Dy(r)); + hints.grav = Pt(tray.edge & East ? 0 : + tray.edge & West ? 2 : 1, + tray.edge & North ? 0 : + tray.edge & South ? 2 : 1); + /* Not necessary, since we specify fixed size, but... */ + // hints.base = Pt(2, 2); + // hints.inc = Pt(tray.iconsize, tray.iconsize); + sethints(tray.win, &hints); + + if(!eqrect(tray.win->r, r)) { + oldimage = tray.pixmap; + + tray.pixmap = allocimage(Dx(r), Dy(r), tray.win->depth); + tray_draw(r); + wa.background_pixmap = tray.pixmap->xid; + setwinattr(tray.win, &wa, CWBackPixmap); + + freeimage(oldimage); + } + + tray.r = r; + tray.win->r = ZR; /* Force the configure event. */ + reshapewin(tray.win, r); + restrut(tray.win, tray.orientation); +} + +void +tray_update(void) { + Rectangle r; + Point p, offset, padding; + Client *c; + + r = Rect(0, 0, tray.iconsize, tray.iconsize); + padding = Pt(tray.padding, tray.padding); + offset = padding; + Dprint("tray_update()\n"); + for(c=tray.clients; c; c=c->next) { + if(c->w.mapped) { + reshapewin(&c->w, rectaddpt(r, offset)); + /* This seems, sadly, to be necessary. */ + sendevent(&c->w, false, StructureNotifyMask, &(XEvent){ + .xconfigure = { + .type = ConfigureNotify, + .event = c->w.xid, + .window = c->w.xid, + .above = None, + .x = c->w.r.min.x, + .y = c->w.r.min.y, + .width = Dx(c->w.r), + .height = Dy(c->w.r), + .border_width = 0, + } + }); + + movewin(c->indicator, addpt(offset, Pt(2, 2))); + if(tray.orientation == OHorizontal) + offset.x += tray.iconsize + tray.padding; + else + offset.y += tray.iconsize + tray.padding; + } + if(c->w.mapped && client_hasmessage(c)) + mapwin(c->indicator); + else + unmapwin(c->indicator); + } + + if(eqpt(offset, padding)) + tray_unmap(); + else { + if(tray.orientation == OHorizontal) + offset.y += tray.iconsize + tray.padding; + else + offset.x += tray.iconsize + tray.padding; + + r = Rpt(ZP, offset); + p = subpt(scr.rect.max, r.max); + if(tray.edge & East) + p.x = 0; + if(tray.edge & North) + p.y = 0; + tray_resize(rectaddpt(r, p)); + mapwin(tray.win); + } + + tray_draw(tray.win->r); +} + +static bool +config_event(Window *w, void *aux, XConfigureEvent *ev) { + + USED(aux); + if(ev->send_event) { + /* + * Per ICCCM §4.2.3, the window manager sends + * synthetic configure events in the root coordinate + * space when it changes the window configuration. + * This code assumes wmii's generous behavior of + * supplying all relevant members in every configure + * notify event. + */ + w->r = rectaddpt(rectsetorigin(Rect(0, 0, ev->width, ev->height), + Pt(ev->x, ev->y)), + Pt(ev->border_width, ev->border_width)); + restrut(w, tray.orientation); + } + return false; +} + +static bool +expose_event(Window *w, void *aux, XExposeEvent *ev) { + + USED(w, aux, ev); + tray_draw(tray.win->r); + return false; +} + +typedef struct Dnd Dnd; + +struct Dnd { + ulong source; + ulong dest; + long data[4]; + Point p; + bool have_actions; +}; + +static Dnd dnd; + +#define Point(l) Pt((ulong)(l) >> 16, (ulong)(l) & 0xffff) +#define Long(p) ((long)(((ulong)(p).x << 16) | (ulong)(p).y)) +#define sendmessage(...) BLOCK( \ + Dprint("(%W) %s 0x%ulx, 0x%ulx, 0x%ulx, 0x%ulx, 0x%ulx\n", __VA_ARGS__); \ + sendmessage(__VA_ARGS__); \ + ) + +static void +dnd_updatestatus(ulong dest) { + if(dest == dnd.dest) + return; + + if(dnd.dest && dnd.dest != ~0UL) + sendmessage(window(dnd.dest), "XdndLeave", tray.win->xid, 0, 0, 0, 0); + dnd.dest = dest; + if(dest) + sendmessage(window(dest), "XdndEnter", tray.win->xid, + dnd.data[0], dnd.data[1], dnd.data[2], dnd.data[3]); + else + sendmessage(window(dnd.source), "XdndStatus", tray.win->xid, (1<<1), + Long(tray.win->r.min), (Dx(tray.win->r)<<16) | Dy(tray.win->r), 0UL); +} + +static void +copyprop_long(Window *src, Window *dst, char *atom, char *type, long max) { + long *data; + long n; + + /* Round trip. Really need to switch to XCB. */ + if((n = getprop_long(src, atom, type, 0, &data, max))) + changeprop_long(dst, atom, type, data, n); + free(data); +} + +static void +copyprop_char(Window *src, Window *dst, char *atom, char *type, long max) { + uchar *data; + ulong actual, n; + int format; + + n = getprop(src, atom, type, &actual, &format, 0, &data, max); + if(n > 0 && format == 8 && xatom(type) == actual) + changeprop_char(dst, atom, type, (char*)data, n); + free(data); +} + +static bool +message_event(Window *w, void *aux, XClientMessageEvent *e) { + Client *c; + long *l; + Rectangle r; + Point p; + ulong msg; + + msg = e->message_type; + l = e->data.l; + Dprint("ClientMessage: %A\n", msg); + if(e->format == 32) + Dprint("\t0x%ulx, 0x%ulx, 0x%ulx, 0x%ulx, 0x%ulx\n", + l[0], l[1], l[2], l[3], l[4]); + + if(msg == xatom("XdndEnter")) { + if(e->format != 32) + return false; + dnd = (Dnd){0}; + dnd.dest = ~0UL; + dnd.source = l[0]; + bcopy(&l[1], dnd.data, sizeof dnd.data); + + copyprop_long(window(dnd.source), tray.win, "XdndSelection", "ATOM", 128); + if(l[1] & 0x01) + copyprop_long(window(dnd.source), tray.win, "XdndTypeList", "ATOM", 128); + return false; + }else + if(msg == xatom("XdndLeave")) { + if(e->format != 32) + return false; + dnd.source = 0UL; + if(dnd.dest) + sendmessage(window(dnd.dest), "XdndLeave", tray.win->xid, l[1], 0, 0, 0); + return false; + }else + if(msg == xatom("XdndPosition")) { + if(e->format != 32) + return false; + + if(!dnd.have_actions && l[4] == xatom("XdndActionAsk")) { + dnd.have_actions = true; + copyprop_long(window(dnd.source), tray.win, "XdndActionList", "ATOM", 16); + copyprop_char(window(dnd.source), tray.win, "XdndActionDescription", "ATOM", 16 * 32); + } + + dnd.p = subpt(Point(l[2]), tray.win->r.min); + for(c=tray.clients; c; c=c->next) + if(rect_haspoint_p(c->w.r, dnd.p)) { + dnd_updatestatus(c->w.xid); + sendmessage(&c->w, "XdndPosition", tray.win->xid, l[1], l[2], l[3], l[4]); + return false; + } + dnd_updatestatus(0UL); + return false; + }else + if(msg == xatom("XdndStatus")) { + if(e->format != 32) + return false; + if(l[0] != dnd.dest) + return false; + + for(c=tray.clients; c; c=c->next) + if(c->w.xid == dnd.dest) { + p = Point(l[2]); + r = Rpt(p, addpt(p, Point(l[3]))); + r = rect_intersection(r, rectaddpt(c->w.r, tray.win->r.min)); + + sendmessage(window(dnd.source), "XdndStatus", tray.win->xid, l[1], + Long(r.min), (Dx(r)<<16) | Dy(r), l[4]); + break; + } + return false; + }else + if(msg == xatom("XdndDrop") || msg == xatom("XdndFinished")) { + if(e->format != 32) + return false; + + for(c=tray.clients; c; c=c->next) + if(c->w.xid == dnd.dest) { + sendmessage(&c->w, atomname(msg), + tray.win->xid, l[1], l[2], 0L, 0L); + break; + } + return false; + } + + return true; +} + +static Handlers handlers = { + .message = message_event, + .config = config_event, + .expose = expose_event, +}; + +static bool +property_event(Window *w, void *aux, XPropertyEvent *ev) { + if(ev->atom == NET("CURRENT_DESKTOP")) + tray_resize(tray.r); + Debug if(ev->atom == NET("CURRENT_DESKTOP")) + print("property_event(_NET_CURRENT_DESKTOP)\n"); + return false; +} + +static Handlers root_handlers = { + .property = property_event, +}; + diff --git a/cmd/tray/xembed.c b/cmd/tray/xembed.c new file mode 100644 index 0000000..cbaf8b7 --- /dev/null +++ b/cmd/tray/xembed.c @@ -0,0 +1,141 @@ +/* Copyright ©2010 Kris Maglione <maglione.k at Gmail> + * See LICENSE file for license details. + */ +#include "dat.h" +#include "fns.h" + +#define DEAD ~0UL + +enum { XEmbedVersion = 0 }; + +enum XEmbedMessage { + XEmbedEmbeddedNotify, + XEmbedWindowActivate, + XEmbedWindowDeactivate, + XEmbedRequestFocus, + XEmbedFocusIn, + XEmbedFocusOut, + XEmbedFocusNext, + XEmbedFocusPrev, + XEmbedModalityOn = 10, + XEmbedModalityOff, + XEmbedRegisterAccelerator, + XEmbedUnregisterAccelerator, + XEmbedActivateAccelerator, +}; + +enum XEmbedFocusDetail { + XEmbedFocusCurrent, + XEmbedFocusFirst, + XEmbedFocusLast, +}; + +static Handlers handlers; + +static void xembed_updateinfo(XEmbed*); +static void xembed_sendmessage(XEmbed*, long, long, long, long); + +XEmbed* +xembed_swallow(Window *parent, Window *client, void (*cleanup)(XEmbed*)) { + XEmbed *xembed; + + xembed = emallocz(sizeof *xembed); + xembed->w = client; + xembed->owner = parent; + xembed->cleanup = cleanup; + selectinput(client, client->eventmask | PropertyChangeMask | StructureNotifyMask); + pushhandler(client, &handlers, xembed); + + reparentwindow(client, parent, ZP); + xembed_updateinfo(xembed); + xembed_sendmessage(xembed, XEmbedEmbeddedNotify, 0, parent->xid, min(XEmbedVersion, xembed->version)); + return xembed; +} + +void +xembed_disown(XEmbed *xembed) { + + pophandler(xembed->w, &handlers); + if(xembed->flags != DEAD) { + reparentwindow(xembed->w, &scr.root, ZP); + unmapwin(xembed->w); + } + if(xembed->cleanup) + xembed->cleanup(xembed); + free(xembed); +} + +static void +xembed_updateinfo(XEmbed *xembed) { + ulong *res; + int n; + + n = getprop_ulong(xembed->w, "_XEMBED_INFO", "_XEMBED_INFO", 0, &res, 2); + xembed->flags = 0UL; + if(n >= 2) { + xembed->version = res[0]; + xembed->flags = res[1]; + } + else { + /* Deal with a Qt system tray replacement bug. */ + xembed->flags = XEmbedMapped; + } + free(res); + + Dprint("xembed_updateinfo(0x%ulx) XEmbedMapped=%s\n", + xembed->w, + xembed->flags & XEmbedMapped ? "true" : "false"); + + if(xembed->flags & XEmbedMapped) + mapwin(xembed->w); + else + unmapwin(xembed->w); +} + +static void +xembed_sendmessage(XEmbed *xembed, long message, long detail, long data1, long data2) { + + traperrors(true); + sendmessage(xembed->w, "_XEMBED", event_xtime, message, detail, data1, data2); + traperrors(false); +} + +static bool +destroy_event(Window *w, void *aux, XDestroyWindowEvent *ev) { + XEmbed *xembed; + + xembed = aux; + xembed->flags = DEAD; + xembed_disown(xembed); + return false; +} + +static bool +property_event(Window *w, void *aux, XPropertyEvent *ev) { + XEmbed *xembed; + + Dprint("property_event(%W, %p, %A)\n", + w, aux, ev->atom); + xembed = aux; + if(ev->atom == xatom("_XEMBED_INFO")) + xembed_updateinfo(xembed); + return false; +} + +static bool +reparent_event(Window *w, void *aux, XReparentEvent *ev) { + XEmbed *xembed; + + xembed = aux; + if(ev->parent != xembed->owner->xid) { + xembed->flags = DEAD; + xembed_disown(xembed); + } + return false; +} + +static Handlers handlers = { + .destroy = destroy_event, + .property = property_event, + .reparent = reparent_event, +}; diff --git a/cmd/util.c b/cmd/util.c deleted file mode 100644 index 2556d28..0000000 --- a/cmd/util.c +++ /dev/null @@ -1,272 +0,0 @@ -/* Written by Kris Maglione <fbsdaemon at gmail dot com> */ -/* Public domain */ -#include <ctype.h> -#include <errno.h> -#include <sys/types.h> -#include <signal.h> -#include <stdarg.h> -#include <stdlib.h> -#include <stdint.h> -#include <stdio.h> -#include <string.h> -#include <strings.h> -#include <unistd.h> -#include <util.h> -#include <fmt.h> - -typedef struct VFmt VFmt; -struct VFmt { - const char *fmt; - va_list args; -}; - -#ifdef VARARGCK -# pragma varargck type "V" VFmt* -#endif - -static int -Vfmt(Fmt *f) { - VFmt *vf; - int i; - - vf = va_arg(f->args, VFmt*); - i = fmtvprint(f, vf->fmt, vf->args); - return i; -} - -void -fatal(const char *fmt, ...) { - VFmt fp; - - fmtinstall('V', Vfmt); - fmtinstall('\001', Vfmt); - - fp.fmt = fmt; - va_start(fp.args, fmt); - fprint(2, "%s: fatal: %V\n", argv0, &fp); - va_end(fp.args); - - exit(1); -} - -void* -freelater(void *p) { - static char* obj[16]; - static long nobj; - int id; - - id = nobj++ % nelem(obj); - free(obj[id]); - obj[id] = p; - return p; -} - -char* -vsxprint(const char *fmt, va_list ap) { - char *s; - - s = vsmprint(fmt, ap); - freelater(s); - return s; -} - -char* -sxprint(const char *fmt, ...) { - va_list ap; - char *ret; - - va_start(ap, fmt); - ret = vsxprint(fmt, ap); - va_end(ap); - return ret; -} - -void -_die(char *file, int line, char *msg, ...) { - va_list ap; - - va_start(ap, msg); - fprint(2, "%s: dieing at %s:%d: %s\n", - argv0, file, line, - vsxprint(msg, ap)); - va_end(ap); - - 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) { - const char - couldnot[] = ": fatal: Could not ", - paren[] = "() ", - bytes[] = " bytes\n"; - char buf[1024]; - char sizestr[8]; - int i; - - i = sizeof sizestr; - do { - sizestr[--i] = '0' + (size%10); - size /= 10; - } while(size > 0); - - strlcat(buf, argv0, sizeof buf); - strlcat(buf, couldnot, sizeof buf); - strlcat(buf, name, sizeof buf); - strlcat(buf, paren, sizeof buf); - strlcat(buf, sizestr+i, sizeof buf); - strlcat(buf, bytes, sizeof buf); - write(2, buf, strlen(buf)); - - exit(1); -} - -void * -emalloc(uint size) { - void *ret = malloc(size); - if(!ret) - mfatal("malloc", size); - return ret; -} - -void * -emallocz(uint size) { - void *ret = emalloc(size); - memset(ret, 0, size); - return ret; -} - -void * -erealloc(void *ptr, uint size) { - void *ret = realloc(ptr, size); - if(!ret) - mfatal("realloc", size); - return ret; -} - -char* -estrdup(const char *str) { - void *ret = strdup(str); - if(!ret) - mfatal("strdup", strlen(str)); - return ret; -} - -char* -estrndup(const char *str, uint len) { - char *ret; - - len = min(len, strlen(str)); - ret = emalloc(len + 1); - memcpy(ret, str, len); - ret[len] = '\0'; - return ret; -} - - -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; -} - -uint -stokenize(char *res[], uint reslen, char *str, char *delim) { - char *s; - uint i; - - i = 0; - s = str; - while(i < reslen && *s) { - while(strchr(delim, *s)) - *(s++) = '\0'; - if(*s) - res[i++] = s; - while(*s && !strchr(delim, *s)) - s++; - } - return i; -} - -int -max(int a, int b) { - if(a > b) - return a; - return b; -} - -int -min(int a, int b) { - if(a < b) - return a; - return b; -} - -int -utflcpy(char *to, const char *from, int l) { - char *p; - - p = utfecpy(to, to+l, from); - return p-to; -} - -uint -strlcat(char *dst, const char *src, uint size) { - const char *s; - char *d; - int n, len; - - d = dst; - s = src; - n = size; - while(n-- > 0 && *d != '\0') - d++; - len = n; - - while(*s != '\0') { - if(n-- > 0) - *d++ = *s; - s++; - } - if(len > 0) - *d = '\0'; - return size - n - 1; -} - -/* TODO: Make this UTF-8 compliant. */ -char* -strcasestr(const char *dst, const char *src) { - int dc, sc; - int len; - - len = strlen(src) - 1; - for(; (sc = *src) && *dst; src++) { - sc = tolower(dc); - for(; (dc = *dst); dst++) { - dc = tolower(dc); - if(sc == dc && !strncasecmp(dst+1, src+1, len)) - return (char*)(uintptr_t)dst; - } - } - return nil; -} - diff --git a/cmd/wihack.sh b/cmd/wihack.sh index 2c401d4..ae06ff0 100644 --- a/cmd/wihack.sh +++ b/cmd/wihack.sh @@ -1,4 +1,5 @@ #!/bin/sh -f +unset WMII_HACK_TRANSIENT WMII_HACK_TYPE WMII_HACK_TAGS usage() { echo 1>&2 Usage: \ diff --git a/cmd/wmii.rc.rc b/cmd/wmii.rc.rc index 392a0d7..96a43a5 100755 --- a/cmd/wmii.rc.rc +++ b/cmd/wmii.rc.rc @@ -9,6 +9,7 @@ wmiiscript=$1 wmiikeys=() +wmiikeyhelp='' wi_newline=' ' @@ -58,10 +59,7 @@ fn wi_fn-p { } fn wi_proglist { - # XXX: maxdepth is not POSIX compliant. - ifs=: { find -L `{echo -n $*} -type f -a -maxdepth 1 \ - '(' -perm -0100 -o -perm -0010 -o -perm -0001 ')' >[2]/dev/null \ - | sed 's,.*/,,' | sort | uniq} + ifs=: { wmiir proglist -- `{echo -n $*} | sort | uniq } } fn wi_actions { @@ -137,15 +135,21 @@ fn wi_selclient { wmiir read /client/sel/ctl | sed 1q } -fn wi_readevent { - wmiir read /event +fn wi_nexttag { + awk -v 'curtag='^`{wi_seltag} ' + NR==1 {first = $0} + $0==curtag { if(getline) print $0; else print first; exit }' } fn wi_eventloop { wi_initkeys - wi_readevent | - while(ifs=$wi_ewlinel{wi_event=`{read}}) { + { + if(~ $1 -i) + cat + if not + wmiir read /event + } | while(ifs=$wi_newline{wi_event=`{read}}) { ifs=$wi_newline{ wi_arg=`{echo $wi_event | sed 's/^[^ ]+ //'}} * = `{echo $wi_event} diff --git a/cmd/wmii.sh.sh b/cmd/wmii.sh.sh index d636f26..0828976 100755 --- a/cmd/wmii.sh.sh +++ b/cmd/wmii.sh.sh @@ -85,25 +85,26 @@ _wi_script() { } _wi_text() { - cat <<'!' -Event Start - if [ "$1" = "$wmiiscript" ]; then - exit - fi -Event Key - Key "$@" -! eval "cat <<! $( (test ! -t 0 && cat; for a; do eval "$a"; done) | sed '/^[ ]/s/\([$`\\]\)/\\\1/g') ! " } +_wi_events="" wi_events() { - #cho "$(_wi_text "$@" | awk "$(_wi_script)")" | cat -n - eval "$(_wi_text "$@" | awk "$(_wi_script)")" + eval=""; [ "$1" = -e ] && eval=1 && shift + _wi_events="$(_wi_text "$@") +$_wi_events" + # -n "$eval" ] && printf %s "$_wi_events" | awk "$(_wi_script)" >&2 + [ -n "$eval" ] && eval "$(printf %s "$_wi_events" | awk "$(_wi_script)")" } +wi_events <<'!' +Event Key + Key "$@" +! + wi_fatal() { echo $scriptname: Fatal: $* exit 1 @@ -135,9 +136,7 @@ wi_fnmenu() { } wi_proglist() { - ls -lL $(echo $* | sed 'y/:/ /') 2>/dev/null \ - | awk '$1 ~ /^[^d].*x/ { print $NF }' \ - | sort | uniq + wmiir proglist -- $(echo $* | sed 'y/:/ /') | sort | uniq } wi_actions() { @@ -190,12 +189,18 @@ wi_selclient() { wmiir read /client/sel/ctl | sed 1q | tr -d '\012' } +wi_nexttag() { + awk -v curtag=$(wi_seltag) ' + NR==1 {first = $0} + $0==curtag { if(getline) print $0; else print first; exit }' +} + wi_eventloop() { echo "$Keys" | wmiir write /keys - if [ "$1" = -i ] - then cat - else wmiir read /event + if [ "$1" = -i ] + then cat + else wmiir read /event fi | while read wi_event; do IFS="$wi_newline" @@ -203,7 +208,9 @@ wi_eventloop() { unset IFS set -- $wi_event event=$1; shift - ( Event $event "$@" ) + [ "$event" = Start -a "$1" = "$wmiiscript" ] && + exit + Event $event "$@" done true } diff --git a/cmd/wmii/Makefile b/cmd/wmii/Makefile index de635ca..b5d41c4 100644 --- a/cmd/wmii/Makefile +++ b/cmd/wmii/Makefile @@ -4,17 +4,18 @@ include $(ROOT)/mk/wmii.mk main.c: $(ROOT)/mk/wmii.mk -TARG = wmii -HFILES= dat.h fns.h +TARG = wmii +HFILES = dat.h fns.h +TAGFILES = dat.h PACKAGES += $(X11PACKAGES) xext xrandr xrender xinerama -LIB = $(LIBIXP) -LIBS += -lm $(LIBS9) +LIB = $(LIBIXP) $(LIBS9) +LIBS += -lm -CFLAGS += $(INCICONV) -DIXP_NEEDAPI=97 OBJ = area \ bar \ + backtrace \ client \ column \ div \ @@ -24,24 +25,19 @@ OBJ = area \ float \ frame \ fs \ - geom \ key \ layout \ main \ - map \ message \ mouse \ print \ root \ rule \ - printevent\ screen \ - _util \ + stack \ + utf \ view \ - xdnd \ - x11 \ - xext \ - ../util + xdnd include $(ROOT)/mk/one.mk diff --git a/cmd/wmii/_util.c b/cmd/wmii/_util.c deleted file mode 100644 index feafba9..0000000 --- a/cmd/wmii/_util.c +++ /dev/null @@ -1,378 +0,0 @@ -/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail> - * See LICENSE file for license details. - */ -#include "dat.h" -#include <errno.h> -#include <fcntl.h> -#include <stdarg.h> -#include <sys/signal.h> -#include <sys/wait.h> -#include <unistd.h> -#include <bio.h> -#include "fns.h" - -/* Blech. */ -#define VECTOR(type, nam, c) \ -void \ -vector_##c##init(Vector_##nam *v) { \ - memset(v, 0, sizeof *v); \ -} \ - \ -void \ -vector_##c##free(Vector_##nam *v) { \ - free(v->ary); \ - memset(v, 0, sizeof *v); \ -} \ - \ -void \ -vector_##c##push(Vector_##nam *v, type 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; \ -} \ - -VECTOR(long, long, l) -VECTOR(Rectangle, rect, r) -VECTOR(void*, ptr, p) - -int -doublefork(void) { - pid_t pid; - int status; - - switch(pid=fork()) { - case -1: - fatal("Can't fork(): %r"); - case 0: - switch(pid=fork()) { - case -1: - fatal("Can't fork(): %r"); - case 0: - return 0; - default: - exit(0); - } - default: - waitpid(pid, &status, 0); - return pid; - } - /* NOTREACHED */ -} - -void -closeexec(int fd) { - if(fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) - fatal("can't set %d close on exec: %r", fd); -} - -int -spawn3(int fd[3], const char *file, char *argv[]) { - /* Some ideas from Russ Cox's libthread port. */ - int p[2]; - int pid; - - if(pipe(p) < 0) - return -1; - closeexec(p[1]); - - switch(pid = doublefork()) { - case 0: - dup2(fd[0], 0); - dup2(fd[1], 1); - dup2(fd[2], 2); - - execvp(file, argv); - write(p[1], &errno, sizeof errno); - exit(1); - break; - default: - close(p[1]); - if(read(p[0], &errno, sizeof errno) == sizeof errno) - pid = -1; - close(p[0]); - break; - case -1: /* can't happen */ - break; - } - - close(fd[0]); - /* These could fail if any of these was also a previous fd. */ - close(fd[1]); - close(fd[2]); - return pid; -} - -int -spawn3l(int fd[3], const char *file, ...) { - va_list ap; - char **argv; - int i, n; - - va_start(ap, file); - for(n=0; va_arg(ap, char*); n++) - ; - va_end(ap); - - argv = emalloc((n+1) * sizeof *argv); - va_start(ap, file); - quotefmtinstall(); - for(i=0; i <= n; i++) - argv[i] = va_arg(ap, char*); - va_end(ap); - - i = spawn3(fd, file, argv); - free(argv); - return i; -} - -#ifdef __linux__ -# define PROGTXT "exe" -#else -# define PROGTXT "file" -#endif - -static void -_backtrace(int pid, char *btarg) { - char *proc, *spid, *gdbcmd; - int fd[3], p[2]; - int status, cmdfd; - - gdbcmd = estrdup("/tmp/gdbcmd.XXXXXX"); - if(pipe(p) < 0) - goto done; - closeexec(p[0]); - - cmdfd = mkstemp(gdbcmd); - if(cmdfd < 0) - goto done; - - fprint(cmdfd, "bt %s\n", btarg); - fprint(cmdfd, "detach\n"); - close(cmdfd); - - fd[0] = open("/dev/null", O_RDONLY); - fd[1] = p[1]; - fd[2] = dup(2); - - proc = sxprint("/proc/%d/" PROGTXT, pid); - spid = sxprint("%d", pid); - if(spawn3l(fd, "gdb", "gdb", "-batch", "-x", gdbcmd, proc, spid, nil) < 0) { - unlink(gdbcmd); - goto done; - } - - Biobuf bp; - char *s; - - Binit(&bp, p[0], OREAD); - while((s = Brdstr(&bp, '\n', 1))) { - Dprint(DStack, "%s\n", s); - free(s); - } - unlink(gdbcmd); - -done: - free(gdbcmd); - kill(pid, SIGKILL); - waitpid(pid, &status, 0); -} - -void -backtrace(char *btarg) { - int pid; - - /* Fork so we can backtrace the child. Keep this stack - * frame minimal, so the trace is fairly clean. - */ - Debug(DStack) - switch(pid = fork()) { - case -1: - return; - case 0: - kill(getpid(), SIGSTOP); - _exit(0); - default: - _backtrace(pid, btarg); - break; - } - -} - -void -reinit(Regex *r, char *regx) { - - refree(r); - - if(regx[0] != '\0') { - r->regex = estrdup(regx); - r->regc = regcomp(regx); - } -} - -void -refree(Regex *r) { - - free(r->regex); - free(r->regc); - r->regex = nil; - r->regc = nil; -} - -void -uniq(char **toks) { - char **p, **q; - - q = toks; - if(*q == nil) - return; - for(p=q+1; *p; p++) - if(strcmp(*q, *p)) - *++q = *p; - *++q = nil; -} - -char** -comm(int cols, char **toka, char **tokb) { - Vector_ptr vec; - char **ret; - int cmp; - - vector_pinit(&vec); - while(*toka || *tokb) { - if(!*toka) - cmp = 1; - else if(!*tokb) - cmp = -1; - else - cmp = strcmp(*toka, *tokb); - if(cmp < 0) { - if(cols & CLeft) - vector_ppush(&vec, *toka); - toka++; - }else if(cmp > 0) { - if(cols & CRight) - vector_ppush(&vec, *tokb); - tokb++; - }else { - if(cols & CCenter) - vector_ppush(&vec, *toka); - toka++; - tokb++; - } - } - vector_ppush(&vec, nil); - ret = strlistdup((char**)vec.ary); - free(vec.ary); - return ret; -} - -void -grep(char **list, Reprog *re, int flags) { - char **p, **q; - int res; - - q = list; - for(p=q; *p; p++) { - res = 0; - if(re) - res = regexec(re, *p, nil, 0); - if(res && !(flags & GInvert) - || !res && (flags & GInvert)) - *q++ = *p; - } - *q = nil; -} - -char* -join(char **list, char *sep) { - Fmt f; - char **p; - - if(fmtstrinit(&f) < 0) - abort(); - - for(p=list; *p; p++) { - if(p != list) - fmtstrcpy(&f, sep); - fmtstrcpy(&f, *p); - } - - return fmtstrflush(&f); -} - -int -strlcatprint(char *buf, int len, const char *fmt, ...) { - va_list ap; - int buflen; - int ret; - - va_start(ap, fmt); - buflen = strlen(buf); - ret = vsnprint(buf+buflen, len-buflen, fmt, ap); - va_end(ap); - return ret; -} - -char* -pathsearch(const char *path, const char *file, bool slashok) { - char *orig, *p, *s; - - if(!slashok && strchr(file, '/') > file) - file = sxprint("%s/%s", getcwd(buffer, sizeof buffer), file); - else if(!strncmp(file, "./", 2)) - file = sxprint("%s/%s", getcwd(buffer, sizeof buffer), file+2); - if(file[0] == '/') { - if(access(file, X_OK)) - return strdup(file); - return nil; - } - - orig = estrdup(path ? path : getenv("PATH")); - for(p=orig; (s=strtok(p, ":")); p=nil) { - s = smprint("%s/%s", s, file); - if(!access(s, X_OK)) - break; - free(s); - } - free(orig); - return s; -} - -int -unquote(char *buf, char *toks[], int ntoks) { - char *s, *t; - bool inquote; - int n; - - n = 0; - s = buf; - while(*s && n < ntoks) { - while(*s && utfrune(" \t\r\n", *s)) - s++; - inquote = false; - toks[n] = s; - t = s; - while(*s && (inquote || !utfrune(" \t\r\n", *s))) { - if(*s == '\'') { - if(inquote && s[1] == '\'') - *t++ = *s++; - else - inquote = !inquote; - } - else - *t++ = *s; - s++; - } - if(*s) - s++; - *t = '\0'; - if(s != toks[n]) - n++; - } - return n; -} - diff --git a/cmd/wmii/area.c b/cmd/wmii/area.c index 0f94e72..6a10d25 100644 --- a/cmd/wmii/area.c +++ b/cmd/wmii/area.c @@ -85,17 +85,16 @@ area_create(View *v, Area *pos, int scrn, uint width) { SET(index); if(v->areas) { /* Creating a column. */ minwidth = column_minwidth(); - index = pos ? area_idx(pos) : 1; + index = pos ? area_idx(pos) : 0; numcols = 0; for(a=v->areas[scrn]; a; a=a->next) numcols++; - /* TODO: Need a better sizing/placing algorithm. - */ + /* TODO: Need a better sizing/placing algorithm. */ if(width == 0) { if(numcols >= 0) { - width = view_newcolwidth(v, index); - if (width == 0) + width = view_newcolwidth(v, scrn, index); + if(width == 0) width = Dx(v->r[scrn]) / (numcols + 1); } else @@ -214,7 +213,7 @@ area_moveto(Area *to, Frame *f) { return; from = f->area; - if (from == to) + if(from == to) return; area_detach(f); @@ -255,6 +254,7 @@ area_attach(Area *a, Frame *f) { column_attach(a, f); view_arrange(a->view); + event("AreaAttach %s %a %#C\n", a->view->name, a, f->client); if(btassert("4 full", a->frame && a->sel == nil)) a->sel = a->frame; @@ -268,12 +268,14 @@ area_detach(Frame *f) { a = f->area; v = a->view; + event("AreaDetach %s %a %#C\n", v->name, a, f->client); if(a->floating) float_detach(f); else column_detach(f); if(v->sel->sel == nil && v->floating->sel) + if(!v->floating->sel->client->nofocus) v->sel = v->floating; view_arrange(v); @@ -300,29 +302,18 @@ area_focus(Area *a) { if(a != old_a) v->oldsel = nil; - if((old_a) && (a->floating != old_a->floating)) { + if(old_a && a->floating != old_a->floating) { v->revert = old_a; if(v->floating->max) view_update(v); } - if(v != selview) - return; - - move_focus(old_a->sel, f); + if(v == selview) { + move_focus(old_a->sel, f); + client_focus(f ? f->client : nil); - if(f) - client_focus(f->client); - else - client_focus(nil); - - if(a != old_a) { - event("AreaFocus %a\n", a); - /* Deprecated */ - if(a->floating) - event("FocusFloating\n"); - else - event("ColumnFocus %d\n", area_idx(a)); + if(a != old_a) + event("AreaFocus %a\n", a); } } diff --git a/cmd/wmii/backtrace.c b/cmd/wmii/backtrace.c new file mode 100644 index 0000000..d459c48 --- /dev/null +++ b/cmd/wmii/backtrace.c @@ -0,0 +1,87 @@ +/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail> + * See LICENSE file for license details. + */ +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <fcntl.h> +#include <signal.h> + +#include <bio.h> +#include <plan9.h> +#undef nelem +#include <stuff/util.h> +#include "debug.h" + +#ifdef __linux__ +# define PROGTXT "exe" +#else +# define PROGTXT "file" +#endif + +static void +_backtrace(int pid, char *btarg) { + char *proc, *spid, *gdbcmd; + int fd[3], p[2]; + int status, cmdfd; + + gdbcmd = estrdup("/tmp/gdbcmd.XXXXXX"); + if(pipe(p) < 0) + goto done; + closeexec(p[0]); + + cmdfd = mkstemp(gdbcmd); + if(cmdfd < 0) + goto done; + + fprint(cmdfd, "bt %s\n", btarg); + fprint(cmdfd, "detach\n"); + close(cmdfd); + + fd[0] = open("/dev/null", O_RDONLY); + fd[1] = p[1]; + fd[2] = dup(2); + + proc = sxprint("/proc/%d/" PROGTXT, pid); + spid = sxprint("%d", pid); + if(spawn3l(fd, "gdb", "gdb", "-batch", "-x", gdbcmd, proc, spid, nil) < 0) { + unlink(gdbcmd); + goto done; + } + + Biobuf bp; + char *s; + + Binit(&bp, p[0], OREAD); + while((s = Brdstr(&bp, '\n', 1))) { + Dprint(DStack, "%s\n", s); + free(s); + } + unlink(gdbcmd); + +done: + free(gdbcmd); + kill(pid, SIGKILL); + waitpid(pid, &status, 0); +} + +void +backtrace(char *btarg) { + int pid; + + /* Fork so we can backtrace the child. Keep this stack + * frame minimal, so the trace is fairly clean. + */ + Debug(DStack) + switch(pid = fork()) { + case -1: + return; + case 0: + kill(getpid(), SIGSTOP); + _exit(0); + default: + _backtrace(pid, btarg); + break; + } + +} diff --git a/cmd/wmii/bar.c b/cmd/wmii/bar.c index fd4ba26..26bcbe5 100644 --- a/cmd/wmii/bar.c +++ b/cmd/wmii/bar.c @@ -14,24 +14,25 @@ void bar_init(WMScreen *s) { WinAttr wa; - if(s->barwin) { - bar_resize(s); + if(s->barwin && (s->barwin->depth == 32) == s->barwin_rgba) return; - } s->brect = s->r; s->brect.min.y = s->brect.max.y - labelh(def.font); wa.override_redirect = 1; - wa.background_pixmap = ParentRelative; wa.event_mask = ExposureMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask; - s->barwin = createwindow(&scr.root, s->brect, scr.depth, InputOutput, - &wa, CWOverrideRedirect - | CWBackPixmap - | CWEventMask); + if(s->barwin_rgba) + s->barwin = createwindow_rgba(&scr.root, s->brect, + &wa, CWOverrideRedirect + | CWEventMask); + else + s->barwin = createwindow(&scr.root, s->brect, scr.depth, InputOutput, + &wa, CWOverrideRedirect + | CWEventMask); s->barwin->aux = s; xdnd_initwindow(s->barwin); sethandler(s->barwin, &handlers); @@ -93,12 +94,12 @@ bar_create(Bar **bp, const char *name) { b = emallocz(sizeof *b); b->id = id++; utflcpy(b->name, name, sizeof b->name); - b->col = def.normcolor; + b->colors = def.normcolor; + + strlcat(b->buf, b->colors.colstr, sizeof b->buf); + strlcat(b->buf, " ", sizeof b->buf); + strlcat(b->buf, b->text, sizeof b->buf); - strlcat(b->buf, b->col.colstr, sizeof(b->buf)); - strlcat(b->buf, " ", sizeof(b->buf)); - strlcat(b->buf, b->text, sizeof(b->buf)); - SET(i); for(sp=screens; (s = *sp); sp++) { i = bp - s->bar; @@ -130,6 +131,7 @@ bar_destroy(Bar **bp, Bar *b) { void bar_draw(WMScreen *s) { Bar *b, *tb, *largest, **pb; + Image *ibuf; Rectangle r; Align align; uint width, tw; @@ -139,6 +141,7 @@ bar_draw(WMScreen *s) { largest = nil; width = 0; + s->barwin_rgba = false; foreach_bar(s, b) { b->r.min = ZP; b->r.max.y = Dy(s->brect); @@ -146,6 +149,7 @@ bar_draw(WMScreen *s) { if(b->text && strlen(b->text)) b->r.max.x += textwidth(def.font, b->text); width += Dx(b->r); + s->barwin_rgba += RGBA_P(b->colors); } if(width > Dx(s->brect)) { /* Not enough room. Shrink bars until they all fit. */ @@ -173,51 +177,30 @@ bar_draw(WMScreen *s) { width += tw * shrink; } + if(s->bar[BRight]) + s->bar[BRight]->r.max.x += Dx(s->brect) - width; tb = nil; foreach_bar(s, b) { if(tb) b->r = rectaddpt(b->r, Pt(tb->r.max.x, 0)); - if(b == s->bar[BRight]) - b->r.max.x += Dx(s->brect) - width; tb = b; } + ibuf = s->barwin_rgba ? disp.ibuf32 : disp.ibuf; + r = rectsubpt(s->brect, s->brect.min); - fill(disp.ibuf, r, def.normcolor.bg); - border(disp.ibuf, r, 1, def.normcolor.border); + fill(ibuf, r, &def.normcolor.bg); + border(ibuf, r, 1, &def.normcolor.border); foreach_bar(s, b) { align = Center; if(b == s->bar[BRight]) align = East; - fill(disp.ibuf, b->r, b->col.bg); - drawstring(disp.ibuf, def.font, b->r, align, b->text, b->col.fg); - border(disp.ibuf, b->r, 1, b->col.border); + fillstring(ibuf, def.font, b->r, align, b->text, &b->colors, 1); } - copyimage(s->barwin, r, disp.ibuf, ZP); -} -void -bar_load(Bar *b) { - IxpMsg m; - char *p, *q; - - p = b->buf; - m = ixp_message(p, strlen(p), 0); - msg_parsecolors(&m, &b->col); - - q = (char*)m.end-1; - while(q >= (char*)m.pos && *q == '\n') - *q-- = '\0'; - - q = b->text; - utflcpy(q, (char*)m.pos, sizeof b->text); - - p[0] = '\0'; - strlcat(p, b->col.colstr, sizeof b->buf); - strlcat(p, " ", sizeof b->buf); - strlcat(p, b->text, sizeof b->buf); - - bar_draw(b->screen); + if(s->barwin_rgba != (s->barwin->depth == 32)) + bar_init(s); + copyimage(s->barwin, r, ibuf, ZP); } Bar* @@ -240,13 +223,13 @@ findbar(WMScreen *s, Point p) { Bar *b; foreach_bar(s, b) - if(rect_haspoint_p(p, b->r)) + if(rect_haspoint_p(b->r, p)) return b; return nil; } -static void -bdown_event(Window *w, XButtonPressedEvent *e) { +static bool +bdown_event(Window *w, void *aux, XButtonPressedEvent *e) { WMScreen *s; Bar *b; @@ -254,29 +237,31 @@ bdown_event(Window *w, XButtonPressedEvent *e) { XUngrabPointer(display, e->time); sync(); - s = w->aux; + s = aux; b = findbar(s, Pt(e->x, e->y)); if(b) event("%sBarMouseDown %d %s\n", barside[b->bar], e->button, b->name); + return false; } -static void -bup_event(Window *w, XButtonPressedEvent *e) { +static bool +bup_event(Window *w, void *aux, XButtonPressedEvent *e) { WMScreen *s; Bar *b; - - s = w->aux; + + s = aux; b = findbar(s, Pt(e->x, e->y)); if(b) event("%sBarClick %d %s\n", barside[b->bar], e->button, b->name); + return false; } static Rectangle -dndmotion_event(Window *w, Point p) { +dndmotion_event(Window *w, void *aux, Point p) { WMScreen *s; Bar *b; - s = w->aux; + s = aux; b = findbar(s, p); if(b) { event("%sBarDND 1 %s\n", barside[b->bar], b->name); @@ -285,10 +270,11 @@ dndmotion_event(Window *w, Point p) { return ZR; } -static void -expose_event(Window *w, XExposeEvent *e) { +static bool +expose_event(Window *w, void *aux, XExposeEvent *e) { USED(w, e); - bar_draw(w->aux); + bar_draw(aux); + return false; } static Handlers handlers = { diff --git a/cmd/wmii/client.c b/cmd/wmii/client.c index 5f82455..c119bd0 100644 --- a/cmd/wmii/client.c +++ b/cmd/wmii/client.c @@ -5,6 +5,7 @@ #include "dat.h" #include <ctype.h> #include <strings.h> +#include <signal.h> #include <X11/Xatom.h> #include "fns.h" @@ -23,7 +24,7 @@ enum { static Group* group; -static void +void group_init(Client *c) { Group *g; long *ret; @@ -53,12 +54,13 @@ group_init(Client *c) { g->ref++; } -static void +void group_remove(Client *c) { Group **gp; Group *g; g = c->group; + c->group = nil; if(g == nil) return; if(g->client == c) @@ -92,32 +94,23 @@ group_leader(Group *g) { Client* client_create(XWindow w, XWindowAttributes *wa) { Client **t, *c; - WinAttr fwa; - Point p; - Visual *vis; - int depth; + char **host = nil; + ulong *pid = nil; c = emallocz(sizeof *c); c->fullscreen = -1; c->border = wa->border_width; - c->r.min = Pt(wa->x, wa->y); - c->r.max = addpt(c->r.min, - Pt(wa->width, wa->height)); + c->r = rectsetorigin(Rect(0, 0, wa->width, wa->height), + Pt(wa->x, wa->y)); c->w.type = WWindow; + c->w.visual = wa->visual; c->w.xid = w; c->w.r = c->r; + c->w.aux = c; - depth = scr.depth; - vis = scr.visual; - /* XXX: Multihead. */ - c->ibuf = &ibuf; - if(render_argb_p(wa->visual)) { - depth = 32; - vis = render_visual; - c->ibuf = &ibuf32; - } + setborder(&c->w, 0, &(Color){0}); client_prop(c, xatom("WM_PROTOCOLS")); client_prop(c, xatom("WM_TRANSIENT_FOR")); @@ -127,43 +120,21 @@ client_create(XWindow w, XWindowAttributes *wa) { client_prop(c, xatom("WM_NAME")); client_prop(c, xatom("_MOTIF_WM_HINTS")); - XSetWindowBorderWidth(display, w, 0); - XAddToSaveSet(display, w); + gethostname(hostname, sizeof(hostname) - 1); + if(getprop_textlist(&c->w, "WM_CLIENT_MACHINE", &host) && + getprop_ulong(&c->w, Net("WM_PID"), "CARDINAL", 0, &pid, 1) && + !strcmp(hostname, *host)) + c->pid = (int)*pid; + freestringlist(host); + free(pid); - fwa.background_pixmap = None; - fwa.bit_gravity = NorthWestGravity; - fwa.border_pixel = 0; - fwa.colormap = XCreateColormap(display, scr.root.xid, vis, AllocNone); - fwa.event_mask = SubstructureRedirectMask - | SubstructureNotifyMask - | StructureNotifyMask - | ExposureMask - | EnterWindowMask - | PointerMotionMask - | ButtonPressMask - | ButtonReleaseMask; - fwa.override_redirect = true; - c->framewin = createwindow_visual(&scr.root, c->r, - depth, vis, InputOutput, - &fwa, CWBackPixmap - | CWBitGravity - /* These next two matter for ARGB windows. Donno why. */ - | CWBorderPixel - | CWColormap - | CWEventMask - | CWOverrideRedirect); - XFreeColormap(display, fwa.colormap); + c->rgba = render_argb_p(c->w.visual); + client_reparent(c); - c->framewin->aux = c; - c->w.aux = c; - sethandler(c->framewin, &framehandler); sethandler(&c->w, &handlers); selectinput(&c->w, ClientMask); - p.x = def.border; - p.y = labelh(def.font); - group_init(c); grab_button(c->framewin->xid, AnyButton, AnyModifier); @@ -176,14 +147,14 @@ client_create(XWindow w, XWindowAttributes *wa) { } - /* + /* * It's actually possible for a window to be destroyed * before we get a chance to reparent it. Check for that * now, because otherwise we'll wind up mapping a * perceptibly empty frame before it's destroyed. */ traperrors(true); - reparentwindow(&c->w, c->framewin, p); + XAddToSaveSet(display, w); if(traperrors(false)) { client_destroy(c); return nil; @@ -191,46 +162,115 @@ client_create(XWindow w, XWindowAttributes *wa) { ewmh_initclient(c); - event("CreateClient %C\n", c); + event("CreateClient %#C\n", c); client_manage(c); return c; } +void +client_reparent(Client *c) { + Window *fw; + WinAttr wa; + bool rgba; + + rgba = c->rgba | RGBA_P(def.normcolor) | RGBA_P(def.focuscolor); + + fw = c->framewin; + if(fw && (fw->depth == 32) == rgba) + return; + + wa.background_pixmap = None; + wa.bit_gravity = NorthWestGravity; + wa.event_mask = ButtonPressMask + | ButtonReleaseMask + | EnterWindowMask + | ExposureMask + | PointerMotionMask + | StructureNotifyMask + | SubstructureNotifyMask + | SubstructureRedirectMask; + wa.override_redirect = true; + if(rgba) + c->framewin = createwindow_rgba(&scr.root, c->r, + &wa, CWBackPixmap + | CWBitGravity + | CWEventMask + | CWOverrideRedirect); + else + c->framewin = createwindow(&scr.root, c->r, scr.depth, InputOutput, + &wa, CWBackPixmap + | CWBitGravity + | CWEventMask + | CWOverrideRedirect); + + c->framewin->aux = c; + sethandler(c->framewin, &framehandler); + reparentwindow(&c->w, c->framewin, ZP); + if(fw) + destroywindow(fw); +} + static bool apply_rules(Client *c) { + IxpMsg m; Rule *r; - - if(def.tagrules.string) - for(r=def.tagrules.rule; r; r=r->next) - if(regexec(r->regex, c->props, nil, 0)) - return client_applytags(c, r->value); - return false; + Ruleval *rv; + bool ret, more; + + ret = true; + more = true; + for(r=def.rules.rule; r && more; r=r->next) + if(regexec(r->regex, c->props, nil, 0)) { + more = false; + for(rv=r->values; rv; rv=rv->next) { + if(!strcmp(rv->key, "continue")) + more = true; + else if(!strcmp(rv->key, "tags")) + utflcpy(c->tags, rv->value, sizeof c->tags); + else if(!strcmp(rv->key, "force-tags")) { + utflcpy(c->tags, rv->value, sizeof c->tags); + ret = false; + }else { + bufclear(); + bufprint("%s %s", rv->key, rv->value); + m = ixp_message(buffer, _buf_end - buffer, MsgPack); + if(waserror()) + warning("processing rule %q=%q: %r", rv->key, rv->value); + else { + message_client(c, &m); + poperror(); + } + } + } + } + return ret; } void client_manage(Client *c) { Client *leader; - Frame *f; char *tags; - bool rules; + bool dotags; if(Dx(c->r) == Dx(screen->r)) if(Dy(c->r) == Dy(screen->r)) if(c->w.ewmh.type == 0) fullscreen(c, true, -1); - tags = getprop_string(&c->w, "_WMII_TAGS"); - rules = apply_rules(c); + dotags = apply_rules(c); - leader = win2client(c->trans); - if(leader == nil && c->group) - leader = group_leader(c->group); + if(!c->tags[0] || dotags) { + leader = win2client(c->trans); + if(leader == nil && c->group) + leader = group_leader(c->group); - if(tags) // && (!leader || leader == c || starting)) - utflcpy(c->tags, tags, sizeof c->tags); - else if(leader && !rules) - utflcpy(c->tags, leader->tags, sizeof c->tags); - free(tags); + tags = getprop_string(&c->w, "_WMII_TAGS"); + if(tags) + utflcpy(c->tags, tags, sizeof c->tags); + else if(leader) + utflcpy(c->tags, leader->tags, sizeof c->tags); + free(tags); + } if(c->tags[0]) client_applytags(c, c->tags); @@ -247,17 +287,17 @@ client_manage(Client *c) { && !client_viewframe(group_leader(c->group), c->sel->view); - f = c->sel; + /* f = c->sel; */ if(!(c->w.ewmh.type & TypeSplash)) - if(newgroup) { - /* XXX: Look over this. - if(f->area != f->view->sel) - f->view->oldsel = f->view->sel; - */ - }else { - frame_restack(c->sel, c->sel->area->sel); - view_restack(c->sel->view); - } + if(newgroup) { + /* XXX: Look over this. + if(f->area != f->view->sel) + f->view->oldsel = f->view->sel; + */ + }else { + frame_restack(c->sel, c->sel->area->sel); + view_restack(c->sel->view); + } } void @@ -278,11 +318,7 @@ client_destroy(Client *c) { r = client_grav(c, ZR); - hide = false; - if(!c->sel || c->sel->view != selview) - hide = true; - - XGrabServer(display); + hide = (!c->sel || c->sel->view != selview); /* In case the client is already destroyed. */ traperrors(true); @@ -293,29 +329,30 @@ client_destroy(Client *c) { else reparentwindow(&c->w, &scr.root, r.min); - if(starting > -1) + if(starting >= 0) XRemoveFromSaveSet(display, c->w.xid); - traperrors(false); - XUngrabServer(display); - none = nil; client_setviews(c, &none); - if(starting > -1) + if(starting >= 0) { client_unmap(c, WithdrawnState); + delproperty(&c->w, "_WMII_TAGS"); + } refree(&c->tagre); refree(&c->tagvre); free(c->retags); + traperrors(false); + destroywindow(c->framewin); ewmh_destroyclient(c); group_remove(c); - if(starting > -1) - event("DestroyClient %C\n", c); + if(starting >= 0) + event("DestroyClient %#C\n", c); - flushevents(FocusChangeMask, true); - free(c->w.hints); + event_flush(FocusChangeMask, true); + cleanupwindow(&c->w); free(c); } @@ -351,17 +388,13 @@ Cfmt(Fmt *f) { c = va_arg(f->args, Client*); if(c) - return fmtprint(f, "%W", &c->w); + if(f->flags & FmtSharp) + return fmtprint(f, "%W", &c->w); + else + return fmtprint(f, "%s", c->name); return fmtprint(f, "<nil>"); } -char* -clientname(Client *c) { - if(c) - return c->name; - return "<nil>"; -} - Rectangle client_grav(Client *c, Rectangle rd) { Rectangle r, cr; @@ -396,13 +429,15 @@ client_grav(Client *c, Rectangle rd) { bool client_floats_p(Client *c) { + if(c->floating == Never) + return false; return c->trans || c->floating || c->fixedsize || c->titleless || c->borderless || c->fullscreen >= 0 - || (c->w.ewmh.type & (TypeDialog|TypeSplash|TypeDock)); + || (c->w.ewmh.type & (TypeDialog|TypeSplash|TypeDock|TypeMenu|TypeToolbar)); } Frame* @@ -466,12 +501,12 @@ client_unmap(Client *c, int state) { } int -map_frame(Client *c) { +client_mapframe(Client *c) { return mapwin(c->framewin); } int -unmap_frame(Client *c) { +client_unmapframe(Client *c) { return unmapwin(c->framewin); } @@ -480,19 +515,15 @@ focus(Client *c, bool user) { View *v; Frame *f; - USED(user); - f = c->sel; - if(!f) - return; - /* - if(!user && c->noinput) - return; - */ - - v = f->view; - if(v != selview) - view_focus(screen, v); - frame_focus(c->sel); + Dprint(DFocus, "focus(%#C, %d)\n", c, user); + if(!c->nofocus || user) + if((f = c->sel)) { + v = f->view; + if(v != selview) + view_focus(screen, v); + frame_focus(c->sel); + view_restack(c->sel->view); + } } void @@ -503,26 +534,26 @@ client_focus(Client *c) { c->group->client = c; sync(); - flushevents(FocusChangeMask, true); + event_flush(FocusChangeMask, true); + + Dprint(DFocus, "client_focus([%#C]%C) collapsed=%s\n", + c, c, c && c->sel->collapsed ? "true" : "false"); + Dprint(DFocus, "\t[%#C]%C\n\t=> [%#C]%C\n", + disp.focus, disp.focus, c, c); - Dprint(DFocus, "client_focus([%C]%s)\n", c, clientname(c)); - Dprint(DFocus, "\t[%C]%s\n\t=> [%C]%s\n", - disp.focus, clientname(disp.focus), - c, clientname(c)); if(disp.focus != c) { - if(c) { + if(c && !c->sel->collapsed) { if(!c->noinput) setfocus(&c->w, RevertToParent); else if(c->proto & ProtoTakeFocus) { - xtime_kludge(); + event_updatextime(); client_message(c, "WM_TAKE_FOCUS", 0); } }else setfocus(screen->barwin, RevertToParent); - event("ClientFocus %C\n", c); sync(); - flushevents(FocusChangeMask, true); + event_flush(FocusChangeMask, true); } } @@ -535,7 +566,7 @@ client_resize(Client *c, Rectangle r) { if(f->view != selview) { client_unmap(c, IconicState); - unmap_frame(c); + client_unmapframe(c); return; } @@ -543,19 +574,20 @@ client_resize(Client *c, Rectangle r) { if(f->collapsed) { if(f->area->max && !resizing) - unmap_frame(c); + client_unmapframe(c); else { reshapewin(c->framewin, f->r); movewin(&c->w, f->crect.min); - map_frame(c); + client_mapframe(c); } client_unmap(c, IconicState); }else { client_map(c); reshapewin(c->framewin, f->r); reshapewin(&c->w, f->crect); - map_frame(c); - client_configure(c); + client_mapframe(c); + if(!eqrect(c->r, c->configr)) + client_configure(c); ewmh_framesize(c); } } @@ -573,37 +605,44 @@ client_setcursor(Client *c, Cursor cur) { void client_configure(Client *c) { - XConfigureEvent e; Rectangle r; + c->configr = c->r; r = rectsubpt(c->r, Pt(c->border, c->border)); - e.type = ConfigureNotify; - e.event = c->w.xid; - e.window = c->w.xid; - e.above = None; - e.override_redirect = false; - - e.x = r.min.x; - e.y = r.min.y; - e.width = Dx(r); - e.height = Dy(r); - e.border_width = c->border; - - sendevent(&c->w, false, StructureNotifyMask, (XEvent*)&e); + sendevent(&c->w, false, StructureNotifyMask, + &(XConfigureEvent) { + .type = ConfigureNotify, + .event = c->w.xid, + .window = c->w.xid, + + .x = r.min.x, + .y = r.min.y, + .width = Dx(r), + .height = Dy(r), + .border_width = c->border, + }); } void client_message(Client *c, char *msg, long l2) { - sendmessage(&c->w, "WM_PROTOCOLS", xatom(msg), xtime, l2, 0, 0); + sendmessage(&c->w, "WM_PROTOCOLS", xatom(msg), event_xtime, l2, 0, 0); } void client_kill(Client *c, bool nice) { - if(nice && (c->proto & ProtoDelete)) { + + if(!nice) { + if(c->pid) + kill(c->pid, SIGKILL); + XKillClient(display, c->w.xid); + } + else if(c->proto & ProtoDelete) { + c->dead = 1; client_message(c, "WM_DELETE_WINDOW", 0); - ewmh_pingclient(c); - }else + ewmh_checkresponsive(c); + } + else XKillClient(display, c->w.xid); } @@ -618,8 +657,7 @@ fullscreen(Client *c, int fullscreen, long screen) { if(fullscreen == (c->fullscreen >= 0)) return; - event("Fullscreen %C %s\n", c, (fullscreen ? "on" : "off")); - ewmh_updatestate(c); + event("Fullscreen %#C %s\n", c, (fullscreen ? "on" : "off")); c->fullscreen = -1; if(!fullscreen) @@ -654,15 +692,14 @@ fullscreen(Client *c, int fullscreen, long screen) { if((f = c->sel)) view_update(f->view); } + ewmh_updatestate(c); } void client_seturgent(Client *c, int urgent, int from) { XWMHints *wmh; char *cfrom, *cnot; - Frame *f, *ff; - Area *a; - int s; + Frame *f; if(urgent == Toggle) urgent = c->urgent ^ On; @@ -671,22 +708,14 @@ client_seturgent(Client *c, int urgent, int from) { cnot = (urgent ? "" : "Not"); if(urgent != c->urgent) { - event("%sUrgent %C %s\n", cnot, c, cfrom); + event("%sUrgent %#C %s\n", cnot, c, cfrom); c->urgent = urgent; ewmh_updatestate(c); - if(c->sel) { - if(c->sel->view == selview) - frame_draw(c->sel); - for(f=c->frame; f; f=f->cnext) { - SET(ff); - if(!urgent) - foreach_frame(f->view, s, a, ff) - if(ff->client->urgent) break; - if(urgent || ff == nil) - event("%sUrgentTag %s %s\n", - cnot, cfrom, f->view->name); - } - } + if(c->sel) + frame_draw(c->sel); + + for(f=c->frame; f; f=f->cnext) + view_update_urgency(f->view, cfrom); } if(from == UrgManager) { @@ -705,16 +734,8 @@ client_seturgent(Client *c, int urgent, int from) { /* X11 stuff */ void update_class(Client *c) { - char *str; - str = utfrune(c->props, L':'); - if(str) - str = utfrune(str+1, L':'); - if(str == nil) { - strcpy(c->props, "::"); - str = c->props + 1; - } - utflcpy(str+1, c->name, sizeof c->props); + snprint(c->props, sizeof c->props, "%s:%s", c->class, c->name); } static void @@ -722,13 +743,10 @@ client_updatename(Client *c) { char *str; c->name[0] = '\0'; - - str = getprop_string(&c->w, "_NET_WM_NAME"); - if(str == nil) - str = getprop_string(&c->w, "WM_NAME"); - if(str) + if((str = windowname(&c->w))) { utflcpy(c->name, str, sizeof c->name); - free(str); + free(str); + } update_class(c); if(c->sel) @@ -776,7 +794,7 @@ updatemwm(Client *c) { } free(ret); - if(c->sel && false) { + if(false && c->sel) { c->sel->floatr = client_grav(c, r); if(c->sel->area->floating) { client_resize(c, c->sel->floatr); @@ -785,7 +803,7 @@ updatemwm(Client *c) { } } -void +bool client_prop(Client *c, Atom a) { WinHints h; XWMHints *wmh; @@ -803,8 +821,7 @@ client_prop(Client *c, Atom a) { else switch (a) { default: - ewmh_prop(c, a); - break; + return true; case XA_WM_TRANSIENT_FOR: XGetTransientForHint(display, c->w.xid, &c->trans); break; @@ -812,12 +829,12 @@ client_prop(Client *c, Atom a) { memset(&h, 0, sizeof h); if(c->w.hints) bcopy(c->w.hints, &h, sizeof h); - sethints(&c->w); + gethints(&c->w); if(c->w.hints) c->fixedsize = eqpt(c->w.hints->min, c->w.hints->max); if(memcmp(&h, c->w.hints, sizeof h)) - if(c->sel) - view_update(c->sel->view); + if(c->sel) + view_update(c->sel->view); break; case XA_WM_HINTS: wmh = XGetWMHints(display, c->w.xid); @@ -829,9 +846,9 @@ client_prop(Client *c, Atom a) { break; case XA_WM_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>")); + snprint(c->class, sizeof c->class, "%s:%s", + (n > 0 ? class[0] : "<nil>"), + (n > 1 ? class[1] : "<nil>")); freestringlist(class); update_class(c); break; @@ -840,15 +857,16 @@ client_prop(Client *c, Atom a) { client_updatename(c); break; } + return false; } /* Handlers */ -static void -configreq_event(Window *w, XConfigureRequestEvent *e) { - Rectangle r, cr; +static bool +configreq_event(Window *w, void *aux, XConfigureRequestEvent *e) { + Rectangle r; Client *c; - c = w->aux; + c = aux; r = client_grav(c, ZR); r.max = subpt(r.max, r.min); @@ -866,45 +884,47 @@ configreq_event(Window *w, XConfigureRequestEvent *e) { c->border = e->border_width; r.max = addpt(r.min, r.max); - cr = r; r = client_grav(c, r); - if(c->sel->area->floating) { + if(c->sel->area->floating) client_resize(c, r); - }else { + else { c->sel->floatr = r; client_configure(c); } + return false; } -static void -destroy_event(Window *w, XDestroyWindowEvent *e) { +static bool +destroy_event(Window *w, void *aux, XDestroyWindowEvent *e) { USED(w, e); - client_destroy(w->aux); + client_destroy(aux); + return false; } -static void -enter_event(Window *w, XCrossingEvent *e) { +static bool +enter_event(Window *w, void *aux, XCrossingEvent *e) { Client *c; - - c = w->aux; + + c = aux; if(e->detail != NotifyInferior) { if(e->detail != NotifyVirtual) - if(e->serial != ignoreenter && disp.focus != c) { - Dprint(DFocus, "enter_notify([%C]%s)\n", c, c->name); + if(e->serial > event_lastconfigure && disp.focus != c) { + Dprint(DFocus, "enter_notify([%#C]%s)\n", c, c->name); focus(c, false); } client_setcursor(c, cursor[CurNormal]); }else - Dprint(DFocus, "enter_notify(%C[NotifyInferior]%s)\n", c, c->name); + Dprint(DFocus, "enter_notify(%#C[NotifyInferior]%s)\n", c, c->name); + return false; } -static void -focusin_event(Window *w, XFocusChangeEvent *e) { +static bool +focusin_event(Window *w, void *aux, XFocusChangeEvent *e) { Client *c, *old; - c = w->aux; + c = aux; print_focus("focusin_event", c, c->name); @@ -914,16 +934,18 @@ focusin_event(Window *w, XFocusChangeEvent *e) { old = disp.focus; disp.focus = c; if(c != old) { + event("ClientFocus %#C\n", c); if(c->sel) frame_draw(c->sel); } + return false; } -static void -focusout_event(Window *w, XFocusChangeEvent *e) { +static bool +focusout_event(Window *w, void *aux, XFocusChangeEvent *e) { Client *c; - c = w->aux; + c = aux; if((e->mode == NotifyWhileGrabbed) && (disp.hasgrab != &c_root)) { if(disp.focus) disp.hasgrab = disp.focus; @@ -933,38 +955,39 @@ focusout_event(Window *w, XFocusChangeEvent *e) { if(c->sel) frame_draw(c->sel); } + return false; } -static void -unmap_event(Window *w, XUnmapEvent *e) { +static bool +unmap_event(Window *w, void *aux, XUnmapEvent *e) { Client *c; - - c = w->aux; - if(!e->send_event) - c->unmapped--; - client_destroy(c); + + c = aux; + if(!e->send_event && w->parent != c->framewin) + c->w.unmapped++; + if(e->send_event || c->w.unmapped < 0) + client_destroy(c); + return false; } -static void -map_event(Window *w, XMapEvent *e) { +static bool +map_event(Window *w, void *aux, XMapEvent *e) { Client *c; USED(e); - - c = w->aux; + + c = aux; if(c == selclient()) client_focus(c); + return true; } -static void -property_event(Window *w, XPropertyEvent *e) { - Client *c; +static bool +property_event(Window *w, void *aux, XPropertyEvent *e) { if(e->state == PropertyDelete) /* FIXME */ - return; - - c = w->aux; - client_prop(c, e->atom); + return true; + return client_prop(aux, e->atom); } static Handlers handlers = { @@ -1004,6 +1027,7 @@ client_setviews(Client *c, char **tags) { if(*tags) { if(!*fp || cmp > 0) { f = frame_create(c, view_create(*tags)); + Dprint(DGeneric, "%#C %p %R %R %R %C\n", c, c->sel, c->r, f->floatr, c->sel ? c->sel->floatr : ZR, c); if(f->view == selview || !c->sel) c->sel = f; kludge = c; /* FIXME */ @@ -1030,7 +1054,7 @@ bsstrcmp(const void *a, const void *b) { static int strpcmp(const void *ap, const void *bp) { char **a, **b; - + a = (char**)ap; b = (char**)bp; return strcmp(*a, *b); @@ -1044,10 +1068,10 @@ static char *badtags[] = { char* client_extratags(Client *c) { + Fmt fmt; Frame *f; char *toks[32]; char **tags; - char *s, *s2; int i; i = 0; @@ -1058,137 +1082,92 @@ client_extratags(Client *c) { toks[i] = nil; tags = comm(CLeft, toks, c->retags); - s = nil; + if(i == 1 && !c->tagre.regex && !c->tagvre.regex) { + free(tags); + return nil; + } + + fmtstrinit(&fmt); if(i > 1) - s = join(tags, "+"); + join(tags, "+", &fmt); free(tags); - if(!c->tagre.regex && !c->tagvre.regex) - return s; - if(c->tagre.regex) { - s2 = s; - s = smprint("%s+/%s/", s ? s : "", c->tagre.regex); - free(s2); - } - if(c->tagvre.regex) { - s2 = s; - s = smprint("%s-/%s/", s ? s : "", c->tagvre.regex); - free(s2); - } - return s; + if(c->tagre.regex) + fmtprint(&fmt, "+/%s/", c->tagre.regex); + if(c->tagvre.regex) + fmtprint(&fmt, "-/%s/", c->tagvre.regex); + return fmtstrflush(&fmt); } bool client_applytags(Client *c, const char *tags) { - uint i, j, k, n; - bool add, found; - char buf[512], last; + Fmt fmt; + uint i, j, k; + char buf[512]; char *toks[32]; char **p; char *cur, *s; + int add, old; buf[0] = 0; - - for(n = 0; tags[n]; n++) - if(!isspace(tags[n])) - break; - - if(tags[n] == '+' || tags[n] == '-') + if(memchr("+-^", tags[0], 4)) utflcpy(buf, c->tags, sizeof c->tags); else { refree(&c->tagre); refree(&c->tagvre); } - strlcat(buf, &tags[n], sizeof buf); - - n = 0; - add = true; - if(buf[0] == '+') - n++; - else if(buf[0] == '-') { - n++; - add = false; - } - - found = false; + strlcat(buf, tags, sizeof buf); j = 0; - while(buf[n] && n < sizeof(buf) && j < 32) { + s = buf; + old = '+'; + while((cur = mask(&s, &add, &old))) { /* Check for regex. */ - if(buf[n] == '/') { - for(i=n+1; i < sizeof(buf) - 1; i++) - if(buf[i] == '/') break; - if(buf[i] == '/') { - i++; - if(buf[i] == '+' - || buf[i] == '-' - || buf[i] == '\0') { /* Don't be lenient */ - buf[i-1] = '\0'; - if(add) - reinit(&c->tagre, buf+n+1); - else - reinit(&c->tagvre, buf+n+1); - last = buf[i]; - buf[i] = '\0'; - - found = true; - goto next; - } - } + if(cur[0] == '/') { + cur++; + *strrchr(cur, '/') = '\0'; + if(add == '+') + reinit(&c->tagre, cur); + else if(add == '-') + reinit(&c->tagvre, cur); } - - for(i = n; i < sizeof(buf) - 1; i++) - if(buf[i] == '+' - || buf[i] == '-' - || buf[i] == '\0') - break; - last = buf[i]; - buf[i] = '\0'; - - trim(buf+n, " \t/"); - - cur = nil; - if(!strcmp(buf+n, "~")) - c->floating = add; - else - if(!strcmp(buf+n, "!") || !strcmp(buf+n, "sel")) - cur = selview->name; - else - if(!Mbsearch(buf+n, badtags, bsstrcmp)) - cur = buf+n; - - if(cur && j < nelem(toks)-1) { - if(add) { - found = true; - toks[j++] = cur; - }else { - for(i = 0, k = 0; i < j; i++) - if(strcmp(toks[i], cur)) - toks[k++] = toks[i]; - j = k; + else if(!strcmp(cur, "~")) + c->floating = add ? On : Never; + else { + trim(cur, " \t\r\n"); + if(!strcmp(cur, "sel")) + cur = selview->name; + else if(Mbsearch(cur, badtags, bsstrcmp)) + continue; + + if(j < nelem(toks)-1) { + if(add == '^') + add = bsearch(cur, toks, j, sizeof *toks, bsstrcmp) ? '-' : '+'; + if(add == '+') + toks[j++] = cur; + else { + for(i = 0, k = 0; i < j; i++) + if(strcmp(toks[i], cur)) + toks[k++] = toks[i]; + j = k; + } } } - - next: - n = i + 1; - if(last == '+') - add = true; - if(last == '-') - add = false; - if(last == '\0') - break; } toks[j] = nil; qsort(toks, j, sizeof *toks, strpcmp); uniq(toks); - s = join(toks, "+"); - utflcpy(c->tags, s, sizeof c->tags); + fmtstrinit(&fmt); + join(toks, "+", &fmt); if(c->tagre.regex) - strlcatprint(c->tags, sizeof c->tags, "+/%s/", c->tagre.regex); + fmtprint(&fmt, "+/%s/", c->tagre.regex); if(c->tagvre.regex) - strlcatprint(c->tags, sizeof c->tags, "-/%s/", c->tagvre.regex); + fmtprint(&fmt, "-/%s/", c->tagvre.regex); + + s = fmtstrflush(&fmt); + utflcpy(c->tags, s, sizeof c->tags); changeprop_string(&c->w, "_WMII_TAGS", c->tags); free(s); @@ -1207,6 +1186,6 @@ client_applytags(Client *c, const char *tags) { p = comm(~0, c->retags, toks); client_setviews(c, p); free(p); - return found; + return true; } diff --git a/cmd/wmii/column.c b/cmd/wmii/column.c index e94f6a9..098e964 100644 --- a/cmd/wmii/column.c +++ b/cmd/wmii/column.c @@ -17,8 +17,8 @@ char *modes[] = { bool column_setmode(Area *a, const char *mode) { - char *str, *tok, *orig; - char add, old; + char *str, *tok; + int add, old; /* * The mapping between the current internal @@ -27,50 +27,36 @@ column_setmode(Area *a, const char *mode) { * change. */ - orig = strdup(mode); - str = orig; - old = '\0'; - while(*(tok = str)) { - add = old; - while((old=*str) && !strchr("+-^", old)) - str++; - *str = '\0'; - if(str > tok) { - print("'%s' %c\n", tok, add); - if(!strcmp(tok, "max")) { - if(add == '\0' || add == '+') - a->max = true; - else if(add == '-') - a->max = false; - else - a->max = !a->max; - }else - if(!strcmp(tok, "stack")) { - if(add == '\0' || add == '+') - a->mode = Colstack; - else if(add == '-') - a->mode = Coldefault; - else - a->mode = a->mode == Colstack ? Coldefault : Colstack; - }else - if(!strcmp(tok, "default")) { - if(add == '\0' || add == '+') { - a->mode = Coldefault; - column_arrange(a, true); - }else if(add == '-') - a->mode = Colstack; - else - a->mode = a->mode == Coldefault ? Colstack : Coldefault; - }else { - free(orig); - return false; - } - } - if(old) - str++; - + str = freelater(estrdup(mode)); + old = '+'; + while((tok = mask(&str, &add, &old))) { + if(!strcmp(tok, "max")) { + if(add == '\0' || add == '+') + a->max = true; + else if(add == '-') + a->max = false; + else + a->max = !a->max; + }else + if(!strcmp(tok, "stack")) { + if(add == '\0' || add == '+') + a->mode = Colstack; + else if(add == '-') + a->mode = Coldefault; + else + a->mode = a->mode == Colstack ? Coldefault : Colstack; + }else + if(!strcmp(tok, "default")) { + if(add == '\0' || add == '+') { + a->mode = Coldefault; + column_arrange(a, true); + }else if(add == '-') + a->mode = Colstack; + else + a->mode = a->mode == Coldefault ? Colstack : Coldefault; + }else + return false; } - free(orig); return true; } @@ -86,6 +72,18 @@ column_minwidth(void) return 4 * labelh(def.font); } +static void +columns_update(View *v) { + Area *a; + Frame *f; + int s; + + foreach_frame(v, s, a, f) { + f->screen = s; + f->column = area_idx(a); + } +} + Area* column_new(View *v, Area *pos, int scrn, uint w) { Area *a; @@ -98,6 +96,7 @@ column_new(View *v, Area *pos, int scrn, uint w) { return nil; view_arrange(v); + columns_update(v); view_update(v); #endif } @@ -106,7 +105,8 @@ void column_insert(Area *a, Frame *f, Frame *pos) { f->area = a; - f->client->floating = false; + if(f->client->floating == On) + f->client->floating = Off; f->screen = a->screen; f->column = area_idx(a); frame_insert(f, pos); @@ -114,140 +114,13 @@ column_insert(Area *a, Frame *f, Frame *pos) { area_setsel(a, f); } -/* Temporary. */ -static void -stack_scale(Frame *first, int height) { - Frame *f; - Area *a; - uint dy; - int surplus; - - a = first->area; - - /* - * Will need something like this. - column_fit(a, &ncol, &nuncol); - */ - - dy = 0; - for(f=first; f && !f->collapsed; f=f->anext) - dy += Dy(f->colr); - - /* Distribute the surplus. - */ - surplus = height - dy; - for(f=first; f && !f->collapsed; f=f->anext) - f->colr.max.y += ((float)Dy(f->r) / dy) * surplus; -} - -static void -stack_info(Frame *f, Frame **firstp, Frame **lastp, int *dyp, int *nframep) { - Frame *ft, *first, *last; - int dy, nframe; - - nframe = 0; - dy = 0; - first = f; - last = f; - - for(ft=f; ft && ft->collapsed; ft=ft->anext) - ; - if(ft && ft != f) { - f = ft; - dy += Dy(f->colr); - } - for(ft=f; ft && !ft->collapsed; ft=ft->aprev) { - first = ft; - nframe++; - dy += Dy(ft->colr); - } - for(ft=f->anext; ft && !ft->collapsed; ft=ft->anext) { - if(first == nil) - first = ft; - last = ft; - nframe++; - dy += Dy(ft->colr); - } - if(nframep) *nframep = nframe; - if(firstp) *firstp = first; - if(lastp) *lastp = last; - if(dyp) *dyp = dy; -} - -int -stack_count(Frame *f, int *mp) { - Frame *fp; - int n, m; - - n = 0; - for(fp=f->aprev; fp && fp->collapsed; fp=fp->aprev) - n++; - m = ++n; - for(fp=f->anext; fp && fp->collapsed; fp=fp->anext) - n++; - if(mp) *mp = m; - return n; -} - -Frame* -stack_find(Area *a, Frame *f, int dir, bool stack) { - Frame *fp; - - switch (dir) { - default: - die("not reached"); - case North: - if(f) - for(f=f->aprev; f && f->collapsed && stack; f=f->aprev) - ; - else { - f = nil; - for(fp=a->frame; fp; fp=fp->anext) - if(!fp->collapsed || !stack) - f = fp; - } - break; - case South: - if(f) - for(f=f->anext; f && f->collapsed && stack; f=f->anext) - ; - else - for(f=a->frame; f && f->collapsed && stack; f=f->anext) - ; - break; - } - return f; -} - -/* TODO: Move elsewhere. */ -bool -find(Area **ap, Frame **fp, int dir, bool wrap, bool stack) { - Rectangle r; - Frame *f; - Area *a; +void +column_destroy(Area *a) { + View *v; - f = *fp; - a = *ap; - r = f ? f->r : a->r; - - if(dir == North || dir == South) { - *fp = stack_find(a, f, dir, stack); - if(*fp) - return true; - if (!a->floating) - *ap = area_find(a->view, r, dir, wrap); - if(!*ap) - return false; - *fp = stack_find(*ap, *fp, dir, stack); - return true; - } - if(dir != East && dir != West) - die("not reached"); - *ap = area_find(a->view, r, dir, wrap); - if(!*ap) - return false; - *fp = ap[0]->sel; - return true; + v = a->view; + area_destroy(a); + columns_update(v); } void @@ -284,7 +157,7 @@ column_detach(Frame *f) { stack_scale(first, dy); column_arrange(a, false); }else if(a->view->areas[a->screen]->next) - area_destroy(a); + column_destroy(a); } static void column_scale(Area*); @@ -292,14 +165,15 @@ static void column_scale(Area*); void column_attachrect(Area *a, Frame *f, Rectangle r) { Frame *fp, *pos; - int before, after; pos = nil; for(fp=a->frame; fp; pos=fp, fp=fp->anext) { if(r.max.y < fp->r.min.y || r.min.y > fp->r.max.y) continue; + /* before = fp->r.min.y - r.min.y; after = -fp->r.max.y + r.max.y; + */ } column_insert(a, f, pos); column_resizeframe_h(f, r); @@ -443,12 +317,12 @@ column_settle(Area *a) { if(n_uncol == 0) { fprint(2, "%s: Badness: No uncollapsed frames, column %d, view %q\n", - argv0, area_idx(a), a->view->name); + argv0, area_idx(a), a->view->name); return; } if(surplus < 0) fprint(2, "%s: Badness: surplus = %d in column_settle, column %d, view %q\n", - argv0, surplus, area_idx(a), a->view->name); + argv0, surplus, area_idx(a), a->view->name); yoff = a->r.min.y; yoffcr = yoff; @@ -497,7 +371,7 @@ comp_frame(const void *a, const void *b) { ia = foo(*(Frame**)a); ib = foo(*(Frame**)b); - /* + /* * I'd like to favor the selected client, but * it causes windows to jump as focus changes. */ @@ -725,10 +599,14 @@ column_resizeframe(Frame *f, Rectangle r) { if(al) { al->r.max.x = a->r.min.x; column_arrange(al, false); + }else { + v->pad[a->screen].min.x = r.min.x - v->r[a->screen].min.x; } if(ar) { ar->r.min.x = a->r.max.x; column_arrange(ar, false); + }else { + v->pad[a->screen].max.x = r.max.x - v->r[a->screen].max.x; } column_resizeframe_h(f, r); diff --git a/cmd/wmii/dat.h b/cmd/wmii/dat.h index 8038026..1b32f9a 100644 --- a/cmd/wmii/dat.h +++ b/cmd/wmii/dat.h @@ -3,7 +3,6 @@ */ #define _XOPEN_SOURCE 600 -#define IXP_P9_STRUCTS #define IXP_NO_P9_ #include <assert.h> #include <regexp9.h> @@ -11,25 +10,39 @@ #include <stdint.h> #include <stdlib.h> #include <string.h> -#include <ixp.h> -#include <util.h> +#include <unistd.h> +#include <limits.h> #include <utf.h> -#include <fmt.h> -#include <x11.h> +#include <ixp.h> +#include <stuff/x.h> +#include <stuff/util.h> +#include "debug.h" -#define FONT "-*-fixed-medium-r-*-*-13-*-*-*-*-*-*-*" -#define FOCUSCOLORS "#ffffff #335577 #447799" -#define NORMCOLORS "#222222 #eeeeee #666666" +#define FONT "fixed" +#define FOCUSCOLORS "#000000 #81654f #000000" +#define NORMCOLORS "#000000 #c1c48b #81654f" + +/* From CGO */ +#define assert_equal(x, y) typedef char _##x##_does_not_equal_##y[((x)-(y))*((x)-(y))*-2+1] + +enum Barpos { + BBottom, + BTop, +}; enum { - PingTime = 10000, + Coldefault, Colstack, Colmax, Collast }; enum { - CLeft = 1<<0, - CCenter = 1<<1, - CRight = 1<<2, + CurNormal, + CurNECorner, CurNWCorner, CurSECorner, CurSWCorner, + CurDHArrow, CurDVArrow, CurMove, CurInput, CurSizing, + CurTCross, CurIcon, + CurNone, + CurLast, }; +Cursor cursor[CurLast]; enum IncMode { IIgnore, @@ -38,12 +51,33 @@ enum IncMode { }; enum { - GInvert = 1<<0, + PDesktop, + PExtents, + PMonitors = PExtents + 4, + PState = PMonitors + 4, + PLast = PState + 3 +}; + +enum ClientPermission { + PermActivate = 1<<0, }; enum { - UrgManager, - UrgClient, + PingTime = 10000, + PingPeriod = 4000, + PingPartition = 10, +}; + +enum Protocols { + ProtoDelete = 1<<0, + ProtoTakeFocus = 1<<1, + ProtoPing = 1<<2, +}; + +enum { + SourceUnknown, + SourceClient, + SourcePager }; enum EWMHType { @@ -58,57 +92,35 @@ enum EWMHType { }; enum { - Coldefault, Colstack, Colmax, Collast + UrgManager, + UrgClient, }; extern char* modes[]; +#define toggle(val, x) \ + ((val) = ((x) == On ? true : \ + (x) == Off ? false : \ + (x) == Toggle ? !(val) : (val))) #define TOGGLE(x) \ - (x == On ? "on" : \ - x == Off ? "off" : \ - x == Toggle ? "toggle" : \ - "<toggle>") + ((x) == On ? "on" : \ + (x) == Off ? "off" : \ + (x) == Toggle ? "toggle" : "<toggle>") enum { + Never = -1, Off, On, + /* Xlib defines this. :( */ + // Always, Toggle, }; -enum Barpos { - BBottom, - BTop, -}; - -enum { - CurNormal, - CurNECorner, CurNWCorner, CurSECorner, CurSWCorner, - CurDHArrow, CurDVArrow, CurMove, CurInput, CurSizing, - CurTCross, CurIcon, - CurNone, - CurLast, -}; +assert_equal(Always, 2); enum { NCOL = 16, }; -enum Protocols { - ProtoDelete = 1<<0, - ProtoTakeFocus = 1<<1, - ProtoPing = 1<<2, -}; - -enum DebugOpt { - D9p = 1<<0, - DDnd = 1<<1, - DEvent = 1<<2, - DEwmh = 1<<3, - DFocus = 1<<4, - DGeneric= 1<<5, - DStack = 1<<6, - NDebugOpt = 7, -}; - /* Data Structures */ typedef struct Area Area; typedef struct Bar Bar; @@ -117,11 +129,9 @@ typedef struct Divide Divide; typedef struct Frame Frame; typedef struct Group Group; typedef struct Key Key; -typedef struct Map Map; -typedef struct MapEnt MapEnt; -typedef struct Regex Regex; typedef struct Rule Rule; typedef struct Ruleset Ruleset; +typedef struct Ruleval Ruleval; typedef struct Strut Strut; typedef struct View View; typedef struct WMScreen WMScreen; @@ -151,44 +161,46 @@ struct Bar { char name[256]; int bar; ushort id; - CTuple col; + CTuple colors; Rectangle r; WMScreen* screen; }; -struct Regex { - char* regex; - Reprog* regc; -}; - struct Client { Client* next; Frame* frame; Frame* sel; Window w; Window* framewin; - Image** ibuf; XWindow trans; Regex tagre; Regex tagvre; Group* group; Strut* strut; Cursor cursor; + Rectangle configr; Rectangle r; char** retags; + char class[256]; char name[256]; - char tags[256]; char props[512]; + char tags[256]; + char proplen[PLast]; + long propcache[PLast]; + long permission; long proto; - uint border; + int border; + int dead; + int floating; int fullscreen; - int unmapped; - bool floating; - bool fixedsize; - bool urgent; + int pid; bool borderless; - bool titleless; + bool fixedsize; + bool nofocus; bool noinput; + bool rgba; + bool titleless; + bool urgent; }; struct Divide { @@ -229,7 +241,7 @@ struct Frame { struct Group { Group* next; XWindow leader; - Client *client; + Client* client; int ref; }; @@ -243,16 +255,11 @@ struct Key { KeyCode key; }; -struct Map { - MapEnt**bucket; - uint nhash; -}; - struct Rule { - Rule* next; - Reprog* regex; - char value[256]; - + Rule* next; + Reprog* regex; + char* value; + Ruleval* values; }; struct Ruleset { @@ -261,6 +268,12 @@ struct Ruleset { uint size; }; +struct Ruleval { + Ruleval* next; + char* key; + char* value; +}; + struct Strut { Rectangle left; Rectangle right; @@ -282,42 +295,26 @@ struct View { int selcol; int selscreen; bool dead; + bool urgent; Rectangle *r; Rectangle *pad; }; -/* Yuck. */ -#define VECTOR(type, nam, c) \ -typedef struct Vector_##nam Vector_##nam; \ -struct Vector_##nam { \ - type* ary; \ - long n; \ - long size; \ -}; \ -void vector_##c##free(Vector_##nam*); \ -void vector_##c##init(Vector_##nam*); \ -void vector_##c##push(Vector_##nam*, type); \ - -VECTOR(long, long, l) -VECTOR(Rectangle, rect, r) -VECTOR(void*, ptr, p) -#undef VECTOR - #ifndef EXTERN # define EXTERN extern #endif /* global variables */ -EXTERN struct { +typedef struct Defs Defs; +EXTERN struct Defs { CTuple focuscolor; CTuple normcolor; Font* font; char* keys; uint keyssz; - Ruleset tagrules; Ruleset colrules; - char grabmod[5]; - ulong mod; + Ruleset rules; + long mod; uint border; uint snap; int colmode; @@ -328,11 +325,10 @@ enum { BLeft, BRight }; -#define BLOCK(x) do { x; }while(0) - EXTERN struct WMScreen { Bar* bar[2]; Window* barwin; + bool barwin_rgba; bool showing; int barpos; int idx; @@ -350,55 +346,33 @@ EXTERN struct { bool sel; } disp; -EXTERN Client* client; -EXTERN View* view; -EXTERN View* selview; -EXTERN Key* key; -EXTERN Divide* divs; EXTERN Client c_magic; EXTERN Client c_root; +EXTERN Client* client; +EXTERN Divide* divs; +EXTERN Key* key; +EXTERN View* selview; +EXTERN View* view; 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; EXTERN Ixp9Srv p9srv; /* X11 */ -EXTERN uint valid_mask; EXTERN uint numlock_mask; -EXTERN Image* ibuf; -EXTERN Image* ibuf32; - -EXTERN Cursor cursor[CurLast]; - -typedef void (*XHandler)(XEvent*); -EXTERN XHandler handler[LASTEvent]; +EXTERN uint valid_mask; /* Misc */ -EXTERN int starting; -EXTERN bool resizing; +EXTERN char* execstr; +EXTERN char hostname[HOST_NAME_MAX + 1]; EXTERN long ignoreenter; +EXTERN bool resizing; +EXTERN int starting; EXTERN char* user; -EXTERN char* execstr; -EXTERN int debugflag; -EXTERN int debugfile; -EXTERN long xtime; -EXTERN Visual* render_visual; EXTERN Client* kludge; extern char* debugtab[]; -#define Debug(x) if(((debugflag|debugfile)&(x)) && setdebug(x)) -#define Dprint(x, ...) BLOCK( if((debugflag|debugfile)&(x)) debug(x, __VA_ARGS__) ) - diff --git a/cmd/wmii/debug.h b/cmd/wmii/debug.h new file mode 100644 index 0000000..b447c93 --- /dev/null +++ b/cmd/wmii/debug.h @@ -0,0 +1,24 @@ +#include <stdbool.h> + +enum DebugOpt { + D9p = 1<<0, + DDnd = 1<<1, + DEvent = 1<<2, + DEvents = 1<<3, + DEwmh = 1<<4, + DFocus = 1<<5, + DGeneric= 1<<6, + DStack = 1<<7, + NDebugOpt = 8, +}; + +#define Debug(x) if(((debugflag|debugfile)&(x)) && setdebug(x)) +#define Dprint(x, ...) BLOCK( if((debugflag|debugfile)&(x)) debug(x, __VA_ARGS__) ) + +void debug(int, const char*, ...); +void dwrite(int, void*, int, bool); +bool setdebug(int); +void vdebug(int, const char*, va_list); + +long debugflag; +long debugfile; diff --git a/cmd/wmii/div.c b/cmd/wmii/div.c index 986d6a2..0ad544f 100644 --- a/cmd/wmii/div.c +++ b/cmd/wmii/div.c @@ -86,15 +86,15 @@ drawimg(Image *img, Color cbg, Color cborder, Divide *d) { start = d->left ? 0 : n/2; n = d->right && d->left ? n : n/2; - fillpoly(img, pt + start, n, cbg); - drawpoly(img, pt + start, n, CapNotLast, 1, cborder); + fillpoly(img, pt + start, n, &cbg); + drawpoly(img, pt + start, n, CapNotLast, 1, &cborder); } static void drawdiv(Divide *d) { - fill(divmask, divmask->r, (Color){0}); - drawimg(divmask, (Color){1}, (Color){1}, d); + fill(divmask, divmask->r, &(Color){0}); + drawimg(divmask, (Color){~0,~0,~0}, (Color){~0,~0,~0}, d); drawimg(divimg, divcolor.bg, divcolor.border, d); copyimage(d->w, divimg->r, divimg, ZP); @@ -140,7 +140,7 @@ div_update_all(void) { dp = &divs; ap = nil; foreach_column(v, s, a) { - if (ap && ap->screen != s) + if(ap && ap->screen != s) ap = nil; d = getdiv(&dp); @@ -163,24 +163,26 @@ div_update_all(void) { } /* Div Handlers */ -static void -bdown_event(Window *w, XButtonEvent *e) { +static bool +bdown_event(Window *w, void *aux, XButtonEvent *e) { Divide *d; USED(e); - - d = w->aux; + + d = aux; mouse_resizecol(d); + return false; } -static void -expose_event(Window *w, XExposeEvent *e) { +static bool +expose_event(Window *w, void *aux, XExposeEvent *e) { Divide *d; - + USED(e); - - d = w->aux; + + d = aux; drawdiv(d); + return false; } static Handlers handlers = { diff --git a/cmd/wmii/event.c b/cmd/wmii/event.c index 82a51eb..b1e73a6 100644 --- a/cmd/wmii/event.c +++ b/cmd/wmii/event.c @@ -5,195 +5,20 @@ #include <X11/keysym.h> #include "fns.h" -typedef void (*EvHandler)(XEvent*); - void -dispatch_event(XEvent *e) { +debug_event(XEvent *e) { Dprint(DEvent, "%E\n", e); - if(e->type < nelem(handler)) { - if(handler[e->type]) - handler[e->type](e); - }else - xext_event(e); -} - -#define handle(w, fn, ev) \ - BLOCK(if((w)->handler->fn) (w)->handler->fn((w), ev)) - -static int -findtime(Display *d, XEvent *e, XPointer v) { - Window *w; - - w = (Window*)v; - if(e->type == PropertyNotify && e->xproperty.window == w->xid) { - xtime = e->xproperty.time; - return true; - } - return false; -} - -void -xtime_kludge(void) { - /* Round trip. */ - static Window *w; - WinAttr wa; - XEvent e; - long l; - - if(w == nil) { - w = createwindow(&scr.root, Rect(0, 0, 1, 1), 0, InputOnly, &wa, 0); - selectinput(w, PropertyChangeMask); - } - changeprop_long(w, "ATOM", "ATOM", &l, 0); - sync(); - XIfEvent(display, &e, findtime, (void*)w); -} - -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 Bool -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; -} - -static void -buttonrelease(XButtonPressedEvent *ev) { - Window *w; - - if((w = findwin(ev->window))) - handle(w, bup, ev); -} - -static void -buttonpress(XButtonPressedEvent *ev) { - Window *w; - - if((w = findwin(ev->window))) - handle(w, bdown, ev); - else - XAllowEvents(display, ReplayPointer, ev->time); -} - -static void -configurerequest(XConfigureRequestEvent *ev) { - XWindowChanges wc; - Window *w; - - if((w = findwin(ev->window))) - handle(w, configreq, ev); - else{ - wc.x = ev->x; - wc.y = ev->y; - wc.width = ev->width; - wc.height = ev->height; - wc.border_width = ev->border_width; - wc.sibling = ev->above; - wc.stack_mode = ev->detail; - XConfigureWindow(display, ev->window, ev->value_mask, &wc); - } -} - -static void -configurenotify(XConfigureEvent *ev) { - Window *w; - - ignoreenter = ev->serial; - if((w = findwin(ev->window))) - handle(w, config, ev); -} - -static void -clientmessage(XClientMessageEvent *ev) { - - if(ewmh_clientmessage(ev)) - return; - if(xdnd_clientmessage(ev)) - return; -} - -static void -destroynotify(XDestroyWindowEvent *ev) { - Window *w; - Client *c; - - if((w = findwin(ev->window))) - handle(w, destroy, ev); - else { - if((c = win2client(ev->window))) - fprint(2, "Badness: Unhandled DestroyNotify: " - "Client: %p, Window: %W, Name: %s\n", - c, &c->w, c->name); - } -} - -static void -enternotify(XCrossingEvent *ev) { - Window *w; - - xtime = ev->time; - if(ev->mode != NotifyNormal) - return; - - if((w = findwin(ev->window))) - handle(w, enter, ev); -} - -static void -leavenotify(XCrossingEvent *ev) { - Window *w; - - xtime = ev->time; - if((w = findwin(ev->window))) - handle(w, leave, ev); } void print_focus(const char *fn, Client *c, const char *to) { Dprint(DFocus, "%s() disp.focus:\n", fn); - Dprint(DFocus, "\t%C => %C\n", disp.focus, c); - Dprint(DFocus, "\t%s => %s\n", clientname(disp.focus), to); + Dprint(DFocus, "\t%#C => %#C\n", disp.focus, c); + Dprint(DFocus, "\t%C => %s\n", disp.focus, to); } -static void -focusin(XFocusChangeEvent *ev) { +void +event_focusin(XFocusChangeEvent *ev) { Window *w; Client *c; @@ -219,7 +44,7 @@ focusin(XFocusChangeEvent *ev) { disp.focus = nil; } else if((w = findwin(ev->window))) - handle(w, focusin, ev); + event_handle(w, focusin, ev); else if(ev->mode == NotifyGrab) { /* Some unmanaged window has grabbed focus */ if((c = disp.focus)) { @@ -231,8 +56,8 @@ focusin(XFocusChangeEvent *ev) { } } -static void -focusout(XFocusChangeEvent *ev) { +void +event_focusout(XFocusChangeEvent *ev) { XEvent me; Window *w; @@ -247,113 +72,8 @@ focusout(XFocusChangeEvent *ev) { if((ev->mode == NotifyGrab) && XCheckMaskEvent(display, KeyPressMask, &me)) - dispatch_event(&me); + event_dispatch(&me); else if((w = findwin(ev->window))) - handle(w, focusout, ev); -} - -static void -expose(XExposeEvent *ev) { - Window *w; - - if(ev->count == 0) - if((w = findwin(ev->window))) - handle(w, expose, ev); -} - -static void -keypress(XKeyEvent *ev) { - Window *w; - - xtime = ev->time; - if((w = findwin(ev->window))) - handle(w, kdown, ev); -} - -static void -mappingnotify(XMappingEvent *ev) { - - XRefreshKeyboardMapping(ev); - if(ev->request == MappingKeyboard) - update_keys(); -} - -static void -maprequest(XMapRequestEvent *ev) { - Window *w; - - if((w = findwin(ev->parent))) - handle(w, mapreq, ev); -} - -static void -motionnotify(XMotionEvent *ev) { - Window *w; - - xtime = ev->time; - if((w = findwin(ev->window))) - handle(w, motion, ev); -} - -static void -propertynotify(XPropertyEvent *ev) { - Window *w; - - xtime = ev->time; - if((w = findwin(ev->window))) - handle(w, property, ev); -} - -static void -mapnotify(XMapEvent *ev) { - Window *w; - - ignoreenter = ev->serial; - if((w = findwin(ev->window))) - handle(w, map, ev); -} - -static void -unmapnotify(XUnmapEvent *ev) { - Window *w; - - ignoreenter = ev->serial; - if((w = findwin(ev->window)) && (ev->event == w->parent->xid)) { - w->mapped = false; - if(ev->send_event || w->unmapped-- == 0) - handle(w, unmap, ev); - } -} - -EvHandler handler[LASTEvent] = { - [ButtonPress] = (EvHandler)buttonpress, - [ButtonRelease] = (EvHandler)buttonrelease, - [ConfigureRequest] = (EvHandler)configurerequest, - [ConfigureNotify] = (EvHandler)configurenotify, - [ClientMessage] = (EvHandler)clientmessage, - [DestroyNotify] = (EvHandler)destroynotify, - [EnterNotify] = (EvHandler)enternotify, - [Expose] = (EvHandler)expose, - [FocusIn] = (EvHandler)focusin, - [FocusOut] = (EvHandler)focusout, - [KeyPress] = (EvHandler)keypress, - [LeaveNotify] = (EvHandler)leavenotify, - [MapNotify] = (EvHandler)mapnotify, - [MapRequest] = (EvHandler)maprequest, - [MappingNotify] = (EvHandler)mappingnotify, - [MotionNotify] = (EvHandler)motionnotify, - [PropertyNotify] = (EvHandler)propertynotify, - [UnmapNotify] = (EvHandler)unmapnotify, -}; - -void -check_x_event(IxpConn *c) { - XEvent ev; - - USED(c); - while(XPending(display)) { - XNextEvent(display, &ev); - dispatch_event(&ev); - } + event_handle(w, focusout, ev); } diff --git a/cmd/wmii/ewmh.c b/cmd/wmii/ewmh.c index 6509e5f..add7d0c 100644 --- a/cmd/wmii/ewmh.c +++ b/cmd/wmii/ewmh.c @@ -9,34 +9,45 @@ Window *ewmhwin; static void ewmh_getwinstate(Client*); static void ewmh_setstate(Client*, Atom, int); +static void tick(long, void*); -#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 Handlers client_handlers; +static Handlers root_handlers; + +static void +clientprop_long(Client *c, int cache, char *prop, char *type, long *data, int l) { + if(l != c->proplen[cache] || memcmp(&c->propcache[cache], data, l * sizeof *data)) { + c->proplen[cache] = l; + memcpy(&c->propcache[cache], data, l * sizeof *data); + changeprop_long(&c->w, prop, type, data, l); + } +} +static void +clientprop_del(Client *c, int cache, char *prop) { + c->proplen[cache] = 0; + delproperty(&c->w, prop); +} void ewmh_init(void) { - WinAttr wa; char myname[] = "wmii"; long win; ewmhwin = createwindow(&scr.root, Rect(0, 0, 1, 1), 0 /*depth*/, - InputOnly, &wa, 0); + InputOnly, nil, 0); win = ewmhwin->xid; 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); - long zz[] = {0, 0}; changeprop_long(&scr.root, Net("DESKTOP_VIEWPORT"), "CARDINAL", - zz, 2); + (long[2]){0, 0}, 2); + + pushhandler(&scr.root, &root_handlers, nil); + + tick(0L, nil); long supported[] = { /* Misc */ @@ -50,8 +61,11 @@ ewmh_init(void) { NET("WM_DESKTOP"), NET("WM_FULLSCREEN_MONITORS"), NET("WM_NAME"), + NET("WM_PID"), NET("WM_STRUT"), NET("WM_STRUT_PARTIAL"), + /* Set this so clients don't update Net("USER_TIME") */ + NET("USER_TIME_WINDOW"), /* States */ NET("WM_STATE"), STATE("DEMANDS_ATTENTION"), @@ -62,7 +76,9 @@ ewmh_init(void) { TYPE("DIALOG"), TYPE("DOCK"), TYPE("NORMAL"), + TYPE("MENU"), TYPE("SPLASH"), + TYPE("TOOLBAR"), /* Actions */ NET("WM_ALLOWED_ACTIONS"), ACTION("FULLSCREEN"), @@ -76,6 +92,44 @@ ewmh_init(void) { changeprop_long(&scr.root, Net("SUPPORTED"), "ATOM", supported, nelem(supported)); } +inline bool +ewmh_responsive_p(Client *c) { + return c->w.ewmh.ping == 0 || (ulong)(nsec() / 1000000) - c->w.ewmh.ping < PingTime; +} + +void +ewmh_checkresponsive(Client *c) { + + if(!ewmh_responsive_p(c)) + if(!c->dead) + frame_draw(c->sel); + else if(c->dead++ == 1) + event("Unresponsive %#C\n", c); +} + +static void +tick(long id, void *v) { + static int count; + Client *c; + ulong time; + int mod, i; + + time = nsec() / 1000000; + count++; + mod = count % PingPartition; + for(i=0, c=client; c; c=c->next, i++) + if(c->proto & ProtoPing) { + if(!ewmh_responsive_p(c)) + ewmh_checkresponsive(c); + if(i % PingPartition == mod) + sendmessage(&c->w, "WM_PROTOCOLS", NET("WM_PING"), time, c->w.xid, 0, 0); + if(i % PingPartition == mod) + Dprint(DEwmh, "_NET_WM_PING %#C %,uld\n", c, time); + } + + ixp_settimer(&srv, PingPeriod / PingPartition, tick, nil); +} + void ewmh_updateclientlist(void) { Vector_long vec; @@ -127,50 +181,109 @@ ewmh_initclient(Client *c) { ewmh_getwintype(c); ewmh_getwinstate(c); ewmh_getstrut(c); + ewmh_framesize(c); ewmh_updateclientlist(); + pushhandler(&c->w, &client_handlers, c); } void ewmh_destroyclient(Client *c) { - Ewmh *e; ewmh_updateclientlist(); - e = &c->w.ewmh; - if(e->timer) - if(!ixp_unsettimer(&srv, e->timer)) - fprint(2, "Badness: %C: Can't unset timer\n", c); free(c->strut); } -static void -pingtimeout(long id, void *v) { - Client *c; +#ifdef notdef +static ulong +usertime(Window *w) { + long *l; + long ret; - USED(id); - c = v; - event("Unresponsive %C\n", c); - c->w.ewmh.ping = 0; - c->w.ewmh.timer = 0; + ret = 0; + if(getprop_long(w, Net("WM_USER_TIME_WINDOW"), "CARDINAL", 0, &l, 1)) { + w = window(*l); + free(l); + } + if(getprop_long(w, Net("WM_USER_TIME"), "CARDINAL", 0, &l, 1)) { + ret = *l; + free(l); + } + return ret; } +#endif -void -ewmh_pingclient(Client *c) { - Ewmh *e; +static bool +event_client_clientmessage(Window *w, void *aux, XClientMessageEvent *e) { + Client *c; + ulong *l; + ulong msg; + int action; - if(!(c->proto & ProtoPing)) - return; + c = aux; + l = (ulong*)e->data.l; + msg = e->message_type; + Dprint(DEwmh, "ClientMessage: %A\n", msg); - e = &c->w.ewmh; - if(e->ping) - return; + if(msg == NET("WM_STATE")) { + enum { + StateUnset, + StateSet, + StateToggle, + }; + if(e->format != 32) + return false; + + switch(l[0]) { + case StateUnset: action = Off; break; + case StateSet: action = On; break; + case StateToggle: action = Toggle; break; + default: return false; + } + + Dprint(DEwmh, "\tAction: %s\n", TOGGLE(action)); + ewmh_setstate(c, l[1], action); + ewmh_setstate(c, l[2], action); + return false; + }else + if(msg == NET("ACTIVE_WINDOW")) { + if(e->format != 32) + return false; + Dprint(DEwmh, "\tsource: %uld\n", l[0]); + Dprint(DEwmh, "\ttimestamp: %,uld\n", l[1]); + Dprint(DEwmh, "\tactive: %#ulx\n", l[2]); + Dprint(DEwmh, "\twindow: %#ulx\n", e->window); + Dprint(DEwmh, "\tclient: %C\n", c); + + if(l[0] == SourceClient && !(c->permission & PermActivate)) + return false; + if(l[0] == SourceClient || l[0] == SourcePager) + focus(c, true); + return false; + }else + if(msg == NET("CLOSE_WINDOW")) { + if(e->format != 32) + return false; + Dprint(DEwmh, "\tsource: %ld\n", l[0]); + Dprint(DEwmh, "\twindow: %#ulx\n", e->window); + client_kill(c, true); + return false; + } - client_message(c, Net("WM_PING"), c->w.xid); - e->ping = xtime++; - e->timer = ixp_settimer(&srv, PingTime, pingtimeout, c); + return false; } -int +static bool +event_client_property(Window *w, void *aux, XPropertyEvent *e) { + return ewmh_prop(aux, e->atom); +} + +static Handlers client_handlers = { + .message = event_client_clientmessage, + .property = event_client_property, +}; + +bool ewmh_prop(Client *c, Atom a) { if(a == NET("WM_WINDOW_TYPE")) ewmh_getwintype(c); @@ -178,8 +291,8 @@ ewmh_prop(Client *c, Atom a) { if(a == NET("WM_STRUT_PARTIAL")) ewmh_getstrut(c); else - return 0; - return 1; + return true; + return false; } typedef struct Prop Prop; @@ -240,10 +353,12 @@ ewmh_getwintype(Client *c) { mask = getprop_mask(&c->w, Net("WM_WINDOW_TYPE"), props); c->w.ewmh.type = mask; - if(mask & TypeDock) { - c->borderless = 1; - c->titleless = 1; + if(mask & (TypeDock|TypeMenu|TypeToolbar)) { + c->borderless = true; + c->titleless = true; } + if(mask & (TypeSplash|TypeDock)) + c->nofocus = true; } static void @@ -283,7 +398,7 @@ ewmh_getstrut(Client *c) { long *strut; ulong n; - if(c->strut == nil) + if(c->strut != nil) free(c->strut); c->strut = nil; @@ -297,7 +412,7 @@ ewmh_getstrut(Client *c) { free(strut); return; } - Dprint(DEwmh, "ewmh_getstrut(%C[%s]) Using WM_STRUT\n", c, clientname(c)); + Dprint(DEwmh, "ewmh_getstrut(%#C[%C]) Using WM_STRUT\n", c, c); strut = erealloc(strut, Last * sizeof *strut); strut[LeftMin] = strut[RightMin] = 0; strut[LeftMax] = strut[RightMax] = INT_MAX; @@ -309,7 +424,7 @@ ewmh_getstrut(Client *c) { 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); - Dprint(DEwmh, "ewmh_getstrut(%C[%s])\n", c, clientname(c)); + Dprint(DEwmh, "ewmh_getstrut(%#C[%C])\n", c, c); Dprint(DEwmh, "\ttop: %R\n", c->strut->top); Dprint(DEwmh, "\tleft: %R\n", c->strut->left); Dprint(DEwmh, "\tright: %R\n", c->strut->right); @@ -332,68 +447,23 @@ ewmh_setstate(Client *c, Atom state, int action) { client_seturgent(c, action, UrgClient); } -int -ewmh_clientmessage(XClientMessageEvent *e) { +static bool +event_root_clientmessage(Window *w, void *aux, XClientMessageEvent *e) { Client *c; View *v; ulong *l; ulong msg; - int action, i; + int i; l = (ulong*)e->data.l; msg = e->message_type; - Dprint(DEwmh, "ClientMessage: %A\n", msg); + Debug(DEwmh) + if(msg != xatom("WM_PROTOCOLS") && l[0] != NET("WM_PING")) + 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)); - ewmh_setstate(c, l[1], action); - ewmh_setstate(c, l[2], action); - 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("CLOSE_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; - client_kill(c, true); - return 1; - }else if(msg == NET("CURRENT_DESKTOP")) { if(e->format != 32) - return -1; + return false; for(v=view, i=l[0]; v; v=v->next, i--) if(i == 0) break; @@ -401,47 +471,52 @@ ewmh_clientmessage(XClientMessageEvent *e) { if(i == 0) view_select(v->name); return 1; - }else + } if(msg == xatom("WM_PROTOCOLS")) { if(e->format != 32) - return 0; - Dprint(DEwmh, "\t%A\n", l[0]); + return false; if(l[0] == NET("WM_PING")) { if(e->window != scr.root.xid) - 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 false; + if(!(c = win2client(l[2]))) + return false; + i = ewmh_responsive_p(c); + c->w.ewmh.ping = nsec() / 1000000; + c->w.ewmh.lag = (c->w.ewmh.ping & 0xffffffff) - (l[1] & 0xffffffff); + if(i == false) + frame_draw(c->sel); + return false; } + return false; } - return 0; + return false; } +static Handlers root_handlers = { + .message = event_root_clientmessage, +}; + + void ewmh_framesize(Client *c) { - Rectangle r; + Rectangle rc, rf; Frame *f; - f = c->sel; - r.min.x = f->crect.min.x; - r.min.y = f->crect.min.y; - r.max.x = Dx(f->r) - f->crect.max.x; - r.max.y = Dy(f->r) - f->crect.max.y; + if((f = c->sel)) { + rc = f->crect; + rf = f->r; + } + else { + rf = frame_client2rect(c, ZR, c->floating); + rc = rectsubpt(ZR, rf.min); + } long extents[] = { - r.min.x, r.max.x, - r.min.y, r.max.y, + rc.min.x, Dx(rf) - rc.max.x, + rc.min.y, Dy(rf) - rc.max.y, }; - changeprop_long(&c->w, Net("FRAME_EXTENTS"), "CARDINAL", + clientprop_long(c, PExtents, Net("FRAME_EXTENTS"), "CARDINAL", extents, nelem(extents)); } @@ -464,17 +539,17 @@ ewmh_updatestate(Client *c) { state[i++] = STATE("DEMANDS_ATTENTION"); if(i > 0) - changeprop_long(&c->w, Net("WM_STATE"), "ATOM", state, i); + clientprop_long(c, PState, Net("WM_STATE"), "ATOM", state, i); else - delproperty(&c->w, Net("WM_STATE")); + clientprop_del(c, PState, Net("WM_STATE")); if(c->fullscreen >= 0) - changeprop_long(&c->w, Net("WM_FULLSCREEN_MONITORS"), "CARDINAL", + clientprop_long(c, PMonitors, Net("WM_FULLSCREEN_MONITORS"), "CARDINAL", (long[]) { c->fullscreen, c->fullscreen, - c->fullscreen, c->fullscreen }, + c->fullscreen, c->fullscreen }, 4); else - delproperty(&c->w, Net("WM_FULLSCREEN_MONITORS")); + clientprop_del(c, PMonitors, Net("WM_FULLSCREEN_MONITORS")); } /* Views */ @@ -528,7 +603,7 @@ ewmh_updateclient(Client *c) { i = -1; if(c->sel) i = viewidx(c->sel->view); - changeprop_long(&c->w, Net("WM_DESKTOP"), "CARDINAL", &i, 1); + clientprop_long(c, PDesktop, Net("WM_DESKTOP"), "CARDINAL", &i, 1); } void diff --git a/cmd/wmii/float.c b/cmd/wmii/float.c index 23998d5..0134446 100644 --- a/cmd/wmii/float.c +++ b/cmd/wmii/float.c @@ -10,7 +10,8 @@ static void float_placeframe(Frame*); void float_attach(Area *a, Frame *f) { - f->client->floating = true; + if(f->client->floating == Off) + f->client->floating = On; f->r = f->floatr; float_placeframe(f); @@ -36,8 +37,11 @@ float_detach(Frame *f) { frame_remove(f); if(a->sel == f) { + while(pr && pr->client->nofocus) + pr = pr->aprev; if(!pr) - pr = a->frame; + for(pr=a->frame; pr && pr->anext; pr=pr->anext) + if(!pr->client->nofocus) break; a->sel = nil; area_setsel(a, pr); } @@ -45,7 +49,7 @@ float_detach(Frame *f) { if(oldsel) area_focus(oldsel); - else if(!a->frame) + else if(!a->frame || pr && pr->client->nofocus) if(sel && sel->frame) area_focus(sel); } @@ -67,12 +71,11 @@ float_arrange(Area *a) { switch(a->mode) { case Coldefault: - for(f=a->frame; f; f=f->anext) - f->collapsed = false; break; case Colstack: for(f=a->frame; f; f=f->anext) - f->collapsed = (f != a->sel); + f->collapsed = !(f->client->w.ewmh.type & (TypeDock|TypeMenu|TypeToolbar)) + && (f != a->sel); break; default: die("not reached"); @@ -160,12 +163,14 @@ float_placeframe(Frame *f) { Vector_rect *vp; Rectangle r; Point dim, p; + Area *a, *sel; Client *c; Frame *ff; - Area *a, *sel; + View *v; long area, l; int i, s; + v = f->view; a = f->area; c = f->client; @@ -198,19 +203,23 @@ float_placeframe(Frame *f) { */ s = -1; ff = client_groupframe(c, f->view); - if (f->screen >= 0) + if(f->screen >= 0) s = f->screen; - else if (ff) + else if(ff) s = ownerscreen(ff->r); - else if (selclient()) + else if(selclient()) s = ownerscreen(selclient()->sel->r); else { sel = view_findarea(a->view, a->view->selscreen, a->view->selcol, false); - if (sel) + if(sel) s = sel->screen; } - r = s == -1 ? a->r : screens[s]->r; + if (s == -1) + r = a->r; + else + r = v->r[s]; + vp = unique_rects(&vec, r); area = LONG_MAX; diff --git a/cmd/wmii/fns.h b/cmd/wmii/fns.h index 9b53ef9..cc2e7e0 100644 --- a/cmd/wmii/fns.h +++ b/cmd/wmii/fns.h @@ -2,14 +2,16 @@ * See LICENSE file for license details. */ +#include <setjmp.h> + #ifdef VARARGCK # pragma varargck argpos debug 2 # pragma varargck argpos dprint 1 # pragma varargck argpos event 1 # pragma varargck argpos warning 1 # -# pragma varargck type "a" Area* -# pragma varargck type "C" Client* +# pragma varargck type "a" Area* +# pragma varargck type "C" Client* # pragma varargck type "r" void #endif @@ -22,21 +24,27 @@ /* Grotesque, but worth it. */ #define foreach_area(v, s, a) \ - with(int, __alive) \ - with(Area*, __anext) \ - for(s=0; _cond(s <= nscreens, 0); _cont(s++)) \ - for((a)=(s < nscreens ? (v)->areas[s] : v->floating), __anext=(a)->next; _cond(a, 1); _cont(((a)=__anext) && (__anext=(a)->next))) + with(int, __alive) \ + with(Area*, __anext) \ + for(s=0; _cond(s <= nscreens, 0); _cont(s++)) \ + for((a)=(s < nscreens ? (v)->areas[s] : v->floating), __anext=((a)?(a)->next:NULL); \ + _cond(a, 1); \ + _cont(((a)=__anext) && (__anext=(a)->next))) #define foreach_column(v, s, a) \ - with(int, __alive) \ - with(Area*, __anext) \ - for(s=0; _cond(s < nscreens, 0); _cont(s++)) \ - for((a)=(v)->areas[s], __anext=(a)->next; _cond(a, 1); _cont(((a)=__anext) && (__anext=(a)->next))) + with(int, __alive) \ + with(Area*, __anext) \ + for(s=0; _cond(s < nscreens, 0); _cont(s++)) \ + for((a)=(v)->areas[s], __anext=((a)?(a)->next:NULL); \ + _cond(a, 1); \ + _cont(((a)=__anext) && (__anext=(a)->next))) #define foreach_frame(v, s, a, f) \ with(Frame*, __fnext) \ foreach_area(v, s, a) \ - for((void)(((f)=(a)->frame) && (__fnext=(f)->anext)); _cond(f, 2); _cont(((f)=__fnext) && (__fnext=(f)->anext))) + for((void)(((f)=(a)->frame) && (__fnext=(f)?((f)->anext):NULL)); \ + _cond(f, 2); \ + _cont(((f)=__fnext) && (__fnext=(f)->anext))) #define btassert(arg, cond) \ (cond ? fprint(1, __FILE__":%d: failed assertion: " #cond "\n", __LINE__), backtrace(arg), true : false) @@ -61,7 +69,6 @@ void bar_destroy(Bar**, Bar*); void bar_draw(WMScreen*); Bar* bar_find(Bar*, const char*); void bar_init(WMScreen*); -void bar_load(Bar*); void bar_resize(WMScreen*); void bar_sety(WMScreen*, int); void bar_setbounds(WMScreen*, int, int); @@ -80,21 +87,22 @@ void client_kill(Client*, bool); void client_manage(Client*); void client_map(Client*); void client_message(Client*, char*, long); -void client_prop(Client*, Atom); -void client_reparent(Client*, Window*, Point); +bool client_prop(Client*, Atom); +void client_reparent(Client*); void client_resize(Client*, Rectangle); void client_setcursor(Client*, Cursor); void client_seturgent(Client*, int, int); void client_setviews(Client*, char**); void client_unmap(Client*, int state); Frame* client_viewframe(Client *c, View *v); -char* clientname(Client*); -void focus(Client*, bool restack); +void focus(Client*, bool user); void fullscreen(Client*, int, long); +void group_init(Client*); Client* group_leader(Group*); -int map_frame(Client*); +void group_remove(Client*); +int client_mapframe(Client*); Client* selclient(void); -int unmap_frame(Client*); +int client_unmapframe(Client*); void update_class(Client*); Client* win2client(XWindow); Rectangle client_grav(Client*, Rectangle); @@ -105,6 +113,7 @@ char* column_getmode(Area*); void column_arrange(Area*, bool dirty); void column_attach(Area*, Frame*); void column_attachrect(Area*, Frame*, Rectangle); +void column_destroy(Area*); void column_detach(Frame*); void column_frob(Area*); void column_insert(Area*, Frame*, Frame*); @@ -117,36 +126,29 @@ void column_settle(Area*); void div_draw(Divide*); void div_set(Divide*, int x); void div_update_all(void); -bool find(Area**, Frame**, int, bool, bool); -int stack_count(Frame*, int*); -Frame* stack_find(Area*, Frame*, int, bool); /* error.c */ -#define waserror() setjmp(pusherror()) +#define waserror() setjmp(*pusherror()) void error(char*, ...); void nexterror(void); void poperror(void); jmp_buf* pusherror(void); /* event.c */ -void check_x_event(IxpConn*); -void dispatch_event(XEvent*); -uint flushenterevents(void); -uint flushevents(long, bool dispatch); +void debug_event(XEvent*); void print_focus(const char*, Client*, const char*); -void xtime_kludge(void); /* ewmh.c */ -int ewmh_clientmessage(XClientMessageEvent*); +void ewmh_checkresponsive(Client*); 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*); -int ewmh_prop(Client*, Atom); +bool ewmh_prop(Client*, Atom); long ewmh_protocols(Window*); +bool ewmh_responsive_p(Client*); void ewmh_updateclient(Client*); void ewmh_updateclientlist(void); void ewmh_updateclients(void); @@ -188,7 +190,7 @@ void fs_attach(Ixp9Req*); void fs_clunk(Ixp9Req*); void fs_create(Ixp9Req*); void fs_flush(Ixp9Req*); -void fs_freefid(Fid*); +void fs_freefid(IxpFid*); void fs_open(Ixp9Req*); void fs_read(Ixp9Req*); void fs_remove(Ixp9Req*); @@ -197,15 +199,6 @@ void fs_walk(Ixp9Req*); void fs_write(Ixp9Req*); void event(const char*, ...); -/* geom.c */ -Align get_sticky(Rectangle src, Rectangle dst); -Cursor quad_cursor(Align); -Align quadrant(Rectangle, Point); -bool rect_contains_p(Rectangle, Rectangle); -bool rect_haspoint_p(Point, Rectangle); -bool rect_intersect_p(Rectangle, Rectangle); -Rectangle rect_intersection(Rectangle, Rectangle); - /* key.c */ void init_lock_keys(void); void kpress(XWindow, ulong mod, KeyCode); @@ -215,34 +208,24 @@ void update_keys(void); void init_screens(void); void spawn_command(const char*); -/* map.c */ -void** hash_get(Map*, const char*, bool create); -void* hash_rm(Map*, const char*); -void** map_get(Map*, ulong, bool create); -void* map_rm(Map*, ulong); - /* message.c */ -bool getlong(const char*, long*); -bool getulong(const char*, ulong*); +char* mask(char**, int*, int*); +char* message_bar(Bar*, IxpMsg*); char* message_client(Client*, IxpMsg*); char* message_root(void*, IxpMsg*); char* message_view(View*, IxpMsg*); -char* msg_debug(IxpMsg*); -char* msg_getword(IxpMsg*); -char* msg_parsecolors(IxpMsg*, CTuple*); +void msg_debug(char*); +void msg_eatrunes(IxpMsg*, int (*)(Rune), int); +char* msg_getword(IxpMsg*, char*); +void msg_parsecolors(IxpMsg*, CTuple*); char* msg_selectarea(Area*, IxpMsg*); char* msg_sendclient(View*, IxpMsg*, bool swap); +char* readctl_bar(Bar*); char* readctl_client(Client*); char* readctl_root(void); char* readctl_view(View*); Area* strarea(View*, ulong, const char*); void warning(const char*, ...); -/* debug */ -void debug(int, const char*, ...); -void dprint(const char*, ...); -void dwrite(int, void*, int, bool); -bool setdebug(int); -void vdebug(int, const char*, va_list); /* mouse.c */ Window* constraintwin(Rectangle); @@ -259,9 +242,6 @@ Align snap_rect(const Rectangle *rects, int num, Rectangle *current, Align *mask /* print.c */ int Ffmt(Fmt*); -/* printevent.c */ -void printevent(XEvent*); - /* root.c */ void root_init(void); @@ -270,8 +250,15 @@ void* findthing(Rectangle, int, Vector_ptr*, Rectangle(*)(void*), bool); int ownerscreen(Rectangle); /* rule.c */ -void trim(char *str, const char *chars); -void update_rules(Rule**, const char*); +void update_rules(Rule**, char*); + +/* stack.c */ +bool find(Area* *, Frame**, int, bool, bool); +int stack_count(Frame*, int*); +Frame* stack_find(Area*, Frame*, int, bool); +void stack_info(Frame*, Frame**, Frame**, int*, int*); +void stack_scale(Frame*, int); + /* view.c */ void view_arrange(View*); @@ -285,7 +272,7 @@ bool view_fullscreen_p(View*, int); char* view_index(View*); void view_init(View*, int iscreen); char** view_names(void); -uint view_newcolwidth(View*, int i); +uint view_newcolwidth(View*, int, int); void view_restack(View*); void view_scale(View*, int, int); Client* view_selclient(View*); @@ -293,36 +280,13 @@ void view_select(const char*); void view_update(View*); void view_update_all(void); void view_update_rect(View*); +void view_update_urgency(View*, char*); Rectangle* view_rects(View*, uint *num, Frame *ignore); -/* _util.c */ -void backtrace(char*); -void closeexec(int); -char** comm(int, char**, char**); -int doublefork(void); -void grep(char**, Reprog*, int); -char* join(char**, char*); -char* pathsearch(const char*, const char*, bool); -void refree(Regex*); -void reinit(Regex*, char*); -int strlcatprint(char*, int, const char*, ...); -int spawn3(int[3], const char*, char*[]); -int spawn3l(int[3], const char*, ...); -void uniq(char**); -int unquote(char*, char*[], int); - /* utf.c */ char* toutf8(const char*); char* toutf8n(const char*, size_t); /* xdnd.c */ -int xdnd_clientmessage(XClientMessageEvent*); void xdnd_initwindow(Window*); -/* xext.c */ -void randr_event(XEvent*); -bool render_argb_p(Visual*); -void xext_event(XEvent*); -void xext_init(void); -Rectangle* xinerama_screens(int*); - diff --git a/cmd/wmii/frame.c b/cmd/wmii/frame.c index 6bedd82..3c1a838 100644 --- a/cmd/wmii/frame.c +++ b/cmd/wmii/frame.c @@ -29,6 +29,9 @@ frame_create(Client *c, View *v) { if(c->sel) { f->floatr = c->sel->floatr; f->r = c->sel->r; + }else if(c->sel) { + f->floatr = c->frame->floatr; + f->r = c->frame->r; }else { f->r = client_grav(c, c->r); f->floatr = f->r; @@ -93,24 +96,14 @@ frame_insert(Frame *f, Frame *pos) { bool frame_restack(Frame *f, Frame *above) { - Client *c; - Frame *fp; Area *a; - c = f->client; a = f->area; if(!a->floating) return false; if(f == above) return false; - if(above == nil && !(c->w.ewmh.type & TypeDock)) - for(fp=a->stack; fp; fp=fp->snext) - if(fp->client->w.ewmh.type & TypeDock) - above = fp; - else - break; - if(f->sprev || f == a->stack) if(f->sprev == above) return false; @@ -139,21 +132,23 @@ frame_restack(Frame *f, Frame *above) { } /* Handlers */ -static void -bup_event(Window *w, XButtonEvent *e) { +static bool +bup_event(Window *w, void *aux, XButtonEvent *e) { if((e->state & def.mod) != def.mod) XAllowEvents(display, ReplayPointer, e->time); else XUngrabPointer(display, e->time); - event("ClientClick %C %d\n", w->aux, e->button); + if(!e->subwindow) + event("ClientClick %#C %d\n", aux, e->button); + return false; } -static void -bdown_event(Window *w, XButtonEvent *e) { +static bool +bdown_event(Window *w, void *aux, XButtonEvent *e) { Frame *f; Client *c; - c = w->aux; + c = aux; f = c->sel; if((e->state & def.mod) == def.mod) { @@ -194,62 +189,56 @@ bdown_event(Window *w, XButtonEvent *e) { XUngrabPointer(display, e->time); sync(); - event("ClientMouseDown %C %d\n", f->client, e->button); + event("ClientMouseDown %#C %d\n", f->client, e->button); } } + return false; } -static void -config_event(Window *w, XConfigureEvent *e) { - - USED(w, e); -} - -static void -enter_event(Window *w, XCrossingEvent *e) { +static bool +enter_event(Window *w, void *aux, XCrossingEvent *e) { Client *c; Frame *f; - c = w->aux; + c = aux; f = c->sel; if(disp.focus != c || selclient() != c) { - Dprint(DFocus, "enter_notify(f) => [%C]%s%s\n", + Dprint(DFocus, "%E\n", e); + Dprint(DFocus, "enter_notify(f) => [%#C]%s%s\n", f->client, f->client->name, - ignoreenter == e->serial ? " (ignored)" : ""); + e->serial <= event_lastconfigure ? " (ignored)" : ""); if(e->detail != NotifyInferior) - if(e->serial != ignoreenter && (f->area->floating || !f->collapsed)) - if(!(c->w.ewmh.type & TypeSplash)) + if(e->serial > event_lastconfigure && !f->collapsed) focus(f->client, false); } mouse_checkresize(f, Pt(e->x, e->y), false); + return false; } -static void -expose_event(Window *w, XExposeEvent *e) { +static bool +expose_event(Window *w, void *aux, XExposeEvent *e) { Client *c; USED(e); - c = w->aux; + c = aux; if(c->sel) frame_draw(c->sel); - else - fprint(2, "Badness: Expose event on a client frame which shouldn't be visible: %C\n", - c); + return false; } -static void -motion_event(Window *w, XMotionEvent *e) { +static bool +motion_event(Window *w, void *aux, XMotionEvent *e) { Client *c; - - c = w->aux; + + c = aux; mouse_checkresize(c->sel, Pt(e->x, e->y), false); + return false; } Handlers framehandler = { .bup = bup_event, .bdown = bdown_event, - .config = config_event, .enter = enter_event, .expose = expose_event, .motion = motion_event, @@ -347,8 +336,8 @@ frame_resize(Frame *f, Rectangle r) { || Dy(r) == 0 && (!f->area->max || resizing) && !f->collapsed)) { fprint(2, "Frame rect: %R\n", r); - r.max.x = min(r.min.x+1, r.max.x); - r.max.y = min(r.min.y+1, r.max.y); + r.max.x = max(r.min.x+1, r.max.x); + r.max.y = max(r.min.y+1, r.max.y); } c = f->client; @@ -407,14 +396,16 @@ pushlabel(Image *img, Rectangle *rp, char *s, CTuple *col) { w = min(w, Dx(*rp) - 30); /* Magic number. */ if(w > 0) { r = *rp; + r.min.x = r.max.x - w; rp->max.x -= w; if(0) drawline(img, Pt(rp->max.x, r.min.y+2), Pt(rp->max.x, r.max.y-2), - CapButt, 1, col->border); + CapButt, 1, &col->border); drawstring(img, def.font, r, East, - s, col->fg); + s, &col->fg); } + free(s); } void @@ -424,94 +415,85 @@ frame_draw(Frame *f) { CTuple *col; Image *img; char *s; - uint w; int n, m; - if(f->view != selview) - return; - if(f->area == nil) /* Blech. */ + if(f == nil || f->view != selview || f->area == nil) return; c = f->client; - img = *c->ibuf; + img = c->framewin->depth == 32 ? disp.ibuf32 : disp.ibuf; fr = rectsetorigin(c->framewin->r, ZP); /* Pick colors. */ - if(c == selclient() || c == disp.focus) + if((c == selclient() || c == disp.focus) && disp.sel) col = &def.focuscolor; else col = &def.normcolor; /* Background/border */ r = fr; - fill(img, r, col->bg); - border(img, r, 1, col->border); + fill(img, r, &col->bg); + border(img, r, 1, &col->border); /* Title border */ r.max.y = r.min.y + labelh(def.font); - border(img, r, 1, col->border); + border(img, r, 1, &col->border); f->titlebar = insetrect(r, 3); f->titlebar.max.y += 3; + f->grabbox = insetrect(r, 2); + f->grabbox.max.x = f->grabbox.min.x + Dy(f->grabbox); + /* Odd focus. Unselected, with keyboard focus. */ /* Draw a border just inside the titlebar. */ if(c != selclient() && c == disp.focus) { - border(img, insetrect(r, 1), 1, def.normcolor.bg); - border(img, insetrect(r, 2), 1, def.focuscolor.border); + border(img, insetrect(r, 1), 1, &def.normcolor.bg); + border(img, insetrect(r, 2), 1, &def.focuscolor.border); } - /* grabbox */ - r.min = Pt(2, 2); - r.max.y -= 2; - r.max.x = r.min.x + Dy(r); - f->grabbox = r; - if(c->urgent) - fill(img, r, col->fg); - border(img, r, 1, col->border); + fill(img, f->grabbox, &col->fg); + border(img, f->grabbox, 1, &col->border); /* Odd focus. Selected, without keyboard focus. */ /* Draw a border around the grabbox. */ if(c != disp.focus && col == &def.focuscolor) - border(img, insetrect(r, -1), 1, def.normcolor.bg); + border(img, insetrect(r, -1), 1, &def.normcolor.bg); /* Draw a border on borderless+titleless selected apps. */ - if(f->area->floating && c->borderless && c->titleless && !c->fullscreen && c == selclient()) - setborder(c->framewin, def.border, def.focuscolor.border); + if(c->borderless && c->titleless && f->area->floating && !c->fullscreen && c == selclient()) + setborder(c->framewin, def.border, &def.focuscolor.border); else - setborder(c->framewin, 0, def.focuscolor.border); + setborder(c->framewin, 0, &def.focuscolor.border); /* Label */ - r.min.x = r.max.x; - r.max.x = fr.max.x; - r.min.y = 0; - r.max.y = labelh(def.font); + r = Rect(f->grabbox.max.x, 0, fr.max.x, labelh(def.font)); + /* Draw count on frames in 'max' columns. */ if(f->area->max && !resizing) { - /* XXX */ n = stack_count(f, &m); - s = smprint("%d/%d", m, n); - pushlabel(img, &r, s, col); - free(s); + pushlabel(img, &r, smprint("%d/%d", m, n), col); } + /* Label clients with extra tags. */ - if((s = client_extratags(c))) { + if((s = client_extratags(c))) pushlabel(img, &r, s, col); - free(s); - }else /* Make sure floating clients have room for their indicators. */ - if(c->floating) - r.max.x -= Dx(f->grabbox); - w = drawstring(img, def.font, r, West, - c->name, col->fg); + + if(f->area->floating) /* Make sure floating clients have room for their indicators. */ + r.max.x -= f->grabbox.max.x; + + if(!ewmh_responsive_p(c)) + r.min.x += drawstring(img, def.font, r, West, "(wedged) ", &col->fg); + r.min.x += drawstring(img, def.font, r, West, c->name, &col->fg); /* Draw inner border on floating clients. */ if(f->area->floating) { - r.min.x = r.min.x + w + 10; - r.max.x += Dx(f->grabbox) - 2; + r.min.x += 10; + r.max.x += Dx(f->grabbox); r.min.y = f->grabbox.min.y; r.max.y = f->grabbox.max.y; - border(img, r, 1, col->border); + border(img, r, 1, &col->border); } /* Border increment gaps... */ @@ -519,7 +501,7 @@ frame_draw(Frame *f) { r.min.x = max(1, f->crect.min.x - 1); r.max.x = min(fr.max.x - 1, f->crect.max.x + 1); r.max.y = min(fr.max.y - 1, f->crect.max.y + 1); - border(img, r, 1, col->border); + border(img, r, 1, &col->border); /* Why? Because some non-ICCCM-compliant apps feel the need to * change the background properties of all of their ancestor windows @@ -603,7 +585,9 @@ frame_focus(Frame *f) { /* XXX */ f->colr.max.y = f->colr.min.y + Dy(ff->colr); ff->colr.max.y = ff->colr.min.y + labelh(def.font); - }else if(f->area->mode == Coldefault) { + } + else if(f->area->mode == Coldefault) { + /* XXX */ for(; f->collapsed && f->anext; f=f->anext) ; for(; f->collapsed && f->aprev; f=f->aprev) @@ -618,18 +602,20 @@ frame_focus(Frame *f) { if(old_a != v->oldsel && f != old_f) v->oldsel = nil; - if(v != selview || a != v->sel || resizing) - return; + if(f->area->floating) + f->collapsed = false; - move_focus(old_f, f); - if(a->floating) - float_arrange(a); - client_focus(f->client); + if(v == selview && a == v->sel && !resizing) { + move_focus(old_f, f); + if(a->floating) + float_arrange(a); - /* - if(!a->floating && ((a->mode == Colstack) || (a->mode == Colmax))) - */ - column_arrange(a, false); + // if(!a->floating && ((a->mode == Colstack) || (a->mode == Colmax))) + if(true) + column_arrange(a, false); + + client_focus(f->client); + } } int @@ -647,7 +633,7 @@ constrain(Rectangle r, int inset) { if(inset < 0) inset = Dy(screen->brect); - /* + /* * FIXME: This will cause problems for windows with * D(r) < 2 * inset */ @@ -655,15 +641,18 @@ constrain(Rectangle r, int inset) { SET(best); sbest = nil; for(sp=screens; (s = *sp); sp++) { - if (!screen->showing) + if(!screen->showing) continue; + isect = rect_intersection(r, insetrect(s->r, inset)); if(Dx(isect) >= 0 && Dy(isect) >= 0) return r; + if(Dx(isect) <= 0 && Dy(isect) <= 0) n = max(Dx(isect), Dy(isect)); else n = min(Dx(isect), Dy(isect)); + if(!sbest || n > best) { sbest = s; best = n; diff --git a/cmd/wmii/fs.c b/cmd/wmii/fs.c index 5fdfca4..242388d 100644 --- a/cmd/wmii/fs.c +++ b/cmd/wmii/fs.c @@ -5,7 +5,6 @@ #include <ctype.h> #include <stdarg.h> #include <time.h> -#include <unistd.h> #include "fns.h" typedef union IxpFileIdU IxpFileIdU; @@ -44,7 +43,7 @@ enum { /* Dirs */ FsFEvent, FsFKeys, FsFRctl, - FsFTagRules, + FsFRules, FsFTctl, FsFTindex, FsFprops, @@ -90,7 +89,7 @@ dirtab_root[]= {{".", QTDIR, FsRoot, 0500|DMDIR }, {"colrules", QTFILE, FsFColRules, 0600 }, {"event", QTFILE, FsFEvent, 0600 }, {"keys", QTFILE, FsFKeys, 0600 }, - {"tagrules", QTFILE, FsFTagRules, 0600 }, + {"rules", QTFILE, FsFRules, 0600 }, {nil}}, dirtab_clients[]={{".", QTDIR, FsDClients, 0500|DMDIR }, {"", QTDIR, FsDClient, 0500|DMDIR }, @@ -124,6 +123,28 @@ static IxpDirtab* dirtab[] = { [FsDTag] = dirtab_tag, }; typedef char* (*MsgFunc)(void*, IxpMsg*); +typedef char* (*BufFunc)(void*); + +typedef struct ActionTab ActionTab; +static struct ActionTab { + MsgFunc msg; + BufFunc read; + size_t buffer; + size_t size; + int max; +} actiontab[] = { + [FsFBar] = { .msg = (MsgFunc)message_bar, .read = (BufFunc)readctl_bar }, + [FsFCctl] = { .msg = (MsgFunc)message_client, .read = (BufFunc)readctl_client }, + [FsFRctl] = { .msg = (MsgFunc)message_root, .read = (BufFunc)readctl_root }, + [FsFTctl] = { .msg = (MsgFunc)message_view, .read = (BufFunc)readctl_view }, + [FsFTindex] = { .msg = (MsgFunc)0, .read = (BufFunc)view_index }, + [FsFColRules] = { .buffer = offsetof(Ruleset, string), .size = offsetof(Ruleset, size) }, + [FsFKeys] = { .buffer = offsetof(Defs, keys), .size = offsetof(Defs, keyssz) }, + [FsFRules] = { .buffer = offsetof(Ruleset, string), .size = offsetof(Ruleset, size) }, + [FsFClabel] = { .buffer = offsetof(Client, name), .max = sizeof ((Client*)0)->name }, + [FsFCtags] = { .buffer = offsetof(Client, tags), .max = sizeof ((Client*)0)->tags }, + [FsFprops] = { .buffer = offsetof(Client, props), .max = sizeof ((Client*)0)->props }, +}; void event(const char *format, ...) { @@ -134,6 +155,7 @@ event(const char *format, ...) { va_end(ap); ixp_pending_write(&events, buffer, strlen(buffer)); + Dprint(DEvents, "%s", buffer); } static int dflags; @@ -169,15 +191,6 @@ debug(int flag, const char *fmt, ...) { } void -dprint(const char *fmt, ...) { - va_list ap; - - va_start(ap, fmt); - vdebug(0, fmt, ap); - va_end(ap); -} - -void dwrite(int flag, void *buf, int n, bool always) { int i; @@ -196,7 +209,7 @@ dwrite(int flag, void *buf, int n, bool always) { static uint fs_size(IxpFileId*); static void -dostat(Stat *s, IxpFileId *f) { +dostat(IxpStat *s, IxpFileId *f) { s->type = 0; s->dev = 0; s->qid.path = QID(f->tab.type, f->id); @@ -212,7 +225,7 @@ dostat(Stat *s, IxpFileId *f) { s->muid = user; } -/* +/* * All lookups and directory organization should be performed through * lookup_file, mostly through the dirtab[] tree. */ @@ -234,8 +247,10 @@ lookup_file(IxpFileId *parent, char *name) last = &ret; ret = nil; for(; dir->name; dir++) { -# define push_file(nam) \ +# define push_file(nam, id_, vol) \ file = ixp_srv_getfile(); \ + file->id = id_; \ + file->volatil = vol; \ *last = file; \ last = &file->next; \ file->tab = *dir; \ @@ -246,10 +261,8 @@ lookup_file(IxpFileId *parent, char *name) case FsDClients: if(!name || !strcmp(name, "sel")) { if((c = selclient())) { - push_file("sel"); - file->volatil = true; + push_file("sel", c->w.xid, true); file->p.client = c; - file->id = c->w.xid; file->index = c->w.xid; } if(name) @@ -263,10 +276,8 @@ lookup_file(IxpFileId *parent, char *name) } for(c=client; c; c=c->next) { if(!name || c->w.xid == id) { - push_file(sxprint("%C", c)); - file->volatil = true; + push_file(sxprint("%#C", c), c->w.xid, true); file->p.client = c; - file->id = c->w.xid; file->index = c->w.xid; assert(file->tab.name); if(name) @@ -277,8 +288,7 @@ lookup_file(IxpFileId *parent, char *name) case FsDDebug: for(i=0; i < nelem(pdebug); i++) if(!name || !strcmp(name, debugtab[i])) { - push_file(debugtab[i]); - file->id = i; + push_file(debugtab[i], i, false); if(name) goto LastItem; } @@ -286,20 +296,16 @@ lookup_file(IxpFileId *parent, char *name) case FsDTags: if(!name || !strcmp(name, "sel")) { if(selview) { - push_file("sel"); - file->volatil = true; + push_file("sel", selview->id, true); file->p.view = selview; - file->id = selview->id; } if(name) goto LastItem; } for(v=view; v; v=v->next) { if(!name || !strcmp(name, v->name)) { - push_file(v->name); - file->volatil = true; + push_file(v->name, v->id, true); file->p.view = v; - file->id = v->id; if(name) goto LastItem; } @@ -308,10 +314,8 @@ lookup_file(IxpFileId *parent, char *name) case FsDBars: for(b=*parent->p.bar_p; b; b=b->next) { if(!name || !strcmp(name, b->name)) { - push_file(b->name); - file->volatil = true; + push_file(b->name, b->id, true); file->p.bar = b; - file->id = b->id; if(name) goto LastItem; } @@ -320,8 +324,7 @@ lookup_file(IxpFileId *parent, char *name) } }else /* Static dirs */ if(!name && !(dir->flags & FLHide) || name && !strcmp(name, dir->name)) { - push_file(file->tab.name); - file->id = 0; + push_file(file->tab.name, 0, false); file->p.ref = parent->p.ref; file->index = parent->index; /* Special considerations: */ @@ -336,8 +339,11 @@ lookup_file(IxpFileId *parent, char *name) case FsFColRules: file->p.rule = &def.colrules; break; - case FsFTagRules: - file->p.rule = &def.tagrules; + case FsFKeys: + file->p.ref = &def; + break; + case FsFRules: + file->p.rule = &def.rules; break; } if(name) @@ -364,7 +370,7 @@ fs_attach(Ixp9Req *r) { r->fid->qid.type = f->tab.qtype; r->fid->qid.path = QID(f->tab.type, 0); r->ofcall.rattach.qid = r->fid->qid; - respond(r, nil); + ixp_respond(r, nil); } void @@ -375,35 +381,33 @@ fs_walk(Ixp9Req *r) { static uint fs_size(IxpFileId *f) { - switch(f->tab.type) { - default: - return 0; - case FsFColRules: - case FsFTagRules: - return f->p.rule->size; - case FsFKeys: - return def.keyssz; - case FsFCtags: - return strlen(f->p.client->tags); - case FsFClabel: - return strlen(f->p.client->name); - case FsFprops: - return strlen(f->p.client->props); - } + ActionTab *t; + + t = &actiontab[f->tab.type]; + if(f->tab.type < nelem(actiontab)) + if(t->size) + return structmember(f->p.ref, int, t->size); + else if(t->buffer && t->max) + return strlen(structptr(f->p.ref, char, t->buffer)); + else if(t->buffer) + return strlen(structmember(f->p.ref, char*, t->buffer)); + else if(t->read) + return strlen(t->read(f->p.ref)); + return 0; } void fs_stat(Ixp9Req *r) { IxpMsg m; - Stat s; + IxpStat s; int size; char *buf; IxpFileId *f; - + f = r->fid->aux; if(!ixp_srv_verifyfile(f, lookup_file)) { - respond(r, Enofile); + ixp_respond(r, Enofile); return; } @@ -416,19 +420,21 @@ fs_stat(Ixp9Req *r) { ixp_pstat(&m, &s); r->ofcall.rstat.stat = (uchar*)m.data; - respond(r, nil); + ixp_respond(r, nil); } void fs_read(Ixp9Req *r) { char *buf; IxpFileId *f; - int n; + ActionTab *t; + int n, found; f = r->fid->aux; + found = 0; if(!ixp_srv_verifyfile(f, lookup_file)) { - respond(r, Enofile); + ixp_respond(r, Enofile); return; } @@ -441,53 +447,26 @@ fs_read(Ixp9Req *r) { ixp_pending_respond(r); return; } - switch(f->tab.type) { - case FsFprops: - ixp_srv_readbuf(r, f->p.client->props, strlen(f->p.client->props)); - respond(r, nil); - return; - case FsFColRules: - case FsFTagRules: - ixp_srv_readbuf(r, f->p.rule->string, f->p.rule->size); - respond(r, nil); - return; - case FsFKeys: - ixp_srv_readbuf(r, def.keys, def.keyssz); - respond(r, nil); - return; - case FsFCtags: - ixp_srv_readbuf(r, f->p.client->tags, strlen(f->p.client->tags)); - respond(r, nil); - return; - case FsFClabel: - ixp_srv_readbuf(r, f->p.client->name, strlen(f->p.client->name)); - respond(r, nil); - return; - case FsFBar: - ixp_srv_readbuf(r, f->p.bar->buf, strlen(f->p.bar->buf)); - respond(r, nil); - return; - case FsFRctl: - buf = readctl_root(); - ixp_srv_readbuf(r, buf, strlen(buf)); - respond(r, nil); - return; - case FsFCctl: - buf = readctl_client(f->p.client); - ixp_srv_readbuf(r, buf, strlen(buf)); - respond(r, nil); - return; - case FsFTindex: - buf = view_index(f->p.view); - ixp_srv_readbuf(r, buf, strlen(buf)); - respond(r, nil); - return; - case FsFTctl: - buf = readctl_view(f->p.view); - n = strlen(buf); + t = &actiontab[f->tab.type]; + if(f->tab.type < nelem(actiontab)) { + if(t->read) + buf = t->read(f->p.ref); + else if(t->buffer && t->max) + buf = structptr(f->p.ref, char, t->buffer); + else if(t->buffer) + buf = structmember(f->p.ref, char*, t->buffer); + else + goto done; + n = t->size ? structmember(f->p.ref, int, t->size) : strlen(buf); ixp_srv_readbuf(r, buf, n); - respond(r, nil); - return; + ixp_respond(r, nil); + found++; + } + done: + switch(f->tab.type) { + default: + if(found) + return; } } /* This should not be called if the file is not open for reading. */ @@ -496,93 +475,92 @@ fs_read(Ixp9Req *r) { void fs_write(Ixp9Req *r) { - MsgFunc mf; IxpFileId *f; + ActionTab *t; char *errstr; - char *p; - uint i; + int found; + found = 0; + errstr = nil; if(r->ifcall.io.count == 0) { - respond(r, nil); + ixp_respond(r, nil); return; } f = r->fid->aux; if(!ixp_srv_verifyfile(f, lookup_file)) { - respond(r, Enofile); + ixp_respond(r, Enofile); return; } switch(f->tab.type) { - case FsFColRules: - case FsFTagRules: - ixp_srv_writebuf(r, &f->p.rule->string, &f->p.rule->size, 0); - respond(r, nil); + case FsFCtags: + r->ofcall.io.count = r->ifcall.io.count; + ixp_srv_data2cstring(r); + client_applytags(f->p.client, r->ifcall.io.data); + ixp_respond(r, nil); return; - case FsFKeys: - ixp_srv_writebuf(r, &def.keys, &def.keyssz, 0); - respond(r, nil); + } + + if(waserror()) { + ixp_respond(r, ixp_errbuf()); return; + } + + t = &actiontab[f->tab.type]; + if(f->tab.type < nelem(actiontab)) { + if(t->msg) { + errstr = ixp_srv_writectl(r, t->msg); + r->ofcall.io.count = r->ifcall.io.count; + } + else if(t->buffer && t->max) + ixp_srv_writebuf(r, (char*[]){ structptr(f->p.ref, char, t->buffer) }, + t->size ? structptr(f->p.ref, uint, t->size) + : (uint[]){ strlen(structptr(f->p.ref, char, t->buffer)) }, + t->max); + else if(t->buffer) + ixp_srv_writebuf(r, structptr(f->p.ref, char*, t->buffer), + t->size ? structptr(f->p.ref, uint, t->size) : nil, + t->max); + else + goto done; + ixp_respond(r, errstr); + found++; + } +done: + switch(f->tab.type) { case FsFClabel: - ixp_srv_data2cstring(r); - utfecpy(f->p.client->name, - f->p.client->name+sizeof(client->name), - r->ifcall.io.data); frame_draw(f->p.client->sel); update_class(f->p.client); - r->ofcall.io.count = r->ifcall.io.count; - respond(r, nil); - return; + break; case FsFCtags: - ixp_srv_data2cstring(r); - client_applytags(f->p.client, r->ifcall.io.data); - r->ofcall.io.count = r->ifcall.io.count; - respond(r, nil); - return; - case FsFBar: - i = strlen(f->p.bar->buf); - p = f->p.bar->buf; - ixp_srv_writebuf(r, &p, &i, 279); - bar_load(f->p.bar); - r->ofcall.io.count = i - r->ifcall.io.offset; - respond(r, nil); - return; - case FsFCctl: - mf = (MsgFunc)message_client; - goto msg; - case FsFTctl: - mf = (MsgFunc)message_view; - goto msg; - case FsFRctl: - mf = (MsgFunc)message_root; - goto msg; - msg: - errstr = ixp_srv_writectl(r, mf); - r->ofcall.io.count = r->ifcall.io.count; - respond(r, errstr); - return; + client_applytags(f->p.client, f->p.client->tags); + break; case FsFEvent: if(r->ifcall.io.data[r->ifcall.io.count-1] == '\n') event("%.*s", (int)r->ifcall.io.count, r->ifcall.io.data); else event("%.*s\n", (int)r->ifcall.io.count, r->ifcall.io.data); r->ofcall.io.count = r->ifcall.io.count; - respond(r, nil); - return; + ixp_respond(r, nil); + break; + default: + /* This should not be called if the file is not open for writing. */ + if(!found) + die("Write called on an unwritable file"); } - /* - /* This should not be called if the file is not open for writing. */ - die("Write called on an unwritable file"); + poperror(); + return; } void fs_open(Ixp9Req *r) { IxpFileId *f; - + f = r->fid->aux; if(!ixp_srv_verifyfile(f, lookup_file)) { - respond(r, Enofile); + ixp_respond(r, Enofile); return; } @@ -600,37 +578,37 @@ fs_open(Ixp9Req *r) { || (r->ifcall.topen.mode&3) != OREAD && !(f->tab.perm & 0200) || (r->ifcall.topen.mode&3) != OWRITE && !(f->tab.perm & 0400) || (r->ifcall.topen.mode & ~(3|OAPPEND|OTRUNC))) - respond(r, Enoperm); + ixp_respond(r, Enoperm); else - respond(r, nil); + ixp_respond(r, nil); } void fs_create(Ixp9Req *r) { IxpFileId *f; - + f = r->fid->aux; switch(f->tab.type) { default: - respond(r, Enoperm); + ixp_respond(r, Enoperm); return; case FsDBars: if(!strlen(r->ifcall.tcreate.name)) { - respond(r, Ebadvalue); + ixp_respond(r, Ebadvalue); return; } bar_create(f->p.bar_p, r->ifcall.tcreate.name); f = lookup_file(f, r->ifcall.tcreate.name); if(!f) { - respond(r, Enofile); + ixp_respond(r, Enofile); return; } r->ofcall.ropen.qid.type = f->tab.qtype; r->ofcall.ropen.qid.path = QID(f->tab.type, f->id); f->next = r->fid->aux; r->fid->aux = f; - respond(r, nil); + ixp_respond(r, nil); break; } } @@ -639,34 +617,36 @@ void fs_remove(Ixp9Req *r) { IxpFileId *f; WMScreen *s; - + f = r->fid->aux; if(!ixp_srv_verifyfile(f, lookup_file)) { - respond(r, Enofile); + ixp_respond(r, Enofile); return; } - switch(f->tab.type) { default: - respond(r, Enoperm); + ixp_respond(r, Enoperm); return; case FsFBar: s = f->p.bar->screen; bar_destroy(f->next->p.bar_p, f->p.bar); bar_draw(s); - respond(r, nil); + break; + case FsDClient: + client_kill(f->p.client, true); break; } + ixp_respond(r, nil); } void fs_clunk(Ixp9Req *r) { IxpFileId *f; - + f = r->fid->aux; if(!ixp_srv_verifyfile(f, lookup_file)) { - respond(r, nil); + ixp_respond(r, nil); return; } @@ -681,21 +661,14 @@ fs_clunk(Ixp9Req *r) { switch(f->tab.type) { case FsFColRules: + case FsFRules: update_rules(&f->p.rule->rule, f->p.rule->string); break; - case FsFTagRules: - update_rules(&f->p.rule->rule, f->p.rule->string); - /* - for(c=client; c; c=c->next) - apply_rules(c); - view_update_all(); - */ - break; case FsFKeys: update_keys(); break; } - respond(r, nil); + ixp_respond(r, nil); } void @@ -708,12 +681,12 @@ fs_flush(Ixp9Req *r) { if(f->pending) ixp_pending_flush(r); /* else die() ? */ - respond(r->oldreq, Einterrupted); - respond(r, nil); + ixp_respond(r->oldreq, Einterrupted); + ixp_respond(r, nil); } void -fs_freefid(Fid *f) { +fs_freefid(IxpFid *f) { IxpFileId *id, *tid; tid = f->aux; diff --git a/cmd/wmii/geom.c b/cmd/wmii/geom.c deleted file mode 100644 index 464eb67..0000000 --- a/cmd/wmii/geom.c +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail> - * See LICENSE file for license details. - */ -#include "dat.h" -#include "fns.h" - -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); -} - -bool -rect_intersect_p(Rectangle r, Rectangle r2) { - return r.min.x <= r2.max.x - && r.max.x >= r2.min.x - && r.min.y <= r2.max.y - && r.max.y >= r2.min.y; -} - -Rectangle -rect_intersection(Rectangle r, Rectangle r2) { - Rectangle ret; - - /* ret != canonrect(ret) ≡ no intersection. */ - ret.min.x = max(r.min.x, r2.min.x); - ret.max.x = min(r.max.x, r2.max.x); - ret.min.y = max(r.min.y, r2.min.y); - ret.max.y = min(r.max.y, r2.max.y); - return ret; -} - -bool -rect_contains_p(Rectangle r, Rectangle r2) { - return r2.min.x >= r.min.x - && r2.max.x <= r.max.x - && r2.min.y >= r.min.y - && r2.max.y <= r.max.y; -} - -Align -quadrant(Rectangle r, Point pt) { - Align ret; - - pt = subpt(pt, r.min); - ret = 0; - - if(pt.x >= Dx(r) * .5) - ret |= East; - if(pt.x <= Dx(r) * .5) - ret |= West; - if(pt.y <= Dy(r) * .5) - ret |= North; - if(pt.y >= Dy(r) * .5) - ret |= South; - - return ret; -} - -Cursor -quad_cursor(Align align) { - switch(align) { - case NEast: return cursor[CurNECorner]; - case NWest: return cursor[CurNWCorner]; - case SEast: return cursor[CurSECorner]; - case SWest: return cursor[CurSWCorner]; - case South: - case North: return cursor[CurDVArrow]; - case East: - case West: return cursor[CurDHArrow]; - default: return cursor[CurMove]; - } -} - -Align -get_sticky(Rectangle src, Rectangle dst) { - Align corner; - - corner = 0; - if(src.min.x != dst.min.x - && src.max.x == dst.max.x) - corner |= East; - else - corner |= West; - - if(src.min.y != dst.min.y - && src.max.y == dst.max.y) - corner |= South; - else - corner |= North; - - return corner; -} - diff --git a/cmd/wmii/key.c b/cmd/wmii/key.c index f2c3471..34836e9 100644 --- a/cmd/wmii/key.c +++ b/cmd/wmii/key.c @@ -6,30 +6,6 @@ #include <X11/keysym.h> #include "fns.h" -void -init_lock_keys(void) { - static int masks[] = { - ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, - Mod3Mask, Mod4Mask, Mod5Mask - }; - XModifierKeymap *modmap; - KeyCode numlock; - int i, max; - - numlock_mask = 0; - modmap = XGetModifierMapping(display); - numlock = keycode("Num_Lock"); - if(numlock) - if(modmap && modmap->max_keypermod > 0) { - max = nelem(masks) * modmap->max_keypermod; - for(i = 0; i < max; i++) - if(modmap->modifiermap[i] == numlock) - numlock_mask = masks[i / modmap->max_keypermod]; - } - XFreeModifiermap(modmap); - valid_mask = 255 & ~(numlock_mask | LockMask); -} - static void freekey(Key *k) { Key *n; @@ -43,7 +19,7 @@ freekey(Key *k) { static void _grab(XWindow w, int keycode, uint mod) { XGrabKey(display, keycode, mod, w, - true, GrabModeAsync, GrabModeAsync); + true, GrabModeAsync, GrabModeAsync); } static void @@ -66,12 +42,12 @@ ungrabkey(Key *k) { } } -static Key * +static Key* name2key(const char *name) { Key *k; for(k=key; k; k=k->lnext) - if(!strncmp(k->name, name, sizeof k->name)) + if(!strcmp(k->name, name)) return k; return nil; } @@ -129,7 +105,7 @@ next_keystroke(ulong *mod, KeyCode *code) { do { XMaskEvent(display, KeyPressMask, &e); *mod |= e.xkey.state & valid_mask; - *code = (KeyCode) e.xkey.keycode; + *code = (KeyCode)e.xkey.keycode; sym = XKeycodeToKeysym(display, e.xkey.keycode, 0); } while(IsModifierKey(sym)); } @@ -143,9 +119,8 @@ fake_keypress(ulong mod, KeyCode key) { if(c == nil || c->w.xid == 0) return; - e.time = CurrentTime; + e.time = event_xtime; e.window = c->w.xid; - e.display = display; e.state = mod; e.keycode = key; @@ -160,7 +135,7 @@ fake_keypress(ulong mod, KeyCode key) { static Key * match_keys(Key *k, ulong mod, KeyCode keycode, bool seq) { Key *ret, *next; - volatile int i; /* shut up ken */ + int i; /* shut up ken */ ret = nil; for(next = k->tnext; k; i = (k=next) && (next=k->tnext)) { @@ -171,6 +146,7 @@ match_keys(Key *k, ulong mod, KeyCode keycode, bool seq) { ret = k; } } + USED(i); return ret; } @@ -208,7 +184,7 @@ kpress(XWindow w, ulong mod, KeyCode keycode) { event("Key %s\n", found->name); else { XGrabKeyboard(display, w, true, GrabModeAsync, GrabModeAsync, CurrentTime); - flushevents(FocusChangeMask, true); + event_flush(FocusChangeMask, true); kpress_seq(w, found); XUngrabKeyboard(display, CurrentTime); } @@ -219,22 +195,21 @@ update_keys(void) { Key *k; char *l, *p; - init_lock_keys(); + numlock_mask = numlockmask(); + valid_mask = 0xff & ~(numlock_mask | LockMask); while((k = key)) { key = key->lnext; ungrabkey(k); freekey(k); } - for(l = p = def.keys; p && *p;) { + for(l = p = def.keys; p && *p; p++) { if(*p == '\n') { *p = 0; if((k = getkey(l))) grabkey(k); *p = '\n'; - l = ++p; + l = p + 1; } - else - p++; } if(l < p && strlen(l)) { if((k = getkey(l))) diff --git a/cmd/wmii/layout.c b/cmd/wmii/layout.c index eb70302..9c0682d 100644 --- a/cmd/wmii/layout.c +++ b/cmd/wmii/layout.c @@ -48,7 +48,7 @@ framerect(Framewin *f) { r = rectaddpt(r, f->pt); scrn = f->screen; - if (scrn == -1) + if(scrn == -1) scrn = max(ownerscreen(f->f->r), 0); /* Keep onscreen */ @@ -72,7 +72,7 @@ framewin(Frame *f, Point pt, int orientation, int n) { Framewin *fw; fw = emallocz(sizeof *fw); - wa.override_redirect = true; + wa.override_redirect = true; wa.event_mask = ExposureMask; fw->w = createwindow(&scr.root, Rect(0, 0, 1, 1), scr.depth, InputOutput, @@ -86,10 +86,9 @@ framewin(Frame *f, Point pt, int orientation, int n) { frameadjust(fw, pt, orientation, n); reshapewin(fw->w, framerect(fw)); - mapwin(fw->w); raisewin(fw->w); - return fw; + return fw; } static void @@ -98,26 +97,27 @@ framedestroy(Framewin *f) { free(f); } -static void -expose_event(Window *w, XExposeEvent *e) { +static bool +expose_event(Window *w, void *aux, XExposeEvent *e) { Rectangle r; Framewin *f; Image *buf; CTuple *c; - + USED(e); - f = w->aux; + f = aux; c = &def.focuscolor; buf = disp.ibuf; - + r = rectsubpt(w->r, w->r.min); - fill(buf, r, c->bg); - border(buf, r, 1, c->border); - border(buf, f->grabbox, 1, c->border); - border(buf, insetrect(f->grabbox, -f->grabbox.min.x), 1, c->border); + fill(buf, r, &c->bg); + border(buf, r, 1, &c->border); + border(buf, f->grabbox, 1, &c->border); + border(buf, insetrect(f->grabbox, -f->grabbox.min.x), 1, &c->border); - copyimage(w, r, buf, ZP); + copyimage(w, r, buf, ZP); + return false; } static Handlers handlers = { @@ -132,7 +132,7 @@ find_area(Point pt) { v = selview; for(s=0; s < nscreens; s++) { - if(!rect_haspoint_p(pt, screens[s]->r)) + if(!rect_haspoint_p(screens[s]->r, pt)) continue; for(a=v->areas[s]; a; a=a->next) if(pt.x < a->r.max.x) @@ -147,12 +147,9 @@ vplace(Framewin *fw, Point pt) { Rectangle r; Frame *f; Area *a; - View *v; long l; int hr; - v = selview; - a = find_area(pt); if(a == nil) return; @@ -200,10 +197,7 @@ done: static void hplace(Framewin *fw, Point pt) { Area *a; - View *v; int minw; - - v = selview; a = find_area(pt); if(a == nil) @@ -223,7 +217,7 @@ hplace(Framewin *fw, Point pt) { pt.y = a->r.min.y; frameadjust(fw, pt, OVert, Dy(a->r)); - reshapewin(fw->w, framerect(fw)); + reshapewin(fw->w, framerect(fw)); } static Point @@ -236,9 +230,9 @@ grabboxcenter(Frame *f) { return p; } -static int tvcol(Frame*); -static int thcol(Frame*); -static int tfloat(Frame*); +static int tvcol(Frame*, bool); +static int thcol(Frame*, bool); +static int tfloat(Frame*, bool); enum { TDone, @@ -247,7 +241,7 @@ enum { TFloat, }; -static int (*tramp[])(Frame*) = { +static int (*tramp[])(Frame*, bool) = { 0, tvcol, thcol, @@ -260,18 +254,26 @@ static int (*tramp[])(Frame*) = { */ static void trampoline(int fn, Frame *f, bool grabbox) { + int moved; + moved = 0; while(fn > 0) { - resizing = fn != TFloat; - view_update(f->view); if(grabbox) warppointer(grabboxcenter(f)); //f->collapsed = false; - fn = tramp[fn](f); + fn = tramp[fn](f, moved++); } ungrabpointer(); - resizing = false; - view_update(f->view); +} + +static void +resizemode(int mode) { + bool orig; + + orig = resizing; + resizing = mode && mode != TFloat; + if(resizing != orig) + view_update(selview); } void @@ -369,10 +371,13 @@ column_openstack(Area *a, Frame *f, int h) { static void column_drop(Area *a, Frame *f, int y) { Frame *ff; - int dy; + int dy, extra_y; - for(ff=a->frame; ff; ff=ff->anext) + extra_y = Dy(a->r); + for(ff=a->frame; ff; ff=ff->anext) { assert(ff != f); + extra_y -= Dy(ff->colr); + } if(a->frame == nil || y <= a->frame->r.min.y) { f->collapsed = true; @@ -395,14 +400,14 @@ column_drop(Area *a, Frame *f, int y) { column_openstack(a, ff, labelh(def.font) - dy); }else { f->colr.min.y = y; - f->colr.max.y = ff->colr.max.y; + f->colr.max.y = ff->colr.max.y + extra_y; ff->colr.max.y = y; } column_insert(a, f, ff); } static int -thcol(Frame *f) { +thcol(Frame *f, bool moved) { Framewin *fw; Frame *fp, *fn; Area *a; @@ -413,21 +418,32 @@ thcol(Frame *f) { focus(f->client, false); ret = TDone; - if(!grabpointer(&scr.root, nil, cursor[CurIcon], MouseMask)) + if(!grabpointer(&scr.root, nil, None, MouseMask)) return TDone; - pt = querypointer(&scr.root); + readmotion(&pt); pt2.x = f->area->r.min.x; pt2.y = pt.y; fw = framewin(f, pt2, OHoriz, Dx(f->area->r)); + if(moved) + goto casemotion; + vplace(fw, pt); for(;;) switch (readmouse(&pt, &button)) { case MotionNotify: + casemotion: + moved = 1; + resizemode(THCol); + if(mapwin(fw->w)) + grabpointer(&scr.root, nil, cursor[CurIcon], MouseMask); vplace(fw, pt); break; case ButtonRelease: + if(!moved) + goto done; + if(button != 1) continue; SET(collapsed); @@ -476,15 +492,15 @@ thcol(Frame *f) { goto done; } done: + resizemode(0); framedestroy(fw); return ret; } static int -tvcol(Frame *f) { +tvcol(Frame *f, bool moved) { Framewin *fw; Window *cwin; - WinAttr wa; Rectangle r; Point pt, pt2; uint button; @@ -499,20 +515,24 @@ tvcol(Frame *f) { scrn = f->area->screen > -1 ? f->area->screen : find_area(pt) ? find_area(pt)->screen : 0; r = f->view->r[scrn]; fw = framewin(f, pt2, OVert, Dy(r)); + mapwin(fw->w); r.min.y += fw->grabbox.min.y + Dy(fw->grabbox)/2; r.max.y = r.min.y + 1; - cwin = createwindow(&scr.root, r, 0, InputOnly, &wa, 0); + cwin = createwindow(&scr.root, r, 0, InputOnly, nil, 0); mapwin(cwin); ret = TDone; if(!grabpointer(&scr.root, cwin, cursor[CurIcon], MouseMask)) goto done; + resizemode(TVCol); + hplace(fw, pt); for(;;) switch (readmouse(&pt, &button)) { case MotionNotify: + moved = 1; hplace(fw, pt); continue; case ButtonPress: @@ -536,11 +556,12 @@ tvcol(Frame *f) { done: framedestroy(fw); destroywindow(cwin); + resizemode(0); return ret; } static int -tfloat(Frame *f) { +tfloat(Frame *f, bool moved) { Rectangle *rects; Rectangle frect, origin; Point pt, pt1; @@ -556,9 +577,12 @@ tfloat(Frame *f) { else if(f->aprev) f->aprev->colr.max.y = f->colr.max.y; area_moveto(f->view->floating, f); + view_update(f->view); + warppointer(grabboxcenter(f)); } - map_frame(f->client); - focus(f->client, false); + client_mapframe(f->client); + if(!f->collapsed) + focus(f->client, false); ret = TDone; if(!grabpointer(c->framewin, nil, cursor[CurMove], MouseMask)) @@ -568,7 +592,10 @@ tfloat(Frame *f) { origin = f->r; frect = f->r; - pt = querypointer(&scr.root); + if(!readmotion(&pt)) { + focus(f->client, false); + goto done; + } /* pt1 = grabboxcenter(f); */ pt1 = pt; goto case_motion; @@ -578,6 +605,7 @@ shut_up_ken: switch (readmouse(&pt, &button)) { default: goto shut_up_ken; case MotionNotify: + moved = 1; case_motion: origin = rectaddpt(origin, subpt(pt, pt1)); origin = constrain(origin, -1); @@ -593,11 +621,15 @@ shut_up_ken: case ButtonRelease: if(button != 1) continue; + if(!moved) { + f->collapsed = !f->collapsed; + client_resize(f->client, f->floatr); + } goto done; case ButtonPress: if(button != 3) continue; - unmap_frame(f->client); + client_unmapframe(f->client); ret = THCol; goto done; } diff --git a/cmd/wmii/main.c b/cmd/wmii/main.c index fba5d5f..e58b858 100644 --- a/cmd/wmii/main.c +++ b/cmd/wmii/main.c @@ -12,7 +12,6 @@ #include <pwd.h> #include <sys/signal.h> #include <sys/stat.h> -#include <unistd.h> #include "fns.h" static const char @@ -43,24 +42,22 @@ scan_wins(void) { uint num; XWindow *wins; XWindowAttributes wa; - XWindow d1, d2; + XWindow root, parent; - if(XQueryTree(display, scr.root.xid, &d1, &d2, &wins, &num)) { + if(XQueryTree(display, scr.root.xid, &root, &parent, &wins, &num)) { for(i = 0; i < num; i++) { - if(!XGetWindowAttributes(display, wins[i], &wa)) - continue; - /* Skip transients. */ - if(wa.override_redirect || XGetTransientForHint(display, wins[i], &d1)) + if(!XGetWindowAttributes(display, wins[i], &wa) || wa.override_redirect) continue; + if(!XGetTransientForHint(display, wins[i], &parent)) if(wa.map_state == IsViewable) client_create(wins[i], &wa); } /* Manage transients. */ for(i = 0; i < num; i++) { - if(!XGetWindowAttributes(display, wins[i], &wa)) + if(!XGetWindowAttributes(display, wins[i], &wa) || wa.override_redirect) continue; - if((XGetTransientForHint(display, wins[i], &d1)) - && (wa.map_state == IsViewable)) + if(XGetTransientForHint(display, wins[i], &parent)) + if(wa.map_state == IsViewable) client_create(wins[i], &wa); } } @@ -95,9 +92,9 @@ init_environment(void) { setenv("WMII_ADDRESS", address, true); else address = smprint("unix!%s/wmii", ns_path); - setenv("WMII_CONFPATH", sxprint("%s/.wmii%s:%s/wmii%s", - getenv("HOME"), CONFVERSION, - CONFPREFIX, CONFVERSION), true); + setenv("WMII_CONFPATH", + sxprint("%s/.%s:%s", getenv("HOME"), CONFDIR, GLOBALCONF), + true); } static void @@ -163,6 +160,7 @@ regerror(char *err) { void init_screens(void) { + static int old_n, old_nscreens; Rectangle *rects; View *v; int i, n, m; @@ -178,35 +176,29 @@ init_screens(void) { /* Reallocate screens, zero any new ones. */ rects = xinerama_screens(&n); - m = max(n, nscreens); - screens = erealloc(screens, (m + 1) * sizeof *screens); - screens[m] = nil; + m = nscreens; + nscreens = max(n, nscreens); + screens = erealloc(screens, (nscreens + 1) * sizeof *screens); + screens[nscreens] = nil; for(v=view; v; v=v->next) { - v->areas = erealloc(v->areas, m * sizeof *v->areas); - v->r = erealloc(v->r, m * sizeof *v->r); - v->pad = erealloc(v->pad, m * sizeof *v->pad); + v->areas = erealloc(v->areas, nscreens * sizeof *v->areas); + v->r = erealloc(v->r, nscreens * sizeof *v->r); + v->pad = erealloc(v->pad, nscreens * sizeof *v->pad); } - for(i=nscreens; i < m; i++) { - screens[i] = emallocz(sizeof *screens[i]); - for(v=view; v; v=v->next) - view_init(v, i); - } - - nscreens = m; - /* Reallocate buffers. */ - freeimage(ibuf); - freeimage(ibuf32); - ibuf = allocimage(Dx(scr.rect), Dy(scr.rect), scr.depth); - ibuf32 = nil; /* Probably shouldn't do this until it's needed. */ + freeimage(disp.ibuf); + freeimage(disp.ibuf32); + disp.ibuf = allocimage(Dx(scr.rect), Dy(scr.rect), scr.depth); + disp.ibuf32 = nil; /* Probably shouldn't do this until it's needed. */ if(render_visual) - ibuf32 = allocimage(Dx(scr.rect), Dy(scr.rect), 32); - disp.ibuf = ibuf; - disp.ibuf32 = ibuf32; + disp.ibuf32 = allocimage(Dx(scr.rect), Dy(scr.rect), 32); /* Resize and initialize screens. */ for(i=0; i < nscreens; i++) { + if(i >= m) + screens[i] = emallocz(sizeof *screens[i]); + screen = screens[i]; screen->idx = i; @@ -215,12 +207,20 @@ init_screens(void) { screen->r = rects[i]; else screen->r = rectsetorigin(screen->r, scr.rect.max); + if(i >= m) + for(v=view; v; v=v->next) + view_init(v, i); def.snap = Dy(screen->r) / 63; bar_init(screens[i]); } screen = screens[0]; if(selview) view_update(selview); + + if (old_n != n || old_nscreens != nscreens) + event("ScreenChange %d %d\n", n, nscreens); + old_n = n; + old_nscreens = nscreens; } static void @@ -320,13 +320,6 @@ spawn_command(const char *cmd) { } static void -check_preselect(IxpServer *s) { - USED(s); - - check_x_event(nil); -} - -static void closedisplay(IxpConn *c) { USED(c); @@ -340,17 +333,18 @@ printfcall(IxpFcall *f) { int main(int argc, char *argv[]) { - IxpMsg m; char **oargv; - char *wmiirc, *s; + char *wmiirc; int i; - quotefmtinstall(); + IXP_ASSERT_VERSION; + + setlocale(LC_CTYPE, ""); fmtinstall('r', errfmt); fmtinstall('a', afmt); fmtinstall('C', Cfmt); -extern int fmtevent(Fmt*); fmtinstall('E', fmtevent); + quotefmtinstall(); wmiirc = "wmiirc"; @@ -363,12 +357,13 @@ extern int fmtevent(Fmt*); wmiirc = EARGF(usage()); break; case 'v': - print("%s", version); + lprint(1, "%s", version); exit(0); case 'D': - s = EARGF(usage()); - m = ixp_message(s, strlen(s), 0); - msg_debug(&m); + if(waserror()) + fatal("parsing debug flags: %r"); + msg_debug(EARGF(usage())); + poperror(); break; default: usage(); @@ -378,19 +373,18 @@ extern int fmtevent(Fmt*); if(argc) usage(); - setlocale(LC_CTYPE, ""); starting = true; initdisplay(); traperrors(true); - selectinput(&scr.root, EnterWindowMask - | SubstructureRedirectMask); + selectinput(&scr.root, SubstructureRedirectMask); if(traperrors(false)) fatal("another window manager is already running"); passwd = getpwuid(getuid()); user = estrdup(passwd->pw_name); + gethostname(hostname, sizeof(hostname) - 1); init_environment(); @@ -399,7 +393,7 @@ extern int fmtevent(Fmt*); sock = ixp_announce(address); if(sock < 0) - fatal("Can't create socket '%s': %r", address); + fatal("Can't create socket %q: %r", address); closeexec(ConnectionNumber(display)); closeexec(sock); @@ -408,13 +402,15 @@ extern int fmtevent(Fmt*); init_traps(); init_cursors(); - init_lock_keys(); + update_keys(); ewmh_init(); xext_init(); - srv.preselect = check_preselect; - ixp_listen(&srv, sock, &p9srv, serve_9pcon, nil); - ixp_listen(&srv, ConnectionNumber(display), nil, check_x_event, closedisplay); + event_debug = debug_event; + + srv.preselect = event_preselect; + ixp_listen(&srv, sock, &p9srv, ixp_serve9conn, nil); + ixp_listen(&srv, ConnectionNumber(display), nil, event_fdready, closedisplay); def.border = 1; def.colmode = Colstack; @@ -422,10 +418,9 @@ extern int fmtevent(Fmt*); def.incmode = ISqueeze; def.mod = Mod1Mask; - strcpy(def.grabmod, "Mod1"); - loadcolor(&def.focuscolor, FOCUSCOLORS); - loadcolor(&def.normcolor, NORMCOLORS); + loadcolor(&def.focuscolor, FOCUSCOLORS, nil); + loadcolor(&def.normcolor, NORMCOLORS, nil); disp.sel = pointerscreen(); diff --git a/cmd/wmii/map.c b/cmd/wmii/map.c deleted file mode 100644 index 08b137a..0000000 --- a/cmd/wmii/map.c +++ /dev/null @@ -1,126 +0,0 @@ -/* Written by Kris Maglione */ -/* Public domain */ -#include "dat.h" -#include "fns.h" - -/* Edit s/^([a-zA-Z].*)\n([a-z].*) {/\1 \2;/g x/^([^a-zA-Z]|static|$)/-+d s/ (\*map|val|*str)//g */ - -struct MapEnt { - ulong hash; - const char* key; - void* val; - MapEnt* next; -}; - -MapEnt *NM; - -/* By Dan Bernstein. Public domain. */ -static ulong -hash(const char *str) { - ulong h; - - h = 5381; - while (*str != '\0') { - h += h << 5; /* h *= 33 */ - h ^= *str++; - } - return h; -} - -static void -insert(MapEnt **e, ulong val, const char *key) { - MapEnt *te; - - te = emallocz(sizeof *te); - te->hash = val; - te->key = key; - te->next = *e; - *e = te; -} - -static MapEnt** -map_getp(Map *map, ulong val, int create) { - MapEnt **e; - - e = &map->bucket[val%map->nhash]; - for(; *e; e = &(*e)->next) - if((*e)->hash >= val) break; - if(*e == nil || (*e)->hash != val) { - if(create) - insert(e, val, nil); - else - e = &NM; - } - return e; -} - -static MapEnt** -hash_getp(Map *map, const char *str, int create) { - MapEnt **e; - ulong h; - int cmp; - - h = hash(str); - e = map_getp(map, h, create); - if(*e && (*e)->key == nil) - (*e)->key = str; - else { - SET(cmp); - for(; *e; e = &(*e)->next) - if((*e)->hash > h || (cmp = strcmp((*e)->key, str)) >= 0) - break; - if(*e == nil || (*e)->hash > h || cmp > 0) - if(create) - insert(e, h, str); - } - return e; -} - -void** -map_get(Map *map, ulong val, bool create) { - MapEnt *e; - - e = *map_getp(map, val, create); - return e ? &e->val : nil; -} - -void** -hash_get(Map *map, const char *str, bool create) { - MapEnt *e; - - e = *hash_getp(map, str, create); - return e ? &e->val : nil; -} - -void* -map_rm(Map *map, ulong val) { - MapEnt **e, *te; - void *ret; - - ret = nil; - e = map_getp(map, val, 0); - if(*e) { - te = *e; - ret = te->val; - *e = te->next; - free(te); - } - return ret; -} - -void* -hash_rm(Map *map, const char *str) { - MapEnt **e, *te; - void *ret; - - ret = nil; - e = hash_getp(map, str, 0); - if(*e) { - te = *e; - ret = te->val; - *e = te->next; - free(te); - } - return ret; -} - diff --git a/cmd/wmii/message.c b/cmd/wmii/message.c index d1dd4a7..d392ad0 100644 --- a/cmd/wmii/message.c +++ b/cmd/wmii/message.c @@ -15,7 +15,7 @@ static char* msg_sendframe(Frame*, int, bool); s == LDOWN ? South : \ s == LLEFT ? West : \ s == LRIGHT ? East : \ - (abort(), 0)) + (error(Ebadvalue), 0)) static char Ebadcmd[] = "bad command", @@ -24,22 +24,26 @@ static char /* Edit |sort Edit |sed 's/"([^"]+)"/L\1/g' | tr 'a-z' 'A-Z' */ enum { - LFULLSCREEN, - LURGENT, + LALLOW, LBAR, LBORDER, LCLIENT, LCOLMODE, + LCOLORS, LDEBUG, LDOWN, LEXEC, + LFLOATING, LFOCUSCOLORS, LFONT, LFONTPAD, + LFULLSCREEN, LGRABMOD, + LGROUP, LGROW, LINCMODE, LKILL, + LLABEL, LLEFT, LNORMCOLORS, LNUDGE, @@ -53,28 +57,34 @@ enum { LSLAY, LSPAWN, LSWAP, + LTAGS, LTOGGLE, LUP, + LURGENT, LVIEW, LTILDE, }; char *symtab[] = { - "Fullscreen", - "Urgent", + "allow", "bar", "border", "client", "colmode", + "colors", "debug", "down", "exec", + "floating", "focuscolors", "font", "fontpad", + "fullscreen", "grabmod", + "group", "grow", "incmode", "kill", + "label", "left", "normcolors", "nudge", @@ -88,35 +98,39 @@ char *symtab[] = { "slay", "spawn", "swap", + "tags", "toggle", "up", + "urgent", "view", "~", }; +static char* barpostab[] = { + "bottom", "top", +}; char* debugtab[] = { "9p", "dnd", "event", + "events", "ewmh", "focus", "generic", "stack", + nil }; - -static char* barpostab[] = { - "bottom", - "top", +static char* permtab[] = { + "activate", nil }; static char* incmodetab[] = { - "ignore", - "show", - "squeeze", + "ignore", "show", "squeeze", +}; +static char* floatingtab[] = { + "never", "off", "on", "always" }; static char* toggletab[] = { - "off", - "on", - "toggle", + "off", "on", "toggle", }; /* Edit ,y/^[a-zA-Z].*\n.* {\n/d @@ -125,17 +139,30 @@ static char* toggletab[] = { */ static int -_bsearch(char *s, char **tab, int ntab) { +_bsearch(char *from, char **tab, int ntab) { int i, n, m, cmp; + char *to, *end; + Rune r; - if(s == nil) + if(from == nil) return -1; + end = buffer + sizeof buffer - UTFmax - 1; + for(to=buffer; *from && to < end;) { + from += chartorune(&r, from); + if(r != 0x80) { + r = tolowerrune(r); + to += runetochar(to, &r); + } + } + *to = '\0'; + to = buffer; + n = ntab; i = 0; while(n) { m = n/2; - cmp = strcmp(s, tab[i+m]); + cmp = strcmp(to, tab[i+m]); if(cmp == 0) return i+m; if(cmp < 0 || m == 0) @@ -149,48 +176,72 @@ _bsearch(char *s, char **tab, int ntab) { } static int +_lsearch(char *from, char **tab, int ntab) { + int i; + + if(from != nil) + for(i=0; i < ntab; i++) + if(!strcmp(from, tab[i])) + return i; + error(Ebadvalue); + return 0; +} + +static int getsym(char *s) { return _bsearch(s, symtab, nelem(symtab)); } -static bool +static void setdef(int *ptr, char *s, char *tab[], int ntab) { int i; i = _bsearch(s, tab, ntab); - if(i >= 0) - *ptr = i; - return i >= 0; + if(i < 0) + error(Ebadvalue); + *ptr = i; } static int gettoggle(char *s) { - switch(getsym(s)) { - case LON: return On; - case LOFF: return Off; - case LTOGGLE: return Toggle; - default: - return -1; - } + return _lsearch(s, toggletab, nelem(toggletab)); } static int getdirection(IxpMsg *m) { int i; - switch(i = getsym(msg_getword(m))) { + switch(i = getsym(msg_getword(m, 0))) { case LLEFT: case LRIGHT: case LUP: case LDOWN: return i; - default: - return -1; } + error(Ebadusage); + return -1; } -static void -eatrunes(IxpMsg *m, int (*p)(Rune), int val) { +static ulong +msg_getulong(const char *s) { + ulong l; + + if(!(s && getulong(s, &l))) + error(Ebadvalue); + return l; +} + +static long +msg_getlong(const char *s) { + long l; + + if(!(s && getlong(s, &l))) + error(Ebadvalue); + return l; +} + +void +msg_eatrunes(IxpMsg *m, int (*p)(Rune), int val) { Rune r; int n; @@ -205,18 +256,18 @@ eatrunes(IxpMsg *m, int (*p)(Rune), int val) { } char* -msg_getword(IxpMsg *m) { +msg_getword(IxpMsg *m, char *errmsg) { char *ret; Rune r; int n; - eatrunes(m, isspacerune, true); + msg_eatrunes(m, isspacerune, true); ret = m->pos; - eatrunes(m, isspacerune, false); + msg_eatrunes(m, isspacerune, false); n = chartorune(&r, m->pos); *m->pos = '\0'; m->pos += n; - eatrunes(m, isspacerune, true); + msg_eatrunes(m, isspacerune, true); /* Filter out comments. */ if(*ret == '#') { @@ -227,123 +278,116 @@ msg_getword(IxpMsg *m) { if(ret[1] == '\\' || ret[1] == '#') ret++; if(*ret == '\0') - return nil; + ret = nil; + if(ret == nil && errmsg) + error(errmsg); return ret; } -#define strbcmp(str, const) (strncmp((str), (const), sizeof(const)-1)) +typedef struct Mask Mask; +struct Mask { + long* mask; + char** table; +}; + 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; +Mfmt(Fmt *f) { + Mask m; - 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; + m = va_arg(f->args, Mask); + return unmask(f, *m.mask, m.table, '+'); } -static bool -getint(const char *s, int *ret) { - long l; - bool res; - - res = getlong(s, &l); - *ret = l; - return res; -} +char* +mask(char **s, int *add, int *old) { + static char seps[] = "+-^"; + char *p, *q; -bool -getlong(const char *s, long *ret) { - const char *end; - char *rend; - int base; - long sign; +again: + p = *s; + if(*old == '\0') + return nil; + *add = *old; + + if(*p == '/') { + /* Check for regex. */ + if(!(q = strchr(p+1, '/'))) + goto fail; + if(*q++ != '/' || !memchr(seps, (*old=*q), sizeof seps)) + goto fail; + } + else { + for(q=p; (*old=*q) && !strchr(seps, *q);) + q++; + if(memchr(p, '/', q-p)) + goto fail; + } - if(s == nil) - return false; - end = s+strlen(s); - base = getbase(&s, &sign); - if(sign == 0) - return false; - - *ret = sign * strtol(s, &rend, base); - return (end == rend); + *q++ = '\0'; + *s = q; + if(p + 1 == q) + goto again; + return p; +fail: + while((*old=*q) && !strchr(seps, *q)) + q++; + goto again; } -bool -getulong(const char *s, ulong *ret) { - const char *end; - char *rend; - int base; - long sign; +static void +setmask(Mask m, char *s) { + char *opt; + int add, old, i, n; + long newmask; if(s == nil) - return false; - end = s+strlen(s); - base = getbase(&s, &sign); - if(sign < 1) - return false; - - *ret = strtoul(s, &rend, base); - return (end == rend); + s = ""; + for(n=0; m.table[n]; n++) + ; + newmask = memchr("+-^", s[0], 3) ? *m.mask : 0L; + + old = '+'; + while((opt = mask(&s, &add, &old))) { + i = _bsearch(opt, m.table, n); + if(i == -1) + error(Ebadvalue); + else if(add = '^') + newmask ^= 1<<i; + else if(add == '+') + newmask |= 1<<i; + else if(add == '-') + newmask &= ~(1<<i); + } + *m.mask = newmask; } -static char* -strend(char *s, int n) { - int len; - - len = strlen(s); - return s + max(0, len - n); +void +msg_debug(char *s) { + setmask((Mask){&debugflag, debugtab}, s); } static Client* strclient(View *v, char *s) { - ulong id; + Client *c; /* * sel * 0x<window xid> */ - if(s == nil) - return nil; - if(!strcmp(s, "sel")) - return view_selclient(v); - if(getulong(s, &id)) - return win2client(id); - - return nil; + if(s && !strcmp(s, "sel")) + c = view_selclient(v); + else + c = win2client(msg_getulong(s)); + if(c == nil) + error(Ebadvalue); + return c; } Area* -strarea(View *v, ulong scrn, const char *s) { +strarea(View *v, ulong scrn, const char *area) { Area *a; + const char *screen; char *p; long i; @@ -353,29 +397,38 @@ strarea(View *v, ulong scrn, const char *s) { * <column number> */ - if(s == nil) - return nil; + if(area == nil) + error(Ebadvalue); - if((p = strchr(s, ':'))) { + if((p = strchr(area, ':'))) { + /* <screen>:<area> */ *p++ = '\0'; - if(!strcmp(s, "sel")) + screen = area; + area = p; + + if(!strcmp(screen, "sel")) scrn = v->selscreen; - else if(!getulong(s, &scrn)) - return nil; - s = p; + else + scrn = msg_getulong(screen); } - else if(!strcmp(s, "sel")) + else if(!strcmp(area, "sel")) return v->sel; - if(!strcmp(s, "sel")) { + if(!strcmp(area, "sel")) { if(scrn != v->selscreen) - return nil; + error(Ebadvalue); return v->sel; } - if(!strcmp(s, "~")) + + if(!strcmp(area, "~")) return v->floating; - if(scrn < 0 || !getlong(s, &i) || i == 0) - return nil; + + if(scrn < 0) + error(Ebadvalue); + + i = msg_getlong(area); + if(i == 0) + error(Ebadvalue); if(i > 0) { for(a = v->areas[scrn]; a; a = a->next) @@ -388,53 +441,81 @@ strarea(View *v, ulong scrn, const char *s) { for(; a; a = a->prev) if(++i == 0) break; } + if(a == nil) + error(Ebadvalue); return a; } static Frame* getframe(View *v, int scrn, IxpMsg *m) { - Client *c; Frame *f; Area *a; char *s; ulong l; - s = msg_getword(m); - if(!s || !strcmp(s, "client")) { - c = strclient(v, msg_getword(m)); - if(c == nil) - return nil; - return client_viewframe(c, v); - } + s = msg_getword(m, Ebadvalue); + if(!strcmp(s, "client")) + f = client_viewframe(strclient(v, msg_getword(m, Ebadvalue)), + v); + else { + /* XXX: Multihead */ + a = strarea(v, scrn, s); - /* XXX: Multihead */ - a = strarea(v, scrn, s); - if(a == nil) { - fprint(2, "a == nil\n"); - return nil; + s = msg_getword(m, Ebadvalue); + f = nil; + if(!strcmp(s, "sel")) + f = a->sel; + else { + l = msg_getulong(s); + for(f=a->frame; f; f=f->anext) + if(--l == 0) break; + } } - - s = msg_getword(m); - if(!s) - return nil; - if(!strcmp(s, "sel")) - return a->sel; - if(!getulong(s, &l)) - return nil; - for(f=a->frame; f; f=f->anext) - if(--l == 0) break; + if(f == nil) + error(Ebadvalue); return f; } char* +readctl_bar(Bar *b) { + bufclear(); + bufprint("colors %s\n", b->colors.colstr); + bufprint("label %s\n", b->text); + return buffer; +} + +char* +message_bar(Bar *b, IxpMsg *m) { + + switch(getsym(msg_getword(m, nil))) { + case LCOLORS: + msg_parsecolors(m, &b->colors); + break; + case LLABEL: + utflcpy(b->text, (char*)m->pos, sizeof b->text); + break; + default: + error(Ebadvalue); + } + bar_draw(b->screen); + return nil; +} + +char* readctl_client(Client *c) { bufclear(); - bufprint("%C\n", c); + bufprint("%#C\n", c); + bufprint("allow %M\n", (Mask){&c->permission, permtab}); + bufprint("floating %s\n", floatingtab[c->floating + 1]); if(c->fullscreen >= 0) - bufprint("Fullscreen %d\n", c->fullscreen); + bufprint("fullscreen %d\n", c->fullscreen); else - bufprint("Fullscreen off\n"); - bufprint("Urgent %s\n", toggletab[(int)c->urgent]); + bufprint("fullscreen off\n"); + bufprint("group %#ulx\n", c->group ? c->group->leader : 0); + if(c->pid) + bufprint("pid %d\n", c->pid); + bufprint("tags %s\n", c->tags); + bufprint("urgent %s\n", TOGGLE(c->urgent)); return buffer; } @@ -442,32 +523,41 @@ char* message_client(Client *c, IxpMsg *m) { char *s; long l; - int i; - s = msg_getword(m); + s = msg_getword(m, Ebadcmd); /* * Toggle ::= on * | off * | toggle * | <screen> - * Fullscreen <toggle> - * Urgent <toggle> + * floating <toggle> + * fullscreen <toggle> * kill * slay + * tags <tags> + * urgent <toggle> */ switch(getsym(s)) { + case LALLOW: + setmask((Mask){&c->permission, permtab}, msg_getword(m, 0)); + break; + case LFLOATING: + c->floating = -1 + _lsearch(msg_getword(m, Ebadvalue), floatingtab, nelem(floatingtab)); + break; case LFULLSCREEN: - s = msg_getword(m); + s = msg_getword(m, Ebadvalue); if(getlong(s, &l)) fullscreen(c, On, l); - else { - i = gettoggle(s); - if(i == -1) - return Ebadusage; - fullscreen(c, i, -1); - } + else + fullscreen(c, gettoggle(s), -1); + break; + case LGROUP: + group_remove(c); + c->w.hints->group = msg_getulong(msg_getword(m, Ebadvalue)); + if(c->w.hints->group) + group_init(c); break; case LKILL: client_kill(c, true); @@ -475,14 +565,14 @@ message_client(Client *c, IxpMsg *m) { case LSLAY: client_kill(c, false); break; + case LTAGS: + client_applytags(c, m->pos); + break; case LURGENT: - i = gettoggle(msg_getword(m)); - if(i == -1) - return Ebadusage; - client_seturgent(c, i, UrgManager); + client_seturgent(c, gettoggle(msg_getword(m, Ebadvalue)), UrgManager); break; default: - return Ebadcmd; + error(Ebadcmd); } return nil; } @@ -496,7 +586,7 @@ message_root(void *p, IxpMsg *m) { USED(p); ret = nil; - s = msg_getword(m); + s = msg_getword(m, 0); if(s == nil) return nil; @@ -505,28 +595,29 @@ message_root(void *p, IxpMsg *m) { return nil; } + if(!strcmp(s, "xinerama")) { + setenv("XINERAMA_SCREENS", m->pos, 1); + init_screens(); + return nil; + } + switch(getsym(s)) { case LBAR: /* bar on? <"top" | "bottom"> */ - s = msg_getword(m); + s = msg_getword(m, Ebadvalue); if(!strcmp(s, "on")) - s = msg_getword(m); - if(!setdef(&screen->barpos, s, barpostab, nelem(barpostab))) - return Ebadvalue; + s = msg_getword(m, Ebadvalue); + setdef(&screen->barpos, s, barpostab, nelem(barpostab)); view_update(selview); break; case LBORDER: - if(!getulong(msg_getword(m), &n)) - return Ebadvalue; - def.border = n; + def.border = msg_getulong(msg_getword(m, 0));; view_update(selview); break; case LCOLMODE: - s = msg_getword(m); - if(!setdef(&def.colmode, s, modes, Collast)) - return Ebadvalue; + setdef(&def.colmode, msg_getword(m, 0), modes, Collast); break; case LDEBUG: - ret = msg_debug(m); + msg_debug(msg_getword(m, 0)); break; case LEXEC: execstr = strdup(m->pos); @@ -536,9 +627,8 @@ message_root(void *p, IxpMsg *m) { spawn_command(m->pos); break; case LFOCUSCOLORS: - ret = msg_parsecolors(m, &def.focuscolor); - view_update(selview); - break; + msg_parsecolors(m, &def.focuscolor); + goto updatecolors; case LFONT: fn = loadfont(m->pos); if(fn) { @@ -551,10 +641,10 @@ message_root(void *p, IxpMsg *m) { view_update(selview); break; case LFONTPAD: - if(!getint(msg_getword(m), &def.font->pad.min.x) || - !getint(msg_getword(m), &def.font->pad.max.x) || - !getint(msg_getword(m), &def.font->pad.max.y) || - !getint(msg_getword(m), &def.font->pad.min.y)) + if(!getint(msg_getword(m, 0), &def.font->pad.min.x) || + !getint(msg_getword(m, 0), &def.font->pad.max.x) || + !getint(msg_getword(m, 0), &def.font->pad.max.y) || + !getint(msg_getword(m, 0), &def.font->pad.min.y)) ret = "invalid rectangle"; else { for(n=0; n < nscreens; n++) @@ -563,20 +653,21 @@ message_root(void *p, IxpMsg *m) { } break; case LGRABMOD: - s = msg_getword(m); + s = msg_getword(m, Ebadvalue); if(!parsekey(s, &i, nil) || i == 0) return Ebadvalue; - utflcpy(def.grabmod, s, sizeof def.grabmod); def.mod = i; break; case LINCMODE: - if(!setdef(&def.incmode, msg_getword(m), incmodetab, nelem(incmodetab))) - return Ebadvalue; + setdef(&def.incmode, msg_getword(m, 0), incmodetab, nelem(incmodetab)); view_update(selview); break; case LNORMCOLORS: - ret = msg_parsecolors(m, &def.normcolor); + msg_parsecolors(m, &def.normcolor); + updatecolors: + for(Client *c=client; c; c=c->next) + client_reparent(c); view_update(selview); break; case LSELCOLORS: @@ -594,38 +685,22 @@ message_root(void *p, IxpMsg *m) { return ret; } -static void -printdebug(int mask) { - int i, j; - - for(i=0, j=0; i < nelem(debugtab); i++) - if(mask & (1<<i)) { - if(j++ > 0) bufprint(" "); - bufprint("%s", debugtab[i]); - } -} - char* readctl_root(void) { + fmtinstall('M', Mfmt); bufclear(); bufprint("bar on %s\n", barpostab[screen->barpos]); bufprint("border %d\n", def.border); bufprint("colmode %s\n", modes[def.colmode]); - if(debugflag) { - bufprint("debug "); - printdebug(debugflag); - bufprint("\n"); - } - if(debugfile) { - bufprint("debugfile "); - printdebug(debugfile); - bufprint("\n"); - } + if(debugflag) + bufprint("debug %M\n", (Mask){&debugflag, debugtab}); + if(debugfile) + bufprint("debugfile %M", (Mask){&debugfile, debugtab}); bufprint("focuscolors %s\n", def.focuscolor.colstr); bufprint("font %s\n", def.font->name); bufprint("fontpad %d %d %d %d\n", def.font->pad.min.x, def.font->pad.max.x, def.font->pad.max.y, def.font->pad.min.y); - bufprint("grabmod %s\n", def.grabmod); + bufprint("grabmod %s\n", (Mask){&def.mod, modkey_names}); bufprint("incmode %s\n", incmodetab[def.incmode]); bufprint("normcolors %s\n", def.normcolor.colstr); bufprint("view %s\n", selview->name); @@ -637,11 +712,11 @@ message_view(View *v, IxpMsg *m) { Area *a; char *s; - s = msg_getword(m); + s = msg_getword(m, 0); if(s == nil) return nil; - /* + /* * area ::= ~ * | <column number> * | sel @@ -669,7 +744,7 @@ message_view(View *v, IxpMsg *m) { * | ~ * | <column> <frame number> * | <column> - * amount ::= + * amount ::= * | <number> * | <number>px * @@ -684,13 +759,11 @@ message_view(View *v, IxpMsg *m) { switch(getsym(s)) { case LCOLMODE: - s = msg_getword(m); + s = msg_getword(m, Ebadvalue); a = strarea(v, screen->idx, s); - if(a == nil) /* || a->floating) */ - return Ebadvalue; - s = msg_getword(m); - if(s == nil || !column_setmode(a, s)) + s = msg_getword(m, Ebadvalue); + if(!column_setmode(a, s)) return Ebadvalue; column_arrange(a, false); @@ -722,6 +795,8 @@ readctl_view(View *v) { bufclear(); bufprint("%s\n", v->name); + bufprint("urgent %s\n", TOGGLE(v->urgent)); + /* select <area>[ <frame>] */ bufprint("select %a", v->sel); if(v->sel->sel) @@ -730,45 +805,19 @@ readctl_view(View *v) { /* select client <client> */ if(v->sel->sel) - bufprint("select client %C\n", v->sel->sel->client); + bufprint("select client %#C\n", v->sel->sel->client); foreach_area(v, s, a) bufprint("colmode %a %s\n", a, column_getmode(a)); return buffer; } -char* -msg_debug(IxpMsg *m) { - char *opt; - int d; - char add; - - bufclear(); - while((opt = msg_getword(m))) { - add = '+'; - if(opt[0] == '+' || opt[0] == '-') - add = *opt++; - d = _bsearch(opt, debugtab, nelem(debugtab)); - if(d == -1) { - bufprint(", %s", opt); - continue; - } - if(add == '+') - debugflag |= 1<<d; - else - debugflag &= ~(1<<d); - } - if(buffer[0] != '\0') - return sxprint("Bad debug options: %s", buffer+2); - return nil; -} - -static bool +static void getamt(IxpMsg *m, Point *amt) { char *s, *p; long l; - s = msg_getword(m); + s = msg_getword(m, 0); if(s) { p = strend(s, 2); if(!strcmp(p, "px")) { @@ -777,30 +826,25 @@ getamt(IxpMsg *m, Point *amt) { amt->y = 1; } - if(!getlong(s, &l)) - return false; + l = msg_getlong(s); amt->x *= l; amt->y *= l; } - return true; } static char* msg_grow(View *v, IxpMsg *m) { Client *c; Frame *f; - Rectangle r; + Rectangle h, r; Point amount; int dir; f = getframe(v, screen->idx, m); - if(f == nil) - return "bad frame"; c = f->client; + h = c->w.hints->aspect; dir = getdirection(m); - if(dir == -1) - return "bad direction"; amount.x = Dy(f->titlebar); amount.y = Dy(f->titlebar); @@ -808,21 +852,22 @@ msg_grow(View *v, IxpMsg *m) { amount.x = c->w.hints->inc.x; if(amount.y < c->w.hints->inc.y) amount.y = c->w.hints->inc.y; + getamt(m, &amount); - if(!getamt(m, &amount)) - return Ebadvalue; + if (dir == LLEFT || dir == LRIGHT) + amount.y = h.min.x ? amount.x * h.min.y / h.min.x : 0; + else + amount.x = h.min.y ? amount.y * h.min.x / h.min.y : 0; if(f->area->floating) r = f->r; else r = f->colr; - switch(dir) { - case LLEFT: r.min.x -= amount.x; break; - case LRIGHT: r.max.x += amount.x; break; - case LUP: r.min.y -= amount.y; break; - case LDOWN: r.max.y += amount.y; break; - default: abort(); - } + + if (dir == LLEFT || dir == LUP) + r.min = subpt(r.min, amount); + else if (dir == LRIGHT || dir == LDOWN) + r.max = addpt(r.max, amount); if(f->area->floating) float_resizeframe(f, r); @@ -840,17 +885,11 @@ msg_nudge(View *v, IxpMsg *m) { int dir; f = getframe(v, screen->idx, m); - if(f == nil) - return "bad frame"; - dir = getdirection(m); - if(dir == -1) - return "bad direction"; amount.x = Dy(f->titlebar); amount.y = Dy(f->titlebar); - if(!getamt(m, &amount)) - return Ebadvalue; + getamt(m, &amount); if(f->area->floating) r = f->r; @@ -868,43 +907,19 @@ msg_nudge(View *v, IxpMsg *m) { float_resizeframe(f, r); else column_resizeframe(f, r); - return nil; } -char* +void msg_parsecolors(IxpMsg *m, CTuple *col) { - static char Ebad[] = "bad color string"; - Rune r; - char c, *p; - int i, j; - - /* '#%6x #%6x #%6x' */ - p = m->pos; - for(i = 0; i < 3 && p < m->end; i++) { - if(*p++ != '#') - return Ebad; - for(j = 0; j < 6; j++) - if(p >= m->end || !isxdigit(*p++)) - return Ebad; - - chartorune(&r, p); - if(i < 2) { - if(r != ' ') - return Ebad; - p++; - }else if(*p != '\0' && !isspacerune(r)) - return Ebad; - } - - c = *p; - *p = '\0'; - loadcolor(col, m->pos); - *p = c; + CTuple tpl; + char n; - m->pos = p; - eatrunes(m, isspacerune, true); - return nil; + n = loadcolor(&tpl, m->pos, m->end); + m->pos += n; + if(n == 0 || msg_getword(m, nil)) + error("bad color string"); + *col = tpl; } char* @@ -917,7 +932,7 @@ msg_selectarea(Area *a, IxpMsg *m) { int sym; v = a->view; - s = msg_getword(m); + s = msg_getword(m, Ebadvalue); sym = getsym(s); switch(sym) { @@ -941,11 +956,11 @@ msg_selectarea(Area *a, IxpMsg *m) { default: /* XXX: Multihead */ ap = strarea(v, a->screen, s); - if(!ap || ap->floating) + if(ap->floating) return Ebadvalue; - if((s = msg_getword(m))) { - if(!getulong(s, &i)) - return Ebadvalue; + + if((s = msg_getword(m, 0))) { + i = msg_getulong(s); for(f = ap->frame; f; f = f->anext) if(--i == 0) break; if(i != 0) @@ -971,49 +986,43 @@ msg_selectframe(Area *a, IxpMsg *m, int sym) { fp = f; stack = false; - if(sym == LUP || sym == LDOWN) { - s = msg_getword(m); - if(s) + if(sym == LUP || sym == LDOWN) + if((s = msg_getword(m, 0))) if(!strcmp(s, "stack")) stack = true; else return Ebadvalue; - } if(sym == LCLIENT) { - s = msg_getword(m); - if(s == nil || !getulong(s, &i)) - return "usage: select client <client>"; + s = msg_getword(m, Ebadvalue); + i = msg_getulong(s); c = win2client(i); if(c == nil) - return "unknown client"; + return Ebadvalue; f = client_viewframe(c, a->view); if(!f) return Ebadvalue; } - else { - if(!find(&a, &f, DIR(sym), true, stack)) - return Ebadvalue; - } + else if(!find(&a, &f, DIR(sym), true, stack)) + return Ebadvalue; area_focus(a); - if(!f) - return nil; + if(f != nil) { + /* XXX */ + if(fp && fp->area == a) + if(f->collapsed && !f->area->floating && f->area->mode == Coldefault) { + dy = Dy(f->colr); + f->colr.max.y = f->colr.min.y + Dy(fp->colr); + fp->colr.max.y = fp->colr.min.y + dy; + column_arrange(a, false); + } - /* XXX */ - if(fp && fp->area == a) - if(f->collapsed && !f->area->floating && f->area->mode == Coldefault) { - dy = Dy(f->colr); - f->colr.max.y = f->colr.min.y + Dy(fp->colr); - fp->colr.max.y = fp->colr.min.y + dy; - column_arrange(a, false); + frame_focus(f); + frame_restack(f, nil); + if(f->view == selview) + view_restack(a->view); } - - frame_focus(f); - frame_restack(f, nil); - if(f->view == selview) - view_restack(a->view); return nil; } @@ -1046,12 +1055,7 @@ msg_sendclient(View *v, IxpMsg *m, bool swap) { char *s; int sym; - s = msg_getword(m); - - c = strclient(v, s); - if(c == nil) - return Ebadvalue; - + c = strclient(v, msg_getword(m, 0)); f = client_viewframe(c, v); if(f == nil) return Ebadvalue; @@ -1059,7 +1063,7 @@ msg_sendclient(View *v, IxpMsg *m, bool swap) { a = f->area; to = nil; - s = msg_getword(m); + s = msg_getword(m, Ebadvalue); sym = getsym(s); /* FIXME: Should use a helper function. */ diff --git a/cmd/wmii/mouse.c b/cmd/wmii/mouse.c index fb7e2ff..122c9a8 100644 --- a/cmd/wmii/mouse.c +++ b/cmd/wmii/mouse.c @@ -13,11 +13,27 @@ enum { ButtonMask | PointerMotionMask }; -static void -cwin_expose(Window *w, XExposeEvent *e) { +static Cursor +quad_cursor(Align align) { + switch(align) { + case NEast: return cursor[CurNECorner]; + case NWest: return cursor[CurNWCorner]; + case SEast: return cursor[CurSECorner]; + case SWest: return cursor[CurSWCorner]; + case South: + case North: return cursor[CurDVArrow]; + case East: + case West: return cursor[CurDHArrow]; + default: return cursor[CurMove]; + } +} - fill(w, rectsubpt(w->r, w->r.min), def.focuscolor.bg); - fill(w, w->r, def.focuscolor.bg); +static bool +cwin_expose(Window *w, void *aux, XExposeEvent *e) { + + fill(w, rectsubpt(w->r, w->r.min), &def.focuscolor.bg); + fill(w, w->r, &def.focuscolor.bg); + return false; } static Handlers chandler = { @@ -27,17 +43,16 @@ static Handlers chandler = { Window* constraintwin(Rectangle r) { Window *w; - WinAttr wa; - w = createwindow(&scr.root, r, 0, InputOnly, &wa, 0); + w = createwindow(&scr.root, r, 0, InputOnly, nil, 0); if(0) { Window *w2; - w2 = createwindow(&scr.root, r, 0, InputOutput, &wa, 0); + w2 = createwindow(&scr.root, r, 0, InputOutput, nil, 0); selectinput(w2, ExposureMask); w->aux = w2; - setborder(w2, 1, def.focuscolor.border); + setborder(w2, 1, &def.focuscolor.border); sethandler(w2, &chandler); mapwin(w2); raisewin(w2); @@ -48,13 +63,9 @@ constraintwin(Rectangle r) { void destroyconstraintwin(Window *w) { - Window *w2; - if(w->aux) { - w2 = w->aux; - sethandler(w2, nil); - destroywindow(w2); - } + if(w->aux) + destroywindow(w->aux); destroywindow(w); } @@ -62,8 +73,8 @@ static Window* gethsep(Rectangle r) { Window *w; WinAttr wa; - - wa.background_pixel = def.normcolor.border.pixel; + + wa.background_pixel = pixelvalue(&scr.root, &def.normcolor.border); w = createwindow(&scr.root, r, scr.depth, InputOutput, &wa, CWBackPixel); mapwin(w); raisewin(w); @@ -137,7 +148,7 @@ Align snap_rect(const Rectangle *rects, int num, Rectangle *r, Align *mask, int snap) { Align ret; Point d; - + d.x = snap+1; d.y = snap+1; @@ -172,11 +183,12 @@ readmouse(Point *p, uint *button) { for(;;) { XMaskEvent(display, MouseMask|ExposureMask|PropertyChangeMask, &ev); + debug_event(&ev); switch(ev.type) { case Expose: case NoExpose: case PropertyNotify: - dispatch_event(&ev); + event_dispatch(&ev); default: Dprint(DEvent, "readmouse(): ignored: %E\n", &ev); continue; @@ -186,6 +198,10 @@ readmouse(Point *p, uint *button) { case MotionNotify: p->x = ev.xmotion.x_root; p->y = ev.xmotion.y_root; + if(p->x == scr.rect.max.x - 1) + p->x = scr.rect.max.x; + if(p->y == scr.rect.max.y - 1) + p->y = scr.rect.max.y; break; } return ev.type; @@ -207,7 +223,7 @@ readmotion(Point *p) { static void mouse_resizecolframe(Frame *f, Align align) { - Window *cwin, *hwin; + Window *cwin, *hwin = nil; Divide *d; View *v; Area *a; @@ -229,86 +245,100 @@ mouse_resizecolframe(Frame *f, Align align) { d = d->next; } - if(align&East) + if(align & East) d = d->next; min.x = column_minwidth(); min.y = /*frame_delta_h() +*/ labelh(def.font); /* Set the limits of where this box may be dragged. */ -#define frob(pred, f, aprev, rmin, rmax, plus, minus, xy) BLOCK( \ +#define frob(pred, f, aprev, rmin, rmax, plus, minus, xy, use_screen) BLOCK( \ if(pred) { \ r.rmin.xy = f->aprev->r.rmin.xy plus min.xy; \ r.rmax.xy = f->r.rmax.xy minus min.xy; \ + }else if(use_screen) { \ + r.rmin.xy = v->r[f->screen].rmin.xy plus 1; \ + r.rmax.xy = a->r.rmax.xy minus min.xy; \ }else { \ r.rmin.xy = a->r.rmin.xy; \ r.rmax.xy = r.rmin.xy plus 1; \ }) - if(align&North) - frob(f->aprev, f, aprev, min, max, +, -, y); - else - frob(f->anext, f, anext, max, min, -, +, y); - if(align&West) - frob(a->prev, a, prev, min, max, +, -, x); - else - frob(a->next, a, next, max, min, -, +, x); + + r = f->r; + if(align & North) + frob(f->aprev, f, aprev, min, max, +, -, y, false); + else if(align & South) + frob(f->anext, f, anext, max, min, -, +, y, false); + if(align & West) + frob(a->prev, a, prev, min, max, +, -, x, true); + else if(align & East) + frob(a->next, a, next, max, min, -, +, x, true); #undef frob cwin = constraintwin(r); r = f->r; - if(align&North) + if(align & North) r.min.y--; - else + else if(align & South) r.min.y = r.max.y - 1; r.max.y = r.min.y + 2; - hwin = gethsep(r); + if(align & (North|South)) + hwin = gethsep(r); if(!grabpointer(&scr.root, cwin, cursor[CurSizing], MouseMask)) goto done; - pt.x = ((align&West) ? f->r.min.x : f->r.max.x); - pt.y = ((align&North) ? f->r.min.y : f->r.max.y); + pt.x = (align & West ? f->r.min.x : f->r.max.x); + pt.y = (align & North ? f->r.min.y : f->r.max.y); warppointer(pt); while(readmotion(&pt)) { - if(align&West) + if(align & West) r.min.x = pt.x; - else + else if(align & East) r.max.x = pt.x; - r.min.y = ((align&South) ? pt.y : pt.y-1); + + if(align & South) + r.min.y = pt.y; + else if(align & North) + r.min.y = pt.y - 1; r.max.y = r.min.y+2; - div_set(d, pt.x); - reshapewin(hwin, r); + if(align & (East|West)) + div_set(d, pt.x); + if(hwin) + reshapewin(hwin, r); } r = f->r; - if(align&West) + if(align & West) r.min.x = pt.x; - else + else if(align & East) r.max.x = pt.x; - if(align&North) + if(align & North) r.min.y = pt.y; - else + else if(align & South) r.max.y = pt.y; column_resizeframe(f, r); /* XXX: Magic number... */ - if(align&West) + if(align & West) pt.x = f->r.min.x + 4; - else + else if(align & East) pt.x = f->r.max.x - 4; - if(align&North) + + if(align & North) pt.y = f->r.min.y + 4; - else + else if(align & South) pt.y = f->r.max.y - 4; warppointer(pt); done: ungrabpointer(); destroyconstraintwin(cwin); - destroywindow(hwin); + if (hwin) + destroywindow(hwin); } void @@ -399,6 +429,7 @@ mouse_resize(Client *c, Align align, bool grabmod) { SET(hrx); SET(hry); + if(align != Center) { hr = subpt(frect.max, frect.min); hr = divpt(hr, Pt(2, 2)); @@ -428,7 +459,7 @@ mouse_resize(Client *c, Align align, bool grabmod) { warppointer(d); } sync(); - flushevents(PointerMotionMask, false); + event_flush(PointerMotionMask, false); while(readmotion(&d)) { if(align == Center) { @@ -588,14 +619,14 @@ mouse_checkresize(Frame *f, Point p, bool exec) { int q; cur = cursor[CurNormal]; - if(rect_haspoint_p(p, f->crect)) { + if(rect_haspoint_p(f->crect, p)) { client_setcursor(f->client, cur); return; } r = rectsubpt(f->r, f->r.min); q = quadrant(r, p); - if(rect_haspoint_p(p, f->grabbox)) { + if(rect_haspoint_p(f->grabbox, p)) { cur = cursor[CurTCross]; if(exec) mouse_movegrabbox(f->client, false); @@ -609,7 +640,7 @@ mouse_checkresize(Frame *f, Point p, bool exec) { if(exec) mouse_resize(f->client, q, false); } - else if(exec && rect_haspoint_p(p, f->titlebar)) + else if(exec && rect_haspoint_p(f->titlebar, p)) mouse_movegrabbox(f->client, true); }else { if(f->aprev && p.y <= 2 @@ -627,7 +658,7 @@ mouse_checkresize(Frame *f, Point p, bool exec) { static void _grab(XWindow w, uint button, ulong mod) { XGrabButton(display, button, mod, w, false, ButtonMask, - GrabModeSync, GrabModeAsync, None, None); + GrabModeSync, GrabModeSync, None, None); } /* Doesn't belong here */ diff --git a/cmd/wmii/print.c b/cmd/wmii/print.c index cddf609..fbb14c0 100644 --- a/cmd/wmii/print.c +++ b/cmd/wmii/print.c @@ -34,15 +34,15 @@ static char* fcnames[] = { }; static int -qid(Fmt *f, Qid *q) { +qid(Fmt *f, IxpQid *q) { return fmtprint(f, "(%uhd,%uld,%ullx)", q->type, q->version, q->path); } int Ffmt(Fmt *f) { - Fcall *fcall; + IxpFcall *fcall; - fcall = va_arg(f->args, Fcall*); + fcall = va_arg(f->args, IxpFcall*); fmtprint(f, "% 2d %s\t", fcall->hdr.tag, fcnames[fcall->hdr.type - TVersion]); switch(fcall->hdr.type) { case TVersion: diff --git a/cmd/wmii/printevent.c b/cmd/wmii/printevent.c deleted file mode 100644 index 5b52c43..0000000 --- a/cmd/wmii/printevent.c +++ /dev/null @@ -1,994 +0,0 @@ -/* - * Original code posted to comp.sources.x - * Modifications by Russ Cox <rsc@swtch.com>. - * Further modifications by Kris Maglione <maglione.k at Gmail> - */ - -/* - * Path: uunet!wyse!mikew From: mikew@wyse.wyse.com (Mike Wexler) Newsgroups: - * comp.sources.x Subject: v02i056: subroutine to print events in human - * readable form, Part01/01 Message-ID: <1935@wyse.wyse.com> Date: 22 Dec 88 - * 19:28:25 GMT Organization: Wyse Technology, San Jose Lines: 1093 Approved: - * mikew@wyse.com - * - * Submitted-by: richsun!darkstar!ken Posting-number: Volume 2, Issue 56 - * Archive-name: showevent/part01 - * - * - * There are times during debugging when it would be real useful to be able to - * print the fields of an event in a human readable form. Too many times I - * found myself scrounging around in section 8 of the Xlib manual looking for - * the valid fields for the events I wanted to see, then adding printf's to - * display the numeric values of the fields, and then scanning through X.h - * trying to decode the cryptic detail and state fields. After playing with - * xev, I decided to write a couple of standard functions that I could keep - * in a library and call on whenever I needed a little debugging verbosity. - * The first function, GetType(), is useful for returning the string - * representation of the type of an event. The second function, ShowEvent(), - * is used to display all the fields of an event in a readable format. The - * functions are not complicated, in fact, they are mind-numbingly boring - - * but that's just the point nobody wants to spend the time writing functions - * like this, they just want to have them when they need them. - * - * A simple, sample program is included which does little else but to - * demonstrate the use of these two functions. These functions have saved me - * many an hour during debugging and I hope you find some benefit to these. - * If you have any comments, suggestions, improvements, or if you find any - * blithering errors you can get it touch with me at the following location: - * - * ken@richsun.UUCP - */ - -#include "dat.h" -#include <stdarg.h> -#include <bio.h> -//#include "fns.h" -#include "printevent.h" -#define Window XWindow - -#define nil ((void*)0) - -typedef struct Pair Pair; - -struct Pair { - int key; - char *val; -}; - -static char* sep = " "; - -static char * -search(Pair *lst, int key, char *(*def)(int)) { - for(; lst->val; lst++) - if(lst->key == key) - return lst->val; - return def(key); -} - -static char* -unmask(Pair *list, uint val) -{ - Pair *p; - char *s, *end; - int n; - - buffer[0] = '\0'; - end = buffer + sizeof buffer; - s = buffer; - - n = 0; - s = utfecpy(s, end, "("); - for (p = list; p->val; p++) - if (val & p->key) { - if(n++) - s = utfecpy(s, end, "|"); - s = utfecpy(s, end, p->val); - } - utfecpy(s, end, ")"); - - return buffer; -} - -static char * -strhex(int key) { - sprint(buffer, "0x%x", key); - return buffer; -} - -static char * -strdec(int key) { - sprint(buffer, "%d", key); - return buffer; -} - -static char * -strign(int key) { - USED(key); - - return "?"; -} - -/******************************************************************************/ -/**** Miscellaneous routines to convert values to their string equivalents ****/ -/******************************************************************************/ - -static void -TInt(Fmt *b, va_list *ap) { - fmtprint(b, "%d", va_arg(*ap, int)); -} - -static void -TWindow(Fmt *b, va_list *ap) { - Window w; - - w = va_arg(*ap, Window); - fmtprint(b, "0x%ux", (uint)w); -} - -static void -TData(Fmt *b, va_list *ap) { - long *l; - int i; - - l = va_arg(*ap, long*); - fmtprint(b, "{"); - for (i = 0; i < 5; i++) { - if(i > 0) - fmtprint(b, ", "); - fmtprint(b, "0x%08lx", l[i]); - } - fmtprint(b, "}"); -} - -/* Returns the string equivalent of a timestamp */ -static void -TTime(Fmt *b, va_list *ap) { - ldiv_t d; - ulong msec; - ulong sec; - ulong min; - ulong hr; - ulong day; - Time time; - - time = va_arg(*ap, Time); - - msec = time/1000; - d = ldiv(msec, 60); - msec = time-msec*1000; - - sec = d.rem; - d = ldiv(d.quot, 60); - min = d.rem; - d = ldiv(d.quot, 24); - hr = d.rem; - day = d.quot; - -#ifdef notdef - sprintf(buffer, "%lu day%s %02lu:%02lu:%02lu.%03lu", - day, day == 1 ? "" : "(s)", hr, min, sec, msec); -#endif - - fmtprint(b, "%ludd_%ludh_%ludm_%lud.%03luds", day, hr, min, sec, msec); -} - -/* Returns the string equivalent of a boolean parameter */ -static void -TBool(Fmt *b, va_list *ap) { - static Pair list[] = { - {True, "True"}, - {False, "False"}, - {0, nil}, - }; - Bool key; - - key = va_arg(*ap, Bool); - fmtprint(b, "%s", search(list, key, strign)); -} - -/* Returns the string equivalent of a property notify state */ -static void -TPropState(Fmt *b, va_list *ap) { - static Pair list[] = { - {PropertyNewValue, "PropertyNewValue"}, - {PropertyDelete, "PropertyDelete"}, - {0, nil}, - }; - uint key; - - key = va_arg(*ap, uint); - fmtprint(b, "%s", search(list, key, strign)); -} - -/* Returns the string equivalent of a visibility notify state */ -static void -TVis(Fmt *b, va_list *ap) { - static Pair list[] = { - {VisibilityUnobscured, "VisibilityUnobscured"}, - {VisibilityPartiallyObscured, "VisibilityPartiallyObscured"}, - {VisibilityFullyObscured, "VisibilityFullyObscured"}, - {0, nil}, - }; - int key; - - key = va_arg(*ap, int); - fmtprint(b, "%s", search(list, key, strign)); -} - -/* Returns the string equivalent of a mask of buttons and/or modifier keys */ -static void -TModState(Fmt *b, va_list *ap) { - static Pair list[] = { - {Button1Mask, "Button1Mask"}, - {Button2Mask, "Button2Mask"}, - {Button3Mask, "Button3Mask"}, - {Button4Mask, "Button4Mask"}, - {Button5Mask, "Button5Mask"}, - {ShiftMask, "ShiftMask"}, - {LockMask, "LockMask"}, - {ControlMask, "ControlMask"}, - {Mod1Mask, "Mod1Mask"}, - {Mod2Mask, "Mod2Mask"}, - {Mod3Mask, "Mod3Mask"}, - {Mod4Mask, "Mod4Mask"}, - {Mod5Mask, "Mod5Mask"}, - {0, nil}, - }; - uint state; - - state = va_arg(*ap, uint); - fmtprint(b, "%s", unmask(list, state)); -} - -/* Returns the string equivalent of a mask of configure window values */ -static void -TConfMask(Fmt *b, va_list *ap) { - static Pair list[] = { - {CWX, "CWX"}, - {CWY, "CWY"}, - {CWWidth, "CWWidth"}, - {CWHeight, "CWHeight"}, - {CWBorderWidth, "CWBorderWidth"}, - {CWSibling, "CWSibling"}, - {CWStackMode, "CWStackMode"}, - {0, nil}, - }; - uint valuemask; - - valuemask = va_arg(*ap, uint); - fmtprint(b, "%s", unmask(list, valuemask)); -} - -/* Returns the string equivalent of a motion hint */ -#if 0 -static void -IsHint(Fmt *b, va_list *ap) { - static Pair list[] = { - {NotifyNormal, "NotifyNormal"}, - {NotifyHint, "NotifyHint"}, - {0, nil}, - }; - char key; - - key = va_arg(*ap, char); - fmtprint(b, "%s", search(list, key, strign)); -} -#endif - -/* Returns the string equivalent of an id or the value "None" */ -static void -TIntNone(Fmt *b, va_list *ap) { - static Pair list[] = { - {None, "None"}, - {0, nil}, - }; - int key; - - key = va_arg(*ap, int); - fmtprint(b, "%s", search(list, key, strhex)); -} - -/* Returns the string equivalent of a colormap state */ -static void -TColMap(Fmt *b, va_list *ap) { - static Pair list[] = { - {ColormapInstalled, "ColormapInstalled"}, - {ColormapUninstalled, "ColormapUninstalled"}, - {0, nil}, - }; - int key; - - key = va_arg(*ap, int); - fmtprint(b, "%s", search(list, key, strign)); -} - -/* Returns the string equivalent of a crossing detail */ -static void -TXing(Fmt *b, va_list *ap) { - static Pair list[] = { - {NotifyAncestor, "NotifyAncestor"}, - {NotifyInferior, "NotifyInferior"}, - {NotifyVirtual, "NotifyVirtual"}, - {NotifyNonlinear, "NotifyNonlinear"}, - {NotifyNonlinearVirtual, "NotifyNonlinearVirtual"}, - {0, nil}, - }; - int key; - - key = va_arg(*ap, int); - fmtprint(b, "%s", search(list, key, strign)); -} - -/* Returns the string equivalent of a focus change detail */ -static void -TFocus(Fmt *b, va_list *ap) { - static Pair list[] = { - {NotifyAncestor, "NotifyAncestor"}, - {NotifyInferior, "NotifyInferior"}, - {NotifyVirtual, "NotifyVirtual"}, - {NotifyNonlinear, "NotifyNonlinear"}, - {NotifyNonlinearVirtual, "NotifyNonlinearVirtual"}, - {NotifyPointer, "NotifyPointer"}, - {NotifyPointerRoot, "NotifyPointerRoot"}, - {NotifyDetailNone, "NotifyDetailNone"}, - {0, nil}, - }; - int key; - - key = va_arg(*ap, int); - fmtprint(b, "%s", search(list, key, strign)); -} - -/* Returns the string equivalent of a configure detail */ -static void -TConfDetail(Fmt *b, va_list *ap) { - static Pair list[] = { - {Above, "Above"}, - {Below, "Below"}, - {TopIf, "TopIf"}, - {BottomIf, "BottomIf"}, - {Opposite, "Opposite"}, - {0, nil}, - }; - int key; - - key = va_arg(*ap, int); - fmtprint(b, "%s", search(list, key, strign)); -} - -/* Returns the string equivalent of a grab mode */ -static void -TGrabMode(Fmt *b, va_list *ap) { - static Pair list[] = { - {NotifyNormal, "NotifyNormal"}, - {NotifyGrab, "NotifyGrab"}, - {NotifyUngrab, "NotifyUngrab"}, - {NotifyWhileGrabbed, "NotifyWhileGrabbed"}, - {0, nil}, - }; - int key; - - key = va_arg(*ap, int); - fmtprint(b, "%s", search(list, key, strign)); -} - -/* Returns the string equivalent of a mapping request */ -static void -TMapping(Fmt *b, va_list *ap) { - static Pair list[] = { - {MappingModifier, "MappingModifier"}, - {MappingKeyboard, "MappingKeyboard"}, - {MappingPointer, "MappingPointer"}, - {0, nil}, - }; - int key; - - key = va_arg(*ap, int); - fmtprint(b, "%s", search(list, key, strign)); -} - -/* Returns the string equivalent of a stacking order place */ -static void -TPlace(Fmt *b, va_list *ap) { - static Pair list[] = { - {PlaceOnTop, "PlaceOnTop"}, - {PlaceOnBottom, "PlaceOnBottom"}, - {0, nil}, - }; - int key; - - key = va_arg(*ap, int); - fmtprint(b, "%s", search(list, key, strign)); -} - -/* Returns the string equivalent of a major code */ -static void -TMajor(Fmt *b, va_list *ap) { - static char *list[] = { XMajors }; - char *s; - uint key; - - key = va_arg(*ap, uint); - s = "<nil>"; - if(key < nelem(list)) - s = list[key]; - fmtprint(b, "%s", s); -} - -static char* -eventtype(int key) { - static Pair list[] = { - {ButtonPress, "ButtonPress"}, - {ButtonRelease, "ButtonRelease"}, - {CirculateNotify, "CirculateNotify"}, - {CirculateRequest, "CirculateRequest"}, - {ClientMessage, "ClientMessage"}, - {ColormapNotify, "ColormapNotify"}, - {ConfigureNotify, "ConfigureNotify"}, - {ConfigureRequest, "ConfigureRequest"}, - {CreateNotify, "CreateNotify"}, - {DestroyNotify, "DestroyNotify"}, - {EnterNotify, "EnterNotify"}, - {Expose, "Expose"}, - {FocusIn, "FocusIn"}, - {FocusOut, "FocusOut"}, - {GraphicsExpose, "GraphicsExpose"}, - {GravityNotify, "GravityNotify"}, - {KeyPress, "KeyPress"}, - {KeyRelease, "KeyRelease"}, - {KeymapNotify, "KeymapNotify"}, - {LeaveNotify, "LeaveNotify"}, - {MapNotify, "MapNotify"}, - {MapRequest, "MapRequest"}, - {MappingNotify, "MappingNotify"}, - {MotionNotify, "MotionNotify"}, - {NoExpose, "NoExpose"}, - {PropertyNotify, "PropertyNotify"}, - {ReparentNotify, "ReparentNotify"}, - {ResizeRequest, "ResizeRequest"}, - {SelectionClear, "SelectionClear"}, - {SelectionNotify, "SelectionNotify"}, - {SelectionRequest, "SelectionRequest"}, - {UnmapNotify, "UnmapNotify"}, - {VisibilityNotify, "VisibilityNotify"}, - {0, nil}, - }; - return search(list, key, strdec); -} -/* Returns the string equivalent the keycode contained in the key event */ -static void -TKeycode(Fmt *b, va_list *ap) { - KeySym keysym_str; - XKeyEvent *ev; - char *keysym_name; - - ev = va_arg(*ap, XKeyEvent*); - - XLookupString(ev, buffer, sizeof buffer, &keysym_str, nil); - - if (keysym_str == NoSymbol) - keysym_name = "NoSymbol"; - else - keysym_name = XKeysymToString(keysym_str); - if(keysym_name == nil) - keysym_name = "(no name)"; - - fmtprint(b, "%ud (keysym 0x%x \"%s\")", (int)ev->keycode, - (int)keysym_str, keysym_name); -} - -/* Returns the string equivalent of an atom or "None" */ -static void -TAtom(Fmt *b, va_list *ap) { - char *atom_name; - Atom atom; - - atom = va_arg(*ap, Atom); - atom_name = XGetAtomName(display, atom); - fmtprint(b, "%s", atom_name); - XFree(atom_name); -} - -#define _(m) #m, ev->m -#define TEnd nil -typedef void (*Tfn)(Fmt*, va_list*); - -static int -pevent(Fmt *fmt, void *e, ...) { - va_list ap; - Tfn fn; - XAnyEvent *ev; - char *key; - int n; - - ev = e; - fmtprint(fmt, "%3ld %-20s ", ev->serial, eventtype(ev->type)); - if(ev->send_event) - fmtstrcpy(fmt, "(sendevent) "); - - n = 0; - va_start(ap, e); - for(;;) { - fn = va_arg(ap, Tfn); - if(fn == TEnd) - break; - - if(n++ != 0) - fmtprint(fmt, "%s", sep); - - key = va_arg(ap, char*); - fmtprint(fmt, "%s=", key); - fn(fmt, &ap); - } - va_end(ap); - return 0; -} - -/*****************************************************************************/ -/*** Routines to print out readable values for the field of various events ***/ -/*****************************************************************************/ - -static int -VerbMotion(Fmt *fmt, XEvent *e) { - XMotionEvent *ev = &e->xmotion; - - return pevent(fmt, ev, - TWindow, _(window), - TWindow, _(root), - TWindow, _(subwindow), - TTime, _(time), - TInt, _(x), TInt, _(y), - TInt, _(x_root), TInt, _(y_root), - TModState, _(state), - TBool, _(same_screen), - TEnd - ); - //fprintf(stderr, "is_hint=%s%s", IsHint(ev->is_hint), sep); -} - -static int -VerbButton(Fmt *fmt, XEvent *e) { - XButtonEvent *ev = &e->xbutton; - - return pevent(fmt, ev, - TWindow, _(window), - TWindow, _(root), - TWindow, _(subwindow), - TTime, _(time), - TInt, _(x), TInt, _(y), - TInt, _(x_root), TInt, _(y_root), - TModState, _(state), - TModState, _(button), - TBool, _(same_screen), - TEnd - ); -} - -static int -VerbColormap(Fmt *fmt, XEvent *e) { - XColormapEvent *ev = &e->xcolormap; - - return pevent(fmt, ev, - TWindow, _(window), - TIntNone, _(colormap), - TBool, _(new), - TColMap, _(state), - TEnd - ); -} - -static int -VerbCrossing(Fmt *fmt, XEvent *e) { - XCrossingEvent *ev = &e->xcrossing; - - return pevent(fmt, ev, - TWindow, _(window), - TWindow, _(root), - TWindow, _(subwindow), - TTime, _(time), - TInt, _(x), TInt, _(y), - TInt, _(x_root), TInt, _(y_root), - TGrabMode, _(mode), - TXing, _(detail), - TBool, _(same_screen), - TBool, _(focus), - TModState, _(state), - TEnd - ); -} - -static int -VerbExpose(Fmt *fmt, XEvent *e) { - XExposeEvent *ev = &e->xexpose; - - return pevent(fmt, ev, - TWindow, _(window), - TInt, _(x), TInt, _(y), - TInt, _(width), TInt, _(height), - TInt, _(count), - TEnd - ); -} - -static int -VerbGraphicsExpose(Fmt *fmt, XEvent *e) { - XGraphicsExposeEvent *ev = &e->xgraphicsexpose; - - return pevent(fmt, ev, - TWindow, _(drawable), - TInt, _(x), TInt, _(y), - TInt, _(width), TInt, _(height), - TMajor, _(major_code), - TInt, _(minor_code), - TEnd - ); -} - -static int -VerbNoExpose(Fmt *fmt, XEvent *e) { - XNoExposeEvent *ev = &e->xnoexpose; - - return pevent(fmt, ev, - TWindow, _(drawable), - TMajor, _(major_code), - TInt, _(minor_code), - TEnd - ); -} - -static int -VerbFocus(Fmt *fmt, XEvent *e) { - XFocusChangeEvent *ev = &e->xfocus; - - return pevent(fmt, ev, - TWindow, _(window), - TGrabMode, _(mode), - TFocus, _(detail), - TEnd - ); -} - -static int -VerbKeymap(Fmt *fmt, XEvent *e) { - XKeymapEvent *ev = &e->xkeymap; - int i; - - fmtprint(fmt, "window=0x%x%s", (int)ev->window, sep); - fmtprint(fmt, "key_vector="); - for (i = 0; i < 32; i++) - fmtprint(fmt, "%02x", ev->key_vector[i]); - fmtprint(fmt, "\n"); - return 0; -} - -static int -VerbKey(Fmt *fmt, XEvent *e) { - XKeyEvent *ev = &e->xkey; - - return pevent(fmt, ev, - TWindow, _(window), - TWindow, _(root), - TWindow, _(subwindow), - TTime, _(time), - TInt, _(x), TInt, _(y), - TInt, _(x_root), TInt, _(y_root), - TModState, _(state), - TKeycode, "keycode", ev, - TBool, _(same_screen), - TEnd - ); -} - -static int -VerbProperty(Fmt *fmt, XEvent *e) { - XPropertyEvent *ev = &e->xproperty; - - return pevent(fmt, ev, - TWindow, _(window), - TAtom, _(atom), - TTime, _(time), - TPropState, _(state), - TEnd - ); -} - -static int -VerbResizeRequest(Fmt *fmt, XEvent *e) { - XResizeRequestEvent *ev = &e->xresizerequest; - - return pevent(fmt, ev, - TWindow, _(window), - TInt, _(width), TInt, _(height), - TEnd - ); -} - -static int -VerbCirculate(Fmt *fmt, XEvent *e) { - XCirculateEvent *ev = &e->xcirculate; - - return pevent(fmt, ev, - TWindow, _(event), - TWindow, _(window), - TPlace, _(place), - TEnd - ); -} - -static int -VerbConfigure(Fmt *fmt, XEvent *e) { - XConfigureEvent *ev = &e->xconfigure; - - return pevent(fmt, ev, - TWindow, _(event), - TWindow, _(window), - TInt, _(x), TInt, _(y), - TInt, _(width), TInt, _(height), - TInt, _(border_width), - TIntNone, _(above), - TBool, _(override_redirect), - TEnd - ); -} - -static int -VerbCreateWindow(Fmt *fmt, XEvent *e) { - XCreateWindowEvent *ev = &e->xcreatewindow; - - return pevent(fmt, ev, - TWindow, _(parent), - TWindow, _(window), - TInt, _(x), TInt, _(y), - TInt, _(width), TInt, _(height), - TInt, _(border_width), - TBool, _(override_redirect), - TEnd - ); -} - -static int -VerbDestroyWindow(Fmt *fmt, XEvent *e) { - XDestroyWindowEvent *ev = &e->xdestroywindow; - - return pevent(fmt, ev, - TWindow, _(event), - TWindow, _(window), - TEnd - ); -} - -static int -VerbGravity(Fmt *fmt, XEvent *e) { - XGravityEvent *ev = &e->xgravity; - - return pevent(fmt, ev, - TWindow, _(event), - TWindow, _(window), - TInt, _(x), TInt, _(y), - TEnd - ); -} - -static int -VerbMap(Fmt *fmt, XEvent *e) { - XMapEvent *ev = &e->xmap; - - return pevent(fmt, ev, - TWindow, _(event), - TWindow, _(window), - TBool, _(override_redirect), - TEnd - ); -} - -static int -VerbReparent(Fmt *fmt, XEvent *e) { - XReparentEvent *ev = &e->xreparent; - - return pevent(fmt, ev, - TWindow, _(event), - TWindow, _(window), - TWindow, _(parent), - TInt, _(x), TInt, _(y), - TBool, _(override_redirect), - TEnd - ); -} - -static int -VerbUnmap(Fmt *fmt, XEvent *e) { - XUnmapEvent *ev = &e->xunmap; - - return pevent(fmt, ev, - TWindow, _(event), - TWindow, _(window), - TBool, _(from_configure), - TEnd - ); -} - -static int -VerbCirculateRequest(Fmt *fmt, XEvent *e) { - XCirculateRequestEvent *ev = &e->xcirculaterequest; - - return pevent(fmt, ev, - TWindow, _(parent), - TWindow, _(window), - TPlace, _(place), - TEnd - ); -} - -static int -VerbConfigureRequest(Fmt *fmt, XEvent *e) { - XConfigureRequestEvent *ev = &e->xconfigurerequest; - - return pevent(fmt, ev, - TWindow, _(parent), - TWindow, _(window), - TInt, _(x), TInt, _(y), - TInt, _(width), TInt, _(height), - TInt, _(border_width), - TIntNone, _(above), - TConfDetail, _(detail), - TConfMask, _(value_mask), - TEnd - ); -} - -static int -VerbMapRequest(Fmt *fmt, XEvent *e) { - XMapRequestEvent *ev = &e->xmaprequest; - - return pevent(fmt, ev, - TWindow, _(parent), - TWindow, _(window), - TEnd - ); -} - -static int -VerbClient(Fmt *fmt, XEvent *e) { - XClientMessageEvent *ev = &e->xclient; - - return pevent(fmt, ev, - TWindow, _(window), - TAtom, _(message_type), - TInt, _(format), - TData, "data (as longs)", &ev->data, - TEnd - ); -} - -static int -VerbMapping(Fmt *fmt, XEvent *e) { - XMappingEvent *ev = &e->xmapping; - - return pevent(fmt, ev, - TWindow, _(window), - TMapping, _(request), - TWindow, _(first_keycode), - TWindow, _(count), - TEnd - ); -} - -static int -VerbSelectionClear(Fmt *fmt, XEvent *e) { - XSelectionClearEvent *ev = &e->xselectionclear; - - return pevent(fmt, ev, - TWindow, _(window), - TAtom, _(selection), - TTime, _(time), - TEnd - ); -} - -static int -VerbSelection(Fmt *fmt, XEvent *e) { - XSelectionEvent *ev = &e->xselection; - - return pevent(fmt, ev, - TWindow, _(requestor), - TAtom, _(selection), - TAtom, _(target), - TAtom, _(property), - TTime, _(time), - TEnd - ); -} - -static int -VerbSelectionRequest(Fmt *fmt, XEvent *e) { - XSelectionRequestEvent *ev = &e->xselectionrequest; - - return pevent(fmt, ev, - TWindow, _(owner), - TWindow, _(requestor), - TAtom, _(selection), - TAtom, _(target), - TAtom, _(property), - TTime, _(time), - TEnd - ); -} - -static int -VerbVisibility(Fmt *fmt, XEvent *e) { - XVisibilityEvent *ev = &e->xvisibility; - - return pevent(fmt, ev, - TWindow, _(window), - TVis, _(state), - TEnd - ); -} - -/******************************************************************************/ -/**************** Print the values of all fields for any event ****************/ -/******************************************************************************/ - -typedef struct Handler Handler; -struct Handler { - int key; - int (*fn)(Fmt*, XEvent*); -}; - -int -fmtevent(Fmt *fmt) { - XEvent *e; - XAnyEvent *ev; - /* - fprintf(stderr, "type=%s%s", eventtype(e->xany.type), sep); - fprintf(stderr, "serial=%lu%s", ev->serial, sep); - fprintf(stderr, "send_event=%s%s", TorF(ev->send_event), sep); - fprintf(stderr, "display=0x%p%s", ev->display, sep); - */ - static Handler fns[] = { - {MotionNotify, VerbMotion}, - {ButtonPress, VerbButton}, - {ButtonRelease, VerbButton}, - {ColormapNotify, VerbColormap}, - {EnterNotify, VerbCrossing}, - {LeaveNotify, VerbCrossing}, - {Expose, VerbExpose}, - {GraphicsExpose, VerbGraphicsExpose}, - {NoExpose, VerbNoExpose}, - {FocusIn, VerbFocus}, - {FocusOut, VerbFocus}, - {KeymapNotify, VerbKeymap}, - {KeyPress, VerbKey}, - {KeyRelease, VerbKey}, - {PropertyNotify, VerbProperty}, - {ResizeRequest, VerbResizeRequest}, - {CirculateNotify, VerbCirculate}, - {ConfigureNotify, VerbConfigure}, - {CreateNotify, VerbCreateWindow}, - {DestroyNotify, VerbDestroyWindow}, - {GravityNotify, VerbGravity}, - {MapNotify, VerbMap}, - {ReparentNotify, VerbReparent}, - {UnmapNotify, VerbUnmap}, - {CirculateRequest, VerbCirculateRequest}, - {ConfigureRequest, VerbConfigureRequest}, - {MapRequest, VerbMapRequest}, - {ClientMessage, VerbClient}, - {MappingNotify, VerbMapping}, - {SelectionClear, VerbSelectionClear}, - {SelectionNotify, VerbSelection}, - {SelectionRequest, VerbSelectionRequest}, - {VisibilityNotify, VerbVisibility}, - {0, nil}, - }; - Handler *p; - - e = va_arg(fmt->args, XEvent*); - ev = &e->xany; - - for (p = fns; p->fn; p++) - if (p->key == ev->type) - return p->fn(fmt, e); - return 1; -} - diff --git a/cmd/wmii/printevent.h b/cmd/wmii/printevent.h deleted file mode 100644 index 22d6b25..0000000 --- a/cmd/wmii/printevent.h +++ /dev/null @@ -1,248 +0,0 @@ -int fmtevent(Fmt *fmt); - -enum { - X_CreateWindow = 1, - X_ChangeWindowAttributes, - X_GetWindowAttributes, - X_DestroyWindow, - X_DestroySubwindows, - X_ChangeSaveSet, - X_ReparentWindow, - X_MapWindow, - X_MapSubwindows, - X_UnmapWindow, - X_UnmapSubwindows, - X_ConfigureWindow, - X_CirculateWindow, - X_GetGeometry, - X_QueryTree, - X_InternAtom, - X_GetAtomName, - X_ChangeProperty, - X_DeleteProperty, - X_GetProperty, - X_ListProperties, - X_SetSelectionOwner, - X_GetSelectionOwner, - X_ConvertSelection, - X_SendEvent, - X_GrabPointer, - X_UngrabPointer, - X_GrabButton, - X_UngrabButton, - X_ChangeActivePointerGrab, - X_GrabKeyboard, - X_UngrabKeyboard, - X_GrabKey, - X_UngrabKey, - X_AllowEvents, - X_GrabServer, - X_UngrabServer, - X_QueryPointer, - X_GetMotionEvents, - X_TranslateCoords, - X_WarpPointer, - X_SetInputFocus, - X_GetInputFocus, - X_QueryKeymap, - X_OpenFont, - X_CloseFont, - X_QueryFont, - X_QueryTextExtents, - X_ListFonts, - X_ListFontsWithInfo, - X_SetFontPath, - X_GetFontPath, - X_CreatePixmap, - X_FreePixmap, - X_CreateGC, - X_ChangeGC, - X_CopyGC, - X_SetDashes, - X_SetClipRectangles, - X_FreeGC, - X_ClearArea, - X_CopyArea, - X_CopyPlane, - X_PolyPoint, - X_PolyLine, - X_PolySegment, - X_PolyRectangle, - X_PolyArc, - X_FillPoly, - X_PolyFillRectangle, - X_PolyFillArc, - X_PutImage, - X_GetImage, - X_PolyText8, - X_PolyText16, - X_ImageText8, - X_ImageText16, - X_CreateColormap, - X_FreeColormap, - X_CopyColormapAndFree, - X_InstallColormap, - X_UninstallColormap, - X_ListInstalledColormaps, - X_AllocColor, - X_AllocNamedColor, - X_AllocColorCells, - X_AllocColorPlanes, - X_FreeColors, - X_StoreColors, - X_StoreNamedColor, - X_QueryColors, - X_LookupColor, - X_CreateCursor, - X_CreateGlyphCursor, - X_FreeCursor, - X_RecolorCursor, - X_QueryBestSize, - X_QueryExtension, - X_ListExtensions, - X_ChangeKeyboardMapping, - X_GetKeyboardMapping, - X_ChangeKeyboardControl, - X_GetKeyboardControl, - X_Bell, - X_ChangePointerControl, - X_GetPointerControl, - X_SetScreenSaver, - X_GetScreenSaver, - X_ChangeHosts, - X_ListHosts, - X_SetAccessControl, - X_SetCloseDownMode, - X_KillClient, - X_RotateProperties, - X_ForceScreenSaver, - X_SetPointerMapping, - X_GetPointerMapping, - X_SetModifierMapping, - X_GetModifierMapping, - X_NoOperation, -}; - -#define XMajors \ - "<nil>",\ - "CreateWindow",\ - "ChangeWindowAttributes",\ - "GetWindowAttributes",\ - "DestroyWindow",\ - "DestroySubwindows",\ - "ChangeSaveSet",\ - "ReparentWindow",\ - "MapWindow",\ - "MapSubwindows",\ - "UnmapWindow",\ - "UnmapSubwindows",\ - "ConfigureWindow",\ - "CirculateWindow",\ - "GetGeometry",\ - "QueryTree",\ - "InternAtom",\ - "GetAtomName",\ - "ChangeProperty",\ - "DeleteProperty",\ - "GetProperty",\ - "ListProperties",\ - "SetSelectionOwner",\ - "GetSelectionOwner",\ - "ConvertSelection",\ - "SendEvent",\ - "GrabPointer",\ - "UngrabPointer",\ - "GrabButton",\ - "UngrabButton",\ - "ChangeActivePointerGrab",\ - "GrabKeyboard",\ - "UngrabKeyboard",\ - "GrabKey",\ - "UngrabKey",\ - "AllowEvents",\ - "GrabServer",\ - "UngrabServer",\ - "QueryPointer",\ - "GetMotionEvents",\ - "TranslateCoords",\ - "WarpPointer",\ - "SetInputFocus",\ - "GetInputFocus",\ - "QueryKeymap",\ - "OpenFont",\ - "CloseFont",\ - "QueryFont",\ - "QueryTextExtents",\ - "ListFonts",\ - "ListFontsWithInfo",\ - "SetFontPath",\ - "GetFontPath",\ - "CreatePixmap",\ - "FreePixmap",\ - "CreateGC",\ - "ChangeGC",\ - "CopyGC",\ - "SetDashes",\ - "SetClipRectangles",\ - "FreeGC",\ - "ClearArea",\ - "CopyArea",\ - "CopyPlane",\ - "PolyPoint",\ - "PolyLine",\ - "PolySegment",\ - "PolyRectangle",\ - "PolyArc",\ - "FillPoly",\ - "PolyFillRectangle",\ - "PolyFillArc",\ - "PutImage",\ - "GetImage",\ - "PolyText8",\ - "PolyText16",\ - "ImageText8",\ - "ImageText16",\ - "CreateColormap",\ - "FreeColormap",\ - "CopyColormapAndFree",\ - "InstallColormap",\ - "UninstallColormap",\ - "ListInstalledColormaps",\ - "AllocColor",\ - "AllocNamedColor",\ - "AllocColorCells",\ - "AllocColorPlanes",\ - "FreeColors",\ - "StoreColors",\ - "StoreNamedColor",\ - "QueryColors",\ - "LookupColor",\ - "CreateCursor",\ - "CreateGlyphCursor",\ - "FreeCursor",\ - "RecolorCursor",\ - "QueryBestSize",\ - "QueryExtension",\ - "ListExtensions",\ - "ChangeKeyboardMapping",\ - "GetKeyboardMapping",\ - "ChangeKeyboardControl",\ - "GetKeyboardControl",\ - "Bell",\ - "ChangePointerControl",\ - "GetPointerControl",\ - "SetScreenSaver",\ - "GetScreenSaver",\ - "ChangeHosts",\ - "ListHosts",\ - "SetAccessControl",\ - "SetCloseDownMode",\ - "KillClient",\ - "RotateProperties",\ - "ForceScreenSaver",\ - "SetPointerMapping",\ - "GetPointerMapping",\ - "SetModifierMapping",\ - "GetModifierMapping",\ - "NoOperation",\ - diff --git a/cmd/wmii/root.c b/cmd/wmii/root.c index e3e53e7..1643f14 100644 --- a/cmd/wmii/root.c +++ b/cmd/wmii/root.c @@ -10,72 +10,69 @@ void root_init(void) { WinAttr wa; + wa.cursor = cursor[CurNormal]; wa.event_mask = EnterWindowMask | FocusChangeMask | LeaveWindowMask | PointerMotionMask | SubstructureNotifyMask | SubstructureRedirectMask; - wa.cursor = cursor[CurNormal]; - setwinattr(&scr.root, &wa, - CWEventMask - | CWCursor); + setwinattr(&scr.root, &wa, CWCursor + | CWEventMask); sethandler(&scr.root, &handlers); } -static void -enter_event(Window *w, XCrossingEvent *e) { +static bool +enter_event(Window *w, void *aux, XCrossingEvent *e) { disp.sel = true; frame_draw_all(); + return false; } -static void -leave_event(Window *w, XCrossingEvent *e) { +static bool +leave_event(Window *w, void *aux, XCrossingEvent *e) { if(!e->same_screen) { disp.sel = false; frame_draw_all(); } + return false; } -static void -focusin_event(Window *w, XFocusChangeEvent *e) { +static bool +focusin_event(Window *w, void *aux, XFocusChangeEvent *e) { if(e->mode == NotifyGrab) disp.hasgrab = &c_root; + return false; } -static void -mapreq_event(Window *w, XMapRequestEvent *e) { +static bool +mapreq_event(Window *w, void *aux, XMapRequestEvent *e) { XWindowAttributes wa; - if(!XGetWindowAttributes(display, e->window, &wa)) - return; - if(wa.override_redirect) { - /* Do I really want these? */ - /* Probably not. - XSelectInput(display, e->window, - PropertyChangeMask | StructureNotifyMask); - */ - return; - } + if(!XGetWindowAttributes(display, e->window, &wa) || wa.override_redirect) + return false; if(!win2client(e->window)) client_create(e->window, &wa); + return false; } -static void -motion_event(Window *w, XMotionEvent *e) { +static bool +motion_event(Window *w, void *aux, XMotionEvent *e) { Rectangle r, r2; r = rectsetorigin(Rect(0, 0, 1, 1), Pt(e->x_root, e->y_root)); r2 = constrain(r, 0); if(!eqrect(r, r2)) warppointer(r2.min); + return false; } -static void -kdown_event(Window *w, XKeyEvent *e) { +static bool +kdown_event(Window *w, void *aux, XKeyEvent *e) { e->state &= valid_mask; kpress(w->xid, e->state, (KeyCode)e->keycode); + return false; } static Handlers handlers = { diff --git a/cmd/wmii/rule.c b/cmd/wmii/rule.c index b2f838f..710b341 100644 --- a/cmd/wmii/rule.c +++ b/cmd/wmii/rule.c @@ -1,4 +1,4 @@ -/* Copyright ©2006 Anselm R. Garbe <garbeam at gmail dot com> +/* Copyright ©2010 Kris Maglione <maglione.k at Gmail> * See LICENSE file for license details. */ @@ -6,102 +6,103 @@ #include "fns.h" void -trim(char *str, const char *chars) { - const char *cp; - char *p, *q; +update_rules(Rule **rule, char *data) { +#define putc(m, c) BLOCK(if((m)->pos < (m)->end) *(m)->pos++ = c;) +#define getc(m) ((m)->pos < (m)->end ? *(m)->pos++ : 0) +#define ungetc(m) BLOCK(if((m)->pos > (m)->data) --(m)->pos) + + IxpMsg buf, valuebuf, rebuf; + Reprog *re; + Rule *r; + Ruleval **rvp; + Ruleval *rv; + char *w; + char regexp[256]; char c; + int len; - q = str; - for(p=str; *p; p++) { - for(cp=chars; (c = *cp); cp++) - if(*p == c) - break; - if(c == '\0') - *q++ = *p; + while((r = *rule)) { + *rule = r->next; + while((rv = r->values)) { + r->values = rv->next; + free(rv); + } + free(r->regex); + free(r->value); + free(r); } - *q = '\0'; -} - -/* XXX: I hate this. --KM */ -void -update_rules(Rule **rule, const char *data) { - /* basic rule matching language /regex/ -> value - * regex might contain POSIX regex syntax defined in regex(3) */ - enum { - IGNORE, - REGEX, - VALUE, - COMMENT, - }; - int state; - Rule *rul; - char regex[256], value[256]; - char *regex_end = regex + sizeof(regex) - 1; - char *value_end = value + sizeof(value) - 1; - char *r, *v; - const char *p; - char c; - - SET(r); - SET(v); - if(!data || !strlen(data)) + if(!data || !data[0]) return; - while((rul = *rule)) { - *rule = rul->next; - free(rul->regex); - free(rul); - } - state = IGNORE; - for(p = data; (c = *p); p++) - switch(state) { - case COMMENT: - if(c == '\n') - state = IGNORE; - break; - case IGNORE: - if(c == '#') - state = COMMENT; - else if(c == '/') { - r = regex; - state = REGEX; - } - else if(c == '>') { - value[0] = 0; - v = value; - state = VALUE; - } - break; - case REGEX: - if(c == '\\' && p[1] == '/') - p++; - else if(c == '/') { - *r = 0; - state = IGNORE; + + buf = ixp_message(data, strlen(data), MsgUnpack); + +begin: + msg_eatrunes(&buf, isspacerune, true); + if(getc(&buf) == '/') + goto regexp; + /* Regexp not at begining of the line. Rest of the line is junk. */ + while((c = getc(&buf))) + if(c == '\n') + goto begin; + goto done; + +regexp: + rebuf = ixp_message(regexp, sizeof regexp - 1, MsgPack); + while((c = getc(&buf))) + if(c == '/') + goto value; + else if(c != '\\') + putc(&rebuf, c); + else if(buf.pos[1] == '/' || buf.pos[1] == '\\' && buf.pos[2] == '/') + putc(&rebuf, getc(&buf)); + else { + putc(&rebuf, c); + putc(&rebuf, getc(&buf)); + } + goto done; + +value: + valuebuf = ixp_message(buffer, sizeof buffer - 1, MsgPack); + while((c = getc(&buf))) { + if(c == '\n') { + putc(&valuebuf, ' '); + msg_eatrunes(&buf, isspacerune, true); + if((c = getc(&buf)) == '/') { + ungetc(&buf); break; } - if(r < regex_end) - *r++ = c; - break; - case VALUE: - if(c == '\n' || c == '#' || c == 0) { - *v = 0; - trim(value, " \t"); - *rule = emallocz(sizeof **rule); - (*rule)->regex = regcomp(regex); - if((*rule)->regex) { - utflcpy((*rule)->value, value, sizeof rul->value); - rule = &(*rule)->next; - }else - free(*rule); - state = IGNORE; - if(c == '#') - state = COMMENT; - } - else if(v < value_end) - *v++ = c; - break; - default: /* can't happen */ - die("invalid state"); } + putc(&valuebuf, c); + } + + putc(&rebuf, '\0'); + re = regcomp(regexp); + if(!re) + goto begin; + r = emallocz(sizeof *r); + *rule = r; + rule = &r->next; + r->regex = re; + + valuebuf.end = valuebuf.pos; + valuebuf.pos = valuebuf.data; + rvp = &r->values; + while((w = msg_getword(&valuebuf, 0))) { + free(r->value); + r->value = estrdup(w); + if(strchr(w, '=')) { + len = strlen(w) + 1; + *rvp = rv = emallocz(sizeof *rv + len); + rvp = &rv->next; + + memcpy(&rv[1], w, len); + tokenize(&rv->key, 2, (char*)&rv[1], '='); + } + } + goto begin; + +done: + return; } + diff --git a/cmd/wmii/screen.c b/cmd/wmii/screen.c index 76d89eb..f448103 100644 --- a/cmd/wmii/screen.c +++ b/cmd/wmii/screen.c @@ -3,7 +3,6 @@ */ #include "dat.h" #include <math.h> -#include <stdlib.h> #include "fns.h" #ifdef notdef diff --git a/cmd/wmii/stack.c b/cmd/wmii/stack.c new file mode 100644 index 0000000..4f471fd --- /dev/null +++ b/cmd/wmii/stack.c @@ -0,0 +1,140 @@ +/* Copyright ©2009-2010 Kris Maglione <maglione.k at Gmail> + * See LICENSE file for license details. + */ +#include "dat.h" +#include "fns.h" + +void +stack_scale(Frame *first, int height) { + Frame *f; + uint dy; + int surplus; + + /* + * Will need something like this. + a = first->area; + column_fit(a, &ncol, &nuncol); + */ + + dy = 0; + for(f=first; f && !f->collapsed; f=f->anext) + dy += Dy(f->colr); + + /* Distribute the surplus. + */ + surplus = height - dy; + for(f=first; f && !f->collapsed; f=f->anext) + f->colr.max.y += ((float)Dy(f->r) / dy) * surplus; +} + +void +stack_info(Frame *f, Frame **firstp, Frame **lastp, int *dyp, int *nframep) { + Frame *ft, *first, *last; + int dy, nframe; + + nframe = 0; + dy = 0; + first = f; + last = f; + + for(ft=f; ft && ft->collapsed; ft=ft->anext) + ; + if(ft && ft != f) { + f = ft; + dy += Dy(f->colr); + } + for(ft=f; ft && !ft->collapsed; ft=ft->aprev) { + first = ft; + nframe++; + dy += Dy(ft->colr); + } + for(ft=f->anext; ft && !ft->collapsed; ft=ft->anext) { + if(first == nil) + first = ft; + last = ft; + nframe++; + dy += Dy(ft->colr); + } + if(nframep) *nframep = nframe; + if(firstp) *firstp = first; + if(lastp) *lastp = last; + if(dyp) *dyp = dy; +} + +int +stack_count(Frame *f, int *mp) { + Frame *fp; + int n, m; + + n = 0; + for(fp=f->aprev; fp && fp->collapsed; fp=fp->aprev) + n++; + m = ++n; + for(fp=f->anext; fp && fp->collapsed; fp=fp->anext) + n++; + if(mp) *mp = m; + return n; +} + +Frame* +stack_find(Area *a, Frame *f, int dir, bool stack) { + Frame *fp; + +#define predicate(f) !((f)->collapsed && stack || (f)->client->nofocus) + switch (dir) { + default: + die("not reached"); + case North: + if(f) + for(f=f->aprev; f && !predicate(f); f=f->aprev) + ; + else { + f = nil; + for(fp=a->frame; fp; fp=fp->anext) + if(predicate(fp)) + f = fp; + } + break; + case South: + if(f) + for(f=f->anext; f && !predicate(f); f=f->anext) + ; + else + for(f=a->frame; f && !predicate(f); f=f->anext) + ; + break; + } +#undef predicate + return f; +} + +bool +find(Area **ap, Frame **fp, int dir, bool wrap, bool stack) { + Rectangle r; + Frame *f; + Area *a; + + f = *fp; + a = *ap; + r = f ? f->r : a->r; + + if(dir == North || dir == South) { + *fp = stack_find(a, f, dir, stack); + if(*fp) + return true; + if(!a->floating) + *ap = area_find(a->view, r, dir, wrap); + if(!*ap) + return false; + *fp = stack_find(*ap, *fp, dir, stack); + return true; + } + if(dir != East && dir != West) + die("not reached"); + *ap = area_find(a->view, r, dir, wrap); + if(!*ap) + return false; + *fp = ap[0]->sel; + return true; +} + diff --git a/cmd/wmii/view.c b/cmd/wmii/view.c index e853003..5bf43c5 100644 --- a/cmd/wmii/view.c +++ b/cmd/wmii/view.c @@ -86,7 +86,6 @@ view_create(const char *name) { for(i=0; i < nscreens; i++) view_init(v, i); - area_focus(v->firstarea); v->next = *vp; @@ -108,6 +107,7 @@ view_create(const char *name) { void view_init(View *v, int iscreen) { v->r[iscreen] = screens[iscreen]->r; + v->pad[iscreen] = ZR; v->areas[iscreen] = nil; column_new(v, nil, iscreen, 0); } @@ -149,6 +149,7 @@ view_destroy(View *v) { } free(v->areas); free(v->r); + free(v->pad); free(v); ewmh_updateviews(); } @@ -207,26 +208,39 @@ view_update_rect(View *v) { WMScreen *scrn; Strut *strut; Frame *f; + int left, right, top, bottom; int s, i; - /* These short variable names are hell, eh? */ /* XXX: if(v != selview) return false; */ + + top = 0; + left = 0; + right = 0; + bottom = 0; vec.n = 0; for(f=v->floating->frame; f; f=f->anext) { strut = f->client->strut; if(!strut) continue; + /* Can do better in the future. */ + top = max(top, strut->top.max.y); + left = max(left, strut->left.max.x); + right = min(right, strut->right.min.x); + bottom = min(bottom, strut->bottom.min.y); vector_rpush(&vec, strut->top); vector_rpush(&vec, strut->left); vector_rpush(&vec, rectaddpt(strut->right, Pt(scr.rect.max.x, 0))); vector_rpush(&vec, rectaddpt(strut->bottom, Pt(0, scr.rect.max.y))); } - /* Find the largest screen space not occupied by struts. */ vp = unique_rects(&vec, scr.rect); - scrnr = max_rect(vp); + scrnr = scr.rect; + scrnr.min.y += top; + scrnr.min.x += left; + scrnr.max.x += right; + scrnr.max.y += bottom; /* FIXME: Multihead. */ v->floating->r = scr.rect; @@ -253,6 +267,7 @@ view_update_rect(View *v) { || scrn->barpos != BTop && sr.max.y > rr.max.y) rr = sr; } + if(scrn->barpos == BTop) { bar_sety(scrn, rr.min.y); r.min.y = max(r.min.y, scrn->brect.max.y); @@ -272,52 +287,72 @@ view_update(View *v) { Area *a; int s; - if(v != selview) - return; - if(starting) - return; - - frames_update_sel(v); + if(v == selview && !starting) { + frames_update_sel(v); - foreach_frame(v, s, a, f) - if(f->client->fullscreen >= 0) { - f->collapsed = false; - if(!f->area->floating) { - f->oldarea = area_idx(f->area); - f->oldscreen = f->area->screen; - area_moveto(v->floating, f); - area_setsel(v->floating, f); - }else if(f->oldarea == -1) - f->oldarea = 0; + foreach_frame(v, s, a, f) + if(f->client->fullscreen >= 0) { + f->collapsed = false; + if(!f->area->floating) { + f->oldarea = area_idx(f->area); + f->oldscreen = f->area->screen; + area_moveto(v->floating, f); + area_setsel(v->floating, f); + }else if(f->oldarea == -1) + f->oldarea = 0; + } + + view_arrange(v); + + for(c=client; c; c=c->next) { + f = c->sel; + if((f && f->view == v) + && (f->area == v->sel || !(f->area && f->area->max && f->area->floating))) { + if(f->area) + client_resize(c, f->r); + }else { + client_unmapframe(c); + client_unmap(c, IconicState); + } + ewmh_updatestate(c); + ewmh_updateclient(c); } - view_arrange(v); + view_restack(v); + if(!v->sel->floating && view_fullscreen_p(v, v->sel->screen)) + area_focus(v->floating); + else + area_focus(v->sel); + frame_draw_all(); + } + view_update_urgency(v, nil); +} - for(c=client; c; c=c->next) { - f = c->sel; - if((f && f->view == v) - && (f->area == v->sel || !(f->area && f->area->max && f->area->floating))) { - if(f->area) - client_resize(c, f->r); - }else { - unmap_frame(c); - client_unmap(c, IconicState); +void +view_update_urgency(View *v, char *from) { + Area *a; + Frame *f; + int s, urgent; + + urgent = 0; + foreach_frame(v, s, a, f) + if (f->client->urgent) { + urgent++; + break; } - ewmh_updatestate(c); - ewmh_updateclient(c); - } - view_restack(v); - if(!v->sel->floating && view_fullscreen_p(v, v->sel->screen)) - area_focus(v->floating); - else - area_focus(v->sel); - frame_draw_all(); + if (urgent != v->urgent) + event("%sUrgentTag %s %s\n", + urgent ? "" : "Not", + from ? from : "Unknown", + v->name); + + v->urgent = urgent; } void view_focus(WMScreen *s, View *v) { - + USED(s); _view_select(v); @@ -345,18 +380,23 @@ view_attach(View *v, Frame *f) { Client *c; Frame *ff; Area *a, *oldsel; - + c = f->client; oldsel = v->oldsel; a = v->sel; - if(client_floats_p(c)) { + if(c->floating == Never) + a = view_findarea(v, v->selscreen, v->selcol, false); + else if(client_floats_p(c)) { if(v->sel != v->floating && c->fullscreen < 0) oldsel = v->sel; a = v->floating; } - else if((ff = client_groupframe(c, v))) + else if((ff = client_groupframe(c, v))) { a = ff->area; + if(v->oldsel && ff->client == view_selclient(v)) + a = v->oldsel; + } else if(v->sel->floating) { if(v->oldsel) a = v->oldsel; @@ -368,9 +408,10 @@ view_attach(View *v, Frame *f) { || c->sel && c->sel->area && !c->sel->area->floating) a = v->firstarea; } - if(!a->floating && view_fullscreen_p(v, a->screen)) + if(!a->floating && c->floating != Never && view_fullscreen_p(v, a->screen)) a = v->floating; + event("ViewAttach %s %#C\n", v->name, c); area_attach(a, f); /* TODO: Decide whether to focus this frame */ bool newgroup = !c->group @@ -410,9 +451,9 @@ view_detach(Frame *f) { if(c->sel == f) c->sel = f->cnext; - if(v == selview) - view_update(v); - else if(empty_p(v)) + event("ViewDetach %s %#C\n", v->name, c); + view_update(v); + if(v != selview && empty_p(v)) view_destroy(v); } @@ -435,20 +476,13 @@ view_restack(View *v) { Frame *f; Area *a; int s; - + if(v != selview) return; wins.n = 0; - /* *sigh */ for(f=v->floating->stack; f; f=f->snext) - if(f->client->w.ewmh.type & TypeDock) - vector_lpush(&wins, f->client->framewin->xid); - else - break; - - for(; f; f=f->snext) vector_lpush(&wins, f->client->framewin->xid); for(int s=0; s < nscreens; s++) @@ -578,19 +612,26 @@ view_update_all(void) { } uint -view_newcolwidth(View *v, int num) { +view_newcolwidth(View *v, int scrn, int num) { Rule *r; char *toks[16]; char buf[sizeof r->value]; ulong n; + /* XXX: Multihead. */ for(r=def.colrules.rule; r; r=r->next) if(regexec(r->regex, v->name, nil, 0)) { utflcpy(buf, r->value, sizeof buf); n = tokenize(toks, 16, buf, '+'); + if(num < n) if(getulong(toks[num], &n)) - return Dx(v->screenr) * (n / 100.0); /* XXX: Multihead. */ + return Dx(v->r[scrn]) * (n / 100.0); + else if(!strcmp("px", strend(toks[num], 2))) { + toks[num][strlen(toks[num]) - 2] = '\0'; + if(getulong(toks[num], &n)) + return n; + } break; } return 0; @@ -613,13 +654,13 @@ view_index(View *v) { for(f=a->frame; f; f=f->anext) { r = &f->r; if(a->floating) - bufprint("%a %C %d %d %d %d %s\n", + bufprint("%a %#C %d %d %d %d %s\n", a, f->client, r->min.x, r->min.y, Dx(*r), Dy(*r), f->client->props); else - bufprint("%a %C %d %d %s\n", + bufprint("%a %#C %d %d %s\n", a, f->client, r->min.y, Dy(*r), f->client->props); diff --git a/cmd/wmii/x11.c b/cmd/wmii/x11.c deleted file mode 100644 index dafe85c..0000000 --- a/cmd/wmii/x11.c +++ /dev/null @@ -1,1317 +0,0 @@ -/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail> - * See LICENSE file for license details. - */ -#define _X11_VISIBLE -#define pointerwin __pointerwin -#include "dat.h" -#include <limits.h> -#include <math.h> -#include <strings.h> -#include <unistd.h> -#include <bio.h> -#include "fns.h" -#undef pointerwin - -const Point ZP = {0, 0}; -const Rectangle ZR = {{0, 0}, {0, 0}}; - -const Window _pointerwin = { .xid = PointerRoot }; -Window* const pointerwin = (Window*)&_pointerwin; - -static Map windowmap; -static Map atommap; -static MapEnt* wbucket[137]; -static MapEnt* abucket[137]; - -static int errorhandler(Display*, XErrorEvent*); -static int (*xlib_errorhandler) (Display*, XErrorEvent*); - -static XftColor* xftcolor(Color); - - -/* Rectangles/Points */ -XRectangle -XRect(Rectangle r) { - XRectangle xr; - - xr.x = r.min.x; - xr.y = r.min.y; - xr.width = Dx(r); - xr.height = Dy(r); - return xr; -} - -int -eqrect(Rectangle a, Rectangle b) { - return a.min.x==b.min.x && a.max.x==b.max.x - && a.min.y==b.min.y && a.max.y==b.max.y; -} - -int -eqpt(Point p, Point q) { - return p.x==q.x && p.y==q.y; -} - -Point -addpt(Point p, Point q) { - p.x += q.x; - p.y += q.y; - return p; -} - -Point -subpt(Point p, Point q) { - p.x -= q.x; - p.y -= q.y; - return p; -} - -Point -mulpt(Point p, Point q) { - p.x *= q.x; - p.y *= q.y; - return p; -} - -Point -divpt(Point p, Point q) { - p.x /= q.x; - p.y /= q.y; - return p; -} - -Rectangle -insetrect(Rectangle r, int n) { - r.min.x += n; - r.min.y += n; - r.max.x -= n; - r.max.y -= n; - return r; -} - -Rectangle -rectaddpt(Rectangle r, Point p) { - r.min.x += p.x; - r.max.x += p.x; - r.min.y += p.y; - r.max.y += p.y; - return r; -} - -Rectangle -rectsubpt(Rectangle r, Point p) { - r.min.x -= p.x; - r.max.x -= p.x; - r.min.y -= p.y; - r.max.y -= p.y; - return r; -} - -Rectangle -rectsetorigin(Rectangle r, Point p) { - Rectangle ret; - - ret.min.x = p.x; - ret.min.y = p.y; - ret.max.x = p.x + Dx(r); - ret.max.y = p.y + Dy(r); - return ret; -} - -/* 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; - - r = va_arg(f->args, Rectangle); - return fmtprint(f, "%P+%dx%d", r.min, Dx(r), Dy(r)); -} - -static int -Pfmt(Fmt *f) { - Point p; - - p = va_arg(f->args, Point); - return fmtprint(f, "(%d,%d)", p.x, p.y); -} - -static int -Wfmt(Fmt *f) { - Window *w; - - w = va_arg(f->args, Window*); - return fmtprint(f, "0x%ulx", w->xid); -} - -/* Init */ -void -initdisplay(void) { - display = XOpenDisplay(nil); - if(display == nil) - fatal("Can't open display"); - scr.screen = DefaultScreen(display); - scr.colormap = DefaultColormap(display, scr.screen); - scr.visual = DefaultVisual(display, scr.screen); - scr.visual32 = DefaultVisual(display, scr.screen); - scr.gc = DefaultGC(display, scr.screen); - scr.depth = DefaultDepth(display, scr.screen); - - scr.white = WhitePixel(display, scr.screen); - scr.black = BlackPixel(display, scr.screen); - - scr.root.xid = RootWindow(display, scr.screen); - scr.root.r = Rect(0, 0, - DisplayWidth(display, scr.screen), - DisplayHeight(display, scr.screen)); - scr.rect = scr.root.r; - - scr.root.parent = &scr.root; - - windowmap.bucket = wbucket; - windowmap.nhash = nelem(wbucket); - atommap.bucket = abucket; - atommap.nhash = nelem(abucket); - - fmtinstall('A', Afmt); - fmtinstall('R', Rfmt); - fmtinstall('P', Pfmt); - fmtinstall('W', Wfmt); - - xlib_errorhandler = XSetErrorHandler(errorhandler); -} - -/* Error handling */ - -extern ErrorCode ignored_xerrors[]; -static bool _trap_errors; -static long nerrors; - -static int -errorhandler(Display *dpy, XErrorEvent *error) { - ErrorCode *e; - - USED(dpy); - - if(_trap_errors) - nerrors++; - - e = ignored_xerrors; - if(e) - for(; e->rcode || e->ecode; e++) - if((e->rcode == 0 || e->rcode == error->request_code) - && (e->ecode == 0 || e->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() */ -} - -int -traperrors(bool enable) { - - sync(); - _trap_errors = enable; - if (enable) - nerrors = 0; - return nerrors; - -} - -/* Images */ -Image* -allocimage(int w, int h, int depth) { - Image *img; - - img = emallocz(sizeof *img); - img->type = WImage; - img->xid = XCreatePixmap(display, scr.root.xid, w, h, depth); - img->gc = XCreateGC(display, img->xid, 0, nil); - img->colormap = scr.colormap; - img->visual = scr.visual; - if(depth == 32) - img->visual = scr.visual32; - img->depth = depth; - img->r = Rect(0, 0, w, h); - return img; -} - -void -freeimage(Image *img) { - if(img == nil) - return; - - assert(img->type == WImage); - - if(img->xft) - XftDrawDestroy(img->xft); - XFreePixmap(display, img->xid); - XFreeGC(display, img->gc); - free(img); -} - -static XftDraw* -xftdrawable(Image *img) { - if(img->xft == nil) - img->xft = XftDrawCreate(display, img->xid, img->visual, img->colormap); - return img->xft; -} - -/* Windows */ -Window* -createwindow_visual(Window *parent, Rectangle r, - int depth, Visual *vis, uint class, - WinAttr *wa, int valmask) { - Window *w; - - assert(parent->type == WWindow); - - w = emallocz(sizeof *w); - w->visual = vis; - w->type = WWindow; - w->parent = parent; - if(valmask & CWColormap) - w->colormap = wa->colormap; - - w->xid = XCreateWindow(display, parent->xid, r.min.x, r.min.y, Dx(r), Dy(r), - 0 /* border */, depth, class, vis, valmask, wa); -#if 0 - print("createwindow_visual(%W, %R, %d, %p, %ud, %p, %x) = %W\n", - parent, r, depth, vis, class, wa, valmask, w); -#endif - if(class != InputOnly) - w->gc = XCreateGC(display, w->xid, 0, nil); - - w->r = r; - w->depth = depth; - return w; -} - -Window* -createwindow(Window *parent, Rectangle r, int depth, uint class, WinAttr *wa, int valmask) { - return createwindow_visual(parent, r, depth, scr.visual, class, wa, valmask); -} - -Window* -window(XWindow xw) { - Window *w; - - w = malloc(sizeof *w); - w->type = WWindow; - w->xid = xw; - return freelater(w); -} - -void -reparentwindow(Window *w, Window *par, Point p) { - assert(w->type == WWindow); - XReparentWindow(display, w->xid, par->xid, p.x, p.y); - w->parent = par; - w->r = rectsubpt(w->r, w->r.min); - w->r = rectaddpt(w->r, p); -} - -void -destroywindow(Window *w) { - assert(w->type == WWindow); - sethandler(w, nil); - if(w->xft) - XftDrawDestroy(w->xft); - if(w->gc) - XFreeGC(display, w->gc); - XDestroyWindow(display, w->xid); - free(w); -} - -void -setwinattr(Window *w, WinAttr *wa, int valmask) { - assert(w->type == WWindow); - XChangeWindowAttributes(display, w->xid, valmask, wa); -} - -void -selectinput(Window *w, long mask) { - XSelectInput(display, w->xid, mask); -} - -static void -configwin(Window *w, Rectangle r, int border) { - XWindowChanges wc; - - if(eqrect(r, w->r) && border == w->border) - return; - - wc.x = r.min.x - border; - wc.y = r.min.y - border; - wc.width = Dx(r); - wc.height = Dy(r); - wc.border_width = border; - XConfigureWindow(display, w->xid, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); - - w->r = r; - w->border = border; -} - -void -setborder(Window *w, int width, Color col) { - - assert(w->type == WWindow); - if(width) - XSetWindowBorder(display, w->xid, col.pixel); - if(width != w->border) - configwin(w, w->r, width); -} - -void -reshapewin(Window *w, Rectangle r) { - assert(w->type == WWindow); - assert(Dx(r) > 0 && Dy(r) > 0); /* Rather than an X error. */ - - configwin(w, r, w->border); -} - -void -movewin(Window *w, Point pt) { - Rectangle r; - - assert(w->type == WWindow); - r = rectsetorigin(w->r, pt); - reshapewin(w, r); -} - -int -mapwin(Window *w) { - assert(w->type == WWindow); - if(!w->mapped) { - XMapWindow(display, w->xid); - w->mapped = 1; - return 1; - } - return 0; -} - -int -unmapwin(Window *w) { - assert(w->type == WWindow); - if(w->mapped) { - XUnmapWindow(display, w->xid); - w->mapped = 0; - w->unmapped++; - return 1; - } - return 0; -} - -void -raisewin(Window *w) { - assert(w->type == WWindow); - XRaiseWindow(display, w->xid); -} - -void -lowerwin(Window *w) { - assert(w->type == WWindow); - XLowerWindow(display, w->xid); -} - -Handlers* -sethandler(Window *w, Handlers *new) { - Handlers *old; - void **e; - - assert(w->type == WWindow); - assert((w->prev != nil && w->next != nil) || w->next == w->prev); - - if(new == nil) - map_rm(&windowmap, (ulong)w->xid); - else { - e = map_get(&windowmap, (ulong)w->xid, true); - *e = w; - } - old = w->handler; - w->handler = new; - return old; -} - -Window* -findwin(XWindow w) { - void **e; - - e = map_get(&windowmap, (ulong)w, false); - if(e) - return *e; - return nil; -} - -/* Shape */ -void -setshapemask(Window *dst, Image *src, Point pt) { - /* Assumes that we have the shape extension... */ - XShapeCombineMask (display, dst->xid, - ShapeBounding, pt.x, pt.y, src->xid, ShapeSet); -} - -static void -setgccol(Image *dst, Color col) { - XSetForeground(display, dst->gc, col.pixel); -} - -/* Drawing */ -void -border(Image *dst, Rectangle r, int w, Color col) { - if(w == 0) - return; - - r = insetrect(r, w/2); - r.max.x -= w%2; - r.max.y -= w%2; - - XSetLineAttributes(display, dst->gc, w, LineSolid, CapButt, JoinMiter); - setgccol(dst, col); - XDrawRectangle(display, dst->xid, dst->gc, - r.min.x, r.min.y, Dx(r), Dy(r)); -} - -void -fill(Image *dst, Rectangle r, Color col) { - setgccol(dst, col); - XFillRectangle(display, dst->xid, dst->gc, - r.min.x, r.min.y, Dx(r), Dy(r)); -} - -static XPoint* -convpts(Point *pt, int np) { - XPoint *rp; - int i; - - rp = emalloc(np * sizeof *rp); - for(i = 0; i < np; i++) { - rp[i].x = pt[i].x; - rp[i].y = pt[i].y; - } - return rp; -} - -void -drawpoly(Image *dst, Point *pt, int np, int cap, int w, Color col) { - XPoint *xp; - - xp = convpts(pt, np); - XSetLineAttributes(display, dst->gc, w, LineSolid, cap, JoinMiter); - setgccol(dst, col); - XDrawLines(display, dst->xid, dst->gc, xp, np, CoordModeOrigin); - free(xp); -} - -void -fillpoly(Image *dst, Point *pt, int np, Color col) { - XPoint *xp; - - xp = convpts(pt, np); - setgccol(dst, col); - XFillPolygon(display, dst->xid, dst->gc, xp, np, Complex, CoordModeOrigin); - free(xp); -} - -void -drawline(Image *dst, Point p1, Point p2, int cap, int w, Color col) { - XSetLineAttributes(display, dst->gc, w, LineSolid, cap, JoinMiter); - setgccol(dst, col); - XDrawLine(display, dst->xid, dst->gc, p1.x, p1.y, p2.x, p2.y); -} - -uint -drawstring(Image *dst, Font *font, - Rectangle r, Align align, - char *text, Color col) { - Rectangle tr; - char *buf; - uint x, y, width, height, len; - int shortened; - - shortened = 0; - - len = strlen(text); - buf = emalloc(len+1); - memcpy(buf, text, len+1); - - r.max.y -= font->pad.min.y; - r.min.y += font->pad.max.y; - - height = font->ascent + font->descent; - y = r.min.y + Dy(r) / 2 - height / 2 + font->ascent; - - width = Dx(r) - font->pad.min.x - font->pad.max.x - (font->height & ~1); - - r.min.x += font->pad.min.x; - r.max.x -= font->pad.max.x; - - /* shorten text if necessary */ - tr = ZR; - while(len > 0) { - tr = textextents_l(font, buf, len + min(shortened, 3), nil); - if(Dx(tr) <= width) - break; - while(len > 0 && (buf[--len]&0xC0) == 0x80) - buf[len] = '.'; - buf[len] = '.'; - shortened++; - } - - if(len == 0 || Dx(tr) > width) - goto done; - - /* mark shortened info in the string */ - if(shortened) - len += min(shortened, 3); - - switch (align) { - case East: - x = r.max.x - (tr.max.x + (font->height / 2)); - break; - case Center: - x = r.min.x + (Dx(r) - Dx(tr)) / 2 - tr.min.x; - break; - default: - x = r.min.x + (font->height / 2) - tr.min.x; - break; - } - - setgccol(dst, col); - switch(font->type) { - case FFontSet: - Xutf8DrawString(display, dst->xid, - font->font.set, dst->gc, - x, y, - buf, len); - break; - case FXft: - XftDrawStringUtf8(xftdrawable(dst), xftcolor(col), - font->font.xft, - x, y, (uchar*)buf, len); - break; - case FX11: - XSetFont(display, dst->gc, font->font.x11->fid); - XDrawString(display, dst->xid, dst->gc, - x, y, buf, len); - break; - default: - die("Invalid font type."); - } - -done: - free(buf); - return Dx(tr); -} - -void -copyimage(Image *dst, Rectangle r, Image *src, Point p) { - XCopyArea(display, - src->xid, dst->xid, - dst->gc, - r.min.x, r.min.y, Dx(r), Dy(r), - p.x, p.y); -} - -/* Colors */ -bool -namedcolor(char *name, Color *ret) { - XColor c, c2; - - if(XAllocNamedColor(display, scr.colormap, name, &c, &c2)) { - *ret = (Color) { - c.pixel, { - c.red, - c.green, - c.blue, - 0xffff - }, - }; - return true; - } - return false; -} - -bool -loadcolor(CTuple *c, char *str) { - char buf[24]; - - utflcpy(buf, str, sizeof buf); - memcpy(c->colstr, str, sizeof c->colstr); - - buf[7] = buf[15] = buf[23] = '\0'; - return namedcolor(buf, &c->fg) - && namedcolor(buf+8, &c->bg) - && namedcolor(buf+16, &c->border); -} - -static XftColor* -xftcolor(Color col) { - XftColor *c; - - c = emallocz(sizeof *c); - *c = (XftColor) { - ((col.render.alpha&0xff00) << 24) - | ((col.render.red&0xff00) << 8) - | ((col.render.green&0xff00) << 0) - | ((col.render.blue&0xff00) >> 8), - col.render - }; - return freelater(c); -} - -/* Fonts */ -Font* -loadfont(char *name) { - XFontStruct **xfonts; - char **missing, **font_names; - Biobuf *b; - Font *f; - int n, i; - - missing = nil; - f = emallocz(sizeof *f); - f->name = estrdup(name); - if(!strncmp(f->name, "xft:", 4)) { - f->type = FXft; - - f->font.xft = XftFontOpenXlfd(display, scr.screen, f->name + 4); - if(!f->font.xft) - f->font.xft = XftFontOpenName(display, scr.screen, f->name + 4); - if(!f->font.xft) - goto error; - - f->ascent = f->font.xft->ascent; - f->descent = f->font.xft->descent; - }else { - f->font.set = XCreateFontSet(display, name, &missing, &n, nil); - if(missing) { - if(false) { - b = Bfdopen(dup(2), O_WRONLY); - Bprint(b, "%s: note: missing fontset%s for '%s':", argv0, - (n > 1 ? "s" : ""), name); - for(i = 0; i < n; i++) - Bprint(b, "%s %s", (i ? "," : ""), missing[i]); - Bprint(b, "\n"); - Bterm(b); - } - freestringlist(missing); - } - - if(f->font.set) { - f->type = FFontSet; - XFontsOfFontSet(f->font.set, &xfonts, &font_names); - f->ascent = xfonts[0]->ascent; - f->descent = xfonts[0]->descent; - }else { - f->type = FX11; - f->font.x11 = XLoadQueryFont(display, name); - if(!f->font.x11) - goto error; - - f->ascent = f->font.x11->ascent; - f->descent = f->font.x11->descent; - } - } - f->height = f->ascent + f->descent; - return f; - -error: - fprint(2, "%s: cannot load font: %s\n", argv0, name); - f->type = 0; - freefont(f); - return nil; -} - -void -freefont(Font *f) { - switch(f->type) { - case FFontSet: - XFreeFontSet(display, f->font.set); - break; - case FXft: - XftFontClose(display, f->font.xft); - break; - case FX11: - XFreeFont(display, f->font.x11); - break; - default: - break; - } - free(f->name); - free(f); -} - -Rectangle -textextents_l(Font *font, char *text, uint len, int *offset) { - Rectangle rect; - XRectangle r; - XGlyphInfo i; - int unused; - - if(!offset) - offset = &unused; - - switch(font->type) { - case FFontSet: - *offset = Xutf8TextExtents(font->font.set, text, len, &r, nil); - return Rect(r.x, -r.y - r.height, r.x + r.width, -r.y); - case FXft: - XftTextExtentsUtf8(display, font->font.xft, (uchar*)text, len, &i); - *offset = i.xOff; - return Rect(-i.x, i.y - i.height, -i.x + i.width, i.y); - case FX11: - rect = ZR; - rect.max.x = XTextWidth(font->font.x11, text, len); - rect.max.y = font->ascent; - *offset = rect.max.x; - return rect; - default: - die("Invalid font type"); - return ZR; /* shut up ken */ - } -} - -uint -textwidth_l(Font *font, char *text, uint len) { - Rectangle r; - - r = textextents_l(font, text, len, nil); - return Dx(r); -} - -uint -textwidth(Font *font, char *text) { - return textwidth_l(font, text, strlen(text)); -} - -uint -labelh(Font *font) { - return max(font->height + font->descent + font->pad.min.y + font->pad.max.y, 1); -} - -/* Misc */ -Atom -xatom(char *name) { - void **e; - - e = hash_get(&atommap, name, true); - if(*e == nil) - *e = (void*)XInternAtom(display, name, false); - return (Atom)*e; -} - -void -sendmessage(Window *w, char *name, long l0, long l1, long l2, long l3, long l4) { - XClientMessageEvent e; - - e.type = ClientMessage; - e.window = w->xid; - e.message_type = xatom(name); - e.format = 32; - e.data.l[0] = l0; - e.data.l[1] = l1; - e.data.l[2] = l2; - e.data.l[3] = l3; - e.data.l[4] = l4; - sendevent(w, false, NoEventMask, (XEvent*)&e); -} - -void -sendevent(Window *w, bool propegate, long mask, XEvent *e) { - XSendEvent(display, w->xid, propegate, mask, e); -} - -KeyCode -keycode(char *name) { - return XKeysymToKeycode(display, XStringToKeysym(name)); -} - -typedef struct KMask KMask; - -static struct KMask { - int mask; - const char* name; -} masks[] = { - {ShiftMask, "Shift"}, - {ControlMask, "Control"}, - {Mod1Mask, "Mod1"}, - {Mod2Mask, "Mod2"}, - {Mod3Mask, "Mod3"}, - {Mod4Mask, "Mod4"}, - {Mod5Mask, "Mod5"}, - {0,} -}; - -bool -parsekey(char *str, int *mask, char **key) { - static char *keys[16]; - KMask *m; - int i, nkeys; - - *mask = 0; - nkeys = tokenize(keys, nelem(keys), str, '-'); - for(i=0; i < nkeys; i++) { - for(m=masks; m->mask; m++) - if(!strcasecmp(m->name, keys[i])) { - *mask |= m->mask; - goto next; - } - break; - next: continue; - } - if(key) { - if(nkeys) - *key = keys[i]; - return i == nkeys - 1; - } - else - return i == nkeys; -} - -void -sync(void) { - XSync(display, false); -} - -/* Properties */ -void -delproperty(Window *w, char *prop) { - XDeleteProperty(display, w->xid, xatom(prop)); -} - -void -changeproperty(Window *w, char *prop, char *type, - int width, uchar data[], int n) { - XChangeProperty(display, w->xid, 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); -} - -void -changeprop_short(Window *w, char *prop, char *type, short data[], int len) { - changeproperty(w, prop, type, 16, (uchar*)data, len); -} - -void -changeprop_long(Window *w, char *prop, char *type, long data[], int len) { - changeproperty(w, prop, type, 32, (uchar*)data, len); -} - -void -changeprop_ulong(Window *w, char *prop, char *type, ulong data[], int len) { - changeproperty(w, prop, type, 32, (uchar*)data, 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); -} - -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; - - typea = (type ? xatom(type) : 0L); - - status = XGetWindowProperty(display, w->xid, - xatom(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; -} - -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; - free(*ret); - *ret = 0; - return 0; -} - -ulong -getprop_ulong(Window *w, char *prop, char *type, - ulong offset, ulong **ret, ulong length) { - return getprop_long(w, prop, type, offset, (long**)ret, length); -} - -char** -strlistdup(char *list[]) { - char **p; - char *q; - int i, m, n; - - n = 0; - m = 0; - for(p=list; *p; p++, n++) - m += strlen(*p) + 1; - - p = malloc((n+1) * sizeof(*p) + m); - 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; -} - -int -getprop_textlist(Window *w, char *name, char **ret[]) { - XTextProperty prop; - char **list; - int n; - - *ret = nil; - n = 0; - - XGetTextProperty(display, w->xid, &prop, xatom(name)); - if(prop.nitems > 0) { - if(Xutf8TextPropertyToTextList(display, &prop, &list, &n) == Success) - *ret = list; - XFree(prop.value); - } - return n; -} - -char* -getprop_string(Window *w, char *name) { - char **list, *str; - int n; - - str = nil; - - n = getprop_textlist(w, name, &list); - if(n > 0) - str = estrdup(*list); - freestringlist(list); - - return str; -} - -Rectangle -getwinrect(Window *w) { - XWindowAttributes wa; - Point p; - - if(!XGetWindowAttributes(display, w->xid, &wa)) - return ZR; - p = translate(w, &scr.root, ZP); - return rectaddpt(Rect(0, 0, wa.width, wa.height), p); -} - -void -setfocus(Window *w, int mode) { - XSetInputFocus(display, w->xid, mode, CurrentTime); -} - -XWindow -getfocus(void) { - XWindow ret; - int revert; - - XGetInputFocus(display, &ret, &revert); - return ret; -} - -/* Mouse */ -Point -querypointer(Window *w) { - XWindow win; - Point pt; - uint ui; - int i; - - XQueryPointer(display, w->xid, &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.xid, &win, &win, &i, &i, - &pt.x, &pt.y, &ui); -} - -void -warppointer(Point pt) { - /* Nasty kludge for xephyr, xnest. */ - static int havereal = -1; - static char* real; - - if(havereal == -1) { - real = getenv("REALDISPLAY"); - havereal = real != nil; - } - if(havereal) - system(sxprint("DISPLAY=%s wiwarp %d %d", real, pt.x, pt.y)); - - XWarpPointer(display, - /* src, dest w */ None, scr.root.xid, - /* src_rect */ 0, 0, 0, 0, - /* target */ pt.x, pt.y); -} - -Point -translate(Window *src, Window *dst, Point sp) { - Point pt; - XWindow w; - - XTranslateCoordinates(display, src->xid, dst->xid, sp.x, sp.y, - &pt.x, &pt.y, &w); - return pt; -} - -int -grabpointer(Window *w, Window *confine, Cursor cur, int mask) { - XWindow cw; - - cw = None; - if(confine) - cw = confine->xid; - return XGrabPointer(display, w->xid, false /* owner events */, mask, - GrabModeAsync, GrabModeAsync, cw, cur, CurrentTime - ) == GrabSuccess; -} - -void -ungrabpointer(void) { - XUngrabPointer(display, CurrentTime); -} - -int -grabkeyboard(Window *w) { - - return XGrabKeyboard(display, w->xid, true /* owner events */, - GrabModeAsync, GrabModeAsync, CurrentTime - ) == GrabSuccess; -} - -void -ungrabkeyboard(void) { - XUngrabKeyboard(display, CurrentTime); -} - -/* Insanity */ -void -sethints(Window *w) { - XSizeHints xs; - XWMHints *wmh; - WinHints *h; - Point p; - long size; - - if(w->hints == nil) - w->hints = emalloc(sizeof *h); - - h = w->hints; - memset(h, 0, sizeof *h); - - h->max = Pt(INT_MAX, INT_MAX); - h->inc = Pt(1,1); - - wmh = XGetWMHints(display, w->xid); - if(wmh) { - if(wmh->flags & WindowGroupHint) - h->group = wmh->window_group; - free(wmh); - } - - if(!XGetWMNormalHints(display, w->xid, &xs, &size)) - return; - - if(xs.flags & PMinSize) { - h->min.x = xs.min_width; - h->min.y = xs.min_height; - } - if(xs.flags & PMaxSize) { - h->max.x = xs.max_width; - h->max.y = xs.max_height; - } - - /* Goddamn buggy clients. */ - if(h->max.x < h->min.x) - h->max.x = h->min.x; - if(h->max.y < h->min.y) - h->max.y = h->min.y; - - h->base = h->min; - if(xs.flags & PBaseSize) { - p.x = xs.base_width; - p.y = xs.base_height; - h->base = p; - h->baspect = p; - } - - if(xs.flags & PResizeInc) { - h->inc.x = max(xs.width_inc, 1); - h->inc.y = max(xs.height_inc, 1); - } - - if(xs.flags & PAspect) { - h->aspect.min.x = xs.min_aspect.x; - h->aspect.min.y = xs.min_aspect.y; - h->aspect.max.x = xs.max_aspect.x; - h->aspect.max.y = xs.max_aspect.y; - } - - h->position = (xs.flags & (USPosition|PPosition)) != 0; - - if(!(xs.flags & PWinGravity)) - xs.win_gravity = NorthWestGravity; - p = ZP; - switch (xs.win_gravity) { - case EastGravity: - case CenterGravity: - case WestGravity: - p.y = 1; - break; - case SouthEastGravity: - case SouthGravity: - case SouthWestGravity: - p.y = 2; - break; - } - switch (xs.win_gravity) { - case NorthGravity: - case CenterGravity: - case SouthGravity: - p.x = 1; - break; - case NorthEastGravity: - case EastGravity: - case SouthEastGravity: - p.x = 2; - break; - } - h->grav = p; - h->gravstatic = (xs.win_gravity == StaticGravity); -} - -Rectangle -sizehint(WinHints *h, Rectangle r) { - Point p, aspect, origin; - - if(h == nil) - return r; - - origin = r.min; - r = rectsubpt(r, origin); - - /* Min/max */ - r.max.x = max(r.max.x, h->min.x); - r.max.y = max(r.max.y, h->min.y); - r.max.x = min(r.max.x, h->max.x); - r.max.y = min(r.max.y, h->max.y); - - /* Increment */ - p = subpt(r.max, h->base); - r.max.x -= p.x % h->inc.x; - r.max.y -= p.y % h->inc.y; - - /* Aspect */ - p = subpt(r.max, h->baspect); - p.y = max(p.y, 1); - - aspect = h->aspect.min; - if(p.x * aspect.y / p.y < aspect.x) - r.max.y = h->baspect.y - + p.x * aspect.y / aspect.x; - - aspect = h->aspect.max; - if(p.x * aspect.y / p.y > aspect.x) - r.max.x = h->baspect.x - + p.y * aspect.x / aspect.y; - - return rectaddpt(r, origin); -} - -Rectangle -gravitate(Rectangle rc, Rectangle rf, Point grav) { - Point d; - - /* Get delta between frame and client rectangles */ - d = subpt(subpt(rf.max, rf.min), - subpt(rc.max, rc.min)); - - /* Divide by 2 and apply gravity */ - d = divpt(d, Pt(2, 2)); - d = mulpt(d, grav); - - return rectsubpt(rc, d); -} - diff --git a/cmd/wmii/xdnd.c b/cmd/wmii/xdnd.c index abb3612..94337dd 100644 --- a/cmd/wmii/xdnd.c +++ b/cmd/wmii/xdnd.c @@ -4,12 +4,15 @@ #include "dat.h" #include "fns.h" +static Handlers handlers; + void xdnd_initwindow(Window *w) { long l; l = 3; /* They are insane. Why is this an ATOM?! */ changeprop_long(w, "XdndAware", "ATOM", &l, 1); + pushhandler(w, &handlers, nil); } typedef struct Dnd Dnd; @@ -18,9 +21,8 @@ struct Dnd { Rectangle r; }; -int -xdnd_clientmessage(XClientMessageEvent *e) { - Window *w; +static bool +clientmessage_event(Window *w, void *aux, XClientMessageEvent *e) { Dnd *dnd; long *l; Rectangle r; @@ -35,43 +37,37 @@ xdnd_clientmessage(XClientMessageEvent *e) { if(msg == xatom("XdndEnter")) { if(e->format != 32) - return -1; - w = findwin(e->window); - if(w) { - if(w->dnd == nil) - w->dnd = emallocz(sizeof *dnd); - dnd = w->dnd; - dnd->source = l[0]; - dnd->r = ZR; - } - return 1; + return false; + if(w->dnd == nil) + w->dnd = emallocz(sizeof *dnd); + dnd = w->dnd; + dnd->source = l[0]; + dnd->r = ZR; + return false; }else if(msg == xatom("XdndLeave")) { if(e->format != 32) - return -1; - w = findwin(e->window); - if(w && w->dnd) { + return false; + if(w->dnd) { free(w->dnd); w->dnd = nil; } - return 1; + return false; }else if(msg == xatom("XdndPosition")) { if(e->format != 32) - return -1; + return false; r = ZR; - w = findwin(e->window); - if(w) - dnd = w->dnd; + dnd = w->dnd; if(dnd) { p.x = (ulong)l[2] >> 16; p.y = (ulong)l[2] & 0xffff; p = subpt(p, w->r.min); Dprint(DDnd, "\tw: %W\n", w); Dprint(DDnd, "\tp: %P\n", p); - if(eqrect(dnd->r, ZR) || !rect_haspoint_p(p, dnd->r)) + if(eqrect(dnd->r, ZR) || !rect_haspoint_p(dnd->r, p)) if(w->handler->dndmotion) - dnd->r = w->handler->dndmotion(w, p); + dnd->r = w->handler->dndmotion(w, w->aux, p); r = dnd->r; if(!eqrect(r, ZR)) r = rectaddpt(r, w->r.min); @@ -80,9 +76,13 @@ xdnd_clientmessage(XClientMessageEvent *e) { pos = (r.min.x<<16) | r.min.y; siz = (Dx(r)<<16) | Dy(r); sendmessage(window(l[0]), "XdndStatus", e->window, 0, pos, siz, 0); - return 1; + return false; } - return 0; + return true; } +static Handlers handlers = { + .message = clientmessage_event +}; + diff --git a/cmd/wmii/xext.c b/cmd/wmii/xext.c deleted file mode 100644 index ba851e5..0000000 --- a/cmd/wmii/xext.c +++ /dev/null @@ -1,160 +0,0 @@ -/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail> - * See LICENSE file for license details. - */ -#define _X11_VISIBLE -#include "dat.h" -#include <X11/extensions/Xrender.h> -#include <X11/extensions/Xinerama.h> -#include "fns.h" - -#if RANDR_MAJOR < 1 -# error XRandR versions less than 1.0 are not supported -#endif - -static void randr_screenchange(XRRScreenChangeNotifyEvent*); -static bool randr_event_p(XEvent *e); -static void randr_init(void); -static void render_init(void); -static void xinerama_init(void); - -typedef void (*EvHandler)(XEvent*); -static EvHandler randr_handlers[RRNumberEvents]; - -bool have_RandR; -bool have_render; -bool have_xinerama; -int randr_eventbase; - -static void -handle(XEvent *e, EvHandler h[], int base) { - - if(h[e->type-base]) - h[e->type-base](e); -} - -void -xext_init(void) { - randr_init(); - render_init(); - xinerama_init(); -} - -void -xext_event(XEvent *e) { - - if(randr_event_p(e)) - handle(e, randr_handlers, randr_eventbase); -} - -static void -randr_init(void) { - int errorbase, major, minor; - - have_RandR = XRRQueryExtension(display, &randr_eventbase, &errorbase); - if(have_RandR) - if(XRRQueryVersion(display, &major, &minor) && major < 1) - have_RandR = false; - if(have_RandR) - XRRSelectInput(display, scr.root.xid, RRScreenChangeNotifyMask); -} - -static bool -randr_event_p(XEvent *e) { - return have_RandR - && (uint)e->type - randr_eventbase < RRNumberEvents; -} - -static void -randr_screenchange(XRRScreenChangeNotifyEvent *ev) { - - XRRUpdateConfiguration((XEvent*)ev); - if(ev->rotation*90 % 180) - scr.rect = Rect(0, 0, ev->width, ev->height); - else - scr.rect = Rect(0, 0, ev->height, ev->width); - init_screens(); -} - -static EvHandler randr_handlers[] = { - [RRScreenChangeNotify] = (EvHandler)randr_screenchange, -}; - -/* Ripped most graciously from ecore_x. XRender documentation - * is sparse. - */ -static void -render_init(void) { - XVisualInfo *vip; - XVisualInfo vi; - int base, i, n; - - have_render = XRenderQueryExtension(display, &base, &base); - if(!have_render) - return; - - vi.class = TrueColor; - vi.depth = 32; - vi.screen = scr.screen; - vip = XGetVisualInfo(display, VisualClassMask - | VisualDepthMask - | VisualScreenMask, - &vi, &n); - for(i=0; i < n; i++) - if(render_argb_p(vip[i].visual)) { - render_visual = vip[i].visual; - scr.visual32 = render_visual; - break; - } - XFree(vip); -} - -bool -render_argb_p(Visual *v) { - XRenderPictFormat *f; - - if(!have_render) - return false; - f = XRenderFindVisualFormat(display, v); - return f - && f->type == PictTypeDirect - && f->direct.alphaMask; -} - -static void -xinerama_init(void) { - int base; - - have_xinerama = XineramaQueryExtension(display, &base, &base); -} - -static bool -xinerama_active(void) { - return have_xinerama && XineramaIsActive(display); -} - -Rectangle* -xinerama_screens(int *np) { - static Rectangle *rects; - XineramaScreenInfo *res; - int i, n; - - if(!xinerama_active()) { - *np = 1; - return &scr.rect; - } - - free(rects); - res = XineramaQueryScreens(display, &n); - rects = emalloc(n * sizeof *rects); - for(i=0; i < n; i++) { - rects[i].min.x = res[i].x_org; - rects[i].min.y = res[i].y_org; - rects[i].max.x = res[i].x_org + res[i].width; - rects[i].max.y = res[i].y_org + res[i].height; - } - XFree(res); - - *np = n; - return rects; -} - diff --git a/cmd/wmiir.c b/cmd/wmiir.c index 1801df8..ecf9a92 100644 --- a/cmd/wmiir.c +++ b/cmd/wmiir.c @@ -1,23 +1,33 @@ -/* Copyight ©2007-2010 Kris Maglione <fbsdaemon@gmail.com> +/* Copyight ©2007-2010 Kris Maglione <maglione.k at Gmail> * See LICENSE file for license details. */ #define IXP_NO_P9_ #define IXP_P9_STRUCTS +#include <dirent.h> +#include <errno.h> +#include <limits.h> +#include <locale.h> #include <stdio.h> -#include <stdlib.h> #include <string.h> +#include <sys/stat.h> +#include <sys/signal.h> #include <time.h> #include <unistd.h> +#include <wchar.h> + #include <ixp.h> -#include <util.h> +#include <stuff/util.h> +#include <bio.h> #include <fmt.h> -static IxpClient *client; +static IxpClient* client; +static Biobuf* outbuf; +static bool binary; static void usage(void) { - fprint(1, - "usage: %s [-a <address>] {create | ls [-dlp] | read | remove | write} <file>\n" + lprint(1, + "usage: %s [-a <address>] [-b] {create | ls [-dlp] | read | remove | write} <file>\n" " %s [-a <address>] xwrite <file> <data>\n" " %s -v\n", argv0, argv0, argv0); exit(1); @@ -28,21 +38,111 @@ errfmt(Fmt *f) { return fmtstrcpy(f, ixp_errbuf()); } +static bool +flush(IxpCFid *fid, char *in, int len, bool binary) { + static mbstate_t state; + static char buf[IXP_MAX_MSG]; + static char *out = buf, *outend = buf + sizeof buf; + char *inend; + wchar_t w; + Rune r; + int res; + + if(binary) + return ixp_write(fid, in, len) == len; + + inend = in + len; + do { + if(in == nil || out + UTFmax > outend) { + if(ixp_write(fid, buf, out - buf) != out - buf) + return false; + out = buf; + } + if(in == nil) { + state = (mbstate_t){0}; + return true; + } + + switch((res = mbrtowc(&w, in, inend - in, &state))) { + case -1: + return false; + case 0: + case -2: + return true; + default: + in += res; + r = w < Runemax ? w : Runesync; + out += runetochar(out, &r); + } + } while(in < inend); + return true; +} + +static bool +unflush(int fd, char *in, int len, bool binary) { + static mbstate_t state; + static char buf[IXP_MAX_MSG], extra[UTFmax]; + static char *out = buf, *outend = buf + sizeof buf; + static int nextra; + char *start; + Rune r; + int res, n; + + if(binary) + return write(fd, in, len) == len; + + if(in) { + if((n = nextra)) { + nextra = 0; + while(len > 0 && n < UTFmax && !fullrune(extra, n)) { + extra[n++] = *in++; + len--; + } + unflush(fd, extra, n, binary); + } + n = utfnlen(in, len); + } + + start = in; + do { + if(in == nil || out + MB_LEN_MAX > outend) { + if(write(fd, buf, out - buf) != out - buf) + return false; + out = buf; + } + if(in == nil || n == 0) { + state = (mbstate_t){0}; + return true; + } + + in += chartorune(&r, in); + n--; + res = wcrtomb(out, r, &state); + if(res == -1) + *out++ = '?'; + else + out += res; + } while(n > 0); + + if(in < start + len) { + nextra = min(sizeof extra, len - (in - start)); + memcpy(extra, in, nextra); + } + return true; +} + /* Utility Functions */ static void -write_data(IxpCFid *fid, char *name) { - void *buf; +write_data(IxpCFid *fid, char *name, bool binary) { + char buf[IXP_MAX_MSG]; int len; - buf = emalloc(fid->iounit);; - for(;;) { - len = read(0, buf, fid->iounit); - if(len <= 0) - break; - if(ixp_write(fid, buf, len) != len) + while((len = read(0, buf, fid->iounit)) > 0) + if(!flush(fid, buf, len, binary)) fatal("cannot write file %q\n", name); - } - free(buf); + + if(!binary) + flush(fid, nil, 0, binary); } static int @@ -98,14 +198,14 @@ print_stat(Stat *s, int lflag, char *file, int pflag) { file = ""; if(lflag) - print("%s %s %s %5llud %s %s%s%s\n", - modestr(s->mode), s->uid, s->gid, s->length, - timestr(s->mtime), file, slash, s->name); + Blprint(outbuf, "%s %s %s %5llud %s %s%s%s\n", + modestr(s->mode), s->uid, s->gid, s->length, + timestr(s->mtime), file, slash, s->name); else { if((s->mode&P9_DMDIR) && strcmp(s->name, "/")) - print("%s%s%s/\n", file, slash, s->name); + Blprint(outbuf, "%s%s%s/\n", file, slash, s->name); else - print("%s%s%s\n", file, slash, s->name); + Blprint(outbuf, "%s%s%s\n", file, slash, s->name); } } @@ -125,7 +225,7 @@ xwrite(int argc, char *argv[]) { if(fid == nil) fatal("Can't open file '%s': %r\n", file); - write_data(fid, file); + write_data(fid, file, binary); ixp_close(fid); return 0; } @@ -157,7 +257,7 @@ xawrite(int argc, char *argv[]) { strcat(buf, " "); } - if(ixp_write(fid, buf, nbuf) == -1) + if(!(flush(fid, buf, nbuf, binary) && (binary || flush(fid, 0, 0, binary)))) fatal("cannot write file '%s': %r\n", file); ixp_close(fid); free(buf); @@ -180,7 +280,7 @@ xcreate(int argc, char *argv[]) { fatal("Can't create file '%s': %r\n", file); if((fid->qid.type&P9_DMDIR) == 0) - write_data(fid, file); + write_data(fid, file, binary); ixp_close(fid); return 0; } @@ -197,7 +297,7 @@ xremove(int argc, char *argv[]) { file = EARGF(usage()); do { if(!ixp_remove(client, file)) - fprint(2, "%s: Can't remove file '%s': %r\n", argv0, file); + lprint(2, "%s: Can't remove file '%s': %r\n", argv0, file); }while((file = ARGF())); return 0; } @@ -222,12 +322,17 @@ xread(int argc, char *argv[]) { fatal("Can't open file '%s': %r\n", file); buf = emalloc(fid->iounit); - while((count = ixp_read(fid, buf, fid->iounit)) > 0) - write(1, buf, count); + while((count = ixp_read(fid, buf, fid->iounit)) > 0) { + unflush(1, buf, count, binary); + if (!binary && count < fid->iounit) + unflush(1, 0, 0, binary); + } + if(!binary) + unflush(1, 0, 0, binary); ixp_close(fid); if(count == -1) - fprint(2, "%s: cannot read file '%s': %r\n", argv0, file); + lprint(2, "%s: cannot read file '%s': %r\n", argv0, file); } while((file = ARGF())); return 0; @@ -324,19 +429,58 @@ xnamespace(int argc, char *argv[]) { path = ixp_namespace(); if(path == nil) fatal("can't find namespace: %r\n"); - print("%s\n", path); + Blprint(outbuf, "%s", path); return 0; } static int +xproglist(int argc, char *argv[]) { + DIR *d; + struct dirent *de; + struct stat st; + char *dir, *cwd; + int i; + + quotefmtinstall(); + + ARGBEGIN{ + default: + usage(); + }ARGEND; + + i = 7, cwd = nil; + do + cwd = erealloc(cwd, 1<<i); + while(!getcwd(cwd, 1<<i) && errno == ERANGE); + + while((dir = ARGF())) + /* Don't use Blprint. wimenu expects UTF-8. */ + if(!chdir(cwd) && !chdir(dir) && (d = opendir(dir))) { + while((de = readdir(d))) { + stat(de->d_name, &st); + if(S_ISREG(st.st_mode) && !access(de->d_name, X_OK)) + Bprint(outbuf, "%q\n", de->d_name); + } + closedir(d); + } + + return 0; /* NOTREACHED */ +} + +static int xsetsid(int argc, char *argv[]) { char *av0; + bool dofork; av0 = nil; + dofork = false; ARGBEGIN{ case '0': av0 = EARGF(usage()); break; + case 'f': + dofork = true; + break; default: usage(); }ARGEND; @@ -346,6 +490,13 @@ xsetsid(int argc, char *argv[]) { return 1; setsid(); + if(dofork) + switch(fork()) { + case 0: break; + case -1: fatal("can't fork: %r\n"); + default: return 0; + } + execvp(av0, argv); fatal("setsid: can't exec: %r"); return 1; /* NOTREACHED */ @@ -368,6 +519,7 @@ struct exectab { }, utiltab[] = { {"namespace", xnamespace}, {"ns", xnamespace}, + {"proglist", xproglist}, {"setsid", xsetsid}, {0, } }; @@ -378,14 +530,22 @@ main(int argc, char *argv[]) { exectab *tab; int ret; + IXP_ASSERT_VERSION; + + setlocale(LC_ALL, ""); + binary = utf8locale(); + quotefmtinstall(); fmtinstall('r', errfmt); address = getenv("WMII_ADDRESS"); ARGBEGIN{ + case 'b': + binary = true; + break; case 'v': - print("%s-" VERSION ", " COPYRIGHT "\n", argv0); + lprint(1, "%s-" VERSION ", " COPYRIGHT "\n", argv0); exit(0); case 'a': address = EARGF(usage()); @@ -397,9 +557,13 @@ main(int argc, char *argv[]) { if(argc < 1) usage(); + outbuf = Bfdopen(1, OWRITE); + for(tab=utiltab; tab->cmd; tab++) - if(!strcmp(*argv, tab->cmd)) - return tab->fn(argc, argv); + if(!strcmp(*argv, tab->cmd)) { + ret = tab->fn(argc, argv); + goto done; + } if(address && *address) client = ixp_mount(address); @@ -408,6 +572,8 @@ main(int argc, char *argv[]) { if(client == nil) fatal("can't mount: %r\n"); + signal(SIGPIPE, SIG_DFL); + for(tab=fstab; tab->cmd; tab++) if(strcmp(*argv, tab->cmd) == 0) break; if(tab->cmd == 0) @@ -416,6 +582,8 @@ main(int argc, char *argv[]) { ret = tab->fn(argc, argv); ixp_unmount(client); +done: + Bterm(outbuf); return ret; } diff --git a/cmd/x11/Makefile b/cmd/x11/Makefile new file mode 100644 index 0000000..5dd7fa3 --- /dev/null +++ b/cmd/x11/Makefile @@ -0,0 +1,18 @@ +ROOT= ../.. +include $(ROOT)/mk/hdr.mk +include $(ROOT)/mk/wmii.mk + +TARG = wikeyname \ + wmii9menu + +PACKAGES += $(X11PACKAGES) + +LIB = $(LIBS9) $(LIBIXP) +LIBS += $(LIB) +CFLAGS += $(INCX11) + +wiclick.out: wiclick.o + $(LINK) $@ $< -lXtst + +include $(ROOT)/mk/many.mk + diff --git a/cmd/x11/setfocus.c b/cmd/x11/setfocus.c new file mode 100644 index 0000000..4b580e1 --- /dev/null +++ b/cmd/x11/setfocus.c @@ -0,0 +1,27 @@ +/* Copyight 2008 Kris Maglione <maglione.k at Gmail> + * See LICENSE file for license details. + */ +#include <ctype.h> +#include <stdarg.h> +#include <stdbool.h> +#include <string.h> +#include <stuff/x.h> +#include <stuff/util.h> +#include <fmt.h> + +int +main(int argc, char *argv[]) { + XWindow w; + + ARGBEGIN{ + }ARGEND; + + initdisplay(); + + if(!getulong(EARGF(exit(1)), &w)) + exit(1); + + XSetInputFocus(display, w, RevertToParent, CurrentTime); + XCloseDisplay(display); +} + diff --git a/cmd/x11/wikeyname.c b/cmd/x11/wikeyname.c new file mode 100644 index 0000000..6e25ac4 --- /dev/null +++ b/cmd/x11/wikeyname.c @@ -0,0 +1,78 @@ +/* Copyright ©2010 Kris Maglione <maglione.k at Gmail> + * See LICENSE file for license details. + */ +#include <stuff/util.h> +#include <stuff/x.h> +#include <fmt.h> +#include <locale.h> +#include <unistd.h> + +static const char version[] = "wikeyname-"VERSION", "COPYRIGHT"\n"; + +static Handlers handlers; +static char* keyname; +static int nkeys; + +static void +usage(void) { + lprint(2, "usage: wikeyname\n"); + exit(1); +} + +int +main(int argc, char *argv[]) { + + setlocale(LC_CTYPE, ""); + + ARGBEGIN{ + case 'v': + lprint(2, version); + return 0; + default: usage(); + }ARGEND; + + if(argc) + usage(); + + fmtinstall('K', fmtkey); + initdisplay(); + + selectinput(&scr.root, KeyPressMask|KeyReleaseMask); + sethandler(&scr.root, &handlers); + if(!grabkeyboard(&scr.root)) + fatal("can't grab keyboard\n"); + + if(isatty(1)) + lprint(2, "Please press a key...\n"); + event_loop(); + lprint(1, "%s\n", keyname); + + XCloseDisplay(display); + return 0; +} + +static bool +kdown_event(Window *w, void *aux, XKeyEvent *ev) { + + USED(w, aux); + nkeys++; + free(keyname); + keyname = smprint("%K", ev); + return false; +} + +static bool +kup_event(Window *w, void *aux, XKeyEvent *ev) { + + USED(w, aux, ev); + if(keyname != nil && --nkeys <= 0) + event_looprunning = false; + return false; +} + + +static Handlers handlers = { + .kup = kup_event, + .kdown = kdown_event, +}; + diff --git a/cmd/x11/wiwarp.c b/cmd/x11/wiwarp.c new file mode 100644 index 0000000..88e0c41 --- /dev/null +++ b/cmd/x11/wiwarp.c @@ -0,0 +1,34 @@ +/* Copyight 2008 Kris Maglione <maglione.k at Gmail> + * See LICENSE file for license details. + */ +#include <ctype.h> +#include <stdarg.h> +#include <stdbool.h> +#include <string.h> +#include <stuff/x.h> +#include <stuff/util.h> +#include <fmt.h> + +int +main(int argc, char *argv[]) { + Point pt; + + ARGBEGIN{ + }ARGEND; + + initdisplay(); + + if(argc) { + if(!getint(EARGF(exit(1)), &pt.x)) + exit(1); + if(!getint(EARGF(exit(1)), &pt.y)) + exit(1); + }else { + pt = querypointer(&scr.root); + lprint(1, "%d %d\n", pt.x, pt.y); + } + + warppointer(pt); + XCloseDisplay(display); +} + diff --git a/cmd/wmii9menu.c b/cmd/x11/wmii9menu.c index 02049f3..f47c8a0 100644 --- a/cmd/wmii9menu.c +++ b/cmd/x11/wmii9menu.c @@ -42,13 +42,13 @@ #include <stdarg.h> #include <stdbool.h> #include <stdio.h> -#include <stdlib.h> #include <string.h> -#include <clientutil.h> -#include <util.h> -#include <x11.h> -char version[] = "wmii9menu-" VERSION " ©2010 Kris Maglione, ©1994 David Hogan, Arnold Robbins"; +#include <stuff/clientutil.h> +#include <stuff/util.h> +#include <stuff/x.h> + +char version[] = "wmii9menu-"VERSION" "COPYRIGHT", ©1994 David Hogan, Arnold Robbins"; static Window* menuwin; @@ -58,15 +58,8 @@ static Font* font; static int wborder; -char buffer[8092]; -char* _buffer; - -/* for XSetWMProperties to use */ -int g_argc; -char **g_argv; - -char *initial = ""; -int cur; +static char* initial = ""; +static int cur; static char** labels; /* list of labels and commands */ static char** commands; @@ -78,23 +71,7 @@ void create_window(void); void size_window(int, int); void redraw(int, int); void warpmouse(int, int); -void memory(void); -int args(void); - -ErrorCode ignored_xerrors[] = { - { 0, } -}; - -/* xext.c */ -void xext_init(void); -Rectangle* xinerama_screens(int*); -/* geom.c */ -bool rect_haspoint_p(Point, Rectangle); -Cursor cursor[1]; -Visual* render_visual; - -void init_screens(void); void init_screens(void) { Rectangle *rects; @@ -104,7 +81,7 @@ init_screens(void) { rects = xinerama_screens(&n); p = querypointer(&scr.root); for(i=0; i < n; i++) { - if(rect_haspoint_p(p, rects[i])) + if(rect_haspoint_p(rects[i], p)) break; } if(i == n) @@ -121,12 +98,9 @@ main(int argc, char **argv) char *cp; int i; - g_argc = argc; - g_argv = argv; - ARGBEGIN{ case 'v': - print("%s\n", version); + lprint(1, "%s\n", version); return 0; case 'a': address = EARGF(usage()); @@ -147,29 +121,24 @@ main(int argc, char **argv) create_window(); numitems = argc; - labels = emalloc(numitems * sizeof *labels); commands = emalloc(numitems * sizeof *labels); for(i = 0; i < numitems; i++) { labels[i] = argv[i]; + commands[i] = argv[i]; if((cp = strchr(labels[i], ':')) != nil) { *cp++ = '\0'; commands[i] = cp; - } else - commands[i] = labels[i]; + } if(strcmp(labels[i], initial) == 0) cur = i; } client_init(address); - wborder = strtol(readctl("border "), nil, 10); - loadcolor(&cnorm, readctl("normcolors ")); - loadcolor(&csel, readctl("focuscolors ")); - font = loadfont(readctl("font ")); - if(!font) - fatal("Can't load font"); + wborder = strtol(readctl("/ctl", "border "), nil, 10); + client_readconfig(&cnorm, &csel, &font); run_menu(); @@ -177,28 +146,22 @@ main(int argc, char **argv) return 0; } -/* usage --- print a usage message and die */ - void usage(void) { - fprintf(stderr, "usage: %s -v\n", argv0); - fprintf(stderr, " %s [-a <address>] [-i <arg>] menitem[:command] ...\n", argv0); + lprint(2, "usage: %s [-a <address>] [-i <arg>] <menitem>[:<command>] ...\n", argv0); + lprint(2, " %s -v\n", argv0); exit(0); } -/* run_menu --- put up the window, execute selected commands */ - enum { - MouseMask = - ButtonPressMask - | ButtonReleaseMask - | ButtonMotionMask - | PointerMotionMask, - MenuMask = - MouseMask - | StructureNotifyMask - | ExposureMask + MouseMask = ButtonPressMask + | ButtonReleaseMask + | ButtonMotionMask + | PointerMotionMask, + MenuMask = MouseMask + | StructureNotifyMask + | ExposureMask }; void @@ -207,8 +170,8 @@ run_menu(void) XEvent ev; int i, old, wide, high; - wide = 0; high = labelh(font); + wide = 0; for(i = 0; i < numitems; i++) wide = max(wide, textwidth(font, labels[i])); wide += font->height & ~1; @@ -220,8 +183,7 @@ run_menu(void) XNextEvent(display, &ev); switch (ev.type) { default: - fprintf(stderr, "%s: unknown ev.type %d\n", - argv0, ev.type); + lprint(2, "%s: unknown ev.type %d\n", argv0, ev.type); break; case ButtonRelease: i = ev.xbutton.y / high; @@ -230,7 +192,7 @@ run_menu(void) else if(i < 0 || i >= numitems) return; - printf("%s\n", commands[i]); + lprint(1, "%s\n", commands[i]); return; case ButtonPress: case MotionNotify: @@ -242,12 +204,10 @@ run_menu(void) break; redraw(high, wide); break; - case MapNotify: - redraw(high, wide); - break; case Expose: redraw(high, wide); break; + case MapNotify: case ConfigureNotify: case MappingNotify: break; @@ -255,13 +215,10 @@ run_menu(void) } } -/* set_wm_hints --- set all the window manager hints */ - void create_window(void) { WinAttr wa = { 0 }; - XEvent e; wa.override_redirect = true; menuwin = createwindow(&scr.root, Rect(-1, -1, 0, 0), @@ -269,10 +226,8 @@ create_window(void) &wa, CWOverrideRedirect); selectinput(menuwin, MenuMask); mapwin(menuwin); - XMaskEvent(display, StructureNotifyMask, &e); if(!grabpointer(menuwin, nil, 0, MouseMask)) fatal("Failed to grab the mouse\n"); - XSetCommand(display, menuwin->xid, g_argv, g_argc); } void @@ -295,34 +250,22 @@ size_window(int wide, int high) p.y = min(p.y, scr.rect.max.y - h); reshapewin(menuwin, rectaddpt(r, p)); - - //XSetWindowBackground(display, menuwin->xid, cnorm.bg); - setborder(menuwin, 1, cnorm.border); + setborder(menuwin, 1, &cnorm.border); } -/* redraw --- actually redraw the menu */ - void redraw(int high, int wide) { Rectangle r; - CTuple *c; int i; r = Rect(0, 0, wide, high); for(i = 0; i < numitems; i++) { - if(cur == i) - c = &csel; - else - c = &cnorm; r = rectsetorigin(r, Pt(0, i * high)); - fill(menuwin, r, c->bg); - drawstring(menuwin, font, r, Center, labels[i], c->fg); + fillstring(menuwin, font, r, Center, labels[i], (cur == i ? &csel : &cnorm), 0); } } -/* warpmouse --- bring the mouse to the menu */ - void warpmouse(int wide, int high) { |