/* Functions for the X window system.
   Copyright (C) 1989, 1992, 1993 Free Software Foundation.

This file is part of GNU Emacs.

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 2, 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.  */

/* Substantially rewritten for Lucid GNU Emacs.  */

#include "config.h"

#include <stdio.h>
#include <signal.h>

#include <X11/IntrinsicP.h>	/* CoreP.h needs this */
#include <X11/CoreP.h>		/* foul, but we need this to use our own
				   window inside a widget instead of one 
				   that Xt creates... */
#include <X11/StringDefs.h>
#include <X11/Xresource.h>
#include <X11/Shell.h>

#include <X11/Xaw/Paned.h>
#include <X11/Xaw/Label.h>

#include <X11/Xos.h>

#include "ScreenWidgetP.h"

#ifdef LINE_INFO_WIDGET
# include "LineInfoWidget.h"
# include "LineInfoWidgetP.h"
#endif

#include "EmacsShell.h"
#include "EmacsShellP.h"

#if (XtSpecificationRelease >= 5)	/* Do the EDITRES protocol */
#define HACK_EDITRES
extern void _XEditResCheckMessages();
#endif /* R5 */

#ifdef USE_SOUND
# include <netdb.h>
#endif

#include "lisp.h"
#include "xterm.h"
#include "window.h"
#include "buffer.h"
#include "extents.h"
#include "screen.h"
#include "events.h"
#include "faces.h"

#ifdef HAVE_X_WINDOWS

#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))
#define COLOR_SCREEN_P(d) (XCellsOfScreen (DefaultScreenOfDisplay (d)) > 2)

Lisp_Object Vx_gc_pointer_shape;

/* If non-nil, use vertical bar cursor. */
Lisp_Object Vbar_cursor;

/* Where bitmaps are; initialized from resource database */
Lisp_Object Vx_bitmap_file_path;

/* The application class of Emacs. */
Lisp_Object Vx_emacs_application_class;

/* The screen on which we have placed a WM_COMMAND property.  Only one. */
Lisp_Object WM_COMMAND_screen;

Atom Xatom_WM_TAKE_FOCUS, Xatom_WM_SAVE_YOURSELF, Xatom_WM_DELETE_WINDOW,
 Xatom_WM_PROTOCOLS;

Lisp_Object Qundefined_color;
Lisp_Object Qx_resource_name;

extern Lisp_Object Vwindow_system_version;

/* Default parameters to use when creating screens.  */
Lisp_Object Vx_screen_defaults;

/* Do we accept events send by other clients? */
int x_allow_sendevents;

extern Lisp_Object Qmouse_enter_screen_hook, Qmouse_leave_screen_hook;
extern Lisp_Object Qmap_screen_hook, Qunmap_screen_hook;
extern Lisp_Object Qcreate_screen_hook;


/* Return the Emacs screen-object corresponding to an X window */
struct screen *
x_window_to_screen (wdesc)
     Window wdesc;
{
  Lisp_Object tail, screen;
  struct screen *s;

  for (tail = Vscreen_list; CONSP (tail); tail = XCONS (tail)->cdr)
    {
      screen = XCONS (tail)->car;
      if (!SCREENP (screen))
        continue;
      s = XSCREEN (screen);
      if (SCREEN_IS_X (s) && XtWindow (s->display.x->edit_widget) == wdesc)
        return s;
    }
  return 0;
}

/* Like x_window_to_screen but also compares the window with the widget's
   widows */
struct screen *
x_any_window_to_screen (wdesc)
     Window wdesc;
{
  Lisp_Object tail, screen;
  struct screen *s;
  struct x_display *x;

  for (tail = Vscreen_list; CONSP (tail); tail = XCONS (tail)->cdr)
    {
      screen = XCONS (tail)->car;
      if (!SCREENP (screen))
        continue;
      s = XSCREEN (screen);
      if (!SCREEN_IS_X (s))
	continue;
      x = s->display.x;
      /* This screen matches if the window is any of its widgets. */
      if (wdesc == XtWindow (x->widget) ||
	  wdesc == XtWindow (x->column_widget) ||
	  wdesc == XtWindow (x->edit_widget))
	return s;
      /* Match if the window is this screen's menubar. */
      if (x->menubar_widget &&
	  wdesc == XtWindow (x->menubar_widget))
	return s;
      /* Do *not* match if the window is this screen's psheet. */
    }
  return 0;
}

Lisp_Object text_part_sym;
Lisp_Object modeline_part_sym;


/* Connect the screen-parameter names (symbols) to the corresponding
   X Resource Manager names.  The name of a parameter, as a Lisp symbol,
   has an `x-resource-name' property which is a Lisp_String. */

static void
init_x_parm_symbols ()
{
  register Lisp_Object propname;
  Qx_resource_name = propname = intern ("x-resource-name");

#define def(sym, rsrc) \
  Fput (intern (sym), propname, build_string (rsrc))
#define defi(sym,rsrc) \
    def (sym, rsrc); Fput (intern (sym), Qintegerp, Qt)

  def ("cursor-color", XtNcursorColor);
  def ("border-color", XtNborderColor);
  defi("border-width", XtNborderWidth);
  defi("internal-border-width", XtNinternalBorderWidth);
  defi("width", XtNwidth);
  defi("height", XtNheight);
  defi("x", XtNx);
  defi("y", XtNy);
/*  def ("icon-type", "iconType"); */
#ifdef LINE_INFO_COLUMN
  defi("line-info-column-width", XtNlineInfoColumnWidth);
  def ("line-info-column-foreground-color", XtNlineInfoColumnForeground);
  def ("line-info-column-background-color", XtNlineInfoColumnBackground);
#endif
/*  def ("vertical-scroll-bar", XtNverticalScrollBar); */
/*  def ("horizontal-scroll-bar", XtNhorizontalScrollBar); */
  def ("minibuffer", XtNminibuffer);
  def ("unsplittable", XtNunsplittable);
  defi("inter-line-space", XtNinterline);
/*  def ("bar-cursor", XtNbarCursor); */
/*  def ("visual-bell", XtNvisualBell); */
/*  defi("bell-volume", XtNbellVolume); */
  
#undef def
}


/* Insert a description of internally-recorded parameters of screen X
   into the parameter alist *ALISTPTR that is to be given to the user.
   Only parameters that are specific to the X window system
   and whose values are not correctly recorded in the screen's
   param_alist need to be considered here.  */

extern Lisp_Object Vinvocation_name;

static void
color_to_string (w, pixel, buf)
     Widget w;
     unsigned long pixel;
     char *buf;
{
  XColor color;
  color.pixel = pixel;
  BLOCK_INPUT;
  XQueryColor (XtDisplay (w), w->core.colormap, &color);
  UNBLOCK_INPUT;
  sprintf (buf, "#%04x%04x%04x", color.red, color.green, color.blue);
}


extern void store_in_alist (Lisp_Object *, char *, Lisp_Object);

void
x_report_screen_params (s, alistptr)
     struct screen *s;
     Lisp_Object *alistptr;
{
  TopLevelShellWidget shell = (TopLevelShellWidget)s->display.x->widget;
  EmacsScreenWidget w = (EmacsScreenWidget)s->display.x->edit_widget;
  char buf [255];

#define store_int(sym, slot) \
  store_in_alist (alistptr, sym, make_number (slot))
#define store_str(sym, slot) \
  store_in_alist (alistptr, sym, build_string (slot))
#define store_bool(sym, slot) \
  store_in_alist (alistptr, sym, (slot) ? Qt : Qnil)
#define store_color(sym, slot) \
  color_to_string ((Widget) w, slot, buf); \
  store_in_alist (alistptr, sym, build_string (buf))
#define store_curs(sym, slot) /* #### don't have the strings any more... */

  store_color ("cursor-color", w->emacs_screen.cursor_color);
  store_color ("border-color", w->core.border_pixel);
  store_int ("left", shell->core.x);
  store_int ("top", shell->core.y);
  store_int ("border-width", w->core.border_width);
  store_int ("internal-border-width", w->emacs_screen.internal_border_width);
  store_int ("inter-line-space", w->emacs_screen.interline);
  store_bool ("minibuffer", w->emacs_screen.minibuffer);
  store_bool ("unsplittable", w->emacs_screen.minibuffer);
/*  store_bool ("visual-bell", w->emacs_screen.visual_bell); */
/*  store_bool ("bar-cursor",  w->emacs_screen.bar_cursor); */
  sprintf (buf, "0x%x", XtWindow (w));
  store_str ("window-id", buf);
}


/* Functions called only from `x_set_screen_param' to set
** individual parameters. */

void 
x_set_title_from_char (struct screen* s, char* name)
{
  char *old_name = 0;
  Arg av [1];
  BLOCK_INPUT;
  XtSetArg (av[0], XtNtitle, &old_name);
  XtGetValues (s->display.x->widget, av, 1);
  if (!old_name || strcmp (name, old_name))
    {
      XtSetArg (av[0], XtNtitle, name);
      XtSetValues (s->display.x->widget, av, 1);
    }
  UNBLOCK_INPUT;
}

void
x_set_icon_name_from_char (struct screen* s, char* name)
{
  char *old_name = 0;
  Arg av [1];
  BLOCK_INPUT;
  XtSetArg (av[0], XtNiconName, &old_name);
  XtGetValues (s->display.x->widget, av, 1);
  if (!old_name || strcmp (name, old_name))
    {
      XtSetArg (av[0], XtNiconName, name);
      XtSetValues (s->display.x->widget, av, 1);
    }
  UNBLOCK_INPUT;
}

/* Report to X that a screen parameter of screen S is being set or changed.
   If the parameter is not specially recognized, do nothing.
 */

extern void store_screen_param (struct screen *s, Lisp_Object, Lisp_Object);

