/* Copyright (c) 1993, 2015, 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.
 */


/* 
 * win_grab.c - the client side code for DGA window grabber
 */

/****
 *
 *
 *	Shared window synchronization routines - client side
 *
 *
 *
 * Functions:
 *
 *    Dga_window
 *    dga_win_grab(devfd, token)
 *		int		devfd ;
 *		Dga_token	token ;
 *
 *	Grab a window.  'token' is the window-info handle returned by
 *	XDgaGrabWindow.  'devfd' is the file descriptor of the frame buffer
 *	if known, -1 otherwise.  If you specify -1, dga_win_grab will open the
 *	frame buffer.  The frame buffer fd may be inquired from the returned
 *	Dga_window structure via the dga_win_devfd() routine.
 *
 *	Returns a pointer to the a struct dga_window on success, NULL on
 *	failure.
 *
 *
 *
 *    dga_win_ungrab(infop, cflag)
 *		Dga_window	infop ;
 *		int		cflag ;
 *
 *	Ungrab a window.  All resources allocated by dga_win_grab are freed.
 *	If 'cflag' is nonzero, the framebuffer fd described for the device
 *	is also closed.
 *
 *	The application should call XDgaUnGrabWindow(dpy,win) after
 *	calling dga_win_ungrab() so that the server may free the window-info
 *	page at the other end.
 *
 *
 *
 *	short *
 *	dga_win_clipinfo(win)
 *		Dga_window	win ;
 *
 *	Returns pointer to cliplist.  Replaces old wx_sh_clipinfo_c() macro.
 *
 *
 *
 *	char *
 *	dga_win_fbname(win)
 *		Dga_window	win ;
 *
 *	Returns name of fb.  Replaces old wx_devname_c() macro.
 *
 *
 *
 *	int
 *	dga_win_clipchg(win)
 *		Dga_window	win ;
 *
 *	Returns 1 if cliplist changed since last call.  Replaces old
 *	wx_modif_c() and wx_seen_c() macros.
 *
 *
 *
 *	int
 *	dga_win_curschg(win)
 *		Dga_window	win ;
 *
 *	Returns 1 if cursor changed since last call.
 *
 *
 *
 *	int
 *	dga_win_rtnchg(win)
 *		Dga_window	win ;
 *
 *	Returns 1 if retained info changed since last call.
 *
 *
 *
 *	int
 *	dga_win_devfd(win)
 *		Dga_window	win ;
 *
 *	Returns framebuffer fd.
 *
 *
 *
 *	dga_win_bbox(win, xp, yp, widthp, heightp)
 *		Dga_window win;
 *		int *xp, *yp, *widthp, *heightp;
 *
 *	Returns window bounding box
 *
 *
 *
 *	int
 *	dga_win_singlerect(win)
 *		Dga_window win;
 *
 *	Returns nonzero if the window is a single rectangle.
 *
 *
 *
 *	int
 *	dga_win_empty(win)
 *		Dga_window win;
 *
 *	Returns nonzero if the window is empty.
 *
 *
 *
 *	int
 *	dga_win_obscured(win)
 *		Dga_window win;
 *
 *	Returns nonzero if the window is obscured.
 *
 *
 *
 *	int
 *	dga_win_cursactive(win)
 *		Dga_window win;
 *
 *	Returns nonzero if the cursor grabber is active.
 *
 *
 *
 *	void
 *	dga_win_cursupdate(win, func, data)
 *		Dga_window	win;
 *		void		(*func)();
 *		void*		data;
 *
 *	Decide if the cursor needs to be taken down, and if so, call
 *		(*func)(data, win, x, y, mem)
 *			void*		data ;
 *			Dga_window	win ;
 *			int		x,y ;
 *			Dga_curs_mpr	*mem ;
 *
 *
 *
 *	Dga_dbinfo *
 *	dga_win_dbinfop(win)
 *		Dga_window win;
 *
 *	Return dbinfo pointer.
 *
 *
 *
 *	Dga_widinfo *
 *	dga_win_widinfop(win)
 *		Dga_window win;
 *
 *	Return window id info pointer.
 *
 *      dga_win_depth(win)
 *              Dga_window win;
 *
 *      Return windows depth .
 *
 *
 *      dga_win_borderwidth(win) 
 *              Dga_window win; 
 * 
 *      Return windows borderwidth .   
 *
 * 	void 
 * 	dga_win_set_client_infop(win, client_info_ptr)
 *		Dga_window win;
 *		void* client_info_ptr;
 *	Sets a client specific pointer in Dga_window
 *
 *
 *      dga_win_get_client_infop(win) 
 *              Dga_window win;
 * 	Returns the client specific pointer
 *
 ****/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#ifdef SERVER_DGA
#include <X11/X.h>
#include <X11/Xmd.h>
#include "windowstr.h"
#include "dga_externaldefs.h"
#include "dga/dgawinstr.h"
#else
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <X11/Xlib.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#ifdef SVR4
#include <sys/fbio.h>
#include <sys/fcntl.h>
#else
#include <sun/fbio.h>
#include <fcntl.h>
#endif
#endif /* SERVER_DGA */

#include "dga_incls.h"
#include "rtn_grab.h"
 
#define	GRABFILE	"/tmp/wg"
#define	CURGFILE	"/tmp/curg"
#define	NDIGITS		8

#define	MINSHMEMSIZE	(8*1024)
#define	MAXSHMEMSIZE	(0x00040000)
#define WX_PAGESZ       (8*1024)

#if 0
#ifdef DEBUG
extern	int	sys_nerr;
extern	char	*sys_errlist[] ;
#endif
#endif

extern int _dga_winlockat(u_long cookie, int **lockp, int **unlockp);
extern int _dga_winlockdt(int *lockp, int *unlockp);

/* Some structure definition for internal bookkeeping */
typedef struct dga_winlist {
    Dga_token		w_token;	 /* Token associated with win */
    struct dga_window	*dga_clientplist;/*List of client ptrs in win */
    struct dga_window	*dga_clientplist_draw; /* List of client ptrs in win
						* using drawable i/f. */
    struct dga_winlist	*next_winlist;  /* Next link in the dga list */
#ifdef MT
    mutex_t		mutex;
#endif
	
} *Dga_winlist;

static struct dga_winlist *dga_wlist = NULL;

static int 	dga_win_update(Dga_drawable dgawin);
static int	dgai_win_initMbufset (_Dga_window dgawin);
static void	release_lockpages(int devfd, _Dga_window clientp);
static _Dga_window check_other_curg_windows(WXINFO *);
void     dgai_win_ungrab_common(_Dga_window dgawin, int cflag,int drawableGrabber);
int 	dgai_win_check_multiple_grab(_Dga_window dgawin, int drawableGrabber);
void safe_free_clientp(_Dga_window clientp);

/*bug fix for 4248958: use safe_free_client() to replace free() */
void
safe_free_clientp(clientp)
    _Dga_window  clientp;
{
     
    if(clientp){
        if(clientp->back) free(clientp->back);
        if(clientp->depth) free(clientp->depth);
        if(clientp->stencil) free(clientp->stencil);
        if(clientp->accum) free(clientp->accum);
        if(clientp->alpha) free(clientp->alpha);
        free(clientp);
    }
}

