Finish code to connect to IBUS daemon
This commit is contained in:
parent
5b7c697dfe
commit
dca81589a7
97
glfw/dbus_glfw.c
vendored
97
glfw/dbus_glfw.c
vendored
@ -29,13 +29,17 @@
|
|||||||
#include "dbus_glfw.h"
|
#include "dbus_glfw.h"
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
report_error(DBusError *err, const char *msg) {
|
report_error(DBusError *err, const char *fmt, ...) {
|
||||||
const char *prefix = msg ? msg : "DBUS error occurred";
|
static char buf[1024];
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR, "%s: %s", prefix, err->message);
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
int n = vsnprintf(buf, sizeof(buf), fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
snprintf(buf + n, sizeof(buf), ". DBUS error: %s", err->message);
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "%s", buf);
|
||||||
dbus_error_free(err);
|
dbus_error_free(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GLFWbool
|
GLFWbool
|
||||||
glfw_dbus_init(_GLFWDBUSData *dbus) {
|
glfw_dbus_init(_GLFWDBUSData *dbus) {
|
||||||
DBusError err;
|
DBusError err;
|
||||||
@ -43,7 +47,7 @@ glfw_dbus_init(_GLFWDBUSData *dbus) {
|
|||||||
dbus_error_init(&err);
|
dbus_error_init(&err);
|
||||||
dbus->session_conn = dbus_bus_get_private(DBUS_BUS_SESSION, &err);
|
dbus->session_conn = dbus_bus_get_private(DBUS_BUS_SESSION, &err);
|
||||||
if (dbus_error_is_set(&err)) {
|
if (dbus_error_is_set(&err)) {
|
||||||
report_error(&err, "Failed to connect to DBUS system bus");
|
report_error(&err, "Failed to connect to DBUS session bus");
|
||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,7 +61,15 @@ glfw_dbus_connect_to(const char *path, const char* err_msg) {
|
|||||||
DBusConnection *ans = dbus_connection_open_private(path, &err);
|
DBusConnection *ans = dbus_connection_open_private(path, &err);
|
||||||
if (!ans) {
|
if (!ans) {
|
||||||
report_error(&err, err_msg);
|
report_error(&err, err_msg);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
dbus_error_free(&err);
|
||||||
|
dbus_connection_flush(ans);
|
||||||
|
if (!dbus_bus_register(ans, &err)) {
|
||||||
|
report_error(&err, err_msg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
dbus_connection_flush(ans);
|
||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,3 +87,78 @@ glfw_dbus_close_connection(DBusConnection *conn) {
|
|||||||
dbus_connection_close(conn);
|
dbus_connection_close(conn);
|
||||||
dbus_connection_unref(conn);
|
dbus_connection_unref(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GLFWbool
|
||||||
|
call_void_method(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, va_list ap) {
|
||||||
|
GLFWbool retval = GLFW_FALSE;
|
||||||
|
|
||||||
|
if (conn) {
|
||||||
|
DBusMessage *msg = dbus_message_new_method_call(node, path, interface, method);
|
||||||
|
if (msg) {
|
||||||
|
int firstarg = va_arg(ap, int);
|
||||||
|
if ((firstarg == DBUS_TYPE_INVALID) || dbus_message_append_args_valist(msg, firstarg, ap)) {
|
||||||
|
if (dbus_connection_send(conn, msg, NULL)) {
|
||||||
|
dbus_connection_flush(conn);
|
||||||
|
retval = GLFW_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dbus_message_unref(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWbool
|
||||||
|
glfw_dbus_call_void_method(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...) {
|
||||||
|
GLFWbool retval;
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, method);
|
||||||
|
retval = call_void_method(conn, node, path, interface, method, ap);
|
||||||
|
va_end(ap);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GLFWbool
|
||||||
|
call_method(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, va_list ap) {
|
||||||
|
GLFWbool retval = GLFW_FALSE;
|
||||||
|
|
||||||
|
if (conn) {
|
||||||
|
DBusMessage *msg = dbus_message_new_method_call(node, path, interface, method);
|
||||||
|
if (msg) {
|
||||||
|
int firstarg = va_arg(ap, int);
|
||||||
|
if ((firstarg == DBUS_TYPE_INVALID) || dbus_message_append_args_valist(msg, firstarg, ap)) {
|
||||||
|
DBusError err;
|
||||||
|
dbus_error_init(&err);
|
||||||
|
DBusMessage *reply = dbus_connection_send_with_reply_and_block(conn, msg, 300, &err);
|
||||||
|
if (reply) {
|
||||||
|
firstarg = va_arg(ap, int);
|
||||||
|
dbus_error_free(&err);
|
||||||
|
if ((firstarg == DBUS_TYPE_INVALID) || dbus_message_get_args_valist(reply, &err, firstarg, ap)) {
|
||||||
|
retval = GLFW_TRUE;
|
||||||
|
} else {
|
||||||
|
report_error(&err, "Failed to get reply args from DBUS method: %s on node: %s and interface: %s", method, node, interface);
|
||||||
|
}
|
||||||
|
dbus_message_unref(reply);
|
||||||
|
} else {
|
||||||
|
report_error(&err, "Failed to call DBUS method: %s on node: %s and interface: %s", method, node, interface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dbus_message_unref(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWbool
|
||||||
|
glfw_dbus_call_method(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...) {
|
||||||
|
GLFWbool retval;
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, method);
|
||||||
|
retval = call_method(conn, node, path, interface, method, ap);
|
||||||
|
va_end(ap);
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
3
glfw/dbus_glfw.h
vendored
3
glfw/dbus_glfw.h
vendored
@ -38,3 +38,6 @@ GLFWbool glfw_dbus_init(_GLFWDBUSData *dbus);
|
|||||||
void glfw_dbus_terminate(_GLFWDBUSData *dbus);
|
void glfw_dbus_terminate(_GLFWDBUSData *dbus);
|
||||||
DBusConnection* glfw_dbus_connect_to(const char *path, const char* err_msg);
|
DBusConnection* glfw_dbus_connect_to(const char *path, const char* err_msg);
|
||||||
void glfw_dbus_close_connection(DBusConnection *conn);
|
void glfw_dbus_close_connection(DBusConnection *conn);
|
||||||
|
GLFWbool glfw_dbus_call_void_method(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...);
|
||||||
|
GLFWbool
|
||||||
|
glfw_dbus_call_method(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...);
|
||||||
|
|||||||
88
glfw/ibus_glfw.c
vendored
88
glfw/ibus_glfw.c
vendored
@ -27,11 +27,25 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "ibus_glfw.h"
|
#include "ibus_glfw.h"
|
||||||
|
|
||||||
#define debug(...) if (_glfw.hints.init.debugKeyboard) printf(__VA_ARGS__);
|
#define debug(...) if (_glfw.hints.init.debugKeyboard) printf(__VA_ARGS__);
|
||||||
|
static const char IBUS_SERVICE[] = "org.freedesktop.IBus";
|
||||||
|
static const char IBUS_PATH[] = "/org/freedesktop/IBus";
|
||||||
|
static const char IBUS_INTERFACE[] = "org.freedesktop.IBus";
|
||||||
|
static const char IBUS_INPUT_INTERFACE[] = "org.freedesktop.IBus.InputContext";
|
||||||
|
enum Capabilities {
|
||||||
|
IBUS_CAP_PREEDIT_TEXT = 1 << 0,
|
||||||
|
IBUS_CAP_AUXILIARY_TEXT = 1 << 1,
|
||||||
|
IBUS_CAP_LOOKUP_TABLE = 1 << 2,
|
||||||
|
IBUS_CAP_FOCUS = 1 << 3,
|
||||||
|
IBUS_CAP_PROPERTY = 1 << 4,
|
||||||
|
IBUS_CAP_SURROUNDING_TEXT = 1 << 5
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static inline GLFWbool
|
static inline GLFWbool
|
||||||
has_env_var(const char *name, const char *val) {
|
has_env_var(const char *name, const char *val) {
|
||||||
@ -44,6 +58,13 @@ MIN(size_t a, size_t b) {
|
|||||||
return a < b ? a : b;
|
return a < b ? a : b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Connection handling {{{
|
||||||
|
static DBusHandlerResult
|
||||||
|
message_handler(DBusConnection *conn, DBusMessage *msg, void *user_data) {
|
||||||
|
_GLFWIBUSData *ibus = (_GLFWIBUSData*)user_data;
|
||||||
|
(void)ibus;
|
||||||
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
static inline const char*
|
static inline const char*
|
||||||
get_ibus_address_file_name(void) {
|
get_ibus_address_file_name(void) {
|
||||||
@ -95,13 +116,15 @@ get_ibus_address_file_name(void) {
|
|||||||
|
|
||||||
|
|
||||||
static inline const char*
|
static inline const char*
|
||||||
read_ibus_address(const char *address_file) {
|
read_ibus_address(_GLFWIBUSData *ibus) {
|
||||||
FILE *addr_file = fopen(address_file, "r");
|
|
||||||
static char buf[1024];
|
static char buf[1024];
|
||||||
|
struct stat s;
|
||||||
|
FILE *addr_file = fopen(ibus->address_file_name, "r");
|
||||||
if (!addr_file) {
|
if (!addr_file) {
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to open IBUS address file: %s with error: %s", address_file, strerror(errno));
|
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to open IBUS address file: %s with error: %s", ibus->address_file_name, strerror(errno));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
int stat_result = fstat(fileno(addr_file), &s);
|
||||||
GLFWbool found = GLFW_FALSE;
|
GLFWbool found = GLFW_FALSE;
|
||||||
while (fgets(buf, sizeof(buf), addr_file)) {
|
while (fgets(buf, sizeof(buf), addr_file)) {
|
||||||
if (strncmp(buf, "IBUS_ADDRESS=", sizeof("IBUS_ADDRESS=")-1) == 0) {
|
if (strncmp(buf, "IBUS_ADDRESS=", sizeof("IBUS_ADDRESS=")-1) == 0) {
|
||||||
@ -113,27 +136,61 @@ read_ibus_address(const char *address_file) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fclose(addr_file); addr_file = NULL;
|
fclose(addr_file); addr_file = NULL;
|
||||||
|
if (stat_result != 0) {
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to stat IBUS address file: %s with error: %s", ibus->address_file_name, strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ibus->address_file_mtime = s.st_mtime;
|
||||||
if (found) return buf + sizeof("IBUS_ADDRESS=") - 1;
|
if (found) return buf + sizeof("IBUS_ADDRESS=") - 1;
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Could not find IBUS_ADDRESS in %s", address_file);
|
_glfwInputError(GLFW_PLATFORM_ERROR, "Could not find IBUS_ADDRESS in %s", ibus->address_file_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GLFWbool
|
||||||
|
setup_connection(_GLFWIBUSData *ibus) {
|
||||||
|
const char *path = NULL;
|
||||||
|
const char *client_name = "GLFW_Application";
|
||||||
|
const char *address_file_name = get_ibus_address_file_name();
|
||||||
|
if (!address_file_name) return GLFW_FALSE;
|
||||||
|
free((void*)ibus->address_file_name);
|
||||||
|
ibus->address_file_name = strdup(address_file_name);
|
||||||
|
const char *address = read_ibus_address(ibus);
|
||||||
|
if (!address) return GLFW_FALSE;
|
||||||
|
free((void*)ibus->address);
|
||||||
|
ibus->address = strdup(address);
|
||||||
|
debug("Connecting to IBUS daemon for IME input management\n");
|
||||||
|
ibus->conn = glfw_dbus_connect_to(ibus->address, "Failed to connect to the IBUS daemon, with error");
|
||||||
|
if (!ibus->conn) return GLFW_FALSE;
|
||||||
|
if (!glfw_dbus_call_method(ibus->conn, IBUS_SERVICE, IBUS_PATH, IBUS_INTERFACE, "CreateInputContext",
|
||||||
|
DBUS_TYPE_STRING, &client_name, DBUS_TYPE_INVALID,
|
||||||
|
DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) return GLFW_FALSE;
|
||||||
|
free((void*)ibus->input_ctx_path);
|
||||||
|
ibus->input_ctx_path = strdup(path);
|
||||||
|
enum Capabilities caps = IBUS_CAP_FOCUS | IBUS_CAP_PREEDIT_TEXT;
|
||||||
|
if (!glfw_dbus_call_void_method(ibus->conn, IBUS_SERVICE, ibus->input_ctx_path, IBUS_INPUT_INTERFACE, "SetCapabilities", DBUS_TYPE_UINT32, &caps, DBUS_TYPE_INVALID)) return GLFW_FALSE;
|
||||||
|
|
||||||
|
dbus_connection_flush(ibus->conn);
|
||||||
|
dbus_bus_add_match(ibus->conn, "type='signal',interface='org.freedesktop.IBus.InputContext'", NULL);
|
||||||
|
|
||||||
|
DBusObjectPathVTable ibus_vtable = {.message_function = message_handler};
|
||||||
|
dbus_connection_try_register_object_path(ibus->conn, ibus->input_ctx_path, &ibus_vtable, ibus, NULL);
|
||||||
|
dbus_connection_flush(ibus->conn);
|
||||||
|
debug("Connected to IBUS daemon for IME input management\n");
|
||||||
|
ibus->ok = GLFW_TRUE;
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
glfw_connect_to_ibus(_GLFWIBUSData *ibus, _GLFWDBUSData *dbus) {
|
glfw_connect_to_ibus(_GLFWIBUSData *ibus, _GLFWDBUSData *dbus) {
|
||||||
if (ibus->ok) return;
|
if (ibus->inited) return;
|
||||||
|
ibus->inited = GLFW_TRUE;
|
||||||
if (!has_env_var("XMODIFIERS", "@im=ibus") && !has_env_var("GTK_IM_MODULE", "ibus") && !has_env_var("QT_IM_MODULE", "ibus")) 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)) {
|
if (!glfw_dbus_init(dbus)) {
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Cannot connect to IBUS as connection to DBUS session bus failed");
|
_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();
|
setup_connection(ibus);
|
||||||
if (!address_file_name) return;
|
|
||||||
const char *address = read_ibus_address(address_file_name);
|
|
||||||
if (!address) return;
|
|
||||||
ibus->conn = glfw_dbus_connect_to(address, "Failed to connect to the IBUS daemon, with error");
|
|
||||||
if (!ibus->conn) return;
|
|
||||||
ibus->ok = GLFW_TRUE;
|
|
||||||
debug("Connected to IBUS daemon for IME input management\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -142,5 +199,10 @@ glfw_ibus_terminate(_GLFWIBUSData *ibus) {
|
|||||||
glfw_dbus_close_connection(ibus->conn);
|
glfw_dbus_close_connection(ibus->conn);
|
||||||
ibus->conn = NULL;
|
ibus->conn = NULL;
|
||||||
}
|
}
|
||||||
|
#define F(x) if (ibus->x) { free((void*)ibus->x); ibus->x = NULL; }
|
||||||
|
F(input_ctx_path); F(address); F(address_file_name);
|
||||||
|
#undef F
|
||||||
|
|
||||||
ibus->ok = GLFW_FALSE;
|
ibus->ok = GLFW_FALSE;
|
||||||
}
|
}
|
||||||
|
// }}}
|
||||||
|
|||||||
4
glfw/ibus_glfw.h
vendored
4
glfw/ibus_glfw.h
vendored
@ -30,8 +30,10 @@
|
|||||||
#include "dbus_glfw.h"
|
#include "dbus_glfw.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
GLFWbool ok;
|
GLFWbool ok, inited;
|
||||||
|
time_t address_file_mtime;
|
||||||
DBusConnection *conn;
|
DBusConnection *conn;
|
||||||
|
const char *input_ctx_path, *address_file_name, *address;
|
||||||
} _GLFWIBUSData;
|
} _GLFWIBUSData;
|
||||||
|
|
||||||
void glfw_connect_to_ibus(_GLFWIBUSData *ibus, _GLFWDBUSData *dbus);
|
void glfw_connect_to_ibus(_GLFWIBUSData *ibus, _GLFWDBUSData *dbus);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user