#ifndef lint static char sccsid[] = "@(#)zap_cursor.c 9.4 88/02/10 Copyright 1987 Sun Micro"; #endif /* * Copyright (c) 1987 by Sun Microsystems, Inc. */ /*- Zap the sunwindows cursor zap_cursor.c, Wed May 7 09:46:42 1986 James Gosling, Sun Microsystems */ /* The only reason for this modules existance is that some of the sunwindows definitions conflict with CScript definitions. Eventually, all the sunwindows crocks will go away. For now, they're necessary for running under overview */ #include #include #include #include #include "/usr/include/pixrect/pixrect.h" /* * Using a non-modified version of struct pixrect so match * the structure used by the kernel. The NeWS version of * struct pixrect has an extra int in it. */ #ifdef pr_close /* pr_close macro added to pixrect.h in 3.2 */ #define RELEASE_3_2_AND_AFTER #endif pr_close #include #include #include #include #include #include #include #ifdef RELEASE_3_2_AND_AFTER #include #include #endif RELEASE_3_2_AND_AFTER #include #include #include #ifndef SHOW_HORIZ_HAIR /* Stolen from sunwindow/cursor_impl.h (private) */ #define SHOW_HORIZ_HAIR 0x00000004 #define SHOW_VERT_HAIR 0x00000008 #define show_horiz_hair(cursor) ((cursor)->flags & SHOW_HORIZ_HAIR) #define show_vert_hair(cursor) ((cursor)->flags & SHOW_VERT_HAIR) #endif static void sun_getwinclip(); static void sun_heavy_lockdevice(); void osi_unlockdevice(); void osi_lockdevice(); /* Turn this data into an instance structure when support multi screens */ static int sun_windowfd; static int sun_winnum; static int sun_clipid; static int sun_lockcount; static int sun_heavy_unlock; Rect sun_wl_rect; static Rectlist sun_rl_latest; static int mypid; int pixwindebug; #ifdef RELEASE_3_2_AND_AFTER static Win_lock_block *sun_win_lock; #define release_lock(which_lock) \ { \ (which_lock)->count = 0; \ (which_lock)->pid = 0; \ (which_lock)->lock = 0; \ } /* return TRUE if lock already taken */ #define acquire_lock(which_lock) \ ((pw_test_set(&(which_lock)->lock)) ? \ TRUE : ((which_lock)->id++, (which_lock)->count = 1, \ (which_lock)->pid = mypid, FALSE)) #else RELEASE_3_2_AND_AFTER static int sun_frame_detected; /* Reduce locking overhead if not * running SunWindows programs */ #endif RELEASE_3_2_AND_AFTER zap_cursor(vsdev) { struct pixrect *mpr = mem_create(16, 16, 1); struct cursor zero; /* Build cursor framework */ zero.cur_shape = mpr; /* Get current cursor */ win_getcursor(vsdev, &zero); /* Set "don't show cursor" flag */ zero.flags = 1; /* Reset cursor */ win_setcursor(vsdev, &zero); /* Free allocated memory */ pr_destroy(mpr); } void osi_lockdevice(sc) struct scene *sc; { #ifdef RELEASE_3_2_AND_AFTER register Win_lock_block *wl = sun_win_lock; #endif RELEASE_3_2_AND_AFTER if (!sc) return; #ifdef RELEASE_3_2_AND_AFTER /* * Hack to avoid locking if no other SunWindows have been * run on this screen, yet. If no one has bumped the display * lock count then there are no other windows visible yet. * There is a race condition such that by the time the display * lock count has been bummped, NeWS and SunWindows may have * collided in their access of the screen. We will have to * see how bad this is in practice. */ if (wl && wl->display.id == 0) return; #else RELEASE_3_2_AND_AFTER /* * Can't quickly detect the condition without shared locking. * However, a single win_getlink is faster then a lock/unlock * pair. */ if (!sun_frame_detected) { if (win_getlink(sun_windowfd, WL_TOPCHILD) == WIN_NULLLINK) return; sun_frame_detected = 1; } #endif RELEASE_3_2_AND_AFTER /* Bump lock count if already locked */ if (sun_lockcount) { sun_lockcount++; return; } sun_lockcount = 1; #ifdef RELEASE_3_2_AND_AFTER /* * Don't do shared locking if no lock block or can't get shared * memory mutual exclusion lock. */ if (!wl || acquire_lock(&wl->mutex)) goto Syscall_lock; /* See if can do light-weight lock */ if (wl->waiting || /* Another process waiting for the lock so let kernel * handle queuing of requests */ ((win_lock_display_locked(wl) && wl->display.pid != mypid)) || /* The display is already locked */ win_lock_grabio_locked(wl) || win_lock_data_locked(wl) || /* Grabio & data locks take precedence over display lock */ (sun_clipid != wl->clip_ids[sun_winnum]) || /* Clip data out-of-date */ wl->go_to_kernel || /* General kernel hook to by-pass shared locking */ show_horiz_hair(&wl->cursor_info.cursor) || show_vert_hair(&wl->cursor_info.cursor)) /* We don't handle cross hairs */ goto Unwind; /* Acquire display lock */ if (win_lock_display_locked(wl)) { /* Already locked, so bump the count */ wl->display.count++; } else if (acquire_lock(&wl->display)) /* Locked already (somehow) */ goto Unwind; if (pixwindebug) osi_unlockdevice(sc); release_lock(&wl->mutex); return; Unwind: release_lock(&wl->mutex); Syscall_lock: #endif RELEASE_3_2_AND_AFTER sun_heavy_lockdevice(sc); } static void sun_heavy_lockdevice(sc) struct scene *sc; { struct winclip winclip; struct rectlist rl; struct winlock winlock; #ifdef RELEASE_3_2_AND_AFTER /* * When a SunWindows window is doing a grabio, but not * collecting mouse motion events (like the prompt package), * the mouse motion is being redirected from the the grabbing * window to it's parent (this is a bug in SunWindows). * The parent is often the NeWS window. * NeWS then reads an event, thus acquiring the event lock. * Unfortunately, NeWS gets stuck in the ioctl below because * the process blocks while waiting for grabio to finish. * This causes the event lock to not be released and the * world to hang for the duration of the event lock timeout * (2 seconds usually or 10 seconds for pre 3.3 users using * click-to-type). So, we explicitly release the event lock * when we are able to detect a grabio. */ if (sun_win_lock && sun_win_lock->grabio.pid != mypid) win_release_event_lock(sun_windowfd); #else RELEASE_3_2_AND_AFTER /* Ignore the problem (user can use "swin -t 1" to alleviate) */ #endif RELEASE_3_2_AND_AFTER winlock.wl_rect = sun_wl_rect; /* * Set lockcount before actually get lock so that reset knows that * it should unlock if called during the time that this ioctl is * happening. This is a race condition. * Extra unlocks are fairly harmless (unless you block). */ werror(ioctl(sun_windowfd, WINLOCKSCREEN, &winlock), WINLOCKSCREEN); if (pixwindebug) werror(ioctl(sun_windowfd, WINUNLOCKSCREEN, 0), WINUNLOCKSCREEN); /* Get new version of the clipping if out of date */ if (sun_clipid != winlock.wl_clipid) { /* Copy exposed clip list from kernel */ rl = rl_null; sun_getwinclip(sun_windowfd, &winclip, &rl, WINGETEXPOSEDRL); /* Update clip id */ sun_clipid = winclip.wc_clipid; /* Set root canvas's clipping */ sun_set_scene_clipping(sc, &rl); rl_copy(&rl, &sun_rl_latest); rl_free(&rl); /* * Tell SunWindows driver that have fixed up damage * (prevents getting unnecessary SIGWINCHs). */ sun_getwinclip(sun_windowfd, &winclip, &rl, WINGETDAMAGEDRL); (void)werror(ioctl(sun_windowfd, WINDONEDAMAGED, &winclip.wc_clipid), WINDONEDAMAGED); rl_free(&rl); } /* Remember to use a heavy unlock later */ sun_heavy_unlock = 1; return; } static void sun_getwinclip(windowfd, winclip, rl, ioctl_number) int windowfd; struct winclip *winclip; struct rectlist *rl; { static char *rlbuf; /* Buffer used when copying rl from kernel */ static rlbufbytes; /* Size of rlbuf */ #define MAXRLBUFBYTES (100*(sizeof(struct rectnode))+sizeof(struct rectlist)) #define RLBUFBYTESINC (10*(sizeof(struct rectnode))) int err; extern char *calloc(); /* Copy clipping data from kernel */ Again: winclip->wc_blockbytes = rlbufbytes; winclip->wc_block = rlbuf; err = ioctl(windowfd, ioctl_number, winclip); if (err) { extern errno; if (errno == EFBIG) { if (rlbuf) free(rlbuf); rlbufbytes += RLBUFBYTESINC; rlbuf = calloc(1, rlbufbytes); if (rlbufbytes > MAXRLBUFBYTES) werror(err, ioctl_number); errno = 0; goto Again; } werror(err, ioctl_number); } else rl_copy((struct rectlist *)(winclip->wc_block), rl); /* * Zero rlbuf. Note: Remove this when fix kernel copyoutrl * bug that doesn't copy out an empty rl right. */ bzero(rlbuf, rlbufbytes); } void osi_unlockdevice(sc) struct scene *sc; { #ifdef RELEASE_3_2_AND_AFTER register Win_lock_block *wl = sun_win_lock; #endif RELEASE_3_2_AND_AFTER if (!sc) goto Return; if (sun_lockcount == 0) { /* * osi_lockdevice has a hack to avoid locking if no * other SunWindows have been run on this screen, yet. * Here we try to detect the race condition alluded to * in the comments in osi_lockdevice and do something * about it. */ #ifdef RELEASE_3_2_AND_AFTER if (wl && wl->display.id != 0) { #else RELEASE_3_2_AND_AFTER if (sun_frame_detected) { #endif RELEASE_3_2_AND_AFTER /* Could redisplay the entire screen */ } goto Return; } if (pixwindebug || sun_lockcount > 1) goto Done; #ifdef RELEASE_3_2_AND_AFTER /* * Don't do shared locking if no lock block or can't get shared * memory mutual exclusion lock. */ if (!wl || acquire_lock(&wl->mutex)) goto Syscall_unlock; /* See if can do light-weight unlock */ if (sun_heavy_unlock || /* We did a heavy lock right before this */ wl->waiting || /* Another process waiting for the lock so let kernel * handle queuing of requests */ !win_lock_display_locked(wl) || (wl->display.pid != mypid) || /* The display is already unlocked */ win_lock_grabio_locked(wl) || win_lock_data_locked(wl) || /* Grabio & data locks take precedence over display lock */ wl->go_to_kernel || /* General kernel hook to by-pass shared locking */ show_horiz_hair(&wl->cursor_info.cursor) || show_vert_hair(&wl->cursor_info.cursor) || /* We don't handle cross hairs */ wl->status.new_cursor) /* New cursor to be drawn */ goto Unwind; wl->display.count--; if (wl->display.count <= 0) /* Release the lock */ release_lock(&wl->display); /* Release the mutex lock */ release_lock(&wl->mutex); goto Done; Unwind: release_lock(&wl->mutex); Syscall_unlock: #endif RELEASE_3_2_AND_AFTER werror(ioctl(sun_windowfd, WINUNLOCKSCREEN, 0), WINUNLOCKSCREEN); Done: sun_lockcount--; Return: sun_heavy_unlock = 0; return; } /* Set up shared memory locking mechanism */ extern void sun_set_shared_locking_info(windowfd) int windowfd; { #ifdef RELEASE_3_2_AND_AFTER extern Win_lock_block *pw_get_lock_block(); /* set up the shared memory info */ sun_win_lock = pw_get_lock_block(windowfd); #endif RELEASE_3_2_AND_AFTER sun_winnum = win_fdtonumber(windowfd); mypid = getpid(); sun_windowfd = windowfd; /* Remember rectangle of vsdev */ win_getrect(windowfd, &sun_wl_rect); } /* * The following have been included to avoid dragging in * large portions of the SunWindow library. */ win_getrect(windowfd, rect) int windowfd; struct rect *rect; { (void)werror(ioctl(windowfd, WINGETRECT, rect), WINGETRECT); return; } win_setrect(windowfd, rect) int windowfd; struct rect *rect; { (void)werror(ioctl(windowfd, WINSETRECT, rect), WINSETRECT); return; } #ifdef RELEASE_3_2_AND_AFTER #include #include #endif RELEASE_3_2_AND_AFTER pw_full_putattributes(pr, planes) struct pixrect *pr; int *planes; { #ifndef planes_fully_implemented #ifdef RELEASE_3_2_AND_AFTER pr_set_planes(pr, pr_get_plane_group(pr), *planes); #endif RELEASE_3_2_AND_AFTER #else pr_putattributes(pr, planes); #endif } sun_init_plane_groups(pr, rl) register struct pixrect *pr; register struct rectlist *rl; { #ifdef RELEASE_3_2_AND_AFTER register struct rectnode *rn_pr; struct win_plane_groups_available win_pg_avail; /* Get this screen's choice of plane groups from kernel */ if (ioctl(sun_windowfd, WINGETAVAILPLANEGROUPS, &win_pg_avail) == -1) return; #ifdef notdef #define PIX_MAX_PLANE_GROUPS 12 char plane_groups_available[PIX_MAX_PLANE_GROUPS]; (void)pr_available_plane_groups(pr, PIX_MAX_PLANE_GROUPS, plane_groups_available); #endif notdef if (win_pg_avail.plane_groups_available[PIXPG_OVERLAY_ENABLE]) { char pg_current = pr_get_plane_group(pr); int enable_color; int plane_group; if (pr->pr_depth == 8) { enable_color = 0; plane_group = PIXPG_OVERLAY; } else { enable_color = 1; plane_group = PIXPG_8BIT_COLOR; } pr_set_plane_group(pr, PIXPG_OVERLAY_ENABLE); for (rn_pr = rl->rl_head; rn_pr; rn_pr = rn_pr->rn_next) pr_rop(pr, rn_pr->rn_rect.r_left, rn_pr->rn_rect.r_top-1, rn_pr->rn_rect.r_width, rn_pr->rn_rect.r_height+1, PIX_COLOR(enable_color) | PIX_SRC, 0, 0, 0); pr_set_plane_group(pr, pg_current); ioctl(sun_windowfd, WINSETPLANEGROUP, &plane_group); } #endif RELEASE_3_2_AND_AFTER }