Fixed bug 2824 - Add Fcitx Input Method Support
authorSam Lantinga <slouken@libsdl.org>
Fri, 07 Oct 2016 18:57:40 -0700
changeset 104966660aa9120d6
parent 10495 f732781d7ddc
child 10497 c87efb3079de
Fixed bug 2824 - Add Fcitx Input Method Support

Weitian Leung

Just moved ibus direct call to SDL_IME_* related functions, and adds fcitx IME support (uses DBus, too),
enable with env: SDL_IM_MODULE=fcitx (ibus still the default one)
configure
configure.in
include/SDL_config.h.in
src/core/linux/SDL_fcitx.c
src/core/linux/SDL_fcitx.h
src/core/linux/SDL_ime.c
src/core/linux/SDL_ime.h
src/video/x11/SDL_x11events.c
src/video/x11/SDL_x11keyboard.c
src/video/x11/SDL_x11video.h
     1.1 --- a/configure	Fri Oct 07 18:24:34 2016 -0700
     1.2 +++ b/configure	Fri Oct 07 18:57:40 2016 -0700
     1.3 @@ -849,7 +849,9 @@
     1.4  enable_video_opengles2
     1.5  enable_libudev
     1.6  enable_dbus
     1.7 +enable_ime
     1.8  enable_ibus
     1.9 +enable_fcitx
    1.10  enable_input_tslib
    1.11  enable_pthreads
    1.12  enable_pthread_sem
    1.13 @@ -1587,7 +1589,9 @@
    1.14                            include OpenGL ES 2.0 support [[default=yes]]
    1.15    --enable-libudev        enable libudev support [[default=yes]]
    1.16    --enable-dbus           enable D-Bus support [[default=yes]]
    1.17 +  --enable-ime            enable IME support [[default=yes]]
    1.18    --enable-ibus           enable IBus support [[default=yes]]
    1.19 +  --enable-fcitx          enable fcitx support [[default=yes]]
    1.20    --enable-input-tslib    use the Touchscreen library for input
    1.21                            [[default=yes]]
    1.22    --enable-pthreads       use POSIX threads for multi-threading
    1.23 @@ -21650,6 +21654,23 @@
    1.24      fi
    1.25  }
    1.26  
    1.27 +CheckIME()
    1.28 +{
    1.29 +    # Check whether --enable-ime was given.
    1.30 +if test "${enable_ime+set}" = set; then :
    1.31 +  enableval=$enable_ime;
    1.32 +else
    1.33 +  enable_ime=yes
    1.34 +fi
    1.35 +
    1.36 +    if test x$enable_ime = xyes; then
    1.37 +
    1.38 +$as_echo "#define SDL_USE_IME 1" >>confdefs.h
    1.39 +
    1.40 +            SOURCES="$SOURCES $srcdir/src/core/linux/SDL_ime.c"
    1.41 +    fi
    1.42 +}
    1.43 +
    1.44  CheckIBus()
    1.45  {
    1.46      # Check whether --enable-ibus was given.
    1.47 @@ -21723,7 +21744,11 @@
    1.48  
    1.49              CFLAGS="$save_CFLAGS"
    1.50              if test x$have_ibus_ibus_h_hdr = xyes; then
    1.51 -                if test x$enable_dbus != xyes; then
    1.52 +                if test x$enable_ime != xyes; then
    1.53 +                    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: IME support is required for IBus." >&5
    1.54 +$as_echo "$as_me: WARNING: IME support is required for IBus." >&2;}
    1.55 +                    have_ibus_ibus_h_hdr=no
    1.56 +                elif test x$enable_dbus != xyes; then
    1.57                      { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: DBus support is required for IBus." >&5
    1.58  $as_echo "$as_me: WARNING: DBus support is required for IBus." >&2;}
    1.59                      have_ibus_ibus_h_hdr=no
    1.60 @@ -21743,6 +21768,90 @@
    1.61      fi
    1.62  }
    1.63  
    1.64 +CheckFcitx()
    1.65 +{
    1.66 +    # Check whether --enable-fcitx was given.
    1.67 +if test "${enable_fcitx+set}" = set; then :
    1.68 +  enableval=$enable_fcitx;
    1.69 +else
    1.70 +  enable_fcitx=yes
    1.71 +fi
    1.72 +
    1.73 +    if test x$enable_fcitx = xyes; then
    1.74 +        # Extract the first word of "pkg-config", so it can be a program name with args.
    1.75 +set dummy pkg-config; ac_word=$2
    1.76 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
    1.77 +$as_echo_n "checking for $ac_word... " >&6; }
    1.78 +if ${ac_cv_path_PKG_CONFIG+:} false; then :
    1.79 +  $as_echo_n "(cached) " >&6
    1.80 +else
    1.81 +  case $PKG_CONFIG in
    1.82 +  [\\/]* | ?:[\\/]*)
    1.83 +  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
    1.84 +  ;;
    1.85 +  *)
    1.86 +  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
    1.87 +for as_dir in $PATH
    1.88 +do
    1.89 +  IFS=$as_save_IFS
    1.90 +  test -z "$as_dir" && as_dir=.
    1.91 +    for ac_exec_ext in '' $ac_executable_extensions; do
    1.92 +  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
    1.93 +    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
    1.94 +    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    1.95 +    break 2
    1.96 +  fi
    1.97 +done
    1.98 +  done
    1.99 +IFS=$as_save_IFS
   1.100 +
   1.101 +  test -z "$ac_cv_path_PKG_CONFIG" && ac_cv_path_PKG_CONFIG="no"
   1.102 +  ;;
   1.103 +esac
   1.104 +fi
   1.105 +PKG_CONFIG=$ac_cv_path_PKG_CONFIG
   1.106 +if test -n "$PKG_CONFIG"; then
   1.107 +  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
   1.108 +$as_echo "$PKG_CONFIG" >&6; }
   1.109 +else
   1.110 +  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
   1.111 +$as_echo "no" >&6; }
   1.112 +fi
   1.113 +
   1.114 +
   1.115 +        if test x$PKG_CONFIG != xno; then
   1.116 +            FCITX_CFLAGS=`$PKG_CONFIG --cflags fcitx`
   1.117 +            CFLAGS="$CFLAGS $FCITX_CFLAGS"
   1.118 +            ac_fn_c_check_header_mongrel "$LINENO" "fcitx/frontend.h" "ac_cv_header_fcitx_frontend_h" "$ac_includes_default"
   1.119 +if test "x$ac_cv_header_fcitx_frontend_h" = xyes; then :
   1.120 +  have_fcitx_frontend_h_hdr=yes
   1.121 +else
   1.122 +  have_fcitx_frontend_h_hdr=no
   1.123 +fi
   1.124 +
   1.125 +
   1.126 +            CFLAGS="$save_CFLAGS"
   1.127 +            if test x$have_fcitx_frontend_h_hdr = xyes; then
   1.128 +                if test x$enable_ime != xyes; then
   1.129 +                    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: IME support is required for fcitx." >&5
   1.130 +$as_echo "$as_me: WARNING: IME support is required for fcitx." >&2;}
   1.131 +                    have_fcitx_frontend_h_hdr=no
   1.132 +                elif test x$enable_dbus != xyes; then
   1.133 +                    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: DBus support is required for fcitx." >&5
   1.134 +$as_echo "$as_me: WARNING: DBus support is required for fcitx." >&2;}
   1.135 +                    have_fcitx_frontend_h_hdr=no
   1.136 +                else
   1.137 +
   1.138 +$as_echo "#define HAVE_FCITX_FRONTEND_H 1" >>confdefs.h
   1.139 +
   1.140 +                    EXTRA_CFLAGS="$EXTRA_CFLAGS $FCITX_CFLAGS"
   1.141 +                    SOURCES="$SOURCES $srcdir/src/core/linux/SDL_fcitx.c"
   1.142 +               fi
   1.143 +            fi
   1.144 +        fi
   1.145 +    fi
   1.146 +}
   1.147 +
   1.148  CheckTslib()
   1.149  {
   1.150      # Check whether --enable-input-tslib was given.
   1.151 @@ -23031,7 +23140,9 @@
   1.152          CheckWayland
   1.153          CheckLibUDev
   1.154          CheckDBus
   1.155 +        CheckIME
   1.156          CheckIBus
   1.157 +        CheckFcitx
   1.158          case $ARCH in
   1.159            linux)
   1.160                CheckInputEvents
   1.161 @@ -23944,11 +24055,21 @@
   1.162  else
   1.163      SUMMARY="${SUMMARY}Using dbus      : NO\n"
   1.164  fi
   1.165 +if test x$enable_ime = xyes; then
   1.166 +    SUMMARY="${SUMMARY}Using ime       : YES\n"
   1.167 +else
   1.168 +    SUMMARY="${SUMMARY}Using ime       : NO\n"
   1.169 +fi
   1.170  if test x$have_ibus_ibus_h_hdr = xyes; then
   1.171      SUMMARY="${SUMMARY}Using ibus      : YES\n"
   1.172  else
   1.173      SUMMARY="${SUMMARY}Using ibus      : NO\n"
   1.174  fi
   1.175 +if test x$have_fcitx_frontend_h_hdr = xyes; then
   1.176 +    SUMMARY="${SUMMARY}Using fcitx     : YES\n"
   1.177 +else
   1.178 +    SUMMARY="${SUMMARY}Using fcitx     : NO\n"
   1.179 +fi
   1.180  ac_config_commands="$ac_config_commands summary"
   1.181  
   1.182  
     2.1 --- a/configure.in	Fri Oct 07 18:24:34 2016 -0700
     2.2 +++ b/configure.in	Fri Oct 07 18:57:40 2016 -0700
     2.3 @@ -2260,6 +2260,18 @@
     2.4      fi
     2.5  }
     2.6  
     2.7 +dnl See if the platform wanna IME support.
     2.8 +CheckIME()
     2.9 +{
    2.10 +    AC_ARG_ENABLE(ime,
    2.11 +AC_HELP_STRING([--enable-ime], [enable IME support [[default=yes]]]),
    2.12 +                  , enable_ime=yes)
    2.13 +    if test x$enable_ime = xyes; then
    2.14 +        AC_DEFINE(SDL_USE_IME, 1, [ ])
    2.15 +            SOURCES="$SOURCES $srcdir/src/core/linux/SDL_ime.c"
    2.16 +    fi
    2.17 +}
    2.18 +
    2.19  dnl See if the platform has libibus IME support.
    2.20  CheckIBus()
    2.21  {
    2.22 @@ -2280,7 +2292,10 @@
    2.23                              have_inotify_inotify_h_hdr=no)
    2.24              CFLAGS="$save_CFLAGS"
    2.25              if test x$have_ibus_ibus_h_hdr = xyes; then
    2.26 -                if test x$enable_dbus != xyes; then
    2.27 +                if test x$enable_ime != xyes; then
    2.28 +                    AC_MSG_WARN([IME support is required for IBus.])
    2.29 +                    have_ibus_ibus_h_hdr=no
    2.30 +                elif test x$enable_dbus != xyes; then
    2.31                      AC_MSG_WARN([DBus support is required for IBus.])
    2.32                      have_ibus_ibus_h_hdr=no
    2.33                  elif test x$have_inotify_inotify_h_hdr != xyes; then
    2.34 @@ -2296,6 +2311,38 @@
    2.35      fi
    2.36  }
    2.37  
    2.38 +dnl See if the platform has fcitx IME support.
    2.39 +CheckFcitx()
    2.40 +{
    2.41 +    AC_ARG_ENABLE(fcitx,
    2.42 +AC_HELP_STRING([--enable-fcitx], [enable fcitx support [[default=yes]]]),
    2.43 +                  , enable_fcitx=yes)
    2.44 +    if test x$enable_fcitx = xyes; then
    2.45 +        AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
    2.46 +        if test x$PKG_CONFIG != xno; then
    2.47 +            FCITX_CFLAGS=`$PKG_CONFIG --cflags fcitx`
    2.48 +            CFLAGS="$CFLAGS $FCITX_CFLAGS"
    2.49 +            AC_CHECK_HEADER(fcitx/frontend.h,
    2.50 +                            have_fcitx_frontend_h_hdr=yes,
    2.51 +                            have_fcitx_frontend_h_hdr=no)
    2.52 +            CFLAGS="$save_CFLAGS"
    2.53 +            if test x$have_fcitx_frontend_h_hdr = xyes; then
    2.54 +                if test x$enable_ime != xyes; then
    2.55 +                    AC_MSG_WARN([IME support is required for fcitx.])
    2.56 +                    have_fcitx_frontend_h_hdr=no
    2.57 +                elif test x$enable_dbus != xyes; then
    2.58 +                    AC_MSG_WARN([DBus support is required for fcitx.])
    2.59 +                    have_fcitx_frontend_h_hdr=no
    2.60 +                else
    2.61 +                    AC_DEFINE(HAVE_FCITX_FRONTEND_H, 1, [ ])
    2.62 +                    EXTRA_CFLAGS="$EXTRA_CFLAGS $FCITX_CFLAGS"
    2.63 +                    SOURCES="$SOURCES $srcdir/src/core/linux/SDL_fcitx.c"
    2.64 +               fi
    2.65 +            fi
    2.66 +        fi
    2.67 +    fi
    2.68 +}
    2.69 +
    2.70  dnl See if we can use the Touchscreen input library
    2.71  CheckTslib()
    2.72  {
    2.73 @@ -2924,7 +2971,9 @@
    2.74          CheckWayland
    2.75          CheckLibUDev
    2.76          CheckDBus
    2.77 +        CheckIME
    2.78          CheckIBus
    2.79 +        CheckFcitx
    2.80          case $ARCH in
    2.81            linux)
    2.82                CheckInputEvents
    2.83 @@ -3679,11 +3728,21 @@
    2.84  else
    2.85      SUMMARY="${SUMMARY}Using dbus      : NO\n"
    2.86  fi
    2.87 +if test x$enable_ime = xyes; then
    2.88 +    SUMMARY="${SUMMARY}Using ime       : YES\n"
    2.89 +else
    2.90 +    SUMMARY="${SUMMARY}Using ime       : NO\n"
    2.91 +fi
    2.92  if test x$have_ibus_ibus_h_hdr = xyes; then
    2.93      SUMMARY="${SUMMARY}Using ibus      : YES\n"
    2.94  else
    2.95      SUMMARY="${SUMMARY}Using ibus      : NO\n"
    2.96  fi
    2.97 +if test x$have_fcitx_frontend_h_hdr = xyes; then
    2.98 +    SUMMARY="${SUMMARY}Using fcitx     : YES\n"
    2.99 +else
   2.100 +    SUMMARY="${SUMMARY}Using fcitx     : NO\n"
   2.101 +fi
   2.102  AC_CONFIG_COMMANDS([summary], [echo -en "$SUMMARY"], [SUMMARY="$SUMMARY"])
   2.103  
   2.104  AC_OUTPUT
     3.1 --- a/include/SDL_config.h.in	Fri Oct 07 18:24:34 2016 -0700
     3.2 +++ b/include/SDL_config.h.in	Fri Oct 07 18:57:40 2016 -0700
     3.3 @@ -82,6 +82,7 @@
     3.4  #undef HAVE_LIBUDEV_H
     3.5  #undef HAVE_DBUS_DBUS_H
     3.6  #undef HAVE_IBUS_IBUS_H
     3.7 +#undef HAVE_FCITX_FRONTEND_H
     3.8  
     3.9  /* C library functions */
    3.10  #undef HAVE_MALLOC
    3.11 @@ -356,4 +357,7 @@
    3.12  #undef SDL_ASSEMBLY_ROUTINES
    3.13  #undef SDL_ALTIVEC_BLITTERS
    3.14  
    3.15 +/* Enable ime support */
    3.16 +#undef SDL_USE_IME
    3.17 +
    3.18  #endif /* _SDL_config_h */
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/core/linux/SDL_fcitx.c	Fri Oct 07 18:57:40 2016 -0700
     4.3 @@ -0,0 +1,548 @@
     4.4 +/*
     4.5 +  Simple DirectMedia Layer
     4.6 +  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
     4.7 +
     4.8 +  This software is provided 'as-is', without any express or implied
     4.9 +  warranty.  In no event will the authors be held liable for any damages
    4.10 +  arising from the use of this software.
    4.11 +
    4.12 +  Permission is granted to anyone to use this software for any purpose,
    4.13 +  including commercial applications, and to alter it and redistribute it
    4.14 +  freely, subject to the following restrictions:
    4.15 +
    4.16 +  1. The origin of this software must not be misrepresented; you must not
    4.17 +     claim that you wrote the original software. If you use this software
    4.18 +     in a product, an acknowledgment in the product documentation would be
    4.19 +     appreciated but is not required.
    4.20 +  2. Altered source versions must be plainly marked as such, and must not be
    4.21 +     misrepresented as being the original software.
    4.22 +  3. This notice may not be removed or altered from any source distribution.
    4.23 +*/
    4.24 +
    4.25 +#include <fcitx/frontend.h>
    4.26 +#include <unistd.h>
    4.27 +
    4.28 +#include "SDL_fcitx.h"
    4.29 +#include "SDL_keycode.h"
    4.30 +#include "SDL_keyboard.h"
    4.31 +#include "../../events/SDL_keyboard_c.h"
    4.32 +#include "SDL_dbus.h"
    4.33 +#include "SDL_syswm.h"
    4.34 +#if SDL_VIDEO_DRIVER_X11
    4.35 +#  include "../../video/x11/SDL_x11video.h"
    4.36 +#endif
    4.37 +#include "SDL_hints.h"
    4.38 +
    4.39 +#define FCITX_DBUS_SERVICE "org.fcitx.Fcitx"
    4.40 +
    4.41 +#define FCITX_IM_DBUS_PATH "/inputmethod"
    4.42 +#define FCITX_IC_DBUS_PATH "/inputcontext_%d"
    4.43 +
    4.44 +#define FCITX_IM_DBUS_INTERFACE "org.fcitx.Fcitx.InputMethod"
    4.45 +#define FCITX_IC_DBUS_INTERFACE "org.fcitx.Fcitx.InputContext"
    4.46 +
    4.47 +#define IC_NAME_MAX 64
    4.48 +#define DBUS_TIMEOUT 500
    4.49 +
    4.50 +typedef struct _FcitxClient
    4.51 +{
    4.52 +    SDL_DBusContext *dbus;
    4.53 +
    4.54 +    char servicename[IC_NAME_MAX];
    4.55 +    char icname[IC_NAME_MAX];
    4.56 +
    4.57 +    int id;
    4.58 +
    4.59 +    SDL_Rect cursor_rect;
    4.60 +} FcitxClient;
    4.61 +
    4.62 +static FcitxClient fcitx_client;
    4.63 +
    4.64 +static int
    4.65 +GetDisplayNumber()
    4.66 +{
    4.67 +    const char *display = SDL_getenv("DISPLAY");
    4.68 +    const char *p = NULL;;
    4.69 +    int number = 0;
    4.70 +
    4.71 +    if (display == NULL)
    4.72 +        return 0;
    4.73 +
    4.74 +    display = SDL_strchr(display, ':');
    4.75 +    if (display == NULL)
    4.76 +        return 0;
    4.77 +
    4.78 +    display++;
    4.79 +    p = SDL_strchr(display, '.');
    4.80 +    if (p == NULL && display != NULL) {
    4.81 +        number = SDL_strtod(display, NULL);
    4.82 +    } else {
    4.83 +        char *buffer = SDL_strdup(display);
    4.84 +        buffer[p - display] = '\0';
    4.85 +        number = SDL_strtod(buffer, NULL);
    4.86 +        SDL_free(buffer);
    4.87 +    }
    4.88 +
    4.89 +    return number;
    4.90 +}
    4.91 +
    4.92 +static char*
    4.93 +GetAppName()
    4.94 +{
    4.95 +#if defined(__LINUX__) || defined(__FREEBSD__)
    4.96 +    char *spot;
    4.97 +    char procfile[1024];
    4.98 +    char linkfile[1024];
    4.99 +    int linksize;
   4.100 +
   4.101 +#if defined(__LINUX__)
   4.102 +    SDL_snprintf(procfile, sizeof(procfile), "/proc/%d/exe", getpid());
   4.103 +#elif defined(__FREEBSD__)
   4.104 +    SDL_snprintf(procfile, sizeof(procfile), "/proc/%d/file", getpid());
   4.105 +#endif
   4.106 +    linksize = readlink(procfile, linkfile, sizeof(linkfile) - 1);
   4.107 +    if (linksize > 0) {
   4.108 +        linkfile[linksize] = '\0';
   4.109 +        spot = SDL_strrchr(linkfile, '/');
   4.110 +        if (spot) {
   4.111 +            return SDL_strdup(spot + 1);
   4.112 +        } else {
   4.113 +            return SDL_strdup(linkfile);
   4.114 +        }
   4.115 +    }
   4.116 +#endif /* __LINUX__ || __FREEBSD__ */
   4.117 +
   4.118 +    return SDL_strdup("SDL_App");
   4.119 +}
   4.120 +
   4.121 +/*
   4.122 + * Copied from fcitx source
   4.123 + */
   4.124 +#define CONT(i)   ISUTF8_CB(in[i])
   4.125 +#define VAL(i, s) ((in[i]&0x3f) << s)
   4.126 +
   4.127 +static char *
   4.128 +_fcitx_utf8_get_char(const char *i, uint32_t *chr)
   4.129 +{
   4.130 +    const unsigned char* in = (const unsigned char *)i;
   4.131 +    if (!(in[0] & 0x80)) {
   4.132 +        *(chr) = *(in);
   4.133 +        return (char *)in + 1;
   4.134 +    }
   4.135 +
   4.136 +    /* 2-byte, 0x80-0x7ff */
   4.137 +    if ((in[0] & 0xe0) == 0xc0 && CONT(1)) {
   4.138 +        *chr = ((in[0] & 0x1f) << 6) | VAL(1, 0);
   4.139 +        return (char *)in + 2;
   4.140 +    }
   4.141 +
   4.142 +    /* 3-byte, 0x800-0xffff */
   4.143 +    if ((in[0] & 0xf0) == 0xe0 && CONT(1) && CONT(2)) {
   4.144 +        *chr = ((in[0] & 0xf) << 12) | VAL(1, 6) | VAL(2, 0);
   4.145 +        return (char *)in + 3;
   4.146 +    }
   4.147 +
   4.148 +    /* 4-byte, 0x10000-0x1FFFFF */
   4.149 +    if ((in[0] & 0xf8) == 0xf0 && CONT(1) && CONT(2) && CONT(3)) {
   4.150 +        *chr = ((in[0] & 0x7) << 18) | VAL(1, 12) | VAL(2, 6) | VAL(3, 0);
   4.151 +        return (char *)in + 4;
   4.152 +    }
   4.153 +
   4.154 +    /* 5-byte, 0x200000-0x3FFFFFF */
   4.155 +    if ((in[0] & 0xfc) == 0xf8 && CONT(1) && CONT(2) && CONT(3) && CONT(4)) {
   4.156 +        *chr = ((in[0] & 0x3) << 24) | VAL(1, 18) | VAL(2, 12) | VAL(3, 6) | VAL(4, 0);
   4.157 +        return (char *)in + 5;
   4.158 +    }
   4.159 +
   4.160 +    /* 6-byte, 0x400000-0x7FFFFFF */
   4.161 +    if ((in[0] & 0xfe) == 0xfc && CONT(1) && CONT(2) && CONT(3) && CONT(4) && CONT(5)) {
   4.162 +        *chr = ((in[0] & 0x1) << 30) | VAL(1, 24) | VAL(2, 18) | VAL(3, 12) | VAL(4, 6) | VAL(5, 0);
   4.163 +        return (char *)in + 6;
   4.164 +    }
   4.165 +
   4.166 +    *chr = *in;
   4.167 +
   4.168 +    return (char *)in + 1;
   4.169 +}
   4.170 +
   4.171 +static size_t
   4.172 +_fcitx_utf8_strlen(const char *s)
   4.173 +{
   4.174 +    unsigned int l = 0;
   4.175 +
   4.176 +    while (*s) {
   4.177 +        uint32_t chr;
   4.178 +
   4.179 +        s = _fcitx_utf8_get_char(s, &chr);
   4.180 +        l++;
   4.181 +    }
   4.182 +
   4.183 +    return l;
   4.184 +}
   4.185 +
   4.186 +static DBusHandlerResult
   4.187 +DBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *data)
   4.188 +{
   4.189 +    SDL_DBusContext *dbus = (SDL_DBusContext *)data;
   4.190 +
   4.191 +    if (dbus->message_is_signal(msg, FCITX_IC_DBUS_INTERFACE, "CommitString")) {
   4.192 +        DBusMessageIter iter;
   4.193 +        const char *text = NULL;
   4.194 +
   4.195 +        dbus->message_iter_init(msg, &iter);
   4.196 +        dbus->message_iter_get_basic(&iter, &text);
   4.197 +
   4.198 +        if (text)
   4.199 +            SDL_SendKeyboardText(text);
   4.200 +
   4.201 +        return DBUS_HANDLER_RESULT_HANDLED;
   4.202 +    }
   4.203 +
   4.204 +    if (dbus->message_is_signal(msg, FCITX_IC_DBUS_INTERFACE, "UpdatePreedit")) {
   4.205 +        DBusMessageIter iter;
   4.206 +        const char *text;
   4.207 +
   4.208 +        dbus->message_iter_init(msg, &iter);
   4.209 +        dbus->message_iter_get_basic(&iter, &text);
   4.210 +
   4.211 +        if (text && *text) {
   4.212 +            char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
   4.213 +            size_t text_bytes = SDL_strlen(text), i = 0;
   4.214 +            size_t cursor = 0;
   4.215 +
   4.216 +            while (i < text_bytes) {
   4.217 +                size_t sz = SDL_utf8strlcpy(buf, text + i, sizeof(buf));
   4.218 +                size_t chars = _fcitx_utf8_strlen(buf);
   4.219 +
   4.220 +                SDL_SendEditingText(buf, cursor, chars);
   4.221 +
   4.222 +                i += sz;
   4.223 +                cursor += chars;
   4.224 +            }
   4.225 +        }
   4.226 +
   4.227 +        SDL_Fcitx_UpdateTextRect(NULL);
   4.228 +        return DBUS_HANDLER_RESULT_HANDLED;
   4.229 +    }
   4.230 +
   4.231 +    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
   4.232 +}
   4.233 +
   4.234 +static DBusMessage*
   4.235 +FcitxClientICNewMethod(FcitxClient *client,
   4.236 +        const char *method)
   4.237 +{
   4.238 +    SDL_DBusContext *dbus = client->dbus;
   4.239 +    return dbus->message_new_method_call(
   4.240 +            client->servicename,
   4.241 +            client->icname,
   4.242 +            FCITX_IC_DBUS_INTERFACE,
   4.243 +            method);
   4.244 +}
   4.245 +
   4.246 +static void
   4.247 +FcitxClientICCallMethod(FcitxClient *client,
   4.248 +        const char *method)
   4.249 +{
   4.250 +    SDL_DBusContext *dbus = client->dbus;
   4.251 +    DBusMessage *msg = FcitxClientICNewMethod(client, method);
   4.252 +
   4.253 +    if (msg == NULL)
   4.254 +        return ;
   4.255 +
   4.256 +    if (dbus->connection_send(dbus->session_conn, msg, NULL)) {
   4.257 +        dbus->connection_flush(dbus->session_conn);
   4.258 +    }
   4.259 +
   4.260 +    dbus->message_unref(msg);
   4.261 +}
   4.262 +
   4.263 +static void
   4.264 +Fcitx_SetCapabilities(void *data,
   4.265 +        const char *name,
   4.266 +        const char *old_val,
   4.267 +        const char *internal_editing)
   4.268 +{
   4.269 +    FcitxClient *client = (FcitxClient *)data;
   4.270 +    SDL_DBusContext *dbus = client->dbus;
   4.271 +    Uint32 caps = CAPACITY_NONE;
   4.272 +
   4.273 +    DBusMessage *msg = FcitxClientICNewMethod(client, "SetCapacity");
   4.274 +    if (msg == NULL)
   4.275 +        return ;
   4.276 +
   4.277 +    if (!(internal_editing && *internal_editing == '1')) {
   4.278 +        caps |= CAPACITY_PREEDIT;
   4.279 +    }
   4.280 +
   4.281 +    dbus->message_append_args(msg,
   4.282 +            DBUS_TYPE_UINT32, &caps,
   4.283 +            DBUS_TYPE_INVALID);
   4.284 +    if (dbus->connection_send(dbus->session_conn, msg, NULL)) {
   4.285 +        dbus->connection_flush(dbus->session_conn);
   4.286 +    }
   4.287 +
   4.288 +    dbus->message_unref(msg);
   4.289 +}
   4.290 +
   4.291 +static void
   4.292 +FcitxClientCreateIC(FcitxClient *client)
   4.293 +{
   4.294 +    char *appname = NULL;
   4.295 +    pid_t pid = 0;
   4.296 +    int id = 0;
   4.297 +    SDL_bool enable;
   4.298 +    Uint32 arg1, arg2, arg3, arg4;
   4.299 +
   4.300 +    SDL_DBusContext *dbus = client->dbus;
   4.301 +    DBusMessage *reply = NULL;
   4.302 +    DBusMessage *msg = dbus->message_new_method_call(
   4.303 +            client->servicename,
   4.304 +            FCITX_IM_DBUS_PATH,
   4.305 +            FCITX_IM_DBUS_INTERFACE,
   4.306 +            "CreateICv3"
   4.307 +            );
   4.308 +
   4.309 +    if (msg == NULL)
   4.310 +        return ;
   4.311 +
   4.312 +    appname = GetAppName();
   4.313 +    pid = getpid();
   4.314 +    dbus->message_append_args(msg,
   4.315 +            DBUS_TYPE_STRING, &appname,
   4.316 +            DBUS_TYPE_INT32, &pid,
   4.317 +            DBUS_TYPE_INVALID);
   4.318 +
   4.319 +    do {
   4.320 +        reply = dbus->connection_send_with_reply_and_block(
   4.321 +                dbus->session_conn,
   4.322 +                msg,
   4.323 +                DBUS_TIMEOUT,
   4.324 +                NULL);
   4.325 +
   4.326 +        if (!reply)
   4.327 +            break;
   4.328 +        if (!dbus->message_get_args(reply, NULL,
   4.329 +                DBUS_TYPE_INT32, &id,
   4.330 +                DBUS_TYPE_BOOLEAN, &enable,
   4.331 +                DBUS_TYPE_UINT32, &arg1,
   4.332 +                DBUS_TYPE_UINT32, &arg2,
   4.333 +                DBUS_TYPE_UINT32, &arg3,
   4.334 +                DBUS_TYPE_UINT32, &arg4,
   4.335 +                DBUS_TYPE_INVALID))
   4.336 +            break;
   4.337 +
   4.338 +        if (id < 0)
   4.339 +            break;
   4.340 +        client->id = id;
   4.341 +
   4.342 +        SDL_snprintf(client->icname, IC_NAME_MAX,
   4.343 +                FCITX_IC_DBUS_PATH, client->id);
   4.344 +
   4.345 +        dbus->bus_add_match(dbus->session_conn,
   4.346 +                "type='signal', interface='org.fcitx.Fcitx.InputContext'",
   4.347 +                NULL);
   4.348 +        dbus->connection_add_filter(dbus->session_conn,
   4.349 +                &DBus_MessageFilter, dbus,
   4.350 +                NULL);
   4.351 +        dbus->connection_flush(dbus->session_conn);
   4.352 +
   4.353 +        SDL_AddHintCallback(SDL_HINT_IME_INTERNAL_EDITING, &Fcitx_SetCapabilities, client);
   4.354 +    }
   4.355 +    while (0);
   4.356 +
   4.357 +    if (reply)
   4.358 +        dbus->message_unref(reply);
   4.359 +    dbus->message_unref(msg);
   4.360 +    SDL_free(appname);
   4.361 +}
   4.362 +
   4.363 +static Uint32
   4.364 +Fcitx_ModState(void)
   4.365 +{
   4.366 +    Uint32 fcitx_mods = 0;
   4.367 +    SDL_Keymod sdl_mods = SDL_GetModState();
   4.368 +
   4.369 +    if (sdl_mods & KMOD_SHIFT) fcitx_mods |= FcitxKeyState_Shift;
   4.370 +    if (sdl_mods & KMOD_CAPS)   fcitx_mods |= FcitxKeyState_CapsLock;
   4.371 +    if (sdl_mods & KMOD_CTRL)  fcitx_mods |= FcitxKeyState_Ctrl;
   4.372 +    if (sdl_mods & KMOD_ALT)   fcitx_mods |= FcitxKeyState_Alt;
   4.373 +    if (sdl_mods & KMOD_NUM)    fcitx_mods |= FcitxKeyState_NumLock;
   4.374 +    if (sdl_mods & KMOD_LGUI)   fcitx_mods |= FcitxKeyState_Super;
   4.375 +    if (sdl_mods & KMOD_RGUI)   fcitx_mods |= FcitxKeyState_Meta;
   4.376 +
   4.377 +    return fcitx_mods;
   4.378 +}
   4.379 +
   4.380 +SDL_bool
   4.381 +SDL_Fcitx_Init()
   4.382 +{
   4.383 +    fcitx_client.dbus = SDL_DBus_GetContext();
   4.384 +
   4.385 +    fcitx_client.cursor_rect.x = -1;
   4.386 +    fcitx_client.cursor_rect.y = -1;
   4.387 +    fcitx_client.cursor_rect.w = 0;
   4.388 +    fcitx_client.cursor_rect.h = 0;
   4.389 +
   4.390 +    SDL_snprintf(fcitx_client.servicename, IC_NAME_MAX,
   4.391 +            "%s-%d",
   4.392 +            FCITX_DBUS_SERVICE, GetDisplayNumber());
   4.393 +
   4.394 +    FcitxClientCreateIC(&fcitx_client);
   4.395 +
   4.396 +    return SDL_TRUE;
   4.397 +}
   4.398 +
   4.399 +void
   4.400 +SDL_Fcitx_Quit()
   4.401 +{
   4.402 +    FcitxClientICCallMethod(&fcitx_client, "DestroyIC");
   4.403 +}
   4.404 +
   4.405 +void
   4.406 +SDL_Fcitx_SetFocus(SDL_bool focused)
   4.407 +{
   4.408 +    if (focused) {
   4.409 +        FcitxClientICCallMethod(&fcitx_client, "FocusIn");
   4.410 +    } else {
   4.411 +        FcitxClientICCallMethod(&fcitx_client, "FocusOut");
   4.412 +    }
   4.413 +}
   4.414 +
   4.415 +void
   4.416 +SDL_Fcitx_Reset(void)
   4.417 +{
   4.418 +    FcitxClientICCallMethod(&fcitx_client, "Reset");
   4.419 +    FcitxClientICCallMethod(&fcitx_client, "CloseIC");
   4.420 +}
   4.421 +
   4.422 +SDL_bool
   4.423 +SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
   4.424 +{
   4.425 +    DBusMessage *msg = NULL;
   4.426 +    DBusMessage *reply = NULL;
   4.427 +    SDL_DBusContext *dbus = fcitx_client.dbus;
   4.428 +
   4.429 +    Uint32 state = 0;
   4.430 +    SDL_bool handled = SDL_FALSE;
   4.431 +    int type = FCITX_PRESS_KEY;
   4.432 +    Uint32 event_time = 0;
   4.433 +
   4.434 +    msg = FcitxClientICNewMethod(&fcitx_client, "ProcessKeyEvent");
   4.435 +    if (msg == NULL)
   4.436 +        return SDL_FALSE;
   4.437 +
   4.438 +    state = Fcitx_ModState();
   4.439 +    dbus->message_append_args(msg,
   4.440 +            DBUS_TYPE_UINT32, &keysym,
   4.441 +            DBUS_TYPE_UINT32, &keycode,
   4.442 +            DBUS_TYPE_UINT32, &state,
   4.443 +            DBUS_TYPE_INT32, &type,
   4.444 +            DBUS_TYPE_UINT32, &event_time,
   4.445 +            DBUS_TYPE_INVALID);
   4.446 +
   4.447 +    reply = dbus->connection_send_with_reply_and_block(dbus->session_conn,
   4.448 +            msg,
   4.449 +            -1,
   4.450 +            NULL);
   4.451 +
   4.452 +    if (reply) {
   4.453 +        dbus->message_get_args(reply,
   4.454 +                NULL,
   4.455 +                DBUS_TYPE_INT32, &handled,
   4.456 +                DBUS_TYPE_INVALID);
   4.457 +
   4.458 +        dbus->message_unref(reply);
   4.459 +    }
   4.460 +
   4.461 +    if (handled) {
   4.462 +        SDL_Fcitx_UpdateTextRect(NULL);
   4.463 +    }
   4.464 +
   4.465 +    return handled;
   4.466 +}
   4.467 +
   4.468 +void
   4.469 +SDL_Fcitx_UpdateTextRect(SDL_Rect *rect)
   4.470 +{
   4.471 +    SDL_Window *focused_win = NULL;
   4.472 +    SDL_SysWMinfo info;
   4.473 +    int x = 0, y = 0;
   4.474 +    SDL_Rect *cursor = &fcitx_client.cursor_rect;
   4.475 +
   4.476 +    SDL_DBusContext *dbus = fcitx_client.dbus;
   4.477 +    DBusMessage *msg = NULL;
   4.478 +    DBusConnection *conn;
   4.479 +
   4.480 +    if (rect) {
   4.481 +        SDL_memcpy(cursor, rect, sizeof(SDL_Rect));
   4.482 +    }
   4.483 +
   4.484 +    focused_win = SDL_GetKeyboardFocus();
   4.485 +    if (!focused_win) {
   4.486 +        return ;
   4.487 +    }
   4.488 +
   4.489 +    SDL_VERSION(&info.version);
   4.490 +    if (!SDL_GetWindowWMInfo(focused_win, &info)) {
   4.491 +        return;
   4.492 +    }
   4.493 +
   4.494 +    SDL_GetWindowPosition(focused_win, &x, &y);
   4.495 +
   4.496 +#if SDL_VIDEO_DRIVER_X11
   4.497 +    if (info.subsystem == SDL_SYSWM_X11) {
   4.498 +        SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(focused_win)->driverdata;
   4.499 +
   4.500 +        Display *x_disp = info.info.x11.display;
   4.501 +        Window x_win = info.info.x11.window;
   4.502 +        int x_screen = displaydata->screen;
   4.503 +        Window unused;
   4.504 +        X11_XTranslateCoordinates(x_disp, x_win, RootWindow(x_disp, x_screen), 0, 0, &x, &y, &unused);
   4.505 +    }
   4.506 +#endif
   4.507 +
   4.508 +    if (cursor->x == -1 && cursor->y == -1 && cursor->w == 0 && cursor->h == 0) {
   4.509 +        // move to bottom left
   4.510 +        int w = 0, h = 0;
   4.511 +        SDL_GetWindowSize(focused_win, &w, &h);
   4.512 +        cursor->x = 0;
   4.513 +        cursor->y = h;
   4.514 +    }
   4.515 +
   4.516 +    x += cursor->x;
   4.517 +    y += cursor->y;
   4.518 +
   4.519 +    msg = FcitxClientICNewMethod(&fcitx_client, "SetCursorRect");
   4.520 +    if (msg == NULL)
   4.521 +        return ;
   4.522 +
   4.523 +    dbus->message_append_args(msg,
   4.524 +            DBUS_TYPE_INT32, &x,
   4.525 +            DBUS_TYPE_INT32, &y,
   4.526 +            DBUS_TYPE_INT32, &cursor->w,
   4.527 +            DBUS_TYPE_INT32, &cursor->h,
   4.528 +            DBUS_TYPE_INVALID);
   4.529 +
   4.530 +    conn = dbus->session_conn;
   4.531 +    if (dbus->connection_send(conn, msg, NULL))
   4.532 +        dbus->connection_flush(conn);
   4.533 +
   4.534 +    dbus->message_unref(msg);
   4.535 +}
   4.536 +
   4.537 +void
   4.538 +SDL_Fcitx_PumpEvents()
   4.539 +{
   4.540 +    SDL_DBusContext *dbus = fcitx_client.dbus;
   4.541 +    DBusConnection *conn = dbus->session_conn;
   4.542 +
   4.543 +    dbus->connection_read_write(conn, 0);
   4.544 +
   4.545 +    while (dbus->connection_dispatch(conn) == DBUS_DISPATCH_DATA_REMAINS) {
   4.546 +        /* Do nothing, actual work happens in DBus_MessageFilter */
   4.547 +        usleep(10);
   4.548 +    }
   4.549 +}
   4.550 +
   4.551 +/* vi: set ts=4 sw=4 expandtab: */
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/core/linux/SDL_fcitx.h	Fri Oct 07 18:57:40 2016 -0700
     5.3 @@ -0,0 +1,40 @@
     5.4 +/*
     5.5 +  Simple DirectMedia Layer
     5.6 +  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
     5.7 +
     5.8 +  This software is provided 'as-is', without any express or implied
     5.9 +  warranty.  In no event will the authors be held liable for any damages
    5.10 +  arising from the use of this software.
    5.11 +
    5.12 +  Permission is granted to anyone to use this software for any purpose,
    5.13 +  including commercial applications, and to alter it and redistribute it
    5.14 +  freely, subject to the following restrictions:
    5.15 +
    5.16 +  1. The origin of this software must not be misrepresented; you must not
    5.17 +     claim that you wrote the original software. If you use this software
    5.18 +     in a product, an acknowledgment in the product documentation would be
    5.19 +     appreciated but is not required.
    5.20 +  2. Altered source versions must be plainly marked as such, and must not be
    5.21 +     misrepresented as being the original software.
    5.22 +  3. This notice may not be removed or altered from any source distribution.
    5.23 +*/
    5.24 +
    5.25 +#ifndef _SDL_fcitx_h
    5.26 +#define _SDL_fcitx_h
    5.27 +
    5.28 +#include "../../SDL_internal.h"
    5.29 +
    5.30 +#include "SDL_stdinc.h"
    5.31 +#include "SDL_rect.h"
    5.32 +
    5.33 +extern SDL_bool SDL_Fcitx_Init(void);
    5.34 +extern void SDL_Fcitx_Quit(void);
    5.35 +extern void SDL_Fcitx_SetFocus(SDL_bool focused);
    5.36 +extern void SDL_Fcitx_Reset(void);
    5.37 +extern SDL_bool SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode);
    5.38 +extern void SDL_Fcitx_UpdateTextRect(SDL_Rect *rect);
    5.39 +extern void SDL_Fcitx_PumpEvents();
    5.40 +
    5.41 +#endif /* _SDL_fcitx_h */
    5.42 +
    5.43 +/* vi: set ts=4 sw=4 expandtab: */
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/core/linux/SDL_ime.c	Fri Oct 07 18:57:40 2016 -0700
     6.3 @@ -0,0 +1,135 @@
     6.4 +/*
     6.5 +  Simple DirectMedia Layer
     6.6 +  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
     6.7 +
     6.8 +  This software is provided 'as-is', without any express or implied
     6.9 +  warranty.  In no event will the authors be held liable for any damages
    6.10 +  arising from the use of this software.
    6.11 +
    6.12 +  Permission is granted to anyone to use this software for any purpose,
    6.13 +  including commercial applications, and to alter it and redistribute it
    6.14 +  freely, subject to the following restrictions:
    6.15 +
    6.16 +  1. The origin of this software must not be misrepresented; you must not
    6.17 +     claim that you wrote the original software. If you use this software
    6.18 +     in a product, an acknowledgment in the product documentation would be
    6.19 +     appreciated but is not required.
    6.20 +  2. Altered source versions must be plainly marked as such, and must not be
    6.21 +     misrepresented as being the original software.
    6.22 +  3. This notice may not be removed or altered from any source distribution.
    6.23 +*/
    6.24 +
    6.25 +#include "SDL_ime.h"
    6.26 +#include "SDL_ibus.h"
    6.27 +#include "SDL_fcitx.h"
    6.28 +
    6.29 +typedef SDL_bool (*_SDL_IME_Init)();
    6.30 +typedef void (*_SDL_IME_Quit)();
    6.31 +typedef void (*_SDL_IME_SetFocus)(SDL_bool);
    6.32 +typedef void (*_SDL_IME_Reset)();
    6.33 +typedef SDL_bool (*_SDL_IME_ProcessKeyEvent)(Uint32, Uint32);
    6.34 +typedef void (*_SDL_IME_UpdateTextRect)(SDL_Rect *);
    6.35 +typedef void (*_SDL_IME_PumpEvents)();
    6.36 +
    6.37 +static _SDL_IME_Init SDL_IME_Init_Real = NULL;
    6.38 +static _SDL_IME_Quit SDL_IME_Quit_Real = NULL;
    6.39 +static _SDL_IME_SetFocus SDL_IME_SetFocus_Real = NULL;
    6.40 +static _SDL_IME_Reset SDL_IME_Reset_Real = NULL;
    6.41 +static _SDL_IME_ProcessKeyEvent SDL_IME_ProcessKeyEvent_Real = NULL;
    6.42 +static _SDL_IME_UpdateTextRect SDL_IME_UpdateTextRect_Real = NULL;
    6.43 +static _SDL_IME_PumpEvents SDL_IME_PumpEvents_Real = NULL;
    6.44 +
    6.45 +static void
    6.46 +InitIME()
    6.47 +{
    6.48 +    static SDL_bool inited = SDL_FALSE;
    6.49 +    const char *im_module = NULL;
    6.50 +
    6.51 +    if (inited == SDL_TRUE)
    6.52 +        return ;
    6.53 +
    6.54 +    inited = SDL_TRUE;
    6.55 +    // TODO:
    6.56 +    // better move every ime implenment to a shared library
    6.57 +
    6.58 +    // default to IBus
    6.59 +#ifdef HAVE_IBUS_IBUS_H
    6.60 +    SDL_IME_Init_Real = SDL_IBus_Init;
    6.61 +    SDL_IME_Quit_Real = SDL_IBus_Quit;
    6.62 +    SDL_IME_SetFocus_Real = SDL_IBus_SetFocus;
    6.63 +    SDL_IME_Reset_Real = SDL_IBus_Reset;
    6.64 +    SDL_IME_ProcessKeyEvent_Real = SDL_IBus_ProcessKeyEvent;
    6.65 +    SDL_IME_UpdateTextRect_Real = SDL_IBus_UpdateTextRect;
    6.66 +    SDL_IME_PumpEvents_Real = SDL_IBus_PumpEvents;
    6.67 +#endif
    6.68 +
    6.69 +    im_module = SDL_getenv("SDL_IM_MODULE");
    6.70 +    if (im_module) {
    6.71 +        if (SDL_strcmp(im_module, "fcitx") == 0) {
    6.72 +#ifdef HAVE_FCITX_FRONTEND_H
    6.73 +            SDL_IME_Init_Real = SDL_Fcitx_Init;
    6.74 +            SDL_IME_Quit_Real = SDL_Fcitx_Quit;
    6.75 +            SDL_IME_SetFocus_Real = SDL_Fcitx_SetFocus;
    6.76 +            SDL_IME_Reset_Real = SDL_Fcitx_Reset;
    6.77 +            SDL_IME_ProcessKeyEvent_Real = SDL_Fcitx_ProcessKeyEvent;
    6.78 +            SDL_IME_UpdateTextRect_Real = SDL_Fcitx_UpdateTextRect;
    6.79 +            SDL_IME_PumpEvents_Real = SDL_Fcitx_PumpEvents;
    6.80 +#endif
    6.81 +        }
    6.82 +    }
    6.83 +}
    6.84 +
    6.85 +SDL_bool
    6.86 +SDL_IME_Init(void)
    6.87 +{
    6.88 +    InitIME();
    6.89 +
    6.90 +    if (SDL_IME_Init_Real)
    6.91 +        return SDL_IME_Init_Real();
    6.92 +
    6.93 +    return SDL_FALSE;
    6.94 +}
    6.95 +
    6.96 +void
    6.97 +SDL_IME_Quit(void)
    6.98 +{
    6.99 +    if (SDL_IME_Quit_Real)
   6.100 +        SDL_IME_Quit_Real();
   6.101 +}
   6.102 +
   6.103 +void
   6.104 +SDL_IME_SetFocus(SDL_bool focused)
   6.105 +{
   6.106 +    if (SDL_IME_SetFocus_Real)
   6.107 +        SDL_IME_SetFocus_Real(focused);
   6.108 +}
   6.109 +
   6.110 +void
   6.111 +SDL_IME_Reset(void)
   6.112 +{
   6.113 +    if (SDL_IME_Reset_Real)
   6.114 +        SDL_IME_Reset_Real();
   6.115 +}
   6.116 +
   6.117 +SDL_bool
   6.118 +SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
   6.119 +{
   6.120 +    if (SDL_IME_ProcessKeyEvent_Real)
   6.121 +        return SDL_IME_ProcessKeyEvent_Real(keysym, keycode);
   6.122 +
   6.123 +    return SDL_FALSE;
   6.124 +}
   6.125 +
   6.126 +void
   6.127 +SDL_IME_UpdateTextRect(SDL_Rect *rect)
   6.128 +{
   6.129 +    if (SDL_IME_UpdateTextRect_Real)
   6.130 +        SDL_IME_UpdateTextRect_Real(rect);
   6.131 +}
   6.132 +
   6.133 +void
   6.134 +SDL_IME_PumpEvents()
   6.135 +{
   6.136 +    if (SDL_IME_PumpEvents_Real)
   6.137 +        SDL_IME_PumpEvents_Real();
   6.138 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/core/linux/SDL_ime.h	Fri Oct 07 18:57:40 2016 -0700
     7.3 @@ -0,0 +1,38 @@
     7.4 +/*
     7.5 +  Simple DirectMedia Layer
     7.6 +  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
     7.7 +
     7.8 +  This software is provided 'as-is', without any express or implied
     7.9 +  warranty.  In no event will the authors be held liable for any damages
    7.10 +  arising from the use of this software.
    7.11 +
    7.12 +  Permission is granted to anyone to use this software for any purpose,
    7.13 +  including commercial applications, and to alter it and redistribute it
    7.14 +  freely, subject to the following restrictions:
    7.15 +
    7.16 +  1. The origin of this software must not be misrepresented; you must not
    7.17 +     claim that you wrote the original software. If you use this software
    7.18 +     in a product, an acknowledgment in the product documentation would be
    7.19 +     appreciated but is not required.
    7.20 +  2. Altered source versions must be plainly marked as such, and must not be
    7.21 +     misrepresented as being the original software.
    7.22 +  3. This notice may not be removed or altered from any source distribution.
    7.23 +*/
    7.24 +
    7.25 +#ifndef _SDL_ime_h
    7.26 +#define _SDL_ime_h
    7.27 +
    7.28 +#include "../../SDL_internal.h"
    7.29 +
    7.30 +#include "SDL_stdinc.h"
    7.31 +#include "SDL_rect.h"
    7.32 +
    7.33 +extern SDL_bool SDL_IME_Init();
    7.34 +extern void SDL_IME_Quit();
    7.35 +extern void SDL_IME_SetFocus(SDL_bool focused);
    7.36 +extern void SDL_IME_Reset();
    7.37 +extern SDL_bool SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode);
    7.38 +extern void SDL_IME_UpdateTextRect(SDL_Rect *rect);
    7.39 +extern void SDL_IME_PumpEvents();
    7.40 +
    7.41 +#endif /* _SDL_ime_h */
     8.1 --- a/src/video/x11/SDL_x11events.c	Fri Oct 07 18:24:34 2016 -0700
     8.2 +++ b/src/video/x11/SDL_x11events.c	Fri Oct 07 18:57:40 2016 -0700
     8.3 @@ -380,8 +380,8 @@
     8.4          X11_XSetICFocus(data->ic);
     8.5      }
     8.6  #endif
     8.7 -#ifdef SDL_USE_IBUS
     8.8 -    SDL_IBus_SetFocus(SDL_TRUE);
     8.9 +#ifdef SDL_USE_IME
    8.10 +    SDL_IME_SetFocus(SDL_TRUE);
    8.11  #endif
    8.12  }
    8.13  
    8.14 @@ -403,8 +403,8 @@
    8.15          X11_XUnsetICFocus(data->ic);
    8.16      }
    8.17  #endif
    8.18 -#ifdef SDL_USE_IBUS
    8.19 -    SDL_IBus_SetFocus(SDL_FALSE);
    8.20 +#ifdef SDL_USE_IME
    8.21 +    SDL_IME_SetFocus(SDL_FALSE);
    8.22  #endif
    8.23  }
    8.24  
    8.25 @@ -786,9 +786,9 @@
    8.26              X11_XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL);
    8.27  #endif
    8.28  
    8.29 -#ifdef SDL_USE_IBUS
    8.30 +#ifdef SDL_USE_IME
    8.31              if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
    8.32 -                handled_by_ime = SDL_IBus_ProcessKeyEvent(keysym, keycode);
    8.33 +                handled_by_ime = SDL_IME_ProcessKeyEvent(keysym, keycode);
    8.34              }
    8.35  #endif
    8.36              if (!handled_by_ime) {
    8.37 @@ -860,10 +860,10 @@
    8.38                  xevent.xconfigure.y != data->last_xconfigure.y) {
    8.39                  SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED,
    8.40                                      xevent.xconfigure.x, xevent.xconfigure.y);
    8.41 -#ifdef SDL_USE_IBUS
    8.42 +#ifdef SDL_USE_IME
    8.43                  if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
    8.44 -                    /* Update IBus candidate list position */
    8.45 -                    SDL_IBus_UpdateTextRect(NULL);
    8.46 +                    /* Update IME candidate list position */
    8.47 +                    SDL_IME_UpdateTextRect(NULL);
    8.48                  }
    8.49  #endif
    8.50              }
    8.51 @@ -1408,9 +1408,9 @@
    8.52          X11_DispatchEvent(_this);
    8.53      }
    8.54  
    8.55 -#ifdef SDL_USE_IBUS
    8.56 +#ifdef SDL_USE_IME
    8.57      if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
    8.58 -        SDL_IBus_PumpEvents();
    8.59 +        SDL_IME_PumpEvents();
    8.60      }
    8.61  #endif
    8.62  
     9.1 --- a/src/video/x11/SDL_x11keyboard.c	Fri Oct 07 18:24:34 2016 -0700
     9.2 +++ b/src/video/x11/SDL_x11keyboard.c	Fri Oct 07 18:57:40 2016 -0700
     9.3 @@ -339,8 +339,8 @@
     9.4  
     9.5      SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
     9.6  
     9.7 -#ifdef SDL_USE_IBUS
     9.8 -    SDL_IBus_Init();
     9.9 +#ifdef SDL_USE_IME
    9.10 +    SDL_IME_Init();
    9.11  #endif
    9.12  
    9.13      return 0;
    9.14 @@ -422,8 +422,8 @@
    9.15      }
    9.16  #endif
    9.17  
    9.18 -#ifdef SDL_USE_IBUS
    9.19 -    SDL_IBus_Quit();
    9.20 +#ifdef SDL_USE_IME
    9.21 +    SDL_IME_Quit();
    9.22  #endif
    9.23  }
    9.24  
    9.25 @@ -436,8 +436,8 @@
    9.26  void
    9.27  X11_StopTextInput(_THIS)
    9.28  {
    9.29 -#ifdef SDL_USE_IBUS
    9.30 -    SDL_IBus_Reset();
    9.31 +#ifdef SDL_USE_IME
    9.32 +    SDL_IME_Reset();
    9.33  #endif
    9.34  }
    9.35  
    9.36 @@ -449,8 +449,8 @@
    9.37          return;
    9.38      }
    9.39         
    9.40 -#ifdef SDL_USE_IBUS
    9.41 -    SDL_IBus_UpdateTextRect(rect);
    9.42 +#ifdef SDL_USE_IME
    9.43 +    SDL_IME_UpdateTextRect(rect);
    9.44  #endif
    9.45  }
    9.46  
    10.1 --- a/src/video/x11/SDL_x11video.h	Fri Oct 07 18:24:34 2016 -0700
    10.2 +++ b/src/video/x11/SDL_x11video.h	Fri Oct 07 18:57:40 2016 -0700
    10.3 @@ -57,7 +57,7 @@
    10.4  #endif
    10.5  
    10.6  #include "../../core/linux/SDL_dbus.h"
    10.7 -#include "../../core/linux/SDL_ibus.h"
    10.8 +#include "../../core/linux/SDL_ime.h"
    10.9  
   10.10  #include "SDL_x11dyn.h"
   10.11