Hello, foreword: this stuff has been sitting around in my head/on my hd for quite some time, and it's really due sharing with a broader audience it seems, so i just hit 'compose' and started to write it down. i'm hoping others will have interest in developing it further.
One of the features that most users ask for is to be able to launch an application in a specific frame. the only answer ion normally offers is to define a winprop/kludge that matches the app's window and positions it. this has the problem that it has to be set in a configuration file, and can't easily tell apart multiple instances of the same application, unless the application supports some option to make the windows distinguishable. (not discussed here) an alternate way, that has it's very own problems, but can do quite a lot of "magic" is to pass identifying information (from the invocation) through the app to the X server, where we can use it to identify windows. this is done by LD_PRELOAD-ing a library that stores identifying information in a program's windows, without the program itself being aware of it, and which can be used on the ion side to do whatever we like with those windows. this way we can finally run a program and have it's window put into frame <x>, without knowing in advance when it will open and what properties it will have. there are two sides to this: - the LD_PRELOAD side this is actually more complex than one might think, and could need lots of hacks and "magic". with the naive approach of just tagging a fixed identifier on all windows of an application (and it's child processes), all new child windows would (for example) always pop up in the same fixed frame, even if we moved the main window to another frame, or (another example) a configuration dialog for a window that was docked this way (my personal main application of the technique) will also be docked. (this can also be worked around with ion-side code, but the client is often in a better position to access relevant information). - the ion side ion3 has already all the infrastructure needed for this in place, most importantly, ioncore.set_get_winprop_fn() lets use define our own function to identify windows and return our favourite settings for them, and secondly a set of utility functions to read window properties (ioncore.x_get_*_property). ion2 provides the value of the "ION_KLUDGES" text property (returned by WClientWin.get_ident()), but does not use it by default. implementation: - the LD_PRELOAD side i mostly used already existing code, written by Per Olofsson for ion2. http://www.mail-archive.com/[email protected]/msg00005.html (the page linked there (and the new page he privately mailed me) are dead, file attached as ionlaunch-20030223.tar.gz) he already added some more sophisticated mechanisms as discussed above, like the library automatically disables itself for child processes spawned by our app, but i removed that from my version for simplicity. (attached as ionkludge.c, compile with: gcc -shared -o libionkludge.so \ ionkludge.c -L/usr/X11R6/lib -lX11 -I/usr/X11R6/include -nostartfiles ) - ion side (for ion2, while i was still using it, i extended the winprop system to include ION_KLUDGES values, the file is attached and should work when dropped in ~/.ion*/ (without the ion2- prefix). to use it define a kludge like: defwinprop({ kludges = "foo", target = "bar",}) and then set ION_KLUDGES to "foo" with the same LD_PRELOAD mechanism as below). the method i currently use with ion3 is to simply store a lua code string that returns the winprops... that is not very clean and secure, but it offers a great amount of flexibility for experimenting with window configurations. (code in my_winprops.lua (attached)) later this should probably replaced with more complex ion-side code that stores configurations ion-side and only passes their IDs. usage: first load the ion-side code, dopath("my_winprops") and then set LD_PRELOAD to point to libionkludge.so (either with full path, or in a place searched by the linker, and set the string to be passed in ION_KLUDGES: LD_PRELOAD=libionkludge.so ION_KLUDGES='return {target="Internet",}' dillo LD_PRELOAD=libionkludge.so ION_KLUDGES='return {target="My_Dock",}' xeyes -g 64x64 (the targets should exist on your desktop, of course) a more sophisticated example could be something like: ION_KLUDGES='if ( tonumber(os.date("%s")) < '$(($(date +%s)+10))' ) then return {target="Internet",} else return {} end' which forces the app's windows into the "Internet" region only for the next ten seconds. (a simple approach to being able to move it elsewhere after startup) i have not tried much more, as i mostly use it to manage my dockapps (see attached dapps.sh) for further reading: source of ionkludge.c and ionlaunch.c http://modeemi.cs.tut.fi/~tuomov/ion/doc-3/ionconf/node7.html#fn:ioncore.set_get_winprop_fn http://modeemi.cs.tut.fi/~tuomov/ion/doc-3/ionconf/node7.html#fn:ioncore.x_get_text_property http://www.lua.org/manual/5.0/ - Thorben
ion2-ioncore-winprops.lua
Description: Binary data
ionlaunch-20030223.tar.gz
Description: Binary data
/*
* ionkludge - no more stupid winprops
* by Thorben Thuermer <[EMAIL PROTECTED]> 2004
* Based on ionkludge by Per Olofsson <[EMAIL PROTECTED]> 2002
* Based on xalfkludge.c by Peter �strand <[EMAIL PROTECTED]> * 2000. GPLV2.
* Based on scwm_set_pid_property.c (C) 1999 Toby Sargeant and Greg J. Badros
*/
/* Uncomment below for debugging */
#define DEBUG
#ifdef DEBUG
# define DPRINTF(args) fprintf args
#else
# define DPRINTF(args)
#endif
#define _GNU_SOURCE
#include <dlfcn.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#define ION_FRAME_ID_ENV "ION_KLUDGES"
#define ION_FRAME_ID_PROP "_ION_KLUDGES"
static char *kludge_string;
static Atom atom_frame_id;
static void restore_env();
#ifdef __FreeBSD__
static void _init(void) __attribute__ ((section (".init")));
#endif /* __FreeBSD__ */
// this one gets called on startup
void _init(){
void *dlh = NULL;
DPRINTF ((stderr,"_init\n"));
kludge_string = getenv (ION_FRAME_ID_ENV);
if (kludge_string) kludge_string=strdup(kludge_string);
DPRINTF ((stderr,"frame_id is \"%s\"\n", kludge_string));
if (kludge_string == NULL) return; // user didn't define kludge string
if (dlsym( dlopen(NULL, RTLD_GLOBAL|RTLD_NOW), "XSync") == NULL)
return; // program doesn't use xlib
}
// set the kludge for a window
static void set_ion_property(Display *display, Window w){
int ret= XChangeProperty(display, w,
XInternAtom(display, ION_FRAME_ID_PROP, False),
XA_STRING, 8, PropModeReplace,
(unsigned char *)kludge_string, strlen(kludge_string)
);
if (ret==1)
DPRINTF ((stderr,"applying kludge \"%s\" to window 0x%x\n", kludge_string,w));
else
fprintf(stderr, "ionkludge: XChangeProperty failed?!\n");
}
//
void inline getsym(void **func, char *symbol){
if (*func == NULL) {
*func = (void *)dlsym(RTLD_NEXT, symbol);
if (*func == NULL) {
fprintf(stderr, "ionkludge: dlsym(\"%s\") failed?!: %s\n", symbol,dlerror());
exit(1);
}
}
}
// this one is hooked before the real XMapWindow()
extern int XMapWindow(Display* display, Window w){
static int (*real_XMapWindow)() = 0;
DPRINTF ((stderr,"in XMapWindow\n"));
getsym(&real_XMapWindow,"XMapWindow");
set_ion_property(display, w);
return ((*real_XMapWindow)(display, w));
}
extern int XMapRaised (Display* display, Window w){
static int (*real_XMapRaised)() = 0;
DPRINTF ((stderr,"in XMapRaised\n"));
getsym(&real_XMapRaised,"XMapRaised");
set_ion_property(display, w);
return ((*real_XMapRaised)(display, w));
}
#!/bin/bash
function dockat(){
export LD_PRELOAD=~/ION/ionkludge/libionkludge.so
export ION_KLUDGES='return {target="mydock",dockposition='$1',}'
shift
"$@" &
}
cat <<EOF |
10 wmpower
20 asclock -theme /usr/share/asclock/penguin/
30 wmdl -m cpu -i 1 -f 1.0 -u 100 -w iconic
#40 wmnd -I wlan0
#50 wmnd -I tun0
60 wmnd
70 procmeter -geometry 64x64+0-0 -horizontal cpu
80 xosview -geometry 64x64 -labels -load +cpu +mem +swap +page +net +ints -xrm "xosview*intOffColor: black" -xrm "xosview*intOnColor: white" -xrm "xosview*background: grey70" &
#90 wmping 192.168.1.2
100 asmixer -1 VOLUME -2 PCM -3 LINE -d /dev/mixer
110 xcb -l v -n 5 -geometry 64x64
120 xeyes -g 64x64
EOF
grep -v '^#' |
while read n l ; do
eval dockat $n $l
done
my_winprops.lua
Description: Binary data
