/* * Copyright 1986, 1987, 1988, 1989, 1990 Ithaca Software, Alameda, CA * */

/**
 *	GrayScale, TrueColor, and StaticGray not tested!
 *	(B&W, 24-bit DirectColor, and 8-bit PseudoColor has been tested)
 *	machines with odd numbers of bits not tested!
 *
 *	Needs:
 *		the possibility of the SaveUnder window attribute
 *		polite usage of WM_HINTS etc. 
 *
 *	Problems:
 *		on aixwm after a move the whole window is always redrawn (still true?)
 *		if (DECWINDOWS) stuff ought to go!
 *		StaticColor not particularly supported
 *		TrueColor/DirectColor can be 24 bits only for pixel arrays
 *
 *	Uncertainties:
 *		under Use_window_ID, should we be setting the keyboard focus?
 *		under Use_window_ID, how should the private color map work?
 *
**/

#include "hoops.h"

#ifndef X11

global boolean HD_X11_Driver (actor, request)
	stack		Driver			*actor;
	stack		int				request; {
	extern		boolean HD_No_Driver ();

	return HD_No_Driver (actor, request, "X11");
}

#else	/* it's a real X driver... */

/**
 *	Header files included
**/

#include	"patterns.h"
#include	"please.h"
#include	"driver.h"

#define		Window			XWindow
#define		Color			XColor
#define		Display			XDisplay
#define		Time			XTime

#ifdef	vms
#	include <decw$include:X.h>
#	include <decw$include:Xlib.h>
#	include <decw$include:keysym.h>
#	include <decw$include:Xutil.h>
#	undef	VMS
#	define	VMS			TRUE
#else	/* vms */
#	include <X11/Xlib.h>
#	include <X11/X.h>
#	include <X11/keysym.h>
#	include <X11/Xutil.h>
#	define	VMS			FALSE
#endif	/* vms */

#undef		Time
#undef		Display
#undef		Color
#undef		Window

#include	"x11data.h"
#include	<stdio.h>


/**
 *	Defines used
**/

#define ALL_EVENTS				(MOUSE_EVENTS|WINDOW_EVENTS|KEYBOARD_EVENTS)

#define CHECK_CLIP(xdata, tr, gc, last) \
	{if ((last) != (tr)->h.incarnation) new_clip (xdata, tr, gc, &(last));}

#define DEBUG_SYNCHRONIZE		1

#define DEBUG_COLOR_TYPE	   016		/* mask for the following choices */
#define DEBUG_DEFAULT_COLOR		00
#define DEBUG_BLACK_AND_WHITE	02
#define DEBUG_GRAY_SCALE		04
#define DEBUG_MAPPED_RGB		06
#define DEBUG_DIRECT_RGB	   010

#define DEBUG_SEQUENCING	   020

#define GET(x,a)				((unsigned long)(x).a)

/* map state of keys to hoops std. */
#define HOOPS_ALT_MASK		0x1000
#define HOOPS_META_MASK		0x1000
#define HOOPS_SHIFT_MASK	0x2000
#define HOOPS_CTRL_MASK		0x4000

#define INVISIBLE				-1	 /* as a pattern */

#define KEYBOARD_EVENTS			KeyPressMask

#define MAX_DASH				12
#define MAX_FONTS				1024
#define MAX_LIST_LENGTH			4

/**
 *	define MAX_POLYLINE_POINTS below per whack. Actually, it's
 *	(display->max_request_size - 12) / 4 which is (4093 - 12)/ 4
 *	usually, but let us pick something "safer". Ie, 512.
**/

#define MAX_POLYLINE_POINTS		512
#define MAX_POLYGON_POINTS		MAX_POLYLINE_POINTS

#define MOUSE_EVENTS			(ButtonPressMask|ButtonReleaseMask| \
								LeaveWindowMask|EnterWindowMask| \
								PointerMotionMask)
#define RGB_TO_LONG(xdata, x)	\
	(xdata->red_first ? \
	(GET (x, r) | ((GET (x, g) | (GET (x, b) << xdata->bits_per_color)) << xdata->bits_per_color)) : \
	(GET (x, b) | ((GET (x, g) | (GET (x, r) << xdata->bits_per_color)) << xdata->bits_per_color)))

#define SEQUENCE(dc, kind)		(BIT (dc->options.debug, DEBUG_SEQUENCING) ? \
									(fprintf (stderr, seqmsg, kind), 0) : 0)

#define UNASSIGNED_MAP_MAP		0xFFFFFFFF

#define WINDOW_EVENTS			(ExposureMask|FocusChangeMask|\
								 StructureNotifyMask)


/**
 *	System dependent defines used
**/

#ifdef	hpux
#	define		MOTIF
#endif	/* hpux */
#ifdef	sony
#	define		MOTIF
#endif	/* sony */
#ifdef	sun
#	define		OPENWINDOWS
#endif	/* sun */
#ifdef	ultrix
#	define		DECWINDOWS
#endif	/* ultrix */
#ifdef	vms
#	define		DECWINDOWS
#endif	/* vms */

#ifdef	MOTIF
#	define		X11_BORDER_LEFT			10
#	define		X11_BORDER_RIGHT		12
#	define		X11_BORDER_BOTTOM		12
#	define		X11_BORDER_TOP			26
#else	/* MOTIF */
#	ifdef	OPENWINDOWS
#		define	X11_BORDER_LEFT			6
#		define	X11_BORDER_RIGHT		6
#		define	X11_BORDER_BOTTOM		14
#		define	X11_BORDER_TOP			28
#	else	/* OPENWINDOWS */
#		define	X11_BORDER_LEFT			3
#		define	X11_BORDER_RIGHT		3
#		define	X11_BORDER_BOTTOM		3
#		define	X11_BORDER_TOP			23
#	endif	/* OPENWINDOWS */
#endif	/* MOTIF */

#ifdef	SUN
#	define		WMGR_BIAS_RIGHT 6
#	define		WMGR_BIAS_DOWN	28
#else	/* SUN */
#	define		WMGR_BIAS_RIGHT 0
#	define		WMGR_BIAS_DOWN	0
#endif	/* SUN */


/**
 *	Declarations of local functions used by action table routines
**/

local	const	char	seqmsg[] = "X Sequence: %s\n";

local	void	get_actions();

local	void	draw_dc_face_common(),
				set_resizing_hints(),
				new_clip();

local	int		error_handler(),
				ioerror_handler(),
				be_quiet_handler();

local	void	new_mapped_line_rendition(),
				new_mapped_text_rendition(),
				new_mapped_face_rendition(),
				new_direct_line_rendition(),
				new_direct_text_rendition(),
				new_direct_face_rendition(),
				new_bandw_line_rendition(),
				new_bandw_text_rendition(),
				new_bandw_face_rendition(),
				new_gray_line_rendition(),
				new_gray_text_rendition(),
				new_gray_face_rendition();

local	void	check_events(),
				enable_parent_events();

local	void	draw_bit_raster(),
				draw_gray_byte_raster(),
				draw_gray_word_raster(),
				draw_rgb_long_raster(),
				draw_mapped_byte_raster(),
				draw_mapped_word_raster();

local	void	pixar_to_gray_byte_rasters(),
				pixar_to_gray_word_rasters(),
				pixar_to_rgb_long_rasters();


/**
 *	Action table routines
**/


global boolean HD_X11_Driver (actor, request)
	stack	Driver	*actor;
	stack	int		request; {
	extern	boolean HD_Connect_Standard_Driver();

	return HD_Connect_Standard_Driver (actor, request, ADDR (get_actions));
}


local boolean start_device (dc)
	stack		Display_Context		*dc; {
	register	XData				*xdata;
	stack		int					planes;
	stack		int					i;
	stack		XGCValues			xgcv;	/* dummy argument for xcreateGC */
	stack		char				dummy[2];

	ALLOC (xdata, XData);
	dc->data = (void *)xdata;
	xdata->dc = dc;

	/**
	 *	Disable the normal error handling -- but note that the
	 *	error handlers are apparently never called by an XOpenDisplay.
	**/

	XSetErrorHandler (be_quiet_handler);
	XSetIOErrorHandler (be_quiet_handler);

	/* make our own display connection */
	if (dc->actor_name[0] == '\0') 
		xdata->display = XOpenDisplay (VMS ? "DECW$DISPLAY" : "unix:0.0");
	else {
		register  char		*in, *out;
		stack	  char		name[MAX_ERRMSG];

		in = dc->actor_name;
		out = &name[0];

		until (*in == '\0' || *in == '+') *out++ = *in++;
		*out = '\0';
		xdata->display = XOpenDisplay (ADDR (name));
	}

	XSetErrorHandler (error_handler);
	XSetIOErrorHandler (ioerror_handler);

	if (xdata->display == (XDisplay *)0) {
		HI_Error3 (Sprintf_S (null,
			"Unable to open X-window display for segment '%s' -",
			dc->actor_name),
			VMS ? 
"(HOOPS_PICTURE should look like 'x11/DECW$DISPLAY' or 'x11/host::DECW$DISPLAY';" :
"(HOOPS_PICTURE should look like 'x11/unix:0.0' or 'x11/host:display.screen';",
"for multiple windows add +nnn. Sorry, X did not say what went wrong.");

		return false;
	}

	if (dc->options.use_window_ID != 0) {
		stack	XWindowAttributes		xwa;

		xdata->window = dc->options.use_window_ID;
		XGetWindowAttributes (xdata->display, xdata->window, &xwa);
		xdata->screen = xwa.screen; 
		xdata->visual = xwa.visual;
	}
	else {
		stack	XVisualInfo		template,
								*info_list;
		stack	int				info_count;

		xdata->window = (XWindow)0;

		/* for the sake of debugging, allow smart displays to play dumb */
		
		switch (dc->options.debug & DEBUG_COLOR_TYPE) {
			case DEBUG_DEFAULT_COLOR: {
				xdata->screen = DefaultScreenOfDisplay (xdata->display);
				xdata->visual = DefaultVisualOfScreen (xdata->screen);
			}	break;

			case DEBUG_BLACK_AND_WHITE:
			case DEBUG_GRAY_SCALE:
			case DEBUG_MAPPED_RGB:
			case DEBUG_DIRECT_RGB: {

				switch (dc->options.debug & DEBUG_COLOR_TYPE) {
					case DEBUG_BLACK_AND_WHITE: 
					case DEBUG_GRAY_SCALE: template.class = StaticGray; break;

					case DEBUG_MAPPED_RGB: template.class = PseudoColor; break;

					case DEBUG_DIRECT_RGB: template.class = TrueColor; break;
				}
				
				info_list = XGetVisualInfo (xdata->display, VisualClassMask,
											&template, &info_count);

				if (info_count == 0) {
					HI_Warning ("Specified color class not available");
					xdata->screen = DefaultScreenOfDisplay (xdata->display);
					xdata->visual = DefaultVisualOfScreen (xdata->screen);
				}
				else {
					stack		XVisualInfo		*this = info_list,
												*best = info_list,
												*end = &info_list[info_count];
					
					until (++this == end) 
						if (best->depth < this->depth) best = this;

					xdata->screen = ScreenOfDisplay (xdata->display, 
													 best->screen);
					xdata->visual = best->visual;
					XFree (info_list);
				}
			}	break;
		}
	}

	xdata->root_window = RootWindowOfScreen (xdata->screen);

	if (BIT (dc->options.debug, DEBUG_SYNCHRONIZE))
		XSynchronize (xdata->display, 1);  /* (For Debugging) */

	/* Create stipples for patterned faces and dither patterns */
	HD_Get_Bit_Patterns (dc, true);

	for (i=0;i<TOTAL_BIT_PATTERNS;i++) {
		xdata->stipples[i] = XCreateBitmapFromData (xdata->display,
								RootWindowOfScreen (xdata->screen),
								dc->bit_pattern[i], 16, 16);
		if (xdata->stipples[i] == null) {
				HI_Fatal2 ("Unexpected XWindows Failure -",
						"Unable to create stipples");
				break;
		}
	}

	/* create appropriate GC's */
	xgcv.fill_style = FillSolid;
	xdata->line_gc = XCreateGC (xdata->display,
								RootWindowOfScreen (xdata->screen),
								GCFillStyle, &xgcv);

	xdata->face_gc = XCreateGC (xdata->display,
								RootWindowOfScreen (xdata->screen),
								GCFillStyle, &xgcv);

	xdata->pixar_gc = XCreateGC (xdata->display,
								RootWindowOfScreen (xdata->screen),
								GCFillStyle, &xgcv);

	xdata->text_gc = XCreateGC (xdata->display,
								RootWindowOfScreen (xdata->screen),
								GCFillStyle, &xgcv);

	xgcv.fill_style = FillStippled;
	xgcv.stipple = xdata->stipples[0];
	xdata->blended_face_gc = XCreateGC (xdata->display,
										RootWindowOfScreen (xdata->screen),
										GCFillStyle|GCStipple, &xgcv);

	/* initialize mouse data */
	xdata->mouse_x = 0;
	xdata->mouse_y = 0;
	xdata->mouse_buttons = 0;
	xdata->mouse_valid = false;
	xdata->mouse_latched = false;
	xdata->latched_mouse_x = 0;
	xdata->latched_mouse_y = 0;
	xdata->latched_mouse_buttons = 0;

	/* Initialize all incarnations to zero */
	xdata->last_face_rendition = (Incarnation)0;
	xdata->last_line_rendition = (Incarnation)0;
	xdata->last_line_xform_rendition = (Incarnation)0;
	xdata->last_text_rendition = (Incarnation)0;
	xdata->last_text_xform_rendition = (Incarnation)0;
	xdata->last_face_xform_rendition = (Incarnation)0;
	xdata->last_blended_face_xform_rendition = (Incarnation)0;
	xdata->last_pixar_xform_rendition = (Incarnation)0;

	xdata->pixar_image = null;
	xdata->xor_in_progress = false;	   
	xdata->first_update = true;
	xdata->resize_in_progress = false;
	xdata->check_since_finish = false;

	/* initialize Compose-key status. Somehow.(?) */
	xdata->compose_status.compose_ptr = null;
	xdata->compose_status.chars_matched = 0;

	/* initialize our Compose-key data. */
	xdata->first_key = 0;

#	ifdef	APOLLO
		xdata->apollo_kludged = false;
#	endif	/* APOLLO */

	return true;
}


local void stop_device (dc)
	stack		Display_Context		*dc;  {
	register	XData				*xdata = (XData *)dc->data;
	stack		int					i;

	SEQUENCE(dc, "stop device");

	if (xdata->pixar_image != null) {
		XDestroyImage(xdata->pixar_image);
	}
	XCloseDisplay(xdata->display);

	if (xdata->compose_status.compose_ptr != null) {
		XFree(xdata->compose_status.compose_ptr);
	}

	FREE(xdata, XData);
}


local void		draw_dc_blended_face (),
				set_device_color_map ();


