open-src/lib/libdga/sun-src/mbsmemb_update.c
author Alan Coopersmith <Alan.Coopersmith@Sun.COM>
Thu, 18 Feb 2010 16:03:08 -0800
changeset 907 3c35d611cdaa
parent 830 186f3c438b46
child 919 425233ae7236
permissions -rw-r--r--
6927784 Remove SCCS ident tags from X gate

/* Copyright 1999 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 *
 * 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, and/or sell copies of the Software, and to permit persons
 * to whom the Software is furnished to do so, provided that the above
 * copyright notice(s) and this permission notice appear in all copies of
 * the Software and that both the above copyright notice(s) and this
 * permission notice appear in supporting documentation.
 *
 * 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
 * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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.
 *
 * Except as contained in this notice, the name of a copyright holder
 * shall not be used in advertising or otherwise to promote the sale, use
 * or other dealings in this Software without prior written authorization
 * of the copyright holder.
 */


/*
**
** mbsmemb_update.c
**
** Routines of the update phase that apply equally to both types of
** multibuffer set members, windows and multibuffers.
*/

#include <stdio.h>
#include <sys/types.h>
#ifdef SERVER_DGA
#include <X11/Xlib.h>
#endif /* SERVER_DGA */
#include "dga_incls.h"
#include "pix_grab.h"
#include "mbufsetstr.h"

static void 		dgai_mbsmemb_notifySiteChg (_Dga_window dgawin);
static void		dgai_mbsmemb_notifyMbChg (_Dga_window dgawin);
static void		dgai_mbsmemb_notifyOvlState (_Dga_window dgawin);

/*
** The update phase entry routine for mbufset members.
** Called if the master change count of the shared info
** differs from the last recorded count in the client structure.
*/

int
dgai_mbsmemb_update (Dga_drawable dgadraw, short bufIndex)
{
    _Dga_window dgawin = (_Dga_window) dgadraw;
    int status;

#ifdef MT
    if (dgaMTOn) {
	mutex_lock(dgawin->mutexp);  /* lock the per-window mutex */
	DGA_LOCK(dgadraw);
	/* check the real change count that we saved away */
	if (dgawin->shadow_chngcnt[bufIndex + 1] == *dgawin->s_chngcnt_p) {
	    DGA_UNLOCK(dgadraw);
	    mutex_unlock(dgawin->mutexp);
	    return (0);
	}
    }
    mutex_lock(&dgaGlobalMutex);
#endif
    /* establish the new real lock subject */
    dgawin->rLockSubj = bufIndex;

    /* save last lock subject.  This may be used later in the update phase */
    dgawin->eLockSubjPrev = dgawin->eLockSubj;
    
    /* start out assuming we're not aliased.  This may change if we detect
       aliasing later in the update phase */
    dgawin->eLockSubj = dgawin->rLockSubj;

    /* the first thing we do is distinguish between locking a window
       and a multibuffer.  The update logic is different */
    if (bufIndex == -1) {
	status = dgai_win_update(dgawin, bufIndex);
    } else {
	status = dgai_mbuf_update(dgawin, bufIndex);
    }
#ifdef MT
    if (dgaMTOn) {
	/* save the real change count */
	dgawin->shadow_chngcnt[bufIndex + 1] =
	    dgawin->c_wm_chngcnt[bufIndex + 1];
	/* For the MT case, make sure that this update function gets called
	 * the next time around, so overwrite the change count to make it
	 * different.
	 */
	dgawin->c_wm_chngcnt[bufIndex + 1] = *dgawin->s_chngcnt_p - 1;
	DGA_UNLOCK(dgadraw);
	mutex_unlock(dgawin->mutexp);  /* unlock the per-window mutex */
    }
    mutex_unlock(&dgaGlobalMutex);
#endif
    return (status);
}


/*
** See if the shared info of the main window is still valid.
** Nonzero is returned if it is no longer valid and has become
** a zombie.
*/

int
dgai_mbsmemb_syncZombie (_Dga_window dgawin)
{
    WXINFO *infop;

    infop = (WXINFO *) dgawin->w_info;

    if (infop->w_obsolete) {
	dgawin->changeMask |= DGA_CHANGE_ZOMBIE;
	return (1);
    } else {
	return (0);
    }
}

/*
** The way we deal with any composition change is to destroy the old
** multibuffer set and establish a new one.
*/

