/*
 * 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.
 *
 * a lots of the content of this file has been adapted from the mesa source
 * code.
 * Authors:
 *    Dodji Seketeli <dodji@openedhand.com>
 */
#ifdef HAVE_CONFIG_H
#include <kdrive-config.h>
#endif

/*
 * including some server headers (like kdrive-config.h)
 * might define the macro _XSERVER64
 * on 64 bits machines. That macro must _NOT_ be defined for Xlib
 * client code, otherwise bad things happen.
 * So let's undef that macro if necessary.
 */
#ifdef _XSERVER64
#undef _XSERVER64
#endif

#include <X11/Xlibint.h>
#include <GL/glx.h>
#include <GL/internal/glcore.h>
#include <GL/glxproto.h>
#include <GL/glxint.h>
#include "ephyrhostglx.h"
#define _HAVE_XALLOC_DECLS
#include "ephyrlog.h"
#include "hostx.h"

enum VisualConfRequestType {
    EPHYR_GET_FB_CONFIG,
    EPHYR_VENDOR_PRIV_GET_FB_CONFIG_SGIX,
    EPHYR_GET_VISUAL_CONFIGS

};

static Bool ephyrHostGLXGetVisualConfigsInternal
                                        (enum VisualConfRequestType a_type,
                                         int32_t a_screen,
                                         int32_t *a_num_visuals,
                                         int32_t *a_num_props,
                                         int32_t *a_props_buf_size,
                                         int32_t **a_props_buf);
Bool
ephyrHostGLXGetMajorOpcode (int *a_opcode)
{
    Bool is_ok=FALSE ;
    Display *dpy=hostx_get_display () ;
    static int opcode ;
    int first_event_return=0, first_error_return=0;

    EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ;
    EPHYR_LOG ("enter\n") ;
    if (!opcode) {
        if (!XQueryExtension (dpy, GLX_EXTENSION_NAME, &opcode,
                              &first_event_return, &first_error_return)) {
            EPHYR_LOG_ERROR ("XQueryExtension() failed\n") ;
            goto out ;
        }
    }
    *a_opcode = opcode ;
    is_ok = TRUE ;
out:
    EPHYR_LOG ("release\n") ;
    return is_ok ;
}

