Allegro.cc - Online Community

Allegro.cc Forums » Allegro Development » Allegro 5.1.8 Native Menus OSX

This thread is locked; no one can reply to it. rss feed Print
Allegro 5.1.8 Native Menus OSX
Malcolm Harrow
Member #15,833
December 2014

Hi I'm trying to create a native menu in OS X with the following structure:

File
Open
Open Recent...
Recent 1
Recent 2
Exit

I can't get this to work .. neither recent item appears, I get:

File
Open
Open Recent...
Exit

What have I done wrong ?
Regards
Malcolm

ALLEGRO_MENU *menu = al_create_menu();
ALLEGRO_MENU *file_menu = al_create_menu();
ALLEGRO_MENU *recent_menu = al_create_menu();

if ((menu == NULL) || (file_menu == NULL) || (recent_menu == NULL))
{
rpclog("Failed to initialise Allegro menu\n");
return 1;
}

al_append_menu_item(recent_menu, "Recent 1", 14, 0, NULL, NULL);
al_append_menu_item(recent_menu, "Recent 2", 15, 0, NULL, NULL);

al_append_menu_item(file_menu, "&Open", 1, 0, NULL, NULL);
al_append_menu_item(file_menu, "Open Recent...", 2, 0, NULL, recent_menu);
al_append_menu_item(file_menu, "Exit", 3, 0, NULL, NULL);

al_append_menu_item(menu, "File", 0, 0, NULL, file_menu);

al_set_display_menu(display, menu);

Trent Gamblin
Member #261
April 2000
avatar

Post a complete example in <code> tags.

Malcolm Harrow
Member #15,833
December 2014

Many thanks for taking an interest in my issue. Here is the code. I've also attached some screenshots showing what I get and another showing the effect I want (sub-menu item from Xcode).
Malcolm

#SelectExpand
1// 2// main.c 3// TestAllegro 4// 5// Created by Malcolm on 20/12/14. 6// 7// Trying to get: 8// File 9// Open 10// Open Recent > Recent 1 11// Recent 2 12// Exit 13// 14// 15// Get: 16// File 17// Open 18// Open Recent 19// Exit 20// 21// 22 23#include <stdio.h> 24#include <allegro5/allegro.h> 25#include <allegro5/allegro_native_dialog.h> 26 27void handleError(char *e) 28{ 29 printf("%s\n", e); 30 exit(1); 31} 32 33int main(int argc, char **argv) 34{ 35 if (!al_init()) handleError("Error al_init"); 36 37 ALLEGRO_DISPLAY *display = al_create_display(640, 480); 38 if (!display) handleError("Error al_create_display"); 39 40 if (!al_install_keyboard()) handleError("Error al_install_keyboard"); 41 42 ALLEGRO_MENU *menu = al_create_menu(); 43 ALLEGRO_MENU *file_menu = al_create_menu(); 44 ALLEGRO_MENU *recent_menu = al_create_menu(); 45 46 if ((menu == NULL) || (file_menu == NULL) || (recent_menu == NULL)) handleError("Error al_create_menu"); 47 48 al_append_menu_item(recent_menu, "Recent 1", 14, 0, NULL, NULL); 49 al_append_menu_item(recent_menu, "Recent 2", 15, 0, NULL, NULL); 50 51 al_append_menu_item(file_menu, "&Open", 1, 0, NULL, NULL); 52 al_append_menu_item(file_menu, "Open Recent...", 2, 0, NULL, recent_menu); 53 al_append_menu_item(file_menu, "Exit", 3, 0, NULL, NULL); 54 55 al_append_menu_item(menu, "File", 0, 0, NULL, file_menu); 56 57 al_set_display_menu(display, menu); 58 59 60 ALLEGRO_EVENT_QUEUE *events = al_create_event_queue(); 61 al_register_event_source(events, al_get_display_event_source(display)); 62 al_register_event_source(events, al_get_default_menu_event_source()); 63 64 bool quited = false; 65 66 while (!quited) 67 { 68 ALLEGRO_EVENT event; 69 70 al_wait_for_event(events, &event); 71 switch (event.type) 72 { 73 case ALLEGRO_EVENT_DISPLAY_CLOSE: 74 quited = true; 75 break; 76 77 case ALLEGRO_EVENT_MENU_CLICK: 78 if (event.user.data1 == 3) quited = true; 79 break; 80 } 81 } 82 83 return 0; 84} 85END_OF_MAIN();

