#ifndef lint
static  char sccsid[] = "@(#)windt.c 1.1 94/10/31 SMI";
#endif

/*
 * Copyright (c) 1987 by Sun Microsystems, Inc.
 */

/*
 * SunWindows Desktop driver with multiple screens support.
 */

#include <sunwindowdev/wintree.h>
#include <sunwindow/cursor_impl.h>	/* for cursor access macros */
#include <pixrect/pr_util.h>		/* for mpr support */
#include <pixrect/pr_dblbuf.h>		/* for double buffering support */
#include <pixrect/pr_planegroups.h>	/* for plane groups */
#include <sys/file.h>			/* for FREAD and FWRITE */
#include <sys/kmem_alloc.h>
#include <sun/fbio.h>
#include <sunwindow/pw_dblbuf.h>
#include <sunwindow/win_ioctl.h>

caddr_t getpages();
void freepages();

extern	struct window *wt_intersected();
extern	int wt_notifychanged();
extern	bool wt_isindisplaytree();

void	dtop_putcolormap();

static void	dtop_init_data_lock();
static void	dtop_init_display_lock();
static void	dtop_init_mutex_lock();
static void	dtop_update_cursor();

static int	dtop_check_lock();

int wincursordisable;	/* Temp: Turns off displaying of the cursor */
int win_do_hw_cursor = 1;	/* Controls hardware cursor stuff */
int fbio_kcopy;			/* See FBIOSCUROR call below */

#ifdef WINDEVDEBUG
int win_waiting_debug;	/* to printf when wakeup waiter */
int win_sharedq_debug;	/* to printf when messing with shared queue */
#endif

void	dtop_change_loc_dtop();
void	dtop_update_enable();
void	dtop_set_enable();
void	dtop_flip_display();	/* Double buffering flip */
void	dtop_choose_dblbuf();
void	dtop_changedisplay();
int	dtop_isdblwin();
int	dtop_dblset();
void	dtop_copy_dblbuffer();

/*
 * The following should only be call when the display lock is off
 * or when you are not sure.
 */
dtop_cursorup(dtop)
	register Desktop *dtop;
{
	if (dtop && !(cursor_up(dtop) ||
	    horiz_hair_up(dtop) || vert_hair_up(dtop)) &&
	    (!win_lock_display_locked(dtop->shared_info))) {
		dtop_drawcursor(dtop);
	}
}

dtop_cursordown(dtop)
	register Desktop *dtop;
{
	if ((cursor_up(dtop) || horiz_hair_up(dtop) || vert_hair_up(dtop)) &&
	    (!win_lock_display_locked(dtop->shared_info))) {
		dtop_drawcursor(dtop);
	}
}

int
dtop_cursor_ioctl(dtop, cmd, data, surpress_err_msg)
	register Desktop *dtop;
	int cmd;
	caddr_t data;
	int surpress_err_msg;
{
	register struct file *fp = dtop->dt_fbfp;
	int err;

	/*
	 * Can't just do ioctls like when setting up the framebuffer
	 * due to the lack of a u area when called from a timer.
	 * This call not suitable for streams.  Might be OK to from
	 * some source other than an timer.
	 */
	err = VOP_IOCTL((struct vnode *)fp->f_data, cmd, data, fp->f_flag,
	    fp->f_cred);
	if (err) {
		/* On error, disable hardware cursor tracking */
		dtop->dt_flags &= ~DTF_HWCURSORAVAILABLE;
		/* Notify user of error */
		if (!surpress_err_msg) {
			if (err == ENOTTY)
				printf(
	  "Tried to use hardware cursor on %s but it is not available.\n",
				    dtop->dt_screen.scr_fbname);
			else
				printf(
  "Disabled hardware cursor due to dtop cursor ioctl err == %D, cmd == %X\n",
				    err, cmd);
		}
		/*
		 * Used to call dtop_set_cursor or win_shared_update_cursor
		 * to show a normal cursor.  However, I was uncomfortable with
		 * the possible circularity situations that could pose.
		 * So, we are just letting some user action (motion
		 * across window boundary, bringing up a menu, etc.)
		 * to cause a new cursor image to be shown in this
		 * rare case (most likely due to user error).
		 */
	}
	return err;
}

void
dtop_hw_cursor_pos_update(dtop)
	register Desktop *dtop;
{
	/* See if doing using hardware cursor tracking */
	if (dtop->shared_info->cursor_info.hardware_cursor) {
		struct fbcurpos cp;

		/* Initialize the cursor position */
		cp.x = dtop->dt_rt_x;
		cp.y = dtop->dt_rt_y;
		/* Update the cursor position */
		(void) dtop_cursor_ioctl(dtop, FBIOSCURPOS, (caddr_t)&cp, 0);
	}
}

int
dtop_cursor_ok_for_hw(dtop)
	register Desktop	*dtop;
{
	struct cursor *cursor = &dtop->dt_cursorwin->w_cursor;
	struct fbcurpos size;

	/* Determine if op is suitable for hardware cursor */
	switch (cursor->cur_function & PIX_SET) {
	case PIX_SRC:
	case PIX_DST:
	case PIX_SRC|PIX_DST:
	case PIX_SRC&PIX_DST:
		/* See if size is OK */
		if (!dtop_cursor_ioctl(dtop, FBIOGCURMAX, (caddr_t)&size, 0) &&
		    (size.x < cursor->cur_shape->pr_width ||
		     size.y < cursor->cur_shape->pr_height))
			return 0;
		return 1;
	default:
		return 0;
	}
}

int
dtop_load_hw_cursor(dtop)
	register Desktop	*dtop;
{
	extern struct pixrectops mem_ops;
	register Window *cursorwin = dtop->dt_cursorwin;
	register struct cursor *cursor = &cursorwin->w_cursor;
	struct fbcursor fbc;
#define	CUR_IMAGE_BYTES	32*4	/* REMIND: should be dynamic but what the heck,
				 * SunWindows doesn't support large cursors */
#define	CUR_CMAP_LEN	2
#define	CUR_CMAP_BG	0
#define	CUR_CMAP_FG	1
	unsigned char red[CUR_CMAP_LEN];
	unsigned char green[CUR_CMAP_LEN];
	unsigned char blue[CUR_CMAP_LEN];
	char image[CUR_IMAGE_BYTES];
	char mask[CUR_IMAGE_BYTES];
	struct mpr_data md;
	struct pixrect pr;
	int cursor_fg_index;
	int err;

	/* Clear struct */
	bzero((caddr_t)&fbc, sizeof (struct fbcursor));
	/* Tell fb to pay attention to all fields */
	fbc.set = FB_CUR_SETALL;
	/* Enable hardware cursor, even if already on */
	fbc.enable = 1;
	/* Set pos in this call so done atomically */
	fbc.pos.x = dtop->dt_rt_x;
	fbc.pos.y = dtop->dt_rt_y;
	/* Set hot spot */
	fbc.hot.x = cursor->cur_xhot;
	fbc.hot.y = cursor->cur_yhot;
	/* Initialize colormap */
	bzero((caddr_t)red, CUR_CMAP_LEN);
	bzero((caddr_t)green, CUR_CMAP_LEN);
	bzero((caddr_t)blue, CUR_CMAP_LEN);
	fbc.cmap.index = 0;
	fbc.cmap.count = CUR_CMAP_LEN;
	fbc.cmap.red = red;
	fbc.cmap.green = green;
	fbc.cmap.blue = blue;
	/* Initialize planes */
	bzero(image, CUR_IMAGE_BYTES);
	bzero(mask, CUR_IMAGE_BYTES);
	bzero((caddr_t)&pr, sizeof(struct pixrect));
	bzero((caddr_t)&md, sizeof(struct mpr_data));
	pr.pr_ops = &mem_ops;
	pr.pr_depth = 1;
	pr.pr_width = 32;		/* Needs to be padded to 4 bytes */
	pr.pr_height = 32;
	pr.pr_data = (caddr_t)&md;
	md.md_image = (short *)image;
	md.md_linebytes = mpr_linebytes(32, 1);
	fbc.image = image;	/* Mask set below */
	fbc.size.x = cursor->cur_shape->pr_width;
	fbc.size.y = cursor->cur_shape->pr_height;
	/* I don't believe that line bytes are set anywhere else */
	cursorwin->w_cursordata.md_linebytes = mpr_linebytes(
	    cursor->cur_shape->pr_width, 1);
	/* Transfer the image */
	if (pr_rop(&pr, 0, 0, fbc.size.x, fbc.size.y,
	    PIX_SRC, &cursorwin->w_cursormpr, 0, 0))
		printf("HW cursor rop err 1\n");
	/*
	 * The cursor foreground color index is either the specified color or
	 * the window's foreground color.
	 */
	cursor_fg_index = PIX_OPCOLOR(cursor->cur_function);
	if (cursorwin->w_cms.cms_size == 0) {
		/* Pick default colors if not set on window yet */
		red[CUR_CMAP_BG] = dtop->dt_screen.scr_background.red;
		green[CUR_CMAP_BG] = dtop->dt_screen.scr_background.green;
		blue[CUR_CMAP_BG] = dtop->dt_screen.scr_background.blue;
		red[CUR_CMAP_FG] = dtop->dt_screen.scr_foreground.red;
		green[CUR_CMAP_FG] = dtop->dt_screen.scr_foreground.green;
		blue[CUR_CMAP_FG] = dtop->dt_screen.scr_foreground.blue;
	} else {
		int cmap_offset;
		struct	cms_map cmap;

		/* Set the foreground color if not explicitly set */
		if ((cursor_fg_index == 0) ||
		    (cursor_fg_index >= cursorwin->w_cms.cms_size))
			cursor_fg_index = cursorwin->w_cms.cms_size-1;
		/* Window color map information can come from one of 2 places */
		if (cursorwin->w_flags & WF_CMSHOG)
			cmap = cursorwin->w_cmap;
		else
			cmap = dtop->dt_cmap;
		/* Window cms addr applies to either shared or private cmaps */
		cmap_offset = cursorwin->w_cms.cms_addr;
		/* Setup the colormap (will be don't cares for some ops) */
		red[CUR_CMAP_BG] = cmap.cm_red[cmap_offset];
		green[CUR_CMAP_BG] = cmap.cm_green[cmap_offset];
		blue[CUR_CMAP_BG] = cmap.cm_blue[cmap_offset];
		red[CUR_CMAP_FG] = cmap.cm_red[cmap_offset+cursor_fg_index];
		green[CUR_CMAP_FG] =cmap.cm_green[cmap_offset+cursor_fg_index];
		blue[CUR_CMAP_FG] = cmap.cm_blue[cmap_offset+cursor_fg_index];
	}
	/*
	 * Set up the mask according to what the op is.
	 * The decisions here should be reflected in dtop_cursor_op_ok_for_hw.
	 *
	 * (image, mask):
	 *	(x,0) means show framebuffer (transparent).
	 *	(0,1) means show image background.
	 *	(1,1) means show image foreground.
	 */
	md.md_image = (short *)mask;
	switch (cursor->cur_function & PIX_SET) {
	case PIX_SRC:
		/*
		 * Mask shape: all ones the size of the image.
		 * Image background: window background.
		 * Image foreground: cursor foreground color.
		 */
		if (pr_rop(&pr, 0, 0, fbc.size.x, fbc.size.y,
		    PIX_SET, (struct pixrect *)0, 0, 0))
			printf("HW cursor rop err 2\n");
		fbc.mask = mask;
		break;
	case PIX_DST:
		/*
		 * Mask shape: all zeros.
		 * Image background: don't care.
		 * Image foreground: don't care.
		 */
		if (pr_rop(&pr, 0, 0, fbc.size.x, fbc.size.y,
		    PIX_CLR, (struct pixrect *)0, 0, 0))
			printf("HW cursor rop err 3\n");
		fbc.mask = mask;
		break;
	case PIX_SRC|PIX_DST:
		/*
		 * Mask shape: same shape as image.
		 * Image background: don't care.
		 * Image foreground: cursor foreground color.
		 */
		fbc.mask = image;
		break;
	case PIX_SRC&PIX_DST:
		/*
		 * Mask shape: all ones except where image has ones.
		 * Image background: window background
		 * Image foreground: don't care.
		 */
		if (pr_rop(&pr, 0, 0, fbc.size.x, fbc.size.y,
		    PIX_SET, (struct pixrect *)0, 0, 0))
			printf("HW cursor rop err 4\n");
		if (pr_rop(&pr, 0, 0, fbc.size.x, fbc.size.y,
		    PIX_SRC^PIX_DST, &cursorwin->w_cursormpr, 0, 0))
			printf("HW cursor rop err 5\n");
		fbc.mask = mask;
		break;
	case PIX_NOT(PIX_SRC)&PIX_DST:
		/* TBD */
	case PIX_NOT(PIX_SRC)|PIX_DST:
		/* TBD */
	default:
		/* Do in software */
		return (EINVAL);
	}
	/*
	 * In order to avoid a security problem with having the
	 * FBIOSCURSOR implementor use kcopy to copy stuff, we go
	 * into a mode that temporarily allows kcopy to be used.
	 */
	fbio_kcopy = 1;
	err = dtop_cursor_ioctl(dtop, FBIOSCURSOR, (caddr_t)&fbc, 0);
	fbio_kcopy = 0;
	return err;
}