local void get_physical_info (dc)
	stack		Display_Context		*dc; {
	register	XData				*xdata = (XData *)dc->data;

	/**
	 *	Set physical info and rendition setting routines based
	 *	on the visual type.
	**/

	switch (xdata->visual->class) {
		case StaticColor:
		case PseudoColor: {
			xdata->mapped_colors = true;
			xdata->bits_per_color = xdata->visual->bits_per_rgb;
			xdata->default_cmap = DefaultColormapOfScreen (xdata->screen);

			/* colors componnents will <<8 into XColor */
			dc->physical.color_system = MAPPED_RGB;
			dc->physical.first_color = 0;
			if (xdata->visual->class == StaticColor)
				dc->physical.number_of_colors = 1000;  /* a 'nice' number */
			else		
				dc->physical.number_of_colors = XCellsOfScreen (xdata->screen);

			dc->physical.nominal_color_resolution = 256;

			/* rendition setting for color mapped visual types */
			xdata->new_line_rendition = ADDR (new_mapped_line_rendition);
			xdata->new_text_rendition = ADDR (new_mapped_text_rendition);
			xdata->new_face_rendition = ADDR (new_mapped_face_rendition);

			/* allow these to exist now too */
			dc->actions.draw_dc_blended_face = ADDR (draw_dc_blended_face);
			dc->actions.set_device_color_map = ADDR (set_device_color_map);
		}		break;

		case TrueColor: /*!! same as Direct Color for now !!*/
		case DirectColor: {
			xdata->mapped_colors = false;
			xdata->bits_per_color = xdata->visual->bits_per_rgb;
			xdata->red_first = BIT (xdata->visual->red_mask, 1);

			dc->physical.color_system = DIRECT_RGB;
			dc->physical.nominal_color_resolution = 1 << xdata->bits_per_color;
			dc->physical.first_color = 0;
			dc->physical.number_of_colors = 1 << (3 * xdata->bits_per_color);
			
			/* rendition setting for Direct Color visual types */
			xdata->new_line_rendition = ADDR (new_direct_line_rendition);
			xdata->new_text_rendition = ADDR (new_direct_text_rendition);
			xdata->new_face_rendition = ADDR (new_direct_face_rendition);

		}		break;

		case StaticGray:		/* same as Gray Scale for now */
		case GrayScale: {
			xdata->mapped_colors = false;
			xdata->bits_per_color = xdata->visual->bits_per_rgb;

			if (xdata->bits_per_color == 1) {
				dc->physical.color_system = GRAY_SCALE;
				dc->physical.nominal_color_resolution = DITHER_BIT_RESOLUTION;

				/* rendition setting for black-and-white visual types */
				xdata->new_line_rendition = ADDR (new_bandw_line_rendition);
				xdata->new_text_rendition = ADDR (new_bandw_text_rendition);
				xdata->new_face_rendition = ADDR (new_bandw_face_rendition);
			}
			else {
				dc->physical.color_system = GRAY_SCALE;
				dc->physical.nominal_color_resolution = 1 << xdata->bits_per_color;

				/* rendition setting for Gray Scale visual types */
				xdata->new_line_rendition = ADDR (new_gray_line_rendition);
				xdata->new_text_rendition = ADDR (new_gray_text_rendition);
				xdata->new_face_rendition = ADDR (new_gray_face_rendition);
			}
		}		break;

	}

	/* this is for the screen not the window */
	dc->physical.offset_in_pixels.x = 0;
	dc->physical.offset_in_pixels.y = 0;
	dc->physical.number_of_pixels.x = WidthOfScreen (xdata->screen);
	dc->physical.number_of_pixels.y = HeightOfScreen (xdata->screen);

	/**
	 *	DisplayWidthMM & DisplayHeightMM almost never work so
	 *	this may need to be over-ridden by setting the driver
	 *	option "physical size=(x,y)".
	**/

	dc->physical.size.x = WidthMMOfScreen (xdata->screen)/10.0;
	dc->physical.size.y = HeightMMOfScreen (xdata->screen)/10.0;
	dc->physical.absolute_coordinates = false;
	dc->physical.windowing_system = true;

	/*!! how to answer this question?? !!*/
	dc->physical.number_of_locater_buttons = 3;
	dc->physical.driver_type = "X11";

	dc->physical.max_polyline_points = MAX_POLYLINE_POINTS;
	dc->physical.max_polygon_points = MAX_POLYGON_POINTS;
}


local void get_current_info (dc)
	stack		Display_Context		*dc; {

	dc->current.first_color = 0;		/* we don't understand anything else */

	if (dc->options.use_window_ID != 0) {
		dc->options.subscreen_moving = true;
		dc->options.subscreen_resizing = true;
		dc->options.subscreen_stretching = true;
	}
	else {
		dc->options.border = dc->options.control_area;	/* together always */

		if (dc->options.control_area) 
			HD_Allow_For_Border (dc, X11_BORDER_LEFT, X11_BORDER_RIGHT,
									 X11_BORDER_BOTTOM, X11_BORDER_TOP);
	}
}


local void init_picture (dc)
	stack		Display_Context			*dc;{
	register	XData					*xdata = (XData *)dc->data;

	if (BIT (dc->options.debug, DEBUG_SEQUENCING)) {
		SEQUENCE (dc, "init picture");

		/* force new_rendition routines to wake up */
		xdata->last_face_rendition = (Incarnation)0;
		xdata->last_line_rendition = (Incarnation)0;
		xdata->last_line_xform_rendition = (Incarnation)0;
		xdata->last_text_rendition = (Incarnation)0;
		xdata->last_text_xform_rendition = (Incarnation)0;
		xdata->last_face_xform_rendition = (Incarnation)0;
		xdata->last_blended_face_xform_rendition = (Incarnation)0;
		xdata->last_pixar_xform_rendition = (Incarnation)0;
	}

	xdata->yfudge = dc->outer.extent.top - dc->outer.extent.bottom;
}


local void init_update (dc)
	stack		Display_Context		*dc; {
	register	XData				*xdata = (XData *)dc->data;

	/**
	 *	Check for mandatory-update happenings
	 *	(also done in Request_Location)!! 
	**/

	xdata->check_since_finish = false;

	SEQUENCE (dc, "init update");

	/**
	 *	The following call to XSync() is made so that Hoops when used
	 *	with widgets will correctly update the window for exposure
	 *	events.
	**/

	if (dc->options.use_window_ID != 0) {
		XSync(xdata->display, False);
	}

	check_events (dc);

	if (dc->options.use_window_ID != 0 && xdata->first_update) {
		stack	int				border_width, 
								depth, 
								global_x, 
								global_y;
		stack	XWindow			rootjunk,
								childjunk;
		stack	XWindow			*children;
		stack	unsigned int	nchildren;

		SEQUENCE (dc, "request resize for initial use-window");

		/* get its parent (kluge) */
		enable_parent_events (xdata, StructureNotifyMask);

		/* get its geometry and tell hoops */
		XGetGeometry (xdata->display, xdata->window, &rootjunk,
					  &xdata->window_x, &xdata->window_y,
					  &xdata->window_width, &xdata->window_height,
					  &border_width, &depth);

		/* translate to root coordinates */
		XTranslateCoordinates (xdata->display, 
							   xdata->parent_window, 
							   xdata->root_window,
							   xdata->window_x,
							   xdata->window_y,
							   &global_x, 
							   &global_y, 
							   &childjunk);

		dc->options.subscreen_moving = true;
		dc->options.subscreen_resizing = true;
		dc->options.subscreen_stretching = true;
		HD_Resize_Subscreen (dc, true,	global_x, 
				global_x + xdata->window_width - 1,
				dc->physical.number_of_pixels.y - 
				(global_y + xdata->window_height),
				dc->physical.number_of_pixels.y - 1 - global_y);
	}
}


local void finish_update (dc)
	stack	Display_Context		*dc; {
	register  XData				*xdata = (XData *)dc->data;

	if (BIT (dc->options.debug, DEBUG_SEQUENCING)) {
		SEQUENCE (dc, "finish update");
		fflush (stderr);
	}
	
	if (xdata->window != (XWindow)0 &&
		dc->options.use_window_ID == 0 &&
		(xdata->resizing_was_on != dc->options.subscreen_resizing ||
		 xdata->stretching_was_on != dc->options.subscreen_stretching)) 
		set_resizing_hints (dc);

	XFlush (xdata->display);
	xdata->first_update = false;
	xdata->check_since_finish = false;
}


/**
 *	get_outer_window()
 *
 *	request a window from the server and force its mapping
 *	to what hoops wants with the OverrideRedirect mask
 *	in the window manager hints
**/

local long get_outer_window (dc)
	stack		Display_Context		*dc; {
	register	XData				*xdata = (XData *)dc->data;
	stack		XSetWindowAttributes	xswa;
	stack		int					x, y, width, height;
	stack		XDisplay			*xdisplay;
	stack		XGCValues			xgcv;	/* dummy argument for xcreateGC */
	stack		char				dummy[2];
	stack		XSizeHints			size_hints;
	stack		XWMHints			wm_hints;

	SEQUENCE (dc, "get outer window");

	if (dc->options.use_window_ID != 0) {
		xswa.bit_gravity = CenterGravity;
		XChangeWindowAttributes (xdata->display, xdata->window,
								 CWBitGravity, &xswa);

		if (xdata->mapped_colors) {
			xswa.colormap = xdata->default_cmap;
			XChangeWindowAttributes (xdata->display, xdata->window,
									 CWColormap, &xswa);
			xdata->cmap = xdata->default_cmap;
		}

		if (dc->options.disable_input)
			XSelectInput (xdata->display, xdata->window, WINDOW_EVENTS);
		else {
			stack		XWindowAttributes		xwa;

			XGetWindowAttributes (xdata->display, xdata->window, &xwa);
			if (ANYBIT (xwa.all_event_masks, MOUSE_EVENTS|KEYBOARD_EVENTS)) {
				HI_Warning3 (
				"Unable to enable mouse/keyboard input events in X driver -",
				Sprintf_LD (null,
				"Another client already has them turned on for Window ID = %D",
							xdata->window),
				"(You may want to use the 'disable input' Driver Option.)");

				XSelectInput (xdata->display, xdata->window, WINDOW_EVENTS);
			}
			else			
				XSelectInput (xdata->display, xdata->window, ALL_EVENTS);
		}
		
		xdata->focus_on_us = false;		/* who knows */
		enable_parent_events (xdata, StructureNotifyMask);
	}
	else {
		stack	unsigned long	xswa_mask;
		stack	int				depth;
		stack	XEvent			xevent;

		xdata->window_x = dc->outer.extent.left;
		xdata->window_y = dc->physical.number_of_pixels.y - 1 
												- dc->outer.extent.top;
		xdata->window_width=dc->outer.extent.right - dc->outer.extent.left +1;
		xdata->window_height=dc->outer.extent.top - dc->outer.extent.bottom + 1;

		xswa_mask = CWBitGravity | CWOverrideRedirect | 
					CWBackPixel | CWBorderPixel;
		xswa.background_pixel = WhitePixelOfScreen (xdata->screen);
		xswa.border_pixel = BlackPixelOfScreen (xdata->screen);
		xswa.bit_gravity = ForgetGravity;
		xswa.override_redirect = !dc->options.control_area;

		if (xdata->mapped_colors) {
			xdata->cmap = xdata->default_cmap;
			xswa_mask |= CWColormap;
			xswa.colormap = xdata->default_cmap;

			/* If XNEWS (StaticColor default) */
			if (xdata->visual->class == PseudoColor &&
				DefaultVisualOfScreen(xdata->screen)->class == StaticColor) {

				/* mustn't inherit a static color map into a dynamic window */
				xdata->cmap = XCreateColormap (xdata->display,
											   xdata->root_window,
											   xdata->visual,
											   AllocNone);
				xswa.colormap = xdata->cmap;
			}
		}

		if ((dc->options.debug & DEBUG_COLOR_TYPE) == DEBUG_BLACK_AND_WHITE)
			depth = 1;
		else
			depth = 0;

		xdata->parent_window = xdata->root_window;
		xdata->window = XCreateWindow (xdata->display,
									   xdata->parent_window,
									   xdata->window_x - WMGR_BIAS_RIGHT, 
									   xdata->window_y - WMGR_BIAS_DOWN,
									   xdata->window_width, 
									   xdata->window_height, 0,
									   depth, InputOutput, xdata->visual,
									   xswa_mask, &xswa);

		/**
		 *	Set a window name for the window manager.
		**/

		if (dc->options.title.length == 0) {
			XStoreName(xdata->display, xdata->window, "hoops");
		}
		else {
			stack		char	name[MAX_ERRMSG];

			XStoreName (xdata->display, xdata->window, 
						Sprintf_N (name, "%n", &dc->options.title));
		}

		/**
		 *	Set size hints for the window manager.
		**/

		size_hints.x = xdata->window_x - WMGR_BIAS_RIGHT;
		size_hints.y = xdata->window_y - WMGR_BIAS_DOWN;
		size_hints.width = xdata->window_width;
		size_hints.height = xdata->window_height;
		size_hints.flags = USPosition|USSize;

		XSetNormalHints (xdata->display, xdata->window, &size_hints);

		if (dc->options.disable_input) {
			XSelectInput (xdata->display, xdata->window, WINDOW_EVENTS);
		}
		else {
			/**
			 *	Set keyboard input hints for the window manager.
			**/

			wm_hints.input = True;
			wm_hints.flags = InputHint;

			XSetWMHints (xdata->display, xdata->window, &wm_hints);

			XSelectInput (xdata->display, xdata->window, ALL_EVENTS);
		}
		
		enable_parent_events (xdata, StructureNotifyMask);

		XMapWindow (xdata->display, xdata->window);

		/**
		 *	Wait for things to settle down and the exposure to arrive.
		**/

		XWindowEvent (xdata->display, xdata->window, ExposureMask, &xevent);

		/**
		 *	note: set resize hints only after mapping; they louse up
		 *	the position/initial size hints with most window
		 *	managers.
		**/

		set_resizing_hints (dc);

#		ifdef	DECWINDOWS
			if (!dc->options.disable_input)
				XSetInputFocus (xdata->display, xdata->window, 
								RevertToParent, CurrentTime);
#		endif	/* DECWINDOWS */

		/* process the accumulated events */
		XSync(xdata->display, False);
		check_events (dc);
		xdata->focus_on_us = false;
	}

	if (xdata->mapped_colors) {
		register		unsigned long	*cmm;
		register		int				i;

		i = (dc->current.number_of_colors + dc->current.first_color) *
			sizeof (unsigned long);
		VALLOC (xdata->colormap_map, i, unsigned long);
		i = dc->current.number_of_colors + dc->current.first_color - 1;
		cmm = xdata->colormap_map;
		do cmm[i] = UNASSIGNED_MAP_MAP;
		until (--i < 0);
	}

	dc->current.window_ID2 = (long)xdata->display;	/* kluge 2nd return value */

	return (long)xdata->window;
}


local void free_outer_window (dc)
	stack		Display_Context		*dc; {
	register	XData				*xdata = (XData *)dc->data;
	register	int					i;

	SEQUENCE (dc, "free outer window");

	enable_parent_events (xdata, (Mask)false);

	if (!dc->options.use_window_ID) 
		XDestroyWindow (xdata->display, xdata->window);
	else
		XSelectInput (xdata->display, xdata->window, (Mask)false);

	if (xdata->mapped_colors) {
		if (xdata->cmap != xdata->default_cmap) {
			if (xdata->cmap_installed) 
				XUninstallColormap(xdata->display, xdata->cmap);
			XFreeColormap (xdata->display, xdata->cmap);
		}
		else if (xdata->visual->class != StaticColor) {
			i = dc->current.number_of_colors + dc->current.first_color - 1;
			
			do if (xdata->colormap_map[i] != UNASSIGNED_MAP_MAP) 
				XFreeColors (xdata->display, xdata->default_cmap, 
							 &xdata->colormap_map[i], 1, 0L);
			until (--i < 0);
		}

		i = (dc->current.number_of_colors + dc->current.first_color) *
			sizeof (unsigned long);
		VFREE (xdata->colormap_map, i, unsigned long);
	}

	xdata->window = (XWindow)0;
}


