I'm told this is an old problem inherited from BeOS (and, indeed, from MacOS), and I'm sure it's been thought about before. However, recently, in my making of a context menu for text boxes, I became very acutely aware of the way Haiku handles popup menus. I realized that it's been secretly nagging me for a long time, and I wonder if other people feel the same. I also wonder what's keeping us from doing something about it. Here's the problem. Without tweaking code, a popup menu will disappear when the user releases the mouse button that activated it, selecting whatever menu item the pointer happened to be on at the moment. Try pulling down the NetworkMonitor in the Deskbar and see what happens. If you check out the ProcessController right next to it, or the volume tool, or Tracker, you see that these menus stay up the way you would expect them to. That's because they have been explicitly (and diversely) tweaked. Many other programs do not handle this. In addition to the NetworkMonitor, try pulling up the context menus in Magnify and the WebPositive address bar. If you use behavior that comes very naturally to anyone who's used an OS in the past decade, you end up selecting menu items by mistake. There are various ways around this behavior. Tracker nudges the menu over by a few pixels, thus preventing the cursor from being over any item when the mouse button comes up. This behavior seems to fail, though, when the menu has to be nudged over because it's on the edge of the screen. (This isn't apparent because the last menu items are submenus that just expand automatically and innocuously.) ProcessController does it by using the openAnyway and clickToOpen options in the BPopUpMenu's Go() method (as suggested in the BeBook). The disadvantage here is that it adds to the complexity of the program. I have tampered a teensy bit with the interface kit to make this last solution default behavior. However, it occurs to me that some people might actually like this behavior. What do people think? Who's worked on this before? What issues have been encountered thus far? What are we likely to encounter as we go forward? I'd be happy to know what you think of the attached patch. -- Travis D. Reed
Index: src/kits/interface/PopUpMenu.cpp =================================================================== --- src/kits/interface/PopUpMenu.cpp (revision 39894) +++ src/kits/interface/PopUpMenu.cpp (working copy) @@ -317,6 +317,11 @@ BPopUpMenu::_Go(BPoint where, bool autoInvoke, bool startOpened, BRect *_specialRect, bool async) { + if(startOpened && _specialRect == NULL) { + _specialRect = new BRect(where, where); + _specialRect->InsetBy(-2, -2); + } + if (fTrackThread >= B_OK) { // we already have an active menu, wait for it to go away before // spawning another Index: headers/os/interface/PopUpMenu.h =================================================================== --- headers/os/interface/PopUpMenu.h (revision 39894) +++ headers/os/interface/PopUpMenu.h (working copy) @@ -23,7 +23,7 @@ static BArchivable* Instantiate(BMessage* archive); BMenuItem* Go(BPoint where, bool autoInvoke = false, - bool keepOpen = false, bool async = false); + bool keepOpen = true, bool async = false); BMenuItem* Go(BPoint where, bool autoInvoke, bool keepOpen, BRect openRect, bool async = false);