void
dtop_remove_hw_cursor(dtop)
	register Desktop	*dtop;
{
	struct fbcursor fbc;

	/* Clear struct, including critical enable flag */
	bzero((caddr_t)&fbc, sizeof (struct fbcursor));
	fbc.set = FB_CUR_SETCUR | FB_CUR_SETHOT;
	(void) dtop_cursor_ioctl(dtop, FBIOSCURSOR, (caddr_t)&fbc, 1);
}

dtop_openfb(dtop, fd)
	register Desktop *dtop;
	int	fd;
{
	register int	err = 0;
	struct	fbpixrect fbpr;
	struct	singlecolor *bkgnd = &dtop->dt_screen.scr_background;
	struct	singlecolor *frgnd = &dtop->dt_screen.scr_foreground;
	struct	singlecolor *tmpgnd;
	register struct	dtopcursor *dc;
	caddr_t dtop_alloccmapdata();
	struct	fbgattr fbgattr;
	int	(*ioctl_op)();
	register int	i;
	int plane_group_count;
	int	max_depth = 1;
	u_int lock_size;
	struct fbcurpos cp;

	if (fd == WSID_DEVNONE)
		return (0);
	/*
	 * Dup file descriptor for frame buffer.
	 */
	err = kern_dupfd(fd, &dtop->dt_fbfp);
	if (err)
		return (err);
	ioctl_op = dtop->dt_fbfp->f_ops->fo_ioctl;
	/* Determine colormap size */
	err = (*ioctl_op)(dtop->dt_fbfp, FBIOGATTR, &fbgattr);
	if (err) {
		if (err != ENOTTY) {
#ifdef WINDEVDEBUG
			printf("ioctl err FBIOGATTR\n");
#endif
			return (err);
		}
		/* Use older ioctl if FBIOGATTR not implemented */
		err = (*ioctl_op)(dtop->dt_fbfp, FBIOGTYPE, &fbgattr.fbtype);
		if (err) {
#ifdef WINDEVDEBUG
			printf("ioctl err FBIOGTYPE\n");
#endif
			return (err);
		}
	}
	/*
	 * Colormap may not be less then 2 long (2 long is monochrome case).
	 * Will allow user programs to allocate colormap segments bigger
	 * than dt_cmsize.  However, colormap entries greater than the
	 * length of the map will be ignored.  This convention enables
	 * programs written for color displays to run without errors on
	 * a monochrome display.
	 */
	if ((dtop->dt_cmsize = fbgattr.fbtype.fb_cmsize) < 2) {
#ifdef WINDEVDEBUG
		printf("illegal colormap size (%D)\n", fbgattr.fbtype.fb_cmsize);
#endif
		return (EINVAL);
	}

	/*
	 * Get pixrect for framebuffer.
	 */
	err = (*ioctl_op)(dtop->dt_fbfp, FBIOGPIXRECT, &fbpr);
	if (err) {
#ifdef WINDEVDEBUG
		printf("ioctl err FBIOGPIXRECT\n");
#endif
		return (err);
	}
	dtop->dt_pixrect = fbpr.fbpr_pixrect;
	if (dtop->dt_pixrect==(struct pixrect *)0)
		return (EBUSY);
	if (dtop->dt_pixrect==(struct pixrect *)-1)
		return (EINVAL);


	/* Determine double buffering capabilities */
	err = pr_dbl_get(dtop->dt_pixrect, PR_DBL_AVAIL);
	if (err == PR_DBL_EXISTS) {
		dtop->dt_flags |= DTF_DBLBUFFER;
		dtop->dt_curdbl = WINDOW_NULL;
		dtop->dt_dbl_bkgnd = PR_DBL_B;
		dtop->dt_dbl_frgnd = PR_DBL_A;
		dtop->dt_curdbl = 0;
	}

	/* Allocate colormap resource map */
	dtop->dt_cmapdata = dtop_alloccmapdata(dtop, &dtop->dt_cmap,
	    dtop->dt_cmsize);
	if (dtop->dt_cmapdata == 0)
		return (ENXIO);
	dtop->dt_rmp = (struct mapent *)new_kmem_zalloc(
	    (u_int)(sizeof (struct mapent) * CRM_SIZE(dtop->dt_cmsize)),
	    KMEM_SLEEP);
	rminit((struct map *)dtop->dt_rmp,
	    (long)(CRM_NSLOTS(dtop->dt_cmsize)*CRM_SLOTSIZE),
	    (u_long)(0+CRM_ADDROFFSET), "colormap", CRM_SIZE(dtop->dt_cmsize));

	/* Determine foreground and background of color map */
	if (dtop->dt_screen.scr_flags & SCR_SWITCHBKGRDFRGRD) {
		tmpgnd = bkgnd;
		bkgnd = frgnd;
		frgnd = tmpgnd;
	}

	/* Determine available plane groups */
	(void) pr_available_plane_groups(dtop->dt_pixrect, DTOP_MAX_PLANE_GROUPS,
	    dtop->dt_plane_groups_available);
	/* Determine if multiple plane groups */
	plane_group_count = 0;
	for (i = 0; i < DTOP_MAX_PLANE_GROUPS; i++) {
		/* Restrict frame buffer plane group access */
		if (((dtop->dt_screen.scr_flags & SCR_8BITCOLORONLY) &&
		    (i != PIXPG_8BIT_COLOR) && (i != PIXPG_WID)) ||
		    ((dtop->dt_screen.scr_flags & SCR_OVERLAYONLY) &&
		    (i != PIXPG_OVERLAY)))
			dtop->dt_plane_groups_available[i] = 0;
		if (dtop->dt_plane_groups_available[i]) {
			int end;

			plane_group_count++;
			/* Don't set e & background for enable plane */
			if ((i != PIXPG_OVERLAY_ENABLE) &&
			    (i != PIXPG_VIDEO_ENABLE) &&
			    (i != PIXPG_CURSOR_ENABLE)) {
				/* Set fore & background in each plane group */
				pr_set_plane_group(dtop->dt_pixrect, i);
				pr_putcolormap(dtop->dt_pixrect, 0, 1,
				    &bkgnd->red, &bkgnd->green, &bkgnd->blue);
				switch (dtop->dt_pixrect->pr_depth) {
				case 1: end = 1; break;
				case 8: end = 255; max_depth = 8; break;
				case 24:
				case 32: end = 255; max_depth = 32; break;
#ifdef WINDEVDEBUG
				default: printf("Unknown depth %D\n",
				    dtop->dt_pixrect->pr_depth);
#endif
				}
				pr_putcolormap(dtop->dt_pixrect, end, 1,
				    &frgnd->red, &frgnd->green, &frgnd->blue);
			}
		}
	}
	if (dtop->dt_plane_groups_available[PIXPG_WID])
	    plane_group_count--;
	if (plane_group_count > 1)
		dtop->dt_flags |= DTF_MULTI_PLANE_GROUPS;
	/* Set initial plane group explicitly */
	if ((dtop->dt_screen.scr_flags & SCR_8BITCOLORONLY) &&
	    dtop->dt_plane_groups_available[PIXPG_8BIT_COLOR])
		pr_set_plane_group(dtop->dt_pixrect, PIXPG_8BIT_COLOR);
	else if ((dtop->dt_screen.scr_flags & SCR_OVERLAYONLY) &&
	    dtop->dt_plane_groups_available[PIXPG_OVERLAY])
		pr_set_plane_group(dtop->dt_pixrect, PIXPG_OVERLAY);
	else if (dtop->dt_plane_groups_available[PIXPG_OVERLAY])
		/*
		 * PIXPG_OVERLAY takes precedence over PIXPG_8BIT_COLOR
		 * for backwards compatibility reasons (see
		 * win_pick_plane_group).
		 */
		pr_set_plane_group(dtop->dt_pixrect, PIXPG_OVERLAY);
	else if (dtop->dt_plane_groups_available[PIXPG_8BIT_COLOR])
		pr_set_plane_group(dtop->dt_pixrect, PIXPG_8BIT_COLOR);

	/*
	 * Set up the cross hair pixrects, but do not allocate image space.
	 */

	dc = &dtop->dt_cursor;

	dc->horiz_hair_mpr.pr_depth = max_depth;
	dc->horiz_hair_mpr.pr_width = dtop->dt_screen.scr_rect.r_width;
	dc->horiz_hair_mpr.pr_height = CURSOR_MAX_HAIR_THICKNESS;

	dc->horiz_hair_size =
		-(dc->horiz_hair_mpr.pr_height *
		dtop_set_linebytes(&dc->horiz_hair_mpr));
	dc->horiz_hair_data.md_image = 0;
	horiz_hair_set_up(dtop, FALSE);

	dc->vert_hair_mpr.pr_depth = max_depth;
	dc->vert_hair_mpr.pr_width = CURSOR_MAX_HAIR_THICKNESS;
	dc->vert_hair_mpr.pr_height = dtop->dt_screen.scr_rect.r_height;

	dc->vert_hair_size =
		-(dc->vert_hair_mpr.pr_height *
		dtop_set_linebytes(&dc->vert_hair_mpr));
	dc->vert_hair_data.md_image = 0;
	vert_hair_set_up(dtop, FALSE);

	/* See if hardware cursor is part of this framebuffer */
	if (win_do_hw_cursor &&
	    (dtop_cursor_ioctl(dtop, FBIOGCURPOS, (caddr_t)&cp, 1) == 0))
		dtop->dt_flags |= DTF_HWCURSORAVAILABLE;

	/* No need to check for null return - we are not at interrupt level */
	lock_size = roundup(sizeof (Win_lock_block), PAGESIZE);

	/*
	 * Allocate the shared_info only once, because we are not going to
	 * free it ever.  This is because there are sleeps on this address
	 * that we can't make sure are all gone before releasing this storage.
	 */
	if (dtop->shared_info == 0)
		dtop->shared_info =
		  (Win_lock_block *)getpages(btopr(sizeof (Win_lock_block)), 0);

	bzero((caddr_t)dtop->shared_info, sizeof (Win_lock_block));
	dtop->display_waiting = 0;

	dtop->shared_info->version = WIN_LOCK_VERSION;
	/* NOTE: maybe RISC instead */
	dtop->shared_info->cpu_type = WIN_LOCK_68000;
	dtop->dt_sharedq = (struct inputevent *)
		((caddr_t) dtop->shared_info + sizeof (Win_lock_block));
	dtop->dt_sharedq_size =
	    (lock_size - sizeof (Win_lock_block)) / sizeof (struct inputevent);
	dtop->shared_info->shared_eventq.size = dtop->dt_sharedq_size;
	return (0);
}

dtop_close(dtop)
	register Desktop *dtop;
{
	register Desktop *dt;
	register int p;
	Desktop *dtopneighbor = NULL;
	Desktop **dt_prev_ptr;
	register Workstation *ws = dtop->dt_ws;
	Win_lock_block *shared_info_tmp;
	int waiting_tmp;

	/*
	 * Flush the notify timeout queue
	 */
	wt_sigwnch_untimeout();

	/*
	 * Remove references to this desktop from other desktops
	 */
	for (dt = desktops; dt < &desktops[ndesktops]; dt++)
		if (dt->dt_flags&DTF_PRESENT) {
			if (dt != dtop && dt->dt_ws == dtop->dt_ws)
				dtopneighbor = dt;
			for (p = 0; p < SCR_POSITIONS; p++)
				if (dt->dt_neighbors[p] == dtop)
					dt->dt_neighbors[p] = NULL;
		}
	/* Handle null workstation */
	if (ws == WORKSTATION_NULL)
		goto NoWs;
	/*
	 * Remove locator from this desktop
	 */
	dtop_change_loc_dtop(dtop, dtopneighbor, 0, 0);
	/* Remove desktop from workstation */
	dt_prev_ptr = &ws->ws_dtop;
	for (dt = ws->ws_dtop; dt; dt = dt->dt_next) {
		if (dt == dtop) {
			*dt_prev_ptr = dt->dt_next;
			break;
		}
		dt_prev_ptr = &dt->dt_next;
	}
	/* Close workstation if no more desktops using it */
	if (ws->ws_dtop == DESKTOP_NULL)
		ws_close(ws);

NoWs:
	/* Reset double buffering states */
	if (dtop->dt_flags & DTF_DBLBUFFER) {
		dtop_changedisplay(dtop, PR_DBL_A, PR_DBL_B, FALSE);
		if (pr_dbl_set(dtop->dt_pixrect, PR_DBL_WRITE, PR_DBL_BOTH, 0))
#ifdef WINDEVDEBUG
			printf("Error pr_dbl_set display  in dtop_close\n");
#else
			;
#endif
	}

	/*
	 * Close frame buffer.
	 */
	if (dtop->dt_fbfp) {
		/*
		 * DON'T clear screen because at this point have no way to
		 * arbitrate kernel access to the screen.  In the case of the
		 * sun1bw frame buffer could clobber some important register.
		 */
		/*
		 * Closing frame buffer will release dtop->dt_pixrect.
		 */
		closef(dtop->dt_fbfp);
	}
	/*
	 * Remove allocated resources
	 */
	rl_free(&dtop->dt_rlinvalid);
	cms_freecmapdata(dtop->dt_cmapdata, &dtop->dt_cmap,
	    dtop->dt_cmsize);
	if (dtop->dt_rmp)
		kmem_free((caddr_t)dtop->dt_rmp,
		    (u_int)(sizeof (struct mapent) * CRM_SIZE(dtop->dt_cmsize)));

	/* free the cross hair storage */
	if (dtop->dt_cursor.horiz_hair_data.md_image)
		kmem_free((caddr_t) dtop->dt_cursor.horiz_hair_data.md_image,
		    (u_int)dtop->dt_cursor.horiz_hair_size);
	if (dtop->dt_cursor.vert_hair_data.md_image)
		kmem_free((caddr_t) dtop->dt_cursor.vert_hair_data.md_image,
		    (u_int)dtop->dt_cursor.vert_hair_size);
	rl_free(&dtop->dt_cursor.horiz_hair_rectlist);
	rl_free(&dtop->dt_cursor.vert_hair_rectlist);

	/*
	 * Never free the shared lock block page(s), because can't be sure
	 * when wakeup will take affect.
	 */
	shared_info_tmp = dtop->shared_info;
	waiting_tmp = dtop->display_waiting;
	bzero((caddr_t)dtop, sizeof (*dtop));
	dtop->shared_info = shared_info_tmp;
	dtop->display_waiting = waiting_tmp;
	/* Wake up to give a chance to restart in win_ioctl */
	wakeup((caddr_t)shared_info_tmp);
}

