Mercurial > hg > xemacs-beta
comparison lisp/specifier.el @ 872:79c6ff3eef26
[xemacs-hg @ 2002-06-20 21:18:01 by ben]
font changes etc.; some 21.4 changes
mule/mule-msw-init-late.el: Specify charset->windows-registry conversion.
mule/mule-x-init.el: Delete extra mule font additions here. Put them in faces.c.
cl-macs.el: Document better.
font-lock.el: Move Lisp function regexp to lisp-mode.el.
lisp-mode.el: Various indentation fixes:
Handle flet functions better.
Handle argument lists in defuns and flets.
Handle quoted lists, e.g. property lists -- don't indent like
function calls. Distinguish between lambdas and other lists.
lisp-mode.el: Handle this form.
faces.el, font-menu.el, font.el, gtk-faces.el, msw-faces.el, msw-font-menu.el, x-faces.el, x-init.el: Major overhaul of face-handling code:
-- Fix lots of bogus code in msw-faces.el, msw-font-menu.el,
font-menu.el that was "truenaming" font specs -- i.e. in the
process of frobbing a particular field in a general user-specified
font spec with wildcarded fields, sticking in particular values
for all the remaining wildcarded fields. This bug was rampant
everywhere except in x-faces.el (the oldest and only correctly
written code). This also means that we need to work with font
names at all times and not font instances, because a font instance
is essentially a truenamed font.
-- Total rewrite of extremely junky code in msw-faces.el. Work
with names as well as font instances, and return names; stop
truenaming when canonicalizing and frobbing; fix handling of the
combined style field, i.e. weight/slant (also fixed in font.el).
-- Totally rewrite the frobbing functions in faces.el. This time,
we frob all the instantiators rather than just computing a single
instance value and working backwards. That way, e.g., `bold' will
work for all charsets that have bold available, rather than only
for whatever charset was part of the computed font instance
(another example of the truename virus). Also fix up code to look
at the fallbacks (all of them) when no global value present, so we
don't need to put something in the global value. Intelligently
handle a request to frob a buffer locale, rather than signalling
an error. When frobbing instantiators, try hard to figure out
what device type is associated with them, and frob each according
to its own proper device type. Correctly handle inheritance
vectors given as instantiators. Preserve existing tags when
putting back frobbed instantiators. Extract out general
specifier-frobbing code into specifier.el. Document everything
cleanly. Do lots of other things better, etc.
-- Don't duplicatively set a global specification for the default
font -- it's already in the fallback and we no longer need a
default global specification present. Delete various code in
x-faces.el and msw-faces.el that duplicated the lists of fonts in
faces.c.
-- init-global-faces was not being called at all under MS Windows!
Major bogosity. That caused device-specific values to get stuck
into all the fonts, making it very hard to change them -- setting
global specs caused nothing to happen.
-- Correct weight names in font.el.
-- Lots more font fixups in objects*.c.
Printer.el: Warning fix.
specifier.el: Add more args to map-specifier.
Add various "heuristic" specifier functions to aid in creation of
specifier-munging code such as in faces.el.
subr.el: New functions.
lwlib.c: Fix warning.
config.inc.samp: Clean up, add args to control fastcall (not yet supported! the
changes needed are in another ws of mine), profile support, vc6
support, union-type.
xemacs.dsp, xemacs.mak: Semi-major overhaul.
Fix bug where dump-id was always getting recomputed, forcing a
redump even when nothing changed.
Add support for fastcall. Support edit-and-continue (on by
default) with vc6. Use incremental linking when doing a debug
compilation. Add support for profiling.
Consolidate the various debug flags.
Partial support for "batch-compiling" -- compiling many files on a
single invocation of the compiler. Doesn't seem to help that much
for me, so it's not finished or enabled by default.
Remove HAVE_MSW_C_DIRED, we always do.
Correct some sloppy use of directories.
s/cygwin32.h: Allow pdump to work under Cygwin (mmap is broken, so need to undefine
HAVE_MMAP).
s/win32-common.h, s/windowsnt.h: Support for fastcall. Add WIN32_ANY for identifying all Win32
variants (Cygwin, native, MinGW). Both of these are properly used
in another ws.
alloc.c, balloon-x.c, buffer.c, bytecode.c, callint.c, cm.c, cmdloop.c, cmds.c, console-gtk.c, console-gtk.h, console-msw.c, console-msw.h, console-stream.c, console-stream.h, console-tty.c, console-tty.h, console-x.c, console-x.h, console.c, console.h, device-gtk.c, device-msw.c, device-tty.c, device-x.c, device.c, device.h, devslots.h, dialog-gtk.c, dialog-msw.c, dialog-x.c, dialog.c, dired-msw.c, editfns.c, emacs.c, event-Xt.c, event-gtk.c, event-msw.c, event-stream.c, event-tty.c, event-unixoid.c, events.c, extents.c, extents.h, faces.c, fileio.c, fns.c, frame-gtk.c, frame-msw.c, frame-tty.c, frame-x.c, frame.c, frame.h, glyphs-eimage.c, glyphs-gtk.c, glyphs-msw.c, glyphs-widget.c, glyphs-x.c, glyphs.c, glyphs.h, gui-gtk.c, gui-msw.c, gui-x.c, gui.c, gutter.c, input-method-xlib.c, intl-encap-win32.c, intl-win32.c, keymap.c, lisp.h, macros.c, menubar-gtk.c, menubar-msw.c, menubar-x.c, menubar.c, menubar.h, minibuf.c, mule-charset.c, nt.c, objects-gtk.c, objects-gtk.h, objects-msw.c, objects-msw.h, objects-tty.c, objects-tty.h, objects-x.c, objects-x.h, objects.c, objects.h, postgresql.c, print.c, process.h, redisplay-gtk.c, redisplay-msw.c, redisplay-output.c, redisplay-tty.c, redisplay-x.c, redisplay.c, redisplay.h, scrollbar-gtk.c, scrollbar-msw.c, scrollbar-x.c, scrollbar.c, select-gtk.c, select-msw.c, select-x.c, select.c, signal.c, sound.c, specifier.c, symbols.c, syntax.c, sysdep.c, syssignal.h, syswindows.h, toolbar-common.c, toolbar-gtk.c, toolbar-msw.c, toolbar-x.c, toolbar.c, unicode.c, window.c, window.h: The following are the major changes made:
(1) Separation of various header files into an external and an
internal version, similar to the existing separation of process.h
and procimpl.h. Eventually this should be done for all Lisp
objects. The external version has the same name as currently; the
internal adds -impl. The external file has XFOO() macros for
objects, but the structure is opaque and defined only in the
internal file. It's now reasonable to move all prototypes in
lisp.h into the appropriate external file, and this should be
done. Currently, separation has been done on extents.h,
objects*.h, console.h, device.h, frame.h, and window.h.
For c/d/f/w, the most basic properties are available in the
external header file, with the macros resolving to functions. In
the internal header file, the macros are redefined to directly
access the structure. Also, the global MARK_FOO_CHANGED macros
have been made into functions so that they can be accessed without
needing to include lots of -impl headers -- they are used in
almost exclusively in non-time-critical functions, and take up
enough time that the function overhead will be negligible.
Similarly, the function overhead from making the basic properties
mentioned above into functions is negligible, and code that does
heavy accessing of c/d/f/w structures inevitably ends up needing
the internal header files, anyway.
(2) More face changes.
-- Major rewrite of objects-msw.c. Now handles wildcard specs
properly, rather than "truenaming" (or even worse, signalling an
error, which previously happened with some of the fallbacks if you
tried to use them in make-font-instance!).
-- Split charset matching of fonts into two stages -- one to find
a font specifically designed for a particular charset (by
examining its registry), the second to find a Unicode font that
can support the charset. This needs to proceed as two complete,
separate instantiations in order to work properly (otherwise many
of the fonts in the HELLO page look wrong). This should also make
it easy to support iso10646 (Unicode) fonts under X.
-- All default values for fonts are now completely specified in
the fallbacks. Stuff from mule-x-init.el has all been moved here,
merged with the existing specs, and totally rethought so you get
sensible results. (HELLO now looks much better!).
-- Generalize the "default X/GTK device" stuff into a
per-device-type "default device".
-- Add mswindows-{set-}charset-registry. In time,
charset<->code-page conversion functions will be removed.
-- Wrap protective code around calls to compute device specifier tags,
and do this computation before calling the face initialization code
because the latter may need these tags to be correctly updated.
(3) Other changes.
EmacsFrame.c, glyphs-msw.c, eval.c, gui-x.c, intl-encap-win32.c, search.c, signal.c, toolbar-msw.c, unicode.c: Warning fixes.
config.h.in: #undefs meant to be frobbed by configure *MUST* go inside of
#ifndef WIN32_NO_CONFIGURE, and everything else *MUST* go outside!
eval.c: Let detailed backtraces be detailed.
specifier.c: Don't override user's print-string-length/print-length settings.
glyphs.c: New function image-instance-instantiator.
config.h.in, sysdep.c: Changes for fastcall.
sysdep.c, nt.c: Fix up a previous botched patch that tried to add support for both
EEXIST and EACCES. IF THE BOTCHED PATCH WENT INTO 21.4, THIS FIXUP
NEEDS TO GO IN, TOO.
search.c: Fix *evil* crash due to incorrect synching of syntax-cache code
with 21.1. THIS SHOULD GO INTO 21.4.
author | ben |
---|---|
date | Thu, 20 Jun 2002 21:19:10 +0000 |
parents | 943eaba38521 |
children | ec2d1e636272 |
comparison
equal
deleted
inserted
replaced
871:732270854293 | 872:79c6ff3eef26 |
---|---|
1 ;;; specifier.el --- Lisp interface to specifiers | 1 ;;; specifier.el --- Lisp interface to specifiers |
2 | 2 |
3 ;; Copyright (C) 1997 Free Software Foundation, Inc. | 3 ;; Copyright (C) 1997 Free Software Foundation, Inc. |
4 ;; Copyright (C) 1995, 1996, 2000 Ben Wing. | 4 ;; Copyright (C) 1995, 1996, 2000, 2002 Ben Wing. |
5 | 5 |
6 ;; Author: Ben Wing <ben@xemacs.org> | 6 ;; Author: Ben Wing <ben@xemacs.org> |
7 ;; Keywords: internal, dumped | 7 ;; Keywords: internal, dumped |
8 | 8 |
9 ;;; Synched up with: Not in FSF. | 9 ;;; Synched up with: Not in FSF. |
48 (add-spec-list-to-specifier sp spec-list) | 48 (add-spec-list-to-specifier sp spec-list) |
49 sp)) | 49 sp)) |
50 | 50 |
51 ;; God damn, do I hate dynamic scoping. | 51 ;; God damn, do I hate dynamic scoping. |
52 | 52 |
53 (defun map-specifier (ms-specifier ms-func &optional ms-locale ms-maparg) | 53 (defun map-specifier (ms-specifier ms-func &optional ms-locale ms-maparg |
54 ms-tag-set ms-exact-p) | |
54 "Apply MS-FUNC to the specification(s) for MS-LOCALE in MS-SPECIFIER. | 55 "Apply MS-FUNC to the specification(s) for MS-LOCALE in MS-SPECIFIER. |
55 | 56 |
56 If MS-LOCALE is a locale, MS-FUNC will be called for that locale. | 57 If MS-LOCALE is a locale, MS-FUNC will be called for that locale. |
57 If MS-LOCALE is a locale type, MS-FUNC will be mapped over all locales | 58 If MS-LOCALE is a locale type, MS-FUNC will be mapped over all locales |
58 of that type. If MS-LOCALE is 'all or nil, MS-FUNC will be mapped | 59 of that type. If MS-LOCALE is 'all or nil, MS-FUNC will be mapped |
59 over all locales in MS-SPECIFIER. | 60 over all locales in MS-SPECIFIER. |
61 | |
62 MS-TAG-SET and MS-EXACT-P are as in `specifier-spec-list'. | |
60 | 63 |
61 MS-FUNC is called with four arguments: the MS-SPECIFIER, the locale | 64 MS-FUNC is called with four arguments: the MS-SPECIFIER, the locale |
62 being mapped over, the inst-list for that locale, and the | 65 being mapped over, the inst-list for that locale, and the |
63 optional MS-MAPARG. If any invocation of MS-FUNC returns non-nil, | 66 optional MS-MAPARG. If any invocation of MS-FUNC returns non-nil, |
64 the mapping will stop and the returned value becomes the | 67 the mapping will stop and the returned value becomes the |
65 value returned from `map-specifier'. Otherwise, `map-specifier' | 68 value returned from `map-specifier'. Otherwise, `map-specifier' |
66 returns nil." | 69 returns nil." |
67 (let ((ms-specs (specifier-spec-list ms-specifier ms-locale)) | 70 (let ((ms-specs (specifier-spec-list ms-specifier ms-locale ms-tag-set |
71 ms-exact-p)) | |
68 ms-result) | 72 ms-result) |
69 (while (and ms-specs (not ms-result)) | 73 (while (and ms-specs (not ms-result)) |
70 (let ((ms-this-spec (car ms-specs))) | 74 (let ((ms-this-spec (car ms-specs))) |
71 (setq ms-result (funcall ms-func ms-specifier (car ms-this-spec) | 75 (setq ms-result (funcall ms-func ms-specifier (car ms-this-spec) |
72 (cdr ms-this-spec) ms-maparg)) | 76 (cdr ms-this-spec) ms-maparg)) |
406 (canonicalize-spec-list nval (specifier-type specifier)) | 410 (canonicalize-spec-list nval (specifier-type specifier)) |
407 how-to-add)))) | 411 how-to-add)))) |
408 value) | 412 value) |
409 | 413 |
410 (defun modify-specifier-instances (specifier func &optional args force default | 414 (defun modify-specifier-instances (specifier func &optional args force default |
411 locale tag-set) | 415 locale tag-set) |
412 "Modify all specifications that match LOCALE and TAG-SET by FUNC. | 416 "Modify all specifications that match LOCALE and TAG-SET by FUNC. |
413 | 417 |
414 For each specification that exists for SPECIFIER, in locale LOCALE | 418 For each specification that exists for SPECIFIER, in locale LOCALE |
415 that matches TAG-SET, call the function FUNC with the instance as its | 419 that matches TAG-SET, call the function FUNC with the instance as its |
416 first argument and with optional arguments ARGS. The result is then | 420 first argument and with optional arguments ARGS. The result is then |
611 ;; code) can safely clear specs with this tag without worrying | 615 ;; code) can safely clear specs with this tag without worrying |
612 ;; about clobbering user settings. | 616 ;; about clobbering user settings. |
613 | 617 |
614 (define-specifier-tag 'default) | 618 (define-specifier-tag 'default) |
615 | 619 |
620 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
621 ;;; "Heuristic" specifier functions ;;; | |
622 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
623 | |
624 ;;; "Heuristic" is a euphemism for kludge. This stuff works well in | |
625 ;;; practice, though. | |
626 | |
627 ;;; You might view all the contortions we do here and in Face-frob-property | |
628 ;;; as indicative of design failures with specifiers, and perhaps you're | |
629 ;;; right. But in fact almost all code that attempts to interface to | |
630 ;;; humans and produce "intuitive" results gets messy, particularly with a | |
631 ;;; system as complicated as specifiers, whose complexity results from an | |
632 ;;; attempt to work well in many different circumstances. We could create | |
633 ;;; a much simpler system, but the tradeoff would be that you'd have to | |
634 ;;; programmatically control all the stuff that gets handled automatically | |
635 ;;; by setting the right specifiers -- and then things wouldn't "just work" | |
636 ;;; if the user simultaneously creates a TTY and X device, or X devices on | |
637 ;;; different types of machines, or wants some buffers to display | |
638 ;;; differently from others, etc. without a lot of hook functions and other | |
639 ;;; glue machinery to set everything up. The result would be just as much | |
640 ;;; complexity, but worse, and much harder to control, since there wouldn't | |
641 ;;; be any standard framework for managing all these hook functions and the | |
642 ;;; user would have to be able to write lots of Lisp code to get things | |
643 ;;; working. | |
644 | |
645 ;;; The problem is that we have no high-level code, e.g. custom, to make it | |
646 ;;; easy for the user to control specifiers nicely. The following | |
647 ;;; lower-level code, though, should make it easier to implement the | |
648 ;;; high-level code. | |
649 | |
650 ;;; #### Something like Face-frob-property, but more general, should be | |
651 ;;; created for general specifier frobbing. | |
652 | |
653 ;;; #### Other possible extensions to specifiers would be | |
654 ;;; | |
655 ;;; (a) the ability to create specifications for particular types of | |
656 ;;; buffers, e.g. all C-mode buffers one way, all text-mode buffers | |
657 ;;; another way, etc. Perhaps this should be implemented through hook | |
658 ;;; functions; but that wouldn't easily allow you to `make-face-bold' | |
659 ;;; and have it work on these other kinds of specifications. Probably | |
660 ;;; a better way is to extend the tag mechanism so that it can specify | |
661 ;;; things other than device types. One way would be to simply allow | |
662 ;;; tags to have arbitrary elisp attached to them -- a function that | |
663 ;;; takes a domain and returns whether the attached instantiator | |
664 ;;; applies. This should be doable given (a) that we now have code to | |
665 ;;; allow elisp to be run inside a "sandbox", sufficiently protected | |
666 ;;; that it can even be called from redisplay, and (b) the large amount | |
667 ;;; of caching we already have, which would minimize the speed hit. | |
668 ;;; However, this still runs into problems -- (a) it requires | |
669 ;;; programming to get anything at all done, and (b) you'll get | |
670 ;;; horrible namespace clashes very quickly. Another possibility to be | |
671 ;;; used in conjunction with this would be vector tags, with an | |
672 ;;; extendable mechanism to control their syntax. For example, | |
673 ;;; | |
674 ;;; [tag :mode 'c] (buffer in c-mode) | |
675 ;;; [tag :buffer-name "\\*Help: function"] (help-on-function buffers) | |
676 ;;; [tag :buffer-coding-system 'japanese-euc] (buffer's coding system is | |
677 ;;; EUC-JP) | |
678 ;;; [tag :buffer-file-name "^#.*#$"] (autosave files) | |
679 ;;; [tag :language-environment "French"] (whenever the global language | |
680 ;;; environment is French) | |
681 ;;; [tag :font-height-minimum '(default 12)] (if the height of the default | |
682 ;;; font is at least 12 pixels | |
683 ;;; in this domain) | |
684 ;;; | |
685 ;;; The general idea is that the properties allowable in a tag vector | |
686 ;;; are extendable, just by specifying the property name and a function | |
687 ;;; of two arguments, the property value and the domain, which should | |
688 ;;; return whether the tag applies. You could imagine very complex | |
689 ;;; behavior (e.g. combining two tags in a single tag set makes an | |
690 ;;; `and', and putting the two tags separately with separate (perhaps | |
691 ;;; identical) instantiators makes an `or'. You could effectively do a | |
692 ;;; lot of what you might want to do with hooks, but in a much more | |
693 ;;; controllable fashion. Obviously, much of this complexity wouldn't | |
694 ;;; necessarily be directly set by the user -- they wouldn't probably | |
695 ;;; do more than simple tags based on mode, buffer or file name, etc. | |
696 ;;; But a higher-level interface could easily have various possible | |
697 ;;; "behaviors" to choose from, implemented using this mechanism. | |
698 ;;; | |
699 ;;; #### WE NEED CUSTOM SUPPORT! | |
700 ;;; | |
701 ;;; (b) Another possibility is "partial" inheritance. For example -- | |
702 ;;; toolbars and menubars are complex specifications. Currently the | |
703 ;;; only way to make a change is to copy the entire value and make the | |
704 ;;; necessary modifications. What we would like instead is to be able | |
705 ;;; to construct a mini-menubar that says something like "add this menu | |
706 ;;; here" and combine with everything else. That would require a | |
707 ;;; slightly different approach to instantiation. Currently it just | |
708 ;;; searches up the tree from specific to general, looking for a match; | |
709 ;;; from this match, it generates the instance. Instead, it would | |
710 ;;; potentially have to record all the matches it found and pass a list | |
711 ;;; of them to the instantiation function. To implement this, we would | |
712 ;;; create another specifier method "instantiator_inherits_up", which | |
713 ;;; looks at the instantiator to determine if it calls for combining | |
714 ;;; itself with the value higher up. this tells the specifier code | |
715 ;;; whether to stop now or keep going. It would then pass a Dynarr of | |
716 ;;; the instantiators to the instantiate method, which might be a | |
717 ;;; special version, e.g. "instantiate_multi". | |
718 | |
719 (defun instance-to-instantiator (inst) | |
720 "Convert an instance to an instantiator. | |
721 If we have an instance object, we fetch the instantiator that generated the object. Otherwise, we just return the instance." | |
722 (cond ((font-instance-p inst) | |
723 (setq inst (font-instance-name inst))) | |
724 ((color-instance-p inst) | |
725 (setq inst (color-instance-name inst))) | |
726 ((image-instance-p inst) | |
727 (setq inst (image-instance-instantiator inst))) | |
728 (t inst))) | |
729 | |
730 (defun device-type-matches-spec (devtype devtype-spec) | |
731 ;; Return DEVTYPE (a devtype) if it matches DEVTYPE-SPEC, else nil. | |
732 ;; DEVTYPE-SPEC can be nil (all types OK), a device type (only that type | |
733 ;; OK), or `window-system' -- window system device types OK. | |
734 (cond ((not devtype-spec) devtype) | |
735 ((eq devtype-spec 'window-system) | |
736 (and (not (memq devtype '(tty stream))) devtype)) | |
737 (t (and (eq devtype devtype-spec) devtype)))) | |
738 | |
739 (defun add-tag-to-inst-list (inst-list tag-set) | |
740 "Add TAG-SET (tag or tag-set) to all tags in INST-LIST." | |
741 ;; Ah, all is sweetness and light with `loop' | |
742 (if (null tag-set) inst-list | |
743 (loop for (t2 . x2) in inst-list | |
744 for newt2 = (delete-duplicates | |
745 (append (if (listp tag-set) tag-set (list tag-set)) | |
746 (if (listp t2) t2 (list t2)))) | |
747 collect (cons newt2 x2)))) | |
748 | |
749 (defun derive-domain-from-locale (locale &optional devtype-spec current-device) | |
750 "Given a locale, try to derive the \"most reasonable\" domain. | |
751 | |
752 This is a heuristic \(\"works most of the time\") algorithm. | |
753 | |
754 \[Remember that, in specifiers, locales are what you attach specifications or | |
755 \"instantiators\" to, and domains are the contexts in which you can | |
756 retrieve the value or \"instance\" of the specifier. Not all locales are | |
757 domains. In particular, buffers are locales but not domains because | |
758 buffers may be displayed in different windows on different frames, and thus | |
759 end up with different values if the frames each have a frame-local | |
760 instantiator and the instantiators are different. However, we may well | |
761 find ourselves in a situation where we want to figure out the most likely | |
762 value of a specifier in a buffer -- for example we might conceptually want | |
763 to make a buffer's modeline face be bold, so we need to figure out what the | |
764 current face is. If the buffer already has an instantiator, it's easy; but | |
765 if it doesn't, we want to do something reasonable rather than just issue an | |
766 error, even though technically the value is not well-defined. We want | |
767 something that gives the right answer most of the time.] | |
768 | |
769 LOCALE is a specifier locale -- i.e. a buffer, window, frame, device, the | |
770 symbol `global', or nil, meaning the same as `global'. | |
771 | |
772 DEVTYPE-SPEC, if given, can restrict the possible return values to domains | |
773 on devices of that device type; or if it's `window-system', to domains on | |
774 window-system devices. | |
775 | |
776 CURRENT-DEVICE is what should be considered as the \"selected device\" when | |
777 this value is needed. It defaults to the currently selected device. | |
778 | |
779 -- If LOCALE is a domain, it's simply returned. | |
780 -- If LOCALE is `all', `global', or nil, we return CURRENT-DEVICE. | |
781 -- If LOCALE is a buffer, we use `get-buffer-window' to find a window viewing | |
782 the buffer, and return it if there is one; otherwise we return the selected | |
783 window on CURRENT-DEVICE. | |
784 | |
785 The return value may be nil if the only possible values don't agree with | |
786 DEVTYPE-SPEC." | |
787 ;; DEVICE aims to be the selected device, but picks some other | |
788 ;; device if that won't work. may be nil. | |
789 (let* ((device (or current-device (selected-device))) | |
790 (device (if (device-type-matches-spec (device-type device) | |
791 devtype-spec) | |
792 device | |
793 (first | |
794 (delete-if-not | |
795 #'(lambda (x) | |
796 (device-type-matches-spec (device-type x) | |
797 devtype-spec)) | |
798 (device-list)))))) | |
799 (cond ((memq locale '(all nil global)) device) | |
800 ((valid-specifier-domain-p locale) | |
801 (and (device-type-matches-spec (device-type (dfw-device locale)) | |
802 devtype-spec) | |
803 locale)) | |
804 ((bufferp locale) | |
805 (let ((win (get-buffer-window locale t devtype-spec))) | |
806 (or win (and device (selected-window device)))))))) | |
807 | |
808 (defun derive-device-type-from-tag-set (tag-set &optional try-stages | |
809 devtype-spec current-device) | |
810 "Given a tag set, try (heuristically) to get a device type from it. | |
811 | |
812 There are three stages that this function proceeds through, each one trying | |
813 harder than the previous to get a value. TRY-STAGES controls how many | |
814 stages to try. If nil or 1, only stage 1 is done; if 2; stages 1 and 2 are | |
815 done; if 3, stages 1-3 are done; if t, all stages are done (currently 1-3). | |
816 | |
817 Stage 1 looks at the tags themselves to see if any of them are device-type | |
818 tags. If so, it returns the device type. If there is more than one device | |
819 type, this tag can never match anything, but we go ahead and return one of | |
820 them. If no device types in the tags, we fail. | |
821 | |
822 Stage 2 runs all devices through the tag set to see if any match, and | |
823 accumulate a list of device types of all matching devices. If there is | |
824 exactly one device type in the list, we return it, else fail. | |
825 | |
826 Stage 3 picks up from where stage 2 left off, and tries hard to return | |
827 *SOME* device type in all possible situations, modulo the DEVTYPE-SPEC | |
828 flag. \(DEVTYPE-SPEC and CURRENT-DEVICE are the same as in | |
829 `derive-domain-from-locale'.) | |
830 | |
831 Specifically: | |
832 | |
833 \(a) if no matching devices, return the selected device's type. | |
834 \(b) if more than device type and the selected device's type is | |
835 listed, use it. | |
836 \(c) else, pick one of the device types (currently the first). | |
837 | |
838 This will never return a device type that's incompatible with the | |
839 DEVTYPE-SPEC flag; thus, it may return nil." | |
840 (or try-stages (setq try-stages 1)) | |
841 (if (eq try-stages t) (setq try-stages 3)) | |
842 (check-argument-range try-stages 1 3) | |
843 (flet ((delete-wrong-type (x) | |
844 (delete-if-not | |
845 #'(lambda (y) | |
846 (device-type-matches-spec y devtype-spec)) | |
847 x))) | |
848 (let ((both (intersection (device-type-list) | |
849 (canonicalize-tag-set tag-set)))) | |
850 ;; shouldn't be more than one (will fail), but whatever | |
851 (if both (first (delete-wrong-type both)) | |
852 (and (>= try-stages 2) | |
853 ;; no device types mentioned. try the hard way, | |
854 ;; i.e. check each existing device to see if it will | |
855 ;; pass muster. | |
856 (let ((okdevs | |
857 (delete-wrong-type | |
858 (delete-duplicates | |
859 (mapcan | |
860 #'(lambda (dev) | |
861 (and (device-matches-specifier-tag-set-p | |
862 dev tag-set) | |
863 (list (device-type dev)))) | |
864 (device-list))))) | |
865 (devtype (cond ((or (null devtype-spec) | |
866 (eq devtype-spec 'window-system)) | |
867 (let ((dev (derive-domain-from-locale | |
868 'global devtype-spec | |
869 current-device))) | |
870 (and dev (device-type dev)))) | |
871 (t devtype-spec)))) | |
872 (cond ((= 1 (length okdevs)) (car okdevs)) | |
873 ((< try-stages 3) nil) | |
874 ((null okdevs) devtype) | |
875 ((memq devtype okdevs) devtype) | |
876 (t (car okdevs))))))))) | |
877 | |
878 ;; Sheesh, the things you do to get "intuitive" behavior. | |
879 (defun derive-device-type-from-locale-and-tag-set (locale tag-set | |
880 &optional devtype-spec | |
881 current-device) | |
882 "Try to derive a device type from a locale and tag set. | |
883 | |
884 If the locale is a domain, use the domain's device type. Else, if the tag | |
885 set uniquely specifies a device type, use it. Else, if a buffer is given, | |
886 find a window visiting the buffer, and if any, use its device type. | |
887 Finally, go back to the tag set and \"try harder\" -- if the selected | |
888 device matches the tag set, use its device type, else use some valid device | |
889 type from the tag set. | |
890 | |
891 DEVTYPE-SPEC and CURRENT-DEVICE as in `derive-domain-from-locale'." | |
892 | |
893 (cond ((valid-specifier-domain-p locale) | |
894 ;; if locale is a domain, then it must match DEVTYPE-SPEC, | |
895 ;; or we exit immediately with nil. | |
896 (device-type-matches-spec (device-type (dfw-device locale)) | |
897 devtype-spec)) | |
898 ((derive-device-type-from-tag-set tag-set 2 devtype-spec | |
899 current-device)) | |
900 ((and (bufferp locale) | |
901 (let ((win (get-buffer-window locale t devtype-spec))) | |
902 (and win (device-type (dfw-device win)))))) | |
903 ((derive-device-type-from-tag-set tag-set t devtype-spec | |
904 current-device)))) | |
905 | |
906 (defun derive-specifier-specs-from-locale (specifier locale | |
907 &optional devtype-spec | |
908 current-device | |
909 global-use-fallback) | |
910 "Heuristically find the specs of a specifier in a locale. | |
911 | |
912 This tries to find some reasonable instantiators that are most likely to | |
913 correspond to the specifier's \"value\" (i.e. instance) in a particular | |
914 locale, even when the user has not specifically set any such instantiators. | |
915 This is useful for functions that want to modify the instance of a | |
916 specifier in a particular locale, and only in that locale. | |
917 | |
918 Keep in mind that this is a heuristic (i.e. kludge) function, and that it | |
919 may not always give the right results, since the operation is not | |
920 technically well-defined in many cases! (See `derive-domain-from-locale'.) | |
921 | |
922 DEVTYPE-SPEC and CURRENT-DEVICE are as in `derive-domain-from-locale'. | |
923 | |
924 The return value is an inst-list, i.e. | |
925 | |
926 ((TAG-SET . INSTANTIATOR) ...) | |
927 | |
928 More specifically, if there is already a spec in the locale, it's just | |
929 returned. Otherwise, if LOCALE is `global', `all', or nil: If | |
930 GLOBAL-USE-FALLBACK is non-nil, the fallback is fetched, and returned, with | |
931 `default' added to the tag set; else, we use CURRENT-DEVICE (defaulting to | |
932 the selected device) as a domain and proceed as in the following. If | |
933 LOCALE is a domain (window, frame, device), the specifier's instance in | |
934 that domain is computed, and converted back to an instantiator | |
935 \(`instance-to-instantiator'). Else, if LOCALE is a buffer, we use | |
936 `derive-domain-from-locale' to heuristically get a likely domain, and | |
937 proceed as if LOCALE were a domain." | |
938 (if (memq locale '(all nil)) (setq locale 'global)) | |
939 (let ((current (specifier-spec-list specifier locale))) | |
940 (if current (cdar current) | |
941 ;; case 1: a global locale, fallbacks | |
942 (cond ((and (eq locale 'global) global-use-fallback) | |
943 ;; if nothing there globally, retrieve the fallback. | |
944 ;; this is either an inst-list or a specifier. in the | |
945 ;; latter case, we need to recursively retrieve its | |
946 ;; fallback. | |
947 (let (sofar | |
948 (fallback (specifier-fallback specifier))) | |
949 (while (specifierp fallback) | |
950 (setq sofar (nconc sofar | |
951 (cdar (specifier-spec-list fallback | |
952 'global)))) | |
953 (setq fallback (specifier-fallback fallback))) | |
954 (add-tag-to-inst-list (nconc sofar fallback) 'default))) | |
955 (t | |
956 (let (domain) | |
957 ;; case 2: window, frame, device locale | |
958 (cond ((eq locale 'global) | |
959 (setq domain (or current-device (selected-device)))) | |
960 ((valid-specifier-domain-p locale) | |
961 (setq domain locale)) | |
962 ;; case 3: buffer locale | |
963 ((bufferp locale) | |
964 (setq domain (derive-domain-from-locale | |
965 locale devtype-spec current-device))) | |
966 (t nil)) | |
967 ;; retrieve an instance, convert back to instantiator | |
968 (when domain | |
969 (let ((inst | |
970 (instance-to-instantiator | |
971 (specifier-instance specifier domain)))) | |
972 (list (cons nil inst)))))))))) | |
973 | |
616 ;;; specifier.el ends here | 974 ;;; specifier.el ends here |