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