/*
 * Xephyr - A kdrive X server thats runs in a host X window.
 *          Authored by Matthew Allum <mallum@openedhand.com>
 * 
 * Copyright © 2007 OpenedHand Ltd 
 *
 * 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 OpenedHand Ltd not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission. OpenedHand Ltd makes no
 * representations about the suitability of this software for any purpose.  It
 * is provided "as is" without express or implied warranty.
 *
 * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL OpenedHand Ltd 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 file is heavily copied from hw/xfree86/dri/xf86dri.c
 *
 * Authors:
 *    Dodji Seketeli <dodji@openedhand.com>
 */

#ifdef HAVE_CONFIG_H
#include <kdrive-config.h>
#endif

#include <string.h>

#include <X11/X.h>
#include <X11/Xproto.h>
#define _XF86DRI_SERVER_
#include <X11/dri/xf86dri.h>
#include <X11/dri/xf86driproto.h>
#include "misc.h"
#include "privates.h"
#include "dixstruct.h"
#include "extnsionst.h"
#include "colormapst.h"
#include "cursorstr.h"
#include "scrnintstr.h"
#include "windowstr.h"
#include "servermd.h"
#include "swaprep.h"
#include "ephyrdri.h"
#include "ephyrdriext.h"
#include "hostx.h"
#define _HAVE_XALLOC_DECLS
#include "ephyrlog.h"
#include "protocol-versions.h"

typedef struct {
    int foo;
} EphyrDRIWindowPrivRec;
typedef EphyrDRIWindowPrivRec* EphyrDRIWindowPrivPtr;

typedef struct {
    CreateWindowProcPtr CreateWindow ;
    DestroyWindowProcPtr DestroyWindow ;
    MoveWindowProcPtr MoveWindow ;
    PositionWindowProcPtr PositionWindow ;
    ClipNotifyProcPtr ClipNotify ;
} EphyrDRIScreenPrivRec;
typedef EphyrDRIScreenPrivRec* EphyrDRIScreenPrivPtr;

static int DRIErrorBase;



static Bool ephyrDRIScreenInit (ScreenPtr a_screen) ;
static Bool ephyrDRICreateWindow (WindowPtr a_win) ;
static Bool ephyrDRIDestroyWindow (WindowPtr a_win) ;
static void ephyrDRIMoveWindow (WindowPtr a_win,
                                int a_x, int a_y,
                                WindowPtr a_siblings,
                                VTKind a_kind);
static Bool ephyrDRIPositionWindow (WindowPtr a_win,
                                    int x, int y) ;
static void ephyrDRIClipNotify (WindowPtr a_win,
                                int a_x, int a_y) ;

static Bool EphyrMirrorHostVisuals (ScreenPtr a_screen) ;
static Bool destroyHostPeerWindow (const WindowPtr a_win) ;
static Bool findWindowPairFromLocal (WindowPtr a_local,
                                     EphyrWindowPair **a_pair);

static unsigned char DRIReqCode = 0;

static DevPrivateKeyRec ephyrDRIWindowKeyRec;
#define ephyrDRIWindowKey (&ephyrDRIWindowKeyRec)
static DevPrivateKeyRec ephyrDRIScreenKeyRec;
#define ephyrDRIScreenKey (&ephyrDRIScreenKeyRec)

#define GET_EPHYR_DRI_WINDOW_PRIV(win) ((EphyrDRIWindowPrivPtr) \
    dixLookupPrivate(&(win)->devPrivates, ephyrDRIWindowKey))
#define GET_EPHYR_DRI_SCREEN_PRIV(screen) ((EphyrDRIScreenPrivPtr) \
    dixLookupPrivate(&(screen)->devPrivates, ephyrDRIScreenKey))

static Bool
ephyrDRIScreenInit (ScreenPtr a_screen)
{
    Bool is_ok=FALSE ;
    EphyrDRIScreenPrivPtr screen_priv=NULL ;

    EPHYR_RETURN_VAL_IF_FAIL (a_screen, FALSE) ;

    screen_priv=GET_EPHYR_DRI_SCREEN_PRIV (a_screen) ;
    EPHYR_RETURN_VAL_IF_FAIL (screen_priv, FALSE) ;

    screen_priv->CreateWindow = a_screen->CreateWindow ;
    screen_priv->DestroyWindow = a_screen->DestroyWindow ;
    screen_priv->MoveWindow = a_screen->MoveWindow ;
    screen_priv->PositionWindow = a_screen->PositionWindow ;
    screen_priv->ClipNotify = a_screen->ClipNotify ;

    a_screen->CreateWindow = ephyrDRICreateWindow ;
    a_screen->DestroyWindow = ephyrDRIDestroyWindow ;
    a_screen->MoveWindow = ephyrDRIMoveWindow ;
    a_screen->PositionWindow = ephyrDRIPositionWindow ;
    a_screen->ClipNotify = ephyrDRIClipNotify ;

    is_ok = TRUE ;

    return is_ok ;
}

static Bool
ephyrDRICreateWindow (WindowPtr a_win)
{
    Bool is_ok=FALSE ;
    ScreenPtr screen=NULL ;
    EphyrDRIScreenPrivPtr screen_priv =NULL;

    EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ;
    screen = a_win->drawable.pScreen ;
    EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ;
    screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ;
    EPHYR_RETURN_VAL_IF_FAIL (screen_priv
                              && screen_priv->CreateWindow,
                              FALSE) ;

    EPHYR_LOG ("enter. win:%p\n", a_win) ;

    screen->CreateWindow = screen_priv->CreateWindow ;
    is_ok = (*screen->CreateWindow) (a_win) ;
    screen->CreateWindow = ephyrDRICreateWindow ;

    if (is_ok) {
	dixSetPrivate(&a_win->devPrivates, ephyrDRIWindowKey, NULL);
    }
    return is_ok ;
}

