Selaa lähdekoodia

Add IBus IME Support, move DBus code to its own file. (v3.3 squashed)

Alex Baines 10 vuotta sitten
vanhempi
commit
41a39837ca

+ 43 - 0
configure.in

@@ -2130,6 +2130,43 @@ AC_HELP_STRING([--enable-dbus], [enable D-Bus support [[default=yes]]]),
             if test x$have_dbus_dbus_h_hdr = xyes; then
                 AC_DEFINE(HAVE_DBUS_DBUS_H, 1, [ ])
                 EXTRA_CFLAGS="$EXTRA_CFLAGS $DBUS_CFLAGS"
+                SOURCES="$SOURCES $srcdir/src/core/linux/SDL_dbus.c"
+            fi
+        fi
+    fi
+}
+
+dnl See if the platform has libibus IME support.
+CheckIBus()
+{
+    AC_ARG_ENABLE(ibus,
+AC_HELP_STRING([--enable-ibus], [enable IBus support [[default=yes]]]),
+                  , enable_ibus=yes)
+    if test x$enable_ibus = xyes; then
+        AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
+        if test x$PKG_CONFIG != xno; then
+            IBUS_CFLAGS=`$PKG_CONFIG --cflags ibus-1.0`
+            save_CFLAGS="$CFLAGS"
+            CFLAGS="$save_CFLAGS $IBUS_CFLAGS"
+            AC_CHECK_HEADER(ibus-1.0/ibus.h,
+                            have_ibus_ibus_h_hdr=yes,
+                            have_ibus_ibus_h_hdr=no)
+            AC_CHECK_HEADER(sys/inotify.h,
+                            have_inotify_inotify_h_hdr=yes,
+                            have_inotify_inotify_h_hdr=no)
+            CFLAGS="$save_CFLAGS"
+            if test x$have_ibus_ibus_h_hdr = xyes; then
+                if test x$enable_dbus != xyes; then
+                    AC_MSG_WARN([DBus support is required for IBus.])
+                    have_ibus_ibus_h_hdr=no
+                elif test x$have_inotify_inotify_h_hdr != xyes; then
+                    AC_MSG_WARN([INotify support is required for IBus.])
+                    have_ibus_ibus_h_hdr=no
+                else
+                    AC_DEFINE(HAVE_IBUS_IBUS_H, 1, [ ])
+                    EXTRA_CFLAGS="$EXTRA_CFLAGS $IBUS_CFLAGS"
+                    SOURCES="$SOURCES $srcdir/src/core/linux/SDL_ibus.c"
+               fi
             fi
         fi
     fi
@@ -2732,6 +2769,7 @@ case "$host" in
         CheckWayland
         CheckLibUDev
         CheckDBus
+        CheckIBus
         CheckInputEvents
         CheckInputKD
         CheckTslib
@@ -3347,6 +3385,11 @@ if test x$have_dbus_dbus_h_hdr = xyes; then
 else
     SUMMARY="${SUMMARY}Using dbus      : NO\n"
 fi
+if test x$have_ibus_ibus_h_hdr = xyes; then
+    SUMMARY="${SUMMARY}Using ibus      : YES\n"
+else
+    SUMMARY="${SUMMARY}Using ibus      : NO\n"
+fi
 AC_CONFIG_COMMANDS([summary], [echo -en "$SUMMARY"], [SUMMARY="$SUMMARY"])
 
 AC_OUTPUT

+ 1 - 0
include/SDL_config.h.in

@@ -78,6 +78,7 @@
 #undef HAVE_PTHREAD_NP_H
 #undef HAVE_LIBUDEV_H
 #undef HAVE_DBUS_DBUS_H
+#undef HAVE_IBUS_IBUS_H
 
 /* C library functions */
 #undef HAVE_MALLOC

+ 236 - 0
src/core/linux/SDL_dbus.c

@@ -0,0 +1,236 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+#include "SDL_dbus.h"
+
+#if SDL_USE_LIBDBUS
+/* we never link directly to libdbus. */
+#include "SDL_loadso.h"
+static const char *dbus_library = "libdbus-1.so.3";
+static void *dbus_handle = NULL;
+static unsigned int screensaver_cookie = 0;
+static SDL_DBusContext dbus = {0};
+
+static int
+load_dbus_syms(void)
+{
+    #define SDL_DBUS_SYM2(x, y) \
+        if (!(dbus.x = SDL_LoadFunction(dbus_handle, #y))) return -1
+        
+    #define SDL_DBUS_SYM(x) \
+        SDL_DBUS_SYM2(x, dbus_##x)
+
+    SDL_DBUS_SYM(bus_get_private);
+    SDL_DBUS_SYM(bus_register);
+    SDL_DBUS_SYM(bus_add_match);
+    SDL_DBUS_SYM(connection_open_private);
+    SDL_DBUS_SYM(connection_set_exit_on_disconnect);
+    SDL_DBUS_SYM(connection_get_is_connected);
+    SDL_DBUS_SYM(connection_add_filter);
+    SDL_DBUS_SYM(connection_send);
+    SDL_DBUS_SYM(connection_send_with_reply_and_block);
+    SDL_DBUS_SYM(connection_close);
+    SDL_DBUS_SYM(connection_unref);
+    SDL_DBUS_SYM(connection_flush);
+    SDL_DBUS_SYM(connection_read_write);
+    SDL_DBUS_SYM(connection_dispatch);
+    SDL_DBUS_SYM(message_is_signal);
+    SDL_DBUS_SYM(message_new_method_call);
+    SDL_DBUS_SYM(message_append_args);
+    SDL_DBUS_SYM(message_get_args);
+    SDL_DBUS_SYM(message_iter_init);
+    SDL_DBUS_SYM(message_iter_next);
+    SDL_DBUS_SYM(message_iter_get_basic);
+    SDL_DBUS_SYM(message_iter_get_arg_type);
+    SDL_DBUS_SYM(message_iter_recurse);
+    SDL_DBUS_SYM(message_unref);
+    SDL_DBUS_SYM(error_init);
+    SDL_DBUS_SYM(error_is_set);
+    SDL_DBUS_SYM(error_free);
+    SDL_DBUS_SYM(get_local_machine_id);
+    SDL_DBUS_SYM(free);
+
+    #undef SDL_DBUS_SYM
+    #undef SDL_DBUS_SYM2
+
+    return 0;
+}
+
+static void
+UnloadDBUSLibrary(void)
+{
+    if (dbus_handle != NULL) {
+        SDL_UnloadObject(dbus_handle);
+        dbus_handle = NULL;
+    }
+}
+
+static int
+LoadDBUSLibrary(void)
+{
+    int retval = 0;
+    if (dbus_handle == NULL) {
+        dbus_handle = SDL_LoadObject(dbus_library);
+        if (dbus_handle == NULL) {
+            retval = -1;
+            /* Don't call SDL_SetError(): SDL_LoadObject already did. */
+        } else {
+            retval = load_dbus_syms();
+            if (retval < 0) {
+                UnloadDBUSLibrary();
+            }
+        }
+    }
+
+    return retval;
+}
+
+void
+SDL_DBus_Init(void)
+{
+    if (LoadDBUSLibrary() != -1) {
+        DBusError err;
+        dbus.error_init(&err);
+        dbus.session_conn = dbus.bus_get_private(DBUS_BUS_SESSION, &err);
+        if (dbus.error_is_set(&err)) {
+            dbus.error_free(&err);
+            if (dbus.session_conn) {
+                dbus.connection_unref(dbus.session_conn);
+                dbus.session_conn = NULL;
+            }
+            return;  /* oh well */
+        }
+        dbus.connection_set_exit_on_disconnect(dbus.session_conn, 0);
+    }
+}
+
+void
+SDL_DBus_Quit(void)
+{
+    if (dbus.session_conn) {
+        dbus.connection_close(dbus.session_conn);
+        dbus.connection_unref(dbus.session_conn);
+        SDL_memset(&dbus, 0, sizeof(dbus));
+    }
+    UnloadDBUSLibrary();
+}
+
+SDL_DBusContext *
+SDL_DBus_GetContext(void)
+{
+    if(!dbus_handle || !dbus.session_conn){
+        SDL_DBus_Init();
+    }
+    
+    if(dbus_handle && dbus.session_conn){
+        return &dbus;
+    } else {
+        return NULL;
+    }
+}
+
+void
+SDL_DBus_ScreensaverTickle(void)
+{
+    DBusConnection *conn = dbus.session_conn;
+    if (conn != NULL) {
+        DBusMessage *msg = dbus.message_new_method_call("org.gnome.ScreenSaver",
+                                                        "/org/gnome/ScreenSaver",
+                                                        "org.gnome.ScreenSaver",
+                                                        "SimulateUserActivity");
+        if (msg != NULL) {
+            if (dbus.connection_send(conn, msg, NULL)) {
+                dbus.connection_flush(conn);
+            }
+            dbus.message_unref(msg);
+        }
+    }
+}
+
+SDL_bool
+SDL_DBus_ScreensaverInhibit(SDL_bool inhibit)
+{
+    DBusConnection *conn = dbus.session_conn;
+
+    if (conn == NULL)
+        return SDL_FALSE;
+
+    if (inhibit &&
+        screensaver_cookie != 0)
+        return SDL_TRUE;
+    if (!inhibit &&
+        screensaver_cookie == 0)
+        return SDL_TRUE;
+
+    if (inhibit) {
+        const char *app = "My SDL application";
+        const char *reason = "Playing a game";
+
+        DBusMessage *msg = dbus.message_new_method_call("org.freedesktop.ScreenSaver",
+                                                         "/org/freedesktop/ScreenSaver",
+                                                         "org.freedesktop.ScreenSaver",
+                                                         "Inhibit");
+        if (msg != NULL) {
+            dbus.message_append_args (msg,
+                                      DBUS_TYPE_STRING, &app,
+                                      DBUS_TYPE_STRING, &reason,
+                                      DBUS_TYPE_INVALID);
+        }
+
+        if (msg != NULL) {
+            DBusMessage *reply;
+
+            reply = dbus.connection_send_with_reply_and_block(conn, msg, 300, NULL);
+            if (reply) {
+                if (!dbus.message_get_args(reply, NULL,
+                                           DBUS_TYPE_UINT32, &screensaver_cookie,
+                                           DBUS_TYPE_INVALID))
+                    screensaver_cookie = 0;
+                dbus.message_unref(reply);
+            }
+
+            dbus.message_unref(msg);
+        }
+
+        if (screensaver_cookie == 0) {
+            return SDL_FALSE;
+        }
+        return SDL_TRUE;
+    } else {
+        DBusMessage *msg = dbus.message_new_method_call("org.freedesktop.ScreenSaver",
+                                                        "/org/freedesktop/ScreenSaver",
+                                                        "org.freedesktop.ScreenSaver",
+                                                        "UnInhibit");
+        dbus.message_append_args (msg,
+                                  DBUS_TYPE_UINT32, &screensaver_cookie,
+                                  DBUS_TYPE_INVALID);
+        if (msg != NULL) {
+            if (dbus.connection_send(conn, msg, NULL)) {
+                dbus.connection_flush(conn);
+            }
+            dbus.message_unref(msg);
+        }
+
+        screensaver_cookie = 0;
+        return SDL_TRUE;
+    }
+}
+#endif

+ 79 - 0
src/core/linux/SDL_dbus.h

@@ -0,0 +1,79 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "../../SDL_internal.h"
+
+#ifndef _SDL_dbus_h
+#define _SDL_dbus_h
+
+#ifdef HAVE_DBUS_DBUS_H
+#define SDL_USE_LIBDBUS 1
+#include "SDL_stdinc.h"
+#include <dbus/dbus.h>
+
+
+typedef struct SDL_DBusContext {
+    DBusConnection *session_conn;
+
+    DBusConnection *(*bus_get_private)(DBusBusType, DBusError *);
+    dbus_bool_t (*bus_register)(DBusConnection *, DBusError *);
+    void (*bus_add_match)(DBusConnection *, const char *, DBusError *);
+    DBusConnection * (*connection_open_private)(const char *, DBusError *);
+    void (*connection_set_exit_on_disconnect)(DBusConnection *, dbus_bool_t);
+    dbus_bool_t (*connection_get_is_connected)(DBusConnection *); 	
+    dbus_bool_t (*connection_add_filter)(DBusConnection *, DBusHandleMessageFunction,
+	    void *, DBusFreeFunction);
+    dbus_bool_t (*connection_send)(DBusConnection *, DBusMessage *, dbus_uint32_t *);
+    DBusMessage *(*connection_send_with_reply_and_block)(DBusConnection *, DBusMessage *, int, DBusError *);
+    void (*connection_close)(DBusConnection *);
+    void (*connection_unref)(DBusConnection *);
+    void (*connection_flush)(DBusConnection *);
+    dbus_bool_t (*connection_read_write)(DBusConnection *, int);
+    DBusDispatchStatus (*connection_dispatch)(DBusConnection *);
+    dbus_bool_t (*message_is_signal)(DBusMessage *, const char *, const char *); 	
+    DBusMessage *(*message_new_method_call)(const char *, const char *, const char *, const char *);
+    dbus_bool_t (*message_append_args)(DBusMessage *, int, ...);
+    dbus_bool_t (*message_get_args)(DBusMessage *, DBusError *, int, ...);
+    dbus_bool_t (*message_iter_init)(DBusMessage *, DBusMessageIter *);
+    dbus_bool_t (*message_iter_next)(DBusMessageIter *);
+    void (*message_iter_get_basic)(DBusMessageIter *, void *);
+    int (*message_iter_get_arg_type)(DBusMessageIter *);
+    void (*message_iter_recurse)(DBusMessageIter *, DBusMessageIter *); 	 	
+    void (*message_unref)(DBusMessage *);
+    void (*error_init)(DBusError *);
+    dbus_bool_t (*error_is_set)(const DBusError *);
+    void (*error_free)(DBusError *);
+    char *(*get_local_machine_id)(void);
+    void (*free)(void *); 	 	
+
+} SDL_DBusContext;
+
+extern void SDL_DBus_Init(void);
+extern void SDL_DBus_Quit(void);
+extern SDL_DBusContext * SDL_DBus_GetContext(void);
+extern void SDL_DBus_ScreensaverTickle(void);
+extern SDL_bool SDL_DBus_ScreensaverInhibit(SDL_bool inhibit);
+
+#endif /* HAVE_DBUS_DBUS_H */
+
+#endif /* _SDL_dbus_h */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 593 - 0
src/core/linux/SDL_ibus.c

@@ -0,0 +1,593 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifdef HAVE_IBUS_IBUS_H
+#include "SDL.h"
+#include "SDL_ibus.h"
+#include "SDL_dbus.h"
+#include "../../video/SDL_sysvideo.h"
+#include "../../events/SDL_keyboard_c.h"
+#include <sys/inotify.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+static const char IBUS_SERVICE[]         = "org.freedesktop.IBus";
+static const char IBUS_PATH[]            = "/org/freedesktop/IBus";
+static const char IBUS_INTERFACE[]       = "org.freedesktop.IBus";
+static const char IBUS_INPUT_INTERFACE[] = "org.freedesktop.IBus.InputContext";
+
+static char *input_ctx_path = NULL;
+static SDL_Rect ibus_cursor_rect = {0};
+static DBusConnection *ibus_conn = NULL;
+static char *ibus_addr_file = NULL;
+int inotify_fd = -1;
+
+static Uint32
+IBus_ModState(void)
+{
+    Uint32 ibus_mods = 0;
+    SDL_Keymod sdl_mods = SDL_GetModState();
+    
+    /* Not sure about MOD3, MOD4 and HYPER mappings */
+    if(sdl_mods & KMOD_LSHIFT) ibus_mods |= IBUS_SHIFT_MASK;
+    if(sdl_mods & KMOD_CAPS)   ibus_mods |= IBUS_LOCK_MASK;
+    if(sdl_mods & KMOD_LCTRL)  ibus_mods |= IBUS_CONTROL_MASK;
+    if(sdl_mods & KMOD_LALT)   ibus_mods |= IBUS_MOD1_MASK;
+    if(sdl_mods & KMOD_NUM)    ibus_mods |= IBUS_MOD2_MASK;
+    if(sdl_mods & KMOD_MODE)   ibus_mods |= IBUS_MOD5_MASK;
+    if(sdl_mods & KMOD_LGUI)   ibus_mods |= IBUS_SUPER_MASK;
+    if(sdl_mods & KMOD_RGUI)   ibus_mods |= IBUS_META_MASK;
+
+    return ibus_mods;
+}
+
+static const char *
+IBus_GetVariantText(DBusConnection *conn, DBusMessageIter *iter, SDL_DBusContext *dbus)
+{
+    /* The text we need is nested weirdly, use dbus-monitor to see the structure better */
+    const char *text = NULL;
+    DBusMessageIter sub1, sub2;
+
+    if(dbus->message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT){
+        return NULL;
+    }
+    
+    dbus->message_iter_recurse(iter, &sub1);
+    
+    if(dbus->message_iter_get_arg_type(&sub1) != DBUS_TYPE_STRUCT){
+        return NULL;
+    }
+    
+    dbus->message_iter_recurse(&sub1, &sub2);
+    
+    if(dbus->message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING){
+        return NULL;
+    }
+    
+    const char *struct_id = NULL;
+    dbus->message_iter_get_basic(&sub2, &struct_id);
+    if(!struct_id || SDL_strncmp(struct_id, "IBusText", sizeof("IBusText")) != 0){
+        return NULL;
+    }
+    
+    dbus->message_iter_next(&sub2);
+    dbus->message_iter_next(&sub2);
+    
+    if(dbus->message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING){
+        return NULL;
+    }
+    
+    dbus->message_iter_get_basic(&sub2, &text);
+    
+    return text;
+}
+
+static size_t 
+IBus_utf8_strlen(const char *str)
+{
+    size_t utf8_len = 0;
+    const char *p;
+    
+    for(p = str; *p; ++p){
+        if(!((*p & 0x80) && !(*p & 0x40))){
+            ++utf8_len;
+        }
+    }
+    
+    return utf8_len;
+}
+
+static DBusHandlerResult
+IBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *user_data)
+{
+    SDL_DBusContext *dbus = (SDL_DBusContext *)user_data;
+        
+    if(dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "CommitText")){
+        DBusMessageIter iter;
+        dbus->message_iter_init(msg, &iter);
+        
+        const char *text = IBus_GetVariantText(conn, &iter, dbus);
+        if(text && *text){
+            char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
+            size_t text_bytes = SDL_strlen(text), i = 0;
+            
+            while(i < text_bytes){
+                size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
+                SDL_SendKeyboardText(buf);
+                
+                i += sz;
+            }
+        }
+        
+        return DBUS_HANDLER_RESULT_HANDLED;
+    }
+    
+    if(dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "UpdatePreeditText")){
+        DBusMessageIter iter;
+        dbus->message_iter_init(msg, &iter);
+        const char *text = IBus_GetVariantText(conn, &iter, dbus);
+        
+        if(text && *text){
+            char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
+            size_t text_bytes = SDL_strlen(text), i = 0;
+            size_t cursor = 0;
+            
+            while(i < text_bytes){
+                size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
+                size_t chars = IBus_utf8_strlen(buf);
+                
+                SDL_SendEditingText(buf, cursor, chars);
+
+                i += sz;
+                cursor += chars;
+            }
+        } else {
+            SDL_SendEditingText("", 0, 0);
+        }
+        
+        SDL_IBus_UpdateTextRect(NULL);
+        
+        return DBUS_HANDLER_RESULT_HANDLED;
+    }
+    
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static char *
+IBus_ReadAddressFromFile(const char *file_path)
+{
+    FILE *addr_file = fopen(file_path, "r");
+    if(!addr_file){
+        return NULL;
+    }
+
+    char addr_buf[1024];
+    SDL_bool success = SDL_FALSE;
+
+    while(fgets(addr_buf, sizeof(addr_buf), addr_file)){
+        if(SDL_strncmp(addr_buf, "IBUS_ADDRESS=", sizeof("IBUS_ADDRESS=")-1) == 0){
+            size_t sz = SDL_strlen(addr_buf);
+            if(addr_buf[sz-1] == '\n') addr_buf[sz-1] = 0;
+            if(addr_buf[sz-2] == '\r') addr_buf[sz-2] = 0;
+            success = SDL_TRUE;
+            break;
+        }
+    }
+
+    fclose(addr_file);
+
+    if(success){
+        return SDL_strdup(addr_buf + (sizeof("IBUS_ADDRESS=") - 1));
+    } else {
+        return NULL;
+    }
+}
+
+static char *
+IBus_GetDBusAddressFilename(void)
+{
+    if(ibus_addr_file){
+        return SDL_strdup(ibus_addr_file);
+    }
+    
+    SDL_DBusContext *dbus = SDL_DBus_GetContext();
+    
+    if(!dbus){
+        return NULL;
+    }
+    
+    /* Use this environment variable if it exists. */
+    const char *addr = SDL_getenv("IBUS_ADDRESS");
+    if(addr && *addr){
+        return SDL_strdup(addr);
+    }
+    
+    /* Otherwise, we have to get the hostname, display, machine id, config dir
+       and look up the address from a filepath using all those bits, eek. */
+    const char *disp_env = SDL_getenv("DISPLAY");
+    char *display = NULL;
+    
+    if(!disp_env || !*disp_env){
+        display = SDL_strdup(":0.0");
+    } else {
+        display = SDL_strdup(disp_env);
+    }
+    
+    const char *host = display;
+    char *disp_num   = SDL_strrchr(display, ':'), 
+         *screen_num = SDL_strrchr(display, '.');
+    
+    if(!disp_num){
+        SDL_free(display);
+        return NULL;
+    }
+    
+    *disp_num = 0;
+    disp_num++;
+    
+    if(screen_num){
+        *screen_num = 0;
+    }
+    
+    if(!*host){
+        host = "unix";
+    }
+        
+    char config_dir[PATH_MAX];
+    SDL_memset(config_dir, 0, sizeof(config_dir));
+    
+    const char *conf_env = SDL_getenv("XDG_CONFIG_HOME");
+    if(conf_env && *conf_env){
+        SDL_strlcpy(config_dir, conf_env, sizeof(config_dir));
+    } else {
+        const char *home_env = SDL_getenv("HOME");
+        if(!home_env || !*home_env){
+            SDL_free(display);
+            return NULL;
+        }
+        SDL_snprintf(config_dir, sizeof(config_dir), "%s/.config", home_env);
+    }
+    
+    char *key = dbus->get_local_machine_id();
+    
+    char file_path[PATH_MAX];
+    SDL_memset(file_path, 0, sizeof(file_path));
+    SDL_snprintf(file_path, sizeof(file_path), "%s/ibus/bus/%s-%s-%s", 
+                                               config_dir, key, host, disp_num);
+    dbus->free(key);
+    SDL_free(display);
+    
+    return SDL_strdup(file_path);
+}
+
+static SDL_bool
+IBus_SetupConnection(SDL_DBusContext *dbus, const char* addr)
+{
+    const char *path = NULL;
+    SDL_bool result = SDL_FALSE;
+    
+    ibus_conn = dbus->connection_open_private(addr, NULL);
+
+    if(!ibus_conn){
+        return SDL_FALSE;
+    }
+
+    dbus->connection_flush(ibus_conn);
+    
+    if(!dbus->bus_register(ibus_conn, NULL)){
+        ibus_conn = NULL;
+        return SDL_FALSE;
+    }
+    
+    dbus->connection_flush(ibus_conn);
+
+    DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
+                                                     IBUS_PATH,
+                                                     IBUS_INTERFACE,
+                                                     "CreateInputContext");
+    if(msg){
+        const char *client_name = "SDL2_Application";
+        dbus->message_append_args(msg,
+                                  DBUS_TYPE_STRING, &client_name,
+                                  DBUS_TYPE_INVALID);
+    }
+    
+    if(msg){
+        DBusMessage *reply;
+        
+        reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 1000, NULL);
+        if(reply){
+            if(dbus->message_get_args(reply, NULL,
+                                       DBUS_TYPE_OBJECT_PATH, &path,
+                                       DBUS_TYPE_INVALID)){
+                if(input_ctx_path){
+                    SDL_free(input_ctx_path);
+                }
+                input_ctx_path = SDL_strdup(path);
+                result = SDL_TRUE;                          
+            }
+            dbus->message_unref(reply);
+        }
+        dbus->message_unref(msg);
+    }
+
+    if(result){
+        DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
+                                                         input_ctx_path,
+                                                         IBUS_INPUT_INTERFACE,
+                                                         "SetCapabilities");
+        if(msg){
+            Uint32 caps = IBUS_CAP_FOCUS | IBUS_CAP_PREEDIT_TEXT;
+            dbus->message_append_args(msg,
+                                      DBUS_TYPE_UINT32, &caps,
+                                      DBUS_TYPE_INVALID);
+        }
+        
+        if(msg){
+            if(dbus->connection_send(ibus_conn, msg, NULL)){
+                dbus->connection_flush(ibus_conn);
+            }
+            dbus->message_unref(msg);
+        }
+        
+        dbus->bus_add_match(ibus_conn, "type='signal',interface='org.freedesktop.IBus.InputContext'", NULL);
+        dbus->connection_add_filter(ibus_conn, &IBus_MessageFilter, dbus, NULL);
+        dbus->connection_flush(ibus_conn);
+    }
+
+    SDL_IBus_SetFocus(SDL_GetFocusWindow() != NULL);
+    SDL_IBus_UpdateTextRect(NULL);
+    
+    return result;
+}
+
+static SDL_bool
+IBus_CheckConnection(SDL_DBusContext *dbus)
+{
+    if(!dbus) return SDL_FALSE;
+    
+    if(ibus_conn && dbus->connection_get_is_connected(ibus_conn)){
+        return SDL_TRUE;
+    }
+    
+    if(inotify_fd != -1){
+        char buf[1024];
+        ssize_t readsize = read(inotify_fd, buf, sizeof(buf));
+        if(readsize > 0){
+        
+            char *p;
+            SDL_bool file_updated = SDL_FALSE;
+            
+            for(p = buf; p < buf + readsize; /**/){
+                struct inotify_event *event = (struct inotify_event*) p;
+                if(event->len > 0){
+                    char *addr_file_no_path = SDL_strrchr(ibus_addr_file, '/');
+                    if(!addr_file_no_path) return SDL_FALSE;
+                 
+                    if(SDL_strcmp(addr_file_no_path + 1, event->name) == 0){
+                        file_updated = SDL_TRUE;
+                        break;
+                    }
+                }
+                
+                p += sizeof(struct inotify_event) + event->len;
+            }
+            
+            if(file_updated){
+                char *addr = IBus_ReadAddressFromFile(ibus_addr_file);
+                if(addr){
+                    SDL_bool result = IBus_SetupConnection(dbus, addr);
+                    SDL_free(addr);
+                    return result;
+                }
+            }
+        }
+    }
+    
+    return SDL_FALSE;
+}
+
+SDL_bool
+SDL_IBus_Init(void)
+{
+    SDL_bool result = SDL_FALSE;
+    SDL_DBusContext *dbus = SDL_DBus_GetContext();
+    
+    if(dbus){
+        char *addr_file = IBus_GetDBusAddressFilename();
+        if(!addr_file){
+            return SDL_FALSE;
+        }
+        
+        ibus_addr_file = SDL_strdup(addr_file);
+        
+        char *addr = IBus_ReadAddressFromFile(addr_file);
+        
+        inotify_fd = inotify_init();
+        fcntl(inotify_fd, F_SETFL, O_NONBLOCK);
+        
+        char *addr_file_dir = SDL_strrchr(addr_file, '/');
+        if(addr_file_dir){
+            *addr_file_dir = 0;
+        }
+        
+        inotify_add_watch(inotify_fd, addr_file, IN_CREATE | IN_MODIFY);
+        SDL_free(addr_file);
+        
+        result = IBus_SetupConnection(dbus, addr);
+        SDL_free(addr);
+    }
+    
+    return result;
+}
+
+void
+SDL_IBus_Quit(void)
+{   
+    if(input_ctx_path){
+        SDL_free(input_ctx_path);
+        input_ctx_path = NULL;
+    }
+    
+    if(ibus_addr_file){
+        SDL_free(ibus_addr_file);
+        ibus_addr_file = NULL;
+    }
+    
+    SDL_DBusContext *dbus = SDL_DBus_GetContext();
+    
+    if(dbus && ibus_conn){
+        dbus->connection_close(ibus_conn);
+        dbus->connection_unref(ibus_conn);
+    }
+    
+    SDL_memset(&ibus_cursor_rect, 0, sizeof(ibus_cursor_rect));
+}
+
+static void
+IBus_SimpleMessage(const char *method)
+{   
+    SDL_DBusContext *dbus = SDL_DBus_GetContext();
+    
+    if(IBus_CheckConnection(dbus)){
+        DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
+                                                         input_ctx_path,
+                                                         IBUS_INPUT_INTERFACE,
+                                                         method);
+        if(msg){
+            if(dbus->connection_send(ibus_conn, msg, NULL)){
+                dbus->connection_flush(ibus_conn);
+            }
+            dbus->message_unref(msg);
+        }
+    }
+}
+
+void
+SDL_IBus_SetFocus(SDL_bool focused)
+{ 
+    const char *method = focused ? "FocusIn" : "FocusOut";
+    IBus_SimpleMessage(method);
+}
+
+void
+SDL_IBus_Reset(void)
+{
+    IBus_SimpleMessage("Reset");
+}
+
+SDL_bool
+SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
+{ 
+    SDL_bool result = SDL_FALSE;   
+    SDL_DBusContext *dbus = SDL_DBus_GetContext();
+    
+    if(IBus_CheckConnection(dbus)){
+        DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
+                                                         input_ctx_path,
+                                                         IBUS_INPUT_INTERFACE,
+                                                         "ProcessKeyEvent");
+        if(msg){
+            Uint32 mods = IBus_ModState();
+            dbus->message_append_args(msg,
+                                      DBUS_TYPE_UINT32, &keysym,
+                                      DBUS_TYPE_UINT32, &keycode,
+                                      DBUS_TYPE_UINT32, &mods,
+                                      DBUS_TYPE_INVALID);
+        }
+        
+        if(msg){
+            DBusMessage *reply;
+            
+            reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 300, NULL);
+            if(reply){
+                if(!dbus->message_get_args(reply, NULL,
+                                           DBUS_TYPE_BOOLEAN, &result,
+                                           DBUS_TYPE_INVALID)){
+                    result = SDL_FALSE;                         
+                }
+                dbus->message_unref(reply);
+            }
+            dbus->message_unref(msg);
+        }
+        
+    }
+    
+    return result;
+}
+
+void
+SDL_IBus_UpdateTextRect(SDL_Rect *rect)
+{
+    if(rect){
+        SDL_memcpy(&ibus_cursor_rect, rect, sizeof(ibus_cursor_rect));
+    }
+    
+    SDL_Window *focused_win = SDL_GetFocusWindow();
+
+    if(!focused_win) return;
+
+    int x = 0, y = 0;
+    SDL_GetWindowPosition(focused_win, &x, &y);
+    x += ibus_cursor_rect.x;
+    y += ibus_cursor_rect.y;
+        
+    SDL_DBusContext *dbus = SDL_DBus_GetContext();
+    
+    if(IBus_CheckConnection(dbus)){
+        DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
+                                                         input_ctx_path,
+                                                         IBUS_INPUT_INTERFACE,
+                                                         "SetCursorLocation");
+        if(msg){
+            dbus->message_append_args(msg,
+                                      DBUS_TYPE_INT32, &x,
+                                      DBUS_TYPE_INT32, &y,
+                                      DBUS_TYPE_INT32, &ibus_cursor_rect.w,
+                                      DBUS_TYPE_INT32, &ibus_cursor_rect.h,
+                                      DBUS_TYPE_INVALID);
+        }
+        
+        if(msg){
+            if(dbus->connection_send(ibus_conn, msg, NULL)){
+                dbus->connection_flush(ibus_conn);
+            }
+            dbus->message_unref(msg);
+        }
+    }
+}
+
+void
+SDL_IBus_PumpEvents(void)
+{
+    SDL_DBusContext *dbus = SDL_DBus_GetContext();
+    
+    if(IBus_CheckConnection(dbus)){
+        dbus->connection_read_write(ibus_conn, 0);
+    
+        while(dbus->connection_dispatch(ibus_conn) == DBUS_DISPATCH_DATA_REMAINS){
+            /* Do nothing, actual work happens in IBus_MessageFilter */
+        }
+    }
+}
+
+#endif