/******************************************
 *
 * dgai_win_grab_common:
 *
 *	create shared memory file for window information
 *	map to lock page
 *
 *	arguments:
 *
 *	int	devfd;	INPUT
 *		file descriptor of graphics device
 *
 *	Dga_token	token;	INPUT
 *		magic cookie supplied by the server
 *
 *	returns a user virtual address for a dga_window structure.
 *	returns NULL if anything goes awry.
 *
 *	'devfd' is the file descriptor of the frame buffer, if known,
 *	-1 otherwise.  If you specify -1, wx_grab will open the
 *	frame buffer.  The frame buffer fd may be inquired from the returned
 *	Dga_window ptr to the struct dga_window via the dga_win_devfd() routine.
 *
 *****************************************/


/*
** Shared between both drawable grabber and window compatibility interface.
*/

Dga_window
dgai_win_grab_common (Display *dpy, int devfd, Dga_token token, int drawableGrabber)
{
	WXINFO	*infop;
	_Dga_window clientp = NULL;
	Dga_winlist wlist;
	int	lockfd ;
	Dga_lockp	lockp, unlockp ;
	char	filename[sizeof(GRABFILE)+NDIGITS+1];
	int	filefd;
	int	locktype ;
	int	i;
#ifdef SERVER_DGA
	WindowPtr	pWin;
	Window		win;

	if (!_dga_is_X_window(token, &dpy, &win)) {
	    return  NULL;
        }
	pWin = (WindowPtr)LookupIDByType(win, RT_WINDOW);
#endif /* SERVER_DGA */

	/* First, check if already grabbed by this client. Note that we
	   always treat the new drawable and old window grabbers separately */
	for(wlist = dga_wlist;wlist != NULL;wlist = wlist->next_winlist) {
	    if (wlist->w_token == token) {
		_Dga_window orig_clientp,new_clientp;

		/* If multiple clients are grabbing the same
		 * window, then we duplicate the per client info
		 * structure and return that instead of the original
		 * allocated clientp structure. Also remember to add
		 * this new info structure to the linked list. This 
		 * change obsoletes the w_grab_count field which
		 * will always be equal to 1
		 */

		if ((new_clientp =  
		  (_Dga_window) malloc(sizeof(struct dga_window))) == NULL)
		    return NULL ;

		if (drawableGrabber) {
		    if (wlist->dga_clientplist_draw)
		        orig_clientp = wlist->dga_clientplist_draw;
                    else
			orig_clientp = wlist->dga_clientplist;
		    *new_clientp = *orig_clientp;
		    new_clientp->w_lockcnt =0;
		    new_clientp->w_grab_count =1;
    
		    if (wlist->dga_clientplist_draw) {
		        /* Add it to the list of clientp structure associated
		         * with this window */

		        new_clientp->w_next = orig_clientp;
		    } else {
			
			/* Need to initialize all drawableGrabber
			 * specific data. */

			infop = (WXINFO *)new_clientp->w_info;
			if (infop->info_sz != sizeof(WXINFO)) {
				/* mismatch on 64 bit port or other trouble */
	    		fprintf(stderr, 
"wx_grab: mismatch on shared WXINFO size info page is %d sizeof is %d \n",
				infop->info_sz, sizeof(WXINFO));
				free(new_clientp);
				return(NULL);
			}
			new_clientp->drawable_type = DGA_DRAW_WINDOW;
			new_clientp->w_update_func = 
				      (int(*)())dgai_mbsmemb_update;
                        new_clientp->c_mbufseq = 0;
                        new_clientp->s_mbufseq_p = &infop->w_mbsInfo.mbufseq;
                        new_clientp->c_mbcomposseq = 0;
                        new_clientp->s_mbcomposseq_p = 
                                          &infop->w_mbsInfo.compositionseq;
                        new_clientp->s_devinfoseq_p = &infop->w_devinfoseq;
                        new_clientp->c_devinfoseq = 0;
                        new_clientp->siteNotifyFunc = NULL;
                        new_clientp->siteNotifyClientData = NULL;
                        new_clientp->mbNotifyFunc = NULL;
                        new_clientp->mbNotifyClientData = NULL;
                        new_clientp->rendBufNotifyFunc = NULL;
                        new_clientp->rendBufNotifyClientData = NULL;
                        new_clientp->rLockSubj = DGA_LOCKSUBJ_INVALID;
                        new_clientp->eLockSubj = DGA_LOCKSUBJ_INVALID;
                        new_clientp->eLockSubjPrev = DGA_LOCKSUBJ_INVALID;
                        new_clientp->changeMask = 0;
                        new_clientp->prevWasMbuffered = 0;
                        new_clientp->mbChgReason = DGA_MBCHG_UNKNOWN;
                        new_clientp->siteChgReason = DGA_SITECHG_UNKNOWN;
                        new_clientp->prevLocked = 0;
			if ((dpy != NULL) && drawableGrabber) {
			    if (!dgai_win_initMbufset(new_clientp)) {
				dga_win_ungrab(new_clientp, 0);
			    }
                        }
			new_clientp->w_next = NULL;
		    }
		    wlist->dga_clientplist_draw = new_clientp;

		    /* the same mbufset is shared between all client 
		     * structures for this window */

		    if (orig_clientp->pMbs) {
		        dgai_mbufset_incref(orig_clientp->pMbs);
		    }
#ifdef MT
		    new_clientp->mutexp = &wlist->mutex;
			/* Same window was grabbed 2 or more times via the
             * drawable interface so turn per-drawable MT
             * locking on if we are linked with -lthread also.
             */
            if (dgaThreaded) {
            /* Currently, this variable gets set to 1 and
             * never gets turned off.  This could be optimized
             * if needed.
             */
            dgaMTOn = 1;
            }
#endif
		    return new_clientp;

		} else {
		    if (wlist->dga_clientplist)
		        orig_clientp = wlist->dga_clientplist;
		    else
			orig_clientp = wlist->dga_clientplist_draw;
		    *new_clientp = *orig_clientp;
	            new_clientp->w_update_func = dga_win_update;
		    new_clientp->w_lockcnt =0;
		    new_clientp->w_grab_count =1;

		    if (wlist->dga_clientplist) {
			/* Add it to the list of clientp structure associated
		         * with this window */
		        new_clientp->w_next = orig_clientp;
                    } else {
			new_clientp->w_next = NULL;
		    }
		    wlist->dga_clientplist = new_clientp;
#ifdef MT
		    new_clientp->mutexp = &wlist->mutex;
#endif
		    return new_clientp;

		}
	    }
	}

	if( (clientp = 
	    (_Dga_window) malloc(sizeof(struct dga_window))) == NULL )
	    return NULL ;
	memset(clientp, 0, sizeof(struct dga_window));
	
#ifdef SERVER_DGA
        {                  
            /* Now get a pointer to the shared info page from
             * pWin's private data */
     
            DgaSetupWindow(pWin);
            WDEV    *wdev;
     
            wdev = pDgaWindow->pDgaWdev;
            infop = (WXINFO *)wdev->infop;
            if (infop == NULL) return NULL;
         }
#else
	sprintf(filename, "%s%08x", GRABFILE, token);

        if ((filefd = open(filename,O_RDWR,0666))<0) {
	    safe_free_clientp(clientp) ;
	    return((Dga_window)NULL);
	}

	/* map the wx_winfo area */
        infop = (WXINFO *)mmap(0,
		    MAXSHMEMSIZE,
		    PROT_READ|PROT_WRITE,
		    MAP_SHARED,
		    filefd,
		    (off_t)0);

	if (infop == (WXINFO *)-1) {
	    close(filefd);
	    safe_free_clientp(clientp) ;
	    return((Dga_window)NULL);
	}
	if (infop->info_sz != sizeof(WXINFO)) {
		/* mismatch on 64 bit port or other trouble */
#ifdef DEBUG
   		fprintf(stderr, 
	"wx_grab: mismatch on WXINFO size info page is %d sizeof is %d \n",
			infop->info_sz, sizeof(WXINFO));
#endif
	    munmap((caddr_t)infop, MAXSHMEMSIZE) ;
	    close(filefd) ;
	    safe_free_clientp(clientp) ;
	    return(NULL);
	}

	/* open the frame buffer if not already opened by client */
	if( devfd >= 0 )
	  lockfd = devfd ;
	else {
	  lockfd = open(infop->w_devname, O_RDWR,0666) ;
	  if( lockfd < 0 )  {
#ifdef DEBUG
	    fprintf(stderr, "wx_grab: cannot open %s, %s\n",
		infop->w_devname, strerror(errno)) ;
#endif
	    munmap((caddr_t)infop, MAXSHMEMSIZE) ;
	    close(filefd) ;
	    safe_free_clientp(clientp) ;
	    return NULL ;
	  }
	}
#endif /* SERVER_DGA */

	if (drawableGrabber) {
	    clientp->drawable_type = DGA_DRAW_WINDOW;
	}
	clientp->w_dpy = dpy;
	clientp->w_info = (void*)infop ;
	clientp->w_infofd = 0; /* no longer needed */
	clientp->w_next = NULL;

	clientp->curs_info = NULL; /* must set up here, may be changed below */
	clientp->curs_fd = -1;

#ifdef SERVER_DGA
	clientp->w_devfd = infop->w_sdevfd; ;
        clientp->w_lockp = (Dga_lockp)infop->w_slockp;
        clientp->w_unlockp = (Dga_lockp)infop->w_slockp;
    
        clientp->w_lib_private = (void *) infop; /* PRIVATE DATA  */
#else
	clientp->w_devfd = lockfd ;
	lockp = NULL; /* init to NULL for check below */
	unlockp = NULL;

	/* On cursor-grabbed devices, find out if we already have a
	 * lockp, unlockp, and cursor page mapping for this device.
	 * We don't want to grab the same lockpage, etc. twice.
	 */
	if (infop->w_version >= 2  &&  infop->c_sinfo) {
	    _Dga_window winp;

	    winp = check_other_curg_windows(infop);
	    if (winp) {
		clientp->curs_fd = winp->curs_fd;
		clientp->curs_info = winp->curs_info;
		lockp = winp->w_lockp;
		unlockp = winp->w_unlockp;
	    }
	}

	if (lockp == NULL) { 
	    /* only get new lock pages if necessary */
	    locktype = infop->w_version >= 2 ? infop->w_locktype : WG_LOCKDEV ;
	    switch( locktype ) {
		case WG_LOCKDEV:
		    /* map the lock page */
		    lockp = (Dga_lockp)mmap(0,
			WX_PAGESZ,
			PROT_READ|PROT_WRITE,
			MAP_SHARED,
			lockfd,(off_t)infop->w_cookie);

		    if (lockp == (Dga_lockp)-1) {
#ifdef DEBUG
		    fprintf(stderr, "wx_grab: cannot map lock page, %s\n",
			strerror(errno)) ;
#endif
		    munmap((caddr_t)infop, MAXSHMEMSIZE) ;
		    close(filefd);
		    if( devfd < 0 )
		    close(lockfd) ;
		    safe_free_clientp(clientp) ;
		    return(NULL);
		}

		/* map the unlock page */
		unlockp = (Dga_lockp)mmap(0,
			WX_PAGESZ,
			PROT_READ|PROT_WRITE,
			MAP_SHARED,
			lockfd,(off_t)infop->w_cookie) ;

		if(unlockp == (Dga_lockp)-1) {
#ifdef DEBUG
		fprintf(stderr, "wx_grab: cannot map unlock page\n") ;
#endif
		munmap((caddr_t)lockp, WX_PAGESZ) ;
		munmap((caddr_t)infop, MAXSHMEMSIZE) ;
		close(filefd);
		if( devfd < 0 )
		  close(lockfd) ;
		safe_free_clientp(clientp) ;
		return(NULL);
	    }
	    break ;

	    case WG_WINLOCK:
		if( _dga_winlockat(infop->w_cookie, &lockp, &unlockp) != 0 ) {
		    munmap((caddr_t)infop, MAXSHMEMSIZE);
		    close(filefd);
		    if( devfd < 0 )
			close(lockfd) ;
		    safe_free_clientp(clientp) ;
		    return(NULL);
		}
	    break ;
	  }
	}

	clientp->w_lockp = lockp ;
	clientp->w_unlockp = unlockp ;

	/* cursor grabber stuff */
	if ((infop->w_version >= 2)  &&  (infop->c_sinfo) &&
	  ((clientp->curs_fd == -1) || (clientp->curs_info == NULL))) {
	    char    cfn[sizeof(CURGFILE)+NDIGITS+1];
	    int	    curs_fd;
	    
	    strcpy(cfn,CURGFILE);
	    sprintf(cfn+sizeof(CURGFILE)-1,"%08x", infop->c_filesuffix);
	    
	    /* open the shared cursor page */
	    if ((curs_fd = open(cfn, O_RDWR,0666))<0) {
#ifdef DEBUG
		fprintf(stderr, "wx_grab: cannot open cursor grabber page\n") ;
#endif		
		release_lockpages(devfd, clientp);
		return((Dga_window)NULL);
	    }
	    clientp->curs_fd = curs_fd;

	    /* Map it */
	    clientp->curs_info = (caddr_t) mmap(0,
			MINSHMEMSIZE,	
			PROT_READ|PROT_WRITE,
			MAP_SHARED,
			curs_fd,
			(off_t)0);
			
	    if (clientp->curs_info == (caddr_t) -1) {
#ifdef DEBUG
		fprintf(stderr, "wx_grab: cannot map cursor page, %s\n",
		    strerror(errno)) ;
#endif
		close(curs_fd);
		release_lockpages(devfd, clientp);
		return(NULL);
	    }
	    /* check to see if you have a good magic number */
	    if (((Dga_cursinfo *) (clientp->curs_info))->c_magic !=
		DGA_CURG_MAGIC) {
#ifdef DEBUG
		fprintf(stderr, "wx_grab: wrong cursor page mapped, %s\n",
		    strerror(errno)) ;
#endif		
		munmap(clientp->curs_info, MINSHMEMSIZE) ;
		close(curs_fd);
		release_lockpages(devfd, clientp);
		return(NULL);
	    }
	}
#endif /* SERVER_DGA */

	/* success, fill out rest of structure */
	clientp->w_token = token;
	clientp->w_client = 0 ;
	clientp->c_clipseq = 0 ;
	clientp->s_clipseq_p = &(infop->u.vn.w_clipseq) ;
	if (drawableGrabber) {
	    clientp->w_update_func = (int(*)())dgai_mbsmemb_update;
	} else {
	    /* compatibility */
	    clientp->w_update_func = dga_win_update;
	}
#ifdef MT
	if (dgaThreaded) {
	    clientp->w_unlock_func = dgai_unlock;
	} else {
	    clientp->w_unlock_func = NULL;
	}
#else
	clientp->w_lock_func = NULL;
	clientp->w_unlock_func = NULL;
#endif
	clientp->w_lockcnt = 0;
	if (infop->w_version != 0) {
	  clientp->w_clipptr = (short *)((char *)infop+infop->u.vn.w_clipoff);
          clientp->w_cliplen = 0;
        }
	if (infop->w_version < 2) {
	    clientp->c_chngcnt = 0;
	    clientp->s_chngcnt_p = clientp->s_clipseq_p;
	} else {
	    clientp->c_chngcnt = 0;
	    clientp->s_chngcnt_p = &(infop->w_chng_cnt);
	    for (i = 0; i < DGA_MAX_GRABBABLE_BUFS + 1; i ++) {
	        clientp->c_wm_chngcnt[i] = 0;
#ifdef MT
	        clientp->shadow_chngcnt[i] = 0;
#endif
	    }
	}
        /* Now initialize the next field to pt to the second member of
         * c_wm_chngcnt array - this is specifically for performance
         * tuning of the lock macro
        */
        clientp->w_wm_2nd = clientp->c_wm_chngcnt + 1;

	if ((infop->w_version < 2) || (clientp->curs_info == NULL)) {
	    clientp->s_curseq_p = &clientp->c_curseq;
	    clientp->c_curseq = 0;
	} else {
	    clientp->s_curseq_p =
	        &(((Dga_cursinfo *) (clientp->curs_info))->c_chng_cnt);
	    clientp->c_curseq =
		((Dga_cursinfo *) (clientp->curs_info))->c_chng_cnt - 1;
	    /* so first test of dga_win_curschg will see a change */
	}

        clientp->back = (void *)malloc(sizeof(dga_internal_buffer_rec));
        if ( !clientp->back )
            return NULL;

        clientp->depth = (void *)malloc(sizeof(dga_internal_buffer_rec));
        if ( !clientp->depth )
            return NULL;

        clientp->stencil = (void *)malloc(sizeof(dga_internal_buffer_rec));
        if ( !clientp->stencil )
            return NULL;

        clientp->accum = (void *)malloc(sizeof(dga_internal_buffer_rec));
        if ( !clientp->accum )
            return NULL;

        clientp->alpha = (void *)malloc(sizeof(dga_internal_buffer_rec));
        if ( !clientp->alpha )
            return NULL;

        ((dga_internal_buffer)clientp->back)->bufferp = NULL;
        ((dga_internal_buffer)clientp->depth)->bufferp = NULL;
        ((dga_internal_buffer)clientp->stencil)->bufferp = NULL;
        ((dga_internal_buffer)clientp->accum)->bufferp = NULL;
        ((dga_internal_buffer)clientp->alpha)->bufferp = NULL;

        ((dga_internal_buffer)clientp->back)->pDraw = (Dga_drawable)clientp;
        ((dga_internal_buffer)clientp->depth)->pDraw = (Dga_drawable)clientp;
        ((dga_internal_buffer)clientp->stencil)->pDraw = (Dga_drawable)clientp;
        ((dga_internal_buffer)clientp->accum)->pDraw = (Dga_drawable)clientp;
        ((dga_internal_buffer)clientp->alpha)->pDraw = (Dga_drawable)clientp;

        ((dga_internal_buffer)clientp->back)->buf_size = 0;
        ((dga_internal_buffer)clientp->depth)->buf_size = 0;
        ((dga_internal_buffer)clientp->stencil)->buf_size = 0;
        ((dga_internal_buffer)clientp->accum)->buf_size = 0;
        ((dga_internal_buffer)clientp->alpha)->buf_size =  0;

        clientp->buf_resize_flag = 0;
        clientp->c_buffer_swap = 0;

	clientp->db_enabled = 0;
	clientp->c_rtnseq = 0;
	clientp->s_rtnseq_p = &clientp->c_rtnseq;
	clientp->rtn_info = NULL;
	clientp->rtn_flags = 0;

        /* initialization for drawable grabber code */
	clientp->pMbs = NULL;
	if (drawableGrabber) {
	    clientp->c_mbufseq = 0;
	    clientp->s_mbufseq_p = &infop->w_mbsInfo.mbufseq;
	    clientp->c_mbcomposseq = 0;
	    clientp->s_mbcomposseq_p = &infop->w_mbsInfo.compositionseq;
	    clientp->s_devinfoseq_p = &infop->w_devinfoseq;
	    clientp->c_devinfoseq = 0;
	    clientp->siteNotifyFunc = NULL;
	    clientp->siteNotifyClientData = NULL;
	    clientp->mbNotifyFunc = NULL;
	    clientp->mbNotifyClientData = NULL;
	    clientp->rendBufNotifyFunc = NULL;
	    clientp->rendBufNotifyClientData = NULL;
	    clientp->rLockSubj = DGA_LOCKSUBJ_INVALID;
	    clientp->eLockSubj = DGA_LOCKSUBJ_INVALID;
	    clientp->eLockSubjPrev = DGA_LOCKSUBJ_INVALID;
	    clientp->changeMask = 0;
	    clientp->prevWasMbuffered = 0;
	    clientp->mbChgReason = DGA_MBCHG_UNKNOWN;
	    clientp->siteChgReason = DGA_SITECHG_UNKNOWN;
	    clientp->prevLocked = 0;
	}

	/* add to linked list of grabbed windows - for internal bookkeeping
	 * Note: this should be done last in order for other code, e.g.
	 * check_other_curg_windows() to work correctly
	 */
	if (!dga_wlist) {

	   if ((dga_wlist = 
	    (Dga_winlist) malloc(sizeof(struct dga_winlist))) == NULL )
	    return NULL ;
	   dga_wlist->w_token = token;
	   if (drawableGrabber) {
	       dga_wlist->dga_clientplist_draw = clientp;
	       dga_wlist->dga_clientplist = NULL;
	   } else {
	       dga_wlist->dga_clientplist_draw = NULL;
	       dga_wlist->dga_clientplist = clientp;
	   }
	   dga_wlist->next_winlist = NULL;
	} else {
	   struct dga_winlist *new_wlist;
		
	   if ((new_wlist =
                   (Dga_winlist) malloc(sizeof(struct dga_winlist))) == NULL )
		return NULL;
	   new_wlist->w_token = token;
	   if (drawableGrabber) {
	       new_wlist->dga_clientplist_draw = clientp;
	       new_wlist->dga_clientplist = NULL;
	   } else {
	       new_wlist->dga_clientplist_draw = NULL;
	       new_wlist->dga_clientplist = clientp;
	   }
	   new_wlist->next_winlist = dga_wlist;
	   dga_wlist = new_wlist;
	}
#ifndef SERVER_DGA
	close(filefd) ;
#endif /* SERVER_DGA */

#ifdef MT
	mutex_init(&dga_wlist->mutex, USYNC_THREAD, NULL);
	clientp->mutexp = &dga_wlist->mutex;
#endif

	/* If window is multibuffered, initialize multibuffer set */
	/* If window is being grabbed through the old interface don't
	 * init the mbufset since mbuffers where not supported int
	 * older versions of DGA */
	if ((dpy != NULL) && drawableGrabber) {
	    if (!dgai_win_initMbufset(clientp)) {
		dga_win_ungrab(clientp, 0);
	    }
	}

	return((Dga_window)clientp);
}


