Compare commits

...

4 Commits

Author SHA1 Message Date
Semphriss cb9cb26e5a
Merge de9ce9ea1a into 3a6f9e01f8 2025-06-22 22:59:10 -04:00
Mitch Cairns 3a6f9e01f8 Fixed Nintendo Switch thumbstick calibration 2025-06-22 15:26:49 -07:00
Sam Lantinga 038a3806eb Fixed Nintendo Switch Pro thumbstick calibration
Fixes https://github.com/libsdl-org/SDL/issues/13246
2025-06-21 19:55:05 -07:00
Semphris de9ce9ea1a Add basic Ubuntu Touch functions
This adds support for:
- System theme
- Sandbox detection
- Platform detection
2025-06-15 17:34:04 -04:00
12 changed files with 183 additions and 15 deletions

View File

@ -1811,6 +1811,7 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
sdl_sources(
"${SDL3_SOURCE_DIR}/src/core/linux/SDL_evdev_capabilities.c"
"${SDL3_SOURCE_DIR}/src/core/linux/SDL_threadprio.c"
"${SDL3_SOURCE_DIR}/src/core/linux/SDL_ubuntu_touch.c"
)
# src/core/unix/*.c is included in a generic if(UNIX) section, elsewhere.

View File

@ -0,0 +1,38 @@
# Ubuntu Touch / Lomiri
Ubuntu Touch being similar to Ubuntu desktop, most features should be supported
out-of-the-box with SDL.
## Developing apps
Ubuntu Touch apps are developed using [Clickable](https://clickable-ut.dev/).
Clickable provides an SDL template. It is highly recommended to use the template
as a starting point for both new and existing apps.
## Considerations
Ubuntu Touch is similar to the desktop version of Ubuntu, but presents some
differences in behavior. Developers should be wary of the following:
### SDL_GetPrefPath
The only allowed writable folder is `~/.local/share/<appname>/`, where
`<appname>` is the identifier string for the app. It can be found in the
`manifest.json` file under the key `"name"`, and usually looks like
`appname.yourname`.
A future version of SDL may change how `SDL_GetPrefPath` operates on Ubuntu
Touch to make it ignore its arguments and always choose the correct writable
folder. For future-proof-ness, using `SDL_GetPrefPath("", "<appname>")` as a
writable directory is a safe choice.
### Video driver
Currently, [a bug](https://github.com/libsdl-org/SDL/issues/12247) forces SDL to
use the Wayland driver on Ubuntu Touch. No changes are needed in apps.
### Extra functions
SDL provides `SDL_IsUbuntuTouch()` to differentiate between Ubuntu Touch and
regular Unix, which can help if certain platform-specific tweaks are needed.

View File

@ -631,7 +631,8 @@ typedef enum SDL_Sandbox
SDL_SANDBOX_UNKNOWN_CONTAINER,
SDL_SANDBOX_FLATPAK,
SDL_SANDBOX_SNAP,
SDL_SANDBOX_MACOS
SDL_SANDBOX_MACOS,
SDL_SANDBOX_LOMIRI
} SDL_Sandbox;
/**
@ -809,6 +810,22 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetGDKDefaultUser(XUserHandle *outUserHandl
#endif
/*
* Functions used only with Ubuntu Touch
*/
#ifdef SDL_PLATFORM_LINUX
/**
* Detect whether the current platform is Ubuntu Touch.
*
* \returns true if the platform is Ubuntu Touch; false otherwise.
*
* \since This function is available since SDL 3.4.0.
*/
extern SDL_DECLSPEC bool SDLCALL SDL_IsUbuntuTouch(void);
#endif
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}

View File

@ -806,6 +806,12 @@ static SDL_Sandbox SDL_DetectSandbox(void)
return SDL_SANDBOX_SNAP;
}
/* Ubuntu Touch also supports Snap; check for classic sandboxing only if
* Snap hasn't been detected. */
if (SDL_getenv("LOMIRI_APPLICATION_ISOLATION") || SDL_getenv("CLICKABLE_DESKTOP_MODE")) {
return SDL_SANDBOX_LOMIRI;
}
if (access("/run/host/container-manager", F_OK) == 0) {
return SDL_SANDBOX_UNKNOWN_CONTAINER;
}