+ 58 - 0
src/core/linux/SDL_ibus.h

@@ -0,0 +1,58 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "../../SDL_internal.h"
+
+#ifndef _SDL_ibus_h
+#define _SDL_ibus_h
+
+#ifdef HAVE_IBUS_IBUS_H
+#define SDL_USE_IBUS 1
+#include "SDL_stdinc.h"
+#include <ibus-1.0/ibus.h>
+
+extern SDL_bool SDL_IBus_Init(void);
+extern void SDL_IBus_Quit(void);
+
+/* Lets the IBus server know about changes in window focus */
+extern void SDL_IBus_SetFocus(SDL_bool focused);
+
+/* Closes the candidate list and resets any text currently being edited */
+extern void SDL_IBus_Reset(void);
+
+/* Sends a keypress event to IBus, returns SDL_TRUE if IBus used this event to
+   update its candidate list or change input methods. PumpEvents should be
+   called some time after this, to recieve the TextInput / TextEditing event back. */
+extern SDL_bool SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode);
+
+/* Update the position of IBus' candidate list. If rect is NULL then this will 
+   just reposition it relative to the focused window's new position. */
+extern void SDL_IBus_UpdateTextRect(SDL_Rect *window_relative_rect);
+
+/* Checks DBus for new IBus events, and calls SDL_SendKeyboardText / 
+   SDL_SendEditingText for each event it finds */
+extern void SDL_IBus_PumpEvents();
+
+#endif /* HAVE_IBUS_IBUS_H */
+
+#endif /* _SDL_ibus_h */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 44 - 7
src/video/x11/SDL_x11events.c