void
dtop_change_loc_dtop(dtop, dtop_new, x, y)
	register Desktop *dtop;
	register Desktop *dtop_new;
	int x, y;
{
	register Workstation *ws = dtop->dt_ws;

	if (dtop == ws->ws_loc_dtop) {
		dtop_cursordown(dtop);
		win_shared_update_cursor_active(dtop->shared_info, FALSE);
		ws->ws_loc_dtop = dtop_new;
		if (dtop_new) {
			dtop_new->dt_rt_x = x;
			dtop_new->dt_rt_y = y;
			dtop_new->shared_info->status.new_cursor = TRUE;
			/* update the shared memory */
			win_shared_update_mouse_xy(dtop_new->shared_info, 0, 0);
			win_shared_update_cursor_active(
			    dtop_new->shared_info, TRUE);
			dtop_update_enable(dtop_new, dtop, 0);
		}
	}
	/* Remove pick focus from this desktop */
	if (dtop == ws->ws_pick_dtop) {
		ws->ws_pick_dtop = dtop_new;
		if (dtop_new) {
			dtop_new->dt_ut_x = x;
			dtop_new->dt_ut_y = y;
		}
	}
}

void
dtop_update_enable(dtop_new, dtop, doit)
	register Desktop *dtop_new;
	Desktop *dtop;
	int doit;
{
	char groups[DTOP_MAX_PLANE_GROUPS];
	register struct pixrect *pr;

	if (dtop_new == DESKTOP_NULL)
		return;
	/* Find a pixrect that is capable of setting the enable plane */
	pr = dtop_new->dt_pixrect;
	(void) pr_available_plane_groups(pr, DTOP_MAX_PLANE_GROUPS, groups);
	if (!groups[PIXPG_OVERLAY_ENABLE]) {
		if (dtop == DESKTOP_NULL)
			return;
		pr = dtop->dt_pixrect;
		(void) pr_available_plane_groups(pr, DTOP_MAX_PLANE_GROUPS,
		    groups);
		if (!groups[PIXPG_OVERLAY_ENABLE])
			return;
	}
	/* See if SCR_TOGGLEENABLE set anywhere */
	if ((dtop_new->dt_screen.scr_flags & SCR_TOGGLEENABLE) ||
	    (dtop && (dtop->dt_screen.scr_flags & SCR_TOGGLEENABLE)) || doit)
		dtop_set_enable(dtop_new, pr);
}

void
dtop_set_enable(dtop, pr)
	Desktop *dtop;
	register struct pixrect *pr;
{
	int original_plane_group;

	original_plane_group = pr_get_plane_group(pr);
	pr_set_planes(pr, PIXPG_OVERLAY_ENABLE, PIX_ALL_PLANES);
	if (dtop->dt_plane_groups_available[PIXPG_OVERLAY] ||
	    dtop->dt_plane_groups_available[PIXPG_MONO])
		pr_rop(pr, 0, 0, pr->pr_width, pr->pr_height,
		    PIX_SET, 0, 0, 0);
	if (dtop->dt_plane_groups_available[PIXPG_8BIT_COLOR])
		pr_rop(pr, 0, 0, pr->pr_width, pr->pr_height,
		    PIX_CLR, 0, 0, 0);
	pr_set_planes(pr, original_plane_group, PIX_ALL_PLANES);
}

int
dtop_removewin(dtop, w)
	Desktop *dtop;
	register struct window *w;
{
	int	error;
	bool	fixclipping;

	if (w->w_link[WL_PARENT] == NULL)
		return (EINVAL);
	fixclipping = wt_isindisplaytree(w);
	if ((error = wt_remove(w)) < 0)
		return (error);
	if (fixclipping)
		dtop_invalidateclipping(dtop, w->w_link[WL_PARENT], &w->w_rect);
	return (0);
}

dtop_interrupt(dtop, poll_rate)
	register Desktop *dtop;
	int poll_rate;
{
	register Win_lock_block	*shared_info = dtop->shared_info;

	/* Do lock timeout resolution */
	if (win_lock_data_locked(shared_info))
		wlok_lockcheck(&dtop->dt_datalock, poll_rate, 0);

	/* checked the shared memory locks */

	dtop_check_lock(dtop, &dtop->dt_mutexlock, &shared_info->mutex,
	    poll_rate, dtop_init_mutex_lock);

	dtop_check_lock(dtop, &dtop->dt_displaylock, &shared_info->display,
	    poll_rate, dtop_init_display_lock);

	/* See if moved or new cursor that should be put up now */
	if (shared_info->status.new_cursor) {
		dtop_cursordown(dtop);
		/*
		dtop->dt_flags &= ~DTF_NEWCURSOR;
		*/
		dtop_cursorup(dtop);
	}

	/* See if overflow from shared q may be shifted */
	if (dtop->dt_sharedq_owner)
		win_sharedq_shift(dtop->dt_sharedq_owner);

	/*
	 * see if a process is waiting for an already released lock.
	 * We need to do this here because of the race condition that
	 * exists between when a user process checks the waiting count
	 * and when the kernel sets it before sleeping.
	 */
	if ((dtop->display_waiting) && !win_lock_display_locked(shared_info)) {
#ifdef WINDEVDEBUG
		if (win_waiting_debug)
			printf("Waking up waiting process because display lock is free\n");
#endif
		wakeup((caddr_t)shared_info);
	}

	/* see if shared locking info needs updating */
	win_shared_update(dtop);
}


dtop_validate_shared_lock(dtop, wlock)
	register Desktop 	*dtop;
	Winlock			*wlock;
{
	register Win_lock_block	*shared_info = dtop->shared_info;

	if (wlock == &dtop->dt_displaylock)
	    dtop_check_lock(dtop, wlock, &shared_info->display,
	    0, dtop_init_display_lock);
	else
	    dtop_check_lock(dtop, wlock, &shared_info->mutex,
	    0, dtop_init_mutex_lock);

	/* see if shared locking info needs updating */
	win_shared_update(dtop);
}


static int
dtop_check_lock(dtop, wlock, shared_lock, poll_rate, init_lock)
	Desktop		*dtop;
	Winlock		*wlock;
	Win_lock	*shared_lock;
	int		poll_rate;
	void		(*init_lock)();

{
	int	orig_count;

	if (!win_lock_locked(shared_lock)) {
	    if (wlock->lok_pid) {
		/*
		 * Here the user has unlocked the mutex lock.
		 * So we clear the kernel lock.
		 * First set the lock bit so we can unlock it with
		 * wlok_unlock().
		 */
		win_lock_set(shared_lock, TRUE);
		shared_lock->count = 1;
		wlok_unlock(wlock);
	    }
	    return;
	}

	/* the shared lock is locked */

	if (wlock->lok_id && (wlock->lok_id != shared_lock->id)) {
	    /*
	     * Here a user process has reacquired the lock.
	     * So we forget about the old lock.
	     * Don't do the usual unlock action, since the lock
	     * is still locked.
	     * Also, be sure to preserve the lock count.
	     */
	    orig_count = shared_lock->count;
	    shared_lock->count = 1;
	    wlock->lok_unlock_action = 0;
	    wlok_unlock(wlock);
	    /* reset the lock, since wlok_unlock() zero'ed it */
	    win_lock_set(shared_lock, TRUE);
	    shared_lock->count = orig_count;
	}

	if (wlock->lok_pid) {
	    /*
	     * Here the lock is set and the timer is
	     * running, so we check the lock.
	     */
	    if (poll_rate)
		wlok_lockcheck(wlock, poll_rate, 0);
	    return;
	}
	/*
	 * Here the lock was set by a user process,
	 * so we need to initialize our internal lock.
	 */
	if (shared_lock->pid) {
	    extern struct proc 	*pfind();
	    struct proc		*process = pfind(shared_lock->pid);

	    orig_count = shared_lock->count;
	    wlok_clear(wlock);
	    (init_lock)(dtop, shared_lock->id, process);
	    shared_lock->count = orig_count;
	    if (!process) {
		/*
		 * Here a user process has set the lock,
		 * and either the process has died, or the pid was
		 * not set correctly.  So we clear the lock.
		 */
		if (!(wlock->lok_options & WLOK_SILENT))
		    printf("Window %s lock broken after process %D went away\n",
				wlock->lok_string, shared_lock->pid);
		wlok_forceunlock(wlock);
	    }
	} else {
	    /*
	     * Here the lock bit is set, but the process has
	     * not set the lock.pid yet.
	     * So complain after a while.
	     */
	    if (wlock->lok_time == 0) {
		/* initialize the lock */
		orig_count = shared_lock->count;
		wlok_clear(wlock);
		(init_lock)(dtop, shared_lock->id, 0);
		shared_lock->count = orig_count;
	    }
	    if (poll_rate)
		wlok_lockcheck(wlock, poll_rate, 0);
	}
}


/*
 * Constrains to be on desktop and moves to another if adjacent.
 */
dtop_track_locator(dtop_ptr, x_ptr, y_ptr)
	Desktop	**dtop_ptr;
	int	*x_ptr;
	int	*y_ptr;
{
	register Desktop *dtop = *dtop_ptr;
	register Desktop *dtop_old = *dtop_ptr;
	register int x = *x_ptr;
	register int y = *y_ptr;

	if (x < dtop->dt_screen.scr_rect.r_left)
		if (dtop->dt_neighbors[SCR_WEST]) {
			dtop = dtop->dt_neighbors[SCR_WEST];
			x = dtop->dt_screen.scr_rect.r_left+
			    dtop->dt_screen.scr_rect.r_width-
			    (dtop_old->dt_screen.scr_rect.r_left-x);
			y = (dtop->dt_screen.scr_rect.r_height*
			    y)/dtop_old->dt_screen.scr_rect.r_height;
		} else
			x = dtop->dt_screen.scr_rect.r_left;
	else if (x > dtop->dt_screen.scr_rect.r_width-1)
		if (dtop->dt_neighbors[SCR_EAST]) {
			dtop = dtop->dt_neighbors[SCR_EAST];
			x = dtop->dt_screen.scr_rect.r_left+
			    (x-dtop_old->dt_screen.scr_rect.r_width);
			y = (dtop->dt_screen.scr_rect.r_height*
			    y)/dtop_old->dt_screen.scr_rect.r_height;
		} else
			x = rect_right(&dtop->dt_screen.scr_rect)-1;
	if (y < dtop->dt_screen.scr_rect.r_top)
		if (dtop->dt_neighbors[SCR_NORTH]) {
			dtop = dtop->dt_neighbors[SCR_NORTH];
			y = dtop->dt_screen.scr_rect.r_top+
			    dtop->dt_screen.scr_rect.r_height-
			    (dtop_old->dt_screen.scr_rect.r_top-y);
			x = (dtop->dt_screen.scr_rect.r_width*
			    x)/dtop_old->dt_screen.scr_rect.r_width;
		} else
			y = dtop->dt_screen.scr_rect.r_top;
	else if (y > dtop->dt_screen.scr_rect.r_height-1)
		if (dtop->dt_neighbors[SCR_SOUTH]) {
			dtop = dtop->dt_neighbors[SCR_SOUTH];
			y = dtop->dt_screen.scr_rect.r_top+
			    (y-dtop_old->dt_screen.scr_rect.r_height);
			x = (dtop->dt_screen.scr_rect.r_width*
			    x)/dtop_old->dt_screen.scr_rect.r_width;
		} else
			y = rect_bottom(&dtop->dt_screen.scr_rect)-1;
	*dtop_ptr = dtop;
	*x_ptr = x;
	*y_ptr = y;
}