View File

@ -211,3 +211,13 @@ Sint32 JNI_OnLoad(void *vm, void *reserved)
return -1; // JNI_ERR
}
#endif
#ifndef SDL_PLATFORM_LINUX
SDL_DECLSPEC bool SDLCALL SDL_IsUbuntuTouch(void);
bool SDL_IsUbuntuTouch(void)
{
return false;
}
#endif

View File

@ -24,6 +24,7 @@
#include "SDL_system_theme.h"
#include "../../video/SDL_sysvideo.h"
#include <stdio.h>
#include <unistd.h>
#define PORTAL_DESTINATION "org.freedesktop.portal.Desktop"
@ -150,7 +151,55 @@ incorrect_type:
return true;
}
SDL_SystemTheme UbuntuTouch_GetSystemTheme(void)
{
SDL_SystemTheme theme = SDL_SYSTEM_THEME_UNKNOWN;
FILE *config_file = NULL;
char *line = NULL;
size_t line_alloc = 0;
ssize_t line_size = 0;
bool is_in_general_category = false;
// "Lomiri": Ubuntu Touch 20.04+
// "Ubuntu": Ubuntu Touch 16.04
config_file = fopen("/home/phablet/.config/lomiri-ui-toolkit/theme.ini", "r");
if (!config_file) {
config_file = fopen("/home/phablet/.config/ubuntu-ui-toolkit/theme.ini", "r");
if (!config_file) {
return SDL_SYSTEM_THEME_UNKNOWN;
}
}
while ((line_size = getline(&line, &line_alloc, config_file)) != -1) {
if (line_size >= 1 && line[0] == '[') {
is_in_general_category = SDL_strcmp(line, "[General]\n") == 0;
} else if (is_in_general_category && SDL_strncmp(line, "theme=", 6) == 0) {
if (SDL_strcmp(line, "theme=Lomiri.Components.Themes.SuruDark\n") == 0 ||
SDL_strcmp(line, "theme=Ubuntu.Components.Themes.SuruDark\n") == 0) {
theme = SDL_SYSTEM_THEME_DARK;
} else if (SDL_strcmp(line, "theme=Lomiri.Components.Themes.Ambiance\n") == 0 ||
SDL_strcmp(line, "theme=Ubuntu.Components.Themes.Ambiance\n") == 0) {
theme = SDL_SYSTEM_THEME_LIGHT;
} else {
theme = SDL_SYSTEM_THEME_UNKNOWN;
}
}
free(line); // This should NOT be SDL_free()
}
fclose(config_file);
return theme;
}
SDL_SystemTheme SDL_SystemTheme_Get(void)
{
if (system_theme_data.theme == SDL_SYSTEM_THEME_UNKNOWN) {
// TODO: Use inotify to watch for changes, so that the config file
// doesn't need to be checked each time.
return UbuntuTouch_GetSystemTheme();
}
return system_theme_data.theme;
}

View File

@ -0,0 +1,32 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_PLATFORM_LINUX
#include <stdio.h>
#include <unistd.h>
bool SDL_IsUbuntuTouch(void)
{
return access("/etc/ubuntu-touch-session.d/", F_OK) == 0;
}
#endif

View File

@ -1254,6 +1254,7 @@ SDL3_0.0.0 {
SDL_SetAudioIterationCallbacks;
SDL_GetEventDescription;
SDL_PutAudioStreamDataNoCopy;
SDL_IsUbuntuTouch;
# extra symbols go here (don't modify this line)
local: *;
};

View File

@ -1279,3 +1279,4 @@
#define SDL_SetAudioIterationCallbacks SDL_SetAudioIterationCallbacks_REAL
#define SDL_GetEventDescription SDL_GetEventDescription_REAL
#define SDL_PutAudioStreamDataNoCopy SDL_PutAudioStreamDataNoCopy_REAL
#define SDL_IsUbuntuTouch SDL_IsUbuntuTouch_REAL

View File