@@ -492,6 +492,11 @@ X11_DispatchEvent(_THIS)
             }
 #ifdef DEBUG_XEVENTS
             printf("window %p: FocusIn!\n", data);
+#endif
+#ifdef SDL_USE_IBUS
+            if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
+                SDL_IBus_SetFocus(SDL_TRUE);
+            }
 #endif
             if (data->pending_focus == PENDING_FOCUS_OUT &&
                 data->window == SDL_GetKeyboardFocus()) {
@@ -529,6 +534,11 @@ X11_DispatchEvent(_THIS)
             }
 #ifdef DEBUG_XEVENTS
             printf("window %p: FocusOut!\n", data);
+#endif
+#ifdef SDL_USE_IBUS
+            if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
+                SDL_IBus_SetFocus(SDL_FALSE);
+            }
 #endif
             data->pending_focus = PENDING_FOCUS_OUT;
             data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_OUT_TIME;
@@ -561,11 +571,14 @@ X11_DispatchEvent(_THIS)
             KeySym keysym = NoSymbol;
             char text[SDL_TEXTINPUTEVENT_TEXT_SIZE];
             Status status = 0;
+            Bool handled = False;
 
 #ifdef DEBUG_XEVENTS
             printf("window %p: KeyPress (X11 keycode = 0x%X)\n", data, xevent.xkey.keycode);
 #endif
