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