# HG changeset patch # User Alex Baines # Date 1406685571 -3600 # Node ID 914c5dac5a3396578f9c36392bbcad0c5e67e017 # Parent 65beae82fc0c5658043cd7044161ce54c5f40dc4 Add a SDL_IM_INTERNAL_EDITING event to make IMs like iBus render editing text in its own UI instead of sending TEXTEDITING events. This is useful for applications that handle TEXTINPUT events but not TEXTEDITING events. Also update the iBus inotify code to clean up after itself better, and update the candidate list position on each keypress. diff -r 65beae82fc0c -r 914c5dac5a33 include/SDL_hints.h --- a/include/SDL_hints.h Sun Jul 27 19:05:40 2014 +0100 +++ b/include/SDL_hints.h Wed Jul 30 02:59:31 2014 +0100 @@ -477,6 +477,18 @@ */ #define SDL_HINT_ANDROID_APK_EXPANSION_PATCH_FILE_VERSION "SDL_ANDROID_APK_EXPANSION_PATCH_FILE_VERSION" +/** + * \brief A variable to control whether certain IMs should handle text editing internally instead of sending TEXTEDITING events. + * + * + * The variable can be set to the following values: + * "0" - TEXTEDITING events are sent, and it is the application's + * responsibility to render the text from these events and + * differentiate it somehow from committed text. (default) + * "1" - If supported by the IM then TEXTEDITING events are not sent, + * and text that is being composed will be rendered in its own UI. + */ +#define SDL_HINT_IM_INTERNAL_EDITING "SDL_IM_INTERNAL_EDITING" /** * \brief An enumeration of hint priorities diff -r 65beae82fc0c -r 914c5dac5a33 src/core/linux/SDL_ibus.c --- a/src/core/linux/SDL_ibus.c Sun Jul 27 19:05:40 2014 +0100 +++ b/src/core/linux/SDL_ibus.c Wed Jul 30 02:59:31 2014 +0100 @@ -46,6 +46,7 @@ static DBusConnection *ibus_conn = NULL; static char *ibus_addr_file = NULL; int inotify_fd = -1; +int inotify_wd = -1; static Uint32 IBus_ModState(void) @@ -289,6 +290,40 @@ return SDL_strdup(file_path); } +static SDL_bool IBus_CheckConnection(SDL_DBusContext *dbus); + +static void +IBus_SetCapabilities(void *data, const char *name, const char *old_val, + const char *internal_editing) +{ + SDL_DBusContext *dbus = SDL_DBus_GetContext(); + + if(IBus_CheckConnection(dbus)){ + + DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE, + input_ctx_path, + IBUS_INPUT_INTERFACE, + "SetCapabilities"); + if(msg){ + Uint32 caps = IBUS_CAP_FOCUS; + if(!(internal_editing && *internal_editing == '1')){ + caps |= IBUS_CAP_PREEDIT_TEXT; + } + + dbus->message_append_args(msg, + DBUS_TYPE_UINT32, &caps, + DBUS_TYPE_INVALID); + } + + if(msg){ + if(dbus->connection_send(ibus_conn, msg, NULL)){ + dbus->connection_flush(ibus_conn); + } + dbus->message_unref(msg); + } + } +} + static SDL_bool IBus_SetupConnection(SDL_DBusContext *dbus, const char* addr) { @@ -341,31 +376,12 @@ } if(result){ - DBusMessage *msg2 = dbus->message_new_method_call(IBUS_SERVICE, - input_ctx_path, - IBUS_INPUT_INTERFACE, - "SetCapabilities"); - if(msg2){ - Uint32 caps = IBUS_CAP_FOCUS | IBUS_CAP_PREEDIT_TEXT; - dbus->message_append_args(msg2, - DBUS_TYPE_UINT32, &caps, - DBUS_TYPE_INVALID); - } - - if(msg2){ - if(dbus->connection_send(ibus_conn, msg2, NULL)){ - dbus->connection_flush(ibus_conn); - } - dbus->message_unref(msg2); - } + SDL_AddHintCallback(SDL_HINT_IM_INTERNAL_EDITING, &IBus_SetCapabilities, NULL); dbus->bus_add_match(ibus_conn, "type='signal',interface='org.freedesktop.IBus.InputContext'", NULL); dbus->connection_add_filter(ibus_conn, &IBus_MessageFilter, dbus, NULL); dbus->connection_flush(ibus_conn); } - - SDL_IBus_SetFocus(SDL_GetFocusWindow() != NULL); - SDL_IBus_UpdateTextRect(NULL); return result; } @@ -379,7 +395,7 @@ return SDL_TRUE; } - if(inotify_fd != -1){ + if(inotify_wd != -1){ char buf[1024]; ssize_t readsize = read(inotify_fd, buf, sizeof(buf)); if(readsize > 0){ @@ -432,15 +448,17 @@ char *addr = IBus_ReadAddressFromFile(addr_file); - inotify_fd = inotify_init(); - fcntl(inotify_fd, F_SETFL, O_NONBLOCK); + if(inotify_fd < 0){ + inotify_fd = inotify_init(); + fcntl(inotify_fd, F_SETFL, O_NONBLOCK); + } char *addr_file_dir = SDL_strrchr(addr_file, '/'); if(addr_file_dir){ *addr_file_dir = 0; } - inotify_add_watch(inotify_fd, addr_file, IN_CREATE | IN_MODIFY); + inotify_wd = inotify_add_watch(inotify_fd, addr_file, IN_CREATE | IN_MODIFY); SDL_free(addr_file); result = IBus_SetupConnection(dbus, addr); @@ -470,6 +488,13 @@ dbus->connection_unref(ibus_conn); } + if(inotify_fd > 0 && inotify_wd > 0){ + inotify_rm_watch(inotify_fd, inotify_wd); + inotify_wd = -1; + } + + SDL_DelHintCallback(SDL_HINT_IM_INTERNAL_EDITING, &IBus_SetCapabilities, NULL); + SDL_memset(&ibus_cursor_rect, 0, sizeof(ibus_cursor_rect)); } @@ -542,6 +567,8 @@ } + SDL_IBus_UpdateTextRect(NULL); + return result; } @@ -582,7 +609,7 @@ x += ibus_cursor_rect.x; y += ibus_cursor_rect.y; - + SDL_DBusContext *dbus = SDL_DBus_GetContext(); if(IBus_CheckConnection(dbus)){