+#ifndef SDL_USE_IBUS
             SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]);
+#endif
 #if 1
             if (videodata->key_layout[keycode] == SDL_SCANCODE_UNKNOWN && keycode) {
                 int min_keycode, max_keycode;
@@ -591,9 +604,21 @@ X11_DispatchEvent(_THIS)
 #else
             XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
 #endif
-            if (*text) {
-                SDL_SendKeyboardText(text);
+#ifdef SDL_USE_IBUS
+            if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
+                if(!(handled = SDL_IBus_ProcessKeyEvent(keysym, keycode))){
+#endif
+                    if(*text){
+                        SDL_SendKeyboardText(text);
+                    }
+#ifdef SDL_USE_IBUS
+                }
+            }
+
+            if (!handled) {
+                SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]);
             }
+#endif
         }
         break;
 
@@ -663,6 +688,12 @@ X11_DispatchEvent(_THIS)
                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED,
                                     xevent.xconfigure.x - border_left,
                                     xevent.xconfigure.y - border_top);
+#ifdef SDL_USE_IBUS
+                if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
+                    /* Update IBus candidate list position */
+                    SDL_IBus_UpdateTextRect(NULL);
+                }
+#endif
             }
             if (xevent.xconfigure.width != data->last_xconfigure.width ||
                 xevent.xconfigure.height != data->last_xconfigure.height) {
@@ -1079,14 +1110,20 @@ X11_PumpEvents(_THIS)
             SDL_TICKS_PASSED(now, data->screensaver_activity + 30000)) {
             X11_XResetScreenSaver(data->display);
 
-            #if SDL_USE_LIBDBUS
-            SDL_dbus_screensaver_tickle(_this);
-            #endif
+#if SDL_USE_LIBDBUS
+            SDL_DBus_ScreensaverTickle();
+#endif
 
             data->screensaver_activity = now;
         }
     }
 