Trent Gamblin
Member #261
April 2000
avatar

One thing you're not doing is calling al_init_native_dialog_addon(). That doesn't seem to fix the issue but is necessary. I compiled your example with Allegro debug libraries and it crashes without that. I'll look further for the rest of the problem.

EDIT: Are you able to compile Allegro for OS X yourself? Well maybe that's a dumb question since there are no binaries. Try the attached patch and let me know how it works.

Malcolm Harrow
Member #15,833
December 2014

Thanks .. I added this in too, but it didn't seem to make any difference on my copy either.
Regards
Malcolm

// start of snippet ...
int main(int argc, char **argv)
{
    if (!al_init()) handleError("Error al_init");
    if (!al_init_native_dialog_addon()) handleError("Error al_init_native_dialog_addon");
    
    
    ALLEGRO_DISPLAY *display = al_create_display(640, 480);
    if (!display) handleError("Error al_create_display");
// end of snippet ...

EDIT: I just saw your edit. Yes, I compiled the libraries myself. Let me try this later. Many thanks!

Todd Cope
Member #998
November 2000
avatar

This discussion might be relevant. There are some patches in that thread that never got accepted.

I'm not sure whether or not any other work has been done on the menu code since then. At that point in time, the OS X implementation was pretty broken.

Malcolm Harrow
Member #15,833
December 2014

Sorry that took a while .. I'd forgotten how I'd compiled the libraries :(

Interestingly, I could only get a good compile by getting the source from git, the copy on the download section gave me a runtime error. Not sure why this would be the case.

Anyway .. success !!! The patch appears to work .. I will test further! Attached are screen shots when you initially select the menu then when you hover over the popup. Thank you so much!

To the point above, how do we make sure this patch is included in the next release ? Is there a daily/weekly build process ?

Regards
Malcolm

Trent Gamblin
Member #261
April 2000
avatar

Thanks. Please let me know how your further testing goes.

I'll commit this to git now. We haven't done a release in a few months but there has been some talk about it. My recommendation is to use git until we do.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Malcolm Harrow
Member #15,833
December 2014

I thought I would try al_build_menu() ..

I copied the menu structure from the online manual. I don't get an "About" item under the help menu .. but I do get the items from sub menu repeated again .. see screenshots. Did we just break this ?

Regards
Malcolm

#SelectExpand
1// 2// main.c 3// TestAllegro 4// 5// Created by Malcolm on 20/12/14. 6// 7// Trying to get: 8// File 9// Open 10// Open Recent > Recent 1 11// Recent 2 12// Exit 13// 14// 15// Get: 16// File 17// Open 18// Open Recent 19// Exit 20// 21// 22 23#include <stdio.h> 24#include <allegro5/allegro.h> 25#include <allegro5/allegro_native_dialog.h> 26 27void handleError(char *e) 28{ 29 printf("%s\n", e); 30 exit(1); 31} 32 33int main(int argc, char **argv) 34{ 35 if (!al_init()) handleError("Error al_init"); 36 if (!al_init_native_dialog_addon()) handleError("Error al_init_native_dialog_addon"); 37 38 39 ALLEGRO_DISPLAY *display = al_create_display(640, 480); 40 if (!display) handleError("Error al_create_display"); 41 42 43 44 if (!al_install_keyboard()) handleError("Error al_install_keyboard"); 45 46// Building menu manually now works 47// 48// ALLEGRO_MENU *menu = al_create_menu(); 49// ALLEGRO_MENU *file_menu = al_create_menu(); 50// ALLEGRO_MENU *recent_menu = al_create_menu(); 51// 52// if ((menu == NULL) || (file_menu == NULL) || (recent_menu == NULL)) handleError("Error al_create_menu"); 53// 54// al_append_menu_item(recent_menu, "Recent 1", 14, 0, NULL, NULL); 55// al_append_menu_item(recent_menu, "Recent 2", 15, 0, NULL, NULL); 56// 57// al_append_menu_item(file_menu, "&Open", 1, 0, NULL, NULL); 58// al_append_menu_item(file_menu, "Open Recent...", 2, 0, NULL, recent_menu); 59// al_append_menu_item(file_menu, "Exit", 3, 0, NULL, NULL); 60// 61// al_append_menu_item(menu, "File", 0, 0, NULL, file_menu); 62 63 ALLEGRO_MENU_INFO menu_info[] = { 64 ALLEGRO_START_OF_MENU("&File", 1), 65 { "&Open", 2, 0, NULL }, 66 ALLEGRO_START_OF_MENU("Open &Recent...", 3), 67 { "Recent 1", 4, 0, NULL }, 68 { "Recent 2", 5, 0, NULL }, 69 ALLEGRO_END_OF_MENU, 70 ALLEGRO_MENU_SEPARATOR, 71 { "E&xit", 6, 0, NULL }, 72 ALLEGRO_END_OF_MENU, 73 ALLEGRO_START_OF_MENU("&Help", 7), 74 {"&About", 8, 0, NULL }, 75 ALLEGRO_END_OF_MENU, 76 ALLEGRO_END_OF_MENU 77 }; 78 79 ALLEGRO_MENU *menu = al_build_menu(menu_info); 80 81 al_set_display_menu(display, menu); 82 83 84 ALLEGRO_EVENT_QUEUE *events = al_create_event_queue(); 85 al_register_event_source(events, al_get_display_event_source(display)); 86 al_register_event_source(events, al_get_default_menu_event_source()); 87 88 bool quited = false; 89 90 while (!quited) 91 { 92 ALLEGRO_EVENT event; 93 94 al_wait_for_event(events, &event); 95 switch (event.type) 96 { 97 case ALLEGRO_EVENT_DISPLAY_CLOSE: 98 quited = true; 99 break; 100 101 case ALLEGRO_EVENT_MENU_CLICK: 102 if (event.user.data1 == 3) quited = true; 103 break; 104 } 105 } 106 107 return 0; 108} 109END_OF_MAIN();

Trent Gamblin
Member #261
April 2000
avatar

Going to look at this now. Will edit post later.

EDIT: BTW, you shouldn't be using END_OF_MAIN() with Allegro 5.

EDIT: Looks like it was doing the same thing before, so we didn't add any new problems that I know of. I'll try to fix it.

Malcolm Harrow
Member #15,833
December 2014

No END_OF_MAIN is good news .. One less warning message from Xcode !
Many thanks
Malcolm

Trent Gamblin
Member #261
April 2000
avatar

Try this patch. It was kind of a fluke that submenus sort of worked at all before. ???

EDIT: Please do a thorough check if you can.

Malcolm Harrow
Member #15,833
December 2014

Brilliant!

Works with the sample program .. plus works with my actual project .. which has some crazy popups. See attached.

I suggest you push both into GIT .. even if there are further issues, it works much better than before. I will continue to do further testing.

Many thanks again ! :D:D
Regards
Malcolm

Trent Gamblin
Member #261
April 2000
avatar

Thanks, it's now in git. Let me know if you have further problems.

Malcolm Harrow
Member #15,833
December 2014

Hi,

This may or may not be related. I'm trying to use al_set_menu_item_flag. The output from the code below is:

Flag ALLEGRO_MENU_ITEM_CHECKBOX 1
Flag ALLEGRO_MENU_ITEM_CHECKED 2
Flags | 3
Should have a flag of 1 as defined as a checkbox. 1=1
After toggle of CHECKED flag, should be 3=3
After using set with a bitwise or should be 3= 2
After directly setting the flags to 3, value should be 3=0

Is al_set_menu_item_flags working, or am I confused?

Regards
Malcolm

#SelectExpand
1// 2// main.c 3// TestAllegro 4// 5 6#include <stdio.h> 7#include <allegro5/allegro.h> 8#include <allegro5/allegro_native_dialog.h> 9 10void handleError(char *e) 11{ 12 printf("%s\n", e); 13 exit(1); 14} 15 16int main(int argc, char **argv) 17{ 18 if (!al_init()) handleError("Error al_init"); 19 if (!al_init_native_dialog_addon()) handleError("Error al_init_native_dialog_addon"); 20 21 22 ALLEGRO_DISPLAY *display = al_create_display(640, 480); 23 if (!display) handleError("Error al_create_display"); 24 25 if (!al_install_keyboard()) handleError("Error al_install_keyboard"); 26 27 // Building menu manually now works 28 // 29 // ALLEGRO_MENU *menu = al_create_menu(); 30 // ALLEGRO_MENU *file_menu = al_create_menu(); 31 // ALLEGRO_MENU *recent_menu = al_create_menu(); 32 // 33 // if ((menu == NULL) || (file_menu == NULL) || (recent_menu == NULL)) handleError("Error al_create_menu"); 34 // 35 // al_append_menu_item(recent_menu, "Recent 1", 14, 0, NULL, NULL); 36 // al_append_menu_item(recent_menu, "Recent 2", 15, 0, NULL, NULL); 37 // 38 // al_append_menu_item(file_menu, "&Open", 1, 0, NULL, NULL); 39 // al_append_menu_item(file_menu, "Open Recent...", 2, 0, NULL, recent_menu); 40 // al_append_menu_item(file_menu, "Exit", 3, 0, NULL, NULL); 41 // 42 // al_append_menu_item(menu, "File", 0, 0, NULL, file_menu); 43 44 ALLEGRO_MENU_INFO menu_info[] = { 45 ALLEGRO_START_OF_MENU("&File", 1), 46 { "&Open", 2, ALLEGRO_MENU_ITEM_CHECKBOX, NULL }, 47 ALLEGRO_START_OF_MENU("Open &Recent...", 3), 48 { "Recent 1", 4, 0, NULL }, 49 { "Recent 2", 5, 0, NULL }, 50 ALLEGRO_END_OF_MENU, 51 ALLEGRO_MENU_SEPARATOR, 52 { "E&xit", 6, 0, NULL }, 53 ALLEGRO_END_OF_MENU, 54 ALLEGRO_START_OF_MENU("&Help", 7), 55 {"&About", 8, 0, NULL }, 56 ALLEGRO_END_OF_MENU, 57 ALLEGRO_END_OF_MENU 58 }; 59 60 ALLEGRO_MENU *menu = al_build_menu(menu_info); 61 62 al_set_display_menu(display, menu); 63 64 65 ALLEGRO_EVENT_QUEUE *events = al_create_event_queue(); 66 al_register_event_source(events, al_get_display_event_source(display)); 67 al_register_event_source(events, al_get_default_menu_event_source()); 68 69 printf("Flag ALLEGRO_MENU_ITEM_CHECKBOX %d\n", ALLEGRO_MENU_ITEM_CHECKBOX); 70 printf("Flag ALLEGRO_MENU_ITEM_CHECKED %d\n", ALLEGRO_MENU_ITEM_CHECKED); 71 printf("Flags | %d\n", ALLEGRO_MENU_ITEM_CHECKBOX | ALLEGRO_MENU_ITEM_CHECKED); 72 73 74 printf("Should have a flag of 1 as defined as a checkbox. 1=%d\n", al_get_menu_item_flags(menu, 2)); 75 al_toggle_menu_item_flags(menu, 2, ALLEGRO_MENU_ITEM_CHECKED); 76 printf("After toggle of CHECKED flag, should be 3=%d\n", al_get_menu_item_flags(menu, 2)); 77 al_set_menu_item_flags(menu, 2, ALLEGRO_MENU_ITEM_CHECKED | ALLEGRO_MENU_ITEM_CHECKBOX); 78 printf("After using set with a bitwise or should be 3= %d\n", al_get_menu_item_flags(menu, 2)); 79 al_set_menu_item_flags(menu, 2, 3); 80 printf("After directly setting the flags to 3, value should be 3=%d\n", al_get_menu_item_flags(menu, 2)); 81 82 83 bool quited = false; 84 85 while (!quited) 86 { 87 ALLEGRO_EVENT event; 88 89 al_wait_for_event(events, &event); 90 switch (event.type) 91 { 92 case ALLEGRO_EVENT_DISPLAY_CLOSE: 93 quited = true; 94 break; 95 case ALLEGRO_EVENT_MENU_CLICK: 96 printf("Clicked %ld\n", event.user.data1); 97 if (event.user.data1 == 6) quited = true; 98 break; 99 } 100 } 101 102 return 0; 103}

Trent Gamblin
Member #261
April 2000
avatar

The documentation on the flags states that ALLEGRO_MENU_ITEM_CHECKBOX can only be set at the time of creation. Might have something to do with it. Check the code in addons/native_dialog if in doubt.

Malcolm Harrow
Member #15,833
December 2014

Ok, I looked at the following code snippet from line 535 in menu.c - the function al_set_menu_item_flags(). As its the first time looking or changing this code, I’ll explain my thought process in detail. This looks like cross-platform code .. and I only have OS X :(

#SelectExpand
1/* Function: al_set_menu_item_flags 2 */ 3void al_set_menu_item_flags(ALLEGRO_MENU *menu, int pos, int flags) 4{ 5 ALLEGRO_MENU_ITEM *item; 6 7 ASSERT(menu); 8 9 item = interpret_menu_id_param(&menu, &pos); 10 11 if (item) { 12 /* The CHECKBOX flag is read-only after the menu is created, and 13 * the CHECKED flag can only be set if it is a CHECKBOX. 14 */ 15 flags &= ~ALLEGRO_MENU_ITEM_CHECKBOX; // Note 1 16 if (!(item->flags & ALLEGRO_MENU_ITEM_CHECKBOX)) { // Note 2 17 flags &= ~ALLEGRO_MENU_ITEM_CHECKED; 18 } 19 20 item->flags = flags; // Note 3 21 _al_update_menu_item_at(item, pos); 22 } 23}

Note 1 .. changes the flags parameter to clear the CHECKBOX flag
Note 2 .. if the menu item is not a CHECKBOX .. the we can’t set the CHECKED flag so clear it from the parameter
Note 3 .. update menu flags with parameter

So .. I think the issue is that line commented “Note 1" always clears the CHECKBOX flag

I think the intended behaviour is that item->flags remains a checkbox if set and cannot be changed, so I think the function needs to be changed to:

#SelectExpand
1/* Function: al_set_menu_item_flags 2 */ 3void al_set_menu_item_flags(ALLEGRO_MENU *menu, int pos, int flags) 4{ 5 ALLEGRO_MENU_ITEM *item; 6 7 ASSERT(menu); 8 9 item = interpret_menu_id_param(&menu, &pos); 10 11 if (item) { 12 /* The CHECKBOX flag is read-only after the menu is created, and 13 * the CHECKED flag can only be set if it is a CHECKBOX. 14 */ 15 if (item->flags & ALLEGRO_MENU_ITEM_CHECKBOX) 16 { 17 flags |= ALLEGRO_MENU_ITEM_CHECKBOX; 18 } 19 else 20 { 21 flags &= ~ALLEGRO_MENU_ITEM_CHECKED; 22 flags &= ~ALLEGRO_MENU_ITEM_CHECKBOX; 23 } 24 25 item->flags = flags; 26 _al_update_menu_item_at(item, pos); 27 } 28}

I’ve attached a diff file

diff menu.c.orig menu.c > al_set_menu_item_flags.patch

What do you think ?
Regards
Malcolm

Trent Gamblin
Member #261
April 2000
avatar

Looks good, will commit. Thank you.

Go to: