/* X Communication module for terminals which understand the X protocol.
   Copyright (C) 1988, 1990 Free Software Foundation, Inc.

This file is part of Epoch.

GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.

GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */

/*
 * $Revision: 1.1 $
 * $Source: /afs/athena.mit.edu/contrib/epoch/epoch-4.2/src/RCS/x11term.c,v $
 * $Date: 1993/03/04 13:15:39 $
 * $Author: jfc $
 */
#ifndef LINT
static char rcsid[] = "$Author: jfc $ $Date: 1993/03/04 13:15:39 $ $Source: /afs/athena.mit.edu/contrib/epoch/epoch-4.2/src/RCS/x11term.c,v $ $Revision: 1.1 $";
#endif

/* On 4.3 this loses if it comes after x11term.h.
   On hp-ux it loses if it comes after config.h.  */
#include <signal.h>
#include <sys/ioctl.h>

/* Load sys/types.h if not already loaded.
   In some systems loading it twice is suicidal.  */
#ifndef makedev
#include <sys/types.h>
#endif

#include "config.h"

#ifdef HAVE_X_WINDOWS

/* Get FIONREAD, if it is available.
   It would be logical to include <sys/ioctl.h> here,
   but it was moved up above to avoid problems.  */
#ifdef USG
#include <termio.h>
#endif /* USG */
#include <fcntl.h>

#include "lisp.h"
#undef NULL

/* Allow m- file to inhibit use of interrupt-driven input.  */
#ifdef BROKEN_FIONREAD
#undef FIONREAD
#endif

/* We are unable to use interrupts if FIONREAD is not available,
   so flush SIGIO so we won't try.  */
#ifndef FIONREAD
#ifdef SIGIO
#undef SIGIO
#endif
#endif

/* This may include sys/types.h, and that somehow loses
   if this is not done before the other system files.
   However, perhaps the problem has been avoided by loading types.h above.  */

#include "x11term.h"

#ifdef HAVE_SOCKETS
#include <sys/socket.h>		/* Must be done before gettime.h */
#endif
/* Include time.h, sys/time.h, or both. */
#include "gettime.h"

#ifdef AIX
static KeySym XMOD_Alt[] = { XK_Alt_L };
static KeySym XMOD_Shift[] = { XK_Shift_L };
static KeySym XMOD_ShiftAlt[] = { XK_Alt_L, XK_Shift_L };
static KeySym XMOD_CtrlAlt[] = { XK_Control_L, XK_Alt_L };
static KeySym XMOD_Ctrl[] = { XK_Control_L };
static KeySym XMOD_CtrlShift[] = { XK_Control_L, XK_Shift_L };
static KeySym XMOD_ShiftCtrlAlt[] = { XK_Control_L, XK_Alt_L, XK_Shift_L };
#endif

#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#ifdef BSD
#include <strings.h>
#endif
#include <sys/stat.h>

#ifndef NULL
#define NULL 0
#endif

#include "dispepoch.h"		/* Epoch */
#include "termhooks.h"
#include "termopts.h"
#include "termchar.h"

#include "window.h"		/* Epoch */
#include "buffer.h"
#include "screen.h"		/* Epoch */
#include "screenW.h"		/* Epoch */
#include "screenX.h"		/* Epoch */
#include "button.h"		/* Epoch */
#include "xresource.h"		/* Epoch */

/* X11 includes used; use NIL rather than NULL from lisp.h */

#define min(a,b) ((a)<(b) ? (a) : (b))
#define max(a,b) ((a)>(b) ? (a) : (b))
#define MAPPINGBUFLEN 256
extern int errno;

#ifdef USG5_4
#define sigunblockx(sig) sigrelse(sig)
#define sigblockx(sig) sighold(sig)
#else
#define sigunblockx(sig) sigblock (SIGEMPTYMASK)
#define sigblockx(sig) sigblock (sigmask ((sig)))
#endif

#define METABIT 0200
#define MINWIDTH 12	/* In pixels */
#define MINHEIGHT 5	/* In pixels */
#define MAXHEIGHT 300	/* In lines */

char *progname;

XButtonEvent *XXm_queue[XMOUSEBUFSIZE];
int XXm_queue_num, XXm_queue_in, XXm_queue_out;
extern Lisp_Object Vx_mouse_events;

extern Lisp_Object selected_window,minibuf_window;

/* External variables for screen display, etc. */
extern Display *XD_display;		/* Default display */
extern int 	XD_plane;		/* x screen to work with */
extern char	XD_is_color;		/* color display? */
extern char    *XD_display_name;	/* Display name */
extern char    *XD_resource_name;
extern char    *XD_screen_name;
extern int distinct_minibuffer; /* Does minibuffer have a distinct screen? */
extern int screen_changed;
extern int initialized;

/* Function for init_keyboard to call with no args (if nonzero).  */
extern void (*keyboard_init_hook) ();
extern char 		*strdup();

extern int xargc;
extern char **xargv;

int XXpid;
  
static XComposeStatus status;

static int InUpdate;		/* many of functions here may be invoked
				 * even if no update in progress; when
				 * no update is in progress the action
				 * can be slightly different */

extern Atom XA_current;

/* 0 for no focus, 1 for Pointer focus, 2 for Explicit focus */
char X_focus;

int (*handler)();

static void x_init_1 ();

#if !defined(NeXT) && !defined(AIX)
extern char *rindex();
#endif

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* List of fonts loaded.
 */
struct X_font *font_list;

/* Load an X11 font, and add it to the list of fonts loaded.
 */