void
dgai_mbsmemb_syncMbufset (_Dga_window dgawin)
{

    DgaMbufSetPtr	pMbs;
    WXINFO 		*infop;

    /* check to see if this is an actual composition change or simply
       a display change */
    if (dgawin->c_mbcomposseq == *dgawin->s_mbcomposseq_p) {
	/* no change -- must be only a display change */
	return;
    }

    /* this is a real composition change.  Destroy the old mbufset (if any)
       and create a new one */

    infop = (WXINFO *) dgawin->w_info;
    pMbs = dgawin->pMbs;

    /* remember whether window was previously multibuffered.  This is 
       used later in the update phase to determine the reason for the
       mbufset change */
    dgawin->prevWasMbuffered = (pMbs != NULL);

    /* destroy the old one */
    if (pMbs) {
	dgai_mbufset_decref(pMbs);
	dgawin->pMbs = NULL;
    }

    dgawin->c_mbcomposseq = *dgawin->s_mbcomposseq_p;

    if (!infop->w_mbsInfo.enabled) {
	return;
    }
    
    /* create a new one */
    pMbs = dgai_mbufset_create(dgawin);
    
    if (!pMbs) {
	/* TODO: really the only way we have of responding to this is treat 
	   it as a zombie.  It's not ideal, but what else can we do? */
	dgawin->changeMask |= DGA_CHANGE_ZOMBIE;
    }

    dgawin->pMbs = pMbs;
}


/*
** If a render buffer notification function has been registered
** and the current effective lock subject differs from the current
** write buffer, call the notification function to change the render 
** buffer state.
*/

void
dgai_mbsmemb_syncRendBuf (_Dga_window dgawin)
{
    WXINFO	*infop;
    short	*pRendBuf;
	
    infop = (WXINFO *) dgawin->w_info;

    /* has client registered the notification function? */
    if (!dgawin->rendBufNotifyFunc) {
	return;
    }

    /* we only need to notify in single-address access mode */
    if (infop->w_mbsInfo.accessMode != DGA_MBACCESS_SINGLEADDR) {
	return;
    }

    /* 
     * Only notify if rend buf is different from what we want it to be 
     * Note: we treat the write buffer index as the render buffer and ignore
     * the read buffer index.
     */
    pRendBuf = &infop->wx_dbuf.write_buffer;
    if (*pRendBuf != dgawin->eLockSubj) {
	(*dgawin->rendBufNotifyFunc)((Dga_drawable)dgawin, dgawin->eLockSubj,
				    dgawin->rendBufNotifyClientData);

	/* update the shared info so both the server and other clients can
	   see and react to the change */
	*pRendBuf = dgawin->eLockSubj;
    }
}

/*
** A derivative change is one which is dependent on changes discovered 
** earlier in the update phase (i.e. the basic changes).  We determine here which ones need
** to be reported.  Derivative changes may be reported along with 
** the basic changes.  The derivative changes in common for mbufset
** members are: site change.
*/

void
dgai_mbsmemb_figureDerivChgs (_Dga_window dgawin)
{
    /* safety */
    dgawin->siteChgReason = DGA_SITECHG_UNKNOWN;

    /* check for zombie */
    if (dgawin->changeMask & DGA_CHANGE_ZOMBIE) {
	/* report both a site change and a clip for zombies.  This is simply
	   more insurance that the client will sync up with the null clip. */
	dgawin->changeMask |= (DGA_CHANGE_SITE | DGA_CHANGE_CLIP);
	dgawin->siteChgReason = DGA_SITECHG_ZOMBIE;
	return;
    }

    /* check for first time */
    if ((dgawin->eLockSubj == -1) && !dgawin->prevLocked) {
	dgawin->changeMask |= DGA_CHANGE_SITE;
	dgawin->siteChgReason = DGA_SITECHG_INITIAL;
	dgawin->prevLocked = 1;
	return;
    } else if ((dgawin->eLockSubj >= 0) &&
               !dgawin->pMbs->prevLocked[(int)dgawin->eLockSubj]) {
	dgawin->changeMask |= DGA_CHANGE_SITE;
	dgawin->siteChgReason = DGA_SITECHG_INITIAL;
	dgawin->pMbs->prevLocked[dgawin->eLockSubj] = 1;
	return;
    }

    /* check for cache change */
    if (dgawin->changeMask & DGA_CHANGE_CACHE) {
	dgawin->changeMask |= DGA_CHANGE_SITE;
	dgawin->siteChgReason = DGA_SITECHG_CACHE;
	return;
    }

    /* check for alias change */
    if (dgawin->changeMask & DGA_CHANGE_ALIAS) {
	dgawin->changeMask |= DGA_CHANGE_SITE;
	dgawin->siteChgReason = DGA_SITECHG_ALIAS;
	return;
    }

    /* check for mbufset composition change */
    if (dgawin->changeMask & DGA_CHANGE_MBUFSET) {
	dgawin->changeMask |= DGA_CHANGE_SITE;
	dgawin->siteChgReason = DGA_SITECHG_MB;
	return;
    }
}


