#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(void)
{
char *app_id = SDL_strdup(SDL_GetAppID());
if (!app_id) {
return NULL;
}
for (char *p = app_id; *p; ++p) {
if (!SDL_isalnum(*p)) {
*p = '_';
}
}
if (!SDL_isalpha(app_id[0]) && app_id[0] != '_') {
app_id = SDL_realloc(app_id, SDL_strlen(app_id) + 2);
if (!app_id) {
return NULL;
}
SDL_memmove(app_id + 1, app_id, SDL_strlen(app_id) + 1);
app_id[0] = '_';
}
char *path;
if (SDL_asprintf(&path, "/org/libsdl/%s_%d", app_id, getpid()) < 0) {
path = NULL;
}
SDL_free(app_id);
return path;
}
static char *GetAppDesktopPath(void)
{
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;
}
return 1;
}
bool DBUS_ApplyWindowProgress(SDL_VideoDevice *_this, SDL_Window *window)
{
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";
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); dbus->message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{sv}", &props); DBusMessageIter key_it, value_it;
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); dbus->message_iter_open_container(&key_it, DBUS_TYPE_VARIANT, "b", &value_it);
dbus->message_iter_append_basic(&value_it, DBUS_TYPE_BOOLEAN, &progress_visible); dbus->message_iter_close_container(&key_it, &value_it);
dbus->message_iter_close_container(&props, &key_it);
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); dbus->message_iter_open_container(&key_it, DBUS_TYPE_VARIANT, "d", &value_it);
dbus->message_iter_append_basic(&value_it, DBUS_TYPE_DOUBLE, &progress); 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