struct X_font *
load_font(name)
     char *name;
{
  XFontStruct *font;
  BLOCK_INPUT_DECLARE();
  struct X_font *f,*new;
  unsigned long wid,widi;

  f = font_list;
  while (f && strcmp(name,f->font_name))
    f = f->next;

  if (f) return f;		/* Font was already loaded */
  
  BLOCK_INPUT();
  font = XLoadQueryFont(XD_display,name);
  UNBLOCK_INPUT();

  if (!font) return 0;		/* No font loaded */

  if (!XGetFontProperty(font,XA_QUAD_WIDTH,&wid))
    wid = XTextWidth(font,"M",1);
  widi = XTextWidth(font,"i",1);
  
  new = (struct X_font *) malloc(sizeof (struct X_font));

  new->font_name = strdup(name);
  new->x_font = font;
  new->next = font_list;
  new->ascent = font->ascent;
  new->descent = font->descent;
  new->width = wid;
  new->variable = (wid != widi);
#ifdef HAVE_GRAPHIC_ZONES
  new->virtual = 0;
#endif  
  font_list = new;

  return new;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Find a font structure, given an fid.
 */
struct X_font *
find_font(fid)
     int fid;
{
  struct X_font *f;

  f = font_list;

  while (f)
    {
      if (fid == XFID(f)) return f;
      f = f->next;
    }
  return 0;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Real fcn to return width of text string displayed in FONT when under X.
 */
TextWidth(font_struct, string,length)
     XFontStruct *font_struct;
     char *string;
     int length;
{
  return XTextWidth(font_struct,string,length);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Used for starting or restarting (after suspension) the X window.  Puts the
 * cursor in a known place, update does not begin with this routine but only
 * with a call to redisplay.
 */
CXTset_terminal_modes (w)
     struct window *w;
{
  struct Root_Block *rb = XROOT(w->root);  
  XS_DEF; WS_DEF;
#ifdef XDEBUG
	fprintf (stderr, "XTset_terminal_modes\n");
#endif
  InUpdate = 0;
  status.compose_ptr = 0;
  status.chars_matched = 0;
   
  if (!initialized)
    {
      xs->cursor_exists = 0;
      ws->vis_xpos = 0;
      ws->vis_ypos = 0;
    }
  CXTclear_screen (w);
}

XTset_terminal_modes ()
{
  return CXTset_terminal_modes(XWINDOW(selected_window));
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Shift region of lines according to scrolling info
 */
XTshift_region(w,start,end)
     struct window *w;
     struct line_header *start,*end;
{
  struct Root_Block *rb = XROOT(w->root);
  XS_DEF; WS_DEF;
  register int old_top,new_top,length,i;
  BLOCK_INPUT_DECLARE();

  BLOCK_INPUT();
  
  if (xs->cursor_exists) CursorToggle(rb);

  old_top = start->prevy - start->ascent;
  new_top = start->ypos - start->ascent;
  length = end->ypos + end->descent - (start->ypos - start->ascent);

  if (length > 0 && old_top != new_top)
    {
      XCopyArea(xs->display,xs->xid,xs->xid,xs->gc_norm,
		XFASTINT(w->pixleft),old_top,
		XFASTINT(w->pixwidth),length,
		XFASTINT(w->pixleft),new_top);

      if (new_top > old_top)
	{
	  /* Shifted region down */
	  length = new_top - old_top;
	  XClearArea(xs->display,xs->xid,
		     XFASTINT(w->pixleft),old_top,
		     XFASTINT(w->pixwidth),length,0);
	}
      else
	{
	  /* Shifted region up */
	  i = end->ypos + end->descent;
	  length = old_top - new_top;
	  XClearArea(xs->display,xs->xid,
		     XFASTINT(w->pixleft),i,
		     XFASTINT(w->pixwidth),length,0);
	}
    }
  UNBLOCK_INPUT();
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Fastmove_cursor - called from output_for_insert().  Note:  in this case,
  * a character has just been inserted (overwriting past cursor), and cursor
  * needs to be redrawn in its new spot.
  */
Fastmove_cursor(rb)
     struct Root_Block *rb;
{
  XS_DEF;
  WS_DEF;
  BLOCK_INPUT_DECLARE();
  
  /* Fudge so we are toggling the cursor BACK into existence. */

  xs->cursor_exists = 0;
  ws->vis_xpos = ws->cursor_x;
  BLOCK_INPUT();
  CursorToggle(rb);
  XFlush(xs->display);
  UNBLOCK_INPUT();
  return;
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* XTmove_cursor moves the cursor to the correct location and checks whether an
 * update is in progress in order to toggle it on.
 */
XTmove_cursor (l,cb,row, col,win,rb)
     struct line_header *l;
     struct char_block *cb;     
     int row, col;
     struct window *win;
     struct Root_Block *rb;
{
  XS_DEF; WS_DEF;
  BLOCK_INPUT_DECLARE ();

#if 0  
  fprintf (stderr, "XTmove_cursor (X %d, Y %d)\n",col,row);
#endif

  BLOCK_INPUT ();

  if (InUpdate)
    {
      /* Cursor is already dead.  Now put it in its place. */
      ws->cur_w = win;
      ws->cur_line = l;
      ws->cur_char = cb;
      ws->vis_xpos = col;
      ws->vis_ypos = row;       
      if (xs->cursor_exists)
	CursorToggle (rb);
      UNBLOCK_INPUT ();
      return;
      /* Generally, XTmove_cursor will be invoked
       * when InUpdate with !CursorExists 
       * so that wasteful XFlush is not called
       */
    }
  if (ws->cur_w &&
      (ws->new_cur_w != ws->cur_w &&
       ws->cur_w != XWINDOW(rb->minibuf_window)) &&
      find_window(ws->cur_w,rb->ewin))
    {
      char a[2];
      struct Lisp_Style *style = find_style(ws->cur_w,0);
      a[0] = ws->cur_char->ch == 0 ? ' ' : ws->cur_char->ch;
      a[1] = 0;
	  
      /* UGLY:  Cursor's previous position may be in another window
       * still being displayed; this will result in a blank or stray
       * cursor left in that other window.  Find the window, and
       * erase the old cursor
       */
      ShipOutTextBlock(a,1,
		       ws->cur_char->xpos,ws->cur_line->ypos,
		       ws->cur_line->ascent,ws->cur_line->descent,0,
		       ws->cur_char->style ? ws->cur_char->style : style,
		       ws->cur_w);

      xs->cursor_exists = 0;
      ws->cur_w = win;
      ws->cur_line = l;
      ws->cur_char = cb;
      ws->vis_xpos = col;
      ws->vis_ypos = row;
      CursorToggle(rb);
      UNBLOCK_INPUT();
      return;
    }     
  if ((row == ws->vis_ypos) && (col == ws->vis_xpos))
    {
      ws->cur_w = win;
      ws->cur_line = l;
      ws->cur_char = cb;
      if (!xs->cursor_exists)
	CursorToggle (rb);
      XFlush (xs->display);
      UNBLOCK_INPUT ();
      return;
    }
  /*
   * First remove cursor from where it is
   */
  if (xs->cursor_exists)
    CursorToggle (rb);
  /*
   * Now update ptrs to where cursor actually is
   */
  ws->cur_w = win;
  ws->cur_line = l;
  ws->cur_char = cb;  
  ws->vis_xpos = col;
  ws->vis_ypos = row;
  /*
   * Now plot it
   */
  if (!xs->cursor_exists)
    CursorToggle (rb);
  XFlush (xs->display);
  UNBLOCK_INPUT ();
#if 0
  fprintf(stderr, "End move cursor\n");
#endif  
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Used to get the terminal back to a known state after resets.  Usually
 * used when restarting suspended or waiting emacs
 */
Ccleanup (w)
     struct window *w;
{
  inverse_video = 0;
}

cleanup ()
{ return Ccleanup(XWINDOW(selected_window)); }
/* - - - -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Clear region from ypos1 to ypos2, for entire window width
 */
XTclear_window_end(w,ypos1,ypos2)
     struct window *w;
     int ypos1,ypos2;
{
  struct Root_Block *rb = XROOT(w->root);
  XS_DEF; WS_DEF;
  BLOCK_INPUT_DECLARE();

  BLOCK_INPUT();
  if (xs->highlight)
    XFillRectangle(xs->display,xs->xid,xs->gc_norm,
		   w->pixleft,ypos1,w->pixwidth,(ypos2 - ypos1));
  else
    XClearArea(xs->display,xs->xid,
	       w->pixleft,ypos1,w->pixwidth,(ypos2 - ypos1),0);
  UNBLOCK_INPUT();
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
CXTreset_terminal_modes (w)
     struct window *w;
{
#ifdef XDEBUG
	fprintf (stderr, "XTreset_terminal_modes\n");
#endif
	CXTclear_screen (w);
}

XTreset_terminal_modes ()
{
  return CXTreset_terminal_modes(XWINDOW(selected_window));
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
CXTclear_screen (w)
     struct window *w;
{
  struct Root_Block *rb = XROOT(w->root);  
  XS_DEF; WS_DEF;
  BLOCK_INPUT_DECLARE ();

#ifdef XDEBUG
	fprintf (stderr, "XTclear_screen\n");
#endif

  BLOCK_INPUT ();
  xs->cursor_exists = 0;

  ws->cursor_x = ws->cursor_y = 0;
  ws->new_cur_line = ws->cur_line = XLINE(w->lines);
  ws->new_cur_char = ws->cur_char = XLINE(w->lines)->body;

  ws->vis_xpos = 0;
  ws->vis_ypos = 0;
  XClearWindow(xs->display, xs->xid);
  CursorToggle (rb);
  if (!InUpdate)
    XFlush (xs->display);
  UNBLOCK_INPUT ();
}

XTclear_screen ()
{ return CXTclear_screen(XWINDOW(selected_window)); }

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
CXTflash (w)
     struct window *w;
{
  struct Root_Block *rb = XROOT(w->root);  
#ifdef HAVE_TIMEVAL
  struct timeval to;
#endif
  XGCValues gcv;
  GC thegc;
  BLOCK_INPUT_DECLARE ();
  XS_DEF; WS_DEF;

#ifdef XDEBUG
  fprintf (stderr, "XTflash\n");
#endif

  gcv.function = GXxor;
  gcv.foreground = XXRESOURCE(XSTYLE(rb->stylenorm)->foreground)->id
    ^ XXRESOURCE(XSTYLE(rb->stylenorm)->background)->id;
  gcv.fill_style = FillSolid;

  BLOCK_INPUT ();
  
  thegc = XCreateGC(xs->display, xs->xid,
		    GCFunction|GCForeground|GCFillStyle, &gcv);

  XFillRectangle (xs->display, xs->xid, thegc, 0, 0,
		  xs->pixwidth,xs->pixheight);
  XFlush (xs->display);

  UNBLOCK_INPUT ();

#ifdef HAVE_TIMEVAL
  to.tv_sec = 0;
  to.tv_usec = 250000;

  select(0, 0, 0, 0, &to);
#endif

  BLOCK_INPUT ();

  XFillRectangle (xs->display, xs->xid, thegc, 0, 0,
		  xs->pixwidth,xs->pixheight);

  XFreeGC(xs->display, thegc);
  XFlush (xs->display);

  UNBLOCK_INPUT ();
}

XTflash()
{ return CXTflash(XWINDOW(selected_window)); }
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
CXTfeep (w)
     struct window *w;
{
  struct Root_Block *rb = XROOT(w->root);  
  XS_DEF;
  int volume = 50;
  BLOCK_INPUT_DECLARE ();
  extern Lisp_Object Vepoch_bell_volume;

  if (XTYPE(Vepoch_bell_volume) == Lisp_Int)
    {
      volume = XINT(Vepoch_bell_volume);
      if (volume < -100 || volume > 100) volume = 50;
    }

#ifdef XDEBUG
  fprintf (stderr, "XTfeep\n");
#endif
  BLOCK_INPUT ();
  XBell (xs->display,volume);
  UNBLOCK_INPUT ();
}

XTfeep ()
{ return CXTfeep(XWINDOW(selected_window)); }

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */  
/* Artificially creating a cursor is hard, the actual position on the
 * screen (either where it is or last was) is tracked with vix_x,y.
 * Gnu Emacs code tends to assume a cursor exists in hardward at ws->cursor_x,y
 * and that output text will appear there.  During updates, the cursor is
 * supposed to be blinked out and will only reappear after the update
 * finishes.
 */
CursorToggle (rb)
     struct Root_Block *rb;
{
  int y;
  WS_DEF; XS_DEF;
  char a[2];
  int wid;
  struct window *w = XWINDOW(rb->select);
  struct buffer *b = XBUFFER(w->buffer);
  struct X_font *font = XXFONT(STYLE_FIELD(w,font,stylenorm));

  if (!xs->mapped)
    {
      xs->cursor_exists = 0;
      return 0;
      /* Currently the return values are not
       * used, but I could anticipate using
       * them in the future.
       */
    }

  if (ws->vis_ypos < 0)
    {
      /* Not much can be done */
      XFlush (xs->display);
      xs->cursor_exists = 0;
      return 0;
    }

  /* This may get called before any layout is done.  Blow if off in that
   * case.
   */

  if (!ws->cur_line || !ws->cur_char
      || ws->cur_char->xpos < w->pixleft
      || ws->cur_char->xpos > w->pixleft + w->pixwidth)
    {
      XFlush(xs->display);
      xs->cursor_exists = 0;
      return 0;
    }

  a[1] = 0;
  /* Epoch:
   * Potential problem:  cursors in minibuffer screen and current edit
   * screen.  If we are toggling cursor on screen other than current screen,
   * force it to not exist.
   */
  if (rb != cur_root) xs->cursor_exists = 1; /* Die a horrible death, cursor */

  if (ws->vis_xpos <= ws->cur_line->chars)
    {
      a[0] = ws->cur_char->ch == 0 ? ' ' : ws->cur_char->ch;
      if (ws->cur_char->style &&
	  (XTYPE(ws->cur_char->style->font) == Lisp_Raw_Data))
	font = XXFONT(ws->cur_char->style->font);
      wid = text_width(font,a,1);
      if (xs->cursor_exists)
	{
	  ShipOutTextBlock(a,1,
			   ws->cur_char->xpos,ws->cur_line->ypos,
			   ws->cur_line->ascent,ws->cur_line->descent,0,
			   ws->cur_char->style,ws->cur_w);
	}
      else if (! X_focus)
	{
	  ShipOutTextBlock(a,1,
			   ws->cur_char->xpos,ws->cur_line->ypos,
			   ws->cur_line->ascent,ws->cur_line->descent,0,
			   ws->cur_char->style,ws->cur_w);
	  XDrawRectangle(xs->display,xs->xid,xs->gc_norm,
			 ws->cur_char->xpos,
			 ws->cur_line->ypos - ws->cur_line->ascent,
			 wid - 1,
			 ws->cur_line->ascent + ws->cur_line->descent - 1);
	}
      else
	/* use reverse attribute for plotting cursor */
	{
	  ShipOutTextBlock(a,1,
			   ws->cur_char->xpos,ws->cur_line->ypos,
			   ws->cur_line->ascent,ws->cur_line->descent,1,
			   ws->cur_char->style,ws->cur_w);
	}
    }
  else
    {
      a[0] = ws->cur_char->ch == 0 ? ' ' : ws->cur_char->ch;
      if (ws->cur_char->style &&
	  (XTYPE(ws->cur_char->style->font) == Lisp_Raw_Data))
	font = XXFONT(ws->cur_char->style->font);
      wid = text_width(font,a,1);
      if (xs->cursor_exists)
	{
	  int height = ws->cur_line->ascent ?
	    (ws->cur_line->ascent + ws->cur_line->descent) : XFHEIGHT(font);

          if (!distinct_minibuffer && ws->cur_w == XWINDOW(rb->minibuf_window))
	    {
	      ;
	    }
	  else
	    {
	      
	    XClearArea(xs->display,xs->xid,
		       ws->cur_char->xpos,
		       ws->cur_line->ypos - ws->cur_line->ascent,
		       wid,
		       height,0);
	    }
	}
      else if (! X_focus)
	XDrawRectangle(xs->display,xs->xid,xs->gc_norm,
		       ws->cur_char->xpos,
		       ws->cur_line->ypos - ws->cur_line->ascent,
		       wid - 1,
		       ws->cur_line->ascent + ws->cur_line->descent -1);
      else
	{
	  ShipOutTextBlock(a,1,
			   ws->cur_char->xpos,ws->cur_line->ypos,
			   ws->cur_line->ascent,ws->cur_line->descent,1,
			   XSTYLE(rb->stylecursor),ws->cur_w);
	}
    }

  xs->cursor_exists = !xs->cursor_exists;

  if (!InUpdate)
    XFlush (xs->display);

  return 1;
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* This routine is used by routines which are called to paint regions 
 * designated by Expose events.  If the cursor may be in the exposed
 * region, this routine makes sure it is gone so that dumprectangle can 
 * toggle it back into existance if dumprectangle is invoked when not in
 * the midst of a screen update.
 */
ClearCursor(rb)
     struct Root_Block *rb;
{
  XS_DEF; WS_DEF;
  BLOCK_INPUT_DECLARE ();
  char a[1];
  int wid,height;
  struct window *w = XWINDOW(rb->select);
  struct buffer *b = XBUFFER(w->buffer);
  struct X_font *font = XXFONT(STYLE_FIELD(w,font,stylenorm));
  
  BLOCK_INPUT ();
  if (!xs->mapped)
    {
      xs->cursor_exists = 0;
      UNBLOCK_INPUT ();
      return;
    }
	
  if (ws->vis_xpos >= ws->width || ws->vis_ypos < 0 ||
      ws->vis_ypos >= ws->height || !ws->new_cur_char || !ws->new_cur_line)
    {
      /* Not much can be done */
      xs->cursor_exists = 0;
      UNBLOCK_INPUT ();
      return;
    }

  a[0] = ' ';
  if (ws->new_cur_char->style &&
      (XTYPE(ws->new_cur_char->style->font) == Lisp_Raw_Data))
    font = XXFONT(ws->new_cur_char->style->font);
  wid = ws->new_cur_char->ch == 0 ? text_width (font,a,1) : 
    ws->new_cur_char->width;
  height = ws->new_cur_line->ascent ?
    (ws->new_cur_line->ascent + ws->new_cur_line->descent) : XFHEIGHT(font);

  XClearArea (xs->display, xs->xid,
	      ws->new_cur_char->xpos,
	      ws->new_cur_line->ypos - ws->new_cur_line->ascent,wid,
	      height,0);
  xs->cursor_exists = 0;
  UNBLOCK_INPUT ();
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
CXTupdate_begin(w)
     struct window *w;
{
  struct Root_Block *rb = XROOT(w->root);  
  XS_DEF; WS_DEF;
  BLOCK_INPUT_DECLARE ();
	
#ifdef XDEBUG
  fprintf (stderr, "XTupdate_begin\n");
#endif

  BLOCK_INPUT ();
  InUpdate = 1;
  if (xs->cursor_exists && w == XWINDOW(rb->select))
    {
#if 0      
      fprintf(stderr,"Blink1\n");
#endif      
      CursorToggle (rb);
    }
  UNBLOCK_INPUT ();
}

XTupdate_begin ()
{ return CXTupdate_begin(XWINDOW(selected_window)); }
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
CXTupdate_end (w)
     struct window *w;
{
  struct Root_Block *rb = XROOT(w->root);  
  XS_DEF; WS_DEF;
  BLOCK_INPUT_DECLARE ();

#ifdef XDEBUG
  fprintf (stderr, "XTupdate_end\n");
#endif

  BLOCK_INPUT ();
  
  if (xs->cursor_exists && rb == cur_root && w == XWINDOW(rb->select))
    {
#if 0      
      fprintf(stderr,"Blink2\n");
#endif      
      CursorToggle (rb);
    }

  InUpdate = 0;
#if 0  
  if (rb == cur_root)
    update_cursor(rb);
#endif  

  XFlush (xs->display);
  UNBLOCK_INPUT ();
  
  {
    /* B<   Brian Kahn   blk@mitre.org   Tue Aug 11 15:36:54 1992
     * Call value of after-update-hook if it is bound and non-nil
     * derived from epoch code for set-window-buffer-hook
     */
    register Lisp_Object tem;
    tem = intern("after-update-hook");
    tem = XSYMBOL (tem)->value;       /* convert to value */
    if (! EQ (tem, Qunbound) && ! EQ (tem, Qnil))
      tem = call0 (tem);
  }
}

XTupdate_end ()
{ return CXTupdate_end(XWINDOW(selected_window)); }
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Used for Expose events.  Have to get the text
 * back into the newly blank areas.
 */
Cdumprectangle (top, left, rows, cols,rb)
     register int top, left, rows, cols;
     struct Root_Block *rb;
{
  XS_DEF;
  WS_DEF;
#if 0  
  int cursor = (!ws->cur_line || !ws->cur_char) ? 0 :
    ((ws->cur_char->xpos > left + cols) |
     ((ws->cur_char->xpos + ws->cur_char->width) < left) |
     ((ws->cur_line->ypos - ws->cur_line->ascent)  > top + rows) |
     ((ws->cur_line->ypos + ws->cur_line->descent) < top));

  if (rb == cur_root && !cursor) ClearCursor(rb);
#endif
  if (rb == cur_root) ClearCursor(rb);
  
  dump_windows(rb->ewin,top,left,rows,cols);

#if 0  
  if (!cursor && !InUpdate && rb == cur_root && !xs->cursor_exists)
#endif
  if (!InUpdate && rb == cur_root && !xs->cursor_exists)
    CursorToggle(rb);

  return;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
dump_windows(window,top,left,rows,cols)
     Lisp_Object window;
     register int top,left,rows,cols;
{
  for (; !NIL(window); window = XWINDOW(window)->next)
    dump_window(window,top,left,rows,cols);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
dump_window(window,top,left,rows,cols)
     Lisp_Object window;
     register int top,left,rows,cols;
{
  register struct window *w = XWINDOW(window);
  struct Root_Block *rb = XROOT(w->root);
  XS_DEF; WS_DEF;
  struct line_header *l;
  register struct char_block *cb,*end;
  register int pixright = XFASTINT(w->pixleft) + XFASTINT(w->pixwidth);
  register int pixbot = XFASTINT(w->pixtop) + XFASTINT(w->pixheight);
  register startx,starty,endx,endy;

  if (!NIL(w->vchild))
    {
      dump_windows(w->vchild,top,left,rows,cols);
      return;
    }
  if (!NIL(w->hchild))
    {
      dump_windows(w->hchild,top,left,rows,cols);
      return;
    }
  if (NIL(w->buffer))
    abort();			/* No buffer...we're screwed */

  if (distinct_minibuffer && window == rb->minibuf_window && rb != mini_root)
    return;

  /*
   * Find out if expose region intersects this window; if not, return.
   */
  if (left > pixright || (left + cols) < w->pixleft ||
      top > pixbot || (top + rows) < w->pixtop)
    return;

  /*
   * Calc top and left of expose region for this window.
   */
  startx = max(w->pixleft,left);
  endx = min(pixright, left + cols);
  starty = max(w->pixtop,top);
  endy = min(pixbot,top + rows);

  /*
   * Find starting line corresponding to this start ypos
   */
  l = XLINE(w->lines);
  while (l && (l->ypos + l->descent) < starty)
    l = l->next;

  while (l && (l->ypos - l->ascent) <= endy)
    {
      if (l->in_display == -1)
	{
	  /* Line is being layed-out in redisplay process, so give it
	   * the left edge of expose region
	   */
	  l->in_display = startx;
	}
      else if (l->ypos)		/* Does line have vertical position? */
	{
	  cb = l->body;
	  while (cb && cb != l->end && (cb->xpos + cb->width) < startx)
	    cb = cb->next;
	  if (cb != l->end)
	    {
	      end = cb;
	      while (end && end != l->end && (end->xpos) <= endx)
		end = end->next;

	      /*
	       * Note we will not clear to the end of line here.  If
	       * expose event doesn't cover end of line, no need to plot
	       * (clear) it; if it does, it is clear anyway.
	       */
	      PlotTextLine(w,l,cb,end,0); /* Replot the line */
	    }
	}
      l = l->next;
    }
  /*
   * Check modeline for window
   */
  if (window != rb->minibuf_window && !NIL(w->modeline))
    {
      l = XLINE(w->modeline);

      if (l)
	{
	  cb = l->body;
	  while (cb && cb != l->end && (cb->xpos + cb->width) < startx)
	    cb = cb->next;
	  if (cb != l->end)
	    {
	      end = cb;
	      while (end && end != l->end && (end->xpos) <= endx)
		end = end->next;
	      PlotTextLine(w,l,cb,end,0); /* Replot the mode line */
	    }
	}
    }
  return;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Substitutes for standard read routine.  Under X not interested in individual
 * bytes but rather individual packets.
 */

XTread_socket (sd, bufp, numchars)
     register int sd;
     register kbd_char_t *bufp;
     register int numchars;
{
#ifdef XDEBUG
  fprintf(stderr,"XTread_socket\n");
#endif

  return (internal_socket_read (bufp, numchars));
}

#define X_FIND_SCREEN(w) \
 x_find_screen((w))

#define QUEUE_EVENT(e) \
  x_queue_event(e) , *bufp++ = EPOCH_EVENT_CHAR , ++count , --numchars
  
/*
 * Interpreting incoming keycodes. Should have table modifiable as needed
 * from elisp.
 */
#ifdef sun
char
*stringFuncVal(keycode)
     KeySym keycode;
{
  switch (keycode)
    {
    case XK_L1: return("192");
    case XK_L2: return("193");
    case XK_L3: return("194");
    case XK_L4: return("195");
    case XK_L5: return("196");
    case XK_L6: return("197");
    case XK_L7: return("198");
    case XK_L8: return("199");
    case XK_L9: return("200");
    case XK_L10: return("201");
    case XK_R1: return("208");
    case XK_R2: return("209");
    case XK_R3: return("210");
    case XK_R4: return("211");
    case XK_R5: return("212");
    case XK_R6: return("213");
    case XK_R7: return("214");
    case XK_R8: return("215");
    case XK_R9: return("216");
    case XK_R10: return("217");
    case XK_R11: return("218");
    case XK_R12: return("219");
    case XK_R13: return("220");
    case XK_R14: return("221");
    case XK_R15: return("222");

    case XK_Break: return("223"); /* Sun3 "Alternate" key */

    case XK_F1: return("224");
    case XK_F2: return("225");
    case XK_F3: return("226");
    case XK_F4: return("227");
    case XK_F5: return("228");
    case XK_F6: return("229");
    case XK_F7: return("230");
    case XK_F8: return("231");
    case XK_F9: return("232");
    default: return("-1");
    }
}
#else
char *stringFuncVal(keycode)
	KeySym keycode;
{
  switch (keycode)
    {
    case XK_F1: return("11");
    case XK_F2: return("12");
    case XK_F3: return("13");
    case XK_F4: return("14");
    case XK_F5: return("15");
    case XK_F6: return("17");
    case XK_F7: return("18");
    case XK_F8: return("19");
    case XK_F9: return("20");
    case XK_F10: return("21");
    case XK_F11: return("23");
    case XK_F12: return("24");
    case XK_F13: return("25");
    case XK_F14: return("26");
    case XK_F15: return("28");
    case XK_Help: return("28");
    case XK_F16: return("29");
    case XK_Menu: return("29");
    case XK_F17: return("31");
    case XK_F18: return("32");
    case XK_F19: return("33");
    case XK_F20: return("34");
	
    case XK_Find : return("1");
    case XK_Insert: return("2");
    case XK_Delete: return("3");
    case XK_Select: return("4");
    case XK_Prior: return("5");
    case XK_Next: return("6");
    default: return("-1");
    }
}
#endif /* not sun */
	
internal_socket_read(bufp, numchars)
	register kbd_char_t *bufp;
	register int numchars;
{
  /* Number of keyboard chars we have produced so far.  */
  int count = 0;
  int nbytes;
  char mapping_buf[MAPPINGBUFLEN];
  BLOCK_INPUT_DECLARE ();
  XEvent event;
  KeySym keysym;
  SIGMASKTYPE oldmask;
  struct Root_Block *rb,*x_find_screen();
  struct X_Screen *xs;
  struct W_Screen *ws;
  struct X_font *font;
  Display *xdisp = XXSCREEN(root->x11)->display;
  extern int meta_prefix_char;

  extern Atom selection_selection;
  extern Window selection_screen;
  extern char selection_available;
  extern Lisp_Object selection_value;
  extern Lisp_Object raw_get_property();

  BLOCK_INPUT ();  

#ifdef BSD
#ifndef BSD4_1
  oldmask = sigblock (sigmask (SIGALRM));
#endif
#endif  
#ifdef FIOSNBIO
  /* If available, Xlib uses FIOSNBIO to make the socket
   * non-blocking, and then looks for EWOULDBLOCK.
   * If O_NDELAY is set, FIOSNBIO is ignored, and instead of
   *signalling EWOULDBLOCK, a read returns
   *  0, which Xlib interprets as equivalent to EPIPE.
   */
  fcntl (fileno (stdin), F_SETFL, 0);
#endif
#ifndef HAVE_SELECT
  if (! (fcntl (fileno (stdin), F_GETFL, 0) & O_NDELAY))
    {
      extern int read_alarm_should_throw;
      read_alarm_should_throw = 1;
      XPeekEvent (xdisp,&event);
      read_alarm_should_throw = 0;
    }
#endif
  while (XPending (xdisp))
    {
      XNextEvent (xdisp,&event);

      switch (event.type)
	{
	case MappingNotify:
	  XRefreshKeyboardMapping(&event.xmapping);
	  break;

	case MapNotify:
	  rb = X_FIND_SCREEN(event.xmap.window);
	  if (rb) XXSCREEN(rb->x11)->mapped = 1;
	  QUEUE_EVENT(&event);
	  break;

	case UnmapNotify:
	  rb = X_FIND_SCREEN(event.xmap.window);
	  if (rb) XXSCREEN(rb->x11)->mapped = 0;
	  QUEUE_EVENT(&event);
	  break;
			
	case ConfigureNotify:
	  rb = X_FIND_SCREEN(event.xconfigure.window);
	  if (!rb) break;
	  xs = XXSCREEN(rb->x11);
	  ws = XWSCREEN(rb->win);
	  QUEUE_EVENT(&event);

	  /* If no net size change, and this is not due to a
	   * change-screen-size or font change request, blow it off and
	   * process the corresponding expose events.  This seems to happen
	   * for TVTWM on changing the virtual root window panner
	   */

	  if ((xs->pixwidth == event.xconfigure.width) &&
	      (xs->pixheight == event.xconfigure.height) &&
	      !ws->size_change) break;
	  
	  xs->configure_pending = 1;

	  /* Actual X11 dimensions of screen */
	  xs->pixwidth = event.xconfigure.width;
	  xs->pixheight = event.xconfigure.height;
	  /* Fudge abstract size of screen */
	  ws->pixw = 0; ws->pixh = 0;

	  screen_changed++;
	  break;
		
	case Expose:
	  rb = X_FIND_SCREEN(event.xexpose.window);
	  if (!rb) break;
	  xs = XXSCREEN(rb->x11);
	  ws = XWSCREEN(rb->win);
	  
	  if (xs->configure_pending)
	    {
	      int width, height;
	      if (event.xexpose.count) break;

	      width = xs->pixwidth - 2 * ws->in_border;
	      height = xs->pixheight - 2 * ws->in_border;

	      change_screen_size (height, width, 0,rb);
#if 0
	      Cdumprectangle(event.xexpose.y-ws->in_border,
			     event.xexpose.x-ws->in_border,
			     event.xexpose.height,
			     event.xexpose.width,rb);
#endif	      
	      xs->configure_pending = 0;
	      break;
	    }
	  if (ws->size_change) break;

	  Cdumprectangle (event.xexpose.y - ws->in_border,
                          event.xexpose.x - ws->in_border,
                          event.xexpose.height,
                          event.xexpose.width,rb);

#if 0
	  /* Adjust screen's bounding box of expose events accordingly */
	  if (xs->expose_pending)
	    {
	      xs->extop = min(xs->extop,event.xexpose.y);
	      xs->exleft = min(xs->exleft,event.xexpose.x);
	      xs->exbot = max(xs->exbot,
			      event.xexpose.y + event.xexpose.height);
	      xs->exright = max(xs->exright,
				event.xexpose.x + event.xexpose.width);
	    }
	  else
	    {
	      xs->extop = event.xexpose.y;
	      xs->exleft = event.xexpose.x;
	      xs->exbot = xs->extop + event.xexpose.height;
	      xs->exright = xs->exleft + event.xexpose.width;
	      xs->expose_pending = 1;
	    }
	  if (!event.xexpose.count)
	    {
	      Cdumprectangle(xs->extop,
			     xs->exleft,
			     xs->exbot - xs->extop,
			     xs->exright - xs->exleft,rb);
	      xs->extop = xs->exleft = xs->exbot = xs->exright = 0;
	      xs->expose_pending = 0;
	    }
#endif	  
	  break;

	case GraphicsExpose:
	  rb = X_FIND_SCREEN(event.xexpose.window);
	  if (!rb) break;
	  xs = XXSCREEN(rb->x11);
	  ws = XWSCREEN(rb->win);
	  Cdumprectangle (event.xgraphicsexpose.y - ws->in_border,
			  event.xgraphicsexpose.x - ws->in_border,
			  event.xgraphicsexpose.height,
			  event.xgraphicsexpose.width,rb);
	  break;

	case NoExpose:
	  break;

	  /* Still not quite right. Here's the current scheme :
           * xcrossing.focus -> Is this the window with focus or an inferior?
	   * X_focus : 0 for no-focus, 1 for pointer focus,
	   *           2 for explicit focus.
	   * Rules : Explicit focus is lost only through FocusOut, and set
	   * through FocusIn. Enter/Leave can set pointer focus iff
	   * no explicit focus. Enter/Leave are meaningless unless the
	   * focus field is set.
	   */
	case EnterNotify :
	case LeaveNotify :
	  if (! event.xcrossing.focus || X_focus == 2) break;
	case FocusIn :
	case FocusOut :
	  if ((event.type == FocusOut || event.type == FocusIn)
	      && event.xfocus.mode != NotifyNormal)
	    break;
	  X_focus = (event.type == FocusIn ? 2 :
	    (event.type == EnterNotify ? 1 : 0));
	  QUEUE_EVENT(&event);

	  if (cur_Xscreen->cursor_exists)
	    {
#if 0	      
	      fprintf(stderr,"Focus\n");
#endif	      
	      ClearCursor(cur_root);
	      CursorToggle(cur_root);
#if 0	      
	      fprintf(stderr,"End Focus\n");
#endif	      
	    }
	  break;

	case PropertyNotify :
	  QUEUE_EVENT(&event); break;
	case SelectionClear :
	  QUEUE_EVENT(&event); break;
	case SelectionRequest :
	  x_selection_request(&event); break;
	case SelectionNotify :
	  if ((event.xselection.requestor == selection_screen) &&
	      (event.xselection.selection == selection_selection) &&
	      !selection_available)
	    {
	      /* Property change for convert selection request.
	       * Get the value from the appropriate property, and
	       * set a flag so that the convert-selection primitive
	       * is aware of it.
	       */
	      selection_value = raw_get_property(event.xselection.display,
						 event.xselection.requestor,
						 event.xselection.property);
	      selection_available++;
	      break;
	    }
	  break;
	case MotionNotify :
	  /* discard stacked up motion events */
	  while (XCheckTypedWindowEvent(XD_display,event.xany.window,
					MotionNotify,&event))
	    ;
	  /* Q the last one only */
	  QUEUE_EVENT(&event);
	  break;

	  /* currently the only client message expected is internal, used
           * to trip the SIGIO handler if there are waiting unprocessed
	   * X Events. This is indicated by a message type of XA_current.
	   */
	case ClientMessage :
	  if (event.xclient.message_type != XA_current)
	    QUEUE_EVENT(&event);
	  break;	  
	  
	case KeyPress:
	  nbytes = XLookupString (&event.xkey,
				  mapping_buf, MAPPINGBUFLEN, &keysym,
				  &status);
	  /* Someday this will be unnecessary as we will
	   * be able to use XRebindKeysym so XLookupString
	   * will have already given us the string we want.
	   */
	  if (nbytes == 0)
	    {
	      extern Lisp_Object Vepoch_function_key_mapping;
	      extern char *stringFuncVal();

	      if (!EQ(Qnil,Vepoch_function_key_mapping) &&
			  (IsFunctionKey(keysym)
            || (IsMiscFunctionKey(keysym) && (keysym != XK_Mode_switch))))
  		
		{
		  strcpy(mapping_buf,"\033[");
		  strcat(mapping_buf,stringFuncVal(keysym));
#ifdef sun
		  strcat(mapping_buf,"z");
#else
 		  strcat(mapping_buf,"~");
#endif /* sun */
 		  nbytes = strlen(mapping_buf);
		}
	      else
		{
		  nbytes = 1;
		  mapping_buf[1] = 0; /* Effect of strcpy() */
		  switch (keysym)
		    {
		    case XK_Left:  *mapping_buf = 2; break;
		    case XK_Right: *mapping_buf = 6; break;
		    case XK_Up:    *mapping_buf = 020; break;
		    case XK_Down:  *mapping_buf = 016; break;
		    default: nbytes = 0; break;
		    }
		}
	    }
	  if (nbytes)
	    {
              if ((nbytes == 1) && (event.xkey.state & Mod1Mask)) 
#ifdef EIGHTBIT_KEYBOARD
                {
                  /* Character typed with META-shift key held down is split
                     into META-prefix + ASCII-character. */
                  mapping_buf[1] = mapping_buf[0] & 0x7F;
                  mapping_buf[0] = meta_prefix_char;
                  nbytes = 2;
                }
              else if ((nbytes == 1) && (event.xkey.state & Mod3Mask)) 
                {
                  KeySym ks;
                  
                  if ((ks = XLookupKeysym
                       (&event.xkey, (event.xkey.state & ShiftMask) ? 3 : 2))
                      != NoSymbol) 
                    {
                      *mapping_buf = ks & 0xff;
                    }
                }
#else /* not EIGHTBIT_KEYBOARD */
              {
                *mapping_buf |= METABIT;
              }
#endif /* not EIGHTBIT_KEYBOARD */
	      if (numchars > nbytes)
		{
		  int i;
                  
		  count += nbytes;
		  numchars -= nbytes;
		  
		  for (i = 0; i < nbytes; ++i)
		    *bufp++ = mapping_buf[i];
		}
	    }
	  break;

	case ButtonPress:
	case ButtonRelease:
	  if (!EQ(Qnil,Vx_mouse_events))
	    {
	      QUEUE_EVENT(&event);
	      break;
	    }
	  *bufp++ = (char) 'X' & 037;
	  ++count;
	  --numchars;
	  *bufp++ = (char) '@' & 037;
	  ++count;
	  --numchars;
	  if (XXm_queue_num == XMOUSEBUFSIZE)
	    break;
	  memcpy((char *) &(XXm_queue[XXm_queue_in]),
		 (char *) &(event.xbutton), sizeof(XButtonEvent));
	  XXm_queue_num++;
	  XXm_queue_in = (XXm_queue_in + 1) % XMOUSEBUFSIZE;
	  break;	  
	}
    }

#ifdef BSD
#ifndef BSD4_1
  sigsetmask (oldmask);
#endif
#endif  
  UNBLOCK_INPUT ();
  return count;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Exit gracefully from gnuemacs, doing an autosave and giving a status.
 */
#if defined(__ultrix) || defined(_AIX)
void
#endif
XExitGracefully ()
{
  XCleanUp();
  exit (70);
}

XIgnoreError ()
{
  return 0;
}

/* Here's the deal: under most systems, if IO errors are ignored, Epoch can
 * spin. However, under HPUX, this apparently doesn't happen, and normal
 * operations seems to cause errors (i.e., the error handler is called during
 * most IO operations, even though no errors have apparently occurred (!)).
 */
#ifdef HPUX
#define EPOCH_IOERRORHANDLER		XIgnoreError
#else
#define EPOCH_IOERRORHANDLER		XExitGracefully
#endif

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
Cxfixscreen (rb)
     struct Root_Block *rb;
{
  XS_DEF;
  BLOCK_INPUT_DECLARE ();

  /* Yes, this is really what I mean -- Check to see if we've
   * lost our connection */
  BLOCK_INPUT ();
  XSetErrorHandler(0);
  XSetIOErrorHandler(0);
  XNoOp (xs->display);
  XFlush (xs->display);
  XSetErrorHandler(handler);
  XSetIOErrorHandler(EPOCH_IOERRORHANDLER);
  if (!InUpdate && !xs->cursor_exists)
    CursorToggle (rb);
  UNBLOCK_INPUT ();

}
xfixscreen ()
{ return Cxfixscreen(cur_root); }
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
x_term_init ()
{
  extern char *getenv ();
  extern XTinterrupt_signal ();
#ifndef NeXT  
  extern char *malloc ();
#endif  
  extern Lisp_Object Vxterm, Vxterm1;
  extern int XIgnoreError();
  int  ix;
	
  baud_rate = 9600;
  meta_key = 1;
  visible_bell = 1;
  inverse_video = 0;
	
  fix_screen_hook = xfixscreen;
  clear_screen_hook = XTclear_screen;
  clear_window_end_hook = XTclear_window_end;
  shift_region_hook = XTshift_region;

  update_line_hook = PlotTextLine;
  insert_chars_hook = InsertChar;
  text_width_hook = TextWidth;  

  ring_bell_hook = XTfeep;
  reset_terminal_modes_hook = XTreset_terminal_modes;
  set_terminal_modes_hook = XTset_terminal_modes;
  update_begin_hook = XTupdate_begin;
  update_end_hook = XTupdate_end;

  read_socket_hook = XTread_socket;
  move_cursor_hook = XTmove_cursor;

  handler = XIgnoreError;
  XSetErrorHandler (handler);
  XSetIOErrorHandler (handler);

  XXpid = getpid ();
  signal (SIGPIPE, XExitGracefully);

#ifndef CANNOT_DUMP
  if (initialized)
#endif				/* CANNOT_DUMP */
    Vxterm = Qt;

  Fset (intern ("window-system-version"), make_number (11));

  init_Xresource();
  x_init_display ();

  keyboard_init_hook = x_init_1;
}

/* Initialize for keyboard input using X.
   This is called by init_keyboard via keyboard_init_hook.  */

static void
x_init_1 ()
{
  Display *d = distinct_minibuffer ?
    XXSCREEN(mini_root->x11)->display :
      XXSCREEN(root->x11)->display; /* see below */
#ifdef F_SETOWN
  extern int old_fcntl_owner;
#endif

  dup2 (ConnectionNumber(d), 0);
#ifndef SYSV_STREAMS
  close (ConnectionNumber(d));
  ConnectionNumber(d) = 0;	/* Looks a little strange?
                                 * check the def of the macro;
                                 * it is a genuine lvalue
				 */
#endif  
  
#ifdef USG
#ifdef USG5_4
  /* In USG5.4 we want a new process group, but not a new session. */
  setpgid (0, 0);
#else
  setpgrp ();		/* No arguments but equivalent in this case */
#endif /* USG5_4 */
#else
  setpgrp (0,getpid());
#endif /* USG */
  
#ifdef F_SETOWN
  old_fcntl_owner = fcntl (0, F_GETOWN, 0);
#ifdef F_SETOWN_SOCK_NEG
  fcntl (0, F_SETOWN, -getpid ()); /* stdin is a socket here */
#else
  fcntl (0, F_SETOWN, getpid ());
#endif				/* F_SETOWN_SOCK_NEG */
#endif				/* F_SETOWN */

  /* Enable interrupt_input because otherwise we cannot asynchronously
    detect C-g sent as a keystroke event from the X server.  */
  Fset_input_mode (Qt, Qnil, Qnil);
}

XSetFlash ()
{
  ring_bell_hook = XTflash;
}

XSetFeep ()
{
  ring_bell_hook = XTfeep;
}

#endif /* HAVE_X_WINDOWS */

/*#include "xundebug.h"*/