local void resize_outer_window(dc)
	stack		Display_Context			*dc; {
	register	XData					*xdata = (XData *)dc->data;
	stack		XWindow					childjunk;
	stack		XWindow					parent,
										root,
										*children;
	stack		unsigned int			nchildren;
	stack		XSizeHints				size_hints;
	stack		int						new_x,
										new_y,
										new_height,
										new_width;
	extern		Time					HI_What_Time ();
	stack		Time					give_up_time;
	extern		boolean					HI_Enable_Timer_Interrupts ();
	stack		int						retries_left = 2;

	top:;

	/* convert coordinates */
	new_x = dc->outer.extent.left;
	new_y = dc->physical.number_of_pixels.y -1- dc->outer.extent.top;
	new_width = dc->outer.extent.right - dc->outer.extent.left + 1;
	new_height = dc->outer.extent.top - dc->outer.extent.bottom + 1;

	if (BIT (dc->options.debug, DEBUG_SEQUENCING)) 
		fprintf (stderr, "X Sequence: resize outer window (%d x %d) @ (%d, %d)\n",
						 new_width, new_height, new_x, new_y);

	/* make sure events are in sync */
	XSync(xdata->display, False);
	check_events (dc);

	/* make sure saved coordinates are in sync */
	{	stack	int				border_width, 
								depth;
		stack	XWindow			rootjunk,
								childjunk;
		stack	XWindow			*children;
		stack	unsigned int	nchildren;

		XGetGeometry (xdata->display, xdata->window, &rootjunk,
					  &xdata->window_x, &xdata->window_y,
					  &xdata->window_width, &xdata->window_height,
					  &border_width, &depth);

		/* translate to root coordinates */
		XQueryTree (xdata->display, xdata->window, &xdata->root_window,
					&xdata->parent_window, &children, &nchildren);
		XFree (children);
		XTranslateCoordinates (xdata->display, 
							   xdata->parent_window, 
							   xdata->root_window,
							   xdata->window_x,
							   xdata->window_y,
							   &xdata->window_x, 
							   &xdata->window_y, 
							   &childjunk);
	}
	
	/* if we're definitely already there, forget it */
	
	if (xdata->window_x == new_x &&
		xdata->window_y == new_y &&
		xdata->window_width == new_width &&
		xdata->window_height == new_height) return;

	/* then explicitly move the window */
	XMoveResizeWindow (xdata->display, xdata->window, 
					   new_x - WMGR_BIAS_RIGHT, new_y - WMGR_BIAS_DOWN, 
					   new_width, new_height);

	/* then hint that the window manager should move the window (redundant?) */
	size_hints.x = new_x - WMGR_BIAS_RIGHT;
	size_hints.y = new_y - WMGR_BIAS_DOWN;
	size_hints.width = new_width;
	size_hints.height = new_height;
	size_hints.flags = USPosition|USSize;
	XSetNormalHints (xdata->display, xdata->window, &size_hints);

	/**
	 *	THE FOLLOWING CODE IS A MESS because the window managers
	 *	enjoy ignoring us or playing with the numbers or responding
	 *	to things that happened long ago.
	**/

	/* wait for the "correct" acknowledgement */
	xdata->resize_in_progress = true;
	if (dc->timer_interrupts_enabled) HI_Disable_Timer_Interrupts ();
	give_up_time = HI_What_Time() + TIME(1);

	forever {
		XSync(xdata->display, False);
		check_events (dc);

		if (xdata->window_x == new_x &&
			xdata->window_y == new_y &&
			xdata->window_width == new_width &&
			xdata->window_height == new_height) break;

		HI_Sleep (TIME (1./8.)); 
		if (HI_What_Time() >= give_up_time) {
			if (--retries_left >= 0) {
				if (dc->timer_interrupts_enabled) 
					(void)HI_Enable_Timer_Interrupts ();
				xdata->resize_in_progress = false;
				goto top;		/* try again */
			}	
			HI_Warning ("X11 didn't respond to resize within time limit");
			break;
		}
#		ifdef	SUN
			if (xdata->window_width == new_width &&
				xdata->window_height == new_height) break; /* "good enough" */
#		endif	/* SUN */
	}

	if (dc->timer_interrupts_enabled) (void)HI_Enable_Timer_Interrupts ();
	xdata->resize_in_progress = false;

	xdata->yfudge = dc->outer.extent.top - dc->outer.extent.bottom;
}


local void draw_dc_polyline (lr, icount, points)
	register	Line_Rendition		*lr;
	stack		int					icount;
	register	DC_Point			*points; {
	register	XPoint				*vertex;
	register	int					count;
	register	XData				*xdata = (XData *)lr->h.data;
	stack		XPoint				vbuf[MAX_POLYLINE_POINTS];

	if (icount <= 1) return;

	/* put line rendition in the line_gc if changed */
	if (lr->h.incarnation != xdata->last_line_rendition)
		(*xdata->new_line_rendition) (lr);

	count = icount;
	vertex = &vbuf[0];
	do {
		vertex->x = points->x;
		vertex->y = xdata->yfudge - points->y;
		++vertex;
		++points;
	}
	until (--count == 0);

	/* draw the polyline using line_gc */
	XDrawLines (xdata->display, xdata->window, xdata->line_gc,
				&vbuf[0], icount, CoordModeOrigin);
}


local void draw_dc_face (fr, icount, points)
	stack	Face_Rendition		*fr;
	stack	int					icount;
	stack	DC_Point			*points; {

	draw_dc_face_common (fr, icount, points, false);
}


local void draw_dc_blended_face (fr, icount, ipoints,
								 color_count, colors, patterns)
	stack		Face_Rendition	*fr;
	stack		int				icount;
	stack		DC_Point		*ipoints;
	stack		int				color_count;
	stack		Color_Index		*colors;
	stack		int				*patterns; {
	stack		XData			*xdata = (XData *)fr->h.data;
	
	stack		XPoint			vbuf[MAX_POLYGON_POINTS];
	register	XPoint			*vertex;
	register	int				count;

	stack		int				i;
	stack		XGCValues		xgcv;
	stack		unsigned long	valuemask;

	count = icount;
	vertex = &vbuf[0];
	do {
		vertex->x = ipoints->x;
		vertex->y = xdata->yfudge - ipoints->y;
		++vertex;
		++ipoints;
	}
	until (--count == 0);

	/* do first two colors in an Opaque Stipple */
	xgcv.foreground = xdata->colormap_map[colors[1]];
	xgcv.background = xdata->colormap_map[colors[0]];
	xgcv.stipple = xdata->stipples[patterns[0]];

	xgcv.fill_style = FillOpaqueStippled;
	XChangeGC (xdata->display, xdata->blended_face_gc, 
			   GCFillStyle|GCStipple|GCForeground|GCBackground, &xgcv);

	CHECK_CLIP (xdata, fr->h.transform_rendition, xdata->blended_face_gc,
				xdata->last_blended_face_xform_rendition);

	XFillPolygon (xdata->display, xdata->window,
				xdata->blended_face_gc, &vbuf[0], icount,
				Complex, CoordModeOrigin);

	/* do subsequent colors as background preserving stipples */
	xgcv.fill_style = FillStippled;
	valuemask = GCFillStyle|GCStipple|GCForeground;

	for (i = 2; i < color_count; i++) {
		xgcv.foreground = xdata->colormap_map[colors[i]];
		xgcv.stipple = xdata->stipples[patterns[i-1]];
		XChangeGC (xdata->display, xdata->blended_face_gc, valuemask, &xgcv);

		XFillPolygon (xdata->display, xdata->window,
					xdata->blended_face_gc, &vbuf[0], icount,
					Complex, CoordModeOrigin);
		valuemask = GCStipple|GCForeground;
	}
}


local void draw_dc_polygon (fr, icount, points)
	stack	Face_Rendition		*fr;
	stack	int					icount;
	stack	DC_Point			*points; {

	draw_dc_face_common (fr, icount, points, true);
}


local void draw_dc_rectangle (fr, left, right, bottom, top)
	register	Face_Rendition		*fr;
	stack		int					left, right, bottom, top; {
	register	XData				*xdata = (XData *)fr->h.data;

	if (fr->h.incarnation != xdata->last_face_rendition)
		(*xdata->new_face_rendition)(fr);

	XFillRectangle (xdata->display, xdata->window, xdata->face_gc,
				left, xdata->yfudge - top,
				right-left+1, top-bottom+1);
}


local void draw_dc_overlay_polyline (lr, count, points, contrast_color)
	register	Line_Rendition	*lr;
	stack		int				count;
	stack		DC_Point		*points;
	register	Driver_Color	*contrast_color; {
	register	XData			*xdata = (XData *)lr->h.data;

	/* play tricks to get it to look up the right hard color index */

	xdata->last_line_rendition = 0;		/* we're messing things up */
	
	switch (lr->h.display_context->physical.color_system) {

		case MAPPED_RGB: {
			stack		int				map_map_0_save;
			stack		Color_Index		color_index_save;

			map_map_0_save = xdata->colormap_map[0];
			xdata->colormap_map[0] =
					xdata->colormap_map[lr->color.map_index] ^
					xdata->colormap_map[contrast_color->map_index];
			color_index_save = lr->color.map_index;
			lr->color.map_index = 0;

			draw_dc_polyline (lr, count, points);

			xdata->colormap_map[0] = map_map_0_save;
			lr->color.map_index = color_index_save;
		}		break;
		
		case DIRECT_RGB: {
			lr->color.direct_rgb.r ^= contrast_color->direct_rgb.r;
			lr->color.direct_rgb.g ^= contrast_color->direct_rgb.g;
			lr->color.direct_rgb.b ^= contrast_color->direct_rgb.b;

			draw_dc_polyline (lr, count, points);

			lr->color.direct_rgb.r ^= contrast_color->direct_rgb.r;
			lr->color.direct_rgb.g ^= contrast_color->direct_rgb.g;
			lr->color.direct_rgb.b ^= contrast_color->direct_rgb.b;
		}		break;
		
		case GRAY_SCALE: {
			lr->color.gray_level ^= contrast_color->gray_level;

			draw_dc_polyline (lr, count, points);

			lr->color.gray_level ^= contrast_color->gray_level;
		}		break;

	}

	xdata->last_line_rendition = 0;		/* we've messed things up */
}


local void draw_dc_overlay_face (fr, count, points, contrast_color)
	register	Face_Rendition	*fr;
	stack		int				count;
	stack		DC_Point		*points;
	register	Driver_Color	*contrast_color; {
	register	XData			*xdata = (XData *)fr->h.data;

	xdata->last_face_rendition = 0;		/* we're messing things up */

	/* play tricks to get it to look up the right hard color index */
	switch (fr->h.display_context->physical.color_system) {

		case MAPPED_RGB: {
			stack		int				map_map_0_save,
										map_map_1_save;
			stack		Color_Index		color_index_save,
										contrast_color_index_save,
										tmp;

			map_map_0_save = xdata->colormap_map[0];
			map_map_1_save = xdata->colormap_map[1];
			tmp = xdata->colormap_map[fr->color.map_index] ^
				  xdata->colormap_map[contrast_color->map_index];
			xdata->colormap_map[1] =
				  xdata->colormap_map[fr->contrast_color.map_index] ^
				  xdata->colormap_map[contrast_color->map_index];
			xdata->colormap_map[0] = tmp;
			color_index_save = fr->color.map_index;
			fr->color.map_index = 0;
			contrast_color_index_save = fr->contrast_color.map_index;
			fr->contrast_color.map_index = 1;

			draw_dc_face_common (fr, count, points, false);

			xdata->colormap_map[0] = map_map_0_save;
			xdata->colormap_map[1] = map_map_1_save;
			fr->color.map_index = color_index_save;
			fr->contrast_color.map_index = contrast_color_index_save;
		}		break;

		case DIRECT_RGB: {
			fr->color.direct_rgb.r ^= contrast_color->direct_rgb.r;
			fr->color.direct_rgb.g ^= contrast_color->direct_rgb.g;
			fr->color.direct_rgb.b ^= contrast_color->direct_rgb.b;
			fr->contrast_color.direct_rgb.r ^= contrast_color->direct_rgb.r;
			fr->contrast_color.direct_rgb.g ^= contrast_color->direct_rgb.g;
			fr->contrast_color.direct_rgb.b ^= contrast_color->direct_rgb.b;

			draw_dc_face_common (fr, count, points, false);

			fr->color.direct_rgb.r ^= contrast_color->direct_rgb.r;
			fr->color.direct_rgb.g ^= contrast_color->direct_rgb.g;
			fr->color.direct_rgb.b ^= contrast_color->direct_rgb.b;
			fr->contrast_color.direct_rgb.r ^= contrast_color->direct_rgb.r;
			fr->contrast_color.direct_rgb.g ^= contrast_color->direct_rgb.g;
			fr->contrast_color.direct_rgb.b ^= contrast_color->direct_rgb.b;
		}		break;

		case GRAY_SCALE: {
			fr->color.gray_level ^= contrast_color->gray_level;
			fr->contrast_color.gray_level ^= contrast_color->gray_level;

			draw_dc_face_common (fr, count, points, false);

			fr->color.gray_level ^= contrast_color->gray_level;
			fr->contrast_color.gray_level ^= contrast_color->gray_level;
		}		break;

	}

	xdata->last_face_rendition = 0;		/* we've messed things up */
}


local void draw_dc_pixel_array (mr, where, vcount, hoffset, hcount, rasters)
	stack		Misc_Rendition			*mr;
	stack		DC_Point				*where;
	stack		int						vcount, 
										hoffset, 
										hcount;
	stack		Color_Index				**rasters; {
	register	XData					*xdata = (XData *)mr->h.data;

	CHECK_CLIP (xdata, mr->h.transform_rendition, xdata->pixar_gc,
				xdata->last_pixar_xform_rendition);

	switch (mr->h.display_context->physical.color_system) {

		case MAPPED_RGB: {
			if (xdata->bits_per_color <= 8) {
				HD_Pixar_To_Byte_Rasters (mr, where, vcount, hoffset, hcount, 
											rasters,
											ADDR (draw_mapped_byte_raster));
			}
			else {
				HD_Pixar_To_Word_Rasters (mr, where, vcount, hoffset, hcount, 
											rasters,
											ADDR (draw_mapped_word_raster));
			}
		}		break;

		case DIRECT_RGB: {
			if (xdata->bits_per_color != 8) {
				HI_Warning2 (
				"Internal error - pixel arrays can only be displayed on X11",
				"\"direct color\" machines which are 24 bits deep.");
			}
			else {
				pixar_to_rgb_long_rasters (mr, where, vcount, hoffset, hcount, 
											rasters, !xdata->red_first,
											ADDR (draw_rgb_long_raster));
			}
		}		break;

		case GRAY_SCALE: {
			if (xdata->bits_per_color == 1) {
				HD_Pixar_To_Bit_Rasters (mr, where, vcount, hoffset, hcount, 
											rasters, ADDR (draw_bit_raster));
			}
			else if (xdata->bits_per_color <= 8) {
				pixar_to_gray_byte_rasters (mr, where, vcount, hoffset, hcount, 
											rasters,
											ADDR (draw_gray_byte_raster));
			}
			else {
				pixar_to_gray_word_rasters (mr, where, vcount, hoffset, hcount, 
											rasters,
											ADDR (draw_gray_word_raster));
			}
		}		break;

	}
}


local void draw_dc_marker (kr, where)
	stack		Marker_Rendition		*kr;
	stack		DC_Point				*where; {
	register	Line_Rendition			*lr = kr->stroke_rendition;
	register	XData					*xdata = (XData *)kr->h.data;

	if	(kr->ysize <= 1) HD_Standard_Draw_DC_Marker (kr, where);
	else switch (kr->symbol) {
		case MK_CIRCLE: {
			if (lr->h.incarnation != xdata->last_line_rendition) 
				(*xdata->new_line_rendition) (lr);

			XDrawArc (xdata->display, xdata->window, xdata->line_gc,
					  where->x - kr->xsize, 
					  xdata->yfudge - where->y - kr->ysize, 
					  2*kr->xsize, 2*kr->ysize, 0, 360*64);

		}		break;
		
		case MK_SOLID_CIRCLE: {
			/* the following assumes that the line_gc fill style is Solid! */
			
			if (lr->h.incarnation != xdata->last_line_rendition) 
				(*xdata->new_line_rendition) (lr);

			XFillArc (xdata->display, xdata->window, xdata->line_gc,
					  where->x - kr->xsize, 
					  xdata->yfudge - where->y - kr->ysize, 
					  2*kr->xsize, 2*kr->ysize, 0, 360*64);

		}		break;

		case MK_DOT: {
			/* (the default line-drawing mode doesn't fill the last
			 *	dot, so nothing happens in Standard_Draw_DC_Marker.)
			 */
			if (lr->h.incarnation != xdata->last_line_rendition) 
				(*xdata->new_line_rendition) (lr);

			XDrawPoint (xdata->display, xdata->window, xdata->line_gc,
						where->x, xdata->yfudge - where->y);

		}		break;

		default: {
			HD_Standard_Draw_DC_Marker (kr, where);
		}		break;
	}
}