/*
** If we can report any changes through notification, do so now.
*/

void
dgai_mbsmemb_notify (_Dga_window dgawin)
{
    /* report any mbufset change */
    if (dgawin->changeMask & DGA_CHANGE_MBUFSET) {
	dgai_mbsmemb_notifyMbChg(dgawin);
    }

    if (dgawin->changeMask & DGA_CHANGE_SITE) {
	 dgai_mbsmemb_notifySiteChg(dgawin);
    }

    if (dgawin->changeMask & DGA_CHANGE_OVLSTATE) {
	dgai_mbsmemb_notifyOvlState(dgawin);
    }

    /* there are no notify functions for the following:
       clip, cursor, bstore, cache */
}

void
dgai_mbsmemb_devinfo_update(_Dga_window dgawin)
{
    if (!DGA_LOCKSUBJ_VALID(dgawin, dgawin->eLockSubj) || 
	dgawin->changeMask & DGA_CHANGE_ZOMBIE) {
	return;
    }

    if        (DGA_LOCKSUBJ_WINDOW(dgawin, dgawin->eLockSubj)) {
	/* check for window devinfo change */
	if (dgawin->c_devinfoseq != *dgawin->s_devinfoseq_p) {
	    dgawin->changeMask |= DGA_CHANGE_DEVINFO;
	    dgawin->c_devinfoseq = *dgawin->s_devinfoseq_p;
	}
    } else if (!DGA_LOCKSUBJ_VIEWABLE(dgawin, dgawin->eLockSubj)) {
	/* check for nonviewable mbuf devinfo change */
	dgai_nmbuf_devinfo_update(dgawin);
    }

    /* Note: viewable mbufs don't have dev info */
}

static void
dgai_mbsmemb_notifySiteChg (_Dga_window dgawin)
{
    if (dgawin->siteNotifyFunc) {
	(*dgawin->siteNotifyFunc)((Dga_drawable)dgawin, dgawin->eLockSubj,
				  dgawin->siteNotifyClientData,
				  dgawin->siteChgReason);
	dgawin->changeMask &= ~DGA_CHANGE_SITE;
	dgawin->siteChgReason = DGA_SITECHG_UNKNOWN;
    } else {
	/* client must find out through dga_draw_sitechg */
    }
}


static void
dgai_mbsmemb_notifyMbChg (_Dga_window dgawin)
{
    /* figure out reason for change */
    if        (!dgawin->prevWasMbuffered && dgawin->pMbs) {
	dgawin->mbChgReason = DGA_MBCHG_ACTIVATION;
    } else if (dgawin->prevWasMbuffered && !dgawin->pMbs) {
	dgawin->mbChgReason = DGA_MBCHG_DEACTIVATION;
    } else if (dgawin->prevWasMbuffered && dgawin->pMbs) {
	dgawin->mbChgReason = DGA_MBCHG_REPLACEMENT;
    } else {
	/* this might happen if the mbufset was activated and then, in
	   the same update phase, deactivated.  In this case, allow it,
	   but just don't report any changes */
	dgawin->changeMask &= ~DGA_CHANGE_MBUFSET;
	dgawin->mbChgReason = DGA_MBCHG_UNKNOWN;
	return;
    }
    
    if (dgawin->mbNotifyFunc) {
	(*dgawin->mbNotifyFunc)((Dga_drawable)dgawin, 
				dgawin->mbNotifyClientData,
				dgawin->mbChgReason); 
	dgawin->changeMask &= ~DGA_CHANGE_MBUFSET;
	dgawin->mbChgReason = DGA_MBCHG_UNKNOWN;
    } else {
	/* client must find out through dga_draw_mbchg */
    }
}


static void
dgai_mbsmemb_notifyOvlState (_Dga_window dgawin)
{
    if (dgawin->ovlStateNotifyFunc) {
	(*dgawin->ovlStateNotifyFunc)((Dga_drawable)dgawin,
				      dgawin->ovlStateNotifyClientData,
				      dgawin->c_ovlstate);
	dgawin->changeMask &= ~DGA_CHANGE_OVLSTATE;
    } else {
	/* client must find out through dga_draw_sitechg */
    }
}