diff --git a/docs/README-migration.md b/docs/README-migration.md index d6e0b0731c..ad9bc6d436 100644 --- a/docs/README-migration.md +++ b/docs/README-migration.md @@ -782,10 +782,12 @@ The following hints have been removed: * SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING - SDL now properly handles the 0x406D1388 Exception if no debugger intercepts it, preventing its propagation. * SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4 - replaced with SDL_HINT_WINDOWS_CLOSE_ON_ALT_F4, defaulting to SDL_TRUE * SDL_HINT_XINPUT_USE_OLD_JOYSTICK_MAPPING +* SDL_HINT_APP_NAME - replaced by either using the appname param to SDL_SetAppMetadata() or setting SDL_PROP_APP_METADATA_NAME_STRING with SDL_SetAppMetadataProperty(). +* SDL_HINT_AUDIO_DEVICE_APP_NAME - replaced by either using the appname param to SDL_SetAppMetadata() or using SDL_PROP_APP_METADATA_NAME_STRING in SDL_SetAppMetadataWithProperties() * Renamed hints SDL_HINT_VIDEODRIVER and SDL_HINT_AUDIODRIVER to SDL_HINT_VIDEO_DRIVER and SDL_HINT_AUDIO_DRIVER * Renamed environment variables SDL_VIDEODRIVER and SDL_AUDIODRIVER to SDL_VIDEO_DRIVER and SDL_AUDIO_DRIVER -* The environment variables SDL_VIDEO_X11_WMCLASS and SDL_VIDEO_WAYLAND_WMCLASS have been removed and replaced with the unified hint SDL_HINT_APP_ID +* The environment variables SDL_VIDEO_X11_WMCLASS and SDL_VIDEO_WAYLAND_WMCLASS have been removed and replaced with app metadata (either use the appindentifier param to SDL_SetAppMetadata() or set SDL_PROP_APP_METADATA_IDENTIFIER_STRING with SDL_SetAppMetadataProperty()). The following hints have been renamed: * SDL_HINT_ALLOW_TOPMOST => SDL_HINT_WINDOW_ALLOW_TOPMOST diff --git a/include/SDL3/SDL_hints.h b/include/SDL3/SDL_hints.h index 51c629c4f6..c2412e4ba6 100644 --- a/include/SDL3/SDL_hints.h +++ b/include/SDL3/SDL_hints.h @@ -125,79 +125,6 @@ extern "C" { */ #define SDL_HINT_ANDROID_TRAP_BACK_BUTTON "SDL_ANDROID_TRAP_BACK_BUTTON" -/** - * A variable setting the app ID string. - * - * This string is used by desktop compositors to identify and group windows - * together, as well as match applications with associated desktop settings - * and icons. - * - * On Wayland this corresponds to the "app ID" window property and on X11 this - * corresponds to the WM_CLASS property. Windows inherit the value of this - * hint at creation time. Changing this hint after a window has been created - * will not change the app ID or class of existing windows. - * - * For *nix platforms, this string should be formatted in reverse-DNS notation - * and follow some basic rules to be valid: - * - * - The application ID must be composed of two or more elements separated by - * a period (.) character. - * - Each element must contain one or more of the alphanumeric characters - * (A-Z, a-z, 0-9) plus underscore (_) and hyphen (-) and must not start - * with a digit. Note that hyphens, while technically allowed, should not be - * used if possible, as they are not supported by all components that use - * the ID, such as D-Bus. For maximum compatibility, replace hyphens with an - * underscore. - * - The empty string is not a valid element (ie: your application ID may not - * start or end with a period and it is not valid to have two periods in a - * row). - * - The entire ID must be less than 255 characters in length. - * - * Examples of valid app ID strings: - * - * - org.MyOrg.MyApp - * - com.your_company.your_app - * - * Desktops such as GNOME and KDE require that the app ID string matches your - * application's .desktop file name (e.g. if the app ID string is - * 'org.MyOrg.MyApp', your application's .desktop file should be named - * 'org.MyOrg.MyApp.desktop'). - * - * If you plan to package your application in a container such as Flatpak, the - * app ID should match the name of your Flatpak container as well. - * - * If not set, SDL will attempt to use the application executable name. If the - * executable name cannot be retrieved, the generic string "SDL_App" will be - * used. - * - * This hint should be set before SDL is initialized. - * - * \since This hint is available since SDL 3.0.0. - */ -#define SDL_HINT_APP_ID "SDL_APP_ID" - -/** - * Specify an application name. - * - * This hint lets you specify the application name sent to the OS when - * required. For example, this will often appear in volume control applets for - * audio streams, and in lists of applications which are inhibiting the - * screensaver. You should use a string that describes your program ("My Game - * 2: The Revenge") - * - * Setting this to "" or leaving it unset will have SDL use a reasonable - * default: probably the application's name or "SDL Application" if SDL - * doesn't have any better information. - * - * Note that, for audio streams, this can be overridden with - * SDL_HINT_AUDIO_DEVICE_APP_NAME. - * - * This hint should be set before SDL is initialized. - * - * \since This hint is available since SDL 3.0.0. - */ -#define SDL_HINT_APP_NAME "SDL_APP_NAME" - /** * A variable controlling whether controllers used with the Apple TV generate * UI events. @@ -254,29 +181,6 @@ extern "C" { */ #define SDL_HINT_AUDIO_CATEGORY "SDL_AUDIO_CATEGORY" -/** - * Specify an application name for an audio device. - * - * Some audio backends (such as PulseAudio) allow you to describe your audio - * stream. Among other things, this description might show up in a system - * control panel that lets the user adjust the volume on specific audio - * streams instead of using one giant master volume slider. - * - * This hints lets you transmit that information to the OS. The contents of - * this hint are used while opening an audio device. You should use a string - * that describes your program ("My Game 2: The Revenge") - * - * Setting this to "" or leaving it unset will have SDL use a reasonable - * default: this will be the name set with SDL_HINT_APP_NAME, if that hint is - * set. Otherwise, it'll probably the application's name or "SDL Application" - * if SDL doesn't have any better information. - * - * This hint should be set before an audio device is opened. - * - * \since This hint is available since SDL 3.0.0. - */ -#define SDL_HINT_AUDIO_DEVICE_APP_NAME "SDL_AUDIO_DEVICE_APP_NAME" - /** * Specify an application icon name for an audio device. * diff --git a/include/SDL3/SDL_init.h b/include/SDL3/SDL_init.h index 18d5d8956d..5b12f77652 100644 --- a/include/SDL3/SDL_init.h +++ b/include/SDL3/SDL_init.h @@ -105,12 +105,18 @@ typedef Uint32 SDL_InitFlags; * call SDL_Quit() to force shutdown). If a subsystem is already loaded then * this call will increase the ref-count and return. * + * Consider reporting some basic metadata about your application before + * calling SDL_Init, using either SDL_SetAppMetadata() or + * SDL_SetAppMetadataProperty(). + * * \param flags subsystem initialization flags. * \returns 0 on success or a negative error code on failure; call * SDL_GetError() for more information. * * \since This function is available since SDL 3.0.0. * + * \sa SDL_SetAppMetadata + * \sa SDL_SetAppMetadataProperty * \sa SDL_InitSubSystem * \sa SDL_Quit * \sa SDL_SetMainReady @@ -182,6 +188,124 @@ extern SDL_DECLSPEC SDL_InitFlags SDLCALL SDL_WasInit(SDL_InitFlags flags); */ extern SDL_DECLSPEC void SDLCALL SDL_Quit(void); +/** + * Specify basic metadata about your app. + * + * You can optionally provide metadata about your app to SDL. This is not + * required, but strongly encouraged. + * + * There are several locations where SDL can make use of metadata (an "About" + * box in the macOS menu bar, the name of the app can be shown on some audio + * mixers, etc). Any piece of metadata can be left as NULL, if a specific detail + * doesn't make sense for the app. + * + * This function should be called as early as possible, before SDL_Init. + * Multiple calls to this function are allowed, but various state might not + * change once it has been set up with a previous call to this function. + * + * Passing a NULL removes any previous metadata. + * + * This is a simplified interface for the most important information. You can + * supply significantly more detailed metadata with SDL_SetAppMetadataProperty(). + * + * \param appname The name of the application ("My Game 2: Bad Guy's Revenge!"). + * \param appversion The version of the application ("1.0.0beta5" or a git hash, or whatever makes sense). + * \param appidentifier A unique string in reverse-domain format that identifies this app ("com.example.mygame2"). + * \returns 0 on success or a negative error code on failure; call + * SDL_GetError() for more information. + * + * \since This function is available since SDL 3.0.0. + * + * \threadsafety It is safe to call this function from any thread. + * + * \sa SDL_SetAppMetadataProperty + */ +extern SDL_DECLSPEC int SDLCALL SDL_SetAppMetadata(const char *appname, const char *appversion, const char *appidentifier); + +/** + * Specify metadata about your app through a set of properties. + * + * You can optionally provide metadata about your app to SDL. This is not + * required, but strongly encouraged. + * + * There are several locations where SDL can make use of metadata (an "About" + * box in the macOS menu bar, the name of the app can be shown on some audio + * mixers, etc). Any piece of metadata can be left out, if a specific detail + * doesn't make sense for the app. + * + * This function should be called as early as possible, before SDL_Init. + * Multiple calls to this function are allowed, but various state might not + * change once it has been set up with a previous call to this function. + * + * Once set, this metadata can be read using SDL_GetMetadataProperty(). + * + * These are the supported properties: + * + * - `SDL_PROP_APP_METADATA_NAME_STRING`: The human-readable name of + * the application, like "My Game 2: Bad Guy's Revenge!". This defaults to "SDL Application". + * - SDL_PROP_APP_METADATA_VERSION_STRING`: The version of the app that + * is running; there are no rules on format, so "1.0.3beta2" and + * "April 22nd, 2024" and a git hash are all valid options. This has no default. + * - `SDL_PROP_APP_METADATA_IDENTIFIER_STRING`: A unique string that + * identifies this app. This must be in reverse-domain format, like + * "com.example.mygame2". This string is used by desktop compositors to + * identify and group windows together, as well as match applications + * with associated desktop settings and icons. This has no default. + * - SDL_PROP_APP_METADATA_CREATOR_STRING`: The human-readable name + * of the creator/developer/maker of this app, like "MojoWorkshop, LLC" + * - SDL_PROP_APP_METADATA_COPYRIGHT_STRING`: The human-readable copyright + * notice, like "Copyright (c) 2024 MojoWorkshop, LLC" or whatnot. Keep + * this to one line, don't paste a copy of a whole software license in + * here. This has no default. + * - SDL_PROP_APP_METADATA_URL_STRING`: A URL to the app on the web. Maybe + * a product page, or a storefront, or even a GitHub repository, for + * user's further information This has no default. + * - SDL_PROP_APP_METADATA_TYPE_STRING`: The type of application this is. + * Currently this string can be "game" for a video game, "mediaplayer" for + * a media player, or generically "application" if nothing else applies. + * Future versions of SDL might add new types. This defaults to "application". + * + * \param name the name of the metadata property to set. + * \param value the value of the property, or NULL to remove that property. + * \returns 0 on success or a negative error code on failure; call + * SDL_GetError() for more information. + * + * \since This function is available since SDL 3.0.0. + * + * \threadsafety It is safe to call this function from any thread. + * + * \sa SDL_GetAppMetadataProperty + * \sa SDL_SetAppMetadata + */ +extern SDL_DECLSPEC int SDLCALL SDL_SetAppMetadataProperty(const char *name, const char *value); + +#define SDL_PROP_APP_METADATA_NAME_STRING "SDL.app.metadata.name" +#define SDL_PROP_APP_METADATA_VERSION_STRING "SDL.app.metadata.version" +#define SDL_PROP_APP_METADATA_IDENTIFIER_STRING "SDL.app.metadata.identifier" +#define SDL_PROP_APP_METADATA_CREATOR_STRING "SDL.app.metadata.creator" +#define SDL_PROP_APP_METADATA_COPYRIGHT_STRING "SDL.app.metadata.copyright" +#define SDL_PROP_APP_METADATA_URL_STRING "SDL.app.metadata.url" +#define SDL_PROP_APP_METADATA_TYPE_STRING "SDL.app.metadata.type" + +/** + * Get metadata about your app. + * + * This returns metadata previously set using SDL_SetAppMetadata() or SDL_SetAppMetadataProperty(). See SDL_SetAppMetadataProperty() for the list of available properties and their meanings. + * + * \param name the name of the metadata property to get. + * \returns the current value of the metadata property, or the default if it is not set, NULL for properties with no default. + * + * \since This function is available since SDL 3.0.0. + * + * \threadsafety It is safe to call this function from any thread, although + * the string returned is not protected and could potentially be + * freed if you call SDL_SetAppMetadataProperty() to set that property from another thread. + * + * \sa SDL_SetAppMetadata + * \sa SDL_SetAppMetadataProperty + */ +extern SDL_DECLSPEC const char * SDLCALL SDL_GetAppMetadataProperty(const char *name); + /* Ends C function definitions when using C++ */ #ifdef __cplusplus } diff --git a/src/SDL.c b/src/SDL.c index 848f897008..654647f653 100644 --- a/src/SDL.c +++ b/src/SDL.c @@ -107,6 +107,63 @@ SDL_NORETURN void SDL_ExitProcess(int exitcode) #endif } +/* App metadata */ + +int SDL_SetAppMetadata(const char *appname, const char *appversion, const char *appidentifier) +{ + SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_NAME_STRING, appname); + SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_VERSION_STRING, appversion); + SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_IDENTIFIER_STRING, appidentifier); + return 0; +} + +static SDL_bool SDL_ValidMetadataProperty(const char *name) +{ + if (!name || !*name) { + return SDL_FALSE; + } + + if (SDL_strcmp(name, SDL_PROP_APP_METADATA_NAME_STRING) == 0 || + SDL_strcmp(name, SDL_PROP_APP_METADATA_VERSION_STRING) == 0 || + SDL_strcmp(name, SDL_PROP_APP_METADATA_IDENTIFIER_STRING) == 0 || + SDL_strcmp(name, SDL_PROP_APP_METADATA_CREATOR_STRING) == 0 || + SDL_strcmp(name, SDL_PROP_APP_METADATA_COPYRIGHT_STRING) == 0 || + SDL_strcmp(name, SDL_PROP_APP_METADATA_URL_STRING) == 0 || + SDL_strcmp(name, SDL_PROP_APP_METADATA_TYPE_STRING) == 0) { + return SDL_TRUE; + } + return SDL_FALSE; +} + +int SDL_SetAppMetadataProperty(const char *name, const char *value) +{ + if (!SDL_ValidMetadataProperty(name)) { + return SDL_InvalidParamError("name"); + } + + return SDL_SetStringProperty(SDL_GetGlobalProperties(), name, value); +} + +const char *SDL_GetAppMetadataProperty(const char *name) +{ + if (!SDL_ValidMetadataProperty(name)) { + SDL_InvalidParamError("name"); + return NULL; + } + + const SDL_PropertiesID props = SDL_GetGlobalProperties(); + const char *value = SDL_GetStringProperty(props, name, NULL); + if (!value || !*value) { + if (SDL_strcmp(name, SDL_PROP_APP_METADATA_NAME_STRING) == 0) { + value = "SDL Application"; + } else if (SDL_strcmp(name, SDL_PROP_APP_METADATA_TYPE_STRING) == 0) { + value = "application"; + } + } + return value; +} + + /* The initialized subsystems */ #ifdef SDL_MAIN_NEEDED static SDL_bool SDL_MainIsReady = SDL_FALSE; diff --git a/src/audio/jack/SDL_jackaudio.c b/src/audio/jack/SDL_jackaudio.c index 1a15078c6b..d334fb3fc1 100644 --- a/src/audio/jack/SDL_jackaudio.c +++ b/src/audio/jack/SDL_jackaudio.c @@ -261,18 +261,10 @@ static void JACK_CloseDevice(SDL_AudioDevice *device) } } -// !!! FIXME: unify this (PulseAudio has a getAppName, Pipewire has a thing, etc +// !!! FIXME: unify this (PulseAudio has a getAppName, Pipewire has a thing, etc) static const char *GetJackAppName(void) { - const char *retval = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME); - if (retval && *retval) { - return retval; - } - retval = SDL_GetHint(SDL_HINT_APP_NAME); - if (retval && *retval) { - return retval; - } - return "SDL Application"; + return SDL_GetAppMetadataProperty(SDL_PROP_APP_METADATA_NAME_STRING); } static int JACK_OpenDevice(SDL_AudioDevice *device) diff --git a/src/audio/pipewire/SDL_pipewire.c b/src/audio/pipewire/SDL_pipewire.c index 272417aed0..c22269c8c0 100644 --- a/src/audio/pipewire/SDL_pipewire.c +++ b/src/audio/pipewire/SDL_pipewire.c @@ -1049,13 +1049,7 @@ static int PIPEWIRE_OpenDevice(SDL_AudioDevice *device) const int min_period = PW_MIN_SAMPLES * SPA_MAX(device->spec.freq / PW_BASE_CLOCK_RATE, 1); // Get the hints for the application name, icon name, stream name and role - app_name = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME); - if (!app_name || *app_name == '\0') { - app_name = SDL_GetHint(SDL_HINT_APP_NAME); - if (!app_name || *app_name == '\0') { - app_name = "SDL Application"; - } - } + app_name = SDL_GetAppMetadataProperty(SDL_PROP_APP_METADATA_NAME_STRING); icon_name = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_APP_ICON_NAME); if (!icon_name || *icon_name == '\0') { @@ -1063,7 +1057,7 @@ static int PIPEWIRE_OpenDevice(SDL_AudioDevice *device) } // App ID. Default to NULL if not available. - app_id = SDL_GetHint(SDL_HINT_APP_ID); + app_id = SDL_GetAppMetadataProperty(SDL_PROP_APP_METADATA_IDENTIFIER_STRING); stream_name = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_STREAM_NAME); if (!stream_name || *stream_name == '\0') { diff --git a/src/audio/pulseaudio/SDL_pulseaudio.c b/src/audio/pulseaudio/SDL_pulseaudio.c index b373ffb70d..1ba721ec46 100644 --- a/src/audio/pulseaudio/SDL_pulseaudio.c +++ b/src/audio/pulseaudio/SDL_pulseaudio.c @@ -264,34 +264,9 @@ static int load_pulseaudio_syms(void) return 0; } -static SDL_INLINE int squashVersion(const int major, const int minor, const int patch) -{ - return ((major & 0xFF) << 16) | ((minor & 0xFF) << 8) | (patch & 0xFF); -} - -// Workaround for older pulse: pa_context_new() must have non-NULL appname static const char *getAppName(void) { - const char *retval = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME); - if (retval && *retval) { - return retval; - } - retval = SDL_GetHint(SDL_HINT_APP_NAME); - if (retval && *retval) { - return retval; - } else { - const char *verstr = PULSEAUDIO_pa_get_library_version(); - retval = "SDL Application"; // the "oh well" default. - if (verstr) { - int maj, min, patch; - if (SDL_sscanf(verstr, "%d.%d.%d", &maj, &min, &patch) == 3) { - if (squashVersion(maj, min, patch) >= squashVersion(0, 9, 15)) { - retval = NULL; // 0.9.15+ handles NULL correctly. - } - } - } - } - return retval; + return SDL_GetAppMetadataProperty(SDL_PROP_APP_METADATA_NAME_STRING); } static void OperationStateChangeCallback(pa_operation *o, void *userdata) diff --git a/src/core/linux/SDL_dbus.c b/src/core/linux/SDL_dbus.c index 9e6a56b65e..15da60520f 100644 --- a/src/core/linux/SDL_dbus.c +++ b/src/core/linux/SDL_dbus.c @@ -495,11 +495,8 @@ SDL_bool SDL_DBus_ScreensaverInhibit(SDL_bool inhibit) const char *interface = "org.freedesktop.ScreenSaver"; if (inhibit) { - const char *app = SDL_GetHint(SDL_HINT_APP_NAME); + const char *app = SDL_GetAppMetadataProperty(SDL_PROP_APP_METADATA_NAME_STRING); const char *reason = SDL_GetHint(SDL_HINT_SCREENSAVER_INHIBIT_ACTIVITY_NAME); - if (!app || !app[0]) { - app = "My SDL application"; - } if (!reason || !reason[0]) { reason = default_inhibit_reason; } diff --git a/src/core/unix/SDL_appid.c b/src/core/unix/SDL_appid.c index eb4bb4b139..30eaf16999 100644 --- a/src/core/unix/SDL_appid.c +++ b/src/core/unix/SDL_appid.c @@ -59,8 +59,7 @@ const char *SDL_GetExeName(void) const char *SDL_GetAppID(void) { - /* Always check the hint, as it may have changed */ - const char *id_str = SDL_GetHint(SDL_HINT_APP_ID); + const char *id_str = SDL_GetAppMetadataProperty(SDL_PROP_APP_METADATA_NAME_STRING); if (!id_str) { /* If the hint isn't set, try to use the application's executable name */ diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 8d789ac741..299fb40380 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -158,6 +158,7 @@ SDL3_0.0.0 { SDL_GetAndroidInternalStoragePath; SDL_GetAndroidJNIEnv; SDL_GetAndroidSDKVersion; + SDL_GetAppMetadataProperty; SDL_GetAssertionHandler; SDL_GetAssertionReport; SDL_GetAudioDeviceChannelMap; @@ -694,6 +695,8 @@ SDL3_0.0.0 { SDL_SendGamepadEffect; SDL_SendJoystickEffect; SDL_SendJoystickVirtualSensorData; + SDL_SetAppMetadata; + SDL_SetAppMetadataProperty; SDL_SetAssertionHandler; SDL_SetAudioDeviceGain; SDL_SetAudioPostmixCallback; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 8a17b98052..6c7b6b158d 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -183,6 +183,7 @@ #define SDL_GetAndroidInternalStoragePath SDL_GetAndroidInternalStoragePath_REAL #define SDL_GetAndroidJNIEnv SDL_GetAndroidJNIEnv_REAL #define SDL_GetAndroidSDKVersion SDL_GetAndroidSDKVersion_REAL +#define SDL_GetAppMetadataProperty SDL_GetAppMetadataProperty_REAL #define SDL_GetAssertionHandler SDL_GetAssertionHandler_REAL #define SDL_GetAssertionReport SDL_GetAssertionReport_REAL #define SDL_GetAudioDeviceChannelMap SDL_GetAudioDeviceChannelMap_REAL @@ -719,6 +720,8 @@ #define SDL_SendGamepadEffect SDL_SendGamepadEffect_REAL #define SDL_SendJoystickEffect SDL_SendJoystickEffect_REAL #define SDL_SendJoystickVirtualSensorData SDL_SendJoystickVirtualSensorData_REAL +#define SDL_SetAppMetadata SDL_SetAppMetadata_REAL +#define SDL_SetAppMetadataProperty SDL_SetAppMetadataProperty_REAL #define SDL_SetAssertionHandler SDL_SetAssertionHandler_REAL #define SDL_SetAudioDeviceGain SDL_SetAudioDeviceGain_REAL #define SDL_SetAudioPostmixCallback SDL_SetAudioPostmixCallback_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index b93fe03451..1bdb1b0b62 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -203,6 +203,7 @@ SDL_DYNAPI_PROC(Uint32,SDL_GetAndroidExternalStorageState,(void),(),return) SDL_DYNAPI_PROC(const char*,SDL_GetAndroidInternalStoragePath,(void),(),return) SDL_DYNAPI_PROC(void*,SDL_GetAndroidJNIEnv,(void),(),return) SDL_DYNAPI_PROC(int,SDL_GetAndroidSDKVersion,(void),(),return) +SDL_DYNAPI_PROC(const char*,SDL_GetAppMetadataProperty,(const char *a),(a),return) SDL_DYNAPI_PROC(SDL_AssertionHandler,SDL_GetAssertionHandler,(void **a),(a),return) SDL_DYNAPI_PROC(const SDL_AssertData*,SDL_GetAssertionReport,(void),(),return) SDL_DYNAPI_PROC(int*,SDL_GetAudioDeviceChannelMap,(SDL_AudioDeviceID a, int *b),(a,b),return) @@ -730,6 +731,8 @@ SDL_DYNAPI_PROC(int,SDL_SendAndroidMessage,(Uint32 a, int b),(a,b),return) SDL_DYNAPI_PROC(int,SDL_SendGamepadEffect,(SDL_Gamepad *a, const void *b, int c),(a,b,c),return) SDL_DYNAPI_PROC(int,SDL_SendJoystickEffect,(SDL_Joystick *a, const void *b, int c),(a,b,c),return) SDL_DYNAPI_PROC(int,SDL_SendJoystickVirtualSensorData,(SDL_Joystick *a, SDL_SensorType b, Uint64 c, const float *d, int e),(a,b,c,d,e),return) +SDL_DYNAPI_PROC(int,SDL_SetAppMetadata,(const char *a, const char *b, const char *c),(a,b,c),return) +SDL_DYNAPI_PROC(int,SDL_SetAppMetadataProperty,(const char *a, const char *b),(a,b),return) SDL_DYNAPI_PROC(void,SDL_SetAssertionHandler,(SDL_AssertionHandler a, void *b),(a,b),) SDL_DYNAPI_PROC(int,SDL_SetAudioDeviceGain,(SDL_AudioDeviceID a, float b),(a,b),return) SDL_DYNAPI_PROC(int,SDL_SetAudioPostmixCallback,(SDL_AudioDeviceID a, SDL_AudioPostmixCallback b, void *c),(a,b,c),return) diff --git a/src/video/cocoa/SDL_cocoaevents.m b/src/video/cocoa/SDL_cocoaevents.m index 3ff9a2ee71..52790a92d4 100644 --- a/src/video/cocoa/SDL_cocoaevents.m +++ b/src/video/cocoa/SDL_cocoaevents.m @@ -362,12 +362,19 @@ static SDL3AppDelegate *appDelegate = nil; static NSString *GetApplicationName(void) { - NSString *appName; + NSString *appName = nil; + + const char *metaname = SDL_GetStringProperty(SDL_GetGlobalProperties(), SDL_PROP_APP_METADATA_NAME_STRING, NULL); + if (metaname && *metaname) { + appName = [NSString stringWithUTF8String:metaname]; + } /* Determine the application name */ - appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]; if (!appName) { - appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]; + appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]; + if (!appName) { + appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]; + } } if (![appName length]) { @@ -420,6 +427,10 @@ static void CreateApplicationMenus(void) /* Add menu items */ title = [@"About " stringByAppendingString:appName]; + + // !!! FIXME: Menu items can't take parameters, just a basic selector, so this should instead call a selector + // !!! FIXME: that itself calls -[NSApplication orderFrontStandardAboutPanelWithOptions:optionsDictionary], + // !!! FIXME: filling in that NSDictionary with SDL_GetAppMetadataProperty() [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; [appleMenu addItem:[NSMenuItem separatorItem]];