local void draw_dc_text (xr, where, count, string)
	stack		Text_Rendition			*xr;
	stack		DC_Point				*where;
	stack		int						count; 
	stack		char					*string; {
	register	XData					*xdata = (XData *)xr->h.data;

	if (xr->h.incarnation != xdata->last_text_rendition) {
		(*xdata->new_text_rendition)(xr);
	}

	XDrawString(xdata->display, xdata->window, xdata->text_gc,
				where->x, xdata->yfudge - where->y, string, count);
}


local void draw_overlay_list (dc, item)
	stack		Display_Context			*dc;
	stack		Overlay_Item			*item; {
	register	XData					*xdata = (XData *)dc->data;
	stack		XGCValues				xgcv;

	xgcv.function = GXxor;
	XChangeGC (xdata->display, xdata->face_gc, GCFunction, &xgcv);
	XChangeGC (xdata->display, xdata->line_gc, GCFunction, &xgcv);
	xdata->last_line_rendition = 0;
	xdata->last_face_rendition = 0;
	xdata->xor_in_progress = true;	  

	HD_Standard_Draw_Overlay_List (dc, item);

	xgcv.function = GXcopy;
	XChangeGC (xdata->display, xdata->face_gc, GCFunction, &xgcv);
	XChangeGC (xdata->display, xdata->line_gc, GCFunction, &xgcv);
	xdata->last_line_rendition = 0;
	xdata->last_face_rendition = 0;
	xdata->xor_in_progress = false;	   
}


local boolean request_location (dc, button, x, y)
	stack		Display_Context		*dc;
	stack		int					*button;
	stack		int					*x, *y; {
	register	XData				*xdata = (XData *)dc->data;

	/* SEQUENCE (dc, "request location"); */

	check_events (dc);

	if (xdata->mouse_valid) {
		if (!xdata->mouse_latched) {
			*button = xdata->mouse_buttons;
			*x = xdata->mouse_x;
			*y = xdata->mouse_y;
		}
		else {
			*button = xdata->latched_mouse_buttons;
			*x = xdata->latched_mouse_x;
			*y = xdata->latched_mouse_y;
			xdata->mouse_latched = false;
		}
		xdata->mouse_valid = false;

		SEQUENCE (dc, "returning valid mouse");

		return true;
	}
	else 
		return false;

}


local boolean request_keyboard (dc, button, status)
	stack		Display_Context *dc;
	stack		int				*button,
								*status; {

	/* SEQUENCE (dc, "request keyboard"); */

	check_events (dc);

	return false;
}


local void set_device_color_map (dc, r, g, b, index)
	stack		Display_Context *dc;
	stack		int				r, g, b;
	stack		int				index; {
	register	XData			*xdata = (XData *)dc->data;
	stack		XColor			xcolor;

	xcolor.red = r<<8;
	xcolor.green = g<<8;
	xcolor.blue = b<<8;
	xcolor.flags = DoRed|DoGreen|DoBlue;

	if (xdata->visual->class == StaticColor) {
#		ifdef	NOTDEF
		/**
		 *	This "Free" gives error messages, tho it looks
		 *	reasonable, so don't do it.
		**/

		if (xdata->colormap_map[index] != UNASSIGNED_MAP_MAP)
			XFreeColors (xdata->display, xdata->cmap, 
						 &xdata->colormap_map[index], 1, 0L);
#		endif	/* NOTDEF */

		if (XAllocColor (xdata->display, xdata->cmap, &xcolor)) {
			xdata->colormap_map[index] = xcolor.pixel;
		}
		else {
			HI_Warning ("X server unexpectedly unable to assign a StaticColor index");
			xdata->colormap_map[index] = UNASSIGNED_MAP_MAP;
		}
	}
	else {
		if (xdata->colormap_map[index] == UNASSIGNED_MAP_MAP) {
			stack		unsigned long	dummy_planemask;

			if (!XAllocColorCells (xdata->display, xdata->cmap,
								   False, &dummy_planemask, 0, 
								   &xdata->colormap_map[index], 1)) {

				if (xdata->cmap != xdata->default_cmap) {
					HI_Internal_Error ("X driver - Can't allocate all the colors");
					xdata->colormap_map[index] = 0;
				}
				else {
					/* there were not enough left in default cmap */

					xdata->cmap = XCopyColormapAndFree (xdata->display,
														xdata->default_cmap);

					/* make it take effect */
					XSetWindowColormap (xdata->display, xdata->window,
										xdata->cmap);
					xdata->cmap_installed = xdata->focus_on_us;
					if (xdata->cmap_installed) 
						XInstallColormap (xdata->display, xdata->cmap);

					/**
					 *	Cheat to get it loaded up and make sure
					**/

					xdata->colormap_map[index] = UNASSIGNED_MAP_MAP;
					set_device_color_map (dc, r, g, b, index);
					return;
				}
			}
		}

		/* just store the color */
		xcolor.pixel = xdata->colormap_map[index];

		XStoreColor (xdata->display, xdata->cmap, &xcolor);
	}
}


local void find_all_fonts (dc)
	stack		Display_Context			*dc; {
	stack		XData					*xdata = (XData *)dc->data;
	register	char					**names;
	stack		char					res[5];
	register	float					xres;
	register	float					yres;
	stack		int						actual_count;
	register	int						remaining;

	/**
	 *	Get the resolution info for this display.
	**/

	xres = dc->current.resolution.x;
	yres = dc->current.resolution.y;

	if ((yres/xres < 0.95) || (yres/xres > 1.05)) {
#		ifdef	DEBUG
			fprintf(stderr, "Non-square pixels!!!\n");
#		endif	/* DEBUG */
	}

	if ((yres < 35.0) || (xres < 35.0)) {
		sprintf(res, "-75-");	/* 75 dots-per-inch */
	}
	else {
		sprintf(res, "-100");	/* 100 dots-per-inch */
	}

	/**
	 *	Get the X11 Font Names
	**/

	names = XListFonts(xdata->display, "*", MAX_FONTS, &actual_count);

	/**
	 *	Loop through all the X11 Font Names to record the ones of
	 *	interest (essentially all).
	**/

	for (remaining = actual_count; remaining > 0; remaining--) {
		register		char					*cp;
		stack			char					*field[MAX_DASH+2];
		register		int						last_dash;
		stack			char					fname[64];
		
		/**
		 *	X11 font names have dash-separated fields and look like:
		 *
		 *	"-adobe-times-medium-r-normal--17-120-100-100-p-84-iso8859-1"
		 *
		 *	where:
		 *	adobe =		foundry that digitized and supplied the font
		 *	times =		font family
		 *	medium =	font weight (bold, medium)
		 *	r =			slant (r = regular, i = italic, o = oblique)
		 *	normal =	set width (font's proportionate width)
		 *	add style = sans-serif (if present; only in b&h-lucida)
		 *	17 =		height of the font in pixels
		 *	120 =		size of the font in tenths of a point
		 *	100 =		horizontal resolution in dots-per-inch
		 *	100 =		vertical resolution in dots-per-inch
		 *	p =			spacing type (p = proportional, m = mono, c = charcell)
		 *	84 =		average width in tenths of a pixel
		 *	iso8859-1 = character set (ISO Latin-1)
		**/

		last_dash = 0;
		for (cp = *names; *cp != '\0'; cp++) {
			if (*cp == '-') {
				field[last_dash] = cp;
				if (++last_dash > MAX_DASH) break;
			}
		}
		field[last_dash] = cp;	/* mark the end */

		if (last_dash > MAX_DASH) {

			/**
			 *	"-adobe-times-medium-r-normal--17-120-100-100-p-84-iso8859-1"
			 *	 0	   1	 2		3 4		 56	 7	 8	 9	 1011 12
			 *
			 *	Construct X11 font family names.
			**/

			HI_Copy_String_To_Max(field[0] + 1, field[2] - field[0] - 1, fname);
			if (!HI_Equal_Strings_To_Max(field[2], 7, "-medium")) {
				HI_Append_String_To_Max(field[2], field[3] - field[2], fname);
			}
			if (!HI_Equal_Strings_To_Max(field[3], 2, "-r")) {
				HI_Append_String_To_Max(field[3], field[4] - field[3], fname);
			}
			if (!HI_Equal_Strings_To_Max(field[4], 7, "-normal")) {
				HI_Append_String_To_Max(field[4], field[5] - field[4], fname);
			}
			if (!HI_Equal_Strings_To_Max(field[5], 2, "--")) {
				HI_Append_String_To_Max(field[5], field[6] - field[5], fname);
			}
			if (!HI_Equal_Strings_To_Max(field[9], 4, res)) {
				HI_Append_String_To_Max(field[9], field[10] - field[9], fname);
			}
			if (!HI_Equal_Strings_To_Max(field[12], 10, "-iso8859-1")) {
				HI_Append_String_To_Max(field[12], HI_String_Length(field[12]),
					fname);
			}

			HD_Record_Font(dc, fname, *names, -1, -1);

		}
		else {
			register		char			*cp1;

			/**
			 *	X11 fonts from earlier than Release 3 - old format names.
			**/

			cp1 = &fname[0];
			for (cp = *names; *cp != '\0'; cp++) {

				switch (*cp) {
					case '0':
					case '1':
					case '2':
					case '3':
					case '4':
					case '5':
					case '6':
					case '7':
					case '8':
					case '9':
						break;

					default:
						*cp1++ = *cp;
						break;
				}
			}
			if (*(cp1-1) == '-') {
				*(cp1-1) = '\0';
			}
			else {
				*cp1 = '\0';
			}
			HD_Record_Font(dc, fname, *names, -1, -1);
		}
		names++;
	}
	names -= actual_count;

	XFreeFontNames(names);

	/**
	 *	Now mark the Hoops Generic Font Families.  Use the X11 font family
	 *	names that match the general characteristics we are looking for.
	 *	We are always looking for medium weight, regular slant, normal set
	 *	width, and ISO Latin-1 character set fonts.
	**/

	/**
	 *	Find the Hoops Generic "Sans Serif" font.  We are looking for
	 *	Helvetica in the appropriate resolution for this display.
	**/

	if (!HD_Mark_Font_As_Generic(dc, "adobe-helvetica", GFN_SANS_SERIF)) {

		/**
		 *	Didn't find it; try for another resolution other than what
		 *	is appropriate for this display since we don't seem to have
		 *	the appropriate resolution Helvetica.
		**/

		if (!HD_Mark_Font_As_Generic(dc,
			HI_Equal_Strings_To_Max(res, 3, "100")
			? "adobe-helvetica-medium-r-normal-75"
			: "adobe-helvetica-medium-r-normal-100",
			GFN_SANS_SERIF)) {

			/**
			 *	Still didn't find it; try the old X11 Helvetica font.
			**/

			if (!HD_Mark_Font_As_Generic(dc, "helvetica", GFN_SANS_SERIF)) {

				/**
				 *	Still didn't find it; try the old X10 Helvetica font.
				 *	If we don't find it this time the user gets the Hoops
				 *	built-in Newfield Stroked font for Sans Serif.
				**/

				(void)HD_Mark_Font_As_Generic(dc, "helv", GFN_SANS_SERIF);

			}
		}
	}

	/**
	 *	Find the Hoops Generic "Typewriter" font.  We are looking for
	 *	Courier in the appropriate resolution for this display.
	**/

	if (!HD_Mark_Font_As_Generic(dc, "adobe-courier", GFN_TYPEWRITER)) {

		/**
		 *	Didn't find it; try for another resolution other than what
		 *	is appropriate for this display since we don't seem to have
		 *	the appropriate resolution Courier.
		**/

		if (!HD_Mark_Font_As_Generic(dc,
			HI_Equal_Strings_To_Max(res, 3, "100")
			? "adobe-courier-medium-r-normal-75"
			: "adobe-courier-medium-r-normal-100",
			GFN_TYPEWRITER)) {

			/**
			 *	Still didn't find it; try the old X11 Courier font.
			**/

			if (!HD_Mark_Font_As_Generic(dc, "courier", GFN_TYPEWRITER)) {

				/**
				 *	Still didn't find it; try the old X10 Courier font.
				 *	If we don't find it this time the user gets the Hoops
				 *	built-in Newfield Stroked font for Typewriter.
				**/

				(void)HD_Mark_Font_As_Generic(dc, "cor", GFN_TYPEWRITER);

			}
		}
	}

	/**
	 *	Find the Hoops Generic "Roman" font.  We are looking for Times
	 *	in the appropriate resolution for this display.
	**/

	if (!HD_Mark_Font_As_Generic(dc, "adobe-times", GFN_ROMAN)) {

		/**
		 *	Didn't find it; try for another resolution other than what
		 *	is appropriate for this display since we don't seem to have
		 *	the appropriate resolution Times.
		**/

		if (!HD_Mark_Font_As_Generic(dc,
			HI_Equal_Strings_To_Max(res, 3, "100")
			? "adobe-times-medium-r-normal-75"
			: "adobe-times-medium-r-normal-100",
			GFN_ROMAN)) {

			/**
			 *	Still didn't find it; try the old X11 Times font.
			**/

			if (!HD_Mark_Font_As_Generic(dc, "times", GFN_ROMAN)) {

				/**
				 *	Still didn't find it; try the old X10 Times font.
				 *	If we don't find it this time the user gets the Hoops
				 *	built-in Newfield Stroked font for Roman.
				**/

				(void)HD_Mark_Font_As_Generic(dc, "timrom", GFN_ROMAN);

			}
		}
	}

	/**
	 *	Find the Hoops System Default font.	 We are looking for Fixed
	 *	9x15 in the appropriate resolution for this display.
	**/

	if (!HD_Mark_Font_As_System_Default(dc, "9x15", -1)) {

		/**
		 *	Didn't find it; try another name for a fixed font.
		 *	If we don't find it this time the user gets the Hoops
		 *	built-in Newfield Stroked font for System Default.
		**/

		(void)HD_Mark_Font_As_Generic(dc, "fixed" -1);

	}

}