static Bool
ephyrDRIDestroyWindow (WindowPtr a_win)
{
    Bool is_ok=FALSE ;
    ScreenPtr screen=NULL ;
    EphyrDRIScreenPrivPtr screen_priv =NULL;

    EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ;
    screen = a_win->drawable.pScreen ;
    EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ;
    screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ;
    EPHYR_RETURN_VAL_IF_FAIL (screen_priv
                              && screen_priv->DestroyWindow,
                              FALSE) ;

    screen->DestroyWindow = screen_priv->DestroyWindow ;
    if (screen->DestroyWindow) {
        is_ok = (*screen->DestroyWindow) (a_win) ;
    }
    screen->DestroyWindow = ephyrDRIDestroyWindow ;

    if (is_ok) {
        EphyrDRIWindowPrivPtr win_priv=GET_EPHYR_DRI_WINDOW_PRIV (a_win) ;
        if (win_priv) {
            destroyHostPeerWindow (a_win) ;
            free(win_priv) ;
	    dixSetPrivate(&a_win->devPrivates, ephyrDRIWindowKey, NULL);
            EPHYR_LOG ("destroyed the remote peer window\n") ;
        }
    }
    return is_ok ;
}

static void
ephyrDRIMoveWindow (WindowPtr a_win,
                    int a_x, int a_y,
                    WindowPtr a_siblings,
                    VTKind a_kind)
{
    Bool is_ok=FALSE ;
    ScreenPtr screen=NULL ;
    EphyrDRIScreenPrivPtr screen_priv =NULL;
    EphyrDRIWindowPrivPtr win_priv=NULL ;
    EphyrWindowPair *pair=NULL ;
    EphyrBox geo;
    int x=0,y=0;/*coords relative to parent window*/

    EPHYR_RETURN_IF_FAIL (a_win) ;

    EPHYR_LOG ("enter\n") ;
    screen = a_win->drawable.pScreen ;
    EPHYR_RETURN_IF_FAIL (screen) ;
    screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ;
    EPHYR_RETURN_IF_FAIL (screen_priv
                          && screen_priv->MoveWindow) ;

    screen->MoveWindow = screen_priv->MoveWindow ;
    if (screen->MoveWindow) {
        (*screen->MoveWindow) (a_win, a_x, a_y, a_siblings, a_kind) ;
    }
    screen->MoveWindow = ephyrDRIMoveWindow ;

    EPHYR_LOG ("window: %p\n", a_win) ;
    if (!a_win->parent) {
        EPHYR_LOG ("cannot move root window\n") ;
        is_ok = TRUE ;
        goto out ;
    }
    win_priv = GET_EPHYR_DRI_WINDOW_PRIV (a_win) ;
    if (!win_priv) {
        EPHYR_LOG ("not a DRI peered window\n") ;
        is_ok = TRUE ;
        goto out ;
    }
    if (!findWindowPairFromLocal (a_win, &pair) || !pair) {
        EPHYR_LOG_ERROR ("failed to get window pair\n") ;
        goto out ;
    }
    /*compute position relative to parent window*/
    x = a_win->drawable.x - a_win->parent->drawable.x ;
    y = a_win->drawable.y - a_win->parent->drawable.y ;
    /*set the geometry to pass to hostx_set_window_geometry*/
    memset (&geo, 0, sizeof (geo)) ;
    geo.x = x ;
    geo.y = y ;
    geo.width = a_win->drawable.width ;
    geo.height = a_win->drawable.height ;
    hostx_set_window_geometry (pair->remote, &geo) ;
    is_ok = TRUE ;

out:
    EPHYR_LOG ("leave. is_ok:%d\n", is_ok) ;
    /*do cleanup here*/
}

static Bool
ephyrDRIPositionWindow (WindowPtr a_win,
                        int a_x, int a_y)
{
    Bool is_ok=FALSE ;
    ScreenPtr screen=NULL ;
    EphyrDRIScreenPrivPtr screen_priv =NULL;
    EphyrDRIWindowPrivPtr win_priv=NULL ;
    EphyrWindowPair *pair=NULL ;
    EphyrBox geo;

    EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ;

    EPHYR_LOG ("enter\n") ;
    screen = a_win->drawable.pScreen ;
    EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ;
    screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ;
    EPHYR_RETURN_VAL_IF_FAIL (screen_priv
                              && screen_priv->PositionWindow,
                              FALSE) ;

    screen->PositionWindow = screen_priv->PositionWindow ;
    if (screen->PositionWindow) {
        (*screen->PositionWindow) (a_win, a_x, a_y) ;
    }
    screen->PositionWindow = ephyrDRIPositionWindow ;

    EPHYR_LOG ("window: %p\n", a_win) ;
    win_priv = GET_EPHYR_DRI_WINDOW_PRIV (a_win) ;
    if (!win_priv) {
        EPHYR_LOG ("not a DRI peered window\n") ;
        is_ok = TRUE ;
        goto out ;
    }
    if (!findWindowPairFromLocal (a_win, &pair) || !pair) {
        EPHYR_LOG_ERROR ("failed to get window pair\n") ;
        goto out ;
    }
    /*set the geometry to pass to hostx_set_window_geometry*/
    memset (&geo, 0, sizeof (geo)) ;
    geo.x = a_x ;
    geo.y = a_y ;
    geo.width = a_win->drawable.width ;
    geo.height = a_win->drawable.height ;
    hostx_set_window_geometry (pair->remote, &geo) ;
    is_ok = TRUE ;

out:
    EPHYR_LOG ("leave. is_ok:%d\n", is_ok) ;
    /*do cleanup here*/
    return is_ok ;
}

static void
ephyrDRIClipNotify (WindowPtr a_win,
                    int a_x, int a_y)
{
    Bool is_ok=FALSE ;
    ScreenPtr screen=NULL ;
    EphyrDRIScreenPrivPtr screen_priv =NULL;
    EphyrDRIWindowPrivPtr win_priv=NULL ;
    EphyrWindowPair *pair=NULL ;
    EphyrRect *rects=NULL;
    int i=0 ;

    EPHYR_RETURN_IF_FAIL (a_win) ;

    EPHYR_LOG ("enter\n") ;
    screen = a_win->drawable.pScreen ;
    EPHYR_RETURN_IF_FAIL (screen) ;
    screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ;
    EPHYR_RETURN_IF_FAIL (screen_priv && screen_priv->ClipNotify) ;

    screen->ClipNotify = screen_priv->ClipNotify ;
    if (screen->ClipNotify) {
        (*screen->ClipNotify) (a_win, a_x, a_y) ;
    }
    screen->ClipNotify = ephyrDRIClipNotify ;

    EPHYR_LOG ("window: %p\n", a_win) ;
    win_priv = GET_EPHYR_DRI_WINDOW_PRIV (a_win) ;
    if (!win_priv) {
        EPHYR_LOG ("not a DRI peered window\n") ;
        is_ok = TRUE ;
        goto out ;
    }
    if (!findWindowPairFromLocal (a_win, &pair) || !pair) {
        EPHYR_LOG_ERROR ("failed to get window pair\n") ;
        goto out ;
    }
    rects = calloc(RegionNumRects (&a_win->clipList),
                     sizeof (EphyrRect)) ;
    for (i=0; i < RegionNumRects (&a_win->clipList); i++) {
        memmove (&rects[i],
                 &RegionRects (&a_win->clipList)[i],
                 sizeof (EphyrRect)) ;
        rects[i].x1 -= a_win->drawable.x;
        rects[i].x2 -= a_win->drawable.x;
        rects[i].y1 -= a_win->drawable.y;
        rects[i].y2 -= a_win->drawable.y;
    }
    /*
     * push the clipping region of this window
     * to the peer window in the host
     */
    is_ok = hostx_set_window_bounding_rectangles
                                (pair->remote,
                                 rects,
                                 RegionNumRects (&a_win->clipList)) ;
    is_ok = TRUE ;

out:
    free(rects) ;
    rects = NULL ;

    EPHYR_LOG ("leave. is_ok:%d\n", is_ok) ;
    /*do cleanup here*/
}