dtop_set_cursor(dtop)
	register Desktop *dtop;
{
	Workstation *ws = dtop->dt_ws;
	register struct	window *oldcursorwin = dtop->dt_cursorwin;
	register struct	window *newcursorwin;
	int new_cmap = dtop->dt_flags & DTF_NEWCMAP;

	dtop->dt_cursorwin = NULL;
	if ((ws == WORKSTATION_NULL) || (dtop->dt_rootwin == NULL) ||
	    (ws->ws_loc_dtop != dtop))
		return;
	if (ws->ws_inputgrabber) {
		/* The cursor reflects the input grabber */
		dtop->dt_cursorwin = ws->ws_inputgrabber;
	} else {
		/* The cursor reflects underlaying window */
		dtop->dt_cursorwin = wt_intersected(dtop->dt_rootwin,
		    dtop->dt_rt_x, dtop->dt_rt_y);
	}
	newcursorwin = dtop->dt_cursorwin;
	/* Might need new cursor up because of change of underlaying window */
	/*
	dtop->dt_flags |= DTF_NEWCURSOR;
	*/
	dtop->shared_info->status.new_cursor = TRUE;

	/* Change colormap if need to */
	if ((new_cmap ||
	    (oldcursorwin != newcursorwin))) {
		if (newcursorwin && (newcursorwin->w_flags & WF_CMSHOG)) {
			dtop_putcolormap(dtop, newcursorwin->w_cms.cms_size,
			    &newcursorwin->w_cmap);
		} else if (new_cmap ||
		    (oldcursorwin && (oldcursorwin->w_flags & WF_CMSHOG))) {
			dtop_putcolormap(dtop, dtop->dt_cmsize, &dtop->dt_cmap);
		}
		dtop->dt_flags &= ~DTF_NEWCMAP;
	}
	/*
	 * Update the shared cursor if the cursor window or mouse window
	 * has changed.  For hardware cursor, need to do this if the color
	 * map has changed, too.
	 */
	if ((oldcursorwin != newcursorwin) ||
	    (new_cmap && dtop->shared_info->cursor_info.hardware_cursor))
		win_shared_update_cursor(dtop);
	/* Try to update hardware cursor position with real time coordinates */
	dtop_hw_cursor_pos_update(dtop);
}

int
dtop_lockdata(dev)
	dev_t	dev;
{
	Window *w = winfromdev(dev);
	register Desktop *dtop = w->w_desktop;
	register Win_lock_block	*shared_info = dtop->shared_info;

	if (!win_lock_data_locked(dtop->shared_info)) {
		/*
		 * mark the shared memory to show that
		 * someone is wating for a lock.
		 */
		shared_info->waiting++;
		dtop->display_waiting++;

		while (
		    win_lock_mutex_locked(shared_info) ||
		    win_lock_data_locked(shared_info) ||
		    (win_lock_display_locked(shared_info) &&
		    (shared_info->display.pid!=u.u_procp->p_pid)))
			if (sleep((caddr_t)dtop->shared_info, LOCKPRI|PCATCH)) {
				shared_info->waiting--;
				dtop->display_waiting--;
				return (-1);
			}

		/* unmark the shared memory lock */
		shared_info->waiting--;
		dtop->display_waiting--;

		dtop_init_data_lock(dtop, u.u_procp);
		shared_info->data.pid = dtop->dt_datalock.lok_pid;
	} else {
		/*
		 * Wouldn't get into this routine unless
		 * calling pid == dt_datalock.lok_pid
		 */
		*(dtop->dt_datalock.lok_count) += 1;
	}
	return (0);
}

void
dtop_timedout_data(wlock)
	Winlock *wlock;
{
	extern	struct proc *pfind();
	register struct proc *process = pfind(wlock->lok_pid);

	/* Send SIGXCPU if process still exists */
	if (process != (struct proc *)0) {
		psignal(process, SIGXCPU);
		printf("The offending process was sent SIGXCPU\n");
	}
}

void
dtop_unlockdata(wlock)
	Winlock *wlock;
{
	Desktop	*dtop = (Desktop *)wlock->lok_client;

	dtop_computeclipping(dtop, TRUE);
	dtop->shared_info->data.pid = 0;
}

dtop_computeclipping(dtop, notify)
	register Desktop *dtop;
	bool	notify;
{
	extern wt_add_to_notifyqueue();
	extern winnotify_inorder;

	if (dtop->dt_parentinvalidwin == NULL)
		return;
	wt_setclipping(dtop->dt_parentinvalidwin, &dtop->dt_rlinvalid);
	ws_set_focus(dtop->dt_ws, FF_PICK_CHANGE);
	dtop_set_cursor(dtop);
	rl_free(&dtop->dt_rlinvalid);
	if (notify) {
	    if (winnotify_inorder) {
		(void) wt_enumerate(wt_add_to_notifyqueue,  WT_TOPTOBOTTOM,
		    dtop->dt_parentinvalidwin);
	    } else {
		(void) wt_enumeratechildren(wt_notifychanged,
		    dtop->dt_parentinvalidwin, (struct rect *)0);
	    }
	    dtop->dt_parentinvalidwin = NULL;
	}
}

dtop_invalidateclipping(dtop, parent, rect)
	register Desktop *dtop;
	register struct window *parent;
	struct	rect *rect;
	/*
	 * The parent relative rect has invalid clipping and
	 * parent is the bottom most window affected.
	 */
{
	struct	rectlist rlparent;
	struct	window *root = parent->w_desktop->dt_rootwin;

	rl_initwithrect(rect, &rlparent);
	/*
	 * Make invalid stuff relative to root.
	 * Need to do this because eventual call to wt_setclipping must be
	 * called with root as the initial window.
	 */
	while (parent != root) {
		wt_passrltoancestor(&rlparent, parent,
		    parent->w_link[WL_PARENT]);
		parent = parent->w_link[WL_PARENT];
	}
	dtop->dt_parentinvalidwin = root;
	rl_union(&rlparent, &dtop->dt_rlinvalid, &dtop->dt_rlinvalid);
	rl_free(&rlparent);
	if (!win_lock_data_locked(dtop->shared_info))
		dtop_computeclipping(dtop, TRUE);
}


/*
 * Display access control
 */
int
dtop_lockdisplay(dev, rect)
    dev_t	dev;
    struct	rect *rect;
{
    register struct window 	*w = winfromdev(dev);
    register Desktop		*dtop = w->w_desktop;
    register Win_lock_block	*shared_info = dtop->shared_info;
    struct rect 		rectcursor, screen_rect;
    short			take_down_cursor = FALSE;
    Win_shared_cursor		*shared_cur;
    /*
     * Currently, locking a dev you have locked increments a ref count.
     */
    if (!win_lock_display_locked(shared_info)) {
	/*
	 * mark the shared memory to show that
	 * someone is wating for a lock.
	 */
	shared_info->waiting++;
	dtop->display_waiting++;

	/* loop until the lock is free */
	while (win_lock_mutex_locked(shared_info) ||
		win_lock_display_locked(shared_info) ||
		((dtop->dt_displaygrabber != NULL) &&
		(dtop->dt_displaygrabber->w_pid != w->w_pid)) ||
		(win_lock_data_locked(shared_info) &&
		(dtop->dt_datalock.lok_pid != u.u_procp->p_pid))) {
		if (sleep((caddr_t)dtop->shared_info, LOCKPRI|PCATCH)) {
			shared_info->waiting--;
			dtop->display_waiting--;
			return (-1);
		}
	}

	/* unmark the shared memory lock */
	shared_info->waiting--;
	dtop->display_waiting--;
	shared_cur = &dtop->shared_info->cursor_info;
	if (!(shared_cur->spare3 )) {
	    if (cursor_up(dtop)) {
		int cursor_in;	/* Whether the cursor is in w ? */

		 rect_construct(&rectcursor,
			    cursor_x(dtop) - w->w_screenx,
			    cursor_y(dtop) - w->w_screeny,
			    cursor_screen_width(dtop),
			    cursor_screen_height(dtop));

		cursor_in = rl_rectintersects(&rectcursor, &w->w_rlexposed);
		/*
		* Don't take down the cursor if the cursor is in the
		* currently active double buffering window.  And we are
		* just accessing the background (the cursor is only in the
		* foreground).
		*/
		if ((dtop->dt_curdbl == w) && 
			(w->w_dbl_wrstate == PW_DBL_BACK) &&
			(w->w_dbl_rdstate == PW_DBL_BACK) && cursor_in)
			take_down_cursor = FALSE;
		else {
		/*
		* Can't restrict cursor removal if
		* displaygrabbed because user may violate
		* w_rlexposed if wants, i.e., to do menus.
		*/
		    take_down_cursor =
			rect_intersectsrect(rect, &rectcursor) &&
			(dtop->dt_displaygrabber == w || cursor_in);
		}
	    }
	}

	/* convert locked area to screen coordinates */
	screen_rect = *rect;
	rect_passtoparent(w->w_screenx, w->w_screeny, &screen_rect);

	/* check for intersection with cross hairs */
	if (horiz_hair_up(dtop)) {
	    take_down_cursor = take_down_cursor ||
		rl_rectintersects(&screen_rect,
				&dtop->dt_cursor.horiz_hair_rectlist);
	}

	if (vert_hair_up(dtop)) {
	    take_down_cursor = take_down_cursor ||
		rl_rectintersects(&screen_rect,
				&dtop->dt_cursor.vert_hair_rectlist);
	}

	if (take_down_cursor) {
	    dtop_cursordown(dtop);
	}

	shared_info->display.pid = u.u_procp->p_pid;
	shared_info->display.id++;
	dtop_init_display_lock(dtop, shared_info->display.id, u.u_procp);

	/*
	 * Double buffer support
	 * Flip the write control bits  if current window is the
	 *  double bufferer else set write to both
	 */
	if (dtop->dt_dblcount) {
		if (dtop->dt_curdbl == w) {
			(void)dtop_dblset(dtop, PR_DBL_WRITE, w->w_dbl_wrstate);
			(void)dtop_dblset(dtop, PR_DBL_READ, w->w_dbl_rdstate);
		} else if (!(dtop->dt_displaygrabber == w)) {
			if (pr_dbl_set(dtop->dt_pixrect, PR_DBL_WRITE,
			    PR_DBL_BOTH, PR_DBL_READ, dtop->dt_dbl_bkgnd, 0))
#ifdef WINDEVDEBUG
				printf("Error dbl_set lock display not",
				" a cur dbl %d\n", dtop->dt_dbl_frgnd);
#else
				;
#endif
		}
	}
    } else if (dtop->dt_displaylock.lok_count)
	*(dtop->dt_displaylock.lok_count) += 1;
#ifdef WINDEVDEBUG
    else
	printf("Warning: display lock count pointer is NULL\n");
#endif
    /*
     * Note: Should check to see if going to write outside of
     * original rect affected.
     */
    return (w->w_clippingid);
}

/* ARGSUSED */
void
dtop_timedout_display(wlock)
	Winlock *wlock;
{
#ifdef WINDEVDEBUG
	Desktop		*dtop = (Desktop *) wlock->lok_client;
	Win_lock	*shared_lock = &dtop->shared_info->display;
#endif

	printf("You may see display garbage because of this action\n");

#ifdef WINDEVDEBUG
	/* debug info */
	if ((wlock->lok_pid != shared_lock->pid) ||
	    (wlock->lok_id != shared_lock->id)) {
		printf("Internal lock: pid = %d, id = %d, time = %d\n",
			wlock->lok_pid, wlock->lok_id, wlock->lok_time);
		printf("Shared lock: pid = %d, id = %d\n",
			shared_lock->pid, shared_lock->id);
	}
#endif
}

static void
dtop_update_cursor(dtop)
	register Desktop *dtop;
{

	if (cursor_up(dtop) || horiz_hair_up(dtop) || vert_hair_up(dtop)) {
		if (dtop != dtop->dt_ws->ws_loc_dtop)
			/*
			 * take down current cursor ms not on dtop anymore.
			 */
			dtop_cursordown(dtop);
		if (dtop->dt_cursorwin &&
		    ((cursor_x(dtop) != dtop->dt_rt_x -
			dtop->dt_cursorwin->w_cursor.cur_xhot) ||
		    (cursor_y(dtop) != dtop->dt_rt_y -
			dtop->dt_cursorwin->w_cursor.cur_yhot))) {
			/*
			 * take down current cursor cause in wrong position
			 */
			dtop_cursordown(dtop);
		}
	}
}

void
dtop_unlockdisplay(wlock)
	Winlock *wlock;
{
	register Desktop *dtop = (Desktop *)wlock->lok_client;

	dtop_update_cursor(dtop);
	dtop->shared_info->display.pid = 0;
	/*
	 * put up current cursor now
	 */
	dtop_cursorup(dtop);
}

void
dtop_unlockmutex(wlock)
	Winlock *wlock;
{
	register Desktop *dtop = (Desktop *)wlock->lok_client;

	dtop->shared_info->mutex.pid = 0;
}

