Nov 2003

Mon, 10 Nov 2003

# XFree Xinerama Extension Hack

When installing my 3 monitor setup I quickly discovered that the native XFree Xinerama extension is incompatible with nvidia TwinView. You can only have either one. This leads to applications believing I have one 2560x1024 screen and one 1280x1024 screen — maximizing windows would always span two screens.

I spent a long time searching for a solution on Google, but unfortunately there are a) few people with 3 monitors and b) no one had solved this. So I decided to patch the X server.

What I've done is to take programs/Xserver/Xext/panoramiX.c and fake the reply like this:

--- x/xc/programs/Xserver/Xext/panoramiX.c      2003-11-10 19:21:43.000000000 +0100
+++ x2/xc/programs/Xserver/Xext/panoramiX.c     2004-02-15 11:39:15.000000000 +0100
@@ -1026,7 +1030,8 @@

     rep.type = X_Reply;
     rep.sequenceNumber = client->sequence;
-    rep.number = (noPanoramiXExtension) ? 0 : PanoramiXNumScreens;
+   /* rep.number = (noPanoramiXExtension) ? 0 : PanoramiXNumScreens; */
+    rep.number = (noPanoramiXExtension) ? 0 : (PanoramiXNumScreens + 1);
     rep.length = rep.number * sz_XineramaScreenInfo >> 2;
     if (client->swapped) {
        register int n;
@@ -1040,11 +1045,17 @@
       xXineramaScreenInfo scratch;
       int i;

-       for(i = 0; i < PanoramiXNumScreens; i++) {
+       for(i = 0; i < (PanoramiXNumScreens + 1); i++) {
+               /*
           scratch.x_org  = panoramiXdataPtr[i].x;
           scratch.y_org  = panoramiXdataPtr[i].y;
           scratch.width  = panoramiXdataPtr[i].width;
           scratch.height = panoramiXdataPtr[i].height;
+           */
+           scratch.x_org  = 1280 * i;
+           scratch.y_org  = 0;
+           scratch.width  = 1280;
+           scratch.height = 1024;

This is pretty specific, so I'm currently working my way through the code to make this configurable in XF86Config-4.

I also wrote a small test program:

#include <stdio.h>
#include <X11/extensions/Xinerama.h>

int main() {
        XineramaScreenInfo *xsi;
        Display *dpy;
        int number;
        int i;
        dpy = XOpenDisplay(NULL);
        xsi = XineramaQueryScreens(dpy, &number);
        for(i = 0; i < number; i++) {
                printf("%d %d %d %d %d\n", xsi[i].screen_number, xsi[i].x_org,
                        xsi[i].y_org, xsi[i].width, xsi[i].height);
        }
        return 1;
}

Output before the patch (columns: screennum x y width height):

0 0 0 2560 1024
2 2560 0 1280 1024

Output after the patch:

0 0 0 1280 1024
1 1280 0 1280 1024
2 2560 0 1280 1024

Pretty successful.

posted at 19:21 | path: /unix | permanent link to this entry

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.