/**
 * Duplicates a visual of a_screen
 * In screen a_screen, for depth a_depth, find a visual which
 * bitsPerRGBValue and colormap size equal
 * a_bits_per_rgb_values and a_colormap_entries.
 * The ID of that duplicated visual is set to a_new_id.
 * That duplicated visual is then added to the list of visuals
 * of the screen.
 */
static Bool
EphyrDuplicateVisual (unsigned int a_screen,
                      short a_depth,
                      short a_class,
                      short a_bits_per_rgb_values,
                      short a_colormap_entries,
                      unsigned int a_red_mask,
                      unsigned int a_green_mask,
                      unsigned int a_blue_mask,
                      unsigned int a_new_id)
{
    Bool is_ok = FALSE, found_visual=FALSE, found_depth=FALSE ;
    ScreenPtr screen=NULL ;
    VisualRec new_visual, *new_visuals=NULL ;
    int i=0 ;

    EPHYR_LOG ("enter\n") ; 
    if (a_screen >= screenInfo.numScreens) {
        EPHYR_LOG_ERROR ("bad screen number\n") ;
        goto out;
    }
    memset (&new_visual, 0, sizeof (VisualRec)) ;

    /*get the screen pointed to by a_screen*/
    screen = screenInfo.screens[a_screen] ;
    EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ;

    /*
     * In that screen, first look for an existing visual that has the
     * same characteristics as those passed in parameter
     * to this function and copy it.
     */
    for (i=0; i < screen->numVisuals; i++) {
        if (screen->visuals[i].bitsPerRGBValue == a_bits_per_rgb_values &&
            screen->visuals[i].ColormapEntries == a_colormap_entries ) {
            /*copy the visual found*/
            memcpy (&new_visual, &screen->visuals[i], sizeof (new_visual)) ;
            new_visual.vid = a_new_id ;
            new_visual.class = a_class ;
            new_visual.redMask = a_red_mask ;
            new_visual.greenMask = a_green_mask ;
            new_visual.blueMask = a_blue_mask ;
            found_visual = TRUE ;
            EPHYR_LOG ("found a visual that matches visual id: %d\n",
                       a_new_id) ;
            break;
        }
    }
    if (!found_visual) {
        EPHYR_LOG ("did not find any visual matching %d\n", a_new_id) ;
        goto out ;
    }
    /*
     * be prepare to extend screen->visuals to add new_visual to it
     */
    new_visuals = calloc(screen->numVisuals+1, sizeof (VisualRec)) ;
    memmove (new_visuals,
             screen->visuals,
             screen->numVisuals*sizeof (VisualRec)) ;
    memmove (&new_visuals[screen->numVisuals],
             &new_visual,
             sizeof (VisualRec)) ;
    /*
     * Now, in that same screen, update the screen->allowedDepths member.
     * In that array, each element represents the visuals applicable to
     * a given depth. So we need to add an entry matching the new visual
     * that we are going to add to screen->visuals
     */
    for (i=0; i<screen->numDepths; i++) {
        VisualID *vids=NULL;
        DepthPtr cur_depth=NULL ;
        /*find the entry matching a_depth*/
        if (screen->allowedDepths[i].depth != a_depth)
            continue ;
        cur_depth = &screen->allowedDepths[i];
        /*
         * extend the list of visual IDs in that entry,
         * so to add a_new_id in there.
         */
        vids = realloc(cur_depth->vids,
                         (cur_depth->numVids+1)*sizeof (VisualID));
        if (!vids) {
            EPHYR_LOG_ERROR ("failed to realloc numids\n") ;
            goto out ;
        }
        vids[cur_depth->numVids] = a_new_id ;
        /*
         * Okay now commit our change.
         * Do really update screen->allowedDepths[i]
         */
        cur_depth->numVids++ ;
        cur_depth->vids = vids ;
        found_depth=TRUE;
    }
    if (!found_depth) {
        EPHYR_LOG_ERROR ("failed to update screen[%d]->allowedDepth\n",
                         a_screen) ;
        goto out ;
    }
    /*
     * Commit our change to screen->visuals
     */
    free(screen->visuals) ;
    screen->visuals = new_visuals ;
    screen->numVisuals++ ;
    new_visuals = NULL ;

    is_ok = TRUE ;
out:
    free(new_visuals) ;
    new_visuals = NULL ;

    EPHYR_LOG ("leave\n") ; 
    return is_ok ;
}

/**
 * Duplicates the visuals of the host X server.
 * This is necessary to have visuals that have the same
 * ID as those of the host X. It is important to have that for
 * GLX.
 */
static Bool
EphyrMirrorHostVisuals (ScreenPtr a_screen)
{
    Bool is_ok=FALSE;
    EphyrHostVisualInfo  *visuals=NULL;
    int nb_visuals=0, i=0;

    EPHYR_LOG ("enter\n") ;
    if (!hostx_get_visuals_info (&visuals, &nb_visuals)) {
        EPHYR_LOG_ERROR ("failed to get host visuals\n") ;
        goto out ;
    }
    for (i=0; i<nb_visuals; i++) {
        if (!EphyrDuplicateVisual (a_screen->myNum,
                                   visuals[i].depth,
                                   visuals[i].class,
                                   visuals[i].bits_per_rgb,
                                   visuals[i].colormap_size,
                                   visuals[i].red_mask,
                                   visuals[i].green_mask,
                                   visuals[i].blue_mask,
                                   visuals[i].visualid)) {
            EPHYR_LOG_ERROR ("failed to duplicate host visual %d\n",
                             (int)visuals[i].visualid) ;
        }
    }

    is_ok = TRUE ;
out:
    EPHYR_LOG ("leave\n") ;
    return is_ok;
}


