On Fri, May 1, 2015 at 1:39 PM, Mike Gabriel
<[email protected]> wrote:
> Hi Ulrich,
>
> On Fri, May 01, 2015 at 01:13:01PM +0200, Ulrich Sibiller wrote:
> If Xinerama support in nx-libs 3.6.x can be handled without any config
> option, at all, then we should enable it always and by default.

Well, thinking about that: there _could_ be people that want to
emulate a really big screen and automatic xinerama would disturb.

> Maybe it is possible to make +xinerama / -xinerama functional again, so
> that nxagent has the option to disable xinerama (via xrandr).

Hmm, I'll have a look.

>> >   o Xinerama in X2Go has been buggy again and again (due to packaging
>> >     issues in the various distros that nx-libs is packaged for; due to
>> >     bugs in X2Go Client when creating xinerama.conf)
>>
>> Yes, I have noticed that. And I doubt that my changes will be perfect
>> on the first shot...
>
> Oh, don't worry about that!

Talking about the first shot: You'll find it attached, I don't want to
go through that github hassle now (it's three o'clock in the
morning..). But I will...

> I try to avoid bringing in new features, but maybe I will even start working
> on getting XComposite available and fixed in nx-libs, soon.

So what's broken there?

>> located in the nxagent. How can I find out the position of the nxproxy
>> window from the server side?
>
> Phew... good question. The way it is done is this:

I found a solution, one just needs the root window (which is easy to
get) and call XTranslateCoordinates() with the nxproxy window. Took me
some time to work that out, but in the end it's easy.

