This is a patch against the Angband CVS as of 21/3/03 (which means it may work
for 3.0.3, but hasn't been tested as such) to allow text to be copied from and
pasted to the X11 port of Angband.

I haven't had any problems with it, but don't blame me if it kills X or causes
demons to fly out of your nose. Do send feedback, and use it for whatever legal
purposes you wish.

Kieron Dunbar (kieron@dimetrodon.demon.co.uk)

Index: src/maid-x11.h
===================================================================
RCS file: /home/rr9/angband/angband/src/maid-x11.h,v
retrieving revision 1.1
diff -c -d -r1.1 maid-x11.h
*** src/maid-x11.h	4 Jun 2001 16:27:51 -0000	1.1
--- src/maid-x11.h	21 Mar 2003 00:27:07 -0000
***************
*** 20,25 ****
--- 20,26 ----
  #include <X11/Xutil.h>
  #include <X11/keysym.h>
  #include <X11/keysymdef.h>
+ #include <X11/Xatom.h>
  #endif /* __MAKEDEPEND__ */
  
  
Index: src/main-x11.c
===================================================================
RCS file: /home/rr9/angband/angband/src/main-x11.c,v
retrieving revision 1.23
diff -c -d -r1.23 main-x11.c
*** src/main-x11.c	26 Jan 2003 14:55:59 -0000	1.23
--- src/main-x11.c	21 Mar 2003 00:32:07 -0000
***************
*** 1479,1484 ****
--- 1479,1516 ----
   */
  static term_data data[MAX_TERM_DATA];
  
+ /* Use short names for the most commonly used elements of various structures. */
+ #define DPY (Metadpy->dpy)
+ #define WIN (Infowin->win)
+ 
+ /*
+  * Simply push a set of co-ordinates around.
+  */
+ typedef struct co_ord co_ord;
+ struct co_ord
+ {
+ 	int x;
+ 	int y;
+ };
+ 
+ /*
+  * A special structure to store information about the text currently
+  * selected.
+  */
+ typedef struct x11_selection_type x11_selection_type;
+ struct x11_selection_type
+ {
+ 	bool select; /* The selection is currently in use. */
+ 	bool drawn; /* The selection is currently displayed. */
+ 	term *t; /* The window where the selection is found. */
+ 	co_ord init; /* The starting co-ordinates. */
+ 	co_ord cur; /* The end co-ordinates (the current ones if still copying). */
+ 	co_ord old; /* The previous end co-ordinates. */
+ 	Time time; /* The time at which the selection was finalised. */
+ };
+ 
+ static x11_selection_type s_ptr[1];
+ 
  
  
  /*
***************
*** 1592,1597 ****
--- 1624,2009 ----
  
  
  
+ /*
+  * Find the square a particular pixel is part of.
+  */
+ static void pixel_to_square(int * const x, int * const y,
+ 	const int ox, const int oy)
+ {
+ 	(*x) = (ox - Infowin->ox) / Infofnt->wid;
+ 	(*y) = (oy - Infowin->oy) / Infofnt->hgt;
+ }
+ 
+ /*
+  * Find the pixel at the top-left corner of a square.
+  */
+ static void square_to_pixel(int * const x, int * const y,
+ 	const int ox, const int oy)
+ {
+ 	(*x) = ox * Infofnt->wid + Infowin->ox;
+ 	(*y) = oy * Infofnt->hgt + Infowin->oy;
+ }
+ 
+ /*
+  * Convert co-ordinates from starting corner/opposite corner to minimum/maximum.
+  */
+ static void sort_co_ord(co_ord *min, co_ord *max,
+ 	const co_ord *b, const co_ord *a)
+ {
+ 	min->x = MIN(a->x, b->x);
+ 	min->y = MIN(a->y, b->y);
+ 	max->x = MAX(a->x, b->x);
+ 	max->y = MAX(a->y, b->y);
+ }
+ 
+ /*
+  * Remove the selection by redrawing it.
+  */
+ static void mark_selection_clear(int x1, int y1, int x2, int y2)
+ {
+ 	Term_redraw_section(x1,y1,x2,y2);
+ }
+ 
+ /*
+  * Select an area by drawing a grey box around it.
+  * NB. These two functions can cause flicker as the selection is modified,
+  * as the game redraws the entire marked section.
+  */
+ static void mark_selection_mark(int x1, int y1, int x2, int y2)
+ {
+ 	square_to_pixel(&x1, &y1, x1, y1);
+ 	square_to_pixel(&x2, &y2, x2, y2);
+ 	XDrawRectangle(Metadpy->dpy, Infowin->win, clr[2]->gc, x1, y1,
+ 		x2-x1+Infofnt->wid - 1, y2-y1+Infofnt->hgt - 1);
+ }
+ 
+ /*
+  * Mark a selection by drawing boxes around it (for now).
+  */
+ static void mark_selection(void)
+ {
+ 	co_ord min, max;
+ 	term *old = Term;
+ 	bool draw = s_ptr->select;
+ 	bool clear = s_ptr->drawn;
+ 
+ 	/* Open the correct term if necessary. */
+ 	if (s_ptr->t != old) Term_activate(s_ptr->t);
+ 
+ 	if (clear)
+ 	{
+ 		sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->old);
+ 		mark_selection_clear(min.x, min.y, max.x, max.y);
+ 	}
+ 	if (draw)
+ 	{
+ 		sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->cur);
+ 		mark_selection_mark(min.x, min.y, max.x, max.y);
+ 	}
+ 
+ 	/* Finish on the current term. */
+ 	if (s_ptr->t != old) Term_activate(old);
+ 
+ 	s_ptr->old.x = s_ptr->cur.x;
+ 	s_ptr->old.y = s_ptr->cur.y;
+ 	s_ptr->drawn = s_ptr->select;
+ }
+ 
+ /*
+  * Forget a selection for one reason or another.
+  */
+ static void copy_x11_release(void)
+ {
+ 	/* Deselect the current selection. */
+ 	s_ptr->select = FALSE;
+ 
+ 	/* Remove its graphical represesntation. */
+ 	mark_selection();
+ }
+ 
+ /*
+  * Start to select some text on the screen.
+  */
+ static void copy_x11_start(int x, int y)
+ {
+ 	if (s_ptr->select) copy_x11_release();
+ 
+ 	/* Remember where the selection started. */
+ 	s_ptr->t = Term;
+ 	s_ptr->init.x = s_ptr->cur.x = s_ptr->old.x = x;
+ 	s_ptr->init.y = s_ptr->cur.y = s_ptr->old.y = y;
+ }
+ 
+ /*
+  * Respond to movement of the mouse when selecting text.
+  */
+ static void copy_x11_cont(int x, int y, unsigned int buttons)
+ {
+ 	/* Use the nearest square within bounds if the mouse is outside. */
+ 	x = MIN(MAX(x, 0), Term->wid-1);
+ 	y = MIN(MAX(y, 0), Term->hgt-1);
+ 
+ 	/* The left mouse button isn't pressed. */
+ 	if (~buttons & Button1Mask) return;
+ 
+ 	/* Not a selection in this window. */
+ 	if (s_ptr->t != Term) return;
+ 
+ 	/* Not enough movement. */
+ 	if (x == s_ptr->old.x && y == s_ptr->old.y && s_ptr->select) return;
+ 
+ 	/* Something is being selected. */
+ 	s_ptr->select = TRUE;
+ 
+ 	/* Track the selection. */
+ 	s_ptr->cur.x = x;
+ 	s_ptr->cur.y = y;
+ 
+ 	/* Hack - display it inefficiently. */
+ 	mark_selection();
+ }
+ 
+ /*
+  * Respond to release of the left mouse button by putting the selected text in
+  * the primary buffer.
+  */
+ static void copy_x11_end(const Time time)
+ {
+ 	/* No selection. */
+ 	if (!s_ptr->select) return;
+ 
+ 	/* Not a selection in this window. */
+ 	if (s_ptr->t != Term) return;
+ 
+ 	/* Remember when the selection was finalised. */
+ 	s_ptr->time = time;
+ 
+ 	/* Acquire the primary selection. */
+ 	XSetSelectionOwner(Metadpy->dpy, XA_PRIMARY, Infowin->win, time);
+ 	if (XGetSelectionOwner(Metadpy->dpy, XA_PRIMARY) != Infowin->win)
+ 	{
+ 		/* Failed to acquire the selection, so forget it. */
+ 		bell("Failed to acquire primary buffer.");
+ 		s_ptr->select = FALSE;
+ 		mark_selection();
+ 	}
+ }
+ 
+ /*
+  * Send a message to request that the PRIMARY buffer be sent here.
+  */
+ static void paste_x11_request(const Time time)
+ {
+ 	XEvent event[1];
+ 	XSelectionRequestEvent *ptr = &(event->xselectionrequest);
+ 
+ 	/* Set various things. */
+ 	ptr->type = SelectionRequest;
+ 	ptr->display = Metadpy->dpy;
+ 	ptr->owner = XGetSelectionOwner(Metadpy->dpy, XA_PRIMARY);
+ 	ptr->requestor = Infowin->win;
+ 	ptr->selection = XA_PRIMARY;
+ 	ptr->target = XA_STRING;
+ 	ptr->property = XA_STRING; /* Unused */
+ 	ptr->time = time;
+ 
+ 	/* Check the owner. */
+ 	if (ptr->owner == None)
+ 	{
+ 		/* No selection. */
+ 		bell("No selection found.");
+ 		return;
+ 	}
+ 
+ 	/* Send the SelectionRequest event. */
+ 	XSendEvent(Metadpy->dpy, ptr->owner, False, NoEventMask, event);
+ }
+ 
+ /*
+  * Add a character to a string in preparation for sending it to another
+  * client as a STRING.
+  * This doesn't change anything, as clients tend not to have difficulty in
+  * receiving this format (although the standard specifies a restricted set).
+  * Strings do not have a colour.
+  */
+ static int add_char_string(char *buf, byte a, char c)
+ {
+ 	*buf = c;
+ 	return 1;
+ }
+ 
+ /*
+  * Send some text requested by another X client.
+  */
+ static void paste_x11_send(XSelectionRequestEvent *rq)
+ {
+ 	XEvent event;
+ 	XSelectionEvent *ptr = &(event.xselection);
+ 	int (*add)(char *, byte, char) = 0;
+ 
+ 	/* Set the event parameters. */
+ 	ptr->type = SelectionNotify;
+ 	ptr->property = rq->property;
+ 	ptr->display = rq->display;
+ 	ptr->requestor = rq->requestor;
+ 	ptr->selection = rq->selection;
+ 	ptr->target = rq->target;
+ 	ptr->time = rq->time;
+ 
+ 	/* Determine the correct "add a character" function. 
+ 	 * As Term->wid is at most 255, these can add up to 4 characters of
+ 	 * output per character of input without problem.
+ 	 * The mechanism will need to change if much more than this is needed.
+ 	 */
+ 	switch (rq->target)
+ 	{
+ 		case XA_STRING: add = add_char_string; break;
+ 		default: goto error;
+ 	}
+ 
+ 	/* Reply to a known target received recently with data. */
+ 	if (rq->time >= s_ptr->time && add)
+ 	{
+ 		char buf[1024];
+ 		co_ord max, min;
+ 		int x,y,l;
+ 		byte a;
+ 		char c;
+ 
+ 		/* Work out which way around to paste. */
+ 		sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->cur);
+ 
+ 		/* Paranoia. */
+ 		if (XGetSelectionOwner(DPY, XA_PRIMARY) != WIN)
+ 		{
+ 			bell("Someone stole my selection!");
+ 			goto error;
+ 		}
+ 
+ 		/* Delete the old value of the property. */
+ 		XDeleteProperty(DPY, rq->requestor, rq->property);
+ 
+ 		for (y = 0; y < Term->hgt; y++)
+ 		{
+ 			if (y < min.y) continue;
+ 			if (y > max.y) break;
+ 
+ 			for (x = l = 0; x < Term->wid; x++)
+ 			{
+ 				if (x < min.x) continue;
+ 				if (x > max.x) break;
+ 
+ 				/* Find the character. */
+ 				Term_what(x, y, &a, &c);
+ 
+ 				/* Add it. */
+ 				l += (*add)(buf+l, a, c);
+ 			}
+ 
+ 			/* Terminate all but the last line in an appropriate way. */
+ 			if (y != max.y) l += (*add)(buf+l, TERM_WHITE, '\n');
+ 
+ 			/* Send the (non-empty) string. */
+ 			XChangeProperty(DPY, rq->requestor, rq->property, rq->target, 8,
+ 				PropModeAppend, buf, l);
+ 		}
+ 	}
+ 	else
+ 	{
+ 		/* Respond to all bad requests with property None. */
+ error:
+ 		ptr->property = None;
+ 	}
+ 
+ 	/* Send whatever event we're left with. */
+ 	XSendEvent(DPY, rq->requestor, FALSE, NoEventMask, &event);
+ }
+ 
+ extern errr type_string(char *str, uint len);
+ 
+ /*
+  * Add the contents of the PRIMARY buffer to the input queue.
+  *
+  * Hack - This doesn't use the "time" of the event, and so accepts anything a
+  * client tries to send it.
+  */
+ static void paste_x11_accept(const XSelectionEvent *ptr)
+ {
+ 	long offset, left;
+ 
+ 	/* Failure. */
+ 	if (ptr->property == None)
+ 	{
+ 		bell("Paste failure (remote client could not send).");
+ 		return;
+ 	}
+ 
+ 	if (ptr->selection != XA_PRIMARY)
+ 	{
+ 		bell("Paste failure (remote client did not send primary selection).");
+ 		return;
+ 	}
+ 	if (ptr->target != XA_STRING)
+ 	{
+ 		bell("Paste failure (selection in unknown format).");
+ 		return;
+ 	}
+ 
+ 	for (offset = 0; ; offset += left)
+ 	{
+ 		errr err;
+ 
+ 		/* A pointer for the pasted information. */
+ 		unsigned char *data;
+ 
+ 		Atom type;
+ 		int fmt;
+ 		unsigned long nitems;
+ 
+ 		/* Set data to the string, and catch errors. */
+ 		if (XGetWindowProperty(Metadpy->dpy, Infowin->win, XA_STRING, offset,
+ 			32767, TRUE, XA_STRING, &type, &fmt, &nitems, &left, &data)
+ 			!= Success) break;
+ 
+ 		/* Paste the text. */
+ 		err = type_string(data, nitems);
+ 
+ 		/* Free the data pasted. */
+ 		XFree(data);
+ 
+ 		/* No room. */
+ 		if (err == 7)
+ 		{
+ 			bell("Paste failure (too much text selected).");
+ 			break;
+ 		}
+ 		/* Paranoia? - strange errors. */
+ 		else if (err)
+ 		{
+ 			break;
+ 		}
+ 
+ 		/* Pasted everything. */
+ 		if (!left) return;
+ 	}
+ 
+ 	/* An error has occurred, so free the last bit of data before returning. */
+ 	XFree(data);
+ }
+ 
+ /*
+  * Handle various events conditional on presses of a mouse button.
+  */
+ static void handle_button(Time time, int x, int y, int button,
+ 	bool press)
+ {
+ 	/* The co-ordinates are only used in Angband format. */
+ 	pixel_to_square(&x, &y, x, y);
+ 
+ 	if (press && button == 1) copy_x11_start(x, y);
+ 	if (!press && button == 1) copy_x11_end(time);
+ 	if (!press && button == 2) paste_x11_request(time);
+ }
  
  /*
   * Process events
***************
*** 1605,1616 ****
  	term_data *td = NULL;
  	infowin *iwin = NULL;
  
! 	int i, x, y;
  	int window = 0;
  
  	/* Do not wait unless requested */
  	if (!wait && !XPending(Metadpy->dpy)) return (1);
  
  	/* Load the Event */
  	XNextEvent(Metadpy->dpy, xev);
  