+#ifdef SDL_USE_IBUS
+    if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
+        SDL_IBus_PumpEvents();
+    }
+#endif
+
     /* Keep processing pending events */
     while (X11_Pending(data->display)) {
         X11_DispatchEvent(_this);
@@ -1107,12 +1144,12 @@ X11_SuspendScreenSaver(_THIS)
 #endif /* SDL_VIDEO_DRIVER_X11_XSCRNSAVER */
 
 #if SDL_USE_LIBDBUS
-    if (SDL_dbus_screensaver_inhibit(_this)) {
+    if (SDL_DBus_ScreensaverInhibit(_this->suspend_screensaver)) {
         return;
     }
 
     if (_this->suspend_screensaver) {
-        SDL_dbus_screensaver_tickle(_this);
+        SDL_DBus_ScreensaverTickle();
     }
 #endif
 

+ 36 - 0
src/video/x11/SDL_x11keyboard.c

@@ -287,6 +287,10 @@ X11_InitKeyboard(_THIS)
 
     SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
 
+#ifdef SDL_USE_IBUS
+    SDL_IBus_Init();
+#endif
+
     return 0;
 }
 
@@ -320,6 +324,38 @@ X11_UpdateKeymap(_THIS)
 void
 X11_QuitKeyboard(_THIS)
 {
+#ifdef SDL_USE_IBUS
+    SDL_IBus_Quit();
+#endif
+}
+
+void
+X11_StartTextInput(_THIS)
+{
+#ifdef SDL_USE_IBUS
+    SDL_IBus_SetFocus(SDL_GetFocusWindow() != NULL);
+#endif
+}
+
+void
+X11_StopTextInput(_THIS)
+{
+#ifdef SDL_USE_IBUS
+    SDL_IBus_Reset();
+#endif
+}
+
+void
+X11_SetTextInputRect(_THIS, SDL_Rect *rect)
+{
+    if (!rect) {
+        SDL_InvalidParamError("rect");
+        return;
+    }
+       
+#ifdef SDL_USE_IBUS
+    SDL_IBus_UpdateTextRect(rect);
+#endif
 }
 
 #endif /* SDL_VIDEO_DRIVER_X11 */

+ 3 - 0
src/video/x11/SDL_x11keyboard.h

@@ -26,6 +26,9 @@
 extern int X11_InitKeyboard(_THIS);
 extern void X11_UpdateKeymap(_THIS);
 extern void X11_QuitKeyboard(_THIS);
+extern void X11_StartTextInput(_THIS);
+extern void X11_StopTextInput(_THIS);
+extern void X11_SetTextInputRect(_THIS, SDL_Rect *rect);
 
 #endif /* _SDL_x11keyboard_h */
 

+ 6 - 217
src/video/x11/SDL_x11video.c

@@ -39,220 +39,6 @@
 #include "SDL_x11opengles.h"
 #endif
 
-/* !!! FIXME: move dbus stuff to somewhere under src/core/linux ... */
-#if SDL_USE_LIBDBUS
-/* we never link directly to libdbus. */
-#include "SDL_loadso.h"
-static const char *dbus_library = "libdbus-1.so.3";
-static void *dbus_handle = NULL;
-static unsigned int screensaver_cookie = 0;
-
-/* !!! FIXME: this is kinda ugly. */
-static SDL_bool
-load_dbus_sym(const char *fn, void **addr)
-{
-    *addr = SDL_LoadFunction(dbus_handle, fn);
-    if (*addr == NULL) {
-        /* Don't call SDL_SetError(): SDL_LoadFunction already did. */
-        return SDL_FALSE;
-    }
-
-    return SDL_TRUE;
-}
-
-/* libdbus entry points... */
-static DBusConnection *(*DBUS_dbus_bus_get_private)(DBusBusType, DBusError *) = NULL;
-static void (*DBUS_dbus_connection_set_exit_on_disconnect)(DBusConnection *, dbus_bool_t) = NULL;
-static dbus_bool_t (*DBUS_dbus_connection_send)(DBusConnection *, DBusMessage *, dbus_uint32_t *) = NULL;
-static DBusMessage *(*DBUS_dbus_connection_send_with_reply_and_block)(DBusConnection *, DBusMessage *, int, DBusError *) = NULL;
-static void (*DBUS_dbus_connection_close)(DBusConnection *) = NULL;
-static void (*DBUS_dbus_connection_unref)(DBusConnection *) = NULL;
-static void (*DBUS_dbus_connection_flush)(DBusConnection *) = NULL;
-static DBusMessage *(*DBUS_dbus_message_new_method_call)(const char *, const char *, const char *, const char *) = NULL;
-static dbus_bool_t (*DBUS_dbus_message_append_args)(DBusMessage *, int, ...) = NULL;
-static dbus_bool_t (*DBUS_dbus_message_get_args)(DBusMessage *, DBusError *, int, ...) = NULL;
-static void (*DBUS_dbus_message_unref)(DBusMessage *) = NULL;
-static void (*DBUS_dbus_error_init)(DBusError *) = NULL;
-static dbus_bool_t (*DBUS_dbus_error_is_set)(const DBusError *) = NULL;
-static void (*DBUS_dbus_error_free)(DBusError *) = NULL;
-
-static int
-load_dbus_syms(void)
-{
-    /* cast funcs to char* first, to please GCC's strict aliasing rules. */
-    #define SDL_DBUS_SYM(x) \
-        if (!load_dbus_sym(#x, (void **) (char *) &DBUS_##x)) return -1
-
-    SDL_DBUS_SYM(dbus_bus_get_private);
-    SDL_DBUS_SYM(dbus_connection_set_exit_on_disconnect);
-    SDL_DBUS_SYM(dbus_connection_send);
-    SDL_DBUS_SYM(dbus_connection_send_with_reply_and_block);
-    SDL_DBUS_SYM(dbus_connection_close);
-    SDL_DBUS_SYM(dbus_connection_unref);
-    SDL_DBUS_SYM(dbus_connection_flush);
-    SDL_DBUS_SYM(dbus_message_append_args);
-    SDL_DBUS_SYM(dbus_message_get_args);
-    SDL_DBUS_SYM(dbus_message_new_method_call);
-    SDL_DBUS_SYM(dbus_message_unref);
-    SDL_DBUS_SYM(dbus_error_init);
-    SDL_DBUS_SYM(dbus_error_is_set);
-    SDL_DBUS_SYM(dbus_error_free);
-
-    #undef SDL_DBUS_SYM
-
-    return 0;
-}
-
-static void
-UnloadDBUSLibrary(void)
-{
-    if (dbus_handle != NULL) {
-        SDL_UnloadObject(dbus_handle);
-        dbus_handle = NULL;
-    }
-}
-
-static int
-LoadDBUSLibrary(void)
-{
-    int retval = 0;
-    if (dbus_handle == NULL) {
-        dbus_handle = SDL_LoadObject(dbus_library);
-        if (dbus_handle == NULL) {
-            retval = -1;
-            /* Don't call SDL_SetError(): SDL_LoadObject already did. */
-        } else {
-            retval = load_dbus_syms();
-            if (retval < 0) {
-                UnloadDBUSLibrary();
-            }
-        }
-    }
-
-    return retval;
-}
-
-static void
-X11_InitDBus(_THIS)
-{
-    if (LoadDBUSLibrary() != -1) {
-        SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
-        DBusError err;
-        DBUS_dbus_error_init(&err);
-        data->dbus = DBUS_dbus_bus_get_private(DBUS_BUS_SESSION, &err);
-        if (DBUS_dbus_error_is_set(&err)) {
-            DBUS_dbus_error_free(&err);
-            if (data->dbus) {
-                DBUS_dbus_connection_unref(data->dbus);
-                data->dbus = NULL;
-            }
-            return;  /* oh well */
-        }
-        DBUS_dbus_connection_set_exit_on_disconnect(data->dbus, 0);
-    }
-}
-
-static void
-X11_QuitDBus(_THIS)
-{
-    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
-    if (data->dbus) {
-        DBUS_dbus_connection_close(data->dbus);
-        DBUS_dbus_connection_unref(data->dbus);
-        data->dbus = NULL;
-    }
-}
-
-void
-SDL_dbus_screensaver_tickle(_THIS)
-{
-    const SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
-    DBusConnection *conn = data->dbus;
-    if (conn != NULL) {
-        DBusMessage *msg = DBUS_dbus_message_new_method_call("org.gnome.ScreenSaver",
-                                                             "/org/gnome/ScreenSaver",
-                                                             "org.gnome.ScreenSaver",
-                                                             "SimulateUserActivity");
-        if (msg != NULL) {
-            if (DBUS_dbus_connection_send(conn, msg, NULL)) {
-                DBUS_dbus_connection_flush(conn);
-            }
-            DBUS_dbus_message_unref(msg);
-        }
-    }
-}
-
-SDL_bool
-SDL_dbus_screensaver_inhibit(_THIS)
-{
-    const SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
-    DBusConnection *conn = data->dbus;
-
-    if (conn == NULL)
-        return SDL_FALSE;
-
-    if (_this->suspend_screensaver &&
-        screensaver_cookie != 0)
-        return SDL_TRUE;
-    if (!_this->suspend_screensaver &&
-        screensaver_cookie == 0)
-        return SDL_TRUE;
-
-    if (_this->suspend_screensaver) {
-        const char *app = "My SDL application";
-        const char *reason = "Playing a game";
-
-        DBusMessage *msg = DBUS_dbus_message_new_method_call("org.freedesktop.ScreenSaver",
-                                                             "/org/freedesktop/ScreenSaver",
-                                                             "org.freedesktop.ScreenSaver",
-                                                             "Inhibit");
-        if (msg != NULL) {
-            DBUS_dbus_message_append_args (msg,
-                                           DBUS_TYPE_STRING, &app,
-                                           DBUS_TYPE_STRING, &reason,
-                                           DBUS_TYPE_INVALID);
-        }
-
-        if (msg != NULL) {
-            DBusMessage *reply;
-
-            reply = DBUS_dbus_connection_send_with_reply_and_block(conn, msg, 300, NULL);
-            if (reply) {
-                if (!DBUS_dbus_message_get_args(reply, NULL,
-                                                DBUS_TYPE_UINT32, &screensaver_cookie,
-                                                DBUS_TYPE_INVALID))
-                    screensaver_cookie = 0;
-                DBUS_dbus_message_unref(reply);
-            }
-
-            DBUS_dbus_message_unref(msg);
-        }
-
-        if (screensaver_cookie == 0) {
-            return SDL_FALSE;
-        }
-        return SDL_TRUE;
-    } else {
-        DBusMessage *msg = DBUS_dbus_message_new_method_call("org.freedesktop.ScreenSaver",
-                                                             "/org/freedesktop/ScreenSaver",
-                                                             "org.freedesktop.ScreenSaver",
-                                                             "UnInhibit");
-        DBUS_dbus_message_append_args (msg,
-                                       DBUS_TYPE_UINT32, &screensaver_cookie,
-                                       DBUS_TYPE_INVALID);
-        if (msg != NULL) {
-            if (DBUS_dbus_connection_send(conn, msg, NULL)) {
-                DBUS_dbus_connection_flush(conn);
-            }
-            DBUS_dbus_message_unref(msg);
-        }
-
-        screensaver_cookie = 0;
-        return SDL_TRUE;
-    }
-}
-#endif
-
 /* Initialization/Query functions */
 static int X11_VideoInit(_THIS);
 static void X11_VideoQuit(_THIS);
@@ -487,7 +273,10 @@ X11_CreateDevice(int devindex)
     device->SetClipboardText = X11_SetClipboardText;
     device->GetClipboardText = X11_GetClipboardText;
     device->HasClipboardText = X11_HasClipboardText;
-
+    device->StartTextInput = X11_StartTextInput;
+    device->StopTextInput = X11_StopTextInput;
+    device->SetTextInputRect = X11_SetTextInputRect;
+    
     device->free = X11_DeleteDevice;
 
     return device;
@@ -635,7 +424,7 @@ X11_VideoInit(_THIS)
     X11_InitTouch(_this);
 
 #if SDL_USE_LIBDBUS
-    X11_InitDBus(_this);
+    SDL_DBus_Init();
 #endif
 
     return 0;
@@ -659,7 +448,7 @@ X11_VideoQuit(_THIS)
     X11_QuitTouch(_this);
 
 #if SDL_USE_LIBDBUS
-    X11_QuitDBus(_this);
+    SDL_DBus_Quit();
 #endif
 }
 

+ 5 - 8
src/video/x11/SDL_x11video.h

@@ -54,8 +54,11 @@
 #endif
 
 #ifdef HAVE_DBUS_DBUS_H
-#define SDL_USE_LIBDBUS 1
-#include <dbus/dbus.h>
+#include "../../core/linux/SDL_dbus.h"
+#endif
+
+#ifdef HAVE_IBUS_IBUS_H
+#include "../../core/linux/SDL_ibus.h"
 #endif
 
 #include "SDL_x11dyn.h"
@@ -114,16 +117,10 @@ typedef struct SDL_VideoData
     SDL_Scancode key_layout[256];
     SDL_bool selection_waiting;
 
-#if SDL_USE_LIBDBUS
-    DBusConnection *dbus;
-#endif
 } SDL_VideoData;
 
 extern SDL_bool X11_UseDirectColorVisuals(void);
 
-SDL_bool SDL_dbus_screensaver_inhibit(_THIS);
-void SDL_dbus_screensaver_tickle(_THIS);
-
 #endif /* _SDL_x11video_h */
 
 /* vi: set ts=4 sw=4 expandtab: */