void
x_set_screen_values (s, alist)
     struct screen *s;
     Lisp_Object alist;
{
  int x, y;
  Dimension width = 0, height = 0;
  Bool size_specified_p = False;
  Bool x_specified_p = False;
  Bool y_specified_p = False;
  Lisp_Object tail;
  Widget w = s->display.x->edit_widget;
  
  for (tail = alist; !EQ (tail, Qnil); tail = Fcdr (tail))
    {
      Lisp_Object elt = Fcar (tail);
      Lisp_Object prop = Fcar (elt);
      Lisp_Object val = Fcdr (elt);
      
      if (STRINGP (prop))
	{
	  if (XSTRING (prop)->size == 0)
	    continue;

	  BLOCK_INPUT;
	  if (STRINGP (val))
	    XtVaSetValues (w, XtVaTypedArg, XSTRING (prop)->data, XtRString,
			   XSTRING (val)->data, XSTRING (val)->size + 1,
			   0);
	  else
	    XtVaSetValues (w, XtVaTypedArg,
			   XSTRING (prop)->data, XtRInt, XINT (val),
			   sizeof (int),
			   0);
	  UNBLOCK_INPUT;
	}
      else
	{
	  Lisp_Object str = Fget (prop, Qx_resource_name);
	  int int_p = !NILP (Fget (prop, Qintegerp));
	  if (NILP (prop) || NILP (str))
	    continue;
	  CHECK_STRING (str, 0);

	  /* Kludge the width/height so that we interpret them in characters
	     instead of pixels.  Yuck yuck yuck. */
	  if (!strcmp ((char *) XSTRING (str)->data, "width"))
	    {
	      CHECK_FIXNUM (val, 0);
	      width = XINT (val);
	      size_specified_p = True;
	      continue;
	    }
	  if (!strcmp ((char *) XSTRING (str)->data, "height"))
	    {
	      CHECK_FIXNUM (val, 0);
	      height = XINT (val);
	      size_specified_p = True;
	      continue;
	    }
	  /* Further kludge the x/y to call set-screen-position instead. */
#if 0
	  /* this doesn't work because the window isn't around yet,.
	     I guess we really need to cons up a geometry spec. */
	  if (!strcmp ((char *) XSTRING (str)->data, "x"))
	    {
	      CHECK_FIXNUM (val, 0);
	      x = XINT (val);
	      x_specified_p = True;
	      continue;
	    }
	  if (!strcmp ((char *) XSTRING (str)->data, "y"))
	    {
	      CHECK_FIXNUM (val, 0);
	      y = XINT (val);
	      y_specified_p = True;
	      continue;
	    }
#endif

	  BLOCK_INPUT;
	  if (int_p)
	    {
	      CHECK_FIXNUM (val, 0);
	      XtVaSetValues (w, (char *) XSTRING (str)->data, XINT (val),
			     0);
	    }
	  else if (EQ (val, Qt))
	    XtVaSetValues (w, (char *) XSTRING (str)->data, /* XtN... */
			   True,
			   0);
	  else if (EQ (val, Qnil))
	    XtVaSetValues (w, (char *) XSTRING (str)->data, /* XtN... */
			   False,
			   0);
	  else
	    {
	      CHECK_STRING (val, 0);
	      XtVaSetValues (w, XtVaTypedArg,
			     (char *) XSTRING (str)->data, /* XtN... */
			     XtRString,
			     XSTRING (val)->data, XSTRING (val)->size + 1,
			     0);
	    }
	  UNBLOCK_INPUT;
	}
    }

  /* Kludge kludge kludge. */
  if (size_specified_p)
    {
      Lisp_Object screen;
      XSET (screen, Lisp_Screen, s);
      if (width == 0) width = SCREEN_WIDTH (s);
      if (height == 0) height = SCREEN_HEIGHT (s);
      Fset_screen_size (screen, make_number (width), make_number (height),
			Qnil);
    }
  /* Kludge kludge kludge kludge. */
  if (x_specified_p || y_specified_p)
    {
      Lisp_Object screen;
      XSET (screen, Lisp_Screen, s);
      if (!x_specified_p) x = s->display.x->widget->core.x;
      if (!y_specified_p) y = s->display.x->widget->core.y;
      Fset_screen_position (screen, make_number (x), make_number (y));
    }
}

void
fix_pane_constraints (w)
  Widget w;
{
  BLOCK_INPUT;
  XtVaSetValues (w, XtNshowGrip, 0, XtNresizeToPreferred, 1,
		 XtNallowResize, 1, 0);
  UNBLOCK_INPUT;
}

#ifdef ENERGIZE

/* #### remove this when we do not use uilib anymore */
void sheet_callback () {}

extern int *get_psheets_for_buffer ();

void
recompute_screen_menubar (screen)
     struct screen *screen;
{
  /* #### This shouldn't be necessary any more */
}


/* This function is invoked by each menu item which Energize should handle.
   Defined in xterm.c.
 */
extern void client_menu_item_cb ();

void
make_psheets_desired (s, buffer)
     struct screen* s;
     Lisp_Object buffer;
{
  struct x_display *x = s->display.x;
  int count;
  int *psheets;

  if (NILP (buffer) || !(psheets = get_psheets_for_buffer (buffer, &count)))
    {
      x->desired_psheets = 0;
      x->desired_psheet_count = 0;
      x->desired_psheet_buffer = Qnil;
    }
  else
    {
      /* Do not show the debugger panel in this function.  The
       * debugger panel should never be listed in the visible psheets. */
      extern int debuggerpanel_sheet;
      
      if (count == 1 && psheets [0] == debuggerpanel_sheet)
	return;

      x->desired_psheets = psheets;
      x->desired_psheet_count = count;
      x->desired_psheet_buffer = buffer;
    }
}

Lisp_Object
desired_psheet_buffer (struct screen* s)
{
  return s->display.x->desired_psheet_buffer;
}

/* This function is invoked when the user clicks on the "sheet" button.
 */
DEFUN ("energize-toggle-psheet", Fenergize_toggle_psheet,
       Senergize_toggle_psheet, 0, 0, "",
       "")
     ()
{
  struct screen *screen = selected_screen;
  Lisp_Object buffer = Fwindow_buffer (Fselected_window ());
  if (EQ (buffer, desired_psheet_buffer (screen)))
    make_psheets_desired (screen, Qnil);
  else
    make_psheets_desired (screen, buffer);
  return Qnil;
}


void energize_show_menubar_of_buffer ();

/* This is called when a buffer becomes visible in some window.

   Show the menubar associated with this buffer, and show the psheets as
   well if this buffer is the last buffer whose psheets were visible in
   this screen.
 */
void energize_buffer_shown_hook (window)
     struct window *window;
{
  struct screen* screen = XSCREEN (window->screen);
  Lisp_Object buffer = window->buffer;
  Lisp_Object pbuf;

  if (! SCREEN_IS_X (screen)) return;
  pbuf = desired_psheet_buffer (screen);

  if (!MINI_WINDOW_P (window))
    energize_show_menubar_of_buffer (window->screen, buffer,
				     (EQ (buffer, pbuf) ? Qt : Qnil));
}


static int
find_buffer_in_different_window (window, buffer, not_in)
     struct window* window;
     Lisp_Object buffer;
     struct window* not_in;
{
  Lisp_Object child;
  if (!NILP (window->buffer))
    {
      /* a leaf window */
      return window->buffer == buffer && window != not_in;
    }
  else
    {
      /* a non leaf window, visit either the hchild or the vchild */
      for (child = !NILP (window->vchild) ? window->vchild : window->hchild;
	   !NILP (child);
	   child = XWINDOW (child)->next)
	{
	  if (find_buffer_in_different_window (XWINDOW (child), buffer,
					       not_in))
	    return 1;
	}
      return 0;
    }
}

/* returns 1 if the buffer is only visible in window on screen s */
static int
buffer_only_visible_in_this_window_p (buffer, s, window)
     Lisp_Object buffer;
     struct screen* s;
     struct window* window;
{
  return !find_buffer_in_different_window (XWINDOW (s->root_window), buffer,
					   window);
}

/* This is called just before a buffer which is visible becomes invisible,
   either because some other buffer is about to be made visible in its window,
   or because that window is being deleted.

   If this buffer's psheets are visible, hide them.
 */
void energize_buffer_hidden_hook (window)
     struct window *window;
{
  struct screen *s;
  s = XSCREEN (window->screen);

  if (! SCREEN_IS_X (s)) return;

  /* hides the p_sheet if we are changing the buffer of the
   * selected window of the screen and the p_sheet where displayed */
  if (EQ (window->buffer, desired_psheet_buffer (s))
      && buffer_only_visible_in_this_window_p (window->buffer, s, window))
    make_psheets_desired (s, Qnil);
}


/* This is called just before the selected window is no longer the selected
   window because some other window is being selected.  The given window is
   not being deleted, it is merely no longer the selected one.

   This doesn't do anything right now.
 */
void energize_window_deselected_hook (window)
     struct window *window;
{
}


/* This is called just after a window has been selected.

   Show the menubar associated with this buffer; leave the psheets as
   they are.
 */
void energize_window_selected_hook (window)
     struct window *window;
{
  struct screen* screen = XSCREEN (window->screen);
  Lisp_Object buffer = window->buffer;

  if (SCREEN_IS_X (screen) && !MINI_WINDOW_P (window))
    energize_show_menubar_of_buffer (window->screen, buffer, Qnil);
}



int current_debuggerpanel_exposed_p;
int desired_debuggerpanel_exposed_p;
int debuggerpanel_sheet;

void
energize_show_menubar_of_buffer (screen, buffer, psheets_too)
     Lisp_Object screen, buffer, psheets_too;
{
  struct screen* s;
  struct x_display *x;
  
  if (NILP (screen))
    s = selected_screen;
  else {
    CHECK_SCREEN (screen, 0);
    s = XSCREEN (screen);
  }

  if (! SCREEN_IS_X (s)) error ("not an X screen");
  x = s->display.x;

  if (! NILP (psheets_too))
    {
      Lisp_Object buffer;
      XSET (buffer, Lisp_Buffer, current_buffer);
      make_psheets_desired (s, buffer);
    }
}


#endif /* ENERGIZE */

/* The one and only application context associated with the connection
** to the one and only X display that Emacs uses. */
XtAppContext Xt_app_con;

