src/core/linux/SDL_ibus.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 21 Aug 2014 23:15:17 -0400
changeset 9107 6485aa2e421c
parent 9098 064ea0b1275c
child 9108 8200b1bdcf83
permissions -rw-r--r--
Adjusted code style slightly for SDL_ibus.c
     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     DBusMessageIter sub1, sub2;
    75 
    76     if (dbus->message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT) {
    77         return NULL;
    78     }
    79     
    80     dbus->message_iter_recurse(iter, &sub1);
    81     
    82     if (dbus->message_iter_get_arg_type(&sub1) != DBUS_TYPE_STRUCT) {
    83         return NULL;
    84     }
    85     
    86     dbus->message_iter_recurse(&sub1, &sub2);
    87     
    88     if (dbus->message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
    89         return NULL;
    90     }
    91     
    92     const char *struct_id = NULL;
    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 
   133         dbus->message_iter_init(msg, &iter);
   134         
   135         const char *text = IBus_GetVariantText(conn, &iter, dbus);
   136         if (text && *text) {
   137             char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
   138             size_t text_bytes = SDL_strlen(text), i = 0;
   139             
   140             while (i < text_bytes) {
   141                 size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
   142                 SDL_SendKeyboardText(buf);
   143                 
   144                 i += sz;
   145             }
   146         }
   147         
   148         return DBUS_HANDLER_RESULT_HANDLED;
   149     }
   150     
   151     if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "UpdatePreeditText")) {
   152         DBusMessageIter iter;
   153         dbus->message_iter_init(msg, &iter);
   154         const char *text = IBus_GetVariantText(conn, &iter, dbus);
   155         
   156         if (text && *text) {
   157             char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
   158             size_t text_bytes = SDL_strlen(text), i = 0;
   159             size_t cursor = 0;
   160             
   161             while (i < text_bytes) {
   162                 size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
   163                 size_t chars = IBus_utf8_strlen(buf);
   164                 
   165                 SDL_SendEditingText(buf, cursor, chars);
   166 
   167                 i += sz;
   168                 cursor += chars;
   169             }
   170         }
   171         
   172         SDL_IBus_UpdateTextRect(NULL);
   173         
   174         return DBUS_HANDLER_RESULT_HANDLED;
   175     }
   176     
   177     if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "HidePreeditText")) {
   178         SDL_SendEditingText("", 0, 0);
   179         return DBUS_HANDLER_RESULT_HANDLED;
   180     }
   181     
   182     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
   183 }
   184 
   185 static char *
   186 IBus_ReadAddressFromFile(const char *file_path)
   187 {
   188     FILE *addr_file = fopen(file_path, "r");
   189     if (!addr_file) {
   190         return NULL;
   191     }
   192 
   193     char addr_buf[1024];
   194     SDL_bool success = SDL_FALSE;
   195 
   196     while (fgets(addr_buf, sizeof(addr_buf), addr_file)) {
   197         if (SDL_strncmp(addr_buf, "IBUS_ADDRESS=", sizeof("IBUS_ADDRESS=")-1) == 0) {
   198             size_t sz = SDL_strlen(addr_buf);
   199             if (addr_buf[sz-1] == '\n') addr_buf[sz-1] = 0;
   200             if (addr_buf[sz-2] == '\r') addr_buf[sz-2] = 0;
   201             success = SDL_TRUE;
   202             break;
   203         }
   204     }
   205 
   206     fclose(addr_file);
   207 
   208     if (success) {
   209         return SDL_strdup(addr_buf + (sizeof("IBUS_ADDRESS=") - 1));
   210     } else {
   211         return NULL;
   212     }
   213 }
   214 
   215 static char *
   216 IBus_GetDBusAddressFilename(void)
   217 {
   218     if (ibus_addr_file) {
   219         return SDL_strdup(ibus_addr_file);
   220     }
   221     
   222     SDL_DBusContext *dbus = SDL_DBus_GetContext();
   223     
   224     if (!dbus) {
   225         return NULL;
   226     }
   227     
   228     /* Use this environment variable if it exists. */
   229     const char *addr = SDL_getenv("IBUS_ADDRESS");
   230     if (addr && *addr) {
   231         return SDL_strdup(addr);
   232     }
   233     
   234     /* Otherwise, we have to get the hostname, display, machine id, config dir
   235        and look up the address from a filepath using all those bits, eek. */
   236     const char *disp_env = SDL_getenv("DISPLAY");
   237     char *display = NULL;
   238     
   239     if (!disp_env || !*disp_env) {
   240         display = SDL_strdup(":0.0");
   241     } else {
   242         display = SDL_strdup(disp_env);
   243     }
   244     
   245     const char *host = display;
   246     char *disp_num   = SDL_strrchr(display, ':'), 
   247          *screen_num = SDL_strrchr(display, '.');
   248     
   249     if (!disp_num) {
   250         SDL_free(display);
   251         return NULL;
   252     }
   253     
   254     *disp_num = 0;
   255     disp_num++;
   256     
   257     if (screen_num) {
   258         *screen_num = 0;
   259     }
   260     
   261     if (!*host) {
   262         host = "unix";
   263     }
   264         
   265     char config_dir[PATH_MAX];
   266     SDL_memset(config_dir, 0, sizeof(config_dir));
   267     
   268     const char *conf_env = SDL_getenv("XDG_CONFIG_HOME");
   269     if (conf_env && *conf_env) {
   270         SDL_strlcpy(config_dir, conf_env, sizeof(config_dir));
   271     } else {
   272         const char *home_env = SDL_getenv("HOME");
   273         if (!home_env || !*home_env) {
   274             SDL_free(display);
   275             return NULL;
   276         }
   277         SDL_snprintf(config_dir, sizeof(config_dir), "%s/.config", home_env);
   278     }
   279     
   280     char *key = dbus->get_local_machine_id();
   281     
   282     char file_path[PATH_MAX];
   283     SDL_memset(file_path, 0, sizeof(file_path));
   284     SDL_snprintf(file_path, sizeof(file_path), "%s/ibus/bus/%s-%s-%s", 
   285                                                config_dir, key, host, disp_num);
   286     dbus->free(key);
   287     SDL_free(display);
   288     
   289     return SDL_strdup(file_path);
   290 }
   291 
   292 static SDL_bool IBus_CheckConnection(SDL_DBusContext *dbus);
   293 
   294 static void
   295 IBus_SetCapabilities(void *data, const char *name, const char *old_val,
   296                                                    const char *internal_editing)
   297 {
   298     SDL_DBusContext *dbus = SDL_DBus_GetContext();
   299     
   300     if (IBus_CheckConnection(dbus)) {
   301 
   302         DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
   303                                                          input_ctx_path,
   304                                                          IBUS_INPUT_INTERFACE,
   305                                                          "SetCapabilities");
   306         if (msg) {
   307             Uint32 caps = IBUS_CAP_FOCUS;
   308             if (!(internal_editing && *internal_editing == '1')) {
   309                 caps |= IBUS_CAP_PREEDIT_TEXT;
   310             }
   311             
   312             dbus->message_append_args(msg,
   313                                       DBUS_TYPE_UINT32, &caps,
   314                                       DBUS_TYPE_INVALID);
   315         }
   316         
   317         if (msg) {
   318             if (dbus->connection_send(ibus_conn, msg, NULL)) {
   319                 dbus->connection_flush(ibus_conn);
   320             }
   321             dbus->message_unref(msg);
   322         }
   323     }
   324 }
   325 
   326 
   327 static SDL_bool
   328 IBus_SetupConnection(SDL_DBusContext *dbus, const char* addr)
   329 {
   330     const char *path = NULL;
   331     SDL_bool result = SDL_FALSE;
   332     
   333     ibus_conn = dbus->connection_open_private(addr, NULL);
   334 
   335     if (!ibus_conn) {
   336         return SDL_FALSE;
   337     }
   338 
   339     dbus->connection_flush(ibus_conn);
   340     
   341     if (!dbus->bus_register(ibus_conn, NULL)) {
   342         ibus_conn = NULL;
   343         return SDL_FALSE;
   344     }
   345     
   346     dbus->connection_flush(ibus_conn);
   347 
   348     DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
   349                                                      IBUS_PATH,
   350                                                      IBUS_INTERFACE,
   351                                                      "CreateInputContext");
   352     if (msg) {
   353         const char *client_name = "SDL2_Application";
   354         dbus->message_append_args(msg,
   355                                   DBUS_TYPE_STRING, &client_name,
   356                                   DBUS_TYPE_INVALID);
   357     }
   358     
   359     if (msg) {
   360         DBusMessage *reply;
   361         
   362         reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 1000, NULL);
   363         if (reply) {
   364             if (dbus->message_get_args(reply, NULL,
   365                                        DBUS_TYPE_OBJECT_PATH, &path,
   366                                        DBUS_TYPE_INVALID)) {
   367                 if (input_ctx_path) {
   368                     SDL_free(input_ctx_path);
   369                 }
   370                 input_ctx_path = SDL_strdup(path);
   371                 result = SDL_TRUE;                          
   372             }
   373             dbus->message_unref(reply);
   374         }
   375         dbus->message_unref(msg);
   376     }
   377 
   378     if (result) {
   379         SDL_AddHintCallback(SDL_HINT_IME_INTERNAL_EDITING, &IBus_SetCapabilities, NULL);
   380         
   381         dbus->bus_add_match(ibus_conn, "type='signal',interface='org.freedesktop.IBus.InputContext'", NULL);
   382         dbus->connection_add_filter(ibus_conn, &IBus_MessageFilter, dbus, NULL);
   383         dbus->connection_flush(ibus_conn);
   384     }
   385 
   386     SDL_IBus_SetFocus(SDL_GetKeyboardFocus() != NULL);
   387     SDL_IBus_UpdateTextRect(NULL);
   388     
   389     return result;
   390 }
   391 
   392 static SDL_bool
   393 IBus_CheckConnection(SDL_DBusContext *dbus)
   394 {
   395     if (!dbus) return SDL_FALSE;
   396     
   397     if (ibus_conn && dbus->connection_get_is_connected(ibus_conn)) {
   398         return SDL_TRUE;
   399     }
   400     
   401     if (inotify_fd > 0 && inotify_wd > 0) {
   402         char buf[1024];
   403         ssize_t readsize = read(inotify_fd, buf, sizeof(buf));
   404         if (readsize > 0) {
   405         
   406             char *p;
   407             SDL_bool file_updated = SDL_FALSE;
   408             
   409             for (p = buf; p < buf + readsize; /**/) {
   410                 struct inotify_event *event = (struct inotify_event*) p;
   411                 if (event->len > 0) {
   412                     char *addr_file_no_path = SDL_strrchr(ibus_addr_file, '/');
   413                     if (!addr_file_no_path) return SDL_FALSE;
   414                  
   415                     if (SDL_strcmp(addr_file_no_path + 1, event->name) == 0) {
   416                         file_updated = SDL_TRUE;
   417                         break;
   418                     }
   419                 }
   420                 
   421                 p += sizeof(struct inotify_event) + event->len;
   422             }
   423             
   424             if (file_updated) {
   425                 char *addr = IBus_ReadAddressFromFile(ibus_addr_file);
   426                 if (addr) {
   427                     SDL_bool result = IBus_SetupConnection(dbus, addr);
   428                     SDL_free(addr);
   429                     return result;
   430                 }
   431             }
   432         }
   433     }
   434     
   435     return SDL_FALSE;
   436 }
   437 
   438 SDL_bool
   439 SDL_IBus_Init(void)
   440 {
   441     SDL_bool result = SDL_FALSE;
   442     SDL_DBusContext *dbus = SDL_DBus_GetContext();
   443     
   444     if (dbus) {
   445         char *addr_file = IBus_GetDBusAddressFilename();
   446         if (!addr_file) {
   447             return SDL_FALSE;
   448         }
   449         
   450         ibus_addr_file = SDL_strdup(addr_file);
   451         
   452         char *addr = IBus_ReadAddressFromFile(addr_file);
   453         
   454         if (inotify_fd < 0) {
   455             inotify_fd = inotify_init();
   456             fcntl(inotify_fd, F_SETFL, O_NONBLOCK);
   457         }
   458         
   459         char *addr_file_dir = SDL_strrchr(addr_file, '/');
   460         if (addr_file_dir) {
   461             *addr_file_dir = 0;
   462         }
   463         
   464         inotify_wd = inotify_add_watch(inotify_fd, addr_file, IN_CREATE | IN_MODIFY);
   465         SDL_free(addr_file);
   466         
   467         result = IBus_SetupConnection(dbus, addr);
   468         SDL_free(addr);
   469     }
   470     
   471     return result;
   472 }
   473 
   474 void
   475 SDL_IBus_Quit(void)
   476 {   
   477     if (input_ctx_path) {
   478         SDL_free(input_ctx_path);
   479         input_ctx_path = NULL;
   480     }
   481     
   482     if (ibus_addr_file) {
   483         SDL_free(ibus_addr_file);
   484         ibus_addr_file = NULL;
   485     }
   486     
   487     SDL_DBusContext *dbus = SDL_DBus_GetContext();
   488     
   489     if (dbus && ibus_conn) {
   490         dbus->connection_close(ibus_conn);
   491         dbus->connection_unref(ibus_conn);
   492     }
   493     
   494     if (inotify_fd > 0 && inotify_wd > 0) {
   495         inotify_rm_watch(inotify_fd, inotify_wd);
   496         inotify_wd = -1;
   497     }
   498     
   499     SDL_DelHintCallback(SDL_HINT_IME_INTERNAL_EDITING, &IBus_SetCapabilities, NULL);
   500     
   501     SDL_memset(&ibus_cursor_rect, 0, sizeof(ibus_cursor_rect));
   502 }
   503 
   504 static void
   505 IBus_SimpleMessage(const char *method)
   506 {   
   507     SDL_DBusContext *dbus = SDL_DBus_GetContext();
   508     
   509     if (IBus_CheckConnection(dbus)) {
   510         DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
   511                                                          input_ctx_path,
   512                                                          IBUS_INPUT_INTERFACE,
   513                                                          method);
   514         if (msg) {
   515             if (dbus->connection_send(ibus_conn, msg, NULL)) {
   516                 dbus->connection_flush(ibus_conn);
   517             }
   518             dbus->message_unref(msg);
   519         }
   520     }
   521 }
   522 
   523 void
   524 SDL_IBus_SetFocus(SDL_bool focused)
   525 { 
   526     const char *method = focused ? "FocusIn" : "FocusOut";
   527     IBus_SimpleMessage(method);
   528 }
   529 
   530 void
   531 SDL_IBus_Reset(void)
   532 {
   533     IBus_SimpleMessage("Reset");
   534 }
   535 
   536 SDL_bool
   537 SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
   538 { 
   539     SDL_bool result = SDL_FALSE;   
   540     SDL_DBusContext *dbus = SDL_DBus_GetContext();
   541     
   542     if (IBus_CheckConnection(dbus)) {
   543         DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
   544                                                          input_ctx_path,
   545                                                          IBUS_INPUT_INTERFACE,
   546                                                          "ProcessKeyEvent");
   547         if (msg) {
   548             Uint32 mods = IBus_ModState();
   549             dbus->message_append_args(msg,
   550                                       DBUS_TYPE_UINT32, &keysym,
   551                                       DBUS_TYPE_UINT32, &keycode,
   552                                       DBUS_TYPE_UINT32, &mods,
   553                                       DBUS_TYPE_INVALID);
   554         }
   555         
   556         if (msg) {
   557             DBusMessage *reply;
   558             
   559             reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 300, NULL);
   560             if (reply) {
   561                 if (!dbus->message_get_args(reply, NULL,
   562                                            DBUS_TYPE_BOOLEAN, &result,
   563                                            DBUS_TYPE_INVALID)) {
   564                     result = SDL_FALSE;                         
   565                 }
   566                 dbus->message_unref(reply);
   567             }
   568             dbus->message_unref(msg);
   569         }
   570         
   571     }
   572     
   573     SDL_IBus_UpdateTextRect(NULL);
   574 
   575     return result;
   576 }
   577 
   578 void
   579 SDL_IBus_UpdateTextRect(SDL_Rect *rect)
   580 {
   581     if (rect) {
   582         SDL_memcpy(&ibus_cursor_rect, rect, sizeof(ibus_cursor_rect));
   583     }
   584     
   585     SDL_Window *focused_win = SDL_GetKeyboardFocus();
   586 
   587     if (!focused_win) {
   588         return;
   589     }
   590 
   591     SDL_SysWMinfo info;
   592     SDL_VERSION(&info.version);
   593     
   594     if (!SDL_GetWindowWMInfo(focused_win, &info)) {
   595         return;
   596     }
   597     
   598     int x = 0, y = 0;
   599     
   600     SDL_GetWindowPosition(focused_win, &x, &y);
   601    
   602 #if SDL_VIDEO_DRIVER_X11    
   603     if (info.subsystem == SDL_SYSWM_X11) {
   604         SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(focused_win)->driverdata;
   605             
   606         Display *x_disp = info.info.x11.display;
   607         Window x_win = info.info.x11.window;
   608         int x_screen = displaydata->screen;
   609         Window unused;
   610             
   611         X11_XTranslateCoordinates(x_disp, x_win, RootWindow(x_disp, x_screen), 0, 0, &x, &y, &unused);
   612     }
   613 #endif
   614 
   615     x += ibus_cursor_rect.x;
   616     y += ibus_cursor_rect.y;
   617         
   618     SDL_DBusContext *dbus = SDL_DBus_GetContext();
   619     
   620     if (IBus_CheckConnection(dbus)) {
   621         DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
   622                                                          input_ctx_path,
   623                                                          IBUS_INPUT_INTERFACE,
   624                                                          "SetCursorLocation");
   625         if (msg) {
   626             dbus->message_append_args(msg,
   627                                       DBUS_TYPE_INT32, &x,
   628                                       DBUS_TYPE_INT32, &y,
   629                                       DBUS_TYPE_INT32, &ibus_cursor_rect.w,
   630                                       DBUS_TYPE_INT32, &ibus_cursor_rect.h,
   631                                       DBUS_TYPE_INVALID);
   632         }
   633         
   634         if (msg) {
   635             if (dbus->connection_send(ibus_conn, msg, NULL)) {
   636                 dbus->connection_flush(ibus_conn);
   637             }
   638             dbus->message_unref(msg);
   639         }
   640     }
   641 }
   642 
   643 void
   644 SDL_IBus_PumpEvents(void)
   645 {
   646     SDL_DBusContext *dbus = SDL_DBus_GetContext();
   647     
   648     if (IBus_CheckConnection(dbus)) {
   649         dbus->connection_read_write(ibus_conn, 0);
   650     
   651         while (dbus->connection_dispatch(ibus_conn) == DBUS_DISPATCH_DATA_REMAINS) {
   652             /* Do nothing, actual work happens in IBus_MessageFilter */
   653         }
   654     }
   655 }
   656 
   657 #endif