--- 2017,2034 ----
  	term_data *td = NULL;
  	infowin *iwin = NULL;
  
! 	int i;
  	int window = 0;
  
  	/* Do not wait unless requested */
  	if (!wait && !XPending(Metadpy->dpy)) return (1);
  
+ 	/* Hack - redraw the selection, if needed.
+ 	 * This doesn't actually check that one of its squares was drawn to,
+ 	 * only that this may have happened.
+ 	 */
+ 	if (s_ptr->select && !s_ptr->drawn) mark_selection();
+ 
  	/* Load the Event */
  	XNextEvent(Metadpy->dpy, xev);
  
***************
*** 1649,1661 ****
  	/* Switch on the Type */
  	switch (xev->type)
  	{
- 
- #if 0
- 
  		case ButtonPress:
  		case ButtonRelease:
  		{
! 			int z = 0;
  
  			/* Which button is involved */
  			if (xev->xbutton.button == Button1) z = 1;
--- 2067,2082 ----
  	/* Switch on the Type */
  	switch (xev->type)
  	{
  		case ButtonPress:
  		case ButtonRelease:
  		{
! 			bool press = (xev->type == ButtonPress);
! 
! 			/* Where is the mouse */
! 			int x = xev->xbutton.x;
! 			int y = xev->xbutton.y;
! 
! 			int z;
  
  			/* Which button is involved */
  			if (xev->xbutton.button == Button1) z = 1;
***************
*** 1663,1674 ****
  			else if (xev->xbutton.button == Button3) z = 3;
  			else if (xev->xbutton.button == Button4) z = 4;
  			else if (xev->xbutton.button == Button5) z = 5;
! 
! 			/* Where is the mouse */
! 			x = xev->xbutton.x;
! 			y = xev->xbutton.y;
  
  			/* XXX Handle */
  
  			break;
  		}
--- 2084,2093 ----
  			else if (xev->xbutton.button == Button3) z = 3;
  			else if (xev->xbutton.button == Button4) z = 4;
  			else if (xev->xbutton.button == Button5) z = 5;
! 			else z = 0;
  
  			/* XXX Handle */
+ 			handle_button(xev->xbutton.time, x, y, z, press);
  
  			break;
  		}
***************
*** 1677,1684 ****
  		case LeaveNotify:
  		{
  			/* Where is the mouse */
! 			x = xev->xcrossing.x;
! 			y = xev->xcrossing.y;
  
  			/* XXX Handle */
  
--- 2096,2103 ----
  		case LeaveNotify:
  		{
  			/* Where is the mouse */
! 			int x = xev->xcrossing.x;
! 			int y = xev->xcrossing.y;
  
  			/* XXX Handle */
  
***************
*** 1688,1714 ****
  		case MotionNotify:
  		{
  			/* Where is the mouse */
! 			x = xev->xmotion.x;
! 			y = xev->xmotion.y;
  
  			/* XXX Handle */
  
  			break;
  		}
  
  		case KeyRelease:
  		{
  			/* Nothing */
  			break;
  		}
  
- #endif
- 
  		case KeyPress:
  		{
  			/* Save the mouse location */
! 			x = xev->xkey.x;
! 			y = xev->xkey.y;
  
  			/* Hack -- use "old" term */
  			Term_activate(&old_td->t);
--- 2107,2157 ----
  		case MotionNotify:
  		{
  			/* Where is the mouse */
! 			int x = xev->xmotion.x;
! 			int y = xev->xmotion.y;
! 			unsigned int z = xev->xmotion.state;
! 
! 			/* Convert to co-ordinates Angband understands. */
! 			pixel_to_square(&x, &y, x, y);
! 
! 			/* Alter the selection if appropriate. */
! 			copy_x11_cont(x, y, z);
  
  			/* XXX Handle */
  
  			break;
  		}
  
+ 		case SelectionNotify:
+ 		{
+ 			paste_x11_accept(&(xev->xselection));
+ 			break;
+ 		}
+ 
+ 		case SelectionRequest:
+ 		{
+ 			paste_x11_send(&(xev->xselectionrequest));
+ 			break;
+ 		}
+ 
+ 		case SelectionClear:
+ 		{
+ 			s_ptr->select = FALSE;
+ 			mark_selection();
+ 			break;
+ 		}
+ 
  		case KeyRelease:
  		{
  			/* Nothing */
  			break;
  		}
  
  		case KeyPress:
  		{
  			/* Save the mouse location */
! 			int x = xev->xkey.x;
! 			int y = xev->xkey.y;
  
  			/* Hack -- use "old" term */
  			Term_activate(&old_td->t);
***************
*** 1911,1918 ****
  		/* Handle change in the "level" */
  		case TERM_XTRA_LEVEL: return (Term_xtra_x11_level(v));
  
! 		/* Clear the screen */
! 		case TERM_XTRA_CLEAR: Infowin_wipe(); return (0);
  
  		/* Delay for some milliseconds */
  		case TERM_XTRA_DELAY:
--- 2354,2361 ----
  		/* Handle change in the "level" */
  		case TERM_XTRA_LEVEL: return (Term_xtra_x11_level(v));
  
! 		/* Clear the screen, and redraw any selection later. */
! 		case TERM_XTRA_CLEAR: Infowin_wipe(); s_ptr->drawn = FALSE; return (0);
  
  		/* Delay for some milliseconds */
  		case TERM_XTRA_DELAY:
***************
*** 1969,1974 ****
--- 2412,2420 ----
  	/* Mega-Hack -- Erase some space */
  	Infofnt_text_non(x, y, "", n);
  
+ 	/* Redraw the selection if any, as it may have been obscured. (later) */
+ 	s_ptr->drawn = FALSE;
+ 
  	/* Success */
  	return (0);
  }
***************
*** 1985,1990 ****
--- 2431,2439 ----
  	/* Draw the text */
  	Infofnt_text_std(x, y, s, n);
  
+ 	/* Redraw the selection if any, as it may have been obscured. (later) */
+ 	s_ptr->drawn = FALSE;
+ 
  	/* Success */
  	return (0);
  }
***************
*** 2087,2092 ****
--- 2536,2544 ----
  		x += td->fnt->wid;
  	}
  
+ 	/* Redraw the selection if any, as it may have been obscured. (later) */
+ 	s_ptr->drawn = FALSE;
+ 
  	/* Success */
  	return (0);
  }
***************
*** 2132,2138 ****
  
  	/* Get default font for this term */
  	font = get_default_font(i);
! 
  	/* Window specific location (x) */
  	sprintf(buf, "ANGBAND_X11_AT_X_%d", i);
  	str = getenv(buf);
--- 2584,2590 ----
  
  	/* Get default font for this term */
  	font = get_default_font(i);
! puts(font);
  	/* Window specific location (x) */
  	sprintf(buf, "ANGBAND_X11_AT_X_%d", i);
  	str = getenv(buf);
***************
*** 2194,2200 ****
  	                 Metadpy->fg, Metadpy->bg);
  
  	/* Ask for certain events */
! 	Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask);
  
  	/* Set the window name */
  	Infowin_set_name(name);
