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