/*
 * 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.
 *
 * Authors:
 *    Dodji Seketeli <dodji@openedhand.com>
 */
#ifdef HAVE_CONFIG_H
#include <kdrive-config.h>
#endif

#include "extnsionst.h"
#include "ephyrglxext.h"
#include "ephyrhostglx.h"
#define _HAVE_XALLOC_DECLS
#include "ephyrlog.h"
#include <GL/glxproto.h>
#include "glx/glxserver.h"
#include "glx/indirect_table.h"
#include "glx/indirect_util.h"
#include "glx/unpack.h"
#include "hostx.h"


#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif


int ephyrGLXQueryVersion (__GLXclientState *cl, GLbyte *pc) ;
int ephyrGLXQueryVersionSwap (__GLXclientState *cl, GLbyte *pc) ;
int ephyrGLXGetVisualConfigs (__GLXclientState *cl, GLbyte *pc) ;
int ephyrGLXGetVisualConfigsSwap (__GLXclientState *cl, GLbyte *pc) ;
int ephyrGLXClientInfo(__GLXclientState *cl, GLbyte *pc) ;
int ephyrGLXClientInfoSwap(__GLXclientState *cl, GLbyte *pc) ;
int ephyrGLXQueryServerString(__GLXclientState *a_cl, GLbyte *a_pc) ;
int ephyrGLXQueryServerStringSwap(__GLXclientState *a_cl, GLbyte *a_pc) ;
int ephyrGLXGetFBConfigsSGIX (__GLXclientState *a_cl, GLbyte *a_pc);
int ephyrGLXGetFBConfigsSGIXSwap (__GLXclientState *a_cl, GLbyte *a_pc);
int ephyrGLXCreateContext (__GLXclientState *a_cl, GLbyte *a_pc);
int ephyrGLXCreateContextSwap (__GLXclientState *a_cl, GLbyte *a_pc);
int ephyrGLXDestroyContext (__GLXclientState *a_cl, GLbyte *a_pc) ;
int ephyrGLXDestroyContextSwap (__GLXclientState *a_cl, GLbyte *a_pc) ;
int ephyrGLXMakeCurrent (__GLXclientState *a_cl, GLbyte *a_pc) ;
int ephyrGLXMakeCurrentSwap (__GLXclientState *a_cl, GLbyte *a_pc) ;
int ephyrGLXGetString (__GLXclientState *a_cl, GLbyte *a_pc) ;
int ephyrGLXGetStringSwap (__GLXclientState *a_cl, GLbyte *a_pc) ;
int ephyrGLXGetIntegerv (__GLXclientState *a_cl, GLbyte *a_pc) ;
int ephyrGLXGetIntegervSwap (__GLXclientState *a_cl, GLbyte *a_pc) ;
int ephyrGLXIsDirect (__GLXclientState *a_cl, GLbyte *a_pc) ;
int ephyrGLXIsDirectSwap (__GLXclientState *a_cl, GLbyte *a_pc) ;

