diff --git a/configure.in b/configure.in index e18301dd2..0fc628b24 100644 --- a/configure.in +++ b/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 diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in index 79e3b6878..6d2ac9d1c 100644 --- a/include/SDL_config.h.in +++ b/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 diff --git a/src/core/linux/SDL_dbus.c b/src/core/linux/SDL_dbus.c new file mode 100644 index 000000000..e865a8c9f --- /dev/null +++ b/src/core/linux/SDL_dbus.c @@ -0,0 +1,236 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + 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 diff --git a/src/core/linux/SDL_dbus.h b/src/core/linux/SDL_dbus.h new file mode 100644 index 000000000..285b39d93 --- /dev/null +++ b/src/core/linux/SDL_dbus.h @@ -0,0 +1,79 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + 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 + + +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: */ diff --git a/src/core/linux/SDL_ibus.c b/src/core/linux/SDL_ibus.c new file mode 100644 index 000000000..a91d31b83 --- /dev/null +++ b/src/core/linux/SDL_ibus.c @@ -0,0 +1,593 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + 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 +#include +#include + +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 diff --git a/src/core/linux/SDL_ibus.h b/src/core/linux/SDL_ibus.h new file mode 100644 index 000000000..d982e6846 --- /dev/null +++ b/src/core/linux/SDL_ibus.h @@ -0,0 +1,58 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + 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 + +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: */ diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index 7f24ebfba..d23b609ba 100644 --- a/src/video/x11/SDL_x11events.c +++ b/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 diff --git a/src/video/x11/SDL_x11keyboard.c b/src/video/x11/SDL_x11keyboard.c index 5014b7181..7ac7d7c62 100644 --- a/src/video/x11/SDL_x11keyboard.c +++ b/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 */ diff --git a/src/video/x11/SDL_x11keyboard.h b/src/video/x11/SDL_x11keyboard.h index 3d1631fe5..6037e5c09 100644 --- a/src/video/x11/SDL_x11keyboard.h +++ b/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 */ diff --git a/src/video/x11/SDL_x11video.c b/src/video/x11/SDL_x11video.c index ca9faee31..d77fb7fe3 100644 --- a/src/video/x11/SDL_x11video.c +++ b/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 } diff --git a/src/video/x11/SDL_x11video.h b/src/video/x11/SDL_x11video.h index 8ab88f728..3c92b5e27 100644 --- a/src/video/x11/SDL_x11video.h +++ b/src/video/x11/SDL_x11video.h @@ -54,8 +54,11 @@ #endif #ifdef HAVE_DBUS_DBUS_H -#define SDL_USE_LIBDBUS 1 -#include +#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: */