>   o X2Go Client detects the X window ID of the nxproxy instance
>   o X2Go Client queries the client-side Xserver for the window position
>     of nxproxy (by using the exact X window ID)
>   o X2Go Client does the calculation internally (intersecting nxproxy
>     position and size with client-side Xserver's Xinerama borders
>
> I'd say this requires a patch in nxproxy, so that it knows its position
> all by itself. Or maybe even let nxproxy do the intersecting???

>> Apart from that I think the client side code for updating that
>> information should move from x2goclient to nxproxy. This way all
>> products using NX will benefit.
>
> /me nods on that! Great!!!

Well, nxproxy isn't doing anything but calling some nx-library functions.
Most of the stuff is done by the nxagent. You can see that by
calling nxagent without nxproxy. I now have everything that's needed
in the nxagent code (in only one file: randr/rrxinerama.c) except
periodical updates (they are currently done only on demand). But even
that could be added to the agent.

>> I think in rootless mode the nxagent should always cover the whole
>> desktop. I am not sure if this is valid currently, but it really
>> should.
>
> I think, it does this.

It does not. Running nxagent -R :77 opens up an invisible window with
a strange geometry. However, that does not matter because my code does
not provide xinerama in rootless mode simply because it is not needed.
In rootless mode the client side X server has xinerama and the client
side window manager should handle that.

>> Yes, that case is tricky as it needs intersection. And here I have the
>> mentioned problem: I need to know the position of the nxproxy window
>> on the client-side X server

solved, intersection is implemented and working fine.

> Let me check that later. It would mean that we can drop libNX_Xrandr
> immediately and that we only have to update the Xserver code itself.

Yeah, i'd like that!

>> I think until that problem with the client window position is solved I
>> will implement the halfway solution that still refers to
>> $NX_XINERAMA_CONFIG but will work without the LD_LIBRARY_PATH hack.
>
> Maybe it would be good to keep both approaches in place for legacy support.
>
> If a xinerama.conf file is present use that. If not, try out your new code.

My current version (attached) does this:

- if env is not set use auto_xinerama
- if env is set to "auto" use auto_xinerama
- if env points to existing file use file_xinerama
- else use original code

We can work out something better if you like.

Please have a look at my code and test.


Uli
/*
 * Copyright © 2006 Keith Packard
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that copyright
 * notice and this permission notice appear in supporting documentation, and
 * that the name of the copyright holders not be used in advertising or
 * publicity pertaining to distribution of the software without specific,
 * written prior permission.  The copyright holders make no representations
 * about the suitability of this software for any purpose.  It is provided "as
 * is" without express or implied warranty.
 *
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 * OF THIS SOFTWARE.
 */
/*
 * This Xinerama implementation comes from the SiS driver which has
 * the following notice:
 */
/* 
 * SiS driver main code
 *
 * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1) Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2) Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3) The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Author: Thomas Winischhofer <[email protected]>
 *	- driver entirely rewritten since 2001, only basic structure taken from
 *	  old code (except sis_dri.c, sis_shadow.c, sis_accel.c and parts of
 *	  sis_dga.c; these were mostly taken over; sis_dri.c was changed for
 *	  new versions of the DRI layer)
 *
 * This notice covers the entire driver code unless indicated otherwise.
 *
 * Formerly based on code which was
 * 	     Copyright (C) 1998, 1999 by Alan Hourihane, Wigan, England.
 * 	     Written by:
 *           Alan Hourihane <[email protected]>,
 *           Mike Chapman <[email protected]>,
 *           Juanjo Santamarta <[email protected]>,
 *           Mitani Hiroshi <[email protected]>,
 *           David Thomas <[email protected]>.
 */

/**************************************************************************/
/*                                                                        */
/* Copyright (c) 2001, 2011 NoMachine, http://www.nomachine.com/.         */
/*                                                                        */
/* NX-X11, NX protocol compression and NX extensions to this software     */
/* are copyright of NoMachine. Redistribution and use of the present      */
/* software is allowed according to terms specified in the file LICENSE   */
/* which comes in the source distribution.                                */
/*                                                                        */
/* Check http://www.nomachine.com/licensing.html for applicability.       */
/*                                                                        */
/* NX and NoMachine are trademarks of Medialogic S.p.A.                   */
/*                                                                        */
/* All rights reserved.                                                   */
/*                                                                        */
/**************************************************************************/

#include "randrstr.h"
#include "swaprep.h"
/* FIXME: there's no difference between
   X11/extensions/panoramiXproto.h and panoramiXproto.h */
#ifndef NXAGENT_SERVER
#include <X11/extensions/panoramiXproto.h>
#else
#include <X11/Xlib.h>
#include <X11/extensions/Xinerama.h>
#include <../hw/nxagent/Windows.h>
#include "panoramiXproto.h"
#endif

#define RR_XINERAMA_MAJOR_VERSION   1
#define RR_XINERAMA_MINOR_VERSION   1

/* Xinerama is not multi-screen capable; just report about screen 0 */
#define RR_XINERAMA_SCREEN  0

static int ProcRRXineramaQueryVersion(ClientPtr client);
static int ProcRRXineramaGetState(ClientPtr client);
static int ProcRRXineramaGetScreenCount(ClientPtr client);
static int ProcRRXineramaGetScreenSize(ClientPtr client);
static int ProcRRXineramaIsActive(ClientPtr client);
static int ProcRRXineramaQueryScreens(ClientPtr client);
#ifdef NXAGENT_SERVER
static int ProcRRXineramaQueryScreens_auto(ClientPtr client);
static int ProcRRXineramaQueryScreens_orig(ClientPtr client);
static int ProcRRXineramaQueryScreens_file(ClientPtr client, FILE *fptr );
#endif
static int SProcRRXineramaDispatch(ClientPtr client);

#ifdef NXAGENT_SERVER
extern Display *nxagentDisplay;
extern Window nxagentDefaultWindows[];
#endif

#undef DEBUG

/* Proc */

int
ProcRRXineramaQueryVersion(ClientPtr client)
{
    xPanoramiXQueryVersionReply	  rep;
    register int		  n;

    REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq);
    rep.type = X_Reply;
    rep.length = 0;
    rep.sequenceNumber = client->sequence;
    rep.majorVersion = RR_XINERAMA_MAJOR_VERSION;
    rep.minorVersion = RR_XINERAMA_MINOR_VERSION;
    if(client->swapped) {
        swaps(&rep.sequenceNumber, n);
        swapl(&rep.length, n);
        swaps(&rep.majorVersion, n);
        swaps(&rep.minorVersion, n);
    }
    WriteToClient(client, sizeof(xPanoramiXQueryVersionReply), (char *)&rep);
    return (client->noClientException);
}

