Skip to content

Commit 13537b8

Browse files
author
Semphris
committed
Add basic Ubuntu Touch functions
This adds support for: - System theme - Sandbox detection - Platform detection - Writable directory (SDL_GetPrefPath)
1 parent b3f4eba commit 13537b8

File tree

12 files changed

+338
-1
lines changed

12 files changed

+338
-1
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2065,6 +2065,7 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
20652065
"${SDL3_SOURCE_DIR}/src/core/linux/SDL_evdev_capabilities.c"
20662066
"${SDL3_SOURCE_DIR}/src/core/linux/SDL_evdev_capabilities.h"
20672067
"${SDL3_SOURCE_DIR}/src/core/linux/SDL_threadprio.c"
2068+
"${SDL3_SOURCE_DIR}/src/core/linux/SDL_ubuntu_touch.c"
20682069
)
20692070

20702071
# src/core/unix/*.c is included in a generic if(UNIX) section, elsewhere.

docs/README-ubuntu-touch.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Ubuntu Touch / Lomiri
2+
3+
Ubuntu Touch being similar to Ubuntu desktop, most features should be supported
4+
out-of-the-box with SDL.
5+
6+
## Developing apps
7+
8+
Ubuntu Touch apps are developed using [Clickable](https://clickable-ut.dev/).
9+
10+
Clickable provides an SDL template. It is highly recommended to use the template
11+
as a starting point for both new and existing apps.
12+
13+
## Considerations
14+
15+
Ubuntu Touch is similar to the desktop version of Ubuntu, but presents some
16+
differences in behavior. Developers should be wary of the following:
17+
18+
### SDL_GetPrefPath
19+
20+
The only allowed writable folder is `~/.local/share/<appname>/`.
21+
`SDL_GetPrefPath` ignores its arguments and will always return that path on
22+
Ubuntu Touch. No changes are needed in apps.
23+
24+
### Video driver
25+
26+
Currently, [a bug](https://github.com/libsdl-org/SDL/issues/12247) forces SDL to
27+
use the Wayland driver on Ubuntu Touch. No changes are needed in apps.
28+
29+
### Extra functions
30+
31+
SDL provides `SDL_IsUbuntuTouch()` to differentiate between Ubuntu Touch and
32+
regular Unix, which can help if certain platform-specific tweaks are needed.

include/SDL3/SDL_system.h

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,8 @@ typedef enum SDL_Sandbox
653653
SDL_SANDBOX_UNKNOWN_CONTAINER,
654654
SDL_SANDBOX_FLATPAK,
655655
SDL_SANDBOX_SNAP,
656-
SDL_SANDBOX_MACOS
656+
SDL_SANDBOX_MACOS,
657+
SDL_SANDBOX_LOMIRI
657658
} SDL_Sandbox;
658659

659660
/**
@@ -831,6 +832,75 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetGDKDefaultUser(XUserHandle *outUserHandl
831832

832833
#endif
833834

835+
/*
836+
* Functions used only with Ubuntu Touch
837+
*/
838+
#ifdef SDL_PLATFORM_LINUX
839+
840+
/**
841+
* Detect whether the current platform is Ubuntu Touch.
842+
*
843+
* \returns true if the platform is Ubuntu Touch; false otherwise.
844+
*
845+
* \since This function is available since SDL 3.6.0.
846+
*/
847+
extern SDL_DECLSPEC bool SDLCALL SDL_IsUbuntuTouch(void);
848+
849+
/**
850+
* Gets the ID of the application on Ubuntu Touch, as reported in the manifest.
851+
*
852+
* This is often called the "App Name"; the human-readable name for an app is
853+
* called the "App Title".
854+
*
855+
* This string is needed by some low-level OS features to operate properly.
856+
*
857+
* \returns the ID string for the application on success or NULL on failure;
858+
* call SDL_GetError() for more information.
859+
*
860+
* \since This function is available since SDL 3.6.0.
861+
*
862+
* \sa SDL_IsUbuntuTouch
863+
* \sa SDL_GetUbuntuTouchAppHook
864+
* \sa SDL_GetUbuntuTouchAppVersion
865+
*/
866+
extern SDL_DECLSPEC const char *SDLCALL SDL_GetUbuntuTouchAppID(void);
867+
868+
/**
869+
* Gets the identifier for the specific hook which launched the current
870+
* executable, as reported in the manifest.
871+
*
872+
* This is relevant for application packages that ship multiple applications
873+
* with their desktop files; they will have the same app ID but will differ by
874+
* their hook.
875+
*
876+
* \returns the ID string for the application on success or NULL on failure;
877+
* call SDL_GetError() for more information.
878+
*
879+
* \since This function is available since SDL 3.6.0.
880+
*
881+
* \sa SDL_IsUbuntuTouch
882+
* \sa SDL_GetUbuntuTouchAppID
883+
* \sa SDL_GetUbuntuTouchAppVersion
884+
*/
885+
extern SDL_DECLSPEC const char *SDLCALL SDL_GetUbuntuTouchAppHook(void);
886+
887+
/**
888+
* Gets the version of the application on Ubuntu Touch, as reported in the
889+
* manifest.
890+
*
891+
* \returns the ID string for the application on success or NULL on failure;
892+
* call SDL_GetError() for more information.
893+
*
894+
* \since This function is available since SDL 3.6.0.
895+
*
896+
* \sa SDL_IsUbuntuTouch
897+
* \sa SDL_GetUbuntuTouchAppID
898+
* \sa SDL_GetUbuntuTouchAppHook
899+
*/
900+
extern SDL_DECLSPEC const char *SDLCALL SDL_GetUbuntuTouchAppVersion(void);
901+
902+
#endif
903+
834904
/* Ends C function definitions when using C++ */
835905
#ifdef __cplusplus
836906
}

