Add IBus IME Support, move DBus code to its own file. (v3.3 squashed)
parent
0d673844ac
commit
41a39837ca
43
configure.in
43
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
#include "SDL_dbus.h"
|
||||
|
||||
#if SDL_USE_LIBDBUS
|
||||
/* we never link directly to libdbus. */
|
||||
#include "SDL_loadso.h"
|
||||
static const char *dbus_library = "libdbus-1.so.3";
|
||||
static void *dbus_handle = NULL;
|
||||
static unsigned int screensaver_cookie = 0;
|
||||
static SDL_DBusContext dbus = {0};
|
||||
|
||||
static int
|
||||
load_dbus_syms(void)
|
||||
{
|
||||
#define SDL_DBUS_SYM2(x, y) \
|
||||
if (!(dbus.x = SDL_LoadFunction(dbus_handle, #y))) return -1
|
||||
|
||||
#define SDL_DBUS_SYM(x) \
|
||||
SDL_DBUS_SYM2(x, dbus_##x)
|
||||
|
||||
SDL_DBUS_SYM(bus_get_private);
|
||||
SDL_DBUS_SYM(bus_register);
|
||||
SDL_DBUS_SYM(bus_add_match);
|
||||
SDL_DBUS_SYM(connection_open_private);
|
||||
SDL_DBUS_SYM(connection_set_exit_on_disconnect);
|
||||
SDL_DBUS_SYM(connection_get_is_connected);
|
||||
SDL_DBUS_SYM(connection_add_filter);
|
||||
SDL_DBUS_SYM(connection_send);
|
||||
SDL_DBUS_SYM(connection_send_with_reply_and_block);
|
||||
SDL_DBUS_SYM(connection_close);
|
||||
SDL_DBUS_SYM(connection_unref);
|
||||
SDL_DBUS_SYM(connection_flush);
|
||||
SDL_DBUS_SYM(connection_read_write);
|
||||
SDL_DBUS_SYM(connection_dispatch);
|
||||
SDL_DBUS_SYM(message_is_signal);
|
||||
SDL_DBUS_SYM(message_new_method_call);
|
||||
SDL_DBUS_SYM(message_append_args);
|
||||
SDL_DBUS_SYM(message_get_args);
|
||||
SDL_DBUS_SYM(message_iter_init);
|
||||
SDL_DBUS_SYM(message_iter_next);
|
||||
SDL_DBUS_SYM(message_iter_get_basic);
|
||||
SDL_DBUS_SYM(message_iter_get_arg_type);
|
||||
SDL_DBUS_SYM(message_iter_recurse);
|
||||
SDL_DBUS_SYM(message_unref);
|
||||
SDL_DBUS_SYM(error_init);
|
||||
SDL_DBUS_SYM(error_is_set);
|
||||
SDL_DBUS_SYM(error_free);
|
||||
SDL_DBUS_SYM(get_local_machine_id);
|
||||
SDL_DBUS_SYM(free);
|
||||
|
||||
#undef SDL_DBUS_SYM
|
||||
#undef SDL_DBUS_SYM2
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
UnloadDBUSLibrary(void)
|
||||
{
|
||||
if (dbus_handle != NULL) {
|
||||
SDL_UnloadObject(dbus_handle);
|
||||
dbus_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
LoadDBUSLibrary(void)
|
||||
{
|
||||
int retval = 0;
|
||||
if (dbus_handle == NULL) {
|
||||
dbus_handle = SDL_LoadObject(dbus_library);
|
||||
if (dbus_handle == NULL) {
|
||||
retval = -1;
|
||||
/* Don't call SDL_SetError(): SDL_LoadObject already did. */
|
||||
} else {
|
||||
retval = load_dbus_syms();
|
||||
if (retval < 0) {
|
||||
UnloadDBUSLibrary();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_DBus_Init(void)
|
||||
{
|
||||
if (LoadDBUSLibrary() != -1) {
|
||||
DBusError err;
|
||||
dbus.error_init(&err);
|
||||
dbus.session_conn = dbus.bus_get_private(DBUS_BUS_SESSION, &err);
|
||||
if (dbus.error_is_set(&err)) {
|
||||
dbus.error_free(&err);
|
||||
if (dbus.session_conn) {
|
||||
dbus.connection_unref(dbus.session_conn);
|
||||
dbus.session_conn = NULL;
|
||||
}
|
||||
return; /* oh well */
|
||||
}
|
||||
dbus.connection_set_exit_on_disconnect(dbus.session_conn, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SDL_DBus_Quit(void)
|
||||
{
|
||||
if (dbus.session_conn) {
|
||||
dbus.connection_close(dbus.session_conn);
|
||||
dbus.connection_unref(dbus.session_conn);
|
||||
SDL_memset(&dbus, 0, sizeof(dbus));
|
||||
}
|
||||
UnloadDBUSLibrary();
|
||||
}
|
||||
|
||||
SDL_DBusContext *
|
||||
SDL_DBus_GetContext(void)
|
||||
{
|
||||
if(!dbus_handle || !dbus.session_conn){
|
||||
SDL_DBus_Init();
|
||||
}
|
||||
|
||||
if(dbus_handle && dbus.session_conn){
|
||||
return &dbus;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SDL_DBus_ScreensaverTickle(void)
|
||||
{
|
||||
DBusConnection *conn = dbus.session_conn;
|
||||
if (conn != NULL) {
|
||||
DBusMessage *msg = dbus.message_new_method_call("org.gnome.ScreenSaver",
|
||||
"/org/gnome/ScreenSaver",
|
||||
"org.gnome.ScreenSaver",
|
||||
"SimulateUserActivity");
|
||||
if (msg != NULL) {
|
||||
if (dbus.connection_send(conn, msg, NULL)) {
|
||||
dbus.connection_flush(conn);
|
||||
}
|
||||
dbus.message_unref(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_DBus_ScreensaverInhibit(SDL_bool inhibit)
|
||||
{
|
||||
DBusConnection *conn = dbus.session_conn;
|
||||
|
||||
if (conn == NULL)
|
||||
return SDL_FALSE;
|
||||
|
||||
if (inhibit &&
|
||||
screensaver_cookie != 0)
|
||||
return SDL_TRUE;
|
||||
if (!inhibit &&
|
||||
screensaver_cookie == 0)
|
||||
return SDL_TRUE;
|
||||
|
||||
if (inhibit) {
|
||||
const char *app = "My SDL application";
|
||||
const char *reason = "Playing a game";
|
||||
|
||||
DBusMessage *msg = dbus.message_new_method_call("org.freedesktop.ScreenSaver",
|
||||
"/org/freedesktop/ScreenSaver",
|
||||
"org.freedesktop.ScreenSaver",
|
||||
"Inhibit");
|
||||
if (msg != NULL) {
|
||||
dbus.message_append_args (msg,
|
||||
DBUS_TYPE_STRING, &app,
|
||||
DBUS_TYPE_STRING, &reason,
|
||||
DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
if (msg != NULL) {
|
||||
DBusMessage *reply;
|
||||
|
||||
reply = dbus.connection_send_with_reply_and_block(conn, msg, 300, NULL);
|
||||
if (reply) {
|
||||
if (!dbus.message_get_args(reply, NULL,
|
||||
DBUS_TYPE_UINT32, &screensaver_cookie,
|
||||
DBUS_TYPE_INVALID))
|
||||
screensaver_cookie = 0;
|
||||
dbus.message_unref(reply);
|
||||
}
|
||||
|
||||
dbus.message_unref(msg);
|
||||
}
|
||||
|
||||
if (screensaver_cookie == 0) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
return SDL_TRUE;
|
||||
} else {
|
||||
DBusMessage *msg = dbus.message_new_method_call("org.freedesktop.ScreenSaver",
|
||||
"/org/freedesktop/ScreenSaver",
|
||||
"org.freedesktop.ScreenSaver",
|
||||
"UnInhibit");
|
||||
dbus.message_append_args (msg,
|
||||
DBUS_TYPE_UINT32, &screensaver_cookie,
|
||||
DBUS_TYPE_INVALID);
|
||||
if (msg != NULL) {
|
||||
if (dbus.connection_send(conn, msg, NULL)) {
|
||||
dbus.connection_flush(conn);
|
||||
}
|
||||
dbus.message_unref(msg);
|
||||
}
|
||||
|
||||
screensaver_cookie = 0;
|
||||
return SDL_TRUE;
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_dbus_h
|
||||
#define _SDL_dbus_h
|
||||
|
||||
#ifdef HAVE_DBUS_DBUS_H
|
||||
#define SDL_USE_LIBDBUS 1
|
||||
#include "SDL_stdinc.h"
|
||||
#include <dbus/dbus.h>
|
||||
|
||||
|
||||
typedef struct SDL_DBusContext {
|
||||
DBusConnection *session_conn;
|
||||
|
||||
DBusConnection *(*bus_get_private)(DBusBusType, DBusError *);
|
||||
dbus_bool_t (*bus_register)(DBusConnection *, DBusError *);
|
||||
void (*bus_add_match)(DBusConnection *, const char *, DBusError *);
|
||||
DBusConnection * (*connection_open_private)(const char *, DBusError *);
|
||||
void (*connection_set_exit_on_disconnect)(DBusConnection *, dbus_bool_t);
|
||||
dbus_bool_t (*connection_get_is_connected)(DBusConnection *);
|
||||
dbus_bool_t (*connection_add_filter)(DBusConnection *, DBusHandleMessageFunction,
|
||||
void *, DBusFreeFunction);
|
||||
dbus_bool_t (*connection_send)(DBusConnection *, DBusMessage *, dbus_uint32_t *);
|
||||
DBusMessage *(*connection_send_with_reply_and_block)(DBusConnection *, DBusMessage *, int, DBusError *);
|
||||
void (*connection_close)(DBusConnection *);
|
||||
void (*connection_unref)(DBusConnection *);
|
||||
void (*connection_flush)(DBusConnection *);
|
||||
dbus_bool_t (*connection_read_write)(DBusConnection *, int);
|
||||
DBusDispatchStatus (*connection_dispatch)(DBusConnection *);
|
||||
dbus_bool_t (*message_is_signal)(DBusMessage *, const char *, const char *);
|
||||
DBusMessage *(*message_new_method_call)(const char *, const char *, const char *, const char *);
|
||||
dbus_bool_t (*message_append_args)(DBusMessage *, int, ...);
|
||||
dbus_bool_t (*message_get_args)(DBusMessage *, DBusError *, int, ...);
|
||||
dbus_bool_t (*message_iter_init)(DBusMessage *, DBusMessageIter *);
|
||||
dbus_bool_t (*message_iter_next)(DBusMessageIter *);
|
||||
void (*message_iter_get_basic)(DBusMessageIter *, void *);
|
||||
int (*message_iter_get_arg_type)(DBusMessageIter *);
|
||||
void (*message_iter_recurse)(DBusMessageIter *, DBusMessageIter *);
|
||||
void (*message_unref)(DBusMessage *);
|
||||
void (*error_init)(DBusError *);
|
||||
dbus_bool_t (*error_is_set)(const DBusError *);
|
||||
void (*error_free)(DBusError *);
|
||||
char *(*get_local_machine_id)(void);
|
||||
void (*free)(void *);
|
||||
|
||||
} SDL_DBusContext;
|
||||
|
||||
extern void SDL_DBus_Init(void);
|
||||
extern void SDL_DBus_Quit(void);
|
||||
extern SDL_DBusContext * SDL_DBus_GetContext(void);
|
||||
extern void SDL_DBus_ScreensaverTickle(void);
|
||||
extern SDL_bool SDL_DBus_ScreensaverInhibit(SDL_bool inhibit);
|
||||
|
||||
#endif /* HAVE_DBUS_DBUS_H */
|
||||
|
||||
#endif /* _SDL_dbus_h */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
@ -0,0 +1,593 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifdef HAVE_IBUS_IBUS_H
|
||||
#include "SDL.h"
|
||||
#include "SDL_ibus.h"
|
||||
#include "SDL_dbus.h"
|
||||
#include "../../video/SDL_sysvideo.h"
|
||||
#include "../../events/SDL_keyboard_c.h"
|
||||
#include <sys/inotify.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static const char IBUS_SERVICE[] = "org.freedesktop.IBus";
|
||||
static const char IBUS_PATH[] = "/org/freedesktop/IBus";
|
||||
static const char IBUS_INTERFACE[] = "org.freedesktop.IBus";
|
||||
static const char IBUS_INPUT_INTERFACE[] = "org.freedesktop.IBus.InputContext";
|
||||
|
||||
static char *input_ctx_path = NULL;
|
||||
static SDL_Rect ibus_cursor_rect = {0};
|
||||
static DBusConnection *ibus_conn = NULL;
|
||||
static char *ibus_addr_file = NULL;
|
||||
int inotify_fd = -1;
|
||||
|
||||
static Uint32
|
||||
IBus_ModState(void)
|
||||
{
|
||||
Uint32 ibus_mods = 0;
|
||||
SDL_Keymod sdl_mods = SDL_GetModState();
|
||||
|
||||
/* Not sure about MOD3, MOD4 and HYPER mappings */
|
||||
if(sdl_mods & KMOD_LSHIFT) ibus_mods |= IBUS_SHIFT_MASK;
|
||||
if(sdl_mods & KMOD_CAPS) ibus_mods |= IBUS_LOCK_MASK;
|
||||
if(sdl_mods & KMOD_LCTRL) ibus_mods |= IBUS_CONTROL_MASK;
|
||||
if(sdl_mods & KMOD_LALT) ibus_mods |= IBUS_MOD1_MASK;
|
||||
if(sdl_mods & KMOD_NUM) ibus_mods |= IBUS_MOD2_MASK;
|
||||
if(sdl_mods & KMOD_MODE) ibus_mods |= IBUS_MOD5_MASK;
|
||||
if(sdl_mods & KMOD_LGUI) ibus_mods |= IBUS_SUPER_MASK;
|
||||
if(sdl_mods & KMOD_RGUI) ibus_mods |= IBUS_META_MASK;
|
||||
|
||||
return ibus_mods;
|
||||
}
|
||||
|
||||
static const char *
|
||||
IBus_GetVariantText(DBusConnection *conn, DBusMessageIter *iter, SDL_DBusContext *dbus)
|
||||
{
|
||||
/* The text we need is nested weirdly, use dbus-monitor to see the structure better */
|
||||
const char *text = NULL;
|
||||
DBusMessageIter sub1, sub2;
|
||||
|
||||
if(dbus->message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dbus->message_iter_recurse(iter, &sub1);
|
||||
|
||||
if(dbus->message_iter_get_arg_type(&sub1) != DBUS_TYPE_STRUCT){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dbus->message_iter_recurse(&sub1, &sub2);
|
||||
|
||||
if(dbus->message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *struct_id = NULL;
|
||||
dbus->message_iter_get_basic(&sub2, &struct_id);
|
||||
if(!struct_id || SDL_strncmp(struct_id, "IBusText", sizeof("IBusText")) != 0){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dbus->message_iter_next(&sub2);
|
||||
dbus->message_iter_next(&sub2);
|
||||
|
||||
if(dbus->message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dbus->message_iter_get_basic(&sub2, &text);
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
static size_t
|
||||
IBus_utf8_strlen(const char *str)
|
||||
{
|
||||
size_t utf8_len = 0;
|
||||
const char *p;
|
||||
|
||||
for(p = str; *p; ++p){
|
||||
if(!((*p & 0x80) && !(*p & 0x40))){
|
||||
++utf8_len;
|
||||
}
|
||||
}
|
||||
|
||||
return utf8_len;
|
||||
}
|
||||
|
||||
static DBusHandlerResult
|
||||
IBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *user_data)
|
||||
{
|
||||
SDL_DBusContext *dbus = (SDL_DBusContext *)user_data;
|
||||
|
||||
if(dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "CommitText")){
|
||||
DBusMessageIter iter;
|
||||
dbus->message_iter_init(msg, &iter);
|
||||
|
||||
const char *text = IBus_GetVariantText(conn, &iter, dbus);
|
||||
if(text && *text){
|
||||
char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
|
||||
size_t text_bytes = SDL_strlen(text), i = 0;
|
||||
|
||||
while(i < text_bytes){
|
||||
size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
|
||||
SDL_SendKeyboardText(buf);
|
||||
|
||||
i += sz;
|
||||
}
|
||||
}
|
||||
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
|
||||
if(dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "UpdatePreeditText")){
|
||||
DBusMessageIter iter;
|
||||
dbus->message_iter_init(msg, &iter);
|
||||
const char *text = IBus_GetVariantText(conn, &iter, dbus);
|
||||
|
||||
if(text && *text){
|
||||
char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
|
||||
size_t text_bytes = SDL_strlen(text), i = 0;
|
||||
size_t cursor = 0;
|
||||
|
||||
while(i < text_bytes){
|
||||
size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
|
||||
size_t chars = IBus_utf8_strlen(buf);
|
||||
|
||||
SDL_SendEditingText(buf, cursor, chars);
|
||||
|
||||
i += sz;
|
||||
cursor += chars;
|
||||
}
|
||||
} else {
|
||||
SDL_SendEditingText("", 0, 0);
|
||||
}
|
||||
|
||||
SDL_IBus_UpdateTextRect(NULL);
|
||||
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
}
|
||||
|
||||
static char *
|
||||
IBus_ReadAddressFromFile(const char *file_path)
|
||||
{
|
||||
FILE *addr_file = fopen(file_path, "r");
|
||||
if(!addr_file){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char addr_buf[1024];
|
||||
SDL_bool success = SDL_FALSE;
|
||||
|
||||
while(fgets(addr_buf, sizeof(addr_buf), addr_file)){
|
||||
if(SDL_strncmp(addr_buf, "IBUS_ADDRESS=", sizeof("IBUS_ADDRESS=")-1) == 0){
|
||||
size_t sz = SDL_strlen(addr_buf);
|
||||
if(addr_buf[sz-1] == '\n') addr_buf[sz-1] = 0;
|
||||
if(addr_buf[sz-2] == '\r') addr_buf[sz-2] = 0;
|
||||
success = SDL_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(addr_file);
|
||||
|
||||
if(success){
|
||||
return SDL_strdup(addr_buf + (sizeof("IBUS_ADDRESS=") - 1));
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
IBus_GetDBusAddressFilename(void)
|
||||
{
|
||||
if(ibus_addr_file){
|
||||
return SDL_strdup(ibus_addr_file);
|
||||
}
|
||||
|
||||
SDL_DBusContext *dbus = SDL_DBus_GetContext();
|
||||
|
||||
if(!dbus){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Use this environment variable if it exists. */
|
||||
const char *addr = SDL_getenv("IBUS_ADDRESS");
|
||||
if(addr && *addr){
|
||||
return SDL_strdup(addr);
|
||||
}
|
||||
|
||||
/* Otherwise, we have to get the hostname, display, machine id, config dir
|
||||
and look up the address from a filepath using all those bits, eek. */
|
||||
const char *disp_env = SDL_getenv("DISPLAY");
|
||||
char *display = NULL;
|
||||
|
||||
if(!disp_env || !*disp_env){
|
||||
display = SDL_strdup(":0.0");
|
||||
} else {
|
||||
display = SDL_strdup(disp_env);
|
||||
}
|
||||
|
||||
const char *host = display;
|
||||
char *disp_num = SDL_strrchr(display, ':'),
|
||||
*screen_num = SDL_strrchr(display, '.');
|
||||
|
||||
if(!disp_num){
|
||||
SDL_free(display);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*disp_num = 0;
|
||||
disp_num++;
|
||||
|
||||
if(screen_num){
|
||||
*screen_num = 0;
|
||||
}
|
||||
|
||||
if(!*host){
|
||||
host = "unix";
|
||||
}
|
||||
|
||||
char config_dir[PATH_MAX];
|
||||
SDL_memset(config_dir, 0, sizeof(config_dir));
|
||||
|
||||
const char *conf_env = SDL_getenv("XDG_CONFIG_HOME");
|
||||
if(conf_env && *conf_env){
|
||||
SDL_strlcpy(config_dir, conf_env, sizeof(config_dir));
|
||||
} else {
|
||||
const char *home_env = SDL_getenv("HOME");
|
||||
if(!home_env || !*home_env){
|
||||
SDL_free(display);
|
||||
return NULL;
|
||||
}
|
||||
SDL_snprintf(config_dir, sizeof(config_dir), "%s/.config", home_env);
|
||||
}
|
||||
|
||||
char *key = dbus->get_local_machine_id();
|
||||
|
||||
char file_path[PATH_MAX];
|
||||
SDL_memset(file_path, 0, sizeof(file_path));
|
||||
SDL_snprintf(file_path, sizeof(file_path), "%s/ibus/bus/%s-%s-%s",
|
||||
config_dir, key, host, disp_num);
|
||||
dbus->free(key);
|
||||
SDL_free(display);
|
||||
|
||||
return SDL_strdup(file_path);
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
IBus_SetupConnection(SDL_DBusContext *dbus, const char* addr)
|
||||
{
|
||||
const char *path = NULL;
|
||||
SDL_bool result = SDL_FALSE;
|
||||
|
||||
ibus_conn = dbus->connection_open_private(addr, NULL);
|
||||
|
||||
if(!ibus_conn){
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
dbus->connection_flush(ibus_conn);
|
||||
|
||||
if(!dbus->bus_register(ibus_conn, NULL)){
|
||||
ibus_conn = NULL;
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
dbus->connection_flush(ibus_conn);
|
||||
|
||||
DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
|
||||
IBUS_PATH,
|
||||
IBUS_INTERFACE,
|
||||
"CreateInputContext");
|
||||
if(msg){
|
||||
const char *client_name = "SDL2_Application";
|
||||
dbus->message_append_args(msg,
|
||||
DBUS_TYPE_STRING, &client_name,
|
||||
DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
if(msg){
|
||||
DBusMessage *reply;
|
||||
|
||||
reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 1000, NULL);
|
||||
if(reply){
|
||||
if(dbus->message_get_args(reply, NULL,
|
||||
DBUS_TYPE_OBJECT_PATH, &path,
|
||||
DBUS_TYPE_INVALID)){
|
||||
if(input_ctx_path){
|
||||
SDL_free(input_ctx_path);
|
||||
}
|
||||
input_ctx_path = SDL_strdup(path);
|
||||
result = SDL_TRUE;
|
||||
}
|
||||
dbus->message_unref(reply);
|
||||
}
|
||||
dbus->message_unref(msg);
|
||||
}
|
||||
|
||||
if(result){
|
||||
DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
|
||||
input_ctx_path,
|
||||
IBUS_INPUT_INTERFACE,
|
||||
"SetCapabilities");
|
||||
if(msg){
|
||||
Uint32 caps = IBUS_CAP_FOCUS | IBUS_CAP_PREEDIT_TEXT;
|
||||
dbus->message_append_args(msg,
|
||||
DBUS_TYPE_UINT32, &caps,
|
||||
DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
if(msg){
|
||||
if(dbus->connection_send(ibus_conn, msg, NULL)){
|
||||
dbus->connection_flush(ibus_conn);
|
||||
}
|
||||
dbus->message_unref(msg);
|
||||
}
|
||||
|
||||
dbus->bus_add_match(ibus_conn, "type='signal',interface='org.freedesktop.IBus.InputContext'", NULL);
|
||||
dbus->connection_add_filter(ibus_conn, &IBus_MessageFilter, dbus, NULL);
|
||||
dbus->connection_flush(ibus_conn);
|
||||
}
|
||||
|
||||
SDL_IBus_SetFocus(SDL_GetFocusWindow() != NULL);
|
||||
SDL_IBus_UpdateTextRect(NULL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
IBus_CheckConnection(SDL_DBusContext *dbus)
|
||||
{
|
||||
if(!dbus) return SDL_FALSE;
|
||||
|
||||
if(ibus_conn && dbus->connection_get_is_connected(ibus_conn)){
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
if(inotify_fd != -1){
|
||||
char buf[1024];
|
||||
ssize_t readsize = read(inotify_fd, buf, sizeof(buf));
|
||||
if(readsize > 0){
|
||||
|
||||
char *p;
|
||||
SDL_bool file_updated = SDL_FALSE;
|
||||
|
||||
for(p = buf; p < buf + readsize; /**/){
|
||||
struct inotify_event *event = (struct inotify_event*) p;
|
||||
if(event->len > 0){
|
||||
char *addr_file_no_path = SDL_strrchr(ibus_addr_file, '/');
|
||||
if(!addr_file_no_path) return SDL_FALSE;
|
||||
|
||||
if(SDL_strcmp(addr_file_no_path + 1, event->name) == 0){
|
||||
file_updated = SDL_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
p += sizeof(struct inotify_event) + event->len;
|
||||
}
|
||||
|
||||
if(file_updated){
|
||||
char *addr = IBus_ReadAddressFromFile(ibus_addr_file);
|
||||
if(addr){
|
||||
SDL_bool result = IBus_SetupConnection(dbus, addr);
|
||||
SDL_free(addr);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_IBus_Init(void)
|
||||
{
|
||||
SDL_bool result = SDL_FALSE;
|
||||
SDL_DBusContext *dbus = SDL_DBus_GetContext();
|
||||
|
||||
if(dbus){
|
||||
char *addr_file = IBus_GetDBusAddressFilename();
|
||||
if(!addr_file){
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
ibus_addr_file = SDL_strdup(addr_file);
|
||||
|
||||
char *addr = IBus_ReadAddressFromFile(addr_file);
|
||||
|
||||
inotify_fd = inotify_init();
|
||||
fcntl(inotify_fd, F_SETFL, O_NONBLOCK);
|
||||
|
||||
char *addr_file_dir = SDL_strrchr(addr_file, '/');
|
||||
if(addr_file_dir){
|
||||
*addr_file_dir = 0;
|
||||
}
|
||||
|
||||
inotify_add_watch(inotify_fd, addr_file, IN_CREATE | IN_MODIFY);
|
||||
SDL_free(addr_file);
|
||||
|
||||
result = IBus_SetupConnection(dbus, addr);
|
||||
SDL_free(addr);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_IBus_Quit(void)
|
||||
{
|
||||
if(input_ctx_path){
|
||||
SDL_free(input_ctx_path);
|
||||
input_ctx_path = NULL;
|
||||
}
|
||||
|
||||
if(ibus_addr_file){
|
||||
SDL_free(ibus_addr_file);
|
||||
ibus_addr_file = NULL;
|
||||
}
|
||||
|
||||
SDL_DBusContext *dbus = SDL_DBus_GetContext();
|
||||
|
||||
if(dbus && ibus_conn){
|
||||
dbus->connection_close(ibus_conn);
|
||||
dbus->connection_unref(ibus_conn);
|
||||
}
|
||||
|
||||
SDL_memset(&ibus_cursor_rect, 0, sizeof(ibus_cursor_rect));
|
||||
}
|
||||
|
||||
static void
|
||||
IBus_SimpleMessage(const char *method)
|
||||
{
|
||||
SDL_DBusContext *dbus = SDL_DBus_GetContext();
|
||||
|
||||
if(IBus_CheckConnection(dbus)){
|
||||
DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
|
||||
input_ctx_path,
|
||||
IBUS_INPUT_INTERFACE,
|
||||
method);
|
||||
if(msg){
|
||||
if(dbus->connection_send(ibus_conn, msg, NULL)){
|
||||
dbus->connection_flush(ibus_conn);
|
||||
}
|
||||
dbus->message_unref(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SDL_IBus_SetFocus(SDL_bool focused)
|
||||
{
|
||||
const char *method = focused ? "FocusIn" : "FocusOut";
|
||||
IBus_SimpleMessage(method);
|
||||
}
|
||||
|
||||
void
|
||||
SDL_IBus_Reset(void)
|
||||
{
|
||||
IBus_SimpleMessage("Reset");
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
|
||||
{
|
||||
SDL_bool result = SDL_FALSE;
|
||||
SDL_DBusContext *dbus = SDL_DBus_GetContext();
|
||||
|
||||
if(IBus_CheckConnection(dbus)){
|
||||
DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
|
||||
input_ctx_path,
|
||||
IBUS_INPUT_INTERFACE,
|
||||
"ProcessKeyEvent");
|
||||
if(msg){
|
||||
Uint32 mods = IBus_ModState();
|
||||
dbus->message_append_args(msg,
|
||||
DBUS_TYPE_UINT32, &keysym,
|
||||
DBUS_TYPE_UINT32, &keycode,
|
||||
DBUS_TYPE_UINT32, &mods,
|
||||
DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
if(msg){
|
||||
DBusMessage *reply;
|
||||
|
||||
reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 300, NULL);
|
||||
if(reply){
|
||||
if(!dbus->message_get_args(reply, NULL,
|
||||
DBUS_TYPE_BOOLEAN, &result,
|
||||
DBUS_TYPE_INVALID)){
|
||||
result = SDL_FALSE;
|
||||
}
|
||||
dbus->message_unref(reply);
|
||||
}
|
||||
dbus->message_unref(msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_IBus_UpdateTextRect(SDL_Rect *rect)
|
||||
{
|
||||
if(rect){
|
||||
SDL_memcpy(&ibus_cursor_rect, rect, sizeof(ibus_cursor_rect));
|
||||
}
|
||||
|
||||
SDL_Window *focused_win = SDL_GetFocusWindow();
|
||||
|
||||
if(!focused_win) return;
|
||||
|
||||
int x = 0, y = 0;
|
||||
SDL_GetWindowPosition(focused_win, &x, &y);
|
||||
x += ibus_cursor_rect.x;
|
||||
y += ibus_cursor_rect.y;
|
||||
|
||||
SDL_DBusContext *dbus = SDL_DBus_GetContext();
|
||||
|
||||
if(IBus_CheckConnection(dbus)){
|
||||
DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
|
||||
input_ctx_path,
|
||||
IBUS_INPUT_INTERFACE,
|
||||
"SetCursorLocation");
|
||||
if(msg){
|
||||
dbus->message_append_args(msg,
|
||||
DBUS_TYPE_INT32, &x,
|
||||
DBUS_TYPE_INT32, &y,
|
||||
DBUS_TYPE_INT32, &ibus_cursor_rect.w,
|
||||
DBUS_TYPE_INT32, &ibus_cursor_rect.h,
|
||||
DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
if(msg){
|
||||
if(dbus->connection_send(ibus_conn, msg, NULL)){
|
||||
dbus->connection_flush(ibus_conn);
|
||||
}
|
||||
dbus->message_unref(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SDL_IBus_PumpEvents(void)
|
||||
{
|
||||
SDL_DBusContext *dbus = SDL_DBus_GetContext();
|
||||
|
||||
if(IBus_CheckConnection(dbus)){
|
||||
dbus->connection_read_write(ibus_conn, 0);
|
||||
|
||||
while(dbus->connection_dispatch(ibus_conn) == DBUS_DISPATCH_DATA_REMAINS){
|
||||
/* Do nothing, actual work happens in IBus_MessageFilter */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_ibus_h
|
||||
#define _SDL_ibus_h
|
||||
|
||||
#ifdef HAVE_IBUS_IBUS_H
|
||||
#define SDL_USE_IBUS 1
|
||||
#include "SDL_stdinc.h"
|
||||
#include <ibus-1.0/ibus.h>
|
||||
|
||||
extern SDL_bool SDL_IBus_Init(void);
|
||||
extern void SDL_IBus_Quit(void);
|
||||
|
||||
/* Lets the IBus server know about changes in window focus */
|
||||
extern void SDL_IBus_SetFocus(SDL_bool focused);
|
||||
|
||||
/* Closes the candidate list and resets any text currently being edited */
|
||||
extern void SDL_IBus_Reset(void);
|
||||
|
||||
/* Sends a keypress event to IBus, returns SDL_TRUE if IBus used this event to
|
||||
update its candidate list or change input methods. PumpEvents should be
|
||||
called some time after this, to recieve the TextInput / TextEditing event back. */
|
||||
extern SDL_bool SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode);
|
||||
|
||||
/* Update the position of IBus' candidate list. If rect is NULL then this will
|
||||
just reposition it relative to the focused window's new position. */
|
||||
extern void SDL_IBus_UpdateTextRect(SDL_Rect *window_relative_rect);
|
||||
|
||||
/* Checks DBus for new IBus events, and calls SDL_SendKeyboardText /
|
||||
SDL_SendEditingText for each event it finds */
|
||||
extern void SDL_IBus_PumpEvents();
|
||||
|
||||
#endif /* HAVE_IBUS_IBUS_H */
|
||||
|
||||
#endif /* _SDL_ibus_h */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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,6 +273,9 @@ 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;
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -54,8 +54,11 @@
|
|||
#endif
|
||||
|
||||
#ifdef HAVE_DBUS_DBUS_H
|
||||
#define SDL_USE_LIBDBUS 1
|
||||
#include <dbus/dbus.h>
|
||||
#include "../../core/linux/SDL_dbus.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IBUS_IBUS_H
|
||||
#include "../../core/linux/SDL_ibus.h"
|
||||
#endif
|
||||
|
||||
#include "SDL_x11dyn.h"
|
||||
|
@ -114,16 +117,10 @@ typedef struct SDL_VideoData
|
|||
SDL_Scancode key_layout[256];
|
||||
SDL_bool selection_waiting;
|
||||
|
||||
#if SDL_USE_LIBDBUS
|
||||
DBusConnection *dbus;
|
||||
#endif
|
||||
} SDL_VideoData;
|
||||
|
||||
extern SDL_bool X11_UseDirectColorVisuals(void);
|
||||
|
||||
SDL_bool SDL_dbus_screensaver_inhibit(_THIS);
|
||||
void SDL_dbus_screensaver_tickle(_THIS);
|
||||
|
||||
#endif /* _SDL_x11video_h */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
Loading…
Reference in New Issue