diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b63bf8a6..64bf067eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1213,6 +1213,8 @@ elseif(UNIX AND NOT APPLE AND NOT ANDROID AND NOT RISCOS) set(HAVE_DBUS_DBUS_H TRUE) include_directories(${DBUS_INCLUDE_DIRS}) list(APPEND EXTRA_LIBS ${DBUS_LIBRARIES}) + # Fcitx need only dbus. + set(HAVE_FCITX TRUE) endif() pkg_search_module(IBUS ibus-1.0 ibus) @@ -1220,6 +1222,9 @@ elseif(UNIX AND NOT APPLE AND NOT ANDROID AND NOT RISCOS) set(HAVE_IBUS_IBUS_H TRUE) include_directories(${IBUS_INCLUDE_DIRS}) list(APPEND EXTRA_LIBS ${IBUS_LIBRARIES}) + endif() + + if (HAVE_IBUS_IBUS_H OR HAVE_FCITX) add_definitions(-DSDL_USE_IME) endif() if(HAVE_LIBUNWIND_H) @@ -1229,8 +1234,6 @@ elseif(UNIX AND NOT APPLE AND NOT ANDROID AND NOT RISCOS) list(APPEND EXTRA_LIBS ${UNWIND_LIBRARIES} ${UNWIND_GENERIC_LIBRARIES}) endif() endif() - - check_include_file("fcitx/frontend.h" HAVE_FCITX_FRONTEND_H) endif() if(INPUT_TSLIB) diff --git a/configure.ac b/configure.ac index fcc5c488a..3cabdabab 100644 --- a/configure.ac +++ b/configure.ac @@ -2731,24 +2731,13 @@ CheckFcitx() AS_HELP_STRING([--enable-fcitx], [enable fcitx support [[default=yes]]]), , enable_fcitx=yes) if test x$enable_fcitx = xyes; then - PKG_CHECK_MODULES([FCITX], [fcitx], have_fcitx=yes, have_fcitx=no) - CFLAGS="$CFLAGS $FCITX_CFLAGS" - AC_CHECK_HEADER(fcitx/frontend.h, - have_fcitx_frontend_h_hdr=yes, - have_fcitx_frontend_h_hdr=no) - CFLAGS="$save_CFLAGS" - if test x$have_fcitx_frontend_h_hdr = xyes; then - if test x$enable_ime != xyes; then - AC_MSG_WARN([IME support is required for fcitx.]) - have_fcitx_frontend_h_hdr=no - elif test x$enable_dbus != xyes; then - AC_MSG_WARN([DBus support is required for fcitx.]) - have_fcitx_frontend_h_hdr=no - else - AC_DEFINE(HAVE_FCITX_FRONTEND_H, 1, [ ]) - EXTRA_CFLAGS="$EXTRA_CFLAGS $FCITX_CFLAGS" - SOURCES="$SOURCES $srcdir/src/core/linux/SDL_fcitx.c" - fi + if test x$enable_ime != xyes; then + AC_MSG_WARN([IME support is required for fcitx.]) + elif test x$enable_dbus != xyes; then + AC_MSG_WARN([DBus support is required for fcitx.]) + else + AC_DEFINE(HAVE_FCITX, 1, [ ]) + SOURCES="$SOURCES $srcdir/src/core/linux/SDL_fcitx.c" fi fi } @@ -4408,7 +4397,7 @@ if test x$have_ibus_ibus_h_hdr = xyes; then else SUMMARY="${SUMMARY}Using ibus : NO\n" fi -if test x$have_fcitx_frontend_h_hdr = xyes; then +if test x$enable_fcitx = xyes; then SUMMARY="${SUMMARY}Using fcitx : YES\n" else SUMMARY="${SUMMARY}Using fcitx : NO\n" diff --git a/include/SDL_config.h.cmake b/include/SDL_config.h.cmake index d74ea9205..22c845df4 100644 --- a/include/SDL_config.h.cmake +++ b/include/SDL_config.h.cmake @@ -203,7 +203,7 @@ #cmakedefine HAVE_ALTIVEC_H 1 #cmakedefine HAVE_DBUS_DBUS_H 1 -#cmakedefine HAVE_FCITX_FRONTEND_H 1 +#cmakedefine HAVE_FCITX 1 #cmakedefine HAVE_IBUS_IBUS_H 1 #cmakedefine HAVE_IMMINTRIN_H 1 #cmakedefine HAVE_LIBSAMPLERATE_H 1 diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in index 42488cc9a..92052fc78 100644 --- a/include/SDL_config.h.in +++ b/include/SDL_config.h.in @@ -204,7 +204,7 @@ #undef HAVE_ALTIVEC_H #undef HAVE_DBUS_DBUS_H -#undef HAVE_FCITX_FRONTEND_H +#undef HAVE_FCITX #undef HAVE_IBUS_IBUS_H #undef HAVE_IMMINTRIN_H #undef HAVE_LIBSAMPLERATE_H diff --git a/src/core/linux/SDL_dbus.c b/src/core/linux/SDL_dbus.c index 02579aa30..4a3b0dfe2 100644 --- a/src/core/linux/SDL_dbus.c +++ b/src/core/linux/SDL_dbus.c @@ -57,6 +57,10 @@ LoadDBUSSyms(void) SDL_DBUS_SYM(message_new_method_call); SDL_DBUS_SYM(message_append_args); SDL_DBUS_SYM(message_append_args_valist); + SDL_DBUS_SYM(message_iter_init_append); + SDL_DBUS_SYM(message_iter_open_container); + SDL_DBUS_SYM(message_iter_append_basic); + SDL_DBUS_SYM(message_iter_close_container); SDL_DBUS_SYM(message_get_args); SDL_DBUS_SYM(message_get_args_valist); SDL_DBUS_SYM(message_iter_init); diff --git a/src/core/linux/SDL_dbus.h b/src/core/linux/SDL_dbus.h index 9f77512aa..334a87ca7 100644 --- a/src/core/linux/SDL_dbus.h +++ b/src/core/linux/SDL_dbus.h @@ -54,6 +54,10 @@ typedef struct SDL_DBusContext { 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_append_args_valist)(DBusMessage *, int, va_list); + void (*message_iter_init_append)(DBusMessage *, DBusMessageIter *); + dbus_bool_t (*message_iter_open_container)(DBusMessageIter *, int, const char *, DBusMessageIter *); + dbus_bool_t (*message_iter_append_basic)(DBusMessageIter *, int, const void *); + dbus_bool_t (*message_iter_close_container)(DBusMessageIter *, DBusMessageIter *); dbus_bool_t (*message_get_args)(DBusMessage *, DBusError *, int, ...); dbus_bool_t (*message_get_args_valist)(DBusMessage *, DBusError *, int, va_list); dbus_bool_t (*message_iter_init)(DBusMessage *, DBusMessageIter *); diff --git a/src/core/linux/SDL_fcitx.c b/src/core/linux/SDL_fcitx.c index 920cb6d9f..c0005b563 100644 --- a/src/core/linux/SDL_fcitx.c +++ b/src/core/linux/SDL_fcitx.c @@ -20,9 +20,6 @@ */ #include "../../SDL_internal.h" -#ifdef HAVE_FCITX_FRONTEND_H - -#include #include #include "SDL_fcitx.h" @@ -36,23 +33,20 @@ #endif #include "SDL_hints.h" -#define FCITX_DBUS_SERVICE "org.fcitx.Fcitx" +#define FCITX_DBUS_SERVICE "org.freedesktop.portal.Fcitx" -#define FCITX_IM_DBUS_PATH "/inputmethod" -#define FCITX_IC_DBUS_PATH "/inputcontext_%d" +#define FCITX_IM_DBUS_PATH "/org/freedesktop/portal/inputmethod" -#define FCITX_IM_DBUS_INTERFACE "org.fcitx.Fcitx.InputMethod" -#define FCITX_IC_DBUS_INTERFACE "org.fcitx.Fcitx.InputContext" +#define FCITX_IM_DBUS_INTERFACE "org.fcitx.Fcitx.InputMethod1" +#define FCITX_IC_DBUS_INTERFACE "org.fcitx.Fcitx.InputContext1" -#define IC_NAME_MAX 64 #define DBUS_TIMEOUT 500 typedef struct _FcitxClient { SDL_DBusContext *dbus; - char servicename[IC_NAME_MAX]; - char icname[IC_NAME_MAX]; + char *ic_path; int id; @@ -61,34 +55,6 @@ typedef struct _FcitxClient static FcitxClient fcitx_client; -static int -GetDisplayNumber() -{ - const char *display = SDL_getenv("DISPLAY"); - const char *p = NULL; - int number = 0; - - if (display == NULL) - return 0; - - display = SDL_strchr(display, ':'); - if (display == NULL) - return 0; - - display++; - p = SDL_strchr(display, '.'); - if (p == NULL && display != NULL) { - number = SDL_strtod(display, NULL); - } else { - char *buffer = SDL_strdup(display); - buffer[p - display] = '\0'; - number = SDL_strtod(buffer, NULL); - SDL_free(buffer); - } - - return number; -} - static char* GetAppName() { @@ -118,6 +84,54 @@ GetAppName() return SDL_strdup("SDL_App"); } +size_t Fcitx_GetPreeditString(SDL_DBusContext *dbus, DBusMessage *msg, char **ret) { + char *text = NULL, *subtext; + size_t text_bytes = 0; + DBusMessageIter iter, array, sub; + + dbus->message_iter_init(msg, &iter); + /* Message type is a(si)i, we only need string part */ + if (dbus->message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY) { + /* First pass: calculate string length */ + dbus->message_iter_recurse(&iter, &array); + while (dbus->message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) { + dbus->message_iter_recurse(&array, &sub); + if (dbus->message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) { + dbus->message_iter_get_basic(&sub, &subtext); + if (subtext && *subtext) { + text_bytes += SDL_strlen(subtext); + } + } + dbus->message_iter_next(&array); + } + if (text_bytes) { + text = SDL_malloc(text_bytes + 1); + } + + if (text) { + char* pivot = text; + /* Second pass: join all the sub string */ + dbus->message_iter_recurse(&iter, &array); + while (dbus->message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) { + dbus->message_iter_recurse(&array, &sub); + if (dbus->message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) { + dbus->message_iter_get_basic(&sub, &subtext); + if (subtext && *subtext) { + size_t length = SDL_strlen(subtext); + SDL_strlcpy(pivot, subtext, length + 1); + pivot += length; + } + } + dbus->message_iter_next(&array); + } + } else { + text_bytes = 0; + } + } + *ret= text; + return text_bytes; +} + static DBusHandlerResult DBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -136,16 +150,12 @@ DBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *data) return DBUS_HANDLER_RESULT_HANDLED; } - if (dbus->message_is_signal(msg, FCITX_IC_DBUS_INTERFACE, "UpdatePreedit")) { - DBusMessageIter iter; - const char *text; - - dbus->message_iter_init(msg, &iter); - dbus->message_iter_get_basic(&iter, &text); - - if (text && *text) { + if (dbus->message_is_signal(msg, FCITX_IC_DBUS_INTERFACE, "UpdateFormattedPreedit")) { + char *text = NULL; + size_t text_bytes = Fcitx_GetPreeditString(dbus, msg, &text); + if (text_bytes) { char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE]; - size_t text_bytes = SDL_strlen(text), i = 0; + size_t i = 0; size_t cursor = 0; while (i < text_bytes) { @@ -157,6 +167,9 @@ DBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *data) i += sz; cursor += chars; } + SDL_free(text); + } else { + SDL_SendEditingText("", 0, 0); } SDL_Fcitx_UpdateTextRect(NULL); @@ -169,7 +182,10 @@ DBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *data) static void FcitxClientICCallMethod(FcitxClient *client, const char *method) { - SDL_DBus_CallVoidMethod(client->servicename, client->icname, FCITX_IC_DBUS_INTERFACE, method, DBUS_TYPE_INVALID); + if (!client->ic_path) { + return; + } + SDL_DBus_CallVoidMethod(FCITX_DBUS_SERVICE, client->ic_path, FCITX_IC_DBUS_INTERFACE, method, DBUS_TYPE_INVALID); } static void SDLCALL @@ -179,40 +195,68 @@ Fcitx_SetCapabilities(void *data, const char *internal_editing) { FcitxClient *client = (FcitxClient *)data; - Uint32 caps = CAPACITY_NONE; - - if (!(internal_editing && *internal_editing == '1')) { - caps |= CAPACITY_PREEDIT; + Uint32 caps = 0; + if (!client->ic_path) { + return; } - SDL_DBus_CallVoidMethod(client->servicename, client->icname, FCITX_IC_DBUS_INTERFACE, "SetCapacity", DBUS_TYPE_UINT32, &caps, DBUS_TYPE_INVALID); + if (!(internal_editing && *internal_editing == '1')) { + caps |= (1 << 1); /* Preedit Flag */ + caps |= (1 << 4); /* Formatted Preedit Flag */ + } + + SDL_DBus_CallVoidMethod(FCITX_DBUS_SERVICE, client->ic_path, FCITX_IC_DBUS_INTERFACE, "SetCapability", DBUS_TYPE_UINT64, &caps, DBUS_TYPE_INVALID); +} + +static SDL_bool +FcitxCreateInputContext(SDL_DBusContext* dbus, const char *appname, char **ic_path) { + const char *program = "program"; + SDL_bool retval = SDL_FALSE; + if (dbus->session_conn) { + DBusMessage *msg = dbus->message_new_method_call(FCITX_DBUS_SERVICE, FCITX_IM_DBUS_PATH, FCITX_IM_DBUS_INTERFACE, "CreateInputContext"); + if (msg) { + DBusMessage *reply = NULL; + DBusMessageIter args, array, sub; + dbus->message_iter_init_append(msg, &args); + dbus->message_iter_open_container(&args, DBUS_TYPE_ARRAY, "(ss)", &array); + dbus->message_iter_open_container(&array, DBUS_TYPE_STRUCT, 0, &sub); + dbus->message_iter_append_basic(&sub, DBUS_TYPE_STRING, &program); + dbus->message_iter_append_basic(&sub, DBUS_TYPE_STRING, &appname); + dbus->message_iter_close_container(&array, &sub); + dbus->message_iter_close_container(&args, &array); + reply = dbus->connection_send_with_reply_and_block(dbus->session_conn, msg, 300, NULL); + if (reply) { + if (dbus->message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, ic_path, DBUS_TYPE_INVALID)) { + retval = SDL_TRUE; + } + dbus->message_unref(reply); + } + dbus->message_unref(msg); + } + } + return retval; } static SDL_bool FcitxClientCreateIC(FcitxClient *client) { char *appname = GetAppName(); - pid_t pid = getpid(); - int id = -1; - Uint32 enable, arg1, arg2, arg3, arg4; + char *ic_path = NULL; + SDL_DBusContext *dbus = client->dbus; - if (!SDL_DBus_CallMethod(client->servicename, FCITX_IM_DBUS_PATH, FCITX_IM_DBUS_INTERFACE, "CreateICv3", - DBUS_TYPE_STRING, &appname, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INVALID, - DBUS_TYPE_INT32, &id, DBUS_TYPE_BOOLEAN, &enable, DBUS_TYPE_UINT32, &arg1, DBUS_TYPE_UINT32, &arg2, DBUS_TYPE_UINT32, &arg3, DBUS_TYPE_UINT32, &arg4, DBUS_TYPE_INVALID)) { - id = -1; /* just in case. */ + /* SDL_DBus_CallMethod cannot handle a(ss) type, call dbus function directly */ + if (!FcitxCreateInputContext(dbus, appname, &ic_path)) { + ic_path = NULL; /* just in case. */ } SDL_free(appname); - if (id >= 0) { - SDL_DBusContext *dbus = client->dbus; - - client->id = id; - - SDL_snprintf(client->icname, IC_NAME_MAX, FCITX_IC_DBUS_PATH, client->id); + if (ic_path) { + SDL_free(client->ic_path); + client->ic_path = SDL_strdup(ic_path); dbus->bus_add_match(dbus->session_conn, - "type='signal', interface='org.fcitx.Fcitx.InputContext'", + "type='signal', interface='org.fcitx.Fcitx.InputContext1'", NULL); dbus->connection_add_filter(dbus->session_conn, &DBus_MessageFilter, dbus, @@ -232,13 +276,14 @@ Fcitx_ModState(void) Uint32 fcitx_mods = 0; SDL_Keymod sdl_mods = SDL_GetModState(); - if (sdl_mods & KMOD_SHIFT) fcitx_mods |= FcitxKeyState_Shift; - if (sdl_mods & KMOD_CAPS) fcitx_mods |= FcitxKeyState_CapsLock; - if (sdl_mods & KMOD_CTRL) fcitx_mods |= FcitxKeyState_Ctrl; - if (sdl_mods & KMOD_ALT) fcitx_mods |= FcitxKeyState_Alt; - if (sdl_mods & KMOD_NUM) fcitx_mods |= FcitxKeyState_NumLock; - if (sdl_mods & KMOD_LGUI) fcitx_mods |= FcitxKeyState_Super; - if (sdl_mods & KMOD_RGUI) fcitx_mods |= FcitxKeyState_Meta; + if (sdl_mods & KMOD_SHIFT) fcitx_mods |= (1 << 0); + if (sdl_mods & KMOD_CAPS) fcitx_mods |= (1 << 1); + if (sdl_mods & KMOD_CTRL) fcitx_mods |= (1 << 2); + if (sdl_mods & KMOD_ALT) fcitx_mods |= (1 << 3); + if (sdl_mods & KMOD_NUM) fcitx_mods |= (1 << 4); + if (sdl_mods & KMOD_MODE) fcitx_mods |= (1 << 7); + if (sdl_mods & KMOD_LGUI) fcitx_mods |= (1 << 6); + if (sdl_mods & KMOD_RGUI) fcitx_mods |= (1 << 28); return fcitx_mods; } @@ -253,10 +298,6 @@ SDL_Fcitx_Init() fcitx_client.cursor_rect.w = 0; fcitx_client.cursor_rect.h = 0; - SDL_snprintf(fcitx_client.servicename, IC_NAME_MAX, - "%s-%d", - FCITX_DBUS_SERVICE, GetDisplayNumber()); - return FcitxClientCreateIC(&fcitx_client); } @@ -264,6 +305,10 @@ void SDL_Fcitx_Quit() { FcitxClientICCallMethod(&fcitx_client, "DestroyIC"); + if (fcitx_client.ic_path) { + SDL_free(fcitx_client.ic_path); + fcitx_client.ic_path = NULL; + } } void @@ -288,12 +333,16 @@ SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode) { Uint32 state = Fcitx_ModState(); Uint32 handled = SDL_FALSE; - int type = FCITX_PRESS_KEY; + Uint32 is_release = SDL_FALSE; Uint32 event_time = 0; - if (SDL_DBus_CallMethod(fcitx_client.servicename, fcitx_client.icname, FCITX_IC_DBUS_INTERFACE, "ProcessKeyEvent", - DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &keycode, DBUS_TYPE_UINT32, &state, DBUS_TYPE_INT32, &type, DBUS_TYPE_UINT32, &event_time, DBUS_TYPE_INVALID, - DBUS_TYPE_INT32, &handled, DBUS_TYPE_INVALID)) { + if (!fcitx_client.ic_path) { + return SDL_FALSE; + } + + if (SDL_DBus_CallMethod(FCITX_DBUS_SERVICE, fcitx_client.ic_path, FCITX_IC_DBUS_INTERFACE, "ProcessKeyEvent", + DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &keycode, DBUS_TYPE_UINT32, &state, DBUS_TYPE_BOOLEAN, &is_release, DBUS_TYPE_UINT32, &event_time, DBUS_TYPE_INVALID, + DBUS_TYPE_BOOLEAN, &handled, DBUS_TYPE_INVALID)) { if (handled) { SDL_Fcitx_UpdateTextRect(NULL); return SDL_TRUE; @@ -350,7 +399,7 @@ SDL_Fcitx_UpdateTextRect(SDL_Rect *rect) x += cursor->x; y += cursor->y; - SDL_DBus_CallVoidMethod(fcitx_client.servicename, fcitx_client.icname, FCITX_IC_DBUS_INTERFACE, "SetCursorRect", + SDL_DBus_CallVoidMethod(FCITX_DBUS_SERVICE, fcitx_client.ic_path, FCITX_IC_DBUS_INTERFACE, "SetCursorRect", DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y, DBUS_TYPE_INT32, &cursor->w, DBUS_TYPE_INT32, &cursor->h, DBUS_TYPE_INVALID); } @@ -368,6 +417,4 @@ SDL_Fcitx_PumpEvents(void) } } -#endif /* HAVE_FCITX_FRONTEND_H */ - /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/core/linux/SDL_ime.c b/src/core/linux/SDL_ime.c index 8c9a47410..b6034227a 100644 --- a/src/core/linux/SDL_ime.c +++ b/src/core/linux/SDL_ime.c @@ -43,7 +43,7 @@ static void InitIME() { static SDL_bool inited = SDL_FALSE; -#ifdef HAVE_FCITX_FRONTEND_H +#ifdef HAVE_FCITX const char *im_module = SDL_getenv("SDL_IM_MODULE"); const char *xmodifiers = SDL_getenv("XMODIFIERS"); #endif @@ -54,7 +54,7 @@ InitIME() inited = SDL_TRUE; /* See if fcitx IME support is being requested */ -#ifdef HAVE_FCITX_FRONTEND_H +#ifdef HAVE_FCITX if (!SDL_IME_Init_Real && ((im_module && SDL_strcmp(im_module, "fcitx") == 0) || (!im_module && xmodifiers && SDL_strstr(xmodifiers, "@im=fcitx") != NULL))) { @@ -66,7 +66,7 @@ InitIME() SDL_IME_UpdateTextRect_Real = SDL_Fcitx_UpdateTextRect; SDL_IME_PumpEvents_Real = SDL_Fcitx_PumpEvents; } -#endif /* HAVE_FCITX_FRONTEND_H */ +#endif /* HAVE_FCITX */ /* default to IBus */ #ifdef HAVE_IBUS_IBUS_H diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index 24e9b0c15..ff65d982e 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -683,7 +683,7 @@ X11_DispatchEvent(_THIS) /* But only if we're using one of the DBus IMEs, otherwise some XIM IMEs will generate duplicate events */ if (orig_keycode) { -#if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX_FRONTEND_H) +#if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX) SDL_Scancode scancode = videodata->key_layout[orig_keycode]; videodata->filter_code = orig_keycode; videodata->filter_time = xevent.xkey.time;