Path: utzoo!utgpu!jarvis.csri.toronto.edu!cs.utexas.edu!tut.cis.ohio-state.edu!ucbvax!hoptoad!tim From: tim@hoptoad.uucp (Tim Maroney) Newsgroups: comp.sys.mac.programmer Subject: Simulating a Menu Bar with Pop-Up Menus Message-ID: <9095@hoptoad.uucp> Date: 28 Nov 89 00:16:58 GMT Organization: Eclectic Software, San Francisco Lines: 77 Some applications, like FullWrite, give windows their own menu bars. That is, beneath the drag rectangle, there is a horizontal bar roughly twenty pixels high, followed by a line or double-line separator, followed by the effective window content region. In this window menu bar, the names of the various menus available for that window appear in 12-point system font, and clicking in this bar works much the same as clicking in the screen's main menu bar -- the menu title clicked in pops up and can be selected from, and going to another title pops up another menu. All well and good. But there is one problem with this -- the raw OS doesn't give you what you need to implement this behavior. It seems as if it would be easy to implement with PopUpMenuSelect, and it is, but I have not been able to do it without a trap patch. It's within the guidelines as much as any trap patch can be, but it still worries me and I'd like to do without it if possible. I wrote all the code to do this in the last 24 hours, so I may be overlooking something that will hit me tomorrow, but I'd appreciate advice from the net. Here's the problem. PopUpMenuSelect keeps the menu in place until the button comes up. This is not how menu bar tracking works. Instead, when the mouse moves up into the menu bar over a different title, a new menu is supposed to pop up (and when the mouse moves off the top edge, right edge or left edge of the menu bar area, the menus are supposed to go away). But there's no way to abort PopUpMenuSelect when this condition is sensed. It's easy enough to sense -- you just use the low-memory MenuHook routine which gets called periodically while MenuSelect or PopUpMenuSelect is active. But MenuHook takes no parameters and returns no arguments; it does not have any built-in way to abort the PopUpMenuSelect. (MBarHook does, but it only gets called once -- in fact, I'm not sure PopUpMenuSelect even calls it once, though MenuSelect does.) So, what I do now is patch Button. I save the address of the real Button before I do menu tracking. I store a routine called MyMenuHook in MenuHook; this is responsible for determining whether the current mouse position would require PopUpMenuSelect to be killed. When MyMenuHook determines that this has happened, it sets a Boolean flag for my tracking loop to pick up when PopUpMenuSelect returns, then puts the address of a routine called FakeButton into the trap table in place of the real Button (using NSetTrapAddress) and posts a fake mouse-up event. PopUpMenuSelect goes to call WaitMouseUp to see if the user has released the button. It calls Button, which is now my fake button routine. FakeButton first restores the trap address of the real Button (again using NSetTrapAddress), then returns false. So it isn't a tail patch; it never calls the original Button. Since Button returned false, WaitMouseUp pulls off the mouse-up event and returns false. This return value signals PopUpMenuSelect to quit. The application checks the "aborted" Boolean flag set by MyMenuHook, and if it is true, gets the new mouse position and restarts the tracking loop on a different menu or no menu. Otherwise, PopUpMenuSelect returned normally, and the application interprets its return value as a menu command. This all works great, and it's not as hard as it sounds. But it really irks me that I have to patch Button this way. I've never had to use that particular devious strategy, an application-specific trap patch, before. It's better than calling the menu definition procedures myself, and it works, but that's about the most I can say for it. Does anyone have a cleaner idea for how to implement a document window menu bar? Also, does anyone see a way that this could fail, as long as PopUpMenuSelect continues to call WaitMouseUp, and WaitMouseUp continues to call Button before checking for a mouse-up event? (I know about the possible vanishing of low-memory globals already, thanks.) (Also, I don't think it's safe to do a longjmp out of a trap into an application, though if you have a different opinion, feel free to defend it.) -- Tim Maroney, Mac Software Consultant, sun!hoptoad!tim, tim@toad.com FROM THE FOOL FILE: "Women's wages are 56% of men's -- but that's not necessarily evidence of discrimination in employment." -- Clayton Cramer in news.groups and soc.women