summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorAndrew Shadura <bugzilla@tut.by>2012-08-10 17:28:37 +0200
committerAndrew Shadura <bugzilla@tut.by>2012-08-10 17:28:37 +0200
commit73a0b1b034b50c3356b51e389daa8bfd5f113853 (patch)
tree89f259da840cdf6a7aad11b983942e7926c70d59 /cmd
parent79e6dfc63311b132887889a6f4f582480575e80a (diff)
Synchronise to the latest hg tip.
Diffstat (limited to 'cmd')
-rw-r--r--cmd/Makefile24
-rw-r--r--cmd/click/Makefile22
-rw-r--r--cmd/click/_util.c77
-rw-r--r--cmd/click/dat.h27
-rw-r--r--cmd/click/fns.h4
-rw-r--r--cmd/click/main.c62
-rw-r--r--cmd/clientutil.c50
-rw-r--r--cmd/menu/Makefile22
-rw-r--r--cmd/menu/bindings.c51
-rw-r--r--cmd/menu/caret.c8
-rw-r--r--cmd/menu/dat.h70
-rw-r--r--cmd/menu/event.c334
-rw-r--r--cmd/menu/fns.h23
-rw-r--r--cmd/menu/history.c24
-rw-r--r--cmd/menu/keys.c29
-rw-r--r--cmd/menu/keys.txt91
-rw-r--r--cmd/menu/main.c143
-rw-r--r--cmd/menu/menu.c516
-rw-r--r--cmd/strut/Makefile24
-rw-r--r--cmd/strut/_util.c77
-rw-r--r--cmd/strut/dat.h26
-rw-r--r--cmd/strut/event.c309
-rw-r--r--cmd/strut/ewmh.c11
-rw-r--r--cmd/strut/fns.h14
-rw-r--r--cmd/strut/main.c143
-rw-r--r--cmd/strut/printevent_kludge.c12
-rw-r--r--cmd/strut/win.c46
-rw-r--r--cmd/tray/Makefile23
-rw-r--r--cmd/tray/client.c206
-rw-r--r--cmd/tray/dat.h73
-rw-r--r--cmd/tray/ewmh.c45
-rw-r--r--cmd/tray/fns.h22
-rw-r--r--cmd/tray/main.c218
-rw-r--r--cmd/tray/selection.c229
-rw-r--r--cmd/tray/selection.h18
-rw-r--r--cmd/tray/tray.c423
-rw-r--r--cmd/tray/xembed.c141
-rw-r--r--cmd/util.c272
-rw-r--r--cmd/wihack.sh1
-rwxr-xr-xcmd/wmii.rc.rc20
-rwxr-xr-xcmd/wmii.sh.sh41
-rw-r--r--cmd/wmii/Makefile22
-rw-r--r--cmd/wmii/_util.c378
-rw-r--r--cmd/wmii/area.c37
-rw-r--r--cmd/wmii/backtrace.c87
-rw-r--r--cmd/wmii/bar.c100
-rw-r--r--cmd/wmii/client.c655
-rw-r--r--cmd/wmii/column.c246
-rw-r--r--cmd/wmii/dat.h238
-rw-r--r--cmd/wmii/debug.h24
-rw-r--r--cmd/wmii/div.c30
-rw-r--r--cmd/wmii/event.c300
-rw-r--r--cmd/wmii/ewmh.c331
-rw-r--r--cmd/wmii/float.c33
-rw-r--r--cmd/wmii/fns.h138
-rw-r--r--cmd/wmii/frame.c189
-rw-r--r--cmd/wmii/fs.c339
-rw-r--r--cmd/wmii/geom.c94
-rw-r--r--cmd/wmii/key.c49
-rw-r--r--cmd/wmii/layout.c122
-rw-r--r--cmd/wmii/main.c115
-rw-r--r--cmd/wmii/map.c126
-rw-r--r--cmd/wmii/message.c722
-rw-r--r--cmd/wmii/mouse.c137
-rw-r--r--cmd/wmii/print.c6
-rw-r--r--cmd/wmii/printevent.c994
-rw-r--r--cmd/wmii/printevent.h248
-rw-r--r--cmd/wmii/root.c49
-rw-r--r--cmd/wmii/rule.c183
-rw-r--r--cmd/wmii/screen.c1
-rw-r--r--cmd/wmii/stack.c140
-rw-r--r--cmd/wmii/view.c159
-rw-r--r--cmd/wmii/x11.c1317
-rw-r--r--cmd/wmii/xdnd.c50
-rw-r--r--cmd/wmii/xext.c160
-rw-r--r--cmd/wmiir.c232
-rw-r--r--cmd/x11/Makefile18
-rw-r--r--cmd/x11/setfocus.c27
-rw-r--r--cmd/x11/wikeyname.c78
-rw-r--r--cmd/x11/wiwarp.c34
-rw-r--r--cmd/x11/wmii9menu.c (renamed from cmd/wmii9menu.c)113
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, &notify);
+}
+
+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)
{