/* Copyright (c) 1996, 1999, Oracle and/or its affiliates. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

 
/*
 * dga_ab.c - the client side code for Ancillary Buffers (ABMG ) 
 */

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/fcntl.h>
#include <X11/X.h>
#include "dga_incls.h"

extern int XDgaGrabABuffers(Display *dpy, Window win, int type, int buffer_site);
extern int XDgaUnGrabABuffers(Display *dpy, Window win, int type);
extern void *_dga_is_X_window(Dga_token token, Display **dpyp, Window *winp);

#ifdef DEBUG
#define assert(expr) \
if(!(expr)) \
{fprintf(stderr, "Assertion fails in file %s, line %d: expr\n",__FILE__,__LINE__); \
abort();}
#else
#define assert(expr)
#endif /* DEBUG */

#define UNMAP_BUFFER(addr, allocsize) \
    if ( addr ) { \
        munmap((char *)addr, allocsize); \
        addr = NULL; \
    }

#define GET_SW_HW_BUFFER(dgawin_buf, fname, bufsize)  \
    bufferp = (dga_buffer)get_specified_buffer((char *)fname, bufsize); \
    (dgawin_buf)->bufferp  = bufferp; \
    (dgawin_buf)->pDraw    = dgadraw; \
    (dgawin_buf)->buf_size = bufsize; \
    ret_buf = dgawin_buf;

#define STORE_BUFFERS(buf_addr, filename, fn_addr0, allocsize) \
    bufferp = (buf_addr)->bufferp; \
    if ( bufferp) { \
        if (resize_flag) \
            UNMAP_BUFFER(bufferp, (buf_addr)->buf_size) \
        if ( filename && fn_addr0)  { \
            if ( bufferp ) { \
                buffers[count++] = (Dga_buffer *)buf_addr; \
                bufferp->pDraw = dgadraw; \
            } \
            else {\
                (buf_addr)->bufferp = bufferp = (void *) \
                    get_specified_buffer((char *)filename, allocsize); \
                 (buf_addr)->pDraw = dgadraw; \
                 if (bufferp) { \
                     buffers[count++] = (Dga_buffer *)buf_addr; \
                     bufferp->pDraw = dgadraw; \
                     (buf_addr)->buf_size = allocsize; \
                 } \
                 else { \
                     (buf_addr)->buf_size = 0; \
                 } \
            }\
        }\
    }

static dga_buffer
get_specified_buffer(char *filename, int allocsize)
{
    int         filefd = -1;
    dga_buffer  return_buf = NULL;

    if ( filename && filename[0] ) {
        if ((filefd = open(filename,O_RDWR,0666)) != -1 ) {
            return_buf = (dga_buffer)mmap(0, allocsize,
                PROT_READ|PROT_WRITE, MAP_SHARED, filefd, (off_t)0);
            close (filefd);  /* May need to keep trap of fds... */

            if ( return_buf == (dga_buffer) -1)
                return ( (dga_buffer)NULL ); /* mmap failed. */

            /* Set the data filed properly */
	    assert(sizeof(dga_buffer_rec) & 0x7 == 0);
            return_buf->data = (char *)(return_buf + 1);
        }
    }
    return return_buf;

}

static void
remap_buffers(Dga_drawable dgadraw)
{
    int         filefd = -1;
    char        *filename;
    int         count = 0;
    dga_buffer  bufferp = NULL;
    static      void     *buffers[DGA_NUM_BUFFER_TYPES];
    _Dga_window dgawin = (_Dga_window)dgadraw;
    WXINFO      *infop = wx_infop(dgawin);
    int         resize_flag = True;
 
    if ( dgawin->buf_resize_flag >= infop->wx_abuf.s_modified )
        return;

    STORE_BUFFERS((dga_internal_buffer)dgawin->back, infop->wx_abuf.back_fn, infop->wx_abuf.back_fn[0], infop->wx_abuf.back_size);

    STORE_BUFFERS((dga_internal_buffer)dgawin->depth, infop->wx_abuf.depth_fn, infop->wx_abuf.depth_fn[0], infop->wx_abuf.depth_size);

    STORE_BUFFERS((dga_internal_buffer)dgawin->stencil, infop->wx_abuf.stencil_fn, infop->wx_abuf.stencil_fn[0], infop->wx_abuf.stencil_size);

    STORE_BUFFERS((dga_internal_buffer)dgawin->accum, infop->wx_abuf.accum_fn, infop->wx_abuf.accum_fn[0], infop->wx_abuf.accum_size);

    STORE_BUFFERS((dga_internal_buffer)dgawin->alpha, infop->wx_abuf.alpha_fn, infop->wx_abuf.alpha_fn[0], infop->wx_abuf.alpha_size);

    dgawin->buf_resize_flag = infop->wx_abuf.s_modified;

    return;
}