/* The one and only application shell.  Emacs screens are popup shells of this
** application. */
Widget Xt_app_shell;

extern Lisp_Object Vscreen_title_format, Vscreen_icon_title_format;
extern Lisp_Object Vscreen_list;

static void
maybe_set_screen_title_format (shell)
     Widget shell;
{
  BLOCK_INPUT;

  if (NILP (Vscreen_list) ||
      (NILP (Fcdr (Vscreen_list)) &&
       XSCREEN (Fcar (Vscreen_list))->display.nothing == 1))
    /* Only do this if this is the first X screen we're creating.
       If the *title resource (or -title option) was specified, then
       set screen-title-format to its value.
     */
    {
      /* No doubt there's a less stupid way to do this. */
      char *results [2];
      XtResource resources [2];
      results [0] = results [1] = 0;
      resources [0].resource_name = XtNtitle;
      resources [0].resource_class = XtCTitle;
      resources [0].resource_type = XtRString;
      resources [0].resource_size = sizeof (String);
      resources [0].resource_offset = 0;
      resources [0].default_type = XtRString;
      resources [0].default_addr = 0;
      resources [1].resource_name = XtNiconName;
      resources [1].resource_class = XtCIconName;
      resources [1].resource_type = XtRString;
      resources [1].resource_size = sizeof (String);
      resources [1].resource_offset = sizeof (char *);
      resources [1].default_type = XtRString;
      resources [1].default_addr = 0;
      XtGetSubresources (XtParent(shell), (XtPointer)results, shell->core.name,
			 shell->core.widget_class->core_class.class_name,
			 resources, XtNumber (resources), 0, 0);
      if (results[0])
	Vscreen_title_format = build_string (results[0]);
      if (results[1])
	Vscreen_icon_title_format = build_string (results[1]);
    }
  UNBLOCK_INPUT;
}


/* Creates the widgets for a screen.  Parms is an alist of
resources/values to use for the screen.  (ignored right now).
reslisp_window_id is a Lisp description of an X window or Xt widget to
resParse.  (ignored right now).  */

extern void maybe_store_wm_command (struct screen *);

static void hack_wm_protocols (Widget);

static void
x_create_widgets (s, parms, lisp_window_id)
     struct screen *s;
     Lisp_Object parms;
     Lisp_Object lisp_window_id;
{
  Widget shell_widget;
  Widget pane_widget;
  Widget screen_widget;
  char* name;
  Arg al [25];
  int ac = 0;

  BLOCK_INPUT;

  if (STRINGP (s->name))
     name = (char*)XSTRING (s->name)->data;
  else
    name = "emacs";
       
  ac = 0;
  XtSetArg (al[ac], XtNallowShellResize, 1); ac++;
  XtSetArg (al[ac], XtNinput, 1); ac++;
  shell_widget = XtCreatePopupShell (name, emacsShellWidgetClass, Xt_app_shell,
				     al, ac);
  maybe_set_screen_title_format (shell_widget);

  ac = 0;
  XtSetArg (al[ac], XtNborderWidth, 0); ac++;
  pane_widget = XtCreateWidget ("pane", panedWidgetClass, shell_widget, al,
				ac);

  /* mappedWhenManaged to false tells to the paned window to not map/unmap 
   * the emacs screen when changing menubar.  This reduces flickering a lot.
   */
  ac = 0;
  XtSetArg (al[ac], XtNmappedWhenManaged, 0); ac++;
  XtSetArg (al[ac], XtNshowGrip, 0); ac++;
  XtSetArg (al[ac], XtNallowResize, 1); ac++;
  XtSetArg (al[ac], XtNresizeToPreferred, 1); ac++;
  XtSetArg (al[ac], XtNemacsScreen, s); ac++;
  screen_widget = XtCreateWidget ("screen", emacsScreenWidgetClass,
				  pane_widget, al, ac);

  s->display.x->widget = shell_widget;
  s->display.x->column_widget = pane_widget;
  s->display.x->edit_widget = screen_widget;

  if (NILP (Vx_screen_defaults))
    x_set_screen_values (s, parms);
  else
    x_set_screen_values (s, nconc2 (Fcopy_sequence (parms),
				    Vx_screen_defaults));

  XtManageChild (screen_widget);
  XtManageChild (pane_widget);
  XtRealizeWidget (shell_widget);
  maybe_store_wm_command (s);
  hack_wm_protocols (shell_widget);

#ifdef HACK_EDITRES
  XtAddEventHandler (shell_widget, 0, True, _XEditResCheckMessages, 0);
#endif

  /* Do a stupid property change to force the server to generate a
     propertyNotify event so that the event_stream server timestamp will
     be initialized to something relevant to the time we created the window.
     */
  XChangeProperty (XtDisplay (screen_widget), XtWindow (screen_widget),
		   Xatom_WM_PROTOCOLS, XA_ATOM, 32, PropModeAppend,
		   (unsigned char*) NULL, 0);

  XtMapWidget (screen_widget);

  XtPopup (shell_widget, XtGrabNone);
  UNBLOCK_INPUT;

#if 0
 * Forget this for now
 *  if (NILP(lisp_window_id))
 *     window_id = 0;
 *  else
 *    { CHECK_STRING(lisp_window_id, 0);
 *      string = (char *) (XSTRING(lisp_window_id)->data);
 *      if (string[0] == '0' && (string[1] == 'x' || string[1] == 'X'))
 *         sscanf(string+2, "%xu", &window_id);
 *#ifdef ENERGIZE
 *      else if (string[0] == 'w'){
 *	sscanf (string+1, "%x", &parent_widget);
 *	if (parent_widget)
 *	  window_id = XtWindow (parent_widget);
 *      }
 *#endif
 *      else
 *         sscanf (string, "%lu", &window_id);
 *    }
#endif
}


/* If the WM_PROTOCOLS property does not already contain WM_TAKE_FOCUS
   and WM_DELETE_WINDOW, then add them.  (They may already be present
   because of the toolkit (Motif adds them, for example, but Xt doesn't.)
 */
static void hack_wm_protocols (Widget widget)
{
  Display *dpy = XtDisplay (widget);
  Window w = XtWindow (widget);
  int need_delete = 1;
  int need_focus = 1;
  BLOCK_INPUT;
  {
    Atom type, *atoms = 0;
    int format = 0;
    unsigned long nitems = 0;
    unsigned long bytes_after;

    if (Success == XGetWindowProperty (dpy, w, Xatom_WM_PROTOCOLS,
				       0, 100, False, XA_ATOM,
				       &type, &format, &nitems, &bytes_after,
				       (unsigned char **) &atoms)
	&& format == 32 && type == XA_ATOM)
      while (nitems > 0)
	{
	  nitems--;
	  if (atoms [nitems] == Xatom_WM_DELETE_WINDOW)   need_delete = 0;
	  else if (atoms [nitems] == Xatom_WM_TAKE_FOCUS) need_focus = 0;
	}
    if (atoms) XFree ((char *) atoms);
  }
  {
    Atom props [10];
    int count = 0;
    if (need_delete) props [count++] = Xatom_WM_DELETE_WINDOW;
    if (need_focus)  props [count++] = Xatom_WM_TAKE_FOCUS;
    if (count)
      XChangeProperty (dpy, w, Xatom_WM_PROTOCOLS, XA_ATOM, 32, PropModeAppend,
		       (unsigned char *) props, count);
  }
  UNBLOCK_INPUT;
}


static void
allocate_x_display_struct (s)
     struct screen* s;
{
  s->output_method = output_x_window;
  s->display.x = (struct x_display *)xmalloc (sizeof (struct x_display));

  /* zero out all slots. */
  memset (s->display.x, 0, sizeof (struct x_display));
}

Lisp_Object Vdefault_screen_name;

extern void x_format_screen_title (struct screen *);

extern void run_hooks_1_arg (Lisp_Object, Lisp_Object);

DEFUN ("x-create-screen", Fx_create_screen, Sx_create_screen,
       1, 2, 0,
  "Make a new X window, which is considered a \"screen\" in Emacs terms.\n\
Return an Emacs screen object representing the X window.\n\
ALIST is an alist of screen parameters.\n\
The value of `x-screen-defaults' is an additional alist\n\
of default parameters which apply when not overridden by ALIST.\n\
Optional second argument is the numerical ID of the X window to use for this\n\
screen (in order to run Emacs on a window created by some other program).\n\
Since this ID number is an unsigned long, you must pass it as a string.\n\
It may be a string of decimal numbers, or a string of hex numbers beginning\n\
with \"0x\".")
  (parms, lisp_window_id)
     Lisp_Object parms, lisp_window_id;
{
  struct screen *s;
  Lisp_Object screen = Qnil;
  Lisp_Object name = Qnil;
  struct gcpro gcpro1;
  struct gcpro gcpro2;
  GCPRO2 (screen, name);
  
  if (x_current_display == 0)
    error ("X windows are not in use or not initialized");
  
  s = make_screen (1);
  
  allocate_x_display_struct (s);
  name = Fassq (intern ("name"), parms);
  if (!NILP (name))
    {
      name = Fcdr (name);
      CHECK_STRING (name, 0);
    }
  else if (STRINGP (Vdefault_screen_name))
    name = Vdefault_screen_name;
  else
    name = build_string ("emacs");

  s->name = name;

  XSET (screen, Lisp_Screen, s);

  x_create_widgets (s, parms, lisp_window_id);
  
  /* do this after anything that might call Fsignal() before the screen
   * is in a usable state. */
  Vscreen_list = Fcons (screen, Vscreen_list);

  /* This runs lisp code, and thus might GC.  If the selected screen is still
     the terminal screen (meaning that we're in the middle of creating the
     initial X screen) then select the X screen now, so that GC messages don't
     get written on the terminal screen.  This is kind of a hack...
   */
  if (selected_screen == XSCREEN (Vterminal_screen))
    select_screen_internal (s);
  init_screen_faces (s);
  x_format_screen_title (s);
  run_hooks_1_arg (Qcreate_screen_hook, screen);
  UNGCPRO;
  return screen;
}


