The Allegro Wiki is migrating to github at

Native Menu Proposal

From Allegro Wiki
Revision as of 05:49, July 1, 2011 by Matthew Leverton (talk | contribs) (Implementation Notes)
Jump to: navigation, search

Allegro's native dialog add-on provides a way to access basic OS dialogs (message boxes, file selectors, etc). This is a proposal to add support for native menus as part of the add-on.

This proposal is a draft. It is likely to change as it is implemented.


<highlightSyntax language="c"> typedef struct ALLEGRO_MENU ALLEGRO_MENU;





 int id;


/* creating/modifying menus */ ALLEGRO_MENU *al_create_menu(void); ALLEGRO_MENU *al_build_menu(ALLEGRO_MENU_INFO *info); int al_append_menu_item(ALLEGRO_MENU *parent, char const *title, int id, int flags, ALLEGRO_MENU *popup); int al_insert_menu_item(ALLEGRO_MENU *parent, int before_id, char const *title, int id, int flags, ALLEGRO_MENU *popup); bool al_remove_menu_item(ALLEGRO_MENU *menu, int id); ALLEGRO_MENU *al_clone_menu(ALLEGRO_MENU *menu); void al_destroy_menu(ALLEGRO_MENU *menu);

/* properties */ int al_get_menu_item_flags(ALLEGRO_MENU *menu, int id); void al_set_menu_item_flags(ALLEGRO_MENU *menu, int id, int flags); void al_toggle_menu_item_flags(ALLEGRO_MENU *menu, int id, int flags);

/* querying menus */ bool al_find_menu_item(ALLEGRO_MENU *haystack, int id, ALLEGRO_MENU **menu, int *index);

/* menu events */ ALLEGRO_EVENT_SOURCE *al_get_default_menu_event_source(void); ALLEGRO_EVENT_SOURCE *al_enable_menu_event_source(ALLEGRO_MENU *menu); void al_disable_menu_event_source(ALLEGRO_MENU *menu);

/* displaying menus */ bool al_set_display_menu(ALLEGRO_DISPLAY *display, ALLEGRO_MENU *menu); bool al_popup_menu(ALLEGRO_MENU *popup, ALLEGRO_DISPLAY *display, int x, int y); ALLEGRO_MENU *al_remove_display_menu(ALLEGRO_DISPLAY *menu);


Basic Use Case

<highlightSyntax language="c"> ALLEGRO_MENU *file = al_create_menu(); al_append_menu_item(file, "Open", OPEN_ID, 0, NULL); al_append_menu_item(file, "Exit", EXIT_ID, 0, NULL);

ALLEGRO_MENU *menu = al_create_menu(); al_append_menu_item(menu, "File", 0, 0, file);

al_set_display_menu(display, menu); </highlightSyntax>

Implementation Notes

  • An ALLEGRO_MENU can only be attached to a single display at a time. A menu that is attached to a display cannot be used as a popup. The al_clone_menu() is intended to be used for the case where the same menu should be displayed on multiple displays.
  • Events are sent via the closest source found in the menu hierarchy. If none is found (al_enable_menu_event_source() was not ever used), then they are sent via a default source.
  • There is no way yet to specify a bitmap icon. If an ALLEGRO_BITMAP is used, then it would have to be converted to the OS's native bitmap format.
  • There is no way yet to specify keyboard triggers.
  • The public functions have "id" parameters that represent a menu id. The entire menu structure is queried for that id, including child menus. If the "id" parameter is zero or negative, then its absolute value is assumed to be the index position of the menu item.


The system menu is always built (with certain default menu items), even if no user menu has been set. So when a user menu is set, those default menu items should be automatically inserted in a transparent manner.

OS X uses a single application menu as opposed to a per window menu. This presents a problem because the API is designed to work with a per-window menu. Some solutions:

  1. Automatically detect when a display gains focus, and update the menu accordingly. If the newly focused display has no menu, then nothing would happen to the existing system menu. If possible, this would be the preferred solution. While it may not be how first-class OS X applications operate, it provides the most transparent cross platform solution.
  2. Always show the most recent menu as set via al_set_display_menu() regardless of the current display. The user would have to explicitly call that function every time a different display gains focus. When a display is destroyed, the user would have to call al_set_display_menu(NULL, NULL). (The first parameter would actually just be ignored, so it could be anything, including the pointer of the destroyed display.)