#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 #include /* for cursor access macros */ #include /* for mpr support */ #include /* for double buffering support */ #include /* for plane groups */ #include /* for FREAD and FWRITE */ #include #include #include #include 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; } }