DEFUN ("x-show-lineinfo-column",
       Fx_show_lineinfo_column, Sx_show_lineinfo_column, 0, 1, 0,
       "Make the current emacs screen have a lineinfo column.")
     (screen)
     Lisp_Object screen;
{
  struct screen* s;
  struct x_display *x;
#ifdef LINE_INFO_WIDGET
  int just_created;
#endif
  
  if (NILP (screen))
    s = selected_screen;
  else {
    CHECK_SCREEN (screen, 0);
    s = XSCREEN (screen);
  }
  if (! SCREEN_IS_X (s)) error ("not an X screen");

  x = s->display.x;

#ifdef LINE_INFO_WIDGET
  
  BLOCK_INPUT;
  XawPanedSetRefigureMode (x->row_widget, 0);
  
  /* the order in which children are managed is the top to
     bottom order in which they are displayed in the paned window. */
  
  XtUnmanageChild (x->edit_widget);
  if (x->lineinfo_widget)
    XtUnmanageChild (x->lineinfo_widget);
  else {
    x->lineinfo_widget =
      XtVaCreateWidget ("lineinfo_widget", lineInfoWidgetClass,
			x->row_widget,
			XtNwidth,  50,
			XtNheight, s->display.x->pixel_height,
			XtNmappedWhenManaged, 0,
			XtNshowGrip, 0,
			0);
    ((LineInfoWidget) x->lineinfo_widget)->lineInfo.screen = s;
    just_created = 1;
  }
  XtManageChild (x->lineinfo_widget);
  XtManageChild (x->edit_widget);

  if (just_created)
    XStoreName (x_current_display, XtWindow(x->lineinfo_widget), "lineinfo_widget");

  XawPanedSetRefigureMode (x->row_widget, 1);

  UNBLOCK_INPUT;

#else
#ifdef LINE_INFO_COLUMN

  s->display.x->line_info_column_width =
    s->display.x->default_line_info_column_width;

#else
  error("support for the lineinfo column was not compiled into emacs.");

#endif
#endif
  return Qnil;
}


DEFUN ("x-hide-lineinfo-column",
       Fx_hide_lineinfo_column, Sx_hide_lineinfo_column, 0, 1, 0,
       "Make the given emacs screen not have a lineinfo column.")
     (screen)
     Lisp_Object screen;
{
  struct screen *s;
  
  if (NILP (screen))
    s = selected_screen;
  else {
    CHECK_SCREEN (screen, 0);
    s = XSCREEN (screen);
  }
  if (! SCREEN_IS_X (s)) error ("not an X screen");

#ifdef LINE_INFO_WIDGET
  if (! s->display.x->lineinfo_widget) return Qnil;
  XtUnmanageChild (s->display.x->lineinfo_widget);

#else
#ifdef LINE_INFO_COLUMN
  s->display.x->line_info_column_width = 0;

#else
  error("support for the lineinfo column was not compiled into emacs.");
#endif
#endif
  return Qnil;
}


#define GET_X_SCREEN(s, screen) { \
  if (NILP (screen))		 \
    s = selected_screen;	 \
  else				 \
    {				 \
      CHECK_SCREEN (screen, 0);	 \
      s = XSCREEN (screen);	 \
    }				 \
  if (!SCREEN_IS_X (s))		 \
    error ("not an X display"); }


DEFUN ("x-display-visual-class", Fx_display_visual_class,
       Sx_display_visual_class, 0, 1, 0,
       "Returns the visual class of the display `screen' is on.\n\
The returned value will be one of the symbols StaticGray, GrayScale,\n\
StaticColor, PseudoColor, TrueColor, or DirectColor.")
	(screen)
     Lisp_Object screen;
{
  struct screen *s;
  Display *dpy;
  GET_X_SCREEN (s, screen);
  dpy = XtDisplay (s->display.x->widget);
  switch (DefaultVisual (dpy, DefaultScreen (dpy))->class)
    {
    case StaticGray:  return (intern ("StaticGray"));
    case GrayScale:   return (intern ("GrayScale"));
    case StaticColor: return (intern ("StaticColor"));
    case PseudoColor: return (intern ("PseudoColor"));
    case TrueColor:   return (intern ("TrueColor"));
    case DirectColor: return (intern ("DirectColor"));
    default:
      error ("display has an unknown visual class");
    }
}

DEFUN ("x-color-display-p", Fx_color_display_p, Sx_color_display_p, 0, 1, 0,
       "Returns t if the X display of the given screen supports color.")
     (screen)
     Lisp_Object screen;
{
  struct screen *s;
  Display *dpy;
  GET_X_SCREEN (s, screen);
  dpy = XtDisplay (s->display.x->widget);
  if (DisplayCells (dpy, DefaultScreen (dpy)) <= 2)
    return Qnil;
  switch (DefaultVisual (dpy, DefaultScreen (dpy))->class)
    {
    case StaticColor:
    case PseudoColor:
    case TrueColor:
    case DirectColor:
      return Qt;
    default:
      return Qnil;
    }
}

DEFUN ("x-pixel-width", Fx_pixel_width, Sx_pixel_width, 0, 1, 0,
  "Returns the width in pixels of the given screen.")
  (screen)
     Lisp_Object screen;
{
  struct screen *s;
  GET_X_SCREEN (s, screen);
  return make_number (PIXEL_WIDTH (s));
}

DEFUN ("x-pixel-height", Fx_pixel_height, Sx_pixel_height, 0, 1, 0,
  "Returns the height in pixels of the given screen.")
  (screen)
     Lisp_Object screen;
{
  struct screen *s;
  GET_X_SCREEN (s, screen);
  return make_number (PIXEL_HEIGHT (s));
}

DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
       0, 1, 0,
       "Returns the width in pixels of the display `screen' is on.")
     (screen)
{
  struct screen *s;
  Display *dpy;
  GET_X_SCREEN (s, screen);
  dpy = XtDisplay (s->display.x->widget);
  return make_number (DisplayWidth (dpy, DefaultScreen (dpy)));
}

DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
       Sx_display_pixel_height,
       0, 1, 0,
       "Returns the height in pixels of the display `screen' is on.")
     (screen)
{
  struct screen *s;
  Display *dpy;
  GET_X_SCREEN (s, screen);
  dpy = XtDisplay (s->display.x->widget);
  return make_number (DisplayHeight (dpy, DefaultScreen (dpy)));
}

DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
       0, 1, 0,
       "Returns the number of bitplanes of the display `screen' is on.")
     (screen)
{
  struct screen *s;
  Display *dpy;
  GET_X_SCREEN (s, screen);
  dpy = XtDisplay (s->display.x->widget);
  return make_number (DisplayPlanes (dpy, DefaultScreen (dpy)));
}

DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
       0, 1, 0,
       "Returns the number of color cells of the display `screen' is on.")
     (screen)
{
  struct screen *s;
  Display *dpy;
  GET_X_SCREEN (s, screen);
  dpy = XtDisplay (s->display.x->widget);
  return make_number (DisplayCells (dpy, DefaultScreen (dpy)));
}

DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
       "Returns the vendor ID string of the X server `screen' is on.")
     (screen)
{
  struct screen *s;
  Display *dpy;
  char *vendor;
  GET_X_SCREEN (s, screen);
  dpy = XtDisplay (s->display.x->widget);
  vendor = ServerVendor (dpy);
  if (! vendor) vendor = "";
  return build_string (vendor);
}

DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
       "Returns the version numbers of the X server `screen' is on.\n\
The returned value is a list of three integers: the major and minor\n\
version numbers of the X Protocol in use, and the vendor-specific release\n\
number.  See also `x-server-vendor'.")
     (screen)
{
  struct screen *s;
  Display *dpy;
  GET_X_SCREEN (s, screen);
  dpy = XtDisplay (s->display.x->widget);
  return list3 (make_number (ProtocolVersion (dpy)),
		make_number (ProtocolRevision (dpy)),
		make_number (VendorRelease (dpy)));
}


DEFUN ("x-set-screen-icon-pixmap", Fx_set_screen_icon_pixmap,
       Sx_set_screen_icon_pixmap, 2, 3, 0,
       "Set the icon-pixmap of the given screen.\n\
This should be the name of a bitmap file, or a bitmap description list\n\
 of the form (width height \"bitmap-data\").\n\
If the optional third argument is specified, it is the bitmap to use for\n\
 the icon-pixmap-mask (not all window managers obey this.)  If the bitmap\n\
 is an XPM file which also contains a mask, the mask argument, if provided,\n\
 will override the mask in the file.\n\
WARNING: when you call this function, the pixmap of the previous icon\n\
 of this screen (if any) is currently not freed (this is a bug).")
  (screen, pixmap, mask)
    Lisp_Object screen, pixmap, mask;
{
  struct screen *s;
  Arg av [10];
  int ac = 0;
  unsigned int w, h, d;
  Pixmap p, m;
  if (NILP (screen))
    s = selected_screen;
  else
    {
      CHECK_SCREEN (screen, 0);
      s = XSCREEN (screen);
    }

  if (NILP (mask))
    m = 0;
  else
    {
      m = (Pixmap) load_pixmap (s, mask, &w, &h, &d, 0);
      if (d > 1)
	{
	  BLOCK_INPUT;
	  XFreePixmap (XtDisplay (s->display.x->widget), m);
	  UNBLOCK_INPUT;
	  m = 0;
	  Fsignal (Qerror,
		   list3 (build_string ("mask pixmap must be 1 plane deep"),
			  mask, make_number (d)));
	}
    }

  if (NILP (pixmap))
    p = 0;
  else
    p = (Pixmap) load_pixmap (s, pixmap, &w, &h, &d, (m ? 0 : &m));

  XtSetArg (av [ac], XtNiconPixmap, p); ac++;
  XtSetArg (av [ac], XtNiconMask, m); ac++;
  XtSetValues (s->display.x->widget, av, ac);
  return pixmap;
}


static Cursor grabbed_cursor;

