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;
}

Reply via email to