Make the DBUS APIs async

This commit is contained in:
Kovid Goyal 2018-07-10 08:41:47 +05:30
parent 78cda7aa74
commit dd9e484336
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 110 additions and 46 deletions

106
glfw/dbus_glfw.c vendored
View File

@ -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
View File

@ -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
View File

@ -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);
}
}