Bool
ephyrHijackGLXExtension (void)
{
    const void *(*dispatch_functions)[2];

    if (!hostx_has_glx ()) {
        EPHYR_LOG ("host X does not have GLX\n") ;
        return FALSE ;
    }
    EPHYR_LOG ("host X does have GLX\n") ;

    if (!Single_dispatch_info.dispatch_functions) {
        EPHYR_LOG_ERROR ("could not get dispatch functions table\n") ;
        return FALSE ;
    }
    /*
     * hijack some single entry point dispatch functions
     */
    dispatch_functions = Single_dispatch_info.dispatch_functions ;
    EPHYR_RETURN_VAL_IF_FAIL (dispatch_functions, FALSE) ;

    dispatch_functions[X_GLXQueryVersion][0] = ephyrGLXQueryVersion ;
    dispatch_functions[X_GLXQueryVersion][1] = ephyrGLXQueryVersionSwap ;

    dispatch_functions[X_GLXGetVisualConfigs][0] = ephyrGLXGetVisualConfigs ;
    dispatch_functions[X_GLXGetVisualConfigs][1] = ephyrGLXGetVisualConfigsSwap ;
    dispatch_functions[X_GLXClientInfo][0] = ephyrGLXClientInfo ;
    dispatch_functions[X_GLXClientInfo][1] = ephyrGLXClientInfoSwap ;

    dispatch_functions[X_GLXQueryServerString][0] = ephyrGLXQueryServerString ;
    dispatch_functions[X_GLXQueryServerString][1] =
                                                ephyrGLXQueryServerStringSwap ;

    dispatch_functions[X_GLXCreateContext][0] = ephyrGLXCreateContext ;
    dispatch_functions[X_GLXCreateContext][1] = ephyrGLXCreateContextSwap ;

    dispatch_functions[X_GLXDestroyContext][0] = ephyrGLXDestroyContext ;
    dispatch_functions[X_GLXDestroyContext][1] = ephyrGLXDestroyContextSwap ;

    dispatch_functions[X_GLXMakeCurrent][0] = ephyrGLXMakeCurrent ;
    dispatch_functions[X_GLXMakeCurrent][1] = ephyrGLXMakeCurrentSwap ;

    dispatch_functions[X_GLXIsDirect][0] = ephyrGLXIsDirect ;
    dispatch_functions[X_GLXIsDirect][1] = ephyrGLXIsDirectSwap ;

    dispatch_functions[73][0] = ephyrGLXGetString ;
    dispatch_functions[73][1] = ephyrGLXGetStringSwap ;

    dispatch_functions[61][0] = ephyrGLXGetIntegerv ;
    dispatch_functions[61][1] = ephyrGLXGetIntegervSwap ;

    /*
     * hijack some vendor priv entry point dispatch functions
     */
    dispatch_functions = VendorPriv_dispatch_info.dispatch_functions ;
    dispatch_functions[92][0] = ephyrGLXGetFBConfigsSGIX;
    dispatch_functions[92][1] = ephyrGLXGetFBConfigsSGIXSwap;
    EPHYR_LOG ("hijacked glx entry points to forward requests to host X\n") ;

    return TRUE ;
}

/*********************
 * implementation of
 * hijacked GLX entry
 * points
 ********************/

int
ephyrGLXQueryVersion(__GLXclientState *a_cl, GLbyte *a_pc)
{
    ClientPtr client = a_cl->client;
    xGLXQueryVersionReq *req = (xGLXQueryVersionReq *) a_pc;
    xGLXQueryVersionReply reply;
    int major, minor;
    int res = BadImplementation ;

    EPHYR_LOG ("enter\n") ;

    major = req->majorVersion ;
    minor = req->minorVersion ;

    if (!ephyrHostGLXQueryVersion (&major, &minor)) {
        EPHYR_LOG_ERROR ("ephyrHostGLXQueryVersion() failed\n") ;
        goto out ;
    }
    EPHYR_LOG ("major:%d, minor:%d\n",
                major, minor);
    reply.majorVersion = major ;
    reply.minorVersion = minor ;
    reply.length = 0 ;
    reply.type = X_Reply ;
    reply.sequenceNumber = client->sequence ;

    if (client->swapped) {
        __glXSwapQueryVersionReply(client, &reply);
    } else {
        WriteToClient(client, sz_xGLXQueryVersionReply, (char *)&reply);
    }

    res = Success ;
out:
    EPHYR_LOG ("leave\n") ;
    return res;
}

int
ephyrGLXQueryVersionSwap (__GLXclientState *a_cl, GLbyte *a_pc)
{
    xGLXQueryVersionReq *req = (xGLXQueryVersionReq *) a_pc;
    __GLX_DECLARE_SWAP_VARIABLES;

    __GLX_SWAP_SHORT (&req->length);
    __GLX_SWAP_INT (&req->majorVersion);
    __GLX_SWAP_INT (&req->minorVersion);
    return ephyrGLXQueryVersion (a_cl, a_pc) ;
}

