|
| 1 | +/* |
| 2 | + Simple DirectMedia Layer |
| 3 | + Copyright (C) 1997-2025 Sam Lantinga <[email protected]> |
| 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_progressbar.h" |
| 22 | +#include "SDL_internal.h" |
| 23 | + |
| 24 | +#include "SDL_dbus.h" |
| 25 | + |
| 26 | +#ifdef SDL_USE_LIBDBUS |
| 27 | + |
| 28 | +#include <unistd.h> |
| 29 | + |
| 30 | +#include "../unix/SDL_appid.h" |
| 31 | + |
| 32 | +#define UnityLauncherAPI_DBUS_INTERFACE "com.canonical.Unity.LauncherEntry" |
| 33 | +#define UnityLauncherAPI_DBUS_SIGNAL "Update" |
| 34 | + |
| 35 | +static char *GetDBUSObjectPath() |
| 36 | +{ |
| 37 | + char *app_id = SDL_strdup(SDL_GetAppID()); |
| 38 | + |
| 39 | + if (!app_id) { |
| 40 | + return NULL; |
| 41 | + } |
| 42 | + |
| 43 | + // Sanitize exe_name to make it a legal D-Bus path element |
| 44 | + for (char *p = app_id; *p; ++p) { |
| 45 | + if (!SDL_isalnum(*p)) { |
| 46 | + *p = '_'; |
| 47 | + } |
| 48 | + } |
| 49 | + |
| 50 | + // Ensure it starts with a letter or underscore |
| 51 | + if (!SDL_isalpha(app_id[0]) && app_id[0] != '_') { |
| 52 | + SDL_memmove(app_id + 1, app_id, SDL_strlen(app_id) + 1); |
| 53 | + app_id[0] = '_'; |
| 54 | + } |
| 55 | + |
| 56 | + // Create full path |
| 57 | + char path[1024]; |
| 58 | + SDL_snprintf(path, sizeof(path), "/org/libsdl/%s_%d", app_id, getpid()); |
| 59 | + |
| 60 | + SDL_free(app_id); |
| 61 | + |
| 62 | + return SDL_strdup(path); |
| 63 | +} |
| 64 | + |
| 65 | +static char *GetAppDesktopPath() |
| 66 | +{ |
| 67 | + const char *desktop_suffix = ".desktop"; |
| 68 | + const char *app_id = SDL_GetAppID(); |
| 69 | + const size_t desktop_path_total_length = SDL_strlen(app_id) + SDL_strlen(desktop_suffix) + 1; |
| 70 | + char *desktop_path = (char *)SDL_malloc(desktop_path_total_length); |
| 71 | + if (!desktop_path) { |
| 72 | + return NULL; |
| 73 | + } |
| 74 | + *desktop_path = '\0'; |
| 75 | + SDL_strlcat(desktop_path, app_id, desktop_path_total_length); |
| 76 | + SDL_strlcat(desktop_path, desktop_suffix, desktop_path_total_length); |
| 77 | + |
| 78 | + return desktop_path; |
| 79 | +} |
| 80 | + |
| 81 | +static int ShouldShowProgress(SDL_ProgressState progressState) |
| 82 | +{ |
| 83 | + if (progressState == SDL_PROGRESS_STATE_INVALID || |
| 84 | + progressState == SDL_PROGRESS_STATE_NONE) { |
| 85 | + return 0; |
| 86 | + } |
| 87 | + |
| 88 | + // Unity LauncherAPI only supports "normal" display of progress |
| 89 | + return 1; |
| 90 | +} |
| 91 | + |
| 92 | +bool DBUS_ApplyWindowProgress(SDL_VideoDevice *_this, SDL_Window *window) |
| 93 | +{ |
| 94 | + // Signal signature: |
| 95 | + // signal com.canonical.Unity.LauncherEntry.Update (in s app_uri, in a{sv} properties) |
| 96 | + |
| 97 | + SDL_DBusContext *dbus = SDL_DBus_GetContext(); |
| 98 | + |
| 99 | + if (!dbus || !dbus->session_conn) { |
| 100 | + return false; |
| 101 | + } |
| 102 | + |
| 103 | + char *objectPath = GetDBUSObjectPath(); |
| 104 | + if (!objectPath) { |
| 105 | + return false; |
| 106 | + } |
| 107 | + |
| 108 | + DBusMessage *msg = dbus->message_new_signal(objectPath, UnityLauncherAPI_DBUS_INTERFACE, UnityLauncherAPI_DBUS_SIGNAL); |
| 109 | + if (!msg) { |
| 110 | + SDL_free(objectPath); |
| 111 | + return false; |
| 112 | + } |
| 113 | + |
| 114 | + char *desktop_path = GetAppDesktopPath(); |
| 115 | + if (!desktop_path) { |
| 116 | + dbus->message_unref(msg); |
| 117 | + SDL_free(objectPath); |
| 118 | + return false; |
| 119 | + } |
| 120 | + |
| 121 | + const char *progress_visible_str = "progress-visible"; |
| 122 | + const char *progress_str = "progress"; |
| 123 | + int dbus_type_boolean_str = DBUS_TYPE_BOOLEAN; |
| 124 | + int dbus_type_double_str = DBUS_TYPE_DOUBLE; |
| 125 | + |
| 126 | + const int progress_visible = ShouldShowProgress(window->progress_state); |
| 127 | + double progress = (double)window->progress_value; |
| 128 | + |
| 129 | + DBusMessageIter args, props; |
| 130 | + dbus->message_iter_init_append(msg, &args); |
| 131 | + dbus->message_iter_append_basic(&args, DBUS_TYPE_STRING, &desktop_path); // Setup app_uri paramter |
| 132 | + dbus->message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{sv}", &props); // Setup properties parameter |
| 133 | + DBusMessageIter key_it, value_it; |
| 134 | + // Set progress visible property |
| 135 | + dbus->message_iter_open_container(&props, DBUS_TYPE_DICT_ENTRY, NULL, &key_it); |
| 136 | + dbus->message_iter_append_basic(&key_it, DBUS_TYPE_STRING, &progress_visible_str); // Append progress-visible key data |
| 137 | + dbus->message_iter_open_container(&key_it, DBUS_TYPE_VARIANT, (const char *)&dbus_type_boolean_str, &value_it); |
| 138 | + dbus->message_iter_append_basic(&value_it, DBUS_TYPE_BOOLEAN, &progress_visible); // Append progress-visible value data |
| 139 | + dbus->message_iter_close_container(&key_it, &value_it); |
| 140 | + dbus->message_iter_close_container(&props, &key_it); |
| 141 | + // Set progress value property |
| 142 | + dbus->message_iter_open_container(&props, DBUS_TYPE_DICT_ENTRY, NULL, &key_it); |
| 143 | + dbus->message_iter_append_basic(&key_it, DBUS_TYPE_STRING, &progress_str); // Append progress key data |
| 144 | + dbus->message_iter_open_container(&key_it, DBUS_TYPE_VARIANT, (const char *)&dbus_type_double_str, &value_it); |
| 145 | + dbus->message_iter_append_basic(&value_it, DBUS_TYPE_DOUBLE, &progress); // Append progress value data |
| 146 | + dbus->message_iter_close_container(&key_it, &value_it); |
| 147 | + dbus->message_iter_close_container(&props, &key_it); |
| 148 | + dbus->message_iter_close_container(&args, &props); |
| 149 | + |
| 150 | + dbus->connection_send(dbus->session_conn, msg, NULL); |
| 151 | + |
| 152 | + SDL_free(desktop_path); |
| 153 | + dbus->message_unref(msg); |
| 154 | + SDL_free(objectPath); |
| 155 | + |
| 156 | + return true; |
| 157 | +} |
| 158 | + |
| 159 | +#endif // SDL_USE_LIBDBUS |
0 commit comments