int
ProcRRXineramaGetState(ClientPtr client)
{
    REQUEST(xPanoramiXGetStateReq);
    WindowPtr			pWin;
    xPanoramiXGetStateReply	rep;
    register int		n, rc;
    ScreenPtr			pScreen;
    rrScrPrivPtr		pScrPriv;
    Bool			active = FALSE;

    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
    #ifndef NXAGENT_SERVER
    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
    #else
    pWin = SecurityLookupWindow(stuff->window, client, SecurityReadAccess);
    rc = pWin ? Success : BadWindow;
    #endif
    if(rc != Success)
	return rc;

    pScreen = pWin->drawable.pScreen;
    pScrPriv = rrGetScrPriv(pScreen);
    if (pScrPriv)
    {
	/* XXX do we need more than this? */
	active = TRUE;
    }

    rep.type = X_Reply;
    rep.length = 0;
    rep.sequenceNumber = client->sequence;
    rep.state = active;
    rep.window = stuff->window;
    if(client->swapped) {
       swaps (&rep.sequenceNumber, n);
       swapl (&rep.length, n);
       swapl (&rep.window, n);
    }
    WriteToClient(client, sizeof(xPanoramiXGetStateReply), (char *)&rep);
    return client->noClientException;
}

static Bool
RRXineramaCrtcActive (RRCrtcPtr crtc)
{
    return crtc->mode != NULL && crtc->numOutputs > 0;
}

static int
RRXineramaScreenCount (ScreenPtr pScreen)
{
    int	i, n;
    
    n = 0;
    if (rrGetScrPriv (pScreen))
    {
	rrScrPriv(pScreen);
	for (i = 0; i < pScrPriv->numCrtcs; i++)
	    if (RRXineramaCrtcActive (pScrPriv->crtcs[i]))
		n++;
    }
    return n;
}

static Bool
RRXineramaScreenActive (ScreenPtr pScreen)
{
    return RRXineramaScreenCount (pScreen) > 0;
}

int
ProcRRXineramaGetScreenCount(ClientPtr client)
{
    REQUEST(xPanoramiXGetScreenCountReq);
    WindowPtr				pWin;
    xPanoramiXGetScreenCountReply	rep;
    register int			n, rc;

    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
    #ifndef NXAGENT_SERVER
    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
    #else
    pWin = SecurityLookupWindow(stuff->window, client, SecurityReadAccess);
    rc = pWin ? Success : BadWindow;
    #endif
    if (rc != Success)
	return rc;
    
    rep.type = X_Reply;
    rep.length = 0;
    rep.sequenceNumber = client->sequence;
    rep.ScreenCount = RRXineramaScreenCount (pWin->drawable.pScreen);
    rep.window = stuff->window;
    if(client->swapped) {
       swaps(&rep.sequenceNumber, n);
       swapl(&rep.length, n);
       swapl(&rep.window, n);
    }
    WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep);
    return client->noClientException;
}

int
ProcRRXineramaGetScreenSize(ClientPtr client)
{
    REQUEST(xPanoramiXGetScreenSizeReq);
    WindowPtr				pWin, pRoot;
    ScreenPtr				pScreen;
    xPanoramiXGetScreenSizeReply	rep;
    register int			n, rc;

    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
    #ifndef NXAGENT_SERVER
    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
    #else
    pWin = SecurityLookupWindow(stuff->window, client, SecurityReadAccess);
    rc = pWin ? Success : BadWindow;
    #endif
    if (rc != Success)
	return rc;

    pScreen = pWin->drawable.pScreen;
    pRoot = WindowTable[pScreen->myNum];
    
    rep.type = X_Reply;
    rep.length = 0;
    rep.sequenceNumber = client->sequence;
    rep.width  = pRoot->drawable.width;
    rep.height = pRoot->drawable.height;
    rep.window = stuff->window;
    rep.screen = stuff->screen;
    if(client->swapped) {
       swaps(&rep.sequenceNumber, n);
       swapl(&rep.length, n);
       swapl(&rep.width, n);
       swapl(&rep.height, n);
       swapl(&rep.window, n);
       swapl(&rep.screen, n);
    }
    WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep);
    return client->noClientException;
}

int
ProcRRXineramaIsActive(ClientPtr client)
{
    xXineramaIsActiveReply	rep;

    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);

    rep.type = X_Reply;
    rep.length = 0;
    rep.sequenceNumber = client->sequence;
#ifndef NXAGENT_SERVER
    rep.state = RRXineramaScreenActive (screenInfo.screens[RR_XINERAMA_SCREEN]);