local long load_font (dc, name, Aheight, vspace, widths)
	stack		Display_Context			*dc; 
	stack		char					*name; 
	stack		int						*Aheight,
										*vspace;
	stack		Character_Width			*widths; {
	stack		XData					*xdata = (XData *)dc->data;

	if ((widths == null) && (*Aheight != -1) && (*vspace != -1)) {
		return ((long)XLoadFont(xdata->display, name));
	}
	else {
		stack			long			id;
		register		XFontStruct		*xfs;

		if ((xfs = XLoadQueryFont(xdata->display, name)) == null) {
			return (0);
		}

		if (*Aheight == -1) {

			/**
			 *	Refigure Aheight as the height of a letter A.
			**/
			
			*Aheight = 0;
			if ((xfs->per_char != null) && (xfs->min_char_or_byte2 <= 'A') && 
				('A' <= xfs->max_char_or_byte2)) {

				*Aheight = xfs->per_char['A' - xfs->min_char_or_byte2].ascent;
			}

			if (*Aheight <= 0) {
			
				/**
				 *	No per-character or no 'A'?
				**/

				*Aheight = xfs->max_bounds.ascent; 

				if (*Aheight <= 0) {

					/**
					 *	No ascent? very funky.
					**/

					*Aheight = xfs->max_bounds.descent;

					if (*Aheight <= 0) {
					
						/**
						 *	No descent? we'd better give up.
						**/

						*Aheight = MAX_SHORT;
					}
				}
			}
		}
		
		if (*vspace == -1) {
			register	char					*cp;
			register	int						dash;

			/**
			 *	X11 font names have dash-separated fields and look like:
			 *
			 *	"-adobe-times-medium-r-normal--17-120-100-100-p-84-iso8859-1"
			 *	 0	   1	 2		3 4		 56	 7
			 *
			 *	where:
			 *	...
			 *	17 =	height of the font in pixels
			 *	...
			**/

			*vspace = 0;
			dash = 0;
			for (cp = name; *cp != '\0'; cp++) {
				if ((*cp == '-') && (dash++ > 5)) {
					cp++;
					while ('0' <= *cp && *cp <= '9') {
						*vspace = *vspace * 10 + ((int)*cp++ - (int)'0');
					}
					break;
				}
			}
			
			if (*vspace < *Aheight) {
				*vspace = xfs->ascent + xfs->descent;
				if (*vspace < *Aheight) {
					*vspace = xfs->max_bounds.ascent + xfs->max_bounds.descent;
					if (*vspace < *Aheight) {
						*vspace = *Aheight;
					}
				}
			}
		}
		
		if (widths != null) {
			register	int				count;
			
			/**
			 *	need the widths
			**/

			if (xfs->max_char_or_byte2 > MAX_FONT_CHAR) {
				count = MAX_FONT_CHAR - xfs->min_char_or_byte2 + 1;
			}
			else {
				count = xfs->max_char_or_byte2 - xfs->min_char_or_byte2 + 1;
			}

			widths += xfs->min_char_or_byte2;
			if (xfs->per_char != null) {
				register		XCharStruct		*xcs;

				for (xcs = xfs->per_char; count > 0; xcs++, count--) {
					*widths++ = xcs->width;
				}
			}
			else {
				register		Character_Width			fwidth;

				fwidth = xfs->max_bounds.rbearing - xfs->max_bounds.lbearing;
				for ( ; count > 0; count--) {
					*widths++ = fwidth;
				}
			}
		}

		id = (long)xfs->fid;

		/**
		 *	The documentation is very confused on how to free the
		 *	fontstruct without unloading the font, if the fontstruct
		 *	is derived from LoadQuery.	We do it the hard way,
		 *	which *may* also be the wrong way.
		**/

		if (xfs->properties != null) {
			XFree(xfs->properties);
		}
		if (xfs->per_char != null) {
			XFree(xfs->per_char);
		}
		XFree(xfs);

		return (id);
	}
}


local void unload_font (dc, identifier)
	stack		Display_Context			*dc;
	stack		long					identifier; {
	stack		XData					*xdata = (XData *)dc->data;

	XUnloadFont(xdata->display, (Font)identifier);
}


/**
 *	Local Utility Routines: includes rendition setting routines
**/


local void draw_dc_face_common (fr, icount, points, edged)
	stack		Face_Rendition	*fr;
	stack		int				icount;
	register	DC_Point		*points;
	stack		boolean			edged; {
	register	XPoint			*vertex;
	register	int				count;
	register	XData			*xdata = (XData *)fr->h.data;
	stack		XPoint			vbuf[MAX_POLYGON_POINTS];

	/* test renditions then draw */
	if (fr->h.incarnation != xdata->last_face_rendition)
		(*xdata->new_face_rendition)(fr);

	count = icount;
	vertex = &vbuf[0];
	do {
		vertex->x = points->x;
		vertex->y = xdata->yfudge - points->y;
		++vertex;
		++points;
	}
	until (--count == 0);

	XFillPolygon (xdata->display, xdata->window,
				  xdata->face_gc, &vbuf[0], icount,
				  Complex, CoordModeOrigin);

	if (edged) {
		if (fr->edge_rendition->h.incarnation != xdata->last_line_rendition)
			(*xdata->new_line_rendition)(fr->edge_rendition);

		XDrawLines (xdata->display, xdata->window, xdata->line_gc,
					&vbuf[0], icount, CoordModeOrigin);
	}
}


local void set_resizing_hints (dc)
	stack		Display_Context		*dc; {
	register	XData				*xdata = (XData *)dc->data;
	stack		XSizeHints			hints;
	
	if (!dc->options.subscreen_resizing) {
		hints.min_width = xdata->window_width;
		hints.min_height = xdata->window_height;
		hints.max_width = xdata->window_width;
		hints.max_height = xdata->window_height;
		hints.min_aspect.x = hints.min_width;
		hints.min_aspect.y = hints.min_height;
		hints.max_aspect.x = hints.min_width;
		hints.max_aspect.y = hints.min_height;
	}
	else if (!dc->options.subscreen_stretching) {
		hints.min_width = 1;
		hints.min_height = 1;
		hints.max_width = WidthOfScreen (xdata->screen);
		hints.max_height = HeightOfScreen (xdata->screen);
		hints.min_aspect.x = MAX (1, xdata->window_width - 1);
		hints.min_aspect.y = xdata->window_height + 1;
		hints.max_aspect.x = xdata->window_width + 1;
		hints.max_aspect.y = MAX (1, xdata->window_height - 1);
	}
	else {
		hints.min_width = 1;
		hints.min_height = 1;
		hints.max_width = WidthOfScreen (xdata->screen);
		hints.max_height = HeightOfScreen (xdata->screen);
		hints.min_aspect.x = 1;
		hints.min_aspect.y = hints.max_height;
		hints.max_aspect.x = hints.max_width;
		hints.max_aspect.y = 1;
	}

	hints.flags = PMinSize|PMaxSize|PAspect;
	XSetNormalHints (xdata->display, xdata->window, &hints);

	xdata->resizing_was_on = dc->options.subscreen_resizing;
	xdata->stretching_was_on = dc->options.subscreen_stretching;
}


local void new_clip (xdata, tr, gc, incarnp)
	stack		XData					*xdata;
	stack		Transform_Rendition		*tr;
	stack		GC						gc; 
	stack		Incarnation				*incarnp; {
	stack		XRectangle				rects[1];

	rects[0].x = tr->hard_clip.left;
	rects[0].y = xdata->yfudge - tr->hard_clip.top;
	rects[0].width = tr->hard_clip.right - tr->hard_clip.left + 1;
	rects[0].height = tr->hard_clip.top - tr->hard_clip.bottom + 1;
	
	/* print out "DRAWING" at least once per update w/ draw_dc's in it */
	if (*incarnp == (Incarnation)0 && 
		BIT (tr->h.display_context->options.debug, DEBUG_SEQUENCING))
		fprintf (stderr, "X Sequence: DRAWING, clip is (%d x %d) @ (%d, %d)\n",
				 rects[0].width, rects[0].height, rects[0].x, rects[0].y);

	XSetClipRectangles (xdata->display, gc, 0, 0, ADDR(rects), 1, YXBanded);

	*incarnp = tr->h.incarnation;
}


#if 1	
	local XData *find_xdata (display)
		stack			XDisplay		*display; {
		return null;
	}
#else	/* depends on obfuscated words, sigh. */

#	include		"database.h"
#	include		"please.h"

	local XData *find_xdata (display)
		stack			XDisplay		*display; {
		register		Driver			*driver;
		stack	XData			*xdata;

		if ((driver = OUR (driver_list)) != null) do {
			if (driver->action == ADDR (HD_X11_Driver) ||
				driver->secondary_action == ADDR (HD_X11_Driver)) {

				if (!BIT (driver->dflags, D_DEAD) && driver->driver_data != null) {
					xdata = ((Display_Context *)driver->driver_data)->data;

					if (xdata != null && xdata->display == display)
						return xdata;
				}
			}
		}
		until ((driver = driver->driver_list) == null);
		return null;
	}
#endif	/* 1 */


local int error_handler (display, err)
	stack		XDisplay		*display;
	stack		XErrorEvent		*err; {
	stack		char			error_string[MAX_ERRMSG];
	stack		XData			*xdata = find_xdata (display);
	
	/* note: should be "void error_handler" except "int" is what Xlib says */

	XGetErrorText (display, (int)err->error_code,
				   error_string, sizeof(error_string));

	if (xdata == null)
		HI_Error2 ("Unexpected X-window system error -",
				   error_string);
	else 
		HI_Error2 (Sprintf_P(null,"Unexpected X-window system error on '%p' -", 
							 xdata->dc->actor_segment),
				   error_string);
}


local int ioerror_handler (display)
	stack		XDisplay		*display; {
	stack		XData			*xdata = find_xdata (display);
	local		const char		sorry[] ="(sorry, the system gives no details)";

	if (xdata == null)
		HI_Error2 ("Unexpected X-window \"fatal IO error\"", ADDR (sorry));
	else 
		HI_Error2 (Sprintf_P (null,
							 "Unexpected X-window \"fatal IO error\" on '%p' -",
							  xdata->dc->actor_segment), ADDR (sorry));
}


local int be_quiet_handler (display, err)
	stack	XDisplay	*display;
	stack	XErrorEvent *err; {
}


local void setdash (xdata, pattern)
	stack		XData			*xdata;
	stack		int				pattern; {

	switch (pattern) {
		case LP_DASHDOT: {
			local const unsigned char	dashdot[] = {8, 8, 2, 6};
			XSetDashes (xdata->display, xdata->line_gc, 0, &dashdot[0], 4);
		}		break;

		case LP_DASHED: {
			local const unsigned char	dashed[] = {8, 8};
			XSetDashes (xdata->display, xdata->line_gc, 0, &dashed[0], 2);
		}		break;

		case LP_DOTTED: {
			local const unsigned char	dotted[] = {2, 6};
			XSetDashes (xdata->display, xdata->line_gc, 0, &dotted[0], 2);
		}		break;
	}
}


/**
 *	Pseudo Color rendition setting routines
**/


local void new_mapped_line_rendition (lr)
	stack		Line_Rendition		*lr; {
	register	XData				*xdata = (XData *)lr->h.data;
	stack		XGCValues			xgcv;

	xgcv.foreground = xdata->colormap_map[lr->color.map_index];

	if (lr->weight <= 1) {
		xgcv.line_width = 0;
	}
	else {
		xgcv.line_width = lr->weight;
	}

	if (lr->pattern == LP_SOLID) {
		xgcv.line_style = LineSolid;
	}
	else {
		setdash (xdata, lr->pattern);
		xgcv.line_style = LineOnOffDash;
	}

	XChangeGC (xdata->display, xdata->line_gc,
		GCForeground | GCLineWidth | GCLineStyle, &xgcv);

	CHECK_CLIP (xdata, lr->h.transform_rendition, xdata->line_gc,
				xdata->last_line_xform_rendition);

	xdata->last_line_rendition = lr->h.incarnation;
}


local void new_mapped_text_rendition (xr)
	stack		Text_Rendition		*xr; {
	register	XData				*xdata = (XData *)xr->h.data;
	stack		XGCValues			xgcv;

	xgcv.foreground = xdata->colormap_map[xr->color.map_index];
	xgcv.font = xr->font->identifier;

	XChangeGC (xdata->display, xdata->text_gc, GCForeground | GCFont, &xgcv);

	CHECK_CLIP (xdata, xr->h.transform_rendition, xdata->text_gc,
				xdata->last_text_xform_rendition);

	xdata->last_text_rendition = xr->h.incarnation;
}


local void new_mapped_face_rendition (fr)
	stack		Face_Rendition		*fr; {
	register	XData				*xdata = (XData *)fr->h.data;
	stack		XGCValues			xgcv;
	stack		unsigned long		valuemask;

	if (fr->pattern != FP_SOLID) {
		xgcv.foreground = xdata->colormap_map[fr->contrast_color.map_index];
		xgcv.background = xdata->colormap_map[fr->color.map_index];
		xgcv.fill_style = FillOpaqueStippled;
		xgcv.stipple = xdata->stipples[fr->pattern];
		valuemask = GCForeground | GCBackground | GCFillStyle | GCStipple;
	}
	else {
		xgcv.foreground = xdata->colormap_map[fr->color.map_index];
		xgcv.fill_style = FillSolid;
		valuemask = GCForeground | GCFillStyle;
	}

	XChangeGC (xdata->display, xdata->face_gc, valuemask, &xgcv);

	CHECK_CLIP (xdata, fr->h.transform_rendition, xdata->face_gc,
				xdata->last_face_xform_rendition);

	xdata->last_face_rendition = fr->h.incarnation;
}


/**
 *	Direct Color rendition setting routines
**/


local void new_direct_line_rendition (lr)
	stack		Line_Rendition		*lr; {
	register	XData				*xdata = (XData *)lr->h.data;
	stack		XGCValues			xgcv;

	xgcv.foreground = RGB_TO_LONG (xdata, lr->color.direct_rgb);

	if (lr->weight <= 1) {
		xgcv.line_width = 0;
	}
	else {
		xgcv.line_width = lr->weight;
	}

	if (lr->pattern == LP_SOLID) {
		xgcv.line_style = LineSolid;
	}
	else {
		setdash (xdata, lr->pattern);
		xgcv.line_style = LineOnOffDash;
	}

	XChangeGC (xdata->display, xdata->line_gc,
		GCForeground | GCLineWidth | GCLineStyle, &xgcv);

	CHECK_CLIP (xdata, lr->h.transform_rendition, xdata->line_gc,
				xdata->last_line_xform_rendition);

	xdata->last_line_rendition = lr->h.incarnation;
}


local void new_direct_text_rendition (xr)
	stack		Text_Rendition		*xr; {
	register	XData				*xdata = (XData *)xr->h.data;
	stack		XGCValues			xgcv;

	xgcv.foreground = RGB_TO_LONG (xdata, xr->color.direct_rgb);
	xgcv.font = xr->font->identifier;

	XChangeGC (xdata->display, xdata->text_gc, GCForeground | GCFont, &xgcv);

	CHECK_CLIP (xdata, xr->h.transform_rendition, xdata->text_gc,
				xdata->last_text_xform_rendition);

	xdata->last_text_rendition = xr->h.incarnation;
}


local void new_direct_face_rendition (fr)
	stack		Face_Rendition		*fr; {
	register	XData				*xdata = (XData *)fr->h.data;
	stack		XGCValues			xgcv;
	stack		unsigned long		valuemask;

	if (fr->pattern != FP_SOLID) {
		xgcv.foreground = RGB_TO_LONG (xdata, fr->contrast_color.direct_rgb);
		xgcv.background = RGB_TO_LONG (xdata, fr->color.direct_rgb);
		xgcv.fill_style = FillOpaqueStippled;
		xgcv.stipple = xdata->stipples[fr->pattern];
		valuemask = GCForeground | GCBackground | GCFillStyle | GCStipple;
	}
	else {
		xgcv.foreground = RGB_TO_LONG (xdata, fr->color.direct_rgb);
		xgcv.fill_style = FillSolid;
		valuemask = GCForeground | GCFillStyle;
	}

	XChangeGC (xdata->display, xdata->face_gc, valuemask, &xgcv);

	CHECK_CLIP (xdata, fr->h.transform_rendition, xdata->face_gc,
				xdata->last_face_xform_rendition);

	xdata->last_face_rendition = fr->h.incarnation;
}


/**
 *	Grayscale rendition setting routines
**/


