diff options
Diffstat (limited to 'nx-X11/programs/Xserver/hw/nxagent')
-rw-r--r-- | nx-X11/programs/Xserver/hw/nxagent/Args.c | 31 | ||||
-rw-r--r-- | nx-X11/programs/Xserver/hw/nxagent/Events.c | 46 | ||||
-rw-r--r-- | nx-X11/programs/Xserver/hw/nxagent/Extensions.c | 38 | ||||
-rw-r--r-- | nx-X11/programs/Xserver/hw/nxagent/Imakefile | 4 | ||||
-rw-r--r-- | nx-X11/programs/Xserver/hw/nxagent/Options.c | 2 | ||||
-rw-r--r-- | nx-X11/programs/Xserver/hw/nxagent/Options.h | 11 | ||||
-rw-r--r-- | nx-X11/programs/Xserver/hw/nxagent/Reconnect.c | 2 | ||||
-rw-r--r-- | nx-X11/programs/Xserver/hw/nxagent/Screen.c | 543 |
8 files changed, 601 insertions, 76 deletions
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Args.c b/nx-X11/programs/Xserver/hw/nxagent/Args.c index 5c5a1e8f8..309f08d0e 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Args.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Args.c @@ -42,6 +42,7 @@ is" without express or implied warranty. #include "screenint.h" #include "input.h" #include "misc.h" +#include "globals.h" #include "scrnintstr.h" #include "dixstruct.h" #include "servermd.h" @@ -1202,6 +1203,36 @@ static void nxagentParseOptions(char *name, char *value) return; } + else if (!strcmp(name, "xinerama")) + { +#ifdef PANORAMIX + if (!PanoramiXExtensionDisabledHack) + { + if (!strcmp(value, "1")) + { + nxagentChangeOption(Xinerama, 1); + } + else if (!strcmp(value, "0")) + { + nxagentChangeOption(Xinerama, 0); + } + else + { + fprintf(stderr, "Warning: Ignoring bad value '%s' for option 'xinerama'.\n", + validateString(value)); + } + } + else + { + nxagentChangeOption(Xinerama, 0); + fprintf(stderr, "Warning: Xinerama extension has been disabled via -disablexineramaextension cmdline switch.\n"); + } +#else + nxagentChangeOption(Xinerama, 0); + fprintf(stderr, "Warning: No Xinerama support compiled into nxagent.\n") +#endif /* of PANORAMIX */ + return; + } else if (!strcmp(name, "resize")) { if (nxagentOption(DesktopResize) == 0 || strcmp(value, "0") == 0) diff --git a/nx-X11/programs/Xserver/hw/nxagent/Events.c b/nx-X11/programs/Xserver/hw/nxagent/Events.c index 9f7d6280f..c04481c92 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Events.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Events.c @@ -568,6 +568,10 @@ void nxagentSwitchResizeMode(ScreenPtr pScreen) { XSizeHints sizeHints; + #ifdef DEBUG + fprintf(stderr, "nxagentSwitchResizeMode called.\n"); + #endif + int desktopResize = nxagentOption(DesktopResize); nxagentChangeOption(DesktopResize, !desktopResize); @@ -3366,7 +3370,9 @@ int nxagentHandleConfigureNotify(XEvent* X) if (nxagentOption(DesktopResize) == 1) { if (nxagentOption(Width) != X -> xconfigure.width || - nxagentOption(Height) != X -> xconfigure.height) + nxagentOption(Height) != X -> xconfigure.height || + nxagentOption(X) != X -> xconfigure.x || + nxagentOption(Y) != X -> xconfigure.y) { Bool newEvents = False; @@ -3423,11 +3429,16 @@ int nxagentHandleConfigureNotify(XEvent* X) nxagentMoveViewport(pScreen, 0, 0); + /* if in shadowing mode or if neither size nor position have + changed we do not need to adjust RandR */ + /* FIXME: Comment makes no sense */ if (nxagentOption(Shadow) == 1 || (nxagentOption(Width) == nxagentOption(RootWidth) && - nxagentOption(Height) == nxagentOption(RootHeight))) + nxagentOption(Height) == nxagentOption(RootHeight) && + nxagentOption(X) == nxagentOption(RootX) && + nxagentOption(Y) == nxagentOption(RootY))) { - doRandR = 0; + doRandR = False; } nxagentChangeOption(Width, X -> xconfigure.width); @@ -3466,12 +3477,31 @@ int nxagentHandleConfigureNotify(XEvent* X) #endif nxagentChangeScreenConfig(0, nxagentOption(Width), - nxagentOption(Height), 0, 0); + nxagentOption(Height), 0, 0); } } return 1; } + else + { + if ( (X -> xconfigure.window == DefaultRootWindow(nxagentDisplay)) || nxagentFullscreenWindow ) + { + #ifdef TEST + fprintf(stderr, "nxagentHandleConfigureNotify: remote root window has changed: %d,%d %dx%d\n", X -> xconfigure.x, X -> xconfigure.y, X -> xconfigure.width, X -> xconfigure.height); + #endif + + nxagentChangeOption(RootX, X -> xconfigure.x); + nxagentChangeOption(RootY, X -> xconfigure.y); + nxagentChangeOption(RootWidth, X -> xconfigure.width); + nxagentChangeOption(RootHeight, X -> xconfigure.height); + + nxagentChangeScreenConfig(0, nxagentOption(Width), + nxagentOption(Height), 0, 0); + + return 1; + } + } } return 0; @@ -4416,6 +4446,10 @@ int nxagentHandleRRScreenChangeNotify(XEvent *X) { XRRScreenChangeNotifyEvent *Xr; + #ifdef DEBUG + fprintf(stderr, "nxagentHandleRRScreenChangeNotify called.\n"); + #endif + Xr = (XRRScreenChangeNotifyEvent *) X; nxagentResizeScreen(screenInfo.screens[DefaultScreen(nxagentDisplay)], Xr -> width, Xr -> height, @@ -4504,6 +4538,10 @@ int nxagentWaitEvents(Display *dpy, struct timeval *tm) { XEvent ev; + #ifdef DEBUG + fprintf(stderr, "nxagentWaitEvents called.\n"); + #endif + NXFlushDisplay(dpy, NXFlushLink); /* diff --git a/nx-X11/programs/Xserver/hw/nxagent/Extensions.c b/nx-X11/programs/Xserver/hw/nxagent/Extensions.c index 6dce644ae..d77d27674 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Extensions.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Extensions.c @@ -35,6 +35,13 @@ static int nxagentRandRScreenSetSize(ScreenPtr pScreen, CARD16 width, static int nxagentRandRInitSizes(ScreenPtr pScreen); +#if RANDR_12_INTERFACE +static Bool nxagentRandRCrtcSet (ScreenPtr pScreen, RRCrtcPtr crtc, + RRModePtr mode, int x, int y, + Rotation rotation, int numOutputs, + RROutputPtr *outputs); +#endif + #ifdef __DARWIN__ void DarwinHandleGUI(int argc, char *argv[]) @@ -83,6 +90,8 @@ void nxagentInitRandRExtension(ScreenPtr pScreen) fprintf(stderr, "Warning: Failed to initialize the RandR extension.\n"); } + + /* FIXME: do we need this at all with the new rand/xinerama stuff? */ nxagentRandRInitSizes(pScreen); /* @@ -97,6 +106,7 @@ void nxagentInitRandRExtension(ScreenPtr pScreen) #if RANDR_12_INTERFACE pRandRScrPriv -> rrScreenSetSize = nxagentRandRScreenSetSize; + pRandRScrPriv -> rrCrtcSet = nxagentRandRCrtcSet; #endif #if RANDR_10_INTERFACE @@ -104,6 +114,34 @@ void nxagentInitRandRExtension(ScreenPtr pScreen) #endif } +void +RRResetProc (ExtensionEntry *extEntry) +{ + fprintf(stderr, "RANDR going down - NX version\n"); +} + + + +#if RANDR_12_INTERFACE +/* + * Request that the Crtc be reconfigured + */ + +static Bool +nxagentRandRCrtcSet (ScreenPtr pScreen, + RRCrtcPtr crtc, + RRModePtr mode, + int x, + int y, + Rotation rotation, + int numOutputs, + RROutputPtr *outputs) +{ + return RRCrtcNotify(crtc, mode, x, y, rotation, numOutputs, outputs); +} +#endif + + int nxagentRandRGetInfo(ScreenPtr pScreen, Rotation *pRotations) { /* diff --git a/nx-X11/programs/Xserver/hw/nxagent/Imakefile b/nx-X11/programs/Xserver/hw/nxagent/Imakefile index 794864cf3..160d01e60 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Imakefile +++ b/nx-X11/programs/Xserver/hw/nxagent/Imakefile @@ -179,7 +179,8 @@ INCLUDES = -I. -I$(XBUILDINCDIR) \ # NXAGENT_CLIPBOARD Enables clipboard cut and paste function between X servers. # NXAGENT_FONTEXCLUDE Exclude some specific font names (only "-ult1mo" at this moment). # NXAGENT FULLSCREEN Fullscreen mode -# +# NXAGENT_RANDR_MODE_PREFIX Use prefixed (i.e., nx_<x>x<y>) RandR modes +# NXAGENT_RANDR_XINERAMA_CLIPPING cut off invisible window parts in xinerama mode (you probably do not want this) #if nxVersion NX_DEFINES=-DNX_VERSION_CURRENT="$(NX_VERSION_CURRENT)" \ @@ -203,6 +204,7 @@ DEFINES = -g $(OS_DEFINES) $(EXT_DEFINES) $(NX_DEFINES) \ -DNXAGENT_ONSTART \ -DNXAGENT_SPLASH \ -DNXAGENT_ARTSD \ + -DNXAGENT_RANDR_MODE_PREFIX \ -UNX_DEBUG_INPUT \ -DRANDR_10_INTERFACE \ -DRANDR_12_INTERFACE \ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Options.c b/nx-X11/programs/Xserver/hw/nxagent/Options.c index 7eac3d8a2..dbe200273 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Options.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Options.c @@ -154,6 +154,8 @@ void nxagentInitOptions() nxagentOptions.CopyBufferSize = COPY_UNLIMITED; nxagentOptions.ImageRateLimit = 0; + + nxagentOptions.Xinerama = 0; } /* diff --git a/nx-X11/programs/Xserver/hw/nxagent/Options.h b/nx-X11/programs/Xserver/hw/nxagent/Options.h index 0e4869926..5bf1597d5 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Options.h +++ b/nx-X11/programs/Xserver/hw/nxagent/Options.h @@ -388,6 +388,17 @@ typedef struct _AgentOptions int NoRootlessExit; + /* + * Store if the user wants Xinerama. There's a variable called + * noPanoramiXExtension in os/utils.c but we cannot rely on that + * because RandR and Panoramix change its value when trying to + * initialize. So we use this variable to save the user preference + * provided by the -/+xinerama parameter before initalizing those + * extensions. + */ + + int Xinerama; + } AgentOptionsRec; typedef AgentOptionsRec *AgentOptionsPtr; diff --git a/nx-X11/programs/Xserver/hw/nxagent/Reconnect.c b/nx-X11/programs/Xserver/hw/nxagent/Reconnect.c index b26fa9cfe..660d30863 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Reconnect.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Reconnect.c @@ -624,7 +624,7 @@ Bool nxagentReconnectSession(void) nxagentRedirectDefaultWindows(); - if (nxagentResizeDesktopAtStartup || nxagentOption(Rootless) == True) + if (nxagentResizeDesktopAtStartup || nxagentOption(Rootless) == True || nxagentOption(Xinerama) == True) { nxagentChangeScreenConfig(0, nxagentOption(RootWidth), nxagentOption(RootHeight), 0, 0); diff --git a/nx-X11/programs/Xserver/hw/nxagent/Screen.c b/nx-X11/programs/Xserver/hw/nxagent/Screen.c index 491a92c2f..a677b7eb4 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Screen.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Screen.c @@ -79,6 +79,10 @@ is" without express or implied warranty. #include "X11/include/Xrandr_nxagent.h" +#include <nx-X11/Xlib.h> +#include "X11/include/Xinerama_nxagent.h" + + #define GC XlibGC #define Font XlibFont #define KeySym XlibKeySym @@ -102,8 +106,8 @@ is" without express or implied warranty. #define PANIC #define WARNING -#undef TEST -#undef DEBUG +#define TEST +#define DEBUG #undef WATCH #undef DUMP @@ -129,14 +133,6 @@ extern Pixmap nxagentIconPixmap; extern Pixmap nxagentIconShape; extern Bool useXpmIcon; -/* - * From randr/randr.c. - */ - -extern Bool RRGetInfo(ScreenPtr pScreen); -extern void RRSendConfigNotify(ScreenPtr pScreen); -extern void RREditConnectionInfo(ScreenPtr pScreen); - Window nxagentDefaultWindows[MAXSCREENS]; Window nxagentInputWindows[MAXSCREENS]; Window nxagentScreenSaverWindows[MAXSCREENS]; @@ -319,7 +315,7 @@ void nxagentMaximizeToFullScreen(ScreenPtr pScreen) XUnmapWindow(nxagentDisplay, nxagentIconWindow); */ /* -FIXME: We'll chech for ReparentNotify and LeaveNotify events after XReparentWindow() +FIXME: We'll check for ReparentNotify and LeaveNotify events after XReparentWindow() in order to avoid the session window is iconified. We could avoid the sesssion window is iconified when a LeaveNotify event is received, so this check would be unnecessary. @@ -1117,6 +1113,11 @@ Bool nxagentOpenScreen(int index, ScreenPtr pScreen, nxagentChangeOption(ViewportXSpan, nxagentOption(Width) - nxagentOption(RootWidth)); nxagentChangeOption(ViewportYSpan, nxagentOption(Height) - nxagentOption(RootHeight)); + /* PanoramiXExtension enabled via cmdline, turn on Xinerama in nxagent + */ + if( (!noPanoramiXExtension) && (!PanoramiXExtensionDisabledHack) ) + nxagentOption(Xinerama) = True; + if (nxagentReconnectTrap == 0) { if (nxagentOption(Persistent)) @@ -1781,7 +1782,9 @@ N/A XSetClassHint(nxagentDisplay,nxagentDefaultWindows[pScreen->myNum],&hint); free(hint.res_name); free(hint.res_class); - } else { + } + else + { #ifdef TEST fprintf(stderr, "nxagentOpenScreen: Setting WM_CLASS and WM_NAME for window withid [%ld].\n", nxagentDefaultWindows[pScreen->myNum]); @@ -2035,6 +2038,9 @@ N/A nxagentCompositeExtensionInit(); + /* We use this to get informed about RandR changes on the real display. + FIXME: It would probably be better to use an RRScreenChangeNotifyEvent here. */ + XSelectInput(nxagentDisplay, DefaultRootWindow(nxagentDisplay), StructureNotifyMask); #ifdef NXAGENT_TIMESTAMP @@ -2071,6 +2077,10 @@ Bool nxagentCloseScreen(int index, ScreenPtr pScreen) { int i; + #ifdef DEBUG + fprintf(stderr, "running nxagentCloseScreen()\n"); + #endif + for (i = 0; i < pScreen->numDepths; i++) { xfree(pScreen->allowedDepths[i].vids); @@ -2240,7 +2250,7 @@ static void nxagentSetRootClip (ScreenPtr pScreen, Bool enable) if (pWin->realized) WindowsRestructured (); FlushAllOutput (); -} +} Bool nxagentResizeScreen(ScreenPtr pScreen, int width, int height, int mmWidth, int mmHeight) @@ -3585,21 +3595,91 @@ Bool nxagentReconnectScreen(void *p0) return True; } -RRModePtr nxagentRRCustomMode = NULL; +/* FIXME: there must be such macros somewhere already...*/ +#define MAX(a,b) ((a) > (b)) ? (a) : (b); +#define MIN(a,b) ((a) < (b)) ? (a) : (b); + +/* intersect two rectangles */ +Bool intersect(int ax1, int ay1, unsigned int aw, unsigned int ah, + int bx1, int by1, unsigned int bw, unsigned int bh, + int *x, int *y, unsigned int *w, unsigned int *h) +{ + int tx1, ty1, tx2, ty2, ix, iy; + unsigned int iw, ih; + + int ax2 = ax1 + aw; + int ay2 = ay1 + ah; + int bx2 = bx1 + bw; + int by2 = by1 + bh; + + /* thanks to http://silentmatt.com/rectangle-intersection */ + + /* check if there's any intersection at all */ + if (ax2 < bx1 || bx2 < ax1 || ay2 < by1 || by2 < ay1) { + return FALSE; + } + + tx1 = MAX(ax1, bx1); + ty1 = MAX(ay1, by1); + tx2 = MIN(ax2, bx2); + ty2 = MIN(ay2, by2); + + ix = tx1 - ax1; + iy = ty1 - ay1; + iw = tx2 - tx1; + ih = ty2 - ty1; + + /* check if the resulting rectangle is feasible */ + if (iw <= 0 || ih <= 0) { + return FALSE; + } + *x = ix; + *y = iy; + *w = iw; + *h = ih; + return TRUE; +} + +#ifndef NXAGENT_RANDR_XINERAMA_CLIPPING +/* intersect two rectangles, return aw/ah for w/h if resulting + rectangle is (partly) outside of bounding box */ +Bool intersect_bb(int ax1, int ay1, unsigned int aw, unsigned int ah, + int bx1, int by1, unsigned int bw, unsigned int bh, + int bbx1, int bby1, int bbx2, int bby2, + int *x, int *y, unsigned int *w, unsigned int *h) +{ + Bool result = intersect(ax1, ay1, aw, ah, bx1, by1, bw, bh, x, y, w, h); + if (result == TRUE) { + /* check if outside of bounding box */ + if (ax1 < bbx1 || ax1 + aw > bbx2) { + #ifdef DEBUG + fprintf(stderr, "intersect: box has parts outside bounding box - width stays unchanged [%d]\n", aw); + #endif + *w = aw; + } + + if (ay1 < bby1 || ay1 + ah > bby2) { + #ifdef DEBUG + fprintf(stderr, "intersect: box has parts outside bounding box - height stays unchanged [%d]\n", ah); + #endif + *h = ah; + } + } + + return result; +} +#endif int nxagentChangeScreenConfig(int screen, int width, int height, int mmWidth, int mmHeight) { ScreenPtr pScreen; - rrScrPrivPtr pScrPriv; - RROutputPtr output; - RRCrtcPtr crtc; - RRModePtr mode; - xRRModeInfo modeInfo; - char name[100]; - int r, c, m; - int refresh = 60; - int doNotify = 1; + /* FIXME: when is this needed? */ + int doNotify = TRUE; + int r; + #ifdef TEST + fprintf(stderr, "nxagentChangeScreenConfig: WindowTable[%d] is %p\n", screen, WindowTable[screen]); + #endif if (WindowTable[screen] == NULL) { return 0; @@ -3607,16 +3687,17 @@ int nxagentChangeScreenConfig(int screen, int width, int height, int mmWidth, in UpdateCurrentTime(); - if (nxagentGrabServerInfo.grabstate == SERVER_GRABBED) + if (nxagentGrabServerInfo.grabstate == SERVER_GRABBED && nxagentGrabServerInfo.client != NULL) { /* - * If any client grabbed the server it won't expect that screen + * If any client grabbed the server it won't expect screen * configuration changes until it releases the grab. That could - * get an X error because available modes are chanded meanwhile. + * lead to an X error because available modes are changed + * in the meantime. */ #ifdef TEST - fprintf(stderr, "nxagentChangeScreenConfig: Cancel with grabbed server.\n"); + fprintf(stderr, "nxagentChangeScreenConfig: Cancel with grabbed server (grab held by %p).\n", nxagentGrabServerInfo.client); #endif return 0; @@ -3632,76 +3713,398 @@ int nxagentChangeScreenConfig(int screen, int width, int height, int mmWidth, in if (r != 0) { - pScrPriv = rrGetScrPriv(pScreen); + nxagentAdjustRandRXinerama(pScreen); + } + + if (doNotify) + { + RRScreenSizeNotify(pScreen); + } + +#ifdef DEBUG + fprintf(stderr, "nxagentChangeScreenConfig: Geometry: %d,%d %dx%d\n", nxagentOption(X), nxagentOption(Y),nxagentOption(Width),nxagentOption(Height)); + fprintf(stderr, "nxagentChangeScreenConfig: return %d\n", r); +#endif + + return r; +} + +int nxagentAdjustRandRXinerama(ScreenPtr pScreen) +{ + rrScrPrivPtr pScrPriv; + RROutputPtr output; + xRRModeInfo modeInfo; + char name[100]; + int refresh = 60; + int width = nxagentOption(Width); + int height = nxagentOption(Height); + + pScrPriv = rrGetScrPriv(pScreen); + + if (pScrPriv) + { + int i, j; + int number = 0; + + XineramaScreenInfo *screeninfo = NULL; - if (pScrPriv) + if (nxagentOption(Xinerama)) { + screeninfo = XineramaQueryScreens(nxagentDisplay, &number); +#ifdef DEBUG + if (number) { + fprintf(stderr, "nxagentAdjustRandRXinerama: XineramaQueryScreens() returned %d screens\n", number); + } + else + { + fprintf(stderr, "nxagentAdjustRandRXinerama: XineramaQueryScreens() failed - continuing without Xinerama\n"); + } + } + else { - output = RRFirstOutput(pScreen); + fprintf(stderr, "nxagentAdjustRandRXinerama: Xinerama is disabled\n"); +#endif + } + + /* + * if there's no xinerama on the real server or xinerama is + * disabled in nxagent we only report one big screen. Clients + * still see xinerama enabled but it will report only one (big) + * screen. This is consistent with the way rrxinerama always + * behaved. The single PanoramiX/Xinerama extension however + * disables xinerama if only one screen exists. + */ + if (number == 0) { + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: faking xinerama\n" ); + #endif + number = 1; + + if (screeninfo) { + xfree(screeninfo); + } + if (!(screeninfo = xalloc(sizeof(XineramaScreenInfo)))) { + return FALSE; + } + + /* fake a xinerama screeninfo that covers the whole screen */ + screeninfo->x_org = nxagentOption(X); + screeninfo->y_org = nxagentOption(Y); + screeninfo->width = nxagentOption(Width); + screeninfo->height = nxagentOption(Height); + } + +#ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: numCrtcs [%d], numOutputs [%d]\n", pScrPriv->numCrtcs, pScrPriv->numOutputs); + { + Bool rrgetinfo; + + /* + * Convert old RANDR 1.0 data (if any) to current structure. This + * is needed once at the first run of this function. If we don't + * do this here it will be done implicitely later and add mode(s) to + * our crtc(s)! + */ + rrgetinfo = RRGetInfo(pScreen); + + fprintf(stderr, "nxagentAdjustRandRXinerama: RRGetInfo returned [%d]\n", rrgetinfo); + } +#else + /* we are not interested in the return code */ + RRGetInfo(pScreen); +#endif - if (output && output -> crtc) +#ifndef NXAGENT_RANDR_XINERAMA_CLIPPING + /* calculate bounding box (outer edges) */ + int bbx2, bbx1, bby1, bby2; + bbx2 = bby2 = 0; + bbx1 = bby1 = INT_MAX; + + for (i = 0; i < number; i++) { + bbx2 = MAX(bbx2, screeninfo[i].x_org + screeninfo[i].width); + bby2 = MAX(bby2, screeninfo[i].y_org + screeninfo[i].height); + bbx1 = MIN(bbx1, screeninfo[i].x_org); + bby1 = MIN(bby1, screeninfo[i].y_org); + } + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: bounding box: left [%d] right [%d] top [%d] bottom[%d]\n", bbx1, bbx2, bby1, bby2); + #endif +#endif + + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: numCrtcs [%d], numOutputs [%d]\n", pScrPriv->numCrtcs, pScrPriv->numOutputs); + #endif + + /* adjust the number of CRTCs to match the number of reported + xinerama screens on the real server */ + while (number != pScrPriv->numCrtcs) { + if (number < pScrPriv->numCrtcs) { + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: destroying crtc\n"); + #endif + RRCrtcDestroy(pScrPriv->crtcs[pScrPriv->numCrtcs - 1]); + } + else { - crtc = output -> crtc; + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: adding crtc\n"); + #endif + RRCrtcCreate(pScreen, NULL); + } + } - for (c = 0; c < pScrPriv -> numCrtcs; c++) - { - RRCrtcSet(pScrPriv -> crtcs[c], NULL, 0, 0, RR_Rotate_0, 0, NULL); + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: numCrtcs [%d], numOutputs [%d]\n", pScrPriv->numCrtcs, pScrPriv->numOutputs); + #endif + + /* set gamma. Currently the only reason for doing this is + preventing the xrandr command from complaining about missing + gamma. */ + for (i = 0; i < pScrPriv->numCrtcs; i++) { + if (pScrPriv->crtcs[i]->gammaSize == 0) { + CARD16 gamma = 0; + RRCrtcGammaSetSize(pScrPriv->crtcs[i], 1); + RRCrtcGammaSet(pScrPriv->crtcs[i], &gamma, &gamma, &gamma); + RRCrtcGammaNotify(pScrPriv->crtcs[i]); + } + } + + /* delete superfluous non-NX outputs */ + for (i = pScrPriv->numOutputs - 1; i >= 0; i--) { + if (strncmp(pScrPriv->outputs[i]->name, "NX", 2)) { + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: destroying output [%s]\n", pScrPriv->outputs[i]->name); + #endif + RROutputDestroy(pScrPriv->outputs[i]); + } + } + + /* at this stage only NX outputs are left - we delete the superfluous ones */ + for (i = pScrPriv->numOutputs - 1; i >= number; i--) { + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: destroying output [%s]\n", pScrPriv->outputs[i]->name); + #endif + RROutputDestroy(pScrPriv->outputs[i]); + } + + /* add and init outputs */ + for (i = 0; i < number; i++) { + if (i >= pScrPriv->numOutputs) { + sprintf(name, "NX%d", i+1); + output = RROutputCreate(pScreen, name, strlen(name), NULL); + /* will be done later + RROutputSetConnection(output, RR_Disconnected); + */ + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: created new output [%s]\n", name); + #endif + } + else + { + output = pScrPriv->outputs[i]; + } + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: adjusting output [%s]\n", pScrPriv->outputs[i]->name); + #endif + RROutputSetCrtcs(output, &(pScrPriv->crtcs[i]), 1); + /* FIXME: Isn't there a function for setting this? */ + output->crtc = pScrPriv->crtcs[i]; + /* FIXME: get SubPixelOrder from real X server */ + RROutputSetSubpixelOrder(output, SubPixelUnknown); + /* FIXME: What is the correct physical size here? */ + RROutputSetPhysicalSize(output, 0, 0); + } + + for (i = 0; i < pScrPriv->numOutputs; i++ ) { + Bool disable_output = FALSE; + RRModePtr mymode, prevmode; + int new_x, new_y; + unsigned int new_w, new_h; + + /* + if ((nxagentOption(X) < bbx1 || (nxagentOption(X) + width >= bbx2 )) { + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: output %d: window has parts outside visible area - width stays unchanged [%d]\n", width); + #endif + new_w = width; + } + + if ((nxagentOption(Y) < bby1 || (nxagentOption(Y) + height >= bby2 ) { + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: output %d: window has parts outside visible area - height stays unchanged [%d]\n", height); + #endif + new_h = height; + } + */ + + /* if there's no intersection disconnect the output */ +#ifdef NXAGENT_RANDR_XINERAMA_CLIPPING + disable_output = !intersect(nxagentOption(X), nxagentOption(Y), + width, height, + screeninfo[i].x_org, screeninfo[i].y_org, + screeninfo[i].width, screeninfo[i].height, + &new_x, &new_y, &new_w, &new_h); +#else + disable_output = !intersect_bb(nxagentOption(X), nxagentOption(Y), + width, height, + screeninfo[i].x_org, screeninfo[i].y_org, + screeninfo[i].width, screeninfo[i].height, + bbx1, bby1, bbx2, bby2, + &new_x, &new_y, &new_w, &new_h); +#endif + + /* save previous mode */ + prevmode = pScrPriv->crtcs[i]->mode; + #ifdef DEBUG + if (prevmode) { + fprintf(stderr, "nxagentAdjustRandRXinerama: output %d: prevmode [%s] ([%p]) refcnt [%d]\n", i, prevmode->name, prevmode, prevmode->refcnt); + } else { + fprintf(stderr, "nxagentAdjustRandRXinerama: output %d: no prevmode\n", i); + } + #endif + + RROutputSetCrtcs(pScrPriv->outputs[i], &(pScrPriv->crtcs[i]), 1); + + if (disable_output) { + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: output %d: no (valid) intersection - disconnecting\n", i); + #endif + RROutputSetConnection(pScrPriv->outputs[i], RR_Disconnected); + + /* + * Tests revealed that some window managers (e.g. LXDE) also + * take disconnected outputs into account when calculating + * stuff like wallpaper tile size and maximum window + * size. This is problematic when a disconnected output is + * smaller than any of the connected ones. Solution: unset the + * mode of the output's crtc. This also leads to xinerama not + * showing the disconnected head anymore. + */ + if (prevmode) { + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: removing mode from output %d\n", i); + #endif + RROutputSetModes(pScrPriv->outputs[i], NULL, 0, 0); + + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: removing mode from ctrc %d\n", i); + #endif + RRCrtcSet(pScrPriv->crtcs[i], NULL, 0, 0, RR_Rotate_0, 1, &(pScrPriv->outputs[i])); } + } + else + { + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: output %d: intersection is x [%d] y [%d] width [%d] height [%d]\n", i, new_x, new_y, new_w, new_h); + #endif + + RROutputSetConnection(pScrPriv->outputs[i], RR_Connected); memset(&modeInfo, '\0', sizeof(modeInfo)); - sprintf(name, "%dx%d", width, height); - - modeInfo.width = width; - modeInfo.height = height; - modeInfo.hTotal = width; - modeInfo.vTotal = height; - modeInfo.dotClock = ((CARD32) width * (CARD32) height * - (CARD32) refresh); + +#ifdef NXAGENT_RANDR_MODE_PREFIX + /* avoid collisions with pre-existing default modes by using a + separate namespace. If we'd simply use XxY we could not + distinguish between pre-existing modes which should stay + and our own modes that should be removed after use. */ + sprintf(name, "nx_%dx%d", new_w, new_h); +#else + sprintf(name, "%dx%d", new_w, new_h); +#endif + + modeInfo.width = new_w; + modeInfo.height = new_h; + modeInfo.hTotal = new_w; + modeInfo.vTotal = new_h; + modeInfo.dotClock = ((CARD32) new_w * (CARD32) new_h * (CARD32) refresh); modeInfo.nameLength = strlen(name); - if (nxagentRRCustomMode != NULL) + mymode = RRModeGet(&modeInfo, name); + +#ifdef DEBUG + if (mymode) { + fprintf(stderr, "nxagentAdjustRandRXinerama: output %d: mode [%s] ([%p]) created/received, refcnt [%d]\n", i, name, mymode, mymode->refcnt); + } + else { - RROutputDeleteUserMode(output, nxagentRRCustomMode); - FreeResource(nxagentRRCustomMode -> mode.id, 0); + /* FIXME: what is the correct behaviour in this case? */ + fprintf(stderr, "nxagentAdjustRandRXinerama: output %d: mode [%s] creation failed!\n", i, name); + } +#endif + if (prevmode && mymode == prevmode) { + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: mymode [%s] ([%p]) == prevmode [%s] ([%p])\n", mymode->name, mymode, prevmode->name, prevmode); + #endif - if (crtc != NULL && crtc -> mode == nxagentRRCustomMode) - { - RRCrtcSet(crtc, NULL, 0, 0, RR_Rotate_0, 0, NULL); - } + /* if they are the same RRModeGet() has increased the + refcnt by 1. We decrease it again by calling only + RRModeDestroy() and forget about prevmode */ + RRModeDestroy(mymode); + } + else + { + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: setting mode [%s] ([%p]) refcnt [%d] for output %d\n", mymode->name, mymode, mymode->refcnt, i); + #endif + RROutputSetModes(pScrPriv->outputs[i], &mymode, 1, 0); - #ifdef TEST - fprintf(stderr, "nxagentChangeScreenConfig: " - "Going to destroy mode %p with refcnt %d.\n", - nxagentRRCustomMode, nxagentRRCustomMode->refcnt); + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: setting mode [%s] ([%p]) refcnt [%d] for crtc %d\n", mymode->name, mymode, mymode->refcnt, i); #endif + RRCrtcSet(pScrPriv->crtcs[i], mymode, new_x, new_y, RR_Rotate_0, 1, &(pScrPriv->outputs[i])); - RRModeDestroy(nxagentRRCustomMode); } + } /* if disable_output */ - nxagentRRCustomMode = RRModeGet(&modeInfo, name); + /* throw away the mode if otherwise unused. We do not need it + anymore. We call FreeResource() to ensure the system will not + try to free it again on shutdown */ - RROutputAddUserMode(output, nxagentRRCustomMode); + if (prevmode && prevmode->refcnt == 1) { + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: destroying prevmode [%s]\n", prevmode->name); + #endif + FreeResource(prevmode->mode.id, 0); + } - RRCrtcSet(crtc, nxagentRRCustomMode, 0, 0, RR_Rotate_0, 1, &output); + RROutputChanged(pScrPriv->outputs[i], TRUE); + RRCrtcChanged(pScrPriv->crtcs[i], TRUE); + } - RROutputChanged(output, 1); + /* release allocated memory */ + if (screeninfo) { + xfree(screeninfo); + screeninfo = NULL; + } - doNotify = 0; +#ifdef DEBUG + for (i = 0; i < pScrPriv->numCrtcs; i++) { + RRModePtr mode = pScrPriv->crtcs[i]->mode; + if (mode) { + fprintf(stderr, "nxagentAdjustRandRXinerama: crtc %d has mode [%s] ([%p]), refcnt [%d] and %d outputs\n", i, pScrPriv->crtcs[i]->mode->name, pScrPriv->crtcs[i]->mode, pScrPriv->crtcs[i]->mode->refcnt, pScrPriv->crtcs[i]->numOutputs); + } + else + { + fprintf(stderr, "nxagentAdjustRandRXinerama: crtc %d has no mode and %d outputs\n", i, pScrPriv->crtcs[i]->numOutputs); } - pScrPriv -> lastSetTime = currentTime; - - pScrPriv->changed = 1; - pScrPriv->configChanged = 1; + if (pScrPriv->crtcs[i]->numOutputs > 0) + fprintf(stderr, " output[%d]->crtc=[%p]\n", i, pScrPriv->outputs[i]->crtc); } +#endif - if (doNotify -) - { - RRScreenSizeNotify(pScreen); - } + pScrPriv -> lastSetTime = currentTime; + + pScrPriv->changed = TRUE; + pScrPriv->configChanged = TRUE; } - return r; + /* FIXME: adjust maximum screen size according to remote randr/xinerama setup */ + + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: Min %dx%d, Max %dx%d \n", pScrPriv->minWidth,pScrPriv->minHeight,pScrPriv->maxWidth,pScrPriv->maxHeight); + #endif + + return TRUE; } void nxagentSaveAreas(PixmapPtr pPixmap, RegionPtr prgnSave, int xorg, int yorg, WindowPtr pWin) |