#else
    /* FIXME: cache that information? */
    if (nxagentOption(Rootless) == 1) {
      /* In rootless mode we do not need any xinerama stuff in the
	 nxagent. Xinerama is only relevant for the client side then. */
      rep.state = FALSE;
    }
    else {
      /* ask remote X server for that information */
      rep.state = !XineramaIsActive(nxagentDisplay);
    }
#ifdef DEBUG
    if (rep.state) {
      fprintf(stderr, "ProcRRXineramaIsActive: remote Xinerama on display %s is active\n", XDisplayString(nxagentDisplay)); 
    } else {
      fprintf(stderr, "ProcRRXineramaIsActive: remote Xinerama on display %s is not active\n", XDisplayString(nxagentDisplay));
    }
#endif
#endif
    if(client->swapped) {
	register int n;
	swaps(&rep.sequenceNumber, n);
	swapl(&rep.length, n);
	swapl(&rep.state, n);
    }
    WriteToClient(client, sizeof(xXineramaIsActiveReply), (char *) &rep);

    return client->noClientException;
}

/* Helper, send the number of xinerama screens to the client */
void writeNumScreens(ClientPtr client, int number)
{
    xXineramaQueryScreensReply rep;

#ifdef DEBUG    
    fprintf(stderr, "writeNumScreens: number=%d\n", number);
#endif

    rep.type = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.number = number;
    rep.length = rep.number * sz_XineramaScreenInfo >> 2;
    if (client->swapped) {
        register int n;
	swaps (&rep.sequenceNumber, n);
	swapl (&rep.length, n);
	swapl (&rep.number, n);
    }	
    WriteToClient (client, sizeof (xXineramaQueryScreensReply), (char *) &rep);
}

/* Helper, send one xinerama screen to the client */
void writeOneScreen(ClientPtr client, int x, int y, int w, int h)
{
    xXineramaScreenInfo scratch;

#ifdef DEBUG    
    fprintf(stderr, "writeOneScreen: x=%d, y=%d, w=%d, h=%d)\n", x, y, w, h);
#endif
    scratch.x_org  = x;
    scratch.y_org  = y;
    scratch.width  = w;
    scratch.height = h;
    if(client->swapped) {
        register int n;
	swaps(&scratch.x_org, n);
	swaps(&scratch.y_org, n);
	swaps(&scratch.width, n);
	swaps(&scratch.height, n);
    }
    WriteToClient(client, sz_XineramaScreenInfo, (char *)&scratch);
}

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

/* second Dispatcher to determine what xinerama code to use */
int
ProcRRXineramaQueryScreens(ClientPtr client)
{
#ifndef NXAGENT_SERVER
    return ProcRRXineramaQueryScreens_orig(client);
#else

    char* envvar = getenv("NX_XINERAMA_CONF");
    int res;
    /* if env is not set use auto_xinerama
       if env is set to "auto" use auto_xinerama
       if env point to existing file use file_xinerama
       else use original code
    */

#ifdef DEBUG
    if (envvar) {
        fprintf(stderr, "ProcRRXineramaQueryScreens: envvar NX_XINERAMA_CONF is set to '%s'\n", envvar);
    } else {
        fprintf(stderr, "ProcRRXineramaQueryScreens: envvar NX_XINERAMA_CONF is not set\n");
    }
#endif

    if (!envvar || strncmp("auto", envvar, 4) == 0) {
        res = ProcRRXineramaQueryScreens_auto(client);
    } else {
        FILE* fptr;
	if((fptr=fopen(envvar,"r"))) {
            res = ProcRRXineramaQueryScreens_file(client, fptr);
        } else {
            res = ProcRRXineramaQueryScreens_orig(client);
        }
    }
    return res;
#endif
}


