From: Ryan McBride Date: Sat, 24 Jan 2009 17:57:26 +0000 (+0000) Subject: Add support for passing variables up to X11 via window properties; done by X-Git-Tag: SCROTWM_0_9_30~364 X-Git-Url: https://code.delx.au/spectrwm/commitdiff_plain/6d08df47448f7f544d1814df558057cc45e845bd Add support for passing variables up to X11 via window properties; done by hooking XCreateWindow and friends via LD_PRELOAD. Used now to make sure that windows come up in the workspace they were spawn()'d from, but more soon. Code to do the nasty borrowed with thanks from Enlightenment. --- diff --git a/Makefile b/Makefile index 030e2ac..2e564ee 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,8 @@ # $scrotwm$ .include +SUBDIR= lib + PROG=scrotwm MAN=scrotwm.1 diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 0000000..c9970f4 --- /dev/null +++ b/lib/Makefile @@ -0,0 +1,22 @@ +# $scrotwm$ + +.include + +LIB= swmhack +NOMAN= yes +SRCS= swm_hack.c +LIBDIR= ${X11BASE}/lib + +DEBUGLIBS= no +NOPROFILE= yes + +CFLAGS+=-Wall -Wno-uninitialized -ggdb3 +CFLAGS+= -I${X11BASE}/include + +install: + ${INSTALL} ${INSTALL_COPY} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \ + lib${LIB}.so.${SHLIB_MAJOR}.${SHLIB_MINOR} \ + ${X11BASE}/lib/swmhack.so + +.include +.include diff --git a/lib/shlib_version b/lib/shlib_version new file mode 100644 index 0000000..97c9f92 --- /dev/null +++ b/lib/shlib_version @@ -0,0 +1,2 @@ +major=0 +minor=0 diff --git a/lib/swm_hack.c b/lib/swm_hack.c new file mode 100644 index 0000000..459d880 --- /dev/null +++ b/lib/swm_hack.c @@ -0,0 +1,190 @@ +/* $scrotwm$ */ +/* + * Copyright (c) 2009 Marco Peereboom + * Copyright (c) 2009 Ryan McBride + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Copyright (C) 2005-2007 Carsten Haitzler + * Copyright (C) 2006-2007 Kim Woelders + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of the Software, its documentation and marketing & publicity + * materials, and acknowledgment shall be given in the documentation, materials + * and software packages that this Software was used. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +/* + * Basic hack mechanism (dlopen etc.) taken from e_hack.c in e17. + */ +#include +#include +#include +#include +#include +#include +#include + +/* dlopened xlib so we can find the symbols in the real xlib to call them */ +static void *lib_xlib = NULL; + +static Window root = None; + +/* Find our root window */ +static Window +MyRoot(Display * dpy) +{ + char *s; + + if (root != None) + return root; + + root = DefaultRootWindow(dpy); + + s = getenv("ENL_WM_ROOT"); + if (!s) + return root; + + sscanf(s, "%lx", &root); + return root; +} + +#define SWM_PROPLEN (16) +void +set_property(Display *dpy, Window id, char *name, char *val) +{ + Atom atom = 0; + char prop[SWM_PROPLEN]; + + /* Try to update the window's workspace property */ + atom = XInternAtom(dpy, name, False); + if (atom) + if (snprintf(prop, SWM_PROPLEN, "%s", val) < SWM_PROPLEN) + XChangeProperty(dpy, id, atom, XA_STRING, + 8, PropModeReplace, prop, SWM_PROPLEN); +} + +typedef Window(CWF) (Display * _display, Window _parent, int _x, + int _y, unsigned int _width, + unsigned int _height, + unsigned int _border_width, int _depth, + unsigned int _class, Visual * _visual, + unsigned long _valuemask, + XSetWindowAttributes * _attributes); + +/* XCreateWindow intercept hack */ +Window +XCreateWindow(Display * display, Window parent, int x, int y, + unsigned int width, unsigned int height, + unsigned int border_width, + int depth, unsigned int clss, Visual * visual, + unsigned long valuemask, XSetWindowAttributes * attributes) +{ + static CWF *func = NULL; + char *env; + Window id; + + /* find the real Xlib and the real X function */ + if (!lib_xlib) + lib_xlib = dlopen("libX11.so", RTLD_GLOBAL | RTLD_LAZY); + if (!func) + func = (CWF *) dlsym(lib_xlib, "XCreateWindow"); + + if (parent == DefaultRootWindow(display)) + parent = MyRoot(display); + + id = (*func) (display, parent, x, y, width, height, border_width, + depth, clss, visual, valuemask, attributes); + + if (id) { + if ((env = getenv("_SWM_WS")) != NULL) + set_property(display, id, "_SWM_WS", env); + if ((env = getenv("_SWM_PID")) != NULL) + set_property(display, id, "_SWM_PID", env); + } + return (id); +} + +typedef Window(CSWF) (Display * _display, Window _parent, int _x, + int _y, unsigned int _width, + unsigned int _height, + unsigned int _border_width, + unsigned long _border, + unsigned long _background); + +/* XCreateSimpleWindow intercept hack */ +Window +XCreateSimpleWindow(Display * display, Window parent, int x, int y, + unsigned int width, unsigned int height, + unsigned int border_width, + unsigned long border, unsigned long background) +{ + static CSWF *func = NULL; + char *env; + Window id; + + /* find the real Xlib and the real X function */ + if (!lib_xlib) + lib_xlib = dlopen("libX11.so", RTLD_GLOBAL | RTLD_LAZY); + if (!func) + func = (CSWF *) dlsym(lib_xlib, "XCreateSimpleWindow"); + + if (parent == DefaultRootWindow(display)) + parent = MyRoot(display); + + id = (*func) (display, parent, x, y, width, height, + border_width, border, background); + + if (id) { + if ((env = getenv("_SWM_WS")) != NULL) + set_property(display, id, "_SWM_WS", env); + if ((env = getenv("_SWM_PID")) != NULL) + set_property(display, id, "_SWM_PID", env); + } + return (id); +} + +typedef int (RWF) (Display * _display, Window _window, Window _parent, + int x, int y); + +/* XReparentWindow intercept hack */ +int +XReparentWindow(Display * display, Window window, Window parent, int x, int y) +{ + static RWF *func = NULL; + + /* find the real Xlib and the real X function */ + if (!lib_xlib) + lib_xlib = dlopen("libX11.so", RTLD_GLOBAL | RTLD_LAZY); + if (!func) + func = (RWF *) dlsym(lib_xlib, "XReparentWindow"); + + if (parent == DefaultRootWindow(display)) + parent = MyRoot(display); + + return (*func) (display, window, parent, x, y); +} diff --git a/scrotwm.c b/scrotwm.c index 91a5ed8..fbcbff3 100644 --- a/scrotwm.c +++ b/scrotwm.c @@ -101,6 +101,8 @@ #define SWM_D_MOVE 0x0010 #define SWM_D_STACK 0x0020 #define SWM_D_MOUSE 0x0040 +#define SWM_D_PROP 0x0080 + u_int32_t swm_debug = 0 | SWM_D_MISC @@ -109,6 +111,7 @@ u_int32_t swm_debug = 0 | SWM_D_FOCUS | SWM_D_MOVE | SWM_D_STACK + | SWM_D_PROP ; #else #define DPRINTF(x...) @@ -125,6 +128,12 @@ u_int32_t swm_debug = 0 #define WIDTH(r) (r)->g.w #define HEIGHT(r) (r)->g.h +#ifndef SWM_LIB +#define SWM_LIB "/usr/X11R6/lib/swmhack.so" +#endif + +#define SWM_PROPLEN (16) + char **start_argv; Atom astate; int (*xerrorxlib)(Display *, XErrorEvent *); @@ -740,8 +749,8 @@ root_to_region(Window root) } else { /* otherwise, choose a region based on pointer location */ TAILQ_FOREACH(r, &screens[i].rl, entry) { - if (x > X(r) && x < X(r) + WIDTH(r) && - y > Y(r) && y < Y(r) + HEIGHT(r)) + if (x >= X(r) && x <= X(r) + WIDTH(r) && + y >= Y(r) && y <= Y(r) + HEIGHT(r)) break; } @@ -775,8 +784,14 @@ spawn(struct swm_region *r, union arg *args) */ if (fork() == 0) { if (fork() == 0) { + char *ret; if (display) close(ConnectionNumber(display)); + setenv("LD_PRELOAD", SWM_LIB, 1); + if (asprintf(&ret, "%d", r->ws->idx)) + setenv("_SWM_WS", ret, 1); + if (asprintf(&ret, "%d", getpid())) + setenv("_SWM_PID", ret, 1); setsid(); execvp(args->argv[0], args->argv); fprintf(stderr, "execvp failed\n"); @@ -1368,7 +1383,7 @@ send_to_ws(struct swm_region *r, union arg *args) struct ws_win *win = cur_focus; struct workspace *ws, *nws; Atom ws_idx_atom = 0; - unsigned char ws_idx_str[1]; + unsigned char ws_idx_str[SWM_PROPLEN]; DNPRINTF(SWM_D_MOVE, "send_to_ws: win: %lu\n", win->id); @@ -1391,9 +1406,13 @@ send_to_ws(struct swm_region *r, union arg *args) /* Try to update the window's workspace property */ ws_idx_atom = XInternAtom(display, "_SWM_WS", False); - ws_idx_str[0] = (unsigned char)nws->idx; - XChangeProperty(display, win->id, ws_idx_atom, XA_STRING, 8, - PropModeReplace, ws_idx_str, 1); + if (ws_idx_atom && + snprintf(ws_idx_str, SWM_PROPLEN, "%d", nws->idx) < SWM_PROPLEN) { + DNPRINTF(SWM_D_PROP, "setting property _SWM_WS to %s\n", + ws_idx_str); + XChangeProperty(display, win->id, ws_idx_atom, XA_STRING, 8, + PropModeReplace, ws_idx_str, SWM_PROPLEN); + } if (count_win(nws, 1) == 1) nws->focus = win; @@ -1631,7 +1650,7 @@ manage_window(Window id) int format; unsigned long nitems, bytes; Atom ws_idx_atom = 0, type; - unsigned char ws_idx_str[1], *prop = NULL; + unsigned char ws_idx_str[SWM_PROPLEN], *prop = NULL; struct swm_region *r; if ((win = find_window(id)) != NULL) @@ -1642,15 +1661,23 @@ manage_window(Window id) ws_idx_atom = XInternAtom(display, "_SWM_WS", False); if (ws_idx_atom) - XGetWindowProperty(display, id, ws_idx_atom, 0, 1, False, XA_STRING, - &type, &format, &nitems, &bytes, &prop); + XGetWindowProperty(display, id, ws_idx_atom, 0, SWM_PROPLEN, + False, XA_STRING, &type, &format, &nitems, &bytes, &prop); XGetWindowAttributes(display, id, &win->wa); r = root_to_region(win->wa.root); /* If the window was managed before, put it in the same workspace */ - if (prop) - ws = &r->s->ws[prop[0]]; - else + if (prop) { + int ws_idx; + const char *errstr; + + DNPRINTF(SWM_D_PROP, "got property _SWM_WS=%s\n", prop); + ws_idx = strtonum(prop, 0, 9, &errstr); + if (errstr) + DNPRINTF(SWM_D_EVENT, "window idx is %s: %s", + errstr, prop); + ws = &r->s->ws[ws_idx]; + } else ws = r->ws; win->id = id; @@ -1672,12 +1699,14 @@ manage_window(Window id) win->g.x = win->wa.x; win->g.y = win->wa.y; - if (ws_idx_atom && prop == NULL) { - /* set the window's workspace property if it wasn't there */ - ws_idx_str[0] = (unsigned char)ws->idx; - XChangeProperty(display, id, ws_idx_atom, XA_STRING, 1, - PropModeReplace, ws_idx_str, 1); + if (ws_idx_atom && prop == NULL && + snprintf(ws_idx_str, SWM_PROPLEN, "%d", ws->idx) < SWM_PROPLEN) { + DNPRINTF(SWM_D_PROP, "setting property _SWM_WS to %s\n", + ws_idx_str); + XChangeProperty(display, win->id, ws_idx_atom, XA_STRING, 8, + PropModeReplace, ws_idx_str, SWM_PROPLEN); } + XFree(prop); /* fprintf(stderr, "manage window: %d x %d y %d w %d h %d\n", win->id, win->g.x, win->g.y, win->g.w, win->g.h);