Dga_window
dga_win_grab(devfd, token)
	int		devfd;
	Dga_token	token;
{
    /* Call the common grab routine with dpy == NULL to signify that
     * mbuffers are not to be initialized. */

    return (dgai_win_grab_common(NULL, devfd, token, 0));
}


#ifndef SERVER_DGA
static _Dga_window
check_other_curg_windows(infop)
WXINFO *infop;
{
	Dga_winlist winp;
	_Dga_window clientp;
	WXINFO *linfop;

	for(winp = dga_wlist; winp != NULL; winp = winp->next_winlist) {
	    if (clientp = winp->dga_clientplist_draw) {
		linfop = (WXINFO *) clientp->w_info;
		if (strcmp(linfop->w_devname, infop->w_devname) == 0) {
		    return(clientp);
		}
	    }
	    if (clientp = winp->dga_clientplist) {
		linfop = (WXINFO *) clientp->w_info;
		if (strcmp(linfop->w_devname, infop->w_devname) == 0) {
		    return(clientp);
		}
	    }
	}
	return NULL;
}


static void
release_lockpages(devfd, clientp)
	int		devfd ;
	_Dga_window	clientp;
{
	int		lockfd = clientp->w_devfd ;
	WXINFO		*infop = (WXINFO *) clientp->w_info ;
	Dga_lockp	lockp = clientp->w_lockp ;
	Dga_lockp	unlockp = clientp->w_unlockp ;
	int		locktype ;

	if ((clientp->curs_info ||
	     ((infop->w_version >= 2)  &&  (infop->c_sinfo))) &&
	    ((check_other_curg_windows(infop) != NULL) ||
	     (check_other_curg_windows(infop) == NULL && infop->w_devname[0] == 0))) { 
	    /* don't free lock pages
	     * Note: check both clientp->curs_info and infop->c_sinfo because
	     * this routine is called both at grab and ungrab time.  Client
	     * may not have set curs_info non-zero at grab time.  Server may
	     * set c_sinfo NULL at window destroy time.
	     */
	} else {
	    locktype = infop->w_version >= 2 ? infop->w_locktype : WG_LOCKDEV ;
	    switch(locktype ) {
	      case WG_LOCKDEV:
	        munmap((caddr_t)lockp, WX_PAGESZ) ;
	        munmap((caddr_t)unlockp, WX_PAGESZ) ;
	        break ;
	      case WG_WINLOCK:
	        (void) _dga_winlockdt((int *)lockp, (int *)unlockp) ;
	        break ;
	    }
	}
	if( devfd < 0 )
	     close(lockfd) ;
	munmap((caddr_t)infop, MAXSHMEMSIZE) ;
	safe_free_clientp(clientp) ;
}
#endif /* SERVER_DGA */

