Skip to content

Commit 17ce1d7

Browse files
committed
Did a documentation pass, worked on appmenu destruction, fixed bugs.
1 parent ffabd75 commit 17ce1d7

File tree

4 files changed

+260
-15
lines changed

4 files changed

+260
-15
lines changed

examples/video/01-menubar/menubar.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ void PrintMenuItems(SDL_Renderer* renderer, SDL_MenuItem *menu_item, int indent,
5555
return;
5656
}
5757

58+
SDL_MenuItem *app_menu = SDL_GetMenuBarAppMenu(menu_item);
59+
if (app_menu) {
60+
SDL_RenderDebugText(renderer, (float)(8 * indent * 2), (float)(*total_index * 8), " -> AppMenu");
61+
++(*total_index);
62+
}
63+
5864
const char* label = SDL_GetMenuItemLabel(menu_item);
5965

6066
if (!label) {

include/SDL3/SDL_video.h

Lines changed: 211 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2975,11 +2975,34 @@ extern SDL_DECLSPEC float SDLCALL SDL_GetWindowProgressValue(SDL_Window *window)
29752975
* Assigns a menu_bar to the given window, which will take ownership of it's destruction. NULL
29762976
* releases the menu_bar without destroying it.
29772977
*/
2978+
2979+
/**
2980+
* Gets the value of the menu bar for the given window.
2981+
*
2982+
* \param window the window to retrieve the Menu Bar of.
2983+
* \returns A pointer to an SDL_MenuBar on success or NULL on failure; call SDL_GetError() for more
2984+
* information.
2985+
*
2986+
* \threadsafety This function should only be called on the main thread.
2987+
*
2988+
* \since This function is available since SDL 3.6.0.
2989+
*/
29782990
extern SDL_DECLSPEC SDL_MenuItem *SDL_GetWindowMenuBar(SDL_Window *window);
29792991

29802992
/**
2981-
* Assigns a menu_bar to the given window, which will take ownership of it's destruction. NULL
2982-
* releases the menu_bar without destroying it.
2993+
* Gets a menu bar for the given window, a NULL menu_bar will unset a menu_bar on the given window.
2994+
*
2995+
* The window will take ownership over this menu_bar, handling destruction of it it the window
2996+
* is destroyed. Ownership will be released back to the user if this function is called again,
2997+
* so make sure to keep a reference to it if you plan to call this function more than once.
2998+
*
2999+
* \param window the window to assign the menu_bar to.
3000+
* \param menu_bar the window to retrieve the Menu Bar of.
3001+
* \returns true on success, or false on failure; call SDL_GetError() for more information.
3002+
*
3003+
* \threadsafety This function should only be called on the main thread.
3004+
*
3005+
* \since This function is available since SDL 3.6.0.
29833006
*/
29843007
extern SDL_DECLSPEC bool SDL_SetWindowMenuBar(SDL_Window *window, SDL_MenuItem *menu_bar);
29853008

@@ -3060,49 +3083,223 @@ extern SDL_DECLSPEC bool SDLCALL SDL_EnableScreenSaver(void);
30603083
*/
30613084
extern SDL_DECLSPEC bool SDLCALL SDL_DisableScreenSaver(void);
30623085

3086+
/**
3087+
* Creates an empty menu bar, on platforms that support it, also creates an empty app menu.
3088+
*
3089+
* \returns a pointer to a menu bar, or -1 on failure; call SDL_GetError() for more
3090+
* information.
3091+
*
3092+
* \threadsafety This function should only be called on the main thread.
3093+
*
3094+
* \since This function is available since SDL 3.6.0.
3095+
*/
30633096
extern SDL_DECLSPEC SDL_MenuItem *SDL_CreateMenuBar();
30643097

3098+
/**
3099+
* Gets the app menu of the given menu bar, must be SDL_MENUITEM_MENUBAR
3100+
*
3101+
* Most platforms do not have an App Menu, notably MacOS does.
3102+
*
3103+
* \param menu_bar the menu item to get the app menu of.
3104+
* \returns a pointer to the app menu, or NULL on failure; call SDL_GetError() for more
3105+
* information.
3106+
*
3107+
* \threadsafety This function should only be called on the main thread.
3108+
*
3109+
* \since This function is available since SDL 3.6.0.
3110+
*/
30653111
extern SDL_DECLSPEC SDL_MenuItem *SDL_GetMenuBarAppMenu(SDL_MenuItem *menu_bar);
30663112

30673113
/**
3068-
* menu_as_item must be a SDL_MENUITEM_MENUBAR or SDL_MENUITEM_SUBMENU
3069-
* event_type will be ignored if type == SDL_MENUITEM_SUBMENU
3070-
* On MacOS, buttoms created under a menubar will go into the "App" submenu
3114+
* Gets the app menu of the given menu bar, must be SDL_MENUITEM_MENUBAR
3115+
*
3116+
* \param menu_as_item must be a SDL_MENUITEM_MENUBAR or SDL_MENUITEM_SUBMENU
3117+
* \param index place to put the new menu item under the menu_as_item.
3118+
* \param label label to use for the given menu_item.
3119+
* \param type type of menu item to create, cannot create an SDL_MENUITEM_MENUBAR.
3120+
* \param event_type the event number you'll be passed in SDL_MenuEvent when this menu
3121+
* item is clicked, ignored when type == SDL_MENUITEM_SUBMENU.
3122+
* \returns a pointer to the app menu, or NULL on failure; call SDL_GetError() for more
3123+
* information.
3124+
*
3125+
* \threadsafety This function should only be called on the main thread.
3126+
*
3127+
* \since This function is available since SDL 3.6.0.
30713128
*/
3072-
extern SDL_DECLSPEC SDL_MenuItem *SDL_CreateMenuItemAt(SDL_MenuItem *menu_as_item, size_t index, const char *Label, SDL_MenuItemType type, Uint16 event_type);
3129+
extern SDL_DECLSPEC SDL_MenuItem *SDL_CreateMenuItemAt(SDL_MenuItem *menu_as_item, size_t index, const char *label, SDL_MenuItemType type, Uint16 event_type);
30733130

30743131
/**
3075-
* menu_as_item must be a SDL_MENUITEM_MENUBAR or SDL_MENUITEM_SUBMENU
3076-
* event_type will be ignored if type == SDL_MENUITEM_SUBMENU
3077-
* On MacOS, buttoms created under a menubar will go into the "App" submenu
3132+
* Gets the app menu of the given menu bar, must be SDL_MENUITEM_MENUBAR
3133+
*
3134+
* Item will be placed at the end of the list of children of the menu_as_item.
3135+
*
3136+
* \param menu_as_item must be a SDL_MENUITEM_MENUBAR or SDL_MENUITEM_SUBMENU
3137+
* \param label label to use for the given menu_item.
3138+
* \param type type of menu item to create, cannot create an SDL_MENUITEM_MENUBAR.
3139+
* \param event_type the event number you'll be passed in SDL_MenuEvent when this menu
3140+
* item is clicked, ignored when type == SDL_MENUITEM_SUBMENU.
3141+
* \returns a pointer to the app menu, or NULL on failure; call SDL_GetError() for more
3142+
* information.
3143+
*
3144+
* \threadsafety This function should only be called on the main thread.
3145+
*
3146+
* \since This function is available since SDL 3.6.0.
30783147
*/
3079-
extern SDL_DECLSPEC SDL_MenuItem *SDL_CreateMenuItem(SDL_MenuItem *menu_as_item, const char *Label, SDL_MenuItemType type, Uint16 event_type);
3148+
extern SDL_DECLSPEC SDL_MenuItem *SDL_CreateMenuItem(SDL_MenuItem *menu_as_item, const char *label, SDL_MenuItemType type, Uint16 event_type);
30803149

30813150
/**
3082-
* -1 on error
3151+
* Gets the number of children of the given menu, must be SDL_MENUITEM_MENUBAR or SDL_MENUITEM_SUBMENU
3152+
*
3153+
* \param menu_item the menu item to get the label of.
3154+
* \returns the number of children of the given menu, or -1 on failure; call SDL_GetError() for more
3155+
* information.
3156+
*
3157+
* \threadsafety This function should only be called on the main thread.
3158+
*
3159+
* \since This function is available since SDL 3.6.0.
30833160
*/
30843161
extern SDL_DECLSPEC Sint64 SDL_GetMenuChildItems(SDL_MenuItem *menu_as_item);
3162+
3163+
/**
3164+
* Gets child of the given menu at index, menu_as_item must be SDL_MENUITEM_MENUBAR or
3165+
* SDL_MENUITEM_SUBMENU.
3166+
*
3167+
* \param menu_as_item the menu item to get the child of.
3168+
* \param index of the child to get.
3169+
* \returns the number of children of the given menu, or -1 on failure; call SDL_GetError() for more
3170+
* information.
3171+
*
3172+
* \threadsafety This function should only be called on the main thread.
3173+
*
3174+
* \since This function is available since SDL 3.6.0.
3175+
*/
30853176
extern SDL_DECLSPEC SDL_MenuItem *SDL_GetMenuChildItem(SDL_MenuItem *menu_as_item, size_t index);
30863177

3178+
3179+
/**
3180+
* Gets the given menu_items label.
3181+
*
3182+
* If called on an SDL_MENUITEM_MENUBAR or an App Menu, the return will be an empty string.
3183+
*
3184+
* \param menu_item the menu item to get the label of.
3185+
* \returns a pointer to the label of the given menu_item, or NULL on failure;
3186+
* call SDL_GetError() for more information.
3187+
*
3188+
* \threadsafety This function should only be called on the main thread.
3189+
*
3190+
* \since This function is available since SDL 3.6.0.
3191+
*/
30873192
extern SDL_DECLSPEC const char *SDL_GetMenuItemLabel(SDL_MenuItem *menu_item);
3193+
3194+
/**
3195+
* Sets the given menu_items label.
3196+
*
3197+
* Cannot set the label of a SDL_MENUITEM_MENUBAR or an App Menu.
3198+
*
3199+
* \param menu_item the menu item to set the label of.
3200+
* \param label the string to set for the menu_items label..
3201+
* \returns a pointer to the label of the given menu_item, or NULL on failure;
3202+
* call SDL_GetError() for more information.
3203+
*
3204+
* \threadsafety This function should only be called on the main thread.
3205+
*
3206+
* \since This function is available since SDL 3.6.0.
3207+
*/
30883208
extern SDL_DECLSPEC bool SDL_SetMenuItemLabel(SDL_MenuItem *menu_item, const char *label);
3209+
3210+
3211+
/**
3212+
* Gets the given menu_items SDL_MenuItemType.
3213+
*
3214+
* \param menu_item the menu item to get the SDL_MenuItemType of.
3215+
* \returns A valid SDL_MenuItemType on success, or SDL_MENUITEM_INVALID on failure;
3216+
* call SDL_GetError() for more information.
3217+
*
3218+
* \threadsafety This function should only be called on the main thread.
3219+
*
3220+
* \since This function is available since SDL 3.6.0.
3221+
*/
30893222
extern SDL_DECLSPEC SDL_MenuItemType SDL_GetMenuItemType(SDL_MenuItem *menu_item);
3223+
3224+
/**
3225+
* Gets the given menu_items user event type.
3226+
*
3227+
* \param menu_item the menu item to get the user type of.
3228+
* \returns >= 0 on success, or -1 on failure; call SDL_GetError() for more information.
3229+
*
3230+
* \threadsafety This function should only be called on the main thread.
3231+
*
3232+
* \since This function is available since SDL 3.6.0.
3233+
*/
30903234
extern SDL_DECLSPEC Sint32 SDL_GetMenuItemEventType(SDL_MenuItem *menu_item);
30913235

30923236
/**
3093-
* Must be a SDL_MENUITEM_CHECKABLE
3237+
* Gets the given menu_items (which must be an SDL_MENUITEM_CHECKABLE) checked state.
3238+
*
3239+
* \param menu_item the menu item to check the state of.
3240+
* \param checked pointer to variable to populate with the menu_items checked state.
3241+
* \returns true on success, or false on failure; call SDL_GetError() for more information.
3242+
*
3243+
* \threadsafety This function should only be called on the main thread.
3244+
*
3245+
* \since This function is available since SDL 3.6.0.
30943246
*/
30953247
extern SDL_DECLSPEC bool SDL_GetMenuItemChecked(SDL_MenuItem *menu_item, bool *checked);
30963248

30973249
/**
3098-
* Must be a SDL_MENUITEM_CHECKABLE
3250+
* Sets the given menu_item (which must be an SDL_MENUITEM_CHECKABLE) to be checked or unchecked.
3251+
*
3252+
* \param menu_item the menu item to have it's state changed.
3253+
* \param checked the value to set for if the menu_item is checked or unchecked.
3254+
* \returns true on success, or false on failure; call SDL_GetError() for more information.
3255+
*
3256+
* \threadsafety This function should only be called on the main thread.
3257+
*
3258+
* \since This function is available since SDL 3.6.0.
30993259
*/
31003260
extern SDL_DECLSPEC bool SDL_SetMenuItemChecked(SDL_MenuItem *menu_item, bool checked);
31013261

3102-
3262+
/**
3263+
* Gets the given menu_items enabled or disabled state.
3264+
*
3265+
* \param menu_item the menu item to check the state of.
3266+
* \param enabled pointer to variable to populate with the menu_items enabled state.
3267+
* \returns true on success, or false on failure; call SDL_GetError() for more information.
3268+
*
3269+
* \threadsafety This function should only be called on the main thread.
3270+
*
3271+
* \since This function is available since SDL 3.6.0.
3272+
*/
31033273
extern SDL_DECLSPEC bool SDL_GetMenuItemEnabled(SDL_MenuItem *menu_item, bool *enabled);
3274+
3275+
/**
3276+
* Sets the given menu_item to be enabled or disabled.
3277+
*
3278+
* \param menu_item the menu item to have it's state changed.
3279+
* \param enabled the value to set for if the menu_item is enabled or disabled.
3280+
* \returns true on success, or false on failure; call SDL_GetError() for more information.
3281+
*
3282+
* \threadsafety This function should only be called on the main thread.
3283+
*
3284+
* \since This function is available since SDL 3.6.0.
3285+
*/
31043286
extern SDL_DECLSPEC bool SDL_SetMenuItemEnabled(SDL_MenuItem *menu_item, bool enabled);
31053287

3288+
/**
3289+
* Destroys the given menu_item and all of it's children.
3290+
*
3291+
* If called on an SDL_MENUITEM_MENUBAR, the menu bar will be unset from a window it may be
3292+
* set to. If called on an SDL_MENUITEM_SUBMENU that happens to be the AppMenu for a menu
3293+
* bar, only it's children will be destroyed, not the AppMenu itself. If called on anything
3294+
* else, the item will be removed from menu tree it's part of.
3295+
*
3296+
* \param menu_item the menu item to be destroyed.
3297+
* \returns true on success, or false on failure; call SDL_GetError() for more information.
3298+
*
3299+
* \threadsafety This function should only be called on the main thread.
3300+
*
3301+
* \since This function is available since SDL 3.6.0.
3302+
*/
31063303
extern SDL_DECLSPEC bool SDL_DestroyMenuItem(SDL_MenuItem *menu_item);
31073304

31083305
/**

src/video/SDL_video.c

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4471,7 +4471,10 @@ void SDL_DestroyWindow(SDL_Window *window)
44714471

44724472
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_DESTROYED, 0, 0);
44734473

4474-
SDL_DestroyMenuItem((SDL_MenuItem*)window->menu_bar);
4474+
if (window->menu_bar) {
4475+
SDL_DestroyMenuItem((SDL_MenuItem *)window->menu_bar);
4476+
window->menu_bar = NULL;
4477+
}
44754478

44764479
SDL_DestroyWindowSurface(window);
44774480

@@ -6244,6 +6247,11 @@ SDL_MenuItem *SDL_CreateMenuItemAt(SDL_MenuItem *menu_as_item, size_t index, con
62446247
return false;
62456248
}
62466249

6250+
if (!label) {
6251+
SDL_SetError("Label cannot be null");
6252+
return NULL;
6253+
}
6254+
62476255
SDL_Menu_CommonData *menu = (SDL_Menu_CommonData *)menu_as_item;
62486256

62496257
if (menu->num_children < (Sint64)index) {
@@ -6370,12 +6378,29 @@ SDL_MenuItem *SDL_GetMenuChildItem(SDL_MenuItem *menu_as_item, size_t index)
63706378
const char *SDL_GetMenuItemLabel(SDL_MenuItem *menu_item)
63716379
{
63726380
CHECK_MENUITEM_MAGIC(menu_item, NULL);
6381+
6382+
if (menu_item->common.menu_bar->app_menu == menu_item ||
6383+
menu_item->common.type == SDL_MENUITEM_MENUBAR) {
6384+
return "";
6385+
}
6386+
63736387
return menu_item->common.label;
63746388
}
63756389

63766390
bool SDL_SetMenuItemLabel(SDL_MenuItem *menu_item, const char *label)
63776391
{
63786392
CHECK_MENUITEM_MAGIC(menu_item, false);
6393+
6394+
if (menu_item->common.menu_bar->app_menu == menu_item) {
6395+
SDL_SetError("Cannot set a label on an app menu.");
6396+
return false;
6397+
}
6398+
6399+
if (menu_item->common.type == SDL_MENUITEM_MENUBAR) {
6400+
SDL_SetError("Cannot set a label on an SDL_MENUITEM_MENUBAR.");
6401+
return false;
6402+
}
6403+
63796404
if (_this->SetMenuItemLabel(menu_item, label)) {
63806405
if (menu_item->common.label) {
63816406
SDL_free((void*)menu_item->common.label);
@@ -6481,6 +6506,11 @@ bool SDL_DestroyMenuItem(SDL_MenuItem *menu_item)
64816506
}
64826507
}
64836508

6509+
// App Menus cannot be destroyed by the user, only their children can, so we can exit out here.
6510+
if (menu_item == menu_item->common.menu_bar->app_menu) {
6511+
return true;
6512+
}
6513+
64846514
if (!_this->DestroyMenuItem(menu_item)) {
64856515
SDL_SetError("Failed to destroy Menu Item");
64866516
return false;

src/video/cocoa/SDL_cocoavideo.m

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,18 @@ bool Cocoa_SetMenuItemEnabled(SDL_MenuItem *menu_item, bool enabled)
459459

460460
bool Cocoa_DestroyMenuItem(SDL_MenuItem *menu_item)
461461
{
462+
if (menu_item->common.type == SDL_MENUITEM_MENUBAR) {
463+
SDL_DestroyMenuItem(menu_item->menu_bar.app_menu);
464+
465+
// The abstract funtion above won't actually delete the app_menu, so take care of the
466+
// platform side of it here.
467+
Cocoa_DestroyMenuItem(menu_item->menu_bar.app_menu);
468+
469+
// And now we're safe to free the app_menu itself and NULL it out.
470+
SDL_free(menu_item->menu_bar.app_menu);
471+
menu_item->menu_bar.app_menu = NULL;
472+
}
473+
462474
PlatformMenuData* platform_data = CFBridgingRelease(menu_item->common.platform_data);
463475
menu_item->common.platform_data = NULL;
464476
PlatformMenuData* parent_platform_data = (__bridge PlatformMenuData*)(menu_item->common.parent->common.platform_data);

0 commit comments

Comments
 (0)