Revert removal of X_FLAGS from libsxeuiTTY_a_CPPFLAGS. We really need to fix this...
[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 #ifdef HAVE_GTK
538         int first_gtk_device = NILP(Vdefault_gtk_device) && EQ(type, Qgtk);
539 #endif
540
541         GCPRO3(device, console, name);
542
543         conmeths = decode_console_type(type, ERROR_ME_NOT);
544         if (!conmeths)
545                 signal_simple_error("Invalid device type", type);
546
547         device = Ffind_device(connection, type);
548         if (!NILP(device))
549                 RETURN_UNGCPRO(device);
550
551         name = Fplist_get(props, Qname, Qnil);
552
553         {
554                 Lisp_Object conconnect =
555                     (HAS_CONTYPE_METH_P(conmeths, device_to_console_connection))
556                     ? CONTYPE_METH(conmeths, device_to_console_connection,
557                                    (connection, ERROR_ME)) : connection;
558                 console = create_console(name, type, conconnect, props);
559         }
560
561         record_unwind_protect(delete_deviceless_console, console);
562
563         con = XCONSOLE(console);
564         d = allocate_device(console);
565         XSETDEVICE(device, d);
566
567         d->devmeths = con->conmeths;
568
569         DEVICE_NAME(d) = name;
570         DEVICE_CONNECTION(d) =
571             semi_canonicalize_device_connection(conmeths, connection, ERROR_ME);
572         DEVICE_CANON_CONNECTION(d) =
573             canonicalize_device_connection(conmeths, connection, ERROR_ME);
574
575         MAYBE_DEVMETH(d, init_device, (d, props));
576
577         /* Do it this way so that the device list is in order of creation */
578         con->device_list = nconc2(con->device_list, Fcons(device, Qnil));
579         RESET_CHANGED_SET_FLAGS;
580         if (NILP(Vdefault_device) || DEVICE_STREAM_P(XDEVICE(Vdefault_device)))
581                 Vdefault_device = device;
582
583 #ifdef HAVE_X_WINDOWS
584         if (first_x_device)
585                 init_global_resources(d);
586 #endif
587 #ifdef HAVE_GTK
588         if (first_gtk_device)
589                 init_global_resources(d);
590 #endif
591         init_device_resources(d);
592
593         MAYBE_DEVMETH(d, finish_init_device, (d, props));
594
595         /* If this is the first device on the console, make it the selected one. */
596         if (NILP(CONSOLE_SELECTED_DEVICE(con)))
597                 CONSOLE_SELECTED_DEVICE(con) = device;
598
599         /* #### the following should trap errors. */
600         setup_device_initial_specifier_tags(d);
601
602         UNGCPRO;
603         unbind_to(speccount, Qnil);
604         return device;
605 }
606
607 /* find a device other than the selected one.  Prefer non-stream
608    devices over stream devices.  Maybe stay on the same console. */
609
610 static Lisp_Object find_other_device(Lisp_Object device, int on_same_console)
611 {
612         Lisp_Object devcons = Qnil, concons;
613         Lisp_Object console = DEVICE_CONSOLE(XDEVICE(device));
614
615         /* look for a non-stream device */
616         DEVICE_LOOP_NO_BREAK(devcons, concons) {
617                 Lisp_Object dev = XCAR(devcons);
618                 if (on_same_console
619                     && !EQ(console, DEVICE_CONSOLE(XDEVICE(dev))))
620                         continue;
621                 if (!DEVICE_STREAM_P(XDEVICE(dev)) && !EQ(dev, device) &&
622                     !NILP(DEVICE_SELECTED_FRAME(XDEVICE(dev))))
623                         goto double_break_1;
624         }
625
626       double_break_1:
627         if (!NILP(devcons))
628                 return XCAR(devcons);
629
630         /* OK, now look for a stream device */
631         DEVICE_LOOP_NO_BREAK(devcons, concons) {
632                 Lisp_Object dev = XCAR(devcons);
633                 if (on_same_console
634                     && !EQ(console, DEVICE_CONSOLE(XDEVICE(dev))))
635                         continue;
636                 if (!EQ(dev, device)
637                     && !NILP(DEVICE_SELECTED_FRAME(XDEVICE(dev))))
638                         goto double_break_2;
639         }
640       double_break_2:
641         if (!NILP(devcons))
642                 return XCAR(devcons);
643
644         /* Sorry, there ain't none */
645         return Qnil;
646 }
647
648 static int
649 find_nonminibuffer_frame_not_on_device_predicate(Lisp_Object frame,
650                                                  void *closure)
651 {
652         Lisp_Object device;
653
654         VOID_TO_LISP(device, closure);
655         if (FRAME_MINIBUF_ONLY_P(XFRAME(frame)))
656                 return 0;
657         if (EQ(device, FRAME_DEVICE(XFRAME(frame))))
658                 return 0;
659         return 1;
660 }
661
662 Lisp_Object find_nonminibuffer_frame_not_on_device(Lisp_Object device)
663 {
664         return find_some_frame(find_nonminibuffer_frame_not_on_device_predicate,
665                                LISP_TO_VOID(device));
666 }
667
668 /* Delete device D.
669
670    If FORCE is non-zero, allow deletion of the only frame.
671
672    If CALLED_FROM_DELETE_CONSOLE is non-zero, then, if
673    deleting the last device on a console, just delete it,
674    instead of calling `delete-console'.
675
676    If FROM_IO_ERROR is non-zero, then the device is gone due
677    to an I/O error.  This affects what happens if we exit
678    (we do an emergency exit instead of `save-buffers-kill-emacs'.)
679 */
680
681 void
682 delete_device_internal(struct device *d, int force,
683                        int called_from_delete_console, int from_io_error)
684 {
685         /* This function can GC */
686         struct console *c;
687         Lisp_Object device;
688         struct gcpro gcpro1;
689
690         /* OK to delete an already-deleted device. */
691         if (!DEVICE_LIVE_P(d))
692                 return;
693
694         XSETDEVICE(device, d);
695         GCPRO1(device);
696
697         c = XCONSOLE(DEVICE_CONSOLE(d));
698
699         if (!called_from_delete_console) {
700                 int delete_console = 0;
701                 /* If we're deleting the only device on the console,
702                    delete the console. */
703                 if ((XINT(Flength(CONSOLE_DEVICE_LIST(c))) == 1)
704                     /* if we just created the device, it might not be listed,
705                        or something ... */
706                     && !NILP(memq_no_quit(device, CONSOLE_DEVICE_LIST(c))))
707                         delete_console = 1;
708                 /* Or if there aren't any nonminibuffer frames that would be
709                    left, delete the console (this will make SXEmacs exit). */
710                 else if (NILP(find_nonminibuffer_frame_not_on_device(device)))
711                         delete_console = 1;
712
713                 if (delete_console) {
714                         delete_console_internal(c, force, 0, from_io_error);
715                         UNGCPRO;
716                         return;
717                 }
718         }
719
720         reset_one_device(d);
721
722         {
723                 Lisp_Object frmcons;
724
725                 /* First delete all frames without their own minibuffers,
726                    to avoid errors coming from attempting to delete a frame
727                    that is a surrogate for another frame. */
728                 DEVICE_FRAME_LOOP(frmcons, d) {
729                         struct frame *f = XFRAME(XCAR(frmcons));
730                         /* delete_frame_internal() might do anything such as run hooks,
731                            so be defensive. */
732                         if (FRAME_LIVE_P(f) && !FRAME_HAS_MINIBUF_P(f))
733                                 delete_frame_internal(f, 1, 1, from_io_error);
734
735                         if (!DEVICE_LIVE_P(d)) {        /* make sure the delete-*-hook didn't
736                                                            go ahead and delete anything */
737                                 UNGCPRO;
738                                 return;
739                         }
740                 }
741
742                 /* #### This should probably be a device method but it is time for
743                    19.14 to go out the door. */
744                 /* #### BILL!!! Should this deal with HAVE_MSWINDOWS as well? */
745 #if defined (HAVE_X_WINDOWS) || defined (HAVE_GTK)
746                 /* Next delete all frames which have the popup property to avoid
747                    deleting a child after its parent. */
748                 DEVICE_FRAME_LOOP(frmcons, d) {
749                         struct frame *f = XFRAME(XCAR(frmcons));
750
751                         if (FRAME_LIVE_P(f)) {
752                                 Lisp_Object popup =
753                                     Fframe_property(XCAR(frmcons), Qpopup,
754                                                     Qnil);
755                                 if (!NILP(popup))
756                                         delete_frame_internal(f, 1, 1,
757                                                               from_io_error);
758
759                                 if (!DEVICE_LIVE_P(d)) {        /* make sure the delete-*-hook didn't
760                                                                    go ahead and delete anything */
761                                         UNGCPRO;
762                                         return;
763                                 }
764                         }
765                 }
766 #endif                          /* HAVE_X_WINDOWS */
767
768                 DEVICE_FRAME_LOOP(frmcons, d) {
769                         struct frame *f = XFRAME(XCAR(frmcons));
770                         /* delete_frame_internal() might do anything such as run hooks,
771                            so be defensive. */
772                         if (FRAME_LIVE_P(f))
773                                 delete_frame_internal(f, 1, 1, from_io_error);
774
775                         if (!DEVICE_LIVE_P(d)) {        /* make sure the delete-*-hook didn't
776                                                            go ahead and delete anything */
777                                 UNGCPRO;
778                                 return;
779                         }
780                 }
781         }
782
783         set_device_selected_frame(d, Qnil);
784
785         /* try to select another device */
786
787         if (EQ(device, Fselected_device(DEVICE_CONSOLE(d)))) {
788                 Lisp_Object other_dev = find_other_device(device, 1);
789                 if (!NILP(other_dev))
790                         Fselect_device(other_dev);
791         }
792
793         if (EQ(device, Vdefault_device))
794                 Vdefault_device = find_other_device(device, 0);
795
796         MAYBE_DEVMETH(d, delete_device, (d));
797
798         CONSOLE_DEVICE_LIST(c) = delq_no_quit(device, CONSOLE_DEVICE_LIST(c));
799         RESET_CHANGED_SET_FLAGS;
800         d->devmeths = dead_console_methods;
801         UNGCPRO;
802 }
803
804 /* delete a device as a result of an I/O error.  Called from
805    an enqueued magic-eval event. */
806
807 void io_error_delete_device(Lisp_Object device)
808 {
809         /* Note: it's the console that should get deleted, but
810            delete_device_internal() contains a hack that also deletes the
811            console when called from this function.  */
812         delete_device_internal(XDEVICE(device), 1, 0, 1);
813 }
814
815 DEFUN("delete-device", Fdelete_device, 1, 2, 0, /*
816 Delete DEVICE, permanently eliminating it from use.
817 Normally, you cannot delete the last non-minibuffer-only frame (you must
818 use `save-buffers-kill-emacs' or `kill-emacs').  However, if optional
819 second argument FORCE is non-nil, you can delete the last frame. (This
820 will automatically call `save-buffers-kill-emacs'.)
821 */
822       (device, force))
823 {
824         CHECK_DEVICE(device);
825         delete_device_internal(XDEVICE(device), !NILP(force), 0, 0);
826         return Qnil;
827 }
828
829 DEFUN("device-frame-list", Fdevice_frame_list, 0, 1, 0, /*
830 Return a list of all frames on DEVICE.
831 If DEVICE is nil, the selected device will be used.
832 */
833       (device))
834 {
835         return Fcopy_sequence(DEVICE_FRAME_LIST(decode_device(device)));
836 }
837
838 DEFUN("device-class", Fdevice_class, 0, 1, 0,   /*
839 Return the class (color behavior) of DEVICE.
840 This will be one of 'color, 'grayscale, or 'mono.
841 */
842       (device))
843 {
844         return DEVICE_CLASS(decode_device(device));
845 }
846
847 DEFUN("set-device-class", Fset_device_class, 2, 2, 0,   /*
848 Set the class (color behavior) of DEVICE.
849 CLASS should be one of 'color, 'grayscale, or 'mono.
850 This is only allowed on device such as TTY devices, where the color
851 behavior cannot necessarily be determined automatically.
852 */
853       (device, class))
854 {
855         struct device *d = decode_device(device);
856         XSETDEVICE(device, d);
857         if (!DEVICE_TTY_P(d))
858                 signal_simple_error("Cannot change the class of this device",
859                                     device);
860         if (!EQ(class, Qcolor) && !EQ(class, Qmono) && !EQ(class, Qgrayscale))
861                 signal_simple_error("Must be color, mono, or grayscale", class);
862         if (!EQ(DEVICE_CLASS(d), class)) {
863                 Lisp_Object frmcons;
864                 DEVICE_CLASS(d) = class;
865                 DEVICE_FRAME_LOOP(frmcons, d) {
866                         struct frame *f = XFRAME(XCAR(frmcons));
867
868                         recompute_all_cached_specifiers_in_frame(f);
869                         MARK_FRAME_FACES_CHANGED(f);
870                         MARK_FRAME_GLYPHS_CHANGED(f);
871                         MARK_FRAME_SUBWINDOWS_CHANGED(f);
872                         MARK_FRAME_TOOLBARS_CHANGED(f);
873                         MARK_FRAME_GUTTERS_CHANGED(f);
874                         f->menubar_changed = 1;
875                 }
876         }
877         return Qnil;
878 }
879
880 DEFUN("set-device-baud-rate", Fset_device_baud_rate, 2, 2, 0,   /*
881 Set the output baud rate of DEVICE to RATE.
882 On most systems, changing this value will affect the amount of padding
883 and other strategic decisions made during redisplay.
884 */
885       (device, rate))
886 {
887         CHECK_INT(rate);
888
889         DEVICE_BAUD_RATE(decode_device(device)) = XINT(rate);
890
891         return rate;
892 }
893
894 DEFUN("device-baud-rate", Fdevice_baud_rate, 0, 1, 0,   /*
895 Return the output baud rate of DEVICE.
896 */
897       (device))
898 {
899         return make_int(DEVICE_BAUD_RATE(decode_device(device)));
900 }
901
902 DEFUN("device-printer-p", Fdevice_printer_p, 0, 1, 0,   /*
903 Return t if DEVICE is a printer, nil if it is a display. DEVICE defaults
904 to selected device if omitted, and must be live if specified.
905 */
906       (device))
907 {
908         return DEVICE_PRINTER_P(decode_device(device)) ? Qt : Qnil;
909 }
910
911 DEFUN("device-system-metric", Fdevice_system_metric, 1, 3, 0,   /*
912 Get a metric for DEVICE as provided by the system.
913
914 METRIC must be a symbol specifying requested metric.  Note that the metrics
915 returned are these provided by the system internally, not read from resources,
916 so obtained from the most internal level.
917
918 If a metric is not provided by the system, then DEFAULT is returned.
919
920 When DEVICE is nil, selected device is assumed
921
922 Metrics, by group, are:
923
924 COLORS.  Colors are returned as valid color instantiators.  No other assumption
925 on the returned value should be made (i.e. it can be a string on one system but
926 a color instance on another).  For colors, returned value is a cons of
927 foreground and background colors.  Note that if the system provides only one
928 color of the pair, the second one may be nil.
929
930 color-default         Standard window text foreground and background.
931 color-select          Selection highlight text and background colors.
932 color-balloon         Balloon popup text and background colors.
933 color-3d-face         3-D object (button, modeline) text and surface colors.
934 color-3d-light        Fore and back colors for 3-D edges facing light source.
935 color-3d-dark         Fore and back colors for 3-D edges facing away from
936 light source.
937 color-menu            Text and background for menus
938 color-menu-highlight  Selected menu item colors
939 color-menu-button     Menu button colors
940 color-menu-disabled   Unselectable menu item colors
941 color-toolbar         Toolbar foreground and background colors
942 color-scrollbar       Scrollbar foreground and background colors
943 color-desktop         Desktop window colors
944 color-workspace       Workspace window colors
945
946 FONTS. Fonts are returned as valid font instantiators.  No other assumption on
947 the returned value should be made (i.e. it can be a string on one system but
948 font instance on another).
949
950 font-default          Default fixed width font.
951 font-menubar          Menubar font
952 font-dialog           Dialog boxes font
953
954 GEOMETRY. These metrics are returned as conses of (X . Y).  As with colors,
955 either car or cdr of the cons may be nil if the system does not provide one
956 of the corresponding dimensions.
957
958 size-cursor           Mouse cursor size.
959 size-scrollbar        Scrollbars (WIDTH . HEIGHT)
960 size-menu             Menubar height, as (nil . HEIGHT)
961 size-toolbar          Toolbar width and height.
962 size-toolbar-button   Toolbar button size.
963 size-toolbar-border   Toolbar border width and height.
964 size-icon             Icon dimensions.
965 size-icon-small       Small icon dimensions.
966 size-device           Device screen or paper size in pixels.
967 size-workspace        Workspace size in pixels. This can be less than or
968 equal to the above. For displays, this is the area
969 available to applications less window manager
970 decorations. For printers, this is the size of
971 printable area.
972 offset-workspace      Offset of workspace area from the top left corner
973 of screen or paper, in pixels.
974 size-device-mm        Device screen size in millimeters.
975 device-dpi            Device resolution, in dots per inch.
976 num-bit-planes        Integer, number of device bit planes.
977 num-color-cells       Integer, number of device color cells.
978
979 FEATURES.  This group reports various device features.  If a feature is
980 present, integer 1 (one) is returned, if it is not present, then integer
981 0 (zero) is returned.  If the system is unaware of the feature, then
982 DEFAULT is returned.
983
984 mouse-buttons         Integer, number of mouse buttons, or zero if no mouse.
985 swap-buttons          Non-zero if left and right mouse buttons are swapped.
986 show-sounds           User preference for visual over audible bell.
987 slow-device           Device is slow, avoid animation.
988 security              Non-zero if user environment is secure.
989 */
990       (device, metric, default_))
991 {
992         struct device *d = decode_device(device);
993         enum device_metrics m;
994         Lisp_Object res;
995
996         /* Decode metric */
997 #define FROB(met)                               \
998   else if (EQ (metric, Q##met))                 \
999     m = DM_##met
1000
1001         if (0) ;
1002         FROB(color_default);
1003         FROB(color_select);
1004         FROB(color_balloon);
1005         FROB(color_3d_face);
1006         FROB(color_3d_light);
1007         FROB(color_3d_dark);
1008         FROB(color_menu);
1009         FROB(color_menu_highlight);
1010         FROB(color_menu_button);
1011         FROB(color_menu_disabled);
1012         FROB(color_toolbar);
1013         FROB(color_scrollbar);
1014         FROB(color_desktop);
1015         FROB(color_workspace);
1016         FROB(font_default);
1017         FROB(font_menubar);
1018         FROB(font_dialog);
1019         FROB(size_cursor);
1020         FROB(size_scrollbar);
1021         FROB(size_menu);
1022         FROB(size_toolbar);
1023         FROB(size_toolbar_button);
1024         FROB(size_toolbar_border);
1025         FROB(size_icon);
1026         FROB(size_icon_small);
1027         FROB(size_device);
1028         FROB(size_workspace);
1029         FROB(offset_workspace);
1030         FROB(size_device_mm);
1031         FROB(device_dpi);
1032         FROB(num_bit_planes);
1033         FROB(num_color_cells);
1034         FROB(mouse_buttons);
1035         FROB(swap_buttons);
1036         FROB(show_sounds);
1037         FROB(slow_device);
1038         FROB(security);
1039         else
1040         signal_simple_error("Invalid device metric symbol", metric);
1041
1042         res = DEVMETH_OR_GIVEN(d, device_system_metrics, (d, m), Qunbound);
1043         return UNBOUNDP(res) ? default_ : res;
1044
1045 #undef FROB
1046 }
1047
1048 DEFUN("device-system-metrics", Fdevice_system_metrics, 0, 1, 0, /*
1049 Get a property list of device metric for DEVICE.
1050
1051 See `device-system-metric' for the description of available metrics.
1052 DEVICE defaults to selected device when omitted.
1053 */
1054       (device))
1055 {
1056         struct device *d = decode_device(device);
1057         Lisp_Object plist = Qnil, one_metric;
1058
1059 #define FROB(m)                                                         \
1060   if (!UNBOUNDP ((one_metric =                                          \
1061                   DEVMETH_OR_GIVEN (d, device_system_metrics,           \
1062                                     (d, DM_##m), Qunbound))))           \
1063     plist = Fcons (Q##m, Fcons (one_metric, plist));
1064
1065         FROB(color_default);
1066         FROB(color_select);
1067         FROB(color_balloon);
1068         FROB(color_3d_face);
1069         FROB(color_3d_light);
1070         FROB(color_3d_dark);
1071         FROB(color_menu);
1072         FROB(color_menu_highlight);
1073         FROB(color_menu_button);
1074         FROB(color_menu_disabled);
1075         FROB(color_toolbar);
1076         FROB(color_scrollbar);
1077         FROB(color_desktop);
1078         FROB(color_workspace);
1079         FROB(font_default);
1080         FROB(font_menubar);
1081         FROB(font_dialog);
1082         FROB(size_cursor);
1083         FROB(size_scrollbar);
1084         FROB(size_menu);
1085         FROB(size_toolbar);
1086         FROB(size_toolbar_button);
1087         FROB(size_toolbar_border);
1088         FROB(size_icon);
1089         FROB(size_icon_small);
1090         FROB(size_device);
1091         FROB(size_workspace);
1092         FROB(offset_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 domain_device_type(Lisp_Object domain)
1109 {
1110         /* This cannot GC */
1111         assert(WINDOWP(domain) || FRAMEP(domain)
1112                || DEVICEP(domain) || CONSOLEP(domain));
1113
1114         if (WINDOWP(domain)) {
1115                 if (!WINDOW_LIVE_P(XWINDOW(domain)))
1116                         return Qdead;
1117                 domain = WINDOW_FRAME(XWINDOW(domain));
1118         }
1119         if (FRAMEP(domain)) {
1120                 if (!FRAME_LIVE_P(XFRAME(domain)))
1121                         return Qdead;
1122                 domain = FRAME_DEVICE(XFRAME(domain));
1123         }
1124         if (DEVICEP(domain)) {
1125                 if (!DEVICE_LIVE_P(XDEVICE(domain)))
1126                         return Qdead;
1127                 domain = DEVICE_CONSOLE(XDEVICE(domain));
1128         }
1129         return CONSOLE_TYPE(XCONSOLE(domain));
1130 }
1131
1132 /*
1133  * Determine whether window system bases window geometry on character
1134  * or pixel counts.
1135  * Return non-zero for pixel-based geometry, zero for character-based.
1136  */
1137 int window_system_pixelated_geometry(Lisp_Object domain)
1138 {
1139         /* This cannot GC */
1140         Lisp_Object winsy = domain_device_type(domain);
1141         struct console_methods *meth = decode_console_type(winsy, ERROR_ME_NOT);
1142         assert(meth);
1143         return CONMETH_IMPL_FLAG(meth, XDEVIMPF_PIXEL_GEOMETRY);
1144 }
1145
1146 DEFUN("domain-device-type", Fdomain_device_type, 0, 1, 0,       /*
1147 Return the device type symbol for a DOMAIN, e.g. 'x or 'tty.
1148 DOMAIN can be either a window, frame, device or console.
1149 */
1150       (domain))
1151 {
1152         if (!WINDOWP(domain) && !FRAMEP(domain)
1153             && !DEVICEP(domain) && !CONSOLEP(domain))
1154                 signal_simple_error
1155                     ("Domain must be either a window, frame, device or console",
1156                      domain);
1157
1158         return domain_device_type(domain);
1159 }
1160
1161 void handle_asynch_device_change(void)
1162 {
1163         int i;
1164         int old_asynch_device_change_pending = asynch_device_change_pending;
1165         for (i = 0; i < Dynarr_length(the_console_type_entry_dynarr); i++) {
1166                 if (Dynarr_at(the_console_type_entry_dynarr, i).meths->
1167                     asynch_device_change_method)
1168                         (Dynarr_at(the_console_type_entry_dynarr, i).meths->
1169                          asynch_device_change_method) ();
1170         }
1171         /* reset the flag to 0 unless another notification occurred while
1172            we were processing this one.  Block SIGWINCH during this
1173            check to prevent a possible race condition. */
1174 #ifdef SIGWINCH
1175         EMACS_BLOCK_SIGNAL(SIGWINCH);
1176 #endif
1177         if (old_asynch_device_change_pending == asynch_device_change_pending)
1178                 asynch_device_change_pending = 0;
1179 #ifdef SIGWINCH
1180         EMACS_UNBLOCK_SIGNAL(SIGWINCH);
1181 #endif
1182 }
1183
1184 void
1185 call_critical_lisp_code(struct device *d, Lisp_Object function,
1186                         Lisp_Object object)
1187 {
1188         int old_gc_currently_forbidden = gc_currently_forbidden;
1189         Lisp_Object old_inhibit_quit = Vinhibit_quit;
1190
1191         /* There's no reason to bother doing specbinds here, because if
1192            initialize-*-faces signals an error, emacs is going to crash
1193            immediately.
1194          */
1195         gc_currently_forbidden = 1;
1196         Vinhibit_quit = Qt;
1197         LOCK_DEVICE(d);
1198
1199         /* But it's useful to have an error handler; otherwise an infinite
1200            loop may result. */
1201         if (!NILP(object))
1202                 call1_with_handler(Qreally_early_error_handler, function,
1203                                    object);
1204         else
1205                 call0_with_handler(Qreally_early_error_handler, function);
1206
1207         UNLOCK_DEVICE(d);
1208         Vinhibit_quit = old_inhibit_quit;
1209         gc_currently_forbidden = old_gc_currently_forbidden;
1210 }
1211 \f
1212 /************************************************************************/
1213 /*                            initialization                            */
1214 /************************************************************************/
1215
1216 void syms_of_device(void)
1217 {
1218         INIT_LRECORD_IMPLEMENTATION(device);
1219
1220         DEFSUBR(Fvalid_device_class_p);
1221         DEFSUBR(Fdevice_class_list);
1222
1223         DEFSUBR(Fdfw_device);
1224         DEFSUBR(Fselected_device);
1225         DEFSUBR(Fselect_device);
1226         DEFSUBR(Fset_device_selected_frame);
1227         DEFSUBR(Fdevicep);
1228         DEFSUBR(Fdevice_live_p);
1229         DEFSUBR(Fdevice_name);
1230         DEFSUBR(Fdevice_connection);
1231         DEFSUBR(Fdevice_console);
1232         DEFSUBR(Ffind_device);
1233         DEFSUBR(Fget_device);
1234         DEFSUBR(Fmake_device);
1235         DEFSUBR(Fdelete_device);
1236         DEFSUBR(Fdevice_frame_list);
1237         DEFSUBR(Fdevice_class);
1238         DEFSUBR(Fset_device_class);
1239         DEFSUBR(Fdevice_system_metrics);
1240         DEFSUBR(Fdevice_system_metric);
1241         DEFSUBR(Fset_device_baud_rate);
1242         DEFSUBR(Fdevice_baud_rate);
1243         DEFSUBR(Fdomain_device_type);
1244         DEFSUBR(Fdevice_printer_p);
1245
1246         defsymbol(&Qdevicep, "devicep");
1247         defsymbol(&Qdevice_live_p, "device-live-p");
1248
1249         defsymbol(&Qcreate_device_hook, "create-device-hook");
1250         defsymbol(&Qdelete_device_hook, "delete-device-hook");
1251
1252         /* Qcolor defined in general.c */
1253         defsymbol(&Qgrayscale, "grayscale");
1254         defsymbol(&Qmono, "mono");
1255
1256         /* Device metrics symbols */
1257         defsymbol(&Qcolor_default, "color-default");
1258         defsymbol(&Qcolor_select, "color-select");
1259         defsymbol(&Qcolor_balloon, "color-balloon");
1260         defsymbol(&Qcolor_3d_face, "color-3d-face");
1261         defsymbol(&Qcolor_3d_light, "color-3d-light");
1262         defsymbol(&Qcolor_3d_dark, "color-3d-dark");
1263         defsymbol(&Qcolor_menu, "color-menu");
1264         defsymbol(&Qcolor_menu_highlight, "color-menu-highlight");
1265         defsymbol(&Qcolor_menu_button, "color-menu-button");
1266         defsymbol(&Qcolor_menu_disabled, "color-menu-disabled");
1267         defsymbol(&Qcolor_toolbar, "color-toolbar");
1268         defsymbol(&Qcolor_scrollbar, "color-scrollbar");
1269         defsymbol(&Qcolor_desktop, "color-desktop");
1270         defsymbol(&Qcolor_workspace, "color-workspace");
1271         defsymbol(&Qfont_default, "font-default");
1272         defsymbol(&Qfont_menubar, "font-menubar");
1273         defsymbol(&Qfont_dialog, "font-dialog");
1274         defsymbol(&Qsize_cursor, "size-cursor");
1275         defsymbol(&Qsize_scrollbar, "size-scrollbar");
1276         defsymbol(&Qsize_menu, "size-menu");
1277         defsymbol(&Qsize_toolbar, "size-toolbar");
1278         defsymbol(&Qsize_toolbar_button, "size-toolbar-button");
1279         defsymbol(&Qsize_toolbar_border, "size-toolbar-border");
1280         defsymbol(&Qsize_icon, "size-icon");
1281         defsymbol(&Qsize_icon_small, "size-icon-small");
1282         defsymbol(&Qsize_device, "size-device");
1283         defsymbol(&Qsize_workspace, "size-workspace");
1284         defsymbol(&Qoffset_workspace, "offset-workspace");
1285         defsymbol(&Qsize_device_mm, "size-device-mm");
1286         defsymbol(&Qnum_bit_planes, "num-bit-planes");
1287         defsymbol(&Qnum_color_cells, "num-color-cells");
1288         defsymbol(&Qdevice_dpi, "device-dpi");
1289         defsymbol(&Qmouse_buttons, "mouse-buttons");
1290         defsymbol(&Qswap_buttons, "swap-buttons");
1291         defsymbol(&Qshow_sounds, "show-sounds");
1292         defsymbol(&Qslow_device, "slow-device");
1293         defsymbol(&Qsecurity, "security");
1294 }
1295
1296 void reinit_vars_of_device(void)
1297 {
1298         staticpro_nodump(&Vdefault_device);
1299         Vdefault_device = Qnil;
1300         asynch_device_change_pending = 0;
1301 }
1302
1303 void vars_of_device(void)
1304 {
1305         reinit_vars_of_device();
1306
1307         DEFVAR_LISP("create-device-hook", &Vcreate_device_hook  /*
1308 Function or functions to call when a device is created.
1309 One argument, the newly-created device.
1310 This is called after the first frame has been created, but before
1311 calling the `create-frame-hook'.
1312 Note that in general the device will not be selected.
1313                                                                  */ );
1314         Vcreate_device_hook = Qnil;
1315
1316         DEFVAR_LISP("delete-device-hook", &Vdelete_device_hook  /*
1317 Function or functions to call when a device is deleted.
1318 One argument, the to-be-deleted device.
1319                                                                  */ );
1320         Vdelete_device_hook = Qnil;
1321
1322         Vdevice_class_list = list3(Qcolor, Qgrayscale, Qmono);
1323         staticpro(&Vdevice_class_list);
1324
1325         /* Death to devices.el !!! */
1326         Fprovide(intern("devices"));
1327 }