--- /dev/null
+#include <X/mit-copyright.h>
+
+/* Copyright Massachusetts Institute of Technology 1985 */
+
+/* Routines for dealing with input devices and events:
+ *
+ * Register_cursor, Unregister_cursor, Interpret_locator,
+ * Grab_mouse, Ungrab_mouse, Grab_button, Ungrab_button, Warp_mouse,
+ * Focus_keyboard, Unbutton_window, Ungrab_client, Select_input,
+ * Set_shiftlock, Startup_mouse,
+ * Deal_with_movement, Deal_with_input,
+ * Stash_changes, Stash_misses, Stash_simple
+ */
+
+#ifndef lint
+static char *rcsid_input_c = "$Header: input.c,v 10.11 86/02/01 15:16:07 tony Rel $";
+#endif
+
+
+#include "Xint.h"
+
+extern u_char Xstatus;
+extern DEVICE device;
+extern WINDOW *rootwindow;
+extern RECTANGLE *free_rectangles;
+#ifdef DUALTCP
+extern int swapped[];
+#endif
+
+typedef struct grab_info {
+ int client; /* Grabbing client */
+ WINDOW *window; /* Event window */
+ long mask; /* Event mask */
+ CURSOR *cursor; /* Cursor info */
+} GRAB_INFO;
+
+static short mouse_x = 0, mouse_y = 0; /* The mouse state */
+CURSOR *cursor = NULL; /* Current cursor */
+static WINDOW *cursor_window = NULL; /* Where cursor came from */
+static WINDOW *mouse_window; /* Where mouse currently is */
+RASTER mbox; /* Mouse motion bounding box */
+WINDOW *button_window = NULL; /* Where button was pressed */
+int mouse_grabber = 0; /* Who has grabbed the mouse */
+WINDOW *mouse_grab_window; /* Window for grab events */
+static long mouse_grab_mask; /* Grab events of interest */
+static unsigned mouse_grab_button; /* Button that caused grab */
+WINDOW *key_window; /* Keyboard focus window */
+static ushort key_level; /* key_window->level */
+static unsigned state_mask = 0; /* key and button state mask */
+static int lock_mode = 1; /* shiftlock mode */
+static unsigned lock_mask = 0; /* shiftlock shadow mask */
+static long motion_mask = MouseMoved; /* motion events */
+#define GRABS 48
+static GRAB_INFO bgrabs[GRABS]; /* button grab info */
+#define GRABIDX(but,mask) ((but << 4) + FullKeyState(mask))
+#define grabbits (ControlMask|MetaMask|ShiftMask|ShiftLockMask|LeftMask|MiddleMask|RightMask)
+
+#define ShiftKeyCode 0256
+#define ControlKeyCode 0257
+#define LockKeyCode 0260
+#define MetaKeyCode 0261
+
+/* Search down the heirarchy for the smallest enclosing window.
+ * This usually should be faster than doing a linear search of mapped_list,
+ * and should be fast enough that we don't need to maintain extra, complicated
+ * data structures like a layered dag.
+ */
+
+#define SEARCH(x,y,w,ww) \
+ ww = rootwindow;\
+ w = ww->last_child;\
+ while (w) {\
+ if (TRUE(w->mapped) &&\
+ x >= w->vs.left && y >= w->vs.top &&\
+ x < w->vs.right && y < w->vs.bottom) {\
+ ww = w;\
+ w = ww->last_child;\
+ } else\
+ w = w->prev_sib;\
+ }\
+ if (w == NULL)\
+ w = ww
+
+/* Define the mouse cursor for a window */
+
+Register_cursor (w, curs)
+ register WINDOW *w;
+ register CURSOR *curs;
+{
+ register CURSOR *ocurs;
+
+ ocurs = w->cursor;
+ curs->refcnt++;
+ w->cursor = curs;
+ if (mouse_grabber == 0)
+ Check_cursor (w);
+ if (ocurs && --ocurs->refcnt == 0)
+ FreeCursor (ocurs);
+}
+
+/* Undefine the mouse cursor for a window */
+
+Unregister_cursor (w)
+ register WINDOW *w;
+{
+ register CURSOR *curs;
+
+ if ((curs = w->cursor) == NULL || w == rootwindow)
+ return;
+ w->cursor = NULL;
+ if (mouse_grabber == 0)
+ Check_cursor (w);
+ if (--curs->refcnt == 0)
+ FreeCursor (curs);
+}
+
+/* Start up the mouse. */
+
+Startup_mouse ()
+{
+ vsCursor mcursor;
+
+ cursor = rootwindow->cursor;
+ LoadCursor (cursor);
+ InitMouse ();
+ mcursor.x = (mouse_x = (device.width >> 1)) - cursor->xoff;
+ mcursor.y = (mouse_y = (device.height >> 1)) - cursor->yoff;
+ SetCursorPosition (&mcursor);
+ mouse_window = rootwindow;
+ mbox.bottom = 0;
+ Set_mbox ();
+}
+
+/* The cursor in the given window has changed. Check if it is/was the cursor
+ * window, and update the cursor if it is.
+ */
+
+Check_cursor (w)
+ register WINDOW *w;
+{
+ register WINDOW *ww;
+
+ if ((ww = mouse_window) == NULL) return;
+ for (; ww->cursor == NULL; ww = ww->parent) ;
+ if (ww != cursor_window || ww == w) {
+ New_cursor (0, 0);
+ Deal_with_movement ();
+ }
+}
+
+/* Change the cursor. The deltas give the physical adjustment from the old
+ * cursor to keep the "point" from moving.
+ */
+
+New_cursor (deltax, deltay)
+ int deltax, deltay;
+{
+ vsCursor mcursor;
+ register CURSOR *curs = cursor;
+ short x, y;
+ register WINDOW *w, *ww;
+ int old = 0;
+
+ mcursor = *device.mouse;
+ x = mcursor.x + cursor->xoff + deltax;
+ y = mcursor.y + cursor->yoff + deltay;
+
+ while (1) {
+ /* force cursor to stay in bounds */
+ if (x < curs->xmin)
+ x = curs->xmin;
+ else if (x > curs->xmax)
+ x = curs->xmax;
+
+ if (y < curs->ymin)
+ y = curs->ymin;
+ else if (y > curs->ymax)
+ y = curs->ymax;
+
+ if (mouse_grabber) break;
+ SEARCH(x, y, w, ww);
+ while (w->cursor == NULL)
+ w = w->parent;
+ if (old && w == cursor_window)
+ break;
+ cursor_window = w;
+ cursor = curs = w->cursor;
+ old = 1;
+ }
+
+ if ((x - curs->xoff) != mcursor.x ||
+ (y - curs->yoff) != mcursor.y) {
+ mcursor.x = x - curs->xoff;
+ mcursor.y = y - curs->yoff;
+ SetCursorPosition (&mcursor);
+ }
+ LoadCursor (curs);
+}
+
+/* Deal with mouse motion or window changes */
+
+Deal_with_movement ()
+{
+ vsCursor mcursor;
+ register CURSOR *curs = cursor;
+ register WINDOW *w, *ww, *oldw;
+ short x, y;
+ int new;
+
+ /* read current mouse coordinates */
+ mcursor = *device.mouse;
+ x = mcursor.x + curs->xoff;
+ y = mcursor.y + curs->yoff;
+
+ oldw = mouse_window;
+
+ /* fast check to see if we are still in box */
+ if (y < mbox.bottom && y >= mbox.top &&
+ x < mbox.right && x >= mbox.left) {
+ if (x != mouse_x || y != mouse_y) {
+ mouse_x = x;
+ mouse_y = y;
+ Stash_event (oldw, motion_mask, 0, x, y, 0);
+ }
+ /* may need to reset device mbox */
+ Set_mbox ();
+ return;
+ }
+ mbox.bottom = 0;
+
+ new = 0;
+ while (1) {
+ /* force cursor to stay in bounds */
+ if (x < curs->xmin)
+ x = curs->xmin;
+ else if (x > curs->xmax)
+ x = curs->xmax;
+
+ if (y < curs->ymin)
+ y = curs->ymin;
+ else if (y > curs->ymax)
+ y = curs->ymax;
+
+ SEARCH(x, y, w, ww);
+ if (w == mouse_window) break;
+ mouse_window = w;
+ if (mouse_grabber) break;
+ while (w->cursor == NULL)
+ w = w->parent;
+ if (w != cursor_window) {
+ cursor_window = w;
+ cursor = curs = w->cursor;
+ new = 1;
+ }
+ }
+
+ if ((x - curs->xoff) != mcursor.x ||
+ (y - curs->yoff) != mcursor.y) {
+ mcursor.x = x - curs->xoff;
+ mcursor.y = y - curs->yoff;
+ SetCursorPosition (&mcursor);
+ }
+ if TRUE(new)
+ LoadCursor (curs);
+
+ w = mouse_window;
+ if (w != oldw) {
+ mouse_x = x;
+ mouse_y = y;
+ while (oldw->level < w->level)
+ w = w->parent;
+ if (w == oldw)
+ Stash_event (oldw, (long) LeaveWindow,
+ IntoOrFromSubwindow, x, y, 0);
+ else {
+ if TRUE(oldw->mapped)
+ Stash_event (oldw, (long) LeaveWindow, 0, x, y, 0);
+ while (oldw->level > w->level) {
+ oldw = oldw->parent;
+ if (oldw == w) {
+ Stash_event (oldw, (long) EnterWindow,
+ IntoOrFromSubwindow, x, y, 0);
+ goto done; /* grot */
+ } else if ((oldw->mask & LeaveWindow) && TRUE(oldw->mapped))
+ Stash_event (oldw, (long) LeaveWindow,
+ VirtualCrossing, x, y, 0);
+ }
+ while (1) {
+ oldw = oldw->parent;
+ w = w->parent;
+ if (oldw == w)
+ break;
+ if ((oldw->mask & LeaveWindow) && TRUE(oldw->mapped))
+ Stash_event (oldw, (long) LeaveWindow,
+ VirtualCrossing, x, y, 0);
+ }
+ }
+ w = mouse_window;
+ if (oldw != w->parent)
+ Stash_enters (oldw, w->parent, 0);
+ Stash_event (w, (long) EnterWindow, 0, x, y, 0);
+ } else if (x != mouse_x || y != mouse_y) {
+ Stash_event (w, motion_mask, 0, x, y, 0);
+ mouse_x = x;
+ mouse_y = y;
+ }
+done: Set_mbox ();
+}
+
+/* Select events */
+
+Select_input (w, client, mask)
+ register WINDOW *w;
+ int client;
+ long mask;
+{
+ long omask = w->mask;
+
+ /* stop a button grab in progress if no longer interested in release */
+ if (w == button_window &&
+ (client != w->client || !(mask & ButtonReleased)))
+ button_window = NULL;
+ w->mask = mask;
+ w->client = client;
+
+ /* recompute motion box if movement interest changes */
+ if (mouse_grabber == 0 && ((omask ^ mask) & motion_mask))
+ Set_mbox ();
+}
+
+/* Change the ShiftLock mode */
+
+Set_shiftlock (mode)
+ register int mode;
+{
+ register unsigned mask;
+
+ if (lock_mode != mode) {
+ lock_mode = mode;
+ mask = state_mask;
+ state_mask &= ~ShiftLockMask;
+ state_mask |= lock_mask;
+ lock_mask = mask & ShiftLockMask;
+ }
+ SetLockLED((lock_mode && (state_mask & ShiftLockMask)) ? 1 : 0);
+}
+
+/* Set motion box */
+
+Set_mbox ()
+{
+ register WINDOW *w, *sw;
+ register RECTANGLE *r;
+ register CURSOR *curs;
+ vsBox b;
+
+ /* recalculate if need be */
+ if (mbox.bottom <= mbox.top) {
+ w = mouse_window;
+ /* use containing visible rectangle if any */
+ for (r = w->visible;
+ r && (mouse_x < r->left || mouse_x >= r->right ||
+ mouse_y < r->top || mouse_y >= r->bottom);
+ r = r->next) ;
+ if (r)
+ mbox = *(RASTER *) r;
+ else
+ mbox = w->vs;
+ if (sw = w->first_child)
+ w = sw;
+ else
+ sw = w->next_sib;
+ /* clip with obscuring windows */
+ while (1) {
+ if (sw == NULL) {
+ if ((w = w->parent) == NULL)
+ break;
+ sw = w->next_sib;
+ continue;
+ } else if (FALSE(sw->mapped) || (r && sw->kind != IsTransparent)) {
+ sw = sw->next_sib;
+ continue;
+ }
+ if (sw->vs.top < mbox.bottom && sw->vs.bottom > mbox.top) {
+ if (sw->vs.right > mbox.left && sw->vs.right <= mouse_x)
+ mbox.left = sw->vs.right;
+ else if (sw->vs.left < mbox.right && sw->vs.left >= mouse_x)
+ mbox.right = sw->vs.left;
+ }
+ if (sw->vs.left < mbox.right && sw->vs.right > mbox.left) {
+ if (sw->vs.bottom > mbox.top && sw->vs.bottom <= mouse_y)
+ mbox.top = sw->vs.bottom;
+ else if (sw->vs.top < mbox.bottom && sw->vs.top >= mouse_y)
+ mbox.bottom = sw->vs.top;
+ }
+ sw = sw->next_sib;
+ }
+ }
+
+ /* if anyone wants motion events, we lose */
+ if ((mouse_grabber && (mouse_grab_mask & motion_mask)) ||
+ (button_window && (button_window->mask & motion_mask))) {
+ device.mbox->bottom = 0;
+ return;
+ }
+ for (w = mouse_window; w; w = w->parent) {
+ if (w->mask & motion_mask) {
+ device.mbox->bottom = 0;
+ return;
+ }
+ }
+ curs = cursor;
+ b.left = mbox.left - curs->xoff;
+ b.right = mbox.right - curs->xoff;
+ b.top = mbox.top - curs->yoff;
+ b.bottom = mbox.bottom - curs->yoff;
+ *device.mbox = b;
+}
+
+/* Deal with a button/key transition */
+
+Deal_with_input (ev)
+ register vsEvent *ev;
+{
+ register WINDOW *w, *ww;
+ short x = ev->vse_x + cursor->xoff;
+ short y = ev->vse_y + cursor->yoff;
+
+ w = mouse_window;
+ /* lightning usually strikes twice */
+ if (y >= mbox.bottom || y < mbox.top ||
+ x >= mbox.right || x < mbox.left) {
+ /* but not this time */
+ SEARCH(x, y, w, ww);
+ }
+ if (ev->vse_device == VSE_DKB) {
+ if (ev->vse_direction == VSE_KBTUP) {
+ Stash_event (w, (long) KeyReleased, ev->vse_key,
+ x, y, ev->vse_time);
+ switch (ev->vse_key) {
+ case ShiftKeyCode:
+ state_mask &= ~ShiftMask;
+ break;
+ case ControlKeyCode:
+ state_mask &= ~ControlMask;
+ break;
+ case LockKeyCode:
+ if TRUE(lock_mode)
+ lock_mask = 0;
+ else
+ state_mask &= ~ShiftLockMask;
+ break;
+ case MetaKeyCode:
+ state_mask &= ~MetaMask;
+ break;
+ }
+ } else {
+ Stash_event (w, (long) KeyPressed, ev->vse_key,
+ x, y, ev->vse_time);
+ switch (ev->vse_key) {
+ case ShiftKeyCode:
+ state_mask |= ShiftMask;
+ break;
+ case ControlKeyCode:
+ state_mask |= ControlMask;
+ break;
+ case LockKeyCode:
+ if TRUE(lock_mode) {
+ state_mask ^= ShiftLockMask;
+ lock_mask = ShiftLockMask;
+ SetLockLED (state_mask & ShiftLockMask ? 1 : 0);
+ } else {
+ state_mask |= ShiftLockMask;
+ lock_mask ^= ShiftLockMask;
+ }
+ break;
+ case MetaKeyCode:
+ state_mask |= MetaMask;
+ break;
+ }
+ }
+ } else {
+ if (ev->vse_direction == VSE_KBTUP) {
+ Stash_event (w, (long) ButtonReleased, 2 - ev->vse_key,
+ x, y, ev->vse_time);
+ motion_mask &= ~(LeftDownMotion >> ev->vse_key);
+ state_mask &= ~(LeftMask >> ev->vse_key);
+ if (!(state_mask & (LeftMask|MiddleMask|RightMask))) {
+ /* check for end of grab */
+ if (button_window || (mouse_grabber && mouse_grab_button))
+ Stash_ungrabs ();
+ }
+ } else {
+ if (button_window == NULL && mouse_grabber == 0) {
+ /* check for start of grab */
+ if (bgrabs[GRABIDX(ev->vse_key, state_mask)].client)
+ Button_grab (ev->vse_key, state_mask);
+ else {
+ ww = w;
+ while (!(ww->mask & ButtonPressed)) {
+ if ((ww = ww->parent) == NULL) break;
+ }
+ if (ww && (ww->mask & ButtonReleased)) {
+ Stash_grabs (ww->client);
+ button_window = ww;
+ }
+ }
+ }
+ Stash_event (w, (long) ButtonPressed, 2 - ev->vse_key,
+ x, y, ev->vse_time);
+ motion_mask |= (LeftDownMotion >> ev->vse_key);
+ state_mask |= (LeftMask >> ev->vse_key);
+ }
+ Deal_with_movement ();
+ }
+}
+
+/* Give the client sole possession of the mouse */
+
+Grab_mouse (w, curs, mask, client)
+ register WINDOW *w;
+ register CURSOR *curs;
+ long mask;
+ int client;
+{
+ register CURSOR *ocurs;
+ int deltax, deltay;
+
+ if ((button_window && button_window->client != client) ||
+ (mouse_grabber && mouse_grabber != client)) {
+ Xstatus = BadGrab;
+ return;
+ }
+ ocurs = cursor;
+ deltax = ocurs->xoff - curs->xoff;
+ deltay = ocurs->yoff - curs->yoff;
+ button_window = NULL;
+ if (mouse_grabber == 0) {
+ Stash_grabs (client);
+ mouse_grabber = client;
+ ocurs = NULL;
+ } else if (mouse_grab_button)
+ ocurs = NULL;
+ mouse_grab_window = w;
+ mouse_grab_mask = mask;
+ mouse_grab_button = 0;
+
+ curs->refcnt++;
+ cursor = curs;
+ New_cursor (deltax, deltay);
+ cursor_window = NULL;
+ Deal_with_movement ();
+ if (ocurs && --ocurs->refcnt == 0)
+ FreeCursor (ocurs);
+}
+
+/* Ungrab the mouse */
+
+Ungrab_mouse (client)
+ int client;
+{
+ if (client == mouse_grabber && mouse_grab_button == 0) {
+ Stash_ungrabs ();
+ Deal_with_movement ();
+ }
+}
+
+/* Indicates that a client wants sole possession of the mouse when the
+ * specified button is down.
+ */
+
+Grab_button (w, curs, button, mask, client)
+ register WINDOW *w;
+ CURSOR *curs;
+ unsigned button;
+ long mask;
+ int client;
+{
+ register int i;
+ register GRAB_INFO *grab;
+ register CURSOR *ocurs;
+
+ i = ButtonState(button);
+ if (i == 0 || (i & (i - 1))) {
+ Xstatus = BadValue;
+ return;
+ } else if (i == 4)
+ i = 3;
+ grab = &bgrabs[GRABIDX(3 - i, button)];
+ if (grab->client && grab->client != client) {
+ Xstatus = BadGrab;
+ return;
+ }
+ if (grab->client) {
+ ocurs = grab->cursor;
+ grab->window->bgrabs--;
+ } else
+ ocurs = NULL;
+
+ grab->client = client;
+ grab->window = w;
+ grab->mask = mask;
+ grab->cursor = curs;
+ curs->refcnt++;
+ w->bgrabs++;
+
+ /* check if this is an in-progress update */
+ if (mouse_grabber && mouse_grab_button == (button & grabbits)) {
+ Button_grab ((unsigned) 3 - i, button);
+ Deal_with_movement ();
+ }
+ if (ocurs && --ocurs->refcnt == 0)
+ FreeCursor (ocurs);
+}
+
+/* Ungrab a button */
+
+Ungrab_button (button, client)
+ unsigned button;
+ int client;
+{
+ register int i;
+ register GRAB_INFO *grab;
+
+ i = ButtonState(button);
+ if (i == 0 || (i & (i - 1))) {
+ Xstatus = BadValue;
+ return;
+ } else if (i == 4)
+ i = 3;
+ grab = &bgrabs[GRABIDX(3 - i, button)];
+ if (grab->client != client)
+ return;
+ grab->client = 0;
+ grab->window->bgrabs--;
+ /* check if aborting */
+ if (client == mouse_grabber && mouse_grab_button == (button & grabbits))
+ Stash_ungrabs ();
+ Deal_with_movement ();
+ if (--grab->cursor->refcnt == 0)
+ FreeCursor (grab->cursor);
+}
+
+/* Start a button grab */
+
+Button_grab (key, mask)
+ register unsigned key, mask;
+{
+ register GRAB_INFO *grab;
+ int deltax, deltay;
+
+ grab = &bgrabs[GRABIDX(key, mask)];
+ if (mouse_grabber == 0) {
+ Stash_grabs (grab->client);
+ mouse_grabber = grab->client;
+ }
+ mouse_grab_window = grab->window;
+ mouse_grab_mask = grab->mask;
+ mouse_grab_button = (mask & (ControlMask|MetaMask|ShiftMask|ShiftLockMask)) |
+ (LeftMask >> key);
+ deltax = cursor->xoff - grab->cursor->xoff;
+ deltay = cursor->yoff - grab->cursor->yoff;
+ cursor = grab->cursor;
+ New_cursor (deltax, deltay);
+ cursor_window = NULL;
+}
+
+/* Conditionally warp mouse to new position */
+
+Warp_mouse (dstw, dstx, dsty, srcw, src)
+ WINDOW *dstw, *srcw;
+ int dstx, dsty;
+ register REGION *src;
+{
+ int x, y, width, height;
+ register int cx, cy;
+ register RECTANGLE *v;
+ register WINDOW *w;
+ vsCursor mcursor;
+
+ w = srcw;
+ if FALSE(w->mapped) return;
+ /* get absolute coordinates */
+ x = w->full.left + src->left;
+ y = w->full.top + src->top;
+ if ((width = src->width) == 0)
+ width = w->full.right - x;
+ if ((height = src->height) == 0)
+ height = w->full.bottom - y;
+ mcursor = *device.mouse;
+ cx = mcursor.x + cursor->xoff;
+ cy = mcursor.y + cursor->yoff;
+ if (cx < x || cy < y || cx >= x + width || cy >= y + height)
+ return;
+ for (v = w->cmvisible; v; v = v->next) {
+ if (cx < v->left || cy < v->top ||
+ cx >= v->right || cy >= v->bottom)
+ continue;
+ cx = dstx;
+ cy = dsty;
+ w = dstw;
+ /* get absolute coordinates */
+ while (1) {
+ cx += w->full.left;
+ cy += w->full.top;
+ if TRUE(w->mapped) break;
+ w = w->parent;
+ }
+ mcursor = *device.mouse;
+ New_cursor (cx - cursor->xoff - mcursor.x,
+ cy - cursor->yoff - mcursor.y);
+ Deal_with_movement ();
+ }
+}
+
+/* Change keyboard focus */
+
+Focus_keyboard (w)
+ register WINDOW *w;
+{
+ if (key_window != w) {
+ if (key_window)
+ Stash_simple (key_window, (long) FocusChange, LeaveWindow);
+ key_window = w;
+ key_level = w->level;
+ Stash_simple (w, (long) FocusChange, EnterWindow);
+ }
+}
+
+/* Remove grabs that use this window */
+
+Unbutton_window (w)
+ register WINDOW *w;
+{
+ register GRAB_INFO *grab;
+
+ for (grab = &bgrabs[0]; ; grab++) {
+ if (w == grab->window && grab->client) {
+ grab->client = 0;
+ if (--grab->cursor->refcnt == 0)
+ FreeCursor (grab->cursor);
+ if (--w->bgrabs == 0)
+ return;
+ }
+ }
+}
+
+/* Remove grabs by this client */
+
+Ungrab_client (client)
+ int client;
+{
+ register GRAB_INFO *grab;
+
+ if (client == mouse_grabber ||
+ (button_window && client == button_window->client))
+ Stash_ungrabs ();
+ for (grab = &bgrabs[0]; grab != &bgrabs[GRABS]; grab++) {
+ if (client == grab->client) {
+ grab->client = 0;
+ grab->window->bgrabs--;
+ if (--grab->cursor->refcnt == 0)
+ FreeCursor (grab->cursor);
+ }
+ }
+}
+
+/* Generate leave events at mouse grab */
+
+Stash_grabs (client)
+ register int client;
+{
+ register WINDOW *w;
+
+ w = mouse_window;
+ if (w == rootwindow) return;
+ if (w->client != client) {
+ while (!(w->mask & LeaveWindow) && (w = w->parent) &&
+ w->client != client) ;
+ if (w && w->client != client)
+ Stash_event (mouse_window, (long) LeaveWindow,
+ 0, mouse_x, mouse_y, 0);
+ w = mouse_window;
+ }
+ while ((w = w->parent) != rootwindow) {
+ if (w->client != client && (w->mask & LeaveWindow))
+ Stash_event (w, (long) LeaveWindow, VirtualCrossing,
+ mouse_x, mouse_y, 0);
+ }
+}
+
+/* Restore cursor and generate enter events at mouse ungrab */
+
+Stash_ungrabs ()
+{
+ register WINDOW *w;
+ register int client;
+ CURSOR *curs;
+
+ if (button_window) {
+ client = button_window->client;
+ button_window = NULL;
+ } else {
+ client = mouse_grabber;
+ mouse_grabber = 0;
+ if (mouse_grab_button)
+ New_cursor (0, 0);
+ else {
+ curs = cursor;
+ New_cursor (0, 0);
+ if (--curs->refcnt == 0)
+ FreeCursor (curs);
+ }
+ }
+ w = mouse_window;
+ while (w != rootwindow &&
+ (w->client == client || !(w->mask & EnterWindow)))
+ w = w->parent;
+ if (w != rootwindow) {
+ w = mouse_window;
+ if (rootwindow != w->parent)
+ Stash_enters (rootwindow, w->parent, client);
+ if (w->client != client) {
+ while (!(w->mask & EnterWindow) && (w = w->parent) &&
+ w->client != client) ;
+ if (w && w->client != client)
+ Stash_event (mouse_window, (long) EnterWindow,
+ 0, mouse_x, mouse_y, 0);
+ }
+ }
+}
+
+/* Stash enter events in windows */
+
+Stash_enters (p, c, client)
+ WINDOW *p, *c;
+ int client;
+{
+ if (p != c->parent)
+ Stash_enters (p, c->parent, client);
+ if (c->client != client && (c->mask & EnterWindow))
+ Stash_event (c, (long) EnterWindow, VirtualCrossing,
+ mouse_x, mouse_y, 0);
+}
+
+/* Place an event in the event queue of a window */
+
+Stash_event (w, event, detail, x, y, time)
+ register WINDOW *w;
+ register long event;
+ short x, y;
+ unsigned detail, time;
+{
+ register WINDOW *sub = NULL;
+ WINDOW *ww;
+ XRep rep;
+ int client;
+#ifdef DUALTCP
+ register swaptype n;
+#endif
+
+ /* Find someone who is interested in dealing with this event
+ * and set w to the window lowest in the hierarchy at or
+ * above the original event window that is interested.
+ */
+
+ if (event & (KeyPressed|KeyReleased)) {
+ while (1) {
+ if (!(w->mask & event)) {
+ sub = w;
+ if (w->level > key_level) {
+ w = w->parent;
+ continue;
+ }
+ } else if (key_level == 0) {
+ break;
+ } else {
+ ww = w;
+ while (ww->level > key_level)
+ ww = ww->parent;
+ if (ww == key_window)
+ break;
+ }
+ w = key_window;
+ if (!(w->mask & event))
+ return;
+ sub = NULL;
+ break;
+ }
+ client = w->client;
+ } else if (button_window) {
+ while (w && !(w->mask & event)) {
+ sub = w;
+ w = w->parent;
+ }
+ client = button_window->client;
+ if (w == NULL || w->client != client) {
+ sub = w;
+ w = button_window;
+ if (!((w->mask & event) & ~(EnterWindow|LeaveWindow)))
+ return;
+ while (sub && sub->parent != w)
+ sub = sub->parent;
+ }
+ } else if (mouse_grabber) {
+ while (w &&
+ !(event & ((w == mouse_grab_window) ? mouse_grab_mask :
+ w->mask))) {
+ sub = w;
+ w = w->parent;
+ }
+ client = mouse_grabber;
+ if (w == NULL || (w != mouse_grab_window && w->client != client)) {
+ if (!((mouse_grab_mask & event) & ~(EnterWindow|LeaveWindow)))
+ return;
+ sub = w;
+ w = mouse_grab_window;
+ while (sub && sub->parent != w)
+ sub = sub->parent;
+ }
+ } else {
+ while (!(w->mask & event)) {
+ sub = w;
+ if ((w = w->parent) == NULL) return;
+ }
+ client = w->client;
+ }
+
+ rep.code = event & ~(LeftDownMotion|MiddleDownMotion|RightDownMotion);
+ rep.param.l[0] = w->rid;
+ rep.param.s[2] = time;
+ rep.param.s[3] = state_mask | detail;
+ rep.param.s[4] = x - w->full.left;
+ rep.param.s[5] = y - w->full.top;
+ rep.param.l[3] = (sub ? sub->rid : 0);
+#ifdef vax
+ rep.param.s[8] = y;
+ rep.param.s[9] = x;
+#else
+#ifdef mc68000
+ rep.param.s[9] = y;
+ rep.param.s[8] = x;
+#else
+ rep.param.l[4] = (x << 16) | y;
+#endif
+#endif
+#ifdef DUALTCP
+ if (swapped[client]) {
+ swapl(&rep.code);
+ pswapl(&rep, 0);
+ pswaps(&rep, 2);
+ pswaps(&rep, 3);
+ pswaps(&rep, 4);
+ pswaps(&rep, 5);
+ pswapl(&rep, 3);
+ pswapl(&rep, 4);
+ }
+#endif
+ Write (client, (caddr_t) &rep, sizeof (XRep));
+}
+
+/* Place window changes in the event queue of a window.
+ * If not_just_new, generate an ExposeWindow, else update visible list and
+ * generate ExposeRegions (or ExposeWindow).
+ */
+
+Stash_changes (w, not_just_new)
+ register WINDOW *w;
+ register int not_just_new;
+{
+ register WINDOW *ew = w;
+ register RECTANGLE *r, **prev;
+ RECTANGLE *changed = NULL;
+ XRep rep;
+#ifdef DUALTCP
+ register swaptype n;
+#endif
+
+ while (!(ew->mask & (ExposeWindow|ExposeRegion))) {
+ if (ew = ew->parent)
+ continue;
+ if TRUE(not_just_new)
+ return;
+ /* nobody interested, just update */
+ prev = &w->visible;
+ while (r = *prev) {
+ if (r->type == new_rec) {
+ r->type = contents_rec;
+ *prev = r->next;
+ r->next = changed;
+ changed = r;
+ } else
+ prev = &r->next;
+ }
+ if (changed) {
+ Merge_rectangles (changed, &w->visible);
+ Windex (w);
+ }
+ return;
+ }
+
+ rep.param.l[0] = ew->rid;
+ rep.param.s[3] = 0;
+ rep.param.l[3] = (w == ew) ? 0 : w->rid;
+#ifdef DUALTCP
+ if (swapped[ew->client]) {
+ rep.code = lswapl(ExposeRegion);
+ pswapl(&rep, 0);
+ pswapl(&rep, 3);
+ } else
+#endif
+ rep.code = ExposeRegion;
+
+ if FALSE(not_just_new) {
+ prev = &w->visible;
+ while (r = *prev) {
+ if (r->type == new_rec) {
+ r->type = contents_rec;
+ *prev = r->next;
+ r->next = changed;
+ changed = r;
+ if (ew->mask & ExposeRegion) {
+ rep.param.s[4] = r->right - r->left;
+ rep.param.s[5] = r->bottom - r->top;
+ rep.param.s[8] = r->top - w->full.top;
+ rep.param.s[9] = r->left - w->full.left;
+#ifdef DUALTCP
+ if (swapped[ew->client]) {
+ pswaps(&rep, 4);
+ pswaps(&rep, 5);
+ pswaps(&rep, 8);
+ pswaps(&rep, 9);
+ }
+#endif
+ Write (ew->client, (caddr_t) &rep, sizeof (XRep));
+ } else
+ not_just_new = 1;
+ } else
+ prev = &r->next;
+ }
+ if (changed) {
+ Merge_rectangles (changed, &w->visible);
+ Windex (w);
+ }
+ }
+ if TRUE(not_just_new) {
+ rep.param.s[4] = w->full.right - w->full.left;
+ rep.param.s[5] = w->full.bottom - w->full.top;
+ rep.param.s[8] = 0;
+ rep.param.s[9] = 0;
+#ifdef DUALTCP
+ if (swapped[ew->client]) {
+ rep.code = lswapl(ExposeWindow);
+ pswaps(&rep, 4);
+ pswaps(&rep, 5);
+ } else
+#endif
+ rep.code = ExposeWindow;
+ Write (ew->client, (caddr_t) &rep, sizeof (XRep));
+ }
+}
+
+/* Stash CopyArea misses in the event queue of a window */
+
+Stash_misses (w, vis)
+ register WINDOW *w;
+ register RECTANGLE *vis;
+{
+ register RECTANGLE *rec;
+ register WINDOW *ew = w;
+ XRep rep;
+#ifdef DUALTCP
+ register swaptype n;
+#endif
+
+ while (!(ew->mask & ExposeCopy)) {
+ if ((ew = ew->parent) == NULL)
+ return;
+ }
+
+ rep.param.l[0] = ew->rid;
+ rep.param.l[3] = (w == ew) ? 0 : w->rid;
+#ifdef DUALTCP
+ if (swapped[ew->client]) {
+ rep.code = lswapl(ExposeRegion);
+ pswapl(&rep, 0);
+ rep.param.s[3] = lswaps(ExposeCopy);
+ pswapl(&rep, 3);
+ } else {
+#endif
+ rep.code = ExposeRegion;
+ rep.param.s[3] = ExposeCopy;
+#ifdef DUALTCP
+ }
+#endif
+ while (rec = vis) {
+ rep.param.s[4] = rec->right - rec->left;
+ rep.param.s[5] = rec->bottom - rec->top;
+ rep.param.s[8] = rec->top - w->full.top;
+ rep.param.s[9] = rec->left - w->full.left;
+#ifdef DUALTCP
+ if (swapped[ew->client]) {
+ pswaps(&rep, 4);
+ pswaps(&rep, 5);
+ pswaps(&rep, 8);
+ pswaps(&rep, 9);
+ }
+#endif
+ Write (ew->client, (caddr_t) &rep, sizeof (XRep));
+ vis = rec->next;
+ FREERECT(rec);
+ }
+
+#ifdef DUALTCP
+ if (swapped[ew->client])
+ rep.code = lswapl(ExposeCopy);
+ else
+#endif
+ rep.code = ExposeCopy;
+ Write (ew->client, (caddr_t) &rep, sizeof (XRep));
+}
+
+/* Stash unmap or focus event in the event queue of a window */
+
+Stash_simple (w, event, detail)
+ register WINDOW *w;
+ register long event;
+ unsigned detail;
+{
+ register WINDOW *ew = w;
+ XRep rep;
+#ifdef DUALTCP
+ register swaptype n;
+#endif
+
+ while (!(ew->mask & event)) {
+ if ((ew = ew->parent) == NULL)
+ return;
+ }
+
+ rep.code = event;
+ rep.param.l[0] = ew->rid;
+ rep.param.s[3] = detail;
+ rep.param.l[3] = (w == ew) ? 0 : w->rid;
+#ifdef DUALTCP
+ if (swapped[ew->client]) {
+ swapl(&rep.code);
+ pswapl(&rep, 0);
+ pswaps(&rep, 3);
+ pswapl(&rep, 3);
+ }
+#endif
+ Write (ew->client, (caddr_t) &rep, sizeof (XRep));
+}
+
+/* Find out coordinates of a point relative to a window. */
+
+Interpret_locator (w, x, y, rep)
+ register WINDOW *w;
+ short x, y;
+ register XRep *rep;
+{
+ register WINDOW *sw;
+
+ rep->param.l[0] = 0;
+ if (x >= w->vs.left && y >= w->vs.top &&
+ x < w->vs.right && y < w->vs.bottom) {
+ /* see if it is in a subwindow */
+ for (sw = w->last_child; sw; sw = sw->prev_sib) {
+ if (TRUE(sw->mapped) &&
+ x >= sw->full.left && y >= sw->full.top &&
+ x < sw->full.right && y < sw->full.bottom) {
+ rep->param.l[0] = sw->rid;
+ break;
+ }
+ }
+ }
+ rep->param.s[2] = x - w->full.left;
+ rep->param.s[3] = y - w->full.top;
+ rep->param.s[4] = state_mask;
+}