void
dga_win_ungrab(clientpi, cflag)
    Dga_window  clientpi;
    int cflag ;
{
    _Dga_window clientp = (struct dga_window *)clientpi;
 
    dgai_win_ungrab_common(clientpi,cflag, 0);
}

void
dgai_win_ungrab_common(clientp, cflag,drawableGrabber)
    _Dga_window	clientp;
    int	cflag ;
    int drawableGrabber;
{

    WXINFO	*infop = (WXINFO *) clientp->w_info ;
    int	infofd, devfd , curs_fd, match;
    struct dga_winlist	*prevwinp, *winp;

    /* remove from linked list of grabbed windows
     * Note: this should be done first in order for other code, e.g.
     * check_other_curg_windows() to work correctly
     */
    match = 0;
    winp = dga_wlist;
    prevwinp = NULL;
    while (winp) {
	if (winp->w_token == clientp->w_token) {
	    struct dga_window *clntp, *prevclntp;
	    if (drawableGrabber)			
	    	clntp = winp->dga_clientplist_draw;
	    else
		clntp = winp->dga_clientplist;

	    prevclntp = NULL;
	    while (clntp) {
		if (clntp == clientp) {
		    match = 1;
		    if( prevclntp )
			prevclntp->w_next = clntp->w_next;
		    else {
			if (drawableGrabber)
			    winp->dga_clientplist_draw = clntp->w_next;
			else
			    winp->dga_clientplist = clntp->w_next;
		    }
		    break;
		}
		prevclntp = clntp;
		clntp = clntp->w_next;
	    }
	    if (!match) {
		/* Check for old style clients */
	        clntp = winp->dga_clientplist;
	        prevclntp = NULL;
	        while (clntp) {
		    if (clntp == clientp) {
		        match = 1;
		        if( prevclntp )
			    prevclntp->w_next = clntp->w_next;
		        else {
			    if (drawableGrabber)
				winp->dga_clientplist_draw = clntp->w_next; 
			    else
			        winp->dga_clientplist = clntp->w_next;
			}
		        break;
		    }
		    prevclntp = clntp;
		    clntp = clntp->w_next;
	        }
	    }
	    break ;
	}
	prevwinp = winp;
	winp = winp->next_winlist;
    }

    if (!match)
	return;	/* error */

    /* TODO: do this for every client, or only once? */
    if ((clientp->rtn_flags & RTN_GRABBED) && (!winp->dga_clientplist))
	dga_rtn_ungrab(clientp);
    if (clientp->db_enabled && (!winp->dga_clientplist))
	dga_db_release(clientp);
    devfd = clientp->w_devfd ;

#ifndef SERVER_DGA
    /* Cursor grabber stuff */
    /* TODO: do this for every client, or only once? */
    if ((clientp->curs_info) && (check_other_curg_windows(infop) == NULL) &&
	(!infop->c_sinfo)) { 
	curs_fd = clientp->curs_fd;
	munmap(clientp->curs_info, MINSHMEMSIZE) ;
	close(curs_fd);
    }
#endif /* SERVER_DGA */

    /* deref any associated multibuffer set */
    if (clientp->pMbs) {
	dgai_mbufset_decref(clientp->pMbs);
	clientp->pMbs = NULL;
    }

    /* TODO: shouldn't we free the clientp??? */
    /* Now check to see  if all that needs to be freed has been freed */
    if ((winp->dga_clientplist_draw == NULL) && 
	(winp->dga_clientplist == NULL)){
#ifndef SERVER_DGA
	release_lockpages( cflag ? -1 : 0, clientp ) ;
#endif /* SERVER_DGA */
	/* Then free this node and unlink it from the list */	
	if( prevwinp != NULL )
	    prevwinp->next_winlist = winp->next_winlist ;
	else
	    dga_wlist = winp->next_winlist ;
#ifdef MT
	mutex_destroy(&winp->mutex);
#endif
	free(winp);
    }
}

