From 03e529a71c9743ae971d224ba353b5c5f9385366 Mon Sep 17 00:00:00 2001 From: Andy Spencer Date: Fri, 16 Sep 2011 23:10:01 +0000 Subject: [PATCH] X11 updates - Ignore non-visible and override_redirect windows - Keep focus when moving windows - Fix pointer motion grabbing --- sys-x11.c | 104 ++++++++++++++++++++++++++++++++++++++++++------------ sys.h | 2 ++ util.c | 14 ++++++++ util.h | 3 ++ wm-wmii.c | 8 +++++ 5 files changed, 109 insertions(+), 22 deletions(-) diff --git a/sys-x11.c b/sys-x11.c index 82f140d..ad12cec 100644 --- a/sys-x11.c +++ b/sys-x11.c @@ -116,11 +116,13 @@ Window getfocus(win_t *root, XEvent *event) return focus; } -/* Helper functions */ +/* Window functions */ win_t *win_new(Display *dpy, Window xid) { XWindowAttributes attr; - XGetWindowAttributes(dpy, xid, &attr); + if (XGetWindowAttributes(dpy, xid, &attr)) + if (attr.override_redirect) + return NULL; win_t *win = new0(win_t); win->x = attr.x; win->y = attr.y; @@ -129,7 +131,7 @@ win_t *win_new(Display *dpy, Window xid) win->sys = new0(win_sys_t); win->sys->dpy = dpy; win->sys->xid = xid; - printf("win_new: %p = %p, %d\n", win, dpy, (int)xid); + printf("%p = %p, %d\n", win, dpy, (int)xid); return win; } @@ -143,15 +145,19 @@ int win_cmp(const void *_a, const void *_b) return 0; } -win_t *win_find(Display *dpy, Window xid) +win_t *win_find(Display *dpy, Window xid, int create) { if (!dpy || !xid) return NULL; //printf("win_find: %p, %d\n", dpy, (int)xid); win_sys_t sys = {.dpy=dpy, .xid=xid}; win_t tmp = {.sys=&sys}; - return *(win_t**)(tfind(&tmp, &win_cache, win_cmp) ?: - tsearch(win_new(dpy,xid), &win_cache, win_cmp)); + win_t **old = NULL, *new = NULL; + if ((old = tfind(&tmp, &win_cache, win_cmp))) + return *old; + if (create && (new = win_new(dpy,xid))) + tsearch(new, &win_cache, win_cmp); + return new; } void win_remove(win_t *win) @@ -161,24 +167,35 @@ void win_remove(win_t *win) free(win); } +int win_viewable(win_t *win) +{ + XWindowAttributes attr; + if (XGetWindowAttributes(win->sys->dpy, win->sys->xid, &attr)) + return attr.map_state == IsViewable; + else + return True; +} + /* Callbacks */ void process_event(int type, XEvent *ev, win_t *root) { Display *dpy = root->sys->dpy; + win_t *win = NULL; /* Common data for all these events ... */ - win_t *win = NULL; ptr_t ptr; mod_t mod; + ptr_t ptr; mod_t mod; if (type == KeyPress || type == KeyRelease || type == ButtonPress || type == ButtonRelease || type == MotionNotify) { Window xid = getfocus(root, ev); - win = win_find(dpy,xid); + if (!(win = win_find(dpy,xid,0))) + return; ptr = x2ptr(ev); mod = x2mod(ev->xkey.state, type==KeyRelease||type==ButtonRelease); } /* Split based on event */ - //printf("event: %d\n", type); + printf("event: %d\n", type); if (type == KeyPress) { while (XCheckTypedEvent(dpy, KeyPress, ev)); KeySym sym = XKeycodeToKeysym(dpy, ev->xkey.keycode, 0); @@ -189,7 +206,7 @@ void process_event(int type, XEvent *ev, win_t *root) } else if (type == ButtonPress) { wm_handle_key(win, x2btn(ev->xbutton.button), mod, ptr); - XGrabPointer(dpy, win->sys->xid, True, PointerMotionMask|ButtonReleaseMask, + XGrabPointer(dpy, ev->xbutton.root, True, PointerMotionMask|ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); } else if (type == ButtonRelease) { @@ -200,6 +217,18 @@ void process_event(int type, XEvent *ev, win_t *root) while (XCheckTypedEvent(dpy, MotionNotify, ev)); wm_handle_ptr(win, ptr); } + else if (type == EnterNotify || type == LeaveNotify) { + printf("enter: %d\n", type); + key_t key = EnterNotify ? key_enter : key_leave; + if ((win = win_find(dpy,ev->xcrossing.window,0))) + wm_handle_key(win, key, MOD(), PTR()); + } + else if (type == FocusIn || type == FocusOut) { + printf("focus: %d\n", type); + key_t key = FocusIn ? key_focus : key_unfocus; + if ((win = win_find(dpy,ev->xfocus.window,0))) + wm_handle_key(win, key, MOD(), PTR()); + } else if (type == ConfigureNotify) { //printf("configure: %d\n", type); } @@ -208,11 +237,13 @@ void process_event(int type, XEvent *ev, win_t *root) } else if (type == DestroyNotify) { //printf("destory: %d\n", type); - win_remove(win_find(dpy,ev->xdestroywindow.window)); + if ((win = win_find(dpy,ev->xdestroywindow.window,0))) + win_remove(win); } else if (type == UnmapNotify) { //printf("unmap: %d\n", type); - wm_remove(win_find(dpy,ev->xmap.window)); + if ((win = win_find(dpy,ev->xmap.window,0))) + wm_remove(win); } else if (type == ConfigureRequest) { XConfigureRequestEvent *cre = &ev->xconfigurerequest; @@ -227,7 +258,8 @@ void process_event(int type, XEvent *ev, win_t *root) } else if (type == MapRequest) { printf("map_req: %d\n", type); - wm_insert(win_find(dpy,ev->xmaprequest.window)); + if ((win = win_find(dpy,ev->xmaprequest.window,1))) + wm_insert(win); XMapWindow(dpy,ev->xmaprequest.window); } else { @@ -235,6 +267,11 @@ void process_event(int type, XEvent *ev, win_t *root) } } +int xwmerror(Display *dpy, XErrorEvent *err) +{ + return error("another window manager is running?"); +} + /***************** * Sys functions * *****************/ @@ -244,6 +281,13 @@ void sys_move(win_t *win, int x, int y, int w, int h) win->x = x; win->y = y; win->w = w; win->h = h; XMoveResizeWindow(win->sys->dpy, win->sys->xid, x, y, w, h); + + /* Flush events, so moving window doesn't cuase re-focus + * There's probably a better way to do this */ + XEvent ev; + XSync(win->sys->dpy, False); + while (XCheckMaskEvent(win->sys->dpy, EnterWindowMask|LeaveWindowMask, &ev)) + printf("Skipping enter/leave event\n"); } void sys_raise(win_t *win) @@ -254,7 +298,7 @@ void sys_raise(win_t *win) void sys_focus(win_t *win) { - //printf("sys_raise: %p\n", win); + printf("sys_focus: %p\n", win); XEvent ev = { .type = ClientMessage, .xclient.window = win->sys->xid, @@ -277,6 +321,12 @@ void sys_watch(win_t *win, Key_t key, mod_t mod) XGrabButton(win->sys->dpy, btn2x(key), mod2x(mod), win->sys->xid, True, mod.up ? ButtonReleaseMask : ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None); + else if (key == key_enter) + XSelectInput(win->sys->dpy, win->sys->xid, EnterWindowMask); + else if (key == key_leave) + XSelectInput(win->sys->dpy, win->sys->xid, LeaveWindowMask); + else if (key == key_focus || key == key_unfocus) + XSelectInput(win->sys->dpy, win->sys->xid, FocusChangeMask); else XGrabKey(win->sys->dpy, XKeysymToKeycode(win->sys->dpy, key2x(key)), mod2x(mod), win->sys->xid, True, GrabModeAsync, GrabModeAsync); @@ -284,23 +334,33 @@ void sys_watch(win_t *win, Key_t key, mod_t mod) win_t *sys_init(void) { - Display *dpy = XOpenDisplay(NULL); - Window xid = DefaultRootWindow(dpy); + Display *dpy; + Window xid; + + if (!(dpy = XOpenDisplay(NULL))) + error("Unable to get display"); + if (!(xid = DefaultRootWindow(dpy))) + error("Unable to get root window"); atoms[wm_proto] = XInternAtom(dpy, "WM_PROTOCOLS", False); atoms[wm_focus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); - XSelectInput(dpy, xid, SubstructureNotifyMask|SubstructureRedirectMask); - return win_find(dpy, xid); + XSelectInput(dpy, xid, SubstructureRedirectMask|SubstructureNotifyMask); + + //XSetInputFocus(dpy, None, RevertToNone, CurrentTime); + return win_find(dpy, xid, 1); } void sys_run(win_t *root) { /* Add each initial window */ unsigned int nkids; - Window par, win, *kids = NULL; + Window par, xid, *kids = NULL; if (XQueryTree(root->sys->dpy, root->sys->xid, - &par, &win, &kids, &nkids)) - for(int i = 0; i < nkids; i++) - wm_insert(win_find(root->sys->dpy, kids[i])); + &par, &xid, &kids, &nkids)) + for(int i = 0; i < nkids; i++) { + win_t *win = win_find(root->sys->dpy, kids[i], 1); + if (win && win_viewable(win)) + wm_insert(win); + } /* Main loop */ for(;;) diff --git a/sys.h b/sys.h index 8caaf1d..5e2d926 100644 --- a/sys.h +++ b/sys.h @@ -29,6 +29,7 @@ typedef enum { key_f5, key_f6, key_f7, key_f8, key_f9, key_f10, key_f11, key_f12, key_alt, key_ctrl, key_shift, key_win, + key_enter, key_leave, key_focus, key_unfocus, } Key_t; typedef struct { @@ -46,6 +47,7 @@ typedef struct { int x, y; int rx, ry; } ptr_t; +#define PTR(...) ((ptr_t){__VA_ARGS__}) void sys_watch(win_t *win, Key_t key, mod_t mod); diff --git a/util.c b/util.c index 2099953..c5f3b9a 100644 --- a/util.c +++ b/util.c @@ -1,5 +1,6 @@ #include #include +#include #include "util.h" @@ -47,3 +48,16 @@ int list_length(list_t *node) void list_move(list_t *node, int offset) { } + +/* Misc */ +int error(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "Error: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + exit(1); + return 0; +} diff --git a/util.h b/util.h index 3c9cb0a..bfea342 100644 --- a/util.h +++ b/util.h @@ -33,3 +33,6 @@ list_t *list_remove(list_t *head, list_t *item); int list_length(list_t *item); void list_move(list_t *item, int offset); + +/* Misc */ +int error(char *fmt, ...); diff --git a/wm-wmii.c b/wm-wmii.c index cb5111d..1b01648 100644 --- a/wm-wmii.c +++ b/wm-wmii.c @@ -201,6 +201,10 @@ int wm_handle_key(win_t *win, Key_t key, mod_t mod, ptr_t ptr) else if (key == key_mouse3 && mod.MODKEY) return set_mode(resize,win,ptr), 1; + /* Focus change */ + if (key == key_enter) + sys_focus(win); + return 0; } @@ -226,6 +230,9 @@ void wm_insert(win_t *win) printf("wm_insert: %p\n", win); print_txt(wm_cols); + /* Watch enter/leave */ + sys_watch(win, key_enter, MOD()); + /* Add to screen */ col_t *col = wm_cols->data; int nrows = list_length(col->rows); @@ -260,6 +267,7 @@ void wm_init(win_t *root) sys_watch(root, key_f1, MOD(.MODKEY=1)); sys_watch(root, key_mouse1, MOD(.MODKEY=1)); sys_watch(root, key_mouse3, MOD(.MODKEY=1)); + sys_watch(root, key_enter, MOD()); key_t keys[] = {'h', 'j', 'k', 'l'}; for (int i = 0; i < countof(keys); i++) { sys_watch(root, keys[i], MOD(.MODKEY=1)); -- 2.43.2