Date: Wed, 29 Oct 1997 04:26:02 EST From: Maciej Stachowiak I apologize in advance for the length of this message (looking over it after having written it I realize it is pretty damn long, but there was a lot to say). I will probably also check it in to CVS so we can communicate through patches to it for easier annotation. I am partially done with an implementation of Button (and thus Title and Border since they are internally the same) styles, but I haven't been checking in my work. Do you think it is better to work on semi-long-term things like this solely in a working directory, or to check things in periodically as long as the code comppiles ar runs? I guess the best thing to do would be to fork off a separate CVS branch and merge it in later, but I haven't read up enough on CVS enough to know how to do that. Anyway, my rough plan is this: 1) Finish {button,title,border}-styles and then make a release; I think between us we have added enough features and fixed enough bugs that people will want access to the code, and I will also feel OK about not making any features releases for a while after, since the wm will reasonably be able to claim to mostly be a superset of fvwm. Oh yeah, I would also like to fix the problem you were seeing before with styles, assuming you are still seeing it, before doing the release. 2) After making this release, I would like to hold off for a while, wait to see some bugs reported, and possibly make a bugfix release if it is warranted. 3) After that, cleanup becomes priority number one. I want to delete all of the code that is #ifdef-ed out, and a lot more that will become unused then. I'd also like to see some things that were poorly implemented, either by fvwm originally, or by me in my rush to get at least all fvwm features working get reimplemented the right way. I think the most important part of this will be a fairly massive change of internal data structures, which I will outline below in a moment. 3a) Since massive internal organization changes will happen in the process, I'd like to look at the other fvwm-derived window managers (fvwm95 and AfterStep, I don't know of others offhand that are still being maintained) and see if they have any useful features that would be relatively easy to integrate and look useful, since that would probably be easier before the data structure migration rather than after. My quick look has not revealed anything too useful in either of the fvwm-descendants I know of yet. Now, here are my plans for the massive data structure migration, although I would like to block them out in more detail with you before going ahead with this, so we should continue communicating on this issue. Fvwm keeps things in a lot of twisty interlinked C structs, and my approach so far has been to wrap them in Scheme objects in a very simple-minded way. Although that approach was reasonable for proof-of-concept purposes, I think there are several drawbacks that should be fixed in the new internal data-structure system. * Right now, many C structures are wrapped in a two-level way; the Scheme object contains its type tag and a pointer to a C structure that is scwm-specific, and in turn that first-level C structure often cotains a pointer to the original C data structure that fvwm uses. Although this was easier to do first off than directly modifying the C data structures this concept should go away; C structures should be wrappend directly, and where possible and reasonable performance-wise, C structures shouldn't be involved at all. Guile's struct support should be looked at to see if it might be useful here. * There are in some cases back-references between the C and Scheme objects to make things work correctly with garbage-collection. That can almost certainly go away with the change. * Fvwm keeps a lot of its structures in linked lists and has a lot of code to traverse these lists. We should use Scheme lists and use the list operations available as C procedures in Guile. This may be a bit less efficient as far as heap space goes, but should be a big win on eliminating redundant code. Fvwm's concept of separate namespaces for each type of data structure is also anti-useful and should go away. * The interface to each data structure is very ad-hoc. Many have fields that are mutable but not readable or vice versa when there is often no reason for this except that at the time I thought only one or the other was really useful and was too lazy/rushed to implement the other. There is also no uniformity in how fields of even the same object are accessed. All of this should be looked over and laid out cleanly from both the Scheme and C ends. * Very frequently when structures get changed, various processing needs to happen, such as redraws of decorations, recaptures and other such stuff. Not all of it is getting done in all cases, and in some cases it is getting done in a way that is not adequate for the level of dynamism we want. This has to be examined carefully. So that is the current set of problems. Here are my thoughts on how to start solving them: * The first thing to do is to remove as much dead fvwm code as possible without large changes to the data structures, as described above. The ifdef'ed things can go. There is probably a lot of other stuff that can go, and this should be looked at very carefully. Stuff I think can probably go away soon includes: ** Any code that relates to the concept of fvwm functions. Most of this is at least commented, but some currently used vestiges remain in the menu code, and there are probably unused or unuseful vestiges as well, like stuff that handles the fvwm list of user-defined functions. ** Code that traverses the fvwm lists of styles and decors. This will definitely require changes to places in the code, but relatively few, I think. ** Code that deals with the fvwm list of menus and the namespace implemented by it. There are probably a fair number of places in the code that make use of this (menu stuff is used for some really odd things), but this too can almost certainly be dealt with without hacking data structures. ** The stuff in the libs directory should all be either moved to the main scwm directory or killed as appropriate; having it be a library isn't really useful any more, and is kind of a miantenance hassle. The reason I have not done this yet ** A lot of other stuff I didn't think of. * After that preliminary cleanup, the window structure should be dealt with. This is going to be a biggie, but I belive it must be done early on to lay a solid foundation for other things. The change will involve several things. ** Window properties should be accessible in a consistent way. I've worked out a somewhat detailed design for this. *** The secheme interface should consist of the following procedures: (set-window-property! WINDOW PROPERTY VALUE) Set the specified property of the window to the given value. (window-property WINDOW PROPERTY) Return the value of the specified property. (window-properties WINDOW) Returns an association list of window properties to values. There may also be a window-property-remove!; my thoughts on this aren't totally clear. *** window properties will include both style options and things currently done as triples. There will be standard properties that have specific efficient implementations in the window structure. Other properties will be implemented through an additional property list in the window structure that has the form of an association list; that should be fast enough for scheme code. *** Property names can be any Scheme object but are conventionally symbols; all built-in properties names should be symbols. However, using non-symbols along with lexical scope or the module system can be used to implement opaque properties. *** Note that the window parameter is not optional in the above procedures. I think the defaulting to a current context window should be done at the Scheme level. For instance, there will be Scheme procedures iconify, deiconify, toggle-iconify, and maybe even iconified which will correspond roughly to (set-window-property! window 'iconified #t) and such, but will default to the current context window. *** Many properties are boolean in nature. These should appear externally (i.e. via window-property and set-window-property!) to be Scheme boooleans. However, those that are frequently accessed by C code should have a faster internal implementation. The current practice of OR-ing and AND-ing ints by hand is goofy and quite possibly non-portable. Two reasonable candidates would be C bitfields or the Scheme-level bit-vectors provided by Guile. *** coordiante-like entities (I include x-y locations and width-height pairs in this) pose an interesting dilemma - you should be able to get the x and y of such a pair separately, since they are separatee internally and you want to deconstruct the structure they come in most of the time. However, it should be possible to set them together because you often want to, and because seeing the window redraw twice on a move or resize would be bad. *** The concept of the current context window may be a bad idea and should be re-examined. Personally, I think it is useful; it means that when making key or mouse bindings, you don't have to worry about wether they are for the root window or a window decoration (presumably the former would get no arguments and the latter a window argument in another universe), and operations that don't really care about being attached to a window aren't forced to take a useless window argument. Plus thunks are easier to deal with for a number of reasons. *** C code can attach callbacks to be done when certain built-in properties are set. Thus, setting the iconified property will iconify or deiconify the window as appropriate. ** Some window operations are not best represented as getting or setting properties. These include interactive-move, interactive-resize, delete-window, destroy-window, and refresh-window. I don't think there are any others in this category currently. These will obviously need to stay separate procedures. I don't include warp-to-window because I think it can easily be reimplemented in Scheme. ** Widows should be kept in a Scheme list, not in the funky doubly-linked list that exists now. ** The way window structures are created should change, Hopefully eliminating the separation between the 'new-window and 'new-window-hint events. * Decors should gradually disappear; the values set in decors should be settable per-window instead of using the weird decor hack. I don't think this will waste too much memory if we do it wisely. Button faces should still be separate structures for instance, and windows will simply end up holding a couple of pointers to these. The same face can be shared between multiple (or all) windows, so memory shouldn't get too massively wasted. * images - there should be a scheme type (or types) for images. By default, it should be possible to load X bitmaps and X pixmaps into an image. Other types of image loaders should be dynamically loadable (eventually). * I can think of two ways to deal with the paging stuff. ** Continue roughly as now, but account for the window structure changes. ** Or - rewrite it all in Scheme. I'm not sure if smooth performance can be achieved this way, but I suspect it can, so it is something to experiment with. * Various global settings - the global settings fall in three general categories, those that are truly global, those that are really per-decor, and those that should be settable individually for various interface elements. ** The truly global settings should become Scheme variables (or at least look like them from the Scheme level, although the internal implemenation may vary). ** Settings that look global but really go into the current decor should become per-window settings. ** Some settings should be per-decor, per-window, or in some cases per-menu but currently aren't; they should become so as appropriate. * event bindings should be dealt with after the other stuff. It may be worth it to make a release between handing the other data structure changes before dealing with bindings. ** I think a lot of new features will appear here, as event bindings get generalized in many ways. We'll probably want enter and leave hooks for app windows and the root window, general callbacks for window property changes, hooks for moving to the edge of the screen (or a general "invisible active window" concept), timers (to do auto-raise and other neat delayed stuff) and so on. ** Our support for synthetic events should also be examined along with this stuff. ** I'd like to take a close look at gwm, nawm and other window managers in general before coming up with a design. nawm is a local MIT hack, I can furnish you a copy whenever you want, but the general point of it is a window-manager-like entity with no decorations or menus, but very strong support for synthetic events and assorted bindings so that you can operate it entirely with the keyboard. ** This is where a lot of the fun behavior generalization will take place. I think we'll have a good time with these changes. * Menus also obviously need work. I put them last because I don't know where they should go in the order of changes; several places seem good, and they can also probably be worked on in parallell with other things. I am not too sure what to do about menus. It seems that when we have a widget set we should be able to use that as the way to render menus. But I also believe that we should not force people to load a lot of code when they only want a little, so I think there should still be a menu-only implementation. Eventually it could be a separate module so that it doesn't annoy people who load a real widget set into Scheme, but that can wait for Guile's module system to stabilize. I think you probably have a better grasp of the menu stuff in general than I do, so I'd like to hear your thoughts. Now, there are three really important features not covered in this plan that I think are very important from a user-interface perspective and are on the queue for handling soon. These are: * Interfacing to one or more scheme-level widget sets, * Providing an external program interface mechanism of some sort. * Providing a way to get a pager window, as it's annoying to try to manage virtual desktops without it. I think the first two should be done _after_ the data structure cleanup, or at least some aspects of the cleanup should be done. That will make it much easier to do them cleanly. I also think that the right way to implement a pager is on top of on or maybe both of these mechanisms. However, people seem to really miss having a pager, so maybe it would be worth it to come up with a hack temporary pager of some kind, because the code will probably not be ready for the real one for some time. If we decide to do that, we should try to do it before the data structure migration, or perhaps in parallel but in a separate CVS branch, because I don't think we will want to be making releases in the middle of the migration. We should also label it as a kludge that is slated to go away (what a novelty - a feature that is already deprecated when it's introduced :-). Doing a quickie pager would surely make users happy, but may be a fair bit of work for us. I will cover my thoughts on the external interface and the and the widget-set issue, as well as other things I have glossed over, in more detail in a later message. - Maciej Stachowiak