static int
ProcXF86DRIQueryVersion (register ClientPtr client)
{
    xXF86DRIQueryVersionReply rep;
    register int n;
    REQUEST_SIZE_MATCH(xXF86DRIQueryVersionReq);

    EPHYR_LOG ("enter\n") ;

    rep.type = X_Reply;
    rep.length = 0;
    rep.sequenceNumber = client->sequence;
    rep.majorVersion = SERVER_XF86DRI_MAJOR_VERSION;
    rep.minorVersion = SERVER_XF86DRI_MINOR_VERSION;
    rep.patchVersion = SERVER_XF86DRI_PATCH_VERSION;
    if (client->swapped) {
    	swaps(&rep.sequenceNumber, n);
    	swapl(&rep.length, n);
	swaps(&rep.majorVersion, n);
	swaps(&rep.minorVersion, n);
	swapl(&rep.patchVersion, n);
    }
    WriteToClient(client, sizeof(xXF86DRIQueryVersionReply), (char *)&rep);
    EPHYR_LOG ("leave\n") ;
    return Success;
}

static int
ProcXF86DRIQueryDirectRenderingCapable (register ClientPtr client)
{
    xXF86DRIQueryDirectRenderingCapableReply	rep;
    Bool isCapable;
    register int n;
    REQUEST(xXF86DRIQueryDirectRenderingCapableReq);
    REQUEST_SIZE_MATCH(xXF86DRIQueryDirectRenderingCapableReq);

    EPHYR_LOG ("enter\n") ;
    if (stuff->screen >= screenInfo.numScreens) {
	client->errorValue = stuff->screen;
	return BadValue;
    }

    rep.type = X_Reply;
    rep.length = 0;
    rep.sequenceNumber = client->sequence;

    if (!ephyrDRIQueryDirectRenderingCapable (stuff->screen, &isCapable)) {
        return BadValue;
    }
    rep.isCapable = isCapable;

    if (!LocalClient(client) || client->swapped)
	rep.isCapable = 0;

    if (client->swapped) {
    	swaps(&rep.sequenceNumber, n);
    	swapl(&rep.length, n);
    }

    WriteToClient(client, sizeof(xXF86DRIQueryDirectRenderingCapableReply), (char *)&rep);
    EPHYR_LOG ("leave\n") ;

    return Success;
}

static int
ProcXF86DRIOpenConnection (register ClientPtr client)
{
    xXF86DRIOpenConnectionReply rep;
    drm_handle_t			hSAREA;
    char*			busIdString = NULL;
    REQUEST(xXF86DRIOpenConnectionReq);
    REQUEST_SIZE_MATCH(xXF86DRIOpenConnectionReq);

    EPHYR_LOG ("enter\n") ;
    if (stuff->screen >= screenInfo.numScreens) {
	client->errorValue = stuff->screen;
	return BadValue;
    }

    if (!ephyrDRIOpenConnection(stuff->screen,
                                &hSAREA,
                                &busIdString)) {
        return BadValue;
    }

    rep.type = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.busIdStringLength = 0;
    if (busIdString)
	rep.busIdStringLength = strlen(busIdString);
    rep.length = bytes_to_int32(SIZEOF(xXF86DRIOpenConnectionReply) - SIZEOF(xGenericReply) +
                  pad_to_int32(rep.busIdStringLength));

    rep.hSAREALow  = (CARD32)(hSAREA & 0xffffffff);
#if defined(LONG64) && !defined(__linux__)
    rep.hSAREAHigh = (CARD32)(hSAREA >> 32);
#else
    rep.hSAREAHigh = 0;
#endif

    WriteToClient(client, sizeof(xXF86DRIOpenConnectionReply), (char *)&rep);
    if (rep.busIdStringLength)
        WriteToClient(client, rep.busIdStringLength, busIdString);
    free(busIdString);
    EPHYR_LOG ("leave\n") ;
    return Success;
}

static int
ProcXF86DRIAuthConnection  (register ClientPtr client)
{
    xXF86DRIAuthConnectionReply rep;
    REQUEST(xXF86DRIAuthConnectionReq);
    REQUEST_SIZE_MATCH(xXF86DRIAuthConnectionReq);

    EPHYR_LOG ("enter\n") ;
    if (stuff->screen >= screenInfo.numScreens) {
	client->errorValue = stuff->screen;
	return BadValue;
    }

    rep.type = X_Reply;
    rep.length = 0;
    rep.sequenceNumber = client->sequence;
    rep.authenticated = 1;

    if (!ephyrDRIAuthConnection (stuff->screen, stuff->magic)) {
        ErrorF("Failed to authenticate %lu\n", (unsigned long)stuff->magic);
        rep.authenticated = 0;
    }
    WriteToClient(client, sizeof(xXF86DRIAuthConnectionReply), (char *)&rep);
    EPHYR_LOG ("leave\n") ;
    return Success;
}

static int
ProcXF86DRICloseConnection (register ClientPtr client)
{
    REQUEST(xXF86DRICloseConnectionReq);
    REQUEST_SIZE_MATCH(xXF86DRICloseConnectionReq);
    EPHYR_LOG ("enter\n") ;
    if (stuff->screen >= screenInfo.numScreens) {
        client->errorValue = stuff->screen;
        return BadValue;
    }

    /*
    DRICloseConnection( screenInfo.screens[stuff->screen]);
    */

    EPHYR_LOG ("leave\n") ;
    return Success;
}

