src/core/linux/SDL_ibus.c
author Edward Rudd <urkle@outoforder.cc>
Wed, 01 Apr 2015 16:11:37 -0400
changeset 9451 28c55cb65416
parent 9114 515603c105ab
child 9462 0288195afd8c
permissions -rw-r--r--
handle the case where the ibus address can't be found. (prevents nasty crash)
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 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_MessageFilter(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 && *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             while (i < text_bytes) {
   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             }
   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 
   345     ibus_conn = dbus->connection_open_private(addr, NULL);
   346 
   347     if (!ibus_conn) {
   348         return SDL_FALSE;
   349     }
   350 
   351     dbus->connection_flush(ibus_conn);
   352     
   353     if (!dbus->bus_register(ibus_conn, NULL)) {
   354         ibus_conn = NULL;
   355         return SDL_FALSE;
   356     }
   357     
   358     dbus->connection_flush(ibus_conn);
   359 
   360     msg = dbus->message_new_method_call(IBUS_SERVICE, IBUS_PATH, IBUS_INTERFACE, "CreateInputContext");
   361     if (msg) {
   362         const char *client_name = "SDL2_Application";
   363         dbus->message_append_args(msg,
   364                                   DBUS_TYPE_STRING, &client_name,
   365                                   DBUS_TYPE_INVALID);
   366     }
   367     
   368     if (msg) {
   369         DBusMessage *reply;
   370         
   371         reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 1000, NULL);
   372         if (reply) {
   373             if (dbus->message_get_args(reply, NULL,
   374                                        DBUS_TYPE_OBJECT_PATH, &path,
   375                                        DBUS_TYPE_INVALID)) {
   376                 if (input_ctx_path) {
   377                     SDL_free(input_ctx_path);
   378                 }
   379                 input_ctx_path = SDL_strdup(path);
   380                 result = SDL_TRUE;                          
   381             }
   382             dbus->message_unref(reply);
   383         }
   384         dbus->message_unref(msg);
   385     }
   386 
   387     if (result) {
   388         SDL_AddHintCallback(SDL_HINT_IME_INTERNAL_EDITING, &IBus_SetCapabilities, NULL);
   389         
   390         dbus->bus_add_match(ibus_conn, "type='signal',interface='org.freedesktop.IBus.InputContext'", NULL);
   391         dbus->connection_add_filter(ibus_conn, &IBus_MessageFilter, dbus, NULL);
   392         dbus->connection_flush(ibus_conn);
   393     }
   394 
   395     SDL_IBus_SetFocus(SDL_GetKeyboardFocus() != NULL);
   396     SDL_IBus_UpdateTextRect(NULL);
   397     
   398     return result;
   399 }
   400 
   401 static SDL_bool
   402 IBus_CheckConnection(SDL_DBusContext *dbus)
   403 {
   404     if (!dbus) return SDL_FALSE;
   405     
   406     if (ibus_conn && dbus->connection_get_is_connected(ibus_conn)) {
   407         return SDL_TRUE;
   408     }
   409     
   410     if (inotify_fd > 0 && inotify_wd > 0) {
   411         char buf[1024];
   412         ssize_t readsize = read(inotify_fd, buf, sizeof(buf));
   413         if (readsize > 0) {
   414         
   415             char *p;
   416             SDL_bool file_updated = SDL_FALSE;
   417             
   418             for (p = buf; p < buf + readsize; /**/) {
   419                 struct inotify_event *event = (struct inotify_event*) p;
   420                 if (event->len > 0) {
   421                     char *addr_file_no_path = SDL_strrchr(ibus_addr_file, '/');
   422                     if (!addr_file_no_path) return SDL_FALSE;
   423                  
   424                     if (SDL_strcmp(addr_file_no_path + 1, event->name) == 0) {
   425                         file_updated = SDL_TRUE;
   426                         break;
   427                     }
   428                 }
   429                 
   430                 p += sizeof(struct inotify_event) + event->len;
   431             }
   432             
   433             if (file_updated) {
   434                 char *addr = IBus_ReadAddressFromFile(ibus_addr_file);
   435                 if (addr) {
   436                     SDL_bool result = IBus_SetupConnection(dbus, addr);
   437                     SDL_free(addr);
   438                     return result;
   439                 }
   440             }
   441         }
   442     }
   443     
   444     return SDL_FALSE;
   445 }
   446 
   447 SDL_bool
   448 SDL_IBus_Init(void)
   449 {
   450     SDL_bool result = SDL_FALSE;
   451     SDL_DBusContext *dbus = SDL_DBus_GetContext();
   452     
   453     if (dbus) {
   454         char *addr_file = IBus_GetDBusAddressFilename();
   455         char *addr;
   456         char *addr_file_dir;
   457 
   458         if (!addr_file) {
   459             return SDL_FALSE;
   460         }
   461         
   462         ibus_addr_file = SDL_strdup(addr_file);
   463         
   464         addr = IBus_ReadAddressFromFile(addr_file);
   465         if (!addr) {
   466             return SDL_FALSE;
   467         }
   468         
   469         if (inotify_fd < 0) {
   470             inotify_fd = inotify_init();
   471             fcntl(inotify_fd, F_SETFL, O_NONBLOCK);
   472         }
   473         
   474         addr_file_dir = SDL_strrchr(addr_file, '/');
   475         if (addr_file_dir) {
   476             *addr_file_dir = 0;
   477         }
   478         
   479         inotify_wd = inotify_add_watch(inotify_fd, addr_file, IN_CREATE | IN_MODIFY);
   480         SDL_free(addr_file);
   481         
   482         result = IBus_SetupConnection(dbus, addr);
   483         SDL_free(addr);
   484     }
   485     
   486     return result;
   487 }
   488 
   489 void
   490 SDL_IBus_Quit(void)
   491 {   
   492     SDL_DBusContext *dbus;
   493 
   494     if (input_ctx_path) {
   495         SDL_free(input_ctx_path);
   496         input_ctx_path = NULL;
   497     }
   498     
   499     if (ibus_addr_file) {
   500         SDL_free(ibus_addr_file);
   501         ibus_addr_file = NULL;
   502     }
   503     
   504     dbus = SDL_DBus_GetContext();
   505     
   506     if (dbus && ibus_conn) {
   507         dbus->connection_close(ibus_conn);
   508         dbus->connection_unref(ibus_conn);
   509     }
   510     
   511     if (inotify_fd > 0 && inotify_wd > 0) {
   512         inotify_rm_watch(inotify_fd, inotify_wd);
   513         inotify_wd = -1;
   514     }
   515     
   516     SDL_DelHintCallback(SDL_HINT_IME_INTERNAL_EDITING, &IBus_SetCapabilities, NULL);
   517     
   518     SDL_memset(&ibus_cursor_rect, 0, sizeof(ibus_cursor_rect));
   519 }
   520 
   521 static void
   522 IBus_SimpleMessage(const char *method)
   523 {   
   524     SDL_DBusContext *dbus = SDL_DBus_GetContext();
   525     
   526     if (IBus_CheckConnection(dbus)) {
   527         DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
   528                                                          input_ctx_path,
   529                                                          IBUS_INPUT_INTERFACE,
   530                                                          method);
   531         if (msg) {
   532             if (dbus->connection_send(ibus_conn, msg, NULL)) {
   533                 dbus->connection_flush(ibus_conn);
   534             }
   535             dbus->message_unref(msg);
   536         }
   537     }
   538 }
   539 
   540 void
   541 SDL_IBus_SetFocus(SDL_bool focused)
   542 { 
   543     const char *method = focused ? "FocusIn" : "FocusOut";
   544     IBus_SimpleMessage(method);
   545 }
   546 
   547 void
   548 SDL_IBus_Reset(void)
   549 {
   550     IBus_SimpleMessage("Reset");
   551 }
   552 
   553 SDL_bool
   554 SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
   555 { 
   556     SDL_bool result = SDL_FALSE;   
   557     SDL_DBusContext *dbus = SDL_DBus_GetContext();
   558     
   559     if (IBus_CheckConnection(dbus)) {
   560         DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
   561                                                          input_ctx_path,
   562                                                          IBUS_INPUT_INTERFACE,
   563                                                          "ProcessKeyEvent");
   564         if (msg) {
   565             Uint32 mods = IBus_ModState();
   566             dbus->message_append_args(msg,
   567                                       DBUS_TYPE_UINT32, &keysym,
   568                                       DBUS_TYPE_UINT32, &keycode,
   569                                       DBUS_TYPE_UINT32, &mods,
   570                                       DBUS_TYPE_INVALID);
   571         }
   572         
   573         if (msg) {
   574             DBusMessage *reply;
   575             
   576             reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 300, NULL);
   577             if (reply) {
   578                 if (!dbus->message_get_args(reply, NULL,
   579                                            DBUS_TYPE_BOOLEAN, &result,
   580                                            DBUS_TYPE_INVALID)) {
   581                     result = SDL_FALSE;                         
   582                 }
   583                 dbus->message_unref(reply);
   584             }
   585             dbus->message_unref(msg);
   586         }
   587         
   588     }
   589     
   590     SDL_IBus_UpdateTextRect(NULL);
   591 
   592     return result;
   593 }
   594 
   595 void
   596 SDL_IBus_UpdateTextRect(SDL_Rect *rect)
   597 {
   598     SDL_Window *focused_win;
   599     SDL_SysWMinfo info;
   600     int x = 0, y = 0;
   601     SDL_DBusContext *dbus;
   602 
   603     if (rect) {
   604         SDL_memcpy(&ibus_cursor_rect, rect, sizeof(ibus_cursor_rect));
   605     }
   606 
   607     focused_win = SDL_GetKeyboardFocus();
   608     if (!focused_win) {
   609         return;
   610     }
   611 
   612     SDL_VERSION(&info.version);
   613     if (!SDL_GetWindowWMInfo(focused_win, &info)) {
   614         return;
   615     }
   616 
   617     SDL_GetWindowPosition(focused_win, &x, &y);
   618    
   619 #if SDL_VIDEO_DRIVER_X11    
   620     if (info.subsystem == SDL_SYSWM_X11) {
   621         SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(focused_win)->driverdata;
   622             
   623         Display *x_disp = info.info.x11.display;
   624         Window x_win = info.info.x11.window;
   625         int x_screen = displaydata->screen;
   626         Window unused;
   627             
   628         X11_XTranslateCoordinates(x_disp, x_win, RootWindow(x_disp, x_screen), 0, 0, &x, &y, &unused);
   629     }
   630 #endif
   631 
   632     x += ibus_cursor_rect.x;
   633     y += ibus_cursor_rect.y;
   634         
   635     dbus = SDL_DBus_GetContext();
   636     
   637     if (IBus_CheckConnection(dbus)) {
   638         DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
   639                                                          input_ctx_path,
   640                                                          IBUS_INPUT_INTERFACE,
   641                                                          "SetCursorLocation");
   642         if (msg) {
   643             dbus->message_append_args(msg,
   644                                       DBUS_TYPE_INT32, &x,
   645                                       DBUS_TYPE_INT32, &y,
   646                                       DBUS_TYPE_INT32, &ibus_cursor_rect.w,
   647                                       DBUS_TYPE_INT32, &ibus_cursor_rect.h,
   648                                       DBUS_TYPE_INVALID);
   649         }
   650         
   651         if (msg) {
   652             if (dbus->connection_send(ibus_conn, msg, NULL)) {
   653                 dbus->connection_flush(ibus_conn);
   654             }
   655             dbus->message_unref(msg);
   656         }
   657     }
   658 }
   659 
   660 void
   661 SDL_IBus_PumpEvents(void)
   662 {
   663     SDL_DBusContext *dbus = SDL_DBus_GetContext();
   664     
   665     if (IBus_CheckConnection(dbus)) {
   666         dbus->connection_read_write(ibus_conn, 0);
   667     
   668         while (dbus->connection_dispatch(ibus_conn) == DBUS_DISPATCH_DATA_REMAINS) {
   669             /* Do nothing, actual work happens in IBus_MessageFilter */
   670         }
   671     }
   672 }
   673 
   674 #endif