tim@hoptoad.uucp (Tim Maroney) (08/18/89)
I'd like to have some discussion on the proper maintenance of a Windows menu. Like many other programs, mine do a complete menu item enable/disable pass whenever the application detects a menu bar click. Theoretically, it could be done at some other time more efficiently, but the code would be harder to maintain. It's better to have all the related code grouped together in time and space. So anyway. Another thing I do at the same time is rebuild my Windows menu. This is a pretty simple piece of code which first truncates the Windows menu down to a fixed header of generic window operations ("Stack", "Tile", "Next", "Previous"), then appends all the window titles, iterating down the window list starting at FrontWindow(). The problem is that under System 6.0, it is neccessary to call DrawMenuBar after adding any items to a menu. If you don't, they will not be visible to the user during MenuSelect. DrawMenuBar causes the menu bar to flicker, so now, every time the mouse is clicked in the menu bar, there's a flicker before tracking starts. I don't like this, but updating the Windows menu this way is so easy I'm loathe to change it. Any suggestions? Unless I get a better idea, I am going to try doing the update of the windows menu when any activate event comes in (including deactivate); if that fails, then I'm going to have to put in a call to the update windows menu routine whenever a window is created or destroyed, and I really do not want to do that. -- Tim Maroney, Mac Software Consultant, sun!hoptoad!tim, tim@toad.com "I am convinced that cross-posting is an evil Satanic plot." -- Eugene Miya on soc.net-people, misc.headlines, misc.kids, misc.misc, news.misc, and soc.misc
earleh@eleazar.dartmouth.edu (Earle R. Horton) (08/18/89)
In article <8320@hoptoad.uucp> tim@hoptoad.uucp (Tim Maroney) writes: >I'd like to have some discussion on the proper maintenance of a Windows >menu. Like many other programs, mine do a complete menu item >enable/disable pass whenever the application detects a menu bar click. >Theoretically, it could be done at some other time more efficiently, >but the code would be harder to maintain. It's better to have all the >related code grouped together in time and space. The problem with doing this at menu bar click time is that if you have a large amount of menu housekeeping to do then you might slow down your reponse time to the menu bar click. If there is too much of a delay before your menus drop down then your program will be perceived as having performance problems. And the worst offender is probably the next subject you mention... >So anyway. Another thing I do at the same time is rebuild my Windows >menu. This is a pretty simple piece of code which first truncates the >Windows menu down to a fixed header of generic window operations >("Stack", "Tile", "Next", "Previous"), then appends all the window >titles, iterating down the window list starting at FrontWindow(). > >The problem is that under System 6.0, it is neccessary to call >DrawMenuBar after adding any items to a menu. If you don't, they will >not be visible to the user during MenuSelect. I have not observed this behavior. I am running 6.0.3 on a Mac II and on a Plus, and find that I can add or delete menu items with impunity without calling DrawMenuBar. I do not get menu items which are not visible. I wish you would give more information about this problem, since what you have written above makes me worry that I am missing something. I also dug out a 6.0 disk and tried it with the same result: No need to call DrawMenuBar. What I have observed, in my programs and apparently in other people's programs, is that when you have one of these window menus you can visibly slow down response time by having a large number of windows open. Rebuild that window menu every time, and you get a perceptable wait between the time you click and the time you first see a menu. I saw one solution to this problem at MacWorld Expo, at the DayStar Digital* booth. For those of us who cannot afford this solution, one has to resort to optimizing the software. Rebuilding menus any time a change occurs which can affect their appearance might be one way to improve response to mouse clicks in the menu bar, but it has one serious disadvantage that I can think of. Many of the changes you make will never be seen, since these will be overridden by later changes. It is also a bear to code this way if there are many things in the menus which need changes, and many events which require them. Another solution is to maintain some kind of data structure which reflects the validity of menus in your program that you determine by testing to be performance offenders. Reset all your validity flags when you rebuild the menus, set them when events occur which call for a change in menu appearance. Some percentage of the time, you will get lucky. For instance, it is certainly possible to have the user do things which will not change the window ordering, and therefore will not invalidate your window menu. If you have a flag that you set every time something happens to change the window list, then you will know whether to rebuild the window menu before calling MenuSelect or not. Earle R. Horton *DayStar Digital makes a 50 MHz accelerator containing a 68030. Eat your heart out if you cannot afford one. Chuckle at the rest of us if you can.
nick@lfcs.ed.ac.uk (Nick Rothwell) (08/21/89)
In article <8320@hoptoad.uucp>, tim@hoptoad (Tim Maroney) writes: >I'd like to have some discussion on the proper maintenance of a Windows >menu. >The problem is that under System 6.0, it is neccessary to call >DrawMenuBar after adding any items to a menu. If you don't, they will >not be visible to the user during MenuSelect. I think this comes from the beginning of time (viz. Inside Mac I), rather than being anything new and System-6.0-ish...? I use Paul duBois' TransSkel, and attach actions to ACTIVATE and DEACTIVATE and so on. When a window activates or deactivates, it alters its own menu item in the window menu, adding a tick or whatever. A similar thing happens for creating and disposing of windows. I essentially implement a lazy update. I have routines for (i) putting in a windows menu, (ii) taking out a windows menu, and (iii) updating the menu bar. There's a cache saying whether there's a window menu or not (in fact, there's a menu ID here, because I have a number of windows menus with different titles, depending on "mode", whoops, pardon me, dirty word...). When a window deactivates, it removes the menu but doesn't do an update. When a window appears, it adds a windows menu, and re-draws the menu bar if the menu title is different to the old one. It looks pretty smooth. >(including deactivate); if that fails, then I'm going to have to put in >a call to the update windows menu routine whenever a window is created >or destroyed, and I really do not want to do that. Any reason why not? I have everything driven from the create/destroy/activate event handlers, and the structure doesn't seem too bad. >Tim Maroney, Mac Software Consultant, sun!hoptoad!tim, tim@toad.com Nick. -- Nick Rothwell, Laboratory for Foundations of Computer Science, Edinburgh. nick@lfcs.ed.ac.uk <Atlantic Ocean>!mcvax!ukc!lfcs!nick ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ Fais que ton reve soit plus long que la nuit.
nick@lfcs.ed.ac.uk (Nick Rothwell) (08/21/89)
In article <193@castle.ed.ac.uk>, I write: >In article <8320@hoptoad.uucp>, tim@hoptoad (Tim Maroney) writes: >>The problem is that under System 6.0, it is neccessary to call >>DrawMenuBar after adding any items to a menu. If you don't, they will >>not be visible to the user during MenuSelect. > >I think this comes from the beginning of time (viz. Inside Mac I), >rather than being anything new and System-6.0-ish...? Whoops, I misread Tim's original comment. You have to call DrawMenuBar after an insert/delete menu, but I've never needed to call it after inserting/deleting/changing a menu *item*. I think the problem must be elsewhere...? Nick. -- Nick Rothwell, Laboratory for Foundations of Computer Science, Edinburgh. nick@lfcs.ed.ac.uk <Atlantic Ocean>!mcvax!ukc!lfcs!nick ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ Fais que ton reve soit plus long que la nuit.
dorner@pequod.cso.uiuc.edu (Steve Dorner) (08/21/89)
In article <8320@hoptoad.uucp> tim@hoptoad.uucp (Tim Maroney) writes: > ... Like many other programs, mine do a complete menu item >enable/disable pass whenever the application detects a menu bar click. >Theoretically, it could be done at some other time more efficiently, >but the code would be harder to maintain. It's better to have all the >related code grouped together in time and space. I keep the related code together by having a routine called EnableMenus, that I call whenever I need to, or every time the event loop runs. It enables/disables menu items based on the program's current state, which is mostly the kind and state of the topmost window (e.g., if the topmost window is dirty, enable File:Save, etc.). Also, the amount of state information is small enough that I can save it each time through; if the state hasn't changed since last time, I can skip the updating process. Finally, there exists a flag in EnableMenus that can be set when I determine that the menu bar needs to be redrawn. The last thing EnableMenus does is call DrawMenuBar if the flag is set. This seemed to me to be a good compromise between efficiency and ease of programming. It's sort of ugly and inelegant, but that's just another way of saying it was done on a Macintosh, isn't it? :-) -- Steve Dorner, U of Illinois Computing Services Office Internet: s-dorner@uiuc.edu UUCP: {convex,uunet}!uiucuxc!dorner IfUMust: (217) 244-1765
tim@hoptoad.uucp (Tim Maroney) (08/24/89)
Thanks to those who've commented by mail and on the network on this issue. Most of the responses boiled down to a few points, so I will try to address those points rather than respond to particular messages in public. (1) The speed of menu updating. Apparently there are a few programs which take forever and a day to show their menus after you click in the menu bar. I have no idea what they are doing with all that time, but it seems unlikely they're just consulting RAM data structures and enabling/disabling menu items. Even when I do build my Windows menu as a response to the mouse click, there is no perceptible delay between the click and the appearance of menus even on a 68000 machine. Perhaps the offending applications' data structures are built in such a way that it takes a long time to access the information of the frontmost window, but even then, I can't imagine it taking as long as a second. My best guess is that they are alphabetizing something or touching the disk. EnableMenu and DisableMenu merely set a single bit at a fixed offset in a menu data structure. I really can't imagine that even a hundred of them would take a humanly perceptible time. (2) Problems with when to fix the menu. Again, I doubt that even with ten windows open, there would be a perceptible delay building at the click. Unless, that is, you do something stupid like bubble sorting the menu items in place. However, just to be sure, I've moved to a different approach. There are only two places where I dispose of a window or dialog, so I rebuild there; and since it is impossible to create a window in front without generating an activate event, and it is undesirable to create a window anywhere but in front, I rebuild when I get an activate event (or a deactivate event) as well. This seems to go more than fast enough, particularly since I prefer to present windows in window list order rather than alphabetically. Why not do it everywhere I create a window or dialog? I always create them invisibly, then have the window-specific module show them when they've been properly initialized. There is no single place where windows enter the list for that reason, though there is a single place where they're created and have information bound to them. Therefore, this is just begging for me (or a developer using my code) to forget the call to fix the windows menu and introduce a bug -- not a very serious bug, but one that is not obvious and could easily find its way into production code. (3) The need to call DrawMenuBar. Those who have pointed out that this is not necessary are correct. I was misremembering a bug that appeared last year when System 6.0 came out, bearing on long menus. Suppose you delete a short menu and add a longer version of the same menu. The appearance of the menu bar doesn't change, so you'd think the call to DrawMenuBar could be omitted (and so the flicker would be avoided). However, apparently System 6.0 caches the menu sizes or something so that the long menu will be visible only up to the point where the short menu ended. I don't know why it didn't happen under earlier systems. So -- It is NOT necessary to call DrawMenuBar after adding to or deleting from a menu. (4) Putting symbols into the windows menu. I don't advise it. One of the things I like least about the Mac interface as practiced is the reliance on cryptic symbols which actually convey far less than text. FullWrite is a good example; the MPW Shell's use of checks and bullets and so forth in its Windows menu is another. Information which is not asked for by the user should only be ionformation which is readily comprehensible to the user. If you must indicate things like who's in front, which windows have changes, what was the last window you worked on, and so forth, don't stick confusing symbols (or even worse, style changes) into the Windows menu. Instead, come up with a genuinely clear icon or small icon and put that where it's needed. Note: a triangle with a dot inside or some such nonsense is not a clear icon. Draw something real or don't draw anything at all -- including a check mark or bullet! -- Tim Maroney, Mac Software Consultant, sun!hoptoad!tim, tim@toad.com "Its failings notwithstanding, there is much to be said in favor of journalism in that by giving us the opinion of the uneducated, it keeps us in touch with the ignorance of the community." -- Oscar Wilde