--- 2646,2653 ----
  	                 Metadpy->fg, Metadpy->bg);
  
  	/* Ask for certain events */
! 	Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask |
! 		PointerMotionMask | ButtonPressMask | ButtonReleaseMask);
  
  	/* Set the window name */
  	Infowin_set_name(name);
Index: src/util.c
===================================================================
RCS file: /home/rr9/angband/angband/src/util.c,v
retrieving revision 1.89
diff -c -d -r1.89 util.c
*** src/util.c	27 Feb 2003 21:43:09 -0000	1.89
--- src/util.c	21 Mar 2003 00:36:44 -0000
***************
*** 4446,4448 ****
--- 4446,4493 ----
  }
  
  #endif /* SUPPORT_GAMMA */
+ 
+ extern int Term_queue_space(void);
+ 
+ /*
+  * Add a series of keypresses to the "queue".
+  *
+  * Return any errors generated by Term_keypress() in doing so, or SUCCESS
+  * if there are none.
+  *
+  * Catch the "out of space" error before anything is printed.
+  *
+  * NB: The keys added here will be interpreted by any macros or keymaps.
+  */
+ errr type_string(char *str, uint len)
+ {
+ 	char *s;
+ 
+ 	term *old = Term;
+ 
+ 	/* Paranoia - no string. */
+ 	if (!str) return 5;
+ 
+ 	/* Hack - calculate the string length here if none given. */
+ 	if (!len) len = strlen(str);
+ 
+ 	/* Activate the main window, as all pastes go there. */
+ 	Term_activate(term_screen);
+ 
+ 	/* Not enough space for the string. */
+ 	if (Term_queue_space() <= (int)len)
+ 		return 7;
+ 
+ 	for (s = str; s < str+len; s++)
+ 	{
+ 		errr err = Term_keypress(*s);
+ 
+ 		/* Catch errors other than "str[i] == 0", which is ignored. */
+ 		if (err && err != -1) return err;
+ 	}
+ 
+ 	/* Activate the original window. */
+ 	Term_activate(old);
+ 
+ 	return 0;
+ }
Index: src/z-term.c
===================================================================
RCS file: /home/rr9/angband/angband/src/z-term.c,v
retrieving revision 1.15
diff -c -d -r1.15 z-term.c
*** src/z-term.c	28 Jul 2002 19:16:41 -0000	1.15
--- src/z-term.c	21 Mar 2003 00:38:07 -0000
***************
*** 1921,1926 ****
--- 1921,1943 ----
  }
  
  
+ /*
+  * Calculate how much space there is in the key queue for the current term.
+  */
+ int Term_queue_space(void)
+ {
+ 	/* Find the gap if the tail is before the head. */
+ 	int space = Term->key_tail - Term->key_head;
+ 
+ 	/* Otherwise, add in the extra for looping. */
+ 	if (space <= 0) space = Term->key_size - space;
+ 
+ 	/* The last space is never used as that would be interpreted as leaving
+ 	 * no pending keypresses. */
+ 	return space-1;
+ }
+ 
+ 
  
  
  
