src/core/linux/SDL_ibus.c
author Alex Baines <alex@abaines.me.uk>
Fri, 27 Feb 2015 21:17:29 +0000
changeset 9646 9d4917e2d909
parent 9645 b1e7169d1dcb
child 9712 a964d651f1dd
permissions -rw-r--r--
[IBus] Only register interest in messages sent to our input context.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2015 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../../SDL_internal.h"
    22 
    23 #ifdef HAVE_IBUS_IBUS_H
    24 #include "SDL.h"
    25 #include "SDL_syswm.h"
    26 #include "SDL_ibus.h"
    27 #include "SDL_dbus.h"
    28 #include "../../video/SDL_sysvideo.h"
    29 #include "../../events/SDL_keyboard_c.h"
    30 
    31 #if SDL_VIDEO_DRIVER_X11
    32     #include "../../video/x11/SDL_x11video.h"
    33 #endif
    34 
    35 #include <sys/inotify.h>
    36 #include <unistd.h>
    37 #include <fcntl.h>
    38 
    39 static const char IBUS_SERVICE[]         = "org.freedesktop.IBus";
    40 static const char IBUS_PATH[]            = "/org/freedesktop/IBus";
    41 static const char IBUS_INTERFACE[]       = "org.freedesktop.IBus";
    42 static const char IBUS_INPUT_INTERFACE[] = "org.freedesktop.IBus.InputContext";
    43 
    44 static char *input_ctx_path = NULL;
    45 static SDL_Rect ibus_cursor_rect = {0};
    46 static DBusConnection *ibus_conn = NULL;
    47 static char *ibus_addr_file = NULL;
    48 int inotify_fd = -1, inotify_wd = -1;
    49 
    50 static Uint32
    51 IBus_ModState(void)
    52 {
    53     Uint32 ibus_mods = 0;
    54     SDL_Keymod sdl_mods = SDL_GetModState();
    55     
    56     /* Not sure about MOD3, MOD4 and HYPER mappings */
    57     if (sdl_mods & KMOD_LSHIFT) ibus_mods |= IBUS_SHIFT_MASK;
    58     if (sdl_mods & KMOD_CAPS)   ibus_mods |= IBUS_LOCK_MASK;
    59     if (sdl_mods & KMOD_LCTRL)  ibus_mods |= IBUS_CONTROL_MASK;
    60     if (sdl_mods & KMOD_LALT)   ibus_mods |= IBUS_MOD1_MASK;
    61     if (sdl_mods & KMOD_NUM)    ibus_mods |= IBUS_MOD2_MASK;
    62     if (sdl_mods & KMOD_MODE)   ibus_mods |= IBUS_MOD5_MASK;
    63     if (sdl_mods & KMOD_LGUI)   ibus_mods |= IBUS_SUPER_MASK;
    64     if (sdl_mods & KMOD_RGUI)   ibus_mods |= IBUS_META_MASK;
    65 
    66     return ibus_mods;
    67 }
    68 
    69 static const char *
    70 IBus_GetVariantText(DBusConnection *conn, DBusMessageIter *iter, SDL_DBusContext *dbus)
    71 {
    72     /* The text we need is nested weirdly, use dbus-monitor to see the structure better */
    73     const char *text = NULL;
    74     const char *struct_id = NULL;
    75     DBusMessageIter sub1, sub2;
    76 
    77     if (dbus->message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT) {
    78         return NULL;
    79     }
    80     
    81     dbus->message_iter_recurse(iter, &sub1);
    82     
    83     if (dbus->message_iter_get_arg_type(&sub1) != DBUS_TYPE_STRUCT) {
    84         return NULL;
    85     }
    86     
    87     dbus->message_iter_recurse(&sub1, &sub2);
    88     
    89     if (dbus->message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
    90         return NULL;
    91     }
    92     
    93     dbus->message_iter_get_basic(&sub2, &struct_id);
    94     if (!struct_id || SDL_strncmp(struct_id, "IBusText", sizeof("IBusText")) != 0) {
    95         return NULL;
    96     }
    97     
    98     dbus->message_iter_next(&sub2);
    99     dbus->message_iter_next(&sub2);
   100     
   101     if (dbus->message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
   102         return NULL;
   103     }
   104     
   105     dbus->message_iter_get_basic(&sub2, &text);
   106     
   107     return text;
   108 }
   109 
   110 static size_t 
   111 IBus_utf8_strlen(const char *str)
   112 {
   113     size_t utf8_len = 0;
   114     const char *p;
   115     
   116     for (p = str; *p; ++p) {
   117         if (!((*p & 0x80) && !(*p & 0x40))) {
   118             ++utf8_len;
   119         }
   120     }
   121     
   122     return utf8_len;
   123 }
   124 
   125 static DBusHandlerResult
   126 IBus_MessageHandler(DBusConnection *conn, DBusMessage *msg, void *user_data)
   127 {
   128     SDL_DBusContext *dbus = (SDL_DBusContext *)user_data;
   129         
   130     if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "CommitText")) {
   131         DBusMessageIter iter;
   132         const char *text;
   133 
   134         dbus->message_iter_init(msg, &iter);
   135         
   136         text = IBus_GetVariantText(conn, &iter, dbus);
   137         if (text && *text) {
   138             char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
   139             size_t text_bytes = SDL_strlen(text), i = 0;
   140             
   141             while (i < text_bytes) {
   142                 size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
   143                 SDL_SendKeyboardText(buf);
   144                 
   145                 i += sz;
   146             }
   147         }
   148         
   149         return DBUS_HANDLER_RESULT_HANDLED;
   150     }
   151     
   152     if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "UpdatePreeditText")) {
   153         DBusMessageIter iter;
   154         const char *text;
   155 
   156         dbus->message_iter_init(msg, &iter);
   157         text = IBus_GetVariantText(conn, &iter, dbus);
   158         
   159         if (text) {
   160             char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
   161             size_t text_bytes = SDL_strlen(text), i = 0;
   162             size_t cursor = 0;
   163             
   164             do {
   165                 size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
   166                 size_t chars = IBus_utf8_strlen(buf);
   167                 
   168                 SDL_SendEditingText(buf, cursor, chars);
   169 
   170                 i += sz;
   171                 cursor += chars;
   172             } while (i < text_bytes);
   173         }
   174         
   175         SDL_IBus_UpdateTextRect(NULL);
   176         
   177         return DBUS_HANDLER_RESULT_HANDLED;
   178     }
   179     
   180     if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "HidePreeditText")) {
   181         SDL_SendEditingText("", 0, 0);
   182         return DBUS_HANDLER_RESULT_HANDLED;
   183     }
   184     
   185     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
   186 }
   187 
   188 static char *
   189 IBus_ReadAddressFromFile(const char *file_path)
   190 {
   191     char addr_buf[1024];
   192     SDL_bool success = SDL_FALSE;
   193     FILE *addr_file;
   194 
   195     addr_file = fopen(file_path, "r");
   196     if (!addr_file) {
   197         return NULL;
   198     }
   199 
   200     while (fgets(addr_buf, sizeof(addr_buf), addr_file)) {
   201         if (SDL_strncmp(addr_buf, "IBUS_ADDRESS=", sizeof("IBUS_ADDRESS=")-1) == 0) {
   202             size_t sz = SDL_strlen(addr_buf);
   203             if (addr_buf[sz-1] == '\n') addr_buf[sz-1] = 0;
   204             if (addr_buf[sz-2] == '\r') addr_buf[sz-2] = 0;
   205             success = SDL_TRUE;
   206             break;
   207         }
   208     }
   209 
   210     fclose(addr_file);
   211 
   212     if (success) {
   213         return SDL_strdup(addr_buf + (sizeof("IBUS_ADDRESS=") - 1));
   214     } else {
   215         return NULL;
   216     }
   217 }
   218 
   219 static char *
   220 IBus_GetDBusAddressFilename(void)
   221 {
   222     SDL_DBusContext *dbus;
   223     const char *disp_env;
   224     char config_dir[PATH_MAX];
   225     char *display = NULL;
   226     const char *addr;
   227     const char *conf_env;
   228     char *key;
   229     char file_path[PATH_MAX];
   230     const char *host;
   231     char *disp_num, *screen_num;
   232 
   233     if (ibus_addr_file) {
   234         return SDL_strdup(ibus_addr_file);
   235     }
   236     
   237     dbus = SDL_DBus_GetContext();
   238     if (!dbus) {
   239         return NULL;
   240     }
   241     
   242     /* Use this environment variable if it exists. */
   243     addr = SDL_getenv("IBUS_ADDRESS");
   244     if (addr && *addr) {
   245         return SDL_strdup(addr);
   246     }
   247     
   248     /* Otherwise, we have to get the hostname, display, machine id, config dir
   249        and look up the address from a filepath using all those bits, eek. */
   250     disp_env = SDL_getenv("DISPLAY");
   251 
   252     if (!disp_env || !*disp_env) {
   253         display = SDL_strdup(":0.0");
   254     } else {
   255         display = SDL_strdup(disp_env);
   256     }
   257     
   258     host = display;
   259     disp_num   = SDL_strrchr(display, ':');
   260     screen_num = SDL_strrchr(display, '.');
   261     
   262     if (!disp_num) {
   263         SDL_free(display);
   264         return NULL;
   265     }
   266     
   267     *disp_num = 0;
   268     disp_num++;
   269     
   270     if (screen_num) {
   271         *screen_num = 0;
   272     }
   273     
   274     if (!*host) {
   275         host = "unix";
   276     }
   277         
   278     SDL_memset(config_dir, 0, sizeof(config_dir));
   279     
   280     conf_env = SDL_getenv("XDG_CONFIG_HOME");
   281     if (conf_env && *conf_env) {
   282         SDL_strlcpy(config_dir, conf_env, sizeof(config_dir));
   283     } else {
   284         const char *home_env = SDL_getenv("HOME");
   285         if (!home_env || !*home_env) {
   286             SDL_free(display);
   287             return NULL;
   288         }
   289         SDL_snprintf(config_dir, sizeof(config_dir), "%s/.config", home_env);
   290     }
   291     
   292     key = dbus->get_local_machine_id();
   293 
   294     SDL_memset(file_path, 0, sizeof(file_path));
   295     SDL_snprintf(file_path, sizeof(file_path), "%s/ibus/bus/%s-%s-%s", 
   296                                                config_dir, key, host, disp_num);
   297     dbus->free(key);
   298     SDL_free(display);
   299     
   300     return SDL_strdup(file_path);
   301 }
   302 
   303 static SDL_bool IBus_CheckConnection(SDL_DBusContext *dbus);
   304 
   305 static void
   306 IBus_SetCapabilities(void *data, const char *name, const char *old_val,
   307                                                    const char *internal_editing)
   308 {
   309     SDL_DBusContext *dbus = SDL_DBus_GetContext();
   310     
   311     if (IBus_CheckConnection(dbus)) {
   312 
   313         DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
   314                                                          input_ctx_path,
   315                                                          IBUS_INPUT_INTERFACE,
   316                                                          "SetCapabilities");
   317         if (msg) {
   318             Uint32 caps = IBUS_CAP_FOCUS;
   319             if (!(internal_editing && *internal_editing == '1')) {
   320                 caps |= IBUS_CAP_PREEDIT_TEXT;
   321             }
   322             
   323             dbus->message_append_args(msg,
   324                                       DBUS_TYPE_UINT32, &caps,
   325                                       DBUS_TYPE_INVALID);
   326         }
   327         
   328         if (msg) {
   329             if (dbus->connection_send(ibus_conn, msg, NULL)) {
   330                 dbus->connection_flush(ibus_conn);
   331             }
   332             dbus->message_unref(msg);
   333         }
   334     }
   335 }
   336 
   337 
   338 static SDL_bool
   339 IBus_SetupConnection(SDL_DBusContext *dbus, const char* addr)
   340 {
   341     const char *path = NULL;
   342     SDL_bool result = SDL_FALSE;
   343     DBusMessage *msg;
   344     DBusObjectPathVTable ibus_vtable = {0};
   345     ibus_vtable.message_function = &IBus_MessageHandler;
   346 
   347     ibus_conn = dbus->connection_open_private(addr, NULL);
   348 
   349     if (!ibus_conn) {
   350         return SDL_FALSE;
   351     }
   352 
   353     dbus->connection_flush(ibus_conn);
   354     
   355     if (!dbus->bus_register(ibus_conn, NULL)) {
   356         ibus_conn = NULL;
   357         return SDL_FALSE;
   358     }
   359     
   360     dbus->connection_flush(ibus_conn);
   361 
   362     msg = dbus->message_new_method_call(IBUS_SERVICE, IBUS_PATH, IBUS_INTERFACE, "CreateInputContext");
   363     if (msg) {
   364         const char *client_name = "SDL2_Application";
   365         dbus->message_append_args(msg,
   366                                   DBUS_TYPE_STRING, &client_name,
   367                                   DBUS_TYPE_INVALID);
   368     }
   369     
   370     if (msg) {
   371         DBusMessage *reply;
   372         
   373         reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 1000, NULL);
   374         if (reply) {
   375             if (dbus->message_get_args(reply, NULL,
   376                                        DBUS_TYPE_OBJECT_PATH, &path,
   377                                        DBUS_TYPE_INVALID)) {
   378                 if (input_ctx_path) {
   379                     SDL_free(input_ctx_path);
   380                 }
   381                 input_ctx_path = SDL_strdup(path);
   382                 result = SDL_TRUE;                          
   383             }
   384             dbus->message_unref(reply);
   385         }
   386         dbus->message_unref(msg);
   387     }
   388 
   389     if (result) {
   390         SDL_AddHintCallback(SDL_HINT_IME_INTERNAL_EDITING, &IBus_SetCapabilities, NULL);
   391         
   392         dbus->bus_add_match(ibus_conn, "type='signal',interface='org.freedesktop.IBus.InputContext'", NULL);
   393         dbus->connection_try_register_object_path(ibus_conn, input_ctx_path, &ibus_vtable, dbus, NULL);
   394         dbus->connection_flush(ibus_conn);
   395     }
   396 
   397     SDL_IBus_SetFocus(SDL_GetKeyboardFocus() != NULL);
   398     SDL_IBus_UpdateTextRect(NULL);
   399     
   400     return result;
   401 }
   402 
   403 static SDL_bool
   404 IBus_CheckConnection(SDL_DBusContext *dbus)
   405 {
   406     if (!dbus) return SDL_FALSE;
   407     
   408     if (ibus_conn && dbus->connection_get_is_connected(ibus_conn)) {
   409         return SDL_TRUE;
   410     }
   411     
   412     if (inotify_fd > 0 && inotify_wd > 0) {
   413         char buf[1024];
   414         ssize_t readsize = read(inotify_fd, buf, sizeof(buf));
   415         if (readsize > 0) {
   416         
   417             char *p;
   418             SDL_bool file_updated = SDL_FALSE;
   419             
   420             for (p = buf; p < buf + readsize; /**/) {
   421                 struct inotify_event *event = (struct inotify_event*) p;
   422                 if (event->len > 0) {
   423                     char *addr_file_no_path = SDL_strrchr(ibus_addr_file, '/');
   424                     if (!addr_file_no_path) return SDL_FALSE;
   425                  
   426                     if (SDL_strcmp(addr_file_no_path + 1, event->name) == 0) {
   427                         file_updated = SDL_TRUE;
   428                         break;
   429                     }
   430                 }
   431                 
   432                 p += sizeof(struct inotify_event) + event->len;
   433             }
   434             
   435             if (file_updated) {
   436                 char *addr = IBus_ReadAddressFromFile(ibus_addr_file);
   437                 if (addr) {
   438                     SDL_bool result = IBus_SetupConnection(dbus, addr);
   439                     SDL_free(addr);
   440                     return result;
   441                 }
   442             }
   443         }
   444     }
   445     
   446     return SDL_FALSE;
   447 }
   448 
   449 SDL_bool
   450 SDL_IBus_Init(void)
   451 {
   452     SDL_bool result = SDL_FALSE;
   453     SDL_DBusContext *dbus = SDL_DBus_GetContext();
   454     
   455     if (dbus) {
   456         char *addr_file = IBus_GetDBusAddressFilename();
   457         char *addr;
   458         char *addr_file_dir;
   459 
   460         if (!addr_file) {
   461             return SDL_FALSE;
   462         }
   463         
   464         ibus_addr_file = SDL_strdup(addr_file);
   465         
   466         addr = IBus_ReadAddressFromFile(addr_file);
   467         if (!addr) {
   468             return SDL_FALSE;
   469         }
   470         
   471         if (inotify_fd < 0) {
   472             inotify_fd = inotify_init();
   473             fcntl(inotify_fd, F_SETFL, O_NONBLOCK);
   474         }
   475         
   476         addr_file_dir = SDL_strrchr(addr_file, '/');
   477         if (addr_file_dir) {
   478             *addr_file_dir = 0;
   479         }
   480         
   481         inotify_wd = inotify_add_watch(inotify_fd, addr_file, IN_CREATE | IN_MODIFY);
   482         SDL_free(addr_file);
   483         
   484         if (addr) {
   485             result = IBus_SetupConnection(dbus, addr);
   486             SDL_free(addr);
   487         }
   488     }
   489     
   490     return result;
   491 }
   492 
   493 void
   494 SDL_IBus_Quit(void)
   495 {   
   496     SDL_DBusContext *dbus;
   497 
   498     if (input_ctx_path) {
   499         SDL_free(input_ctx_path);
   500         input_ctx_path = NULL;
   501     }
   502     
   503     if (ibus_addr_file) {
   504         SDL_free(ibus_addr_file);
   505         ibus_addr_file = NULL;
   506     }
   507     
   508     dbus = SDL_DBus_GetContext();
   509     
   510     if (dbus && ibus_conn) {
   511         dbus->connection_close(ibus_conn);
   512         dbus->connection_unref(ibus_conn);
   513     }
   514     
   515     if (inotify_fd > 0 && inotify_wd > 0) {
   516         inotify_rm_watch(inotify_fd, inotify_wd);
   517         inotify_wd = -1;
   518     }
   519     
   520     SDL_DelHintCallback(SDL_HINT_IME_INTERNAL_EDITING, &IBus_SetCapabilities, NULL);
   521     
   522     SDL_memset(&ibus_cursor_rect, 0, sizeof(ibus_cursor_rect));
   523 }
   524 
   525 static void
   526 IBus_SimpleMessage(const char *method)
   527 {   
   528     SDL_DBusContext *dbus = SDL_DBus_GetContext();
   529     
   530     if (IBus_CheckConnection(dbus)) {
   531         DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
   532                                                          input_ctx_path,
   533                                                          IBUS_INPUT_INTERFACE,
   534                                                          method);
   535         if (msg) {
   536             if (dbus->connection_send(ibus_conn, msg, NULL)) {
   537                 dbus->connection_flush(ibus_conn);
   538             }
   539             dbus->message_unref(msg);
   540         }
   541     }
   542 }
   543 
   544 void
   545 SDL_IBus_SetFocus(SDL_bool focused)
   546 { 
   547     const char *method = focused ? "FocusIn" : "FocusOut";
   548     IBus_SimpleMessage(method);
   549 }
   550 
   551 void
   552 SDL_IBus_Reset(void)
   553 {
   554     IBus_SimpleMessage("Reset");
   555 }
   556 
   557 SDL_bool
   558 SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
   559 { 
   560     SDL_bool result = SDL_FALSE;   
   561     SDL_DBusContext *dbus = SDL_DBus_GetContext();
   562     
   563     if (IBus_CheckConnection(dbus)) {
   564         DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
   565                                                          input_ctx_path,
   566                                                          IBUS_INPUT_INTERFACE,
   567                                                          "ProcessKeyEvent");
   568         if (msg) {
   569             Uint32 mods = IBus_ModState();
   570             dbus->message_append_args(msg,
   571                                       DBUS_TYPE_UINT32, &keysym,
   572                                       DBUS_TYPE_UINT32, &keycode,
   573                                       DBUS_TYPE_UINT32, &mods,
   574                                       DBUS_TYPE_INVALID);
   575         }
   576         
   577         if (msg) {
   578             DBusMessage *reply;
   579             
   580             reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 300, NULL);
   581             if (reply) {
   582                 if (!dbus->message_get_args(reply, NULL,
   583                                            DBUS_TYPE_BOOLEAN, &result,
   584                                            DBUS_TYPE_INVALID)) {
   585                     result = SDL_FALSE;                         
   586                 }
   587                 dbus->message_unref(reply);
   588             }
   589             dbus->message_unref(msg);
   590         }
   591         
   592     }
   593     
   594     SDL_IBus_UpdateTextRect(NULL);
   595 
   596     return result;
   597 }
   598 
   599 void
   600 SDL_IBus_UpdateTextRect(SDL_Rect *rect)
   601 {
   602     SDL_Window *focused_win;
   603     SDL_SysWMinfo info;
   604     int x = 0, y = 0;
   605     SDL_DBusContext *dbus;
   606 
   607     if (rect) {
   608         SDL_memcpy(&ibus_cursor_rect, rect, sizeof(ibus_cursor_rect));
   609     }
   610 
   611     focused_win = SDL_GetKeyboardFocus();
   612     if (!focused_win) {
   613         return;
   614     }
   615 
   616     SDL_VERSION(&info.version);
   617     if (!SDL_GetWindowWMInfo(focused_win, &info)) {
   618         return;
   619     }
   620 
   621     SDL_GetWindowPosition(focused_win, &x, &y);
   622    
   623 #if SDL_VIDEO_DRIVER_X11    
   624     if (info.subsystem == SDL_SYSWM_X11) {
   625         SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(focused_win)->driverdata;
   626             
   627         Display *x_disp = info.info.x11.display;
   628         Window x_win = info.info.x11.window;
   629         int x_screen = displaydata->screen;
   630         Window unused;
   631             
   632         X11_XTranslateCoordinates(x_disp, x_win, RootWindow(x_disp, x_screen), 0, 0, &x, &y, &unused);
   633     }
   634 #endif
   635 
   636     x += ibus_cursor_rect.x;
   637     y += ibus_cursor_rect.y;
   638         
   639     dbus = SDL_DBus_GetContext();
   640     
   641     if (IBus_CheckConnection(dbus)) {
   642         DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
   643                                                          input_ctx_path,
   644                                                          IBUS_INPUT_INTERFACE,
   645                                                          "SetCursorLocation");
   646         if (msg) {
   647             dbus->message_append_args(msg,
   648                                       DBUS_TYPE_INT32, &x,
   649                                       DBUS_TYPE_INT32, &y,
   650                                       DBUS_TYPE_INT32, &ibus_cursor_rect.w,
   651                                       DBUS_TYPE_INT32, &ibus_cursor_rect.h,
   652                                       DBUS_TYPE_INVALID);
   653         }
   654         
   655         if (msg) {
   656             if (dbus->connection_send(ibus_conn, msg, NULL)) {
   657                 dbus->connection_flush(ibus_conn);
   658             }
   659             dbus->message_unref(msg);
   660         }
   661     }
   662 }
   663 
   664 void
   665 SDL_IBus_PumpEvents(void)
   666 {
   667     SDL_DBusContext *dbus = SDL_DBus_GetContext();
   668     
   669     if (IBus_CheckConnection(dbus)) {
   670         dbus->connection_read_write(ibus_conn, 0);
   671     
   672         while (dbus->connection_dispatch(ibus_conn) == DBUS_DISPATCH_DATA_REMAINS) {
   673             /* Do nothing, actual work happens in IBus_MessageHandler */
   674         }
   675     }
   676 }
   677 
   678 #endif