local void new_bandw_line_rendition (lr)
	stack		Line_Rendition		*lr; {
	register	XData				*xdata = (XData *)lr->h.data;
	stack		XGCValues			xgcv;

	if (xdata->xor_in_progress) {
		xgcv.foreground = 1;
	}
	else if (lr->color.gray_level<DITHER_BIT_RESOLUTION/2) {
		xgcv.foreground = BlackPixelOfScreen (xdata->screen);
	}
	else {
		xgcv.foreground = WhitePixelOfScreen (xdata->screen);
	}

	if (lr->weight <= 1) {
		xgcv.line_width = 0;
	}
	else {
		xgcv.line_width = lr->weight;
	}


	if (lr->pattern == LP_SOLID) {
		xgcv.line_style = LineSolid;
	}
	else {
		setdash (xdata, lr->pattern);
		xgcv.line_style = LineOnOffDash;
	}

	XChangeGC (xdata->display, xdata->line_gc,
		GCForeground | GCLineWidth | GCLineStyle, &xgcv);

	CHECK_CLIP (xdata, lr->h.transform_rendition, xdata->line_gc,
				xdata->last_line_xform_rendition);

	xdata->last_line_rendition = lr->h.incarnation;
}


local void new_bandw_text_rendition (xr)
	stack		Text_Rendition		*xr; {
	register	XData				*xdata = (XData *)xr->h.data;
	stack		XGCValues			xgcv;

	if (xr->color.gray_level < DITHER_BIT_RESOLUTION/2) {
		xgcv.foreground = BlackPixelOfScreen (xdata->screen);
	}
	else {
		xgcv.foreground = WhitePixelOfScreen (xdata->screen);
	}

	xgcv.font = xr->font->identifier;

	XChangeGC (xdata->display, xdata->text_gc, GCForeground | GCFont, &xgcv);

	CHECK_CLIP (xdata, xr->h.transform_rendition, xdata->text_gc,
				xdata->last_text_xform_rendition);

	xdata->last_text_rendition = xr->h.incarnation;
}


local void new_bandw_face_rendition (fr)
	stack		Face_Rendition		*fr; {
	register	XData				*xdata = (XData *)fr->h.data;
	stack		XGCValues			xgcv;
	stack		unsigned long		valuemask;

	if (fr->color.gray_level != 0 && 
		fr->color.gray_level != DITHER_BIT_RESOLUTION - 1) {

		/* shade of gray - fake it. THIS LOSES PATTERNED GRAYS! */
		if (fr->color.gray_level < DITHER_BIT_RESOLUTION/2) {
			xgcv.stipple =
				xdata->stipples[FACE_BIT_PATTERNS+fr->color.gray_level];
			xgcv.background = BlackPixelOfScreen (xdata->screen);
			xgcv.foreground = WhitePixelOfScreen (xdata->screen);
		}
		else {
			xgcv.background = WhitePixelOfScreen (xdata->screen);
			xgcv.foreground = BlackPixelOfScreen (xdata->screen);
			xgcv.stipple = xdata->stipples [FACE_BIT_PATTERNS +
						DITHER_BIT_RESOLUTION - 1 - fr->color.gray_level];
		}

		xgcv.fill_style = FillOpaqueStippled;

		valuemask = GCForeground | GCBackground | GCFillStyle | GCStipple;
	}
	else if (fr->pattern == FP_SOLID) {
		if (xdata->xor_in_progress) {
			xgcv.foreground = 1;
		}
		else if (fr->color.gray_level == 0) {
			xgcv.foreground = BlackPixelOfScreen (xdata->screen);
		}
		else {
			xgcv.foreground = WhitePixelOfScreen (xdata->screen);
		}
		
		xgcv.fill_style = FillSolid;

		valuemask = GCForeground | GCFillStyle;
	}
	else {		/* patterned black-and-white */
		if (fr->color.gray_level == 0) {
			xgcv.foreground = WhitePixelOfScreen (xdata->screen);
			xgcv.background = BlackPixelOfScreen (xdata->screen);
		}
		else {
			xgcv.foreground = BlackPixelOfScreen (xdata->screen);
			xgcv.background = WhitePixelOfScreen (xdata->screen);
		}
		
		xgcv.fill_style = FillOpaqueStippled;
		xgcv.stipple = xdata->stipples[fr->pattern];

		valuemask = GCForeground | GCBackground | GCFillStyle | GCStipple;
	}

	XChangeGC (xdata->display, xdata->face_gc, valuemask, &xgcv);

	CHECK_CLIP (xdata, fr->h.transform_rendition, xdata->face_gc,
				xdata->last_face_xform_rendition);

	xdata->last_face_rendition = fr->h.incarnation;
}


local void new_gray_line_rendition (lr)
	stack		Line_Rendition		*lr; {
	register	XData				*xdata = (XData *)lr->h.data;
	stack		XGCValues			xgcv;

	xgcv.foreground = lr->color.gray_level;

	if (lr->weight <= 1) {
		xgcv.line_width = 0;
	}
	else {
		xgcv.line_width = lr->weight;
	}

	if (lr->pattern == LP_SOLID) {
		xgcv.line_style = LineSolid;
	}
	else {
		setdash (xdata, lr->pattern);
		xgcv.line_style = LineOnOffDash;
	}

	XChangeGC (xdata->display, xdata->line_gc, 
			   GCForeground | GCLineWidth | GCLineStyle, &xgcv);

	CHECK_CLIP (xdata, lr->h.transform_rendition, xdata->line_gc,
				xdata->last_line_xform_rendition);

	xdata->last_line_rendition = lr->h.incarnation;
}


local void new_gray_text_rendition (xr)
	stack		Text_Rendition		*xr; {
	register	XData				*xdata = (XData *)xr->h.data;
	stack		XGCValues			xgcv;

	xgcv.foreground = xr->color.gray_level;
	xgcv.font = xr->font->identifier;

	XChangeGC (xdata->display, xdata->text_gc, GCForeground | GCFont, &xgcv);

	CHECK_CLIP (xdata, xr->h.transform_rendition, xdata->text_gc,
				xdata->last_text_xform_rendition);

	xdata->last_text_rendition = xr->h.incarnation;
}


local void new_gray_face_rendition (fr)
	stack		Face_Rendition		*fr; {
	register	XData				*xdata = (XData *)fr->h.data;
	stack		XGCValues			xgcv;
	stack		unsigned long		valuemask;

	if (fr->pattern != FP_SOLID) {
		xgcv.foreground = fr->contrast_color.gray_level;
		xgcv.background = fr->color.gray_level;
		xgcv.fill_style = FillOpaqueStippled;
		xgcv.stipple = xdata->stipples[fr->pattern];
		valuemask = GCForeground | GCBackground | GCFillStyle | GCStipple;
	}
	else {
		xgcv.foreground = fr->color.gray_level;
		xgcv.fill_style = FillSolid;
		valuemask = GCForeground | GCFillStyle;
	}

	XChangeGC (xdata->display, xdata->face_gc, valuemask, &xgcv);

	CHECK_CLIP (xdata, fr->h.transform_rendition, xdata->face_gc,
				xdata->last_face_xform_rendition);

	xdata->last_face_rendition = fr->h.incarnation;
}


/**
 *	End of rendition setting routines
**/


local void draw_bit_raster (mr, where, icount, raster)
	stack		Misc_Rendition	*mr;
	stack		DC_Point		*where;
	stack		int				icount;
	register	unsigned char	*raster; {
	register	unsigned char	*end;
	register	XData			*xdata = (XData *)mr->h.data;

	if (xdata->pixar_image == null) 
		xdata->pixar_image = XCreateImage (xdata->display, xdata->visual, 1,
										   XYBitmap, 0, null, 
										   WidthOfScreen (xdata->screen), 
										   1, 8, 0);

	xdata->pixar_image->data = (char *)raster;

	if (WhitePixelOfScreen (xdata->screen) != 0) {
		end = raster + (icount + 7)/8;
		do *raster = ~*raster;
		until (++raster == end);
	}

	XPutImage (xdata->display, xdata->window,
			   xdata->pixar_gc, xdata->pixar_image, 0, 0,
			   where->x, xdata->yfudge - where->y, icount, 1);
}


local void draw_gray_byte_raster (mr, where, icount, raster)
	stack		Misc_Rendition	*mr;
	stack		DC_Point		*where;
	stack		int				icount;
	register	unsigned char	*raster; {
	register	XData			*xdata = (XData *)mr->h.data;

	if (xdata->pixar_image == null) 
		xdata->pixar_image = XCreateImage (xdata->display, xdata->visual, 8,
										   ZPixmap, 0, null, 
										   WidthOfScreen (xdata->screen), 
										   1, 8, 0);

	xdata->pixar_image->data = (char *)raster;

	XPutImage (xdata->display, xdata->window,
			   xdata->pixar_gc, xdata->pixar_image, 0, 0,
			   where->x, xdata->yfudge - where->y, icount, 1);
}


local void draw_gray_word_raster (mr, where, icount, raster)
	stack		Misc_Rendition	*mr;
	stack		DC_Point		*where;
	stack		int				icount;
	register	unsigned short	*raster; {
	register	XData			*xdata = (XData *)mr->h.data;

	if (xdata->pixar_image == null) 
		xdata->pixar_image = XCreateImage (xdata->display, xdata->visual, 16,
										   ZPixmap, 0, null, 
										   WidthOfScreen (xdata->screen), 
										   1, 16, 0);

	xdata->pixar_image->data = (char *)raster;

	XPutImage (xdata->display, xdata->window,
			   xdata->pixar_gc, xdata->pixar_image, 0, 0,
			   where->x, xdata->yfudge - where->y, icount, 1);
}


local void draw_rgb_long_raster (mr, where, icount, raster)
	stack		Misc_Rendition	*mr;
	stack		DC_Point		*where;
	stack		int				icount;
	register	unsigned short	*raster; {
	register	XData			*xdata = (XData *)mr->h.data;

	if (xdata->pixar_image == null) 
		xdata->pixar_image = XCreateImage (xdata->display, xdata->visual, 24,
										   ZPixmap, 0, null, 
										   WidthOfScreen (xdata->screen), 
										   1, 32, 0);

	xdata->pixar_image->data = (char *)raster;

	XPutImage (xdata->display, xdata->window,
			   xdata->pixar_gc, xdata->pixar_image, 0, 0,
			   where->x, xdata->yfudge - where->y, icount, 1);
}


local void draw_mapped_byte_raster (mr, where, icount, raster)
	stack		Misc_Rendition	*mr;
	stack		DC_Point		*where;
	stack		int				icount;
	register	unsigned char	*raster; {
	register	unsigned long	*mapper;
	register	int				count = icount;
	register	XData			*xdata = (XData *)mr->h.data;

	if (xdata->pixar_image == null) 
		xdata->pixar_image = XCreateImage (xdata->display, xdata->visual, 8,
										   ZPixmap, 0, null, 
										   WidthOfScreen (xdata->screen), 
										   1, 8, 0);

	xdata->pixar_image->data = (char *)raster;

	mapper = xdata->colormap_map;
	until (--count < 0) {
		*raster = (unsigned char)mapper[*raster];
		++raster;
	}

	XPutImage (xdata->display, xdata->window,
			   xdata->pixar_gc, xdata->pixar_image, 0, 0,
			   where->x, xdata->yfudge - where->y, icount, 1);
}


local void draw_mapped_word_raster (mr, where, icount, raster)
	stack		Misc_Rendition	*mr;
	stack		DC_Point		*where;
	stack		int				icount;
	register	unsigned short	*raster; {
	register	unsigned long	*mapper;
	register	int				count = icount;
	register	XData			*xdata = (XData *)mr->h.data;

	if (xdata->pixar_image == null) 
		xdata->pixar_image = XCreateImage (xdata->display, xdata->visual, 16,
										   ZPixmap, 0, null, 
										   WidthOfScreen (xdata->screen), 
										   1, 16, 0);

	xdata->pixar_image->data = (char *)raster;

	mapper = xdata->colormap_map;
	until (--count < 0) {
		*raster = (unsigned short)mapper[*raster];
		++raster;
	}

	XPutImage (xdata->display, xdata->window,
			   xdata->pixar_gc, xdata->pixar_image, 0, 0,
			   where->x, xdata->yfudge - where->y, icount, 1);
}


local void pixar_to_gray_byte_rasters (mr, iwhere,
									   vcount, hoffset, hcount,
									   pixar_rasters, action)
	stack		Misc_Rendition	*mr;
	stack		DC_Point		*iwhere;
	stack		int				vcount, hoffset, hcount;
	stack		Color_Index		**pixar_rasters; 
	stack		void			(*action)(); {
	register	Driver_Color	*map;
	extern		boolean			HD_Exit_Update();
	stack		unsigned char	*raster;
	stack		int				rsize;
	stack		DC_Point		where;
	
	where.x = iwhere->x;
	where.y = iwhere->y;
	where.z = iwhere->z;
	
	map = mr->color_map_rendition->driver_colors;

	rsize = hcount * sizeof(unsigned char);
	VALLOC (raster, rsize, unsigned char);

	do {
		register		unsigned char	*out = raster;
		register		Color_Index		*in = *pixar_rasters++ + hoffset;
		register		int				loops = hcount;

		while ((loops -= 8) >= 0) {
			out[0] = (unsigned char)map[in[0]].gray_level; 
			out[1] = (unsigned char)map[in[1]].gray_level;
			out[2] = (unsigned char)map[in[2]].gray_level;		
			out[3] = (unsigned char)map[in[3]].gray_level;
			out[4] = (unsigned char)map[in[4]].gray_level; 
			out[5] = (unsigned char)map[in[5]].gray_level;
			out[6] = (unsigned char)map[in[6]].gray_level; 
			out[7] = (unsigned char)map[in[7]].gray_level;
			out += 8;
			in += 8;
		}

		if ((loops += 8) > 0) {
			do *out++ = (unsigned char)map[*in++].gray_level;
			until (--loops == 0);
		}

		(*action) (mr, &where, hcount, raster);
		--where.y;
	}
	until (--vcount == 0 ||
		   (OUR (timer_expired) && HD_Exit_Update (mr->h.display_context)));

	VFREE (raster, rsize, unsigned char);
}


local void pixar_to_gray_word_rasters (mr, iwhere,
									   vcount, hoffset, hcount,
									   pixar_rasters, action)
	stack		Misc_Rendition	*mr;
	stack		DC_Point		*iwhere;
	stack		int				vcount, hoffset, hcount;
	stack		Color_Index		**pixar_rasters; 
	stack		void			(*action)(); {
	register	Driver_Color	*map;
	extern		boolean			HD_Exit_Update();
	stack		unsigned short	*raster;
	stack		int				rsize;
	stack		DC_Point		where;
	
	where.x = iwhere->x;
	where.y = iwhere->y;
	where.z = iwhere->z;
	
	map = mr->color_map_rendition->driver_colors;

	rsize = hcount * sizeof(unsigned short);
	VALLOC (raster, rsize, unsigned short);

	do {
		register		unsigned short	*out = raster;
		register		Color_Index		*in = *pixar_rasters++ + hoffset;
		register		int				loops = hcount;

		while ((loops -= 8) >= 0) {
			out[0] = (unsigned short)map[in[0]].gray_level; 
			out[1] = (unsigned short)map[in[1]].gray_level;
			out[2] = (unsigned short)map[in[2]].gray_level;		
			out[3] = (unsigned short)map[in[3]].gray_level;
			out[4] = (unsigned short)map[in[4]].gray_level; 
			out[5] = (unsigned short)map[in[5]].gray_level;
			out[6] = (unsigned short)map[in[6]].gray_level; 
			out[7] = (unsigned short)map[in[7]].gray_level;
			out += 8;
			in += 8;
		}

		if ((loops += 8) > 0) {
			do *out++ = (unsigned short)map[*in++].gray_level;
			until (--loops == 0);
		}

		(*action) (mr, &where, hcount, raster);
		--where.y;
	}
	until (--vcount == 0 ||
		   (OUR (timer_expired) && HD_Exit_Update (mr->h.display_context)));

	VFREE (raster, rsize, unsigned short);
}


