From 5e8c055004a335cc24a7bf71aac6ba1f124bc518 Mon Sep 17 00:00:00 2001 From: GamesTrap Date: Sun, 5 Mar 2023 00:16:39 +0100 Subject: [PATCH] glfwSetWindowsTaskbarBadge() Added Linux implementation --- src/posix_dbus.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++ src/posix_dbus.h | 2 ++ src/wl_window.c | 7 ++-- src/x11_window.c | 7 ++-- 4 files changed, 103 insertions(+), 4 deletions(-) diff --git a/src/posix_dbus.c b/src/posix_dbus.c index dff557a9..d755ab48 100644 --- a/src/posix_dbus.c +++ b/src/posix_dbus.c @@ -220,3 +220,94 @@ void _glfwUpdateTaskbarProgressDBusPOSIX(dbus_bool_t progressVisible, double pro //Free the message dbus_message_unref(msg); } + +void _glfwUpdateTaskbarBadgeDBusPOSIX(dbus_bool_t badgeVisible, int badgeCount) +{ + if(!_glfw.dbus.handle || !_glfw.dbus.connection) + return; + + long long badgeCountLL = badgeCount; + + //Signal signature: + //signal com.canonical.Unity.LauncherEntry.Update (in s app_uri, in a{sv} properties) + + struct DBusMessageIter args; + memset(&args, 0, sizeof(args)); + + //Get name of the running executable + char exeName[PATH_MAX]; + memset(exeName, 0, sizeof(char) * PATH_MAX); + if(readlink("/proc/self/exe", exeName, PATH_MAX) == -1) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to get name of the running executable"); + return; + } + char* exeNameEnd = strchr(exeName, '\0'); + char* lastFound = strrchr(exeName, '/'); + if(!lastFound || !exeNameEnd) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to get name of the running executable"); + return; + } + unsigned int exeNameLength = (exeNameEnd - lastFound) - 1; + + //Create our final desktop file uri + unsigned int desktopFileLength = strlen("application://") + exeNameLength + strlen(".desktop") + 1; + char desktopFile[desktopFileLength]; + memset(desktopFile, 0, sizeof(char) * desktopFileLength); + strcpy(desktopFile, "application://"); + memcpy(desktopFile + strlen("application://"), lastFound + 1, exeNameLength); + strcpy(desktopFile + strlen("application://") + (exeNameLength), ".desktop"); + desktopFile[desktopFileLength - 1] = '\0'; + + DBusMessage* msg = dbus_message_new_signal("/org/glfw", "com.canonical.Unity.LauncherEntry", "Update"); + if(!msg) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to create new DBus message"); + return; + } + + dbus_message_iter_init_append(msg, &args); + + //Setup app_uri parameter + const char* desktopFileStr = desktopFile; + dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &desktopFileStr); + + //Set properties parameter + struct DBusMessageIter sub1, sub2, sub3; + memset(&sub1, 0, sizeof(sub1)); + memset(&sub2, 0, sizeof(sub2)); + memset(&sub3, 0, sizeof(sub3)); + + dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{sv}", &sub1); + + //Set count visible property + dbus_message_iter_open_container(&sub1, DBUS_TYPE_DICT_ENTRY, NULL, &sub2); + const char* countVisibleStr = "count-visible"; + dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &countVisibleStr); + dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "b", &sub3); + dbus_message_iter_append_basic(&sub3, DBUS_TYPE_BOOLEAN, &badgeVisible); + dbus_message_iter_close_container(&sub2, &sub3); + dbus_message_iter_close_container(&sub1, &sub2); + + //Set count value property + dbus_message_iter_open_container(&sub1, DBUS_TYPE_DICT_ENTRY, NULL, &sub2); + const char* countValueStr = "count"; + dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &countValueStr); + dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "x", &sub3); + dbus_message_iter_append_basic(&sub3, DBUS_TYPE_INT64, &badgeCountLL); + dbus_message_iter_close_container(&sub2, &sub3); + dbus_message_iter_close_container(&sub1, &sub2); + + dbus_message_iter_close_container(&args, &sub1); + + //Finally send the signal + unsigned int serial = 0; + if(!dbus_connection_send(_glfw.dbus.connection, msg, &serial)) + _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to send DBus message"); + else + dbus_connection_flush(_glfw.dbus.connection); + + //Free the message + dbus_message_unref(msg); +} \ No newline at end of file diff --git a/src/posix_dbus.h b/src/posix_dbus.h index 82d81bbb..887cbfd5 100644 --- a/src/posix_dbus.h +++ b/src/posix_dbus.h @@ -69,6 +69,7 @@ struct DBusMessageIter #define DBUS_TYPE_VARIANT (unsigned int)'v' #define DBUS_TYPE_BOOLEAN (unsigned int)'b' #define DBUS_TYPE_DOUBLE (unsigned int)'d' +#define DBUS_TYPE_INT64 (unsigned int)'x' typedef void (* PFN_dbus_error_init)(struct DBusError*); typedef dbus_bool_t (* PFN_dbus_error_is_set)(const struct DBusError*); @@ -130,3 +131,4 @@ typedef struct _GLFWDBusPOSIX void _glfwInitDBusPOSIX(void); void _glfwTerminateDBusPOSIX(void); void _glfwUpdateTaskbarProgressDBusPOSIX(dbus_bool_t progressVisible, double progressValue); +void _glfwUpdateTaskbarBadgeDBusPOSIX(dbus_bool_t badgeVisible, int badgeCount); diff --git a/src/wl_window.c b/src/wl_window.c index b91fd8f5..246e392e 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -1913,8 +1913,11 @@ void _glfwSetWindowTaskbarProgressWayland(_GLFWwindow* window, const int progres void _glfwSetWindowTaskbarBadgeWayland(_GLFWwindow* window, int count) { - _glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, - "Wayland: Setting the taskbar progress badge is not implemented"); + (void)window; + + const dbus_bool_t badgeVisible = (count != GLFW_DONT_CARE); + + _glfwUpdateTaskbarBadgeDBusPOSIX(badgeVisible, count); } void _glfwGetWindowPosWayland(_GLFWwindow* window, int* xpos, int* ypos) diff --git a/src/x11_window.c b/src/x11_window.c index 99e8a974..7ee61612 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -2163,8 +2163,11 @@ void _glfwSetWindowTaskbarProgressX11(_GLFWwindow* window, int progressState, do void _glfwSetWindowTaskbarBadgeX11(_GLFWwindow* window, int count) { - _glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, - "X11: Setting the taskbar progress badge is not implemented"); + (void)window; + + const dbus_bool_t badgeVisible = (count != GLFW_DONT_CARE); + + _glfwUpdateTaskbarBadgeDBusPOSIX(badgeVisible, count); } void _glfwGetWindowPosX11(_GLFWwindow* window, int* xpos, int* ypos)