From 8675659fcb7b2f267d01b3f8794de3b7d75a00d1 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 10 Jul 2018 13:30:36 +0530 Subject: [PATCH] Fix remaining sync BUS calls Also work on IBUS integration --- glfw/dbus_glfw.c | 37 +++----------------- glfw/dbus_glfw.h | 1 - glfw/ibus_glfw.c | 91 ++++++++++++++++++++++++++++++++++++++++++++---- glfw/ibus_glfw.h | 10 ++++++ glfw/xkb_glfw.c | 4 +++ 5 files changed, 103 insertions(+), 40 deletions(-) diff --git a/glfw/dbus_glfw.c b/glfw/dbus_glfw.c index b5a557016..235a29636 100644 --- a/glfw/dbus_glfw.c +++ b/glfw/dbus_glfw.c @@ -180,38 +180,6 @@ glfw_dbus_close_connection(DBusConnection *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; -} - GLFWbool glfw_dbus_get_args(DBusMessage *msg, const char *failmsg, ...) { DBusError err; @@ -267,11 +235,14 @@ call_method(DBusConnection *conn, const char *node, const char *path, const char 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); + retval = GLFW_TRUE; } 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)) { + if (dbus_connection_send(conn, msg, NULL)) { + retval = GLFW_TRUE; + } else { _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to call DBUS method: %s on node: %s and interface: %s out of memory", method, node, interface); } } diff --git a/glfw/dbus_glfw.h b/glfw/dbus_glfw.h index 589dd922e..e391bf703 100644 --- a/glfw/dbus_glfw.h +++ b/glfw/dbus_glfw.h @@ -41,7 +41,6 @@ GLFWbool glfw_dbus_init(_GLFWDBUSData *dbus, EventLoopData *eld); void glfw_dbus_terminate(_GLFWDBUSData *dbus); DBusConnection* glfw_dbus_connect_to(const char *path, const char* err_msg, const char* name); 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_no_reply(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...); GLFWbool diff --git a/glfw/ibus_glfw.c b/glfw/ibus_glfw.c index b26a4eb9b..66fa90244 100644 --- a/glfw/ibus_glfw.c +++ b/glfw/ibus_glfw.c @@ -164,8 +164,12 @@ input_context_created(DBusMessage *msg, const char* errmsg, void *data) { _GLFWIBUSData *ibus = (_GLFWIBUSData*)data; free((void*)ibus->input_ctx_path); ibus->input_ctx_path = strdup(path); + if (!ibus->input_ctx_path) return; + 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); 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; + if (!glfw_dbus_call_method_no_reply(ibus->conn, IBUS_SERVICE, ibus->input_ctx_path, IBUS_INPUT_INTERFACE, "SetCapabilities", DBUS_TYPE_UINT32, &caps, DBUS_TYPE_INVALID)) return; ibus->ok = GLFW_TRUE; glfw_ibus_set_focused(ibus, GLFW_FALSE); set_cursor_geometry(ibus, 0, 0, 0, 0); @@ -195,10 +199,6 @@ setup_connection(_GLFWIBUSData *ibus) { 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); return GLFW_TRUE; } @@ -250,7 +250,7 @@ glfw_ibus_dispatch(_GLFWIBUSData *ibus) { static void simple_message(_GLFWIBUSData *ibus, const char *method) { if (check_connection(ibus)) { - glfw_dbus_call_void_method(ibus->conn, IBUS_SERVICE, ibus->input_ctx_path, IBUS_INPUT_INTERFACE, method, DBUS_TYPE_INVALID); + glfw_dbus_call_method_no_reply(ibus->conn, IBUS_SERVICE, ibus->input_ctx_path, IBUS_INPUT_INTERFACE, method, DBUS_TYPE_INVALID); } } @@ -266,3 +266,82 @@ set_cursor_geometry(_GLFWIBUSData *ibus, int x, int y, int w, int h) { DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y, DBUS_TYPE_INT32, &w, DBUS_TYPE_INT32, &h, DBUS_TYPE_INVALID); } } + +typedef enum +{ + IBUS_SHIFT_MASK = 1 << 0, + IBUS_LOCK_MASK = 1 << 1, + IBUS_CONTROL_MASK = 1 << 2, + IBUS_MOD1_MASK = 1 << 3, + IBUS_MOD2_MASK = 1 << 4, + IBUS_MOD3_MASK = 1 << 5, + IBUS_MOD4_MASK = 1 << 6, + IBUS_MOD5_MASK = 1 << 7, + IBUS_BUTTON1_MASK = 1 << 8, + IBUS_BUTTON2_MASK = 1 << 9, + IBUS_BUTTON3_MASK = 1 << 10, + IBUS_BUTTON4_MASK = 1 << 11, + IBUS_BUTTON5_MASK = 1 << 12, + + /* The next few modifiers are used by XKB, so we skip to the end. + * Bits 15 - 23 are currently unused. Bit 29 is used internally. + */ + + /* ibus mask */ + IBUS_HANDLED_MASK = 1 << 24, + IBUS_FORWARD_MASK = 1 << 25, + IBUS_IGNORED_MASK = IBUS_FORWARD_MASK, + + IBUS_SUPER_MASK = 1 << 26, + IBUS_HYPER_MASK = 1 << 27, + IBUS_META_MASK = 1 << 28, + + IBUS_RELEASE_MASK = 1 << 30, + + IBUS_MODIFIER_MASK = 0x5f001fff +} IBusModifierType; + + +static inline uint32_t +ibus_key_state(unsigned int glfw_modifiers, int action) { + uint32_t ans = action == GLFW_RELEASE ? IBUS_RELEASE_MASK : 0; +#define M(g, i) if(glfw_modifiers & GLFW_MOD_##g) ans |= i + M(SHIFT, IBUS_SHIFT_MASK); + M(CAPS_LOCK, IBUS_LOCK_MASK); + M(CONTROL, IBUS_CONTROL_MASK); + M(ALT, IBUS_MOD1_MASK); + M(NUM_LOCK, IBUS_MOD2_MASK); + M(SUPER, IBUS_MOD4_MASK); +#undef M + return ans; +} + +void +key_event_processed(DBusMessage *msg, const char* errmsg, void *data) { + if (errmsg) { + _glfwInputError(GLFW_PLATFORM_ERROR, "IBUS: Failed to process key with error: %s", errmsg); + return; + } + uint32_t handled; + if (!glfw_dbus_get_args(msg, "Failed to get IBUS handled key from reply", DBUS_TYPE_BOOLEAN, &handled, DBUS_TYPE_INVALID)) return; + KeyEvent *ev = (KeyEvent*)data; + free(ev); +} + +GLFWbool +process_key(const KeyEvent *ev_) { + if (!check_connection(ev_->ibus)) return GLFW_FALSE; + KeyEvent *ev = malloc(sizeof(KeyEvent)); + if (!ev) return GLFW_FALSE; + memcpy(ev, ev_, sizeof(KeyEvent)); + uint32_t state = ibus_key_state(ev->glfw_modifiers, ev->action); + if (!glfw_dbus_call_method_with_reply( + ev->ibus->conn, IBUS_SERVICE, ev->ibus->input_ctx_path, IBUS_INPUT_INTERFACE, "ProcessKeyEvent", + key_event_processed, ev, + DBUS_TYPE_UINT32, &ev->keysym, DBUS_TYPE_UINT32, &ev->keycode, DBUS_TYPE_UINT32, + &state, DBUS_TYPE_INVALID)) { + free(ev); + return GLFW_FALSE; + } + return GLFW_TRUE; +} diff --git a/glfw/ibus_glfw.h b/glfw/ibus_glfw.h index 669eca9a5..04039b50b 100644 --- a/glfw/ibus_glfw.h +++ b/glfw/ibus_glfw.h @@ -28,6 +28,7 @@ #pragma once #include "dbus_glfw.h" +#include typedef struct { GLFWbool ok, inited; @@ -36,7 +37,16 @@ typedef struct { const char *input_ctx_path, *address_file_name, *address; } _GLFWIBUSData; +typedef struct { + xkb_keycode_t keycode; + xkb_keysym_t keysym; + unsigned int glfw_modifiers; + int action; + _GLFWIBUSData *ibus; +} KeyEvent; + void glfw_connect_to_ibus(_GLFWIBUSData *ibus); void glfw_ibus_terminate(_GLFWIBUSData *ibus); void glfw_ibus_set_focused(_GLFWIBUSData *ibus, GLFWbool focused); void glfw_ibus_dispatch(_GLFWIBUSData *ibus); +GLFWbool process_key(const KeyEvent *ev_); diff --git a/glfw/xkb_glfw.c b/glfw/xkb_glfw.c index 0f9453e8e..727802730 100644 --- a/glfw/xkb_glfw.c +++ b/glfw/xkb_glfw.c @@ -408,6 +408,7 @@ format_xkb_mods(_GLFWXKBData *xkb, const char* name, xkb_mod_mask_t mods) { void glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t scancode, int action) { const xkb_keysym_t *syms, *clean_syms, *default_syms; + static KeyEvent ev; xkb_keysym_t glfw_sym; xkb_keycode_t code_for_sym = scancode; #ifdef _GLFW_WAYLAND @@ -425,6 +426,9 @@ glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t } glfw_sym = clean_syms[0]; debug("clean_sym: %s ", glfw_xkb_keysym_name(clean_syms[0])); + ev.action = action; ev.glfw_modifiers = xkb->modifiers; ev.keycode = scancode; ev.keysym = glfw_sym; + ev.ibus = &xkb->ibus; + process_key(&ev); if (action == GLFW_PRESS || action == GLFW_REPEAT) { const char *text_type = "composed_text"; glfw_sym = compose_symbol(xkb, syms[0]);