#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 #include #include #include #include #include #include #include /* for mpr_static support */ #include /* for double buffering support */ #include /* for uio_resid */ #include /* for FREAD and FWRITE */ #include #include #include #include /* 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; } }