DEFUN ("x-grab-pointer", Fx_grab_pointer, Sx_grab_pointer, 0, 2, 0,
  "Grab the pointer and restrict it to its current window.  If optional\n\
SHAPE is non-nil, change the pointer shape to that.  If second optional\n\
argument MOUSE-ONLY is non-nil, ignore keyboard events during the grab.")
  (shape, ignore_keyboard)
     Lisp_Object shape, ignore_keyboard;
{
  Window w;
  int pointer_mode, result;

  BLOCK_INPUT;
  if (! NILP (ignore_keyboard))
    pointer_mode = GrabModeSync;
  else
    pointer_mode = GrabModeAsync;

  if (! NILP (shape))
    {
      CHECK_FIXNUM (shape, 0);
      grabbed_cursor = XCreateFontCursor (x_current_display, XINT (shape));
    }

  w = XtWindow (XSCREEN (XWINDOW (selected_window)->screen)->display.x->edit_widget);

  result = XGrabPointer (x_current_display, w,
			 False,
			 ButtonMotionMask | ButtonPressMask
			 | ButtonReleaseMask | PointerMotionHintMask,
			 GrabModeAsync,	      /* Keep pointer events flowing */
			 pointer_mode,	      /* Stall keyboard events */
			 w,		      /* Stay in this window */
			 grabbed_cursor,
			 CurrentTime);
  UNBLOCK_INPUT;
  if (result == GrabSuccess)
    {
      return Qt;
    }

  BLOCK_INPUT;
  XFreeCursor (x_current_display, grabbed_cursor);
  UNBLOCK_INPUT;
  return Qnil;
}

DEFUN ("x-ungrab-pointer", Fx_ungrab_pointer, Sx_ungrab_pointer, 0, 0, 0,
  "Release the pointer.")
  ()
{
  BLOCK_INPUT;
  XUngrabPointer (x_current_display, CurrentTime);

  if ((int) grabbed_cursor)
    {
      XFreeCursor (x_current_display, grabbed_cursor);
      grabbed_cursor = (Cursor) 0;
    }

  UNBLOCK_INPUT;
  return Qnil;
}


/* handlers for the eval-events pushed on the queue by event-Xt.c */

Lisp_Object Qx_EnterNotify_internal, Qx_LeaveNotify_internal;
Lisp_Object Qx_FocusIn_internal, Qx_FocusOut_internal;
Lisp_Object Qx_VisibilityNotify_internal, Qx_non_VisibilityNotify_internal;
Lisp_Object Qx_MapNotify_internal, Qx_UnmapNotify_internal;

DEFUN ("x-EnterNotify-internal", Fx_EnterNotify_internal,
       Sx_EnterNotify_internal, 1, 1, 0, "hands off")
     (screen)
     Lisp_Object screen;
{
  CHECK_SCREEN (screen, 0);
  if (! SCREEN_IS_X (XSCREEN (screen))) return Qnil; /* may be deleted */
/*  XSCREEN (screen)->display.x->mouse_p = 1; */
  run_hooks_1_arg (Qmouse_enter_screen_hook, screen);
  return Qnil;
}

DEFUN ("x-LeaveNotify-internal", Fx_LeaveNotify_internal,
       Sx_LeaveNotify_internal, 1, 1, 0, "hands off")
     (screen)
     Lisp_Object screen;
{
  CHECK_SCREEN (screen, 0);
  if (! SCREEN_IS_X (XSCREEN (screen))) return Qnil; /* may be deleted */
/*  XSCREEN (screen)->display.x->mouse_p = 0; */
  run_hooks_1_arg (Qmouse_leave_screen_hook, screen);
  return Qnil;
}

/* This is true if any widget in any emacs screen has the X keyboard focus
   Flase otherwise. */
int any_screen_has_focus_p;

/* The select-screen-hook and deselect-screen-hook are run from the 
   select_screen_internal() function; however, we run them from the FocusIn
   and FocusOut handlers as well, because under X, the "selectedness" of a
   screen has slightly funny semantics; according to emacs, a screen is
   not "deselected" unless some other screen is selected.  This is so that
   there is always some current window and buffer, and so on.  However, it's
   useful to run the deselect-screen-hook when emacs loses the X keyboard
   focus (that is, no emacs screen is the X selected window).  Likewise,
   it's useful to run the select-screen-hook when some emacs window regains
   the focus, even if that window is already the selected screen from emacs's
   point of view.

   If we don't do this, then the select-screen-hook (meaning auto-raise)
   isn't run if (in a point-to-type world) the mouse moves into the same
   emacs window that it originally left.  Clearly this isn't what someone
   who would want auto-raise would want.

   This means that sometimes the deselect-screen-hook will be called twice.
   This kind of stinks.

   If there are two screens, s1, and s2, where s1 is selected:

    mouse moves into s1:   FocusIn s1 runs select-screen-hook, because s1
    			   is the selected screen (FocusIn only does this
			   for the selected screen.)

    			   select_screen_internal doesn't run deselect-hook
			   since s1 is already selected_screen, although it
			   didn't have the X focus.

			   net result: select s1 run.

    mouse moves into s2:   FocusOut s1 runs deselect-screen-hook, but the
			   selected_screen is still s1.

			   FocusIn s2 does not run select-screen-hook,
			   because s2 is not the selected screen.

			   select_screen_internal runs deselect-hook s1,
			   then selects s2, then runs select-hook s2.

			   net result: deselect s1, deselect s1, select s2.
			   One of those deselects is superfluous.

    mouse moves elsewhere: FocusOut s2 runs deselect-screen-hook, but the
			   selected_screen is still s2.

			   net result: deselect s2.

    mouse moves into s1:   FocusIn s1 does not run select-screen-hook.

    			   select_screen_internal runs deselect-hook s2;
			   changes selected_screen, runs select-hook s1.

			   net result: deselect s2, select s1.
			   That deselect is superfluous.

   Things get even nastier if there is a big delay between when select-screen
   is called and when the Focus events are handled (as when lisp code calls
   select-screen and then doesn't return to top level for a while.)
 */

extern Lisp_Object Qselect_screen_hook, Qdeselect_screen_hook;

extern void x_screen_redraw_cursor (struct screen *);

DEFUN ("x-FocusIn-internal", Fx_FocusIn_internal,
       Sx_FocusIn_internal, 1, 1, 0, "hands off")
     (screen)
     Lisp_Object screen;
{
  int getting_focus = !any_screen_has_focus_p;
  CHECK_SCREEN (screen, 0);
  if (! SCREEN_IS_X (XSCREEN (screen))) return Qnil; /* may be deleted */
  any_screen_has_focus_p = 1;
  XSCREEN (screen)->display.x->focus_p = 1;
  if (XSCREEN (screen) == selected_screen)
    {
      x_screen_redraw_cursor (XSCREEN (screen));
      /* see comment above */
      if (getting_focus)
	if (!NILP (Vrun_hooks))
	  call1 (Vrun_hooks, Qselect_screen_hook);
    }
  else
    select_screen_internal (XSCREEN (screen));
  return Qnil;
}

DEFUN ("x-FocusOut-internal", Fx_FocusOut_internal,
       Sx_FocusOut_internal, 1, 1, 0, "hands off")
     (screen)
     Lisp_Object screen;
{
  CHECK_SCREEN (screen, 0);
  if (! SCREEN_IS_X (XSCREEN (screen))) return Qnil; /* may be deleted */
  any_screen_has_focus_p = 0;
  XSCREEN (screen)->display.x->focus_p = 0;
  if (XSCREEN (screen) == selected_screen)
    {
      x_screen_redraw_cursor (XSCREEN (screen));
      /* see comment above */
      if (!NILP (Vrun_hooks))
	call1 (Vrun_hooks, Qdeselect_screen_hook);
    }
  return Qnil;
}

DEFUN ("x-VisibilityNotify-internal", Fx_VisibilityNotify_internal,
       Sx_VisibilityNotify_internal, 1, 1, 0, "hands off")
     (screen)
     Lisp_Object screen;
{
  CHECK_SCREEN (screen, 0);
  if (! SCREEN_IS_X (XSCREEN (screen))) return Qnil; /* may be deleted */
  XSCREEN (screen)->display.x->totally_visible_p = 1;
  return Qnil;
}

DEFUN ("x-non-VisibilityNotify-internal", Fx_non_VisibilityNotify_internal,
       Sx_non_VisibilityNotify_internal, 1, 1, 0, "hands off")
     (screen)
     Lisp_Object screen;
{
  CHECK_SCREEN (screen, 0);
  if (! SCREEN_IS_X (XSCREEN (screen))) return Qnil; /* may be deleted */
  XSCREEN (screen)->display.x->totally_visible_p = 0;
  return Qnil;
}

DEFUN ("x-MapNotify-internal", Fx_MapNotify_internal,
       Sx_MapNotify_internal, 1, 1, 0, "hands off")
     (screen)
     Lisp_Object screen;
{
  CHECK_SCREEN (screen, 0);
  if (! SCREEN_IS_X (XSCREEN (screen))) return Qnil; /* may be deleted */
  XSCREEN (screen)->display.x->totally_visible_p = 1;
  if (! XSCREEN (screen)->visible)
    {
      XSCREEN (screen)->visible = 1;
      SET_SCREEN_GARBAGED (XSCREEN (screen));
      run_hooks_1_arg (Qmap_screen_hook, screen);
    }
  return Qnil;
}


DEFUN ("x-UnmapNotify-internal", Fx_UnmapNotify_internal,
       Sx_UnmapNotify_internal, 1, 1, 0, "hands off")
     (screen)
     Lisp_Object screen;
{
  CHECK_SCREEN (screen, 0);
  if (! SCREEN_IS_X (XSCREEN (screen))) return Qnil; /* may be deleted */
  XSCREEN (screen)->display.x->totally_visible_p = 0;
  if (XSCREEN (screen)->visible)
    {
      XSCREEN (screen)->visible = 0;
      run_hooks_1_arg (Qunmap_screen_hook, screen);
    }
  return Qnil;
}


#if 0 /* #### This stuff is obsolete; with the new event model, 
	      regular keyboard macros work just as well as this.
       */