dtop_drawcursor(dtop)
    register Desktop *dtop;
{
#define	ROPERR(tag) { rop_err_id = (tag); goto Roperr; }
    register struct dtopcursor 	*dc;
    register struct cursor 	*cursor;
    register struct mpr_data 	*scrmpr_data;
    struct mpr_data 		*data;
    struct pixrect		*shape;
    int				planes;	/* Can't be register */
    struct rect 		hair_rect;
    short			want_cursor;
    Workstation			*ws;
    Win_shared_cursor		*shared;
    struct window		*cursorwin;
    struct pixrect		*pr;
    register int		full_planes = PIX_ALL_PLANES;
    register int		original_plane_group;
    register int		rop_err_id = 0;
    int				readstate;
    int				writestate;
    int				cursor_offset_x, cursor_offset_y;
    char			pgroups[PIXPG_INVALID+1];


    if (dtop == NULL || dtop->dt_pixrect == NULL || wincursordisable)
	return;

    /* can't do anything if the shared structure is locked down */
    if (win_lock_mutex_locked(dtop->shared_info))
	return;
    (void) pr_available_plane_groups(dtop->dt_pixrect, PIXPG_INVALID,
					pgroups);

    /* For FBs with dedicated cursor planes */
    if ((pgroups[PIXPG_CURSOR]) && (pgroups[PIXPG_CURSOR_ENABLE])) {

	shared = &dtop->shared_info->cursor_info;
	 shared->spare3 = TRUE;
	dc = &dtop->dt_cursor;
	pr = dtop->dt_pixrect;
	original_plane_group = pr_get_plane_group(pr);
	if (cursor_up(dtop) || 	horiz_hair_up(dtop) || vert_hair_up(dtop)) {
	    /* Set up plane group to be cursor image plane */
	    if (cursor_up(dtop)) {
		pr_set_planes(pr, PIXPG_CURSOR, full_planes);
		/* take down existing cursor by clearing the bits in *
		* image  planes */
		win_lock_prepare_screen_pr(shared);
		cursor_set_up(dtop, FALSE);
		if (pr_rop(pr, shared->x, shared->y,
		    shared->screen_pr.pr_width, shared->screen_pr.pr_height,
			PIX_CLR, NULL, 0, 0))
		    ROPERR(1)
		/* Now do the enable plane */
		pr_set_planes(pr, PIXPG_CURSOR_ENABLE,full_planes);
		if (pr_rop(pr, shared->x-1, shared->y-1,
		    shared->screen_pr.pr_width+2, 
		    shared->screen_pr.pr_height+2,
		    PIX_CLR, NULL, 0, 0))
		    ROPERR(2)
	    }
	    /* Now take the cross hairs down*/
	    if (horiz_hair_up(dtop)) {
		horiz_hair_set_up(dtop, FALSE);
	    	pr_set_planes(pr, PIXPG_CURSOR, full_planes);
		if (dtop_rl_rop(pr, 0, 0,
				&dc->horiz_hair_rectlist,
				PIX_CLR, (Pixrect *) 0,
				0, 0))
		    ROPERR(3)
		pr_set_planes(pr, PIXPG_CURSOR_ENABLE, full_planes);
		if (dtop_rl_rop_enable(pr, 0, 0,
				&dc->horiz_hair_rectlist,
				PIX_CLR, (Pixrect *)0,
				0, 0))
		    ROPERR(4)
		rl_free(&dc->horiz_hair_rectlist);
	    }
	    if (vert_hair_up(dtop)) {
		vert_hair_set_up(dtop, FALSE);
		pr_set_planes(pr, PIXPG_CURSOR, full_planes);
		if (dtop_rl_rop(pr, 0, 0,
				&dc->vert_hair_rectlist,
				PIX_CLR, (Pixrect *)0,
				0, 0))
		    ROPERR(5)
		pr_set_planes(pr, PIXPG_CURSOR_ENABLE, full_planes);
		if (dtop_rl_rop_enable(pr, 0, 0,
				&dc->vert_hair_rectlist,
				PIX_CLR, (Pixrect *)0,
				0, 0))
		    ROPERR(6)
		rl_free(&dc->vert_hair_rectlist);
	    }
	    goto Cursor_Done;
	}
	if (dtop->dt_cursorwin && !(dtop->dt_cursorwin->w_flags & WF_OPEN)) {
		dtop->dt_cursorwin = WINDOW_NULL;
		goto Cursor_Done;
	}
	/* Putup  the new cursor */
	cursorwin = dtop->dt_cursorwin;
	if (!cursorwin || !(ws = dtop->dt_ws) || (ws->ws_loc_dtop != dtop))
	    goto Cursor_Done;

	/* we are dealing with the latest cursor */
	dtop->shared_info->status.new_cursor = FALSE;
	cursor = &cursorwin->w_cursor;
	data = &cursorwin->w_cursordata;
	shape = cursor->cur_shape;
	want_cursor = shape->pr_width && shape->pr_height &&
			shape->pr_depth && data->md_image &&
			show_cursor(cursor);

	if (!(want_cursor || show_horiz_hair(cursor) 
					|| show_vert_hair(cursor)))
	    goto Cursor_Done;

	/*
	* Figure out where on screen to draw cursor.
	*/
	shared->x = dtop->dt_rt_x - cursor->cur_xhot;
	shared->y = dtop->dt_rt_y - cursor->cur_yhot;
	shared->screen_pr.pr_height = shape->pr_height;
	shared->screen_pr.pr_width = shape->pr_width;
	shared->spare3 = TRUE;		

	 win_lock_prepare_screen_pr(shared);
	/* The rectlist of the cross hairs has to be
	 * generated. So we will do the same as before 
	 * to save the image below cross hairs.

        if (show_horiz_hair(cursor) || show_vert_hair(cursor)) {
	/* prepare cross hair storage */
	/* get the horizontal & vertical info from the input window */
    	
	pr_set_planes(pr, PIXPG_CURSOR,full_planes);
	dc->horiz_hair_mpr.pr_depth = 1;
	dc->horiz_hair_mpr.pr_height = cursor->horiz_hair_thickness;
	(void) dtop_set_linebytes(&dc->horiz_hair_mpr);

	dc->vert_hair_mpr.pr_depth = 1;
	dc->vert_hair_mpr.pr_width = cursor->vert_hair_thickness;
	(void) dtop_set_linebytes(&dc->vert_hair_mpr);

	dc->hair_x = dtop->dt_rt_x - (dc->vert_hair_mpr.pr_width / 2);
	dc->hair_y = dtop->dt_rt_y - (dc->horiz_hair_mpr.pr_height / 2);

	if (show_horiz_hair(cursor)) {
	    /* construct the horizontal hair window/fullscreen rect */
	    rect_construct(&hair_rect, 0,
				fullscreen(cursor) ? dc->hair_y :
				dc->hair_y - cursorwin->w_screeny,
				dc->horiz_hair_mpr.pr_width,
				dc->horiz_hair_mpr.pr_height);

	    /*
	     * determine the intersection with the exposed area of
	     *  the window.
	     */
	    dc->horiz_hair_rectlist = rl_null;
	    if (fullscreen(cursor))
		rl_initwithrect(&hair_rect, &dc->horiz_hair_rectlist);
	    else {
		rl_rectintersection(&hair_rect, &cursorwin->w_rlexposed,
				    &dc->horiz_hair_rectlist);
		/* convert to screen coordinates */
		dc->horiz_hair_rectlist.rl_x = cursorwin->w_screenx;
		dc->horiz_hair_rectlist.rl_y = cursorwin->w_screeny;
		rl_normalize(&dc->horiz_hair_rectlist);
		/* convert hair_rect top to screen coordinates */
		hair_rect.r_top = dc->hair_y;
	    }

	    /* if length is not full, cut out excess */
	    if (cursor->horiz_hair_length != CURSOR_TO_EDGE) {
		int	max_length;
		int	x_left;

		if (horiz_border_gravity(cursor)) {
		    max_length = fullscreen(cursor)?
			dc->horiz_hair_mpr.pr_width : cursorwin->w_rect.r_width;
		    x_left = fullscreen(cursor) ? cursor->horiz_hair_length :
			cursorwin->w_screenx + cursor->horiz_hair_length;

		    hair_rect.r_left = x_left;
		    hair_rect.r_width = max_length-2*cursor->horiz_hair_length;
		    rl_rectdifference(&hair_rect, &dc->horiz_hair_rectlist,
					&dc->horiz_hair_rectlist);
		} else {
		    /* length is from center */
		    x_left = fullscreen(cursor) ? 0 : cursorwin->w_screenx;

		    hair_rect.r_left = x_left;
		    hair_rect.r_width =
			dc->hair_x - cursor->horiz_hair_length - x_left;
		    rl_rectdifference(&hair_rect, &dc->horiz_hair_rectlist,
					&dc->horiz_hair_rectlist);

		    hair_rect.r_left = dc->hair_x + cursor->horiz_hair_length;
		    hair_rect.r_width = dc->horiz_hair_mpr.pr_width;
		    rl_rectdifference(&hair_rect, &dc->horiz_hair_rectlist,
					&dc->horiz_hair_rectlist);
		}
	    }

	    if (cursor->horiz_hair_gap) {
		/* cut out a gap the width of the cursor or as specified */
		if (cursor->horiz_hair_gap == CURSOR_TO_EDGE) {
		    hair_rect.r_width = shape->pr_width;
		    hair_rect.r_left = shared->x;
		} else {
		    hair_rect.r_width = cursor->horiz_hair_gap;
		    hair_rect.r_left = dc->hair_x - hair_rect.r_width / 2;
		}
		rl_rectdifference(&hair_rect, &dc->horiz_hair_rectlist,
					&dc->horiz_hair_rectlist);
	    }
	}
	if (show_vert_hair(cursor)) {
	   /* construct the vertical hair window/fullscreen rect */
	    rect_construct(&hair_rect,
		fullscreen(cursor) ? dc->hair_x :
			dc->hair_x - cursorwin->w_screenx,
			0,
			dc->vert_hair_mpr.pr_width,
			dc->vert_hair_mpr.pr_height);

	    /*
	     * determine the intersection with the exposed area of
	     *  the window.
	     */
	    dc->vert_hair_rectlist = rl_null;
	    if (fullscreen(cursor))
		rl_initwithrect(&hair_rect, &dc->vert_hair_rectlist);
	    else {
		rl_rectintersection(&hair_rect, &cursorwin->w_rlexposed,
				    &dc->vert_hair_rectlist);
		/* convert to screen coordinates */
		dc->vert_hair_rectlist.rl_x = cursorwin->w_screenx;
		dc->vert_hair_rectlist.rl_y = cursorwin->w_screeny;
		rl_normalize(&dc->vert_hair_rectlist);
		/* convert hair_rect left to screen coordinates */
		hair_rect.r_left = dc->hair_x;
	    }

	    /* if length is not full, cut out excess */
	    if (cursor->vert_hair_length != CURSOR_TO_EDGE) {
		int	max_length;
		int	y_top;

		if (vert_border_gravity(cursor)) {
		    max_length = fullscreen(cursor)?
			dc->vert_hair_mpr.pr_height:cursorwin->w_rect.r_height;
		    y_top = fullscreen(cursor) ? cursor->vert_hair_length :
			cursorwin->w_screeny + cursor->vert_hair_length;

		    hair_rect.r_top = y_top;
		    hair_rect.r_height = max_length-2*cursor->vert_hair_length;
		    rl_rectdifference(&hair_rect, &dc->vert_hair_rectlist,
					&dc->vert_hair_rectlist);
		} else {
		    /* length is from center */
		    y_top = fullscreen(cursor) ? 0 : cursorwin->w_screeny;

		    hair_rect.r_top = y_top;
		    hair_rect.r_height =
			dc->hair_y - cursor->vert_hair_length - y_top;
		    rl_rectdifference(&hair_rect, &dc->vert_hair_rectlist,
					&dc->vert_hair_rectlist);

		    hair_rect.r_top = dc->hair_y + cursor->vert_hair_length;
		    hair_rect.r_height = dc->vert_hair_mpr.pr_height;
		    rl_rectdifference(&hair_rect, &dc->vert_hair_rectlist,
					&dc->vert_hair_rectlist);
		}
	    }

	    if (cursor->vert_hair_gap) {
		/* cut out a gap the height of the cursor or as specified */
		if (cursor->vert_hair_gap == CURSOR_TO_EDGE) {
		    hair_rect.r_height = shape->pr_height;
		    hair_rect.r_top = shared->y;
		} else {
		    hair_rect.r_height = cursor->vert_hair_gap;
		    hair_rect.r_top = dc->hair_y - hair_rect.r_height / 2;
		}
		rl_rectdifference(&hair_rect, &dc->vert_hair_rectlist,
				&dc->vert_hair_rectlist);
	    }
	}
	/*
	 * Need to add something here to change colormap of 
         * of cursor plane so that cursor has correct colors
         */
	/* Write to display */

	if (want_cursor) {
	    /* write the cursor */
	    if (show_cursor(cursor)) {
		cursor_set_up(dtop, TRUE);

		pr_set_planes(pr, PIXPG_CURSOR, full_planes);
		if (pr_rop(pr, shared->x, shared->y,
		    shared->screen_pr.pr_width, shared->screen_pr.pr_height,
		    PIX_SRC, shape, 0, 0))
		ROPERR(10)
	    	pr_set_planes(pr, PIXPG_CURSOR_ENABLE, full_planes);
		if (pr_rop(pr, shared->x, shared->y, 
		    shared->screen_pr.pr_width, shared->screen_pr.pr_height,
		    PIX_SRC, (Pixrect *)shape, 0, 0))
		    ROPERR(11)

		/* smear */
		if (pr_rop(pr, shared->x-1, shared->y-1, 
		    shared->screen_pr.pr_width, 
		    shared->screen_pr.pr_height,
		    PIX_SRC|PIX_DST, shape, 0, 0))
		    ROPERR(11)	/*U-L*/
		if (pr_rop(pr, shared->x, shared->y-1, 
		    shared->screen_pr.pr_width, 
		    shared->screen_pr.pr_height,
		    PIX_SRC|PIX_DST, shape, 0, 0))
		    ROPERR(11) /*U */
		if (pr_rop(pr, shared->x+1, shared->y-1, 
		    shared->screen_pr.pr_width, 
		    shared->screen_pr.pr_height,
		    PIX_SRC|PIX_DST, shape, 0, 0))
		    ROPERR(11)/*U-R */
		if (pr_rop(pr, shared->x+1, shared->y, 
		    shared->screen_pr.pr_width, 
		    shared->screen_pr.pr_height,
		    PIX_SRC|PIX_DST, shape, 0, 0))
		    ROPERR(11) /* R */
		if (pr_rop(pr, shared->x+1, shared->y+1, 
		    shared->screen_pr.pr_width, 
		    shared->screen_pr.pr_height,
		    PIX_SRC|PIX_DST, shape, 0, 0))
		    ROPERR(11) /*L - R */
		if (pr_rop(pr, shared->x, shared->y+1, 
		    shared->screen_pr.pr_width, 
		    shared->screen_pr.pr_height,
		    PIX_SRC|PIX_DST, shape, 0, 0))
		    ROPERR(11) /*L */
		if (pr_rop(pr, shared->x-1, shared->y+1, 
		    shared->screen_pr.pr_width, 
		    shared->screen_pr.pr_height,
		    PIX_SRC|PIX_DST, shape, 0, 0))
		    ROPERR(11) /*L-L */
		if (pr_rop(pr, shared->x-1, shared->y, 
		    shared->screen_pr.pr_width,
		     shared->screen_pr.pr_height,
		    PIX_SRC|PIX_DST, shape, 0, 0))
		    ROPERR(11) /* L */
	    }	 
	}
	if (show_horiz_hair(cursor) && !rl_empty(&dc->horiz_hair_rectlist)) {
	    horiz_hair_set_up(dtop, TRUE);
	    pr_set_planes(pr, PIXPG_CURSOR, full_planes);
	    if (dtop_rl_rop(pr, 0, 0, &dc->horiz_hair_rectlist,
	            PIX_SET , (struct pixrect *)0, 0, 0))
		ROPERR(9)
	    pr_set_planes(pr, PIXPG_CURSOR_ENABLE, full_planes);
	    if (dtop_rl_rop_enable(pr, 0, 0, &dc->horiz_hair_rectlist,
		    PIX_SET, (struct pixrect *)0, 0, 0))
	    ROPERR(10)
	}
	/* write the vertical cross hair */
	if (show_vert_hair(cursor) && !rl_empty(&dc->vert_hair_rectlist)) {
	    vert_hair_set_up(dtop, TRUE);
	    pr_set_planes(pr, PIXPG_CURSOR, full_planes);
	    if (dtop_rl_rop(pr, 0, 0, &dc->vert_hair_rectlist,
	            PIX_SET, (struct pixrect *)0, 0, 0))
		ROPERR(11)
	    pr_set_planes(pr, PIXPG_CURSOR_ENABLE, full_planes);
	    if (dtop_rl_rop_enable(pr, 0, 0, &dc->vert_hair_rectlist,
		    PIX_SET, (struct pixrect *)0, 0, 0))
		ROPERR(12)
	}

Cursor_Done:
    pr_set_planes(pr, original_plane_group, full_planes);
    return;
    }

    /*
     *  A Hack of Sorts ...
     *  we don't need to mess with the double registers on the
     *  Crane (or other 24 bit fb's, as the kernel can't access
     *  them, and therefore can't draw a cursor in them.  This
     *  means that we don't need a sync in pr_dbl_set associated
     *  with cursor drawing, which is a big performance plus.
     *
     *  So, don't mess with the double register if we've got
     *  24 bit color.
     *
     * (Dwight Wilcox - 10 May 89)
     */

    /* Save the read/write control states */
    /* Set read/write control bits to read/write from the foreground */
    if (dtop->dt_dblcount &&
	!(dtop->dt_plane_groups_available[PIXPG_24BIT_COLOR])) {
	readstate = pr_dbl_get(dtop->dt_pixrect, PR_DBL_READ);
	writestate = pr_dbl_get(dtop->dt_pixrect, PR_DBL_WRITE);
	if (pr_dbl_set(dtop->dt_pixrect, PR_DBL_WRITE, dtop->dt_dbl_frgnd,
			PR_DBL_READ, dtop->dt_dbl_frgnd, 0))
#ifdef WINDEVDEBUG
		printf("Error dbl_set draw cursor\n");
#else
		;
#endif
    }

    /*
     * Keep 24-bit cursors and fullscreen cursors (such as wmgr move/strech,
     * menu cursors, confirm cursors, or fullscreen crosshairs) in the overlay.
     * Fullscreen crosshairs (in general but especially on a multiple plane
     * group framebuffers) are very suspect.
     */

    if (dtop->dt_plane_groups_available[PIXPG_OVERLAY] &&
	(dtop->shared_info->mouse_plane_group == PIXPG_24BIT_COLOR ||
	(dtop->dt_cursorwin && fullscreen(&dtop->dt_cursorwin->w_cursor))))
    {
	dtop->dt_cursor.enable_color = 1;
	dtop->shared_info->mouse_plane_group = PIXPG_OVERLAY;
    }

    shared = &dtop->shared_info->cursor_info;
    dc = &dtop->dt_cursor;
    pr = dtop->dt_pixrect;
    original_plane_group = pr_get_plane_group(pr);

    if (cursor_up(dtop) ||
	enable_plane_cursor_up(dtop) || videnb_plane_cursor_up(dtop) ||
	horiz_hair_up(dtop) || vert_hair_up(dtop)) {

	/* Set up plane group to be the one that holds the screen image */
	pr_set_planes(pr, shared->plane_group, full_planes);

	/*
	 * Take existing cursor down by putting old screen image there
	 */
	if (cursor_up(dtop)) {
	    /* prepare the screen pixrect for use */
	    win_lock_prepare_screen_pr(shared);
	    cursor_set_up(dtop, FALSE);
	    /* rop up the saved bits */
	    if (pr_rop(pr, shared->x, shared->y,
			shared->screen_pr.pr_width, shared->screen_pr.pr_height,
			PIX_SRC, &shared->screen_pr, 0, 0))
		ROPERR(1)
	}
	/* replace bits in enable plane */
	if (enable_plane_cursor_up(dtop)) {
	    enable_plane_cursor_set_up(dtop, FALSE);
	    pr_set_planes(pr, PIXPG_OVERLAY_ENABLE, full_planes);
	    if (pr_rop(pr, shared->x, shared->y,
		dc->enable_mpr.pr_width, dc->enable_mpr.pr_height,
		PIX_SRC, &dc->enable_mpr, 0, 0))
		ROPERR(2)
	    pr_set_planes(pr, original_plane_group, full_planes);
	}

	/* replace bits in video enable plane */
	if (videnb_plane_cursor_up(dtop)) {
	    videnb_plane_cursor_set_up(dtop, FALSE);
	    pr_set_planes(pr, PIXPG_VIDEO_ENABLE, full_planes);
	    if (pr_rop(pr, shared->x, shared->y,
		dc->videnb_mpr.pr_width, dc->videnb_mpr.pr_height,
		PIX_SRC, &dc->videnb_mpr, 0, 0))
		ROPERR(2)
	    pr_set_planes(pr, original_plane_group, full_planes);
	}

	/* replace image under cross hairs */
	if (horiz_hair_up(dtop)) {
	    horiz_hair_set_up(dtop, FALSE);
	    if (dtop_rl_rop(pr, 0, 0,
				&dc->horiz_hair_rectlist,
				PIX_SRC, &dc->horiz_hair_mpr,
				0, dc->hair_y))
		ROPERR(3)
	    rl_free(&dc->horiz_hair_rectlist);
	}

	if (vert_hair_up(dtop)) {
	    vert_hair_set_up(dtop, FALSE);
	    if (dtop_rl_rop(pr, 0, 0,
				&dc->vert_hair_rectlist,
				PIX_SRC, &dc->vert_hair_mpr,
				dc->hair_x, 0))
		ROPERR(4)
	    rl_free(&dc->vert_hair_rectlist);
	}

	goto Done;
    }

    shared = &dtop->shared_info->cursor_info;

    if (shared->hardware_cursor) {	/* SEVANS */
	/*
	 * Mark cursor as inactive if in hardware now that we have the software
	 * cursor off the screen.  This is for client program's locking code
	 * sake.
	 */
	shared->cursor_active = 0;
	/*
	 * For hardware cursors, should have the latest image by now.
	 * Update new_cursor here so that we don't keep tripping through this
	 * code (when cursorwin == NULL) until something interesting changes.
	 * Didn't clear new_cursor before in case software cursor needed to
	 * be removed.
	 */
        dtop->shared_info->status.new_cursor = FALSE;
    }

    /*
     * Setting of shared->plane_group was moved up from just above the next
     * pr_set_planes call so that is would always be set, even in the case of
     * using a hardware cursor, so that client locking would not be forced into
     * the kernel (see libsunwindow/pw/pw_shared.c).
     */
    shared->plane_group = dtop->shared_info->mouse_plane_group;	/* SEVANS */

    /*
     * if dtop_cursorwin is not open then zero out and return;
     * this shouldn't really be necessary since the cursor window
     * should be zeroed out when the window is closed
     */

    if (dtop->dt_cursorwin && !(dtop->dt_cursorwin->w_flags & WF_OPEN)) {
		dtop->dt_cursorwin = WINDOW_NULL;
		goto Done;
    }

    /*
     * Put up new cursor by saving old screen image then writing
     * new cursor.
     */
    cursorwin = dtop->dt_cursorwin;
    if (!cursorwin || !(ws = dtop->dt_ws) || (ws->ws_loc_dtop != dtop))
	goto Done;

    /*
     * We are dealing with the latest cursor.
     * Doesn't hurt to mark this again if hardware cursor.
     */
    dtop->shared_info->status.new_cursor = FALSE;

    cursor = &cursorwin->w_cursor;
    data = &cursorwin->w_cursordata;
    shape = cursor->cur_shape;

    want_cursor = shape->pr_width && shape->pr_height &&
			shape->pr_depth && data->md_image &&
			show_cursor(cursor) && !shared->hardware_cursor;

    if (!(want_cursor || show_horiz_hair(cursor) || show_vert_hair(cursor)))
	goto Done;

    /*
     * Figure out where on screen to draw cursor.
     */
    shared->x = dtop->dt_rt_x - cursor->cur_xhot;
    shared->y = dtop->dt_rt_y - cursor->cur_yhot;

    /* Set plane group of plane group to write into */
    pr_set_planes(pr, shared->plane_group, full_planes);

    if (want_cursor) {
	if (show_cursor(cursor)) {
	    /*
	     * Prepare pixrect in which will store screen image.
	     */
	    win_lock_prepare_screen_pr(shared);

	    scrmpr_data = (struct mpr_data *)(shared->screen_pr.pr_data);
	    shared->screen_pr = *shape;
	    shared->screen_pr.pr_depth = pr->pr_depth;
	    shared->screen_pr.pr_data = (caddr_t) scrmpr_data;
	    *scrmpr_data = *data;
	    scrmpr_data->md_image = shared->screen_image;
	    (void) dtop_set_linebytes(&shared->screen_pr);

	    cursor_offset_x = shared->x;
	    cursor_offset_y = shared->y;

	    if (dtop->dt_plane_groups_available[PIXPG_24BIT_COLOR] &&
		shared->plane_group == PIXPG_8BIT_COLOR)
	    {
		struct rect         cursor_rect;
		struct rectlist     cursor_rect_list;

		rect_construct(&cursor_rect,
		    shared->x - cursorwin->w_screenx,
		    shared->y - cursorwin->w_screeny,
		    shared->screen_pr.pr_width, shared->screen_pr.pr_height);
		cursor_rect_list = rl_null;
		rl_rectintersection(&cursor_rect, &cursorwin->w_rlexposed,
		    &cursor_rect_list);

		shared->x=cursorwin->w_screenx+cursor_rect_list.rl_bound.r_left;
		shared->y=cursorwin->w_screeny+cursor_rect_list.rl_bound.r_top;
		shared->screen_pr.pr_width = cursor_rect_list.rl_bound.r_width;
		shared->screen_pr.pr_height=cursor_rect_list.rl_bound.r_height;
		rl_free(&cursor_rect_list);
	    }

	    cursor_offset_x = shared->x - cursor_offset_x;
	    cursor_offset_y = shared->y - cursor_offset_y;

	    /* Copy from display to memory */
	    if (pr_rop(&shared->screen_pr, 0, 0,
			shared->screen_pr.pr_width, shared->screen_pr.pr_height,
			PIX_SRC, pr, shared->x, shared->y))
		ROPERR(5)
	}
	if (show_enable_plane_cursor(dtop)) {
	    /* Prepare pixrect in which will store enable plane image */
	    dc->enable_mpr.pr_width = shape->pr_width;
	    dc->enable_mpr.pr_height = shape->pr_height;
	    (void) dtop_set_linebytes(&dc->enable_mpr);
	    /* Copy from display to memory */
	    pr_set_planes(pr, PIXPG_OVERLAY_ENABLE, full_planes);
	    if (pr_rop(&dc->enable_mpr, 0, 0, shape->pr_width, shape->pr_height,
			PIX_SRC, pr, shared->x, shared->y))
		ROPERR(6)
	    pr_set_planes(pr, shared->plane_group, full_planes);
	}

	if (show_videnb_plane_cursor(dtop)) {
	    /* Prepare pixrect in which will store video enable plane image */
	    dc->videnb_mpr.pr_width = shape->pr_width;
	    dc->videnb_mpr.pr_height = shape->pr_height;
	    ((struct mpr_data *)dc->videnb_mpr.pr_data)->md_linebytes =
		mpr_linebytes(dc->videnb_mpr.pr_width, 1);
	    /* Copy from display to memory */
	    pr_set_planes(pr, PIXPG_VIDEO_ENABLE, full_planes);
	    if (pr_rop(&dc->videnb_mpr, 0, 0, shape->pr_width, shape->pr_height,
		PIX_SRC, pr, shared->x, shared->y))
		ROPERR(601)
	    pr_set_planes(pr, shared->plane_group, full_planes);
	}
    }

    if (show_horiz_hair(cursor) || show_vert_hair(cursor)) {
	/* prepare cross hair storage */
	/* get the horizontal & vertical info from the input window */

	dc->horiz_hair_mpr.pr_depth = pr->pr_depth;
	dc->horiz_hair_mpr.pr_height = cursor->horiz_hair_thickness;
	(void) dtop_set_linebytes(&dc->horiz_hair_mpr);

	dc->vert_hair_mpr.pr_depth = pr->pr_depth;
	dc->vert_hair_mpr.pr_width = cursor->vert_hair_thickness;
	(void) dtop_set_linebytes(&dc->vert_hair_mpr);

	dc->hair_x = dtop->dt_rt_x - (dc->vert_hair_mpr.pr_width / 2);
	dc->hair_y = dtop->dt_rt_y - (dc->horiz_hair_mpr.pr_height / 2);

	if (show_horiz_hair(cursor)) {
	    /* construct the horizontal hair window/fullscreen rect */
	    rect_construct(&hair_rect, 0,
				fullscreen(cursor) ? dc->hair_y :
				dc->hair_y - cursorwin->w_screeny,
				dc->horiz_hair_mpr.pr_width,
				dc->horiz_hair_mpr.pr_height);

	    /*
	     * determine the intersection with the exposed area of
	     *  the window.
	     */
	    dc->horiz_hair_rectlist = rl_null;
	    if (fullscreen(cursor))
		rl_initwithrect(&hair_rect, &dc->horiz_hair_rectlist);
	    else {
		rl_rectintersection(&hair_rect, &cursorwin->w_rlexposed,
				    &dc->horiz_hair_rectlist);
		/* convert to screen coordinates */
		dc->horiz_hair_rectlist.rl_x = cursorwin->w_screenx;
		dc->horiz_hair_rectlist.rl_y = cursorwin->w_screeny;
		rl_normalize(&dc->horiz_hair_rectlist);
		/* convert hair_rect top to screen coordinates */
		hair_rect.r_top = dc->hair_y;
	    }

	    /* if length is not full, cut out excess */
	    if (cursor->horiz_hair_length != CURSOR_TO_EDGE) {
		int	max_length;
		int	x_left;

		if (horiz_border_gravity(cursor)) {
		    max_length = fullscreen(cursor)?
			dc->horiz_hair_mpr.pr_width : cursorwin->w_rect.r_width;
		    x_left = fullscreen(cursor) ? cursor->horiz_hair_length :
			cursorwin->w_screenx + cursor->horiz_hair_length;

		    hair_rect.r_left = x_left;
		    hair_rect.r_width = max_length-2*cursor->horiz_hair_length;
		    rl_rectdifference(&hair_rect, &dc->horiz_hair_rectlist,
					&dc->horiz_hair_rectlist);
		} else {
		    /* length is from center */
		    x_left = fullscreen(cursor) ? 0 : cursorwin->w_screenx;

		    hair_rect.r_left = x_left;
		    hair_rect.r_width =
			dc->hair_x - cursor->horiz_hair_length - x_left;
		    rl_rectdifference(&hair_rect, &dc->horiz_hair_rectlist,
					&dc->horiz_hair_rectlist);

		    hair_rect.r_left = dc->hair_x + cursor->horiz_hair_length;
		    hair_rect.r_width = dc->horiz_hair_mpr.pr_width;
		    rl_rectdifference(&hair_rect, &dc->horiz_hair_rectlist,
					&dc->horiz_hair_rectlist);
		}
	    }

	    if (cursor->horiz_hair_gap) {
		/* cut out a gap the width of the cursor or as specified */
		if (cursor->horiz_hair_gap == CURSOR_TO_EDGE) {
		    hair_rect.r_width = shape->pr_width;
		    hair_rect.r_left = shared->x;
		} else {
		    hair_rect.r_width = cursor->horiz_hair_gap;
		    hair_rect.r_left = dc->hair_x - hair_rect.r_width / 2;
		}
		rl_rectdifference(&hair_rect, &dc->horiz_hair_rectlist,
					&dc->horiz_hair_rectlist);
	    }

	    /* copy the image under the exposed area of the cross hair */
	    if (!rl_empty(&dc->horiz_hair_rectlist)) {
		if (dtop_rl_rop(&dc->horiz_hair_mpr, 0, dc->hair_y,
				&dc->horiz_hair_rectlist,
				PIX_SRC, pr, 0, 0))
		    ROPERR(7)
		}
	}

	if (show_vert_hair(cursor)) {
	    /* construct the vertical hair window/fullscreen rect */
	    rect_construct(&hair_rect,
		fullscreen(cursor) ? dc->hair_x :
			dc->hair_x - cursorwin->w_screenx,
			0,
			dc->vert_hair_mpr.pr_width,
			dc->vert_hair_mpr.pr_height);

	    /*
	     * determine the intersection with the exposed area of
	     *  the window.
	     */
	    dc->vert_hair_rectlist = rl_null;
	    if (fullscreen(cursor))
		rl_initwithrect(&hair_rect, &dc->vert_hair_rectlist);
	    else {
		rl_rectintersection(&hair_rect, &cursorwin->w_rlexposed,
				    &dc->vert_hair_rectlist);
		/* convert to screen coordinates */
		dc->vert_hair_rectlist.rl_x = cursorwin->w_screenx;
		dc->vert_hair_rectlist.rl_y = cursorwin->w_screeny;
		rl_normalize(&dc->vert_hair_rectlist);
		/* convert hair_rect left to screen coordinates */
		hair_rect.r_left = dc->hair_x;
	    }

	    /* if length is not full, cut out excess */
	    if (cursor->vert_hair_length != CURSOR_TO_EDGE) {
		int	max_length;
		int	y_top;

		if (vert_border_gravity(cursor)) {
		    max_length = fullscreen(cursor)?
			dc->vert_hair_mpr.pr_height:cursorwin->w_rect.r_height;
		    y_top = fullscreen(cursor) ? cursor->vert_hair_length :
			cursorwin->w_screeny + cursor->vert_hair_length;

		    hair_rect.r_top = y_top;
		    hair_rect.r_height = max_length-2*cursor->vert_hair_length;
		    rl_rectdifference(&hair_rect, &dc->vert_hair_rectlist,
					&dc->vert_hair_rectlist);
		} else {
		    /* length is from center */
		    y_top = fullscreen(cursor) ? 0 : cursorwin->w_screeny;

		    hair_rect.r_top = y_top;
		    hair_rect.r_height =
			dc->hair_y - cursor->vert_hair_length - y_top;
		    rl_rectdifference(&hair_rect, &dc->vert_hair_rectlist,
					&dc->vert_hair_rectlist);

		    hair_rect.r_top = dc->hair_y + cursor->vert_hair_length;
		    hair_rect.r_height = dc->vert_hair_mpr.pr_height;
		    rl_rectdifference(&hair_rect, &dc->vert_hair_rectlist,
					&dc->vert_hair_rectlist);
		}
	    }

	    if (cursor->vert_hair_gap) {
		/* cut out a gap the height of the cursor or as specified */
		if (cursor->vert_hair_gap == CURSOR_TO_EDGE) {
		    hair_rect.r_height = shape->pr_height;
		    hair_rect.r_top = shared->y;
		} else {
		    hair_rect.r_height = cursor->vert_hair_gap;
		    hair_rect.r_top = dc->hair_y - hair_rect.r_height / 2;
		}
		rl_rectdifference(&hair_rect, &dc->vert_hair_rectlist,
				&dc->vert_hair_rectlist);
	    }

	    /* copy the image under the exposed area of the cross hair */
	    if (!rl_empty(&dc->vert_hair_rectlist)) {
		if (dtop_rl_rop(&dc->vert_hair_mpr, dc->hair_x, 0,
				&dc->vert_hair_rectlist,
				PIX_SRC, pr, 0, 0))
		    ROPERR(8)
	    }
	}
    }

    /*
     * Set planes such that will write to foreground and background
     * of current colormap segment.
     */
    planes = cursorwin->w_cms.cms_size - 1;
    if( (planes & cursorwin->w_cms.cms_size) != 0 )
    {
      /* colormap wasn't a power of 2 in length,
	 compute planes a different way */
      register int i = planes ;
      planes = 1 ;
      while( i != 0 )
      {  
	planes <<= 1 ;
	i >>= 1 ;
      }  
      --planes ;
    }
#define	planes_fully_implemented
#ifdef	planes_fully_implemented
    pr_putattributes(pr, &planes);
#else
    pr_set_planes(pr, shared->plane_group, planes);
#endif	planes_fully_implemented

    /*
     * Write to display
     */
    /* write the horizontal cross hair */
    if (show_horiz_hair(cursor) && !rl_empty(&dc->horiz_hair_rectlist)) {
	horiz_hair_set_up(dtop, TRUE);
	if (dtop_rl_rop(pr, 0, 0, &dc->horiz_hair_rectlist,
		    cursor->horiz_hair_op | PIX_COLOR(cursor->horiz_hair_color),
		    (struct pixrect *)0, 0, 0))
	    ROPERR(9)
    }

    /* write the vertical cross hair */
    if (show_vert_hair(cursor) && !rl_empty(&dc->vert_hair_rectlist)) {
	vert_hair_set_up(dtop, TRUE);
	if (dtop_rl_rop(pr, 0, 0, &dc->vert_hair_rectlist,
		    cursor->vert_hair_op | PIX_COLOR(cursor->vert_hair_color),
		    (struct pixrect *)0, 0, 0))
	    ROPERR(10)
    }

    if (want_cursor) {
	int op;

	/* write the cursor */
	if (show_cursor(cursor)) {
	    cursor_set_up(dtop, TRUE);
	    if (pr_rop(pr, shared->x, shared->y,
			shared->screen_pr.pr_width, shared->screen_pr.pr_height,
			cursor->cur_function, shape,
			cursor_offset_x, cursor_offset_y))
		ROPERR(11)
	}
	/* write the enable plane cursor */
	if (show_enable_plane_cursor(dtop)) {
	    op = (dc->enable_color)? PIX_SRC | PIX_DST:
		PIX_NOT(PIX_SRC) & PIX_DST;
	    enable_plane_cursor_set_up(dtop, TRUE);
	    pr_set_planes(pr, PIXPG_OVERLAY_ENABLE, full_planes);
	    if (pr_rop(pr, shared->x, shared->y, dc->enable_mpr.pr_width,
			dc->enable_mpr.pr_height, op, shape, 0, 0))
		    ROPERR(12)
	    pr_set_planes(pr, original_plane_group, full_planes);
	}

	/* write the video enable plane cursor */
	if (show_videnb_plane_cursor(dtop)) {
	    op = PIX_NOT(PIX_SRC) & PIX_DST;
	    videnb_plane_cursor_set_up(dtop, TRUE);
	    pr_set_planes(pr, PIXPG_VIDEO_ENABLE, full_planes);
	    if (pr_rop(pr, shared->x, shared->y, dc->videnb_mpr.pr_width,
			dc->videnb_mpr.pr_height, op, shape, 0, 0))
		    ROPERR(12)
	    pr_set_planes(pr, shared->plane_group, full_planes);
	}
    }

Done:
    if (dtop->dt_dblcount &&
	!(dtop->dt_plane_groups_available[PIXPG_24BIT_COLOR])) {
	if (pr_dbl_set(dtop->dt_pixrect, PR_DBL_READ, readstate, PR_DBL_WRITE,
	    writestate, 0))
#ifdef WINDEVDEBUG
		printf("Error in drawcursor: pr_dbl_set\n");
#else
		;
#endif
    }
    pr_set_planes(pr, original_plane_group, full_planes);
    return;

Roperr:
    pr_set_planes(pr, original_plane_group, full_planes);
#ifdef WINDEVDEBUG
    printf("Kernel cursor Roperr %D\n", rop_err_id);
#endif
#ifdef lint
    printf("Kernel cursor Roperr %D\n", rop_err_id);
#endif
}