src/SDL.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,16 @@ const char *SDL_GetAppMetadataProperty(const char *name)
172172
value = SDL_GetStringProperty(SDL_GetGlobalProperties(), name, NULL);
173173
}
174174
if (!value || !*value) {
175+
#ifdef SDL_PLATFORM_LINUX
176+
if (SDL_IsUbuntuTouch()) {
177+
if (SDL_strcmp(name, SDL_PROP_APP_METADATA_IDENTIFIER_STRING) == 0) {
178+
value = SDL_GetUbuntuTouchAppID();
179+
} else if (SDL_strcmp(name, SDL_PROP_APP_METADATA_VERSION_STRING) == 0) {
180+
value = SDL_GetUbuntuTouchAppVersion();
181+
}
182+
}
183+
#endif
184+
175185
if (SDL_strcmp(name, SDL_PROP_APP_METADATA_NAME_STRING) == 0) {
176186
value = "SDL Application";
177187
} else if (SDL_strcmp(name, SDL_PROP_APP_METADATA_TYPE_STRING) == 0) {
@@ -865,6 +875,12 @@ static SDL_Sandbox SDL_DetectSandbox(void)
865875
return SDL_SANDBOX_SNAP;
866876
}
867877

878+
/* Ubuntu Touch also supports Snap; check for classic sandboxing only if
879+
* Snap hasn't been detected. */
880+
if (SDL_getenv("LOMIRI_APPLICATION_ISOLATION") || SDL_getenv("CLICKABLE_DESKTOP_MODE")) {
881+
return SDL_SANDBOX_LOMIRI;
882+
}
883+
868884
if (access("/run/host/container-manager", F_OK) == 0) {
869885
return SDL_SANDBOX_UNKNOWN_CONTAINER;
870886
}

src/core/SDL_core_unsupported.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,13 @@ Sint32 JNI_OnLoad(JavaVM *vm, void *reserved)
195195
return 0x00010004; // JNI_VERSION_1_4
196196
}
197197
#endif
198+
199+
#ifndef SDL_PLATFORM_LINUX
200+
201+
SDL_DECLSPEC bool SDLCALL SDL_IsUbuntuTouch(void);
202+
bool SDL_IsUbuntuTouch(void)
203+
{
204+
return false;
205+
}
206+
207+
#endif

src/core/linux/SDL_system_theme.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "SDL_system_theme.h"
2525
#include "../../video/SDL_sysvideo.h"
2626

27+
#include <stdio.h>
2728
#include <unistd.h>
2829

2930
#define PORTAL_DESTINATION "org.freedesktop.portal.Desktop"
@@ -150,7 +151,55 @@ bool SDL_SystemTheme_Init(void)
150151
return true;
151152
}
152153

