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
6 This file is part of SXEmacs
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.
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.
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/>. */
22 /* Synched up with: Not in FSF. */
24 /* Original version by Chuck Thompson;
25 rewritten and expanded by Ben Wing. */
34 #include "events/events.h"
38 #include "redisplay.h"
39 #include "specifier.h"
43 #ifdef HAVE_SCROLLBARS
44 #include "scrollbar.h"
47 #include "syssignal.h"
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;
55 Lisp_Object Vcreate_device_hook, Vdelete_device_hook;
58 /* Qcolor defined in general.c */
59 Lisp_Object Qgrayscale, Qmono;
61 /* Device metrics symbols */
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;
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;
79 static Lisp_Object mark_device(Lisp_Object obj)
81 struct device *d = XDEVICE(obj);
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);
96 mark_object(d->color_instance_cache);
97 mark_object(d->font_instance_cache);
99 mark_object(d->charset_font_cache);
101 mark_object(d->image_instance_cache);
104 mark_object(d->devmeths->symbol);
105 MAYBE_DEVMETH(d, mark_device, (d));
108 return (d->frame_list);
112 print_device(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
114 struct device *d = XDEVICE(obj);
117 error("printing unreadable object #<device %s 0x%x>",
118 XSTRING_DATA(d->name), d->header.uid);
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);
126 write_fmt_str(printcharfun, " 0x%x>", d->header.uid);
129 DEFINE_LRECORD_IMPLEMENTATION("device", device,
130 mark_device, print_device, 0, 0, 0, 0,
133 int valid_device_class_p(Lisp_Object class)
135 return !NILP(memq_no_quit(class, Vdevice_class_list));
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.
144 return valid_device_class_p(device_class) ? Qt : Qnil;
147 DEFUN("device-class-list", Fdevice_class_list, 0, 0, 0, /*
148 Return a list of valid device classes.
152 return Fcopy_sequence(Vdevice_class_list);
155 static struct device *allocate_device(Lisp_Object console)
158 struct device *d = alloc_lcrecord_type(struct device, &lrecord_device);
163 XSETDEVICE(device, d);
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;
180 d->infd = d->outfd = -1;
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);
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);
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.
197 d->image_instance_cache =
198 make_lisp_hash_table(5, HASH_TABLE_NON_WEAK, HASH_TABLE_EQ);
204 struct device *decode_device(Lisp_Object 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);
215 DEFUN("dfw-device", Fdfw_device, 1, 1, 0, /*
216 Given a device, frame, or window, return the associated device.
217 Return nil otherwise.
221 return DFW_DEVICE(object);
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.
231 if (NILP(console) && NILP(Vselected_console))
232 return Qnil; /* happens early in temacs */
233 return CONSOLE_SELECTED_DEVICE(decode_console(console));
236 /* Called from selected_frame_1(), called from Fselect_window() */
237 void select_device_1(Lisp_Object device)
239 struct device *dev = XDEVICE(device);
240 Lisp_Object old_selected_device = Fselected_device(Qnil);
242 if (EQ(device, old_selected_device))
245 /* now select the device's console */
246 CONSOLE_SELECTED_DEVICE(XCONSOLE(DEVICE_CONSOLE(dev))) = device;
247 select_console_1(DEVICE_CONSOLE(dev));
250 DEFUN("select-device", Fselect_device, 1, 1, 0, /*
251 Select the device DEVICE.
252 Subsequent editing commands apply to its console, selected frame,
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
260 CHECK_LIVE_DEVICE(device);
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)))),
269 error("Can't select a device with no frames");
273 void set_device_selected_frame(struct device *d, Lisp_Object frame)
275 if (!NILP(frame) && !FRAME_MINIBUF_ONLY_P(XFRAME(frame)))
276 set_console_last_nonminibuf_frame(XCONSOLE(DEVICE_CONSOLE(d)),
278 d->selected_frame = frame;
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.
288 XSETDEVICE(device, decode_device(device));
289 CHECK_LIVE_FRAME(frame);
291 if (!EQ(device, FRAME_DEVICE(XFRAME(frame))))
292 error("In `set-device-selected-frame', FRAME is not on DEVICE");
294 if (EQ(device, Fselected_device(Qnil)))
295 return Fselect_frame(frame);
297 set_device_selected_frame(XDEVICE(device), frame);
301 DEFUN("devicep", Fdevicep, 1, 1, 0, /*
302 Return non-nil if OBJECT is a device.
306 return DEVICEP(object) ? Qt : Qnil;
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.
314 return DEVICEP(object) && DEVICE_LIVE_P(XDEVICE(object)) ? Qt : Qnil;
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.
323 return DEVICE_NAME(decode_device(device));
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.
332 return DEVICE_CONNECTION(decode_device(device));
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.
341 return DEVICE_CONSOLE(decode_device(device));
344 #ifdef HAVE_WINDOW_SYSTEM
346 static void init_global_resources(struct device *d)
348 init_global_faces(d);
349 #ifdef HAVE_SCROLLBARS
350 init_global_scrollbars(d);
353 init_global_toolbars(d);
359 static void init_device_resources(struct device *d)
361 init_device_faces(d);
362 #ifdef HAVE_SCROLLBARS
363 init_device_scrollbars(d);
366 init_device_toolbars(d);
371 semi_canonicalize_device_connection(struct console_methods *meths,
372 Lisp_Object name, Error_behavior errb)
374 if (HAS_CONTYPE_METH_P(meths, semi_canonicalize_device_connection))
375 return CONTYPE_METH(meths, semi_canonicalize_device_connection,
378 return CONTYPE_METH_OR_GIVEN(meths,
379 canonicalize_device_connection,
384 canonicalize_device_connection(struct console_methods *meths,
385 Lisp_Object name, Error_behavior errb)
387 if (HAS_CONTYPE_METH_P(meths, canonicalize_device_connection))
388 return CONTYPE_METH(meths, canonicalize_device_connection,
391 return CONTYPE_METH_OR_GIVEN(meths,
392 semi_canonicalize_device_connection,
397 find_device_of_type(struct console_methods *meths, Lisp_Object canon)
399 Lisp_Object devcons, concons;
401 DEVICE_LOOP_NO_BREAK(devcons, concons) {
402 Lisp_Object device = XCAR(devcons);
404 if (EQ(CONMETH_TYPE(meths), DEVICE_TYPE(XDEVICE(device)))
405 && internal_equal(DEVICE_CANON_CONNECTION(XDEVICE(device)),
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.
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.)
424 Lisp_Object canon = Qnil;
430 struct console_methods *conmeths =
431 decode_console_type(type, ERROR_ME);
433 canonicalize_device_connection(conmeths, connection,
436 RETURN_UNGCPRO(Qnil);
438 RETURN_UNGCPRO(find_device_of_type(conmeths, canon));
442 for (i = 0; i < Dynarr_length(the_console_type_entry_dynarr);
444 struct console_methods *conmeths =
445 Dynarr_at(the_console_type_entry_dynarr, i).meths;
447 canonicalize_device_connection(conmeths, connection,
449 if (!UNBOUNDP(canon)) {
451 find_device_of_type(conmeths, canon);
453 RETURN_UNGCPRO(device);
457 RETURN_UNGCPRO(Qnil);
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.
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.)
472 Lisp_Object device = Ffind_device(connection, type);
475 signal_simple_error("No such device", connection);
477 signal_simple_error_2("No such device", type,
483 static Lisp_Object delete_deviceless_console(Lisp_Object console)
485 if (NILP(XCONSOLE(console)->device_list))
486 Fdelete_console(console, Qnil);
490 DEFUN("make-device", Fmake_device, 2, 3, 0, /*
491 Return a new device of type TYPE, attached to connection CONNECTION.
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
500 PROPS, if specified, should be a plist of properties controlling
503 If CONNECTION specifies an already-existing device connection, that
504 device is simply returned; no new device is created, and PROPS
507 (type, connection, props))
509 /* This function can GC */
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();
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.
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);
538 GCPRO3(device, console, name);
540 conmeths = decode_console_type(type, ERROR_ME_NOT);
542 signal_simple_error("Invalid device type", type);
544 device = Ffind_device(connection, type);
546 RETURN_UNGCPRO(device);
548 name = Fplist_get(props, Qname, Qnil);
551 Lisp_Object conconnect =
552 (HAS_CONTYPE_METH_P(conmeths, device_to_console_connection))
553 ? CONTYPE_METH(conmeths, device_to_console_connection,
554 (connection, ERROR_ME)) : connection;
555 console = create_console(name, type, conconnect, props);
558 record_unwind_protect(delete_deviceless_console, console);
560 con = XCONSOLE(console);
561 d = allocate_device(console);
562 XSETDEVICE(device, d);
564 d->devmeths = con->conmeths;
566 DEVICE_NAME(d) = name;
567 DEVICE_CONNECTION(d) =
568 semi_canonicalize_device_connection(conmeths, connection, ERROR_ME);
569 DEVICE_CANON_CONNECTION(d) =
570 canonicalize_device_connection(conmeths, connection, ERROR_ME);
572 MAYBE_DEVMETH(d, init_device, (d, props));
574 /* Do it this way so that the device list is in order of creation */
575 con->device_list = nconc2(con->device_list, Fcons(device, Qnil));
576 RESET_CHANGED_SET_FLAGS;
577 if (NILP(Vdefault_device) || DEVICE_STREAM_P(XDEVICE(Vdefault_device)))
578 Vdefault_device = device;
580 #ifdef HAVE_X_WINDOWS
582 init_global_resources(d);
584 init_device_resources(d);
586 MAYBE_DEVMETH(d, finish_init_device, (d, props));
588 /* If this is the first device on the console, make it the selected one. */
589 if (NILP(CONSOLE_SELECTED_DEVICE(con)))
590 CONSOLE_SELECTED_DEVICE(con) = device;
592 /* #### the following should trap errors. */
593 setup_device_initial_specifier_tags(d);
596 unbind_to(speccount, Qnil);
600 /* find a device other than the selected one. Prefer non-stream
601 devices over stream devices. Maybe stay on the same console. */
603 static Lisp_Object find_other_device(Lisp_Object device, int on_same_console)
605 Lisp_Object devcons = Qnil, concons;
606 Lisp_Object console = DEVICE_CONSOLE(XDEVICE(device));
608 /* look for a non-stream device */
609 DEVICE_LOOP_NO_BREAK(devcons, concons) {
610 Lisp_Object dev = XCAR(devcons);
612 && !EQ(console, DEVICE_CONSOLE(XDEVICE(dev))))
614 if (!DEVICE_STREAM_P(XDEVICE(dev)) && !EQ(dev, device) &&
615 !NILP(DEVICE_SELECTED_FRAME(XDEVICE(dev))))
621 return XCAR(devcons);
623 /* OK, now look for a stream device */
624 DEVICE_LOOP_NO_BREAK(devcons, concons) {
625 Lisp_Object dev = XCAR(devcons);
627 && !EQ(console, DEVICE_CONSOLE(XDEVICE(dev))))
630 && !NILP(DEVICE_SELECTED_FRAME(XDEVICE(dev))))
635 return XCAR(devcons);
637 /* Sorry, there ain't none */
642 find_nonminibuffer_frame_not_on_device_predicate(Lisp_Object frame,
647 VOID_TO_LISP(device, closure);
648 if (FRAME_MINIBUF_ONLY_P(XFRAME(frame)))
650 if (EQ(device, FRAME_DEVICE(XFRAME(frame))))
655 Lisp_Object find_nonminibuffer_frame_not_on_device(Lisp_Object device)
657 return find_some_frame(find_nonminibuffer_frame_not_on_device_predicate,
658 LISP_TO_VOID(device));
663 If FORCE is non-zero, allow deletion of the only frame.
665 If CALLED_FROM_DELETE_CONSOLE is non-zero, then, if
666 deleting the last device on a console, just delete it,
667 instead of calling `delete-console'.
669 If FROM_IO_ERROR is non-zero, then the device is gone due
670 to an I/O error. This affects what happens if we exit
671 (we do an emergency exit instead of `save-buffers-kill-emacs'.)
675 delete_device_internal(struct device *d, int force,
676 int called_from_delete_console, int from_io_error)
678 /* This function can GC */
683 /* OK to delete an already-deleted device. */
684 if (!DEVICE_LIVE_P(d))
687 XSETDEVICE(device, d);
690 c = XCONSOLE(DEVICE_CONSOLE(d));
692 if (!called_from_delete_console) {
693 int delete_console = 0;
694 /* If we're deleting the only device on the console,
695 delete the console. */
696 if ((XINT(Flength(CONSOLE_DEVICE_LIST(c))) == 1)
697 /* if we just created the device, it might not be listed,
699 && !NILP(memq_no_quit(device, CONSOLE_DEVICE_LIST(c))))
701 /* Or if there aren't any nonminibuffer frames that would be
702 left, delete the console (this will make SXEmacs exit). */
703 else if (NILP(find_nonminibuffer_frame_not_on_device(device)))
706 if (delete_console) {
707 delete_console_internal(c, force, 0, from_io_error);
718 /* First delete all frames without their own minibuffers,
719 to avoid errors coming from attempting to delete a frame
720 that is a surrogate for another frame. */
721 DEVICE_FRAME_LOOP(frmcons, d) {
722 struct frame *f = XFRAME(XCAR(frmcons));
723 /* delete_frame_internal() might do anything such as run hooks,
725 if (FRAME_LIVE_P(f) && !FRAME_HAS_MINIBUF_P(f))
726 delete_frame_internal(f, 1, 1, from_io_error);
728 if (!DEVICE_LIVE_P(d)) { /* make sure the delete-*-hook didn't
729 go ahead and delete anything */
735 /* #### This should probably be a device method but it is time for
736 19.14 to go out the door. */
737 /* #### BILL!!! Should this deal with HAVE_MSWINDOWS as well? */
738 #ifdef HAVE_X_WINDOWS
739 /* Next delete all frames which have the popup property to avoid
740 deleting a child after its parent. */
741 DEVICE_FRAME_LOOP(frmcons, d) {
742 struct frame *f = XFRAME(XCAR(frmcons));
744 if (FRAME_LIVE_P(f)) {
746 Fframe_property(XCAR(frmcons), Qpopup,
749 delete_frame_internal(f, 1, 1,
752 if (!DEVICE_LIVE_P(d)) { /* make sure the delete-*-hook didn't
753 go ahead and delete anything */
759 #endif /* HAVE_X_WINDOWS */
761 DEVICE_FRAME_LOOP(frmcons, d) {
762 struct frame *f = XFRAME(XCAR(frmcons));
763 /* delete_frame_internal() might do anything such as run hooks,
766 delete_frame_internal(f, 1, 1, from_io_error);
768 if (!DEVICE_LIVE_P(d)) { /* make sure the delete-*-hook didn't
769 go ahead and delete anything */
776 set_device_selected_frame(d, Qnil);
778 /* try to select another device */
780 if (EQ(device, Fselected_device(DEVICE_CONSOLE(d)))) {
781 Lisp_Object other_dev = find_other_device(device, 1);
782 if (!NILP(other_dev))
783 Fselect_device(other_dev);
786 if (EQ(device, Vdefault_device))
787 Vdefault_device = find_other_device(device, 0);
789 MAYBE_DEVMETH(d, delete_device, (d));
791 CONSOLE_DEVICE_LIST(c) = delq_no_quit(device, CONSOLE_DEVICE_LIST(c));
792 RESET_CHANGED_SET_FLAGS;
793 d->devmeths = dead_console_methods;
797 /* delete a device as a result of an I/O error. Called from
798 an enqueued magic-eval event. */
800 void io_error_delete_device(Lisp_Object device)
802 /* Note: it's the console that should get deleted, but
803 delete_device_internal() contains a hack that also deletes the
804 console when called from this function. */
805 delete_device_internal(XDEVICE(device), 1, 0, 1);
808 DEFUN("delete-device", Fdelete_device, 1, 2, 0, /*
809 Delete DEVICE, permanently eliminating it from use.
810 Normally, you cannot delete the last non-minibuffer-only frame (you must
811 use `save-buffers-kill-emacs' or `kill-emacs'). However, if optional
812 second argument FORCE is non-nil, you can delete the last frame. (This
813 will automatically call `save-buffers-kill-emacs'.)
817 CHECK_DEVICE(device);
818 delete_device_internal(XDEVICE(device), !NILP(force), 0, 0);
822 DEFUN("device-frame-list", Fdevice_frame_list, 0, 1, 0, /*
823 Return a list of all frames on DEVICE.
824 If DEVICE is nil, the selected device will be used.
828 return Fcopy_sequence(DEVICE_FRAME_LIST(decode_device(device)));
831 DEFUN("device-class", Fdevice_class, 0, 1, 0, /*
832 Return the class (color behavior) of DEVICE.
833 This will be one of 'color, 'grayscale, or 'mono.
837 return DEVICE_CLASS(decode_device(device));
840 DEFUN("set-device-class", Fset_device_class, 2, 2, 0, /*
841 Set the class (color behavior) of DEVICE.
842 CLASS should be one of 'color, 'grayscale, or 'mono.
843 This is only allowed on device such as TTY devices, where the color
844 behavior cannot necessarily be determined automatically.
848 struct device *d = decode_device(device);
849 XSETDEVICE(device, d);
850 if (!DEVICE_TTY_P(d))
851 signal_simple_error("Cannot change the class of this device",
853 if (!EQ(class, Qcolor) && !EQ(class, Qmono) && !EQ(class, Qgrayscale))
854 signal_simple_error("Must be color, mono, or grayscale", class);
855 if (!EQ(DEVICE_CLASS(d), class)) {
857 DEVICE_CLASS(d) = class;
858 DEVICE_FRAME_LOOP(frmcons, d) {
859 struct frame *f = XFRAME(XCAR(frmcons));
861 recompute_all_cached_specifiers_in_frame(f);
862 MARK_FRAME_FACES_CHANGED(f);
863 MARK_FRAME_GLYPHS_CHANGED(f);
864 MARK_FRAME_SUBWINDOWS_CHANGED(f);
865 MARK_FRAME_TOOLBARS_CHANGED(f);
866 MARK_FRAME_GUTTERS_CHANGED(f);
867 f->menubar_changed = 1;
873 DEFUN("set-device-baud-rate", Fset_device_baud_rate, 2, 2, 0, /*
874 Set the output baud rate of DEVICE to RATE.
875 On most systems, changing this value will affect the amount of padding
876 and other strategic decisions made during redisplay.
882 DEVICE_BAUD_RATE(decode_device(device)) = XINT(rate);
887 DEFUN("device-baud-rate", Fdevice_baud_rate, 0, 1, 0, /*
888 Return the output baud rate of DEVICE.
892 return make_int(DEVICE_BAUD_RATE(decode_device(device)));
895 DEFUN("device-printer-p", Fdevice_printer_p, 0, 1, 0, /*
896 Return t if DEVICE is a printer, nil if it is a display. DEVICE defaults
897 to selected device if omitted, and must be live if specified.
901 return DEVICE_PRINTER_P(decode_device(device)) ? Qt : Qnil;
904 DEFUN("device-system-metric", Fdevice_system_metric, 1, 3, 0, /*
905 Get a metric for DEVICE as provided by the system.
907 METRIC must be a symbol specifying requested metric. Note that the metrics
908 returned are these provided by the system internally, not read from resources,
909 so obtained from the most internal level.
911 If a metric is not provided by the system, then DEFAULT is returned.
913 When DEVICE is nil, selected device is assumed
915 Metrics, by group, are:
917 COLORS. Colors are returned as valid color instantiators. No other assumption
918 on the returned value should be made (i.e. it can be a string on one system but
919 a color instance on another). For colors, returned value is a cons of
920 foreground and background colors. Note that if the system provides only one
921 color of the pair, the second one may be nil.
923 color-default Standard window text foreground and background.
924 color-select Selection highlight text and background colors.
925 color-balloon Balloon popup text and background colors.
926 color-3d-face 3-D object (button, modeline) text and surface colors.
927 color-3d-light Fore and back colors for 3-D edges facing light source.
928 color-3d-dark Fore and back colors for 3-D edges facing away from
930 color-menu Text and background for menus
931 color-menu-highlight Selected menu item colors
932 color-menu-button Menu button colors
933 color-menu-disabled Unselectable menu item colors
934 color-toolbar Toolbar foreground and background colors
935 color-scrollbar Scrollbar foreground and background colors
936 color-desktop Desktop window colors
937 color-workspace Workspace window colors
939 FONTS. Fonts are returned as valid font instantiators. No other assumption on
940 the returned value should be made (i.e. it can be a string on one system but
941 font instance on another).
943 font-default Default fixed width font.
944 font-menubar Menubar font
945 font-dialog Dialog boxes font
947 GEOMETRY. These metrics are returned as conses of (X . Y). As with colors,
948 either car or cdr of the cons may be nil if the system does not provide one
949 of the corresponding dimensions.
951 size-cursor Mouse cursor size.
952 size-scrollbar Scrollbars (WIDTH . HEIGHT)
953 size-menu Menubar height, as (nil . HEIGHT)
954 size-toolbar Toolbar width and height.
955 size-toolbar-button Toolbar button size.
956 size-toolbar-border Toolbar border width and height.
957 size-icon Icon dimensions.
958 size-icon-small Small icon dimensions.
959 size-device Device screen or paper size in pixels.
960 size-workspace Workspace size in pixels. This can be less than or
961 equal to the above. For displays, this is the area
962 available to applications less window manager
963 decorations. For printers, this is the size of
965 offset-workspace Offset of workspace area from the top left corner
966 of screen or paper, in pixels.
967 size-device-mm Device screen size in millimeters.
968 device-dpi Device resolution, in dots per inch.
969 num-bit-planes Integer, number of device bit planes.
970 num-color-cells Integer, number of device color cells.
972 FEATURES. This group reports various device features. If a feature is
973 present, integer 1 (one) is returned, if it is not present, then integer
974 0 (zero) is returned. If the system is unaware of the feature, then
977 mouse-buttons Integer, number of mouse buttons, or zero if no mouse.
978 swap-buttons Non-zero if left and right mouse buttons are swapped.
979 show-sounds User preference for visual over audible bell.
980 slow-device Device is slow, avoid animation.
981 security Non-zero if user environment is secure.
983 (device, metric, default_))
985 struct device *d = decode_device(device);
986 enum device_metrics m;
991 else if (EQ (metric, Q##met)) \
999 FROB(color_3d_light);
1000 FROB(color_3d_dark);
1002 FROB(color_menu_highlight);
1003 FROB(color_menu_button);
1004 FROB(color_menu_disabled);
1005 FROB(color_toolbar);
1006 FROB(color_scrollbar);
1007 FROB(color_desktop);
1008 FROB(color_workspace);
1013 FROB(size_scrollbar);
1016 FROB(size_toolbar_button);
1017 FROB(size_toolbar_border);
1019 FROB(size_icon_small);
1021 FROB(size_workspace);
1022 FROB(offset_workspace);
1023 FROB(size_device_mm);
1025 FROB(num_bit_planes);
1026 FROB(num_color_cells);
1027 FROB(mouse_buttons);
1033 signal_simple_error("Invalid device metric symbol", metric);
1035 res = DEVMETH_OR_GIVEN(d, device_system_metrics, (d, m), Qunbound);
1036 return UNBOUNDP(res) ? default_ : res;
1041 DEFUN("device-system-metrics", Fdevice_system_metrics, 0, 1, 0, /*
1042 Get a property list of device metric for DEVICE.
1044 See `device-system-metric' for the description of available metrics.
1045 DEVICE defaults to selected device when omitted.
1049 struct device *d = decode_device(device);
1050 Lisp_Object plist = Qnil, one_metric;
1053 if (!UNBOUNDP ((one_metric = \
1054 DEVMETH_OR_GIVEN (d, device_system_metrics, \
1055 (d, DM_##m), Qunbound)))) \
1056 plist = Fcons (Q##m, Fcons (one_metric, plist));
1058 FROB(color_default);
1060 FROB(color_balloon);
1061 FROB(color_3d_face);
1062 FROB(color_3d_light);
1063 FROB(color_3d_dark);
1065 FROB(color_menu_highlight);
1066 FROB(color_menu_button);
1067 FROB(color_menu_disabled);
1068 FROB(color_toolbar);
1069 FROB(color_scrollbar);
1070 FROB(color_desktop);
1071 FROB(color_workspace);
1076 FROB(size_scrollbar);
1079 FROB(size_toolbar_button);
1080 FROB(size_toolbar_border);
1082 FROB(size_icon_small);
1084 FROB(size_workspace);
1085 FROB(offset_workspace);
1086 FROB(size_device_mm);
1088 FROB(num_bit_planes);
1089 FROB(num_color_cells);
1090 FROB(mouse_buttons);
1101 Lisp_Object domain_device_type(Lisp_Object domain)
1103 /* This cannot GC */
1104 assert(WINDOWP(domain) || FRAMEP(domain)
1105 || DEVICEP(domain) || CONSOLEP(domain));
1107 if (WINDOWP(domain)) {
1108 if (!WINDOW_LIVE_P(XWINDOW(domain)))
1110 domain = WINDOW_FRAME(XWINDOW(domain));
1112 if (FRAMEP(domain)) {
1113 if (!FRAME_LIVE_P(XFRAME(domain)))
1115 domain = FRAME_DEVICE(XFRAME(domain));
1117 if (DEVICEP(domain)) {
1118 if (!DEVICE_LIVE_P(XDEVICE(domain)))
1120 domain = DEVICE_CONSOLE(XDEVICE(domain));
1122 return CONSOLE_TYPE(XCONSOLE(domain));
1126 * Determine whether window system bases window geometry on character
1128 * Return non-zero for pixel-based geometry, zero for character-based.
1130 int window_system_pixelated_geometry(Lisp_Object domain)
1132 /* This cannot GC */
1133 Lisp_Object winsy = domain_device_type(domain);
1134 struct console_methods *meth = decode_console_type(winsy, ERROR_ME_NOT);
1136 return CONMETH_IMPL_FLAG(meth, XDEVIMPF_PIXEL_GEOMETRY);
1139 DEFUN("domain-device-type", Fdomain_device_type, 0, 1, 0, /*
1140 Return the device type symbol for a DOMAIN, e.g. 'x or 'tty.
1141 DOMAIN can be either a window, frame, device or console.
1145 if (!WINDOWP(domain) && !FRAMEP(domain)
1146 && !DEVICEP(domain) && !CONSOLEP(domain))
1148 ("Domain must be either a window, frame, device or console",
1151 return domain_device_type(domain);
1154 void handle_asynch_device_change(void)
1157 int old_asynch_device_change_pending = asynch_device_change_pending;
1158 for (i = 0; i < Dynarr_length(the_console_type_entry_dynarr); i++) {
1159 if (Dynarr_at(the_console_type_entry_dynarr, i).meths->
1160 asynch_device_change_method)
1161 (Dynarr_at(the_console_type_entry_dynarr, i).meths->
1162 asynch_device_change_method) ();
1164 /* reset the flag to 0 unless another notification occurred while
1165 we were processing this one. Block SIGWINCH during this
1166 check to prevent a possible race condition. */
1168 EMACS_BLOCK_SIGNAL(SIGWINCH);
1170 if (old_asynch_device_change_pending == asynch_device_change_pending)
1171 asynch_device_change_pending = 0;
1173 EMACS_UNBLOCK_SIGNAL(SIGWINCH);
1178 call_critical_lisp_code(struct device *d, Lisp_Object function,
1181 int old_gc_currently_forbidden = gc_currently_forbidden;
1182 Lisp_Object old_inhibit_quit = Vinhibit_quit;
1184 /* There's no reason to bother doing specbinds here, because if
1185 initialize-*-faces signals an error, emacs is going to crash
1188 gc_currently_forbidden = 1;
1192 /* But it's useful to have an error handler; otherwise an infinite
1195 call1_with_handler(Qreally_early_error_handler, function,
1198 call0_with_handler(Qreally_early_error_handler, function);
1201 Vinhibit_quit = old_inhibit_quit;
1202 gc_currently_forbidden = old_gc_currently_forbidden;
1205 /************************************************************************/
1206 /* initialization */
1207 /************************************************************************/
1209 void syms_of_device(void)
1211 INIT_LRECORD_IMPLEMENTATION(device);
1213 DEFSUBR(Fvalid_device_class_p);
1214 DEFSUBR(Fdevice_class_list);
1216 DEFSUBR(Fdfw_device);
1217 DEFSUBR(Fselected_device);
1218 DEFSUBR(Fselect_device);
1219 DEFSUBR(Fset_device_selected_frame);
1221 DEFSUBR(Fdevice_live_p);
1222 DEFSUBR(Fdevice_name);
1223 DEFSUBR(Fdevice_connection);
1224 DEFSUBR(Fdevice_console);
1225 DEFSUBR(Ffind_device);
1226 DEFSUBR(Fget_device);
1227 DEFSUBR(Fmake_device);
1228 DEFSUBR(Fdelete_device);
1229 DEFSUBR(Fdevice_frame_list);
1230 DEFSUBR(Fdevice_class);
1231 DEFSUBR(Fset_device_class);
1232 DEFSUBR(Fdevice_system_metrics);
1233 DEFSUBR(Fdevice_system_metric);
1234 DEFSUBR(Fset_device_baud_rate);
1235 DEFSUBR(Fdevice_baud_rate);
1236 DEFSUBR(Fdomain_device_type);
1237 DEFSUBR(Fdevice_printer_p);
1239 defsymbol(&Qdevicep, "devicep");
1240 defsymbol(&Qdevice_live_p, "device-live-p");
1242 defsymbol(&Qcreate_device_hook, "create-device-hook");
1243 defsymbol(&Qdelete_device_hook, "delete-device-hook");
1245 /* Qcolor defined in general.c */
1246 defsymbol(&Qgrayscale, "grayscale");
1247 defsymbol(&Qmono, "mono");
1249 /* Device metrics symbols */
1250 defsymbol(&Qcolor_default, "color-default");
1251 defsymbol(&Qcolor_select, "color-select");
1252 defsymbol(&Qcolor_balloon, "color-balloon");
1253 defsymbol(&Qcolor_3d_face, "color-3d-face");
1254 defsymbol(&Qcolor_3d_light, "color-3d-light");
1255 defsymbol(&Qcolor_3d_dark, "color-3d-dark");
1256 defsymbol(&Qcolor_menu, "color-menu");
1257 defsymbol(&Qcolor_menu_highlight, "color-menu-highlight");
1258 defsymbol(&Qcolor_menu_button, "color-menu-button");
1259 defsymbol(&Qcolor_menu_disabled, "color-menu-disabled");
1260 defsymbol(&Qcolor_toolbar, "color-toolbar");
1261 defsymbol(&Qcolor_scrollbar, "color-scrollbar");
1262 defsymbol(&Qcolor_desktop, "color-desktop");
1263 defsymbol(&Qcolor_workspace, "color-workspace");
1264 defsymbol(&Qfont_default, "font-default");
1265 defsymbol(&Qfont_menubar, "font-menubar");
1266 defsymbol(&Qfont_dialog, "font-dialog");
1267 defsymbol(&Qsize_cursor, "size-cursor");
1268 defsymbol(&Qsize_scrollbar, "size-scrollbar");
1269 defsymbol(&Qsize_menu, "size-menu");
1270 defsymbol(&Qsize_toolbar, "size-toolbar");
1271 defsymbol(&Qsize_toolbar_button, "size-toolbar-button");
1272 defsymbol(&Qsize_toolbar_border, "size-toolbar-border");
1273 defsymbol(&Qsize_icon, "size-icon");
1274 defsymbol(&Qsize_icon_small, "size-icon-small");
1275 defsymbol(&Qsize_device, "size-device");
1276 defsymbol(&Qsize_workspace, "size-workspace");
1277 defsymbol(&Qoffset_workspace, "offset-workspace");
1278 defsymbol(&Qsize_device_mm, "size-device-mm");
1279 defsymbol(&Qnum_bit_planes, "num-bit-planes");
1280 defsymbol(&Qnum_color_cells, "num-color-cells");
1281 defsymbol(&Qdevice_dpi, "device-dpi");
1282 defsymbol(&Qmouse_buttons, "mouse-buttons");
1283 defsymbol(&Qswap_buttons, "swap-buttons");
1284 defsymbol(&Qshow_sounds, "show-sounds");
1285 defsymbol(&Qslow_device, "slow-device");
1286 defsymbol(&Qsecurity, "security");
1289 void reinit_vars_of_device(void)
1291 staticpro_nodump(&Vdefault_device);
1292 Vdefault_device = Qnil;
1293 asynch_device_change_pending = 0;
1296 void vars_of_device(void)
1298 reinit_vars_of_device();
1300 DEFVAR_LISP("create-device-hook", &Vcreate_device_hook /*
1301 Function or functions to call when a device is created.
1302 One argument, the newly-created device.
1303 This is called after the first frame has been created, but before
1304 calling the `create-frame-hook'.
1305 Note that in general the device will not be selected.
1307 Vcreate_device_hook = Qnil;
1309 DEFVAR_LISP("delete-device-hook", &Vdelete_device_hook /*
1310 Function or functions to call when a device is deleted.
1311 One argument, the to-be-deleted device.
1313 Vdelete_device_hook = Qnil;
1315 Vdevice_class_list = list3(Qcolor, Qgrayscale, Qmono);
1316 staticpro(&Vdevice_class_list);
1318 /* Death to devices.el !!! */
1319 Fprovide(intern("devices"));