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

Attachment: ion2-ioncore-winprops.lua
Description: Binary data

Attachment: 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

Attachment: my_winprops.lua
Description: Binary data

Reply via email to