static int
ProcXF86DRIGetClientDriverName (register ClientPtr client)
{
    xXF86DRIGetClientDriverNameReply	rep;
    char* clientDriverName;
    REQUEST(xXF86DRIGetClientDriverNameReq);
    REQUEST_SIZE_MATCH(xXF86DRIGetClientDriverNameReq);

    EPHYR_LOG ("enter\n") ;
    if (stuff->screen >= screenInfo.numScreens) {
	client->errorValue = stuff->screen;
	return BadValue;
    }

    ephyrDRIGetClientDriverName (stuff->screen,
                                 (int *)&rep.ddxDriverMajorVersion,
                                 (int *)&rep.ddxDriverMinorVersion,
                                 (int *)&rep.ddxDriverPatchVersion,
                                 &clientDriverName);

    rep.type = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.clientDriverNameLength = 0;
    if (clientDriverName)
	rep.clientDriverNameLength = strlen(clientDriverName);
    rep.length = bytes_to_int32(SIZEOF(xXF86DRIGetClientDriverNameReply) -
			SIZEOF(xGenericReply) +
			pad_to_int32(rep.clientDriverNameLength));

    WriteToClient(client, 
	sizeof(xXF86DRIGetClientDriverNameReply), (char *)&rep);
    if (rep.clientDriverNameLength)
	WriteToClient(client, 
                      rep.clientDriverNameLength, 
                      clientDriverName);
    EPHYR_LOG ("leave\n") ;
    return Success;
}

static int
ProcXF86DRICreateContext (register ClientPtr client)
{
    xXF86DRICreateContextReply	rep;
    ScreenPtr pScreen;
    VisualPtr visual;
    int i=0;
    unsigned long context_id=0;
    REQUEST(xXF86DRICreateContextReq);
    REQUEST_SIZE_MATCH(xXF86DRICreateContextReq);

    EPHYR_LOG ("enter\n") ;
    if (stuff->screen >= screenInfo.numScreens) {
	client->errorValue = stuff->screen;
	return BadValue;
    }

    rep.type = X_Reply;
    rep.length = 0;
    rep.sequenceNumber = client->sequence;

    pScreen = screenInfo.screens[stuff->screen];
    visual = pScreen->visuals;

    /* Find the requested X visual */
    for (i = 0; i < pScreen->numVisuals; i++, visual++)
	if (visual->vid == stuff->visual)
	    break;
    if (i == pScreen->numVisuals) {
	/* No visual found */
	return BadValue;
    }

    context_id = stuff->context ;
    if (!ephyrDRICreateContext (stuff->screen,
                                stuff->visual,
                                &context_id,
                                (drm_context_t *)&rep.hHWContext)) {
        return BadValue;
    }

    WriteToClient(client, sizeof(xXF86DRICreateContextReply), (char *)&rep);
    EPHYR_LOG ("leave\n") ;
    return Success;
}

static int
ProcXF86DRIDestroyContext (register ClientPtr client)
{
    REQUEST(xXF86DRIDestroyContextReq);
    REQUEST_SIZE_MATCH(xXF86DRIDestroyContextReq);
    EPHYR_LOG ("enter\n") ;

    if (stuff->screen >= screenInfo.numScreens) {
        client->errorValue = stuff->screen;
        return BadValue;
    }

   if (!ephyrDRIDestroyContext (stuff->screen, stuff->context)) {
       return BadValue;
   }

    EPHYR_LOG ("leave\n") ;
    return Success;
}

static Bool
getWindowVisual (const WindowPtr a_win,
                 VisualPtr *a_visual)
{
    int i=0, visual_id=0 ;
    EPHYR_RETURN_VAL_IF_FAIL (a_win
                              && a_win->drawable.pScreen
                              && a_win->drawable.pScreen->visuals,
                              FALSE) ;

    visual_id = wVisual (a_win) ;
    for (i=0; i < a_win->drawable.pScreen->numVisuals; i++) {
        if (a_win->drawable.pScreen->visuals[i].vid == visual_id) {
            *a_visual = &a_win->drawable.pScreen->visuals[i] ;
            return TRUE ;
        }
    }
    return FALSE ;
}


#define NUM_WINDOW_PAIRS 256
static EphyrWindowPair window_pairs[NUM_WINDOW_PAIRS] ;

static Bool
appendWindowPairToList (WindowPtr a_local,
                        int a_remote)
{
    int i=0 ;

    EPHYR_RETURN_VAL_IF_FAIL (a_local, FALSE) ;

    EPHYR_LOG ("(local,remote):(%p, %d)\n", a_local, a_remote) ;

    for (i=0; i < NUM_WINDOW_PAIRS; i++) {
        if (window_pairs[i].local == NULL) {
            window_pairs[i].local = a_local ;
            window_pairs[i].remote = a_remote ;
            return TRUE ;
        }
    }
    return FALSE ;
}

static Bool
findWindowPairFromLocal (WindowPtr a_local,
                         EphyrWindowPair **a_pair)
{
    int i=0 ;

    EPHYR_RETURN_VAL_IF_FAIL (a_pair && a_local, FALSE) ;

    for (i=0; i < NUM_WINDOW_PAIRS; i++) {
        if (window_pairs[i].local == a_local) {
            *a_pair = &window_pairs[i] ;
            EPHYR_LOG ("found (%p, %d)\n",
                       (*a_pair)->local,
                       (*a_pair)->remote) ;
            return TRUE ;
        }
    }
    return FALSE ;
}

Bool
findWindowPairFromRemote (int a_remote,
                          EphyrWindowPair **a_pair)
{
    int i=0 ;

    EPHYR_RETURN_VAL_IF_FAIL (a_pair, FALSE) ;

    for (i=0; i < NUM_WINDOW_PAIRS; i++) {
        if (window_pairs[i].remote == a_remote) {
            *a_pair = &window_pairs[i] ;
            EPHYR_LOG ("found (%p, %d)\n",
                       (*a_pair)->local,
                       (*a_pair)->remote) ;
            return TRUE ;
        }
    }
    return FALSE ;
}