int
dgai_win_check_multiple_grab(clientp, drawableGrabber)
_Dga_window clientp;
{

    struct dga_winlist *winp;
    int match;

    /* Checking to see if this client is grabbing a multiply grabbed
     * window	
    */
    match = 0;
    winp = dga_wlist;

    while (winp) {
	if (winp->w_token == clientp->w_token) {
	    /* Now we have the correct window */
	    struct dga_window *clntp, *prevclntp;

            if (drawableGrabber)         
                clntp = winp->dga_clientplist_draw;
            else
                clntp = winp->dga_clientplist;

            prevclntp = NULL;
            while (clntp) {
		/* Now we have the correct client */
                if (clntp == clientp) {
		   /* Check to see if there are any more... */
		   if (prevclntp || clntp->w_next) {
			match = 1;
			break;	
		    }	
		}
		prevclntp = clntp;
		clntp = clntp->w_next;
	    }
	    if (match) break;
        }
	winp = winp->next_winlist;
    }
    return match; 
}

short *
dga_win_clipinfo(wini)
Dga_window	wini ;
{
    _Dga_window win = (struct dga_window *)wini;
    WXINFO	*infop = (WXINFO *) win->w_info ;

    if (wx_shape_flags(infop) & DGA_SH_RECT_FLAG)
	  return((short *)&((struct class_SHAPE_vn *)((char *)(infop) +
	      (infop)->u.vn.w_shapeoff))->SHAPE_YMIN);
    return(win->w_clipptr);
}