/* rl should be normalized and in screen coordinates */
dtop_rl_rop(dest_pixrect, dest_dx, dest_dy, rl, op, src_pixrect,
	    src_dx, src_dy)
	struct pixrect	*dest_pixrect;
	int		dest_dx, dest_dy;
	struct rectlist	*rl;
	int		op;
	struct pixrect	*src_pixrect;
	int		src_dx, src_dy;
/*
 * dtop_rl_rop does a pr_rop from src_pixrect to dst_pixrect for each
 * area described in rl.
 */
{
    register struct rectnode	*rectnode;
    register struct rect	*r;

    for (rectnode = rl->rl_head; rectnode;
	rectnode = rectnode->rn_next) {
	r = &rectnode->rn_rect;
	if (pr_rop(dest_pixrect, r->r_left - dest_dx, r->r_top - dest_dy,
			r->r_width, r->r_height, op, src_pixrect,
			r->r_left - src_dx, r->r_top - src_dy))
		return (1);
    }
    return (0);
} /* dtop_rl_rop*/

/*  This "smears" the enable plane a pixel in each each dir 
    Used only if cursor planes are available - mostly for cross
    hairs. rl should be normalized and in screen coordinates */
dtop_rl_rop_enable(dest_pixrect, dest_dx, dest_dy, rl, op, src_pixrect,
	    src_dx, src_dy)
	struct pixrect	*dest_pixrect;
	int		dest_dx, dest_dy;
	struct rectlist	*rl;
	int		op;
	struct pixrect	*src_pixrect;
	int		src_dx, src_dy;
