XEmacs 21.2-b2
[chise/xemacs-chise.git.1] / src / device.c
1  /* Generic device functions.
2    Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
3    Copyright (C) 1994, 1995 Free Software Foundation, Inc.
4    Copyright (C) 1995, 1996 Ben Wing
5
6 This file is part of XEmacs.
7
8 XEmacs is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any
11 later version.
12
13 XEmacs is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with XEmacs; see the file COPYING.  If not, write to
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.  */
22
23 /* Synched up with: Not in FSF. */
24
25 /* Original version by Chuck Thompson;
26    rewritten and expanded by Ben Wing. */
27
28 #include <config.h>
29 #include "lisp.h"
30
31 #include "buffer.h"
32 #include "console.h"
33 #include "device.h"
34 #include "elhash.h"
35 #include "events.h"
36 #include "faces.h"
37 #include "frame.h"
38 #include "keymap.h"
39 #include "redisplay.h"
40 #include "scrollbar.h"
41 #include "specifier.h"
42 #include "sysdep.h"
43 #include "window.h"
44
45 #include "syssignal.h"
46
47 /* Vdefault_device is the firstly-created non-stream device that's still
48    around.  We don't really use it anywhere currently, but it might
49    be used for resourcing at some point.  (Currently we use
50    Vdefault_x_device.) */
51 Lisp_Object Vdefault_device;
52
53 Lisp_Object Vcreate_device_hook, Vdelete_device_hook;
54
55 /* Device classes */
56 /* Qcolor defined in general.c */
57 Lisp_Object Qgrayscale, Qmono;
58
59 /* Device metrics symbols */
60 Lisp_Object
61   Qcolor_default, Qcolor_select, Qcolor_balloon, Qcolor_3d_face,
62   Qcolor_3d_light, Qcolor_3d_dark, Qcolor_menu, Qcolor_menu_highlight,
63   Qcolor_menu_button, Qcolor_menu_disabled, Qcolor_toolbar,
64   Qcolor_scrollbar, Qcolor_desktop, Qcolor_workspace, Qfont_default,
65   Qfont_menubar, Qfont_dialog, Qsize_cursor, Qsize_scrollbar,
66   Qsize_menu, Qsize_toolbar, Qsize_toolbar_button,
67   Qsize_toolbar_border, Qsize_icon, Qsize_icon_small, Qsize_device,
68   Qsize_workspace, Qsize_device_mm, Qdevice_dpi, Qnum_bit_planes,
69   Qnum_color_cells, Qmouse_buttons, Qswap_buttons, Qshow_sounds,
70   Qslow_device, Qsecurity;
71
72 Lisp_Object Qdevicep, Qdevice_live_p;
73 Lisp_Object Qdelete_device;
74 Lisp_Object Qcreate_device_hook;
75 Lisp_Object Qdelete_device_hook;
76
77 Lisp_Object Vdevice_class_list;
78
79 \f
80 static Lisp_Object
81 mark_device (Lisp_Object obj, void (*markobj) (Lisp_Object))
82 {
83   struct device *d = XDEVICE (obj);
84
85   ((markobj) (d->name));
86   ((markobj) (d->connection));
87   ((markobj) (d->canon_connection));
88   ((markobj) (d->console));
89   ((markobj) (d->_selected_frame));
90   ((markobj) (d->frame_with_focus_real));
91   ((markobj) (d->frame_with_focus_for_hooks));
92   ((markobj) (d->frame_that_ought_to_have_focus));
93   ((markobj) (d->device_class));
94   ((markobj) (d->user_defined_tags));
95   ((markobj) (d->pixel_to_glyph_cache.obj1));
96   ((markobj) (d->pixel_to_glyph_cache.obj2));
97
98   ((markobj) (d->color_instance_cache));
99   ((markobj) (d->font_instance_cache));
100 #ifdef MULE
101   ((markobj) (d->charset_font_cache));
102 #endif
103   ((markobj) (d->image_instance_cache));
104
105   if (d->devmeths)
106     {
107       ((markobj) (d->devmeths->symbol));
108       MAYBE_DEVMETH (d, mark_device, (d, markobj));
109     }
110
111   return (d->frame_list);
112 }
113
114 static void
115 print_device (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
116 {
117   struct device *d = XDEVICE (obj);
118   char buf[256];
119
120   if (print_readably)
121     error ("printing unreadable object #<device %s 0x%x>",
122            XSTRING_DATA (d->name), d->header.uid);
123
124   sprintf (buf, "#<%s-device", !DEVICE_LIVE_P (d) ? "dead" :
125            DEVICE_TYPE_NAME (d));
126   write_c_string (buf, printcharfun);
127   if (DEVICE_LIVE_P (d))
128     {
129       write_c_string (" on ", printcharfun);
130       print_internal (DEVICE_CONNECTION (d), printcharfun, 1);
131     }
132   sprintf (buf, " 0x%x>", d->header.uid);
133   write_c_string (buf, printcharfun);
134 }
135
136 DEFINE_LRECORD_IMPLEMENTATION ("device", device,
137                                mark_device, print_device, 0, 0, 0,
138                                struct device);
139 \f
140 int
141 valid_device_class_p (Lisp_Object class)
142 {
143   return !NILP (memq_no_quit (class, Vdevice_class_list));
144 }
145
146 DEFUN ("valid-device-class-p", Fvalid_device_class_p, 1, 1, 0, /*
147 Given a DEVICE-CLASS, return t if it is valid.
148 Valid classes are 'color, 'grayscale, and 'mono.
149 */
150        (device_class))
151 {
152   return valid_device_class_p (device_class) ? Qt : Qnil;
153 }
154
155 DEFUN ("device-class-list", Fdevice_class_list, 0, 0, 0, /*
156 Return a list of valid device classes.
157 */
158        ())
159 {
160   return Fcopy_sequence (Vdevice_class_list);
161 }
162
163 static struct device *
164 allocate_device (Lisp_Object console)
165 {
166   Lisp_Object device;
167   struct device *d = alloc_lcrecord_type (struct device, lrecord_device);
168   struct gcpro gcpro1;
169
170   zero_lcrecord (d);
171
172   XSETDEVICE (device, d);
173   GCPRO1 (device);
174
175   d->name = Qnil;
176   d->console = console;
177   d->connection = Qnil;
178   d->canon_connection = Qnil;
179   d->frame_list = Qnil;
180   d->_selected_frame = Qnil;
181   d->frame_with_focus_real = Qnil;
182   d->frame_with_focus_for_hooks = Qnil;
183   d->frame_that_ought_to_have_focus = Qnil;
184   d->device_class = Qnil;
185   d->user_defined_tags = Qnil;
186   d->pixel_to_glyph_cache.obj1 = Qnil;
187   d->pixel_to_glyph_cache.obj2 = Qnil;
188
189   d->infd = d->outfd = -1;
190
191   /* #### is 20 reasonable? */
192   d->color_instance_cache = make_lisp_hashtable (20, HASHTABLE_KEY_WEAK,
193                                                  HASHTABLE_EQUAL);
194   d->font_instance_cache = make_lisp_hashtable (20, HASHTABLE_KEY_WEAK,
195                                                 HASHTABLE_EQUAL);
196 #ifdef MULE
197   /* Note that the following table is bi-level. */
198   d->charset_font_cache = make_lisp_hashtable (20, HASHTABLE_NONWEAK,
199                                                HASHTABLE_EQ);
200 #endif
201   /*
202      Note that the image instance cache is actually bi-level.
203      See device.h.  We use a low number here because most of the
204      time there aren't very many diferent masks that will be used.
205      */
206   d->image_instance_cache = make_lisp_hashtable (5, HASHTABLE_NONWEAK,
207                                                  HASHTABLE_EQ);
208
209   UNGCPRO;
210   return d;
211 }
212
213 struct device *
214 decode_device (Lisp_Object device)
215 {
216   if (NILP (device))
217     device = Fselected_device (Qnil);
218   /* quietly accept frames for the device arg */
219   if (FRAMEP (device))
220     device = FRAME_DEVICE (decode_frame (device));
221   CHECK_LIVE_DEVICE (device);
222   return XDEVICE (device);
223 }
224
225 DEFUN ("dfw-device", Fdfw_device, 1, 1, 0, /*
226 Given a device, frame, or window, return the associated device.
227 Return nil otherwise.
228 */
229        (obj))
230 {
231   return DFW_DEVICE (obj);
232 }
233
234 \f
235 DEFUN ("selected-device", Fselected_device, 0, 1, 0, /*
236 Return the device which is currently active.
237 If optional CONSOLE is non-nil, return the device that would be currently
238 active if CONSOLE were the selected console.
239 */
240        (console))
241 {
242   if (NILP (console) && NILP (Vselected_console))
243     return Qnil; /* happens early in temacs */
244   return CONSOLE_SELECTED_DEVICE (decode_console (console));
245 }
246
247 /* Called from selected_frame_1(), called from Fselect_window() */
248 void
249 select_device_1 (Lisp_Object device)
250 {
251   struct device *dev = XDEVICE (device);
252   Lisp_Object old_selected_device = Fselected_device (Qnil);
253
254   if (EQ (device, old_selected_device))
255     return;
256
257   /* now select the device's console */
258   CONSOLE_SELECTED_DEVICE (XCONSOLE (DEVICE_CONSOLE (dev))) = device;
259   select_console_1 (DEVICE_CONSOLE (dev));
260 }
261
262 DEFUN ("select-device", Fselect_device, 1, 1, 0, /*
263 Select the device DEVICE.
264 Subsequent editing commands apply to its console, selected frame,
265 and selected window.
266 The selection of DEVICE lasts until the next time the user does
267 something to select a different device, or until the next time this
268 function is called.
269 */
270        (device))
271 {
272   CHECK_LIVE_DEVICE (device);
273
274   /* select the device's selected frame's selected window.  This will call
275      selected_frame_1()->selected_device_1()->selected_console_1(). */
276   if (!NILP (DEVICE_SELECTED_FRAME (XDEVICE (device))))
277     Fselect_window (FRAME_SELECTED_WINDOW
278                     (XFRAME (DEVICE_SELECTED_FRAME (XDEVICE (device)))),
279                     Qnil);
280   else
281     error ("Can't select a device with no frames");
282   return Qnil;
283 }
284
285 void
286 set_device_selected_frame (struct device *d, Lisp_Object frame)
287 {
288   if (!NILP (frame) && !FRAME_MINIBUF_ONLY_P (XFRAME (frame)))
289     set_console_last_nonminibuf_frame (XCONSOLE (DEVICE_CONSOLE (d)), frame);
290   d->_selected_frame = frame;
291 }
292
293 DEFUN ("set-device-selected-frame", Fset_device_selected_frame, 2, 2, 0, /*
294 Set the selected frame of device object DEVICE to FRAME.
295 If DEVICE is nil, the selected device is used.
296 If DEVICE is the selected device, this makes FRAME the selected frame.
297 */
298        (device, frame))
299 {
300   XSETDEVICE (device, decode_device (device));
301   CHECK_LIVE_FRAME (frame);
302
303   if (! EQ (device, FRAME_DEVICE (XFRAME (frame))))
304     error ("In `set-device-selected-frame', FRAME is not on DEVICE");
305
306   if (EQ (device, Fselected_device (Qnil)))
307     return Fselect_frame (frame);
308
309   set_device_selected_frame (XDEVICE (device), frame);
310   return frame;
311 }
312
313 DEFUN ("devicep", Fdevicep, 1, 1, 0, /*
314 Return non-nil if OBJECT is a device.
315 */
316        (object))
317 {
318   return DEVICEP (object) ? Qt : Qnil;
319 }
320
321 DEFUN ("device-live-p", Fdevice_live_p, 1, 1, 0, /*
322 Return non-nil if OBJECT is a device that has not been deleted.
323 */
324        (object))
325 {
326   return DEVICEP (object) && DEVICE_LIVE_P (XDEVICE (object)) ? Qt : Qnil;
327 }
328
329 DEFUN ("device-name", Fdevice_name, 0, 1, 0, /*
330 Return the name of the specified device.
331 DEVICE defaults to the selected device if omitted.
332 */
333        (device))
334 {
335   return DEVICE_NAME (decode_device (device));
336 }
337
338 DEFUN ("device-connection", Fdevice_connection, 0, 1, 0, /*
339 Return the connection of the specified device.
340 DEVICE defaults to the selected device if omitted.
341 */
342        (device))
343 {
344   return DEVICE_CONNECTION (decode_device (device));
345 }
346
347 DEFUN ("device-console", Fdevice_console, 0, 1, 0, /*
348 Return the console of the specified device.
349 DEVICE defaults to the selected device if omitted.
350 */
351        (device))
352 {
353   return DEVICE_CONSOLE (decode_device (device));
354 }
355
356 #ifdef HAVE_WINDOW_SYSTEM
357
358 static void
359 init_global_resources (struct device *d)
360 {
361   init_global_faces (d);
362 #ifdef HAVE_SCROLLBARS
363   init_global_scrollbars (d);
364 #endif
365 #ifdef HAVE_TOOLBARS
366   init_global_toolbars (d);
367 #endif
368 }
369
370 #endif
371
372 static void
373 init_device_resources (struct device *d)
374 {
375   init_device_faces (d);
376 #ifdef HAVE_SCROLLBARS
377   init_device_scrollbars (d);
378 #endif
379 #ifdef HAVE_TOOLBARS
380   init_device_toolbars (d);
381 #endif
382 }
383
384 static Lisp_Object
385 semi_canonicalize_device_connection (struct console_methods *meths,
386                                      Lisp_Object name, Error_behavior errb)
387 {
388   return CONTYPE_METH_OR_GIVEN (meths, semi_canonicalize_device_connection,
389                                 (name, errb), name);
390 }
391
392 static Lisp_Object
393 canonicalize_device_connection (struct console_methods *meths,
394                                 Lisp_Object name, Error_behavior errb)
395 {
396   return CONTYPE_METH_OR_GIVEN (meths, canonicalize_device_connection,
397                                 (name, errb), name);
398 }
399
400 static Lisp_Object
401 find_device_of_type (struct console_methods *meths, Lisp_Object canon)
402 {
403   Lisp_Object devcons, concons;
404
405   DEVICE_LOOP_NO_BREAK (devcons, concons)
406     {
407       Lisp_Object device = XCAR (devcons);
408
409       if (EQ (CONMETH_TYPE (meths), DEVICE_TYPE (XDEVICE (device)))
410           && internal_equal (DEVICE_CANON_CONNECTION (XDEVICE (device)),
411                              canon, 0))
412         return device;
413     }
414
415   return Qnil;
416 }
417
418 DEFUN ("find-device", Ffind_device, 1, 2, 0, /*
419 Look for an existing device attached to connection CONNECTION.
420 Return the device if found; otherwise, return nil.
421
422 If TYPE is specified, only return devices of that type; otherwise,
423 return devices of any type. (It is possible, although unlikely,
424 that two devices of different types could have the same connection
425 name; in such a case, the first device found is returned.)
426 */
427        (connection, type))
428 {
429   Lisp_Object canon = Qnil;
430   struct gcpro gcpro1;
431
432   GCPRO1 (canon);
433
434   if (!NILP (type))
435     {
436       struct console_methods *conmeths = decode_console_type (type, ERROR_ME);
437       canon = canonicalize_device_connection (conmeths, connection,
438                                               ERROR_ME_NOT);
439       if (UNBOUNDP (canon))
440         RETURN_UNGCPRO (Qnil);
441
442       RETURN_UNGCPRO (find_device_of_type (conmeths, canon));
443     }
444   else
445     {
446       int i;
447
448       for (i = 0; i < Dynarr_length (the_console_type_entry_dynarr); i++)
449         {
450           struct console_methods *conmeths =
451             Dynarr_at (the_console_type_entry_dynarr, i).meths;
452           canon = canonicalize_device_connection (conmeths, connection,
453                                                   ERROR_ME_NOT);
454           if (!UNBOUNDP (canon))
455             {
456               Lisp_Object device = find_device_of_type (conmeths, canon);
457               if (!NILP (device))
458                 RETURN_UNGCPRO (device);
459             }
460         }
461
462       RETURN_UNGCPRO (Qnil);
463     }
464 }
465
466 DEFUN ("get-device", Fget_device, 1, 2, 0, /*
467 Look for an existing device attached to connection CONNECTION.
468 Return the device if found; otherwise, signal an error.
469
470 If TYPE is specified, only return devices of that type; otherwise,
471 return devices of any type. (It is possible, although unlikely,
472 that two devices of different types could have the same connection
473 name; in such a case, the first device found is returned.)
474 */
475        (connection, type))
476 {
477   Lisp_Object device = Ffind_device (connection, type);
478   if (NILP (device))
479     {
480       if (NILP (type))
481         signal_simple_error ("No such device", connection);
482       else
483         signal_simple_error_2 ("No such device", type, connection);
484     }
485   return device;
486 }
487
488 static Lisp_Object
489 delete_deviceless_console (Lisp_Object console)
490 {
491   if (NILP (XCONSOLE (console)->device_list))
492     Fdelete_console (console, Qnil);
493   return Qnil;
494 }
495
496 DEFUN ("make-device", Fmake_device, 2, 3, 0, /*
497 Return a new device of type TYPE, attached to connection CONNECTION.
498
499 The valid values for CONNECTION are device-specific; however,
500 CONNECTION is generally a string. (Specifically, for X devices,
501 CONNECTION should be a display specification such as "foo:0", and
502 for TTY devices, CONNECTION should be the filename of a TTY device
503 file, such as "/dev/ttyp4", or nil to refer to XEmacs' standard
504 input/output.)
505
506 PROPS, if specified, should be a plist of properties controlling
507 device creation.
508
509 If CONNECTION specifies an already-existing device connection, that
510 device is simply returned; no new device is created, and PROPS
511 have no effect.
512 */
513        (type, connection, props))
514 {
515   /* This function can GC */
516   struct device *d;
517   struct console *con;
518   Lisp_Object device = Qnil;
519   Lisp_Object console = Qnil;
520   Lisp_Object name = Qnil;
521   struct console_methods *conmeths;
522   int speccount = specpdl_depth();
523
524   struct gcpro gcpro1, gcpro2, gcpro3;
525 #ifdef HAVE_X_WINDOWS
526   /* #### icky-poo.  If this is the first X device we are creating,
527      then retrieve the global face resources.  We have to do it
528      here, at the same time as (or just before) the device face
529      resources are retrieved; specifically, it needs to be done
530      after the device has been created but before any frames have
531      been popped up or much anything else has been done.  It's
532      possible for other devices to specify different global
533      resources (there's a property on each X server's root window
534      that holds some resources); tough luck for the moment.
535
536      This is a nasty violation of device independence, but
537      there's not a whole lot I can figure out to do about it.
538      The real problem is that the concept of resources is not
539      generalized away from X.  Similar resource-related
540      device-independence violations occur in faces.el. */
541   int first_x_device = NILP (Vdefault_x_device) && EQ (type, Qx);
542 #endif
543
544   GCPRO3 (device, console, name);
545
546   conmeths = decode_console_type (type, ERROR_ME_NOT);
547   if (!conmeths)
548     signal_simple_error ("Invalid device type", type);
549
550   device = Ffind_device (connection, type);
551   if (!NILP (device))
552     RETURN_UNGCPRO (device);
553
554   name = Fplist_get (props, Qname, Qnil);
555
556   {
557     Lisp_Object conconnect =
558       (HAS_CONTYPE_METH_P (conmeths, device_to_console_connection)) ?
559       CONTYPE_METH (conmeths, device_to_console_connection,
560                     (connection, ERROR_ME)) :
561       connection;
562     console = create_console (name, type, conconnect, props);
563   }
564
565   record_unwind_protect(delete_deviceless_console, console);
566
567   con = XCONSOLE (console);
568   d = allocate_device (console);
569   XSETDEVICE (device, d);
570
571   d->devmeths = con->conmeths;
572
573   DEVICE_NAME (d) = name;
574   DEVICE_CONNECTION (d) =
575     semi_canonicalize_device_connection (conmeths, connection, ERROR_ME);
576   DEVICE_CANON_CONNECTION (d) =
577     canonicalize_device_connection (conmeths, connection, ERROR_ME);
578
579   MAYBE_DEVMETH (d, init_device, (d, props));
580
581   /* Do it this way so that the device list is in order of creation */
582   con->device_list = nconc2 (con->device_list, Fcons (device, Qnil));
583   RESET_CHANGED_SET_FLAGS;
584   if (NILP (Vdefault_device) || DEVICE_STREAM_P (XDEVICE (Vdefault_device)))
585     Vdefault_device = device;
586
587   init_device_sound (d);
588 #ifdef HAVE_X_WINDOWS
589   if (first_x_device)
590     init_global_resources (d);
591 #endif
592   init_device_resources (d);
593
594   MAYBE_DEVMETH (d, finish_init_device, (d, props));
595
596   /* If this is the first device on the console, make it the selected one. */
597   if (NILP (CONSOLE_SELECTED_DEVICE (con)))
598     CONSOLE_SELECTED_DEVICE (con) = device;
599
600   /* #### the following should trap errors. */
601   setup_device_initial_specifier_tags (d);
602
603   UNGCPRO;
604   unbind_to(speccount, Qnil);
605   return device;
606 }
607
608 /* find a device other than the selected one.  Prefer non-stream
609    devices over stream devices.  Maybe stay on the same console. */
610
611 static Lisp_Object
612 find_other_device (Lisp_Object device, int on_same_console)
613 {
614   Lisp_Object devcons = Qnil, concons;
615   Lisp_Object console = DEVICE_CONSOLE (XDEVICE (device));
616
617   /* look for a non-stream device */
618   DEVICE_LOOP_NO_BREAK (devcons, concons)
619     {
620       Lisp_Object dev = XCAR (devcons);
621       if (on_same_console && !EQ (console, DEVICE_CONSOLE (XDEVICE (dev))))
622         continue;
623       if (!DEVICE_STREAM_P (XDEVICE (dev)) && !EQ (dev, device) &&
624           !NILP (DEVICE_SELECTED_FRAME (XDEVICE (dev))))
625         goto double_break_1;
626     }
627
628  double_break_1:
629   if (!NILP (devcons))
630     return XCAR (devcons);
631
632   /* OK, now look for a stream device */
633   DEVICE_LOOP_NO_BREAK (devcons, concons)
634     {
635       Lisp_Object dev = XCAR (devcons);
636       if (on_same_console && !EQ (console, DEVICE_CONSOLE (XDEVICE (dev))))
637         continue;
638       if (!EQ (dev, device) && !NILP (DEVICE_SELECTED_FRAME (XDEVICE (dev))))
639         goto double_break_2;
640     }
641  double_break_2:
642   if (!NILP (devcons))
643     return XCAR (devcons);
644
645   /* Sorry, there ain't none */
646   return Qnil;
647 }
648
649 static int
650 find_nonminibuffer_frame_not_on_device_predicate (Lisp_Object frame,
651                                                   void *closure)
652 {
653   Lisp_Object device;
654
655   VOID_TO_LISP (device, closure);
656   if (FRAME_MINIBUF_ONLY_P (XFRAME (frame)))
657     return 0;
658   if (EQ (device, FRAME_DEVICE (XFRAME (frame))))
659     return 0;
660   return 1;
661 }
662
663 Lisp_Object
664 find_nonminibuffer_frame_not_on_device (Lisp_Object device)
665 {
666   return find_some_frame (find_nonminibuffer_frame_not_on_device_predicate,
667                           LISP_TO_VOID (device));
668 }
669
670
671 /* Delete device D.
672
673    If FORCE is non-zero, allow deletion of the only frame.
674
675    If CALLED_FROM_DELETE_CONSOLE is non-zero, then, if
676    deleting the last device on a console, just delete it,
677    instead of calling `delete-console'.
678
679    If FROM_IO_ERROR is non-zero, then the device is gone due
680    to an I/O error.  This affects what happens if we exit
681    (we do an emergency exit instead of `save-buffers-kill-emacs'.)
682 */
683
684 void
685 delete_device_internal (struct device *d, int force,
686                         int called_from_delete_console,
687                         int from_io_error)
688 {
689   /* This function can GC */
690   struct console *c;
691   Lisp_Object device;
692   struct gcpro gcpro1;
693
694   /* OK to delete an already-deleted device. */
695   if (!DEVICE_LIVE_P (d))
696     return;
697
698   XSETDEVICE (device, d);
699   GCPRO1 (device);
700
701   c = XCONSOLE (DEVICE_CONSOLE (d));
702
703   if (!called_from_delete_console)
704     {
705       int delete_console = 0;
706       /* If we're deleting the only device on the console,
707          delete the console. */
708       if ((XINT (Flength (CONSOLE_DEVICE_LIST (c))) == 1)
709           /* if we just created the device, it might not be listed,
710              or something ... */
711           && !NILP (memq_no_quit (device, CONSOLE_DEVICE_LIST (c))))
712         delete_console = 1;
713       /* Or if there aren't any nonminibuffer frames that would be
714          left, delete the console (this will make XEmacs exit). */
715       else if (NILP (find_nonminibuffer_frame_not_on_device (device)))
716         delete_console = 1;
717
718       if (delete_console)
719         {
720           delete_console_internal (c, force, 0, from_io_error);
721           UNGCPRO;
722           return;
723         }
724     }
725
726   reset_one_device (d);
727
728   {
729     Lisp_Object frmcons;
730
731     /* First delete all frames without their own minibuffers,
732        to avoid errors coming from attempting to delete a frame
733        that is a surrogate for another frame. */
734     DEVICE_FRAME_LOOP (frmcons, d)
735       {
736         struct frame *f = XFRAME (XCAR (frmcons));
737         /* delete_frame_internal() might do anything such as run hooks,
738            so be defensive. */
739         if (FRAME_LIVE_P (f) && !FRAME_HAS_MINIBUF_P (f))
740           delete_frame_internal (f, 1, 1, from_io_error);
741
742         if (!DEVICE_LIVE_P (d)) /* make sure the delete-*-hook didn't
743                                    go ahead and delete anything */
744           {
745             UNGCPRO;
746             return;
747           }
748       }
749
750     /* #### This should probably be a device method but it is time for
751        19.14 to go out the door. */
752 #ifdef HAVE_X_WINDOWS
753     /* Next delete all frames which have the popup property to avoid
754        deleting a child after its parent. */
755     DEVICE_FRAME_LOOP (frmcons, d)
756       {
757         struct frame *f = XFRAME (XCAR (frmcons));
758
759         if (FRAME_LIVE_P (f))
760           {
761             Lisp_Object popup = Fframe_property (XCAR (frmcons), Qpopup, Qnil);
762             if (!NILP (popup))
763               delete_frame_internal (f, 1, 1, from_io_error);
764
765             if (!DEVICE_LIVE_P (d)) /* make sure the delete-*-hook didn't
766                                        go ahead and delete anything */
767               {
768                 UNGCPRO;
769                 return;
770               }
771           }
772       }
773 #endif /* HAVE_X_WINDOWS */
774
775     DEVICE_FRAME_LOOP (frmcons, d)
776       {
777         struct frame *f = XFRAME (XCAR (frmcons));
778         /* delete_frame_internal() might do anything such as run hooks,
779            so be defensive. */
780         if (FRAME_LIVE_P (f))
781           delete_frame_internal (f, 1, 1, from_io_error);
782
783         if (!DEVICE_LIVE_P (d)) /* make sure the delete-*-hook didn't
784                                    go ahead and delete anything */
785           {
786             UNGCPRO;
787             return;
788           }
789       }
790   }
791
792   set_device_selected_frame (d, Qnil);
793
794   /* try to select another device */
795
796   if (EQ (device, Fselected_device (DEVICE_CONSOLE (d))))
797     {
798       Lisp_Object other_dev = find_other_device (device, 1);
799       if (!NILP (other_dev))
800         Fselect_device (other_dev);
801     }
802
803   if (EQ (device, Vdefault_device))
804     Vdefault_device = find_other_device (device, 0);
805
806   MAYBE_DEVMETH (d, delete_device, (d));
807
808   CONSOLE_DEVICE_LIST (c) = delq_no_quit (device, CONSOLE_DEVICE_LIST (c));
809   RESET_CHANGED_SET_FLAGS;
810   d->devmeths = dead_console_methods;
811   UNGCPRO;
812 }
813
814 /* delete a device as a result of an I/O error.  Called from
815    an enqueued magic-eval event. */
816
817 void
818 io_error_delete_device (Lisp_Object device)
819 {
820   /* Note: it's the console that should get deleted, but
821      delete_device_internal() contains a hack that also deletes the
822      console when called from this function.  */
823   delete_device_internal (XDEVICE (device), 1, 0, 1);
824 }
825
826 DEFUN ("delete-device", Fdelete_device, 1, 2, 0, /*
827 Delete DEVICE, permanently eliminating it from use.
828 Normally, you cannot delete the last non-minibuffer-only frame (you must
829 use `save-buffers-kill-emacs' or `kill-emacs').  However, if optional
830 second argument FORCE is non-nil, you can delete the last frame. (This
831 will automatically call `save-buffers-kill-emacs'.)
832 */
833        (device, force))
834 {
835   CHECK_DEVICE (device);
836   delete_device_internal (XDEVICE (device), !NILP (force), 0, 0);
837   return Qnil;
838 }
839
840 DEFUN ("device-frame-list", Fdevice_frame_list, 0, 1, 0, /*
841 Return a list of all frames on DEVICE.
842 If DEVICE is nil, the selected device will be used.
843 */
844        (device))
845 {
846   return Fcopy_sequence (DEVICE_FRAME_LIST (decode_device (device)));
847 }
848
849 DEFUN ("device-class", Fdevice_class, 0, 1, 0, /*
850 Return the class (color behavior) of DEVICE.
851 This will be one of 'color, 'grayscale, or 'mono.
852 */
853        (device))
854 {
855   return DEVICE_CLASS (decode_device (device));
856 }
857
858 DEFUN ("set-device-class", Fset_device_class, 2, 2, 0, /*
859 Set the class (color behavior) of DEVICE.
860 CLASS should be one of 'color, 'grayscale, or 'mono.
861 This is only allowed on device such as TTY devices, where the color
862 behavior cannot necessarily be determined automatically.
863 */
864        (device, class))
865 {
866   struct device *d = decode_device (device);
867   XSETDEVICE (device, d);
868   if (!DEVICE_TTY_P (d))
869     signal_simple_error ("Cannot change the class of this device", device);
870   if (!EQ (class, Qcolor) && !EQ (class, Qmono) && !EQ (class, Qgrayscale))
871     signal_simple_error ("Must be color, mono, or grayscale", class);
872   if (! EQ (DEVICE_CLASS (d), class))
873     {
874       Lisp_Object frmcons;
875       DEVICE_CLASS (d) = class;
876       DEVICE_FRAME_LOOP (frmcons, d)
877         {
878           struct frame *f = XFRAME (XCAR (frmcons));
879
880           recompute_all_cached_specifiers_in_frame (f);
881           MARK_FRAME_FACES_CHANGED (f);
882           MARK_FRAME_GLYPHS_CHANGED (f);
883           MARK_FRAME_TOOLBARS_CHANGED (f);
884           f->menubar_changed = 1;
885         }
886     }
887   return Qnil;
888 }
889
890 DEFUN ("set-device-baud-rate", Fset_device_baud_rate, 2, 2, 0, /*
891 Set the output baud rate of DEVICE to RATE.
892 On most systems, changing this value will affect the amount of padding
893 and other strategic decisions made during redisplay.
894 */
895        (device, rate))
896 {
897   CHECK_INT (rate);
898
899   DEVICE_BAUD_RATE (decode_device (device)) = XINT (rate);
900
901   return rate;
902 }
903
904 DEFUN ("device-baud-rate", Fdevice_baud_rate, 0, 1, 0, /*
905 Return the output baud rate of DEVICE.
906 */
907        (device))
908 {
909   return make_int (DEVICE_BAUD_RATE (decode_device (device)));
910 }
911
912 DEFUN ("device-system-metric", Fdevice_system_metric, 1, 3, 0, /*
913 Get a metric for DEVICE as provided by the system.
914
915 METRIC must be a symbol specifying requested metric.  Note that the metrics
916 returned are these provided by the system internally, not read from resources,
917 so obtained from the most internal level. 
918
919 If a metric is not provided by the system, then DEFAULT is returned.
920
921 When DEVICE is nil, selected device is assumed
922
923 Metrics, by group, are:
924
925 COLORS.  Colors are returned as valid color instantiators.  No other assumption
926 on the returned valie should be made (i.e. it can be a string on one system but
927 a color instance on another).  For colors, returned value is a cons of
928 foreground and background colors.  Note that if the system provides only one
929 color of the pair, the second one may be nil.
930
931 color-default         Standard window text foreground and background.
932 color-select          Selection highligh text and backgroun colors.
933 color-balloon         Ballon popup text and background colors.
934 color-3d-face         3-D object (button, modeline) text and surface colors.
935 color-3d-light        Fore and back colors for 3-D edges facing light source.
936 color-3d-dark         Fore and back colors for 3-D edges facing away from
937                       light source.
938 color-menu            Text and background for menus
939 color-menu-highlight  Selected menu item colors
940 color-menu-button     Menu button colors
941 color-menu-disabled   Unselectable menu item colors
942 color-toolbar         Toolbar foreground and background colors
943 color-scrollbar       Scrollbar foreground and background colors
944 color-desktop         Desktop window colors
945 color-workspace       Workspace window colors
946
947 FONTS. Fonts are returned as valid font instantiators.  No other assumption on
948 the returned value should be made (i.e. it can be a string on one system but
949 font instance on another).
950
951 font-default          Default fixed width font.
952 font-menubar          Menubar font
953 font-dialog           Dialog boxes font
954
955 GEOMETRY. These metrics are returned as conses of (X . Y).  As with colors,
956 either car or cdr of the cons may be nil if the system does not provide one
957 of corresponding dimensions.
958
959 size-cursor           Mouse cursor size.
960 size-scrollbar        Scrollbars (WIDTH . HEIGHT)
961 size-menu             Menubar height, as (nil . HEIGHT)
962 size-toolbar          Toolbar width and height.
963 size-toolbar-button   Toolbar button size.
964 size-toolbar-border   Toolbar border width and height.
965 size-icon             Icon dimensions.
966 size-icon-small       Small icon dimensions.
967 size-device           Device screen size in pixels.
968 size-workspace        Workspace size in pixels. This can be less than the
969                       above if window manager has decorations which
970                       effectively shrink the area remaining for application
971                       windows.
972 size-device-mm        Device screen size in millimeters.
973 device-dpi            Device resolution, in dots per inch.
974 num-bit-planes        Integer, number of deivce bit planes.
975 num-color-cells       Integer, number of device color cells.
976
977 FEATURES.  This group reports various device features.  If a feature is
978 present, integer 1 (one) is returned, if it is not present, then integer
979 0 (zero) is returned.  If the system is unaware of the feature, then
980 DEFAULT is returned.
981                 
982 mouse-buttons         Integer, number of mouse buttons, or zero if no mouse.
983 swap-buttons          Non-zero if left and right mouse buttons are swapped.
984 show-sounds           User preference for visual over audible bell.
985 slow-device           Device is slow, avoid animation.
986 security              Non-zero if user environment is secure.
987 */
988        (device, metric, default_))
989 {
990   struct device *d = decode_device (device);
991   enum device_metrics m;
992   Lisp_Object res;
993
994   /* Decode metric */
995 #define FROB(met)                               \
996   else if (EQ (metric, Q##met))                 \
997     m = DM_##met
998
999   if (0)
1000     ;
1001   FROB (color_default);
1002   FROB (color_select);
1003   FROB (color_balloon);
1004   FROB (color_3d_face);
1005   FROB (color_3d_light);
1006   FROB (color_3d_dark);
1007   FROB (color_menu);
1008   FROB (color_menu_highlight);
1009   FROB (color_menu_button);
1010   FROB (color_menu_disabled);
1011   FROB (color_toolbar);
1012   FROB (color_scrollbar);
1013   FROB (color_desktop);
1014   FROB (color_workspace);
1015   FROB (font_default);
1016   FROB (font_menubar);
1017   FROB (font_dialog);
1018   FROB (size_cursor);
1019   FROB (size_scrollbar);
1020   FROB (size_menu);
1021   FROB (size_toolbar);
1022   FROB (size_toolbar_button);
1023   FROB (size_toolbar_border);
1024   FROB (size_icon);
1025   FROB (size_icon_small);
1026   FROB (size_device);
1027   FROB (size_workspace);
1028   FROB (size_device_mm);
1029   FROB (device_dpi);
1030   FROB (num_bit_planes);
1031   FROB (num_color_cells);
1032   FROB (mouse_buttons);
1033   FROB (swap_buttons);
1034   FROB (show_sounds);
1035   FROB (slow_device);
1036   FROB (security);
1037   else
1038     signal_simple_error ("Invalid device metric symbol", metric);
1039
1040   res = DEVMETH_OR_GIVEN (d, device_system_metrics, (d, m), Qunbound);
1041   return UNBOUNDP(res) ? default_ : res;
1042
1043 #undef FROB
1044 }
1045
1046 DEFUN ("device-system-metrics", Fdevice_system_metrics, 0, 1, 0, /*
1047 Get a property list of device metric for DEVICE.
1048
1049 See `device-system-metric' for the description of available metrics.
1050 DEVICE defaults to selected device when omitted.
1051 */
1052        (device))
1053 {
1054   struct device *d = decode_device (device);
1055   Lisp_Object plist = Qnil, one_metric;
1056
1057 #define FROB(m)                                                         \
1058   if (!UNBOUNDP ((one_metric =                                          \
1059                   DEVMETH_OR_GIVEN (d, device_system_metrics,           \
1060                                     (d, DM_##m), Qunbound))))           \
1061     plist = Fcons (Q##m, Fcons (one_metric, plist));
1062
1063   FROB (color_default);
1064   FROB (color_select);
1065   FROB (color_balloon);
1066   FROB (color_3d_face);
1067   FROB (color_3d_light);
1068   FROB (color_3d_dark);
1069   FROB (color_menu);
1070   FROB (color_menu_highlight);
1071   FROB (color_menu_button);
1072   FROB (color_menu_disabled);
1073   FROB (color_toolbar);
1074   FROB (color_scrollbar);
1075   FROB (color_desktop);
1076   FROB (color_workspace);
1077   FROB (font_default);
1078   FROB (font_menubar);
1079   FROB (font_dialog);
1080   FROB (size_cursor);
1081   FROB (size_scrollbar);
1082   FROB (size_menu);
1083   FROB (size_toolbar);
1084   FROB (size_toolbar_button);
1085   FROB (size_toolbar_border);
1086   FROB (size_icon);
1087   FROB (size_icon_small);
1088   FROB (size_device);
1089   FROB (size_workspace);
1090   FROB (size_device_mm);
1091   FROB (device_dpi);
1092   FROB (num_bit_planes);
1093   FROB (num_color_cells);
1094   FROB (mouse_buttons);
1095   FROB (swap_buttons);
1096   FROB (show_sounds);
1097   FROB (slow_device);
1098   FROB (security);
1099
1100   return plist;
1101
1102 #undef FROB
1103 }
1104
1105 Lisp_Object
1106 domain_device_type (Lisp_Object domain)
1107 {
1108   /* This cannot GC */
1109   assert (WINDOWP (domain) || FRAMEP (domain)
1110           || DEVICEP (domain) || CONSOLEP (domain));
1111
1112   if (WINDOWP (domain))
1113     {
1114       if (!WINDOW_LIVE_P (XWINDOW (domain)))
1115         return Qdead;
1116       domain = WINDOW_FRAME (XWINDOW (domain));
1117     }
1118   if (FRAMEP (domain))
1119     {
1120       if (!FRAME_LIVE_P (XFRAME (domain)))
1121         return Qdead;
1122       domain = FRAME_DEVICE (XFRAME (domain));
1123     }
1124   if (DEVICEP (domain))
1125     {
1126       if (!DEVICE_LIVE_P (XDEVICE (domain)))
1127         return Qdead;
1128       domain = DEVICE_CONSOLE (XDEVICE (domain));
1129     }
1130   return CONSOLE_TYPE (XCONSOLE (domain));
1131 }
1132
1133 /*
1134  * Determine whether window system bases window geometry on character
1135  * or pixel counts.
1136  * Return non-zero for pixel-based geometry, zero for character-based.
1137  */
1138 int
1139 window_system_pixelated_geometry (Lisp_Object domain)
1140 {
1141   /* This cannot GC */
1142   Lisp_Object winsy = domain_device_type (domain);
1143   struct console_methods *meth = decode_console_type (winsy, ERROR_ME_NOT);
1144   assert (meth);
1145   return (MAYBE_INT_CONTYPE_METH (meth, device_implementation_flags, ())
1146           & XDEVIMPF_PIXEL_GEOMETRY);
1147 }
1148
1149 DEFUN ("domain-device-type", Fdomain_device_type, 0, 1, 0, /*
1150 Return the device type symbol for a DOMAIN, e.g. 'x or 'tty.
1151 DOMAIN can be either a window, frame, device or console.
1152 */
1153        (domain))
1154 {
1155   if (!WINDOWP (domain) && !FRAMEP (domain)
1156       && !DEVICEP (domain) && !CONSOLEP (domain))
1157     signal_simple_error
1158       ("Domain must be either a window, frame, device or console", domain);
1159
1160   return domain_device_type (domain);
1161 }
1162
1163 void
1164 handle_asynch_device_change (void)
1165 {
1166   int i;
1167   int old_asynch_device_change_pending = asynch_device_change_pending;
1168   for (i = 0; i < Dynarr_length (the_console_type_entry_dynarr); i++)
1169     {
1170       if (Dynarr_at (the_console_type_entry_dynarr, i).meths->
1171           asynch_device_change_method)
1172         (Dynarr_at (the_console_type_entry_dynarr, i).meths->
1173          asynch_device_change_method) ();
1174     }
1175   /* reset the flag to 0 unless another notification occurred while
1176      we were processing this one.  Block SIGWINCH during this
1177      check to prevent a possible race condition. */
1178 #ifndef WINDOWSNT
1179   EMACS_BLOCK_SIGNAL (SIGWINCH);
1180 #endif
1181   if (old_asynch_device_change_pending == asynch_device_change_pending)
1182     asynch_device_change_pending = 0;
1183 #ifndef WINDOWSNT
1184   EMACS_UNBLOCK_SIGNAL (SIGWINCH);
1185 #endif
1186 }
1187
1188 void
1189 call_critical_lisp_code (struct device *d, Lisp_Object function,
1190                          Lisp_Object object)
1191 {
1192   int old_gc_currently_forbidden = gc_currently_forbidden;
1193   Lisp_Object old_inhibit_quit = Vinhibit_quit;
1194
1195   /* There's no reason to bother doing specbinds here, because if
1196      initialize-*-faces signals an error, emacs is going to crash
1197      immediately.
1198      */
1199   gc_currently_forbidden = 1;
1200   Vinhibit_quit = Qt;
1201   LOCK_DEVICE (d);
1202
1203   /* But it's useful to have an error handler; otherwise an infinite
1204      loop may result. */
1205   if (!NILP (object))
1206     call1_with_handler (Qreally_early_error_handler, function, object);
1207   else
1208     call0_with_handler (Qreally_early_error_handler, function);
1209
1210   UNLOCK_DEVICE (d);
1211   Vinhibit_quit = old_inhibit_quit;
1212   gc_currently_forbidden = old_gc_currently_forbidden;
1213 }
1214
1215 \f
1216 /************************************************************************/
1217 /*                            initialization                            */
1218 /************************************************************************/
1219
1220 void
1221 syms_of_device (void)
1222 {
1223   DEFSUBR (Fvalid_device_class_p);
1224   DEFSUBR (Fdevice_class_list);
1225
1226   DEFSUBR (Fdfw_device);
1227   DEFSUBR (Fselected_device);
1228   DEFSUBR (Fselect_device);
1229   DEFSUBR (Fset_device_selected_frame);
1230   DEFSUBR (Fdevicep);
1231   DEFSUBR (Fdevice_live_p);
1232   DEFSUBR (Fdevice_name);
1233   DEFSUBR (Fdevice_connection);
1234   DEFSUBR (Fdevice_console);
1235   DEFSUBR (Ffind_device);
1236   DEFSUBR (Fget_device);
1237   DEFSUBR (Fmake_device);
1238   DEFSUBR (Fdelete_device);
1239   DEFSUBR (Fdevice_frame_list);
1240   DEFSUBR (Fdevice_class);
1241   DEFSUBR (Fset_device_class);
1242   DEFSUBR (Fdevice_system_metrics);
1243   DEFSUBR (Fdevice_system_metric);
1244   DEFSUBR (Fset_device_baud_rate);
1245   DEFSUBR (Fdevice_baud_rate);
1246   DEFSUBR (Fdomain_device_type);
1247
1248   defsymbol (&Qdevicep, "devicep");
1249   defsymbol (&Qdevice_live_p, "device-live-p");
1250   defsymbol (&Qdelete_device, "delete-device");
1251
1252   defsymbol (&Qcreate_device_hook, "create-device-hook");
1253   defsymbol (&Qdelete_device_hook, "delete-device-hook");
1254
1255   /* Qcolor defined in general.c */
1256   defsymbol (&Qgrayscale, "grayscale");
1257   defsymbol (&Qmono, "mono");
1258
1259   /* Device metrics symbols */
1260   defsymbol (&Qcolor_default, "color-default");
1261   defsymbol (&Qcolor_select, "color-select");
1262   defsymbol (&Qcolor_balloon, "color-balloon");
1263   defsymbol (&Qcolor_3d_face, "color-3d-face");
1264   defsymbol (&Qcolor_3d_light, "color-3d-light");
1265   defsymbol (&Qcolor_3d_dark, "color-3d-dark");
1266   defsymbol (&Qcolor_menu, "color-menu");
1267   defsymbol (&Qcolor_menu_highlight, "color-menu-highlight");
1268   defsymbol (&Qcolor_menu_button, "color-menu-button");
1269   defsymbol (&Qcolor_menu_disabled, "color-menu-disabled");
1270   defsymbol (&Qcolor_toolbar, "color-toolbar");
1271   defsymbol (&Qcolor_scrollbar, "color-scrollbar");
1272   defsymbol (&Qcolor_desktop, "color-desktop");
1273   defsymbol (&Qcolor_workspace, "color-workspace");
1274   defsymbol (&Qfont_default, "font-default");
1275   defsymbol (&Qfont_menubar, "font-menubar");
1276   defsymbol (&Qfont_dialog, "font-dialog");
1277   defsymbol (&Qsize_cursor, "size-cursor");
1278   defsymbol (&Qsize_scrollbar, "size-scrollbar");
1279   defsymbol (&Qsize_menu, "size-menu");
1280   defsymbol (&Qsize_toolbar, "size-toolbar");
1281   defsymbol (&Qsize_toolbar_button, "size-toolbar-button");
1282   defsymbol (&Qsize_toolbar_border, "size-toolbar-border");
1283   defsymbol (&Qsize_icon, "size-icon");
1284   defsymbol (&Qsize_icon_small, "size-icon-small");
1285   defsymbol (&Qsize_device, "size-device");
1286   defsymbol (&Qsize_workspace, "size-workspace");
1287   defsymbol (&Qsize_device_mm, "size-device-mm");
1288   defsymbol (&Qnum_bit_planes, "num-bit-planes");
1289   defsymbol (&Qnum_color_cells, "num-color-cells");
1290   defsymbol (&Qdevice_dpi, "device-dpi");
1291   defsymbol (&Qmouse_buttons, "mouse-buttons");
1292   defsymbol (&Qswap_buttons, "swap-buttons");
1293   defsymbol (&Qshow_sounds, "show-sounds");
1294   defsymbol (&Qslow_device, "slow-device");
1295   defsymbol (&Qsecurity, "security");
1296 }
1297
1298 void
1299 vars_of_device (void)
1300 {
1301   DEFVAR_LISP ("create-device-hook", &Vcreate_device_hook /*
1302 Function or functions to call when a device is created.
1303 One argument, the newly-created device.
1304 This is called after the first frame has been created, but before
1305   calling the `create-frame-hook'.
1306 Note that in general the device will not be selected.
1307 */ );
1308   Vcreate_device_hook = Qnil;
1309
1310   DEFVAR_LISP ("delete-device-hook", &Vdelete_device_hook /*
1311 Function or functions to call when a device is deleted.
1312 One argument, the to-be-deleted device.
1313 */ );
1314   Vdelete_device_hook = Qnil;
1315
1316   staticpro (&Vdefault_device);
1317   Vdefault_device = Qnil;
1318
1319   asynch_device_change_pending = 0;
1320
1321   Vdevice_class_list = list3 (Qcolor, Qgrayscale, Qmono);
1322   staticpro (&Vdevice_class_list);
1323
1324   /* Death to devices.el !!! */
1325   Fprovide(intern("devices"));
1326 }