XPToolkit Menu Spec

Draft 1.6

Written by Chris Saari
Last Modified: 2/23/99

Overview

This document is the engineering details behind the Menu Requirements document. It supplements that document with examples and a comprehensive listing of attributes and parent/child relationships.

From the Requirements Document:

A menu item is a line item in a visible UI menu. It has text (displayed visually) and may contain a shortcut key (cmd-Q for example). A menu item can be enabled or disabled separately from the other items around it. A special kind of menu item, called a separator, is visually represented as a disabled horizontal line with no text.

A menu list corresponds to an entire UI menu, and is a sequential ordered list of menu items. A menu list may be hierarchical and have sub-menu lists hanging off of items.

A menu bar is an ordered collection of menu lists. Menu bars are used to present several menus, usually in a non-transient way. Context menus, for example, would not use a menu bar since they are only displaying a single transient menu.


Syntax

Tag

Allowed Children

Attributes

Description

menubar

menu

none

The root tag for a menu bar.

menu

menuitem, separator,
menu

name, enabled, icon

Child of <menubar>. A menu list has a name that will be displayed in the menu bar. The menu list can be enabled and disabled. The menu list can have an icon to be displayed in the menu bar.

menuitem

none

name, enabled, checked, cmd

Child of <menu>. A menu item has a name to be displayed, can be enabled or disabled, and can be checked or unchecked.

separator

none

 none

A separator line

Styles

While the idea of having style sheets for a menu is intriguing, it presents significant problems when menus are rendering via native OS calls, which may or may not respond to all styles. The current plan is for menus to not obey styles.


Examples

<menubar>
<menu name="File">
    <menu name="New">
        <menuitem name="Navigator" cmd="commandid:newnavigator" />
        <menuitem name="Message" cmd="commandid:newmessage" />
        <menuitem name="Blank Page" cmd="commandid:newblankpage" />
        <separator/>
        <menuitem name="Blank Page From Template..." cmd="commandid:blankpagefromtemplate" />
    </menu>
    <menuitem name="Open" cmd="commandid:open" />
    <separator/>
    <menuitem name="Close" cmd="commandid:close"/>
    <menuitem name="Save As..." cmd="commandid:saveas"/>
    <separator/>
    <menuitem name="Quit" cmd="commandid:quit"/>
</menu>
<menu name="Edit">
etc...
</menu>
</menubar>


Implementation Details

The implementation of the menu facilities will be native code on each platform with cross platform interfaces, primarily consisting of the DOM interfaces. Some interfaces may only have meaning on one platform however. For example, the interface to set the default menu bar may only make sense on MacOS where menu bars are not always associated with a window.

Because of the uniqueness of menu events not having an associated visible component inside the window frame on all platforms, the events will be captured via custom mechanism inside of Gecko and sent to the listening nsMenuBars for dispatch. This means menus cannot be scripted directly, but the Command Nodes associated with a menuitem will still be scriptable. In other words, if you execute a command via a Command Node with a script, the menu item will not flash accordingly, but the command will be executed.

As for the frames vs. widget question, it is the author's current opinion that nsIWidget is the correct interface for XPToolkit menu facilities. Note: saying that a menu is a widget is in some sense a lie. The nsIWidget interface is a convenient for fitting into the XPToolkit object model. Menus are not proper widgets.

Menus construction sequence:

  1. The XUL file is parsed and a content tree is created.
  2. The menubar content subtree (with menubar as root) is passed off to the nsMenuManager for construction. Construction means iteration over the content subtree and construction of the associated nsMenuBars, nsMenus, and nsMenuItems. The nsMenuBar registers itself as an nsMenuEventListener with an nsWindow via a custom private mechanism. The nsMenuBar, nsMenus, and nsMenuItems register themselves as listeners with their corresponding content nodes. The nsMenuManager then hands back the constructed, hooked up nsMenuBar.
  3. The standard Command Nodes are hooked up in another content tree pass. This includes the Command Nodes referenced by menuitems.

After all of this, there is a complete menubar, ready for action.

Menu Item Arbitration and Merging

If a widget wishes to place menus in the menu bar, or menu items in a menu, it may do so by making a request to the host application. A request includes the desired menu position in the menu bar (if a menu is being merged) or the position of the menu item in the menu list (if a menu item is being merged), and a reference to the menuitem widget's AOM node, which should have been set up during a XUL load to have a reference to a Command Node. This seems an elegant way to do merging that meshes well with the proposed command architecture.

A merge request will usually happen when a widget gets focus. When the widget looses focus, it should remove the merged items that it does not wish to be persistent across focus changes. It was debated that the menu facilities manager should automatically undo the merge for the widget upon focus loss, but that requires the manager to be aware of focus changed events, which it is not currently.

It has been requested that a "widget" have the capability to do a menu merge, even before a widget is instantiated. It is the author's belief that the intended effect can be achieved via a Command Node and a XUL modification. Simply add a new menu item to the XUL with a Command that can fulfill the desired behavior. This is a general purpose approach that is actually not related to widgets at all.

Proposed Extensions

(read as: not a requirement, but would be nice)

MacOS support for Frontier's Shared Menus


Questions, comments, or concerns about this document should go to netscape.public.mozilla.xpfe