154+
SDL_SystemTheme UbuntuTouch_GetSystemTheme(void)
155+
{
156+
SDL_SystemTheme theme = SDL_SYSTEM_THEME_UNKNOWN;
157+
FILE *config_file = NULL;
158+
char *line = NULL;
159+
size_t line_alloc = 0;
160+
ssize_t line_size = 0;
161+
bool is_in_general_category = false;
162+
163+
// "Lomiri": Ubuntu Touch 20.04+
164+
// "Ubuntu": Ubuntu Touch 16.04
165+
config_file = fopen("/home/phablet/.config/lomiri-ui-toolkit/theme.ini", "r");
166+
if (!config_file) {
167+
config_file = fopen("/home/phablet/.config/ubuntu-ui-toolkit/theme.ini", "r");
168+
if (!config_file) {
169+
return SDL_SYSTEM_THEME_UNKNOWN;
170+
}
171+
}
172+
173+
while ((line_size = getline(&line, &line_alloc, config_file)) != -1) {
174+
if (line_size >= 1 && line[0] == '[') {
175+
is_in_general_category = SDL_strcmp(line, "[General]\n") == 0;
176+
} else if (is_in_general_category && SDL_strncmp(line, "theme=", 6) == 0) {
177+
if (SDL_strcmp(line, "theme=Lomiri.Components.Themes.SuruDark\n") == 0 ||
178+
SDL_strcmp(line, "theme=Ubuntu.Components.Themes.SuruDark\n") == 0) {
179+
theme = SDL_SYSTEM_THEME_DARK;
180+
} else if (SDL_strcmp(line, "theme=Lomiri.Components.Themes.Ambiance\n") == 0 ||
181+
SDL_strcmp(line, "theme=Ubuntu.Components.Themes.Ambiance\n") == 0) {
182+
theme = SDL_SYSTEM_THEME_LIGHT;
183+
} else {
184+
theme = SDL_SYSTEM_THEME_UNKNOWN;
185+
}
186+
}
187+
188+
free(line); // This should NOT be SDL_free()
189+
}
190+
191+
fclose(config_file);
192+
193+
return theme;
194+
}
195+
153196
SDL_SystemTheme SDL_SystemTheme_Get(void)
154197
{
198+
if (system_theme_data.theme == SDL_SYSTEM_THEME_UNKNOWN) {
199+
// TODO: Use inotify to watch for changes, so that the config file
200+
// doesn't need to be checked each time.
201+
return UbuntuTouch_GetSystemTheme();
202+
}
203+
155204
return system_theme_data.theme;
156205
}

src/core/linux/SDL_ubuntu_touch.c

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/*
2+
Simple DirectMedia Layer
3+
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4+
5+
This software is provided 'as-is', without any express or implied
6+
warranty. In no event will the authors be held liable for any damages
7+
arising from the use of this software.
8+
9+
Permission is granted to anyone to use this software for any purpose,
10+
including commercial applications, and to alter it and redistribute it
11+
freely, subject to the following restrictions:
12+
13+
1. The origin of this software must not be misrepresented; you must not
14+
claim that you wrote the original software. If you use this software
15+
in a product, an acknowledgment in the product documentation would be
16+
appreciated but is not required.
17+
2. Altered source versions must be plainly marked as such, and must not be
18+
misrepresented as being the original software.
19+
3. This notice may not be removed or altered from any source distribution.
20+
*/
21+
#include "SDL_internal.h"
22+
23+
#ifdef SDL_PLATFORM_LINUX
24+
#include <stdio.h>
25+
#include <unistd.h>
26+
27+
bool SDL_IsUbuntuTouch(void)
28+
{
29+
const char *xdg_session_desktop = SDL_getenv("XDG_SESSION_DESKTOP");
30+
31+
if (!xdg_session_desktop) {
32+
return false;
33+
}
34+
35+
return SDL_strcmp(xdg_session_desktop, "ubuntu-touch") == 0;
36+
}
37+
38+
#define UT_APPINFO_APPNAME 0
39+
#define UT_APPINFO_HOOKNAME 1
40+
#define UT_APPINFO_APPVERSION 2
41+
42+
static char **SDL_ubuntu_touch_get_app_info(void)
43+
{
44+
static char info[3][257];
45+
static bool set = false;
46+
char *it, *it2;
47+
48+
if (set) {
49+
return info;
50+
}
51+
52+
if (!SDL_IsUbuntuTouch()) {
53+
SDL_SetError("Not running under Ubuntu Touch");
54+
return NULL;
55+
}
56+
57+
// Format is <appname>_<hookname>_<version>, like myapp.myname_myapp_1.0.0.
58+
// None of those are allowed to have underscores.
59+
const char *app_id = SDL_getenv("APP_ID");
60+
61+
if (!app_id) {
62+
SDL_SetError("Environment variable 'APP_ID' not set by the OS");
63+
return NULL;
64+
}
65+
66+
it = SDL_strchr(app_id, '_');
67+
68+
if (!*it) {
69+
SDL_SetError("Malformed APP_ID");
70+
return NULL;
71+
}
72+
73+
it2 = SDL_strchr(it + 1, '_');
74+
75+
if (!*it2) {
76+
SDL_SetError("Malformed APP_ID");
77+
return NULL;
78+
}
79+
80+
if (SDL_snprintf(info[UT_APPINFO_APPNAME], sizeof(info[UT_APPINFO_APPNAME]), "%.*s", (int) (it - app_id) + 1, app_id) > 255) {
81+
SDL_SetError("APP_ID appname too long");
82+
return NULL;
83+
}
84+
85+
if (SDL_snprintf(info[UT_APPINFO_HOOKNAME], sizeof(info[UT_APPINFO_HOOKNAME]), "%.*s", (int) (it2 - it) + 1, it) > 255) {
86+
SDL_SetError("APP_ID hook name too long");
87+
return NULL;
88+
}
89+
90+
if (SDL_snprintf(info[UT_APPINFO_APPVERSION], sizeof(info[UT_APPINFO_APPVERSION]), "%s", it2) > 255) {
91+
SDL_SetError("APP_ID version too long");
92+
return NULL;
93+
}
94+
95+
set = true;
96+
return info;
97+
}
98+
99+
const char *SDL_GetUbuntuTouchAppID(void)
100+
{
101+
char **info = SDL_ubuntu_touch_get_app_info();
102+
103+
if (!info) {
104+
return NULL;
105+
}
106+
107+
// On Ubuntu Touch, the ID of the app is called the "app name", whereas the
108+
// human-readable name is called the "app title".
109+
return info[UT_APPINFO_APPNAME];
110+
}
111+
112+
const char *SDL_GetUbuntuTouchAppHook(void)
113+
{
114+
char **info = SDL_ubuntu_touch_get_app_info();
115+
116+
if (!info) {
117+
return NULL;
118+
}
119+
120+
return info[UT_APPINFO_HOOKNAME];
121+
}
122+
123+
const char *SDL_GetUbuntuTouchAppVersion(void)
124+
{
125+
char **info = SDL_ubuntu_touch_get_app_info();
126+
127+
if (!info) {
128+
return NULL;
129+
}
130+
131+
return info[UT_APPINFO_APPVERSION];
132+
}
133+
134+
#endif