/* determine the position and size of the nxproxy window */
/* FIXME: is border_width relevant here? */
BOOL getWindowGeometry(Display *display, Window win, int *x_org, int *y_org, unsigned int *width, unsigned int *height)
{
    int x,y, ox, oy;
    unsigned int w, h, border_width, depth;
    Status stat;
    Window root = NULL;
    Window child = NULL;

    x = y = 0;
    w = h = border_width = depth = 0;

    stat = XGetGeometry(display, win, &root, &x, &y, &w, &h, &border_width, &depth);
    if (stat) {
#ifdef DEBUG
        fprintf(stderr, "getGeometry: stat=%d, root=0x%x, x=%d, y=%d, width=%d, height=%d, border_width=%d, DISPLAY='%s'\n",
	        stat, root, x, y, w, h, border_width, XDisplayString(display));
#endif
        *width = w;
        *height = h;
    } else {
#ifdef DEBUG
        fprintf(stderr, "getGeometry: Cannot determine geometry for window 0x%x\n", win);	      
#endif
        return FALSE;
    }

    /* Get coordinates of the nxproxy window relative to
       the root window */
    if (!XTranslateCoordinates(display, win, root, 0, 0, &ox, &oy, &child)) {
        /* rc=FALSE means the window and root are on different
	   screens. This cannot happen as we got the root window
	   from the XGetGeometry call above so win MUST
	   reside on that root window. 
	   FIXME: We skip this for now as it is unclear what to
	   do in this situation.*/
       ;
#ifdef DEBUG
       fprintf(stderr, "getGeometry: XTranslateCoordinates() failed\n");	      
#endif
    } else {
#ifdef DEBUG
        fprintf(stderr, "getGeometry: XTranslateCoordinates() result: x_org=%d, offset_y=%d\n", ox, oy);	      
#endif
        *x_org = ox;
        *y_org = oy;
    }

    return TRUE;
}


int
ProcRRXineramaQueryScreens_auto(ClientPtr client)
{
#ifdef DEBUG
    fprintf(stderr, "ProcRRXineramaQueryScreens_auto: entry\n");
#endif
    XineramaScreenInfo *screeninfo;

    /* these are used to store the xinerama screens */
    static XineramaScreenInfo *cache_screeninfo = NULL;
    static int cache_number = -1;

    int number;
    int i;

    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);

    /* This call will fail if nxagent is in disconnected mode. For now we
       try to use cached values then. */ 
    /* FIXME: if nxcomp could answer this call from its cache we could drop
       this code here */
    if ((screeninfo = XineramaQueryScreens(nxagentDisplay, &number)) == NULL) {
#ifdef DEBUG    
        fprintf(stderr, "ProcRRXineramaQueryScreens_auto: remote XineramaQueryScreens() for display %s failed\n", XDisplayString(nxagentDisplay)); 
#endif
	/* if we have a cached result use that */
	if (cache_number > -1) {
#ifdef DEBUG    
	    fprintf(stderr, "ProcRRXineramaQueryScreens_auto: using cached values\n"); 
#endif
	  
	    writeNumScreens(client, cache_number);
	    for (i = 0; i < cache_number; i++) {
	        writeOneScreen(client, cache_screeninfo[i].x_org,
			               cache_screeninfo[i].y_org,
                                       cache_screeninfo[i].width,
                                       cache_screeninfo[i].height);
            }
        } else {
#ifdef DEBUG
            fprintf(stderr, "ProcRRXineramaQueryScreens_auto: cache is empty\n"); 
#endif
            /* we report "no xinerama screens found" */
	    writeNumScreens(client, 0);
        }
        return client->noClientException;
    }
            
#ifdef DEBUG
    fprintf(stderr, "ProcRRXineramaQueryScreens_auto: remote XineramaQueryScreens() for display %s was successful, returned %d screens\n", XDisplayString(nxagentDisplay), number); 