/*
 * Name    : dga_draw_grab_buffer
 * Synopsis: This function requests the window system to provide 
 * ancillary buffer service for the grabbed drawable name in the
 * dgadraw argument.  The call requests  the type of the buffer
 * specified to be grabbed to the client.  If buffer_site is 
 * DGA_SITE_SYSTEM, server allocates the buffer in the shared 
 * memory.  If it is DGA_SITE_DEVICE, the server tries to grab
 * hardware buffers.  If the device does not support the given 
 * buffer type in hardware, the request fails.
 * The drawable must have been grabbed previously via XDgaGrabDrawable.
 * 
 * Implementation:  If buffer_stie is DGA_SITE_SYSTEM, this function
 * increments the grab_cnt if the buffer is already grabbed by other clients.
 * If this client has grabbed the specified buffer already, this function
 * returns the grabbed buffer pointer.
 * Otherwise, it sends a request to the server to grab a buffer.
 * If the request is successful, this function returns the buffer 
 * address.
 * A special case where if the grab_cnt is "0", this function still sends
 * a request to the server to grab the buffer  because there is a chance
 * that the visual capabilities of the window might have been changed. 
 */

Dga_buffer 
dga_draw_grab_buffer(Dga_drawable dgadraw, Dga_buffer_type type, int buffer_site)
{
    _Dga_window dgawin = (struct dga_window *)dgadraw;
    Dga_window  clientpi = (Dga_window)dgawin;
    _Dga_window clientp = (struct dga_window *)clientpi;
    WXINFO      *infop;
    Display     *dpy;
    Window      win;
    int         depth  = 0;
    dga_buffer  bufferp = NULL;
    dga_internal_buffer ret_buf = NULL;
    dga_internal_buffer c_bufferp = NULL;

    /* Ancillary Buffers are not supported for drawable_type 
     * DGA_DRAW_PIXMAP
     */
    if ( ((_Dga_drawable)dgadraw)->drawable_type != DGA_DRAW_WINDOW ) 
        return (0);

    if (!DGA_LOCKSUBJ_WINDOW(dgawin, dgawin->eLockSubj)) 
        return (0);

    if ((clientp == (_Dga_window) NULL)) {
#ifdef DEBUG
        (void) fprintf(stderr, "dga_draw_grab_buffer: passed null pointer\n");
#endif
        return (0);
    }

    /*
     *  Find out if this is an X window.  If so get the Display and window
     *  id.
     */
    if (!_dga_is_X_window(clientp->w_token, &dpy, &win)) {
#ifdef DEBUG
        (void) fprintf(stderr, "dga_draw_grab_buffer: Unsupported window type\n");
#endif
        return (0);
    }

    infop = wx_infop(dgawin) ;

    if ( dgawin->buf_resize_flag < infop->wx_abuf.s_modified )
        remap_buffers(dgadraw);
 
    switch ( type ) {
    case DGA_BACK_BUFFER:
        c_bufferp = (dga_internal_buffer)dgawin->back;
        if ( c_bufferp->bufferp )
            return dgawin->back;
        GET_SW_HW_BUFFER(c_bufferp, infop->wx_abuf.back_fn, infop->wx_abuf.back_size);
        break;
    case DGA_DEPTH_BUFFER:
        c_bufferp = (dga_internal_buffer)dgawin->depth;
        if ( c_bufferp->bufferp )
            return dgawin->depth;
        GET_SW_HW_BUFFER(c_bufferp, infop->wx_abuf.depth_fn, infop->wx_abuf.depth_size);
        break;
    case DGA_STENCIL_BUFFER:
        c_bufferp = (dga_internal_buffer)dgawin->stencil;
        if ( c_bufferp->bufferp )
            return dgawin->stencil;
        GET_SW_HW_BUFFER(c_bufferp, infop->wx_abuf.stencil_fn, infop->wx_abuf.stencil_size);
        break;
    case DGA_ACCUM_BUFFER:
        c_bufferp = (dga_internal_buffer)dgawin->accum;
        if ( c_bufferp->bufferp )
            return dgawin->accum;
        GET_SW_HW_BUFFER(c_bufferp, infop->wx_abuf.accum_fn, infop->wx_abuf.accum_size);
        break;
    case DGA_ALPHA_BUFFER:
        c_bufferp = (dga_internal_buffer)dgawin->alpha;
        if ( c_bufferp->bufferp )
            return dgawin->alpha;
        GET_SW_HW_BUFFER(c_bufferp, infop->wx_abuf.alpha_fn, infop->wx_abuf.alpha_size);
        break;
    default:
        return (0);
    }

    /* If grab_cnt is "0", then the reinitialization should go thru'
     * server.  We can not just increment the grab_cnt.
     * There is a chance that the buffers capabilities might have
     * been changed in which case the server gets the bitsPerPixel
     * from SunExtVis info struct and reallocates the buffer.
     * If buffer_site is not DGA_SITE_SYSTEM, then it might be
     * a Hardware Buffers.
     */
    if ( bufferp && (bufferp->buffer_site == DGA_SITE_SYSTEM) &&  
            bufferp->grab_cnt > 0 ) {
        bufferp->grab_cnt++;
        return (Dga_buffer ) ret_buf;
    }

    /*
     *  Request the server to allow DGA to the buffers associated
     *  with this Dga_window.
     */
    if (!XDgaGrabABuffers(dpy, win, type, buffer_site)) {
#ifdef DEBUG
        (void)fprintf(stderr, "dga_draw_grab_buffer: XDgaGrabABuffers failed\n");
#endif
        return (0);
    }

    /* infop will contain the proper pointer to the selected buffer since
     * it is in the dga shared page.
     */
    infop = wx_infop(dgawin) ;
 
    /* get_specified_buffer:  This function checks on the filenames
     * where if it is software buffer this member should have a 
     * valid file name.
     * If it is NULL, then it may be a hardware buffer and just
     * return from this point where the hardware buffer would have
     * been allocated already.
     */
    switch ( type ) {
    case DGA_BACK_BUFFER:
        c_bufferp = (dga_internal_buffer)dgawin->back;
        GET_SW_HW_BUFFER(c_bufferp, infop->wx_abuf.back_fn, infop->wx_abuf.back_size);
        break;
        
    case DGA_DEPTH_BUFFER:
        c_bufferp = (dga_internal_buffer)dgawin->depth;
        GET_SW_HW_BUFFER(c_bufferp, infop->wx_abuf.depth_fn, infop->wx_abuf.depth_size);
        break;

    case DGA_STENCIL_BUFFER:
        c_bufferp = (dga_internal_buffer)dgawin->stencil;
        GET_SW_HW_BUFFER(c_bufferp, infop->wx_abuf.stencil_fn, infop->wx_abuf.stencil_size);
        break;

    case DGA_ACCUM_BUFFER:
        c_bufferp = (dga_internal_buffer)dgawin->accum;
        GET_SW_HW_BUFFER(c_bufferp, infop->wx_abuf.accum_fn, infop->wx_abuf.accum_size);
        break;

    case DGA_ALPHA_BUFFER:
        c_bufferp = (dga_internal_buffer)dgawin->alpha;
        GET_SW_HW_BUFFER(c_bufferp, infop->wx_abuf.alpha_fn, infop->wx_abuf.alpha_size);
        break; 

    }

    if ( bufferp ) {
        bufferp->pDraw = ret_buf->pDraw = dgadraw;
        return (Dga_buffer) ret_buf;
    } else {
        if (buffer_site == DGA_SITE_DEVICE)
            return (Dga_buffer) c_bufferp;
    }

    return NULL;
}