/*
 * dtop_rl_rop does a pr_rop from src_pixrect to dst_pixrect for each
 * area described in rl.
 */
{
    register struct rectnode	*rectnode;
    register struct rect	*r;

    for (rectnode = rl->rl_head; rectnode;
	rectnode = rectnode->rn_next) {
	r = &rectnode->rn_rect;
	if (pr_rop(dest_pixrect, r->r_left - dest_dx-1, r->r_top - dest_dy-1,
			r->r_width+2, r->r_height+2, op, src_pixrect,
			r->r_left - src_dx, r->r_top - src_dy))
		return (1);
    }
    return (0);
} /* dtop_rl_rop */


/* return TRUE if the mutex, display or data locks are set. */
int
dtop_check_all_locks(lok_client)
	caddr_t	lok_client;
{
	Desktop			*dtop = (Desktop *) lok_client;
	register Win_lock_block	*shared_info = dtop->shared_info;

	return (shared_info->mutex.lock || shared_info->data.lock ||
		shared_info->display.lock);
}


static void
dtop_init_data_lock(dtop, process)
	register Desktop	*dtop;
	struct proc		*process;
{
	register Winlock	*wlock = &dtop->dt_datalock;

	wlok_setlock(wlock, &dtop->shared_info->data.lock, WLOK_SHAREDLOCK_BITS,
	    &wlock->lok_count_storage, process);
	wlock->lok_client = (caddr_t)dtop;
	wlock->lok_unlock_action = dtop_unlockdata;
	wlock->lok_timeout_action = dtop_timedout_data;
	wlock->lok_string = "data";
	wlock->lok_wakeup = (caddr_t) dtop->shared_info;
	wlock->lok_other_check = dtop_check_all_locks;
}