char *
dga_win_fbname(wini)
Dga_window wini;
{
    _Dga_window win = (struct dga_window *)wini;
    
    return(((WXINFO *) (win->w_info))->w_devname);
}

int
dga_win_clipchg(wini)
Dga_window wini;
{
    _Dga_window win = (struct dga_window *)wini;
    
    if (win->c_clipseq != *(win->s_clipseq_p)) {
	((WXINFO *) win->w_info)->w_flag &= ~WMODIF;
	win->c_clipseq = *(win->s_clipseq_p);
	return 1;
    }
    return 0;
}

int
dga_win_curschg(wini)
Dga_window wini;
{
    _Dga_window win = (struct dga_window *)wini;
    
    if (win->c_curseq != *(win->s_curseq_p)) {
	win->c_curseq = *(win->s_curseq_p);
	return 1;
    }
    return 0;
}

int
dga_win_rtnchg(wini)
Dga_window wini;
{
    _Dga_window win = (struct dga_window *)wini;
    if ((win->rtn_flags & RTN_GRABBED) && !(win->rtn_flags & RTN_MAPPED)) {
	/* rtn grabbed, but not currently mapped */
	if (win->rtn_flags & RTN_MAPCHG) {
	    /* just went unmapped */
	    win->rtn_flags &= ~RTN_MAPCHG;
	    return 1;
	}
	return 0;
    }
    /* otherwise either not rtn grabbed or have a rtn mapping */
    if (win->c_rtnseq != *(win->s_rtnseq_p)) {
	win->c_rtnseq = *(win->s_rtnseq_p);
	return 1;
    }
    return 0;
}

int
dga_win_devfd(wini)
Dga_window wini;
{
    _Dga_window win = (struct dga_window *)wini;
    return(win->w_devfd);
}

void
dga_win_bbox(wini, xp, yp, widthp, heightp)
Dga_window wini;
int *xp, *yp, *widthp, *heightp;
{
    _Dga_window win = (struct dga_window *)wini;
    WXINFO *infop = (WXINFO *) win->w_info;

    if (infop->w_version < 2) {
	*xp = infop->w_org.x >> 16;
	*yp = infop->w_org.y >> 16;
	*widthp = infop->w_dim.x >> 16;
	*heightp = infop->w_dim.y >> 16;
	return;
    }
    *xp = infop->w_window_boundary.xleft;
    *yp = infop->w_window_boundary.ytop;
    *widthp = infop->w_window_boundary.width;
    *heightp = infop->w_window_boundary.height;
}

int
dga_win_singlerect(wini)
Dga_window wini;
{
    _Dga_window win = (struct dga_window *)wini;
    WXINFO *infop = (WXINFO *) win->w_info;

    return(wx_shape_flags(infop) & DGA_SH_RECT_FLAG);
}

int
dga_win_empty(wini)
Dga_window wini; 
{ 
    _Dga_window win = (struct dga_window *)wini;
    WXINFO *infop = (WXINFO *) win->w_info;

    return(wx_shape_flags(infop) & DGA_SH_EMPTY_FLAG);
}

u_char
dga_win_depth(wini)
Dga_window wini;
{
    _Dga_window win = (struct dga_window *)wini;
    WXINFO *infop = (WXINFO *) win->w_info;
	
    if (infop->w_version >= 3) 
	return(infop->w_depth);
    else 
	return 0;
}

u_short
dga_win_borderwidth(wini) 
Dga_window wini; 
{ 
    _Dga_window win = (struct dga_window *)wini;
    WXINFO *infop = (WXINFO *) win->w_info; 
      
    if (infop->w_version >= 3) 
        return(infop->w_borderwidth);
    else  
        return 0; 
} 

int
dga_win_obscured(wini)
Dga_window wini;
{
    _Dga_window win = (struct dga_window *)wini;
    WXINFO *infop = (WXINFO *) win->w_info;
    int xb, yb, wb, hb;
    int ytop, ybot, xleft, xright;
    int tmp;
    short *ptr;

    if (wx_shape_flags(infop) & DGA_SH_RECT_FLAG) {
	dga_win_bbox(win, &xb, &yb, &wb, &hb);
	ptr = dga_win_clipinfo(win);
	ytop = *ptr++; ybot = *ptr++; xleft = *ptr++; xright = *ptr++;
	if (ytop > ybot) {
	    tmp = ytop; ytop = ybot; ybot = tmp;
	}
	if (xleft > xright) {
	    tmp = xleft; xleft = xright; xright = tmp;
	}
	if ((yb == ytop) && (xb == xleft) &&
	    (hb == (ybot - ytop)) && (wb == (xright - xleft))) {
		return 1;
	}
    }
    return 0;
}

int
dgai_win_visibility(Dga_window wini)
{
    if (dga_win_empty(wini))
	return (DGA_VIS_FULLY_OBSCURED);
    /* This routine returns the reverse of what one would think.
     * it returns true if the window is unobscured false otherwise. */
    else if (!dga_win_obscured(wini))
	return (DGA_VIS_PARTIALLY_OBSCURED);
    
    return (DGA_VIS_UNOBSCURED);

    /*  This will work when we get to R6 but for now the visibility
     * entry in the window structure (which is where this comes from)
     * is bogus.  I looked at the R6 code and it looks like they
     * attempted to get this working.
    _Dga_window win = (struct dga_window *)wini;
    WXINFO *infop = (WXINFO *) win->w_info;
    
    return (infop->w_visibility);
    */
}	

#define	ROUNDUP(i)	(((i)+WX_PAGESZ-1)&~(WX_PAGESZ-1))

void
dgai_win_clip_update (_Dga_window clientp)
{
    /* Do anything here that may require unlock/relock, because
    * it takes so long.
    */

    WXINFO	*infop = (WXINFO *) clientp->w_info ;
    unsigned int	cliplen;
    short	*clipptr;
    short	*cmclip;
#ifndef SERVER_DGA
    char	filename[sizeof(GRABFILE)+NDIGITS+1];
    int		filefd;
#endif /*SERVER_DGA */

    cmclip = (short *)((char *)infop+infop->u.vn.w_clipoff);

#ifdef SERVER_DGA
    if (infop->w_flag & WEXTEND) { /* server has an extended mapping */
        if (clientp->w_clipptr == cmclip) {
            clientp->w_cliplen = infop->w_scliplen;
            clientp->w_clipptr = (short *)infop->u.vn.w_sclipptr;
        }
    } else {
        if (clientp->w_clipptr != cmclip) {
            clientp->w_clipptr = cmclip;
        }
    }
#else
    while(1) {
	if (infop->w_flag & WEXTEND) { 
	    /* server has an extended mapping */
	    if (clientp->w_clipptr == cmclip) { 
		/* ...and we don't. */
		cliplen = infop->w_scliplen;
		DGA_UNLOCK(clientp);
		sprintf(filename, "%s%08x", GRABFILE, clientp->w_token);

		if ((filefd = open(filename,O_RDWR,0666))<0) {
		    return;
		}
		if (ftruncate(filefd,MINSHMEMSIZE+cliplen)<0) {
		    close(filefd);
		    return;
		}

		close(filefd);

		clipptr = (short *)((char *)infop + MINSHMEMSIZE);

		DGA_LOCK(clientp);
		if ((int)clipptr != -1) {
		    clientp->w_cliplen = cliplen;
		    clientp->w_clipptr = clipptr;
		}
		continue;  /* at while */
	    }
	    if (clientp->w_cliplen != infop->w_scliplen) {
		/* ...and we do... but the wrong size. */
		cliplen = infop->w_scliplen;
		DGA_UNLOCK(clientp);
		sprintf(filename, "%s%08x", GRABFILE, clientp->w_token);

		if ((filefd = open(filename,O_RDWR,0666))<0) {
		    return;
		}
		if (ftruncate(filefd,MINSHMEMSIZE+cliplen)<0) {
		    close(filefd);
		    return;
		}
		close(filefd);
		clipptr = (short *)((char *)infop + MINSHMEMSIZE);

		DGA_LOCK(clientp);
		if ((int)clipptr == -1)
		    clientp->w_clipptr = cmclip;
		else {
		    clientp->w_cliplen = cliplen;
		    clientp->w_clipptr = clipptr;
		}
		continue;  /* at while */
	    }
	} else { 	
	    /* server doesn't have an extended mapping */
            if (clientp->w_clipptr != cmclip) { 
		/* ...and we do. */
                DGA_UNLOCK(clientp);
		sprintf(filename, "%s%08x", GRABFILE, clientp->w_token);

		if ((filefd = open(filename,O_RDWR,0666))<0) {
		    clientp->w_clipptr = cmclip;
		    return;
		}
		if (ftruncate(filefd,MINSHMEMSIZE)<0) {
		    clientp->w_clipptr = cmclip;
		    close(filefd);
		    return;
		}
		close(filefd);

                DGA_LOCK(clientp);
		clientp->w_clipptr = cmclip;
		continue;  /* at while */
	    }
	    /*
	    else {	 ...nor do we
		break;
	    }
	    */
	}
    break;
    }
#endif /* SERVER_DGA */
}