#endif

    if (number) {
        int x_org, y_org;
	unsigned int width, height;
	int count = 0;

	/* nxagentDefaultWindows[0] is the window that is referred to in
	   hw/nxagent/Extensions.c:nxagentRandRSetWindowsSize() and in
	   this file's header, too. So this should be correct. This
	   window is NULL when nxagent is in disconnected state, but if
	   we reach this point it should always be set. Nevertheless we
	   do some sanity checks */
	if (!nxagentDefaultWindows[RR_XINERAMA_SCREEN]) {
	    /* should not happen... */
#ifdef DEBUG    
	    fprintf(stderr, "ProcRRXineramaQueryScreens_auto: nxagentDefaultWindows[RR_XINERAMA_SCREEN] is NULL\n"); 
#endif
	    number = 0;
	} else {
            x_org = y_org = 0; /* get rid of compiler warning */
	    if (!getWindowGeometry(nxagentDisplay, nxagentDefaultWindows[RR_XINERAMA_SCREEN], &x_org, &y_org, &width, &height)) {
	        /* should also not happen... */
	        fprintf(stderr, "ProcRRXineramaQueryScreens_auto: could not determine pos and size of nxagentDefaultWindows[RR_XINERAMA_SCREEN]\n"); 
		number = 0;
	    }
	}

        /* We need to send the number of screens prior to the
	   screens. But we do not want to send screens that are outside
	   the nxproxy window so we do not know the right number
	   here. So we update the screeninfo structures and count the
	   number. After the loop we send the updated structures.  NOTE:
	   If we skip screens the caches screeninfo will be slightly
	   bigger than needed! But for ease of implementation this is
	   tolerable.
	*/
	for (i = 0; i < number; i++) {
	    int new_x, new_y;
	    unsigned int new_w, new_h;

	    /* if there's no intersection we skip that screen */
	    if (!intersect(x_org, y_org,
                           width, height,
                           screeninfo[i].x_org, screeninfo[i].y_org,
                           screeninfo[i].width, screeninfo[i].height,
			   &new_x, &new_y, &new_w, &new_h)) {
#ifdef DEBUG
	        fprintf(stderr, "ProcRRXineramaQueryScreens_auto: no (valid) intersection - skipping screen %d'\n", i);
#endif
		continue;
	    }

	    /* store the new values for reply/cache */
	    screeninfo[count].x_org  = new_x;  
	    screeninfo[count].y_org  = new_y;  
	    screeninfo[count].width  = new_w;  
	    screeninfo[count].height = new_h;  
	    count++;

#ifdef DEBUG
	    fprintf(stderr, "ProcRRXineramaQueryScreens_auto: intersected screen is x=%d, y=%d, width=%d, height=%d'\n", new_x, new_y, new_w, new_h);
#endif
	} /* end for */

	/* correct the number of screens we determined to be valid/of
	   interest for us (for reply and cache)*/
	number = count;
    } /* end if (number) */

    /* we have checked all screens, now answer with the valid ones */ 
    writeNumScreens(client, number);
    for (i = 0; i < number; i++) {
        writeOneScreen(client, screeninfo[i].x_org, screeninfo[i].y_org, screeninfo[i].width, screeninfo[i].height);
    }

    /* now cache the result */ 
    {
        /* invalidate exiting cache */
        if (cache_screeninfo != NULL) {
            XFree(cache_screeninfo);
	    cache_screeninfo = NULL;
        }

#ifdef DEBUG      
        fprintf(stderr, "ProcRRXineramaQueryScreens_auto: caching calculated screeninfo\n");
#endif
        cache_screeninfo = screeninfo;
        cache_number = number;
    }
	      
    return client->noClientException;
}


int
ProcRRXineramaQueryScreens_file(ClientPtr client, FILE* fptr)
{
#ifdef DEBUG
    fprintf(stderr, "ProcRRXineramaQueryScreens_file: entry\n");
#endif
    int i;
    int x,y,w,h;
    int number = 0;
	
    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);

    if (fptr) {
        while (!feof(fptr)) {
            w = h = 0;
	    fscanf(fptr,"%d %d %d %d",&x,&y,&w,&h);
	    if (w && h)
	        number++;
	}
	rewind(fptr);

	writeNumScreens(client, number);
  
	for (i = 0; i < number; i++) {
	    while (!feof(fptr)){
	        w = h = 0;
		fscanf(fptr,"%d %d %d %d", &x, &y, &w, &h);
		if (w && h) {
	            writeOneScreen(client, x, y, w, h);
		}
	    }
	}
	fclose(fptr);
    } else {
        /* report "no xinerama screens" */ 
        writeNumScreens(client, 0);
    }
    return client->noClientException;
}

int
ProcRRXineramaQueryScreens_orig(ClientPtr client)
{
#ifdef DEBUG
    fprintf(stderr, "ProcRRXineramaQueryScreens_orig: entry\n");
#endif
    ScreenPtr	pScreen = screenInfo.screens[RR_XINERAMA_SCREEN];
    int number;

    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);

    if (RRXineramaScreenActive (pScreen))
    {
	rrScrPriv(pScreen);
	if (pScrPriv->numCrtcs == 0 || pScrPriv->numOutputs == 0)
	    RRGetInfo (pScreen);
    }
    
    number = RRXineramaScreenCount (pScreen);
    writeNumScreens(client, number);

    if(number) {
	rrScrPriv(pScreen);
	int i;

	for(i = 0; i < pScrPriv->numCrtcs; i++) {
	    RRCrtcPtr	crtc = pScrPriv->crtcs[i];
	    if (RRXineramaCrtcActive (crtc))
	    {
	        int width, height;
		RRCrtcGetScanoutSize (crtc, &width, &height);
		writeOneScreen(client, crtc->x, crtc->y, width, height);
	    }
	}
    }

    return client->noClientException;
}


