The week began by implementing the functionality needed to handle clicking on menu items. This involved sending a callback notification for the currently selected item, asking the callback to execute the appropriate action of the item.
Some of the items are not meant to be clicked on and are supposed to show a submenu instead. For these items I had to subclass the toolbar windows so that I could add a timer on hover and handle the opening of the submenu in the resulting WM_TIMER event, which would be received by the toolbar, but needed to be handled by my code.
I found a sizing issue where items with a dropdown arrow would be wider than expected and get cut. I disabled the dropdown flags as a workaround, so there are no submenu arrows at the moment.
I added the necessary functionality so that the submenu windows would be shown when hovering an item with submenu. The windows would show, but they seemed to be unresponsive. I managed to trace the issue to the OnPaint method, which wasn’t assigning a return value properly.
I took a break from adding new things, so that I could go back and compare the new features with how Windows does things. The goal was to figure out the system used by Windows to handle interactions between menus and submenus, and how Windows handles the closing of the menu when another window gets activated.
After some fixes and improvements the logged behaviours are closer and the classes are more cross-compatible, but the behaviour of the IMenuPopup interface including the OnSelect and SetSubMenu methods was a mystery.
I took the chance to do some refactoring work, fixing coding styles, method names, and such.
After many long hours over multiple days, I figured the behaviour to be something close to this:
- The DeskBar’s SubMenu parent is the IMenuPopup interface of the DeskBar’s “owner” Site, except for the top-level start menu, which does not have a submenu parent.
- The DeskBar’s SubMenu child is the contained Band obtained through the contained MenuSite by using the SID_SMenuPopup service.
- The Band’s SubMenu parent is the DeskBar obtained through the parent MenuSite which is itself obtained through the SID_SMenuBandChild.
- When a user clicks a toolbar item and the item executes an action, the Band sends an OnSelect(Execute) notification to its SubMenu parent.
- When a user presses the alt key, the Band sends an OnSelect(FullCancel) notification to its parent.
- When a different window activates, the DeskBar sends an OnSelect(FullCancel) to itself.
- When the DeskBar receives an OnSelect notification that results in closing of a submenu, it notifies the child using OnSelect(CancelLevel).
- When the DeskBar receives a notification other than CancelLevel, it notifies its parent menu. This is not mutually exclusive with the previous “rule”: Some notifications are forwarded to the child and parent.
- When the Band receives a cancellation event it cancels its current child, if any.
- When the Band receives a keyboard navigation event it either notifies the parent or, in the case of SelectRight, it opens the submenu of the currently selected item.
- SelectLeft is equivalent to CancelLevel except that it is notified to the parent also so it can select the appropriate item.
The information is incomplete, and I may have got something wrong, but based on these rules, I implemented a working flow of OnSelect events.
This implementation required a focus manager class, which would take care of hooking the application’s message flow to intercept keyboard and mouse events and do the appropriate actions in each case.
Since the focus manager is unable to process the WM_ACTIVATION messages I added a handler to the DeskBar class, which will send OnSelect notifications when a window gets deactivated in favour of a foreign one. To be able to prevent the menu from closing if the window being shown is a submenu, I repurposed the GetSite method (which was not used) of the contained Band to query the SubMenu child of the band. This is probably not the way Windows does it, but it serves its purpose until a better method is found.
There are many missing features yet, and lots of things to polish. But I believe it is now time to start looking again at the look&feel of the menu, to make it look even closer to how the Windows Server 2003 start menu looks like.
I would post a screenshot, but it would not show anything you haven't already seen. Except...
Now you can see how they compare.