local void pixar_to_rgb_long_rasters (mr, iwhere,
									  vcount, hoffset, hcount,
									  pixar_rasters, reverse, action)
	stack		Misc_Rendition	*mr;
	stack		DC_Point		*iwhere;
	stack		int				vcount, hoffset, hcount;
	stack		Color_Index		**pixar_rasters; 
	stack		boolean			reverse;
	stack		void			(*action)(); {
	register	Driver_Color	*dcolor;
	register	Driver_Color	*map;
	extern		boolean			HD_Exit_Update();
	stack		unsigned long	*raster;
	stack		int				rsize;
	stack		DC_Point		where;
	
	where.x = iwhere->x;
	where.y = iwhere->y;
	where.z = iwhere->z;
	
	map = mr->color_map_rendition->driver_colors;

	rsize = hcount * sizeof(unsigned long);
	VALLOC (raster, rsize, unsigned long);

	do {
		register		unsigned long	*out = raster;
		register		Color_Index		*in = *pixar_rasters++ + hoffset;
		register		int				loops = hcount;

		if (!reverse) {
			do {
				dcolor = map + *in++;
				*out++ = (unsigned long)dcolor->direct_rgb.r |
						 (((unsigned long)dcolor->direct_rgb.g |
						   ((unsigned long)dcolor->direct_rgb.b << 8)) << 8);
			}				
			until (--loops == 0);
		}
		else {
			do {
				dcolor = map + *in++;
				*out++ = (unsigned long)dcolor->direct_rgb.b |
						 (((unsigned long)dcolor->direct_rgb.g |
						   ((unsigned long)dcolor->direct_rgb.r << 8)) << 8);
			}				
			until (--loops == 0);
		}

		(*action) (mr, &where, hcount, raster);
		--where.y;
	}
	until (--vcount == 0 ||
		   (OUR (timer_expired) && HD_Exit_Update (mr->h.display_context)));

	VFREE (raster, rsize, unsigned long);
}


local void enable_parent_events (xdata, mask)
	register	XData			*xdata; 
	stack		Mask			mask; {
	stack		XWindow			parent,
								root,
								*children;
	stack		unsigned int	nchildren;

#	ifdef SUN
		/* don't try - this will leave our known position wrong! */
#	else	/* SUN */

	/* first record the immediate parent of our window */
	XQueryTree (xdata->display, xdata->window, &xdata->root_window,
				&xdata->parent_window, &children, &nchildren);
	XFree (children);

	/* if anyone has interposed themselves between us and the
	 * root window, arrange to be notified on window
	 * position changes for them too.
	 */
	parent = xdata->window;
	if (parent != (XWindow)0) forever {
		XQueryTree (xdata->display, parent, &root, &parent,
					&children, &nchildren);
		XFree (children);
		if (parent == root) break;
		XSelectInput (xdata->display, parent, mask);
	}
#	endif	/* SUN */
}