Bool
ephyrHostGLXQueryVersion (int *a_major, int *a_minor)
{
    Bool is_ok = FALSE ;
    Display *dpy = hostx_get_display () ;
    int major_opcode=0;
    xGLXQueryVersionReq *req=NULL;
    xGLXQueryVersionReply reply;

    EPHYR_RETURN_VAL_IF_FAIL (a_major && a_minor, FALSE) ;
    EPHYR_LOG ("enter\n") ;

    if (!ephyrHostGLXGetMajorOpcode (&major_opcode)) {
        EPHYR_LOG_ERROR ("failed to get major opcode\n") ;
        goto out ;
    }
    EPHYR_LOG ("major opcode: %d\n", major_opcode) ;

    /* Send the glXQueryVersion request */
    memset (&reply, 0, sizeof (reply)) ;
    LockDisplay (dpy);
    GetReq (GLXQueryVersion, req);
    req->reqType = major_opcode;
    req->glxCode = X_GLXQueryVersion;
    req->majorVersion = 2;
    req->minorVersion = 1;
    _XReply(dpy, (xReply*) &reply, 0, False);
    UnlockDisplay (dpy);
    SyncHandle ();

    *a_major = reply.majorVersion ;
    *a_minor = reply.minorVersion ;

    EPHYR_LOG ("major:%d, minor:%d\n", *a_major, *a_minor) ;

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

/**
 * GLX protocol structure for the ficticious "GXLGenericGetString" request.
 * 
 * This is a non-existant protocol packet.  It just so happens that all of
 * the real protocol packets used to request a string from the server have
 * an identical binary layout.  The only difference between them is the
 * meaning of the \c for_whom field and the value of the \c glxCode.
 * (this has been copied from the mesa source code)
 */
typedef struct GLXGenericGetString {
    CARD8 reqType;
    CARD8 glxCode;
    CARD16 length B16;
    CARD32 for_whom B32;
    CARD32 name B32;
} xGLXGenericGetStringReq;

/* These defines are only needed to make the GetReq macro happy.
 */
#define sz_xGLXGenericGetStringReq 12
#define X_GLXGenericGetString 0

Bool
ephyrHostGLXGetStringFromServer (int a_screen_number,
                                 int a_string_name,
                                 enum EphyrHostGLXGetStringOps a_op,
                                 char **a_string)
{
    Bool is_ok=FALSE ;
    Display *dpy = hostx_get_display () ;
    int default_screen = DefaultScreen (dpy);
    xGLXGenericGetStringReq *req=NULL;
    xGLXSingleReply reply;
    int length=0, numbytes=0, major_opcode=0, get_string_op=0;

    EPHYR_RETURN_VAL_IF_FAIL (dpy && a_string, FALSE) ;

    EPHYR_LOG ("enter\n") ;
    switch (a_op) {
        case EPHYR_HOST_GLX_QueryServerString:
            get_string_op = X_GLXQueryServerString;
            break ;
        case EPHYR_HOST_GLX_GetString:
            get_string_op = X_GLsop_GetString;
            EPHYR_LOG ("Going to glXGetString. strname:%#x, ctxttag:%d\n",
                       a_string_name, a_screen_number) ;
            break ;
        default:
            EPHYR_LOG_ERROR ("unknown EphyrHostGLXGetStringOp:%d\n", a_op) ;
            goto out ;
    }

    if (!ephyrHostGLXGetMajorOpcode (&major_opcode)) {
        EPHYR_LOG_ERROR ("failed to get major opcode\n") ;
        goto out ;
    }
    EPHYR_LOG ("major opcode: %d\n", major_opcode) ;

    LockDisplay (dpy);

    /* All of the GLX protocol requests for getting a string from the server
     * look the same.  The exact meaning of the a_for_whom field is usually
     * either the screen number (for glXQueryServerString) or the context tag
     * (for GLXSingle).
     */
    GetReq (GLXGenericGetString, req);
    req->reqType = major_opcode;
    req->glxCode = get_string_op;
    req->for_whom = default_screen;
    req->name = a_string_name;

    _XReply (dpy, (xReply *)&reply, 0, False);

    length = reply.length * 4;
    if (!length) {
        numbytes = 0;
    } else {
        numbytes = reply.size;
    }
    EPHYR_LOG ("going to get a string of size:%d\n", numbytes) ;

    *a_string = (char *) Xmalloc (numbytes +1);
    if (!a_string) {
        EPHYR_LOG_ERROR ("allocation failed\n") ;
        goto out;
    }

    memset (*a_string, 0, numbytes+1) ;
    if (_XRead (dpy, *a_string, numbytes)) {
        UnlockDisplay (dpy);
        SyncHandle ();
        EPHYR_LOG_ERROR ("read failed\n") ;
        goto out ;
    }
    length -= numbytes;
    _XEatData (dpy, length) ;
    UnlockDisplay (dpy);
    SyncHandle ();
    EPHYR_LOG ("strname:%#x, strvalue:'%s', strlen:%d\n",
               a_string_name, *a_string, numbytes) ;

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

static Bool
ephyrHostGLXGetVisualConfigsInternal (enum VisualConfRequestType a_type,
                                      int32_t a_screen,
                                      int32_t *a_num_visuals,
                                      int32_t *a_num_props,
                                      int32_t *a_props_buf_size,
                                      int32_t **a_props_buf)
{
    Bool is_ok = FALSE ;
    Display *dpy = hostx_get_display () ;
    xGLXGetVisualConfigsReq *req;
    xGLXGetFBConfigsReq *fb_req;
    xGLXVendorPrivateWithReplyReq *vpreq;
    xGLXGetFBConfigsSGIXReq *sgi_req;
    xGLXGetVisualConfigsReply reply;
    char *server_glx_version=NULL,
         *server_glx_extensions=NULL ;
    int j=0,
        screens=0,
        major_opcode=0,
        num_props=0,
        num_visuals=0,
        props_buf_size=0,
        props_per_visual_size=0;
    int32_t *props_buf=NULL;

    EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ;

    screens = ScreenCount (dpy);
    if (!ephyrHostGLXGetMajorOpcode (&major_opcode)) {
        EPHYR_LOG_ERROR ("failed to get opcode\n") ;
        goto out ;
    }

    LockDisplay(dpy);
    switch (a_type) {
        case EPHYR_GET_FB_CONFIG:
        GetReq(GLXGetFBConfigs,fb_req);
        fb_req->reqType = major_opcode;
        fb_req->glxCode = X_GLXGetFBConfigs;
        fb_req->screen = DefaultScreen (dpy);
        break;

        case EPHYR_VENDOR_PRIV_GET_FB_CONFIG_SGIX:
        GetReqExtra(GLXVendorPrivateWithReply,
                    sz_xGLXGetFBConfigsSGIXReq
                         -
                    sz_xGLXVendorPrivateWithReplyReq,
                    vpreq);
        sgi_req = (xGLXGetFBConfigsSGIXReq *) vpreq;
        sgi_req->reqType = major_opcode;
        sgi_req->glxCode = X_GLXVendorPrivateWithReply;
        sgi_req->vendorCode = X_GLXvop_GetFBConfigsSGIX;
        sgi_req->screen = DefaultScreen (dpy);
        break;

        case EPHYR_GET_VISUAL_CONFIGS:
        GetReq(GLXGetVisualConfigs,req);
        req->reqType = major_opcode;
        req->glxCode = X_GLXGetVisualConfigs;
        req->screen = DefaultScreen (dpy);
        break;
    }

    if (!_XReply(dpy, (xReply*) &reply, 0, False)) {
        EPHYR_LOG_ERROR ("unknown error\n") ;
        UnlockDisplay(dpy);
        goto out ;
    }
   if (!reply.numVisuals) {
        EPHYR_LOG_ERROR ("screen does not support GL rendering\n") ;
        UnlockDisplay(dpy);
        goto out ;
    }
   num_visuals = reply.numVisuals ;

    /* FIXME: Is the __GLX_MIN_CONFIG_PROPS test correct for
     * FIXME: FBconfigs? 
     */
    /* Check number of properties */
    num_props = reply.numProps;
    if ((num_props < __GLX_MIN_CONFIG_PROPS) ||
        (num_props > __GLX_MAX_CONFIG_PROPS)) {
        /* Huh?  Not in protocol defined limits.  Punt */
        EPHYR_LOG_ERROR ("got a bad reply to request\n") ;
        UnlockDisplay(dpy);
        goto out ;
    }

    if (a_type != EPHYR_GET_VISUAL_CONFIGS) {
        num_props *= 2;
    }
    props_per_visual_size = num_props * __GLX_SIZE_INT32;
    props_buf_size = props_per_visual_size * reply.numVisuals;
    props_buf = malloc (props_buf_size) ;
    for (j = 0; j < reply.numVisuals; j++) {
        if (_XRead (dpy,
                    &((char*)props_buf)[j*props_per_visual_size],
                    props_per_visual_size) != Success) {
            EPHYR_LOG_ERROR ("read failed\n") ;
        }
    }
    UnlockDisplay(dpy);

    *a_num_visuals = num_visuals ;
    *a_num_props = reply.numProps ;
    *a_props_buf_size = props_buf_size ;
    *a_props_buf = props_buf ;
    is_ok = TRUE ;

out:
    if (server_glx_version) {
        XFree (server_glx_version) ;
        server_glx_version = NULL ;
    }
    if (server_glx_extensions) {
        XFree (server_glx_extensions) ;
        server_glx_extensions = NULL ;
    }
    SyncHandle () ;
    return is_ok;
}

Bool
ephyrHostGLXGetVisualConfigs (int32_t a_screen,
                              int32_t *a_num_visuals,
                              int32_t *a_num_props,
                              int32_t *a_props_buf_size,
                              int32_t **a_props_buf)
{
    Bool is_ok = FALSE;

    EPHYR_LOG ("enter\n") ;
    is_ok = ephyrHostGLXGetVisualConfigsInternal (EPHYR_GET_VISUAL_CONFIGS,
                                                  a_screen,
                                                  a_num_visuals,
                                                  a_num_props,
                                                  a_props_buf_size,
                                                  a_props_buf) ;

    EPHYR_LOG ("leave:%d\n", is_ok) ;
    return is_ok;
}

Bool
ephyrHostGLXVendorPrivGetFBConfigsSGIX (int a_screen,
                                        int32_t *a_num_visuals,
                                        int32_t *a_num_props,
                                        int32_t *a_props_buf_size,
                                        int32_t **a_props_buf)
{
    Bool is_ok=FALSE ;
    EPHYR_LOG ("enter\n") ;
    is_ok = ephyrHostGLXGetVisualConfigsInternal
                                        (EPHYR_VENDOR_PRIV_GET_FB_CONFIG_SGIX,
                                         a_screen,
                                         a_num_visuals,
                                         a_num_props,
                                         a_props_buf_size,
                                         a_props_buf) ;
    EPHYR_LOG ("leave\n") ;
    return is_ok ;
}

Bool
ephyrHostGLXSendClientInfo (int32_t a_major, int32_t a_minor,
                            const char* a_extension_list)
{
    Bool is_ok = FALSE ;
    Display *dpy = hostx_get_display () ;
    xGLXClientInfoReq *req;
    int size;
    int32_t major_opcode=0 ;

    EPHYR_RETURN_VAL_IF_FAIL (dpy && a_extension_list, FALSE) ;

    if (!ephyrHostGLXGetMajorOpcode (&major_opcode)) {
        EPHYR_LOG_ERROR ("failed to get major opcode\n") ;
        goto out ;
    }

    LockDisplay (dpy);

    GetReq (GLXClientInfo,req);
    req->reqType = major_opcode;
    req->glxCode = X_GLXClientInfo;
    req->major = a_major;
    req->minor = a_minor;

    size = strlen (a_extension_list) + 1;
    req->length += bytes_to_int32(size);
    req->numbytes = size;
    Data (dpy, a_extension_list, size);

    UnlockDisplay(dpy);
    SyncHandle();

    is_ok=TRUE ;

out:
    return is_ok ;
}

Bool
ephyrHostGLXCreateContext (int a_screen,
                           int a_visual_id,
                           int a_context_id,
                           int a_share_list_ctxt_id,
                           Bool a_direct)
{
    Bool is_ok = FALSE;
    Display *dpy = hostx_get_display ();
    int major_opcode=0, remote_context_id=0;
    xGLXCreateContextReq *req;

    EPHYR_LOG ("enter. screen:%d, visual:%d, contextid:%d, direct:%d\n",
               a_screen, a_visual_id, a_context_id, a_direct) ;

    if (!hostx_allocate_resource_id_peer (a_context_id, &remote_context_id)) {
        EPHYR_LOG_ERROR ("failed to peer the context id %d host X",
                         remote_context_id) ;
        goto out ;
    }

    if (!ephyrHostGLXGetMajorOpcode (&major_opcode)) {
        EPHYR_LOG_ERROR ("failed to get major opcode\n") ;
        goto out ;
    }

    LockDisplay (dpy) ;

    /* Send the glXCreateContext request */
    GetReq(GLXCreateContext,req);
    req->reqType = major_opcode;
    req->glxCode = X_GLXCreateContext;
    req->context = remote_context_id;
    req->visual = a_visual_id;
    req->screen = DefaultScreen (dpy);
    req->shareList = a_share_list_ctxt_id;
    req->isDirect = a_direct;

    UnlockDisplay (dpy);
    SyncHandle ();

    is_ok = TRUE ;

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

Bool
ephyrHostDestroyContext (int a_ctxt_id)
{
    Bool is_ok=FALSE;
    Display *dpy=hostx_get_display ();
    int major_opcode=0, remote_ctxt_id=0 ;
    xGLXDestroyContextReq *req=NULL;

    EPHYR_LOG ("enter:%d\n", a_ctxt_id) ;

    if (!ephyrHostGLXGetMajorOpcode (&major_opcode)) {
        EPHYR_LOG_ERROR ("failed to get major opcode\n") ;
        goto out ;
    }
    if (!hostx_get_resource_id_peer (a_ctxt_id, &remote_ctxt_id)) {
        EPHYR_LOG_ERROR ("failed to get remote glx ctxt id\n") ;
        goto out ;
    }
    EPHYR_LOG ("host context id:%d\n", remote_ctxt_id) ;

    LockDisplay (dpy);
    GetReq (GLXDestroyContext,req);
    req->reqType = major_opcode;
    req->glxCode = X_GLXDestroyContext;
    req->context = remote_ctxt_id;
    UnlockDisplay (dpy);
    SyncHandle ();

    is_ok = TRUE ;

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

Bool
ephyrHostGLXMakeCurrent (int a_drawable,
                         int a_glx_ctxt_id,
                         int a_old_ctxt_tag,
                         int *a_ctxt_tag)
{
    Bool is_ok=FALSE ;
    Display *dpy = hostx_get_display () ;
    int32_t major_opcode=0 ;
    int remote_glx_ctxt_id=0 ;
    xGLXMakeCurrentReq *req;
    xGLXMakeCurrentReply reply;

    EPHYR_RETURN_VAL_IF_FAIL (a_ctxt_tag, FALSE) ;

    EPHYR_LOG ("enter. drawable:%d, context:%d, oldtag:%d\n",
               a_drawable, a_glx_ctxt_id, a_old_ctxt_tag) ;

    if (!ephyrHostGLXGetMajorOpcode (&major_opcode)) {
        EPHYR_LOG_ERROR ("failed to get major opcode\n") ;
        goto out ;
    }
    if (!hostx_get_resource_id_peer (a_glx_ctxt_id, &remote_glx_ctxt_id)) {
        EPHYR_LOG_ERROR ("failed to get remote glx ctxt id\n") ;
        goto out ;
    }

    LockDisplay (dpy);

    GetReq (GLXMakeCurrent,req);
    req->reqType = major_opcode;
    req->glxCode = X_GLXMakeCurrent;
    req->drawable = a_drawable;
    req->context = remote_glx_ctxt_id;
    req->oldContextTag = a_old_ctxt_tag;

    memset (&reply, 0, sizeof (reply)) ;
    if (!_XReply (dpy, (xReply*)&reply, 0, False)) {
        EPHYR_LOG_ERROR ("failed to get reply from host\n") ;
        UnlockDisplay (dpy);
        SyncHandle ();
        goto out ;
    }
    UnlockDisplay (dpy);
    SyncHandle ();
    *a_ctxt_tag = reply.contextTag ;
    EPHYR_LOG ("context tag:%d\n", *a_ctxt_tag) ;
    is_ok = TRUE ;

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

#define X_GLXSingle 0

#define __EPHYR_GLX_SINGLE_PUT_CHAR(offset,a) \
    *((INT8 *) (pc + offset)) = a

#define EPHYR_GLX_SINGLE_PUT_SHORT(offset,a) \
    *((INT16 *) (pc + offset)) = a

#define EPHYR_GLX_SINGLE_PUT_LONG(offset,a) \
    *((INT32 *) (pc + offset)) = a

#define EPHYR_GLX_SINGLE_PUT_FLOAT(offset,a) \
    *((FLOAT32 *) (pc + offset)) = a

#define EPHYR_GLX_SINGLE_READ_XREPLY()       \
    (void) _XReply(dpy, (xReply*) &reply, 0, False)

#define EPHYR_GLX_SINGLE_GET_RETVAL(a,cast) \
    a = (cast) reply.retval

#define EPHYR_GLX_SINGLE_GET_SIZE(a) \
    a = (GLint) reply.size

#define EPHYR_GLX_SINGLE_GET_CHAR(p) \
    *p = *(GLbyte *)&reply.pad3;

#define EPHYR_GLX_SINGLE_GET_SHORT(p) \
    *p = *(GLshort *)&reply.pad3;

#define EPHYR_GLX_SINGLE_GET_LONG(p) \
    *p = *(GLint *)&reply.pad3;

#define EPHYR_GLX_SINGLE_GET_FLOAT(p) \
    *p = *(GLfloat *)&reply.pad3;

Bool
ephyrHostGetIntegerValue (int a_current_context_tag, int a_int, int *a_val)
{
    Bool is_ok=FALSE;
    Display *dpy = hostx_get_display () ;
    int major_opcode=0, size=0;
    xGLXSingleReq *req=NULL;
    xGLXSingleReply reply;
    unsigned char* pc=NULL ;

    EPHYR_RETURN_VAL_IF_FAIL (a_val, FALSE) ;

    EPHYR_LOG ("enter\n") ;
    if (!ephyrHostGLXGetMajorOpcode (&major_opcode)) {
        EPHYR_LOG_ERROR ("failed to get major opcode\n") ;
        goto out ;
    }
    LockDisplay (dpy) ;
    GetReqExtra (GLXSingle, 4, req) ;
    req->reqType = major_opcode ;
    req->glxCode = X_GLsop_GetIntegerv ;
    req->contextTag = a_current_context_tag;
    pc = ((unsigned char *)(req) + sz_xGLXSingleReq) ;
    EPHYR_GLX_SINGLE_PUT_LONG (0, a_int) ;
    EPHYR_GLX_SINGLE_READ_XREPLY () ;
    EPHYR_GLX_SINGLE_GET_SIZE (size) ;
    if (!size) {
        UnlockDisplay (dpy) ;
        SyncHandle () ;
        EPHYR_LOG_ERROR ("X_GLsop_GetIngerv failed\n") ;
        goto out ;
    }
    EPHYR_GLX_SINGLE_GET_LONG (a_val) ;
    UnlockDisplay (dpy) ;
    SyncHandle () ;
    is_ok = TRUE ;

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

Bool
ephyrHostIsContextDirect (int a_ctxt_id,
                          int *a_is_direct)
{
    Bool is_ok=FALSE;
    Display *dpy = hostx_get_display () ;
    xGLXIsDirectReq *req=NULL;
    xGLXIsDirectReply reply;
    int major_opcode=0, remote_glx_ctxt_id=0;

    EPHYR_LOG ("enter\n") ;
    if (!ephyrHostGLXGetMajorOpcode (&major_opcode)) {
        EPHYR_LOG_ERROR ("failed to get major opcode\n") ;
        goto out ;
    }
    if (!hostx_get_resource_id_peer (a_ctxt_id, &remote_glx_ctxt_id)) {
        EPHYR_LOG_ERROR ("failed to get remote glx ctxt id\n") ;
        goto out ;
    }
    memset (&reply, 0, sizeof (reply)) ;

    /* Send the glXIsDirect request */
    LockDisplay (dpy);
    GetReq (GLXIsDirect,req);
    req->reqType = major_opcode;
    req->glxCode = X_GLXIsDirect;
    req->context = remote_glx_ctxt_id;
    if (!_XReply (dpy, (xReply*) &reply, 0, False)) {
        EPHYR_LOG_ERROR ("fail in reading reply from host\n") ;
        UnlockDisplay (dpy);
        SyncHandle ();
        goto out ;
    }
    UnlockDisplay (dpy);
    SyncHandle ();
    *a_is_direct = reply.isDirect ;
    is_ok = TRUE ;

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