void
dgai_win_curs_update(_Dga_window win)
{
    /* Do anything here that may require unlock/relock, because
    * it takes so long.
    *
    * We can add code here in the future to remap the cursor page,
    * etc., if we want.
    */
    return;
}


/*
 *
 *  dgai_rtn_update()
 *
 *  Do anything here that may require unlock/relock, because
 *  it takes so long.  Remap retained info, etc.
 *
 *  DGA Retained Window Information Update.  This function checks that the
 *  shared retained information structure hasn't become obsolete.  If the
 *  structure is found to be obsolete, this routine attempts to free and
 *  re-allocate the resources associated with the retained window.  Nothing
 *  is done in the event that the shared retained information is not obsolete.
 *
 *  Inputs:     Dga_window - Pointer to the dga_window structure for which
 *                           the the shared retained info structure is to
 *                           be removed.
 *
 *  Outputs:    None.
 *
 *  Globals:    None.
 *
 *  Externals:  DGA_LOCK()              DGA MACRO
 *              DGA_UNLOCK()            DGA MACRO
 *              RTN_INFOP()             DGA MACRO
 *              _dga_rtn_map()
 *              _dga_rtn_unmap()
 *
 */
void
dgai_win_rtn_update (_Dga_window clientp)
{
    unsigned int         mapped;
 
#ifdef SERVER_DGA
    mapped = clientp->rtn_flags & RTN_MAPPED;
    if (mapped && RTN_INFOP(clientp)->obsolete) {
        /* mapped, but obsolete */
        (void) _dga_rtn_unmap(clientp);
        (void)  _dga_rtn_map(clientp);
    }
 
    if (!mapped && (((WXINFO *) clientp->w_info)->w_srtndlink != NULL)) {
        /* unmapped on client side, but server has valid w_srtndlink */
        (void) _dga_rtn_map(clientp);
    }
#else
    while (1) {
	mapped = clientp->rtn_flags & RTN_MAPPED;
        if (mapped && RTN_INFOP(clientp)->obsolete) {
	    /* mapped, but obsolete */
            DGA_UNLOCK(clientp);
            (void) _dga_rtn_unmap(clientp);
            (void)  _dga_rtn_map(clientp);
            DGA_LOCK(clientp);
            continue;
        } 
	if (!mapped && (((WXINFO *) clientp->w_info)->w_srtndlink != NULL)) {
	    /* unmapped on client side, but server has valid w_srtndlink */
	    DGA_UNLOCK(clientp);
	    (void) _dga_rtn_map(clientp);
	    DGA_LOCK(clientp);
	    continue;
	}
        break;
    }    
#endif /* SERVER_DGA */
}


static int
dga_win_update(wini)
Dga_window wini;
{
    _Dga_window win = (struct dga_window *)wini;
    WXINFO *infop = (WXINFO *) win->w_info;
    unsigned int sav_clipseq, sav_curseq, sav_rtnseq;

    /* establish the new real lock subject */
    win->rLockSubj = -1;
 
    /* save last lock subject.  This may be used later in the update phase */
    win->eLockSubjPrev = win->eLockSubj;

    /* start out assuming we're not aliased.  This may change if we detect
       aliasing later in the update phase */
    win->eLockSubj = win->rLockSubj;

    /* Do anything here that may require unlock/relock, because
    * it takes so long.  Also, update win->c_chngcnt.
    */

    sav_clipseq = win->c_clipseq;
    sav_curseq = win->c_curseq;
    sav_rtnseq = win->c_rtnseq;
    do {
	/* repeat update functions as needed
	 * through possible unlock/relocks
	*/
	if (sav_clipseq != *win->s_clipseq_p) {
	    dgai_win_clip_update(win);
	    sav_clipseq = *win->s_clipseq_p;
	}
	if (sav_curseq != *win->s_curseq_p) {
	    dgai_win_curs_update(win);
	    sav_curseq = *win->s_curseq_p;
	}
	if ((sav_rtnseq != *win->s_rtnseq_p) ||
	    ((win->rtn_flags & RTN_GRABBED) &&
	     !(win->rtn_flags & RTN_MAPPED))) {
		dgai_win_rtn_update(win);
		sav_rtnseq = *win->s_rtnseq_p;
	}
    } while ((sav_clipseq != *win->s_clipseq_p) ||
	 (sav_curseq != *win->s_curseq_p) ||
	 (sav_rtnseq != *win->s_rtnseq_p));

    if (infop->w_version < 2) {	
	/* pre OWV3 */
	win->c_chngcnt = *win->s_chngcnt_p;
	return 1;
    } else {		
	/* post OWV3 beta */
	win->c_chngcnt = *win->s_chngcnt_p;
	return 1;
    }
}

int
dga_win_cursactive(wini)
Dga_window wini;
{
    _Dga_window win = (struct dga_window *)wini;
    if (win->curs_info)
	return 1;
    return 0;
}

void
dga_win_cursupdate(wini, func, data)
Dga_window	wini;
void		(*func)();
void*		data;
{
    _Dga_window win = (struct dga_window *)wini;
    /* assumes the window is already locked */

    Dga_cursinfo	*curgp = (Dga_cursinfo *) (win->curs_info);
    Dga_curs_mpr	*curg_mpr;
    Dga_curs_memimage curg_mem;
    int		x, y, w, h;

    if ((curgp == 0) || (curgp->c_state_flag != DGA_CURSOR_UP))
		return;

    curg_mpr = (Dga_curs_mpr *) ((char *) curgp + curgp->c_offset);

    dga_win_bbox(win, &x, &y, &w, &h);
    if (((curgp->c_org.x + curg_mpr->curg_dim.x) < x) ||
        (curgp->c_org.x > (x + w)) ||
        ((curgp->c_org.y + curg_mpr->curg_dim.y) < y) ||
        (curgp->c_org.y > (y + h)))
    	return;

    if (func) {
	curg_mem.width = curg_mpr->curg_dim.x;
	curg_mem.height = curg_mpr->curg_dim.y;
	curg_mem.depth = curg_mpr->curg_depth;
	curg_mem.linebytes = curg_mpr->curg_linebytes;
#ifdef _LP64
	curg_mem.memptr = (void *)(curg_mpr + 1);
#else  /* _LP64 */
	curg_mem.memptr = ((caddr_t) curg_mpr) + sizeof(Dga_curs_mpr);
#endif /* _LP64 */
	(*func) (data, win, curgp->c_org.x, curgp->c_org.y, &curg_mem);
	curgp->c_state_flag = DGA_CURSOR_DOWN;
	/* have to bump the shared memory counter, so update the saved
	* version as well
	*/
	win->c_curseq = ++(curgp->c_chng_cnt); 
    }
}