local void consume_key (dc, xevent)
	stack		Display_Context *dc;
	register	XKeyEvent		*xevent; {
	stack		int				key;
	stack		KeySym			keysym;
	stack		char			string[10];
	stack		int				hoops_key_state;
	stack		XData			*xdata = (XData *)dc->data;

	XLookupString(xevent, string, sizeof(string), &keysym, null);
#ifdef	NOTDEF
	if (XLookupString (xevent, string, sizeof(string), &keysym, 
					   &xdata->compose_status) != 1) 
		return;
#endif	/* NOTDEF */

	if (keysym < 256) {

		/* X11 default is ISO Latin-1, like us */
		key = string[0];

		/* Check to see if this is the first key of a compose sequence. */
		if (xdata->first_key < 0) {
			xdata->first_key = key;
			return;
		}
	}
	else {
		switch (keysym) {
			case XK_F1:				key = FIRST_FUNCTION_KEY + 1;	break;
			case XK_F2:				key = FIRST_FUNCTION_KEY + 2;	break;
			case XK_F3:				key = FIRST_FUNCTION_KEY + 3;	break;
			case XK_F4:				key = FIRST_FUNCTION_KEY + 4;	break;
			case XK_F5:				key = FIRST_FUNCTION_KEY + 5;	break;
			case XK_F6:				key = FIRST_FUNCTION_KEY + 6;	break;
			case XK_F7:				key = FIRST_FUNCTION_KEY + 7;	break;
			case XK_F8:				key = FIRST_FUNCTION_KEY + 8;	break;
			case XK_F9:				key = FIRST_FUNCTION_KEY + 9;	break;
			case XK_F10:			key = FIRST_FUNCTION_KEY + 10;	break;
			case XK_F11:			key = FIRST_FUNCTION_KEY + 11;	break;
			case XK_F12:			key = FIRST_FUNCTION_KEY + 12;	break;
			case XK_F13:			key = FIRST_FUNCTION_KEY + 13;	break;
			case XK_F14:			key = FIRST_FUNCTION_KEY + 14;	break;
			case XK_F15:			key = FIRST_FUNCTION_KEY + 15;	break;
			case XK_F16:			key = FIRST_FUNCTION_KEY + 16;	break;
			case XK_F17:			key = FIRST_FUNCTION_KEY + 17;	break;
			case XK_F18:			key = FIRST_FUNCTION_KEY + 18;	break;
			case XK_F19:			key = FIRST_FUNCTION_KEY + 19;	break;
			case XK_F20:			key = FIRST_FUNCTION_KEY + 20;	break;
			case XK_F21:			key = FIRST_FUNCTION_KEY + 21;	break;
			case XK_F22:			key = FIRST_FUNCTION_KEY + 22;	break;
			case XK_F23:			key = FIRST_FUNCTION_KEY + 23;	break;
			case XK_F24:			key = FIRST_FUNCTION_KEY + 24;	break;
			case XK_F25:			key = FIRST_FUNCTION_KEY + 25;	break;
			case XK_F26:			key = FIRST_FUNCTION_KEY + 26;	break;
			case XK_F27:			key = FIRST_FUNCTION_KEY + 27;	break;
			case XK_F29:			key = FIRST_FUNCTION_KEY + 29;	break;
			case XK_F31:			key = FIRST_FUNCTION_KEY + 31;	break;
			case XK_F33:			key = FIRST_FUNCTION_KEY + 33;	break;
			case XK_F35:			key = FIRST_FUNCTION_KEY + 35;	break;

#			ifdef	SUN
				/* The following are only meaningful on the Sun */
				case XK_R8:			key = UP_ARROW_KEY;				break;
				case XK_R10:		key = LEFT_ARROW_KEY;			break;
				case XK_R12:		key = RIGHT_ARROW_KEY;			break;
				case XK_R14:		key = DOWN_ARROW_KEY;			break;
#			else	/* SUN */
				/* (These numbers collide with the XK_Rxx numbers) */
				case XK_F28:		key = FIRST_FUNCTION_KEY + 28;	break;
				case XK_F30:		key = FIRST_FUNCTION_KEY + 30;	break;
				case XK_F32:		key = FIRST_FUNCTION_KEY + 32;	break;
				case XK_F34:		key = FIRST_FUNCTION_KEY + 34;	break;
#			endif	/* SUN */

			case XK_KP_0:			key = FIRST_KEYPAD_KEY + 0;		break;
			case XK_KP_1:			key = FIRST_KEYPAD_KEY + 1;		break;
			case XK_KP_2:			key = FIRST_KEYPAD_KEY + 2;		break;
			case XK_KP_3:			key = FIRST_KEYPAD_KEY + 3;		break;
			case XK_KP_4:			key = FIRST_KEYPAD_KEY + 4;		break;
			case XK_KP_5:			key = FIRST_KEYPAD_KEY + 5;		break;
			case XK_KP_6:			key = FIRST_KEYPAD_KEY + 6;		break;
			case XK_KP_7:			key = FIRST_KEYPAD_KEY + 7;		break;
			case XK_KP_8:			key = FIRST_KEYPAD_KEY + 8;		break;
			case XK_KP_9:			key = FIRST_KEYPAD_KEY + 9;		break;
			case XK_KP_F1:			key = FIRST_KEYPAD_KEY + 10;	break;
			case XK_KP_F2:			key = FIRST_KEYPAD_KEY + 11;	break;
			case XK_KP_F3:			key = FIRST_KEYPAD_KEY + 12;	break;
			case XK_KP_F4:			key = FIRST_KEYPAD_KEY + 13;	break;
			case XK_KP_Space:		key = FIRST_KEYPAD_KEY + 14;	break;
			case XK_KP_Subtract:	key = FIRST_KEYPAD_KEY + 15;	break;
			case XK_KP_Separator:	key = FIRST_KEYPAD_KEY + 16;	break;
			case XK_KP_Decimal:		key = FIRST_KEYPAD_KEY + 17;	break;
			case XK_KP_Tab:			key = FIRST_KEYPAD_KEY + 18;	break;
			case XK_KP_Enter:		key = FIRST_KEYPAD_KEY + 19;	break;
			case XK_KP_Equal:		key = FIRST_KEYPAD_KEY + 20;	break;
			case XK_KP_Multiply:	key = FIRST_KEYPAD_KEY + 21;	break;
			case XK_KP_Add:			key = FIRST_KEYPAD_KEY + 22;	break;
			case XK_KP_Divide:		key = FIRST_KEYPAD_KEY + 23;	break;

			case XK_Left:			key = LEFT_ARROW_KEY;			break;
			case XK_Up:				key = UP_ARROW_KEY;				break;
			case XK_Right:			key = RIGHT_ARROW_KEY;			break;
			case XK_Down:			key = DOWN_ARROW_KEY;			break;

			case XK_Delete:			key = RUBOUT_KEY;				break;
			case XK_Return:			key = 13;						break;
			case XK_BackSpace:		key = 8;						break;
			case XK_Tab:			key = 9;						break;
			case XK_Escape:			key = 27;						break;
			case XK_Linefeed:		key = 10;						break;
			case XK_Clear:			key = 11;						break;
			case XK_Pause:			key = 19;						break;

			case XK_Shift_L:
			case XK_Shift_R:
			case XK_Caps_Lock:
			case XK_Shift_Lock: {

				/**
				 *	Return directly without reseting first_key since
				 *	the shift keys are allowed to be used in compose
				 *	key sequences.
				**/

			}	return;

			case XK_Multi_key:
			case XK_Meta_L:
			case XK_Alt_L: {

				/**
				 *	Set first_key to -1 to signal the start of a
				 *	compose sequence.
				**/

				xdata->first_key = -1;
			}	return;

			default: {

				/**
				 *	Not one of the special keys that we know.
				 *	Set "key" to LAST_KEY + 1 so that we will
				 *	return in an if test below before queuing
				 *	the key event.
				**/

				key = LAST_KEY + 1;
			}	break;
		}
		/**
		 *	Set first_key to 0 to abort a compose sequence
		 *	if one was in progress.
		**/
		xdata->first_key = 0;
	}

	if (xdata->first_key > 0) {
		register	int		key1;
		register	int		key2;

		/**
		 *	We have a compose sequence of two keys.	 First sort the
		 *	two keys so that our code is shorter - according to the
		 *	general rules, a compose sequence of two keys is NOT
		 *	order-dependent.  Next, check the combination of the
		 *	two keys and if it is not a recognized compose key
		 *	combination, set "key" to LAST_KEY + 1 so that we will
		 *	return in the if test below before queuing the key event.
		**/

		key1 = (xdata->first_key < key) ? xdata->first_key : key;
		key2 = (xdata->first_key < key) ? key : xdata->first_key;

		switch (key1) {

			case XK_space: {
				switch (key2) {
					case XK_space:			key = XK_nobreakspace;		break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_exclam: {
				switch (key2) {
					case XK_exclam:			key = XK_exclamdown;		break;
					case XK_P:				key = XK_paragraph;			break;
					case XK_p:				key = XK_paragraph;			break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_quotedbl: {
				switch (key2) {
					case XK_quotedbl:		key = XK_diaeresis;			break;
					case XK_A:				key = XK_Adiaeresis;		break;
					case XK_E:				key = XK_Ediaeresis;		break;
					case XK_I:				key = XK_Idiaeresis;		break;
					case XK_O:				key = XK_Odiaeresis;		break;
					case XK_U:				key = XK_Udiaeresis;		break;
					case XK_a:				key = XK_adiaeresis;		break;
					case XK_e:				key = XK_ediaeresis;		break;
					case XK_i:				key = XK_idiaeresis;		break;
					case XK_o:				key = XK_odiaeresis;		break;
					case XK_u:				key = XK_udiaeresis;		break;
					case XK_y:				key = XK_ydiaeresis;		break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_quoteright: {
				switch (key2) {
					case XK_A:				key = XK_Aacute;			break;
					case XK_E:				key = XK_Eacute;			break;
					case XK_I:				key = XK_Iacute;			break;
					case XK_O:				key = XK_Oacute;			break;
					case XK_U:				key = XK_Uacute;			break;
					case XK_Y:				key = XK_Yacute;			break;
					case XK_a:				key = XK_aacute;			break;
					case XK_e:				key = XK_eacute;			break;
					case XK_i:				key = XK_iacute;			break;
					case XK_o:				key = XK_oacute;			break;
					case XK_u:				key = XK_uacute;			break;
					case XK_y:				key = XK_yacute;			break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_asterisk: {
				switch (key2) {
					case XK_A:				key = XK_Aring;				break;
					case XK_asciicircum:	key = XK_degree;			break;
					case XK_a:				key = XK_aring;				break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_plus: {
				switch (key2) {
					case XK_minus:			key = XK_plusminus;			break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_comma: {
				switch (key2) {
					case XK_comma:			key = XK_cedilla;			break;
					case XK_minus:			key = XK_notsign;			break;
					case XK_C:				key = XK_Ccedilla;			break;
					case XK_c:				key = XK_ccedilla;			break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_minus: {
				switch (key2) {
					case XK_minus:			key = XK_hyphen;			break;
					case XK_colon:			key = XK_division;			break;
					case XK_A:				key = XK_ordfeminine;		break;
					case XK_D:				key = XK_Eth;				break;
					case XK_L:				key = XK_sterling;			break;
					case XK_Y:				key = XK_yen;				break;
					case XK_asciicircum:	key = XK_macron;			break;
					case XK_a:				key = XK_ordfeminine;		break;
					case XK_d:				key = XK_eth;				break;
					case XK_l:				key = XK_sterling;			break;
					case XK_y:				key = XK_yen;				break;
					case XK_bar:			key = XK_notsign;			break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_period: {
				switch (key2) {
					case XK_asciicircum:	key = XK_periodcentered;	break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_slash: {
				switch (key2) {
					case XK_C:				key = XK_cent;				break;
					case XK_O:				key = XK_Ooblique;			break;
					case XK_c:				key = XK_cent;				break;
					case XK_o:				key = XK_oslash;			break;
					case XK_u:				key = XK_mu;				break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_0: {
				switch (key2) {
					case XK_X:				key = XK_currency;			break;
					case XK_asciicircum:	key = XK_degree;			break;
					case XK_x:				key = XK_currency;			break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_1: {
				switch (key2) {
					case XK_asciicircum:	key = XK_onesuperior;		break;
					case XK_2:				key = XK_onehalf;			break;
					case XK_4:				key = XK_onequarter;		break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_2: {
				switch (key2) {
					case XK_asciicircum:	key = XK_twosuperior;		break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_3: {
				switch (key2) {
					case XK_4:				key = XK_threequarters;		break;
					case XK_asciicircum:	key = XK_threesuperior;		break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_less: {
				switch (key2) {
					case XK_less:			key = XK_guillemotleft;		break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_greater: {
				switch (key2) {
					case XK_greater:		key = XK_guillemotright;	break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_question: {
				switch (key2) {
					case XK_question:		key = XK_questiondown;		break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_A: {
				switch (key2) {
					case XK_E:				key = XK_AE;				break;
					case XK_asciicircum:	key = XK_Acircumflex;		break;
					case XK_quoteleft:		key = XK_Agrave;			break;
					case XK_asciitilde:		key = XK_Atilde;			break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_C: {
				switch (key2) {
					case XK_O:				key = XK_copyright;			break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_E: {
				switch (key2) {
					case XK_asciicircum:	key = XK_Ecircumflex;		break;
					case XK_quoteleft:		key = XK_Egrave;			break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_H: {
				switch (key2) {
					case XK_T:				key = XK_Thorn;				break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_I: {
				switch (key2) {
					case XK_asciicircum:	key = XK_Icircumflex;		break;
					case XK_quoteleft:		key = XK_Igrave;			break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_N: {
				switch (key2) {
					case XK_asciitilde:		key = XK_Ntilde;			break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_O: {
				switch (key2) {
					case XK_R:				key = XK_registered;		break;
					case XK_S:				key = XK_section;			break;
					case XK_X:				key = XK_currency;			break;
					case XK_asciicircum:	key = XK_Ocircumflex;		break;
					case XK_underscore:		key = XK_masculine;			break;
					case XK_quoteleft:		key = XK_Ograve;			break;
					case XK_asciitilde:		key = XK_Otilde;			break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_P: {
				switch (key2) {
					case XK_bar:			key = XK_Thorn;				break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_U: {
				switch (key2) {
					case XK_asciicircum:	key = XK_Ucircumflex;		break;
					case XK_quoteleft:		key = XK_Ugrave;			break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_backslash: {
				switch (key2) {
					case XK_backslash:		key = XK_acute;				break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_asciicircum: {
				switch (key2) {
					case XK_a:				key = XK_acircumflex;		break;
					case XK_e:				key = XK_ecircumflex;		break;
					case XK_i:				key = XK_icircumflex;		break;
					case XK_o:				key = XK_ocircumflex;		break;
					case XK_u:				key = XK_ucircumflex;		break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_underscore: {
				switch (key2) {
					case XK_o:				key = XK_masculine;			break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_quoteleft: {
				switch (key2) {
					case XK_a:				key = XK_agrave;			break;
					case XK_e:				key = XK_egrave;			break;
					case XK_i:				key = XK_igrave;			break;
					case XK_o:				key = XK_ograve;			break;
					case XK_u:				key = XK_ugrave;			break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_a: {
				switch (key2) {
					case XK_e:				key = XK_ae;				break;
					case XK_asciitilde:		key = XK_atilde;			break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_c: {
				switch (key2) {
					case XK_o:				key = XK_copyright;			break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_h: {
				switch (key2) {
					case XK_t:				key = XK_thorn;				break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_n: {
				switch (key2) {
					case XK_asciitilde:		key = XK_ntilde;			break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_o: {
				switch (key2) {
					case XK_r:				key = XK_registered;		break;
					case XK_s:				key = XK_section;			break;
					case XK_x:				key = XK_currency;			break;
					case XK_asciitilde:		key = XK_otilde;			break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_p: {
				switch (key2) {
					case XK_bar:			key = XK_thorn;				break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_s: {
				switch (key2) {
					case XK_s:				key = XK_ssharp;			break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_x: {
				switch (key2) {
					case XK_x:				key = XK_multiply;			break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			case XK_bar: {
				switch (key2) {
					case XK_bar:			key = XK_brokenbar;			break;
					default:				key = LAST_KEY + 1;			break;
				}
			}	break;
			default: {
				/* not one we know */
				key = LAST_KEY + 1;
				break;
			}
		}

		/* Ring the XBell if we had an invalid sequence. */
		if (key > LAST_KEY) {
			XBell(xdata->display, 0);
			XFlush(xdata->display);
		}

		/* Set first_key to 0 to reinitialize the compose key sequence. */
		xdata->first_key = 0;
	}

	if (key > LAST_KEY) {
		/* oops, got carried away */
		return;
	}

	hoops_key_state = false;

	if (BIT (xevent->state, Mod1Mask)) {
		hoops_key_state |= HOOPS_ALT_MASK;
	}
	if (BIT (xevent->state, ControlMask)) {
		hoops_key_state |= HOOPS_CTRL_MASK;
	}
	if (BIT (xevent->state, ShiftMask)) {
		hoops_key_state |= HOOPS_SHIFT_MASK;
	}

	SEQUENCE (dc, "queueing keystroke");

	HI_Queue_Keyboard_Event (dc->actor, key, hoops_key_state);
}


local void consume_mouse (dc, xevent)
	stack	Display_Context		*dc;
	stack	XEvent				*xevent;{
	stack	XData				*xdata = (XData *)dc->data;
	stack	int					new_buttons;

	xdata->mouse_valid = true;

	if (xevent->type == ButtonPress) {
		xdata->mouse_latched = true;
		xdata->latched_mouse_buttons = (xevent->xbutton.state >>8) ^ 
										(1<< (xevent->xbutton.button-1));
		xdata->latched_mouse_x = xevent->xbutton.x;
		xdata->latched_mouse_y = xdata->yfudge - xevent->xbutton.y;
	}
	else if (xevent->type == ButtonRelease && !xdata->mouse_latched) {
		xdata->mouse_latched = true;
		xdata->latched_mouse_buttons = (xevent->xbutton.state >>8) ^ 
										(1<< (xevent->xbutton.button-1));
		xdata->latched_mouse_x = xevent->xbutton.x;
		xdata->latched_mouse_y = xdata->yfudge - xevent->xbutton.y;
	}
	else {
		xdata->mouse_buttons = xevent->xmotion.state >>8;
		xdata->mouse_x = xevent->xmotion.x;
		xdata->mouse_y = xdata->yfudge - xevent->xmotion.y;
	}

#	ifdef	APOLLO
		/**
		 *	The purpose of the following code is to get around a BUG
		 *	in the Apollo X11 server.  The very first time the mouse
		 *	is moved into a window (or if the mouse is in the window
		 *	when it is created), the event structure returned by the
		 *	Apollo X11 server will indicate that a mouse button is
		 *	pressed.
		 *
		 *	We get around this Apollo X11 server BUG by explicitly
		 *	telling ourselves that no mouse button is pressed the first
		 *	time.  All user button presses will be handled correctly.
		**/

		if (!xdata->apollo_kludged) {
			if ((xevent->type == ButtonPress) ||
				(xevent->type == ButtonRelease && !xdata->mouse_latched)) {
				xdata->apollo_kludged = true;
			}
			else {
				xdata->mouse_buttons = 0;
			}
		}
#	endif	/* APOLLO */
}


local void check_events (dc)
	stack		Display_Context *dc; {
	register	XData			*xdata = (XData *)dc->data;
	stack		XEvent			xevent;
	stack		boolean			resize_pending = false,
								expose_pending = false;
	stack		Int_Rectangle	expose;
	stack		int				resize_x,
								resize_y,
								resize_width,
								resize_height;

	if (!xdata->check_since_finish) {
		SEQUENCE (dc, "check events");
		if (!dc->update_in_progress) xdata->check_since_finish = true;
	}

	while (QLength (xdata->display) > 0 ||
		   XEventsQueued (xdata->display, QueuedAfterReading) > 0) {

		XNextEvent (xdata->display, &xevent);

		switch (xevent.type) {
			case MotionNotify:
			case ButtonPress:
			case ButtonRelease: {
				SEQUENCE (dc, "mouse event");

				consume_mouse (dc, &xevent);	
			}	break;

			case Expose: {
				stack	Int_Rectangle			tmp;

				SEQUENCE (dc, "exposure event");

				if (BIT (dc->options.debug, DEBUG_SEQUENCING)) 
					fprintf (stderr, "X Sequence: exposure notify (%d x %d) @ (%d, %d)\n",
									 xevent.xexpose.width, xevent.xexpose.height,
									 xevent.xexpose.x, xevent.xexpose.y);

				tmp.left = xevent.xexpose.x; 
				tmp.right = xevent.xexpose.x + xevent.xexpose.width - 1;
				tmp.top = xdata->yfudge - xevent.xexpose.y;
				tmp.bottom = xdata->yfudge - xevent.xexpose.y -
					xevent.xexpose.height - 1;

				if (expose_pending) {
					if (expose.left > tmp.left) expose.left = tmp.left;
					if (expose.right < tmp.right) expose.right = tmp.right;
					if (expose.bottom > tmp.bottom) expose.bottom = tmp.bottom;
					if (expose.top < tmp.top) expose.top = tmp.top;
				}
				else {
					expose.left = tmp.left;
					expose.right = tmp.right;
					expose.bottom = tmp.bottom;
					expose.top = tmp.top;
					expose_pending = true;
				}
			}	break;

			case ReparentNotify: {
				SEQUENCE (dc, "reparent event");

				enable_parent_events (xdata, StructureNotifyMask);	 
			}	break;

			case ConfigureNotify: {
				stack		XWindow			childjunk, rootjunk;
				stack		int				x, y, width, height;
				stack		int				border_width, depth;
				stack		XWindow			*children;
				stack		unsigned int	nchildren;
	
				SEQUENCE (dc, "configure notify event");

				/* get its geometry and tell hoops */

				/* double-check - xconfigure isn't always right */

				XGetGeometry (xdata->display, xdata->window, &rootjunk,
								  &x, &y, &width, &height,
								  &border_width, &depth); 

				/* (double-check xdata->parent_window) */
				XQueryTree (xdata->display, xdata->window, &xdata->root_window,
								&xdata->parent_window, &children, &nchildren);
				XFree (children);

				/* translate to root coordinates */
				XTranslateCoordinates (xdata->display, 
										   xdata->parent_window, 
										   xdata->root_window,
										   x, y, &x, &y, 
										   &childjunk);
#				ifdef	SUN
					/* GetGeometry x and y are right but width and height
					 * are wrong. Xconfig event's x and y are wrong but
					 * width and height are right.
					 */
					width = xevent.xconfigure.width;
					height = xevent.xconfigure.height;
#				endif	/* SUN */

				if (BIT (dc->options.debug, DEBUG_SEQUENCING)) 
					fprintf (stderr, "X Sequence: configure resize notify (%d x %d) @ (%d, %d)\n",
									 width, height, x, y);

				if (xdata->window_x == x && 
					xdata->window_y == y &&
					xdata->window_width == width && 
					xdata->window_height == height) {
					
					SEQUENCE (dc, "resize not pending");
					resize_pending = false;
				}
				else {
					if (xdata->resize_in_progress) {
						xdata->window_x = x;
						xdata->window_y = y;
						xdata->window_width = width;
						xdata->window_height = height;

						SEQUENCE (dc, "resize in progress");
						return;/* let caller think */
					}
					else {
						SEQUENCE (dc, "resize confirmed");

#						ifdef	SUN
							/* permit all the Expose events to accumulate */

							if (!dc->timer_interrupts_enabled)
								HI_Sleep (TIME (0.5));
							else {
								extern	boolean HI_Enable_Timer_Interrupts ();	
								/* disable, in case Sleep confuses the timer */
								HI_Disable_Timer_Interrupts ();
								HI_Sleep (TIME (0.5));
								(void)HI_Enable_Timer_Interrupts ();
							}
#						endif	/* SUN */

						resize_x = x;
						resize_y = y;
						resize_width = width;
						resize_height = height;
						resize_pending = true;
					}
				}
			}	break;

			case KeyPress: {
				SEQUENCE (dc, "keypress event");

				consume_key (dc, (XKeyEvent *)&xevent);
			}	break;
	
			case FocusIn: {
				SEQUENCE (dc, "focus-in event");

				if (xdata->mapped_colors) {
					if (xdata->cmap != xdata->default_cmap && 
						!xdata->cmap_installed) {
						XInstallColormap(xdata->display, xdata->cmap);
						xdata->cmap_installed = true;
					}
				}
				xdata->focus_on_us = true;
			}	break;

			case FocusOut: {
				SEQUENCE (dc, "focus-out event");

				if (xdata->mapped_colors) {
					if (xdata->cmap != xdata->default_cmap && 
						xdata->cmap_installed) {
						XUninstallColormap(xdata->display, xdata->cmap);
						xdata->cmap_installed = false;
					}
				}
				xdata->focus_on_us = false;
			}	break;
		}
	}

	if (resize_pending || expose_pending) {
		++OUR(update_suspensions);		/* kill Update_Display */

		if (expose_pending) {
			HD_Force_Partial_Refresh (dc, expose.left, expose.right, 
										  expose.bottom, expose.top);
		}

		if (resize_pending) {
			HD_Resize_Subscreen (dc, true, 
				resize_x, resize_x + resize_width - 1,
				dc->physical.number_of_pixels.y - (resize_y + resize_height),
				dc->physical.number_of_pixels.y - 1 - resize_y);
			xdata->window_x = resize_x;
			xdata->window_y = resize_y;
			xdata->window_width = resize_width;
			xdata->window_height = resize_height;
		}

		--OUR(update_suspensions);		/* resume Update_Display */

		if (!dc->update_in_progress) {
			/* get a new update started */
			PUSHNAME ();
			HC_Update_Display();
			POPNAME ();
		}			
	}
}


local void get_actions (at)
	register  Action_Table	 *at; {

	at->start_device				= ADDR (start_device);
	at->stop_device					= ADDR (stop_device);
	at->get_physical_info			= ADDR (get_physical_info);
	at->get_current_info			= ADDR (get_current_info);
	/* No action table routine for select */
	/* No action table routine for render */
	/* No action table routine for update */
	/* No action table routine for draw_tree */
	at->init_picture				= ADDR (init_picture);
	/* No action table routine for finish_picture */
	at->init_update					= ADDR (init_update);
	at->finish_update				= ADDR (finish_update);
	at->get_outer_window			= ADDR (get_outer_window);
	at->free_outer_window			= ADDR (free_outer_window);
	at->resize_outer_window			= ADDR (resize_outer_window); 
	/* No action table routine for draw_3d_circle */
	/* No action table routine for draw_3d_circular_arc */
	/* No action table routine for draw_3d_ellipse */
	/* No action table routine for draw_3d_elliptical_arc */
	/* No action table routine for draw_3d_marker */
	/* No action table routine for draw_3d_polyline */
	/* No action table routine for draw_3d_polygon */
	/* No action table routine for draw_3d_pixel_array */
	/* No action table routine for draw_3d_text */
	/* No action table routine for draw_window */
	/* No action table routine for draw_dc_ellipse */
	/* No action table routine for draw_dc_outline_ellipse */
	at->draw_dc_polyline			= ADDR (draw_dc_polyline);
	at->draw_dc_face				= ADDR (draw_dc_face);
	/* draw_dc_blended_face assigned in get_physical_info */
	at->draw_dc_polygon				= ADDR (draw_dc_polygon);
	at->draw_dc_rectangle			= ADDR (draw_dc_rectangle);
	at->draw_dc_overlay_polyline	= ADDR (draw_dc_overlay_polyline);
	at->draw_dc_overlay_face		= ADDR (draw_dc_overlay_face);
	at->draw_dc_pixel_array			= ADDR (draw_dc_pixel_array);
	at->draw_dc_marker				= ADDR (draw_dc_marker);
	at->draw_dc_text				= ADDR (draw_dc_text);
	/* No action table routine for draw_inter_text */
	/* No action table routine for clear_z_buffer */
	at->draw_overlay_list			= ADDR (draw_overlay_list);
	at->undraw_overlay_list			= ADDR (draw_overlay_list);
	at->request_location			= ADDR (request_location);
	at->request_keyboard			= ADDR (request_keyboard);
	/* set_device_color_map assigned in get_physical_info */
	/* No action table routine for enable_cursor */
	/* No action table routine for disable_cursor */
	/* No action table routine for move_cursor */
	at->find_all_fonts				= ADDR (find_all_fonts);
	at->load_font					= ADDR (load_font);
	at->unload_font					= ADDR (unload_font);
}
#endif	 /* end of ifdef X11 */

/* (mustn't end with a '#' line) */