static int
ephyrGLXGetVisualConfigsReal (__GLXclientState *a_cl,
                              GLbyte *a_pc,
                              Bool a_do_swap)
{
    xGLXGetVisualConfigsReq *req = (xGLXGetVisualConfigsReq *) a_pc;
    ClientPtr client = a_cl->client;
    xGLXGetVisualConfigsReply reply;
    int32_t *props_buf=NULL, num_visuals=0,
            num_props=0, res=BadImplementation, i=0,
            props_per_visual_size=0,
            props_buf_size=0;
    __GLX_DECLARE_SWAP_VARIABLES;
    __GLX_DECLARE_SWAP_ARRAY_VARIABLES;

    EPHYR_LOG ("enter\n") ;

    if (!ephyrHostGLXGetVisualConfigs (req->screen,
                                       &num_visuals,
                                       &num_props,
                                       &props_buf_size,
                                       &props_buf)) {
        EPHYR_LOG_ERROR ("ephyrHostGLXGetVisualConfigs() failed\n") ;
        goto out ;
    }
    EPHYR_LOG ("num_visuals:%d, num_props:%d\n", num_visuals, num_props) ;

    reply.numVisuals = num_visuals;
    reply.numProps = num_props;
    reply.length = (num_visuals *__GLX_SIZE_CARD32 * num_props) >> 2;
    reply.type = X_Reply;
    reply.sequenceNumber = client->sequence;

    if (a_do_swap) {
        __GLX_SWAP_SHORT(&reply.sequenceNumber);
        __GLX_SWAP_INT(&reply.length);
        __GLX_SWAP_INT(&reply.numVisuals);
        __GLX_SWAP_INT(&reply.numProps);
        __GLX_SWAP_INT_ARRAY (props_buf, num_props) ;
    }
    WriteToClient(client, sz_xGLXGetVisualConfigsReply, (char*)&reply);
    props_per_visual_size = props_buf_size/num_visuals ;
    for (i=0; i < num_visuals; i++) {
        WriteToClient (client,
                       props_per_visual_size,
                       (char*)props_buf +i*props_per_visual_size);
    }
    res = Success ;

out:
    EPHYR_LOG ("leave\n") ;
    free(props_buf) ;
    props_buf = NULL ;

    return res ;
}

static int
ephyrGLXGetFBConfigsSGIXReal (__GLXclientState *a_cl,
                              GLbyte *a_pc,
                              Bool a_do_swap)
{
    xGLXGetFBConfigsSGIXReq *req = (xGLXGetFBConfigsSGIXReq *)a_pc;
    ClientPtr client = a_cl->client;
    xGLXGetVisualConfigsReply reply;
    int32_t *props_buf=NULL, num_visuals=0,
            num_props=0, res=BadImplementation, i=0,
            props_per_visual_size=0,
            props_buf_size=0;
    __GLX_DECLARE_SWAP_VARIABLES;
    __GLX_DECLARE_SWAP_ARRAY_VARIABLES;

    EPHYR_LOG ("enter\n") ;

    if (!ephyrHostGLXVendorPrivGetFBConfigsSGIX (req->screen,
                                                 &num_visuals,
                                                 &num_props,
                                                 &props_buf_size,
                                                 &props_buf)) {
        EPHYR_LOG_ERROR ("ephyrHostGLXGetVisualConfigs() failed\n") ;
        goto out ;
    }
    EPHYR_LOG ("num_visuals:%d, num_props:%d\n", num_visuals, num_props) ;

    reply.numVisuals = num_visuals;
    reply.numProps = num_props;
    reply.length = props_buf_size >> 2;
    reply.type = X_Reply;
    reply.sequenceNumber = client->sequence;

    if (a_do_swap) {
        __GLX_SWAP_SHORT(&reply.sequenceNumber);
        __GLX_SWAP_INT(&reply.length);
        __GLX_SWAP_INT(&reply.numVisuals);
        __GLX_SWAP_INT(&reply.numProps);
        __GLX_SWAP_INT_ARRAY (props_buf, num_props) ;
    }
    WriteToClient(client, sz_xGLXGetVisualConfigsReply, (char*)&reply);
    props_per_visual_size = props_buf_size/num_visuals ;
    for (i=0; i < num_visuals; i++) {
        WriteToClient (client,
                       props_per_visual_size,
                       &((char*)props_buf)[i*props_per_visual_size]);
    }
    res = Success ;

out:
    EPHYR_LOG ("leave\n") ;
    free(props_buf) ;
    props_buf = NULL ;

    return res ;
}