DEFUN ("x-rebind-key", Fx_rebind_key, Sx_rebind_key, 3, 3, 0,
"Rebind X keysym KEYSYM, with MODIFIERS, to generate NEWSTRING.\n\
KEYSYM is a string which conforms to the X keysym definitions found\n\
in X11/keysymdef.h, sans the initial XK_. MODIFIERS is nil or a\n\
list of strings specifying modifier keys such as Control_L, which must\n\
also be depressed for NEWSTRING to appear.")
  (x_keysym, modifiers, newstring)
     register Lisp_Object x_keysym;
     register Lisp_Object modifiers;
     register Lisp_Object newstring;
{
  char *rawstring;
  register KeySym keysym, modifier_list[16];

  CHECK_STRING (x_keysym, 1);
  CHECK_STRING (newstring, 3);

  BLOCK_INPUT;
  keysym = XStringToKeysym ((char *) XSTRING (x_keysym)->data);
  UNBLOCK_INPUT;

  if (keysym == NoSymbol)
    error ("Keysym does not exist");

  if (NILP (modifiers))
    {
      BLOCK_INPUT;
      XRebindKeysym (x_current_display, keysym, modifier_list, 0,
		     XSTRING (newstring)->data, XSTRING (newstring)->size);
      UNBLOCK_INPUT;
    }
  else
    {
      register Lisp_Object rest, mod;
      register int i = 0;

      for (rest = modifiers; !NILP (rest); rest = Fcdr (rest))
	{
	  if (i == 16)
	    error ("Can't have more than 16 modifiers");

	  mod = Fcar (rest);
	  CHECK_STRING (mod, 3);
	  BLOCK_INPUT;
	  modifier_list[i] = XStringToKeysym ((char *) XSTRING (mod)->data);
	  UNBLOCK_INPUT;
	  if (modifier_list[i] == NoSymbol
	      || !IsModifierKey (modifier_list[i]))
	    error ("Element is not a modifier keysym");
	  i++;
	}
      
      BLOCK_INPUT;
      XRebindKeysym (x_current_display, keysym, modifier_list, i,
		     XSTRING (newstring)->data, XSTRING (newstring)->size);
      UNBLOCK_INPUT;
    }

  return Qnil;
}
  
DEFUN ("x-rebind-keys", Fx_rebind_keys, Sx_rebind_keys, 2, 2, 0,
  "Rebind KEYCODE to list of strings STRINGS.\n\
STRINGS should be a list of 16 elements, one for each shift combination.\n\
nil as element means don't change.\n\
See the documentation of `x-rebind-key' for more information.")
  (keycode, strings)
     register Lisp_Object keycode;
     register Lisp_Object strings;
{
  register Lisp_Object item;
  register unsigned char *rawstring;
  KeySym rawkey, modifier[1];
  int strsize;
  register unsigned i;

  CHECK_FIXNUM (keycode, 1);
  CHECK_CONS (strings, 2);
  rawkey = (KeySym) ((unsigned) (XINT (keycode))) & 255;
  for (i = 0; i <= 15; strings = Fcdr (strings), i++)
    {
      item = Fcar (strings);
      if (!NILP (item))
	{
	  CHECK_STRING (item, 2);
	  strsize = XSTRING (item)->size;
	  rawstring = (unsigned char *) xmalloc (strsize);
	  bcopy (XSTRING (item)->data, rawstring, strsize);
	  modifier[1] = 1 << i;
	  BLOCK_INPUT;
	  XRebindKeysym (x_current_display, rawkey, modifier, 1,
			 rawstring, strsize);
	  UNBLOCK_INPUT;
	}
    }
  return Qnil;
}
#endif


/* This comment supplies the doc string for x-get-resource,
   for make-docfile to see.  We cannot put this in the real DEFUN
   due to limits in the Unix cpp.

DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 3, 4, 0,
       "Retrieve an X resource from the resource manager.\n\
The first arg is the name of the resource to retrieve, such as \"font\".\n\
The second arg is the class of the resource to retrieve, like \"Font\".\n\
The third arg should be one of the symbols string, integer, or boolean,\n\
specifying the type of object that the database is searched for.\n\
The fourth arg is the screen to search for the resources on, defaulting\n\
to the selected screen.\n\
\n\
The call\n\
    (x-get-resource \"font\" \"Font\" 'string)\n\
\n\
is an interface to the C call\n\
\n\
    XrmGetResource (db, \"emacs.this_screen_name.font\",\n\
			\"Emacs.EmacsScreen.Font\",\n\
			\"String\");\n\
\n\
Therefore if you want to retrieve a deeper resource, for example,\n\
\"Emacs.foo.foreground\", you need to specify the same number of links\n\
in the class path:\n\
    (x-get-resource \"foo.foreground\" \"Thing.Foreground\" 'string)\n\
\n\
which is equivalent to 
\n\
    XrmGetResource (db, \"emacs.screen_name.foo.foreground\",\n\
			\"Emacs.EmacsScreen.Thing.Foreground\",\n\
			\"String\");\n\

\n\
The returned value of this function is nil if the queried resource is not\n\
found.  If the third arg is `string', a string is returned, and if it is\n\
`integer', an integer is returned.  If the third arg is `boolean', then the\n\
returned value is the list (t) for true, (nil) for false, and is nil to\n\
mean ``unspecified.''")
     (name, class, type, screen)
*/


DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 3, 4, 0, 0)
     (name, class, type, screen)
     Lisp_Object name, class, type, screen;
{
  char *name_string, *class_string;
  char *app_name, *app_class, *screen_name, *screen_class, *s;
  Widget widget;

  CHECK_STRING (name, 0);
  CHECK_STRING (class, 0);
  CHECK_SYMBOL (type, 0);
  if (NILP (screen))
    screen = Fselected_screen ();
  else
    CHECK_SCREEN (screen, 0);
  if (! SCREEN_IS_X (XSCREEN (screen)))
/*    error ("not an X screen"); */
    return Qnil;

  widget = XSCREEN (screen)->display.x->widget;
  BLOCK_INPUT;
  XtGetApplicationNameAndClass (XtDisplay (widget), &app_name, &app_class);
  UNBLOCK_INPUT;
  screen_name = widget->core.name;
  screen_class = XtClass (widget)->core_class.class_name;
  name_string = (char *) alloca (XSTRING (name)->size + strlen (app_name)
				 + strlen (screen_name) + 3);
  class_string = (char *) alloca (XSTRING (class)->size + strlen (app_class)
				  + strlen (screen_class) + 3);
  strcpy (name_string, (char *) app_name);
  for (s = name_string; *s; s++) if (*s == '.') *s = '_';
  strcat (name_string, ".");
  s++;
  strcat (name_string, (char *) screen_name);
  for (; *s; s++) if (*s == '.') *s = '_';
  strcat (name_string, ".");
  strcat (name_string, (char *) XSTRING (name)->data);
  strcpy (class_string, app_class);
  strcat (class_string, ".");
  strcat (class_string, screen_class);
  strcat (class_string, ".");
  strcat (class_string, (char *) XSTRING (class)->data);

  {
    XrmValue xrm_value;
    XrmName namelist [100];
    XrmClass classlist [100];
    XrmName *namerest = namelist;
    XrmClass *classrest = classlist;
    XrmRepresentation xrm_type;
    XrmRepresentation string_quark;
    int result;
    BLOCK_INPUT;
    XrmStringToNameList (name_string, namelist);
    XrmStringToClassList (class_string, classlist);
    string_quark = XrmStringToQuark ("String");
    UNBLOCK_INPUT;

    /* ensure that they have the same length */
    while (namerest [0] && classrest [0])
      namerest++, classrest++;
    if (namerest [0] || classrest [0])
      Fsignal (Qerror,
	       Fcons (build_string
		      ("class list and name list must be the same length"),
		      Fcons (build_string (name_string),
			     Fcons (build_string (class_string), Qnil))));
    BLOCK_INPUT;
    result = XrmQGetResource (XtDatabase (XtDisplay (widget)),
			      namelist, classlist, &xrm_type, &xrm_value);
    UNBLOCK_INPUT;

    if (result != True || xrm_type != string_quark)
      return Qnil;
    s = (char *) xrm_value.addr;
  }

  if (EQ (type, intern ("string")))
    return build_string (s);
  else if (EQ (type, intern ("boolean")))
    {
      if (!strcasecmp (s, "off") || !strcasecmp (s, "false") ||
	  !strcasecmp (s,"no"))
	return Fcons (Qnil, Qnil);
      else if (!strcasecmp (s, "on") || !strcasecmp (s, "true") ||
	       !strcasecmp (s, "yes"))
	return Fcons (Qt, Qnil);
      else
	{
	  char str[255];
	  sprintf (str, "can't convert %s: %s to a Boolean",
		   name_string, s);
	  return Fsignal (Qerror, Fcons (build_string (str), Qnil));
	}
    }
  else if (EQ (type, intern ("integer")))
    {
      int i, c;
      if (1 != sscanf (s, "%d%c", &i, &c))
	{
	  char str [255];
	  sprintf (str, "can't convert %s: %s to an integer",
		   name_string, s);
	  return Fsignal (Qerror, Fcons (build_string (str), Qnil));
	}
      else
	return make_number (i);
    }
  else
    return
      Fsignal (Qwrong_type_argument,
	       Fcons (build_string ("should be string, integer, or boolean"),
		      Fcons (type, Qnil)));
}


#ifndef BITMAPDIR
#define BITMAPDIR "/usr/include/X11/bitmaps"
#endif

void
initialize_x_bitmap_file_path ()
{
  Display *dpy = x_current_display;
  char *type = 0;
  XrmValue value;
  if (XrmGetResource (XtDatabase (dpy),
		      "bitmapFilePath", "BitmapFilePath", &type, &value)
      && !strcmp (type, "String"))
    {
      char *s1, *s2;
      char *p = (char *) value.addr;
      s1 = p;
      for (s2 = p; *s2; s2++)
	if (*s2 == ':' && s1 != s2)
	  {
	    Vx_bitmap_file_path = Fcons (make_string (s1, s2 - s1),
					 Vx_bitmap_file_path);
	    s1 = s2 + 1;
	  }
      if (s1 != s2)
	Vx_bitmap_file_path = Fcons (make_string (s1, s2 - s1),
				     Vx_bitmap_file_path);
    }
  Vx_bitmap_file_path = Fnreverse (Fcons (build_string (BITMAPDIR),
					  Vx_bitmap_file_path));
}


