diff --git a/glfw/ibus_glfw.c b/glfw/ibus_glfw.c index 32cf731e3..7b205ada5 100644 --- a/glfw/ibus_glfw.c +++ b/glfw/ibus_glfw.c @@ -24,6 +24,7 @@ // //======================================================================== +#include #include #include @@ -33,12 +34,98 @@ static inline GLFWbool has_env_var(const char *name, const char *val) { const char *q = getenv(name); - return (q && strcmp(q, val)) ? GLFW_TRUE : GLFW_FALSE; + return (q && strcmp(q, val) == 0) ? GLFW_TRUE : GLFW_FALSE; } +static inline GLFWbool +MIN(size_t a, size_t b) { + return a < b ? a : b; +} + + +static inline const char* +get_ibus_address_file_name(void) { + const char *addr; + static char ans[PATH_MAX]; + addr = getenv("IBUS_ADDRESS"); + int offset = 0; + if (addr && addr[0]) { + memcpy(ans, addr, MIN(strlen(addr), sizeof(ans))); + return ans; + } + + const char *de = getenv("DISPLAY"); + if (!de || !de[0]) de = ":0.0"; + char *display = strdup(de); + const char *host = display; + char *disp_num = strrchr(display, ':'); + char *screen_num = strrchr(display, '.'); + + if (!disp_num) { + _glfwInputError(GLFW_PLATFORM_ERROR, "Could not get IBUS address file name as DISPLAY env var has no colon"); + free(display); + return NULL; + } + *disp_num = 0; + disp_num++; + if (screen_num) *screen_num = 0; + if (!*host) host = "unix"; + + memset(ans, 0, sizeof(ans)); + const char *conf_env = getenv("XDG_CONFIG_HOME"); + if (conf_env && conf_env[0]) { + offset = snprintf(ans, sizeof(ans), "%s", conf_env); + } else { + conf_env = getenv("HOME"); + if (!conf_env || !conf_env[0]) { + _glfwInputError(GLFW_PLATFORM_ERROR, "Could not get IBUS address file name as no HOME env var is set"); + free(display); + return NULL; + } + offset = snprintf(ans, sizeof(ans), "%s/.config", conf_env); + } + char *key = dbus_get_local_machine_id(); + snprintf(ans + offset, sizeof(ans) - offset, "/ibus/bus/%s-%s-%s", key, host, disp_num); + dbus_free(key); + free(display); + return ans; +} + + +static inline const char* +read_ibus_address(const char *address_file) { + FILE *addr_file = fopen(address_file, "r"); + static char buf[1024]; + if (!addr_file) { + _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to open IBUS address file: %s with error: %s", address_file, strerror(errno)); + return NULL; + } + GLFWbool found = GLFW_FALSE; + while (fgets(buf, sizeof(buf), addr_file)) { + if (strncmp(buf, "IBUS_ADDRESS=", sizeof("IBUS_ADDRESS=")-1) == 0) { + size_t sz = strlen(buf); + if (buf[sz-1] == '\n') buf[sz-1] = 0; + if (buf[sz-2] == '\r') buf[sz-2] = 0; + found = GLFW_TRUE; + break; + } + } + fclose(addr_file); addr_file = NULL; + if (found) return buf + sizeof("IBUS_ADDRESS=") - 1; + _glfwInputError(GLFW_PLATFORM_ERROR, "Could not find IBUS_ADDRESS in %s", address_file); + return NULL; +} + + void glfw_connect_to_ibus(_GLFWIBUSData *ibus, _GLFWDBUSData *dbus) { if (ibus->ok) return; if (!has_env_var("XMODIFIERS", "@im=ibus") && !has_env_var("GTK_IM_MODULE", "ibus") && !has_env_var("QT_IM_MODULE", "ibus")) return; - if (!glfw_dbus_init(dbus)) return; + if (!glfw_dbus_init(dbus)) { + _glfwInputError(GLFW_PLATFORM_ERROR, "Cannot connect to IBUS as connection to DBUS session bus failed"); + } + const char* address_file_name = get_ibus_address_file_name(); + if (!address_file_name) return; + const char *address = read_ibus_address(address_file_name); + if (!address) return; }