/*
 * Name    : dga_draw_ungrab_buffer
 * Synopsis: This function ungrabs the buffer for the specified drawable
 * which has been grabbed previously. Note that ungrabbing a buffer does
 * not necessarily cause it to be freed.  If any of these steps fail,
 * zero is returned.  True is returned upon success.
 *
 * Implementation: If the buffer is grabbed already, this function
 * decrements the grab_cnt.  If grab_cnt  is negative, it will be 
 * reset to "0".  
 * If this client hasn't grabbed the buffer already, this function returns 0.
 * This function will send a request to the server to ungrab the
 * buffer only if buffer grabbed is in DGA_SITE_DEVICE ( Hardware ).
 */
int
dga_draw_ungrab_buffer(Dga_drawable dgadraw, Dga_buffer_type type)
{
    _Dga_window dgawin = (_Dga_window)dgadraw;
    WXINFO     *infop;
    Display     *dpy;
    Window       win;
    dga_buffer  bufferp = NULL;
    dga_internal_buffer ret_buf = NULL;
    dga_internal_buffer c_bufferp = NULL;

    /* Ancillary Buffers are not supported for drawable_type 
     * DGA_DRAW_PIXMAP
     */
    if ( ((_Dga_drawable)dgadraw)->drawable_type != DGA_DRAW_WINDOW ) 
        return (0);

    if (!DGA_LOCKSUBJ_WINDOW(dgawin, dgawin->eLockSubj)) 
        return (0);

    if ((dgawin == (_Dga_window) NULL)) {
#ifdef DEBUG
        (void) fprintf(stderr, "dga_draw_ungrab_buffer: passed null pointer\n");
#endif
        return (0);
    }

    /*
     *  Find out if this is an X window.  If so get the Display and window
     *  id.
     */
    if (!_dga_is_X_window(dgawin->w_token, &dpy, &win)) {
#ifdef DEBUG
        (void) fprintf(stderr, "dga_draw_ungrab_buffer: Unsupported window type\n");
#endif
        return (0);
    }

    infop = wx_infop(dgawin) ;
 
    switch ( type ) {
    case DGA_BACK_BUFFER:
        c_bufferp = (dga_internal_buffer)dgawin->back;
        if ( c_bufferp->bufferp )
            return 0;   
        GET_SW_HW_BUFFER(c_bufferp, infop->wx_abuf.back_fn, infop->wx_abuf.back_size);
        break;
    case DGA_DEPTH_BUFFER:
        c_bufferp = (dga_internal_buffer)dgawin->depth;
        if ( c_bufferp->bufferp )
            return 0;   
        GET_SW_HW_BUFFER(c_bufferp, infop->wx_abuf.depth_fn, infop->wx_abuf.depth_size);
        break;
    case DGA_STENCIL_BUFFER:
        c_bufferp = (dga_internal_buffer)dgawin->stencil;
        if ( c_bufferp->bufferp )
            return 0;   
        GET_SW_HW_BUFFER(c_bufferp, infop->wx_abuf.stencil_fn, infop->wx_abuf.stencil_size);
        break;
    case DGA_ACCUM_BUFFER:
        c_bufferp = (dga_internal_buffer)dgawin->accum;
        if ( c_bufferp->bufferp )
            return 0;   
        GET_SW_HW_BUFFER(c_bufferp, infop->wx_abuf.accum_fn, infop->wx_abuf.accum_size);
        break;
    case DGA_ALPHA_BUFFER:
        c_bufferp = (dga_internal_buffer)dgawin->alpha;
        if ( c_bufferp->bufferp )
            return 0;   
        GET_SW_HW_BUFFER(c_bufferp, infop->wx_abuf.alpha_fn, infop->wx_abuf.alpha_size);
        break;
    default:
        return (0);
    } /* end of switch ( type ).. */

/* Currently Just decrement the grab_cnt and if there is no grab
 * don't free it.  Next time when it is getting grabbed, we will
 * increment the count
 * If the when the grab_cnt is "0" and the dga_drawable is getting
 * resized then the buffers are thrown away.
 */

    if ( !bufferp )
        return (0);
        
    if ( bufferp->buffer_site == DGA_SITE_SYSTEM ) {
        bufferp->grab_cnt--;

        if ( bufferp->grab_cnt < 0 ) 
            bufferp->grab_cnt = 0;

        switch ( type ) {
        case DGA_BACK_BUFFER:
            ((dga_internal_buffer)dgawin->back)->bufferp = NULL;
            break;
        case DGA_DEPTH_BUFFER:
            ((dga_internal_buffer)dgawin->depth)->bufferp = NULL;
            break;
        case DGA_STENCIL_BUFFER:
            ((dga_internal_buffer)dgawin->stencil)->bufferp = NULL;
            break;
        case DGA_ACCUM_BUFFER:
            ((dga_internal_buffer)dgawin->accum)->bufferp = NULL;
            break;
        case DGA_ALPHA_BUFFER:
            ((dga_internal_buffer)dgawin->alpha)->bufferp = NULL;
            break;
        default:
            return (0);
        } /* end of switch */
    }
    else {
        /* Buffer site is DGA_SITE_DEVICE */
        if (!XDgaUnGrabABuffers(dpy, win, type)) {
#ifdef DEBUG
        (void) fprintf(stderr, "dga_draw_ungrab_buffer: XDgaUnGrabABuffers failed\n");
#endif
        return (0);

        }
    } /* end of ( ret_buf->buffer_site == DGA_SITE_SYSTEM ).. */

    return 1;
}

