Hi,
wmii has Xinerama support, and at the moment I have only one
monitor. So, rather than rip it out or let it get bitrotton,
I've been looking for some way to simulate Xinerama on one
screen. Xephyr, in theory, can fake Xinerama screens, but it
doesn't work here--I just get a normal multihead setup. Xephyr
combined with XdmX works, but it's ugly and a pain in the ass.
So, I've decided to go the hacky way. Inspired by someone else's
fake Xinerama lib, I've written my own.
Just compile it, stick it in LD_PRELOAD, and set
XINERAMA_SCREENS. I use Xephyr for testing, and my setup goes
something like this:
sh fakexinerama.c
mv libfakexinerama.c $home/lib
wihack -tags x Xephyr +bs -br -softCursor -ac -screen 1280x800 :3 &
export DISPLAY=:3
export LD_PRELOAD=$home/lib/libfakexinerama.so
export XINERAMA_SCREENS='0,0 640x800; 640,0 640x400; 640,400 640x400'
urxvt
wmii
In addition to making it easier to test Xinerama code, it makes
it easier to test eccentric setups, like the one above. I've
wound up with such strange configurations when, for instance, I
attach a TV to my S-video port.
--
Kris Maglione
Long hair minimizes the need for barbers; socks can be done without;
one leather jacket solves the coat problem for many years; suspenders
are superfluous.
--Albert Einstein
#ifdef notdef
set -x
exec cc -O2 -std=c99 -pedantic -Wall $0 -fPIC -o lib${0%.c}.so -shared
#endif
#define _XOPEN_SOURCE 600
#include <X11/Xlibint.h>
#include <X11/extensions/Xinerama.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <dlfcn.h>
const char SETTINGS[] = "XINERAMA_SCREENS";
const char SEP[] = ";";
static XineramaScreenInfo* screens;
static int num_screens;
typedef XineramaScreenInfo* (queryfn)(Display*, int*);
typedef Status (versionfn)(Display*, int*, int*);
typedef Bool (extensionfn)(Display*, int*, int*);
typedef Bool (activefn)(Display*);
static void* libxinerama;
static queryfn* queryscreens;
static extensionfn* queryextension;
static versionfn* queryversion;
static activefn* isactive;
static _Bool
init()
{
char *str, *p, *q;
int i;
if(screens || libxinerama)
return screens;
str = getenv(SETTINGS);
if(!str) {
libxinerama = dlopen("libXinerama.so.1", RTLD_GLOBAL | RTLD_LAZY);
if(!libxinerama)
abort();
isactive = (activefn*) (uintptr_t)dlsym(libxinerama, "XineramaIsActive");
queryversion = (versionfn*) (uintptr_t)dlsym(libxinerama, "XineramaQueryVersion");
queryextension = (extensionfn*) (uintptr_t)dlsym(libxinerama, "XineramaQueryExtension");
queryscreens = (queryfn*) (uintptr_t)dlsym(libxinerama, "XineramaQueryScreens");
return False;
}
for(i=1, p=str; strchr(p, *SEP); p++)
i++;
screens = malloc(i * sizeof *screens);
i = 0;
str = strdup(str);
for(q=str; (p = strtok(q, SEP)); q=NULL) {
if(sscanf(p, "%hd,%hd %hdx%hd",
&screens[i].x_org, &screens[i].y_org,
&screens[i].width, &screens[i].height)
== 4)
i++;
}
num_screens = i;
return True;
}
Bool
XineramaQueryExtension(Display *dpy, int *event_base, int *error_base)
{
if(!init())
return queryextension(dpy, event_base, error_base);
*event_base = 0;
*error_base = 0;
return True;
}
Status
XineramaQueryVersion(Display *dpy, int *major, int *minor)
{
if(!init())
return queryversion(dpy, major, minor);
*major = 1;
*minor = 1;
return True;
}
Bool
XineramaIsActive(Display *dpy)
{
if(!init())
return isactive(dpy);
return num_screens > 0;
}
XineramaScreenInfo*
XineramaQueryScreens(Display *dpy, int *number)
{
XineramaScreenInfo *ret;
if(!init())
return queryscreens(dpy, number);
*number = num_screens;
ret = Xmalloc(num_screens * sizeof *screens);
memcpy(ret, screens, num_screens * sizeof *screens);
return screens;
}