mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-09-29 14:38: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(
|
sdl_sources(
|
||||||
"${SDL3_SOURCE_DIR}/src/core/linux/SDL_dbus.c"
|
"${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_system_theme.c"
|
||||||
|
"${SDL3_SOURCE_DIR}/src/core/linux/SDL_progressbar.c"
|
||||||
)
|
)
|
||||||
endif()
|
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
|
`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`.
|
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
|
### 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.
|
- 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 *, const char *), message_is_signal);
|
||||||
SDL_DBUS_SYM(dbus_bool_t (*)(DBusMessage *, const char *), message_has_path);
|
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 *, 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, ...), message_append_args);
|
||||||
SDL_DBUS_SYM(dbus_bool_t (*)(DBusMessage *, int, va_list), message_append_args_valist);
|
SDL_DBUS_SYM(dbus_bool_t (*)(DBusMessage *, int, va_list), message_append_args_valist);
|
||||||
SDL_DBUS_SYM(void (*)(DBusMessage *, DBusMessageIter *), message_iter_init_append);
|
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_is_signal)(DBusMessage *, const char *, const char *);
|
||||||
dbus_bool_t (*message_has_path)(DBusMessage *, 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_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)(DBusMessage *, int, ...);
|
||||||
dbus_bool_t (*message_append_args_valist)(DBusMessage *, int, va_list);
|
dbus_bool_t (*message_append_args_valist)(DBusMessage *, int, va_list);
|
||||||
void (*message_iter_init_append)(DBusMessage *, DBusMessageIter *);
|
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);
|
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)
|
static bool SDL_ContextNotSupported(const char *name)
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND
|
#ifdef SDL_VIDEO_DRIVER_WAYLAND
|
||||||
|
|
||||||
#include "../../core/linux/SDL_system_theme.h"
|
#include "../../core/linux/SDL_system_theme.h"
|
||||||
|
#include "../../core/linux/SDL_progressbar.h"
|
||||||
#include "../../events/SDL_events_c.h"
|
#include "../../events/SDL_events_c.h"
|
||||||
|
|
||||||
#include "SDL_waylandclipboard.h"
|
#include "SDL_waylandclipboard.h"
|
||||||
@@ -629,6 +630,9 @@ static SDL_VideoDevice *Wayland_CreateDevice(bool require_preferred_protocols)
|
|||||||
device->DestroyWindow = Wayland_DestroyWindow;
|
device->DestroyWindow = Wayland_DestroyWindow;
|
||||||
device->SetWindowHitTest = Wayland_SetWindowHitTest;
|
device->SetWindowHitTest = Wayland_SetWindowHitTest;
|
||||||
device->FlashWindow = Wayland_FlashWindow;
|
device->FlashWindow = Wayland_FlashWindow;
|
||||||
|
#ifdef SDL_USE_LIBDBUS
|
||||||
|
device->ApplyWindowProgress = DBUS_ApplyWindowProgress;
|
||||||
|
#endif // SDL_USE_LIBDBUS
|
||||||
device->HasScreenKeyboardSupport = Wayland_HasScreenKeyboardSupport;
|
device->HasScreenKeyboardSupport = Wayland_HasScreenKeyboardSupport;
|
||||||
device->ShowWindowSystemMenu = Wayland_ShowWindowSystemMenu;
|
device->ShowWindowSystemMenu = Wayland_ShowWindowSystemMenu;
|
||||||
device->SyncWindow = Wayland_SyncWindow;
|
device->SyncWindow = Wayland_SyncWindow;
|
||||||
|
@@ -25,6 +25,7 @@
|
|||||||
#include <unistd.h> // For getpid() and readlink()
|
#include <unistd.h> // For getpid() and readlink()
|
||||||
|
|
||||||
#include "../../core/linux/SDL_system_theme.h"
|
#include "../../core/linux/SDL_system_theme.h"
|
||||||
|
#include "../../core/linux/SDL_progressbar.h"
|
||||||
#include "../../events/SDL_keyboard_c.h"
|
#include "../../events/SDL_keyboard_c.h"
|
||||||
#include "../../events/SDL_mouse_c.h"
|
#include "../../events/SDL_mouse_c.h"
|
||||||
#include "../SDL_pixels_c.h"
|
#include "../SDL_pixels_c.h"
|
||||||
@@ -204,6 +205,9 @@ static SDL_VideoDevice *X11_CreateDevice(void)
|
|||||||
device->AcceptDragAndDrop = X11_AcceptDragAndDrop;
|
device->AcceptDragAndDrop = X11_AcceptDragAndDrop;
|
||||||
device->UpdateWindowShape = X11_UpdateWindowShape;
|
device->UpdateWindowShape = X11_UpdateWindowShape;
|
||||||
device->FlashWindow = X11_FlashWindow;
|
device->FlashWindow = X11_FlashWindow;
|
||||||
|
#ifdef SDL_USE_LIBDBUS
|
||||||
|
device->ApplyWindowProgress = DBUS_ApplyWindowProgress;
|
||||||
|
#endif // SDL_USE_LIBDBUS
|
||||||
device->ShowWindowSystemMenu = X11_ShowWindowSystemMenu;
|
device->ShowWindowSystemMenu = X11_ShowWindowSystemMenu;
|
||||||
device->SetWindowFocusable = X11_SetWindowFocusable;
|
device->SetWindowFocusable = X11_SetWindowFocusable;
|
||||||
device->SyncWindow = X11_SyncWindow;
|
device->SyncWindow = X11_SyncWindow;
|
||||||
|
Reference in New Issue
Block a user