/*
 * Name    : dga_draw_get_buffers
 * Synopsis: This function returns the number of ancillary buffers
 * associated with the specified dgadraw and an arry of buffer
 * pointers.  Note that only buffers which have been grabbed by
 * the client are returned.  Buffers which might exist (because of 
 * grabs by other clients or the server) are not returned.
 */
int
dga_draw_get_buffers(Dga_drawable dgadraw, Dga_buffer **pBufs )
{
    char        *filename;
    int         count = 0;
    dga_buffer  bufferp = NULL;
    static      void     *buffers[DGA_NUM_BUFFER_TYPES];
    _Dga_window dgawin = (_Dga_window)dgadraw;
    WXINFO      *infop = wx_infop(dgawin);
    int         resize_flag = False;
    
    if ( dgawin->buf_resize_flag < infop->wx_abuf.s_modified )
        resize_flag = True;

    STORE_BUFFERS((dga_internal_buffer)dgawin->back, infop->wx_abuf.back_fn, infop->wx_abuf.back_fn[0], infop->wx_abuf.back_size);

    STORE_BUFFERS((dga_internal_buffer)dgawin->depth, infop->wx_abuf.depth_fn, infop->wx_abuf.depth_fn[0], infop->wx_abuf.depth_size);

    STORE_BUFFERS((dga_internal_buffer)dgawin->stencil, infop->wx_abuf.stencil_fn, infop->wx_abuf.stencil_fn[0], infop->wx_abuf.stencil_size);

    STORE_BUFFERS((dga_internal_buffer)dgawin->accum, infop->wx_abuf.accum_fn, infop->wx_abuf.accum_fn[0], infop->wx_abuf.accum_size);

    STORE_BUFFERS((dga_internal_buffer)dgawin->alpha, infop->wx_abuf.alpha_fn, infop->wx_abuf.alpha_fn[0], infop->wx_abuf.alpha_size);

    if ( resize_flag )
        dgawin->buf_resize_flag = infop->wx_abuf.s_modified;
 
    *pBufs = buffers;

    return count;
}


