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

1060 lines
27 KiB
C

#ifndef lint
static char sccsid[] = "@(#)win.c 1.1 94/10/31 SMI";
#endif
/*
* Copyright (c) 1988 by Sun Microsystems, Inc.
*/
/*
* SunWindows routines that deal with the UNIX device nature of the driver,
* i.e., open, close, read, select. ioctls handled in winioctl.c.
*/
#include <sys/param.h>
#include <sys/mman.h>
#include <sys/kmem_alloc.h>
#include <vm/hat.h>
#include <vm/as.h>
#include <sunwindowdev/wintree.h>
#include <sunwindow/win_ioctl.h>
#include <pixrect/pr_util.h> /* for mpr_static support */
#include <pixrect/pr_dblbuf.h> /* for double buffering support */
#include <sys/uio.h> /* for uio_resid */
#include <sys/file.h> /* for FREAD and FWRITE */
#include <machine/pte.h>
#include <machine/mmu.h>
#include <machine/cpu.h>
#include <sunwindow/pw_dblbuf.h> /* For double buffering */
/* TODO: Be able to mask non-standard vuid events. */
int win_disable_shared_locking = 0; /* turn off shared locking if set to 1*/
int win_send_one_debug; /* Temp: Debugging message for win_send_one */
int win_send_one_other_debug; /* Temp: Debug other_mask in win_send_one */
int wintossmsg; /* Message with toss input for lack of clist space */
int winpsnotkill; /* Reach around communication from */
/* WINSCREENDESTROY to winkill */
int win_infinite_redirect; /* See how many events tossed due */
/* to infinite redirection loop. */
extern void dtop_choose_dblbuf();
extern void dtop_changedisplay();
/*
* Number of windows open.
*/
static int winsopen;
static int winclosebusy;
/*
* Max number of characters that window system can have in all its clists.
*/
extern int winclistcharsmax;
/*
* Current number of characters that window system has in all its clists.
*/
int winclistchars;
short wincursordefaultimage[16] = {
0x0000, 0x7fe0, 0x7f80, 0x7e00,
0x7e00, 0x7f00, 0x7f80, 0x67c0,
0x63e0, 0x41f0, 0x40f8, 0x007c,
0x003e, 0x001f, 0x000e, 0x0004
};
mpr_static(wincursordefaultmpr, 16, 16, 1, wincursordefaultimage);
struct cursor wincursordefault =
{ 0, 0, PIX_SRC|PIX_DST, &wincursordefaultmpr};
int winkill();
extern int shift_statearray_meta[]; /* Reference to array kept in ws_dispense.c to keep shift state on key down */
struct window *
winfromdev(dev)
dev_t dev;
{
register struct window *w;
register int wnum = minor(dev);
if (wnum >= win_nwindows) {
return (0);
}
w = winbufs[wnum];
if (!w) {
w = (struct window *)
new_kmem_zalloc(sizeof (struct window), KMEM_SLEEP);
winbufs[wnum] = w;
}
return (w);
}
struct window *
winfromopendev(dev)
dev_t dev;
{
register int wnum = minor(dev);
if (wnum >= win_nwindows) {
return (0);
}
return (winbufs[wnum]);
}
/*
* All windows can be opened more than once.
* If flag&WIN_EXCLOPEN then this must be the first time being opened.
*/
int
winopen(dev, flag)
dev_t dev;
{
register struct window *w = winfromdev(dev);
if (!w)
return (ENXIO);
if ((flag&WIN_EXCLOPEN) && (w->w_flags&WF_OPEN))
return (EACCES);
if (w->w_flags&WF_OPEN)
return (0);
/*
* Initialize window data structure
*/
w->w_flags = WF_OPEN;
w->w_cursor = wincursordefault;
w->w_cursormpr = wincursordefaultmpr;
w->w_cursordata = *((struct mpr_data *)(wincursordefaultmpr.pr_data));
bcopy((caddr_t)wincursordefaultimage, (caddr_t)w->w_cursorimage,
CUR_MAXIMAGEBYTES);
winfixupcursor(w);
w->w_pid = u.u_procp->p_pid;
winsopen++;
w->w_dbl_rdstate = PW_DBL_BACK;
w->w_dbl_wrstate = PW_DBL_BOTH;
w->w_wid_dbl_info.dbl_wid.wa_count = 0;
w->w_wid_dbl_info.dbl_wid.wa_type = -1;
w->w_wid_dbl_info.dbl_wid.wa_index = -1;
return (0);
}
/*
* Force lock closed if owned by w or we are closing a root window
* and there is a reference to the roots desktop in the lock.
* We are try to avoid dangling references in the lock.
*/
void
wincloselock(wlock, dtop, w)
Winlock *wlock;
Desktop *dtop;
Window *w;
{
if (wlock->lok_pid == w->w_pid ||
(wlock->lok_client == (caddr_t)dtop && w->w_flags & WF_ROOTWINDOW))
wlok_forceunlock(wlock);
}
/*ARGSUSED*/
int
winclose(dev, flag)
dev_t dev;
{
register struct window *w;
register struct desktop *dtop;
Workstation *ws;
register struct window *wchild;
int set_focus = 0;
int pri;
/*
* Protect access to close routine.
*/
while (winclosebusy)
(void) sleep((caddr_t)&winclosebusy, PZERO-1);
/*
* Can't have interrupts going off during closing.
*/
pri = spl_timeout();
winclosebusy = 1;
w = winfromdev(dev);
dtop = w->w_desktop;
ws = w->w_ws;
if (dtop && !(dtop->dt_flags & DTF_PRESENT))
dtop = DESKTOP_NULL;
if (ws && !(ws->ws_flags & WSF_PRESENT))
ws = WORKSTATION_NULL;
winsopen--;
if (ws) {
/* Release any locks held */
wincloselock(&ws->ws_eventlock, dtop, w);
if (ws->ws_pre_grab_kbd_focus == w)
ws->ws_pre_grab_kbd_focus = WINDOW_NULL;
if (ws->ws_pre_grab_kbd_focus_next == w)
ws->ws_pre_grab_kbd_focus_next = WINDOW_NULL;
if (ws->ws_pre_grab_pick_focus == w)
ws->ws_pre_grab_pick_focus = WINDOW_NULL;
if (ws->ws_pre_grab_pick_focus_next == w)
ws->ws_pre_grab_pick_focus_next = WINDOW_NULL;
wincloselock(&ws->ws_iolock, dtop, w);
/* Reset any workstation references to w */
if (ws->ws_kbdfocus == w) {
ws->ws_kbdfocus = WINDOW_NULL;
set_focus = 1;
}
if (ws->ws_pickfocus == w) {
ws->ws_pickfocus = WINDOW_NULL;
set_focus = 1;
}
if (ws->ws_pickfocus_next == w)
ws->ws_pickfocus_next = WINDOW_NULL;
if (ws->ws_kbdfocus_next == w)
ws->ws_kbdfocus_next = WINDOW_NULL;
if (ws->ws_favor_pid == w->w_pid)
ws_favor(ws, WINDOW_NULL);
}
if (dtop) {
/*
* Release any locks held
*/
wincloselock(&dtop->dt_datalock, dtop, w);
dtop_validate_shared_lock(dtop, &dtop->dt_mutexlock);
wincloselock(&dtop->dt_mutexlock, dtop, w);
dtop_validate_shared_lock(dtop, &dtop->dt_displaylock);
wincloselock(&dtop->dt_displaylock, dtop, w);
/*
* Release shared input queue, if owner
*/
if (dtop->dt_sharedq_owner == w) {
dtop->dt_sharedq_owner = 0;
dtop->shared_info->shared_eventq.head = 0;
dtop->shared_info->shared_eventq.tail = 0;
}
/*
* if the window was the last window to have the
* double buffer access reset the go_to_kernel and
* set write to both. If the count is greater than
* zero and the window was the current bufferer then
* choose another double bufferer.
*/
if (w->w_flags & WF_DBLBUF_ACCESS)
{
if (--dtop->dt_dblcount)
{
if (dtop->dt_curdbl == w)
dtop_choose_dblbuf(dtop);
} else {
dtop_changedisplay(dtop, dtop->dt_dbl_bkgnd,
dtop->dt_dbl_frgnd, FALSE);
dtop->shared_info->go_to_kernel = 0;
if ( pr_dbl_set(dtop->dt_pixrect,
PR_DBL_READ,dtop->dt_dbl_bkgnd,
PR_DBL_WRITE, PR_DBL_BOTH, 0))
#ifdef WINDEVDEBUG
printf("Error dbl_set in winclose\n");
#else
;
#endif
}
}
/*
* Remove from tree and fixup screen
*/
if (w->w_flags & WF_INSTALLED)
(void) dtop_removewin(dtop, w);
/*
* Reset any desktop references to w
*/
if (dtop->dt_rootwin==w)
dtop->dt_rootwin = NULL;
if (dtop->dt_cursorwin == w)
dtop_set_cursor(dtop);
/*
* Free any resources of w that are sharable with other
* windows on dtop (if not currently being shared).
*/
dtop_cmsfree(dtop, w);
}
/* Set new input focus, after removed from tree */
if (set_focus)
ws_set_focus(ws, FF_PICK_CHANGE);
/*
* Free resources allocated to window
*/
rl_free(&w->w_rlexposed);
rl_free(&w->w_rlexposedold);
rl_free(&w->w_rlfixup);
/*
* Flush input buffer
* Note: Should redistribute this to surviving windows.
* Note: if eventq was shared, c_cc should be zero.
*/
while (w->w_input.c_cc) {
(void) getc(&w->w_input);
winclistchars--;
continue;
}
/*
* Remove exiting children's references to w.
* Kill controlling processes of descendent windows
*/
for (wchild = w->w_link[WL_YOUNGESTCHILD]; wchild;
wchild = wchild->w_link[WL_OLDERSIB]) {
wchild->w_link[WL_PARENT] = NULL;
wt_enumeratechildren(winkill, wchild, (struct rect *)0);
}
/*
* If w is rootwindow then close desktop as well.
*/
if (w->w_flags & WF_ROOTWINDOW && dtop != NULL) {
dtop_close(dtop);
}
bzero((caddr_t)w, sizeof (*w));
if (!winsopen) {
int wi;
/*
* Just deallocate when no more windows around
*/
for (wi = 0; wi < win_nwindows; wi++) {
if (winbufs[wi] != NULL) {
kmem_free((caddr_t)winbufs[wi],
sizeof (struct window));
winbufs[wi] = NULL;
}
}
/*
* Zero global char count
*/
winclistchars = 0;
}
winclosebusy = 0;
(void) splx(pri);
wakeup((caddr_t)&winclosebusy);
return (0);
}
int
winread(dev, uio)
dev_t dev;
struct uio *uio;
{
register struct window *w = winfromdev(dev);
register struct win_shared_eventqueue *q = NULL;
register int error = 0;
register char c;
int sharedq_owner = FALSE;
int pri;
pri = spl_timeout();
/* Try to nudge next event off workstation's input queue */
ws_window_nudge(w);
if (w->w_desktop && w->w_desktop->shared_info) {
q = &w->w_desktop->shared_info->shared_eventq;
sharedq_owner = w->w_desktop->dt_sharedq_owner == w;
}
win_sharedq_shift(w);
while (sharedq_owner ?
(q->tail == q->head) :
(w->w_input.c_cc < sizeof (struct inputevent)))
if (w->w_flags&WF_NBIO) {
(void) splx(pri);
return (EWOULDBLOCK);
} else {
w->w_flags |= WF_WANTINPUT;
(void) sleep((caddr_t)&w->w_input, STIPRI);
win_sharedq_shift(w);
}
if (sharedq_owner) {
struct inputevent *events = w->w_desktop->dt_sharedq;
while (!error && q->tail != q->head && uio->uio_resid) {
error = uiomove((caddr_t) (events + q->head),
sizeof (struct inputevent),
UIO_READ, uio);
if (q->head == w->w_desktop->dt_sharedq_size - 1)
q->head = 0;
else
q->head++;
}
} else {
while (!error && w->w_input.c_cc && uio->uio_resid) {
c = getc(&w->w_input);
winclistchars--;
error = ureadc(c, uio);
}
}
(void) splx(pri);
return (error);
}
/*ARGSUSED*/
int
winwrite(dev, uio)
dev_t dev;
struct uio *uio;
{
#ifdef WINSVJ
return (svjwrite(dev, uio));
#else
return (0);
#endif
}
/*
* Send fe to w if mask allows it.
* Return -1 if don't, 0 otherwise.
*/
int
win_send_one(w, fe, mask, other_mask)
register Window *w;
register Firm_event *fe;
register struct inputmask *mask;
struct inputmask *other_mask;
{
register int flags;
extern u_char kb_numlock_table[];
#ifdef WINDEVDEBUG
if (win_send_one_debug)
printf("win_send_one w=%X, id=%D, value=%D, mask=%X",
w, fe->id, fe->value, mask);
#endif
/* Determine if event should be thought of as negative */
if ((fe->value == 0) &&
((fe->pair_type == FE_PAIR_NONE) || (fe->pair_type == FE_PAIR_SET)))
flags = IE_NEGEVENT;
else
flags = 0;
/*
* See if event id falls outside input mask domain.
* We don't yet have a mechanism for masking non-standard
* vuid events. Thus, every application gets all non-standard
* vuid events, both positive and negative.
*/
if (!(((((short)fe->id) >= ASCII_FIRST) && (fe->id <= TOP_LAST)) ||
((fe->id >= VKEY_FIRST) && (fe->id <= VKEY_LAST)))) {
winsendevent(w, fe->id, flags, &fe->time);
#ifdef WINDEVDEBUG
if (win_send_one_debug) printf(" other\n");
#endif
return (0);
}
if ((((short)fe->id) >= ASCII_FIRST) && (fe->id <= ASCII_LAST)) {
/*
* Event is ASCII key. If IM_{NEG}EUC or IM_{NEG}ASCII is set,
* send it up.
*/
if ((mask->im_flags & IM_EUC) && (flags == 0)) {
winsendevent(w, fe->id, flags, &fe->time);
if (win_send_one_debug) printf(" euc (lower half)\n");
return (0);
}
if ((mask->im_flags & IM_NEGEUC) && (flags == IE_NEGEVENT)) {
winsendevent(w, fe->id, flags, &fe->time);
if (win_send_one_debug) printf(" neg euc (lower half)\n");
return (0);
}
if ((mask->im_flags & IM_ASCII) && (flags == 0)) {
winsendevent(w, fe->id, flags, &fe->time);
#ifdef WINDEVDEBUG
if (win_send_one_debug) printf(" ascii\n");
#endif
return (0);
}
if ((mask->im_flags & IM_NEGASCII) && (flags == IE_NEGEVENT)) {
winsendevent(w, fe->id, flags, &fe->time);
#ifdef WINDEVDEBUG
if (win_send_one_debug) printf(" neg ascii\n");
#endif
return (0);
}
goto ignore;
}
if ((fe->id >= META_FIRST) && (fe->id <= META_LAST)) {
/*
* Event is either an EUC character event in the "upper half"
* or a META event. You can tell the difference by checking
* wheether the META bit is in the shift mask.
*
* If it's an EUC event, send it up as is only if IM_{NEG}EUC
* is set, and send it up in backwards-compatible form if
* IM_ISO is set. (Map the event to the ISO range for
* backwards compatibility.) (Note that there is no IM_NEGISO
* bit. Is this a bug?)
*
* If it's a META event, send it up only if IM_{NEG}META
* is set.
*/
/* Look at the shift state when the key went _down_, not when it comes up */
if(!(shift_statearray_meta[fe->id-META_FIRST] & META_SHIFT_MASK)) {
/*
* "Upper half of EUC" event. If requesting EUC
* events, send it up as is; if requesting ISO events,
* send it up translated; otherwise, ignore it.
*/
if ((mask->im_flags & IM_EUC) && (flags == 0)) {
winsendevent(w, fe->id, flags, &fe->time);
if (win_send_one_debug) printf(" euc (upper half)\n");
return (0);
}
if ((mask->im_flags & IM_NEGEUC) && (flags == IE_NEGEVENT)) {
winsendevent(w, fe->id, flags, &fe->time);
if (win_send_one_debug) printf(" neg euc (upper half)\n");
return (0);
}
if ((mask->im_flags & IM_ISO) && (flags == 0)) {
fe->id += (ISO_FIRST - ASCII_FIRST);
winsendevent(w, fe->id, flags, &fe->time);
if (win_send_one_debug) printf(" iso\n");
return (0);
}
} else {
/*
* "Meta" event. If requesting META events, send it up
* as is; otherwise, ignore it.
*/
if ((mask->im_flags & IM_META) && (flags == 0)) {
winsendevent(w, fe->id, flags, &fe->time);
#ifdef WINDEVDEBUG
if (win_send_one_debug) printf(" meta\n");
#endif
return (0);
}
if ((mask->im_flags & IM_NEGMETA) && (flags == IE_NEGEVENT)) {
winsendevent(w, fe->id, flags, &fe->time);
#ifdef WINDEVDEBUG
if (win_send_one_debug) printf(" neg meta\n");
#endif
return (0);
}
}
goto ignore;
}
/* Try to send top */
if ((fe->id >= TOP_FIRST) && (fe->id <= TOP_LAST)) {
if ((mask->im_flags & IM_TOP) && (flags == 0)) {
winsendevent(w, fe->id, flags, &fe->time);
#ifdef WINDEVDEBUG
if (win_send_one_debug) printf(" top\n");
#endif
return (0);
}
if ((mask->im_flags & IM_NEGTOP) && (flags == IE_NEGEVENT)) {
winsendevent(w, fe->id, flags, &fe->time);
#ifdef WINDEVDEBUG
if (win_send_one_debug) printf(" neg top\n");
#endif
return (0);
}
goto ignore;
}
/*
* Try to send escape sequence if asked for ascii or EUC but not
* given function key. Only send if the "other" input mask not
* interested in the function key, i.e., function keys take
* priority over escape sequences.
*/
if ((fe->id >= KEY_LEFTFIRST) && (fe->id <= KEY_BOTTOMLAST) &&
(!win_getinputcodebit(mask, fe->id)) &&
(mask->im_flags & (IM_ASCII|IM_EUC)) && (flags == 0)) {
char buf[10], *strsetwithdecimal() /* from kbd.c */;
char *cp;
u_int entry;
struct timeval to;
/*
* Only send if the "other" input mask not interested in the
* function key, i.e., function keys take priority over escape
* sequences.
*/
#ifdef WINDEVDEBUG
if (win_send_one_other_debug && other_mask)
printf("other_mask %X, bit %D\n",
other_mask, win_getinputcodebit(other_mask, fe->id));
#endif
if ((other_mask != INPUTMASK_NULL) &&
(win_getinputcodebit(other_mask, fe->id)))
goto ignore;
#ifdef WINDEVDEBUG
if (win_send_one_debug) printf(" escape sequence\n");
#endif
/* Get string going to send */
entry = fe->id - KEY_LEFTFIRST + 192;
cp = strsetwithdecimal(&buf[0], entry, sizeof (buf) - 1);
/* Turn off event lock for entire escape sequence */
to = w->w_ws->ws_eventtimeout;
timerclear(&w->w_ws->ws_eventtimeout);
/* Send escape sequence */
win_send_unlocked(w, (u_short)'\033', flags, &fe->time); /*Esc*/
win_send_unlocked(w, (u_short)'[', flags, &fe->time);
while (*cp != '\0') {
win_send_unlocked(w, (u_short)*cp, flags, &fe->time);
cp++;
}
/* Restore event lock for last character in escape sequence */
w->w_ws->ws_eventtimeout = to;
winsendevent(w, (u_short)'z', flags, &fe->time);
/* Surpress sending up for this function key */
win_setinputcodebit(&w->w_ws->ws_surpress_mask, fe->id);
return (0);
}
/*
* Try to send keypad character if asked for ascii or EUC but not
* given keypad key. Only send if the "other" input mask not
* interested in the function key, i.e., keypad keys take
* priority over keypad characters.
*/
if ((fe->id >= VKEY_FIRSTPAD) && (fe->id <= VKEY_LASTPAD) &&
(!win_getinputcodebit(mask, fe->id)) &&
(mask->im_flags & (IM_ASCII|IM_EUC)) && (flags == 0)) {
/*
* Only send if the "other" input mask not interested in the
* keypad key, i.e., keypad keys take priority over keypad
* characters.
*/
if (win_send_one_other_debug && other_mask) {
printf("other_mask %X, bit %D\n",
other_mask, win_getinputcodebit(other_mask, fe->id));
}
if ((other_mask != INPUTMASK_NULL) &&
(win_getinputcodebit(other_mask, fe->id)))
goto ignore;
if (win_send_one_debug) printf(" keypad key\n");
fe->id = kb_numlock_table[fe->id - VKEY_FIRSTPAD];
if (!(mask->im_flags & IM_EUC) &&
w->w_ws->ws_shiftmask & META_SHIFT_MASK)
fe->id |= 0x80;
winsendevent(w, fe->id, flags, &fe->time);
return (0);
}
/*
* Try to send LOC_DRAG. Do before general purpose
* send because want to send this variant on LOC_MOVE instead of
* LOC_MOVE if also on in mask. LOC_DRAG is the same as
* LOC_MOVEWHILEBUTDOWN.
*/
#ifndef lint
if ((fe->id == LOC_MOVE) &&
(win_getinputcodebit(mask, LOC_DRAG))) {
register Vuid_state is = w->w_desktop->dt_ws->ws_instate;
if ((vuid_get_value(is, MS_LEFT)) ||
(vuid_get_value(is, MS_MIDDLE)) ||
(vuid_get_value(is, MS_RIGHT))) {
winsendevent(w, LOC_DRAG, flags, &fe->time);
#ifdef WINDEVDEBUG
if (win_send_one_debug) printf(" LOC_DRAG\n");
#endif
return (0);
}
}
#endif
/*
* Try to send LOC_TRAJECTORY. Do before general purpose
* send because want to send this variant on LOC_MOVE instead of
* LOC_MOVE if also on in mask.
*/
#ifndef lint
if ((fe->id == LOC_MOVE) &&
(win_getinputcodebit(mask, LOC_TRAJECTORY))) {
winsendevent(w, LOC_TRAJECTORY, flags, &fe->time);
#ifdef WINDEVDEBUG
if (win_send_one_debug) printf(" LOC_TRAJECTORY\n");
#endif
return (0);
}
#endif
/*
* Send only if mask indicates and the event is positive or
* the event is negative and the mask enables negative events.
*/
if ((win_getinputcodebit(mask, fe->id)) &&
((flags == 0) ||
((mask->im_flags & IM_NEGEVENT) && (flags == IE_NEGEVENT)))) {
/* Don't send if ws_surpress_mask bit is set. */
if (win_getinputcodebit(&w->w_ws->ws_surpress_mask, fe->id) && (fe->id >= KEY_LEFTFIRST) && (fe->id <= KEY_BOTTOMRIGHT))
goto ignore;
winsendevent(w, fe->id, flags, &fe->time);
#ifdef WINDEVDEBUG
if (win_send_one_debug) printf(" vuid\n");
#endif
return (0);
}
/*
* No longer supporting IM_UNENCODED (pure device codes).
*
* Never supported IM_POSASCII (no neg ASCII even if IM_NEGEVENT).
* Should invent new IM_NEGASCII & IM_NEGMETA options.
*
* Never supported IM_ANSI (ansi with funcs encoded in ESC[).
* It is the applications responsibility to turn function key
* events into escape sequences.
*/
ignore:
#ifdef WINDEVDEBUG
if (win_send_one_debug) printf(" IGNORED\n");
#endif
return (-1);
}
int
win_send_it(kbd_win, pick_win, fe)
register Window *kbd_win;
register Window *pick_win;
Firm_event *fe;
{
/* See if kbd window wants the event */
if ((kbd_win != WINDOW_NULL) &&
(kbd_win->w_flags & WF_KBD_MASK_SET) &&
(win_send_one(kbd_win, fe, &kbd_win->w_kbdmask,
(pick_win != WINDOW_NULL)? &pick_win->w_pickmask :
INPUTMASK_NULL) == 0))
return (0);
/* See if pick window wants the event */
if ((pick_win != WINDOW_NULL) &&
(win_send_one(pick_win, fe, &pick_win->w_pickmask,
INPUTMASK_NULL) == 0))
return (0);
return (-1);
}
win_send(ws, fe)
Workstation *ws;
register Firm_event *fe;
{
register Window *w;
#define WIN_PATH_MAX 15
int count = 0;
if (win_send_it(ws->ws_kbdfocus, ws->ws_pickfocus, fe) == 0)
goto Done;
/* Try to deliver event to pick focus' input link or its parent(s) */
w = ws->ws_pickfocus;
while (w != WINDOW_NULL) {
/* Decide who to try next */
if ((w->w_inputnext != WINDOW_NULL) &&
(w->w_inputnext->w_flags & WF_OPEN))
w = w->w_inputnext;
else
w = w->w_link[WL_PARENT];
if (win_send_it(w, w, fe) == 0)
goto Done;
if (count++ > WIN_PATH_MAX) {
win_infinite_redirect++;
break;
}
}
/* Dropped event on the floor */
Done:
/* Reenable function key on up if surpressed due to escape sequence */
if ((fe->id >= KEY_LEFTFIRST) && (fe->id <= KEY_BOTTOMRIGHT) &&
(fe->value == 0))
win_unsetinputcodebit(&ws->ws_surpress_mask, fe->id);
}
winwakeup(w)
register struct window *w;
{
w->w_flags &= ~WF_WANTINPUT;
if (w->w_rsel) {
selwakeup(w->w_rsel, w->w_flags & WF_RCOLL);
w->w_flags &= ~WF_RCOLL;
w->w_rsel = 0;
}
wakeup((caddr_t)&w->w_input);
}
int
winselect(dev, rw)
dev_t dev;
int rw;
{
register struct window *w = winfromdev(dev);
register Desktop *dtop = w->w_desktop;
extern int selwait; /* see ../h/systm.h */
int pri = spl_timeout();
win_sharedq_shift(w);
switch (rw) {
case FREAD:
/* Try to nudge next event off workstation's input queue */
ws_window_nudge(w);
if (dtop && dtop->dt_sharedq_owner == w &&
dtop->shared_info->shared_eventq.tail !=
dtop->shared_info->shared_eventq.head)
goto win;
if (w->w_input.c_cc >= sizeof (struct inputevent))
goto win;
w->w_flags |= WF_WANTINPUT;
if (w->w_rsel && w->w_rsel->p_wchan == (caddr_t)&selwait)
w->w_flags |= WF_RCOLL;
else
w->w_rsel = u.u_procp;
break;
case FWRITE:
goto win;
}
(void) splx(pri);
return (0);
win:
(void) splx(pri);
return (1);
}
/*
* Utilities
*/
win_send_unlocked(w, code, flags, time_ptr)
register struct window *w;
u_short code;
short flags;
struct timeval *time_ptr;
{
if ((w == WINDOW_NULL) || !(w->w_ws))
return;
winsendevent(w, code, flags, time_ptr);
wlok_unlock(&w->w_ws->ws_eventlock);
}
winsendevent(w, code, flags, time_ptr)
register struct window *w;
u_short code;
short flags;
struct timeval *time_ptr;
{
register int i, notmoved = 0, moved2sharedq = 0;
struct inputevent event;
struct desktop *dtop;
Workstation *ws;
#ifdef WINSVJ
void svjsendevent();
#endif
if ((w == WINDOW_NULL) || !(dtop = w->w_desktop) || !(ws = dtop->dt_ws))
return;
#ifdef WINSVJ
if (ws->ws_flags&WSF_RECORD_EVENT)
(void) svjsendevent(code, ws, time_ptr);
#endif
win_sharedq_shift(w);
/*
* Try to keep window system overall usage to a limit
* but allow small clist consumers through.
*/
if ((winclistchars > winclistcharsmax) &&
(w->w_input.c_cc >= sizeof (event) * 10)) {
if (wintossmsg)
printf("Win sys tossing input!\n");
goto Wakeup;
}
/* Construct struct input event to send */
event.ie_code = code;
event.ie_flags = flags;
event.ie_shiftmask = ws->ws_shiftmask;
event.ie_locx = dtop->dt_ut_x - w->w_screenx;
event.ie_locy = dtop->dt_ut_y - w->w_screeny;
event.ie_time = *time_ptr;
/* Place on windows clist */
if (dtop->dt_sharedq_owner == w) {
notmoved = dtop_event_to_sharedq(dtop, &event);
moved2sharedq = !notmoved;
}
if (!moved2sharedq &&
(notmoved = b_to_q((caddr_t)&event, sizeof (event), &w->w_input))) {
for (i = sizeof (event) - notmoved; i; i--) {
if (unputc(&w->w_input) == -1) {
#ifdef WINDEVDEBUG
printf("Trouble unputc in winsendevent\n");
#endif
break;
}
}
}
#ifdef WINDEVDEBUG
if (notmoved && wintossmsg)
printf("Win sys tossing partial input!\n");
#endif
if (!moved2sharedq)
winclistchars += sizeof (event) - notmoved;
/* Acquire event lock */
ws_lock_event(ws, w);
Wakeup:
if (w->w_flags & WF_ASYNC) {
if (w->w_aproc->p_pid == w->w_apid)
psignal(w->w_aproc, SIGIO);
}
if (w->w_flags & WF_WANTINPUT)
winwakeup(w);
return;
}
/*
* Called from wt_enumeratechildren so don't change calling sequence
*/
/*ARGSUSED*/
winkill(w, rect)
struct window *w;
struct rect *rect; /* Don't use for anything else (not caddr_t) */
{
if (!(w->w_flags & WF_OPEN)) {
return (-1);
} else {
if (w->w_pid != winpsnotkill)
winsignal(w, SIGTERM);
}
return (0);
}
winsignal(w, sig)
struct window *w;
int sig;
{
extern struct proc *pfind();
register struct proc *p = pfind(w->w_pid);
if (p)
psignal(p, sig);
}
win_freecmapdata(w)
register struct window *w;
{
cms_freecmapdata(w->w_cmapdata, &w->w_cmap, w->w_cms.cms_size);
w->w_cmapdata = 0;
}
/* return the address of the window's shared lock block */
/*ARGSUSED*/
winmmap(dev, off, prot)
dev_t dev;
off_t off;
int prot;
{
Window *w = winfromdev(dev);
register caddr_t addr;
u_int hat_getkpfnum();
if (!w || !w->w_desktop || win_disable_shared_locking)
return (-1);
addr = (caddr_t) w->w_desktop->shared_info;
if (off > sizeof (Win_lock_block))
return (-1);
return ((int)hat_getkpfnum(addr + off));
}
/*
* Set up the mapping to window's shared lock block
* The only reason why we don't want to just use the
* default spec_segmap() routine directly is that
* we want the opportunity to pick the address ourselves.
*/
int
winsegmap(dev, off, as, addrp, len, prot, maxprot, flags, cred)
dev_t dev;
u_int off;
struct as *as;
addr_t *addrp;
u_int len;
u_int prot, maxprot;
u_int flags;
struct ucred *cred;
{
if ((flags & MAP_FIXED) == 0) {
Window *w = winfromdev(dev);
int addr = (int)w->w_desktop->shared_info;
/*
* Pick an address consistent with the current address.
*/
#ifndef sun3x
off += (addr & (shm_alignment - 1));
#else
/* no vac on a sun3x */
off += addr;
#endif
map_addr(addrp, len, (off_t)off, 1);
if (*addrp == NULL)
return (ENOMEM);
flags |= MAP_FIXED;
}
/*
* Now that we selected the address ourselves, let spec_map
* handle the rest using our fixed virtual address.
*/
return (spec_segmap(dev, off, as, addrp, len, prot, maxprot, flags,
cred));
}
win_sharedq_shift(w)
register struct window *w;
{
register struct desktop *dtop;
register struct win_shared_eventqueue *q;
register int tail;
#ifdef WINDEVDEBUG
extern int win_sharedq_debug;
#endif
if ((w == WINDOW_NULL) ||
!(dtop = w->w_desktop) ||
(dtop->dt_sharedq_owner != w))
return;
q = &dtop->shared_info->shared_eventq;
/* check for corrupted queue */
if (q->head < 0 || q->head >= dtop->dt_sharedq_size ||
q->tail < 0 || q->tail >= dtop->dt_sharedq_size) {
q->head = q->tail = 0;
q->size = dtop->dt_sharedq_size;
}
tail = q->tail + 1;
if (tail >= dtop->dt_sharedq_size)
tail = 0;
#ifdef WINDEVDEBUG
if (win_sharedq_debug && w->w_input.c_cc > 0 && tail != q->head) {
printf("win_sharedq_shift: shifting inputevents\n");
}
#endif
/*
* while non-empty overflow q and room on shared q,
* shift input over to shared q.
*/
while (w->w_input.c_cc > 0 && tail != q->head) {
char *cp = (char *)(&dtop->dt_sharedq[tail]);
int i = 0, c;
for (; i < sizeof (struct inputevent); i++, cp++) {
c = getc(&w->w_input);
if (c >= 0) {
*cp = (char) c;
} else {
#ifdef WINDEVDEBUG
if (win_sharedq_debug) {
printf(
"win_sharedq_shift: non integer multiple of size of struct inputevent\n");
}
#endif
return;
}
}
q->tail = tail;
if (++tail >= dtop->dt_sharedq_size)
tail = 0;
}
}