(U+6215): Apply new conventions for glyph granularity.
[chise/xemacs-chise.git.1] / src / device-x.c
index b0cad36..540e407 100644 (file)
@@ -21,6 +21,8 @@ Boston, MA 02111-1307, USA.  */
 
 /* Synched up with: Not in FSF. */
 
+/* 7-8-00 !!#### This file needs definite Mule review. */
+
 /* Original authors: Jamie Zawinski and the FSF */
 /* Rewritten by Ben Wing and Chuck Thompson. */
 
@@ -39,6 +41,7 @@ Boston, MA 02111-1307, USA.  */
 #include "objects-x.h"
 
 #include "buffer.h"
+#include "elhash.h"
 #include "events.h"
 #include "faces.h"
 #include "frame.h"
@@ -49,6 +52,10 @@ Boston, MA 02111-1307, USA.  */
 #include "sysfile.h"
 #include "systime.h"
 
+#if defined(HAVE_SHLIB) && defined(LWLIB_USES_ATHENA) && !defined(HAVE_ATHENA_3D)
+#include "sysdll.h"
+#endif /* HAVE_SHLIB and LWLIB_USES_ATHENA and not HAVE_ATHENA_3D */
+
 #ifdef HAVE_OFFIX_DND
 #include "offix.h"
 #endif
@@ -134,7 +141,7 @@ get_device_from_display (Display *dpy)
        (STRINGP (Vinvocation_name) ?
        (char *) XSTRING_DATA (Vinvocation_name) : FALLBACK_RESOURCE_NAME),
        DisplayString (dpy) ? DisplayString (dpy) : "???");
-    abort();
+    ABORT();
   }
 
 #undef FALLBACK_RESOURCE_NAME
@@ -161,6 +168,8 @@ get_x_display (Lisp_Object device)
 /*                   initializing an X connection                      */
 /************************************************************************/
 
