Make the DBUS APIs async
This commit is contained in:
parent
78cda7aa74
commit
dd9e484336
106
glfw/dbus_glfw.c
vendored
106
glfw/dbus_glfw.c
vendored
@ -211,45 +211,93 @@ glfw_dbus_call_void_method(DBusConnection *conn, const char *node, const char *p
|
||||
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;
|
||||
GLFWbool
|
||||
glfw_dbus_get_args(DBusMessage *msg, const char *failmsg, ...) {
|
||||
DBusError err;
|
||||
dbus_error_init(&err);
|
||||
va_list ap;
|
||||
va_start(ap, failmsg);
|
||||
int firstarg = va_arg(ap, int);
|
||||
GLFWbool ret = dbus_message_get_args_valist(msg, &err, firstarg, ap) ? GLFW_TRUE : GLFW_FALSE;
|
||||
va_end(ap);
|
||||
if (!ret) report_error(&err, failmsg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
typedef struct {
|
||||
dbus_pending_callback callback;
|
||||
void *user_data;
|
||||
} MethodResponse;
|
||||
|
||||
static const char*
|
||||
format_message_error(DBusError *err) {
|
||||
static char buf[1024];
|
||||
snprintf(buf, sizeof(buf), "[%s] %s", err->name ? err->name : "", err->message);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void
|
||||
method_reply_received(DBusPendingCall *pending, void *user_data) {
|
||||
MethodResponse *res = (MethodResponse*)user_data;
|
||||
DBusMessage *msg = dbus_pending_call_steal_reply(pending);
|
||||
if (msg) {
|
||||
DBusError err;
|
||||
dbus_error_init(&err);
|
||||
if (dbus_set_error_from_message(&err, msg)) res->callback(NULL, format_message_error(&err), res->user_data);
|
||||
else res->callback(msg, NULL, res->user_data);
|
||||
dbus_message_unref(msg);
|
||||
}
|
||||
}
|
||||
|
||||
static GLFWbool
|
||||
call_method(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, dbus_pending_callback callback, void *user_data, va_list ap) {
|
||||
if (!conn) return GLFW_FALSE;
|
||||
DBusMessage *msg = dbus_message_new_method_call(node, path, interface, method);
|
||||
if (!msg) return GLFW_FALSE;
|
||||
GLFWbool retval = GLFW_FALSE;
|
||||
MethodResponse *res = malloc(sizeof(MethodResponse));
|
||||
if (!res) { dbus_message_unref(msg); return GLFW_FALSE; }
|
||||
res->callback = callback;
|
||||
res->user_data = user_data;
|
||||
|
||||
int firstarg = va_arg(ap, int);
|
||||
if ((firstarg == DBUS_TYPE_INVALID) || dbus_message_append_args_valist(msg, firstarg, ap)) {
|
||||
if (callback) {
|
||||
DBusPendingCall *pending = NULL;
|
||||
if (dbus_connection_send_with_reply(conn, msg, &pending, DBUS_TIMEOUT_USE_DEFAULT)) {
|
||||
dbus_pending_call_set_notify(pending, method_reply_received, res, free);
|
||||
} else {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to call DBUS method: %s on node: %s and interface: %s out of memory", method, node, interface);
|
||||
}
|
||||
} else {
|
||||
if (!dbus_connection_send(conn, msg, NULL)) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to call DBUS method: %s on node: %s and interface: %s out of memory", method, node, interface);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to call DBUS method: %s on node: %s and interface: %s could not add arguments", 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, ...) {
|
||||
glfw_dbus_call_method_with_reply(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, dbus_pending_callback callback, void* user_data, ...) {
|
||||
GLFWbool retval;
|
||||
va_list ap;
|
||||
va_start(ap, user_data);
|
||||
retval = call_method(conn, node, path, interface, method, callback, user_data, ap);
|
||||
va_end(ap);
|
||||
return retval;
|
||||
}
|
||||
|
||||
GLFWbool
|
||||
glfw_dbus_call_method_no_reply(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);
|
||||
retval = call_method(conn, node, path, interface, method, NULL, NULL, ap);
|
||||
va_end(ap);
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
7
glfw/dbus_glfw.h
vendored
7
glfw/dbus_glfw.h
vendored
@ -30,6 +30,8 @@
|
||||
#include <dbus/dbus.h>
|
||||
#include "backend_utils.h"
|
||||
|
||||
typedef void(*dbus_pending_callback)(DBusMessage *msg, const char* err, void* data);
|
||||
|
||||
typedef struct {
|
||||
EventLoopData* eld;
|
||||
} _GLFWDBUSData;
|
||||
@ -41,5 +43,8 @@ DBusConnection* glfw_dbus_connect_to(const char *path, const char* err_msg);
|
||||
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, ...);
|
||||
glfw_dbus_call_method_no_reply(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...);
|
||||
GLFWbool
|
||||
glfw_dbus_call_method_with_reply(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, dbus_pending_callback callback, void *user_data, ...);
|
||||
void glfw_dbus_dispatch(DBusConnection *);
|
||||
GLFWbool glfw_dbus_get_args(DBusMessage *msg, const char *failmsg, ...);
|
||||
|
||||
43
glfw/ibus_glfw.c
vendored
43
glfw/ibus_glfw.c
vendored
@ -153,11 +153,30 @@ read_ibus_address(_GLFWIBUSData *ibus) {
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
input_context_created(DBusMessage *msg, const char* errmsg, void *data) {
|
||||
if (errmsg) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "IBUS: Failed to create input context with error: %s", errmsg);
|
||||
return;
|
||||
}
|
||||
const char *path = NULL;
|
||||
if (!glfw_dbus_get_args(msg, "Failed to get IBUS context path from reply", DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) return;
|
||||
_GLFWIBUSData *ibus = (_GLFWIBUSData*)data;
|
||||
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_ibus_set_focused(ibus, GLFW_FALSE);
|
||||
set_cursor_geometry(ibus, 0, 0, 0, 0);
|
||||
debug("Connected to IBUS daemon for IME input management\n");
|
||||
ibus->ok = GLFW_TRUE;
|
||||
}
|
||||
|
||||
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();
|
||||
ibus->ok = GLFW_FALSE;
|
||||
if (!address_file_name) return GLFW_FALSE;
|
||||
free((void*)ibus->address_file_name);
|
||||
ibus->address_file_name = strdup(address_file_name);
|
||||
@ -169,25 +188,17 @@ setup_connection(_GLFWIBUSData *ibus) {
|
||||
debug("Connecting to IBUS daemon @ %s for IME input management\n", ibus->address);
|
||||
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;
|
||||
|
||||
free((void*)ibus->input_ctx_path); ibus->input_ctx_path = NULL;
|
||||
if (!glfw_dbus_call_method_with_reply(
|
||||
ibus->conn, IBUS_SERVICE, IBUS_PATH, IBUS_INTERFACE, "CreateInputContext", input_context_created, ibus,
|
||||
DBUS_TYPE_STRING, &client_name, 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);
|
||||
glfw_ibus_set_focused(ibus, GLFW_FALSE);
|
||||
set_cursor_geometry(ibus, 0, 0, 0, 0);
|
||||
debug("Connected to IBUS daemon for IME input management\n");
|
||||
ibus->ok = GLFW_TRUE;
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
@ -251,7 +262,7 @@ glfw_ibus_set_focused(_GLFWIBUSData *ibus, GLFWbool focused) {
|
||||
static void
|
||||
set_cursor_geometry(_GLFWIBUSData *ibus, int x, int y, int w, int h) {
|
||||
if (check_connection(ibus)) {
|
||||
glfw_dbus_call_method(ibus->conn, IBUS_SERVICE, ibus->input_ctx_path, IBUS_INPUT_INTERFACE, "SetCursorLocation",
|
||||
glfw_dbus_call_method_no_reply(ibus->conn, IBUS_SERVICE, ibus->input_ctx_path, IBUS_INPUT_INTERFACE, "SetCursorLocation",
|
||||
DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y, DBUS_TYPE_INT32, &w, DBUS_TYPE_INT32, &h, DBUS_TYPE_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user