/*
 * Name    : dga_buffer_type
 * Synopsis: This function returns the type of the buffer specified.
 */
Dga_buffer_type
dga_buffer_type(Dga_buffer bufferp)
{
    _Dga_window dgawin;
    WXINFO      *infop;
    dga_buffer local_buf;
 
    if ( !bufferp || !(local_buf = ((dga_internal_buffer)bufferp)->bufferp))
        return -1;
 
    dgawin =  (_Dga_window)((dga_internal_buffer)bufferp)->pDraw;
    infop  = wx_infop(dgawin);
 
    if ( dgawin->buf_resize_flag < infop->wx_abuf.s_modified ) {
        remap_buffers((Dga_drawable)((dga_internal_buffer)bufferp)->pDraw);
        local_buf = ((dga_internal_buffer)bufferp)->bufferp;
    }
 
    return local_buf->buffer_type;
}


#if 0
/* We had this function for completeness. */
/*
 * Name    : dga_buffer_get_drawable
 * Synopsis: This function returns the Dga_drawable associated with the
 * buffer specified.
 */
Dga_drawable
dga_buffer_get_drawable(Dga_buffer bufferp )
{
    if ( !bufferp )
        return NULL;

    return ((dga_buffer)bufferp)->pDraw;
}
#endif


/*
 * Name    : dga_buffer_site (Lock Only)
 * Synopsis: This function returns the site of the buffer specified.
 * The values are the same as those returned by dga_draw_site().
 * DGA_SITE_SYSTEM, DGA_SITE_DEVICE and DGA_SITE_NULL.
 */