static Bool
createHostPeerWindow (const WindowPtr a_win,
                      int *a_peer_win)
{
    Bool is_ok=FALSE ;
    VisualPtr visual=NULL;
    EphyrBox geo ;

    EPHYR_RETURN_VAL_IF_FAIL (a_win && a_peer_win, FALSE) ;
    EPHYR_RETURN_VAL_IF_FAIL (a_win->drawable.pScreen,
                              FALSE) ;

    EPHYR_LOG ("enter. a_win '%p'\n", a_win) ;
    if (!getWindowVisual (a_win, &visual)) {
        EPHYR_LOG_ERROR ("failed to get window visual\n") ;
        goto out ;
    }
    if (!visual) {
        EPHYR_LOG_ERROR ("failed to create visual\n") ;
        goto out ;
    }
    memset (&geo, 0, sizeof (geo)) ;
    geo.x = a_win->drawable.x ;
    geo.y = a_win->drawable.y ;
    geo.width = a_win->drawable.width ;
    geo.height = a_win->drawable.height ;
    if (!hostx_create_window (a_win->drawable.pScreen->myNum,
                              &geo, visual->vid, a_peer_win)) {
        EPHYR_LOG_ERROR ("failed to create host peer window\n") ;
        goto out ;
    }
    if (!appendWindowPairToList (a_win, *a_peer_win)) {
        EPHYR_LOG_ERROR ("failed to append window to pair list\n") ;
        goto out ;
    }
    is_ok = TRUE ;
out:
    EPHYR_LOG ("leave:remote win%d\n", *a_peer_win) ;
    return is_ok ;
}

static Bool
destroyHostPeerWindow (const WindowPtr a_win)
{
    Bool is_ok = FALSE ;
    EphyrWindowPair *pair=NULL ;
    EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ;

    EPHYR_LOG ("enter\n") ;

    if (!findWindowPairFromLocal (a_win, &pair) || !pair) {
        EPHYR_LOG_ERROR ("failed to find peer to local window\n") ;
        goto out;
    }
    hostx_destroy_window (pair->remote) ;
    is_ok = TRUE ;

out:
    EPHYR_LOG ("leave\n") ;
    return is_ok;
}

static int
ProcXF86DRICreateDrawable (ClientPtr client)
{
    xXF86DRICreateDrawableReply	rep;
    DrawablePtr drawable=NULL;
    WindowPtr window=NULL ;
    EphyrWindowPair *pair=NULL ;
    EphyrDRIWindowPrivPtr win_priv=NULL;
    int rc=0, remote_win=0;
    REQUEST(xXF86DRICreateDrawableReq);
    REQUEST_SIZE_MATCH(xXF86DRICreateDrawableReq);

    EPHYR_LOG ("enter\n") ;
    if (stuff->screen >= screenInfo.numScreens) {
        client->errorValue = stuff->screen;
        return BadValue;
    }

    rep.type = X_Reply;
    rep.length = 0;
    rep.sequenceNumber = client->sequence;

    rc = dixLookupDrawable (&drawable, stuff->drawable, client, 0,
                            DixReadAccess);
    if (rc != Success)
        return rc;
    if (drawable->type != DRAWABLE_WINDOW) {
        EPHYR_LOG_ERROR ("non drawable windows are not yet supported\n") ;
        return BadImplementation ;
    }
    EPHYR_LOG ("lookedup drawable %p\n", drawable) ;
    window = (WindowPtr)drawable;
    if (findWindowPairFromLocal (window, &pair) && pair) {
        remote_win = pair->remote ;
        EPHYR_LOG ("found window '%p' paire with remote '%d'\n",
                   window, remote_win) ;
    } else if (!createHostPeerWindow (window, &remote_win)) {
        EPHYR_LOG_ERROR ("failed to create host peer window\n") ;
        return BadAlloc ;
    }

    if (!ephyrDRICreateDrawable (stuff->screen,
                                 remote_win,
                                 (drm_drawable_t *)&rep.hHWDrawable)) {
        EPHYR_LOG_ERROR ("failed to create dri drawable\n") ;
        return BadValue;
    }

    win_priv = GET_EPHYR_DRI_WINDOW_PRIV (window) ;
    if (!win_priv) {
        win_priv = calloc(1, sizeof (EphyrDRIWindowPrivRec)) ;
        if (!win_priv) {
            EPHYR_LOG_ERROR ("failed to allocate window private\n") ;
            return BadAlloc ;
        }
	dixSetPrivate(&window->devPrivates, ephyrDRIWindowKey, win_priv);
        EPHYR_LOG ("paired window '%p' with remote '%d'\n",
                   window, remote_win) ;
    }

    WriteToClient(client, sizeof(xXF86DRICreateDrawableReply), (char *)&rep);
    EPHYR_LOG ("leave\n") ;
    return Success;
}

static int
ProcXF86DRIDestroyDrawable (register ClientPtr client)
{
    DrawablePtr drawable=NULL;
    WindowPtr window=NULL;
    EphyrWindowPair *pair=NULL;
    int rc=0;
    REQUEST(xXF86DRIDestroyDrawableReq);
    REQUEST_SIZE_MATCH(xXF86DRIDestroyDrawableReq);

    EPHYR_LOG ("enter\n") ;
    if (stuff->screen >= screenInfo.numScreens) {
        client->errorValue = stuff->screen;
        return BadValue;
    }

    rc = dixLookupDrawable(&drawable,
                           stuff->drawable,
                           client,
                           0,
                           DixReadAccess);
    if (rc != Success)
        return rc;
    if (drawable->type != DRAWABLE_WINDOW) {
        EPHYR_LOG_ERROR ("non drawable windows are not yet supported\n") ;
        return BadImplementation ;
    }
    window = (WindowPtr)drawable;
    if (!findWindowPairFromLocal (window, &pair) && pair) {
        EPHYR_LOG_ERROR ("failed to find pair window\n") ;
        return BadImplementation;
    }
    if (!ephyrDRIDestroyDrawable(stuff->screen,
                                 pair->remote/*drawable in host x*/)) {
        EPHYR_LOG_ERROR ("failed to destroy dri drawable\n") ;
        return BadImplementation;
    }
    pair->local=NULL ;
    pair->remote=0;

    EPHYR_LOG ("leave\n") ;
    return Success;
}

