Skip to content

Commit

Permalink
metadata: Added SDL_SetAppMetadata and SDL_SetAppMetadataWithProperties.
Browse files Browse the repository at this point in the history
Removed duplicate hints SDL_HINT_APP_NAME, SDL_HINT_APP_ID, and
SDL_HINT_AUDIO_DEVICE_APP_NAME.

Wired up a few things to use the metadata; more to come!

Fixes libsdl-org#4703.
  • Loading branch information
icculus committed Jul 28, 2024
1 parent 538adc5 commit 164928a
Show file tree
Hide file tree
Showing 14 changed files with 203 additions and 133 deletions.
4 changes: 3 additions & 1 deletion docs/README-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 using SDL_PROP_APP_METADATA_NAME_STRING in SDL_SetAppMetadataWithProperties()
* 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 SDL_PROP_APP_METADATA_IDENTIFIER_STRING in SDL_SetAppMetadataWithProperties()).

The following hints have been renamed:
* SDL_HINT_ALLOW_TOPMOST => SDL_HINT_WINDOW_ALLOW_TOPMOST
Expand Down
96 changes: 0 additions & 96 deletions include/SDL3/SDL_hints.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
*
Expand Down
106 changes: 106 additions & 0 deletions include/SDL3/SDL_init.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_SetAppMetadataWithProperties.
*
* \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_SetAppMetadataWithProperties
* \sa SDL_InitSubSystem
* \sa SDL_Quit
* \sa SDL_SetMainReady
Expand Down Expand Up @@ -182,6 +188,106 @@ 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_SetAppMetadataWithProperties.
*
* \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 This function is not thread-safe.
*
* \sa SDL_SetAppMetadataWithProperties
*/
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.
*
* Any previously set values not included in `props` will be removed.
* Passing a 0 for `props` removes all previous metadata.
*
* 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!"
* - 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.
* - `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.
* - 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.
* - 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.
* - 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.
*
* \param props the properties to use.
* \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 This function is not thread-safe.
*
* \sa SDL_SetAppMetadata
*/
extern SDL_DECLSPEC int SDLCALL SDL_SetAppMetadataWithProperties(SDL_PropertiesID props);

#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"

/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
Expand Down
49 changes: 49 additions & 0 deletions src/SDL.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,52 @@ SDL_NORETURN void SDL_ExitProcess(int exitcode)
#endif
}

/* App metadata */
static SDL_PropertiesID SDL_app_metadata_properties = 0;

int SDL_SetAppMetadata(const char *appname, const char *appversion, const char *appidentifier)
{
const SDL_PropertiesID props = SDL_CreateProperties();

if (appname && *appname) {
SDL_SetStringProperty(props, SDL_PROP_APP_METADATA_NAME_STRING, appname);
}
if (appversion && *appversion) {
SDL_SetStringProperty(props, SDL_PROP_APP_METADATA_VERSION_STRING, appversion);
}
if (appidentifier && *appidentifier) {
SDL_SetStringProperty(props, SDL_PROP_APP_METADATA_IDENTIFIER_STRING, appidentifier);
}

const int retval = SDL_SetAppMetadataWithProperties(props);
SDL_DestroyProperties(props);
return retval;
}

int SDL_SetAppMetadataWithProperties(SDL_PropertiesID props)
{
SDL_PropertiesID new_props = 0;
if (props) {
new_props = SDL_CreateProperties();
if (!new_props) {
return -1;
} else if (SDL_CopyProperties(props, new_props) < 0) {
SDL_DestroyProperties(new_props);
return -1;
}
}
SDL_DestroyProperties(SDL_app_metadata_properties);
SDL_app_metadata_properties = new_props;
return 0;
}

SDL_PropertiesID SDL_GetAppMetadata(void)
{
return SDL_app_metadata_properties;
}



/* The initialized subsystems */
#ifdef SDL_MAIN_NEEDED
static SDL_bool SDL_MainIsReady = SDL_FALSE;
Expand Down Expand Up @@ -571,6 +617,9 @@ void SDL_Quit(void)
SDL_DBus_Quit();
#endif

SDL_DestroyProperties(SDL_app_metadata_properties);
SDL_app_metadata_properties = 0;

SDL_SetObjectsInvalid();
SDL_ClearHints();
SDL_AssertionsQuit();
Expand Down
2 changes: 2 additions & 0 deletions src/SDL_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,8 @@ extern "C" {

#include "SDL_utils_c.h"

extern SDL_PropertiesID SDL_GetAppMetadata(void);

/* Do any initialization that needs to happen before threads are started */
extern void SDL_InitMainThread(void);

Expand Down
14 changes: 5 additions & 9 deletions src/audio/jack/SDL_jackaudio.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,18 +261,14 @@ 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;
const char *retval = SDL_GetStringProperty(SDL_GetAppMetadata(), SDL_PROP_APP_METADATA_NAME_STRING, NULL);
if (!retval || !*retval) {
retval = "SDL Application";
}
retval = SDL_GetHint(SDL_HINT_APP_NAME);
if (retval && *retval) {
return retval;
}
return "SDL Application";
return retval;
}

static int JACK_OpenDevice(SDL_AudioDevice *device)
Expand Down
10 changes: 4 additions & 6 deletions src/audio/pipewire/SDL_pipewire.c
Original file line number Diff line number Diff line change
Expand Up @@ -1049,12 +1049,10 @@ 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);
const SDL_PropertiesID metadata = SDL_GetAppMetadata();
app_name = SDL_GetStringProperty(metadata, SDL_PROP_APP_METADATA_NAME_STRING, NULL);
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 Application";
}

icon_name = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_APP_ICON_NAME);
Expand All @@ -1063,7 +1061,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_GetStringProperty(metadata, SDL_PROP_APP_METADATA_IDENTIFIER_STRING, NULL);

stream_name = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_STREAM_NAME);
if (!stream_name || *stream_name == '\0') {
Expand Down
Loading

0 comments on commit 164928a

Please sign in to comment.