[haiku] Behavior of popup menus

  • From: "Travis D. Reed" <tdreed@xxxxxxxxx>
  • To: haiku@xxxxxxxxxxxxx
  • Date: Sun, 19 Dec 2010 18:31:36 -0600

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 
keepOpen, BRect openRect,
async = false);

Other related posts: