mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-09-29 06:28:29 +00:00
Add progress bar support for Linux
This commit is contained in:
@@ -1736,6 +1736,7 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
|
||||
sdl_sources(
|
||||
"${SDL3_SOURCE_DIR}/src/core/linux/SDL_dbus.c"
|
||||
"${SDL3_SOURCE_DIR}/src/core/linux/SDL_system_theme.c"
|
||||
"${SDL3_SOURCE_DIR}/src/core/linux/SDL_progressbar.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
|
@@ -59,6 +59,15 @@ encounter limitations or behavior that is different from other windowing systems
|
||||
`SDL_APP_ID` hint string, the desktop entry file name should match the application ID. For example, if your
|
||||
application ID is set to `org.my_org.sdl_app`, the desktop entry file should be named `org.my_org.sdl_app.desktop`.
|
||||
|
||||
### The application progress bar can't be set via ```SDL_SetWindowProgressState()``` or ```SDL_SetWindowProgressValue()```
|
||||
|
||||
- Only some Desktop Environemnts support the underlying API. Known compatible DEs: Unity, KDE
|
||||
- The underlying API requires a desktop entry file, aka a `.desktop` file.
|
||||
Please see the [Desktop Entry Specification](https://specifications.freedesktop.org/desktop-entry-spec/latest/) for
|
||||
more information on the format of this file. Note that if your application manually sets the application ID via the
|
||||
`SDL_APP_ID` hint string, the desktop entry file name should match the application ID. For example, if your
|
||||
application ID is set to `org.my_org.sdl_app`, the desktop entry file should be named `org.my_org.sdl_app.desktop`.
|
||||
|
||||
### Keyboard grabs don't work when running under XWayland
|
||||
|
||||
- On GNOME based desktops, the dconf setting `org/gnome/mutter/wayland/xwayland-allow-grabs` must be enabled.
|
||||
|
@@ -68,6 +68,7 @@ static bool LoadDBUSSyms(void)
|
||||
SDL_DBUS_SYM(dbus_bool_t (*)(DBusMessage *, const char *, const char *), message_is_signal);
|
||||
SDL_DBUS_SYM(dbus_bool_t (*)(DBusMessage *, const char *), message_has_path);
|
||||
SDL_DBUS_SYM(DBusMessage *(*)(const char *, const char *, const char *, const char *), message_new_method_call);
|
||||
SDL_DBUS_SYM(DBusMessage *(*)(const char *, const char *, const char *), message_new_signal);
|
||||
SDL_DBUS_SYM(dbus_bool_t (*)(DBusMessage *, int, ...), message_append_args);
|
||||
SDL_DBUS_SYM(dbus_bool_t (*)(DBusMessage *, int, va_list), message_append_args_valist);
|
||||
SDL_DBUS_SYM(void (*)(DBusMessage *, DBusMessageIter *), message_iter_init_append);
|
||||
|
@@ -67,6 +67,7 @@ typedef struct SDL_DBusContext
|
||||
dbus_bool_t (*message_is_signal)(DBusMessage *, const char *, const char *);
|
||||
dbus_bool_t (*message_has_path)(DBusMessage *, const char *);
|
||||
DBusMessage *(*message_new_method_call)(const char *, const char *, const char *, const char *);
|
||||
DBusMessage *(*message_new_signal)(const char *, const char *, const char *);
|
||||
dbus_bool_t (*message_append_args)(DBusMessage *, int, ...);
|
||||
dbus_bool_t (*message_append_args_valist)(DBusMessage *, int, va_list);
|
||||
void (*message_iter_init_append)(DBusMessage *, DBusMessageIter *);
|
||||
|
159
src/core/linux/SDL_progressbar.c
Normal file
159
src/core/linux/SDL_progressbar.c
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
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_progressbar.h"
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#include "SDL_dbus.h"
|
||||
|
||||
#ifdef SDL_USE_LIBDBUS
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../unix/SDL_appid.h"
|
||||
|
||||
#define UnityLauncherAPI_DBUS_INTERFACE "com.canonical.Unity.LauncherEntry"
|
||||
#define UnityLauncherAPI_DBUS_SIGNAL "Update"
|
||||
|
||||
static char *GetDBUSObjectPath()
|
||||
{
|
||||
char *app_id = SDL_strdup(SDL_GetAppID());
|
||||
|
||||
if (!app_id) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Sanitize exe_name to make it a legal D-Bus path element
|
||||
for (char *p = app_id; *p; ++p) {
|
||||
if (!SDL_isalnum(*p)) {
|
||||
*p = '_';
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure it starts with a letter or underscore
|
||||
if (!SDL_isalpha(app_id[0]) && app_id[0] != '_') {
|
||||
SDL_memmove(app_id + 1, app_id, SDL_strlen(app_id) + 1);
|
||||
app_id[0] = '_';
|
||||
}
|
||||
|
||||
// Create full path
|
||||
char path[1024];
|
||||
SDL_snprintf(path, sizeof(path), "/org/libsdl/%s_%d", app_id, getpid());
|
||||
|
||||
SDL_free(app_id);
|
||||
|
||||
return SDL_strdup(path);
|
||||
}
|
||||
|
||||
static char *GetAppDesktopPath()
|
||||
{
|
||||
const char *desktop_suffix = ".desktop";
|
||||
const char *app_id = SDL_GetAppID();
|
||||
const size_t desktop_path_total_length = SDL_strlen(app_id) + SDL_strlen(desktop_suffix) + 1;
|
||||
char *desktop_path = (char *)SDL_malloc(desktop_path_total_length);
|
||||
if (!desktop_path) {
|
||||
return NULL;
|
||||
}
|
||||
*desktop_path = '\0';
|
||||
SDL_strlcat(desktop_path, app_id, desktop_path_total_length);
|
||||
SDL_strlcat(desktop_path, desktop_suffix, desktop_path_total_length);
|
||||
|
||||
return desktop_path;
|
||||
}
|
||||
|
||||
static int ShouldShowProgress(SDL_ProgressState progressState)
|
||||
{
|
||||
if (progressState == SDL_PROGRESS_STATE_INVALID ||
|
||||
progressState == SDL_PROGRESS_STATE_NONE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Unity LauncherAPI only supports "normal" display of progress
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool DBUS_ApplyWindowProgress(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
// Signal signature:
|
||||
// signal com.canonical.Unity.LauncherEntry.Update (in s app_uri, in a{sv} properties)
|
||||
|
||||
SDL_DBusContext *dbus = SDL_DBus_GetContext();
|
||||
|
||||
if (!dbus || !dbus->session_conn) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char *objectPath = GetDBUSObjectPath();
|
||||
if (!objectPath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DBusMessage *msg = dbus->message_new_signal(objectPath, UnityLauncherAPI_DBUS_INTERFACE, UnityLauncherAPI_DBUS_SIGNAL);
|
||||
if (!msg) {
|
||||
SDL_free(objectPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
char *desktop_path = GetAppDesktopPath();
|
||||
if (!desktop_path) {
|
||||
dbus->message_unref(msg);
|
||||
SDL_free(objectPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *progress_visible_str = "progress-visible";
|
||||
const char *progress_str = "progress";
|
||||
int dbus_type_boolean_str = DBUS_TYPE_BOOLEAN;
|
||||
int dbus_type_double_str = DBUS_TYPE_DOUBLE;
|
||||
|
||||
const int progress_visible = ShouldShowProgress(window->progress_state);
|
||||
double progress = (double)window->progress_value;
|
||||
|
||||
DBusMessageIter args, props;
|
||||
dbus->message_iter_init_append(msg, &args);
|
||||
dbus->message_iter_append_basic(&args, DBUS_TYPE_STRING, &desktop_path); // Setup app_uri paramter
|
||||
dbus->message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{sv}", &props); // Setup properties parameter
|
||||
DBusMessageIter key_it, value_it;
|
||||
// Set progress visible property
|
||||
dbus->message_iter_open_container(&props, DBUS_TYPE_DICT_ENTRY, NULL, &key_it);
|
||||
dbus->message_iter_append_basic(&key_it, DBUS_TYPE_STRING, &progress_visible_str); // Append progress-visible key data
|
||||
dbus->message_iter_open_container(&key_it, DBUS_TYPE_VARIANT, (const char *)&dbus_type_boolean_str, &value_it);
|
||||
dbus->message_iter_append_basic(&value_it, DBUS_TYPE_BOOLEAN, &progress_visible); // Append progress-visible value data
|
||||
dbus->message_iter_close_container(&key_it, &value_it);
|
||||
dbus->message_iter_close_container(&props, &key_it);
|
||||
// Set progress value property
|
||||
dbus->message_iter_open_container(&props, DBUS_TYPE_DICT_ENTRY, NULL, &key_it);
|
||||
dbus->message_iter_append_basic(&key_it, DBUS_TYPE_STRING, &progress_str); // Append progress key data
|
||||
dbus->message_iter_open_container(&key_it, DBUS_TYPE_VARIANT, (const char *)&dbus_type_double_str, &value_it);
|
||||
dbus->message_iter_append_basic(&value_it, DBUS_TYPE_DOUBLE, &progress); // Append progress value data
|
||||
dbus->message_iter_close_container(&key_it, &value_it);
|
||||
dbus->message_iter_close_container(&props, &key_it);
|
||||
dbus->message_iter_close_container(&args, &props);
|
||||
|
||||
dbus->connection_send(dbus->session_conn, msg, NULL);
|
||||
|
||||
SDL_free(desktop_path);
|
||||
dbus->message_unref(msg);
|
||||
SDL_free(objectPath);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // SDL_USE_LIBDBUS
|
30
src/core/linux/SDL_progressbar.h
Normal file
30
src/core/linux/SDL_progressbar.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef SDL_prograssbar_h_
|
||||
#define SDL_prograssbar_h_
|
||||
|
||||
#include "../../video/SDL_sysvideo.h"
|
||||
#include "SDL_internal.h"
|
||||
|
||||
extern bool DBUS_ApplyWindowProgress(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
|
||||
#endif // SDL_prograssbar_h_
|
@@ -2266,6 +2266,12 @@ static void SDL_FinishWindowCreation(SDL_Window *window, SDL_WindowFlags flags)
|
||||
SDL_ShowWindow(window);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(SDL_PLATFORM_LINUX)
|
||||
// On Linux the progress state is persisted throughout multiple program runs, so reset state on window creation
|
||||
SDL_SetWindowProgressState(window, SDL_PROGRESS_STATE_NONE);
|
||||
SDL_SetWindowProgressValue(window, 0.0f);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool SDL_ContextNotSupported(const char *name)
|
||||
|
@@ -24,6 +24,7 @@
|
||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND
|
||||
|
||||
#include "../../core/linux/SDL_system_theme.h"
|
||||
#include "../../core/linux/SDL_progressbar.h"
|
||||
#include "../../events/SDL_events_c.h"
|
||||
|
||||
#include "SDL_waylandclipboard.h"
|
||||
@@ -629,6 +630,9 @@ static SDL_VideoDevice *Wayland_CreateDevice(bool require_preferred_protocols)
|
||||
device->DestroyWindow = Wayland_DestroyWindow;
|
||||
device->SetWindowHitTest = Wayland_SetWindowHitTest;
|
||||
device->FlashWindow = Wayland_FlashWindow;
|
||||
#ifdef SDL_USE_LIBDBUS
|
||||
device->ApplyWindowProgress = DBUS_ApplyWindowProgress;
|
||||
#endif // SDL_USE_LIBDBUS
|
||||
device->HasScreenKeyboardSupport = Wayland_HasScreenKeyboardSupport;
|
||||
device->ShowWindowSystemMenu = Wayland_ShowWindowSystemMenu;
|
||||
device->SyncWindow = Wayland_SyncWindow;
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include <unistd.h> // For getpid() and readlink()
|
||||
|
||||
#include "../../core/linux/SDL_system_theme.h"
|
||||
#include "../../core/linux/SDL_progressbar.h"
|
||||
#include "../../events/SDL_keyboard_c.h"
|
||||
#include "../../events/SDL_mouse_c.h"
|
||||
#include "../SDL_pixels_c.h"
|
||||
@@ -204,6 +205,9 @@ static SDL_VideoDevice *X11_CreateDevice(void)
|
||||
device->AcceptDragAndDrop = X11_AcceptDragAndDrop;
|
||||
device->UpdateWindowShape = X11_UpdateWindowShape;
|
||||
device->FlashWindow = X11_FlashWindow;
|
||||
#ifdef SDL_USE_LIBDBUS
|
||||
device->ApplyWindowProgress = DBUS_ApplyWindowProgress;
|
||||
#endif // SDL_USE_LIBDBUS
|
||||
device->ShowWindowSystemMenu = X11_ShowWindowSystemMenu;
|
||||
device->SetWindowFocusable = X11_SetWindowFocusable;
|
||||
device->SyncWindow = X11_SyncWindow;
|
||||
|
Reference in New Issue
Block a user