Files
Arquivotheca.SunOS-4.1.4/usr.lib/libsunwindow/pw/pw_shared.c
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

564 lines
16 KiB
C

#ifndef lint
#ifdef sccs
static char sccsid[] = "@(#)pw_shared.c 1.1 94/10/31 Copyr 1987 Sun Micro";
#endif
#endif
/*
* Copyright (c) 1987 by Sun Microsystems, Inc.
*/
/*
* Pw_shared.c: Use shared memory for faster locking.
*/
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <pixrect/pixrect.h>
#include <pixrect/pr_planegroups.h>
#include <pixrect/memvar.h>
#include <sunwindow/rect.h>
#include <sunwindow/rectlist.h>
#include <sunwindow/cms.h>
#include <sunwindow/pixwin.h>
#include <sunwindow/win_screen.h>
#include <sunwindow/win_cursor.h>
#include <sunwindow/win_lock.h>
#include <sunwindow/cursor_impl.h> /* for crosshairs active check */
static void pw_do_shared_lock(), pw_do_shared_unlock();
#define pw_release_lock(which_lock) \
{ \
(which_lock)->count = 0; \
(which_lock)->pid = 0; \
(which_lock)->lock = 0; \
}
typedef struct pw_dtop_entry {
char dtop_name[SCR_NAMESIZE];
int ref_count;
Win_lock_block *shared_info;
} Pw_dtop_entry;
/* set this to TRUE to turn off the shared locking */
/* initialize pw_disable_shared_locking to 0. */
int pw_disable_shared_locking = 0;
static Pw_dtop_entry pw_dtop_table[WIN_LOCK_MAX_DTOP];
static int pw_lock_block_bytes;
static int pw_mypid;
/* return TRUE if lock already taken */
#define pw_get_lock(which_lock) \
((pw_test_set(&(which_lock)->lock)) ? \
TRUE : ((which_lock)->id++, (which_lock)->count = 1, \
(which_lock)->pid = pw_mypid, FALSE))
pw_shared_lock(pw, rect_paint)
register Pixwin *pw;
Rect *rect_paint;
{
register Win_lock_block *wl = pw->pw_clipdata->pwcd_wl;
/*
* Cursors, 24-bit planegroups, and shared locking don't currently
* mix too well.
*/
if (pw->pw_clipdata->pwcd_plane_groups_available[PIXPG_24BIT_COLOR])
return(FALSE);
/*
* if double buffering is on, we do not want to use the shared
* memory lock or else pw_rop and friends will behave abnormally
* (for cg{3,5} only)
*/
if ((pw->pw_clipdata->pwcd_flags & PWCD_DBL_AVAIL) &&
!pw->pw_clipdata->pwcd_plane_groups_available[PIXPG_24BIT_COLOR] &&
pw_dbl_rect(pw))
return(FALSE);
/*
* See if locked already. Assume that don't get here if this
* pixwin has the display lock already.
* Grabio and window data locks take precedence over display lock.
*/
if (!wl || pw_get_lock(&wl->mutex))
return FALSE;
/*
* Don't do own locking if io is grabbed. This is because we
* aren't prepared to adequately track the cursor when the
* pixwin has multiple plane groups available. We could beef
* this up to check to see if multiple available planes are
* present before we go to pw_release_lock.
* Also, bail out if going to to be taking cursor down
* that was put up over another plane group.
*/
if (wl->waiting || wl->go_to_kernel || win_lock_grabio_locked(wl) ||
(win_lock_data_locked(wl) && wl->data.pid != pw_mypid) ||
(win_lock_display_locked(wl) && wl->display.pid != pw_mypid) ||
(pw->pw_clipdata->pwcd_plane_group != wl->cursor_info.plane_group)){
pw_release_lock(&wl->mutex);
return FALSE;
}
/* See if pixwin clip data out-of-date or xhairs involved */
if ((pw->pw_clipdata->pwcd_clipid !=
wl->clip_ids[pw->pw_clipdata->pwcd_winnum]) ||
show_horiz_hair(&wl->cursor_info.cursor) ||
show_vert_hair(&wl->cursor_info.cursor)) {
/* Since have to call kernel to get clipping ... */
pw_release_lock(&wl->mutex);
return FALSE;
}
/* acquire display lock */
if (win_lock_display_locked(wl)) {
/* already locked, so bump the count */
wl->display.count++;
} else if (pw_get_lock(&wl->display)) {
/* locked already (somehow) */
pw_release_lock(&wl->mutex);
return FALSE;
}
pw_do_shared_lock(pw, rect_paint);
pw_release_lock(&wl->mutex);
return TRUE;
}
static void
pw_do_shared_lock(pw, rect_paint)
register Pixwin *pw;
Rect *rect_paint;
{
Win_lock_block *wl = pw->pw_clipdata->pwcd_wl;
register Win_shared_cursor *shared_cursor = &wl->cursor_info;
int original_planes;
int planes;
#ifdef ecd.cursor
short olddata;
#endif ecd.cursor
/*
* See if cursor is active, up on the screen and intersects
* area that are going to paint in. If a cursor plane exists -
* i.e spare3 is set, you dont have to paint it in
*/
if (shared_cursor->cursor_active && shared_cursor->cursor_is_up &&
pw_cursor_intersect_exposed(pw, rect_paint) &&
(!shared_cursor->spare3)) {
/* Take cursor off of the screen */
if (pw->pw_clipdata->pwcd_flags & PWCD_CURSOR_INVERTED)
(void)pr_reversevideo(pw->pw_pixrect, 0, 1);
win_lock_prepare_screen_pr(shared_cursor);
/* Set up full planes */
(void)pr_getattributes(pw->pw_pixrect, &original_planes);
planes = PIX_ALL_PLANES;
#ifdef planes_fully_implemented
pr_putattributes(pw->pw_pixrect, &planes);
#else
(void)pw_full_putattributes(pw->pw_pixrect, &planes);
#endif planes_fully_implemented
#ifdef ecd.cusror
/* This fix is mainly for MS windows which runs in
* reverse video. When we rop from the MS win pixrect
* we would use a reverse rop. However, the kernel uses
* the shared memory pixrect when it moves the cursor
* and doesn't know we rop'd from a reverse video window.
* The kernel just uses the display pixrect which has the
* attributes that were used when sunview was started.
* The fix is to clear the window pixrect MP_REVERSEVIDEO
* flag while we rop into the memory pixrect. The kernel
* also has some similar code to fix the situation where
* sunview was started with -i (inverse). (See sys/
* sunwindowdev/windt.c)
*/
olddata = ((struct mpr_data *)(pw->pw_pixrect->pr_data))->md_flags;
((struct mpr_data *)(pw->pw_pixrect->pr_data))->md_flags &= ~MP_REVERSEVIDEO;
#endif ecd.cursor
(void)pr_rop(pw->pw_pixrect, shared_cursor->x, shared_cursor->y,
shared_cursor->screen_pr.pr_width,
shared_cursor->screen_pr.pr_height,
PIX_SRC, &shared_cursor->screen_pr, 0, 0);
#ifdef ecd.cursor
((struct mpr_data *)(pw->pw_pixrect->pr_data))->md_flags = olddata;
#endif ecd.cursor
/* Reset planes */
#ifdef planes_fully_implemented
pr_putattributes(pw->pw_pixrect, &original_planes);
#else
(void)pw_full_putattributes(pw->pw_pixrect, &original_planes);
#endif planes_fully_implemented
if (pw->pw_clipdata->pwcd_flags & PWCD_CURSOR_INVERTED)
(void)pr_reversevideo(pw->pw_pixrect, 0, 1);
shared_cursor->cursor_is_up = FALSE;
}
#ifdef DEBUG
printf("locked display\n");
#endif
}
pw_shared_unlock(pw)
register Pixwin *pw;
{
register Win_lock_block *wl = pw->pw_clipdata->pwcd_wl;
register Win_shared_cursor *shared_cursor;
/*
* Cursors, 24-bit planegroups, and shared locking don't currently
* mix too well.
*/
if (pw->pw_clipdata->pwcd_plane_groups_available[PIXPG_24BIT_COLOR])
return(FALSE);
/*
* if double buffering is on, we do not want to use the shared
* memory unlock or else pw_rop and friends will behave abnormally
* (for cg{3,5} only)
*/
if ((pw->pw_clipdata->pwcd_flags & PWCD_DBL_AVAIL) &&
!pw->pw_clipdata->pwcd_plane_groups_available[PIXPG_24BIT_COLOR] &&
pw_dbl_rect(pw))
return(FALSE);
if (!wl || pw_get_lock(&wl->mutex))
return FALSE;
shared_cursor = &wl->cursor_info;
/* See if we have it locked, no one waiting for
* lock and no xhairs. Also, bail out if going to
* to be putting cursor up over another plane group.
*
* Also, don't do own locking if io is grabbed. This is because we
* aren't prepared to adequately track the cursor when the
* pixwin has multiple plane groups available.
*/
if (wl->waiting || wl->go_to_kernel || win_lock_grabio_locked(wl) ||
wl->status.new_cursor ||
!win_lock_display_locked(wl) || (wl->display.pid != pw_mypid) ||
(pw->pw_clipdata->pwcd_plane_group != wl->mouse_plane_group) ||
show_horiz_hair(&shared_cursor->cursor) ||
show_vert_hair(&shared_cursor->cursor)) {
pw_release_lock(&wl->mutex);
return FALSE;
}
wl->display.count--;
if (wl->display.count <= 0) {
/* Release the lock */
pw_do_shared_unlock(pw);
pw_release_lock(&wl->display);
}
/* release the mutex lock */
pw_release_lock(&wl->mutex);
return TRUE;
}
static void
pw_do_shared_unlock(pw)
register Pixwin *pw;
{
register Win_lock_block *wl = pw->pw_clipdata->pwcd_wl;
register Win_shared_cursor *shared_cursor = &wl->cursor_info;
int original_planes;
int planes;
#ifdef ecd.cursor
short olddata;
struct mpr_data *mpds, *mpdd;
#endif ecd.cursor
#ifdef DEBUG
printf("unlocked display\n");
#endif
/* only draw the cursor if not up, active and want it or
* we dont have cursor planes
*/
if ((shared_cursor->spare3)|| (shared_cursor->cursor_is_up) ||
(!shared_cursor->cursor_active) ||
(!(show_cursor(&shared_cursor->cursor) &&
shared_cursor->pr_data.md_image &&
shared_cursor->pr.pr_width &&
shared_cursor->pr.pr_depth &&
shared_cursor->pr.pr_height)))
return;
/* Set up full planes */
(void)pr_getattributes(pw->pw_pixrect, &original_planes);
planes = PIX_ALL_PLANES;
#ifdef planes_fully_implemented
pr_putattributes(pw->pw_pixrect, &planes);
#else
(void)pw_full_putattributes(pw->pw_pixrect, &planes);
#endif planes_fully_implemented
/*
* Get current mouse position.
* Race with kernel but not critical.
*/
shared_cursor->x = wl->mouse_x;
shared_cursor->y = wl->mouse_y;
/* Note what plane group using */
shared_cursor->plane_group = pw->pw_clipdata->pwcd_plane_group;
/* adjust for the hot spot */
shared_cursor->x -= shared_cursor->cursor.cur_xhot;
shared_cursor->y -= shared_cursor->cursor.cur_yhot;
if (pw->pw_clipdata->pwcd_flags & PWCD_CURSOR_INVERTED)
(void)pr_reversevideo(pw->pw_pixrect, 0, 1);
/* save the bits under the cursor */
shared_cursor->screen_pr.pr_width = shared_cursor->pr.pr_width;
shared_cursor->screen_pr.pr_height = shared_cursor->pr.pr_height;
win_lock_prepare_screen_pr(shared_cursor);
#ifdef ecd.cursor
olddata = ((struct mpr_data *)(pw->pw_pixrect->pr_data))->md_flags;
((struct mpr_data *)(pw->pw_pixrect->pr_data))->md_flags &= ~MP_REVERSEVIDEO;
#endif ecd.cursor
(void)pr_rop(&shared_cursor->screen_pr, 0, 0,
shared_cursor->screen_pr.pr_width,
shared_cursor->screen_pr.pr_height,
PIX_SRC, pw->pw_pixrect, shared_cursor->x, shared_cursor->y);
#ifdef ecd.cursor
((struct mpr_data *)(pw->pw_pixrect->pr_data))->md_flags = olddata;
#endif ecd.cursor
/*
* Reset planes so that will write to foreground and background
* of current colormap segment.
*/
#ifdef planes_fully_implemented
pr_putattributes(pw->pw_pixrect, &original_planes);
#else
(void)pw_full_putattributes(pw->pw_pixrect, &original_planes);
#endif planes_fully_implemented
/* Put cursor on the screen */
win_lock_prepare_cursor_pr(shared_cursor);
(void)pr_rop(pw->pw_pixrect, shared_cursor->x, shared_cursor->y,
shared_cursor->screen_pr.pr_width,
shared_cursor->screen_pr.pr_height,
shared_cursor->cursor.cur_function, &shared_cursor->pr, 0, 0);
shared_cursor->cursor_is_up = TRUE;
if (pw->pw_clipdata->pwcd_flags & PWCD_CURSOR_INVERTED)
(void)pr_reversevideo(pw->pw_pixrect, 0, 1);
}
static int
pw_cursor_intersect_exposed(pw, rect_paint)
register Pixwin *pw;
Rect *rect_paint;
{
Win_lock_block *shared_info = pw->pw_clipdata->pwcd_wl;
Win_shared_cursor *cursor_info = &shared_info->cursor_info;
Rect rect;
int have_grabio;
/* if the data lock is ours, we can't trust the
* screen_x, screen_Y coordinates of the window, since
* a win_setrect() could have been done without changing
* the clipping id. So play it safe and take down the cursor.
*/
if (win_lock_data_locked(shared_info) &&
(shared_info->data.pid == pw_mypid))
return TRUE;
rect_construct(&rect, cursor_info->x, cursor_info->y,
cursor_info->pr.pr_width, cursor_info->pr.pr_height);
/* transform to window space */
rect_passtochild(pw->pw_clipdata->pwcd_screen_x,
pw->pw_clipdata->pwcd_screen_y, &rect);
/*
* Since the clipping list is in the space of the pixwin,
* transform the window-space cursor rect to region space.
*/
if (pw->pw_clipdata->pwcd_regionrect)
rect_passtochild(pw->pw_clipdata->pwcd_regionrect->r_left,
pw->pw_clipdata->pwcd_regionrect->r_top, &rect);
/* cursor must be on the intended paint area to intersect.
* Also, either this process must have the grabio lock or
* the cursor must be in the exposed rectlist of pw.
*/
have_grabio = win_lock_grabio_locked(shared_info) &&
(shared_info->grabio.pid == pw_mypid);
return (rect_intersectsrect(&rect, rect_paint) &&
(have_grabio ||
rl_rectintersects(&rect, &pw->pw_clipdata->pwcd_clipping)));
}
/* Defining MAP_FIXED is for compiling under 3.4 environment */
#ifndef MAP_FIXED
#define MAP_FIXED 0
#endif
Win_lock_block *
pw_get_lock_block(windowfd)
int windowfd;
{
struct screen screen;
register char *dtop_name = screen.scr_fbname;
register int i;
register Pw_dtop_entry *entry;
Pw_dtop_entry *free_entry = 0;
Win_lock_block *shared_info;
static Win_lock_block *last_valloc; /* = 0 */
static int wrong_version; /* = 0 */
char *strcpy();
if (wrong_version || pw_disable_shared_locking)
return 0;
pw_mypid = getpid();
(void)win_screenget(windowfd, &screen);
/* see if this dtop is already mapped in */
for (i = 0, entry = &pw_dtop_table[i]; i < WIN_LOCK_MAX_DTOP;
i++, entry = &pw_dtop_table[i])
if (!entry->shared_info) {
if (!free_entry)
free_entry = entry;
} else if (strcmp(dtop_name, entry->dtop_name) == 0) {
entry->ref_count++;
return entry->shared_info;
}
/* not already in the table, so there better be a
* free slot.
*/
if (!free_entry)
return 0;
/* there is a free slot, so mmap the shared info */
if (!pw_lock_block_bytes)
pw_lock_block_bytes = round_to_page(sizeof(Win_lock_block));
/* Note that here we mmap() using the windowfd and that
* other windows will share this mmaped memory.
* If close(windowfd) is changed to munmap() the storage,
* the other windows will be left pointing to invalid storage.
*/
if (last_valloc)
shared_info = last_valloc;
else {
extern char *valloc();
shared_info = (Win_lock_block *) valloc((u_int)pw_lock_block_bytes);
}
if ((int)mmap((caddr_t)shared_info, pw_lock_block_bytes,
PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, windowfd, 0) == -1) {
last_valloc = shared_info;
return 0;
}
/* if the kernel has a different version number,
* don't use the shared memory.
*/
if (shared_info->version != WIN_LOCK_VERSION) {
wrong_version = TRUE;
return 0;
}
last_valloc = 0;
entry = free_entry;
entry->shared_info = shared_info;
(void) strcpy(entry->dtop_name, dtop_name);
entry->ref_count = 1;
return shared_info;
}
void
pw_free_lock_block(shared_info)
register Win_lock_block *shared_info;
{
if (!shared_info)
return;
/* Don't free up the shared memory, since this is probably
* no big win (and a waste of cycles).
for (i = 0, entry = &pw_dtop_table[i]; i < WIN_LOCK_MAX_DTOP;
i++, entry = &pw_dtop_table[i])
if (shared_info == entry->shared_info) {
entry->ref_count--;
if (entry->ref_count <= 0) {
munmap(shared_info, pw_lock_block_bytes);
free(shared_info);
}
return;
}
*/
}
/* Update process specific data */
pw_fork()
{
pw_mypid = getpid();
}
static int
round_to_page(bytes)
register int bytes;
{
register int pagesize = getpagesize();
register int roundup = pagesize-(bytes%pagesize);
if (roundup != pagesize)
bytes += roundup;
return(bytes);
}
pw_reset_lock(pw)
Pixwin *pw;
{
Win_lock_block *wl = pw->pw_clipdata->pwcd_wl;
if (!wl)
return;
pw_release_lock(&wl->mutex);
pw_release_lock(&wl->display);
}
/* turn shared locking on or off */
pw_set_shared_locking(on)
int on;
{
/* pw_disable_shared_locking = !on; */
}