Moved to -beta because this is general design discussion.
>>>> "Andy" == Andy Piper
<andy(a)xemacs.org> writes:
Andy> At 07:36 PM 8/23/00 +0900, Stephen J. Turnbull wrote:
> xemacs -vanilla followed by repeated `C-x 2's allows me
> to produce as many tab control widgets as I want, all
> instantiated for the *scratch* buffer. That can't be right.
> Nor do they go away when I start coalescing the windows.
Andy> No that *is* correct.
See [*] below.
Andy> You are creating lots of different domains (windows) and
Andy> there has to be a control for each. If you go back to one
Andy> window and garbage collect they should go away eventually.
This was not true under the pre-(sel.patch) setup, and I banged on
that for quite a while. The only thing that ever made them go away
was destroying the whole frame. They now go away immediately (with
http://www.xemacs.org/list-archives/xemacs-patches/ ... ach, not there
yet, look for Andy's patches dated 8/23 and subjects "Re: new dialogs:
bug" and "Re: Tab selection crash fix ... NOT!! \"Houston, we, uh,
crashed.\"")
*****
[*] You are defining "correct" as "works as designed." That is
important, of course, but I think that the design is making a lot of
assumptions that probably will turn out to be not true for some
applications. This will result in more bugs in the future.
Above you _equate_ domains to windows. But for the tab control,
that's wrong. The domain most relevant to a tab control is a set of
buffers. It is true that most of the time the buffer-set to window
correspondence is one-to-one and pretty stable. Furthermore, the most
likely application (and the one currently implemented) for the tab
control is to switch among buffers in a set in a given window. So for
the buffer tabs application, this assumption is plausible. But it's
wasteful; I don't see any reason at all why a frame should have more
than one buffer tabs widget when only one will ever be displayed at a
time.
It seems to me that from the point of view of Emacs a glyph is really
a three-level object. The top level is a specifier, ie, a mapping
from domains to instantiation methods. The middle level is the
instantiation method for a given domain. The bottom level is the
on-screen realization.
For a character glyph, the top layers are trivial (ignoring the
complexity of faces). For each domain, the instantiation method is to
pass the character on. So in the domain, you simply pass the
character to the display. The display looks up the bitmap in a font,
and blits it to the screen. No computation and no caches needed for
handling this kind of glyph. (The display is a black box, I am
deliberately abstracting from it here.)
For a pixmap glyph from a PNG file, things are somewhat more complex.
The top level basically has to decide whether the domain handles
pixmaps or not. If it does, it passes the file name to the
instantiation method. The method then does some expensive i/o,
decodes the pixmap in memory, and passes the pixmap to the display,
which then blits it to the screen. Here, the i/o and decoding are
expensive, as is passing the pixmap itself (in X11 anyway, as this may
involve a fairly large network transaction). So there are two
opportunities for caching here, one at the display level, and one of
the decoded pixmap. AFAIK we actually have the X server cache the
pixmap, and when this image is gc-ed, we call XFreePixmap on the
pixmap.
Now, we could do exactly the same thing with a widget glyph. No?
However, we do want to be more efficient than that. First, let's
define a `widget glyph' to be a glyph from the point of view of
XEmacs. It is a Lisp object. On the other hand, a `ws-widget' is a
toolkit object.
There are three differences between widget glyphs and image glyphs
that I can see.
(1) The entity that handles the ws-widget for us is the toolkit,
rather than the display server for the pixmap. Just a different
level of black box.
(2) ws-widgets are "alive". This means that, unlike pixmaps, we can't
just paint over their displayed image; we need to keep track of
whether a ws-widget is supposed to be displayed or not, and
deactivate is if not. (Of course, we should and do clean up
pixmaps too. Otherwise you get those obnoxious birdturds like
when font metrics are hosed. But pixmaps don't eat CPU and cause
flicker and all that ugliness.) As far as I can see this has no
direct implications for caching.
(3) A ws-widget is, from our point of view, its own screen image.
That means that a widget glyph that is displayed in multiple
places in the same domain needs to use multiple ws-widgets. By
contrast, we can XCopyArea (or its equivalent for other WSes) an X
Pixmap freely.
(4) ws-widgets are much heavier objects than even pixmaps. So we
would like to avoid creating and destroying them. The question is
"how many do we need?" The answer is, typically, "as many as are
being displayed at one time in the window system parent." (3)
means we need at least that many. But we usually don't need any
more, because widgets can be moved about and their features
changed as necessary.
(3) and (4) together imply that free'd ws-widgets ought to be cached.
But they should be cached by the object that determines the
restrictions on moving them. In general, this is the window system
parent, or, actually the Lisp object that manages that object. (I
guess they could even be reparented, but that's a can of worms I'd
rather not open. Although I guess if we want to embed an instance of
say xanim in an XEmacs buffer, we would need to do exactly that.)
In this case, the Emacs frame, not the Emacs window.
Of course, if there are other expensive operations to conduct on
ws-widgets that would be entailed by using the same ws-widget in
multiple domains, the caching strategy should take that into account.
But I can't see any that would be forced simply by having two
different Emacs windows in the same Emacs frame. In particular, for
both the progress gauge and the buffers tab control, they live in the
gutter, which is part of the frame, not any particular window.
It seems to me that what should happen is that you create a (Lisp)
buffers tab control, it instantiates a (ws-widget) tab control for the
frame in the gutter, with callbacks to change buffers when it is
activated. The same operation should install a Lisp function on some
`buffer-configuration-change-hook' which informs the ws-widget about
the new set of relevant buffers and the active one. The Lisp tab
control object maintains enough state to reinitialize the ws-widget
tab control when the Lisp object wants to display itself. I don't see
any reason for the tab widget, either the Lisp object or the
ws-widget, to know or care about the Emacs window configuration.
BTW, some things I find disconcerting about the current behavior:
(1) If two buffers in the same mode are displayed simultaneously in
the same frame, then using the tab to switch buffers switches windows,
not buffers in the current window. This behavior makes sense for the
keystroke equivalent, but if I'm moving the mouse anyway click-to-
focus makes more sense than using the tab control. If I use the tab
control I expect the buffer to end up in the top window.
(2) Splitting windows horizontally does _not_ increase the number of
tab controls (but seems to work fine). Coalesing horizontally split
windows doesn't decrease the number of tab controls, either.
--
University of Tsukuba Tennodai 1-1-1 Tsukuba 305-8573 JAPAN
Institute of Policy and Planning Sciences Tel/fax: +81 (298) 53-5091
_________________ _________________ _________________ _________________
What are those straight lines for? "XEmacs rules."