int
dga_buffer_site(Dga_buffer bufferp)
{
    _Dga_window dgawin;
    WXINFO      *infop;
    dga_buffer local_buf;
 
    if ( !bufferp || !(local_buf = ((dga_internal_buffer)bufferp)->bufferp))
        return DGA_SITE_NULL;  
 
    dgawin =  (_Dga_window)((dga_internal_buffer)bufferp)->pDraw;
    infop  = wx_infop(dgawin);
 
    if ( dgawin->buf_resize_flag < infop->wx_abuf.s_modified ) {
        remap_buffers((Dga_drawable)((dga_internal_buffer)bufferp)->pDraw);
        local_buf = ((dga_internal_buffer)bufferp)->bufferp;
    }

    return local_buf->buffer_site;
}


/*
 * Name    : dga_draw_bufferchg
 * Synopsis: This function returns True if any of the buffers 
 * associated with the dgadraw have undergone a state change
 * since the last lock.  When dga_draw_bufferchg returns True,
 * the client should call dga_buffer_sitechg for each of the
 * Drawable's buffers.
 */
int
dga_draw_bufferchg(Dga_drawable dgadraw)
{
    _Dga_window dgawin = (_Dga_window)dgadraw;
    WXINFO      *infop = wx_infop(dgawin);

    if (infop && (infop->wx_abuf.s_modified))
        return True;
 
    return False;
}

/*
 * Name    : dga_buffer_sitechg
 * Synopsis: This function returns True if the buffer has sitechg 
 * flag set.  Note that this function always returns False for 
 * device buffers.  Only memory buffers ever have a site chagne.
 * dga_buffer_sitechg() also returns the reason for site change.
 * Currenly the only possible values for reason are DGA_SITECHG_INITIAL,
 * which is reported the first time a Drawable is locaked after a buffer
 * has been created and DGA_SITECHG_CACHE which indicates that the
 * buffer has been resized since the time that the Dga_drawable was last 
 * locked.
 */
int
dga_buffer_sitechg(Dga_buffer bufferp, int *reason)
{
    _Dga_window dgawin; 
    WXINFO      *infop; 
    dga_buffer local_buf;
 
    if ( !bufferp || !(local_buf = ((dga_internal_buffer)bufferp)->bufferp))
        return False; /* Returning False may mislead the developer */
 
    dgawin =  (_Dga_window)((dga_internal_buffer)bufferp)->pDraw;
    infop  = wx_infop(dgawin);
 
    if ( dgawin->buf_resize_flag < infop->wx_abuf.s_modified ) {
        remap_buffers((Dga_drawable)((dga_internal_buffer)bufferp)->pDraw);
        local_buf = ((dga_internal_buffer)bufferp)->bufferp;
    }
 
    if  (local_buf->buffer_site != DGA_SITE_SYSTEM)
        return False;

    if (local_buf->sitechg) {
        *reason = local_buf->sitechg;
        local_buf->sitechg = DGA_SITECHG_UNKNOWN;
        return True;
    } else
        return False;
}

/*
 * Name    : dga_buffer_address (Lock Only)
 * Synopsis: This function returns the data pointer from the shared
 * buffer page of the buffer specified.  An address will be returned
 * only for buffers which are located in system memory.  
 * If dga_buffer_address is called on a buffer located with 
 * DGA_SITE_DEVICE, NULL will be returned.  The value returned 
 * remains valid across locks until a sitechg is reported as 
 * described above.
 */
