1165 lines
31 KiB
C
1165 lines
31 KiB
C
#ifndef lint
|
|
static char sccsid[] = "@(#)ws_dispense.c 1.1 94/10/31";
|
|
#endif
|
|
|
|
/*
|
|
* Copyright (c) 1986 by Sun Microsystems, Inc.
|
|
*/
|
|
|
|
/*
|
|
* SunWindows Workstation code that is responsible for handling the
|
|
* top of the input queue, dispensing events at the appropriate times
|
|
* to the appropriate windows.
|
|
*/
|
|
|
|
#include <sunwindowdev/wintree.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/kernel.h> /* for time */
|
|
#include <pixrect/pr_planegroups.h> /* for plane groups */
|
|
|
|
static void ws_set_dtop_grabio();
|
|
void ws_set_dtop_waiting();
|
|
|
|
void dtop_restore_grnds();
|
|
void dtop_save_grnds();
|
|
void dtop_set_bkgnd();
|
|
|
|
/* TODO: How about some sort of meta mask? */
|
|
/* TODO: Worry about ALL_LOCKS */
|
|
|
|
#ifdef WINDEVDEBUG
|
|
int ws_qget_debug; /* Temp: Debugging messages when dequeue firm event */
|
|
int ws_qputback_debug;
|
|
/* Temp: Debugging messages when putback firm event */
|
|
int ws_set_focus_debug;
|
|
/* Temp: Debugging messages when ws_set_focus called */
|
|
int ws_track_debug;
|
|
/* Temp: Debug messages in ws_set_pick_focus_next */
|
|
#endif
|
|
int ws_focus_during_each_transit;
|
|
/* Temp: Set focus if loc moves & in transit*/
|
|
|
|
int ws_verbose_event_lock; /* Turn on event lock broken messages */
|
|
int ws_no_in_transit;
|
|
int ws_no_collapse;
|
|
|
|
extern int ws_q_collapse_trigger; /* # q items that trigger collapse */
|
|
|
|
#define ws_is_loc_change(id) \
|
|
((((id) >= LOC_FIRST_DELTA) && ((id) <= LOC_LAST_ABSOLUTE)) || \
|
|
((id) == LOC_MOVE))
|
|
|
|
Firm_event ws_get_event();
|
|
|
|
int ws_lock_control_pid; /* Used in lock control enumerator */
|
|
int ws_empty_input_flag; /* Used in lock control enumerator */
|
|
|
|
int shift_statearray_meta[META_LAST-META_FIRST+1]; /* Array to keep the state of the shift keys
|
|
when a key goes down, if it's a possible META
|
|
event */
|
|
|
|
ws_window_nudge(w)
|
|
Window *w;
|
|
{
|
|
register Workstation *ws;
|
|
register Desktop *dtop;
|
|
|
|
dtop = w->w_desktop;
|
|
if (dtop == DESKTOP_NULL)
|
|
return;
|
|
win_sharedq_shift(w);
|
|
ws = dtop->dt_ws;
|
|
if (ws == WORKSTATION_NULL)
|
|
return;
|
|
/*
|
|
* If window's process is currently unsyncronized, see if can
|
|
* allow it to acquire the event lock.
|
|
*/
|
|
if (w->w_flags & WF_UNSYNCHRONIZED)
|
|
ws_try_event_enable(w);
|
|
/* If no current event lock holder then nudge next event off queue */
|
|
if (~ws->ws_flags & WSF_LOCKED_EVENT)
|
|
ws_nudge(ws);
|
|
/*
|
|
* If window's process is current event lock holder & there is
|
|
* no input on window's queue then nudge next event (if any) off
|
|
* of queue. Before do that, unlock current event lock because
|
|
* next event may not be for this window.
|
|
*/
|
|
else if ((ws->ws_event_consumer != WINDOW_NULL) &&
|
|
(ws->ws_event_consumer->w_pid == w->w_pid) &&
|
|
(dtop->dt_sharedq_owner == w ?
|
|
(dtop->shared_info->shared_eventq.head ==
|
|
dtop->shared_info->shared_eventq.tail) :
|
|
(ws->ws_event_consumer->w_input.c_cc <
|
|
sizeof (struct inputevent)))) {
|
|
wlok_unlock(&ws->ws_eventlock);
|
|
ws_nudge(ws);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Try to send an event to the one of the input focuses.
|
|
* Any caller of ws_nudge that has the event lock should unlock it first.
|
|
*
|
|
* We preserve the user's preception of the ordering amoung LOC_WINENTER,
|
|
* LOC_WINEXIT, KBD_REQUEST, KBD_USE, and KBD_DONE, reguardless of kbd
|
|
* focus change event type. However, KBD_REQUESTs are not issued when
|
|
* LOC_WINENTER is the kbd focus change event. Here is the order:
|
|
*
|
|
* LOC_WINEXIT
|
|
* LOC_WINENTER
|
|
* KBD_REQUEST
|
|
* KBD_DONE
|
|
* KBD_USE
|
|
*
|
|
* It might seem that the KBD_DONE ought to follow the LOC_WINEXIT in the
|
|
* LOC_WINEXIT kbd focus change event case. But this is hard to implement
|
|
* and doesn't move well to a MS_LEFT kbd focus change event case.
|
|
*/
|
|
ws_nudge(ws)
|
|
register Workstation *ws;
|
|
{
|
|
Firm_event firm_event; /* Gotten from input q */
|
|
Firm_event fe; /* Contructed */
|
|
|
|
|
|
/*
|
|
* See if some process/window in middle of processing input.
|
|
*/
|
|
if (ws->ws_flags & WSF_LOCKED_EVENT)
|
|
return;
|
|
/* Collapse locator events at top of queue to keep from being full */
|
|
ws_collapse_q(ws);
|
|
/*
|
|
* Go around focus change state machine until need to waiting
|
|
* for event consumer to clear the event lock.
|
|
*/
|
|
while (~ws->ws_flags & WSF_LOCKED_EVENT) {
|
|
/* Pre-set fe fields */
|
|
fe.value = 1;
|
|
/* Set to one because event has no neg */
|
|
if (ws->ws_flags & WSF_SEND_FOCUS_EVENT)
|
|
fe.time = ws->ws_focus_event.time;
|
|
else if (!vq_is_empty(&ws->ws_q))
|
|
fe.time = ws->ws_q.top->firm_event.time;
|
|
else
|
|
fe.time = time;
|
|
fe.pair = 0;
|
|
fe.pair_type = FE_PAIR_NONE;
|
|
|
|
switch (ws->ws_focus_state) {
|
|
|
|
case SEND_EXIT:
|
|
/* Send LOC_WINEXIT to ws_pickfocus */
|
|
fe.id = LOC_WINEXIT;
|
|
if (ws->ws_pickfocus)
|
|
(void) win_send_one(ws->ws_pickfocus,
|
|
&fe, &ws->ws_pickfocus->w_pickmask,
|
|
INPUTMASK_NULL);
|
|
/* Set in-transit flag */
|
|
if (!ws_no_in_transit)
|
|
if (ws->ws_flags & WSF_LATEST_WAS_MOTION)
|
|
ws->ws_flags |= WSF_LOC_IN_TRANSIT;
|
|
/* Move to next state */
|
|
ws->ws_focus_state = SEND_ENTER;
|
|
break;
|
|
|
|
case SEND_ENTER:
|
|
/*
|
|
* Do in-transit processing, by conditionally gliding
|
|
* over windows without waking them up.
|
|
*/
|
|
ws_window_transit(ws);
|
|
/* See if completed focus transition */
|
|
if (ws->ws_flags & WSF_LOC_IN_TRANSIT) {
|
|
/*
|
|
* See if should ignore in-transit locator
|
|
* event surpression.
|
|
*/
|
|
if(ws->ws_pickfocus_next &&
|
|
(ws->ws_pickfocus_next->w_pickmask.im_flags &
|
|
IM_INTRANSIT)) {
|
|
/* Continue */
|
|
} else
|
|
return;
|
|
}
|
|
ws_set_focus(ws, FF_PICK_CHANGE);
|
|
/* Send LOC_WINENTER to ws_pickfocus_next */
|
|
fe.id = LOC_WINENTER;
|
|
if (ws->ws_pickfocus_next)
|
|
(void) win_send_one(ws->ws_pickfocus_next,
|
|
&fe, &ws->ws_pickfocus_next->w_pickmask,
|
|
INPUTMASK_NULL);
|
|
/* Update ws_pickfocus */
|
|
ws->ws_pickfocus = ws->ws_pickfocus_next;
|
|
/* Move to next state */
|
|
ws->ws_focus_state = SEND_Q_TOP;
|
|
break;
|
|
|
|
case SEND_DIRECT_REQUEST:
|
|
ws_send_kbd_request(ws, ws->ws_kbdfocus_next, &fe);
|
|
break;
|
|
|
|
case SEND_REQUEST:
|
|
ws_send_kbd_request(ws, ws->ws_pickfocus, &fe);
|
|
break;
|
|
|
|
case REQUEST_WAIT:
|
|
/*
|
|
* If requesting flag is set then didn't disapprove
|
|
* of the request.
|
|
*/
|
|
if (ws->ws_flags & WSF_KBD_REQUEST_PENDING) {
|
|
/* Clear requesting flag */
|
|
ws->ws_flags &= ~WSF_KBD_REQUEST_PENDING;
|
|
/* Move to next state */
|
|
ws->ws_focus_state = SEND_DONE;
|
|
} else {
|
|
/* Reset ws_kbdfocus_next */
|
|
ws->ws_kbdfocus_next = ws->ws_kbdfocus;
|
|
/* Move to next state */
|
|
ws->ws_focus_state = SEND_FOCUS_EVENT;
|
|
}
|
|
break;
|
|
|
|
case SEND_DONE:
|
|
/* Send KBD_DONE to ws_kbdfocus */
|
|
fe.id = KBD_DONE;
|
|
if (ws->ws_kbdfocus)
|
|
(void) win_send_one(ws->ws_kbdfocus,
|
|
&fe, &ws->ws_kbdfocus->w_kbdmask,
|
|
INPUTMASK_NULL);
|
|
/* Move to next state */
|
|
ws->ws_focus_state = SEND_USE;
|
|
break;
|
|
|
|
case SEND_USE:
|
|
/* Send KBD_USE to ws_kbdfocus_next */
|
|
fe.id = KBD_USE;
|
|
if (ws->ws_kbdfocus_next)
|
|
(void) win_send_one(ws->ws_kbdfocus_next,
|
|
&fe, &ws->ws_kbdfocus_next->w_kbdmask,
|
|
INPUTMASK_NULL);
|
|
/* Update ws_kbdfocus */
|
|
ws->ws_kbdfocus = ws->ws_kbdfocus_next;
|
|
/* Move to next state */
|
|
if ((ws->ws_flags & WSF_SWALLOW_FOCUS_EVENT) ||
|
|
(!(ws->ws_flags & WSF_SEND_FOCUS_EVENT)))
|
|
ws->ws_focus_state = SEND_Q_TOP;
|
|
else
|
|
ws->ws_focus_state = SEND_FOCUS_EVENT;
|
|
ws->ws_flags &= ~WSF_SWALLOW_FOCUS_EVENT;
|
|
break;
|
|
|
|
case SEND_FOCUS_EVENT:
|
|
/*
|
|
* Send ws_focus_event to kbd or pick focus. If did a
|
|
* win_send on this event then would have windows
|
|
* jumping around because of passing, for example,
|
|
* MS_LEFT's up to a tool parent (which cause a top).
|
|
*/
|
|
if ((ws->ws_kbdfocus == WINDOW_NULL) ||
|
|
(win_send_one(ws->ws_kbdfocus, &ws->ws_focus_event,
|
|
&ws->ws_kbdfocus->w_kbdmask,
|
|
INPUTMASK_NULL) == -1)) {
|
|
if (ws->ws_pickfocus) {
|
|
(void) win_send_one(ws->ws_pickfocus,
|
|
&ws->ws_focus_event,
|
|
&ws->ws_pickfocus->w_pickmask,
|
|
INPUTMASK_NULL);
|
|
}
|
|
}
|
|
/* Clear focus event flags */
|
|
ws->ws_flags &= ~WSF_SEND_FOCUS_EVENT;
|
|
/* Move to next state */
|
|
ws->ws_focus_state = SEND_Q_TOP;
|
|
break;
|
|
|
|
case SEND_Q_TOP: /* Could break into smaller states */
|
|
/*
|
|
* Set state if new focuses and break. Gets any focus
|
|
* changes since last got to this state.
|
|
*/
|
|
if (ws_set_focus_state(ws))
|
|
break;
|
|
/*
|
|
* Get top of q and use this event to try to change
|
|
* focuses. Nothing to do if the input queue is empty.
|
|
*/
|
|
if (vq_is_empty(&ws->ws_q))
|
|
return;
|
|
firm_event = ws_get_event(ws);
|
|
/*
|
|
* Set focus if LOC_MOVE. Also, if LOC_STILL set the
|
|
* focus because all the LOC_MOVE's may have been
|
|
* collapsed away.
|
|
*
|
|
* Order of swallow vs pass thru test is important.
|
|
* Since swallow contricts what should be done, it
|
|
* comes first.
|
|
*/
|
|
if ((firm_event.id == LOC_MOVE) ||
|
|
(firm_event.id == LOC_STILL))
|
|
ws_set_focus(ws, FF_PICK_CHANGE);
|
|
else if ((firm_event.id == ws->ws_kbd_focus_sw.id) &&
|
|
ws_focus_match(ws, &ws->ws_kbd_focus_sw,
|
|
&firm_event)) {
|
|
ws->ws_flags |= WSF_SWALLOW_FOCUS_EVENT;
|
|
ws->ws_focus_event = firm_event;
|
|
ws_set_focus(ws, FF_KBD_EVENT);
|
|
} else if ((firm_event.id == ws->ws_kbd_focus_pt.id) &&
|
|
ws_focus_match(ws, &ws->ws_kbd_focus_pt,
|
|
&firm_event)) {
|
|
ws->ws_flags &= ~WSF_SWALLOW_FOCUS_EVENT;
|
|
ws->ws_focus_event = firm_event;
|
|
ws_set_focus(ws, FF_KBD_EVENT);
|
|
}
|
|
/* Send firm_event if no new focuses */
|
|
if (ws_set_focus_state(ws))
|
|
break;
|
|
else {
|
|
/* Clear focus event flag if haven't yet */
|
|
ws->ws_flags &= ~WSF_SEND_FOCUS_EVENT;
|
|
/* Send batched events all at once */
|
|
if (firm_event.id == VLOC_BATCH)
|
|
ws_send_batch(ws, firm_event.value);
|
|
else
|
|
win_send(ws, &firm_event);
|
|
}
|
|
break;
|
|
|
|
#ifdef WINDEVDEBUG
|
|
default:
|
|
printf("Unknown input state\n");
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
ws_send_kbd_request(ws, w, fe)
|
|
Workstation *ws;
|
|
Window *w;
|
|
Firm_event *fe;
|
|
{
|
|
/*
|
|
* If LOC_WINENTER is not the kbd focus change event and
|
|
* event timeout is not zero (both of which make a
|
|
* kbd change request not workable) then give
|
|
* application a chance to say no to change.
|
|
*/
|
|
fe->id = KBD_REQUEST;
|
|
if (((ws->ws_kbd_focus_sw.id != LOC_WINENTER) ||
|
|
(ws->ws_kbd_focus_pt.id != LOC_WINENTER)) &&
|
|
(timerisset(&ws->ws_eventtimeout)) &&
|
|
(w != WINDOW_NULL) &&
|
|
(win_send_one(w, fe, &w->w_pickmask, INPUTMASK_NULL) != -1)) {
|
|
/* Set requesting flag */
|
|
ws->ws_flags |= WSF_KBD_REQUEST_PENDING;
|
|
/* Move to next state */
|
|
ws->ws_focus_state = REQUEST_WAIT;
|
|
} else
|
|
/* Move to next state */
|
|
ws->ws_focus_state = SEND_DONE;
|
|
}
|
|
|
|
int
|
|
ws_focus_match(ws, fs, fe)
|
|
Workstation *ws;
|
|
Ws_focus_set *fs;
|
|
Firm_event *fe;
|
|
{
|
|
if ((fe->id == fs->id) &&
|
|
(vuid_get_value(ws->ws_instate, fe->id) == fs->value) &&
|
|
((fs->shifts == WS_FOCUS_ANY_SHIFT) ||
|
|
(((fs->shifts & ws->ws_shiftmask) ^ fs->shifts) == 0)))
|
|
return (1);
|
|
else
|
|
return (0);
|
|
}
|
|
|
|
/* Return 1 if change focus state due to new focuses, return 0 otherwise */
|
|
int
|
|
ws_set_focus_state(ws)
|
|
register Workstation *ws;
|
|
{
|
|
/* Do error check */
|
|
if (ws->ws_focus_state != SEND_Q_TOP) {
|
|
#ifdef WINDEVDEBUG
|
|
printf("Focus state should be SEND_Q_TOP %D\n",
|
|
ws->ws_focus_state);
|
|
#endif
|
|
ws->ws_focus_state = SEND_Q_TOP;
|
|
return (1);
|
|
}
|
|
/*
|
|
* If current pick focus not equal to next pick focus
|
|
* then set to new state (SEND_ENTER or SEND_EXIT)
|
|
* and return 1.
|
|
*/
|
|
if (ws->ws_pickfocus != ws->ws_pickfocus_next) {
|
|
if (ws->ws_pickfocus == WINDOW_NULL)
|
|
ws->ws_focus_state = SEND_ENTER;
|
|
else
|
|
ws->ws_focus_state = SEND_EXIT;
|
|
return (1);
|
|
}
|
|
/*
|
|
* If current kbd focus not equal to next kbd focus
|
|
* then set to new state (SEND_REQUEST) and return 1.
|
|
*/
|
|
if (ws->ws_kbdfocus != ws->ws_kbdfocus_next) {
|
|
ws->ws_focus_state = SEND_REQUEST;
|
|
return (1);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
/* Conditionally collapse locator events at top of input queue */
|
|
ws_collapse_q(ws)
|
|
register Workstation *ws;
|
|
{
|
|
Firm_event peek_fe;
|
|
Firm_event collapse_fe;
|
|
int collapsed = 0;
|
|
extern u_int ws_vq_node_bytes;
|
|
extern void ws_shrink_queue();
|
|
|
|
if (ws_no_collapse)
|
|
return;
|
|
if (vq_used(&ws->ws_q) == 0 && ws->ws_qbytes > ws_vq_node_bytes)
|
|
ws_shrink_queue(ws);
|
|
/*
|
|
* Don't collapse if going to send focus event because will mess up
|
|
* shift mask state and loc positions when get around to sending, later.
|
|
*/
|
|
if (ws->ws_flags & WSF_SEND_FOCUS_EVENT)
|
|
return;
|
|
/* Don't collapse if pick focus is tracking trajectory */
|
|
#ifndef lint
|
|
if ((ws->ws_pickfocus != WINDOW_NULL) &&
|
|
(win_getinputcodebit(&ws->ws_pickfocus->w_pickmask,LOC_TRAJECTORY)))
|
|
return;
|
|
#endif
|
|
while ((vq_used(&ws->ws_q) > 1) && /* Check possibility of collapse */
|
|
(vq_used(&ws->ws_q) > ws_q_collapse_trigger) &&
|
|
(vq_peek(&ws->ws_q, &peek_fe) != VUID_Q_EMPTY)) {
|
|
if ((ws_is_loc_change(peek_fe.id)) ||
|
|
(peek_fe.id == LOC_STILL)) {
|
|
collapse_fe = ws_get_event(ws);
|
|
collapsed = 1;
|
|
} else
|
|
break;
|
|
}
|
|
/*
|
|
* Put back last event taken so don't wipe out event trigger
|
|
* and loose an event.
|
|
*/
|
|
if (collapsed) {
|
|
if (ws_is_loc_change(collapse_fe.id))
|
|
collapse_fe.id = LOC_MOVE;
|
|
/* else will be LOC_STILL */
|
|
collapse_fe.value = 1; /* Set to one because event has no neg */
|
|
/* use given time */
|
|
collapse_fe.pair = 0;
|
|
collapse_fe.pair_type = FE_PAIR_NONE;
|
|
#ifdef WS_DEBUG
|
|
if (ws_qputback_debug) printf("q putback id %D value %D avail %D\n",
|
|
collapse_fe.id, collapse_fe.value, vq_avail(&ws->ws_q));
|
|
#endif WS_DEBUG
|
|
if (vq_putback(&ws->ws_q, &collapse_fe) != VUID_Q_OK)
|
|
#ifdef WINDEVDEBUG
|
|
printf("putback error\n");
|
|
#else
|
|
;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Non-wakeup window transition capability over windows which are looking
|
|
* for LOC_MOVEs, LOC_WINENTERs, LOC_WINEXITs, KBD_USE and KBD_DONE.
|
|
*/
|
|
ws_window_transit(ws)
|
|
register Workstation *ws;
|
|
{
|
|
Firm_event firm_event;
|
|
int dequeued_loc_change = 0;
|
|
|
|
while (ws->ws_flags & WSF_LOC_IN_TRANSIT) {
|
|
/* Peek at top of input queue */
|
|
if (vq_peek(&ws->ws_q, &firm_event) == VUID_Q_EMPTY)
|
|
break;
|
|
if (!ws_is_loc_change(firm_event.id)) {
|
|
ws->ws_flags &= ~WSF_LOC_IN_TRANSIT;
|
|
} else {
|
|
/* Get locator motion from input queue */
|
|
firm_event = ws_get_event(ws);
|
|
dequeued_loc_change = 1;
|
|
if (ws_focus_during_each_transit)
|
|
ws_set_focus(ws, FF_PICK_CHANGE);
|
|
}
|
|
}
|
|
if (dequeued_loc_change && !ws_focus_during_each_transit)
|
|
ws_set_focus(ws, FF_PICK_CHANGE);
|
|
}
|
|
|
|
/*
|
|
* Depending on flags and ws fields update either ws_kbdfocus_next or
|
|
* ws_pickfocus_next or both. FF_PICK_CHANGE or FF_KBD_EVENT are the flags.
|
|
*
|
|
* This routine is called in a variety of circumstances:
|
|
*
|
|
* 1) A user action has been pulled off the top of the input q that might
|
|
* require a change in focus.
|
|
* 2) A window is being closed that held one or both of the input focuses
|
|
* thus forcing the selection of a new focus.
|
|
* 3) A change of window clipping, visibility or position that might
|
|
* affect locator position dependent focus changing (the pick focus
|
|
* will surely be affected). Programmatic setting of the locator
|
|
* position is a similar situation.
|
|
* 4) When a workstation is first started and there is no focus.
|
|
* 5) When a window has grabbed or released the input focus.
|
|
* 6) When trying to complete a focus transition.
|
|
*
|
|
* A focus is never null unless starting out or current focus closed.
|
|
* There is enough difference between a LOC_WINENTER based kbd focus change
|
|
* event and others (say MS_LEFT) that we treat the others separately.
|
|
*/
|
|
void
|
|
ws_set_focus(ws, flags)
|
|
register Workstation *ws;
|
|
int flags;
|
|
{
|
|
#ifdef WS_DEBUG
|
|
if (ws_set_focus_debug) printf(
|
|
"ws_set_focus start: flags %X k %X kn %X p %X pn %X\n",
|
|
flags,
|
|
ws->ws_kbdfocus, ws->ws_kbdfocus_next,
|
|
ws->ws_pickfocus, ws->ws_pickfocus_next);
|
|
#endif WS_DEBUG
|
|
/* Check pick focus if might have changed */
|
|
if (flags & (FF_PICK_CHANGE | FF_KBD_EVENT))
|
|
ws_set_pick_focus_next(ws);
|
|
/* If kbd focus event is LOC_WINENTER follow pick focus */
|
|
if (ws->ws_kbd_focus_sw.id == LOC_WINENTER &&
|
|
ws->ws_kbd_focus_pt.id == LOC_WINENTER)
|
|
ws->ws_kbdfocus_next = ws->ws_pickfocus_next;
|
|
/* Set both focuses from ws_inputgrabber */
|
|
if (ws->ws_inputgrabber != WINDOW_NULL) {
|
|
ws->ws_pickfocus_next = ws->ws_inputgrabber;
|
|
ws->ws_kbdfocus_next = ws->ws_inputgrabber;
|
|
return;
|
|
}
|
|
/* Update kbd focus on a focus change event */
|
|
if (flags & FF_KBD_EVENT) {
|
|
ws->ws_flags |= WSF_SEND_FOCUS_EVENT;
|
|
ws->ws_kbdfocus_next = ws->ws_pickfocus_next;
|
|
}
|
|
#ifdef WS_DEBUG
|
|
if (ws_set_focus_debug) printf("ws_set_focus end: k %X kn %X p %X pn %X\n",
|
|
ws->ws_kbdfocus, ws->ws_kbdfocus_next,
|
|
ws->ws_pickfocus, ws->ws_pickfocus_next);
|
|
#endif WS_DEBUG
|
|
}
|
|
|
|
/*
|
|
* Take next item off input queue.
|
|
* Take two if locator changes if have same time.
|
|
*/
|
|
Firm_event
|
|
ws_get_event(ws)
|
|
register Workstation *ws;
|
|
{
|
|
Firm_event firm_event;
|
|
register Desktop *dtop_pick = ws->ws_pick_dtop;
|
|
|
|
Again:
|
|
/* Get top of input queue */
|
|
if (vq_get(&ws->ws_q, &firm_event) == VUID_Q_EMPTY) {
|
|
#ifdef WINDEVDEBUG
|
|
printf("Window input: tried to read empty q\n");
|
|
#endif
|
|
}
|
|
#ifdef WINDEVDEBUG
|
|
if (ws_qget_debug) printf("q get id %D value %D avail %D sec %D usec %D\n",
|
|
firm_event.id, firm_event.value, vq_avail(&ws->ws_q),
|
|
firm_event.time.tv_sec, firm_event.time.tv_usec);
|
|
#endif
|
|
/* Turn locator motion into LOC_MOVE */
|
|
if (ws_is_loc_change(firm_event.id)) {
|
|
Firm_event loc_event;
|
|
|
|
switch (firm_event.id) {
|
|
|
|
case LOC_X_DELTA:
|
|
dtop_pick->dt_ut_x += firm_event.value;
|
|
break;
|
|
|
|
case LOC_Y_DELTA:
|
|
dtop_pick->dt_ut_y += firm_event.value;
|
|
break;
|
|
|
|
case LOC_X_ABSOLUTE:
|
|
dtop_pick->dt_ut_x = firm_event.value;
|
|
break;
|
|
|
|
case LOC_Y_ABSOLUTE:
|
|
dtop_pick->dt_ut_y = firm_event.value;
|
|
break;
|
|
|
|
case LOC_MOVE:
|
|
break;
|
|
|
|
default:
|
|
{}
|
|
}
|
|
ws->ws_flags |= WSF_LATEST_WAS_MOTION;
|
|
if (vq_peek(&ws->ws_q, &loc_event) == VUID_Q_EMPTY)
|
|
goto LocMove;
|
|
/* See if should merge with firm_event in to one event */
|
|
if ((ws_is_loc_change(loc_event.id)) &&
|
|
(tv_equal(loc_event.time, firm_event.time)))
|
|
goto Again;
|
|
LocMove:
|
|
firm_event.id = LOC_MOVE;
|
|
firm_event.value = 1; /* Set to one because event has no neg */
|
|
firm_event.pair = 0;
|
|
firm_event.pair_type = FE_PAIR_NONE;
|
|
/* use given time */
|
|
} else {
|
|
/* Set user time state */
|
|
vuid_set_value(&ws->ws_instate, &firm_event);
|
|
/* Maintain shiftmask state for win_sendevent */
|
|
ws_set_shiftmask(ws, &firm_event);
|
|
/* Maintain state of shift keys when a key goes down, for META events. This is
|
|
done as a META event may be missed if shift state has changed when it comes up */
|
|
if(firm_event.value == 1 && firm_event.id >= META_FIRST && firm_event.id <= META_LAST)
|
|
shift_statearray_meta[firm_event.id-META_FIRST] = ws->ws_shiftmask;
|
|
/* Maintain latest motion flag */
|
|
if (firm_event.id == LOC_STILL)
|
|
ws->ws_flags &= ~WSF_LATEST_WAS_MOTION;
|
|
}
|
|
return (firm_event);
|
|
}
|
|
|
|
ws_flush_input(ws)
|
|
register Workstation *ws;
|
|
{
|
|
register Desktop *dtop;
|
|
|
|
while (!vq_is_empty(&ws->ws_q))
|
|
(void) ws_get_event(ws);
|
|
vuid_destroy_state(ws->ws_instate);
|
|
ws->ws_instate = vuid_copy_state(ws->ws_rtstate);
|
|
if ((dtop = ws->ws_loc_dtop) != DESKTOP_NULL) {
|
|
dtop->dt_ut_x = dtop->dt_rt_x;
|
|
dtop->dt_ut_y = dtop->dt_rt_y;
|
|
}
|
|
bzero((caddr_t)&ws->ws_surpress_mask, sizeof (ws->ws_surpress_mask));
|
|
}
|
|
|
|
ws_set_shiftmask(ws, fe)
|
|
register Workstation *ws;
|
|
register Firm_event *fe;
|
|
{
|
|
#define shift_mask_update(ws, fe, bit) \
|
|
if ((fe)->value) \
|
|
(ws)->ws_shiftmask |= (1 << (bit)); \
|
|
else \
|
|
(ws)->ws_shiftmask &= ~(1 << (bit));
|
|
|
|
switch (fe->id) {
|
|
|
|
case SHIFT_CAPSLOCK:
|
|
shift_mask_update(ws, fe, CAPSLOCK);
|
|
break;
|
|
|
|
case SHIFT_LOCK:
|
|
shift_mask_update(ws, fe, SHIFTLOCK);
|
|
break;
|
|
|
|
case SHIFT_LEFT:
|
|
shift_mask_update(ws, fe, LEFTSHIFT);
|
|
break;
|
|
|
|
case SHIFT_RIGHT:
|
|
shift_mask_update(ws, fe, RIGHTSHIFT);
|
|
break;
|
|
|
|
case SHIFT_LEFTCTRL:
|
|
shift_mask_update(ws, fe, LEFTCTRL);
|
|
break;
|
|
|
|
case SHIFT_RIGHTCTRL:
|
|
shift_mask_update(ws, fe, RIGHTCTRL);
|
|
break;
|
|
|
|
case SHIFT_META:
|
|
#define META_SHIFT_BIT 6
|
|
/*
|
|
* Use of 6 instead of constant: Done at last minute in 3.0
|
|
* release so would have meta mask. Wanted to use METAMASK
|
|
* (from kbd.h) but value is the same as the no longer
|
|
* supported UPMASK. Chose to use 6 because corresponds to
|
|
* the "unused... 0x0040" value in kbd.h.
|
|
* META_SHIFT_MASK is in win_input.h & need to claim that it
|
|
* is used in kbd.h.
|
|
*/
|
|
shift_mask_update(ws, fe, META_SHIFT_BIT);
|
|
break;
|
|
|
|
case SHIFT_ALT:
|
|
shift_mask_update(ws, fe, ALT);
|
|
break;
|
|
|
|
default:
|
|
/* No longer supporting UPMASK or CTLSMASK */
|
|
{}
|
|
}
|
|
}
|
|
|
|
ws_set_pick_focus_next(ws)
|
|
Workstation *ws;
|
|
{
|
|
Desktop *dtop_pick = ws->ws_pick_dtop; /* can't be register */
|
|
int x_now, y_now; /* can't be register */
|
|
|
|
if ((dtop_pick == NULL) || (dtop_pick->dt_rootwin == NULL))
|
|
return;
|
|
|
|
/* Clamp locator to desktop or move onto adjoinning desktop */
|
|
x_now = dtop_pick->dt_ut_x;
|
|
y_now = dtop_pick->dt_ut_y;
|
|
#ifdef WS_DEBUG
|
|
if (ws_track_debug) printf("TRACK dtop=%X, x=%D, y=%D\n",
|
|
dtop_pick, x_now, y_now);
|
|
#endif WS_DEBUG
|
|
dtop_track_locator(&dtop_pick, &x_now, &y_now);
|
|
#ifdef WS_DEBUG
|
|
if (ws_track_debug) printf("RESULT dtop=%X, x=%D, y=%D\n",
|
|
dtop_pick, x_now, y_now);
|
|
#endif WS_DEBUG
|
|
/* Reset pick desktop */
|
|
ws->ws_pick_dtop = dtop_pick;
|
|
/* Update dtop_pick's notion of locator position */
|
|
dtop_pick->dt_ut_x = x_now;
|
|
dtop_pick->dt_ut_y = y_now;
|
|
|
|
/* Use locator position to determine pick focus */
|
|
ws->ws_pickfocus_next = wt_intersected(dtop_pick->dt_rootwin,
|
|
x_now, y_now);
|
|
}
|
|
|
|
ws_send_batch(ws, n)
|
|
register Workstation *ws;
|
|
int n;
|
|
{
|
|
Firm_event firm_event;
|
|
register i;
|
|
|
|
if (vq_used(&ws->ws_q) < n) {
|
|
#ifdef WINDEVDEBUG
|
|
printf("ws_send_batch: batch number too large\n");
|
|
#endif
|
|
return;
|
|
}
|
|
for (i = 0; i < n; i++) {
|
|
if (vq_is_empty(&ws->ws_q))
|
|
break;
|
|
firm_event = ws_get_event(ws);
|
|
win_send(ws, &firm_event);
|
|
}
|
|
}
|
|
|
|
/* return TRUE if a workstation lock is set or
|
|
* a lock is set on the desktop.
|
|
*/
|
|
static int
|
|
ws_check_all_locks(lok_client)
|
|
caddr_t lok_client;
|
|
{
|
|
register Desktop *dtop = (Desktop *) lok_client;
|
|
|
|
if (!dtop)
|
|
return FALSE;
|
|
|
|
return ((dtop->dt_ws->ws_flags & WSF_ALL_LOCKS) ||
|
|
dtop_check_all_locks((caddr_t) dtop));
|
|
}
|
|
|
|
|
|
/*
|
|
* Acquire the event processing lock for the event consumer window's process.
|
|
* Kernel thread of control can't sleep, so must know that lock is
|
|
* not on when call. Actually, unlike other locks, callers of this routine
|
|
* should never block and it should never be locked multiple times.
|
|
* This lock is acquired before placing an input event on a window's clist.
|
|
*/
|
|
|
|
extern int noproc;
|
|
|
|
ws_lock_event(ws, w)
|
|
register Workstation *ws;
|
|
register Window *w;
|
|
{
|
|
void ws_unlock_event(), ws_timedout_event(), ws_force_event();
|
|
register struct proc *process;
|
|
extern int noproc; /* true if no one is running */
|
|
|
|
if (ws->ws_flags & WSF_LOCKED_EVENT) {
|
|
#ifdef WINDEVDEBUG
|
|
printf("ws_lock_event: already locked\n");
|
|
#endif
|
|
return;
|
|
}
|
|
if (w == WINDOW_NULL) {
|
|
#ifdef WINDEVDEBUG
|
|
printf("ws_lock_event: NULL window arg\n");
|
|
#endif
|
|
return;
|
|
}
|
|
/*
|
|
* If this process can not acquire the
|
|
* event lock then no event synchronization.
|
|
*/
|
|
if (w->w_flags & WF_UNSYNCHRONIZED)
|
|
return;
|
|
/* Favor the event recipient */
|
|
ws_favor(ws, w);
|
|
/* If event time out is not set then no event synchronization */
|
|
if (!timerisset(&ws->ws_eventtimeout))
|
|
return;
|
|
/*
|
|
* Get process pointer to use for lock
|
|
* Note - cannot use u.u_procp if noproc is true!
|
|
*/
|
|
if (noproc == 0 && w->w_pid == u.u_procp->p_pid) {
|
|
/* Case when read or select thread reacquiring lock */
|
|
process = u.u_procp;
|
|
} else {
|
|
extern struct proc *pfind();
|
|
|
|
/* Case when kernel thread acquiring lock (more expensive) */
|
|
if ((process = pfind(w->w_pid)) == ((struct proc *)0)) {
|
|
/* Process has gone away */
|
|
return;
|
|
}
|
|
}
|
|
wlok_setlock(&ws->ws_eventlock, &ws->ws_flags, WSF_LOCKED_EVENT,
|
|
&ws->ws_eventlock.lok_count_storage, process);
|
|
ws->ws_eventlock.lok_client = (caddr_t)w->w_desktop;
|
|
ws->ws_eventlock.lok_unlock_action = ws_unlock_event;
|
|
ws->ws_eventlock.lok_limit = ws->ws_eventtimeout;
|
|
ws->ws_eventlock.lok_timeout_action = ws_timedout_event;
|
|
ws->ws_eventlock.lok_string = "event";
|
|
ws->ws_eventlock.lok_force_action = ws_force_event;
|
|
ws->ws_eventlock.lok_wakeup = (caddr_t) &ws->ws_flags;
|
|
if (!ws_verbose_event_lock)
|
|
ws->ws_eventlock.lok_options |= WLOK_SILENT;
|
|
ws->ws_eventlock.lok_other_check = ws_check_all_locks;
|
|
ws->ws_event_consumer = w;
|
|
}
|
|
|
|
/*
|
|
* Unlock the access right to the next event on the queue.
|
|
* ws_unlock_event doesn't care if the unlock is forced or
|
|
* congenial.
|
|
*/
|
|
void
|
|
ws_unlock_event(wlock)
|
|
Winlock *wlock;
|
|
{
|
|
Desktop *dtop = (Desktop *)wlock->lok_client;
|
|
Workstation *ws = dtop->dt_ws;
|
|
|
|
ws->ws_event_consumer = WINDOW_NULL;
|
|
}
|
|
|
|
/* No-op but needed if doing timeout stuff */
|
|
void
|
|
ws_timedout_event()
|
|
{
|
|
#ifdef WINDEVDEBUG
|
|
if (ws_event_timeout_msg) printf("TIMEOUT EVENT\n");
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Make it so that the offending process doesn't acquire the event lock
|
|
* until input queue empties or gets to read or select.
|
|
*/
|
|
void
|
|
ws_force_event(wlock)
|
|
Winlock *wlock;
|
|
{
|
|
Desktop *dtop = (Desktop *)wlock->lok_client;
|
|
Workstation *ws = dtop->dt_ws;
|
|
int win_dont_lock();
|
|
|
|
/* Find every window in this process and mark as not lockable */
|
|
ws_lock_control_pid = wlock->lok_pid;
|
|
if (ws->ws_event_consumer && ws->ws_event_consumer->w_desktop)
|
|
wt_enumeratechildren(win_dont_lock,
|
|
ws->ws_event_consumer->w_desktop->dt_rootwin,
|
|
(struct rect *)0);
|
|
ws_lock_control_pid = 0;
|
|
}
|
|
|
|
/*
|
|
* If window's process is currently unsyncronized, see if can
|
|
* allow it to acquire the event lock.
|
|
*/
|
|
ws_try_event_enable(w)
|
|
register Window *w;
|
|
{
|
|
int win_empty_input();
|
|
|
|
/* Find every window in this process and see if all have empty qs */
|
|
ws_lock_control_pid = w->w_pid;
|
|
ws_empty_input_flag = 1;
|
|
wt_enumeratechildren(win_empty_input, w->w_desktop->dt_rootwin,
|
|
(struct rect *)0);
|
|
ws_lock_control_pid = 0;
|
|
if (ws_empty_input_flag)
|
|
ws_enable_event(w);
|
|
}
|
|
|
|
/*
|
|
* Make it so that the windows in w's process can acquire the event lock.
|
|
*/
|
|
ws_enable_event(w)
|
|
register Window *w;
|
|
{
|
|
int win_can_lock();
|
|
|
|
/* Find every window in this process and mark as not lockable */
|
|
ws_lock_control_pid = w->w_pid;
|
|
wt_enumeratechildren(win_can_lock, w->w_desktop->dt_rootwin,
|
|
(struct rect *)0);
|
|
ws_lock_control_pid = 0;
|
|
}
|
|
|
|
/*
|
|
* Called from wt_enumeratechildren so don't change calling sequence
|
|
*/
|
|
/*ARGSUSED*/
|
|
win_dont_lock(w, rect)
|
|
struct window *w;
|
|
struct rect *rect; /* Don't use for anything else (not caddr_t) */
|
|
{
|
|
|
|
if (!(w->w_flags & WF_OPEN) || (w->w_pid != ws_lock_control_pid))
|
|
return (-1);
|
|
w->w_flags |= WF_UNSYNCHRONIZED;
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Called from wt_enumeratechildren so don't change calling sequence
|
|
*/
|
|
/*ARGSUSED*/
|
|
win_empty_input(w, rect)
|
|
struct window *w;
|
|
struct rect *rect; /* Don't use for anything else (not caddr_t) */
|
|
{
|
|
|
|
if (!(w->w_flags & WF_OPEN) || (w->w_pid != ws_lock_control_pid))
|
|
return (-1);
|
|
if (w->w_desktop->dt_sharedq_owner == w) {
|
|
win_sharedq_shift(w);
|
|
if (w->w_desktop->shared_info->shared_eventq.head
|
|
== w->w_desktop->shared_info->shared_eventq.tail)
|
|
ws_empty_input_flag = 0;
|
|
} else
|
|
if (w->w_input.c_cc != 0)
|
|
ws_empty_input_flag = 0;
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Called from wt_enumeratechildren so don't change calling sequence
|
|
*/
|
|
/*ARGSUSED*/
|
|
win_can_lock(w, rect)
|
|
struct window *w;
|
|
struct rect *rect; /* Don't use for anything else (not caddr_t) */
|
|
{
|
|
|
|
if (!(w->w_flags & WF_OPEN) || (w->w_pid != ws_lock_control_pid))
|
|
return (-1);
|
|
w->w_flags &= ~WF_UNSYNCHRONIZED;
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
ws_lockio(dev)
|
|
dev_t dev;
|
|
{
|
|
register struct window *w = winfromdev(dev);
|
|
register Desktop *dtop = w->w_desktop;
|
|
register Workstation *ws = dtop->dt_ws;
|
|
void ws_unlock_io();
|
|
|
|
/* Currently, locking a dev you have locked increments a ref count */
|
|
if ((ws->ws_flags & WSF_LOCKED_IO) == 0) {
|
|
/* update the shared memory to show we are waiting */
|
|
ws_set_dtop_waiting(ws, 1);
|
|
|
|
while ((ws->ws_flags & WSF_LOCKED_IO) &&
|
|
ws_dtop_mutex_locked(ws))
|
|
if (sleep((caddr_t)&ws->ws_flags, LOCKPRI|PCATCH)) {
|
|
ws_set_dtop_waiting(ws, -1);
|
|
return (-1);
|
|
}
|
|
|
|
/* update the shared memory to show we are not waiting */
|
|
ws_set_dtop_waiting(ws, -1);
|
|
|
|
wlok_setlock(&ws->ws_iolock, &ws->ws_flags, WSF_LOCKED_IO,
|
|
&ws->ws_iolock.lok_count_storage, u.u_procp);
|
|
ws->ws_iolock.lok_client = (caddr_t)dtop;
|
|
/* So can get to ws, too */
|
|
ws->ws_iolock.lok_unlock_action = ws_unlock_io;
|
|
ws->ws_iolock.lok_timeout_action = NULL;
|
|
ws->ws_iolock.lok_string = "io";
|
|
ws->ws_iolock.lok_wakeup = (caddr_t) &ws->ws_flags;
|
|
ws->ws_iolock.lok_other_check = ws_check_all_locks;
|
|
|
|
/* update the shared memory */
|
|
ws_set_dtop_grabio(ws, TRUE, ws->ws_iolock.lok_pid);
|
|
|
|
dtop->dt_displaygrabber = w;
|
|
ws->ws_inputgrabber = w;
|
|
ws->ws_pre_grab_kbd_focus = ws->ws_kbdfocus;
|
|
ws->ws_pre_grab_kbd_focus_next = ws->ws_kbdfocus_next;
|
|
ws->ws_pre_grab_pick_focus = ws->ws_pickfocus;
|
|
ws->ws_pre_grab_pick_focus_next = ws->ws_pickfocus_next;
|
|
ws->ws_kbdfocus = w;
|
|
ws->ws_pickfocus = w;
|
|
ws_set_focus(ws, 0);
|
|
/* Save extremes of std colormap, set to standard values */
|
|
dtop_save_grnds(dtop);
|
|
dtop_set_bkgnd(dtop);
|
|
dtop->dt_flags |= DTF_NEWCMAP;
|
|
/* Set cursor */
|
|
dtop_set_cursor(dtop);
|
|
/* Write cursor to enable plane */
|
|
if (dtop->dt_flags & DTF_MULTI_PLANE_GROUPS &&
|
|
dtop->dt_plane_groups_available[PIXPG_OVERLAY_ENABLE]) {
|
|
enable_plane_cursor_set_active(dtop, TRUE);
|
|
/* Choose color of enable plane cursor */
|
|
switch (w->w_plane_group) {
|
|
case PIXPG_OVERLAY:
|
|
case PIXPG_CURRENT:
|
|
case PIXPG_MONO:
|
|
#ifndef PRE_FLAMINGO
|
|
case PIXPG_24BIT_COLOR:
|
|
case PIXPG_VIDEO:
|
|
#endif
|
|
dtop->dt_cursor.enable_color = 1;
|
|
break;
|
|
default:
|
|
dtop->dt_cursor.enable_color = 0;
|
|
}
|
|
}
|
|
#ifndef PRE_FLAMINGO
|
|
/* Write cursor to video enable plane */
|
|
if (dtop->dt_flags & DTF_MULTI_PLANE_GROUPS &&
|
|
dtop->dt_plane_groups_available[PIXPG_VIDEO_ENABLE])
|
|
videnb_plane_cursor_set_active(dtop, TRUE);
|
|
#endif
|
|
} else
|
|
*(ws->ws_iolock.lok_count) += 1;
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
ws_unlock_io(wlock)
|
|
Winlock *wlock;
|
|
{
|
|
register Desktop *dtop = (Desktop *)wlock->lok_client;
|
|
register Workstation *ws = dtop->dt_ws;
|
|
|
|
dtop->dt_displaygrabber = NULL;
|
|
ws->ws_inputgrabber = NULL;
|
|
/*
|
|
* This is a hack to force reloading of the colormap even
|
|
* though it may not be needed. This is meant to give the
|
|
* user a way that he can cleanup after a non-window
|
|
* or errant program that left the color map messed up.
|
|
* Moving a window, envoking a menu both are ways to cause
|
|
* WINRELEASEIO to be called.
|
|
*/
|
|
dtop_restore_grnds(dtop);
|
|
dtop->dt_flags |= DTF_NEWCMAP;
|
|
ws->ws_kbdfocus = ws->ws_pre_grab_kbd_focus;
|
|
ws->ws_kbdfocus_next = ws->ws_pre_grab_kbd_focus_next;
|
|
ws->ws_pickfocus = ws->ws_pre_grab_pick_focus;
|
|
ws->ws_pickfocus_next = ws->ws_pre_grab_pick_focus_next;
|
|
ws_set_focus(ws, FF_PICK_CHANGE);
|
|
/*
|
|
* Stop writing cursor to enable plane.
|
|
* Take down cursor first so that enable plane is restored.
|
|
*/
|
|
dtop_cursordown(dtop);
|
|
enable_plane_cursor_set_active(dtop, FALSE);
|
|
#ifndef PRE_FLAMINGO
|
|
videnb_plane_cursor_set_active(dtop, FALSE);
|
|
#endif
|
|
dtop_set_cursor(dtop);
|
|
dtop_cursorup(dtop);
|
|
|
|
/* clear the grabio lock in each dtop's
|
|
* shared memory.
|
|
*/
|
|
ws_set_dtop_grabio(ws, FALSE, 0);
|
|
|
|
/*
|
|
* The following wakeup is done because a WINLOCKSCREEN
|
|
* may be waiting on io lock being released.
|
|
*/
|
|
wakeup((caddr_t)dtop->shared_info);
|
|
}
|
|
|
|
static int
|
|
ws_dtop_mutex_locked(ws)
|
|
Workstation *ws;
|
|
{
|
|
register Desktop *dtop;
|
|
|
|
for (dtop = ws->ws_dtop; dtop; dtop = dtop->dt_next)
|
|
if (win_lock_mutex_locked(dtop->shared_info))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static void
|
|
ws_set_dtop_grabio(ws, on, pid)
|
|
Workstation *ws;
|
|
int on;
|
|
int pid;
|
|
{
|
|
register Desktop *dtop;
|
|
|
|
for (dtop = ws->ws_dtop; dtop; dtop = dtop->dt_next) {
|
|
win_lock_set(&dtop->shared_info->grabio, on);
|
|
dtop->shared_info->grabio.pid = pid;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
ws_set_dtop_waiting(ws, num)
|
|
Workstation *ws;
|
|
int num;
|
|
{
|
|
register Desktop *dtop;
|
|
|
|
for (dtop = ws->ws_dtop; dtop; dtop = dtop->dt_next) {
|
|
dtop->shared_info->waiting += num;
|
|
}
|
|
}
|