static int
ProcRRXineramaDispatch(ClientPtr client)
{
    REQUEST(xReq);
    switch (stuff->data) {
	case X_PanoramiXQueryVersion:
	     return ProcRRXineramaQueryVersion(client);
	case X_PanoramiXGetState:
	     return ProcRRXineramaGetState(client);
	case X_PanoramiXGetScreenCount:
	     return ProcRRXineramaGetScreenCount(client);
	case X_PanoramiXGetScreenSize:
	     return ProcRRXineramaGetScreenSize(client);
	case X_XineramaIsActive:
	     return ProcRRXineramaIsActive(client);
	case X_XineramaQueryScreens:
	     return ProcRRXineramaQueryScreens(client);
    }
    return BadRequest;
}

/* SProc */

static int
SProcRRXineramaQueryVersion (ClientPtr client)
{
    REQUEST(xPanoramiXQueryVersionReq);
    register int n;
    swaps(&stuff->length,n);
    REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq);
    return ProcRRXineramaQueryVersion(client);
}

static int
SProcRRXineramaGetState(ClientPtr client)
{
    REQUEST(xPanoramiXGetStateReq);
    register int n;
    swaps (&stuff->length, n);
    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
    swapl (&stuff->window, n);
    return ProcRRXineramaGetState(client);
}

static int
SProcRRXineramaGetScreenCount(ClientPtr client)
{
    REQUEST(xPanoramiXGetScreenCountReq);
    register int n;
    swaps (&stuff->length, n);
    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
    swapl (&stuff->window, n);
    return ProcRRXineramaGetScreenCount(client);
}

static int
SProcRRXineramaGetScreenSize(ClientPtr client)
{
    REQUEST(xPanoramiXGetScreenSizeReq);
    register int n;
    swaps (&stuff->length, n);
    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
    swapl (&stuff->window, n);
    swapl (&stuff->screen, n);
    return ProcRRXineramaGetScreenSize(client);
}

static int
SProcRRXineramaIsActive(ClientPtr client)
{
    REQUEST(xXineramaIsActiveReq);
    register int n;
    swaps (&stuff->length, n);
    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
    return ProcRRXineramaIsActive(client);
}

static int
SProcRRXineramaQueryScreens(ClientPtr client)
{
    REQUEST(xXineramaQueryScreensReq);
    register int n;
    swaps (&stuff->length, n);
    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
    return ProcRRXineramaQueryScreens(client);
}

int
SProcRRXineramaDispatch(ClientPtr client)
{
    REQUEST(xReq);
    switch (stuff->data) {
	case X_PanoramiXQueryVersion:
	     return SProcRRXineramaQueryVersion(client);
	case X_PanoramiXGetState:
	     return SProcRRXineramaGetState(client);
	case X_PanoramiXGetScreenCount:
	     return SProcRRXineramaGetScreenCount(client);
	case X_PanoramiXGetScreenSize:
	     return SProcRRXineramaGetScreenSize(client);
	case X_XineramaIsActive:
	     return SProcRRXineramaIsActive(client);
	case X_XineramaQueryScreens:
	     return SProcRRXineramaQueryScreens(client);
    }
    return BadRequest;
}

static void
RRXineramaResetProc(ExtensionEntry* extEntry)
{
}

void
RRXineramaExtensionInit(void)
{
#ifdef PANORAMIX
    if(!noPanoramiXExtension)
	return;
#endif

    /*
     * Xinerama isn't capable enough to have multiple protocol screens each
     * with their own output geometry.  So if there's more than one protocol
     * screen, just don't even try.
     */
    if (screenInfo.numScreens > 1)
	return;

    (void) AddExtension(PANORAMIX_PROTOCOL_NAME, 0,0,
			ProcRRXineramaDispatch,
			SProcRRXineramaDispatch,
			RRXineramaResetProc,
			StandardMinorOpcode);
}
_______________________________________________
x2go-dev mailing list
[email protected]
http://lists.x2go.org/listinfo/x2go-dev

Reply via email to