static int
ProcXF86DRIGetDrawableInfo (register ClientPtr client)
{
    xXF86DRIGetDrawableInfoReply rep;
    DrawablePtr drawable;
    WindowPtr window=NULL;
    EphyrWindowPair *pair=NULL;
    int X=0, Y=0, W=0, H=0, backX=0, backY=0, rc=0, i=0;
    drm_clip_rect_t *clipRects=NULL;
    drm_clip_rect_t *backClipRects=NULL;
    REQUEST(xXF86DRIGetDrawableInfoReq);
    REQUEST_SIZE_MATCH(xXF86DRIGetDrawableInfoReq);

    EPHYR_LOG ("enter\n") ;
    memset (&rep, 0, sizeof (rep)) ;
    if (stuff->screen >= screenInfo.numScreens) {
        client->errorValue = stuff->screen;
        return BadValue;
    }

    rep.type = X_Reply;
    rep.length = 0;
    rep.sequenceNumber = client->sequence;

    rc = dixLookupDrawable(&drawable, stuff->drawable, client, 0,
                           DixReadAccess);
    if (rc != Success || !drawable) {
        EPHYR_LOG_ERROR ("could not get drawable\n") ;
        return rc;
    }

    if (drawable->type != DRAWABLE_WINDOW) {
        EPHYR_LOG_ERROR ("non windows type drawables are not yes supported\n") ;
        return BadImplementation ;
    }
    window = (WindowPtr)drawable ;
    memset (&pair, 0, sizeof (pair)) ;
    if (!findWindowPairFromLocal (window, &pair) || !pair) {
        EPHYR_LOG_ERROR ("failed to find remote peer drawable\n") ;
        return BadMatch ;
    }
    EPHYR_LOG ("clip list of xephyr gl drawable:\n") ;
    for (i=0; i < RegionNumRects (&window->clipList); i++) {
        EPHYR_LOG ("x1:%d, y1:%d, x2:%d, y2:%d\n",
                   RegionRects (&window->clipList)[i].x1,
                   RegionRects (&window->clipList)[i].y1,
                   RegionRects (&window->clipList)[i].x2,
                   RegionRects (&window->clipList)[i].y2) ;
    }

    if (!ephyrDRIGetDrawableInfo (stuff->screen,
                                  pair->remote/*the drawable in hostx*/,
                                  (unsigned int*)&rep.drawableTableIndex,
                                  (unsigned int*)&rep.drawableTableStamp,
                                  (int*)&X,
                                  (int*)&Y,
                                  (int*)&W,
                                  (int*)&H,
                                  (int*)&rep.numClipRects,
                                  &clipRects,
                                  &backX,
                                  &backY,
                                  (int*)&rep.numBackClipRects,
                                  &backClipRects)) {
        return BadValue;
    }
    EPHYR_LOG ("num clip rects:%d, num back clip rects:%d\n",
               (int)rep.numClipRects, (int)rep.numBackClipRects) ;

    rep.drawableX = X;
    rep.drawableY = Y;
    rep.drawableWidth = W;
    rep.drawableHeight = H;
    rep.length = (SIZEOF(xXF86DRIGetDrawableInfoReply) -
                  SIZEOF(xGenericReply));

    rep.backX = backX;
    rep.backY = backY;


    if (rep.numClipRects) {
        if (clipRects) {
            ScreenPtr pScreen = screenInfo.screens[stuff->screen];
            int i=0;
            EPHYR_LOG ("clip list of host gl drawable:\n") ;
            for (i = 0; i < rep.numClipRects; i++) {
                clipRects[i].x1 = max (clipRects[i].x1, 0);
                clipRects[i].y1 = max (clipRects[i].y1, 0);
                clipRects[i].x2 = min (clipRects[i].x2,
                                       pScreen->width + clipRects[i].x1) ;
                clipRects[i].y2 = min (clipRects[i].y2,
                                       pScreen->width + clipRects[i].y1) ;

                EPHYR_LOG ("x1:%d, y1:%d, x2:%d, y2:%d\n",
                           clipRects[i].x1, clipRects[i].y1,
                           clipRects[i].x2, clipRects[i].y2) ;
            }
        } else {
            rep.numClipRects = 0;
        }
    } else {
        EPHYR_LOG ("got zero host gl drawable clipping rects\n") ;
    }
    rep.length += sizeof(drm_clip_rect_t) * rep.numClipRects;
    backClipRects = clipRects ;
    rep.numBackClipRects = rep.numClipRects ;
    if (rep.numBackClipRects)
        rep.length += sizeof(drm_clip_rect_t) * rep.numBackClipRects;
    EPHYR_LOG ("num host clip rects:%d\n", (int)rep.numClipRects) ;
    EPHYR_LOG ("num host back clip rects:%d\n", (int)rep.numBackClipRects) ;

    rep.length = bytes_to_int32(rep.length);

    WriteToClient(client, sizeof(xXF86DRIGetDrawableInfoReply), (char *)&rep);

    if (rep.numClipRects) {
        WriteToClient(client,
                      sizeof(drm_clip_rect_t) * rep.numClipRects,
                      (char *)clipRects);
    }

    if (rep.numBackClipRects) {
        WriteToClient(client,
                      sizeof(drm_clip_rect_t) * rep.numBackClipRects,
                      (char *)backClipRects);
    }
    free(clipRects);
    clipRects = NULL ;

    EPHYR_LOG ("leave\n") ;

    return Success;
}

static int
ProcXF86DRIGetDeviceInfo (register ClientPtr client)
{
    xXF86DRIGetDeviceInfoReply	rep;
    drm_handle_t hFrameBuffer;
    void *pDevPrivate;
    REQUEST(xXF86DRIGetDeviceInfoReq);
    REQUEST_SIZE_MATCH(xXF86DRIGetDeviceInfoReq);

    EPHYR_LOG ("enter\n") ;
    if (stuff->screen >= screenInfo.numScreens) {
        client->errorValue = stuff->screen;
        return BadValue;
    }

    rep.type = X_Reply;
    rep.length = 0;
    rep.sequenceNumber = client->sequence;

    if (!ephyrDRIGetDeviceInfo (stuff->screen,
                &hFrameBuffer,
                (int*)&rep.framebufferOrigin,
                (int*)&rep.framebufferSize,
                (int*)&rep.framebufferStride,
                (int*)&rep.devPrivateSize,
                &pDevPrivate)) {
        return BadValue;
    }

    rep.hFrameBufferLow  = (CARD32)(hFrameBuffer & 0xffffffff);
#if defined(LONG64) && !defined(__linux__)
    rep.hFrameBufferHigh = (CARD32)(hFrameBuffer >> 32);
#else
    rep.hFrameBufferHigh = 0;
#endif

    rep.length = 0;
    if (rep.devPrivateSize) {
        rep.length = bytes_to_int32(SIZEOF(xXF86DRIGetDeviceInfoReply) -
                SIZEOF(xGenericReply) +
                pad_to_int32(rep.devPrivateSize));
    }

    WriteToClient(client, sizeof(xXF86DRIGetDeviceInfoReply), (char *)&rep);
    if (rep.length) {
        WriteToClient(client, rep.devPrivateSize, (char *)pDevPrivate);
    }
    EPHYR_LOG ("leave\n") ;
    return Success;
}