@ -1287,3 +1287,4 @@ SDL_DYNAPI_PROC(bool,SDL_PutAudioStreamPlanarData,(SDL_AudioStream *a,const void
SDL_DYNAPI_PROC(bool,SDL_SetAudioIterationCallbacks,(SDL_AudioDeviceID a,SDL_AudioIterationCallback b,SDL_AudioIterationCallback c,void *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_GetEventDescription,(const SDL_Event *a,char *b,int c),(a,b,c),return)
SDL_DYNAPI_PROC(bool,SDL_PutAudioStreamDataNoCopy,(SDL_AudioStream *a,const void *b,int c,SDL_AudioStreamDataCompleteCallback d,void *e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(bool,SDL_IsUbuntuTouch,(void),(),return)

View File

@ -1109,14 +1109,17 @@ static Sint16 ApplyStickCalibration(SDL_DriverSwitch_Context *ctx, int nStick, i
{
sRawValue -= ctx->m_StickCalData[nStick].axis[nAxis].sCenter;
if (sRawValue > ctx->m_StickExtents[nStick].axis[nAxis].sMax) {
ctx->m_StickExtents[nStick].axis[nAxis].sMax = sRawValue;
if (sRawValue >= 0) {
if (sRawValue > ctx->m_StickExtents[nStick].axis[nAxis].sMax) {
ctx->m_StickExtents[nStick].axis[nAxis].sMax = sRawValue;
}
return (Sint16)HIDAPI_RemapVal(sRawValue, 0, ctx->m_StickExtents[nStick].axis[nAxis].sMax, 0, SDL_MAX_SINT16);
} else {
if (sRawValue < ctx->m_StickExtents[nStick].axis[nAxis].sMin) {
ctx->m_StickExtents[nStick].axis[nAxis].sMin = sRawValue;
}
return (Sint16)HIDAPI_RemapVal(sRawValue, ctx->m_StickExtents[nStick].axis[nAxis].sMin, 0, SDL_MIN_SINT16, 0);
}
if (sRawValue < ctx->m_StickExtents[nStick].axis[nAxis].sMin) {
ctx->m_StickExtents[nStick].axis[nAxis].sMin = sRawValue;
}
return (Sint16)HIDAPI_RemapVal(sRawValue, ctx->m_StickExtents[nStick].axis[nAxis].sMin, ctx->m_StickExtents[nStick].axis[nAxis].sMax, SDL_MIN_SINT16, SDL_MAX_SINT16);
}
static Sint16 ApplySimpleStickCalibration(SDL_DriverSwitch_Context *ctx, int nStick, int nAxis, Sint16 sRawValue)
@ -1126,14 +1129,17 @@ static Sint16 ApplySimpleStickCalibration(SDL_DriverSwitch_Context *ctx, int nSt
sRawValue -= usJoystickCenter;
if (sRawValue > ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax) {
ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax = sRawValue;
if (sRawValue >= 0) {
if (sRawValue > ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax) {
ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax = sRawValue;
}
return (Sint16)HIDAPI_RemapVal(sRawValue, 0, ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax, 0, SDL_MAX_SINT16);
} else {
if (sRawValue < ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin) {
ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin = sRawValue;
}
return (Sint16)HIDAPI_RemapVal(sRawValue, ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin, 0, SDL_MIN_SINT16, 0);
}
if (sRawValue < ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin) {
ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin = sRawValue;
}
return (Sint16)HIDAPI_RemapVal(sRawValue, ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin, ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax, SDL_MIN_SINT16, SDL_MAX_SINT16);
}
static Uint8 RemapButton(SDL_DriverSwitch_Context *ctx, Uint8 button)

View File

@ -647,6 +647,12 @@ bool SDL_VideoInit(const char *driver_name)
// Select the proper video driver
video = NULL;
#ifdef SDL_PLATFORM_LINUX
// https://github.com/libsdl-org/SDL/issues/12247
if (SDL_IsUbuntuTouch()) {
driver_name = "wayland";
}
#endif
if (!driver_name) {
driver_name = SDL_GetHint(SDL_HINT_VIDEO_DRIVER);
}