diff --git a/glfw/dbus_glfw.c b/glfw/dbus_glfw.c index aa9622d03..43ba40311 100644 --- a/glfw/dbus_glfw.c +++ b/glfw/dbus_glfw.c @@ -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; - } diff --git a/glfw/dbus_glfw.h b/glfw/dbus_glfw.h index c5bce2eff..141e02c78 100644 --- a/glfw/dbus_glfw.h +++ b/glfw/dbus_glfw.h @@ -30,6 +30,8 @@ #include #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, ...); diff --git a/glfw/ibus_glfw.c b/glfw/ibus_glfw.c index d03b677b9..b514e5475 100644 --- a/glfw/ibus_glfw.c +++ b/glfw/ibus_glfw.c @@ -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); } }