static int
ProcXF86DRIDispatch (register ClientPtr	client)
{
    REQUEST(xReq);
    EPHYR_LOG ("enter\n") ;

    switch (stuff->data)
    {
        case X_XF86DRIQueryVersion: {
                EPHYR_LOG ("leave\n") ;
                return ProcXF86DRIQueryVersion(client);
        }
        case X_XF86DRIQueryDirectRenderingCapable: {
                EPHYR_LOG ("leave\n") ;
                return ProcXF86DRIQueryDirectRenderingCapable(client);
        }
    }

    if (!LocalClient(client))
        return DRIErrorBase + XF86DRIClientNotLocal;

    switch (stuff->data)
    {
        case X_XF86DRIOpenConnection: {
            EPHYR_LOG ("leave\n") ;
            return ProcXF86DRIOpenConnection(client);
        }
        case X_XF86DRICloseConnection: {
            EPHYR_LOG ("leave\n") ;
            return ProcXF86DRICloseConnection(client);
        }
        case X_XF86DRIGetClientDriverName: {
            EPHYR_LOG ("leave\n") ;
            return ProcXF86DRIGetClientDriverName(client);
        }
        case X_XF86DRICreateContext: {
            EPHYR_LOG ("leave\n") ;
            return ProcXF86DRICreateContext(client);
        }
        case X_XF86DRIDestroyContext: {
            EPHYR_LOG ("leave\n") ;
            return ProcXF86DRIDestroyContext(client);
        }
        case X_XF86DRICreateDrawable: {
            EPHYR_LOG ("leave\n") ;
            return ProcXF86DRICreateDrawable(client);
        }
        case X_XF86DRIDestroyDrawable: {
            EPHYR_LOG ("leave\n") ;
            return ProcXF86DRIDestroyDrawable(client);
        }
        case X_XF86DRIGetDrawableInfo: {
            EPHYR_LOG ("leave\n") ;
            return ProcXF86DRIGetDrawableInfo(client);
        }
        case X_XF86DRIGetDeviceInfo: {
            EPHYR_LOG ("leave\n") ;
            return ProcXF86DRIGetDeviceInfo(client);
        }
        case X_XF86DRIAuthConnection: {
            EPHYR_LOG ("leave\n") ;
            return ProcXF86DRIAuthConnection(client);
        }
            /* {Open,Close}FullScreen are deprecated now */
        default: {
            EPHYR_LOG ("leave\n") ;
            return BadRequest;
        }
    }
}

static int
SProcXF86DRIQueryVersion (register ClientPtr	client)
{
    register int n;
    REQUEST(xXF86DRIQueryVersionReq);
    swaps(&stuff->length, n);
    return ProcXF86DRIQueryVersion(client);
}

static int
SProcXF86DRIQueryDirectRenderingCapable (register ClientPtr client)
{
    register int n;
    REQUEST(xXF86DRIQueryDirectRenderingCapableReq);
    swaps(&stuff->length, n);
    swapl(&stuff->screen, n);
    return ProcXF86DRIQueryDirectRenderingCapable(client);
}

static int
SProcXF86DRIDispatch (register ClientPtr client)
{
    REQUEST(xReq);

    EPHYR_LOG ("enter\n") ;
    /*
     * Only local clients are allowed DRI access, but remote clients still need
     * these requests to find out cleanly.
     */
    switch (stuff->data)
    {
        case X_XF86DRIQueryVersion: {
            EPHYR_LOG ("leave\n") ;
            return SProcXF86DRIQueryVersion(client);
        }
        case X_XF86DRIQueryDirectRenderingCapable: {
            EPHYR_LOG ("leave\n") ;
            return SProcXF86DRIQueryDirectRenderingCapable(client);
        }
        default: {
            EPHYR_LOG ("leave\n") ;
            return DRIErrorBase + XF86DRIClientNotLocal;
        }
    }
}

Bool
ephyrDRIExtensionInit (ScreenPtr a_screen)
{
    Bool is_ok=FALSE ;
    ExtensionEntry* extEntry=NULL;
    EphyrDRIScreenPrivPtr screen_priv=NULL ;

    EPHYR_LOG ("enter\n") ;
    if (!hostx_has_dri ()) {
        EPHYR_LOG ("host does not have DRI extension\n") ;
        goto out ;
    }
    EPHYR_LOG ("host X does have DRI extension\n") ;
    if (!hostx_has_xshape ()) {
        EPHYR_LOG ("host does not have XShape extension\n") ;
        goto out ;
    }
    EPHYR_LOG ("host X does have XShape extension\n") ;

#ifdef XF86DRI_EVENTS
    EventType = CreateNewResourceType (XF86DRIFreeEvents, "DRIEvents");
    if (!EventType) {
        EPHYR_LOG_ERROR ("failed to register DRI event resource type\n") ;
        goto out ;
    }
#endif

    if ((extEntry = AddExtension(XF86DRINAME,
				 XF86DRINumberEvents,
				 XF86DRINumberErrors,
				 ProcXF86DRIDispatch,
				 SProcXF86DRIDispatch,
				 NULL,
				 StandardMinorOpcode))) {
	DRIReqCode = (unsigned char)extEntry->base;
	DRIErrorBase = extEntry->errorBase;
    } else {
        EPHYR_LOG_ERROR ("failed to register DRI extension\n") ;
        goto out ;
    }
    if (!dixRegisterPrivateKey(&ephyrDRIScreenKeyRec, PRIVATE_SCREEN, 0))
        goto out ;
    if (!dixRegisterPrivateKey(&ephyrDRIWindowKeyRec, PRIVATE_WINDOW, 0))
        goto out ;
    screen_priv = calloc(1, sizeof (EphyrDRIScreenPrivRec)) ;
    if (!screen_priv) {
        EPHYR_LOG_ERROR ("failed to allocate screen_priv\n") ;
        goto out ;
    }
    dixSetPrivate(&a_screen->devPrivates, ephyrDRIScreenKey, screen_priv);

    if (!ephyrDRIScreenInit (a_screen)) {
        EPHYR_LOG_ERROR ("ephyrDRIScreenInit() failed\n") ;
        goto out ;
    }
    EphyrMirrorHostVisuals (a_screen) ;
    is_ok=TRUE ;
out:
    EPHYR_LOG ("leave\n") ;
    return is_ok ;
}
