XEmacs 21.2-b2
[chise/xemacs-chise.git.1] / src / device-x.c
1 /* Device functions for X windows.
2    Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
3    Copyright (C) 1994, 1995 Free Software Foundation, Inc.
4
5 This file is part of XEmacs.
6
7 XEmacs is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
10 later version.
11
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with XEmacs; see the file COPYING.  If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.  */
21
22 /* Synched up with: Not in FSF. */
23
24 /* Original authors: Jamie Zawinski and the FSF */
25 /* Rewritten by Ben Wing and Chuck Thompson. */
26
27 #include <config.h>
28 #include "lisp.h"
29
30 #include "console-x.h"
31 #include "xintrinsicp.h"        /* CoreP.h needs this */
32 #include <X11/CoreP.h>          /* Numerous places access the fields of
33                                    a core widget directly.  We could
34                                    use XtGetValues(), but ... */
35 #include "xgccache.h"
36 #include <X11/Shell.h>
37 #include "xmu.h"
38 #include "glyphs-x.h"
39 #include "objects-x.h"
40
41 #include "buffer.h"
42 #include "events.h"
43 #include "faces.h"
44 #include "frame.h"
45 #include "redisplay.h"
46 #include "sysdep.h"
47 #include "window.h"
48
49 #include "sysfile.h"
50 #include "systime.h"
51
52 #ifdef HAVE_OFFIX_DND
53 #include "offix.h"
54 #endif
55
56 Lisp_Object Vdefault_x_device;
57 #if defined(MULE) && (defined(LWLIB_MENUBARS_MOTIF) || defined(HAVE_XIM) || defined (USE_XFONTSET))
58 Lisp_Object Vx_app_defaults_directory;
59 #endif
60
61 /* Qdisplay in general.c */
62 Lisp_Object Qx_error;
63 Lisp_Object Qinit_pre_x_win, Qinit_post_x_win;
64
65 /* The application class of Emacs. */
66 Lisp_Object Vx_emacs_application_class;
67
68 Lisp_Object Vx_initial_argv_list; /* #### ugh! */
69
70 static XrmOptionDescRec emacs_options[] =
71 {
72   {"-geometry", ".geometry", XrmoptionSepArg, NULL},
73   {"-iconic", ".iconic", XrmoptionNoArg, "yes"},
74
75   {"-internal-border-width", "*EmacsFrame.internalBorderWidth", XrmoptionSepArg, NULL},
76   {"-ib",                    "*EmacsFrame.internalBorderWidth", XrmoptionSepArg, NULL},
77   {"-scrollbar-width",       "*EmacsFrame.scrollBarWidth",      XrmoptionSepArg, NULL},
78   {"-scrollbar-height",      "*EmacsFrame.scrollBarHeight",     XrmoptionSepArg, NULL},
79
80   {"-privatecolormap", ".privateColormap", XrmoptionNoArg,  "yes"},
81   {"-visual",   ".EmacsVisual",     XrmoptionSepArg, NULL},
82
83   /* #### Beware!  If the type of the shell changes, update this. */
84   {"-T",        "*TopLevelEmacsShell.title",    XrmoptionSepArg, NULL},
85   {"-wn",       "*TopLevelEmacsShell.title",    XrmoptionSepArg, NULL},
86   {"-title",    "*TopLevelEmacsShell.title",    XrmoptionSepArg, NULL},
87
88   {"-iconname", "*TopLevelEmacsShell.iconName", XrmoptionSepArg, NULL},
89   {"-in",       "*TopLevelEmacsShell.iconName", XrmoptionSepArg, NULL},
90   {"-mc",       "*pointerColor",                XrmoptionSepArg, NULL},
91   {"-cr",       "*cursorColor",                 XrmoptionSepArg, NULL},
92   {"-fontset",  "*FontSet",                     XrmoptionSepArg, NULL},
93 };
94
95 /* Functions to synchronize mirroring resources and specifiers */
96 int in_resource_setting;
97 \f
98 /************************************************************************/
99 /*                          helper functions                            */
100 /************************************************************************/
101
102 /* JH 97/11/25 removed the static declaration because I need it during setup in event-Xt... */
103 struct device * get_device_from_display_1 (Display *dpy);
104 struct device *
105 get_device_from_display_1 (Display *dpy)
106 {
107   Lisp_Object devcons, concons;
108
109   DEVICE_LOOP_NO_BREAK (devcons, concons)
110     {
111       struct device *d = XDEVICE (XCAR (devcons));
112       if (DEVICE_X_P (d) && DEVICE_X_DISPLAY (d) == dpy)
113         return d;
114     }
115
116   return 0;
117 }
118
119 struct device *
120 get_device_from_display (Display *dpy)
121 {
122   struct device *d = get_device_from_display_1 (dpy);
123
124 #if !defined(INFODOCK)
125 # define FALLBACK_RESOURCE_NAME "xemacs"
126 # else
127 # define FALLBACK_RESOURCE_NAME "infodock"
128 #endif
129
130   if (!d) {
131     /* This isn't one of our displays.  Let's crash? */
132     stderr_out
133       ("\n%s: Fatal X Condition.  Asked about display we don't own: \"%s\"\n",
134        (STRINGP (Vinvocation_name) ?
135         (char *) XSTRING_DATA (Vinvocation_name) : FALLBACK_RESOURCE_NAME),
136        DisplayString (dpy) ? DisplayString (dpy) : "???");
137     abort();
138   }
139
140 #undef FALLBACK_RESOURCE_NAME
141
142   return d;
143 }
144
145 struct device *
146 decode_x_device (Lisp_Object device)
147 {
148   XSETDEVICE (device, decode_device (device));
149   CHECK_X_DEVICE (device);
150   return XDEVICE (device);
151 }
152
153 static Display *
154 get_x_display (Lisp_Object device)
155 {
156   return DEVICE_X_DISPLAY (decode_x_device (device));
157 }
158
159 \f
160 /************************************************************************/
161 /*                    initializing an X connection                      */
162 /************************************************************************/
163
164 static void
165 allocate_x_device_struct (struct device *d)
166 {
167   d->device_data = xnew_and_zero (struct x_device);
168 }
169
170 static void
171 Xatoms_of_device_x (struct device *d)
172 {
173   Display *D = DEVICE_X_DISPLAY (d);
174
175   DEVICE_XATOM_WM_PROTOCOLS    (d) = XInternAtom (D, "WM_PROTOCOLS",    False);
176   DEVICE_XATOM_WM_DELETE_WINDOW(d) = XInternAtom (D, "WM_DELETE_WINDOW",False);
177   DEVICE_XATOM_WM_SAVE_YOURSELF(d) = XInternAtom (D, "WM_SAVE_YOURSELF",False);
178   DEVICE_XATOM_WM_TAKE_FOCUS   (d) = XInternAtom (D, "WM_TAKE_FOCUS",   False);
179   DEVICE_XATOM_WM_STATE        (d) = XInternAtom (D, "WM_STATE",        False);
180 }
181
182 static void
183 sanity_check_geometry_resource (Display *dpy)
184 {
185   char *app_name, *app_class, *s;
186   char buf1 [255], buf2 [255];
187   char *type;
188   XrmValue value;
189   XtGetApplicationNameAndClass (dpy, &app_name, &app_class);
190   strcpy (buf1, app_name);
191   strcpy (buf2, app_class);
192   for (s = buf1; *s; s++) if (*s == '.') *s = '_';
193   strcat (buf1, "._no_._such_._resource_.geometry");
194   strcat (buf2, "._no_._such_._resource_.Geometry");
195   if (XrmGetResource (XtDatabase (dpy), buf1, buf2, &type, &value) == True)
196     {
197       warn_when_safe (Qgeometry, Qerror,
198                       "\n"
199 "Apparently \"%s*geometry: %s\" or \"%s*geometry: %s\" was\n"
200 "specified in the resource database.  Specifying \"*geometry\" will make\n"
201 "XEmacs (and most other X programs) malfunction in obscure ways. (i.e.\n"
202 "the Xt or Xm libraries will probably crash, which is a very bad thing.)\n"
203 "You should always use \".geometry\" or \"*EmacsFrame.geometry\" instead.\n",
204                   app_name, (char *) value.addr,
205                   app_class, (char *) value.addr);
206       suppress_early_error_handler_backtrace = 1;
207       error ("Invalid geometry resource");
208     }
209 }
210
211 static void
212 x_init_device_class (struct device *d)
213 {
214   if (DEVICE_X_DEPTH(d) > 2)
215     {
216       switch (DEVICE_X_VISUAL(d)->class)
217         {
218         case StaticGray:
219         case GrayScale:
220           DEVICE_CLASS (d) = Qgrayscale;
221           break;
222         default:
223           DEVICE_CLASS (d) = Qcolor;
224         }
225     }
226   else
227     DEVICE_CLASS (d) = Qmono;
228 }
229
230 /*
231  * Figure out what application name to use for xemacs
232  *
233  * Since we have decomposed XtOpenDisplay into XOpenDisplay and
234  * XtDisplayInitialize, we no longer get this for free.
235  *
236  * If there is a `-name' argument in argv, use that.
237  * Otherwise use the last component of argv[0].
238  *
239  * I have removed the gratuitous use of getenv("RESOURCE_NAME")
240  * which was in X11R5, but left the matching of any prefix of `-name'.
241  * Finally, if all else fails, return `xemacs', as it is more
242  * appropriate (X11R5 returns `main').
243  */
244 static char *
245 compute_x_app_name (int argc, char **argv)
246 {
247   int i;
248   char *ptr;
249
250   for (i = 1; i < argc - 1; i++)
251     if (!strncmp(argv[i], "-name", max (2, strlen (argv[1]))))
252       return argv[i+1];
253
254   if (argc > 0 && argv[0] && *argv[0])
255     return (ptr = strrchr (argv[0], '/')) ? ++ptr : argv[0];
256
257   return "xemacs";
258 }
259
260 /*
261  * This function figures out whether the user has any resources of the
262  * form "XEmacs.foo" or "XEmacs*foo".
263  *
264  * Currently we only consult the display's global resources; to look
265  * for screen specific resources, we would need to also consult:
266  * xdefs = XScreenResourceString(ScreenOfDisplay(dpy, scrno));
267  */
268 static int
269 have_xemacs_resources_in_xrdb (Display *dpy)
270 {
271   char *xdefs, *key;
272   int len;
273
274 #ifdef INFODOCK
275   key = "InfoDock";
276 #else
277   key = "XEmacs";
278 #endif
279   len = strlen (key);
280
281   if (!dpy)
282     return 0;
283
284   xdefs = XResourceManagerString (dpy);      /* don't free - owned by X */
285   while (xdefs && *xdefs)
286     {
287       if (strncmp (xdefs, key, len) == 0  &&
288           (xdefs[len] == '*' || xdefs[len] == '.'))
289         return 1;
290
291       while (*xdefs && *xdefs++ != '\n')     /* find start of next entry.. */
292         ;
293     }
294
295   return 0;
296 }
297
298 /* Only the characters [-_A-Za-z0-9] are allowed in the individual
299    components of a resource.  Convert invalid characters to `-' */
300
301 static char valid_resource_char_p[256];
302
303 static void
304 validify_resource_component (char *str, size_t len)
305 {
306   for (; len; len--, str++)
307     if (!valid_resource_char_p[(unsigned char) (*str)])
308       *str = '-';
309 }
310
311 static void
312 Dynarr_add_validified_lisp_string (char_dynarr *cda, Lisp_Object str)
313 {
314   Bytecount len = XSTRING_LENGTH (str);
315   Dynarr_add_many (cda, (char *) XSTRING_DATA (str), len);
316   validify_resource_component (Dynarr_atp (cda, Dynarr_length (cda) - len), len);
317 }
318
319 static void
320 x_init_device (struct device *d, Lisp_Object props)
321 {
322   Lisp_Object display;
323   Lisp_Object device;
324   Display *dpy;
325   Widget app_shell;
326   int argc;
327   char **argv;
328   CONST char *app_class;
329   CONST char *app_name;
330   CONST char *disp_name;
331   Arg xargs[6];
332   Cardinal numargs;
333   Visual *visual = NULL;
334   int depth = 8;                /* shut up the compiler */
335   Colormap cmap;
336   int screen;
337
338   XSETDEVICE (device, d);
339   display = DEVICE_CONNECTION (d);
340
341   allocate_x_device_struct (d);
342
343   make_argc_argv (Vx_initial_argv_list, &argc, &argv);
344
345   GET_C_STRING_CTEXT_DATA_ALLOCA (display, disp_name);
346
347   /*
348    * Break apart the old XtOpenDisplay call into XOpenDisplay and
349    * XtDisplayInitialize so we can figure out whether there
350    * are any XEmacs resources in the resource database before
351    * we intitialize Xt.  This is so we can automagically support
352    * both `Emacs' and `XEmacs' application classes.
353    */
354   slow_down_interrupts ();
355   /* May not be needed but XtOpenDisplay could not deal with signals here. */
356   dpy = DEVICE_X_DISPLAY (d) = XOpenDisplay (disp_name);
357   speed_up_interrupts ();
358
359   if (dpy == 0)
360     {
361       suppress_early_error_handler_backtrace = 1;
362       signal_simple_error ("X server not responding\n", display);
363     }
364
365   if (STRINGP (Vx_emacs_application_class) &&
366       XSTRING_LENGTH (Vx_emacs_application_class) > 0)
367     GET_C_STRING_CTEXT_DATA_ALLOCA (Vx_emacs_application_class, app_class);
368   else
369     {
370       app_class = (NILP (Vx_emacs_application_class)  &&
371                    have_xemacs_resources_in_xrdb (dpy))
372 #ifdef INFODOCK
373                   ? "InfoDock"
374 #else
375                   ? "XEmacs"
376 #endif
377                   : "Emacs";
378       /* need to update Vx_emacs_application_class: */
379       Vx_emacs_application_class = build_string (app_class);
380     }
381
382   slow_down_interrupts ();
383   /* May not be needed but XtOpenDisplay could not deal with signals here.
384      Yuck. */
385   XtDisplayInitialize (Xt_app_con, dpy, compute_x_app_name (argc, argv),
386                        app_class, emacs_options,
387                        XtNumber (emacs_options), &argc, argv);
388   speed_up_interrupts ();
389
390   screen = DefaultScreen(dpy);
391   if (NILP (Vdefault_x_device))
392     Vdefault_x_device = device;
393
394 #ifdef MULE
395 #if defined(LWLIB_MENUBARS_MOTIF) || defined(HAVE_XIM) || defined (USE_XFONTSET)
396   {
397     /* Read in locale-specific resources from
398        data-directory/app-defaults/$LANG/Emacs.
399        This is in addition to the standard app-defaults files, and
400        does not override resources defined elsewhere */
401     CONST char *data_dir;
402     char *path;
403     XrmDatabase db = XtDatabase (dpy); /* ### XtScreenDatabase(dpy) ? */
404     CONST char *locale = XrmLocaleOfDatabase (db);
405
406     if (STRINGP (Vx_app_defaults_directory) &&
407         XSTRING_LENGTH (Vx_app_defaults_directory) > 0)
408       {
409         GET_C_STRING_FILENAME_DATA_ALLOCA(Vx_app_defaults_directory, data_dir);
410         path = (char *)alloca (strlen (data_dir) + strlen (locale) + 7);
411         sprintf (path, "%s%s/Emacs", data_dir, locale);
412         if (!access (path, R_OK))
413           XrmCombineFileDatabase (path, &db, False);
414       }
415     else if (STRINGP (Vdata_directory) && XSTRING_LENGTH (Vdata_directory) > 0)
416       {
417         GET_C_STRING_FILENAME_DATA_ALLOCA (Vdata_directory, data_dir);
418         path = (char *)alloca (strlen (data_dir) + 13 + strlen (locale) + 7);
419         sprintf (path, "%sapp-defaults/%s/Emacs", data_dir, locale);
420         if (!access (path, R_OK))
421           XrmCombineFileDatabase (path, &db, False);
422       }
423  }
424 #endif /* LWLIB_MENUBARS_MOTIF or HAVE_XIM USE_XFONTSET */
425 #endif /* MULE */
426
427   if (NILP (DEVICE_NAME (d)))
428     DEVICE_NAME (d) = display;
429
430   /* We're going to modify the string in-place, so be a nice XEmacs */
431   DEVICE_NAME (d) = Fcopy_sequence (DEVICE_NAME (d));
432   /* colons and periods can't appear in individual elements of resource
433      strings */
434
435   XtGetApplicationNameAndClass (dpy, (char **) &app_name, (char **) &app_class);
436   /* search for a matching visual if requested by the user, or setup the display default */
437   numargs = 0;
438   {
439     char *buf1 = (char *)alloca (strlen (app_name) + 17);
440     char *buf2 = (char *)alloca (strlen (app_class) + 17);
441     char *type;
442     XrmValue value;
443
444     sprintf (buf1, "%s.emacsVisual", app_name);
445     sprintf (buf2, "%s.EmacsVisual", app_class);
446     if (XrmGetResource (XtDatabase (dpy), buf1, buf2, &type, &value) == True)
447       {
448         int cnt = 0, vis_class= PseudoColor;
449         XVisualInfo vinfo;
450         char *res, *str = (char*)value.addr;
451
452         if      (strncmp(str, "StaticGray", 10) == 0)   cnt = 10, vis_class = StaticGray;
453         else if (strncmp(str, "StaticColor", 11) == 0)  cnt = 11, vis_class = StaticColor;
454         else if (strncmp(str, "TrueColor", 9) == 0)     cnt = 9,  vis_class = TrueColor;
455         else if (strncmp(str, "GrayScale", 9) == 0)     cnt = 9,  vis_class = GrayScale;
456         else if (strncmp(str, "PseudoColor", 11) == 0)  cnt = 11, vis_class = PseudoColor;
457         else if (strncmp(str, "DirectColor", 11) == 0)  cnt = 11, vis_class = DirectColor;
458         if (cnt)
459           {
460             res = str + cnt;
461             depth = atoi(res);
462             if (depth == 0)
463               {
464                 stderr_out("Invalid Depth specification in %s... ignoring...\n",(char*)str);
465               }
466             else
467               {
468                 if (XMatchVisualInfo(dpy, screen, depth, vis_class, &vinfo))
469                   {
470                     visual = vinfo.visual;
471                   }
472                 else
473                   {
474                     stderr_out("Can't match the requested visual %s... using defaults\n",str);
475                   }
476               }
477           }
478         else
479           {
480             stderr_out("Invalid Visual specification in %s... ignoring.\n",(char*)str);
481           }
482       }
483     if (visual == NULL)
484       {
485         visual = DefaultVisual(dpy, screen);
486         depth = DefaultDepth(dpy, screen);
487       }
488
489     /* If we've got the same visual as the default and it's PseudoColor,
490        check to see if the user specified that we need a private colormap */
491     if (visual == DefaultVisual(dpy, screen))
492       {
493         sprintf (buf1, "%s.privateColormap", app_name);
494         sprintf (buf2, "%s.PrivateColormap", app_class);
495         if ((visual->class == PseudoColor) &&
496             (XrmGetResource (XtDatabase (dpy), buf1, buf2, &type, &value) == True))
497           {
498              cmap = XCopyColormapAndFree(dpy, DefaultColormap(dpy, screen));
499           }
500         else
501           {
502             cmap = DefaultColormap(dpy, screen);
503           }
504       }
505     else
506       {
507         /* We have to create a matching colormap anyway...
508            ### think about using standard colormaps (need the Xmu libs?) */
509         cmap = XCreateColormap(dpy, RootWindow(dpy, screen), visual, AllocNone);
510         XInstallColormap(dpy, cmap);
511       }
512   }
513   XtSetArg(xargs[numargs],XtNvisual, visual); numargs++;
514   XtSetArg(xargs[numargs],XtNdepth, depth); numargs++;
515   XtSetArg(xargs[numargs],XtNcolormap, cmap); numargs++;
516   DEVICE_X_VISUAL (d) = visual;
517   DEVICE_X_COLORMAP (d) = cmap;
518   DEVICE_X_DEPTH (d) = depth;
519
520   validify_resource_component ((char *) XSTRING_DATA (DEVICE_NAME (d)),
521                                XSTRING_LENGTH (DEVICE_NAME (d)));
522   app_shell = XtAppCreateShell (NULL, app_class,
523                                 applicationShellWidgetClass,
524                                 dpy, xargs, numargs);
525
526   DEVICE_XT_APP_SHELL (d) = app_shell;
527 #ifdef HAVE_XIM
528   XIM_init_device(d);
529 #endif /* HAVE_XIM */
530
531   /* Realize the app_shell so that its window exists for GC creation purposes,
532      and set it to the size of the root window for child placement purposes */
533   {
534     Screen *scrn = ScreenOfDisplay(dpy, screen);
535     int screen_width, screen_height;
536     screen_width = WidthOfScreen(scrn);
537     screen_height = HeightOfScreen(scrn);
538     numargs = 0;
539     XtSetArg (xargs[numargs], XtNmappedWhenManaged, False); numargs++;
540     XtSetArg (xargs[numargs], XtNx, 0); numargs++;
541     XtSetArg (xargs[numargs], XtNy, 0); numargs++;
542     XtSetArg (xargs[numargs], XtNwidth,  screen_width); numargs++;
543     XtSetArg (xargs[numargs], XtNheight, screen_height); numargs++;
544     XtSetValues (app_shell, xargs, numargs);
545     XtRealizeWidget (app_shell);
546   }
547 #ifdef HAVE_SESSION
548   {
549     int new_argc;
550     char **new_argv;
551     make_argc_argv (Vcommand_line_args, &new_argc, &new_argv);
552     XSetCommand (XtDisplay (app_shell), XtWindow (app_shell), new_argv, new_argc);
553     free_argc_argv (new_argv);
554   }
555 #endif /* HAVE_SESSION */
556
557
558 #ifdef HAVE_OFFIX_DND
559   DndInitialize ( app_shell );
560 #endif
561
562   Vx_initial_argv_list = make_arg_list (argc, argv);
563   free_argc_argv (argv);
564
565   DEVICE_X_WM_COMMAND_FRAME (d) = Qnil;
566
567   sanity_check_geometry_resource (dpy);
568
569   /* In event-Xt.c */
570   x_init_modifier_mapping (d);
571
572   DEVICE_INFD (d) = DEVICE_OUTFD (d) = ConnectionNumber (dpy);
573   init_baud_rate (d);
574   init_one_device (d);
575
576   DEVICE_X_GC_CACHE (d) = make_gc_cache (dpy, XtWindow(app_shell));
577   DEVICE_X_GRAY_PIXMAP (d) = None;
578   Xatoms_of_device_x (d);
579   Xatoms_of_xselect (d);
580   Xatoms_of_objects_x (d);
581   x_init_device_class (d);
582
583   /* Run the elisp side of the X device initialization. */
584   call0 (Qinit_pre_x_win);
585 }
586
587 static void
588 x_finish_init_device (struct device *d, Lisp_Object props)
589 {
590   call0 (Qinit_post_x_win);
591 }
592
593 static void
594 x_mark_device (struct device *d, void (*markobj) (Lisp_Object))
595 {
596   ((markobj) (DEVICE_X_WM_COMMAND_FRAME (d)));
597   ((markobj) (DEVICE_X_DATA (d)->x_keysym_map_hashtable));
598 }
599
600 \f
601 /************************************************************************/
602 /*                       closing an X connection                        */
603 /************************************************************************/
604
605 static void
606 free_x_device_struct (struct device *d)
607 {
608   xfree (d->device_data);
609 }
610
611 static void
612 x_delete_device (struct device *d)
613 {
614   Lisp_Object device;
615   Display *display;
616 #ifdef FREE_CHECKING
617   extern void (*__free_hook)();
618   int checking_free;
619 #endif
620
621   XSETDEVICE (device, d);
622   display = DEVICE_X_DISPLAY (d);
623
624   if (display)
625     {
626 #ifdef FREE_CHECKING
627       checking_free = (__free_hook != 0);
628
629       /* Disable strict free checking, to avoid bug in X library */
630       if (checking_free)
631         disable_strict_free_check ();
632 #endif
633
634       free_gc_cache (DEVICE_X_GC_CACHE (d));
635       if (DEVICE_X_DATA (d)->x_modifier_keymap)
636         XFreeModifiermap (DEVICE_X_DATA (d)->x_modifier_keymap);
637       if (DEVICE_X_DATA (d)->x_keysym_map)
638         XFree ((char *) DEVICE_X_DATA (d)->x_keysym_map);
639
640       XtCloseDisplay (display);
641       DEVICE_X_DISPLAY (d) = 0;
642 #ifdef FREE_CHECKING
643       if (checking_free)
644         enable_strict_free_check ();
645 #endif
646     }
647
648   if (EQ (device, Vdefault_x_device))
649     {
650       Lisp_Object devcons, concons;
651       /* #### handle deleting last X device */
652       Vdefault_x_device = Qnil;
653       DEVICE_LOOP_NO_BREAK (devcons, concons)
654         {
655           if (DEVICE_X_P (XDEVICE (XCAR (devcons))) &&
656               !EQ (device, XCAR (devcons)))
657             {
658               Vdefault_x_device = XCAR (devcons);
659               goto double_break;
660             }
661         }
662     }
663  double_break:
664   free_x_device_struct (d);
665 }
666
667 \f
668 /************************************************************************/
669 /*                              handle X errors                         */
670 /************************************************************************/
671
672 CONST char *
673 x_event_name (int event_type)
674 {
675   static CONST char *events[] =
676   {
677     "0: ERROR!",
678     "1: REPLY",
679     "KeyPress",
680     "KeyRelease",
681     "ButtonPress",
682     "ButtonRelease",
683     "MotionNotify",
684     "EnterNotify",
685     "LeaveNotify",
686     "FocusIn",
687     "FocusOut",
688     "KeymapNotify",
689     "Expose",
690     "GraphicsExpose",
691     "NoExpose",
692     "VisibilityNotify",
693     "CreateNotify",
694     "DestroyNotify",
695     "UnmapNotify",
696     "MapNotify",
697     "MapRequest",
698     "ReparentNotify",
699     "ConfigureNotify",
700     "ConfigureRequest",
701     "GravityNotify",
702     "ResizeRequest",
703     "CirculateNotify",
704     "CirculateRequest",
705     "PropertyNotify",
706     "SelectionClear",
707     "SelectionRequest",
708     "SelectionNotify",
709     "ColormapNotify",
710     "ClientMessage",
711     "MappingNotify",
712     "LASTEvent"
713   };
714
715   if (event_type < 0 || event_type >= countof (events))
716     return NULL;
717   return events [event_type];
718 }
719
720 /* Handling errors.
721
722    If an X error occurs which we are not expecting, we have no alternative
723    but to print it to stderr.  It would be nice to stuff it into a pop-up
724    buffer, or to print it in the minibuffer, but that's not possible, because
725    one is not allowed to do any I/O on the display connection from an error
726    handler. The guts of Xlib expect these functions to either return or exit.
727
728    However, there are occasions when we might expect an error to reasonably
729    occur.  The interface to this is as follows:
730
731    Before calling some X routine which may error, call
732         expect_x_error (dpy);
733
734    Just after calling the X routine, call either:
735
736         x_error_occurred_p (dpy);
737
738    to ask whether an error happened (and was ignored), or:
739
740         signal_if_x_error (dpy, resumable_p);
741
742    which will call Fsignal() with args appropriate to the X error, if there
743    was one.  (Resumable_p is whether the debugger should be allowed to
744    continue from the call to signal.)
745
746    You must call one of these two routines immediately after calling the X
747    routine; think of them as bookends like BLOCK_INPUT and UNBLOCK_INPUT.
748  */
749
750 static int error_expected;
751 static int error_occurred;
752 static XErrorEvent last_error;
753
754 /* OVERKILL! */
755
756 #ifdef EXTERNAL_WIDGET
757 static Lisp_Object
758 x_error_handler_do_enqueue (Lisp_Object frame)
759 {
760   enqueue_magic_eval_event (io_error_delete_frame, frame);
761   return Qt;
762 }
763
764 static Lisp_Object
765 x_error_handler_error (Lisp_Object data, Lisp_Object dummy)
766 {
767   return Qnil;
768 }
769 #endif /* EXTERNAL_WIDGET */
770
771 int
772 x_error_handler (Display *disp, XErrorEvent *event)
773 {
774   if (error_expected)
775     {
776       error_expected = 0;
777       error_occurred = 1;
778       last_error = *event;
779     }
780   else
781     {
782 #ifdef EXTERNAL_WIDGET
783       struct frame *f;
784       struct device *d = get_device_from_display (disp);
785
786       if ((event->error_code == BadWindow ||
787            event->error_code == BadDrawable)
788           && ((f = x_any_window_to_frame (d, event->resourceid)) != 0))
789         {
790           Lisp_Object frame;
791
792         /* one of the windows comprising one of our frames has died.
793            This occurs particularly with ExternalShell frames when the
794            client that owns the ExternalShell's window dies.
795
796            We cannot do any I/O on the display connection so we need
797            to enqueue an eval event so that the deletion happens
798            later.
799
800            Furthermore, we need to trap any errors (out-of-memory) that
801            may occur when Fenqueue_eval_event is called.
802          */
803
804         if (f->being_deleted)
805           return 0;
806         XSETFRAME (frame, f);
807         if (!NILP (condition_case_1 (Qerror, x_error_handler_do_enqueue,
808                                      frame, x_error_handler_error, Qnil)))
809           {
810             f->being_deleted = 1;
811             f->visible = 0;
812           }
813         return 0;
814       }
815 #endif /* EXTERNAL_WIDGET */
816
817       stderr_out ("\n%s: ",
818                   (STRINGP (Vinvocation_name)
819                    ? (char *) XSTRING_DATA (Vinvocation_name)
820                    : "xemacs"));
821       XmuPrintDefaultErrorMessage (disp, event, stderr);
822     }
823   return 0;
824 }
825
826 void
827 expect_x_error (Display *dpy)
828 {
829   assert (!error_expected);
830   XSync (dpy, 0);       /* handle pending errors before setting flag */
831   error_expected = 1;
832   error_occurred = 0;
833 }
834
835 int
836 x_error_occurred_p (Display *dpy)
837 {
838   int val;
839   XSync (dpy, 0);       /* handle pending errors before setting flag */
840   val = error_occurred;
841   error_expected = 0;
842   error_occurred = 0;
843   return val;
844 }
845
846 int
847 signal_if_x_error (Display *dpy, int resumable_p)
848 {
849   char buf[1024];
850   Lisp_Object data;
851   if (! x_error_occurred_p (dpy))
852     return 0;
853   data = Qnil;
854   sprintf (buf, "0x%X", (unsigned int) last_error.resourceid);
855   data = Fcons (build_string (buf), data);
856   {
857     char num [32];
858     sprintf (num, "%d", last_error.request_code);
859     XGetErrorDatabaseText (last_error.display, "XRequest", num, "",
860                            buf, sizeof (buf));
861     if (! *buf)
862       sprintf (buf, "Request-%d", last_error.request_code);
863     data = Fcons (build_string (buf), data);
864   }
865   XGetErrorText (last_error.display, last_error.error_code, buf, sizeof (buf));
866   data = Fcons (build_string (buf), data);
867  again:
868   Fsignal (Qx_error, data);
869   if (! resumable_p) goto again;
870   return 1;
871 }
872
873 int
874 x_IO_error_handler (Display *disp)
875 {
876   /* This function can GC */
877   Lisp_Object dev;
878   struct device *d = get_device_from_display_1 (disp);
879
880   assert (d != NULL);
881   XSETDEVICE (dev, d);
882
883   if (NILP (find_nonminibuffer_frame_not_on_device (dev)))
884     {
885       /* We're going down. */
886       stderr_out
887         ("\n%s: Fatal I/O Error %d (%s) on display connection \"%s\"\n",
888          (STRINGP (Vinvocation_name) ?
889           (char *) XSTRING_DATA (Vinvocation_name) : "xemacs"),
890          errno, strerror (errno), DisplayString (disp));
891       stderr_out
892         ("  after %lu requests (%lu known processed) with %d events remaining.\n",
893          NextRequest (disp) - 1, LastKnownRequestProcessed (disp),
894          QLength (disp));
895       /* assert (!_Xdebug); */
896     }
897   else
898     {
899       warn_when_safe
900         (Qx, Qcritical,
901          "I/O Error %d (%s) on display connection\n"
902          "  \"%s\" after after %lu requests (%lu known processed)\n"
903          "  with %d events remaining.\n"
904          "  Throwing to top level.\n",
905          errno, strerror (errno), DisplayString (disp),
906          NextRequest (disp) - 1, LastKnownRequestProcessed (disp),
907          QLength (disp));
908     }
909
910   /* According to X specs, we should not return from this function, or
911      Xlib might just decide to exit().  So we mark the offending
912      console for deletion and throw to top level.  */
913   if (d)
914     enqueue_magic_eval_event (io_error_delete_device, dev);
915   DEVICE_X_BEING_DELETED (d) = 1;
916   Fthrow (Qtop_level, Qnil);
917
918   RETURN_NOT_REACHED (0);
919 }
920
921 DEFUN ("x-debug-mode", Fx_debug_mode, 1, 2, 0, /*
922 With a true arg, make the connection to the X server synchronous.
923 With false, make it asynchronous.  Synchronous connections are much slower,
924 but are useful for debugging. (If you get X errors, make the connection
925 synchronous, and use a debugger to set a breakpoint on `x_error_handler'.
926 Your backtrace of the C stack will now be useful.  In asynchronous mode,
927 the stack above `x_error_handler' isn't helpful because of buffering.)
928 If DEVICE is not specified, the selected device is assumed.
929
930 Calling this function is the same as calling the C function `XSynchronize',
931 or starting the program with the `-sync' command line argument.
932 */
933        (arg, device))
934 {
935   struct device *d = decode_x_device (device);
936
937   XSynchronize (DEVICE_X_DISPLAY (d), !NILP (arg));
938
939   if (!NILP (arg))
940     message ("X connection is synchronous");
941   else
942     message ("X connection is asynchronous");
943
944   return arg;
945 }
946
947 \f
948 /************************************************************************/
949 /*                             X resources                              */
950 /************************************************************************/
951
952 #if 0 /* bah humbug.  The whole "widget == resource" stuff is such
953          a crock of shit that I'm just going to ignore it all. */
954
955 /* If widget is NULL, we are retrieving device or global face data. */
956
957 static void
958 construct_name_list (Display *display, Widget widget, char *fake_name,
959                      char *fake_class, char *name, char *class)
960 {
961   char *stack [100][2];
962   Widget this;
963   int count = 0;
964   char *name_tail, *class_tail;
965
966   if (widget)
967     {
968       for (this = widget; this; this = XtParent (this))
969         {
970           stack [count][0] = this->core.name;
971           stack [count][1] = XtClass (this)->core_class.class_name;
972           count++;
973         }
974       count--;
975     }
976   else if (fake_name && fake_class)
977     {
978       stack [count][0] = fake_name;
979       stack [count][1] = fake_class;
980       count++;
981     }
982
983   /* The root widget is an application shell; resource lookups use the
984      specified application name and application class in preference to
985      the name/class of that widget (which is argv[0] / "ApplicationShell").
986      Generally the app name and class will be argv[0] / "Emacs" but
987      the former can be set via the -name command-line option, and the
988      latter can be set by changing `x-emacs-application-class' in
989      lisp/term/x-win.el.
990    */
991   XtGetApplicationNameAndClass (display,
992                                 &stack [count][0],
993                                 &stack [count][1]);
994
995   name [0] = 0;
996   class [0] = 0;
997
998   name_tail  = name;
999   class_tail = class;
1000   for (; count >= 0; count--)
1001     {
1002       strcat (name_tail,  stack [count][0]);
1003       for (; *name_tail; name_tail++)
1004         if (*name_tail == '.') *name_tail = '_';
1005       strcat (name_tail, ".");
1006       name_tail++;
1007
1008       strcat (class_tail, stack [count][1]);
1009       for (; *class_tail; class_tail++)
1010         if (*class_tail == '.') *class_tail = '_';
1011       strcat (class_tail, ".");
1012       class_tail++;
1013     }
1014 }
1015
1016 #endif /* 0 */
1017
1018 static char_dynarr *name_char_dynarr;
1019 static char_dynarr *class_char_dynarr;
1020
1021 /* Given a locale and device specification from x-get-resource or
1022 x-get-resource-prefix, return the resource prefix and display to
1023 fetch the resource on. */
1024
1025 static void
1026 x_get_resource_prefix (Lisp_Object locale, Lisp_Object device,
1027                        Display **display_out, char_dynarr *name,
1028                        char_dynarr *class)
1029 {
1030   if (NILP (locale))
1031     locale = Qglobal;
1032   if (NILP (Fvalid_specifier_locale_p (locale)))
1033     signal_simple_error ("Invalid locale", locale);
1034   if (WINDOWP (locale))
1035     /* #### I can't come up with any coherent way of naming windows.
1036        By relative position?  That seems tricky because windows
1037        can change position, be split, etc.  By order of creation?
1038        That seems less than useful. */
1039     signal_simple_error ("Windows currently can't be resourced", locale);
1040
1041   if (!NILP (device) && !DEVICEP (device))
1042     CHECK_DEVICE (device);
1043   if (DEVICEP (device) && !DEVICE_X_P (XDEVICE (device)))
1044     device = Qnil;
1045   if (NILP (device))
1046     {
1047       device = DFW_DEVICE (locale);
1048       if (DEVICEP (device) && !DEVICE_X_P (XDEVICE (device)))
1049         device = Qnil;
1050       if (NILP (device))
1051         device = Vdefault_x_device;
1052       if (NILP (device))
1053         {
1054           *display_out = 0;
1055           return;
1056         }
1057     }
1058
1059   *display_out = DEVICE_X_DISPLAY (XDEVICE (device));
1060
1061   {
1062     char *appname, *appclass;
1063     int name_len, class_len;
1064     XtGetApplicationNameAndClass (*display_out, &appname, &appclass);
1065     name_len  = strlen (appname);
1066     class_len = strlen (appclass);
1067     Dynarr_add_many (name , appname,  name_len);
1068     Dynarr_add_many (class, appclass, class_len);
1069     validify_resource_component (Dynarr_atp (name,  0), name_len);
1070     validify_resource_component (Dynarr_atp (class, 0), class_len);
1071   }
1072
1073   if (EQ (locale, Qglobal))
1074     return;
1075   if (BUFFERP (locale))
1076     {
1077       Dynarr_add_literal_string (name, ".buffer.");
1078       /* we know buffer is live; otherwise we got an error above. */
1079       Dynarr_add_validified_lisp_string (name, Fbuffer_name (locale));
1080       Dynarr_add_literal_string (class, ".EmacsLocaleType.EmacsBuffer");
1081     }
1082   else if (FRAMEP (locale))
1083     {
1084       Dynarr_add_literal_string (name, ".frame.");
1085       /* we know frame is live; otherwise we got an error above. */
1086       Dynarr_add_validified_lisp_string (name, Fframe_name (locale));
1087       Dynarr_add_literal_string (class, ".EmacsLocaleType.EmacsFrame");
1088     }
1089   else
1090     {
1091       assert (DEVICEP (locale));
1092       Dynarr_add_literal_string (name, ".device.");
1093       /* we know device is live; otherwise we got an error above. */
1094       Dynarr_add_validified_lisp_string (name, Fdevice_name (locale));
1095       Dynarr_add_literal_string (class, ".EmacsLocaleType.EmacsDevice");
1096     }
1097   return;
1098 }
1099
1100 DEFUN ("x-get-resource", Fx_get_resource, 3, 6, 0, /*
1101 Retrieve an X resource from the resource manager.
1102
1103 The first arg is the name of the resource to retrieve, such as "font".
1104 The second arg is the class of the resource to retrieve, such as "Font".
1105 The third arg must be one of the symbols 'string, 'integer, 'natnum, or
1106   'boolean, specifying the type of object that the database is searched for.
1107 The fourth arg is the locale to search for the resources on, and can
1108   currently be a buffer, a frame, a device, or 'global.  If omitted, it
1109   defaults to 'global.
1110 The fifth arg is the device to search for the resources on. (The resource
1111   database for a particular device is constructed by combining non-device-
1112   specific resources such as any command-line resources specified and any
1113   app-defaults files found [or the fallback resources supplied by XEmacs,
1114   if no app-defaults file is found] with device-specific resources such as
1115   those supplied using xrdb.) If omitted, it defaults to the device of
1116   LOCALE, if a device can be derived (i.e. if LOCALE is a frame or device),
1117   and otherwise defaults to the value of `default-x-device'.
1118 The sixth arg NOERROR, if non-nil, means do not signal an error if a
1119   bogus resource specification was retrieved (e.g. if a non-integer was
1120   given when an integer was requested).  In this case, a warning is issued
1121   instead.
1122
1123 The resource names passed to this function are looked up relative to the
1124 locale.
1125
1126 If you want to search for a subresource, you just need to specify the
1127 resource levels in NAME and CLASS.  For example, NAME could be
1128 "modeline.attributeFont", and CLASS "Face.AttributeFont".
1129
1130 Specifically,
1131
1132 1) If LOCALE is a buffer, a call
1133
1134     (x-get-resource "foreground" "Foreground" 'string SOME-BUFFER)
1135
1136 is an interface to a C call something like
1137
1138     XrmGetResource (db, "xemacs.buffer.BUFFER-NAME.foreground",
1139                         "Emacs.EmacsLocaleType.EmacsBuffer.Foreground",
1140                         "String");
1141
1142 2) If LOCALE is a frame, a call
1143
1144     (x-get-resource "foreground" "Foreground" 'string SOME-FRAME)
1145
1146 is an interface to a C call something like
1147
1148     XrmGetResource (db, "xemacs.frame.FRAME-NAME.foreground",
1149                         "Emacs.EmacsLocaleType.EmacsFrame.Foreground",
1150                         "String");
1151
1152 3) If LOCALE is a device, a call
1153
1154     (x-get-resource "foreground" "Foreground" 'string SOME-DEVICE)
1155
1156 is an interface to a C call something like
1157
1158     XrmGetResource (db, "xemacs.device.DEVICE-NAME.foreground",
1159                         "Emacs.EmacsLocaleType.EmacsDevice.Foreground",
1160                         "String");
1161
1162 4) If LOCALE is 'global, a call
1163
1164     (x-get-resource "foreground" "Foreground" 'string 'global)
1165
1166 is an interface to a C call something like
1167
1168     XrmGetResource (db, "xemacs.foreground",
1169                         "Emacs.Foreground",
1170                         "String");
1171
1172 Note that for 'global, no prefix is added other than that of the
1173 application itself; thus, you can use this locale to retrieve
1174 arbitrary application resources, if you really want to.
1175
1176 The returned value of this function is nil if the queried resource is not
1177 found.  If the third arg is `string', a string is returned, and if it is
1178 `integer', an integer is returned.  If the third arg is `boolean', then the
1179 returned value is the list (t) for true, (nil) for false, and is nil to
1180 mean ``unspecified.''
1181 */
1182        (name, class, type, locale, device, no_error))
1183 {
1184   char* name_string, *class_string;
1185   char *raw_result;
1186   XrmDatabase db;
1187   Display *display;
1188   Error_behavior errb = decode_error_behavior_flag (no_error);
1189
1190   CHECK_STRING (name);
1191   CHECK_STRING (class);
1192   CHECK_SYMBOL (type);
1193
1194   Dynarr_reset (name_char_dynarr);
1195   Dynarr_reset (class_char_dynarr);
1196
1197   x_get_resource_prefix (locale, device, &display,
1198                          name_char_dynarr, class_char_dynarr);
1199   if (!display)
1200     return Qnil;
1201
1202   db = XtDatabase (display);
1203
1204   Dynarr_add (name_char_dynarr, '.');
1205   Dynarr_add_lisp_string (name_char_dynarr, name);
1206   Dynarr_add (class_char_dynarr, '.');
1207   Dynarr_add_lisp_string (class_char_dynarr, class);
1208   Dynarr_add (name_char_dynarr,  '\0');
1209   Dynarr_add (class_char_dynarr, '\0');
1210
1211   name_string  = Dynarr_atp (name_char_dynarr,  0);
1212   class_string = Dynarr_atp (class_char_dynarr, 0);
1213
1214   {
1215     XrmValue xrm_value;
1216     XrmName namelist[100];
1217     XrmClass classlist[100];
1218     XrmName *namerest = namelist;
1219     XrmClass *classrest = classlist;
1220     XrmRepresentation xrm_type;
1221     XrmRepresentation string_quark;
1222     int result;
1223     XrmStringToNameList (name_string, namelist);
1224     XrmStringToClassList (class_string, classlist);
1225     string_quark = XrmStringToQuark ("String");
1226
1227     /* ensure that they have the same length */
1228     while (namerest[0] && classrest[0])
1229       namerest++, classrest++;
1230     if (namerest[0] || classrest[0])
1231       signal_simple_error_2
1232         ("class list and name list must be the same length", name, class);
1233     result = XrmQGetResource (db, namelist, classlist, &xrm_type, &xrm_value);
1234
1235     if (result != True || xrm_type != string_quark)
1236       return Qnil;
1237     raw_result = (char *) xrm_value.addr;
1238   }
1239
1240   if (EQ (type, Qstring))
1241     return build_string (raw_result);
1242   else if (EQ (type, Qboolean))
1243     {
1244       if (!strcasecmp (raw_result, "off")   ||
1245           !strcasecmp (raw_result, "false") ||
1246           !strcasecmp (raw_result, "no"))
1247         return Fcons (Qnil, Qnil);
1248       if (!strcasecmp (raw_result, "on")   ||
1249           !strcasecmp (raw_result, "true") ||
1250           !strcasecmp (raw_result, "yes"))
1251         return Fcons (Qt, Qnil);
1252       return maybe_continuable_error
1253         (Qresource, errb,
1254          "can't convert %s: %s to a Boolean", name_string, raw_result);
1255     }
1256   else if (EQ (type, Qinteger) || EQ (type, Qnatnum))
1257     {
1258       int i;
1259       char c;
1260       if (1 != sscanf (raw_result, "%d%c", &i, &c))
1261         return maybe_continuable_error
1262           (Qresource, errb,
1263            "can't convert %s: %s to an integer", name_string, raw_result);
1264       else if (EQ (type, Qnatnum) && i < 0)
1265         return maybe_continuable_error
1266           (Qresource, errb,
1267            "invalid numerical value %d for resource %s", i, name_string);
1268       else
1269         return make_int (i);
1270     }
1271   else
1272     {
1273       return maybe_signal_continuable_error
1274         (Qwrong_type_argument,
1275          list2 (build_translated_string
1276                 ("should be string, integer, natnum or boolean"),
1277                 type),
1278          Qresource, errb);
1279     }
1280 }
1281
1282 DEFUN ("x-get-resource-prefix", Fx_get_resource_prefix, 1, 2, 0, /*
1283 Return the resource prefix for LOCALE on DEVICE.
1284 The resource prefix is the strings used to prefix resources if
1285 the LOCALE and DEVICE arguments were passed to `x-get-resource'.
1286 The returned value is a cons of a name prefix and a class prefix.
1287 For example, if LOCALE is a frame, the returned value might be
1288 \("xemacs.frame.FRAME-NAME" . "Emacs.EmacsLocaleType.EmacsFrame").
1289 If no valid X device for resourcing can be obtained, this function
1290 returns nil. (In such a case, `x-get-resource' would always return nil.)
1291 */
1292        (locale, device))
1293 {
1294   Display *display;
1295
1296   Dynarr_reset (name_char_dynarr );
1297   Dynarr_reset (class_char_dynarr);
1298
1299   x_get_resource_prefix (locale, device, &display,
1300                          name_char_dynarr, class_char_dynarr);
1301   if (!display)
1302     return Qnil;
1303
1304   return Fcons (make_string ((Bufbyte *) Dynarr_atp (name_char_dynarr, 0),
1305                              Dynarr_length (name_char_dynarr)),
1306                 make_string ((Bufbyte *) Dynarr_atp (class_char_dynarr, 0),
1307                              Dynarr_length (class_char_dynarr)));
1308 }
1309
1310 DEFUN ("x-put-resource", Fx_put_resource, 1, 2, 0, /*
1311 Add a resource to the resource database for DEVICE.
1312 RESOURCE-LINE specifies the resource to add and should be a
1313 standard resource specification.
1314 */
1315        (resource_line, device))
1316 {
1317   struct device *d = decode_device (device);
1318   char *str, *colon_pos;
1319
1320   CHECK_STRING (resource_line);
1321   str = (char *) XSTRING_DATA (resource_line);
1322   if (!(colon_pos = strchr (str, ':')) || strchr (str, '\n'))
1323   invalid:
1324     signal_simple_error ("Invalid resource line", resource_line);
1325   if (strspn (str,
1326               /* Only the following chars are allowed before the colon */
1327               " \t.*?abcdefghijklmnopqrstuvwxyz"
1328               "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-")
1329       != (size_t) (colon_pos - str))
1330     goto invalid;
1331
1332   if (DEVICE_X_P (d))
1333     {
1334       XrmDatabase db = XtDatabase (DEVICE_X_DISPLAY (d));
1335       XrmPutLineResource (&db, str);
1336     }
1337
1338   return Qnil;
1339 }
1340
1341 \f
1342 /************************************************************************/
1343 /*                   display information functions                      */
1344 /************************************************************************/
1345
1346 DEFUN ("default-x-device", Fdefault_x_device, 0, 0, 0, /*
1347 Return the default X device for resourcing.
1348 This is the first-created X device that still exists.
1349 */
1350        ())
1351 {
1352   return Vdefault_x_device;
1353 }
1354
1355 DEFUN ("x-display-visual-class", Fx_display_visual_class, 0, 1, 0, /*
1356 Return the visual class of the X display DEVICE is using.
1357 This can be altered from the default at startup using the XResource "EmacsVisual".
1358 The returned value will be one of the symbols `static-gray', `gray-scale',
1359 `static-color', `pseudo-color', `true-color', or `direct-color'.
1360 */
1361        (device))
1362 {
1363   Visual *vis = DEVICE_X_VISUAL (decode_x_device (device));
1364   switch (vis->class)
1365     {
1366     case StaticGray:  return intern ("static-gray");
1367     case GrayScale:   return intern ("gray-scale");
1368     case StaticColor: return intern ("static-color");
1369     case PseudoColor: return intern ("pseudo-color");
1370     case TrueColor:   return intern ("true-color");
1371     case DirectColor: return intern ("direct-color");
1372     default:
1373       error ("display has an unknown visual class");
1374       return Qnil;      /* suppress compiler warning */
1375     }
1376 }
1377
1378 DEFUN ("x-display-visual-depth", Fx_display_visual_depth, 0, 1, 0, /*
1379 Return the bitplane depth of the visual the X display DEVICE is using.
1380 */
1381        (device))
1382 {
1383    return make_int (DEVICE_X_DEPTH (decode_x_device (device)));
1384 }
1385
1386 static Lisp_Object
1387 x_device_system_metrics (struct device *d,
1388                          enum device_metrics m)
1389 {
1390   Display *dpy = DEVICE_X_DISPLAY (d);
1391
1392   switch (m)
1393     {
1394     case DM_size_device:
1395       return Fcons (make_int (DisplayWidth (dpy, DefaultScreen (dpy))),
1396                     make_int (DisplayHeight (dpy, DefaultScreen (dpy))));
1397     case DM_size_device_mm:
1398       return Fcons (make_int (DisplayWidthMM (dpy, DefaultScreen (dpy))),
1399                     make_int (DisplayHeightMM (dpy, DefaultScreen (dpy))));
1400     case DM_num_bit_planes:
1401       return make_int (DisplayPlanes (dpy, DefaultScreen (dpy)));
1402     case DM_num_color_cells:
1403       return make_int (DisplayCells (dpy, DefaultScreen (dpy)));
1404     default: /* No such device metric property for X devices  */
1405       return Qunbound;
1406     }
1407 }
1408
1409 DEFUN ("x-server-vendor", Fx_server_vendor, 0, 1, 0, /*
1410 Return the vendor ID string of the X server DEVICE is on.
1411 Return the empty string if the vendor ID string cannot be determined.
1412 */
1413        (device))
1414 {
1415   Display *dpy = get_x_display (device);
1416   char *vendor = ServerVendor (dpy);
1417
1418   return build_string (vendor ? vendor : "");
1419 }
1420
1421 DEFUN ("x-server-version", Fx_server_version, 0, 1, 0, /*
1422 Return the version numbers of the X server DEVICE is on.
1423 The returned value is a list of three integers: the major and minor
1424 version numbers of the X Protocol in use, and the vendor-specific release
1425 number.  See also `x-server-vendor'.
1426 */
1427        (device))
1428 {
1429   Display *dpy = get_x_display (device);
1430
1431   return list3 (make_int (ProtocolVersion  (dpy)),
1432                 make_int (ProtocolRevision (dpy)),
1433                 make_int (VendorRelease    (dpy)));
1434 }
1435
1436 DEFUN ("x-valid-keysym-name-p", Fx_valid_keysym_name_p, 1, 1, 0, /*
1437 Return true if KEYSYM names a keysym that the X library knows about.
1438 Valid keysyms are listed in the files /usr/include/X11/keysymdef.h and in
1439 /usr/lib/X11/XKeysymDB, or whatever the equivalents are on your system.
1440 */
1441        (keysym))
1442 {
1443   CONST char *keysym_ext;
1444
1445   CHECK_STRING (keysym);
1446   GET_C_STRING_CTEXT_DATA_ALLOCA (keysym, keysym_ext);
1447
1448   return XStringToKeysym (keysym_ext) ? Qt : Qnil;
1449 }
1450
1451 DEFUN ("x-keysym-hashtable", Fx_keysym_hashtable, 0, 1, 0, /*
1452 Return a hashtable which contains a hash key for all keysyms which
1453 name keys on the keyboard.  See `x-keysym-on-keyboard-p'.
1454 */
1455        (device))
1456 {
1457   struct device *d = decode_device (device);
1458   if (!DEVICE_X_P (d))
1459     signal_simple_error ("Not an X device", device);
1460
1461   return DEVICE_X_DATA (d)->x_keysym_map_hashtable;
1462 }
1463
1464 DEFUN ("x-keysym-on-keyboard-sans-modifiers-p", Fx_keysym_on_keyboard_sans_modifiers_p,
1465        1, 2, 0, /*
1466 Return true if KEYSYM names a key on the keyboard of DEVICE.
1467 More precisely, return true if pressing a physical key
1468 on the keyboard of DEVICE without any modifier keys generates KEYSYM.
1469 Valid keysyms are listed in the files /usr/include/X11/keysymdef.h and in
1470 /usr/lib/X11/XKeysymDB, or whatever the equivalents are on your system.
1471 The keysym name can be provided in two forms:
1472 - if keysym is a string, it must be the name as known to X windows.
1473 - if keysym is a symbol, it must be the name as known to XEmacs.
1474 The two names differ in capitalization and underscoring.
1475 */
1476        (keysym, device))
1477 {
1478   struct device *d = decode_device (device);
1479   if (!DEVICE_X_P (d))
1480     signal_simple_error ("Not an X device", device);
1481
1482   return (EQ (Qsans_modifiers,
1483               Fgethash (keysym, DEVICE_X_KEYSYM_MAP_HASHTABLE (d), Qnil)) ?
1484           Qt : Qnil);
1485 }
1486
1487
1488 DEFUN ("x-keysym-on-keyboard-p", Fx_keysym_on_keyboard_p, 1, 2, 0, /*
1489 Return true if KEYSYM names a key on the keyboard of DEVICE.
1490 More precisely, return true if some keystroke (possibly including modifiers)
1491 on the keyboard of DEVICE keys generates KEYSYM.
1492 Valid keysyms are listed in the files /usr/include/X11/keysymdef.h and in
1493 /usr/lib/X11/XKeysymDB, or whatever the equivalents are on your system.
1494 The keysym name can be provided in two forms:
1495 - if keysym is a string, it must be the name as known to X windows.
1496 - if keysym is a symbol, it must be the name as known to XEmacs.
1497 The two names differ in capitalization and underscoring.
1498 */
1499        (keysym, device))
1500 {
1501   struct device *d = decode_device (device);
1502   if (!DEVICE_X_P (d))
1503     signal_simple_error ("Not an X device", device);
1504
1505   return (NILP (Fgethash (keysym, DEVICE_X_KEYSYM_MAP_HASHTABLE (d), Qnil)) ?
1506           Qnil : Qt);
1507 }
1508
1509 \f
1510 /************************************************************************/
1511 /*                          grabs and ungrabs                           */
1512 /************************************************************************/
1513
1514 DEFUN ("x-grab-pointer", Fx_grab_pointer, 0, 3, 0, /*
1515 Grab the pointer and restrict it to its current window.
1516 If optional DEVICE argument is nil, the default device will be used.
1517 If optional CURSOR argument is non-nil, change the pointer shape to that
1518  until `x-ungrab-pointer' is called (it should be an object returned by the
1519  `make-cursor-glyph' function).
1520 If the second optional argument IGNORE-KEYBOARD is non-nil, ignore all
1521   keyboard events during the grab.
1522 Returns t if the grab is successful, nil otherwise.
1523 */
1524        (device, cursor, ignore_keyboard))
1525 {
1526   Window w;
1527   int pointer_mode, result;
1528   struct device *d = decode_x_device (device);
1529
1530   if (!NILP (cursor))
1531     {
1532       CHECK_POINTER_GLYPH (cursor);
1533       cursor = glyph_image_instance (cursor, device, ERROR_ME, 0);
1534     }
1535
1536   if (!NILP (ignore_keyboard))
1537     pointer_mode = GrabModeSync;
1538   else
1539     pointer_mode = GrabModeAsync;
1540
1541   w = XtWindow (FRAME_X_TEXT_WIDGET (device_selected_frame (d)));
1542
1543   /* #### Possibly this needs to gcpro the cursor somehow, but it doesn't
1544      seem to cause a problem if XFreeCursor is called on a cursor in use
1545      in a grab; I suppose the X server counts the grab as a reference
1546      and doesn't free it until it exits? */
1547   result = XGrabPointer (DEVICE_X_DISPLAY (d), w,
1548                          False,
1549                          ButtonMotionMask  |
1550                          ButtonPressMask   |
1551                          ButtonReleaseMask |
1552                          PointerMotionHintMask,
1553                          GrabModeAsync,       /* Keep pointer events flowing */
1554                          pointer_mode,        /* Stall keyboard events */
1555                          w,                   /* Stay in this window */
1556                          (NILP (cursor) ? 0
1557                           : XIMAGE_INSTANCE_X_CURSOR (cursor)),
1558                          CurrentTime);
1559   return (result == GrabSuccess) ? Qt : Qnil;
1560 }
1561
1562 DEFUN ("x-ungrab-pointer", Fx_ungrab_pointer, 0, 1, 0, /*
1563 Release a pointer grab made with `x-grab-pointer'.
1564 If optional first arg DEVICE is nil the default device is used.
1565 If it is t the pointer will be released on all X devices.
1566 */
1567        (device))
1568 {
1569   if (!EQ (device, Qt))
1570     {
1571       Display *dpy = get_x_display (device);
1572       XUngrabPointer (dpy, CurrentTime);
1573     }
1574   else
1575     {
1576       Lisp_Object devcons, concons;
1577
1578       DEVICE_LOOP_NO_BREAK (devcons, concons)
1579         {
1580           struct device *d = XDEVICE (XCAR (devcons));
1581
1582           if (DEVICE_X_P (d))
1583             XUngrabPointer (DEVICE_X_DISPLAY (d), CurrentTime);
1584         }
1585     }
1586
1587   return Qnil;
1588 }
1589
1590 DEFUN ("x-grab-keyboard", Fx_grab_keyboard, 0, 1, 0, /*
1591 Grab the keyboard on the given device (defaulting to the selected one).
1592 So long as the keyboard is grabbed, all keyboard events will be delivered
1593 to emacs -- it is not possible for other X clients to eavesdrop on them.
1594 Ungrab the keyboard with `x-ungrab-keyboard' (use an unwind-protect).
1595 Returns t if the grab was successful; nil otherwise.
1596 */
1597        (device))
1598 {
1599   struct device *d = decode_x_device (device);
1600   Window w = XtWindow (FRAME_X_TEXT_WIDGET (device_selected_frame (d)));
1601   Display *dpy = DEVICE_X_DISPLAY (d);
1602   Status status;
1603   XSync (dpy, False);
1604   status = XGrabKeyboard (dpy, w, True,
1605                           /* I don't really understand sync-vs-async
1606                              grabs, but this is what xterm does. */
1607                           GrabModeAsync, GrabModeAsync,
1608                           /* Use the timestamp of the last user action
1609                              read by emacs proper; xterm uses CurrentTime
1610                              but there's a comment that says "wrong"...
1611                              (Despite the name this is the time of the
1612                              last key or mouse event.) */
1613                           DEVICE_X_MOUSE_TIMESTAMP (d));
1614   if (status == GrabSuccess)
1615     {
1616       /* The XUngrabKeyboard should generate a FocusIn back to this
1617          window but it doesn't unless we explicitly set focus to the
1618          window first (which should already have it.  The net result
1619          is that without this call when x-ungrab-keyboard is called
1620          the selected frame ends up not having focus. */
1621       XSetInputFocus (dpy, w, RevertToParent, DEVICE_X_MOUSE_TIMESTAMP (d));
1622       return Qt;
1623     }
1624   else
1625     return Qnil;
1626 }
1627
1628 DEFUN ("x-ungrab-keyboard", Fx_ungrab_keyboard, 0, 1, 0, /*
1629 Release a keyboard grab made with `x-grab-keyboard'.
1630 */
1631        (device))
1632 {
1633   Display *dpy = get_x_display (device);
1634   XUngrabKeyboard (dpy, CurrentTime);
1635   return Qnil;
1636 }
1637
1638 \f
1639 /************************************************************************/
1640 /*                            initialization                            */
1641 /************************************************************************/
1642
1643 void
1644 syms_of_device_x (void)
1645 {
1646   DEFSUBR (Fx_debug_mode);
1647   DEFSUBR (Fx_get_resource);
1648   DEFSUBR (Fx_get_resource_prefix);
1649   DEFSUBR (Fx_put_resource);
1650
1651   DEFSUBR (Fdefault_x_device);
1652   DEFSUBR (Fx_display_visual_class);
1653   DEFSUBR (Fx_display_visual_depth);
1654   DEFSUBR (Fx_server_vendor);
1655   DEFSUBR (Fx_server_version);
1656   DEFSUBR (Fx_valid_keysym_name_p);
1657   DEFSUBR (Fx_keysym_hashtable);
1658   DEFSUBR (Fx_keysym_on_keyboard_p);
1659   DEFSUBR (Fx_keysym_on_keyboard_sans_modifiers_p);
1660
1661   DEFSUBR (Fx_grab_pointer);
1662   DEFSUBR (Fx_ungrab_pointer);
1663   DEFSUBR (Fx_grab_keyboard);
1664   DEFSUBR (Fx_ungrab_keyboard);
1665
1666   defsymbol (&Qx_error, "x-error");
1667   defsymbol (&Qinit_pre_x_win, "init-pre-x-win");
1668   defsymbol (&Qinit_post_x_win, "init-post-x-win");
1669 }
1670
1671 void
1672 console_type_create_device_x (void)
1673 {
1674   CONSOLE_HAS_METHOD (x, init_device);
1675   CONSOLE_HAS_METHOD (x, finish_init_device);
1676   CONSOLE_HAS_METHOD (x, mark_device);
1677   CONSOLE_HAS_METHOD (x, delete_device);
1678   CONSOLE_HAS_METHOD (x, device_system_metrics);
1679
1680   {
1681     /* Initialize variables to speed up X resource interactions */
1682     CONST char *valid_resource_chars =
1683       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
1684     while (*valid_resource_chars)
1685       valid_resource_char_p[(unsigned int) (*valid_resource_chars++)] = 1;
1686
1687     name_char_dynarr  = Dynarr_new (char);
1688     class_char_dynarr = Dynarr_new (char);
1689   }
1690 }
1691
1692 void
1693 vars_of_device_x (void)
1694 {
1695   DEFVAR_LISP ("x-emacs-application-class", &Vx_emacs_application_class /*
1696 The X application class of the XEmacs process.
1697 This controls, among other things, the name of the `app-defaults' file
1698 that XEmacs will use.  For changes to this variable to take effect, they
1699 must be made before the connection to the X server is initialized, that is,
1700 this variable may only be changed before emacs is dumped, or by setting it
1701 in the file lisp/term/x-win.el.
1702
1703 If this variable is nil before the connection to the X server is first
1704 initialized (which it is by default), the X resource database will be
1705 consulted and the value will be set according to whether any resources
1706 are found for the application class `XEmacs'.  If the user has set any
1707 resources for the XEmacs application class, the XEmacs process will use
1708 the application class `XEmacs'.  Otherwise, the XEmacs process will use
1709 the application class `Emacs' which is backwards compatible to previous
1710 XEmacs versions but may conflict with resources intended for GNU Emacs.
1711 */ );
1712   Vx_emacs_application_class = Qnil;
1713
1714   DEFVAR_LISP ("x-initial-argv-list", &Vx_initial_argv_list /*
1715 You don't want to know.
1716 This is used during startup to communicate the remaining arguments in
1717 `command-line-args-left' to the C code, which passes the args to
1718 the X initialization code, which removes some args, and then the
1719 args are placed back into `x-initial-arg-list' and thence into
1720 `command-line-args-left'.  Perhaps `command-line-args-left' should
1721 just reside in C.
1722 */ );
1723   Vx_initial_argv_list = Qnil;
1724
1725 #if defined(MULE) && (defined(LWLIB_MENUBARS_MOTIF) || defined(HAVE_XIM) || defined (USE_XFONTSET))
1726   DEFVAR_LISP ("x-app-defaults-directory", &Vx_app_defaults_directory /*
1727 Used by the Lisp code to communicate to the low level X initialization
1728 where the localized init files are.
1729 */ );
1730   Vx_app_defaults_directory = Qnil;
1731 #endif
1732
1733   Fprovide (Qx);
1734
1735   staticpro (&Vdefault_x_device);
1736   Vdefault_x_device = Qnil;
1737
1738   error_expected = 0;
1739   error_occurred = 0;
1740
1741   in_resource_setting = 0;
1742 }