Dga_dbinfo *
dga_win_dbinfop(wini)
Dga_window wini;
{
    _Dga_window win = (struct dga_window *)wini;
    return ((Dga_dbinfo *)&(((WXINFO *) win->w_info)->wx_dbuf));
}

Dga_widinfo *
dga_win_widinfop(wini)
Dga_window wini;
{
    _Dga_window win = (struct dga_window *)wini;
    return ((Dga_widinfo *)(&(((WXINFO *) win->w_info)->w_wid_info)));
}

void
dga_win_set_client_infop(wini, client_info_ptr)
Dga_window wini;
void* client_info_ptr;
{
    _Dga_window win = (struct dga_window *)wini;
    win->w_client = client_info_ptr;
}

void *
dga_win_get_client_infop(wini)
Dga_window wini;
{
    _Dga_window win = (struct dga_window *)wini;
    return (void *)(win->w_client);
}


static int
dgai_win_initMbufset (_Dga_window dgawin)
{
    WXINFO	*infop;
    int		status = 0; 

    /* Lock the window to see if it is multibuffered */
#ifndef SERVER_DGA
    DGA_LOCK(dgawin);
#endif /* SERVER_DGA */

    infop = (WXINFO *) dgawin->w_info;
    if (!infop->w_mbsInfo.enabled) {
	/* it's okay if it's not multibuffered; return success */
	dgawin->pMbs = NULL;
	status = 1;
	goto Exit;
    }

    if (!(dgawin->pMbs = dgai_mbufset_create(dgawin))) {
	goto Exit;
    }

    dgawin->c_mbcomposseq = *dgawin->s_mbcomposseq_p;

    /* success */
    status = 1;

Exit:
#ifndef SERVER_DGA
    DGA_UNLOCK(dgawin);
#endif /* SERVER_DGA */
    return (status);
}

#ifdef SERVER_DGA
/*
 *  There is no equivalent for the following function in client side
 *  The main purpose of this function is to isolate SHAPES header files
 *  and XGL files.
 */

void
dga_win_lock(win)
Dga_window win;
{
       _Dga_window 	wini = (_Dga_window)win;

       if (((wini)->w_lockcnt)++ == 0) {
            wg_lock((WXINFO *) (wini->w_lib_private));
            DGA_S_LOCK(wini);
            wini->w_modif = ((((wini)->c_chngcnt) == (*((wini)->s_chngcnt_p)))
                 ? 0 : (*((wini)->w_update_func))(wini));
       } 
 
}
 
/*
 *  There is no equivalent for the following function in client side
 *  The main purpose of this function is to isolate SHAPES header file
 *  and XGL files.
 */
 
void
dga_win_unlock(win)
Dga_window win;
{
       _Dga_window 	wini = (_Dga_window)win;

        if (--((wini)->w_lockcnt) == 0) {
                        wg_unlock((WXINFO *) (wini->w_lib_private));
                        if ((wini)->w_unlock_func)
                                (*((wini)->w_unlock_func))(wini);
        }
 
}
#endif /* SERVER_DGA */


#ifdef	DEBUG
dga_win_dump(clientpi)
	Dga_window	clientpi ;
{
	_Dga_window clientp = (struct dga_window *)clientpi;
WXINFO	*infop = (WXINFO *) clientp->w_info ;

	printf("client page is %p\n", clientp) ;
	printf("  w_info = %p\n", (WXINFO *) clientp->w_info) ;
	printf("  w_next = %p\n", clientp->w_next) ;
	printf("  w_client = %p\n", clientp->w_client) ;
	printf("  c_clipseq = %u\n", clientp->c_clipseq) ;
	printf("  s_clipseq_p = %p\n", clientp->s_clipseq_p) ;
	printf("  w_update_func = %p\n", clientp->w_update_func) ;
	printf("  w_infofd = %d\n", clientp->w_infofd) ;
	printf("  w_devfd = %d\n", clientp->w_devfd) ;
	printf("  w_lockcnt = %d\n", clientp->w_lockcnt) ;
	printf("  w_lockp = %p\n", clientp->w_lockp) ;
	printf("  w_unlockp = %p\n", clientp->w_unlockp) ;
	printf("  w_clipptr = %p\n", clientp->w_clipptr) ;
	printf("  w_cliplen = %u\n", clientp->w_cliplen) ;

	printf("info page is %p\n", infop) ;
	printf("  w_flag = %lu\n", infop->w_flag) ;
	printf("  w_magic = %ld\n", infop->w_magic) ;
	printf("  w_version = %ld\n", infop->w_version) ;
	printf("  w_cunlockp = %p\n", infop->w_cunlockp) ;
	printf("  w_devname = %s\n", infop->w_devname) ;
	printf("  w_cookie = %lu\n", infop->w_cookie) ;
	printf("  w_clipoff = %ld\n", infop->u.vn.w_clipoff) ;
	printf("  w_scliplen = %u\n", infop->w_scliplen) ;
	printf("  w_org = %u,(%f,%f)\n",
		infop->w_org.t, infop->w_org.x/65536., infop->w_org.y/65536.) ;
	printf("  w_dim = %u,(%f,%f)\n",
		infop->w_dim.t, infop->w_dim.x/65536., infop->w_dim.y/65536.) ;
	printf("  &w_shape_hdr = %p\n", &infop->u.v0.w_shape_hdr) ;
	printf("  &w_shape = %p\n", &infop->w_shape) ;
	printf("  w_shape.SHAPE_FLAGS = %u\n", infop->w_shape.SHAPE_FLAGS) ;
	printf("  w_shape.SHAPE_YMIN = %d\n", infop->w_shape.SHAPE_YMIN) ;
	printf("  w_shape.SHAPE_YMAX = %d\n", infop->w_shape.SHAPE_YMAX) ;
	printf("  w_shape.SHAPE_XMIN = %d\n", infop->w_shape.SHAPE_XMIN) ;
	printf("  w_shape.SHAPE_XMAX = %d\n", infop->w_shape.SHAPE_XMAX) ;
	printf("  w_shape.SHAPE_X_EOL = %d\n", infop->w_shape.SHAPE_X_EOL) ;
	printf("  w_shape.SHAPE_Y_EOL = %d\n", infop->w_shape.u.SHAPE_Y_EOL) ;
	printf("  &w_cliparray = %p\n", &infop->w_cliparray) ;
}
#endif /* DEBUG */

#ifdef MT
int
dgai_unlock(Dga_drawable dgadraw)
{
    _Dga_window dgawin;

    if (dgaMTOn) {
	dgawin = (_Dga_window) dgadraw;
	mutex_unlock(dgawin->mutexp);
    }
    return Success;
}
#endif