static void
dtop_init_display_lock(dtop, id, process)
	register Desktop	*dtop;
	int			id;
	struct proc		*process;
{
	register Winlock	*wlock = &dtop->dt_displaylock;

	wlok_setlock(wlock, &dtop->shared_info->display.lock,
	    WLOK_SHAREDLOCK_BITS, &dtop->shared_info->display.count, process);
		/*
		 * 1 use to be used instead of WLOK_SHAREDLOCK_BITS, but,
		 * due to the fact that sparc wants to set different bits
		 * from 68K, there was a problem.  Now, setting all the bits
		 * should allow both schemes to work.
		 */
	wlock->lok_client = (caddr_t) dtop;
	wlock->lok_unlock_action = dtop_unlockdisplay;
	wlock->lok_timeout_action = dtop_timedout_display;
	wlock->lok_string = "display";
	wlock->lok_wakeup = (caddr_t) dtop->shared_info;
	wlock->lok_id = id;
	wlock->lok_other_check = dtop_check_all_locks;
}

static void
dtop_init_mutex_lock(dtop, id, process)
	register Desktop	*dtop;
	int			id;
	struct proc		*process;
{
	register Winlock	*wlock = &dtop->dt_mutexlock;

	wlok_setlock(wlock, &dtop->shared_info->mutex.lock,
	    WLOK_SHAREDLOCK_BITS, &dtop->shared_info->mutex.count, process);
	wlock->lok_client = (caddr_t) dtop;
	wlock->lok_unlock_action = dtop_unlockmutex;
	/* use the display timedout routine */
	wlock->lok_timeout_action = dtop_timedout_display;
	wlock->lok_string = "mutex";
	wlock->lok_wakeup = (caddr_t) dtop->shared_info;
	wlock->lok_id = id;
	wlock->lok_other_check = dtop_check_all_locks;
}

void
dtop_putcolormap(dtop, cms_size, cmap)
	Desktop *dtop;
	int cms_size;
	struct cms_map *cmap;
{
	register struct pixrect *pr = dtop->dt_pixrect;
	int original_plane_group;

	/*
	 * Don't change colormap of monochrome
	 * because not really a colormap under device.  This code (in
	 * combination with the cursor tracking stuff) assumes
	 * that changing the colormap doesn't changed the bits.
	 * Removing test for colormap size leaves reverse cursor images
	 * whenever you change cursor windows with different backgrounds.
	 */
	if (dtop->dt_cmsize <= 2)
		return;
	/*
	 * Don't try to set colormap of a pixrect of depth one.
	 * If such a beast is encounted, change the plane group
	 * to a color plane group.
	 */
	original_plane_group = pr_get_plane_group(pr);
	if (pr->pr_depth == 1) {
		 if (dtop->dt_plane_groups_available[PIXPG_8BIT_COLOR])
			pr_set_planes(pr, PIXPG_8BIT_COLOR, PIX_ALL_PLANES);
		else if (dtop->dt_plane_groups_available[PIXPG_24BIT_COLOR])
			pr_set_planes(pr, PIXPG_24BIT_COLOR, PIX_ALL_PLANES);
		else {
#ifdef WINDEVDEBUG
			if (!(dtop->dt_screen.scr_flags & SCR_OVERLAYONLY))
				printf("Tried to set 1 bit deep colormap\n");
#endif
			return;
		}
	}
	if (pr_putcolormap(pr, 0, cms_size,
	    cmap->cm_red, cmap->cm_green, cmap->cm_blue))
#ifdef WINDEVDEBUG
		printf("pr_putcolormap error\n");
#else
		;
#endif
	pr_set_planes(pr, original_plane_group, PIX_ALL_PLANES);
}



/*
 * Pick the window with the cursor. If this window is not a double
 * bufferer or cursor is not in any of the windows, choose a double
 * bufferer from the list of windows (first one from the top to the
 * the bottom). There will always be atleast one double bufferer
 * when this routine is called. Flip the display, write and read states.
 */

void
dtop_flip_display(dtop, w)
	register Desktop *dtop;
	register struct window *w;
{
	struct window *active_dbl = dtop->dt_curdbl;

	if (w == active_dbl) {
		/*
		 * Flip the display and set write to old foreground, read to old
		 * background.  Flip the dt_dbl_backgr and dt_dbl_frgnd field
		 */
		dtop_changedisplay(dtop, dtop->dt_dbl_bkgnd, dtop->dt_dbl_frgnd,
			FALSE);
		/*
		 * If the cursor is not in the active double bufferer
		 * choose another double bufferer.  The same double
		 * bufferer might get chosen again.
		 */
		if (dtop->dt_cursorwin != active_dbl) {
			/* Choose a new double bufferer */
			dtop_choose_dblbuf(dtop);
			/*
			 * If a new double bufferrer was chosen, copy from
			 * background buffer to forground buffer
			 */
			if (active_dbl != dtop->dt_curdbl)
			    dtop_copy_dblbuffer(dtop, w);
		}
	}
#if 0
	else {
		/* Pick a  window if current double bufferer is not active */
		if (curdbl process not active)
			dtop_choose_dblbuf(dtop);

	}
#endif
	return;
}


/*
 * Choose a double bufferer
 */
void
dtop_choose_dblbuf(dtop)
	register Desktop *dtop;
{
	register struct window *w = dtop->dt_cursorwin;

	dtop->dt_curdbl = WINDOW_NULL;
	if (dtop->dt_flags & DTF_DBLBUFFER) {
		if (w == WINDOW_NULL) {
			wt_enumeratechildren(dtop_isdblwin, dtop->dt_rootwin,
					(struct rect *)0);
			dtop->dt_flags &= ~DTF_DBL_FOUND;
		} else if (!(w->w_flags & WF_DBLBUF_ACCESS)) {
			wt_enumeratechildren(dtop_isdblwin, dtop->dt_rootwin,
					(struct rect *)0);
			dtop->dt_flags &= ~DTF_DBL_FOUND;
		} else
			dtop->dt_curdbl = w;
	}
}

/*
 * This routine is called by wt_enumeratechildren for each of the
 * windows determines whether the window is a double bufferer or not.
 * It sets a flag DTF_DBL_FOUND if a double bufferer is found.  The idea
 * is to find the first double bufferer (from TOP to BOTTOM).
 */

/*ARGSUSED*/
int
dtop_isdblwin(w, rect)
	register struct window *w;
	struct rect *rect;
{
	if (!(w->w_desktop->dt_flags & DTF_DBL_FOUND))
		if (w->w_flags & WF_DBLBUF_ACCESS) {
			w->w_desktop->dt_flags |= DTF_DBL_FOUND;
			w->w_desktop->dt_curdbl = w;
		}
}


/*
 * Remove the cursor, flip the display and redraw the
 * cursor in the foreground
 */
void
dtop_changedisplay(dtop, fore, back, first)
	Desktop *dtop;
	int 	fore, back;
	int	first;	/* Is it called for the first time ? */
{

	if (dtop) {
		int was_up = dtop_cursordraw(dtop);
		if (cursor_up(dtop) || horiz_hair_up(dtop) ||
		    vert_hair_up(dtop))
#ifdef WINDEVDEBUG
			printf("Warning: Cursor up dtop_changedisplay [windt.c]\n");
#else
			;
#endif
		if (first)
			dtop->dt_dblcount++;
		dtop->dt_dbl_frgnd = fore;
		dtop->dt_dbl_bkgnd = back;
		if (pr_dbl_set(dtop->dt_pixrect, PR_DBL_DISPLAY,
						dtop->dt_dbl_frgnd, 0))
#ifdef WINDEVDEBUG
			printf("Error in dtop_changedisplay \n");
#else
			;
#endif
		if (was_up)
			dtop_cursorup(dtop);
	}

}

static int
dtop_cursordraw(dtop)
	Desktop *dtop;
{
  /* cg9 doesn't need cursor updates during double buffering */
  /* don't remove: see comments in dtop_drawcursor() */
  if (dtop->dt_flags & DTF_DBLBUFFER &&
      dtop->dt_plane_groups_available[PIXPG_24BIT_COLOR])
    return(0);

	if (cursor_up(dtop) || horiz_hair_up(dtop) || vert_hair_up(dtop))
	    if (!win_lock_mutex_locked(dtop->shared_info)) {
		dtop_drawcursor(dtop);
		return (1);
	    }
     	return (0);
}



void
dtop_copy_dblbuffer(dtop, w)
	register Desktop *dtop;
	register struct window *w;
{

	int cursor_removed;

	cursor_removed = dtop_cursordraw(dtop);
	/* Copy foreground buffer into bkgnd buffer */
	if (pr_dbl_set(dtop->dt_pixrect, PR_DBL_READ, dtop->dt_dbl_frgnd,
	    PR_DBL_WRITE, dtop->dt_dbl_bkgnd, 0))
#ifdef WINDEVDEBUG
		printf("Error dbl_set flip disp #2\n");
#else
		;
#endif
	/* Screen x, y need to be normalized */
	if (dtop_rl_rop(dtop->dt_pixrect, -w->w_screenx, -w->w_screeny,
	    &w->w_rlexposed, PIX_SRC, dtop->dt_pixrect, -w->w_screenx,
	    -w->w_screeny))
#ifdef WINDEVDEBUG
		printf("roperr in flip display\n");
#else
		;
#endif
	if (cursor_removed)
		(void)dtop_cursorup(dtop);
}


dtop_event_to_sharedq(dtop, event)
	Desktop *dtop;
	struct	inputevent *event;
{
	register int	old_tail = dtop->shared_info->shared_eventq.tail;
	register int	new_tail = old_tail + 1;
	register int	head = dtop->shared_info->shared_eventq.head;
	register int	size = dtop->shared_info->shared_eventq.size;

	if (size <= 0) {
		return (sizeof (*event));
	}
	if (new_tail == size)
		new_tail = 0;
	if (new_tail == head)
		return (sizeof (*event));
	dtop->dt_sharedq[old_tail] = *event;
#ifdef WINDEVDEBUG
	if (win_sharedq_debug) {
		printf("size=%d head=%d oldtail=%d\n",
			size, head, old_tail);
	}
#endif
	dtop->shared_info->shared_eventq.tail = new_tail;

	return (0);
}


int
dtop_dblset(dtop, attribute, value)
	register Desktop *dtop;
	int	attribute;
	int	value;
{
	int pr_value;

	if (value == PW_DBL_BOTH)
		pr_value = PR_DBL_BOTH;
	else if (value == PW_DBL_FORE)
		pr_value = dtop->dt_dbl_frgnd;
	else if (value == PW_DBL_BACK)
		pr_value = dtop->dt_dbl_bkgnd;
	else return (-1);

	if (pr_dbl_set(dtop->dt_pixrect, attribute, pr_value, 0)) {
#ifdef WINDEVDEBUG
		printf("error in ioctl SET for dbl_set\n");
#endif
		return (-1);
	}
	return (0);
}


static int
dtop_set_linebytes(mpr)
	register Pixrect *mpr;
{
	register int bytes;

	bytes = mpr_linebytes(mpr->pr_size.x, mpr->pr_depth);

#ifndef mc68010
	if (bytes & 2 && bytes > 2)
		bytes += 2;
#endif

	mpr_d(mpr)->md_linebytes = bytes;
	return (bytes);
}


/*
 * Allocate image space for crosshair pixrects
 */
dtop_setup_crosshairs(dtop)
	Desktop *dtop;
{
	struct dtopcursor *dc;
	int size;

	dc = &dtop->dt_cursor;

	if ((size = -dc->horiz_hair_size) > 0) {
		dc->horiz_hair_data.md_image =
			(short *)new_kmem_zalloc((u_int) size, KMEM_SLEEP);
		dc->horiz_hair_size = size;
	}
	if ((size = -dc->vert_hair_size) > 0) {
		dc->vert_hair_data.md_image =
			(short *) new_kmem_zalloc((u_int) size, KMEM_SLEEP);
		dc->vert_hair_size = size;
	}
}
