2021-10-11 18:37:13 -03:00

2778 lines
80 KiB
C

#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;
}
}