void *
dga_buffer_address(Dga_buffer bufferp)
{
    _Dga_window dgawin; 
    WXINFO      *infop; 
    dga_buffer local_buf;
 
    if ( !bufferp || !(local_buf = ((dga_internal_buffer)bufferp)->bufferp))
        return NULL;
 
    dgawin =  (_Dga_window)((dga_internal_buffer)bufferp)->pDraw;
    infop  = wx_infop(dgawin);

    if ( dgawin->buf_resize_flag < infop->wx_abuf.s_modified ) {
        remap_buffers((Dga_drawable)((dga_internal_buffer)bufferp)->pDraw);
        local_buf = ((dga_internal_buffer)bufferp)->bufferp;
    }
 
    if  (local_buf->buffer_site == DGA_SITE_SYSTEM) {
        local_buf->data = (char *)(local_buf + 1);
        return local_buf->data; 
    }
    else
        return NULL;
}

/*
 * Name    : dga_buffer_linebytes
 * Synopsis: This function returns the number of bytes per scanline
 * of the buffer specified.  Only buffers which are located in
 * system memory are addressable.  If dga_buffer_linebytes is called
 * for a buffer located on the device, "0" is returned.
 */
int
dga_buffer_linebytes(Dga_buffer bufferp)
{
    _Dga_window dgawin; 
    WXINFO      *infop; 
    dga_buffer local_buf;

    if ( !bufferp || !(local_buf = ((dga_internal_buffer)bufferp)->bufferp))
        return 0;
 
    dgawin =  (_Dga_window)((dga_internal_buffer)bufferp)->pDraw;
    infop  = wx_infop(dgawin);
 
    if ( dgawin->buf_resize_flag < infop->wx_abuf.s_modified ) {
        remap_buffers((Dga_drawable)((dga_internal_buffer)bufferp)->pDraw);
        local_buf = ((dga_internal_buffer)bufferp)->bufferp;
    }

    if  (local_buf->buffer_site == DGA_SITE_SYSTEM)
        return local_buf->linebytes; 
    else
        return 0;
}

/*
 * Name    : dga_buffer_bitsperpixel
 * Synopsis: This function returns bitsperpixel of the buffer 
 * specified if the buffer is located in system memory.  If the
 * buffer is located on the device, zero is returned.  Note that
 * the value might be different than the number of significant bits.
 * For example, an unpacked 4 bit stencil buffer would return
 * 8 bits per pixel, and a 24 bit Z buffer would return 
 * 32 bits per pixel.
 */
int
dga_buffer_bitsperpixel(Dga_buffer bufferp)
{
    _Dga_window dgawin; 
    WXINFO      *infop; 
    dga_buffer local_buf;

    if ( !bufferp || !(local_buf = ((dga_internal_buffer)bufferp)->bufferp))
        return 0;

    dgawin =  (_Dga_window)((dga_internal_buffer)bufferp)->pDraw;
    infop  = wx_infop(dgawin);

    if ( dgawin->buf_resize_flag < infop->wx_abuf.s_modified ) {
        remap_buffers((Dga_drawable)((dga_internal_buffer)bufferp)->pDraw);
        local_buf = ((dga_internal_buffer)bufferp)->bufferp;
    }

    if  (local_buf->buffer_site == DGA_SITE_SYSTEM)
        return local_buf->bitsPerPixel; 
    else
        return 0;
}

void
dga_draw_buffer_swap(Dga_drawable dgadraw, int (*visfunc)(Dga_window))
{
     _Dga_window dgawin = (_Dga_window)dgadraw;
     WXINFO      *infop = wx_infop(dgawin);

    if (visfunc)
        (*visfunc)(dgawin);

    if ( infop && infop->wx_abuf.back_fn && infop->wx_abuf.back_fn[0] 
                && infop->wx_abuf.back ) {
        infop->wx_abuf.buffer_swap++;
        dgawin->c_buffer_swap = infop->wx_abuf.buffer_swap;
    }
 
    return; 
}

int
dga_draw_swap_check(Dga_drawable dgadraw)
{
    _Dga_window dgawin = (_Dga_window)dgadraw;
    WXINFO      *infop = wx_infop(dgawin);
 
    if ( infop && infop->wx_abuf.back_fn && infop->wx_abuf.back_fn[0]  
           && infop->wx_abuf.back 
           && ( dgawin->c_buffer_swap != infop->wx_abuf.buffer_swap)) {
        dgawin->c_buffer_swap = infop->wx_abuf.buffer_swap;
        return 1;
    }

    return 0; 
}