+static struct device *device_being_initialized = NULL;
+
 static void
 allocate_x_device_struct (struct device *d)
 {
@@ -241,11 +250,11 @@ x_init_device_class (struct device *d)
  * Finally, if all else fails, return `xemacs', as it is more
  * appropriate (X11R5 returns `main').
  */
-static char *
-compute_x_app_name (int argc, char **argv)
+static Extbyte *
+compute_x_app_name (int argc, Extbyte **argv)
 {
   int i;
-  char *ptr;
+  Extbyte *ptr;
 
   for (i = 1; i < argc - 1; i++)
     if (!strncmp(argv[i], "-name", max (2, strlen (argv[1]))))
@@ -316,6 +325,136 @@ Dynarr_add_validified_lisp_string (char_dynarr *cda, Lisp_Object str)
   validify_resource_component (Dynarr_atp (cda, Dynarr_length (cda) - len), len);
 }
 
+#if 0
+/* compare visual info for qsorting */
+static int
+x_comp_visual_info (const void *elem1, const void *elem2)
+{
+  XVisualInfo *left, *right;
+
+  left = (XVisualInfo *)elem1;
+  right = (XVisualInfo *)elem2;
+
+  if ( left == NULL )
+    return -1;
+  if ( right == NULL )
+    return 1;
+
+  if ( left->depth > right->depth ) {
+    return 1;
+  }
+  else if ( left->depth == right->depth ) {
+    if ( left->colormap_size > right->colormap_size )
+      return 1;
+    if ( left->class > right->class )
+      return 1;
+    else if ( left->class < right->class )
+      return -1;
+    else
+      return 0;
+  }
+  else {
+    return -1;
+  }
+
+}
+#endif /* if 0 */
+
+#define XXX_IMAGE_LIBRARY_IS_SOMEWHAT_BROKEN
+static Visual *
+x_try_best_visual_class (Screen *screen, int scrnum, int visual_class)
+{
+  Display *dpy = DisplayOfScreen (screen);
+  XVisualInfo vi_in;
+  XVisualInfo *vi_out = NULL;
+  int out_count;
+
+  vi_in.class = visual_class;
+  vi_in.screen = scrnum;
+  vi_out = XGetVisualInfo (dpy, (VisualClassMask | VisualScreenMask),
+                          &vi_in, &out_count);
+  if ( vi_out )
+    {
+      int i, best;
+      Visual *visual;
+      for (i = 0, best = 0; i < out_count; i++)
+       /* It's better if it's deeper, or if it's the same depth with
+          more cells (does that ever happen?  Well, it could...)
+          NOTE: don't allow pseudo color to get larger than 8! */
+       if (((vi_out [i].depth > vi_out [best].depth) ||
+            ((vi_out [i].depth == vi_out [best].depth) &&
+             (vi_out [i].colormap_size > vi_out [best].colormap_size)))
+#ifdef XXX_IMAGE_LIBRARY_IS_SOMEWHAT_BROKEN
+           /* For now, the image library doesn't like PseudoColor visuals
+              of depths other than 1 or 8.  Depths greater than 8 only occur
+              on machines which have TrueColor anyway, so probably we'll end
+              up using that (it is the one that `Best' would pick) but if a
+              PseudoColor visual is explicitly specified, pick the 8 bit one.
+           */
+           && (visual_class != PseudoColor ||
+               vi_out [i].depth == 1 ||
+               vi_out [i].depth == 8)
+#endif
+
+           /* SGI has 30-bit deep visuals.  Ignore them.
+                (We only have 24-bit data anyway.)
+              */
+           && (vi_out [i].depth <= 24)
+           )
+         best = i;
+      visual = vi_out[best].visual;
+      XFree ((char *) vi_out);
+      return visual;
+    }
+  else
+    return 0;
+}
+
+static int
+x_get_visual_depth (Display *dpy, Visual *visual)
+{
+  XVisualInfo vi_in;
+  XVisualInfo *vi_out;
+  int out_count, d;
+
+  vi_in.visualid = XVisualIDFromVisual (visual);
+  vi_out = XGetVisualInfo (dpy, /*VisualScreenMask|*/VisualIDMask,
+                          &vi_in, &out_count);
+  if (! vi_out) ABORT ();
+  d = vi_out [0].depth;
+  XFree ((char *) vi_out);
+  return d;
+}
+
+static Visual *
+x_try_best_visual (Display *dpy, int scrnum)
+{
+  Visual *visual = NULL;
+  Screen *screen = ScreenOfDisplay (dpy, scrnum);
+  if ((visual = x_try_best_visual_class (screen, scrnum, TrueColor))
+      && x_get_visual_depth (dpy, visual) >= 16 )
+    return visual;
+  if ((visual = x_try_best_visual_class (screen, scrnum, PseudoColor)))
+    return visual;
+  if ((visual = x_try_best_visual_class (screen, scrnum, TrueColor)))
+    return visual;
+#ifdef DIRECTCOLOR_WORKS
+  if ((visual = x_try_best_visual_class (screen, scrnum, DirectColor)))
+    return visual;
+#endif
+
+  visual = DefaultVisualOfScreen (screen);
+  if ( x_get_visual_depth (dpy, visual) >= 8 )
+    return visual;
+
+  if ((visual = x_try_best_visual_class (screen, scrnum, StaticGray)))
+    return visual;
+  if ((visual = x_try_best_visual_class (screen, scrnum, GrayScale)))
+    return visual;
+  return DefaultVisualOfScreen (screen);
+}
+
+
 static void
 x_init_device (struct device *d, Lisp_Object props)
 {
@@ -324,16 +463,88 @@ x_init_device (struct device *d, Lisp_Object props)
   Display *dpy;
   Widget app_shell;
   int argc;
-  char **argv;
-  CONST char *app_class;
-  CONST char *app_name;
-  CONST char *disp_name;
-  Arg xargs[6];
-  Cardinal numargs;
+  Extbyte **argv;
+  const char *app_class;
+  const char *app_name;
+  const char *disp_name;
   Visual *visual = NULL;
   int depth = 8;               /* shut up the compiler */
   Colormap cmap;
   int screen;
+  /* */
+  int best_visual_found = 0;
+
+#if defined(HAVE_SHLIB) && defined(LWLIB_USES_ATHENA) && !defined(HAVE_ATHENA_3D)
+  /*
+   * In order to avoid the lossage with flat Athena widgets dynamically
+   * linking to one of the ThreeD variants, using the dynamic symbol helpers
+   * to look for symbols that shouldn't be there and refusing to run if they
+   * are seems a less toxic idea than having XEmacs crash when we try and
+   * use a subclass of a widget that has changed size.
+   *
+   * It's ugly, I know, and not going to work everywhere. It seems better to
+   * do our damnedest to try and tell the user what to expect rather than
+   * simply blow up though.
+   *
+   * All the ThreeD variants I have access to define the following function
+   * symbols in the shared library. The flat Xaw library does not define them:
+   *
+   * Xaw3dComputeBottomShadowRGB
+   * Xaw3dComputeTopShadowRGB
+   *
+   * So far only Linux has shown this problem. This seems to be portable to
+   * all the distributions (certainly all the ones I checked - Debian and
+   * Redhat)
+   *
+   * This will only work, sadly, with dlopen() -- the other dynamic linkers
+   * are simply not capable of doing what is needed. :/
+   */
+
+  {
+    /* Get a dll handle to the main process. */
+    dll_handle xaw_dll_handle = dll_open (NULL);
+
+    /* Did that fail?  If so, continue without error.
+     * We could die here but, well, that's unfriendly and all -- plus I feel
+     * better about some crashing somewhere rather than preventing a perfectly
+     * good configuration working just because dll_open failed.
+     */
+    if (xaw_dll_handle != NULL)
+      {
+       /* Look for the Xaw3d function */
+       dll_func xaw_function_handle =
+         dll_function (xaw_dll_handle, "Xaw3dComputeTopShadowRGB");
+
+       /* If we found it, warn the user in big, nasty, unfriendly letters */
+       if (xaw_function_handle != NULL)
+         {
+           warn_when_safe (Qdevice, Qerror, "\n"
+"It seems that XEmacs is built dynamically linked to the flat Athena widget\n"
+"library but it finds a 3D Athena variant with the same name at runtime.\n"
+"\n"
+"This WILL cause your XEmacs process to dump core at some point.\n"
+"You should not continue to use this binary without resolving this issue.\n"
+"\n"
+"This can be solved with the xaw-wrappers package under Debian\n"
+"(register XEmacs as incompatible with all 3d widget sets, see\n"
+"update-xaw-wrappers(8) and .../doc/xaw-wrappers/README.packagers).  It\n"
+"can be verified by checking the runtime path in /etc/ld.so.conf and by\n"
+"using `ldd /path/to/xemacs' under other Linux distributions.  One\n"
+"solution is to use LD_PRELOAD or LD_LIBRARY_PATH to force ld.so to\n"
+"load the flat Athena widget library instead of the aliased 3D widget\n"
+"library (see ld.so(8) for use of these environment variables).\n\n"
+                           );
+
+         }
+
+       /* Otherwise release the handle to the library
+        * No error catch here; I can't think of a way to recover anyhow.
+        */
+       dll_close (xaw_dll_handle);
+      }
+  }
+#endif /* HAVE_SHLIB and LWLIB_USES_ATHENA and not HAVE_ATHENA_3D */
+
 
   XSETDEVICE (device, d);
   display = DEVICE_CONNECTION (d);
@@ -342,18 +553,20 @@ x_init_device (struct device *d, Lisp_Object props)
 
   make_argc_argv (Vx_initial_argv_list, &argc, &argv);
 
-  GET_C_STRING_CTEXT_DATA_ALLOCA (display, disp_name);
+  LISP_STRING_TO_EXTERNAL (display, disp_name, Qctext);
 
   /*
    * Break apart the old XtOpenDisplay call into XOpenDisplay and
    * XtDisplayInitialize so we can figure out whether there
    * are any XEmacs resources in the resource database before
-   * we intitialize Xt.  This is so we can automagically support
+   * we initialize Xt.  This is so we can automagically support
    * both `Emacs' and `XEmacs' application classes.
    */
   slow_down_interrupts ();
   /* May not be needed but XtOpenDisplay could not deal with signals here. */
+  device_being_initialized = d;
   dpy = DEVICE_X_DISPLAY (d) = XOpenDisplay (disp_name);
+  device_being_initialized = NULL;
   speed_up_interrupts ();
 
   if (dpy == 0)
@@ -364,7 +577,7 @@ x_init_device (struct device *d, Lisp_Object props)
 
   if (STRINGP (Vx_emacs_application_class) &&
       XSTRING_LENGTH (Vx_emacs_application_class) > 0)
-    GET_C_STRING_CTEXT_DATA_ALLOCA (Vx_emacs_application_class, app_class);
+    LISP_STRING_TO_EXTERNAL (Vx_emacs_application_class, app_class, Qctext);
   else
     {
       app_class = (NILP (Vx_emacs_application_class)  &&
@@ -384,10 +597,10 @@ x_init_device (struct device *d, Lisp_Object props)
      Yuck. */
   XtDisplayInitialize (Xt_app_con, dpy, compute_x_app_name (argc, argv),
                        app_class, emacs_options,
-                       XtNumber (emacs_options), &argc, argv);
+                       XtNumber (emacs_options), &argc, (char **) argv);
   speed_up_interrupts ();
 
-  screen = DefaultScreen(dpy);
+  screen = DefaultScreen (dpy);
   if (NILP (Vdefault_x_device))
     Vdefault_x_device = device;
 
@@ -398,15 +611,15 @@ x_init_device (struct device *d, Lisp_Object props)
        data-directory/app-defaults/$LANG/Emacs.
        This is in addition to the standard app-defaults files, and
        does not override resources defined elsewhere */
-    CONST char *data_dir;
+    const char *data_dir;
     char *path;
-    XrmDatabase db = XtDatabase (dpy); /* ### XtScreenDatabase(dpy) ? */
-    CONST char *locale = XrmLocaleOfDatabase (db);
+    XrmDatabase db = XtDatabase (dpy); /* #### XtScreenDatabase(dpy) ? */
+    const char *locale = XrmLocaleOfDatabase (db);
 
     if (STRINGP (Vx_app_defaults_directory) &&
        XSTRING_LENGTH (Vx_app_defaults_directory) > 0)
       {
-       GET_C_STRING_FILENAME_DATA_ALLOCA(Vx_app_defaults_directory, data_dir);
+       LISP_STRING_TO_EXTERNAL (Vx_app_defaults_directory, data_dir, Qfile_name);
        path = (char *)alloca (strlen (data_dir) + strlen (locale) + 7);
        sprintf (path, "%s%s/Emacs", data_dir, locale);
        if (!access (path, R_OK))
@@ -414,7 +627,7 @@ x_init_device (struct device *d, Lisp_Object props)
       }
     else if (STRINGP (Vdata_directory) && XSTRING_LENGTH (Vdata_directory) > 0)
       {
-       GET_C_STRING_FILENAME_DATA_ALLOCA (Vdata_directory, data_dir);
+       LISP_STRING_TO_EXTERNAL (Vdata_directory, data_dir, Qfile_name);
        path = (char *)alloca (strlen (data_dir) + 13 + strlen (locale) + 7);
        sprintf (path, "%sapp-defaults/%s/Emacs", data_dir, locale);
        if (!access (path, R_OK))
@@ -434,10 +647,11 @@ x_init_device (struct device *d, Lisp_Object props)
 
   XtGetApplicationNameAndClass (dpy, (char **) &app_name, (char **) &app_class);
   /* search for a matching visual if requested by the user, or setup the display default */
-  numargs = 0;
   {
-    char *buf1 = (char *)alloca (strlen (app_name) + 17);
-    char *buf2 = (char *)alloca (strlen (app_class) + 17);
+    int resource_name_length = max (sizeof (".emacsVisual"),
+                                   sizeof (".privateColormap"));
+    char *buf1 = alloca_array (char, strlen (app_name)  + resource_name_length);
+    char *buf2 = alloca_array (char, strlen (app_class) + resource_name_length);
     char *type;
     XrmValue value;
 
@@ -445,85 +659,110 @@ x_init_device (struct device *d, Lisp_Object props)
     sprintf (buf2, "%s.EmacsVisual", app_class);
     if (XrmGetResource (XtDatabase (dpy), buf1, buf2, &type, &value) == True)
       {
-       int cnt = 0, vis_class= PseudoColor;
+       int cnt = 0;
+       int vis_class = PseudoColor;
        XVisualInfo vinfo;
-       char *res, *str = (char*)value.addr;
-
-       if      (strncmp(str, "StaticGray", 10) == 0)   cnt = 10, vis_class = StaticGray;
-       else if (strncmp(str, "StaticColor", 11) == 0)  cnt = 11, vis_class = StaticColor;
-       else if (strncmp(str, "TrueColor", 9) == 0)     cnt = 9,  vis_class = TrueColor;
-       else if (strncmp(str, "GrayScale", 9) == 0)     cnt = 9,  vis_class = GrayScale;
-       else if (strncmp(str, "PseudoColor", 11) == 0)  cnt = 11, vis_class = PseudoColor;
-       else if (strncmp(str, "DirectColor", 11) == 0)  cnt = 11, vis_class = DirectColor;
+       char *str = (char*) value.addr;
+
+#define CHECK_VIS_CLASS(visual_class)                                  \
+ else if (memcmp (str, #visual_class, sizeof (#visual_class) - 1) == 0)        \
+       cnt = sizeof (#visual_class) - 1, vis_class = visual_class
+
+       if (1)
+         ;
+       CHECK_VIS_CLASS (StaticGray);
+       CHECK_VIS_CLASS (StaticColor);
+       CHECK_VIS_CLASS (TrueColor);
+       CHECK_VIS_CLASS (GrayScale);
+       CHECK_VIS_CLASS (PseudoColor);
+       CHECK_VIS_CLASS (DirectColor);
+
        if (cnt)
          {
-           res = str + cnt;
-           depth = atoi(res);
+           depth = atoi (str + cnt);
            if (depth == 0)
              {
-               stderr_out("Invalid Depth specification in %s... ignoring...\n",(char*)str);
+               stderr_out ("Invalid Depth specification in %s... ignoring...\n", str);
              }
            else
              {
-               if (XMatchVisualInfo(dpy, screen, depth, vis_class, &vinfo))
+               if (XMatchVisualInfo (dpy, screen, depth, vis_class, &vinfo))
                  {
                    visual = vinfo.visual;
                  }
                else
                  {
-                   stderr_out("Can't match the requested visual %s... using defaults\n",str);
+                   stderr_out ("Can't match the requested visual %s... using defaults\n", str);
                  }
              }
          }
        else
          {
-           stderr_out("Invalid Visual specification in %s... ignoring.\n",(char*)str);
+           stderr_out( "Invalid Visual specification in %s... ignoring.\n", str);
          }
       }
     if (visual == NULL)
       {
-       visual = DefaultVisual(dpy, screen);
-       depth = DefaultDepth(dpy, screen);
+       /*
+         visual = DefaultVisual(dpy, screen);
+         depth = DefaultDepth(dpy, screen);
+       */
+       visual = x_try_best_visual (dpy, screen);
+       depth = x_get_visual_depth (dpy, visual);
+       best_visual_found = (visual != DefaultVisual (dpy, screen));
       }
 
     /* If we've got the same visual as the default and it's PseudoColor,
        check to see if the user specified that we need a private colormap */
-    if (visual == DefaultVisual(dpy, screen))
+    if (visual == DefaultVisual (dpy, screen))
       {
        sprintf (buf1, "%s.privateColormap", app_name);
        sprintf (buf2, "%s.PrivateColormap", app_class);
        if ((visual->class == PseudoColor) &&
            (XrmGetResource (XtDatabase (dpy), buf1, buf2, &type, &value) == True))
          {
-            cmap = XCopyColormapAndFree(dpy, DefaultColormap(dpy, screen));
+            cmap = XCopyColormapAndFree (dpy, DefaultColormap (dpy, screen));
          }
        else
          {
-           cmap = DefaultColormap(dpy, screen);
+           cmap = DefaultColormap (dpy, screen);
          }
       }
     else
       {
-       /* We have to create a matching colormap anyway...
-          ### think about using standard colormaps (need the Xmu libs?) */
-       cmap = XCreateColormap(dpy, RootWindow(dpy, screen), visual, AllocNone);
-       XInstallColormap(dpy, cmap);
+       if ( best_visual_found )
+         {
+           cmap = XCreateColormap (dpy,  RootWindow (dpy, screen), visual, AllocNone);
+         }
+       else
+         {
+           /* We have to create a matching colormap anyway...
+              #### think about using standard colormaps (need the Xmu libs?) */
+           cmap = XCreateColormap(dpy, RootWindow(dpy, screen), visual, AllocNone);
+           XInstallColormap(dpy, cmap);
+         }
       }
   }
-  XtSetArg(xargs[numargs],XtNvisual, visual); numargs++;
-  XtSetArg(xargs[numargs],XtNdepth, depth); numargs++;
-  XtSetArg(xargs[numargs],XtNcolormap, cmap); numargs++;
-  DEVICE_X_VISUAL (d) = visual;
-  DEVICE_X_COLORMAP (d) = cmap;
-  DEVICE_X_DEPTH (d) = depth;
 
+  DEVICE_X_VISUAL   (d) = visual;
+  DEVICE_X_COLORMAP (d) = cmap;
+  DEVICE_X_DEPTH    (d) = depth;
   validify_resource_component ((char *) XSTRING_DATA (DEVICE_NAME (d)),
                               XSTRING_LENGTH (DEVICE_NAME (d)));
-  app_shell = XtAppCreateShell (NULL, app_class,
-                               applicationShellWidgetClass,
-                               dpy, xargs, numargs);
+
+  {
+    Arg al[3];
+    XtSetArg (al[0], XtNvisual,   visual);
+    XtSetArg (al[1], XtNdepth,    depth);
+    XtSetArg (al[2], XtNcolormap, cmap);
+
+    app_shell = XtAppCreateShell (NULL, app_class,
+                                 applicationShellWidgetClass,
+                                 dpy, al, countof (al));
+  }
 
   DEVICE_XT_APP_SHELL (d) = app_shell;
+
 #ifdef HAVE_XIM
   XIM_init_device(d);
 #endif /* HAVE_XIM */
@@ -531,28 +770,26 @@ x_init_device (struct device *d, Lisp_Object props)
   /* Realize the app_shell so that its window exists for GC creation purposes,
      and set it to the size of the root window for child placement purposes */
   {
-    Screen *scrn = ScreenOfDisplay(dpy, screen);
-    int screen_width, screen_height;
-    screen_width = WidthOfScreen(scrn);
-    screen_height = HeightOfScreen(scrn);
-    numargs = 0;
-    XtSetArg (xargs[numargs], XtNmappedWhenManaged, False); numargs++;
-    XtSetArg (xargs[numargs], XtNx, 0); numargs++;
-    XtSetArg (xargs[numargs], XtNy, 0); numargs++;
-    XtSetArg (xargs[numargs], XtNwidth,  screen_width); numargs++;
-    XtSetArg (xargs[numargs], XtNheight, screen_height); numargs++;
-    XtSetValues (app_shell, xargs, numargs);
+    Arg al[5];
+    XtSetArg (al[0], XtNmappedWhenManaged, False);
+    XtSetArg (al[1], XtNx, 0);
+    XtSetArg (al[2], XtNy, 0);
+    XtSetArg (al[3], XtNwidth,  WidthOfScreen  (ScreenOfDisplay (dpy, screen)));
+    XtSetArg (al[4], XtNheight, HeightOfScreen (ScreenOfDisplay (dpy, screen)));
+    XtSetValues (app_shell, al, countof (al));
     XtRealizeWidget (app_shell);
   }
-#ifdef HAVE_SESSION
+
+#ifdef HAVE_WMCOMMAND
   {
     int new_argc;
-    char **new_argv;
+    Extbyte **new_argv;
     make_argc_argv (Vcommand_line_args, &new_argc, &new_argv);
-    XSetCommand (XtDisplay (app_shell), XtWindow (app_shell), new_argv, new_argc);
+    XSetCommand (XtDisplay (app_shell), XtWindow (app_shell),
+                (char **) new_argv, new_argc);
     free_argc_argv (new_argv);
   }
-#endif /* HAVE_SESSION */
+#endif /* HAVE_WMCOMMAND */
 
 
 #ifdef HAVE_OFFIX_DND
@@ -576,7 +813,7 @@ x_init_device (struct device *d, Lisp_Object props)
   DEVICE_X_GC_CACHE (d) = make_gc_cache (dpy, XtWindow(app_shell));
   DEVICE_X_GRAY_PIXMAP (d) = None;
   Xatoms_of_device_x (d);
-  Xatoms_of_xselect (d);
+  Xatoms_of_select_x (d);
   Xatoms_of_objects_x (d);
   x_init_device_class (d);
 
@@ -591,10 +828,10 @@ x_finish_init_device (struct device *d, Lisp_Object props)
 }
 
 static void
-x_mark_device (struct device *d, void (*markobj) (Lisp_Object))
+x_mark_device (struct device *d)
 {
-  ((markobj) (DEVICE_X_WM_COMMAND_FRAME (d)));
-  ((markobj) (DEVICE_X_DATA (d)->x_keysym_map_hashtable));
+  mark_object (DEVICE_X_WM_COMMAND_FRAME (d));
+  mark_object (DEVICE_X_DATA (d)->x_keysym_map_hash_table);
 }
 
 \f
@@ -614,7 +851,7 @@ x_delete_device (struct device *d)
   Lisp_Object device;
   Display *display;
 #ifdef FREE_CHECKING
-  extern void (*__free_hook)();
+  extern void (*__free_hook) (void *);
   int checking_free;
 #endif
 
@@ -637,6 +874,12 @@ x_delete_device (struct device *d)
       if (DEVICE_X_DATA (d)->x_keysym_map)
        XFree ((char *) DEVICE_X_DATA (d)->x_keysym_map);
 
+      if (DEVICE_XT_APP_SHELL (d))
+       {
+         XtDestroyWidget (DEVICE_XT_APP_SHELL (d));
+         DEVICE_XT_APP_SHELL (d) = NULL;
+       }
+
       XtCloseDisplay (display);
       DEVICE_X_DISPLAY (d) = 0;
 #ifdef FREE_CHECKING
@@ -669,10 +912,10 @@ x_delete_device (struct device *d)
 /*                             handle X errors                         */
 /************************************************************************/
 
-CONST char *
+const char *
 x_event_name (int event_type)
 {
-  static CONST char *events[] =
+  static const char *events[] =
   {
     "0: ERROR!",
     "1: REPLY",
@@ -814,10 +1057,14 @@ x_error_handler (Display *disp, XErrorEvent *event)
       }
 #endif /* EXTERNAL_WIDGET */
 
+#if 0
+      /* This ends up calling X, which isn't allowed in an X error handler
+       */
       stderr_out ("\n%s: ",
                  (STRINGP (Vinvocation_name)
                   ? (char *) XSTRING_DATA (Vinvocation_name)
                   : "xemacs"));
+#endif
       XmuPrintDefaultErrorMessage (disp, event, stderr);
     }
   return 0;
@@ -877,6 +1124,9 @@ x_IO_error_handler (Display *disp)
   Lisp_Object dev;
   struct device *d = get_device_from_display_1 (disp);
 
+  if (!d)
+    d = device_being_initialized;
+
   assert (d != NULL);
   XSETDEVICE (dev, d);
 
@@ -911,11 +1161,13 @@ x_IO_error_handler (Display *disp)
      Xlib might just decide to exit().  So we mark the offending
      console for deletion and throw to top level.  */
   if (d)
-    enqueue_magic_eval_event (io_error_delete_device, dev);
-  DEVICE_X_BEING_DELETED (d) = 1;
+    {
+      enqueue_magic_eval_event (io_error_delete_device, dev);
+      DEVICE_X_BEING_DELETED (d) = 1;
+    }
   Fthrow (Qtop_level, Qnil);
 
-  RETURN_NOT_REACHED (0);
+  return 0; /* not reached */
 }
 
 DEFUN ("x-debug-mode", Fx_debug_mode, 1, 2, 0, /*
@@ -1015,6 +1267,22 @@ construct_name_list (Display *display, Widget widget, char *fake_name,
 
 #endif /* 0 */
 
+/* strcasecmp() is not sufficiently portable or standard,
+   and it's easier just to write our own. */
+static int
+ascii_strcasecmp (const char *s1, const char *s2)
+{
+  while (1)
+    {
+      char c1 = *s1++;
+      char c2 = *s2++;
+      if (c1 >= 'A' && c1 <= 'Z') c1 += 'a' - 'A';
+      if (c2 >= 'A' && c2 <= 'Z') c2 += 'a' - 'A';
+      if (c1 != c2) return c1 - c2;
+      if (c1 == '\0') return 0;
+    }
+}
+
 static char_dynarr *name_char_dynarr;
 static char_dynarr *class_char_dynarr;
 
@@ -1118,7 +1386,7 @@ The fifth arg is the device to search for the resources on. (The resource
 The sixth arg NOERROR, if non-nil, means do not signal an error if a
   bogus resource specification was retrieved (e.g. if a non-integer was
   given when an integer was requested).  In this case, a warning is issued
-  instead.
+  instead, unless NOERROR is t, in which case no warning is issued.
 
 The resource names passed to this function are looked up relative to the
 locale.
@@ -1177,15 +1445,15 @@ The returned value of this function is nil if the queried resource is not
 found.  If the third arg is `string', a string is returned, and if it is
 `integer', an integer is returned.  If the third arg is `boolean', then the
 returned value is the list (t) for true, (nil) for false, and is nil to
-mean ``unspecified.''
+mean ``unspecified''.
 */
-       (name, class, type, locale, device, no_error))
+       (name, class, type, locale, device, noerror))
 {
   char* name_string, *class_string;
   char *raw_result;
   XrmDatabase db;
   Display *display;
-  Error_behavior errb = decode_error_behavior_flag (no_error);
+  Error_behavior errb = decode_error_behavior_flag (noerror);
 
   CHECK_STRING (name);
   CHECK_STRING (class);
@@ -1241,13 +1509,13 @@ mean ``unspecified.''
     return build_string (raw_result);
   else if (EQ (type, Qboolean))
     {
-      if (!strcasecmp (raw_result, "off")   ||
-         !strcasecmp (raw_result, "false") ||
-         !strcasecmp (raw_result, "no"))
+      if (!ascii_strcasecmp (raw_result, "off")   ||
+         !ascii_strcasecmp (raw_result, "false") ||
+         !ascii_strcasecmp (raw_result, "no"))
        return Fcons (Qnil, Qnil);
-      if (!strcasecmp (raw_result, "on")   ||
-         !strcasecmp (raw_result, "true") ||
-         !strcasecmp (raw_result, "yes"))
+      if (!ascii_strcasecmp (raw_result, "on")   ||
+         !ascii_strcasecmp (raw_result, "true") ||
+         !ascii_strcasecmp (raw_result, "yes"))
        return Fcons (Qt, Qnil);
       return maybe_continuable_error
        (Qresource, errb,
@@ -1440,17 +1708,17 @@ Valid keysyms are listed in the files /usr/include/X11/keysymdef.h and in
 */
        (keysym))
 {
-  CONST char *keysym_ext;
+  const char *keysym_ext;
 
   CHECK_STRING (keysym);
-  GET_C_STRING_CTEXT_DATA_ALLOCA (keysym, keysym_ext);
+  LISP_STRING_TO_EXTERNAL (keysym, keysym_ext, Qctext);
 
   return XStringToKeysym (keysym_ext) ? Qt : Qnil;
 }
 
-DEFUN ("x-keysym-hashtable", Fx_keysym_hashtable, 0, 1, 0, /*
-Return a hashtable which contains a hash key for all keysyms which
-name keys on the keyboard.  See `x-keysym-on-keyboard-p'.
+DEFUN ("x-keysym-hash-table", Fx_keysym_hash_table, 0, 1, 0, /*
+Return a hash table containing a key for all keysyms on DEVICE.
+DEVICE must be an X11 display device.  See `x-keysym-on-keyboard-p'.
 */
        (device))
 {
@@ -1458,7 +1726,7 @@ name keys on the keyboard.  See `x-keysym-on-keyboard-p'.
   if (!DEVICE_X_P (d))
     signal_simple_error ("Not an X device", device);
 
-  return DEVICE_X_DATA (d)->x_keysym_map_hashtable;
+  return DEVICE_X_DATA (d)->x_keysym_map_hash_table;
 }
 
 DEFUN ("x-keysym-on-keyboard-sans-modifiers-p", Fx_keysym_on_keyboard_sans_modifiers_p,
@@ -1480,7 +1748,7 @@ The two names differ in capitalization and underscoring.
     signal_simple_error ("Not an X device", device);
 
   return (EQ (Qsans_modifiers,
-             Fgethash (keysym, DEVICE_X_KEYSYM_MAP_HASHTABLE (d), Qnil)) ?
+             Fgethash (keysym, DEVICE_X_KEYSYM_MAP_HASH_TABLE (d), Qnil)) ?
          Qt : Qnil);
 }
 
@@ -1502,7 +1770,7 @@ The two names differ in capitalization and underscoring.
   if (!DEVICE_X_P (d))
     signal_simple_error ("Not an X device", device);
 
-  return (NILP (Fgethash (keysym, DEVICE_X_KEYSYM_MAP_HASHTABLE (d), Qnil)) ?
+  return (NILP (Fgethash (keysym, DEVICE_X_KEYSYM_MAP_HASH_TABLE (d), Qnil)) ?
          Qnil : Qt);
 }
 
@@ -1592,7 +1860,7 @@ Grab the keyboard on the given device (defaulting to the selected one).
 So long as the keyboard is grabbed, all keyboard events will be delivered
 to emacs -- it is not possible for other X clients to eavesdrop on them.
 Ungrab the keyboard with `x-ungrab-keyboard' (use an unwind-protect).
-Returns t if the grab was successful; nil otherwise.
+Returns t if the grab is successful, nil otherwise.
 */
        (device))
 {
@@ -1635,6 +1903,70 @@ Release a keyboard grab made with `x-grab-keyboard'.
   return Qnil;
 }
 
+DEFUN ("x-get-font-path", Fx_get_font_path, 0, 1, 0, /*
+Get the X Server's font path.
+
+See also `x-set-font-path'.
+*/
+       (device))
+{
+  Display *dpy = get_x_display (device);
+  int ndirs_return;
+  const char **directories = (const char **) XGetFontPath (dpy, &ndirs_return);
+  Lisp_Object font_path = Qnil;
+
+  if (!directories)
+    signal_simple_error ("Can't get X font path", device);
+
+  while (ndirs_return--)
+      font_path = Fcons (build_ext_string (directories[ndirs_return],
+                                           Qfile_name),
+                        font_path);
+
+  return font_path;
+}
+
+DEFUN ("x-set-font-path", Fx_set_font_path, 1, 2, 0, /*
+Set the X Server's font path to FONT-PATH.
+
+There is only one font path per server, not one per client.  Use this
+sparingly.  It uncaches all of the X server's font information.
+
+Font directories should end in the path separator and should contain
+a file called fonts.dir usually created with the program mkfontdir.
+
+Setting the FONT-PATH to nil tells the X server to use the default
+font path.
+
+See also `x-get-font-path'.
+*/
+       (font_path, device))
+{
+  Display *dpy = get_x_display (device);
+  Lisp_Object path_entry;
+  const char **directories;
+  int i=0,ndirs=0;
+
+  EXTERNAL_LIST_LOOP (path_entry, font_path)
+    {
+      CHECK_STRING (XCAR (path_entry));
+      ndirs++;
+    }
+
+  directories = alloca_array (const char *, ndirs);
+
+  EXTERNAL_LIST_LOOP (path_entry, font_path)
+    {
+      LISP_STRING_TO_EXTERNAL (XCAR (path_entry), directories[i++], Qfile_name);
+    }
+
+  expect_x_error (dpy);
+  XSetFontPath (dpy, (char **) directories, ndirs);
+  signal_if_x_error (dpy, 1/*resumable_p*/);
+
+  return Qnil;
+}
+
 \f
 /************************************************************************/
 /*                            initialization                            */
@@ -1654,7 +1986,7 @@ syms_of_device_x (void)
   DEFSUBR (Fx_server_vendor);
   DEFSUBR (Fx_server_version);
   DEFSUBR (Fx_valid_keysym_name_p);
-  DEFSUBR (Fx_keysym_hashtable);
+  DEFSUBR (Fx_keysym_hash_table);
   DEFSUBR (Fx_keysym_on_keyboard_p);
   DEFSUBR (Fx_keysym_on_keyboard_sans_modifiers_p);
 
@@ -1663,35 +1995,52 @@ syms_of_device_x (void)
   DEFSUBR (Fx_grab_keyboard);
   DEFSUBR (Fx_ungrab_keyboard);
 
+  DEFSUBR (Fx_get_font_path);
+  DEFSUBR (Fx_set_font_path);
+
   defsymbol (&Qx_error, "x-error");
   defsymbol (&Qinit_pre_x_win, "init-pre-x-win");
   defsymbol (&Qinit_post_x_win, "init-post-x-win");
 }
 
 void
+reinit_console_type_create_device_x (void)
+{
+  /* Initialize variables to speed up X resource interactions */
+  const char *valid_resource_chars =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+  while (*valid_resource_chars)
+    valid_resource_char_p[(unsigned int) (*valid_resource_chars++)] = 1;
+
+  name_char_dynarr  = Dynarr_new (char);
+  class_char_dynarr = Dynarr_new (char);
+}
+
+void
 console_type_create_device_x (void)
 {
+  reinit_console_type_create_device_x ();
   CONSOLE_HAS_METHOD (x, init_device);
   CONSOLE_HAS_METHOD (x, finish_init_device);
   CONSOLE_HAS_METHOD (x, mark_device);
   CONSOLE_HAS_METHOD (x, delete_device);
   CONSOLE_HAS_METHOD (x, device_system_metrics);
+}
 
-  {
-    /* Initialize variables to speed up X resource interactions */
-    CONST char *valid_resource_chars =
-      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
-    while (*valid_resource_chars)
-      valid_resource_char_p[(unsigned int) (*valid_resource_chars++)] = 1;
-
-    name_char_dynarr  = Dynarr_new (char);
-    class_char_dynarr = Dynarr_new (char);
-  }
+void
+reinit_vars_of_device_x (void)
+{
+  error_expected = 0;
+  error_occurred = 0;
+
+  in_resource_setting = 0;
 }
 
 void
 vars_of_device_x (void)
 {
+  reinit_vars_of_device_x ();
+
   DEFVAR_LISP ("x-emacs-application-class", &Vx_emacs_application_class /*
 The X application class of the XEmacs process.
 This controls, among other things, the name of the `app-defaults' file
@@ -1734,9 +2083,4 @@ where the localized init files are.
 
   staticpro (&Vdefault_x_device);
   Vdefault_x_device = Qnil;
-
-  error_expected = 0;
-  error_occurred = 0;
-
-  in_resource_setting = 0;
 }