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

2175 lines
56 KiB
C

#ifndef lint
static char sccsid[] = "@(#)winioctl.c 1.1 94/10/31 SMI";
#endif
/*
* Copyright (c) 1989 by Sun Microsystems, Inc.
*/
/*
* SunWindows ioctls, see sunwindow/win_ioctl.h.
*/
#include <sunwindowdev/wintree.h>
#include <sunwindow/cursor_impl.h> /* for cursor access macros */
#include <sunwindow/win_enum.h>
#include <sunwindow/win_ioctl.h>
#include <pixrect/pr_util.h> /* for mpr support */
#include <pixrect/pr_dblbuf.h> /* for double buffering support */
#include <pixrect/pr_planegroups.h> /* for plane groups */
#include <sys/kernel.h> /* for time */
#include <sunwindow/pw_dblbuf.h>
#include <sun/fbio.h>
#ifdef WINDEVDEBUG
int winprintall; /* Temp: Debugging message when call winioctl */
int winprintexits; /* Temp: Debugging message when return from winioctl */
int winfilterlockscreen; /* Temp: Don't print debugging messages about
WINLOCKSCREEN and WINUNLOCKSCREEN calls */
#endif
int winnodisplaylock; /* Temp: Don't actually lock if WINLOCKSCREEN */
/*
* Scaling is accomplished by finding the first entry in the following
* table whose ceiling >= the current motion, and multiplying that
* motion by the corresponding factor.
*/
Ws_scale ws_scaling[WS_SCALE_MAX_COUNT+1] = {
{WS_SCALE_MAX_CEILING, 2}
};
extern int MS_DEBUG;
extern int ws_button_order; /* current button mapping */
extern void ws_set_dtop_waiting();
extern void dtop_putcolormap();
extern struct window *wt_intersected();
extern int winkill(), wt_positionchanged(), wt_partialrepair(),
wt_sizechanged();
extern int winpsnotkill; /* Reach around communication from
WINSCREENDESTROY to winkill */
extern struct proc *pfind();
extern bool wt_isindisplaytree();
extern caddr_t dtop_alloccmapdata();
extern void dtop_update_enable();
extern void dtop_choose_dblbuf();
extern void dtop_changedisplay();
extern void dtop_flip_display();
extern void dtop_copy_dblbuffer();
extern Workstation *ws_indev_match_name();
extern Workstation *ws_open();
extern Wsindev *ws_open_indev();
extern int copyin(), copyout();
static int check_crosshair_info(),
wt_gettreelayer();
static void wt_copy_layer_node(),
wt_count_layer();
static void win_prepare_surface();
static void win_return_cms();
static void win_pick_plane_group();
static void win_initialize_plane_group();
static void win_clear_cursor_plane_groups();
int win_errno; /* Set from calls out of module (same values as errno)*/
int win_exit_seconds = 1000;
int print_waiting = TRUE;
int print_still_waiting = TRUE;
int always_signal = 1;
/*ARGSUSED*/
int
winioctl(dev, cmd, data, flag)
dev_t dev;
register caddr_t data;
{
register struct window *w = winfromdev(dev);
register struct desktop *dtop = w->w_desktop;
register Workstation *ws = NULL;
register int i;
int pri;
register int error = 0;
#ifdef WINSVJ
register short win_playrec_sync_flg = 1; /* Flag for syncing type */
#endif
extern winnotify_inorder;
#define returnerror(e) {error = (e); goto done;}
#ifdef WINDEVDEBUG
if (winprintall) {
if (winfilterlockscreen && (cmd == WINLOCKSCREEN ||
cmd == WINUNLOCKSCREEN))
{}
else
printf("winioctl dev: %X, cmd: %X, data: %X [%X,%X,%X...]\n",
dev, cmd, data, *(int *)data, *(int *)(data+4),
*(int *)(data+8));
}
#endif
/* Block out timeouts */
pri = spl_timeout();
if (dtop == NULL) {
/*
* All but the following operations need dtop not NULL because
* so much of the code assumes a not NULL dtop.
* Note: the list of allowable operations should be expanded.
*/
switch (cmd) {
case WINSCREENNEW:
case WINSETLINK:
case WINSETRECT:
case WINGETRECT:
case WINSETSAVEDRECT:
case WINGETSAVEDRECT:
case WINNEXTFREE:
case WINGETBUTTONORDER:
case WINSETBUTTONORDER:
case WINGETSCALING:
case WINSETSCALING:
case WINGETUSERFLAGS:
case WINSETUSERFLAGS:
#ifndef PRE_FLAMINGO
case WINGETNOTIFYALL:
case WINSETNOTIFYALL:
#endif
case _IO(g, 100):
break;
default:
returnerror(ESPIPE);
}
} else {
ws = dtop->dt_ws;
if (!dtop->shared_info) /* Has happened but don't know why */
returnerror(ESPIPE);
dtop->shared_info->waiting++;
if (wlok_waitunlocked(&dtop->dt_datalock)) {
if (dtop->shared_info)
dtop->shared_info->waiting--;
goto restart;
}
dtop->shared_info->waiting--;
switch (cmd) {
/*
* Don't tamper with display lock while locked by another.
*/
case WINLOCKSCREEN:
case WINUNLOCKSCREEN:
case WINGRABIO:
/*
* Any operation that involes double buffering waits
* while the display is locked.
*
*/
case WINDBLCURRENT:
case WINDBLACCESS:
case WINDBLRLSE:
case WINDBLFLIP:
case WINDBLABSORB:
case WINDBLSET:
case WINDBLGET:
/*
* Any operation that might invoke a clipping change while the
* display is locked must wait until the lock is released.
* An exception to this is if the calling user process is
* the same as the original locker.
*/
case WININSERT:
case WINREMOVE:
case WINSETRECT:
case WINSETOWNER:
case WINUNLOCKDATA:
case WINSCREENDESTROY:
/*
* Don't tamper with colormap while display locked by another.
*/
case WINSETCMS:
case WINRELEASEIO:
/*
* Don't tamper with plane group while display locked
* by another.
*/
case WINSETPLANEGROUP:
case WINGETDAMAGEDRL:
/* Make sure dt still around if waited before */
if (!(dtop->dt_flags & DTF_PRESENT))
returnerror(EACCES);
/* Bump the waiting count and wait for the
* display lock to be released, or just
* go on through if we have the display lock.
* Note that we look at the shared lock only,
* since we can't trust the internal wlok after
* we sleep.
*/
dtop->shared_info->waiting++;
dtop->display_waiting++;
while (win_lock_display_locked(dtop->shared_info) &&
(dtop->shared_info->display.pid != u.u_procp->p_pid))
if (sleep((caddr_t)dtop->shared_info,
LOCKPRI|PCATCH)) {
if (dtop->shared_info)
dtop->shared_info->waiting--;
dtop->display_waiting--;
goto restart;
}
/* Now make sure the internal display lock
* is valid. We have to do this here because
* we don't know what went on while we were sleeping.
*/
dtop_validate_shared_lock(dtop, &dtop->dt_displaylock);
dtop->shared_info->waiting--;
dtop->display_waiting--;
}
switch (cmd) {
/*
* Don't tamper with colormap while io rights locked by another.
*/
case WINSETCMS:
case WINSETPLANEGROUP:
/*
* Don't tamper with io right lock while locked by another.
*/
case WINGRABIO:
case WINRELEASEIO:
case WINDBLCURRENT:
case WINDBLACCESS:
case WINDBLRLSE:
case WINDBLFLIP:
case WINDBLABSORB:
case WINDBLSET:
case WINDBLGET:
/*
* Don't acquire data lock while io rights locked by another.
* If we did, one could get into a situation in which the
* data lock holder might try to access the screen but be
* prevented by the other process having the io lock. Also,
* the io lock holder couldn't access the screen because
* the data lock is more powerful. Deadlock.
*/
case WINLOCKDATA:
if (ws == NULL)
returnerror(ESPIPE);
/* Make sure ws still around if waited before */
if (!(ws->ws_flags & WSF_PRESENT))
returnerror(EACCES);
ws_set_dtop_waiting(ws, 1);
if (wlok_waitunlocked(&ws->ws_iolock)) {
ws_set_dtop_waiting(ws, -1);
goto restart;
}
ws_set_dtop_waiting(ws, -1);
}
/* Make sure ws & dt still around if waited before */
if ((!(dtop->dt_flags & DTF_PRESENT)) ||
(!(ws->ws_flags & WSF_PRESENT)))
returnerror(EACCES);
}
if (ws == NULL) {
/*
* Same drill as above, except this time for ws -- avoid
* operations that assume it's nonnull. This is a gross hack;
* the code leading to this point should have insured that ws
* is nonnull, but unfortunately does not always do so.
*/
switch (cmd) {
case WINSETMOUSE:
case WINSCREENDESTROY:
case WINSETKBD:
case WINSETMS:
case WINSETINPUTDEV:
case WINGETINPUTDEV:
case WINGETVUIDVALUE:
case WINGETFOCUSEVENT:
case WINSETFOCUSEVENT:
case WINGETSWALLOWEVENT:
case WINSETSWALLOWEVENT:
case WINGETKBDFOCUS:
case WINSETKBDFOCUS:
case WINGETEVENTTIMEOUT:
case WINSETEVENTTIMEOUT:
case WINUNLOCKEVENT:
case WINREFUSEKBDFOCUS:
returnerror(ESPIPE);
}
}
switch (cmd) {
/*
* Display management operations
* (placed at beginning for faster access[?] because high frequency).
*/
case WINLOCKSCREEN: {
struct winlock *winlock = (struct winlock *)data;
int new_id;
if (winnodisplaylock)
goto done;
new_id = dtop_lockdisplay(dev, &winlock->wl_rect);
if (new_id < 0)
goto restart;
winlock->wl_clipid = new_id;
break;
}
case WINUNLOCKSCREEN:
if (winnodisplaylock)
goto done;
wlok_unlock(&dtop->dt_displaylock);
break;
case FIONREAD:
/* return # of CHARACTERS (not events) immediately available */
win_sharedq_shift(w);
if (dtop && w->w_desktop->dt_sharedq_owner == w) {
if (dtop->shared_info->shared_eventq.tail >=
dtop->shared_info->shared_eventq.head) {
*(int *)data =
dtop->shared_info->shared_eventq.tail -
dtop->shared_info->shared_eventq.head;
} else {
*(int *)data =
dtop->shared_info->shared_eventq.tail +
dtop->shared_info->shared_eventq.size -
dtop->shared_info->shared_eventq.head;
}
*(int *)data *= sizeof (struct inputevent);
*(int *)data += w->w_input.c_cc;
} else
*(int *)data = w->w_input.c_cc;
break;
case FIOASYNC:
/*
* Note: If ignore FIOASYNC then
* need to explicitely ignore it due to way that fcntl is
* implemented in ../sys/kern_descrip.c.
*/
if (*(int *)data) {
w->w_flags |= WF_ASYNC;
w->w_aproc = u.u_procp;
w->w_apid = u.u_procp->p_pid;
} else {
w->w_flags &= ~WF_ASYNC;
w->w_aproc = 0;
w->w_apid = 0;
}
break;
case FIONBIO:
if (*(int *)data)
w->w_flags |= WF_NBIO;
else
w->w_flags &= ~WF_NBIO;
break;
/*
* Tree operations
*/
case WINGETLINK: {
struct winlink *winlink = (struct winlink *)data;
if ((unsigned)winlink->wl_which >= WIN_LINKS)
returnerror(EINVAL);
wt_windowtonumber(w->w_link[winlink->wl_which],
&winlink->wl_link);
break;
}
case WINSETLINK: {
struct winlink *winlink = (struct winlink *)data;
struct window *windowlink;
if ((unsigned)winlink->wl_which >= WIN_LINKS)
returnerror(EINVAL);
if (wt_numbertowindow(winlink->wl_link, &windowlink) < 0)
returnerror(EINVAL);
if (w->w_flags & WF_INSTALLED || (windowlink == w))
returnerror(EINVAL);
w->w_link[winlink->wl_which] = windowlink;
if (winlink->wl_which==WL_PARENT && w->w_link[WL_PARENT]) {
w->w_desktop = w->w_link[WL_PARENT]->w_desktop;
if (w->w_desktop) {
/* Make sure dt still around before reference */
if (!(w->w_desktop->dt_flags & DTF_PRESENT))
returnerror(EACCES);
w->w_ws = w->w_desktop->dt_ws;
win_pick_plane_group(w->w_desktop, w);
}
}
break;
}
case WININSERT:
if (dtop->dt_flags & DTF_EXITING) {
winsignal(w, SIGKILL);
returnerror(EACCES);
}
if ((error = wt_install(w)) != 0)
returnerror(error);
if (wt_isindisplaytree(w))
dtop_invalidateclipping(
dtop, w->w_link[WL_PARENT], &w->w_rect);
break;
case WINREMOVE:
if ((error = dtop_removewin(dtop, w)))
returnerror(error);
break;
case WINNEXTFREE: {
struct winlink *winlink = (struct winlink *)data;
struct window *win;
winlink->wl_link = WIN_NULLLINK;
#if NWIN > 0
for (i = 0; win = winfromdev(i); i++)
if (!(win->w_flags&WF_OPEN)) {
wt_windowtonumber(win, &winlink->wl_link);
break;
}
#endif
break;
}
case WINGETTREELAYER:
if (dtop->dt_flags & DTF_EXITING) {
winsignal(w, SIGKILL);
returnerror(EACCES);
}
if ((error = wt_gettreelayer(w, (Win_tree_layer *)data)))
returnerror(error);
break;
/*
* Mouse cursor operations.
*/
case WINSETMOUSE: {
struct mouseposition *mp = (struct mouseposition *)data;
Firm_event fe;
int delta;
Desktop *dtop_old = ws->ws_loc_dtop;
if (!dtop_old) {
returnerror(ENOENT);
}
if (dtop != dtop_old) {
void dtop_change_loc_dtop();
dtop_change_loc_dtop(dtop_old, dtop,
mp->msp_x+w->w_screenx, mp->msp_y+w->w_screeny);
} else {
/*
* Apply the absolute to the user state. Apply the
* difference between the original user state and the
* new user state to the real time state.
*/
delta = mp->msp_x + w->w_screenx - dtop->dt_ut_x;
dtop->dt_ut_x = mp->msp_x + w->w_screenx;
dtop->dt_rt_x += delta;
delta = mp->msp_y + w->w_screeny - dtop->dt_ut_y;
dtop->dt_ut_y = mp->msp_y + w->w_screeny;
dtop->dt_rt_y += delta;
}
/*
* Update the shared memory mouse x, y
*/
win_shared_update_mouse_xy(dtop->shared_info,
dtop->dt_rt_x, dtop->dt_rt_y);
/*
* We enqueue a bogus LOC_MOVE at the user time end of
* the queue so that LOC_WINENTERs, EXITs and STILLs
* are generated.
*/
if (vq_is_full(&ws->ws_q))
break;
if (vq_peek(&ws->ws_q, &fe) == VUID_Q_EMPTY)
/* Use the current time */
fe.time = time;
/* else use the time at the top of the queue */
fe.id = LOC_MOVE;
fe.value = 1; /* Set to one because event has no neg */
fe.pair = 0;
fe.pair_type = FE_PAIR_NONE;
if (vq_putback(&ws->ws_q, &fe) != VUID_Q_OK)
#ifdef WINDEVDEBUG
printf("putback error\n");
#else
;
#endif
/* Update the locator (real time end of queue) */
ws_track_locator(ws);
/* Update pick focus if changed */
ws_set_focus(ws, FF_PICK_CHANGE);
break;
}
case WINSETLOCATOR:
/* check the validity of the
* crosshair info.
*/
if (error = check_crosshair_info((struct cursor *) data))
returnerror(error);
/* and fall through ... */
case WINSETCURSOR: {
struct cursor *cursor = (struct cursor *)data;
struct pixrect mpr;
struct mpr_data mpr_data;
short image[CUR_MAXIMAGEWORDS];
int empty;
if (error = winio_getusercursor(
cursor, &mpr, &mpr_data, image, &empty))
returnerror(error);
if (empty)
/*
* dtop_drawcursor knows 0 depth is nop cursor.
*/
w->w_cursormpr.pr_depth = 0;
else {
/*
* Now that have reasonable cursor, copy to w.
*/
/* this if-else will go away when our
* kernel is released and the SETLOCATOR
* and GETLOCATOR code is removed.
*/
if (cmd == WINSETCURSOR) {
w->w_cursor.cur_xhot = cursor->cur_xhot;
w->w_cursor.cur_yhot = cursor->cur_yhot;
w->w_cursor.cur_function = cursor->cur_function;
w->w_cursor.cur_shape = cursor->cur_shape;
w->w_cursor.flags = 0;
} else
w->w_cursor = *cursor;
w->w_cursormpr = mpr;
w->w_cursordata = mpr_data;
bcopy((caddr_t)image, (caddr_t)w->w_cursorimage,
CUR_MAXIMAGEBYTES);
/*
* Fixup cursor internal pointers.
*/
winfixupcursor(w);
/*
* Allocate crosshair cursor pixrect storage
* if necessary.
*/
if (show_horiz_hair(cursor) ||
show_vert_hair(cursor))
dtop_setup_crosshairs(dtop);
}
/*
* Replace new for old on screen if old was up.
* Do it now incase client is counting on cursor state.
*/
if (dtop->dt_cursorwin == w) {
dtop_cursordown(dtop);
/* update the shared cusor */
win_shared_update_cursor(dtop);
dtop_cursorup(dtop);
}
break;
}
case WINGETLOCATOR:
case WINGETCURSOR: {
struct cursor *cursor = (struct cursor *)data;
struct pixrect mpr, *mprsave;
struct mpr_data mpr_data, *mpr_datasave;
struct pixrectops *mpr_opssave;
short image[CUR_MAXIMAGEWORDS], *imagesave;
int empty;
/*
* Get user cursor that will copyout to.
*/
if (error = winio_getusercursor(
cursor, &mpr, &mpr_data, image, &empty))
returnerror(error);
if (empty)
returnerror(EINVAL);
/*
* Save the user pointers that are needed as destinations
* of copyouts.
*/
mprsave = cursor->cur_shape;
mpr_datasave = (struct mpr_data *)mpr.pr_data;
mpr_opssave = mpr.pr_ops;
imagesave = mpr_data.md_image;
/*
* Copy cursor info and fixup data pointer.
* (Copyout happens by ioctl mechanism)
*/
/* this if-else will go away when our
* kernel is released and the SETLOCATOR
* and GETLOCATOR code is removed.
*/
if (cmd == WINGETCURSOR) {
cursor->cur_xhot = w->w_cursor.cur_xhot;
cursor->cur_yhot = w->w_cursor.cur_yhot;
cursor->cur_function = w->w_cursor.cur_function;
} else
*cursor = w->w_cursor;
cursor->cur_shape = mprsave;
/*
* Set pixrect info, fixup pointers and copyout.
*/
mpr = w->w_cursormpr;
mpr.pr_data = (caddr_t)mpr_datasave;
mpr.pr_ops = mpr_opssave;
if (error = copyout((caddr_t)&mpr, (caddr_t)mprsave,
sizeof(struct pixrect)))
returnerror(error);
/*
* Set pixrect info, fixup pointers and copyout.
*/
mpr_data = w->w_cursordata;
mpr_data.md_image = imagesave;
if (error = copyout((caddr_t)&mpr_data, (caddr_t)mpr_datasave,
sizeof(struct mpr_data)))
returnerror(error);
/*
* Copyout image.
*/
if (error = copyout((caddr_t)w->w_cursorimage,
(caddr_t)imagesave, CUR_MAXIMAGEBYTES))
returnerror(error);
break;
}
case WINFINDINTERSECT: {
struct winintersect *winintersect = (struct winintersect *)data;
struct window *window;
window = wt_intersected(w, winintersect->wi_x + w->w_screenx,
winintersect->wi_y + w->w_screeny);
wt_windowtonumber(window, &winintersect->wi_link);
break;
}
/*
* Geometry operations.
*/
case WINGETRECT:
*(struct rect *)data = w->w_rect;
break;
case WINSETRECT: {
struct rect *rect = (struct rect *)data;
bool ilocked = FALSE;
struct window *winparent;
if (dtop == NULL) {
w->w_rect = *rect;
break;
}
if (w==dtop->dt_rootwin)
winparent = w;
else
winparent = w->w_link[WL_PARENT];
if (!win_lock_data_locked(dtop->shared_info)) {
if (dtop_lockdata(dev))
goto restart;
ilocked = TRUE;
}
if (wt_isindisplaytree(w))
dtop_invalidateclipping(dtop, winparent, &w->w_rect);
if ((w->w_rect.r_width != rect->r_width) ||
(w->w_rect.r_height != rect->r_height))
w->w_flags |= WF_SIZECHANGED;
if ((w->w_rect.r_left != rect->r_left) ||
(w->w_rect.r_top != rect->r_top))
wt_enumeratechildren(wt_positionchanged, w,
(struct rect *)0);
w->w_rect = *rect;
/*
* Let blanket windows pick up parent's new size.
*/
wt_enumeratechildren(wt_sizechanged, w, (struct rect *)0);
if (wt_isindisplaytree(w))
dtop_invalidateclipping(dtop, winparent, &w->w_rect);
if (ilocked)
wlok_unlock(&dtop->dt_datalock);
break;
}
case WINSETSAVEDRECT:
w->w_rectsaved = *(struct rect *)data;
break;
case WINGETSAVEDRECT:
*(struct rect *)data = w->w_rectsaved;
break;
/*
* Misc operations.
*/
case WINGETUSERFLAGS:
*(int *)data = w->w_userflags;
break;
case WINSETUSERFLAGS:
w->w_userflags = *(int *)data;
break;
case WINGETOWNER: {
struct proc *p = pfind(w->w_pid);
/*
* Return 0 if can't find current owner process
* Can't rely on kill(pid, 0) to tell user if processes
* exists because will say doesn't exist if, say, owner is root.
*/
*(int *)data = (p == 0)? 0: w->w_pid;
break;
}
case WINSETOWNER: {
int pid = *(int *)data;
struct proc *p = pfind(pid);
if (p==0)
returnerror(EINVAL);
w->w_pid = pid;
rl_copy(&w->w_rlexposed, &w->w_rlfixup);
winsignal(w, SIGWINCH);
break;
}
#ifndef PRE_FLAMINGO
case WINGETNOTIFYALL:
*(int *)data = (w->w_flags&WF_NOTIFYALLCHANGES) != 0;
break;
case WINSETNOTIFYALL:
if (*(int *)data)
w->w_flags |= WF_NOTIFYALLCHANGES;
else
w->w_flags &= ~WF_NOTIFYALLCHANGES;
break;
#endif
/*
* Input control.
*/
case WINGETINPUTMASK: {
struct inputmaskdata *inputmaskdata =
(struct inputmaskdata *)data;
inputmaskdata->ims_set = w->w_pickmask;
wt_windowtonumber(w->w_inputnext,
&inputmaskdata->ims_nextwindow);
break;
}
case WINSETINPUTMASK: {
struct inputmaskdata *inputmaskdata =
(struct inputmaskdata *)data;
struct window *windownext;
int flushit = 0;
if (wt_numbertowindow(inputmaskdata->ims_nextwindow,
&windownext) < 0)
returnerror(EINVAL);
/*
* Flush input buffer
* Note: For now flush entire queue if any thing in ims_flush
*/
for (i = 0; i < IM_CODEARRAYSIZE; i++)
if (inputmaskdata->ims_flush.im_inputcode[i] != 0) {
flushit = 1;
break;
}
if (flushit || inputmaskdata->ims_flush.im_flags) {
if (w->w_desktop->dt_sharedq_owner
&& w->w_desktop->dt_sharedq_owner == w) {
w->w_desktop->shared_info->shared_eventq.tail =
w->w_desktop->shared_info->shared_eventq.head;
}
while (getc(&w->w_input) >= 0)
continue;
}
/*
* Set new mask
*/
w->w_pickmask = inputmaskdata->ims_set;
w->w_inputnext = windownext;
break;
}
/*
* Operations applying globally to a screen.
*/
case WINLOCKDATA:
if (dtop_lockdata(dev))
goto restart;
break;
case WINCOMPUTECLIPPING:
if (!win_lock_data_locked(dtop->shared_info))
returnerror(EINVAL);
dtop_computeclipping(dtop, FALSE);
break;
case WINPARTIALREPAIR: {
struct rect *rectok = (struct rect *)data;
if (!win_lock_data_locked(dtop->shared_info))
returnerror(EINVAL);
wt_enumeratechildren(wt_partialrepair, w, rectok);
break;
}
case WINUNLOCKDATA:
wlok_unlock(&dtop->dt_datalock);
break;
case WINGRABIO:
if (ws_lockio(dev))
goto restart;
break;
case WINRELEASEIO:
wlok_unlock(&ws->ws_iolock);
break;
case WINGETDAMAGEDRL:
if (dtop->dt_flags & DTF_MULTI_PLANE_GROUPS &&
!(w->w_flags & WF_PLANE_GROUP_SET))
/*
* Prepare surface for this application because it
* doesn't know how to play multiple planes.
*/
win_prepare_surface(w);
/* Fall through */
case WINGETEXPOSEDRL: {
struct winclip *winclip = (struct winclip *)data;
winclip->wc_clipid = w->w_clippingid;
rect_construct(&winclip->wc_screenrect, w->w_screenx,
w->w_screeny, w->w_rect.r_width, w->w_rect.r_height);
returnerror(wincopyoutrl(
cmd == WINGETDAMAGEDRL ? &w->w_rlfixup : &w->w_rlexposed,
winclip));
}
case WINDONEDAMAGED: {
int userclippingid = *((int *)data);
if (userclippingid==w->w_clippingid) {
rl_free(&w->w_rlfixup);
w->w_flags &= ~WF_PREVIOUSDAMAGED;
}
break;
}
/*
* Colormap sharing mechanism.
*/
case WINSETCMS: {
register struct cmschange *cmschange = (struct cmschange *)data;
register struct window *wmatch;
struct window *dtop_cmsmatch();
int to_offset;
/*
* Cmschange->cc_cms.cms_addr describes the destination
* within the window's colormap segment.
* Always reading from cmschange->cc_map at [0]th slot.
*/
to_offset = cmschange->cc_cms.cms_addr;
cmschange->cc_cms.cms_addr = 0;
if (cmschange->cc_cms.cms_size == 0 ||
(cmschange->cc_map.cm_red == 0 &&
cmschange->cc_map.cm_green == 0 &&
cmschange->cc_map.cm_blue == 0)) {
/*
* Releasing color map segment.
*/
dtop_cmsfree(dtop, w);
/*
* If had semantic that color map addr could change like
* clipping then could retry allocate any CMSHOGs that
* we were not able to allocate in past and notify
* window with sigwinch.
*/
} else {
/*
* If new and existing cms are same then bypass
* allocation phase.
*/
if ((cmschange->cc_cms.cms_size <= w->w_cms.cms_size)&&
(strncmp(cmschange->cc_cms.cms_name,
w->w_cms.cms_name, CMS_NAMESIZE) == 0)) {
if (w->w_flags & WF_CMSHOG) {
goto loadcmshog;
} else {
goto loadcmsstd;
}
}
/*
* Start using a color map segment.
*/
if ((wmatch = dtop_cmsmatch(
dtop, w, &cmschange->cc_cms))) {
/*
* Using an existing color map segment.
* Sanity check: if trying to replace
* the current cms with a smaller sized
* cms, then return error.
*/
if (w->w_cms.cms_size > wmatch->w_cms.cms_size)
returnerror(EINVAL);
w->w_cms = wmatch->w_cms;
w->w_cmap = wmatch->w_cmap;
w->w_cmapdata = wmatch->w_cmapdata;
if (wmatch->w_flags & WF_CMSHOG) {
w->w_flags |= WF_CMSHOG;
goto loadcmshog;
} else {
goto loadcmsstd;
}
} else {
/*
* Free existing cms if not shared.
*/
dtop_cmsfree(dtop, w);
/*
* Try allocating a new color map segment.
*/
w->w_cms = cmschange->cc_cms;
if ((w->w_cms.cms_addr = dtop_cmsalloc(dtop,
(long)w->w_cms.cms_size)) != -1) {
loadcmsstd:
/*
* Allocation succeded. Load std map.
*/
if (error = winioctl_cmapcopy(
&w->w_cms, &dtop->dt_cmap,
to_offset,
&cmschange->cc_cms,
&cmschange->cc_map, 0, copyin)) {
bzero((caddr_t)&w->w_cms,
sizeof (struct colormapseg));
returnerror(error);
}
dtop_stdizecmap(dtop, &dtop->dt_cmap,
w->w_cms.cms_addr,
w->w_cms.cms_size);
} else {
/*
* Allocation failed. Make hog.
*/
w->w_cms.cms_addr = 0;
w->w_cmapdata = dtop_alloccmapdata(dtop,
&w->w_cmap, w->w_cms.cms_size);
if (w->w_cmapdata == 0) {
returnerror(ENXIO);
}
loadcmshog:
if (error = winioctl_cmapcopy(
&w->w_cms, &w->w_cmap, to_offset,
&cmschange->cc_cms,
&cmschange->cc_map, 0, copyin)) {
cms_freecmapdata(w->w_cmapdata,
&w->w_cmap,
w->w_cms.cms_size);
w->w_cmapdata = 0;
bzero((caddr_t)&w->w_cms,
sizeof (struct colormapseg));
returnerror(error);
}
dtop_stdizecmap(dtop, &w->w_cmap,
w->w_cms.cms_addr,
w->w_cms.cms_size);
w->w_flags |= WF_CMSHOG;
}
}
}
if (dtop->dt_cursorwin == w) {
dtop->dt_flags |= DTF_NEWCMAP;
dtop_set_cursor(dtop);
} else if (dtop->dt_cursorwin &&
(strncmp(dtop->dt_cursorwin->w_cms.cms_name,
w->w_cms.cms_name, CMS_NAMESIZE) == 0)) {
/* Case when w is hog and cms is same as cursor win */
dtop->dt_flags |= DTF_NEWCMAP;
dtop_set_cursor(dtop);
} else {
/*
* Update color map with std if not being hogged on
* this desktop and change was to the std map.
*/
if (!(w->w_flags & WF_CMSHOG)) {
if (dtop->dt_cursorwin &&
(dtop->dt_cursorwin->w_flags & WF_CMSHOG))
{}
else
dtop_putcolormap(dtop, dtop->dt_cmsize,
&dtop->dt_cmap);
}
}
win_return_cms(w, &cmschange->cc_cms);
break;
}
case WINGETCMS: {
register struct cmschange *cmschange = (struct cmschange *)data;
int from_offset;
if (cmschange->cc_map.cm_red != 0 &&
cmschange->cc_map.cm_green != 0 &&
cmschange->cc_map.cm_blue != 0) {
/*
* cmschange->cc_cms.cms_size is the count of the
* section of the color map wanted.
*/
if (cmschange->cc_cms.cms_size > w->w_cms.cms_size)
returnerror(EINVAL);
/*
* Cmschange->cc_cms.cms_addr describes the source
* within the window's colormap segment.
* Always loading into cmschange->cc_map at [0]th slot.
*/
from_offset = cmschange->cc_cms.cms_addr;
cmschange->cc_cms.cms_addr = 0;
if (w->w_flags & WF_CMSHOG)
error = winioctl_cmapcopy(
&cmschange->cc_cms, &cmschange->cc_map, 0,
&w->w_cms, &w->w_cmap, from_offset,
copyout);
else
error = winioctl_cmapcopy(
&cmschange->cc_cms, &cmschange->cc_map, 0,
&w->w_cms, &dtop->dt_cmap, from_offset,
copyout);
if (error)
returnerror(error);
}
win_return_cms(w, &cmschange->cc_cms);
break;
}
case WINSETPLANEGROUP: {
int new_plane_group = *(int *)data;
/* Validate plane group */
if (new_plane_group >= DTOP_MAX_PLANE_GROUPS ||
dtop->dt_plane_groups_available[new_plane_group] == 0)
returnerror(EINVAL);
if (w->w_plane_group != new_plane_group) {
w->w_plane_group = new_plane_group;
/* Potentially new colormap usage (hog vs std) */
if (dtop->dt_cursorwin == w) {
dtop->dt_flags |= DTF_NEWCMAP;
dtop_set_cursor(dtop);
}
/*
* Replace cursor if up because it will be in another
* plane group. Do it now incase client is counting
* on cursor state.
*/
if ((dtop->dt_cursorwin == w) &&
(!(dtop->dt_plane_groups_available[PIXPG_CURSOR]))) {
dtop_cursordown(dtop);
/* update the shared cusor */
win_shared_update_cursor(dtop);
dtop_cursorup(dtop);
}
}
/* Notice that window owner knows about plane groups */
w->w_flags |= WF_PLANE_GROUP_SET;
break;
}
case WINGETPLANEGROUP:
*(int *)data = w->w_plane_group;
break;
case WINGETAVAILPLANEGROUPS:
bcopy((caddr_t)dtop->dt_plane_groups_available,
(caddr_t)((struct win_plane_groups_available
*)data)->plane_groups_available,
WIN_MAX_PLANE_GROUPS);
break;
/*
* Screen creation, inquiry and deletion.
*/
case WINSCREENNEW: {
struct usrdesktop *udtop = (struct usrdesktop *)data;
register Desktop *dt;
dtop = NULL;
/* Allocate an unused desktop */
for (dt = desktops; dt < &desktops[ndesktops]; dt++) {
if (!dtop && !(dt->dt_flags&DTF_PRESENT))
dtop = dt;
if (dt->dt_screen.scr_fbname[0] != '\0' &&
(strncmp(udtop->udt_scr.scr_fbname,
dt->dt_screen.scr_fbname, SCR_NAMESIZE) == 0))
returnerror(EBUSY);
}
if (!dtop || dtop->dt_rootwin)
returnerror(EBUSY);
/* Check window that is to become root for cleanliness */
if ((w->w_flags & WF_INSTALLED) ||
w->w_link[WL_OLDERSIB] || w->w_link[WL_YOUNGERSIB] ||
wt_badchildren(w)) {
returnerror(EINVAL);
}
/*
* Set up w and rootwin now so that dtop_close gets called
* if encounter error during opening of dtop.
*/
dtop->dt_rootwin = w;
dtop->dt_exit_seconds = 0;
w->w_desktop = dtop;
w->w_flags |= WF_ROOTWINDOW;
/* Initialize cursor data. */
dtopcursorfixup(&dtop->dt_cursor);
/* Copy screen. */
dtop->dt_screen = udtop->udt_scr;
/* Open frame buffer. */
if (error = dtop_openfb(dtop, udtop->udt_fbfd)) {
returnerror(error);
}
/* Initialize root windows plane group */
win_pick_plane_group(dtop, w);
/* Initialize root window's rect. */
w->w_rect = dtop->dt_screen.scr_rect;
/* Set cursor in middle of screen */
dtop->dt_rt_x = dtop->dt_ut_x = dtop->dt_screen.scr_rect.r_left+
(dtop->dt_screen.scr_rect.r_width/2);
dtop->dt_rt_y = dtop->dt_ut_y = dtop->dt_screen.scr_rect.r_top+
(dtop->dt_screen.scr_rect.r_height/2);
/*
* Update the shared memory mouse x, y
*/
win_shared_update_mouse_xy(dtop->shared_info,
dtop->dt_rt_x, dtop->dt_rt_y);
/*
* Install on desktop so that if input turn on fails then
* dtop_close will clean up.
*/
w->w_flags |= WF_INSTALLED;
dtop->dt_flags |= DTF_PRESENT;
/*
* See if input devices that window wants to use are in service.
* If so then use that workstation else open a new one.
*/
if ((ws = ws_indev_match_name(udtop->udt_scr.scr_kbdname,
(Wsindev **)0)) != WORKSTATION_NULL)
goto UseWs;
if ((ws = ws_indev_match_name(udtop->udt_scr.scr_msname,
(Wsindev **)0)) != WORKSTATION_NULL)
goto UseWs;
/* Open new workstation */
if ((ws = ws_open()) == WORKSTATION_NULL)
returnerror(EBUSY);
/* Place locator on first dtop */
ws->ws_loc_dtop = dtop;
win_shared_update_cursor_active(dtop->shared_info, TRUE);
ws->ws_pick_dtop = dtop;
/* Initialize restricted plane groups */
if (dtop->dt_screen.scr_flags & SCR_8BITCOLORONLY ||
dtop->dt_screen.scr_flags & SCR_OVERLAYONLY)
dtop_update_enable(dtop, DESKTOP_NULL, 1);
UseWs:
/*
* Install desktop with workstation so that if input open
* fails then ws_close will clean up.
*/
dtop->dt_next = ws->ws_dtop;
ws->ws_dtop = dtop;
dtop->dt_ws = ws;
w->w_ws = ws;
/* Invalidate clipping so that SIGWINCH generated */
dtop_invalidateclipping(dtop, w, &w->w_rect);
/* Open kbd & ms input devices if not already open */
if ((udtop->udt_scr.scr_kbdname[0] != NULL) &&
(ws_indev_match_name(udtop->udt_scr.scr_kbdname,
(Wsindev **)0) == WORKSTATION_NULL)) {
if (ws_open_indev(ws, udtop->udt_scr.scr_kbdname,
udtop->udt_kbdfd) == WSINDEV_NULL)
returnerror(u.u_error);
}
if ((udtop->udt_scr.scr_msname[0] != NULL) &&
(ws_indev_match_name(udtop->udt_scr.scr_msname,
(Wsindev **)0) == WORKSTATION_NULL)) {
if (ws_open_indev(ws, udtop->udt_scr.scr_msname,
udtop->udt_msfd) == WSINDEV_NULL)
returnerror(u.u_error);
}
/* Set focuses and cursor window */
ws_set_focus(ws, FF_PICK_CHANGE);
dtop_set_cursor(dtop);
break;
}
case WINSCREENGET:
*(struct screen *)data = dtop->dt_screen;
break;
case WINSCREENDESTROY: {
extern int hz;
int win_check_destroy();
int wnum;
Window *w_probe;
/* Don't let any other processes install on dtop */
dtop->dt_flags |= DTF_EXITING;
/* Stop reading input if workstation going away */
if ((ws->ws_dtop == dtop) && (dtop->dt_next == DESKTOP_NULL))
ws->ws_flags |= WSF_EXITING;
/* Tell everyone, other than the caller, to terminate */
winpsnotkill = u.u_procp->p_pid;
wt_enumeratechildren(winkill, dtop->dt_rootwin,
(struct rect *)0);
winpsnotkill = 0;
/* Setup timeout to do wakeup for following wait */
timeout(win_check_destroy, (caddr_t)dtop, hz);
/* Wait for all children of root to go away */
while ((dtop->dt_flags & DTF_PRESENT) &&
(dtop->dt_exit_seconds < win_exit_seconds) &&
(dtop->dt_rootwin != WINDOW_NULL) &&
(dtop->dt_rootwin->w_link[WL_OLDESTCHILD] != WINDOW_NULL) &&
(dtop->dt_rootwin->w_link[WL_YOUNGESTCHILD] != WINDOW_NULL)) {
(void) sleep((caddr_t)&dtop->dt_flags, LOCKPRI);
if (dtop->dt_exit_seconds > 300 && print_waiting) {
printf("Waiting for tools to terminate...\n");
print_waiting = FALSE;
} else {
if (dtop->dt_exit_seconds > 700 &&
print_still_waiting) {
printf("Still waiting...\n");
print_still_waiting = FALSE;
}
}
}
/* Kill processes that wouldn't go away */
if (dtop->dt_flags & DTF_PRESENT) {
/* Look for any window that is connected to dtop */
for (wnum = 0; wnum < win_nwindows; wnum++) {
w_probe = winbufs[wnum];
if ((w_probe != WINDOW_NULL) &&
(w_probe->w_flags & WF_OPEN) &&
(w_probe->w_desktop == dtop) &&
(w_probe->w_pid != u.u_procp->p_pid))
winsignal(w_probe, SIGKILL);
}
}
/* Calling process is responsible for cleaning self up */
print_waiting = TRUE;
print_still_waiting = TRUE;
break;
}
case WINSCREENPOSITIONS: {
int *neighbors = (int *)data;
struct window *window;
for (i = 0; i < SCR_POSITIONS; i++) {
if (neighbors[i] == WIN_NULLLINK) {
dtop->dt_neighbors[i] = NULL;
continue;
}
if (wt_numbertowindow(neighbors[i], &window) < 0)
returnerror(EINVAL);
dtop->dt_neighbors[i] = window->w_desktop;
}
break;
}
case WINGETSCREENPOSITIONS: {
int *neighbors = (int *)data;
for (i = 0; i < SCR_POSITIONS; i++) {
if (dtop->dt_neighbors[i] == NULL) {
neighbors[i] = WIN_NULLLINK;
continue;
}
wt_windowtonumber(dtop->dt_neighbors[i]->dt_rootwin,
&neighbors[i]);
}
break;
}
case WINSETKBD: {
struct usrdesktop *udtop = (struct usrdesktop *)data;
/* Open kbd input device if not already open */
if ((udtop->udt_scr.scr_kbdname[0] != NULL) &&
(ws_indev_match_name(udtop->udt_scr.scr_kbdname,
(Wsindev **)0) == WORKSTATION_NULL)) {
if (ws_open_indev(ws, udtop->udt_scr.scr_kbdname,
udtop->udt_kbdfd) == WSINDEV_NULL)
returnerror(u.u_error);
}
break;
}
case WINSETMS: {
struct usrdesktop *udtop = (struct usrdesktop *)data;
/* Open ms input device if not already open */
if ((udtop->udt_scr.scr_msname[0] != NULL) &&
(ws_indev_match_name(udtop->udt_scr.scr_msname,
(Wsindev **)0) == WORKSTATION_NULL)) {
if (ws_open_indev(ws, udtop->udt_scr.scr_msname,
udtop->udt_msfd) == WSINDEV_NULL)
returnerror(u.u_error);
}
break;
}
case WINSETINPUTDEV: {
struct input_device *ind = (struct input_device *)data;
Wsindev *indev;
if (ind->id == -1) {
/* See if given device in open */
if ((ind->name[0] != NULL) &&
(ws_indev_match_name(ind->name, &indev) !=
WORKSTATION_NULL)) {
/* Close given device */
(void) ws_close_indev(ws, indev);
}
} else {
/* Open input device if not already open */
if ((ind->name[0] != NULL) &&
(ws_indev_match_name(ind->name,
(Wsindev **)0) == WORKSTATION_NULL)) {
if (ws_open_indev(ws, ind->name, ind->id) ==
WSINDEV_NULL)
returnerror(u.u_error);
}
}
break;
}
case WINGETINPUTDEV: {
struct input_device *ind = (struct input_device *)data;
int n;
Wsindev *indev;
if (ind->id == -1) {
/* See if given device in open */
if ((ind->name[0] != NULL) &&
(ws_indev_match_name(ind->name, &indev) !=
WORKSTATION_NULL)) {
returnerror (0);
} else {
returnerror (ENODEV);
}
} else {
/* Get given numbered device */
for (indev = ws->ws_indev, n = 0; indev != WSINDEV_NULL;
indev = indev->wsid_next, n++) {
if (n == ind->id) {
for (i = 0;i < SCR_NAMESIZE; i++)
ind->name[i] = indev->wsid_name[i];
returnerror (0);
}
}
returnerror (ENODEV);
}
/* NOTREACHED */
}
case WINGETKBDMASK: {
struct inputmask *im = (struct inputmask *)data;
*im = w->w_kbdmask;
break;
}
case WINGETPICKMASK: {
struct inputmask *im = (struct inputmask *)data;
*im = w->w_pickmask;
break;
}
case WINSETKBDMASK: {
struct inputmask *im = (struct inputmask *)data;
w->w_kbdmask = *im;
w->w_flags |= WF_KBD_MASK_SET;
break;
}
case WINSETPICKMASK: {
struct inputmask *im = (struct inputmask *)data;
w->w_pickmask = *im;
break;
}
case WINSETNEXTINPUT: {
struct window *windownext;
if (wt_numbertowindow(*(int *)data, &windownext) < 0)
returnerror(EINVAL);
w->w_inputnext = windownext;
break;
}
case WINGETNEXTINPUT:
wt_windowtonumber(w->w_inputnext, (int *)data);
break;
case WINGETBUTTONORDER:
*(u_int *)data = ws_button_order;
break;
case WINSETBUTTONORDER:
if (*(u_int *)data > 5) {
returnerror(EINVAL);
} else {
ws_button_order = *(u_int *)data;
}
break;
case WINGETSCALING: {
register Ws_scale *buffer = (Ws_scale *)data;
register Ws_scale *scales = ws_scaling;
register int count;
for (count = 0; count < WS_SCALE_MAX_COUNT; count++) {
*buffer++ = *scales;
if (scales->ceiling == WS_SCALE_MAX_CEILING)
break;
scales++;
}
break;
}
case WINSETSCALING: {
register Ws_scale *buffer = (Ws_scale *)data;
register Ws_scale *scales = ws_scaling;
register int count;
for (count = 0; count < WS_SCALE_MAX_COUNT; count++) {
*scales = *buffer++;
if (scales->ceiling == WS_SCALE_MAX_CEILING)
break;
scales++;
}
if (count == WS_SCALE_MAX_COUNT) {
scales->ceiling = WS_SCALE_MAX_CEILING;
scales->factor = 1;
}
break;
}
case WINGETVUIDVALUE: {
Firm_event *fe = (Firm_event *)data;
switch (fe->id) {
case LOC_X_ABSOLUTE:
fe->value = dtop->dt_ut_x - w->w_screenx;
break;
case LOC_Y_ABSOLUTE:
fe->value = dtop->dt_ut_y - w->w_screeny;
break;
default:
fe->value = vuid_get_value(ws->ws_instate, fe->id);
}
break;
}
case WINGETFOCUSEVENT: {
Focus_event *foe = ((Focus_event *)data);
foe->id = ws->ws_kbd_focus_pt.id;
foe->value = ws->ws_kbd_focus_pt.value;
foe->shifts = ws->ws_kbd_focus_pt.shifts;
break;
}
case WINSETFOCUSEVENT: {
Focus_event *foe = ((Focus_event *)data);
ws->ws_kbd_focus_pt.id = foe->id;
ws->ws_kbd_focus_pt.value = foe->value;
ws->ws_kbd_focus_pt.shifts = foe->shifts;
break;
}
case WINGETSWALLOWEVENT: {
Focus_event *foe = ((Focus_event *)data);
foe->id = ws->ws_kbd_focus_sw.id;
foe->value = ws->ws_kbd_focus_sw.value;
foe->shifts = ws->ws_kbd_focus_sw.shifts;
break;
}
case WINSETSWALLOWEVENT: {
Focus_event *foe = ((Focus_event *)data);
ws->ws_kbd_focus_sw.id = foe->id;
ws->ws_kbd_focus_sw.value = foe->value;
ws->ws_kbd_focus_sw.shifts = foe->shifts;
break;
}
case WINSETKBDFOCUS: {
Window *windowfocus;
if (wt_numbertowindow(*(int *)data, &windowfocus) < 0)
returnerror(EINVAL);
/* Update kbd focus */
if ((ws->ws_kbdfocus_next != windowfocus) &&
((ws->ws_kbd_focus_sw.id != LOC_WINENTER) ||
(ws->ws_kbd_focus_pt.id != LOC_WINENTER))) {
ws->ws_kbdfocus_next = windowfocus;
ws->ws_flags |= WSF_SWALLOW_FOCUS_EVENT;
/*
* Send directly unless in middle of focus change
* sequence, then will catch the request next
* time get to SEND_Q_TOP.
*/
if (ws->ws_focus_state == SEND_Q_TOP)
ws->ws_focus_state = SEND_DIRECT_REQUEST;
}
break;
}
case WINGETKBDFOCUS: {
int winnumber;
wt_windowtonumber(ws->ws_kbdfocus, &winnumber);
*(int *)data = winnumber;
break;
}
case WINGETEVENTTIMEOUT: {
struct timeval *tv = (struct timeval *)data;
*tv = ws->ws_eventtimeout;
break;
}
case WINSETEVENTTIMEOUT: {
struct timeval *tv = (struct timeval *)data;
ws->ws_eventtimeout = *tv;
break;
}
case WINUNLOCKEVENT:
/*
* Explicitly check that w is lock holder because some parameter
* configurations (ws_eventtimeout == 0,0) cause the event
* lock to be very loosely acquired and released. Thus, we
* don't want to accidently release another window's lock.
*/
if ((ws->ws_flags & WSF_LOCKED_EVENT) &&
(ws->ws_event_consumer == w))
wlok_forceunlock(&ws->ws_eventlock);
break;
case WINREFUSEKBDFOCUS:
/*
* Turning off the WSF_KBD_REQUEST_PENDING flag says to
* not give ws_kbdfocus_next the kbd focus.
*/
ws->ws_flags &= ~WSF_KBD_REQUEST_PENDING;
break;
case WINDBLACCESS:
/*
* Turnon the WF_DBL_ACCESS flag. If this was the first
* Double bufferer, pick background to be PR_DBL_A (arbitrary)
*/
if ((dtop->dt_flags & DTF_DBLBUFFER ) &&
!(w->w_flags & WF_DBLBUF_ACCESS)) {
w->w_flags |= WF_DBLBUF_ACCESS;
if ( dtop->dt_dblcount == 0 ) {
dtop->dt_curdbl = w;
dtop->shared_info->go_to_kernel = 1;
w->w_dbl_rdstate = PW_DBL_BACK;
w->w_dbl_wrstate = PW_DBL_BACK;
/*
* Increment the count only after
* taking down the cursor and redrawing it in
* the foreground.
*/
dtop_changedisplay(dtop, PR_DBL_A,
PR_DBL_B, TRUE);
}
else dtop->dt_dblcount++;
}
break;
case WINDBLRLSE:
/*
* Release the double buffer and if there is any
* other double bufferer choose it.
*/
if (( dtop->dt_flags & DTF_DBLBUFFER ) &&
(w->w_flags & WF_DBLBUF_ACCESS)) {
dtop_copy_dblbuffer(dtop, w);
w->w_flags &= ~WF_DBLBUF_ACCESS;
w->w_dbl_wrstate = PW_DBL_BOTH;
w->w_dbl_rdstate = PW_DBL_BACK;
if (--dtop->dt_dblcount == 0) {
dtop->shared_info->go_to_kernel = 0;
if (pr_dbl_set(dtop->dt_pixrect,
PR_DBL_READ, w->w_dbl_rdstate,
PR_DBL_WRITE, w->w_dbl_wrstate,
0))
#ifdef WINDEVDEBUG
printf("Error in WINDRLSE\n");
#else
;
#endif
dtop->dt_curdbl = WINDOW_NULL;
}
else dtop_choose_dblbuf(dtop);
}
break;
case WINDBLFLIP:
/*
* Flip the display and choose another double bufferer
* (dt_curdbl field in the dtop struct) if the cursor is
* not in the current bufferer.
*/
if (dtop->dt_flags & DTF_DBLBUFFER)
dtop_flip_display(dtop, w);
break;
case WINDBLSET: {
/*
* Set display, write or read control bits. Converts
* Values like PW_DBL_FORE, PW_DBL_BACK to PR_DBL_A
* or PR_DBL_B. (Allowed only when the window is the current
* double bufferer).
*/
register struct pwset *list = (struct pwset *)data;
if (!dtop->dt_dblcount)
break;
/* Keep track of what the read/write setting is */
if (list->attribute == PR_DBL_WRITE)
w->w_dbl_wrstate = list->value;
else if (list->attribute == PR_DBL_READ)
w->w_dbl_rdstate = list->value;
if ((dtop->dt_flags & DTF_DBLBUFFER) &&
((w == dtop->dt_curdbl) || (dtop->dt_displaygrabber == w))){
int value;
if (list->value == PW_DBL_BOTH)
value = PR_DBL_BOTH;
else if (list->value == PW_DBL_FORE)
value = dtop->dt_dbl_frgnd;
else if (list->value == PW_DBL_BACK)
value = dtop->dt_dbl_bkgnd;
else returnerror(0);
if (pr_dbl_set(dtop->dt_pixrect, list->attribute,
value, 0))
#ifdef WINDEVDEBUG
printf("error in ioctl SET for dbl_set\n");
#else
;
#endif
}
break;
}
case WINDBLGET: {
register struct pwset *list = (struct pwset *)data;
if (dtop->dt_flags & DTF_DBLBUFFER ) {
if (list->attribute == PR_DBL_AVAIL)
list->value = TRUE;
else if (list->attribute == PR_DBL_READ )
list->value = w->w_dbl_rdstate;
else if (list->attribute == PR_DBL_WRITE)
list->value = w->w_dbl_wrstate;
else list->value = PW_DBL_ERROR; /* Error ? */
}
else list->value = FALSE;
break;
}
case WINDBLCURRENT:{
/*
* Returns the rect of the dbl bufferer in relation to the
* current pixwin
*/
register struct rect *rectobj = (struct rect *)data;
if (dtop->dt_curdbl && dtop == dtop->dt_curdbl->w_desktop){
rectobj->r_left = dtop->dt_curdbl->w_screenx - w->w_screenx;
rectobj->r_top = dtop->dt_curdbl->w_screeny - w->w_screeny;
rectobj->r_width = dtop->dt_curdbl->w_rect.r_width;
rectobj->r_height = dtop->dt_curdbl->w_rect.r_height;
}
break;
}
case WINWIDSET:
w->w_wid_dbl_info = *(struct fb_wid_dbl_info *) data;
break;
case WINWIDGET:
*(struct fb_wid_dbl_info *) data = w->w_wid_dbl_info;
break;
case WINSHAREQUEUE:
if (dtop->dt_sharedq_owner) {
returnerror(EADDRINUSE);
} else if (dtop->shared_info->shared_eventq.size <= 0) {
returnerror(0);
} else {
dtop->dt_sharedq_owner = w;
}
break;
case WINCLEARCURSORPLANES:
{
register struct rect *rectobj = (struct rect *)data;
if ((dtop->dt_plane_groups_available[PIXPG_CURSOR])
&& (dtop->dt_plane_groups_available[PIXPG_CURSOR_ENABLE])) {
win_clear_cursor_plane_groups(w, rectobj);
}
break;
}
/*
* Record/playback utilities
*/
#ifdef WINSVJ
case WINSETRECQUE:
case WINSETRECORD:
case WINREADRECQ:
case WINSETPLAYBACK:
case WINSETPLAYINTR:
case WINSETSYNCPT:
error = svjioctl(dev, (int) cmd, data, dtop, ws, pri, error);
win_playrec_sync_flg = 0;
break;
#endif
default:
returnerror(ENOTTY); /* Note: ?? */
}
done:
if (always_signal) {
/*
* Clear go_to_kernel field.
*/
if (winnotify_inorder) {
if (dtop && dtop->shared_info)
dtop->shared_info->go_to_kernel = 0;
wt_sigwnch_nextwin(); /* notify next window */
}
}
#ifdef WINSVJ
if (((ws != NULL) && (ws->ws_flags&WSF_RECORD_QUEUE)) &&
(win_playrec_sync_flg))
(void) svjioctl(dev, (int) cmd, data, dtop, ws, pri, error);
#endif
(void) splx(pri);
return (error);
restart:
u.u_eosys = RESTARTSYS;
returnerror(EINTR);
}
static void
win_return_cms(w, cms)
register Window *w;
struct colormapseg *cms;
{
*cms = w->w_cms;
/*
* Adjust addr if window is in the overlay plane.
* Note: This is a hack to get around the fact that
* we haven't provided a separate colormap allocation
* mechanism for each plane group. We are allocating
* from a single colormap instead. If this situation
* is fixed in a future release then the following
* code could be removed.
*/
if (w->w_plane_group == PIXPG_OVERLAY ||
(w->w_desktop->dt_flags & DTF_MULTI_PLANE_GROUPS &&
!(w->w_flags & WF_PLANE_GROUP_SET)))
cms->cms_addr = 0;
}
static void
win_pick_plane_group(dtop, w)
Desktop *dtop;
Window *w;
{
if (dtop->dt_pixrect) {
if (!(w->w_flags & WF_PLANE_GROUP_SET)) {
w->w_plane_group = pr_get_plane_group(dtop->dt_pixrect);
}
}
}
/*ARGSUSED*/
wt_sizechanged(window, rectnotused)
register struct window *window;
struct rect *rectnotused;
{
register struct window *winparent = window->w_link[WL_PARENT];
struct rect rect;
/*
* Blanket windows should stay the same size as their parents.
*/
if ((window->w_userflags & WUF_BLANKET) && (winparent)) {
/*
* Construct rect of what blanket window should be.
*/
rect_construct(&rect, 0, 0,
winparent->w_rect.r_width,
winparent->w_rect.r_height);
/*
* Change only if different.
*/
if (!rect_equal(&rect, &window->w_rect)) {
window->w_rect = rect;
window->w_flags |= WF_SIZECHANGED;
}
}
}
wincopyoutrl(rl, winclip)
register struct rectlist *rl;
register struct winclip *winclip;
{
int bytesneeded;
register struct rectnode *rn;
struct rectlist rluser;
caddr_t ptuser;
bytesneeded = sizeof (struct rectlist);
for (rn = rl->rl_head; rn; rn = rn->rn_next)
bytesneeded += sizeof (struct rectnode);
if (bytesneeded > winclip->wc_blockbytes) {
winclip->wc_blockbytes = bytesneeded;
return (EFBIG);
}
rluser = *rl;
ptuser = (caddr_t)(winclip->wc_block + sizeof (struct rectlist));
if (rl->rl_head != NULL)
rluser.rl_head = (struct rectnode *)ptuser;
for (rn = rl->rl_head; rn; rn = rn->rn_next) {
struct rectnode rnuser;
rnuser = *rn;
if (rn->rn_next)
rnuser.rn_next = (struct rectnode *)
(ptuser + sizeof (struct rectnode));
if (copyout((char *)&rnuser, ptuser, sizeof (struct rectnode)))
return (EFAULT);
if (rn == rl->rl_tail)
rluser.rl_tail = (struct rectnode *)ptuser;
ptuser += sizeof (struct rectnode);
}
if (copyout((caddr_t)&rluser, (caddr_t)winclip->wc_block,
sizeof (struct rectlist)))
return (EFAULT);
return (0);
}
static int
check_crosshair_info(cursor)
register struct cursor *cursor;
{
if ((cursor->horiz_hair_thickness < 0) ||
(cursor->horiz_hair_thickness > CURSOR_MAX_HAIR_THICKNESS))
return (EINVAL);
if ((cursor->vert_hair_thickness < 0) ||
(cursor->vert_hair_thickness > CURSOR_MAX_HAIR_THICKNESS))
return (EINVAL);
return (0);
}
winio_getusercursor(cursor, mpr, mpr_data, image, empty)
register struct cursor *cursor;
register struct pixrect *mpr;
struct mpr_data *mpr_data;
short *image;
int *empty;
{
int error, imagesize;
*empty = 1;
if (!cursor->cur_shape)
return (0);
if (error = copyin((caddr_t)cursor->cur_shape,
(caddr_t)mpr, sizeof(struct pixrect)))
return (error);
if (!mpr->pr_data)
return (0);
if (error = copyin((caddr_t)mpr->pr_data,
(caddr_t)mpr_data, sizeof(struct mpr_data)))
return (error);
if (!mpr_data->md_image)
return (0);
imagesize = mpr_data->md_linebytes * mpr->pr_height;
if (imagesize > CUR_MAXIMAGEBYTES)
return (E2BIG);
bzero((caddr_t) image, CUR_MAXIMAGEBYTES);
if (error = copyin((caddr_t)mpr_data->md_image,
(caddr_t)image, (u_int) imagesize))
return (error);
*empty = 0;
return (0);
}
winioctl_cmapcopy(cmsto, cmapto, offsetto, cmsfrom, cmapfrom, offsetfrom, func)
register struct colormapseg *cmsto, *cmsfrom;
register struct cms_map *cmapto, *cmapfrom;
int (*func)(), offsetto, offsetfrom;
{
register int firstto = cmsto->cms_addr+offsetto;
register int firstfrom = cmsfrom->cms_addr+offsetfrom;
register int n;
int lastto = firstto+cmsto->cms_size-1;
int lastfrom = firstfrom+cmsfrom->cms_size-1;
/*
* Test to see that source and destination data is consistent with self.
*/
if (firstto > lastto || firstto < 0 ||
firstfrom > lastfrom || firstfrom < 0 ||
!cmapto->cm_red || !cmapto->cm_green || !cmapto->cm_blue ||
!cmapfrom->cm_red || !cmapfrom->cm_green || !cmapfrom->cm_blue)
return (EINVAL);
/*
* Limit range so that destination not overrun.
*/
n = ((firstto+cmsfrom->cms_size-1) > lastto) ?
lastto-firstto+1 : cmsfrom->cms_size;
/*
* Move data.
*/
if ((*func)(&(cmapfrom->cm_red[firstfrom]),
&(cmapto->cm_red[firstto]), n) ||
(*func)(&(cmapfrom->cm_green[firstfrom]),
&(cmapto->cm_green[firstto]), n) ||
(*func)(&(cmapfrom->cm_blue[firstfrom]),
&(cmapto->cm_blue[firstto]), n))
return (EFAULT);
return (0);
}
win_check_destroy(data)
caddr_t data;
{
register Desktop *dtop = (Desktop *)data;
extern int hz;
/* Wakeup destroy even if desktop not present */
wakeup((caddr_t)&dtop->dt_flags);
if (dtop->dt_flags & DTF_PRESENT) {
dtop->dt_exit_seconds++;
timeout(win_check_destroy, (caddr_t)dtop, hz);
}
}
static int
wt_gettreelayer(parent, data)
register Window *parent;
register Win_tree_layer *data;
{
register Window *w;
register Win_enum_node *nodep;
register int size;
int installed, uninstalled;
int w_num;
if (parent == WINDOW_NULL)
return EINVAL;
wt_count_layer(parent, &installed, &uninstalled);
size = (installed + uninstalled) * sizeof (struct win_enum_node);
if (data->bytecount < size) {
data->bytecount -= size;
return EFBIG;
} else
data->bytecount = size;
nodep = data->buffer;
w = parent->w_link[WL_OLDESTCHILD];
while (w != WINDOW_NULL) {
wt_copy_layer_node(w, nodep++);
w = w->w_link[WL_YOUNGERSIB];
}
for (w_num = 0; w = winfromopendev(w_num); w_num++) {
if (w->w_link[WL_PARENT] == parent &&
!(w->w_flags & WF_INSTALLED))
wt_copy_layer_node(w, nodep++);
}
return 0;
}
static void
wt_copy_layer_node(w, nodep)
register Window *w;
register Win_enum_node *nodep;
{
int w_num;
Win_enum_node node;
wt_windowtonumber(w, &w_num);
node.me = w_num;
wt_windowtonumber(w->w_link[WL_PARENT], &w_num);
node.parent = w_num;
wt_windowtonumber(w->w_link[WL_YOUNGERSIB], &w_num);
node.upper_sib = w_num;
wt_windowtonumber(w->w_link[WL_OLDESTCHILD], &w_num);
node.lowest_kid = w_num;
if (w->w_flags & WF_INSTALLED)
node.flags = WIN_NODE_INSERTED;
else
node.flags = 0;
if (w->w_userflags & WUF_WMGR1) { /* iconic */
node.icon_rect = w->w_rect;
node.open_rect = w->w_rectsaved;
} else { /* open */
node.flags |= WIN_NODE_OPEN;
node.open_rect = w->w_rect;
node.icon_rect = w->w_rectsaved;
}
(void) copyout((caddr_t)&node, (caddr_t)nodep,
sizeof (struct win_enum_node));
}
static void
wt_count_layer(parent, in, out)
register Window *parent;
register int *in, *out;
{
/* register */ int i;
register Window *w;
*in = 0;
*out = 0;
for (i = 0; w = winfromopendev(i); i++) {
if (w->w_link[WL_PARENT] == parent) {
if (w->w_flags & WF_INSTALLED) {
*in += 1;
} else {
*out += 1;
}
}
}
}
static void
win_prepare_surface(w)
register Window *w;
{
register Desktop *dtop = w->w_desktop;
/* See if anything to do */
if (rl_empty(&w->w_rlfixup))
/* Assumes no side affects from calling this routine */
return;
/* Dont take the cursor down if there are cursor planes */
if ((dtop->dt_cursorwin == w) &&
(!dtop->dt_plane_groups_available[PIXPG_CURSOR]))
dtop_cursordown(dtop);
if (dtop->dt_plane_groups_available[PIXPG_OVERLAY_ENABLE]) {
/* NOTE: ADD HERE AS NEW ENABLE PLANES BECOME AVAILABLE */
/* Enable black and white overlay enable plane */
win_initialize_plane_group(w, PIXPG_OVERLAY_ENABLE, 1);
#ifndef PRE_FLAMINGO
/* Disable video if available */
if (dtop->dt_plane_groups_available[PIXPG_VIDEO_ENABLE])
win_initialize_plane_group(w, PIXPG_VIDEO_ENABLE, 0);
#endif
/* Clear color plane group (for tidiness) */
if (dtop->dt_plane_groups_available[PIXPG_8BIT_COLOR])
win_initialize_plane_group(w, PIXPG_8BIT_COLOR, 0);
else if (dtop->dt_plane_groups_available[PIXPG_24BIT_COLOR])
win_initialize_plane_group(w, PIXPG_24BIT_COLOR, 0);
}
if (dtop->dt_plane_groups_available[PIXPG_CURSOR_ENABLE]) {
win_initialize_plane_group(w, PIXPG_CURSOR_ENABLE, 0);
/* Color planes for tidines*/
if (dtop->dt_plane_groups_available[PIXPG_8BIT_COLOR])
win_initialize_plane_group(w, PIXPG_8BIT_COLOR, 0);
else if (dtop->dt_plane_groups_available[PIXPG_24BIT_COLOR])
win_initialize_plane_group(w, PIXPG_24BIT_COLOR, 0);
}
if ((dtop->dt_cursorwin == w) &&
(!(dtop->dt_plane_groups_available[PIXPG_CURSOR])))
dtop_cursordown(dtop);
}
static void
win_initialize_plane_group(w, plane_group, color)
Window *w;
int plane_group;
int color;
{
int plane_group_save;
register struct pixrect *pr = w->w_desktop->dt_pixrect;
/* Remember original plane group (the planes should be full) */
plane_group_save = pr_get_plane_group(pr);
/* Set plane group */
pr_set_plane_group(pr, plane_group);
/* Set planes to enable writing offset, effectively clears */
(void) dtop_rl_rop(pr, -w->w_screenx, -w->w_screeny, &w->w_rlfixup,
PIX_COLOR(color)|PIX_SRC|PIX_DONTCLIP, (struct pixrect *)0, 0, 0);
/* Reset plane group */
pr_set_plane_group(pr, plane_group_save);
}
static void
win_clear_cursor_plane_groups(w, rect)
Window *w;
struct rect *rect;
{
int plane_group_save;
register struct pixrect *pr = w->w_desktop->dt_pixrect;
/* Remember original plane group (the planes should be full) */
plane_group_save = pr_get_plane_group(pr);
pr_set_plane_group(pr, PIXPG_CURSOR_ENABLE);
(void) pr_rop(pr, rect->r_left, rect->r_top,rect->r_width,
rect->r_height, PIX_CLR|PIX_DONTCLIP, (struct pixrect *)0, 0, 0);
pr_set_plane_group(pr, PIXPG_CURSOR);
(void) pr_rop(pr, rect->r_left, rect->r_top,rect->r_width,
rect->r_height, PIX_CLR|PIX_DONTCLIP, (struct pixrect *)0, 0, 0);
/* Reset plane group */
pr_set_plane_group(pr, plane_group_save);
}