int
ephyrGLXGetVisualConfigs (__GLXclientState *a_cl, GLbyte *a_pc)
{
    return ephyrGLXGetVisualConfigsReal (a_cl, a_pc, FALSE) ;
}

int
ephyrGLXGetVisualConfigsSwap (__GLXclientState *a_cl, GLbyte *a_pc)
{
    return ephyrGLXGetVisualConfigsReal (a_cl, a_pc, TRUE) ;
}


int
ephyrGLXClientInfo(__GLXclientState *a_cl, GLbyte *a_pc)
{
    int res=BadImplementation ;
    xGLXClientInfoReq *req = (xGLXClientInfoReq *) a_pc;

    EPHYR_LOG ("enter\n") ;
    if (!ephyrHostGLXSendClientInfo (req->major, req->minor, (char*)req+1)) {
        EPHYR_LOG_ERROR ("failed to send client info to host\n") ;
        goto out ;
    }
    res = Success ;

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

int
ephyrGLXClientInfoSwap (__GLXclientState *a_cl, GLbyte *a_pc)
{
    xGLXClientInfoReq *req = (xGLXClientInfoReq *)a_pc;
    __GLX_DECLARE_SWAP_VARIABLES;

    __GLX_SWAP_SHORT (&req->length);
    __GLX_SWAP_INT (&req->major);
    __GLX_SWAP_INT (&req->minor);
    __GLX_SWAP_INT (&req->numbytes);

    return ephyrGLXClientInfo (a_cl, a_pc) ;
}

int
ephyrGLXQueryServerString(__GLXclientState *a_cl, GLbyte *a_pc)
{
    int res = BadImplementation ;
    ClientPtr client = a_cl->client;
    xGLXQueryServerStringReq *req = (xGLXQueryServerStringReq *) a_pc;
    xGLXQueryServerStringReply reply;
    char *server_string=NULL, *buf=NULL;
    int length=0 ;

    EPHYR_LOG ("enter\n") ;
    if (!ephyrHostGLXGetStringFromServer (req->screen,
                                          req->name,
                                          EPHYR_HOST_GLX_QueryServerString,
                                          &server_string)) {
        EPHYR_LOG_ERROR ("failed to query string from host\n") ;
        goto out ;
    }
    EPHYR_LOG ("string: %s\n", server_string) ;
    length= strlen (server_string) + 1;
    reply.type = X_Reply ;
    reply.sequenceNumber = client->sequence ;
    reply.length = __GLX_PAD (length) >> 2 ;
    reply.n = length ;
    buf = calloc(reply.length << 2, 1);
    if (!buf) {
        EPHYR_LOG_ERROR ("failed to allocate string\n;");
        return BadAlloc;
    }
    memcpy (buf, server_string, length);

    WriteToClient(client, sz_xGLXQueryServerStringReply, (char*)&reply);
    WriteToClient(client, (int)(reply.length << 2), server_string);

    res = Success ;

out:
    EPHYR_LOG ("leave\n") ;
    free(server_string) ;
    server_string = NULL;

    free(buf);
    buf = NULL;

    return res ;
}

int
ephyrGLXQueryServerStringSwap(__GLXclientState *a_cl, GLbyte *a_pc)
{
    EPHYR_LOG_ERROR ("not yet implemented\n") ;
    return BadImplementation ;
}


int
ephyrGLXGetFBConfigsSGIX (__GLXclientState *a_cl, GLbyte *a_pc)
{
    return ephyrGLXGetFBConfigsSGIXReal (a_cl, a_pc, FALSE) ;
}

int
ephyrGLXGetFBConfigsSGIXSwap (__GLXclientState *a_cl, GLbyte *a_pc)
{
    return ephyrGLXGetFBConfigsSGIXReal (a_cl, a_pc, TRUE) ;
}

static int
ephyrGLXCreateContextReal (xGLXCreateContextReq *a_req, Bool a_do_swap)
{
    int res=BadImplementation;
    EphyrHostWindowAttributes host_w_attrs ;
    __GLX_DECLARE_SWAP_VARIABLES;

    EPHYR_RETURN_VAL_IF_FAIL (a_req, BadValue) ;
    EPHYR_LOG ("enter\n") ;

    if (a_do_swap) {
        __GLX_SWAP_SHORT(&a_req->length);
        __GLX_SWAP_INT(&a_req->context);
        __GLX_SWAP_INT(&a_req->visual);
        __GLX_SWAP_INT(&a_req->screen);
        __GLX_SWAP_INT(&a_req->shareList);
    }

    EPHYR_LOG ("context creation requested. localid:%d, "
               "screen:%d, visual:%d, direct:%d\n",
               (int)a_req->context, (int)a_req->screen,
               (int)a_req->visual, (int)a_req->isDirect) ;

    memset (&host_w_attrs, 0, sizeof (host_w_attrs)) ;
    if (!hostx_get_window_attributes (hostx_get_window (a_req->screen),
                                      &host_w_attrs)) {
        EPHYR_LOG_ERROR ("failed to get host window attrs\n") ;
        goto out ;
    }

    EPHYR_LOG ("host window visual id: %d\n", host_w_attrs.visualid) ;

    if (!ephyrHostGLXCreateContext (a_req->screen,
                                    host_w_attrs.visualid,
                                    a_req->context,
                                    a_req->shareList,
                                    a_req->isDirect)) {
        EPHYR_LOG_ERROR ("ephyrHostGLXCreateContext() failed\n") ;
        goto out ;
    }
    res = Success;
out:
    EPHYR_LOG ("leave\n") ;
    return res ;
}

int
ephyrGLXCreateContext (__GLXclientState *cl, GLbyte *pc)
{
    xGLXCreateContextReq *req = (xGLXCreateContextReq *) pc;

    return ephyrGLXCreateContextReal (req, FALSE) ;
}

int ephyrGLXCreateContextSwap (__GLXclientState *cl, GLbyte *pc)
{
    xGLXCreateContextReq *req = (xGLXCreateContextReq *) pc;
    return ephyrGLXCreateContextReal (req, TRUE) ;
}

static int
ephyrGLXDestroyContextReal (__GLXclientState *a_cl,
                            GLbyte *a_pc,
                            Bool a_do_swap)
{
    int res=BadImplementation;
    ClientPtr client = a_cl->client;
    xGLXDestroyContextReq *req = (xGLXDestroyContextReq *) a_pc;

    EPHYR_LOG ("enter. id:%d\n", (int)req->context) ;
    if (!ephyrHostDestroyContext (req->context)) {
        EPHYR_LOG_ERROR ("ephyrHostDestroyContext() failed\n") ;
        client->errorValue = req->context ;
        goto out ;
    }
    res = Success ;

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

int
ephyrGLXDestroyContext (__GLXclientState *a_cl, GLbyte *a_pc)
{
    return ephyrGLXDestroyContextReal (a_cl, a_pc, FALSE) ;
}

int
ephyrGLXDestroyContextSwap (__GLXclientState *a_cl, GLbyte *a_pc)
{
    return ephyrGLXDestroyContextReal (a_cl, a_pc, TRUE) ;
}

static int
ephyrGLXMakeCurrentReal (__GLXclientState *a_cl, GLbyte *a_pc, Bool a_do_swap)
{
    int res=BadImplementation;
    xGLXMakeCurrentReq *req = (xGLXMakeCurrentReq *) a_pc;
    xGLXMakeCurrentReply reply ;
    DrawablePtr drawable=NULL;
    int rc=0;

    EPHYR_LOG ("enter\n") ;
    rc = dixLookupDrawable (&drawable,
                            req->drawable,
                            a_cl->client,
                            0,
                            DixReadAccess);
    EPHYR_RETURN_VAL_IF_FAIL (drawable, BadValue) ;
    EPHYR_RETURN_VAL_IF_FAIL (drawable->pScreen, BadValue) ;
    EPHYR_LOG ("screen nummber requested:%d\n",
               drawable->pScreen->myNum) ;

    memset (&reply, 0, sizeof (reply)) ;
    if (!ephyrHostGLXMakeCurrent (hostx_get_window (drawable->pScreen->myNum),
                                  req->context,
                                  req->oldContextTag,
                                  (int*)&reply.contextTag)) {
        EPHYR_LOG_ERROR ("ephyrHostGLXMakeCurrent() failed\n") ;
        goto out;
    }
    reply.length = 0;
    reply.type = X_Reply;
    reply.sequenceNumber = a_cl->client->sequence;
    if (a_do_swap) {
        __GLX_DECLARE_SWAP_VARIABLES;
        __GLX_SWAP_SHORT(&reply.sequenceNumber);
        __GLX_SWAP_INT(&reply.length);
        __GLX_SWAP_INT(&reply.contextTag);
    }
    WriteToClient(a_cl->client, sz_xGLXMakeCurrentReply, (char *)&reply);

    res = Success ;
out:
    EPHYR_LOG ("leave\n") ;
    return res ;
}

int
ephyrGLXMakeCurrent (__GLXclientState *a_cl, GLbyte *a_pc)
{
    return ephyrGLXMakeCurrentReal (a_cl, a_pc, FALSE) ;
}

int
ephyrGLXMakeCurrentSwap (__GLXclientState *a_cl, GLbyte *a_pc)
{
    return ephyrGLXMakeCurrentReal (a_cl, a_pc, TRUE) ;
}

static int
ephyrGLXGetStringReal (__GLXclientState *a_cl, GLbyte *a_pc, Bool a_do_swap)
{
    ClientPtr client=NULL ;
    int context_tag=0, name=0, res=BadImplementation, length=0 ;
    char *string=NULL;
    __GLX_DECLARE_SWAP_VARIABLES;

    EPHYR_RETURN_VAL_IF_FAIL (a_cl && a_pc, BadValue) ;

    EPHYR_LOG ("enter\n") ;

    client = a_cl->client ;

    if (a_do_swap) {
        __GLX_SWAP_INT (a_pc + 4);
        __GLX_SWAP_INT (a_pc + __GLX_SINGLE_HDR_SIZE);
    }
    context_tag = __GLX_GET_SINGLE_CONTEXT_TAG (a_pc) ;
    a_pc += __GLX_SINGLE_HDR_SIZE;
    name = *(GLenum*)(a_pc + 0);
    EPHYR_LOG ("context_tag:%d, name:%d\n", context_tag, name) ;
    if (!ephyrHostGLXGetStringFromServer (context_tag,
                                          name,
                                          EPHYR_HOST_GLX_GetString,
                                          &string)) {
        EPHYR_LOG_ERROR ("failed to get string from server\n") ;
        goto out ;
    }
    if (string) {
        length = strlen (string) + 1;
        EPHYR_LOG ("got string:'%s', size:%d\n", string, length) ;
    } else {
        EPHYR_LOG ("got string: string (null)\n") ;
    }
    __GLX_BEGIN_REPLY (length);
    __GLX_PUT_SIZE (length);
    __GLX_SEND_HEADER ();
    if (a_do_swap) {
        __GLX_SWAP_REPLY_SIZE ();
        __GLX_SWAP_REPLY_HEADER ();
    }
    WriteToClient (client, length, (char *)string);

    res = Success ;
out:
    EPHYR_LOG ("leave\n") ;
    return res ;
}

int
ephyrGLXGetString (__GLXclientState *a_cl, GLbyte *a_pc)
{
    return ephyrGLXGetStringReal (a_cl, a_pc, FALSE) ;
}

int
ephyrGLXGetStringSwap (__GLXclientState *a_cl, GLbyte *a_pc)
{
    return ephyrGLXGetStringReal (a_cl, a_pc, TRUE) ;
}

static int
ephyrGLXGetIntegervReal (__GLXclientState *a_cl, GLbyte *a_pc, Bool a_do_swap)
{
    int res=BadImplementation;
    xGLXSingleReq * const req = (xGLXSingleReq *) a_pc;
    GLenum int_name ;
    int value=0 ;
    GLint answer_buf_room[200];
    GLint *buf=NULL ;

    EPHYR_LOG ("enter\n") ;

    a_pc += __GLX_SINGLE_HDR_SIZE;

    int_name = *(GLenum*) (a_pc+0) ;
    if (!ephyrHostGetIntegerValue (req->contextTag, int_name, &value)) {
        EPHYR_LOG_ERROR ("ephyrHostGetIntegerValue() failed\n") ;
        goto out ;
    }
    buf = __glXGetAnswerBuffer (a_cl, sizeof (value),
                                answer_buf_room,
                                sizeof (answer_buf_room),
                                4) ;

    if (!buf) {
        EPHYR_LOG_ERROR ("failed to allocate reply buffer\n") ;
        res = BadAlloc ;
        goto out ;
    }
    __glXSendReply (a_cl->client, buf, 1, sizeof (value), GL_FALSE, 0) ;
    res = Success ;

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

int
ephyrGLXGetIntegerv (__GLXclientState *a_cl, GLbyte *a_pc)
{
    return ephyrGLXGetIntegervReal (a_cl, a_pc, FALSE) ;
}

int
ephyrGLXGetIntegervSwap (__GLXclientState *a_cl, GLbyte *a_pc)
{
    return ephyrGLXGetIntegervReal (a_cl, a_pc, TRUE) ;
}

static int
ephyrGLXIsDirectReal (__GLXclientState *a_cl, GLbyte *a_pc, Bool a_do_swap)
{
    int res=BadImplementation;
    ClientPtr client = a_cl->client;
    xGLXIsDirectReq *req = (xGLXIsDirectReq *) a_pc;
    xGLXIsDirectReply reply;
    int is_direct=0 ;

    EPHYR_RETURN_VAL_IF_FAIL (a_cl && a_pc, FALSE) ;

    EPHYR_LOG ("enter\n") ;

    memset (&reply, 0, sizeof (reply)) ;
    if (!ephyrHostIsContextDirect (req->context, (int*)&is_direct)) {
        EPHYR_LOG_ERROR ("ephyrHostIsContextDirect() failed\n") ;
        goto out ;
    }
    reply.isDirect = is_direct ;
    reply.length = 0;
    reply.type = X_Reply;
    reply.sequenceNumber = client->sequence;
    WriteToClient(client, sz_xGLXIsDirectReply, (char *)&reply);
    res = Success ;

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

int
ephyrGLXIsDirect (__GLXclientState *a_cl, GLbyte *a_pc)
{
    return ephyrGLXIsDirectReal (a_cl, a_pc, FALSE) ;
}

int
ephyrGLXIsDirectSwap (__GLXclientState *a_cl, GLbyte *a_pc)
{
    return ephyrGLXIsDirectReal (a_cl, a_pc, TRUE) ;
}