/* Cursors.  Once emacs allocates an X cursor, it never frees it.
   Presumably cursors are very lightweight, and this it ok.  If
   this turns out not to be the case, we should only cache the 
   last N cursors used (2<n<10?) and XFreeCursor() on the least
   recently used ones.
 */

Lisp_Object Vcursor_alist;

/* XmuCvtStringToCursor is a little bogus, and when it can't convert to
   a real cursor, it will sometimes return a "success" value, after 
   triggering a BadPixmap error.  It then gives you a cursor that will
   itself generate BadCursor errors.  So we install this error handler
   to catch/notice the X error and take that as meaning "couldn't convert."
 */

static int XmuCvtStringToCursor_got_error;
static int XmuCvtStringToCursor_error_handler (dpy, error)
     Display *dpy;
     XErrorEvent *error;
{
  XmuCvtStringToCursor_got_error = 1;
  return 0;
}

DEFUN ("x-valid-color-name-p", Fx_valid_color_name_p, Sx_valid_color_name_p,
       1, 2, 0,
       "Returns true if COLOR names a color that X knows about.\n\
Valid color names are listed in the file /usr/lib/X11/rgb.txt, or\n\
whatever the equivalent is on your system.")
     (color, screen)
     Lisp_Object color, screen;
{
  int ok;
  XColor c;
  Widget widget;
  if (NILP (screen))
    screen = Fselected_screen ();
  CHECK_SCREEN (screen, 0);
  if (! SCREEN_IS_X (XSCREEN (screen)))
    return Qnil;
  CHECK_STRING (color, 0);
  widget = XSCREEN (screen)->display.x->widget;
  BLOCK_INPUT;
  ok = XParseColor (XtDisplay (widget),
		    DefaultColormapOfScreen (XtScreen (widget)),
		    (char *) XSTRING (color)->data, &c);
  UNBLOCK_INPUT;
  return ok ? Qt : Qnil;
}

DEFUN ("x-valid-keysym-name-p", Fx_valid_keysym_name_p, Sx_valid_keysym_name_p,
       1, 1, 0,
  "Returns true if KEYSYM names a keysym that the X library knows about.\n\
Valid keysyms are listed in the files /usr/include/X11/keysymdef.h and in\n\
/usr/lib/X11/XKeysymDB, or whatever the equivalents are on your system.")
     (keysym)
     Lisp_Object keysym;
{
  CHECK_STRING (keysym, 0);
  if (XStringToKeysym ((char *) XSTRING (keysym)->data))
    return Qt;
  return Qnil;
}


static Cursor
x_get_cursor (s, name, fg, bg, noerror)
     struct screen *s;
     Lisp_Object name, fg, bg;
     int noerror;
{
  Cursor cursor;
  Lisp_Object cons, ofg, obg;
  if (noerror)
    {
      if ((!STRINGP (name)) ||
	  (!NILP (fg) && !STRINGP (fg)) ||
	  (!NILP (bg) && !STRINGP (bg)))
	return 0;
    }
  else
    {
      CHECK_STRING (name, 0);
      if (!NILP (fg)) CHECK_STRING (fg, 0);
      if (!NILP (bg)) CHECK_STRING (bg, 0);
    }
  cons = assoc_no_quit (name, Vcursor_alist);
  if (NILP (cons))
    {
      int (*old_handler) ();
      XrmValue arg, from, to;
      Cardinal nargs = 1;
      Screen *screen = XtScreen (s->display.x->widget);
      arg.addr = (XtPointer) &screen;
      arg.size = sizeof (Screen *);
      from.addr = (XtPointer) XSTRING (name)->data;
      from.size = (unsigned int) XSTRING (name)->size;
      to.addr = 0;
      to.size = 0;
      BLOCK_INPUT;
      XSync (XtDisplay (s->display.x->widget), 0);
      XmuCvtStringToCursor_got_error = 0;
      old_handler = XSetErrorHandler (XmuCvtStringToCursor_error_handler);
      XmuCvtStringToCursor (&arg, &nargs, &from, &to);
      XSync (XtDisplay (s->display.x->widget), 0);
      XSetErrorHandler (old_handler);
      UNBLOCK_INPUT;
      if (XmuCvtStringToCursor_got_error) cursor = 0;
      else if (to.addr) cursor = *((Cursor *) to.addr);
      else cursor = 0;
      if (! cursor && noerror)
	return 0;
      else if (! cursor)
	while (1)
	  Fsignal (Qerror, Fcons (build_string ("unknown cursor"),
				  Fcons (name, Qnil)));
      ofg = obg = Qnil;
      cons = Fcons (name, Fcons (word_to_lisp ((int) cursor),
				 Fcons (ofg, Fcons (obg, Qnil))));
      Vcursor_alist = Fcons (cons, Vcursor_alist);
    }
  else
    {
      cursor = lisp_to_word (XCONS (XCONS (cons)->cdr)->car);
      ofg = XCONS (XCONS (XCONS (cons)->cdr)->cdr)->car;
      obg = XCONS (XCONS (XCONS (XCONS (cons)->cdr)->cdr)->cdr)->car;
    }
  if (!NILP (fg) && !NILP (bg) &&
      (NILP (Fequal (fg, ofg)) || NILP (Fequal (bg, obg))))
    {
      XColor fgc, bgc;
      int result;
      Widget widget = s->display.x->widget;
      Display *dpy = XtDisplay (widget);
      Colormap cmap = DefaultColormapOfScreen (XtScreen (widget));

      BLOCK_INPUT;
      result = XParseColor (dpy, cmap, (char *) XSTRING (fg)->data, &fgc);
      UNBLOCK_INPUT;
      if (! result && noerror)
	return 0;
      else if (! result)
	while (1)
	  Fsignal (Qerror, Fcons (build_string ("unrecognised color"),
				  Fcons (fg, Qnil)));
      BLOCK_INPUT;
      result = XParseColor (dpy, cmap, (char *) XSTRING (bg)->data, &bgc);
      UNBLOCK_INPUT;
      if (! result && noerror)
	return 0;
      else if (! result)
	while (1)
	  Fsignal (Qerror, Fcons (build_string ("unrecognised color"),
				  Fcons (bg, Qnil)));
      XCONS (XCONS (XCONS (cons)->cdr)->cdr)->car = fg;
      XCONS (XCONS (XCONS (XCONS (cons)->cdr)->cdr)->cdr)->car = bg;
      BLOCK_INPUT;
      XRecolorCursor (dpy, cursor, &fgc, &bgc);
      UNBLOCK_INPUT;
    }
  return cursor;
}


DEFUN ("x-set-screen-pointer", Fx_set_screen_pointer, Sx_set_screen_pointer,
       2, 4, 0,
       "Set the mouse cursor of SCREEN to the cursor named CURSOR-NAME,\n\
with colors FOREGROUND and BACKGROUND.  The string may be any of the\n\
standard cursor names from appendix B of the Xlib manual (also known as\n\
the file <X11/cursorfont.h>) minus the XC_ prefix, or it may be a font\n\
name and glyph index of the form \"FONT fontname index [[font] index]\",\n\
or it may be a bitmap file acceptable to XmuLocateBitmapFile().\n\
If it is a bitmap file, and if a bitmap file whose name is the name of\n\
the cursor with \"msk\" exists, then it is used as the mask.  For example,\n\
a pair of files may be named \"cursor.xbm\" and \"cursor.xbmmsk\".")
     (screen, cursor_name, fg, bg)
     Lisp_Object screen, cursor_name, fg, bg;
{
  Cursor cursor;
  CHECK_SCREEN (screen, 0);
  if (! SCREEN_IS_X (XSCREEN (screen)))
    return Qnil;
  cursor = x_get_cursor (XSCREEN (screen), cursor_name, fg, bg, 0);
  BLOCK_INPUT;
  XDefineCursor (XtDisplay (XSCREEN (screen)->display.x->edit_widget),
		 XtWindow (XSCREEN (screen)->display.x->edit_widget),
		 cursor);
  XFlush (XtDisplay (XSCREEN (screen)->display.x->edit_widget));
  UNBLOCK_INPUT;
  store_screen_param (XSCREEN (screen), intern ("pointer"), cursor_name);
  return Qnil;
}


/* GC calls x_show_gc_cursor() to change the mouse pointer to indicate GC.
   If this returns 0, then it couldn't change the cursor for whatever reason,
   and a minibuffer message will be output instead.  x_show_normal_cursor()
   will be called at the end.
*/
static int change_cursor_for_gc ();

int
x_show_gc_cursor (s)
     struct screen* s;
{
  return change_cursor_for_gc (s, 1);
}

int
x_show_normal_cursor (s)
     struct screen* s;
{
  return change_cursor_for_gc (s, 0);
}


extern Lisp_Object get_screen_param (struct screen *, Lisp_Object);

static int
change_cursor_for_gc (s, gc_p)
     struct screen *s;
     int gc_p;
{
  Cursor cursor;
  static int changed;

  if (!s || !SCREEN_IS_X(s) || NILP (Vx_gc_pointer_shape))
    return 0;
  
  if (! gc_p && !changed)
    return 0;

  if (gc_p)
    cursor = x_get_cursor (s, Vx_gc_pointer_shape, Qnil, Qnil, 1);
  else
    cursor = x_get_cursor (s, get_screen_param (s, intern ("pointer")),
			   Qnil, Qnil, 1);
  if (! cursor)
    {
      if (gc_p)
	message ("Garbage collecting... (x-gc-pointer-shape is bogus!)");
      changed = 0;
      return 1;
    }

  BLOCK_INPUT;
  XDefineCursor (XtDisplay (s->display.x->edit_widget),
		 XtWindow (s->display.x->edit_widget),
		 cursor);
  XFlushQueue ();
  UNBLOCK_INPUT;
  changed = 1;
  return 1;
}