src/dynapi/SDL_dynapi.sym

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,6 +1285,10 @@ SDL3_0.0.0 {
12851285
SDL_SetGPURenderStateStorageBuffers;
12861286
SDL_GDKSuspendRenderer;
12871287
SDL_GDKResumeRenderer;
1288+
SDL_IsUbuntuTouch;
1289+
SDL_GetUbuntuTouchAppID;
1290+
SDL_GetUbuntuTouchAppHook;
1291+
SDL_GetUbuntuTouchAppVersion;
12881292
# extra symbols go here (don't modify this line)
12891293
local: *;
12901294
};

src/dynapi/SDL_dynapi_overrides.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,3 +1311,7 @@
13111311
#define SDL_SetGPURenderStateStorageBuffers SDL_SetGPURenderStateStorageBuffers_REAL
13121312
#define SDL_GDKSuspendRenderer SDL_GDKSuspendRenderer_REAL
13131313
#define SDL_GDKResumeRenderer SDL_GDKResumeRenderer_REAL
1314+
#define SDL_IsUbuntuTouch SDL_IsUbuntuTouch_REAL
1315+
#define SDL_GetUbuntuTouchAppID SDL_GetUbuntuTouchAppID_REAL
1316+
#define SDL_GetUbuntuTouchAppHook SDL_GetUbuntuTouchAppHook_REAL
1317+
#define SDL_GetUbuntuTouchAppVersion SDL_GetUbuntuTouchAppVersion_REAL

src/dynapi/SDL_dynapi_procs.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,3 +1319,7 @@ SDL_DYNAPI_PROC(bool,SDL_SetGPURenderStateStorageTextures,(SDL_GPURenderState *a
13191319
SDL_DYNAPI_PROC(bool,SDL_SetGPURenderStateStorageBuffers,(SDL_GPURenderState *a,int b,SDL_GPUBuffer *const*c),(a,b,c),return)
13201320
SDL_DYNAPI_PROC(void,SDL_GDKSuspendRenderer,(SDL_Renderer *a),(a),)
13211321
SDL_DYNAPI_PROC(void,SDL_GDKResumeRenderer,(SDL_Renderer *a),(a),)
1322+
SDL_DYNAPI_PROC(bool,SDL_IsUbuntuTouch,(void),(),return)
1323+
SDL_DYNAPI_PROC(const char*,SDL_GetUbuntuTouchAppID,(void),(),return)
1324+
SDL_DYNAPI_PROC(const char*,SDL_GetUbuntuTouchAppHook,(void),(),return)
1325+
SDL_DYNAPI_PROC(const char*,SDL_GetUbuntuTouchAppVersion,(void),(),return)

0 commit comments

Comments
 (0)