comparison src/device.c @ 428:3ecd8885ac67 r21-2-22

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