#ifdef USE_SOUND
extern int not_on_console;  /* defined in fns.c */
#endif

extern Lisp_Object x_term_init (Lisp_Object);

DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
       1, 1, 0, "Open a connection to an X server.\n\
Argument ARGV is a list of strings describing the command line options.\n\
Returns a copy of ARGV from which the arguments used by the Xt code\n\
to open the connect have been removed.")
 	(argv_list)
	Lisp_Object argv_list;
{
  Lisp_Object argv_rest;

  if (x_current_display != 0)
    error ("X server connection is already initialized");

  /* This is what sets x_current_display.  This also initializes many symbols,
     such as those used for input. */
  argv_rest = x_term_init (argv_list);
  
  text_part_sym = intern ("text-part");
  modeline_part_sym = intern ("modeline-part");
  
  XFASTINT (Vwindow_system_version) = 11;
  Xatoms_of_xfns ();
  Xatoms_of_xselect ();

#ifdef USE_SOUND
  /* When running on a SparcStation or SGI, we cannot use digitized sounds as
     beeps unless emacs is running on the same machine that $DISPLAY points
     to, and $DISPLAY points to screen 0 of that machine.
   */
  {
    char *dpy = x_current_display->display_name;
    char *tail = (char *) strchr (dpy, ':');
    if (! tail ||
	strncmp (tail, ":0", 2))
      not_on_console = 1;
    else {
      char dpyname[255], localname[255];
      strncpy (dpyname, dpy, tail-dpy);
      dpyname [tail-dpy] = 0;
      if (!*dpyname ||
	  !strcmp(dpyname, "unix") ||
	  !strcmp(dpyname, "localhost"))
	not_on_console = 0;
      else if (gethostname (localname, sizeof (localname)))
	not_on_console = 1;  /* can't find hostname? */
      else {
	/* gethostbyname() reuses the structure it returns,
	   so we have to copy the string out of it. */
	struct hostent *h = gethostbyname (dpyname);
	not_on_console = !h || !!(strcmp (localname, h->h_name));
      }
    }
  }
#endif /* USE_SOUND */

  return argv_rest;
}

DEFUN ("x-window-id", Fx_window_id, Sx_window_id, 1, 1, 0,
       "Get the ID of the X11 window. This gives us a chance to manipulate\n\
the Emacs window from within a different program. Since the id is an\n\
unsigned long, we return it as a string.")
  (screen)
  Lisp_Object screen;
{
  char str[20];

  CHECK_SCREEN (screen, 0);
  if (! SCREEN_IS_X (XSCREEN (screen)))
    return Qnil;
  sprintf (str, "%lu", XtWindow (XSCREEN (screen)->display.x->edit_widget));
  return (make_string (str, strlen (str)));
}


DEFUN ("x-close-current-connection", Fx_close_current_connection,
       Sx_close_current_connection,
       0, 0, 0, "Close the connection to the current X server.")
  ()
{
  /* This is ONLY used when killing emacs;  For switching displays
     we'll have to take care of setting CloseDownMode elsewhere. */
#ifdef FREE_CHECKING
  extern void (*__free_hook)();
  int checking_free;
#endif

  if (x_current_display)
    {
      BLOCK_INPUT;
#ifdef FREE_CHECKING
      checking_free = (__free_hook != 0);
      
      /* Disable strict free checking, to avoid bug in X library */
      if (checking_free)
	disable_strict_free_check ();
#endif
      XCloseDisplay (x_current_display);
      x_current_display = 0;
      Vwindow_system = Qnil;
#ifdef FREE_CHECKING
      if (checking_free)
	enable_strict_free_check ();
#endif
      UNBLOCK_INPUT;
    }
  else
    fatal ("No current X display connection to close");
  return Qnil;
}

static int
emacs_safe_XSyncFunction(dpy)
     register Display *dpy;
{
  BLOCK_INPUT;
  XSync (dpy, 0);
  UNBLOCK_INPUT;
  return 0;
}

DEFUN ("x-debug-mode", Fx_debug_mode, Sx_debug_mode, 1, 1, 0,
       "With a true arg, put the connection to the X server in synchronous\n\
mode; this is slower.  False turns it off.\n\
Do not simply call XSynchronize() from gdb; that won't work.")
    (arg)
    Lisp_Object arg;
{
  if (!NILP (arg))
    {
      BLOCK_INPUT;
      XSetAfterFunction (x_current_display, emacs_safe_XSyncFunction);
      UNBLOCK_INPUT;
      message ("X connection is synchronous");
    }
  else
    {
      BLOCK_INPUT;
      XSetAfterFunction (x_current_display, 0);
      UNBLOCK_INPUT;
      message ("X connection is asynchronous");
    }
  return arg;
}


void
syms_of_xfns ()
{
  init_x_parm_symbols ();

  /* This is zero if not using X windows.  */
  x_current_display = 0;

  WM_COMMAND_screen = Qnil;
  staticpro (&WM_COMMAND_screen);

  DEFVAR_LISP ("x-gc-pointer-shape", &Vx_gc_pointer_shape,
   "The shape of the mouse-pointer during garbage collection.\n\
If this is nil, then the cursor will not be changed, and echo-area messages\n\
will be used instead.");
  Vx_gc_pointer_shape = Qnil;

  DEFVAR_LISP ("bar-cursor", &Vbar_cursor,
	       "Use vertical bar cursor if non-nil.");
  Vbar_cursor = Qnil;

  DEFVAR_LISP ("x-screen-defaults", &Vx_screen_defaults,
    "Alist of default screen-creation parameters for X-window screens.\n\
These override what is specified in `~/.Xdefaults' but are overridden\n\
by the arguments to the particular call to `x-create-screen'.");
  Vx_screen_defaults = Qnil;

  DEFVAR_LISP ("default-screen-name", &Vdefault_screen_name,
    "The default name to assign to newly-created screens.\n\
This can be overridden by arguments to `x-create-screen'.\n\
This must be a string.");
  Vdefault_screen_name = Fpurecopy (build_string ("emacs"));

  DEFVAR_LISP ("x-emacs-application-class", &Vx_emacs_application_class,
	       "The X application class of the Emacs process.\n\
This controls, among other things, the name of the `app-defaults' file\n\
that emacs will use.  For changes to this variable to take effect, they\n\
must be made before the connection to the X server is initialized, that is,\n\
this variable may only be changed before emacs is dumped, or by setting it\n\
in the file lisp/term/x-win.el.");
  Vx_emacs_application_class = Fpurecopy (build_string ("Emacs"));

  DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
       "A list of the directories in which X bitmap files may be found.\n\
If nil, this is initialized from the \"*bitmapFilePath\" resource.");
  Vx_bitmap_file_path = Qnil;

  DEFVAR_BOOL ("x-allow-sendevents", &x_allow_sendevents,
    "*Non-nil means to allow synthetic events.  Nil means they are ignored.\n\
Beware: allowing emacs to process SendEvents opens a big security hole.");
  x_allow_sendevents = 0;

  staticpro (&Vcursor_alist);
  Vcursor_alist = Qnil;

  defsubr (&Sx_display_visual_class);
  defsubr (&Sx_color_display_p);
  defsubr (&Sx_pixel_width);
  defsubr (&Sx_pixel_height);
  defsubr (&Sx_display_pixel_width);
  defsubr (&Sx_display_pixel_height);
  defsubr (&Sx_display_planes);
  defsubr (&Sx_display_color_cells);
  defsubr (&Sx_server_vendor);
  defsubr (&Sx_server_version);
  defsubr (&Sx_window_id);
  defsubr (&Sx_grab_pointer);
  defsubr (&Sx_ungrab_pointer);
  defsubr (&Sx_create_screen);
  defsubr (&Sx_open_connection);
  defsubr (&Sx_close_current_connection);
#ifdef ENERGIZE
  defsubr (&Senergize_toggle_psheet);
#endif
  defsubr (&Sx_show_lineinfo_column);
  defsubr (&Sx_hide_lineinfo_column);
  defsubr (&Sx_debug_mode);
  defsubr (&Sx_get_resource);
  defsubr (&Sx_set_screen_icon_pixmap);
  defsubr (&Sx_set_screen_pointer);
  defsubr (&Sx_valid_color_name_p);
  defsubr (&Sx_valid_keysym_name_p);

  defsubr (&Sx_EnterNotify_internal);
  defsubr (&Sx_LeaveNotify_internal);
  defsubr (&Sx_FocusIn_internal);
  defsubr (&Sx_FocusOut_internal);
  defsubr (&Sx_MapNotify_internal);
  defsubr (&Sx_UnmapNotify_internal);
  defsubr (&Sx_VisibilityNotify_internal);
  defsubr (&Sx_non_VisibilityNotify_internal);

  Qx_EnterNotify_internal = intern ("x-EnterNotify-internal");
  Qx_LeaveNotify_internal = intern ("x-LeaveNotify-internal");
  Qx_FocusIn_internal  = intern ("x-FocusIn-internal");
  Qx_FocusOut_internal = intern ("x-FocusOut-internal");
  Qx_MapNotify_internal = intern ("x-MapNotify-internal");
  Qx_UnmapNotify_internal = intern ("x-UnmapNotify-internal");
  Qx_VisibilityNotify_internal = intern ("x-VisibilityNotify-internal");
  Qx_non_VisibilityNotify_internal = intern("x-non-VisibilityNotify-internal");
}

void
Xatoms_of_xfns ()
{
#define ATOM(x) XInternAtom(x_current_display, (x), False)

  BLOCK_INPUT;
  Xatom_WM_PROTOCOLS = ATOM("WM_PROTOCOLS");
  Xatom_WM_DELETE_WINDOW = ATOM("WM_DELETE_WINDOW");
  Xatom_WM_SAVE_YOURSELF = ATOM("WM_SAVE_YOURSELF");
  Xatom_WM_TAKE_FOCUS = ATOM("WM_TAKE_FOCUS");
  UNBLOCK_INPUT;
}

#endif /* HAVE_X_WINDOWS */
