From: Yan Wang Date: Wed, 4 Jun 2014 08:53:33 +0000 (+0800) Subject: Enable Wayland input method protocol. X-Git-Tag: submit/tizen/20150128.083920~217 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F54%2F22454%2F3;p=platform%2Fcore%2Fuifw%2Fisf.git Enable Wayland input method protocol. Change-Id: Ifaf99647e1ad6dd5137de562ea80e6d5e542d87c --- diff --git a/configure.ac b/configure.ac index 7c411fd..0c092d4 100755 --- a/configure.ac +++ b/configure.ac @@ -215,10 +215,18 @@ if test "$ISF_HAS_GCONF" = "yes"; then fi # Check EFL library -PKG_CHECK_MODULES(EFL, [elementary ecore-x evas ecore ecore-evas ecore-file edje ecore-input ecore-ipc ecore-imf], +PKG_CHECK_MODULES(EFL, [elementary evas ecore ecore-evas ecore-file edje ecore-input ecore-ipc ecore-imf], [ISF_HAS_EFL=yes], [ISF_HAS_EFL=no]) +PKG_CHECK_MODULES(ECOREX, [ecore-x], + [ISF_HAS_ECOREX=yes], + [ISF_HAS_ECOREX=no]) + +PKG_CHECK_MODULES(WAYLAND, [ecore-wayland wayland-client >= 1.2.0 xkbcommon], + [ISF_HAS_ECOREWL=yes], + [ISF_HAS_ECOREWL=no]) + if test "$ISF_HAS_EFL" = "yes"; then EFL_LIBDIR=`$PKG_CONFIG --variable=libdir ecore-imf` if test -z "$EFL_LIBDIR)"; then @@ -233,7 +241,9 @@ fi PKG_CHECK_MODULES(EFL_ASSIST, [efl-assist]) # Check x11 library -PKG_CHECK_MODULES(X11, [x11]) +PKG_CHECK_MODULES(X11, [x11], + [ISF_HAS_X11=yes], + [ISF_HAS_X11=no]) # Check ui-gadget library PKG_CHECK_MODULES(UIGADGET, [ui-gadget-1], @@ -241,7 +251,9 @@ PKG_CHECK_MODULES(UIGADGET, [ui-gadget-1], [ISF_HAS_UIGADGET=no]) # Check utilX library -PKG_CHECK_MODULES(UTILX, [utilX]) +PKG_CHECK_MODULES(UTILX, [utilX], + [ISF_HAS_UTILX=yes], + [ISF_HAS_UTILX=no]) # Check appcore-efl library PKG_CHECK_MODULES(APPCORE_EFL, [appcore-efl]) @@ -441,6 +453,16 @@ AC_ARG_ENABLE(panel-efl, enable_panel_efl=no, enable_panel_efl=check) +AC_ARG_ENABLE(wsm-efl, + [ --disable-wsm-efl Do not build EFL Wsm], + enable_wsm_efl=no, + enable_wsm_efl=check) + +AC_ARG_ENABLE(wsc-efl, + [ --disable-wsc-efl Do not build EFL Wsc], + enable_wsc_efl=no, + enable_wsc_efl=yes) + AC_ARG_ENABLE(setting-efl, [ --disable-setting-efl Do not build EFL Setting], enable_setting_efl=no, @@ -560,6 +582,13 @@ else enable_efl_immodule=no fi +if test "$enable_wsc_efl" = "yes" -a "$ISF_HAS_EFL" = "yes"; then + ISF_BUILD_WSC_EFL=1 +else + ISF_BUILD_WSC_EFL=0 + enable_wsc_efl=no +fi + ISF_BUILD_PANEL_EFL=0 if test "$enable_panel_efl" != "no"; then enable_panel_efl=no @@ -569,6 +598,15 @@ if test "$enable_panel_efl" != "no"; then fi fi +ISF_BUILD_WSM_EFL=0 +if test "$enable_wsm_efl" != "no"; then + enable_wsm_efl=no + if test "$ISF_HAS_EFL" = "yes"; then + ISF_BUILD_WSM_EFL=1 + enable_wsm_efl=yes + fi +fi + ISF_BUILD_SETTING_EFL=0 if test "$enable_setting_efl" != "no"; then enable_setting_efl=no @@ -584,6 +622,9 @@ if test "$enable_panel_gtk" != "yes"; then SCIM_BUILD_GTK_UTILS=0 fi +AM_CONDITIONAL(HAVE_X, + [test "$have_x" = "yes"]) + AM_CONDITIONAL(SCIM_LD_VERSION_SCRIPT, [test "$enable_ld_version_script" = "yes"]) @@ -626,9 +667,15 @@ AM_CONDITIONAL(SCIM_BUILD_TRAY_ICON, AM_CONDITIONAL(ISF_BUILD_EFL_IMMODULE, [test "$enable_efl_immodule" = "yes"]) +AM_CONDITIONAL(ISF_BUILD_WSC_EFL, + [test "$enable_wsc_efl" = "yes"]) + AM_CONDITIONAL(ISF_BUILD_PANEL_EFL, [test "$enable_panel_efl" = "yes"]) +AM_CONDITIONAL(ISF_BUILD_WSM_EFL, + [test "$enable_wsm_efl" = "yes"]) + AM_CONDITIONAL(ISF_BUILD_SETTING_EFL, [test "$enable_setting_efl" = "yes"]) @@ -701,6 +748,8 @@ AC_CONFIG_FILES([Makefile ism/extras/gtk2_immodule/Makefile ism/extras/efl_immodule/Makefile ism/extras/efl_panel/Makefile + ism/extras/efl_wsm/Makefile + ism/extras/efl_wsc/Makefile ism/demos/Makefile intltool-extract intltool-merge @@ -741,6 +790,8 @@ Module options: EFL IMModule $enable_efl_immodule EFL IMModule dir $EFL_IM_MODULEDIR EFL Panel GUI $enable_panel_efl + EFL Wsm GUI $enable_wsm_efl + EFL Wsc GUI $enable_wsc_efl EFL Setting $enable_setting_efl Enable TrayIcon $enable_tray_icon diff --git a/ism/configs/global b/ism/configs/global index 7913bcd..e8ff055 100755 --- a/ism/configs/global +++ b/ism/configs/global @@ -1,5 +1,6 @@ /SupportedUnicodeLocales = en_US.UTF-8 /DefaultPanelProgram = isf-panel-efl +/DefaultPanelProgram2 = isf-wsm-efl /DefaultConfigModule = simple /DefaultSocketFrontEndAddress = local:/tmp/scim-socket-frontend /DefaultSocketIMEngineAddress = local:/tmp/scim-socket-frontend diff --git a/ism/demos/Makefile.am b/ism/demos/Makefile.am index 6506159..6e19cd3 100644 --- a/ism/demos/Makefile.am +++ b/ism/demos/Makefile.am @@ -42,6 +42,7 @@ isf_demo_efl_SOURCES = isf_demo_efl.cpp \ isf_ondemand_efl.cpp isf_demo_efl_CXXFLAGS = @EFL_CFLAGS@ \ + @ECOREX_CFLAGS@ \ @APPCORE_EFL_CFLAGS@ \ @UIGADGET_CFLAGS@ \ @VCONF_CFLAGS@ \ @@ -49,6 +50,7 @@ isf_demo_efl_CXXFLAGS = @EFL_CFLAGS@ \ @EFL_ASSIST_CFLAGS@ isf_demo_efl_LDFLAGS = @EFL_LIBS@ @LTLIBINTL@ -rpath $(libdir) \ + @ECOREX_LIBS@ \ @VCONF_LIBS@ \ @APPCORE_EFL_LIBS@ \ @UIGADGET_LIBS@ \ diff --git a/ism/extras/Makefile.am b/ism/extras/Makefile.am index 65bee7b..73c28a6 100644 --- a/ism/extras/Makefile.am +++ b/ism/extras/Makefile.am @@ -18,4 +18,4 @@ MAINTAINERCLEANFILES = Makefile.in CLEANFILES = *.bak -SUBDIRS = gtk2_immodule efl_panel efl_immodule +SUBDIRS = gtk2_immodule efl_panel efl_immodule efl_wsm efl_wsc diff --git a/ism/extras/efl_immodule/Makefile.am b/ism/extras/efl_immodule/Makefile.am index 364f893..dae8f1d 100644 --- a/ism/extras/efl_immodule/Makefile.am +++ b/ism/extras/efl_immodule/Makefile.am @@ -35,6 +35,7 @@ libisf_imf_module_la_SOURCES = isf_imf_module.cpp \ isf_imf_control.cpp libisf_imf_module_la_CXXFLAGS = @EFL_CFLAGS@ \ + @ECOREX_CFLAGS@ \ @UTILX_CFLAGS@ \ @VCONF_CFLAGS@ \ @DLOG_CFLAGS@ @@ -46,6 +47,7 @@ libisf_imf_module_la_LDFLAGS = -rpath $(moduledir) \ libisf_imf_module_la_LIBADD = -lstdc++ \ $(LD_VERSION_SCRIPT_OPTION) \ @EFL_LIBS@ \ + @ECOREX_LIBS@ \ @UTILX_LIBS@ \ @VCONF_LIBS@ \ @DLOG_LIBS@ \ diff --git a/ism/extras/efl_panel/Makefile.am b/ism/extras/efl_panel/Makefile.am index 4625af6..144c028 100644 --- a/ism/extras/efl_panel/Makefile.am +++ b/ism/extras/efl_panel/Makefile.am @@ -33,10 +33,11 @@ if ISF_BUILD_MINICONTROL isf_panel_efl_SOURCES += minicontrol.cpp endif -isf_panel_efl_CXXFLAGS = @EFL_CFLAGS@ @EFL_ASSIST_CFLAGS@ @VCONF_CFLAGS@ @X11_CFLAGS@ @PRIVILEGE_CONTROL_CFLAGS@ @DLOG_CFLAGS@ \ +isf_panel_efl_CXXFLAGS = @EFL_CFLAGS@ @ECOREX_CFLAGS@ @EFL_ASSIST_CFLAGS@ @VCONF_CFLAGS@ @X11_CFLAGS@ @PRIVILEGE_CONTROL_CFLAGS@ @DLOG_CFLAGS@ \ @MINICONTROL_PROVIDER_CFLAGS@ @NOTIFICATION_CFLAGS@ @TTS_CFLAGS@ @EDBUS_CFLAGS@ @BLUETOOTH_CFLAGS@ @FEEDBACK_CFLAGS@ isf_panel_efl_LDFLAGS = @EFL_LIBS@ @LTLIBINTL@ -rpath $(libdir) \ + @ECOREX_LIBS@ \ @EFL_ASSIST_LIBS@ \ @VCONF_LIBS@ \ @X11_LIBS@ \ diff --git a/ism/extras/efl_wsc/Makefile.am b/ism/extras/efl_wsc/Makefile.am new file mode 100644 index 0000000..40bd1fa --- /dev/null +++ b/ism/extras/efl_wsc/Makefile.am @@ -0,0 +1,49 @@ +MAINTAINERCLEANFILES = Makefile.in +CLEANFILES = *.bak *.edj + +INCLUDES = -I$(top_builddir) \ + -I$(top_builddir)/ism/src \ + -I$(top_srcdir) \ + -I$(top_srcdir)/ism/src \ + -I$(top_srcdir)/ism/intl \ + -I$(top_srcdir)/ism/data \ + -I$(top_srcdir)/ism/utils \ + -I$(includedir) \ + -DSCIM_DATADIR=\"@SCIM_DATADIR@\" \ + -DSCIM_LOCALEDIR=\"@SCIM_LOCALEDIR@\" \ + -DSCIM_SYSCONFDIR=\"@SCIM_SYSCONFDIR@\" \ + -DSCIM_LIBEXECDIR=\"@SCIM_LIBEXECDIR@\" \ + -DSCIM_ICONDIR=\"@SCIM_ICONDIR@\" \ + -DSCIM_MODULE_PATH=\"@SCIM_MODULE_PATH@\" \ + -DSCIM_TEMPDIR=\"@SCIM_TEMPDIR@\" + +noinst_HEADERS = input-method-client-protocol.h \ + text-client-protocol.h \ + isf_wsc_context.h \ + isf_wsc_control.h \ + isf_wsc_control_ui.h + +if ISF_BUILD_WSC_EFL +CONFIG_WSC_EFL = isf-wsc-efl +endif + +bin_PROGRAMS = $(CONFIG_WSC_EFL) + +isf_wsc_efl_SOURCES = isf_wsc_efl.cpp \ + input-method-protocol.c \ + text-protocol.c \ + isf_wsc_context.cpp \ + isf_wsc_control.cpp \ + isf_wsc_control_ui.cpp + +isf_wsc_efl_CXXFLAGS = @EFL_CFLAGS@ @VCONF_CFLAGS@ @DLOG_CFLAGS@ @TTS_CFLAGS@ @FEEDBACK_CFLAGS@ + +isf_wsc_efl_LDFLAGS = @EFL_LIBS@ @LTLIBINTL@ -rpath $(libdir) \ + @VCONF_LIBS@ \ + @WAYLAND_LIBS@ \ + @DLOG_LIBS@ \ + @TTS_LIBS@ \ + @FEEDBACK_LIBS@ + +isf_wsc_efl_LDADD = $(top_builddir)/ism/src/libscim@SCIM_EPOCH@.la + diff --git a/ism/extras/efl_wsc/input-method-client-protocol.h b/ism/extras/efl_wsc/input-method-client-protocol.h new file mode 100644 index 0000000..676b5a2 --- /dev/null +++ b/ism/extras/efl_wsc/input-method-client-protocol.h @@ -0,0 +1,446 @@ +/* + * Copyright © 2012, 2013 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this + * software and its documentation for any purpose is hereby granted + * without fee, provided that the above copyright notice appear in + * all copies and that both that copyright notice and this permission + * notice appear in supporting documentation, and that the name of + * the copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + * THIS SOFTWARE. + */ + +#ifndef INPUT_METHOD_CLIENT_PROTOCOL_H +#define INPUT_METHOD_CLIENT_PROTOCOL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "wayland-client.h" + +struct wl_client; +struct wl_resource; + +struct wl_input_method_context; +struct wl_input_method; +struct wl_input_panel; +struct wl_input_panel_surface; + +extern const struct wl_interface wl_input_method_context_interface; +extern const struct wl_interface wl_input_method_interface; +extern const struct wl_interface wl_input_panel_interface; +extern const struct wl_interface wl_input_panel_surface_interface; + +/** + * wl_input_method_context - input method context + * @surrounding_text: surrounding text event + * @reset: (none) + * @content_type: (none) + * @invoke_action: (none) + * @commit_state: (none) + * @preferred_language: (none) + * + * Corresponds to a text model on input method side. An input method + * context is created on text mode activation on the input method side. It + * allows to receive information about the text model from the application + * via events. Input method contexts do not keep state after deactivation + * and should be destroyed after deactivation is handled. + * + * Text is generally UTF-8 encoded, indices and lengths are in bytes. + * + * Serials are used to synchronize the state between the text input and an + * input method. New serials are sent by the text input in the commit_state + * request and are used by the input method to indicate the known text + * input state in events like preedit_string, commit_string, and keysym. + * The text input can then ignore events from the input method which are + * based on an outdated state (for example after a reset). + */ +struct wl_input_method_context_listener { + /** + * surrounding_text - surrounding text event + * @text: (none) + * @cursor: (none) + * @anchor: (none) + * + * The plain surrounding text around the input position. Cursor + * is the position in bytes within the surrounding text relative to + * the beginning of the text. Anchor is the position in bytes of + * the selection anchor within the surrounding text relative to the + * beginning of the text. If there is no selected text anchor is + * the same as cursor. + */ + void (*surrounding_text)(void *data, + struct wl_input_method_context *wl_input_method_context, + const char *text, + uint32_t cursor, + uint32_t anchor); + /** + * reset - (none) + */ + void (*reset)(void *data, + struct wl_input_method_context *wl_input_method_context); + /** + * content_type - (none) + * @hint: (none) + * @purpose: (none) + */ + void (*content_type)(void *data, + struct wl_input_method_context *wl_input_method_context, + uint32_t hint, + uint32_t purpose); + /** + * invoke_action - (none) + * @button: (none) + * @index: (none) + */ + void (*invoke_action)(void *data, + struct wl_input_method_context *wl_input_method_context, + uint32_t button, + uint32_t index); + /** + * commit_state - (none) + * @serial: serial of text input state + */ + void (*commit_state)(void *data, + struct wl_input_method_context *wl_input_method_context, + uint32_t serial); + /** + * preferred_language - (none) + * @language: (none) + */ + void (*preferred_language)(void *data, + struct wl_input_method_context *wl_input_method_context, + const char *language); +}; + +static inline int +wl_input_method_context_add_listener(struct wl_input_method_context *wl_input_method_context, + const struct wl_input_method_context_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_input_method_context, + (void (**)(void)) listener, data); +} + +#define WL_INPUT_METHOD_CONTEXT_DESTROY 0 +#define WL_INPUT_METHOD_CONTEXT_COMMIT_STRING 1 +#define WL_INPUT_METHOD_CONTEXT_PREEDIT_STRING 2 +#define WL_INPUT_METHOD_CONTEXT_PREEDIT_STYLING 3 +#define WL_INPUT_METHOD_CONTEXT_PREEDIT_CURSOR 4 +#define WL_INPUT_METHOD_CONTEXT_DELETE_SURROUNDING_TEXT 5 +#define WL_INPUT_METHOD_CONTEXT_CURSOR_POSITION 6 +#define WL_INPUT_METHOD_CONTEXT_MODIFIERS_MAP 7 +#define WL_INPUT_METHOD_CONTEXT_KEYSYM 8 +#define WL_INPUT_METHOD_CONTEXT_GRAB_KEYBOARD 9 +#define WL_INPUT_METHOD_CONTEXT_KEY 10 +#define WL_INPUT_METHOD_CONTEXT_MODIFIERS 11 +#define WL_INPUT_METHOD_CONTEXT_LANGUAGE 12 +#define WL_INPUT_METHOD_CONTEXT_TEXT_DIRECTION 13 + +static inline void +wl_input_method_context_set_user_data(struct wl_input_method_context *wl_input_method_context, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_input_method_context, user_data); +} + +static inline void * +wl_input_method_context_get_user_data(struct wl_input_method_context *wl_input_method_context) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_input_method_context); +} + +static inline void +wl_input_method_context_destroy(struct wl_input_method_context *wl_input_method_context) +{ + wl_proxy_marshal((struct wl_proxy *) wl_input_method_context, + WL_INPUT_METHOD_CONTEXT_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) wl_input_method_context); +} + +static inline void +wl_input_method_context_commit_string(struct wl_input_method_context *wl_input_method_context, uint32_t serial, const char *text) +{ + wl_proxy_marshal((struct wl_proxy *) wl_input_method_context, + WL_INPUT_METHOD_CONTEXT_COMMIT_STRING, serial, text); +} + +static inline void +wl_input_method_context_preedit_string(struct wl_input_method_context *wl_input_method_context, uint32_t serial, const char *text, const char *commit) +{ + wl_proxy_marshal((struct wl_proxy *) wl_input_method_context, + WL_INPUT_METHOD_CONTEXT_PREEDIT_STRING, serial, text, commit); +} + +static inline void +wl_input_method_context_preedit_styling(struct wl_input_method_context *wl_input_method_context, uint32_t index, uint32_t length, uint32_t style) +{ + wl_proxy_marshal((struct wl_proxy *) wl_input_method_context, + WL_INPUT_METHOD_CONTEXT_PREEDIT_STYLING, index, length, style); +} + +static inline void +wl_input_method_context_preedit_cursor(struct wl_input_method_context *wl_input_method_context, int32_t index) +{ + wl_proxy_marshal((struct wl_proxy *) wl_input_method_context, + WL_INPUT_METHOD_CONTEXT_PREEDIT_CURSOR, index); +} + +static inline void +wl_input_method_context_delete_surrounding_text(struct wl_input_method_context *wl_input_method_context, int32_t index, uint32_t length) +{ + wl_proxy_marshal((struct wl_proxy *) wl_input_method_context, + WL_INPUT_METHOD_CONTEXT_DELETE_SURROUNDING_TEXT, index, length); +} + +static inline void +wl_input_method_context_cursor_position(struct wl_input_method_context *wl_input_method_context, int32_t index, int32_t anchor) +{ + wl_proxy_marshal((struct wl_proxy *) wl_input_method_context, + WL_INPUT_METHOD_CONTEXT_CURSOR_POSITION, index, anchor); +} + +static inline void +wl_input_method_context_modifiers_map(struct wl_input_method_context *wl_input_method_context, struct wl_array *map) +{ + wl_proxy_marshal((struct wl_proxy *) wl_input_method_context, + WL_INPUT_METHOD_CONTEXT_MODIFIERS_MAP, map); +} + +static inline void +wl_input_method_context_keysym(struct wl_input_method_context *wl_input_method_context, uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers) +{ + wl_proxy_marshal((struct wl_proxy *) wl_input_method_context, + WL_INPUT_METHOD_CONTEXT_KEYSYM, serial, time, sym, state, modifiers); +} + +static inline struct wl_keyboard * +wl_input_method_context_grab_keyboard(struct wl_input_method_context *wl_input_method_context) +{ + struct wl_proxy *keyboard; + + keyboard = wl_proxy_create((struct wl_proxy *) wl_input_method_context, + &wl_keyboard_interface); + if (!keyboard) + return NULL; + + wl_proxy_marshal((struct wl_proxy *) wl_input_method_context, + WL_INPUT_METHOD_CONTEXT_GRAB_KEYBOARD, keyboard); + + return (struct wl_keyboard *) keyboard; +} + +static inline void +wl_input_method_context_key(struct wl_input_method_context *wl_input_method_context, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) +{ + wl_proxy_marshal((struct wl_proxy *) wl_input_method_context, + WL_INPUT_METHOD_CONTEXT_KEY, serial, time, key, state); +} + +static inline void +wl_input_method_context_modifiers(struct wl_input_method_context *wl_input_method_context, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) +{ + wl_proxy_marshal((struct wl_proxy *) wl_input_method_context, + WL_INPUT_METHOD_CONTEXT_MODIFIERS, serial, mods_depressed, mods_latched, mods_locked, group); +} + +static inline void +wl_input_method_context_language(struct wl_input_method_context *wl_input_method_context, uint32_t serial, const char *language) +{ + wl_proxy_marshal((struct wl_proxy *) wl_input_method_context, + WL_INPUT_METHOD_CONTEXT_LANGUAGE, serial, language); +} + +static inline void +wl_input_method_context_text_direction(struct wl_input_method_context *wl_input_method_context, uint32_t serial, uint32_t direction) +{ + wl_proxy_marshal((struct wl_proxy *) wl_input_method_context, + WL_INPUT_METHOD_CONTEXT_TEXT_DIRECTION, serial, direction); +} + +/** + * wl_input_method - input method + * @activate: activate event + * @deactivate: activate event + * + * An input method object is responsible to compose text in response to + * input from hardware or virtual keyboards. There is one input method + * object per seat. On activate there is a new input method context object + * created which allows the input method to communicate with the text + * model. + */ +struct wl_input_method_listener { + /** + * activate - activate event + * @id: (none) + * + * A text model was activated. Creates an input method context + * object which allows communication with the text model. + */ + void (*activate)(void *data, + struct wl_input_method *wl_input_method, + struct wl_input_method_context *id); + /** + * deactivate - activate event + * @context: (none) + * + * The text model corresponding to the context argument was + * deactivated. The input method context should be destroyed after + * deactivation is handled. + */ + void (*deactivate)(void *data, + struct wl_input_method *wl_input_method, + struct wl_input_method_context *context); +}; + +static inline int +wl_input_method_add_listener(struct wl_input_method *wl_input_method, + const struct wl_input_method_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_input_method, + (void (**)(void)) listener, data); +} + +static inline void +wl_input_method_set_user_data(struct wl_input_method *wl_input_method, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_input_method, user_data); +} + +static inline void * +wl_input_method_get_user_data(struct wl_input_method *wl_input_method) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_input_method); +} + +static inline void +wl_input_method_destroy(struct wl_input_method *wl_input_method) +{ + wl_proxy_destroy((struct wl_proxy *) wl_input_method); +} + +#define WL_INPUT_PANEL_GET_INPUT_PANEL_SURFACE 0 + +static inline void +wl_input_panel_set_user_data(struct wl_input_panel *wl_input_panel, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_input_panel, user_data); +} + +static inline void * +wl_input_panel_get_user_data(struct wl_input_panel *wl_input_panel) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_input_panel); +} + +static inline void +wl_input_panel_destroy(struct wl_input_panel *wl_input_panel) +{ + wl_proxy_destroy((struct wl_proxy *) wl_input_panel); +} + +static inline struct wl_input_panel_surface * +wl_input_panel_get_input_panel_surface(struct wl_input_panel *wl_input_panel, struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_create((struct wl_proxy *) wl_input_panel, + &wl_input_panel_surface_interface); + if (!id) + return NULL; + + wl_proxy_marshal((struct wl_proxy *) wl_input_panel, + WL_INPUT_PANEL_GET_INPUT_PANEL_SURFACE, id, surface); + + return (struct wl_input_panel_surface *) id; +} + +#ifndef WL_INPUT_PANEL_SURFACE_POSITION_ENUM +#define WL_INPUT_PANEL_SURFACE_POSITION_ENUM +enum wl_input_panel_surface_position { + WL_INPUT_PANEL_SURFACE_POSITION_CENTER_BOTTOM = 0, +}; +#endif /* WL_INPUT_PANEL_SURFACE_POSITION_ENUM */ + +struct wl_input_panel_surface_listener { + /** + * cursor_rectangle - cursor rectangle + * @x: (none) + * @y: (none) + * @width: (none) + * @height: (none) + * + * Notify when the cursor rectangle relative to the input panel + * surface change. + */ + void (*cursor_rectangle)(void *data, + struct wl_input_panel_surface *wl_input_panel_surface, + int32_t x, + int32_t y, + int32_t width, + int32_t height); +}; + +static inline int +wl_input_panel_surface_add_listener(struct wl_input_panel_surface *wl_input_panel_surface, + const struct wl_input_panel_surface_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_input_panel_surface, + (void (**)(void)) listener, data); +} + +#define WL_INPUT_PANEL_SURFACE_SET_TOPLEVEL 0 +#define WL_INPUT_PANEL_SURFACE_SET_OVERLAY_PANEL 1 + +static inline void +wl_input_panel_surface_set_user_data(struct wl_input_panel_surface *wl_input_panel_surface, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_input_panel_surface, user_data); +} + +static inline void * +wl_input_panel_surface_get_user_data(struct wl_input_panel_surface *wl_input_panel_surface) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_input_panel_surface); +} + +static inline void +wl_input_panel_surface_destroy(struct wl_input_panel_surface *wl_input_panel_surface) +{ + wl_proxy_destroy((struct wl_proxy *) wl_input_panel_surface); +} + +static inline void +wl_input_panel_surface_set_toplevel(struct wl_input_panel_surface *wl_input_panel_surface, struct wl_output *output, uint32_t position) +{ + wl_proxy_marshal((struct wl_proxy *) wl_input_panel_surface, + WL_INPUT_PANEL_SURFACE_SET_TOPLEVEL, output, position); +} + +static inline void +wl_input_panel_surface_set_overlay_panel(struct wl_input_panel_surface *wl_input_panel_surface) +{ + wl_proxy_marshal((struct wl_proxy *) wl_input_panel_surface, + WL_INPUT_PANEL_SURFACE_SET_OVERLAY_PANEL); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ism/extras/efl_wsc/input-method-protocol.c b/ism/extras/efl_wsc/input-method-protocol.c new file mode 100644 index 0000000..771af97 --- /dev/null +++ b/ism/extras/efl_wsc/input-method-protocol.c @@ -0,0 +1,117 @@ +/* + * Copyright © 2012, 2013 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this + * software and its documentation for any purpose is hereby granted + * without fee, provided that the above copyright notice appear in + * all copies and that both that copyright notice and this permission + * notice appear in supporting documentation, and that the name of + * the copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + * THIS SOFTWARE. + */ +#include +#include +#include "wayland-util.h" + +extern const struct wl_interface wl_keyboard_interface; +extern const struct wl_interface wl_input_method_context_interface; +extern const struct wl_interface wl_input_method_context_interface; +extern const struct wl_interface wl_input_panel_surface_interface; +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface wl_output_interface; + +static const struct wl_interface *types[] = { + NULL, + NULL, + NULL, + NULL, + NULL, + &wl_keyboard_interface, + &wl_input_method_context_interface, + &wl_input_method_context_interface, + &wl_input_panel_surface_interface, + &wl_surface_interface, + &wl_output_interface, + NULL, +}; + +static const struct wl_message wl_input_method_context_requests[] = { + { "destroy", "", types + 0 }, + { "commit_string", "us", types + 0 }, + { "preedit_string", "uss", types + 0 }, + { "preedit_styling", "uuu", types + 0 }, + { "preedit_cursor", "i", types + 0 }, + { "delete_surrounding_text", "iu", types + 0 }, + { "cursor_position", "ii", types + 0 }, + { "modifiers_map", "a", types + 0 }, + { "keysym", "uuuuu", types + 0 }, + { "grab_keyboard", "n", types + 5 }, + { "key", "uuuu", types + 0 }, + { "modifiers", "uuuuu", types + 0 }, + { "language", "us", types + 0 }, + { "text_direction", "uu", types + 0 }, +}; + +static const struct wl_message wl_input_method_context_events[] = { + { "surrounding_text", "suu", types + 0 }, + { "reset", "", types + 0 }, + { "content_type", "uu", types + 0 }, + { "invoke_action", "uu", types + 0 }, + { "commit_state", "u", types + 0 }, + { "preferred_language", "s", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_input_method_context_interface = { + "wl_input_method_context", 1, + 14, wl_input_method_context_requests, + 6, wl_input_method_context_events, +}; + +static const struct wl_message wl_input_method_events[] = { + { "activate", "n", types + 6 }, + { "deactivate", "o", types + 7 }, +}; + +WL_EXPORT const struct wl_interface wl_input_method_interface = { + "wl_input_method", 1, + 0, NULL, + 2, wl_input_method_events, +}; + +static const struct wl_message wl_input_panel_requests[] = { + { "get_input_panel_surface", "no", types + 8 }, +}; + +WL_EXPORT const struct wl_interface wl_input_panel_interface = { + "wl_input_panel", 1, + 1, wl_input_panel_requests, + 0, NULL, +}; + +static const struct wl_message wl_input_panel_surface_requests[] = { + { "set_toplevel", "ou", types + 10 }, + { "set_overlay_panel", "", types + 0 }, +}; + +static const struct wl_message wl_input_panel_surface_events[] = { + { "cursor_rectangle", "iiii", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_input_panel_surface_interface = { + "wl_input_panel_surface", 1, + 2, wl_input_panel_surface_requests, + 1, wl_input_panel_surface_events, +}; diff --git a/ism/extras/efl_wsc/isf_wsc_context.cpp b/ism/extras/efl_wsc/isf_wsc_context.cpp new file mode 100644 index 0000000..13c223b --- /dev/null +++ b/ism/extras/efl_wsc/isf_wsc_context.cpp @@ -0,0 +1,2949 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define Uses_SCIM_BACKEND +#define Uses_SCIM_IMENGINE_MODULE +#define Uses_SCIM_HELPER_MODULE +#define Uses_SCIM_HOTKEY +#define Uses_SCIM_PANEL_CLIENT + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "scim_private.h" +#include "scim.h" +#include "isf_wsc_context.h" +#include "isf_wsc_control_ui.h" + +#define ENABLE_BACKKEY 1 + +using namespace scim; + +struct _WSCContextISFImpl { + WSCContextISF *parent; + IMEngineInstancePointer si; + Ecore_Wl_Window *client_window; + Evas *client_canvas; + Ecore_IMF_Input_Mode input_mode; + WideString preedit_string; + AttributeList preedit_attrlist; + Ecore_IMF_Autocapital_Type autocapital_type; + void *imdata; + int imdata_size; + int preedit_caret; + int cursor_x; + int cursor_y; + int cursor_top_y; + int cursor_pos; + bool use_preedit; + bool is_on; + bool shared_si; + bool preedit_started; + bool preedit_updating; + bool need_commit_preedit; + bool prediction_allow; + int next_shift_status; + int shift_mode_enabled; + + WSCContextISFImpl *next; +}; + +/* private functions */ +static void panel_slot_reload_config (int context); +static void panel_slot_exit (int context); +static void panel_slot_update_candidate_item_layout (int context, + const std::vector &row_items); +static void panel_slot_update_lookup_table_page_size(int context, + int page_size); +static void panel_slot_lookup_table_page_up (int context); +static void panel_slot_lookup_table_page_down (int context); +static void panel_slot_trigger_property (int context, + const String &property); +static void panel_slot_process_helper_event (int context, + const String &target_uuid, + const String &helper_uuid, + const Transaction &trans); +static void panel_slot_move_preedit_caret (int context, + int caret_pos); +static void panel_slot_update_preedit_caret (int context, + int caret); +static void panel_slot_select_aux (int context, + int aux_index); +static void panel_slot_select_candidate (int context, + int cand_index); +static void panel_slot_process_key_event (int context, + const KeyEvent &key); +static void panel_slot_commit_string (int context, + const WideString &wstr); +static void panel_slot_forward_key_event (int context, + const KeyEvent &key); +static void panel_slot_request_help (int context); +static void panel_slot_request_factory_menu (int context); +static void panel_slot_change_factory (int context, + const String &uuid); +static void panel_slot_reset_keyboard_ise (int context); +static void panel_slot_update_keyboard_ise (int context); +static void panel_slot_show_preedit_string (int context); +static void panel_slot_hide_preedit_string (int context); +static void panel_slot_update_preedit_string (int context, + const WideString &str, + const AttributeList &attrs, + int caret); +static void panel_slot_get_surrounding_text (int context, + int maxlen_before, + int maxlen_after); +static void panel_slot_delete_surrounding_text (int context, + int offset, + int len); + +static void panel_req_focus_in (WSCContextISF *ic); +static void panel_req_update_factory_info (WSCContextISF *ic); +static void panel_req_update_spot_location (WSCContextISF *ic); +static void panel_req_update_cursor_position (WSCContextISF *ic, int cursor_pos); +static void panel_req_show_help (WSCContextISF *ic); +static void panel_req_show_factory_menu (WSCContextISF *ic); + +/* Panel iochannel handler*/ +static bool panel_initialize (void); +static void panel_finalize (void); +static Eina_Bool panel_iochannel_handler (void *data, + Ecore_Fd_Handler *fd_handler); + +/* utility functions */ +static bool filter_hotkeys (WSCContextISF *ic, + const KeyEvent &key); +static void turn_on_ic (WSCContextISF *ic); +static void turn_off_ic (WSCContextISF *ic); +static void set_ic_capabilities (WSCContextISF *ic); + +static void initialize (void); +static void finalize (void); + +static void open_next_factory (WSCContextISF *ic); +static void open_previous_factory (WSCContextISF *ic); +static void open_specific_factory (WSCContextISF *ic, + const String &uuid); +static void send_wl_key_event (WSCContextISF *ic, const KeyEvent &key, bool fake); +static void _hide_preedit_string (int context, bool update_preedit); + +static void attach_instance (const IMEngineInstancePointer &si); + +/* slot functions */ +static void slot_show_preedit_string (IMEngineInstanceBase *si); +static void slot_show_aux_string (IMEngineInstanceBase *si); +static void slot_show_lookup_table (IMEngineInstanceBase *si); + +static void slot_hide_preedit_string (IMEngineInstanceBase *si); +static void slot_hide_aux_string (IMEngineInstanceBase *si); +static void slot_hide_lookup_table (IMEngineInstanceBase *si); + +static void slot_update_preedit_caret (IMEngineInstanceBase *si, + int caret); +static void slot_update_preedit_string (IMEngineInstanceBase *si, + const WideString &str, + const AttributeList &attrs, + int caret); +static void slot_update_aux_string (IMEngineInstanceBase *si, + const WideString &str, + const AttributeList &attrs); +static void slot_commit_string (IMEngineInstanceBase *si, + const WideString &str); +static void slot_forward_key_event (IMEngineInstanceBase *si, + const KeyEvent &key); +static void slot_update_lookup_table (IMEngineInstanceBase *si, + const LookupTable &table); + +static void slot_register_properties (IMEngineInstanceBase *si, + const PropertyList &properties); +static void slot_update_property (IMEngineInstanceBase *si, + const Property &property); +static void slot_beep (IMEngineInstanceBase *si); +static void slot_start_helper (IMEngineInstanceBase *si, + const String &helper_uuid); +static void slot_stop_helper (IMEngineInstanceBase *si, + const String &helper_uuid); +static void slot_send_helper_event (IMEngineInstanceBase *si, + const String &helper_uuid, + const Transaction &trans); +static bool slot_get_surrounding_text (IMEngineInstanceBase *si, + WideString &text, + int &cursor, + int maxlen_before, + int maxlen_after); +static bool slot_delete_surrounding_text (IMEngineInstanceBase *si, + int offset, + int len); + +static void slot_expand_candidate (IMEngineInstanceBase *si); +static void slot_contract_candidate (IMEngineInstanceBase *si); + +static void slot_set_candidate_style (IMEngineInstanceBase *si, + ISF_CANDIDATE_PORTRAIT_LINE_T portrait_line, + ISF_CANDIDATE_MODE_T mode); + +static void reload_config_callback (const ConfigPointer &config); + +static void fallback_commit_string_cb (IMEngineInstanceBase *si, + const WideString &str); +static void _display_input_language (WSCContextISF *ic); + +/* Local variables declaration */ +static String _language; +static WSCContextISFImpl *_used_ic_impl_list = 0; +static WSCContextISFImpl *_free_ic_impl_list = 0; +static WSCContextISF *_ic_list = 0; + +static KeyboardLayout _keyboard_layout = SCIM_KEYBOARD_Default; +static int _valid_key_mask = SCIM_KEY_AllMasks; + +static FrontEndHotkeyMatcher _frontend_hotkey_matcher; +static IMEngineHotkeyMatcher _imengine_hotkey_matcher; + +static IMEngineInstancePointer _default_instance; + +static ConfigPointer _config; +static Connection _config_connection; +static BackEndPointer _backend; + +static WSCContextISF *_focused_ic = 0; + +static bool _scim_initialized = false; + +static int _instance_count = 0; +static int _context_count = 0; + +static IMEngineFactoryPointer _fallback_factory; +static IMEngineInstancePointer _fallback_instance; +PanelClient _panel_client; +static int _panel_client_id = 0; + +static Ecore_Fd_Handler *_panel_iochannel_read_handler = 0; +static Ecore_Fd_Handler *_panel_iochannel_err_handler = 0; + +static Ecore_Wl_Window *_client_window = 0; +static Ecore_Event_Handler *_key_down_handler = 0; +static Ecore_Event_Handler *_key_up_handler = 0; + +static bool _on_the_spot = true; +static bool _shared_input_method = false; +static double space_key_time = 0.0; + +static Eina_Bool autoperiod_allow = EINA_FALSE; +static Eina_Bool autocap_allow = EINA_FALSE; +static Eina_Bool desktop_mode = EINA_FALSE; + +static bool _x_key_event_is_valid = false; + +typedef enum { + INPUT_LANG_JAPANESE, + INPUT_LANG_OTHER +} Input_Language; + +static Input_Language input_lang = INPUT_LANG_OTHER; + +#define SHIFT_MODE_OFF 0xffe1 +#define SHIFT_MODE_ON 0xffe2 +#define SHIFT_MODE_LOCK 0xffe6 +#define SHIFT_MODE_ENABLE 0x9fe7 +#define SHIFT_MODE_DISABLE 0x9fe8 + +EAPI WSCContextISF * +get_focused_ic () +{ + return _focused_ic; +} + +EAPI int +get_panel_client_id (void) +{ + return _panel_client_id; +} + +EAPI Eina_Bool +get_desktop_mode () +{ + return desktop_mode; +} + +EAPI void +get_language(char **language) +{ + *language = strdup(_language.c_str()); +} + +static unsigned int +get_time (void) +{ + unsigned int tint; + struct timeval tv; + struct timezone tz; /* is not used since ages */ + gettimeofday (&tv, &tz); + tint = tv.tv_sec * 1000; + tint = tint / 1000 * 1000; + tint = tint + tv.tv_usec / 1000; + return tint; +} + +/* Function Implementations */ +static WSCContextISFImpl * +new_ic_impl (WSCContextISF *parent) +{ + WSCContextISFImpl *impl = NULL; + + if (_free_ic_impl_list != NULL) { + impl = _free_ic_impl_list; + _free_ic_impl_list = _free_ic_impl_list->next; + } else { + impl = new WSCContextISFImpl; + if (impl == NULL) + return NULL; + } + + impl->autocapital_type = ECORE_IMF_AUTOCAPITAL_TYPE_NONE; + impl->next_shift_status = 0; + impl->shift_mode_enabled = 1; + impl->next = _used_ic_impl_list; + _used_ic_impl_list = impl; + + impl->parent = parent; + impl->imdata = NULL; + impl->imdata_size = 0; + + return impl; +} + +static void +delete_ic_impl (WSCContextISFImpl *impl) +{ + WSCContextISFImpl *rec = _used_ic_impl_list, *last = 0; + + for (; rec != 0; last = rec, rec = rec->next) { + if (rec == impl) { + if (last != 0) + last->next = rec->next; + else + _used_ic_impl_list = rec->next; + + rec->next = _free_ic_impl_list; + _free_ic_impl_list = rec; + + if (rec->imdata) { + free (rec->imdata); + rec->imdata = NULL; + } + + rec->imdata_size = 0; + rec->parent = 0; + rec->si.reset (); + rec->client_window = 0; + rec->preedit_string = WideString (); + rec->preedit_attrlist.clear (); + + return; + } + } +} + +static void +delete_all_ic_impl (void) +{ + WSCContextISFImpl *it = _used_ic_impl_list; + + while (it != 0) { + _used_ic_impl_list = it->next; + delete it; + it = _used_ic_impl_list; + } + + it = _free_ic_impl_list; + while (it != 0) { + _free_ic_impl_list = it->next; + delete it; + it = _free_ic_impl_list; + } +} + +static WSCContextISF * +find_ic (int id) +{ + WSCContextISFImpl *rec = _used_ic_impl_list; + + while (rec != 0) { + if (rec->parent && rec->parent->id == id) + return rec->parent; + rec = rec->next; + } + + return 0; +} + +static bool +check_valid_ic (WSCContextISF * ic) +{ + if (ic && ic->impl && ic->ctx) + return true; + else + return false; +} + +static void +set_prediction_allow (WSCContextISF *ctx, bool prediction) +{ + WSCContextISF *context_scim = ctx; + + if (context_scim && context_scim->impl && context_scim == _focused_ic) { + _panel_client.prepare (context_scim->id); + context_scim->impl->si->set_prediction_allow (prediction); + _panel_client.send (); + } +} + +static Eina_Bool +check_symbol (Eina_Unicode ucode, Eina_Unicode symbols[], int symbol_num) +{ + for (int i = 0; i < symbol_num; i++) { + // Check symbol + if (ucode == symbols[i]) + return EINA_TRUE; + } + + return EINA_FALSE; +} + +static void +autoperiod_insert (WSCContextISF *ctx) +{ + char *plain_str = NULL; + char *markup_str = NULL; + int cursor_pos = 0; + Eina_Unicode *ustr = NULL; + Eina_Unicode space_symbols[] = {' ', 0x00A0 /* no-break space */, 0x3000 /* ideographic space */}; + Eina_Unicode symbols[] = {' ', 0x00A0 /* no-break space */, 0x3000 /* ideographic space */, + ':', ';', '.', '!', '?', 0x00BF /* ¿ */, 0x00A1 /* ¡ */, 0x3002 /* 。 */}; + const int symbol_num = sizeof (symbols) / sizeof (symbols[0]); + char *fullstop_mark = NULL; + + if (autoperiod_allow == EINA_FALSE) + return; + + if (!ctx) return; + + Ecore_IMF_Input_Panel_Layout layout = wsc_context_input_panel_layout_get (ctx->ctx); + if (layout != ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL) + return; + + if ((ecore_time_get () - space_key_time) > DOUBLE_SPACE_INTERVAL) + goto done; + + wsc_context_surrounding_get (ctx->ctx, &markup_str, &cursor_pos); + if (!markup_str) goto done; + + // Convert into plain string + plain_str = evas_textblock_text_markup_to_utf8 (NULL, markup_str); + if (!plain_str) goto done; + + // Convert string from UTF-8 to unicode + ustr = eina_unicode_utf8_to_unicode (plain_str, NULL); + if (!ustr) goto done; + + if (cursor_pos < 2) goto done; + + if (check_symbol (ustr[cursor_pos-1], space_symbols, (sizeof (space_symbols) / sizeof (space_symbols[0]))) && + (!check_symbol (ustr[cursor_pos-2], symbols, symbol_num))) { + wsc_context_delete_surrounding(ctx->ctx, -1, 1); + + if (input_lang == INPUT_LANG_JAPANESE) { + fullstop_mark = strdup ("。"); + } + else { + fullstop_mark = strdup ("."); + } + + wsc_context_commit_string(ctx->ctx, fullstop_mark); + + if (fullstop_mark) { + free (fullstop_mark); + } + } + +done: + if (markup_str) free (markup_str); + if (plain_str) free (plain_str); + if (ustr) free (ustr); + space_key_time = ecore_time_get (); +} + +static Eina_Bool +analyze_surrounding_text (WSCContextISF *ctx) +{ + char *plain_str = NULL; + char *markup_str = NULL; + Eina_Unicode puncs[] = {'\n','.', '!', '?', 0x00BF /* ¿ */, 0x00A1 /* ¡ */, 0x3002 /* 。 */}; + Eina_Unicode space_symbols[] = {' ', 0x00A0 /* no-break space */, 0x3000 /* ideographic space */}; + Eina_Unicode *ustr = NULL; + Eina_Bool ret = EINA_FALSE; + Eina_Bool detect_space = EINA_FALSE; + int cursor_pos = 0; + int i = 0; + const int punc_num = sizeof (puncs) / sizeof (puncs[0]); + WSCContextISF *context_scim; + + if (!ctx) return EINA_FALSE; + context_scim = ctx; + if (!context_scim || !context_scim->impl) return EINA_FALSE; + + switch (context_scim->impl->autocapital_type) { + case ECORE_IMF_AUTOCAPITAL_TYPE_NONE: + return EINA_FALSE; + case ECORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER: + return EINA_TRUE; + default: + break; + } + + if (context_scim->impl->cursor_pos == 0) + return EINA_TRUE; + + wsc_context_surrounding_get (ctx->ctx, &markup_str, &cursor_pos); + if (!markup_str) goto done; + + if (cursor_pos == 0) { + ret = EINA_TRUE; + goto done; + } + + // Convert into plain string + plain_str = evas_textblock_text_markup_to_utf8 (NULL, markup_str); + if (!plain_str) goto done; + + // Convert string from UTF-8 to unicode + ustr = eina_unicode_utf8_to_unicode (plain_str, NULL); + if (!ustr) goto done; + + if (eina_unicode_strlen (ustr) < (size_t)cursor_pos) goto done; + + if (cursor_pos >= 1) { + if (context_scim->impl->autocapital_type == ECORE_IMF_AUTOCAPITAL_TYPE_WORD) { + // Check space or no-break space + if (check_symbol (ustr[cursor_pos-1], space_symbols, (sizeof (space_symbols) / sizeof (space_symbols[0])))) { + ret = EINA_TRUE; + goto done; + } + } + + // Check paragraph separator or carriage return
+ if ((ustr[cursor_pos-1] == 0x2029) || (ustr[cursor_pos-1] == '\n')) { + ret = EINA_TRUE; + goto done; + } + + for (i = cursor_pos; i > 0; i--) { + // Check space or no-break space + if (check_symbol (ustr[i-1], space_symbols, (sizeof (space_symbols) / sizeof (space_symbols[0])))) { + detect_space = EINA_TRUE; + continue; + } + + // Check punctuation and following the continuous space(s) + if (detect_space && check_symbol (ustr[i-1], puncs, punc_num)) { + ret = EINA_TRUE; + goto done; + } + else { + ret = EINA_FALSE; + goto done; + } + } + + if ((i == 0) && (detect_space == EINA_TRUE)) { + // continuous space(s) without any character + ret = EINA_TRUE; + goto done; + } + } + +done: + if (ustr) free (ustr); + if (markup_str) free (markup_str); + if (plain_str) free (plain_str); + + return ret; +} + +EAPI Eina_Bool +caps_mode_check (WSCContextISF *ctx, Eina_Bool force, Eina_Bool noti) +{ + Eina_Bool uppercase; + WSCContextISF *context_scim; + + if (hw_keyboard_num_get () > 0) return EINA_FALSE; + + if (!ctx) return EINA_FALSE; + context_scim = ctx; + + if (!context_scim || !context_scim->impl) + return EINA_FALSE; + + if (context_scim->impl->next_shift_status == SHIFT_MODE_LOCK) return EINA_TRUE; + + Ecore_IMF_Input_Panel_Layout layout = wsc_context_input_panel_layout_get (ctx->ctx); + if (layout != ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL) + return EINA_FALSE; + + // Check autocapital type + if (wsc_context_input_panel_caps_lock_mode_get (ctx->ctx)) { + uppercase = EINA_TRUE; + } else { + if (autocap_allow == EINA_FALSE) + return EINA_FALSE; + + if (analyze_surrounding_text (ctx)) { + uppercase = EINA_TRUE; + } else { + uppercase = EINA_FALSE; + } + } + + if (force) { + context_scim->impl->next_shift_status = uppercase ? SHIFT_MODE_ON : SHIFT_MODE_OFF; + if (noti) + isf_wsc_context_input_panel_caps_mode_set (ctx, uppercase); + } else { + if (context_scim->impl->next_shift_status != (uppercase ? SHIFT_MODE_ON : SHIFT_MODE_OFF)) { + context_scim->impl->next_shift_status = uppercase ? SHIFT_MODE_ON : SHIFT_MODE_OFF; + if (noti) + isf_wsc_context_input_panel_caps_mode_set (ctx, uppercase); + } + } + + return uppercase; +} + +static void +get_input_language () +{ + char *input_lang_str = vconf_get_str (VCONFKEY_ISF_INPUT_LANGUAGE); + if (!input_lang_str) return; + + if (strcmp (input_lang_str, "ja_JP") == 0) + input_lang = INPUT_LANG_JAPANESE; + else + input_lang = INPUT_LANG_OTHER; + + free (input_lang_str); +} + +static void autoperiod_allow_changed_cb (keynode_t *key, void* data) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + autoperiod_allow = vconf_keynode_get_bool (key); +} + +static void autocapital_allow_changed_cb (keynode_t *key, void* data) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + autocap_allow = vconf_keynode_get_bool (key); +} + +static void input_language_changed_cb (keynode_t *key, void* data) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + get_input_language (); +} + +EAPI void context_scim_imdata_get (WSCContextISF *ctx, void* data, int* length) +{ + WSCContextISF *context_scim = ctx; + + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + if (context_scim && context_scim->impl) { + if (data && context_scim->impl->imdata) + memcpy (data, context_scim->impl->imdata, context_scim->impl->imdata_size); + + if (length) + *length = context_scim->impl->imdata_size; + } +} + +EAPI void +imengine_layout_set (WSCContextISF *ctx, Ecore_IMF_Input_Panel_Layout layout) +{ + WSCContextISF *context_scim = ctx; + + if (context_scim && context_scim->impl && context_scim == _focused_ic) { + _panel_client.prepare (context_scim->id); + context_scim->impl->si->set_layout (layout); + _panel_client.send (); + } +} + +/* Public functions */ +EAPI WSCContextISF * +isf_wsc_context_new (void) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + int val; + + WSCContextISF *context_scim = new WSCContextISF; + if (context_scim == NULL) { + std::cerr << "memory allocation failed in " << __FUNCTION__ << "\n"; + return NULL; + } + + if (_context_count == 0) { + _context_count = getpid () % 50000; + } + context_scim->id = _context_count++; + + if (!_scim_initialized) { + ecore_wl_init (NULL); + initialize (); + _scim_initialized = true; + isf_wsc_input_panel_init (); + //isf_wsc_context_set_hardware_keyboard_mode(context_scim); + + /* get autoperiod allow vconf value */ + if (vconf_get_bool (VCONFKEY_AUTOPERIOD_ALLOW_BOOL, &val) == 0) { + if (val == EINA_TRUE) + autoperiod_allow = EINA_TRUE; + } + + vconf_notify_key_changed (VCONFKEY_AUTOPERIOD_ALLOW_BOOL, autoperiod_allow_changed_cb, NULL); + + /* get autocapital allow vconf value */ + if (vconf_get_bool (VCONFKEY_AUTOCAPITAL_ALLOW_BOOL, &val) == 0) { + if (val == EINA_TRUE) + autocap_allow = EINA_TRUE; + } + + vconf_notify_key_changed (VCONFKEY_AUTOCAPITAL_ALLOW_BOOL, autocapital_allow_changed_cb, NULL); + + /* get input language vconf value */ + get_input_language (); + + vconf_notify_key_changed (VCONFKEY_ISF_INPUT_LANGUAGE, input_language_changed_cb, NULL); + } + + return context_scim; +} + +EAPI void +isf_wsc_context_shutdown (void) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + ConfigBase::set (0); + if (_scim_initialized) { + _scim_initialized = false; + + vconf_ignore_key_changed (VCONFKEY_AUTOPERIOD_ALLOW_BOOL, autoperiod_allow_changed_cb); + vconf_ignore_key_changed (VCONFKEY_AUTOCAPITAL_ALLOW_BOOL, autocapital_allow_changed_cb); + vconf_ignore_key_changed (VCONFKEY_ISF_INPUT_LANGUAGE, input_language_changed_cb); + + isf_wsc_input_panel_shutdown (); + finalize (); + ecore_wl_shutdown (); + } +} + +EAPI void +isf_wsc_context_add (WSCContextISF *ctx) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *context_scim = ctx; + + if (!context_scim) return; + + context_scim->impl = NULL; + + if (_backend.null ()) + return; + + IMEngineInstancePointer si; + + // Use the default instance if "shared input method" mode is enabled. + if (_shared_input_method && !_default_instance.null ()) { + si = _default_instance; + SCIM_DEBUG_FRONTEND(2) << "use default instance: " << si->get_id () << " " << si->get_factory_uuid () << "\n"; + } + + // Not in "shared input method" mode, or no default instance, create an instance. + if (si.null ()) { + IMEngineFactoryPointer factory = _backend->get_default_factory (_language, "UTF-8"); + if (factory.null ()) return; + si = factory->create_instance ("UTF-8", _instance_count++); + if (si.null ()) return; + attach_instance (si); + SCIM_DEBUG_FRONTEND(2) << "create new instance: " << si->get_id () << " " << si->get_factory_uuid () << "\n"; + } + + // If "shared input method" mode is enabled, and there is no default instance, + // then store this instance as default one. + if (_shared_input_method && _default_instance.null ()) { + SCIM_DEBUG_FRONTEND(2) << "update default instance.\n"; + _default_instance = si; + } + + context_scim->impl = new_ic_impl (context_scim); + if (context_scim->impl == NULL) { + std::cerr << "memory allocation failed in " << __FUNCTION__ << "\n"; + return; + } + + context_scim->impl->si = si; + context_scim->impl->client_window = 0; + context_scim->impl->client_canvas = NULL; + context_scim->impl->preedit_caret = 0; + context_scim->impl->cursor_x = 0; + context_scim->impl->cursor_y = 0; + context_scim->impl->cursor_pos = -1; + context_scim->impl->cursor_top_y = 0; + context_scim->impl->is_on = true; + context_scim->impl->shared_si = _shared_input_method; + context_scim->impl->use_preedit = _on_the_spot; + context_scim->impl->preedit_started = false; + context_scim->impl->preedit_updating = false; + context_scim->impl->need_commit_preedit = false; + context_scim->impl->prediction_allow = true; + + if (!_ic_list) + context_scim->next = NULL; + else + context_scim->next = _ic_list; + _ic_list = context_scim; + + if (_shared_input_method) + context_scim->impl->is_on = _config->read (String (SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), context_scim->impl->is_on); + + _panel_client.prepare (context_scim->id); + _panel_client.register_input_context (context_scim->id, si->get_factory_uuid ()); + set_ic_capabilities (context_scim); + _panel_client.send (); + + SCIM_DEBUG_FRONTEND(2) << "input context created: id = " << context_scim->id << "\n"; +} + +EAPI void +isf_wsc_context_del (WSCContextISF *ctx) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + if (!_ic_list) return; + + WSCContextISF *context_scim = ctx; + + if (context_scim) { + if (context_scim->id != _ic_list->id) { + WSCContextISF * pre = _ic_list; + WSCContextISF * cur = _ic_list->next; + while (cur != NULL) { + if (cur->id == context_scim->id) { + pre->next = cur->next; + break; + } + pre = cur; + cur = cur->next; + } + } else { + _ic_list = _ic_list->next; + } + } + + if (context_scim && context_scim->impl) { + _panel_client.prepare (context_scim->id); + + if (context_scim == _focused_ic) + context_scim->impl->si->focus_out (); + + // Delete the instance. + // FIXME: + // In case the instance send out some helper event, + // and this context has been focused out, + // we need set the focused_ic to this context temporary. + WSCContextISF *old_focused = _focused_ic; + _focused_ic = context_scim; + context_scim->impl->si.reset (); + _focused_ic = old_focused; + + if (context_scim == _focused_ic) { + _panel_client.turn_off (context_scim->id); + _panel_client.focus_out (context_scim->id); + } + + _panel_client.remove_input_context (context_scim->id); + _panel_client.send (); + + if (context_scim->impl) { + delete_ic_impl (context_scim->impl); + context_scim->impl = 0; + } + } + + if (context_scim == _focused_ic) + _focused_ic = 0; + + if (context_scim) { + delete context_scim; + context_scim = 0; + } +} + +EAPI void +isf_wsc_context_focus_in (WSCContextISF *ctx) +{ + WSCContextISF *context_scim = ctx; + + if (!context_scim) + return; + + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__<< "(" << context_scim->id << ")...\n"; + + if (_focused_ic) { + if (_focused_ic == context_scim) { + SCIM_DEBUG_FRONTEND(1) << "It's already focused.\n"; + return; + } + SCIM_DEBUG_FRONTEND(1) << "Focus out previous IC first: " << _focused_ic->id << "\n"; + if (_focused_ic->ctx) + isf_wsc_context_focus_out (_focused_ic); + } + + bool need_cap = false; + bool need_reset = false; + bool need_reg = false; + + if (context_scim && context_scim->impl) { + _focused_ic = context_scim; + + _panel_client.send (); + + _panel_client.prepare (context_scim->id); + + // Handle the "Shared Input Method" mode. + if (_shared_input_method) { + SCIM_DEBUG_FRONTEND(2) << "shared input method.\n"; + IMEngineFactoryPointer factory = _backend->get_default_factory (_language, "UTF-8"); + if (!factory.null ()) { + if (_default_instance.null () || _default_instance->get_factory_uuid () != factory->get_uuid ()) { + _default_instance = factory->create_instance ("UTF-8", _default_instance.null () ? _instance_count++ : _default_instance->get_id ()); + attach_instance (_default_instance); + SCIM_DEBUG_FRONTEND(2) << "create new default instance: " << _default_instance->get_id () << " " << _default_instance->get_factory_uuid () << "\n"; + } + + context_scim->impl->shared_si = true; + context_scim->impl->si = _default_instance; + + context_scim->impl->is_on = _config->read (String (SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), context_scim->impl->is_on); + context_scim->impl->preedit_string.clear (); + context_scim->impl->preedit_attrlist.clear (); + context_scim->impl->preedit_caret = 0; + context_scim->impl->preedit_started = false; + need_cap = true; + need_reset = true; + need_reg = true; + } + } else if (context_scim->impl->shared_si) { + SCIM_DEBUG_FRONTEND(2) << "exit shared input method.\n"; + IMEngineFactoryPointer factory = _backend->get_default_factory (_language, "UTF-8"); + if (!factory.null ()) { + context_scim->impl->si = factory->create_instance ("UTF-8", _instance_count++); + context_scim->impl->preedit_string.clear (); + context_scim->impl->preedit_attrlist.clear (); + context_scim->impl->preedit_caret = 0; + context_scim->impl->preedit_started = false; + attach_instance (context_scim->impl->si); + need_cap = true; + need_reg = true; + context_scim->impl->shared_si = false; + SCIM_DEBUG_FRONTEND(2) << "create new instance: " << context_scim->impl->si->get_id () << " " << context_scim->impl->si->get_factory_uuid () << "\n"; + } + } + + context_scim->impl->si->set_frontend_data (static_cast (context_scim)); + + if (need_reg) _panel_client.register_input_context (context_scim->id, context_scim->impl->si->get_factory_uuid ()); + if (need_cap) set_ic_capabilities (context_scim); + + panel_req_focus_in (context_scim); +// panel_req_update_spot_location (context_scim); +// panel_req_update_factory_info (context_scim); + + if (need_reset) context_scim->impl->si->reset (); + if (context_scim->impl->is_on) { + _panel_client.turn_on (context_scim->id); +// _panel_client.hide_preedit_string (context_scim->id); +// _panel_client.hide_aux_string (context_scim->id); +// _panel_client.hide_lookup_table (context_scim->id); + context_scim->impl->si->focus_in (); + context_scim->impl->si->set_layout (wsc_context_input_panel_layout_get (ctx->ctx)); + context_scim->impl->si->set_prediction_allow (context_scim->impl->prediction_allow); + if (context_scim->impl->imdata) + context_scim->impl->si->set_imdata ((const char *)context_scim->impl->imdata, context_scim->impl->imdata_size); + } else { + _panel_client.turn_off (context_scim->id); + } + + _panel_client.send (); + if (caps_mode_check (ctx, EINA_FALSE, EINA_TRUE) == EINA_FALSE) { + context_scim->impl->next_shift_status = 0; + } + } + + LOGD ("ctx : %p\n", ctx); +} + +EAPI void +isf_wsc_context_focus_out (WSCContextISF *ctx) +{ + WSCContextISF *context_scim = ctx; + + if (!context_scim) return; + + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "(" << context_scim->id << ")...\n"; + + if (context_scim && context_scim->impl && context_scim == _focused_ic) { + + LOGD ("ctx : %p\n", ctx); + + if (context_scim->impl->need_commit_preedit) { + _hide_preedit_string (context_scim->id, false); + + wsc_context_commit_preedit_string(context_scim->ctx); + _panel_client.prepare (context_scim->id); + _panel_client.reset_input_context (context_scim->id); + _panel_client.send (); + } + + _panel_client.prepare (context_scim->id); + + context_scim->impl->si->focus_out (); + context_scim->impl->si->reset (); + context_scim->impl->cursor_pos = -1; + +// if (context_scim->impl->shared_si) context_scim->impl->si->reset (); + + _panel_client.focus_out (context_scim->id); + _panel_client.send (); + _focused_ic = 0; + } + _x_key_event_is_valid = false; +} + +EAPI void +isf_wsc_context_reset (WSCContextISF *ctx) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *context_scim = ctx; + + if (context_scim && context_scim->impl && context_scim == _focused_ic) { + _panel_client.prepare (context_scim->id); + context_scim->impl->si->reset (); + _panel_client.reset_input_context (context_scim->id); + _panel_client.send (); + + if (context_scim->impl->need_commit_preedit) { + _hide_preedit_string (context_scim->id, false); + wsc_context_commit_preedit_string(context_scim->ctx); + } + } +} + +EAPI void +isf_wsc_context_preedit_string_get (WSCContextISF *ctx, char** str, int *cursor_pos) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *context_scim = ctx; + + if (context_scim && context_scim->impl && context_scim->impl->is_on) { + String mbs = utf8_wcstombs (context_scim->impl->preedit_string); + + if (str) { + if (mbs.length ()) + *str = strdup (mbs.c_str ()); + else + *str = strdup (""); + } + + if (cursor_pos) { + //*cursor_pos = context_scim->impl->preedit_caret; + mbs = utf8_wcstombs ( + context_scim->impl->preedit_string.substr(0, context_scim->impl->preedit_caret)); + *cursor_pos = mbs.length(); + } + } else { + if (str) + *str = strdup (""); + + if (cursor_pos) + *cursor_pos = 0; + } +} + +EAPI void +isf_wsc_context_prediction_allow_set (WSCContextISF* ctx, Eina_Bool prediction) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " = " << (prediction == EINA_TRUE ? "true" : "false") << "...\n"; + + WSCContextISF *context_scim = ctx; + + if (context_scim && context_scim->impl && context_scim->impl->prediction_allow != prediction) { + context_scim->impl->prediction_allow = prediction; + set_prediction_allow (ctx, prediction); + } +} + +EAPI Eina_Bool +isf_wsc_context_prediction_allow_get (WSCContextISF* ctx) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *context_scim = ctx; + + Eina_Bool ret = EINA_FALSE; + if (context_scim && context_scim->impl) { + ret = context_scim->impl->prediction_allow; + } else { + std::cerr << __FUNCTION__ << " failed!!!\n"; + } + return ret; +} + +static void +turn_on_ic (WSCContextISF *ic) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + if (ic && ic->impl && !ic->impl->is_on) { + ic->impl->is_on = true; + + if (ic == _focused_ic) { + panel_req_focus_in (ic); +// panel_req_update_spot_location (ic); + panel_req_update_factory_info (ic); + _panel_client.turn_on (ic->id); +// _panel_client.hide_preedit_string (ic->id); +// _panel_client.hide_aux_string (ic->id); +// _panel_client.hide_lookup_table (ic->id); + ic->impl->si->focus_in (); + ic->impl->si->set_layout (ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL); + ic->impl->si->set_prediction_allow (ic->impl->prediction_allow); + } + + //Record the IC on/off status + if (_shared_input_method) { + _config->write (String (SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), true); + _config->flush (); + } + + if (ic->impl->use_preedit && ic->impl->preedit_string.length ()) { + if (!check_valid_ic (ic)) + return; + + if (check_valid_ic (ic)) + ic->impl->preedit_started = true; + } + } +} + +static void +turn_off_ic (WSCContextISF *ic) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + if (ic && ic->impl && ic->impl->is_on) { + ic->impl->is_on = false; + + if (ic == _focused_ic) { + ic->impl->si->focus_out (); + +// panel_req_update_factory_info (ic); + _panel_client.turn_off (ic->id); + } + + //Record the IC on/off status + if (_shared_input_method) { + _config->write (String (SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), false); + _config->flush (); + } + + if (ic->impl->use_preedit && ic->impl->preedit_string.length ()) { + if (!check_valid_ic (ic)) + return; + + if (check_valid_ic (ic)) + ic->impl->preedit_started = false; + } + } +} + +static void +set_ic_capabilities (WSCContextISF *ic) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + if (ic && ic->impl) { + unsigned int cap = SCIM_CLIENT_CAP_ALL_CAPABILITIES; + + if (!_on_the_spot || !ic->impl->use_preedit) + cap -= SCIM_CLIENT_CAP_ONTHESPOT_PREEDIT; + + ic->impl->si->update_client_capabilities (cap); + } +} + +static bool +check_socket_frontend (void) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + SocketAddress address; + SocketClient client; + + uint32 magic; + + address.set_address (scim_get_default_socket_frontend_address ()); + + if (!client.connect (address)) + return false; + + if (!scim_socket_open_connection (magic, + String ("ConnectionTester"), + String ("SocketFrontEnd"), + client, + 1000)) { + return false; + } + + return true; +} + +/* Panel Requestion functions. */ +static void +panel_req_show_help (WSCContextISF *ic) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + String help; + + help = String (_("Smart Common Input Method platform ")) + + String (SCIM_VERSION) + + String (_("\n(C) 2002-2005 James Su \n\n")); + + if (ic && ic->impl) { + IMEngineFactoryPointer sf = _backend->get_factory (ic->impl->si->get_factory_uuid ()); + if (sf) { + help += utf8_wcstombs (sf->get_name ()); + help += String (_(":\n\n")); + + help += utf8_wcstombs (sf->get_help ()); + help += String (_("\n\n")); + + help += utf8_wcstombs (sf->get_credits ()); + } + _panel_client.show_help (ic->id, help); + } +} + +static void +panel_req_show_factory_menu (WSCContextISF *ic) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + std::vector factories; + std::vector menu; + + _backend->get_factories_for_encoding (factories, "UTF-8"); + + for (size_t i = 0; i < factories.size (); ++ i) { + menu.push_back (PanelFactoryInfo ( + factories [i]->get_uuid (), + utf8_wcstombs (factories [i]->get_name ()), + factories [i]->get_language (), + factories [i]->get_icon_file ())); + } + + if (menu.size ()) + _panel_client.show_factory_menu (ic->id, menu); +} + +static void +panel_req_update_factory_info (WSCContextISF *ic) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + if (ic && ic->impl && ic == _focused_ic) { + PanelFactoryInfo info; + if (ic->impl->is_on) { + IMEngineFactoryPointer sf = _backend->get_factory (ic->impl->si->get_factory_uuid ()); + if (sf) + info = PanelFactoryInfo (sf->get_uuid (), utf8_wcstombs (sf->get_name ()), sf->get_language (), sf->get_icon_file ()); + } else { + info = PanelFactoryInfo (String (""), String (_("English Keyboard")), String ("C"), String (SCIM_KEYBOARD_ICON_FILE)); + } + _panel_client.update_factory_info (ic->id, info); + } +} + +static void +panel_req_focus_in (WSCContextISF *ic) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + if (ic && ic->impl && ic->impl->si) + _panel_client.focus_in (ic->id, ic->impl->si->get_factory_uuid ()); +} + +static void +panel_req_update_spot_location (WSCContextISF *ic) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + if (ic && ic->impl) + _panel_client.update_spot_location (ic->id, ic->impl->cursor_x, ic->impl->cursor_y, ic->impl->cursor_top_y); +} + +static void +panel_req_update_cursor_position (WSCContextISF *ic, int cursor_pos) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + if (ic) + _panel_client.update_cursor_position (ic->id, cursor_pos); +} + +static bool +filter_hotkeys (WSCContextISF *ic, const KeyEvent &key) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + bool ret = false; + + if (!check_valid_ic (ic)) + return ret; + + _frontend_hotkey_matcher.push_key_event (key); + _imengine_hotkey_matcher.push_key_event (key); + + FrontEndHotkeyAction hotkey_action = _frontend_hotkey_matcher.get_match_result (); + + if (hotkey_action == SCIM_FRONTEND_HOTKEY_TRIGGER) { + IMEngineFactoryPointer sf = _backend->get_factory (ic->impl->si->get_factory_uuid ()); + if (sf && (sf->get_option () & SCIM_IME_SUPPORT_LANGUAGE_TOGGLE_KEY)) { + ret = false; + } else { + if (!ic->impl->is_on) { + turn_on_ic (ic); + } else { + turn_off_ic (ic); + _panel_client.hide_aux_string (ic->id); + _panel_client.hide_lookup_table (ic->id); + } + + _display_input_language (ic); + ret = true; + } + } else if (hotkey_action == SCIM_FRONTEND_HOTKEY_ON) { + if (!ic->impl->is_on) { + turn_on_ic (ic); + _display_input_language (ic); + } + ret = true; + } else if (hotkey_action == SCIM_FRONTEND_HOTKEY_OFF) { + if (ic->impl->is_on) { + turn_off_ic (ic); + _display_input_language (ic); + } + ret = true; + } else if (hotkey_action == SCIM_FRONTEND_HOTKEY_NEXT_FACTORY) { + open_next_factory (ic); + ret = true; + } else if (hotkey_action == SCIM_FRONTEND_HOTKEY_PREVIOUS_FACTORY) { + open_previous_factory (ic); + ret = true; + } else if (hotkey_action == SCIM_FRONTEND_HOTKEY_SHOW_FACTORY_MENU) { + panel_req_show_factory_menu (ic); + ret = true; + } else if (_imengine_hotkey_matcher.is_matched ()) { + ISEInfo info = _imengine_hotkey_matcher.get_match_result (); + ISE_TYPE type = info.type; + if (type == IMENGINE_T) + open_specific_factory (ic, info.uuid); + else if (type == HELPER_T) + _panel_client.start_helper (ic->id, info.uuid); + ret = true; + } + return ret; +} + +static bool +panel_initialize (void) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + String display_name; + { + const char *p = getenv ("DISPLAY"); + if (p) display_name = String (p); + } + + if (_panel_client.open_connection (_config->get_name (), display_name) >= 0) { + if (_panel_client.get_client_id (_panel_client_id)) { + _panel_client.prepare (0); + _panel_client.register_client (_panel_client_id); + _panel_client.send (); + } + + int fd = _panel_client.get_connection_number (); + + _panel_iochannel_read_handler = ecore_main_fd_handler_add (fd, ECORE_FD_READ, panel_iochannel_handler, NULL, NULL, NULL); +// _panel_iochannel_err_handler = ecore_main_fd_handler_add (fd, ECORE_FD_ERROR, panel_iochannel_handler, NULL, NULL, NULL); + + SCIM_DEBUG_FRONTEND(2) << " Panel FD= " << fd << "\n"; + + WSCContextISF *context_scim = _ic_list; + while (context_scim != NULL) { + if (context_scim->impl && context_scim->impl->si) { + _panel_client.prepare (context_scim->id); + _panel_client.register_input_context (context_scim->id, context_scim->impl->si->get_factory_uuid ()); + _panel_client.send (); + } + context_scim = context_scim->next; + } + + if (_focused_ic) { + _focused_ic = 0; + } + + return true; + } + std::cerr << "panel_initialize () failed!!!\n"; + return false; +} + +static void +panel_finalize (void) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + _panel_client.close_connection (); + + if (_panel_iochannel_read_handler) { + ecore_main_fd_handler_del (_panel_iochannel_read_handler); + _panel_iochannel_read_handler = 0; + } + if (_panel_iochannel_err_handler) { + ecore_main_fd_handler_del (_panel_iochannel_err_handler); + _panel_iochannel_err_handler = 0; + } +} + +static Eina_Bool +panel_iochannel_handler (void *data, Ecore_Fd_Handler *fd_handler) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + if (fd_handler == _panel_iochannel_read_handler) { + if (_panel_client.has_pending_event () && !_panel_client.filter_event ()) { + panel_finalize (); + panel_initialize (); + return ECORE_CALLBACK_CANCEL; + } + } else if (fd_handler == _panel_iochannel_err_handler) { + panel_finalize (); + panel_initialize (); + return ECORE_CALLBACK_CANCEL; + } + return ECORE_CALLBACK_RENEW; +} + +/* Panel Slot functions */ +static void +panel_slot_reload_config (int context) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; +} + +static void +panel_slot_exit (int /* context */) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + finalize (); +} + +static void +panel_slot_update_candidate_item_layout (int context, const std::vector &row_items) +{ + WSCContextISF *ic = find_ic (context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " row size=" << row_items.size () << " ic=" << ic << "\n"; + if (ic && ic->impl) { + _panel_client.prepare (ic->id); + ic->impl->si->update_candidate_item_layout (row_items); + _panel_client.send (); + } +} + +static void +panel_slot_update_lookup_table_page_size (int context, int page_size) +{ + WSCContextISF *ic = find_ic (context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " page_size=" << page_size << " ic=" << ic << "\n"; + if (ic && ic->impl) { + _panel_client.prepare (ic->id); + ic->impl->si->update_lookup_table_page_size (page_size); + _panel_client.send (); + } +} + +static void +panel_slot_lookup_table_page_up (int context) +{ + WSCContextISF *ic = find_ic (context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n"; + if (ic && ic->impl) { + _panel_client.prepare (ic->id); + ic->impl->si->lookup_table_page_up (); + _panel_client.send (); + } +} + +static void +panel_slot_lookup_table_page_down (int context) +{ + WSCContextISF *ic = find_ic (context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n"; + if (ic && ic->impl) { + _panel_client.prepare (ic->id); + ic->impl->si->lookup_table_page_down (); + _panel_client.send (); + } +} + +static void +panel_slot_trigger_property (int context, const String &property) +{ + WSCContextISF *ic = find_ic (context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " property=" << property << " ic=" << ic << "\n"; + if (ic && ic->impl) { + _panel_client.prepare (ic->id); + ic->impl->si->trigger_property (property); + _panel_client.send (); + } +} + +static void +panel_slot_process_helper_event (int context, const String &target_uuid, const String &helper_uuid, const Transaction &trans) +{ + WSCContextISF *ic = find_ic (context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " target=" << target_uuid + << " helper=" << helper_uuid << " ic=" << ic << " ic->impl=" << (ic != NULL ? ic->impl : 0) << " ic-uuid=" + << ((ic && ic->impl) ? ic->impl->si->get_factory_uuid () : "" ) << "\n"; + if (ic && ic->impl && ic->impl->si->get_factory_uuid () == target_uuid) { + _panel_client.prepare (ic->id); + SCIM_DEBUG_FRONTEND(2) << "call process_helper_event\n"; + ic->impl->si->process_helper_event (helper_uuid, trans); + _panel_client.send (); + } +} + +static void +panel_slot_move_preedit_caret (int context, int caret_pos) +{ + WSCContextISF *ic = find_ic (context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " caret=" << caret_pos << " ic=" << ic << "\n"; + if (ic && ic->impl) { + _panel_client.prepare (ic->id); + ic->impl->si->move_preedit_caret (caret_pos); + _panel_client.send (); + } +} + +static void +panel_slot_update_preedit_caret (int context, int caret) +{ + WSCContextISF *ic = find_ic (context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " caret=" << caret << " ic=" << ic << "\n"; + + if (ic && ic->impl && _focused_ic == ic && ic->impl->preedit_caret != caret) { + ic->impl->preedit_caret = caret; + if (ic->impl->use_preedit) { + if (!ic->impl->preedit_started) { + if (check_valid_ic (ic)) + ic->impl->preedit_started = true; + } + } else { + _panel_client.prepare (ic->id); + _panel_client.update_preedit_caret (ic->id, caret); + _panel_client.send (); + } + } +} + +static void +panel_slot_select_aux (int context, int aux_index) +{ + WSCContextISF *ic = find_ic (context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " aux=" << aux_index << " ic=" << ic << "\n"; + if (ic && ic->impl) { + _panel_client.prepare (ic->id); + ic->impl->si->select_aux (aux_index); + _panel_client.send (); + } +} + +static void +panel_slot_select_candidate (int context, int cand_index) +{ + WSCContextISF *ic = find_ic (context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " candidate=" << cand_index << " ic=" << ic << "\n"; + if (ic && ic->impl) { + _panel_client.prepare (ic->id); + ic->impl->si->select_candidate (cand_index); + _panel_client.send (); + } +} + +static Eina_Bool +feed_key_event (WSCContextISF *ic, const KeyEvent &key, bool fake) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + if (key.code <= 0x7F || + (key.code >= SCIM_KEY_BackSpace && key.code <= SCIM_KEY_Delete) || + (key.code >= SCIM_KEY_Home && key.code <= SCIM_KEY_Hyper_R)) { + // ascii code and function keys + send_wl_key_event(ic, key, fake); + return EINA_TRUE; + } else { + return EINA_FALSE; + } +} + +static void +panel_slot_process_key_event (int context, const KeyEvent &key) +{ + WSCContextISF *ic = find_ic (context); + Eina_Bool process_key = EINA_TRUE; + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " key=" << key.get_key_string () << " ic=" << ic << "\n"; + + if (!(ic && ic->impl)) + return; + + if ((_focused_ic != NULL) && (_focused_ic != ic)) + return; + + KeyEvent _key = key; + if (key.is_key_press () && + wsc_context_input_panel_layout_get (ic->ctx) == ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL) { + if (key.code == SHIFT_MODE_OFF || + key.code == SHIFT_MODE_ON || + key.code == SHIFT_MODE_LOCK) { + ic->impl->next_shift_status = _key.code; + } else if (key.code == SHIFT_MODE_ENABLE ) { + ic->impl->shift_mode_enabled = true; + caps_mode_check (ic, EINA_TRUE, EINA_TRUE); + } else if (key.code == SHIFT_MODE_DISABLE ) { + ic->impl->shift_mode_enabled = false; + } + } + + if (key.code != SHIFT_MODE_OFF && + key.code != SHIFT_MODE_ON && + key.code != SHIFT_MODE_LOCK && + key.code != SHIFT_MODE_ENABLE && + key.code != SHIFT_MODE_DISABLE) { + if (ic->impl->preedit_string.length() < 1) { + if (!((key.code >= 'a' && key.code <= 'z') || + (key.code >= 'A' && key.code <= 'Z'))) { + if (feed_key_event (ic, _key, false)) return; + } + } + } + + if (key.code == SHIFT_MODE_ENABLE || + key.code == SHIFT_MODE_DISABLE) { + process_key = EINA_FALSE; + } + + _panel_client.prepare (ic->id); + + if (!filter_hotkeys (ic, _key)) { + if (process_key) { + if (!_focused_ic || !_focused_ic->impl->is_on || + !_focused_ic->impl->si->process_key_event (_key)) { + _fallback_instance->process_key_event (_key); + } + } + } + + _panel_client.send (); +} + +static void +panel_slot_commit_string (int context, const WideString &wstr) +{ + WSCContextISF *ic = find_ic (context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " str=" << utf8_wcstombs (wstr) << " ic=" << ic << "\n"; + + if (ic && ic->impl) { + if (_focused_ic != ic) + return; + + if (utf8_wcstombs (wstr) == String (" ") || utf8_wcstombs (wstr) == String (" ")) + autoperiod_insert (ic); + + if (ic->impl->need_commit_preedit) + _hide_preedit_string (ic->id, false); + wsc_context_commit_string (ic->ctx, utf8_wcstombs (wstr).c_str ()); + } +} + +static void +panel_slot_forward_key_event (int context, const KeyEvent &key) +{ + WSCContextISF *ic = find_ic (context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " key=" << key.get_key_string () << " ic=" << ic << "\n"; + + if (!(ic && ic->impl)) + return; + + if ((_focused_ic != NULL) && (_focused_ic != ic)) + return; + + if (strlen (key.get_key_string ().c_str ()) >= 116) + return; + + feed_key_event (ic, key, true); +} + +static void +panel_slot_request_help (int context) +{ + WSCContextISF *ic = find_ic (context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n"; + if (ic && ic->impl) { + _panel_client.prepare (ic->id); + panel_req_show_help (ic); + _panel_client.send (); + } +} + +static void +panel_slot_request_factory_menu (int context) +{ + WSCContextISF *ic = find_ic (context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n"; + if (ic && ic->impl) { + _panel_client.prepare (ic->id); + panel_req_show_factory_menu (ic); + _panel_client.send (); + } +} + +static void +panel_slot_change_factory (int context, const String &uuid) +{ + WSCContextISF *ic = find_ic (context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " factory=" << uuid << " ic=" << ic << "\n"; + if (ic && ic->impl) { + _panel_client.prepare (ic->id); + ic->impl->si->reset (); + open_specific_factory (ic, uuid); + _panel_client.send (); + } +} + +static void +panel_slot_reset_keyboard_ise (int context) +{ + WSCContextISF *ic = find_ic (context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n"; + if (ic && ic->impl) { + WideString wstr = ic->impl->preedit_string; + if (ic->impl->need_commit_preedit) { + _hide_preedit_string (ic->id, false); + + if (wstr.length ()) { + wsc_context_commit_string (ic->ctx, utf8_wcstombs (wstr).c_str ()); + if (!check_valid_ic (ic)) + return; + } + } + _panel_client.prepare (ic->id); + ic->impl->si->reset (); + _panel_client.send (); + } +} + +static void +panel_slot_update_keyboard_ise (int context) +{ + WSCContextISF *ic = find_ic (context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n"; + + _backend->add_module (_config, "socket", false); +} + +static void +panel_slot_show_preedit_string (int context) +{ + WSCContextISF *ic = find_ic (context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << "\n"; + + if (ic && ic->impl && _focused_ic == ic) { + if (!ic->impl->is_on) + ic->impl->is_on = true; + + if (ic->impl->use_preedit) { + if (!ic->impl->preedit_started) { + if (check_valid_ic (ic)) { + ic->impl->preedit_started = true; + ic->impl->need_commit_preedit = true; + } + } + } else { + _panel_client.prepare (ic->id); + _panel_client.show_preedit_string (ic->id); + _panel_client.send (); + } + } +} + +static void +_hide_preedit_string (int context, bool update_preedit) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = find_ic (context); + + if (ic && ic->impl && _focused_ic == ic) { + if (!ic->impl->is_on) + ic->impl->is_on = true; + + bool emit = false; + if (ic->impl->preedit_string.length ()) { + ic->impl->preedit_string = WideString (); + ic->impl->preedit_caret = 0; + ic->impl->preedit_attrlist.clear (); + emit = true; + } + if (ic->impl->use_preedit) { + if (update_preedit && emit) { + if (!check_valid_ic (ic)) + return; + } + if (ic->impl->preedit_started) { + if (check_valid_ic (ic)) { + ic->impl->preedit_started = false; + ic->impl->need_commit_preedit = false; + } + } + wsc_context_send_preedit_string(ic->ctx); + } else { + _panel_client.prepare (ic->id); + _panel_client.hide_preedit_string (ic->id); + _panel_client.send (); + } + } +} + +static void +panel_slot_hide_preedit_string (int context) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + _hide_preedit_string (context, true); +} + +static void +panel_slot_update_preedit_string (int context, + const WideString &str, + const AttributeList &attrs, + int caret) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = find_ic (context); + + if (ic && ic->impl && _focused_ic == ic) { + if (!ic->impl->is_on) + ic->impl->is_on = true; + + if (ic->impl->preedit_string != str || str.length ()) { + ic->impl->preedit_string = str; + ic->impl->preedit_attrlist = attrs; + + if (ic->impl->use_preedit) { + if (!ic->impl->preedit_started) { + if (!check_valid_ic (ic)) + return; + + ic->impl->preedit_started = true; + ic->impl->need_commit_preedit = true; + } + if (caret >= 0 && caret <= (int)str.length ()) + ic->impl->preedit_caret = caret; + else + ic->impl->preedit_caret = str.length (); + ic->impl->preedit_updating = true; + if (check_valid_ic (ic)) + ic->impl->preedit_updating = false; + wsc_context_send_preedit_string(ic->ctx); + } else { + _panel_client.prepare (ic->id); + _panel_client.update_preedit_string (ic->id, str, attrs, caret); + _panel_client.send (); + } + } + } +} + +static void +panel_slot_get_surrounding_text (int context, int maxlen_before, int maxlen_after) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = find_ic (context); + + if (ic && ic->impl && _focused_ic == ic && ic->impl->si) { + int cursor = 0; + WideString text = WideString (); + slot_get_surrounding_text (ic->impl->si, text, cursor, maxlen_before, maxlen_after); + _panel_client.prepare (ic->id); + _panel_client.update_surrounding_text (ic->id, text, cursor); + _panel_client.send (); + } +} + +static void +panel_slot_delete_surrounding_text (int context, int offset, int len) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = find_ic (context); + + if (ic && ic->impl && _focused_ic == ic && ic->impl->si) + slot_delete_surrounding_text (ic->impl->si, offset, len); +} + +static void +panel_slot_update_displayed_candidate_number (int context, int number) +{ + WSCContextISF *ic = find_ic (context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " number=" << number << " ic=" << ic << "\n"; + if (ic && ic->impl && _focused_ic == ic && ic->impl->si) { + _panel_client.prepare (ic->id); + ic->impl->si->update_displayed_candidate_number (number); + _panel_client.send (); + } +} + +static void +panel_slot_candidate_more_window_show (int context) +{ + WSCContextISF *ic = find_ic (context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n"; + if (ic && ic->impl && _focused_ic == ic && ic->impl->si) { + _panel_client.prepare (ic->id); + ic->impl->si->candidate_more_window_show (); + _panel_client.send (); + } +} + +static void +panel_slot_candidate_more_window_hide (int context) +{ + WSCContextISF *ic = find_ic (context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n"; + if (ic && ic->impl && _focused_ic == ic && ic->impl->si) { + _panel_client.prepare (ic->id); + ic->impl->si->candidate_more_window_hide (); + _panel_client.send (); + } +} + +static void +panel_slot_longpress_candidate (int context, int index) +{ + WSCContextISF *ic = find_ic (context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " index=" << index << " ic=" << ic << "\n"; + if (ic && ic->impl && _focused_ic == ic && ic->impl->si) { + _panel_client.prepare (ic->id); + ic->impl->si->longpress_candidate (index); + _panel_client.send (); + } +} + +static void +panel_slot_update_ise_input_context (int context, int type, int value) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; +} + +static void +panel_slot_update_isf_candidate_panel (int context, int type, int value) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; +} + +void +initialize (void) +{ + std::vector config_list; + std::vector engine_list; + std::vector helper_list; + std::vector load_engine_list; + + std::vector::iterator it; + + bool manual = false; + bool socket = true; + String config_module_name = "simple"; + + LOGD ("Initializing Ecore ISF IMModule...\n"); + + // Get system language. + _language = scim_get_locale_language (scim_get_current_locale ()); + + if (socket) { + // If no Socket FrontEnd is running, then launch one. + // And set manual to false. + bool check_result = check_socket_frontend (); + if (!check_result) { + std::cerr << "Launching a ISF daemon with Socket FrontEnd...\n"; + //get modules list + scim_get_imengine_module_list (engine_list); + scim_get_helper_module_list (helper_list); + + for (it = engine_list.begin (); it != engine_list.end (); it++) { + if (*it != "socket") + load_engine_list.push_back (*it); + } + for (it = helper_list.begin (); it != helper_list.end (); it++) + load_engine_list.push_back (*it); + const char *new_argv [] = { "--no-stay", 0 }; + scim_launch (true, + config_module_name, + (load_engine_list.size () > 0 ? scim_combine_string_list (load_engine_list, ',') : "none"), + "socket", + (char **)new_argv); + manual = false; + } + + // If there is one Socket FrontEnd running and it's not manual mode, + // then just use this Socket Frontend. + if (!manual) { + for (int i = 0; i < 200; ++i) { + if (check_result) { + config_module_name = "socket"; + load_engine_list.clear (); + load_engine_list.push_back ("socket"); + break; + } + scim_usleep (50000); + check_result = check_socket_frontend (); + } + } + } + + if (config_module_name != "dummy") { + _config = ConfigBase::get (true, config_module_name); + } + + if (_config.null ()) { + LOGD ("Config module cannot be loaded, using dummy Config.\n"); + _config = new DummyConfig (); + config_module_name = "dummy"; + } + + reload_config_callback (_config); + _config_connection = _config->signal_connect_reload (slot (reload_config_callback)); + + // create backend + _backend = new CommonBackEnd (_config, load_engine_list.size () > 0 ? load_engine_list : engine_list); + + if (_backend.null ()) { + std::cerr << "Cannot create BackEnd Object!\n"; + } else { + _backend->initialize (_config, load_engine_list.size () > 0 ? load_engine_list : engine_list, false, false); + _fallback_factory = _backend->get_factory (SCIM_COMPOSE_KEY_FACTORY_UUID); + } + + if (_fallback_factory.null ()) + _fallback_factory = new DummyIMEngineFactory (); + + _fallback_instance = _fallback_factory->create_instance (String ("UTF-8"), 0); + _fallback_instance->signal_connect_commit_string (slot (fallback_commit_string_cb)); + + // Attach Panel Client signal. + _panel_client.signal_connect_reload_config (slot (panel_slot_reload_config)); + _panel_client.signal_connect_exit (slot (panel_slot_exit)); + _panel_client.signal_connect_update_candidate_item_layout (slot (panel_slot_update_candidate_item_layout)); + _panel_client.signal_connect_update_lookup_table_page_size (slot (panel_slot_update_lookup_table_page_size)); + _panel_client.signal_connect_lookup_table_page_up (slot (panel_slot_lookup_table_page_up)); + _panel_client.signal_connect_lookup_table_page_down (slot (panel_slot_lookup_table_page_down)); + _panel_client.signal_connect_trigger_property (slot (panel_slot_trigger_property)); + _panel_client.signal_connect_process_helper_event (slot (panel_slot_process_helper_event)); + _panel_client.signal_connect_move_preedit_caret (slot (panel_slot_move_preedit_caret)); + _panel_client.signal_connect_update_preedit_caret (slot (panel_slot_update_preedit_caret)); + _panel_client.signal_connect_select_aux (slot (panel_slot_select_aux)); + _panel_client.signal_connect_select_candidate (slot (panel_slot_select_candidate)); + _panel_client.signal_connect_process_key_event (slot (panel_slot_process_key_event)); + _panel_client.signal_connect_commit_string (slot (panel_slot_commit_string)); + _panel_client.signal_connect_forward_key_event (slot (panel_slot_forward_key_event)); + _panel_client.signal_connect_request_help (slot (panel_slot_request_help)); + _panel_client.signal_connect_request_factory_menu (slot (panel_slot_request_factory_menu)); + _panel_client.signal_connect_change_factory (slot (panel_slot_change_factory)); + _panel_client.signal_connect_reset_keyboard_ise (slot (panel_slot_reset_keyboard_ise)); + _panel_client.signal_connect_update_keyboard_ise (slot (panel_slot_update_keyboard_ise)); + _panel_client.signal_connect_show_preedit_string (slot (panel_slot_show_preedit_string)); + _panel_client.signal_connect_hide_preedit_string (slot (panel_slot_hide_preedit_string)); + _panel_client.signal_connect_update_preedit_string (slot (panel_slot_update_preedit_string)); + _panel_client.signal_connect_get_surrounding_text (slot (panel_slot_get_surrounding_text)); + _panel_client.signal_connect_delete_surrounding_text (slot (panel_slot_delete_surrounding_text)); + _panel_client.signal_connect_update_displayed_candidate_number (slot (panel_slot_update_displayed_candidate_number)); + _panel_client.signal_connect_candidate_more_window_show (slot (panel_slot_candidate_more_window_show)); + _panel_client.signal_connect_candidate_more_window_hide (slot (panel_slot_candidate_more_window_hide)); + _panel_client.signal_connect_longpress_candidate (slot (panel_slot_longpress_candidate)); + _panel_client.signal_connect_update_ise_input_context (slot (panel_slot_update_ise_input_context)); + _panel_client.signal_connect_update_isf_candidate_panel (slot (panel_slot_update_isf_candidate_panel)); + + if (!panel_initialize ()) { + std::cerr << "Ecore IM Module: Cannot connect to Panel!\n"; + } +} + +static void +finalize (void) +{ + LOGD ("Finalizing Ecore ISF IMModule...\n"); + + // Reset this first so that the shared instance could be released correctly afterwards. + _default_instance.reset (); + + SCIM_DEBUG_FRONTEND(2) << "Finalize all IC partially.\n"; + while (_used_ic_impl_list) { + // In case in "shared input method" mode, + // all contexts share only one instance, + // so we need point the reference pointer correctly before finalizing. + _used_ic_impl_list->si->set_frontend_data (static_cast (_used_ic_impl_list->parent)); + isf_wsc_context_del (_used_ic_impl_list->parent); + } + + delete_all_ic_impl (); + + _fallback_instance.reset (); + _fallback_factory.reset (); + + SCIM_DEBUG_FRONTEND(2) << " Releasing BackEnd...\n"; + _backend.reset (); + + SCIM_DEBUG_FRONTEND(2) << " Releasing Config...\n"; + _config.reset (); + _config_connection.disconnect (); + + _focused_ic = NULL; + _ic_list = NULL; + + _scim_initialized = false; + + _panel_client.reset_signal_handler (); + panel_finalize (); +} + +static void +_display_input_language (WSCContextISF *ic) +{ +} + +static void +open_next_factory (WSCContextISF *ic) +{ + if (!check_valid_ic (ic)) + return; + + SCIM_DEBUG_FRONTEND(2) << __FUNCTION__ << " context=" << ic->id << "\n"; + IMEngineFactoryPointer sf = _backend->get_next_factory ("", "UTF-8", ic->impl->si->get_factory_uuid ()); + + if (!sf.null ()) { + turn_off_ic (ic); + ic->impl->si = sf->create_instance ("UTF-8", ic->impl->si->get_id ()); + ic->impl->si->set_frontend_data (static_cast (ic)); + ic->impl->preedit_string = WideString (); + ic->impl->preedit_caret = 0; + attach_instance (ic->impl->si); + _backend->set_default_factory (_language, sf->get_uuid ()); + _panel_client.register_input_context (ic->id, sf->get_uuid ()); + _panel_client.set_candidate_style (ic->id, ONE_LINE_CANDIDATE, FIXED_CANDIDATE_WINDOW); + set_ic_capabilities (ic); + turn_on_ic (ic); + + if (_shared_input_method) { + _default_instance = ic->impl->si; + ic->impl->shared_si = true; + } + //_popup_message (utf8_wcstombs (sf->get_name ()).c_str ()); + } +} + +static void +open_previous_factory (WSCContextISF *ic) +{ + if (!check_valid_ic (ic)) + return; + + SCIM_DEBUG_FRONTEND(2) << __FUNCTION__ << " context=" << ic->id << "\n"; + IMEngineFactoryPointer sf = _backend->get_previous_factory ("", "UTF-8", ic->impl->si->get_factory_uuid ()); + + if (!sf.null ()) { + turn_off_ic (ic); + ic->impl->si = sf->create_instance ("UTF-8", ic->impl->si->get_id ()); + ic->impl->si->set_frontend_data (static_cast (ic)); + ic->impl->preedit_string = WideString (); + ic->impl->preedit_caret = 0; + attach_instance (ic->impl->si); + _backend->set_default_factory (_language, sf->get_uuid ()); + _panel_client.register_input_context (ic->id, sf->get_uuid ()); + _panel_client.set_candidate_style (ic->id, ONE_LINE_CANDIDATE, FIXED_CANDIDATE_WINDOW); + set_ic_capabilities (ic); + turn_on_ic (ic); + + if (_shared_input_method) { + _default_instance = ic->impl->si; + ic->impl->shared_si = true; + } + //_popup_message (utf8_wcstombs (sf->get_name ()).c_str ()); + } +} + +static void +open_specific_factory (WSCContextISF *ic, + const String &uuid) +{ + if (!check_valid_ic (ic)) + return; + + SCIM_DEBUG_FRONTEND(2) << __FUNCTION__ << " context=" << ic->id << "\n"; + + // The same input method is selected, just turn on the IC. + if (ic->impl->si->get_factory_uuid () == uuid) { + turn_on_ic (ic); + return; + } + + IMEngineFactoryPointer sf = _backend->get_factory (uuid); + + if (uuid.length () && !sf.null ()) { + turn_off_ic (ic); + ic->impl->si = sf->create_instance ("UTF-8", ic->impl->si->get_id ()); + ic->impl->si->set_frontend_data (static_cast (ic)); + ic->impl->preedit_string = WideString (); + ic->impl->preedit_caret = 0; + attach_instance (ic->impl->si); + _backend->set_default_factory (_language, sf->get_uuid ()); + _panel_client.register_input_context (ic->id, sf->get_uuid ()); + set_ic_capabilities (ic); + turn_on_ic (ic); + + if (_shared_input_method) { + _default_instance = ic->impl->si; + ic->impl->shared_si = true; + } + } else { + std::cerr << "open_specific_factory () is failed!!!!!!\n"; + LOGE ("open_specific_factory () is failed. ic : %x uuid : %s", ic->id, uuid.c_str ()); + + // turn_off_ic comment out panel_req_update_factory_info () + //turn_off_ic (ic); + if (ic && ic->impl->is_on) { + ic->impl->is_on = false; + + if (ic == _focused_ic) { + ic->impl->si->focus_out (); + + panel_req_update_factory_info (ic); + _panel_client.turn_off (ic->id); + } + + //Record the IC on/off status + if (_shared_input_method) { + _config->write (String (SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), false); + _config->flush (); + } + + if (ic->impl->use_preedit && ic->impl->preedit_string.length ()) { + if (!check_valid_ic (ic)) + return; + + if (check_valid_ic (ic)) + ic->impl->preedit_started = false; + } + } + } +} + +#define MOD_SHIFT_MASK 0x01 +#define MOD_ALT_MASK 0x02 +#define MOD_CONTROL_MASK 0x04 + +static uint32_t _keyname_to_keysym(uint32_t keyname, uint32_t *modifiers) +{ + if (!modifiers) + return keyname; + + if ((keyname >= '0' && keyname <= '9') || + (keyname >= 'a' && keyname <= 'z')) { + return keyname; + } + else if (keyname >= 'A' && keyname <= 'Z') { + *modifiers |= MOD_SHIFT_MASK; + return keyname + 32; + } + + switch (keyname) { + case '!': + *modifiers |= MOD_SHIFT_MASK; + return '1'; + case '@': + *modifiers |= MOD_SHIFT_MASK; + return '2'; + case '#': + *modifiers |= MOD_SHIFT_MASK; + return '3'; + case '$': + *modifiers |= MOD_SHIFT_MASK; + return '4'; + case '%': + *modifiers |= MOD_SHIFT_MASK; + return '5'; + case '^': + *modifiers |= MOD_SHIFT_MASK; + return '6'; + case '&': + *modifiers |= MOD_SHIFT_MASK; + return '7'; + case '*': + *modifiers |= MOD_SHIFT_MASK; + return '8'; + case '(': + *modifiers |= MOD_SHIFT_MASK; + return '9'; + case ')': + *modifiers |= MOD_SHIFT_MASK; + return '0'; + case '_': + *modifiers |= MOD_SHIFT_MASK; + return '-'; + case '+': + *modifiers |= MOD_SHIFT_MASK; + return '='; + case '{': + *modifiers |= MOD_SHIFT_MASK; + return '['; + case '}': + *modifiers |= MOD_SHIFT_MASK; + return ']'; + case '|': + *modifiers |= MOD_SHIFT_MASK; + return '\\'; + case '\:': + *modifiers |= MOD_SHIFT_MASK; + return ';'; + case '\"': + *modifiers |= MOD_SHIFT_MASK; + return '\''; + case '<': + *modifiers |= MOD_SHIFT_MASK; + return ','; + case '>': + *modifiers |= MOD_SHIFT_MASK; + return '.'; + case '?': + *modifiers |= MOD_SHIFT_MASK; + return '/'; + default: + return keyname; + } +} + +static void send_wl_key_event (WSCContextISF *ic, const KeyEvent &key, bool fake) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + uint32_t time = 0; + uint32_t sym = 0; + + if (!fake) + time = get_time (); + + uint32_t modifiers = 0; + if (key.is_shift_down ()) + modifiers |= MOD_SHIFT_MASK; + if (key.is_alt_down ()) + modifiers |= MOD_ALT_MASK; + if (key.is_control_down ()) + modifiers |= MOD_CONTROL_MASK; + + sym = _keyname_to_keysym(key.code, &modifiers); + wsc_context_send_key(ic->ctx, sym, modifiers, time, key.is_key_press()); +} + +static void +attach_instance (const IMEngineInstancePointer &si) +{ + si->signal_connect_show_preedit_string ( + slot (slot_show_preedit_string)); + si->signal_connect_show_aux_string ( + slot (slot_show_aux_string)); + si->signal_connect_show_lookup_table ( + slot (slot_show_lookup_table)); + + si->signal_connect_hide_preedit_string ( + slot (slot_hide_preedit_string)); + si->signal_connect_hide_aux_string ( + slot (slot_hide_aux_string)); + si->signal_connect_hide_lookup_table ( + slot (slot_hide_lookup_table)); + + si->signal_connect_update_preedit_caret ( + slot (slot_update_preedit_caret)); + si->signal_connect_update_preedit_string ( + slot (slot_update_preedit_string)); + si->signal_connect_update_aux_string ( + slot (slot_update_aux_string)); + si->signal_connect_update_lookup_table ( + slot (slot_update_lookup_table)); + + si->signal_connect_commit_string ( + slot (slot_commit_string)); + + si->signal_connect_forward_key_event ( + slot (slot_forward_key_event)); + + si->signal_connect_register_properties ( + slot (slot_register_properties)); + + si->signal_connect_update_property ( + slot (slot_update_property)); + + si->signal_connect_beep ( + slot (slot_beep)); + + si->signal_connect_start_helper ( + slot (slot_start_helper)); + + si->signal_connect_stop_helper ( + slot (slot_stop_helper)); + + si->signal_connect_send_helper_event ( + slot (slot_send_helper_event)); + + si->signal_connect_get_surrounding_text ( + slot (slot_get_surrounding_text)); + + si->signal_connect_delete_surrounding_text ( + slot (slot_delete_surrounding_text)); + + si->signal_connect_expand_candidate ( + slot (slot_expand_candidate)); + si->signal_connect_contract_candidate ( + slot (slot_contract_candidate)); + + si->signal_connect_set_candidate_style ( + slot (slot_set_candidate_style)); +} + +// Implementation of slot functions +static void +slot_show_preedit_string (IMEngineInstanceBase *si) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = static_cast (si->get_frontend_data ()); + + if (ic && ic->impl && _focused_ic == ic) { + if (ic->impl->use_preedit) { + if (!ic->impl->preedit_started) { + if (check_valid_ic (ic)) + ic->impl->preedit_started = true; + } + } else { + _panel_client.show_preedit_string (ic->id); + } + } +} + +static void +slot_show_aux_string (IMEngineInstanceBase *si) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = static_cast (si->get_frontend_data ()); + + if (ic && ic->impl && _focused_ic == ic) + _panel_client.show_aux_string (ic->id); +} + +static void +slot_show_lookup_table (IMEngineInstanceBase *si) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = static_cast (si->get_frontend_data ()); + + if (ic && ic->impl && _focused_ic == ic) + _panel_client.show_lookup_table (ic->id); +} + +static void +slot_hide_preedit_string (IMEngineInstanceBase *si) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = static_cast (si->get_frontend_data ()); + + if (ic && ic->impl && _focused_ic == ic) { + bool emit = false; + if (ic->impl->preedit_string.length ()) { + ic->impl->preedit_string = WideString (); + ic->impl->preedit_caret = 0; + ic->impl->preedit_attrlist.clear (); + emit = true; + } + if (ic->impl->use_preedit) { + if (check_valid_ic (ic) && ic->impl->preedit_started) { + if (check_valid_ic (ic)) + ic->impl->preedit_started = false; + } + wsc_context_send_preedit_string(ic->ctx); + } else { + _panel_client.hide_preedit_string (ic->id); + } + } +} + +static void +slot_hide_aux_string (IMEngineInstanceBase *si) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = static_cast (si->get_frontend_data ()); + + if (ic && ic->impl && _focused_ic == ic) + _panel_client.hide_aux_string (ic->id); +} + +static void +slot_hide_lookup_table (IMEngineInstanceBase *si) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = static_cast (si->get_frontend_data ()); + + if (ic && ic->impl && _focused_ic == ic) + _panel_client.hide_lookup_table (ic->id); +} + +static void +slot_update_preedit_caret (IMEngineInstanceBase *si, int caret) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = static_cast (si->get_frontend_data ()); + + if (ic && ic->impl && _focused_ic == ic && ic->impl->preedit_caret != caret) { + ic->impl->preedit_caret = caret; + if (ic->impl->use_preedit) { + if (!ic->impl->preedit_started) { + if (!check_valid_ic (ic)) + return; + + ic->impl->preedit_started = true; + } + } else { + _panel_client.update_preedit_caret (ic->id, caret); + } + } +} + +static void +slot_update_preedit_string (IMEngineInstanceBase *si, + const WideString & str, + const AttributeList & attrs, + int caret) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = static_cast (si->get_frontend_data ()); + + if (ic && ic->impl && _focused_ic == ic && (ic->impl->preedit_string != str || str.length ())) { + ic->impl->preedit_string = str; + ic->impl->preedit_attrlist = attrs; + if (ic->impl->use_preedit) { + if (!ic->impl->preedit_started) { + if (!check_valid_ic (ic)) + return; + + ic->impl->preedit_started = true; + } + if (caret >= 0 && caret <= (int)str.length ()) + ic->impl->preedit_caret = caret; + else + ic->impl->preedit_caret = str.length (); + ic->impl->preedit_updating = true; + if (check_valid_ic (ic)) + ic->impl->preedit_updating = false; + wsc_context_send_preedit_string(ic->ctx); + } else { + _panel_client.update_preedit_string (ic->id, str, attrs, caret); + } + } +} + +static void +slot_update_aux_string (IMEngineInstanceBase *si, + const WideString & str, + const AttributeList & attrs) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = static_cast (si->get_frontend_data ()); + + if (ic && ic->impl && _focused_ic == ic) + _panel_client.update_aux_string (ic->id, str, attrs); +} + +static void +slot_commit_string (IMEngineInstanceBase *si, + const WideString & str) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = static_cast (si->get_frontend_data ()); + + if (ic && ic->ctx) { + if (utf8_wcstombs (str) == String (" ") || utf8_wcstombs (str) == String (" ")) + autoperiod_insert (ic); + + Eina_Bool auto_capitalized = EINA_FALSE; + + if (ic->impl) { + if (wsc_context_input_panel_layout_get (ic->ctx) == ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL && + ic->impl->shift_mode_enabled && + ic->impl->autocapital_type != ECORE_IMF_AUTOCAPITAL_TYPE_NONE && + hw_keyboard_num_get () == 0) { + char converted[2] = {'\0'}; + if (utf8_wcstombs (str).length () == 1) { + Eina_Bool uppercase; + switch (ic->impl->next_shift_status) { + case 0: + uppercase = caps_mode_check (ic, EINA_FALSE, EINA_FALSE); + break; + case SHIFT_MODE_OFF: + uppercase = EINA_FALSE; + ic->impl->next_shift_status = 0; + break; + case SHIFT_MODE_ON: + uppercase = EINA_TRUE; + ic->impl->next_shift_status = 0; + break; + case SHIFT_MODE_LOCK: + uppercase = EINA_TRUE; + break; + default: + uppercase = EINA_FALSE; + } + converted[0] = utf8_wcstombs (str).at (0); + if (uppercase) { + if (converted[0] >= 'a' && converted[0] <= 'z') + converted[0] -= 32; + } else { + if (converted[0] >= 'A' && converted[0] <= 'Z') + converted[0] += 32; + } + + wsc_context_commit_string (ic->ctx, converted); + auto_capitalized = EINA_TRUE; + } + } + } + + if (!auto_capitalized) { + wsc_context_commit_string (ic->ctx, utf8_wcstombs (str).c_str ()); + } + } +} + +static void +slot_forward_key_event (IMEngineInstanceBase *si, + const KeyEvent & key) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = static_cast (si->get_frontend_data ()); + + if (ic && _focused_ic == ic) { + if (!_fallback_instance->process_key_event (key)) { + feed_key_event (ic, key, true); + } + } +} + +static void +slot_update_lookup_table (IMEngineInstanceBase *si, + const LookupTable & table) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = static_cast (si->get_frontend_data ()); + + if (ic && ic->impl && _focused_ic == ic) + _panel_client.update_lookup_table (ic->id, table); +} + +static void +slot_register_properties (IMEngineInstanceBase *si, + const PropertyList & properties) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = static_cast (si->get_frontend_data ()); + + if (ic && ic->impl && _focused_ic == ic) + _panel_client.register_properties (ic->id, properties); +} + +static void +slot_update_property (IMEngineInstanceBase *si, + const Property & property) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = static_cast (si->get_frontend_data ()); + + if (ic && ic->impl && _focused_ic == ic) + _panel_client.update_property (ic->id, property); +} + +static void +slot_beep (IMEngineInstanceBase *si) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = static_cast (si->get_frontend_data ()); +} + +static void +slot_start_helper (IMEngineInstanceBase *si, + const String &helper_uuid) +{ + WSCContextISF *ic = static_cast (si->get_frontend_data ()); + + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " helper= " << helper_uuid << " context=" + << (ic != NULL ? ic->id : -1) << " ic=" << ic + << " ic-uuid=" << ((ic != NULL && ic->impl != NULL) ? ic->impl->si->get_factory_uuid () : "") << "...\n"; + + if (ic && ic->impl) + _panel_client.start_helper (ic->id, helper_uuid); +} + +static void +slot_stop_helper (IMEngineInstanceBase *si, + const String &helper_uuid) +{ + WSCContextISF *ic = static_cast (si->get_frontend_data ()); + + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " helper= " << helper_uuid << " context=" << (ic != NULL ? ic->id : -1) << " ic=" << ic << "...\n"; + + if (ic && ic->impl) + _panel_client.stop_helper (ic->id, helper_uuid); +} + +static void +slot_send_helper_event (IMEngineInstanceBase *si, + const String &helper_uuid, + const Transaction &trans) +{ + WSCContextISF *ic = static_cast (si->get_frontend_data ()); + + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " helper= " << helper_uuid << " context=" + << (ic != NULL ? ic->id : -1) << " ic=" << ic + << " ic-uuid=" << ((ic != NULL && ic->impl != NULL) ? ic->impl->si->get_factory_uuid () : "") << "...\n"; + + if (ic && ic->impl) + _panel_client.send_helper_event (ic->id, helper_uuid, trans); +} + +static bool +slot_get_surrounding_text (IMEngineInstanceBase *si, + WideString &text, + int &cursor, + int maxlen_before, + int maxlen_after) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = static_cast (si->get_frontend_data ()); + + if (ic && ic->impl && _focused_ic == ic) { + char *surrounding = NULL; + int cursor_index; + if (wsc_context_surrounding_get (_focused_ic->ctx, &surrounding, &cursor_index)) { + SCIM_DEBUG_FRONTEND(2) << "Surrounding text: " << surrounding <<"\n"; + SCIM_DEBUG_FRONTEND(2) << "Cursor Index : " << cursor_index <<"\n"; + + if (!surrounding) + return false; + + if (cursor_index < 0) { + free (surrounding); + surrounding = NULL; + return false; + } + + WideString before = utf8_mbstowcs (String (surrounding)); + free (surrounding); + surrounding = NULL; + + if (cursor_index > (int)before.length ()) + return false; + WideString after = before; + before = before.substr (0, cursor_index); + after = after.substr (cursor_index, after.length () - cursor_index); + if (maxlen_before > 0 && ((unsigned int)maxlen_before) < before.length ()) + before = WideString (before.begin () + (before.length () - maxlen_before), before.end ()); + else if (maxlen_before == 0) + before = WideString (); + if (maxlen_after > 0 && ((unsigned int)maxlen_after) < after.length ()) + after = WideString (after.begin (), after.begin () + maxlen_after); + else if (maxlen_after == 0) + after = WideString (); + text = before + after; + cursor = before.length (); + return true; + } + } + return false; +} + +static bool +slot_delete_surrounding_text (IMEngineInstanceBase *si, + int offset, + int len) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = static_cast (si->get_frontend_data ()); + + if (ic && ic->impl && _focused_ic == ic) { + wsc_context_delete_surrounding(_focused_ic->ctx, offset, len); + return true; + } + return false; +} + +static void +slot_expand_candidate (IMEngineInstanceBase *si) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = static_cast (si->get_frontend_data ()); + + if (ic && ic->impl && _focused_ic == ic) + _panel_client.expand_candidate (ic->id); +} + +static void +slot_contract_candidate (IMEngineInstanceBase *si) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = static_cast (si->get_frontend_data ()); + + if (ic && ic->impl && _focused_ic == ic) + _panel_client.contract_candidate (ic->id); +} + +static void +slot_set_candidate_style (IMEngineInstanceBase *si, ISF_CANDIDATE_PORTRAIT_LINE_T portrait_line, ISF_CANDIDATE_MODE_T mode) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + WSCContextISF *ic = static_cast (si->get_frontend_data ()); + + if (ic && ic->impl && _focused_ic == ic) + _panel_client.set_candidate_style (ic->id, portrait_line, mode); +} + +static void +reload_config_callback (const ConfigPointer &config) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + _frontend_hotkey_matcher.load_hotkeys (config); + _imengine_hotkey_matcher.load_hotkeys (config); + + KeyEvent key; + scim_string_to_key (key, + config->read (String (SCIM_CONFIG_HOTKEYS_FRONTEND_VALID_KEY_MASK), + String ("Shift+Control+Alt+Lock"))); + + _valid_key_mask = (key.mask > 0) ? (key.mask) : 0xFFFF; + _valid_key_mask |= SCIM_KEY_ReleaseMask; + // Special treatment for two backslash keys on jp106 keyboard. + _valid_key_mask |= SCIM_KEY_QuirkKanaRoMask; + + _on_the_spot = config->read (String (SCIM_CONFIG_FRONTEND_ON_THE_SPOT), _on_the_spot); + _shared_input_method = config->read (String (SCIM_CONFIG_FRONTEND_SHARED_INPUT_METHOD), _shared_input_method); + + // Get keyboard layout setting + // Flush the global config first, in order to load the new configs from disk. + scim_global_config_flush (); + + _keyboard_layout = scim_get_default_keyboard_layout (); +} + +static void +fallback_commit_string_cb (IMEngineInstanceBase *si, + const WideString &str) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + if (_focused_ic && _focused_ic->impl) { + wsc_context_commit_string (_focused_ic->ctx, utf8_wcstombs (str).c_str ()); + } +} + diff --git a/ism/extras/efl_wsc/isf_wsc_context.h b/ism/extras/efl_wsc/isf_wsc_context.h new file mode 100644 index 0000000..c794501 --- /dev/null +++ b/ism/extras/efl_wsc/isf_wsc_context.h @@ -0,0 +1,71 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ISF_WSC_CONTEXT_H_ +#define __ISF_WSC_CONTEXT_H_ + +#include +#include +#include + +struct weescim; + +const double DOUBLE_SPACE_INTERVAL = 1.0; +const double HIDE_TIMER_INTERVAL = 0.05; +const double WILL_SHOW_TIMER_INTERVAL = 5.0; + +typedef struct _WSCContextISF WSCContextISF; +typedef struct _WSCContextISFImpl WSCContextISFImpl; + +struct _WSCContextISF { + weescim *ctx; + + WSCContextISFImpl *impl; + + int id; /* Input Context id*/ + _WSCContextISF *next; +}; + +EAPI void get_language(char **language); +EAPI int get_panel_client_id (); +EAPI Eina_Bool caps_mode_check (WSCContextISF *ctx, Eina_Bool force, Eina_Bool noti); + +EAPI WSCContextISF *get_focused_ic (); + +EAPI void context_scim_imdata_get (WSCContextISF *ctx, void* data, int* length); +EAPI void imengine_layout_set (WSCContextISF *ctx, Ecore_IMF_Input_Panel_Layout layout); + +EAPI void isf_wsc_context_add (WSCContextISF *ctx); +EAPI void isf_wsc_context_del (WSCContextISF *ctx); +EAPI void isf_wsc_context_focus_in (WSCContextISF *ctx); +EAPI void isf_wsc_context_focus_out (WSCContextISF *ctx); +EAPI void isf_wsc_context_reset (WSCContextISF *ctx); +EAPI void isf_wsc_context_preedit_string_get (WSCContextISF *ctx, char** str, int *cursor_pos); +EAPI void isf_wsc_context_prediction_allow_set (WSCContextISF* ctx, Eina_Bool prediction); + +EAPI WSCContextISF* isf_wsc_context_new (void); +EAPI void isf_wsc_context_shutdown (void); + +bool wsc_context_surrounding_get (weescim *ctx, char **text, int *cursor_pos); +Ecore_IMF_Input_Panel_Layout wsc_context_input_panel_layout_get(weescim *ctx); +bool wsc_context_input_panel_caps_lock_mode_get(weescim *ctx); +void wsc_context_delete_surrounding (weescim *ctx, int offset, int len); +void wsc_context_commit_preedit_string(weescim *ctx); +void wsc_context_commit_string(weescim *ctx, const char *str); +void wsc_context_send_preedit_string(weescim *ctx); +void wsc_context_send_key(weescim *ctx, uint32_t keysym, uint32_t modifiers, uint32_t time, bool press); + +#endif /* __ISF_WSC_CONTEXT_H_ */ diff --git a/ism/extras/efl_wsc/isf_wsc_control.cpp b/ism/extras/efl_wsc/isf_wsc_control.cpp new file mode 100644 index 0000000..8500848 --- /dev/null +++ b/ism/extras/efl_wsc/isf_wsc_control.cpp @@ -0,0 +1,228 @@ +/* + * ISF(Input Service Framework) + * + * ISF is based on SCIM 1.4.7 and extended for supporting more mobile fitable. + * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. + * + * Contact: Jihoon Kim , Haifeng Deng + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define Uses_SCIM_TRANSACTION +#define Uses_ISF_IMCONTROL_CLIENT +#define Uses_SCIM_PANEL_CLIENT + +#include +#include +#include +#include "isf_wsc_control.h" +#include "scim.h" + + +using namespace scim; + + +//#define IMFCONTROLDBG(str...) printf(str) +#define IMFCONTROLDBG(str...) +#define IMFCONTROLERR(str...) printf(str) + + +extern PanelClient _panel_client; + + +int _isf_wsc_context_input_panel_show (int client_id, int context, void *data, int length, bool &input_panel_show) +{ + int temp = 0; + _panel_client.prepare (context); + _panel_client.show_ise (client_id, context, data, length, &temp); + input_panel_show = (bool)temp; + return 0; +} + +int _isf_wsc_context_input_panel_hide (int client_id, int context) +{ + _panel_client.prepare (context); + _panel_client.hide_ise (client_id, context); + _panel_client.send (); + return 0; +} + +int _isf_wsc_context_control_panel_show (int context) +{ + _panel_client.prepare (context); + _panel_client.show_control_panel (); + _panel_client.send (); + return 0; +} + +int _isf_wsc_context_control_panel_hide (int context) +{ + _panel_client.prepare (context); + _panel_client.hide_control_panel (); + _panel_client.send (); + return 0; +} + +int _isf_wsc_context_input_panel_language_set (int context, Ecore_IMF_Input_Panel_Lang lang) +{ + _panel_client.prepare (context); + _panel_client.set_ise_language (lang); + _panel_client.send (); + return 0; +} + +int _isf_wsc_context_input_panel_language_locale_get (int context, char **locale) +{ + _panel_client.prepare (context); + _panel_client.get_ise_language_locale (locale); + return 0; +} + +int _isf_wsc_context_input_panel_imdata_set (int context, const void *data, int len) +{ + _panel_client.prepare (context); + _panel_client.set_imdata ((const char *)data, len); + _panel_client.send (); + return 0; +} + +int _isf_wsc_context_input_panel_imdata_get (int context, void *data, int *len) +{ + _panel_client.prepare (context); + _panel_client.get_imdata ((char *)data, len); + return 0; +} + +int _isf_wsc_context_input_panel_geometry_get (int context, int *x, int *y, int *w, int *h) +{ + _panel_client.prepare (context); + _panel_client.get_ise_window_geometry (x, y, w, h); + return 0; +} + +int _isf_wsc_context_input_panel_return_key_type_set (int context, Ecore_IMF_Input_Panel_Return_Key_Type type) +{ + _panel_client.prepare (context); + _panel_client.set_return_key_type ((int)type); + _panel_client.send (); + return 0; +} + +int _isf_wsc_context_input_panel_return_key_type_get (int context, Ecore_IMF_Input_Panel_Return_Key_Type &type) +{ + int temp = 0; + _panel_client.prepare (context); + _panel_client.get_return_key_type (temp); + type = (Ecore_IMF_Input_Panel_Return_Key_Type)temp; + return 0; +} + +int _isf_wsc_context_input_panel_return_key_disabled_set (int context, Eina_Bool disabled) +{ + _panel_client.prepare (context); + _panel_client.set_return_key_disable ((int)disabled); + _panel_client.send (); + return 0; +} + +int _isf_wsc_context_input_panel_return_key_disabled_get (int context, Eina_Bool &disabled) +{ + int temp = 0; + _panel_client.prepare (context); + _panel_client.get_return_key_disable (temp); + disabled = (Eina_Bool)temp; + return 0; +} + +int _isf_wsc_context_input_panel_layout_set (int context, Ecore_IMF_Input_Panel_Layout layout) +{ + _panel_client.prepare (context); + _panel_client.set_layout (layout); + _panel_client.send (); + return 0; +} + +int _isf_wsc_context_input_panel_layout_get (int context, Ecore_IMF_Input_Panel_Layout *layout) +{ + int layout_temp; + _panel_client.prepare (context); + _panel_client.get_layout (&layout_temp); + + *layout = (Ecore_IMF_Input_Panel_Layout)layout_temp; + return 0; +} + +int _isf_wsc_context_input_panel_state_get (int context, Ecore_IMF_Input_Panel_State &state) +{ + int temp = 0; + _panel_client.prepare (context); + _panel_client.get_ise_state (temp); + + state = (Ecore_IMF_Input_Panel_State)temp; + return 0; +} + +int _isf_wsc_context_input_panel_caps_mode_set (int context, unsigned int mode) +{ + _panel_client.prepare (context); + _panel_client.set_caps_mode (mode); + _panel_client.send (); + return 0; +} + +int _isf_wsc_context_candidate_window_geometry_get (int context, int *x, int *y, int *w, int *h) +{ + _panel_client.prepare (context); + _panel_client.get_candidate_window_geometry (x, y, w, h); + return 0; +} + +int _isf_wsc_context_input_panel_send_will_show_ack (int context) +{ + _panel_client.prepare (context); + _panel_client.send_will_show_ack (); + _panel_client.send (); + return 0; +} + +int _isf_wsc_context_input_panel_send_will_hide_ack (int context) +{ + _panel_client.prepare (context); + _panel_client.send_will_hide_ack (); + _panel_client.send (); + return 0; +} + +int _isf_wsc_context_set_hardware_keyboard_mode (int context) +{ + _panel_client.prepare (context); + _panel_client.set_hardware_keyboard_mode (); + _panel_client.send (); + return 0; +} + +int _isf_wsc_context_input_panel_send_candidate_will_hide_ack (int context) +{ + _panel_client.prepare (context); + _panel_client.send_candidate_will_hide_ack (); + _panel_client.send (); + return 0; +} + +/* +vi:ts=4:expandtab:nowrap +*/ diff --git a/ism/extras/efl_wsc/isf_wsc_control.h b/ism/extras/efl_wsc/isf_wsc_control.h new file mode 100644 index 0000000..70e7958 --- /dev/null +++ b/ism/extras/efl_wsc/isf_wsc_control.h @@ -0,0 +1,69 @@ +/* + * ISF(Input Service Framework) + * + * ISF is based on SCIM 1.4.7 and extended for supporting more mobile fitable. + * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. + * + * Contact: Jihoon Kim , Haifeng Deng + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __ISF_WSC_CONTROL_H +#define __ISF_WSC_CONTROL_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + int _isf_wsc_context_input_panel_show (int client_id, int context, void *data, int length, bool &input_panel_show); + int _isf_wsc_context_input_panel_hide (int client_id, int context); + int _isf_wsc_context_control_panel_show (int context); + int _isf_wsc_context_control_panel_hide (int context); + + int _isf_wsc_context_input_panel_language_set (int context, Ecore_IMF_Input_Panel_Lang lang); + int _isf_wsc_context_input_panel_language_locale_get (int context, char **locale); + + int _isf_wsc_context_input_panel_imdata_set (int context, const void *data, int len); + int _isf_wsc_context_input_panel_imdata_get (int context, void *data, int *len); + int _isf_wsc_context_input_panel_geometry_get (int context, int *x, int *y, int *w, int *h); + int _isf_wsc_context_input_panel_layout_set (int context, Ecore_IMF_Input_Panel_Layout layout); + int _isf_wsc_context_input_panel_layout_get (int context, Ecore_IMF_Input_Panel_Layout *layout); + int _isf_wsc_context_input_panel_state_get (int context, Ecore_IMF_Input_Panel_State &state); + int _isf_wsc_context_input_panel_return_key_type_set (int context, Ecore_IMF_Input_Panel_Return_Key_Type type); + int _isf_wsc_context_input_panel_return_key_type_get (int context, Ecore_IMF_Input_Panel_Return_Key_Type &type); + int _isf_wsc_context_input_panel_return_key_disabled_set (int context, Eina_Bool disabled); + int _isf_wsc_context_input_panel_return_key_disabled_get (int context, Eina_Bool &disabled); + int _isf_wsc_context_input_panel_caps_mode_set (int context, unsigned int mode); + + int _isf_wsc_context_candidate_window_geometry_get (int context, int *x, int *y, int *w, int *h); + + int _isf_wsc_context_input_panel_send_will_show_ack (int context); + int _isf_wsc_context_input_panel_send_will_hide_ack (int context); + + int _isf_wsc_context_set_hardware_keyboard_mode (int context); + + int _isf_wsc_context_input_panel_send_candidate_will_hide_ack (int context); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __ISF_WSC_CONTROL_H */ + diff --git a/ism/extras/efl_wsc/isf_wsc_control_ui.cpp b/ism/extras/efl_wsc/isf_wsc_control_ui.cpp new file mode 100644 index 0000000..106a922 --- /dev/null +++ b/ism/extras/efl_wsc/isf_wsc_control_ui.cpp @@ -0,0 +1,252 @@ +/* + * ISF(Input Service Framework) + * + * ISF is based on SCIM 1.4.7 and extended for supporting more mobile fitable. + * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. + * + * Contact: Jihoon Kim , Haifeng Deng + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define Uses_SCIM_TRANSACTION + + +/* IM control UI part */ +#include +#include +#include +#include +#include +#include "scim.h" +#include "isf_wsc_control_ui.h" +#include "isf_wsc_context.h" +#include "isf_wsc_control.h" +#include "ise_context.h" + +using namespace scim; + +/* IM control related variables */ +static Ise_Context iseContext; +static bool IfInitContext = false; +static unsigned int hw_kbd_num = 0; +WSCContextISF *input_panel_ctx = NULL; + +static void _isf_wsc_context_init (void) +{ + iseContext.language = ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC; + iseContext.return_key_type = ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT; + iseContext.return_key_disabled = FALSE; + iseContext.prediction_allow = TRUE; + + if (!IfInitContext) { + IfInitContext = true; + } +} + +static int _get_context_id (WSCContextISF *ctx) +{ + WSCContextISF *context_scim = ctx; + + if (!context_scim) return -1; + + return context_scim->id; +} + +int hw_keyboard_num_get () +{ + return hw_kbd_num; +} + +void isf_wsc_input_panel_init (void) +{ + //FIXME: Use wl_input protocol to check hw keyboard. + hw_kbd_num = 0; + LOGD ("The number of connected H/W keyboard : %d\n", hw_kbd_num); +} + +void isf_wsc_input_panel_shutdown (void) +{ +} + +void isf_wsc_context_input_panel_show (WSCContextISF* ctx) +{ + int length = -1; + void *packet = NULL; + char imdata[1024] = {0}; + bool input_panel_show = false; + input_panel_ctx = ctx; + + if (IfInitContext == false) { + _isf_wsc_context_init (); + } + + /* set password mode */ + iseContext.password_mode = EINA_FALSE; + + /* set language */ + iseContext.language = ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC; + + /* set layout in ise context info */ + iseContext.layout = wsc_context_input_panel_layout_get (ctx->ctx); + + /* set layout variation in ise context info */ + iseContext.layout_variation = 0; + + /* set prediction allow */ + iseContext.prediction_allow = EINA_TRUE; + + if (iseContext.layout == ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD) + iseContext.password_mode = EINA_TRUE; + + if (iseContext.password_mode) + iseContext.prediction_allow = EINA_FALSE; + + if (iseContext.layout == ECORE_IMF_INPUT_PANEL_LAYOUT_TERMINAL) + iseContext.prediction_allow = EINA_FALSE; + + isf_wsc_context_prediction_allow_set (ctx, iseContext.prediction_allow); + + if (hw_kbd_num != 0) { + LOGD ("H/W keyboard is existed.\n"); + return; + } + + /* set return key type */ + iseContext.return_key_type = ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT; + + /* set return key disabled */ + iseContext.return_key_disabled = EINA_FALSE; + + /* set caps mode */ + iseContext.caps_mode = caps_mode_check (ctx, EINA_TRUE, EINA_FALSE); + + /* set the size of imdata */ + context_scim_imdata_get (ctx, (void *)imdata, &iseContext.imdata_size); + + /* set the cursor position of the editable widget */ + //ecore_imf_context_surrounding_get (ctx, NULL, &iseContext.cursor_pos); + iseContext.cursor_pos = 0; + + iseContext.autocapital_type = ECORE_IMF_AUTOCAPITAL_TYPE_NONE; + + LOGD ("ctx : %p, layout : %d, layout variation : %d\n", ctx, iseContext.layout, iseContext.layout_variation); + LOGD ("language : %d, cursor position : %d, caps mode : %d\n", iseContext.language, iseContext.cursor_pos, iseContext.caps_mode); + LOGD ("return_key_type : %d, return_key_disabled : %d, autocapital type : %d\n", iseContext.return_key_type, iseContext.return_key_disabled, iseContext.autocapital_type); + + /* calculate packet size */ + length = sizeof (iseContext); + length += iseContext.imdata_size; + + /* create packet */ + packet = calloc (1, length); + if (!packet) + return; + + memcpy (packet, (void *)&iseContext, sizeof (iseContext)); + memcpy ((void *)((unsigned int)packet + sizeof (iseContext)), (void *)imdata, iseContext.imdata_size); + + int context_id = _get_context_id (ctx); + + _isf_wsc_context_input_panel_show (get_panel_client_id (), context_id, packet, length, input_panel_show); + + free (packet); + + caps_mode_check (ctx, EINA_TRUE, EINA_TRUE); +} + +void isf_wsc_context_input_panel_hide (WSCContextISF *ctx) +{ + int context_id = _get_context_id (ctx); + _isf_wsc_context_input_panel_hide (get_panel_client_id (), context_id); +} + +void isf_wsc_context_set_hardware_keyboard_mode (WSCContextISF *ctx) +{ + if (IfInitContext == false) { + _isf_wsc_context_init (); + } + + hw_kbd_num = 1; + SECURE_LOGD ("The number of connected H/W keyboard : %d\n", hw_kbd_num); + _isf_wsc_context_set_hardware_keyboard_mode (_get_context_id (ctx)); +} + +void +isf_wsc_context_input_panel_layout_set (WSCContextISF *ctx, Ecore_IMF_Input_Panel_Layout layout) +{ + WSCContextISF *context_scim = ctx; + + if (!IfInitContext) + _isf_wsc_context_init (); + + if (context_scim == get_focused_ic ()) { + LOGD ("layout type : %d\n", layout); + _isf_wsc_context_input_panel_layout_set (_get_context_id (ctx), layout); + imengine_layout_set (ctx, layout); + } +} + +Ecore_IMF_Input_Panel_Layout isf_wsc_context_input_panel_layout_get (WSCContextISF *ctx) +{ + Ecore_IMF_Input_Panel_Layout layout; + if (!IfInitContext) + _isf_wsc_context_init (); + _isf_wsc_context_input_panel_layout_get (_get_context_id (ctx), &layout); + + return layout; +} + +void isf_wsc_context_input_panel_caps_mode_set (WSCContextISF *ctx, unsigned int mode) +{ + if (!IfInitContext) + _isf_wsc_context_init (); + LOGD ("ctx : %p, mode : %d\n", ctx, mode); + _isf_wsc_context_input_panel_caps_mode_set (_get_context_id (ctx), mode); +} + +void isf_wsc_context_input_panel_caps_lock_mode_set (WSCContextISF *ctx, Eina_Bool mode) +{ + WSCContextISF *context_scim = ctx; + + if (!IfInitContext) + _isf_wsc_context_init (); + + if (context_scim == get_focused_ic ()) + caps_mode_check (ctx, EINA_TRUE, EINA_TRUE); +} + +void isf_wsc_context_input_panel_language_set (WSCContextISF *ctx, Ecore_IMF_Input_Panel_Lang language) +{ + WSCContextISF *context_scim = ctx; + + if (!IfInitContext) + _isf_wsc_context_init (); + iseContext.language = language; + + if (context_scim == get_focused_ic ()) { + LOGD ("language mode : %d\n", language); + _isf_wsc_context_input_panel_language_set (_get_context_id (ctx), language); + } +} + +Ecore_IMF_Input_Panel_Lang isf_imf_context_input_panel_language_get (WSCContextISF *ctx) +{ + if (!IfInitContext) + _isf_wsc_context_init (); + return iseContext.language; +} + diff --git a/ism/extras/efl_wsc/isf_wsc_control_ui.h b/ism/extras/efl_wsc/isf_wsc_control_ui.h new file mode 100644 index 0000000..d2dfb37 --- /dev/null +++ b/ism/extras/efl_wsc/isf_wsc_control_ui.h @@ -0,0 +1,56 @@ +/* + * ISF(Input Service Framework) + * + * ISF is based on SCIM 1.4.7 and extended for supporting more mobile fitable. + * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. + * + * Contact: Jihoon Kim , Haifeng Deng + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __ISF_IMF_CONTROL_UI_H +#define __ISF_IMF_CONTROL_UI_H + +#include "isf_wsc_context.h" +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + int hw_keyboard_num_get (); + bool process_update_input_context (int type, int value); + void clear_hide_request (); + + void isf_wsc_input_panel_init (); + void isf_wsc_input_panel_shutdown (); + void isf_wsc_context_input_panel_show (WSCContextISF *ctx); + void isf_wsc_context_input_panel_hide (WSCContextISF *ctx); + void isf_wsc_context_input_panel_language_set (WSCContextISF *ctx, Ecore_IMF_Input_Panel_Lang lang); + Ecore_IMF_Input_Panel_Lang isf_wsc_context_input_panel_language_get (WSCContextISF *ctx); + void isf_wsc_context_input_panel_layout_set (WSCContextISF *ctx, Ecore_IMF_Input_Panel_Layout layout); + Ecore_IMF_Input_Panel_Layout isf_wsc_context_input_panel_layout_get (WSCContextISF *ctx); + void isf_wsc_context_input_panel_caps_mode_set (WSCContextISF *ctx, unsigned int mode); + void isf_wsc_context_input_panel_caps_lock_mode_set (WSCContextISF *ctx, Eina_Bool mode); + void isf_wsc_context_set_hardware_keyboard_mode (WSCContextISF *ctx); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __ISF_IMF_CONTROL_UI_H */ + diff --git a/ism/extras/efl_wsc/isf_wsc_efl.cpp b/ism/extras/efl_wsc/isf_wsc_efl.cpp new file mode 100644 index 0000000..0a082fb --- /dev/null +++ b/ism/extras/efl_wsc/isf_wsc_efl.cpp @@ -0,0 +1,760 @@ +/* + * ISF(Input Service Framework) + * + * ISF is based on SCIM 1.4.7 and extended for supporting more fitable. + * Copyright (c) 2012-2014 Intel Co., Ltd. + * + * Contact: Yan Wang + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define Uses_SCIM_CONFIG_PATH +#define Uses_SCIM_HELPER_MODULE +#define Uses_SCIM_PANEL_AGENT +#define Uses_SCIM_COMPOSE_KEY +#define Uses_SCIM_IMENGINE_MODULE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scim_private.h" +#include "scim.h" +#include "scim_stl_map.h" +#if HAVE_VCONF +#include +#include +#endif +#include +#include + +#include +#include +#include +#include "input-method-client-protocol.h" +#include "text-client-protocol.h" +#include "isf_wsc_context.h" +#include "isf_wsc_control_ui.h" +#include "scim_stl_map.h" + +using namespace scim; + +#if SCIM_USE_STL_EXT_HASH_MAP + typedef __gnu_cxx::hash_map > KeycodeRepository; +#elif SCIM_USE_STL_HASH_MAP + typedef std::hash_map > KeycodeRepository; +#else + typedef std::map KeycodeRepository; +#endif + +static KeycodeRepository _keysym2keycode; + +///////////////////////////////////////////////////////////////////////////// +// Declaration of macro. +///////////////////////////////////////////////////////////////////////////// +#define LOG_TAG "ISF_WSC_EFL" + +/* This structure stores the wayland input method information */ +struct weescim; + +#define MOD_SHIFT_MASK 0x01 +#define MOD_ALT_MASK 0x02 +#define MOD_CONTROL_MASK 0x04 + +typedef void (*keyboard_input_key_handler_t)(struct weescim *wsc, + uint32_t serial, + uint32_t time, uint32_t key, uint32_t unicode, + enum wl_keyboard_key_state state); + +struct weescim +{ + struct wl_input_method *im; + struct wl_input_method_context *im_ctx; + struct wl_seat *seat; + struct wl_keyboard *keyboard; + + struct xkb_context *xkb_context; + + uint32_t modifiers; + + struct xkb_keymap *keymap; + struct xkb_state *state; + xkb_mod_mask_t control_mask; + xkb_mod_mask_t alt_mask; + xkb_mod_mask_t shift_mask; + + keyboard_input_key_handler_t key_handler; + + char *surrounding_text; + char *preedit_str; + char *language; + + uint32_t serial; + uint32_t text_direction; + uint32_t preedit_style; + uint32_t content_hint; + uint32_t content_purpose; + uint32_t surrounding_cursor; + + Eina_Bool context_changed; + Eina_Bool hw_kbd; + + WSCContextISF *wsc_ctx; +}; +static struct weescim _wsc = {0}; + +static char * +append(char *s1, const char *s2) +{ + int len1, len2; + char *s; + + len1 = strlen(s1); + len2 = strlen(s2); + s = (char*)realloc(s1, len1 + len2 + 1); + memcpy(s + len1, s2, len2); + s[len1 + len2] = '\0'; + + return s; +} + +static char * +insert_text(const char *text, uint32_t offset, const char *insert) +{ + int tlen = strlen(text), ilen = strlen(insert); + char *new_text = (char*)malloc(tlen + ilen + 1); + + memcpy(new_text, text, offset); + memcpy(new_text + offset, insert, ilen); + memcpy(new_text + offset + ilen, text + offset, tlen - offset); + new_text[tlen + ilen] = '\0'; + + return new_text; +} + +static void +wsc_commit_preedit(weescim *ctx) +{ + char *surrounding_text; + + if (!ctx->preedit_str || + strlen(ctx->preedit_str) == 0) + return; + + wl_input_method_context_cursor_position(ctx->im_ctx, + 0, 0); + wl_input_method_context_commit_string(ctx->im_ctx, + ctx->serial, + ctx->preedit_str); + + if (ctx->surrounding_text) { + surrounding_text = insert_text(ctx->surrounding_text, + ctx->surrounding_cursor, + ctx->preedit_str); + free(ctx->surrounding_text); + ctx->surrounding_text = surrounding_text; + ctx->surrounding_cursor += strlen(ctx->preedit_str); + } else { + ctx->surrounding_text = strdup(ctx->preedit_str); + ctx->surrounding_cursor = strlen(ctx->preedit_str); + } + + free(ctx->preedit_str); + ctx->preedit_str = strdup(""); +} + +static void +wsc_send_preedit(weescim *ctx, int32_t cursor) +{ + uint32_t index = strlen(ctx->preedit_str); + + if (ctx->preedit_style) + wl_input_method_context_preedit_styling(ctx->im_ctx, + 0, + strlen(ctx->preedit_str), + ctx->preedit_style); + if (cursor > 0) + index = cursor; + wl_input_method_context_preedit_cursor(ctx->im_ctx, index); + wl_input_method_context_preedit_string(ctx->im_ctx, + ctx->serial, + ctx->preedit_str, + ctx->preedit_str); +} + +bool wsc_context_surrounding_get(weescim *ctx, char **text, int *cursor_pos) +{ + if (!ctx) + return false; + + *text = strdup (ctx->surrounding_text); + *cursor_pos = ctx->surrounding_cursor; + return true; +} + +Ecore_IMF_Input_Panel_Layout wsc_context_input_panel_layout_get(weescim *ctx) +{ + Ecore_IMF_Input_Panel_Layout layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL; + + switch (ctx->content_purpose) { + case WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS: + case WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER: + case WL_TEXT_INPUT_CONTENT_PURPOSE_DATE: + case WL_TEXT_INPUT_CONTENT_PURPOSE_TIME: + case WL_TEXT_INPUT_CONTENT_PURPOSE_DATETIME: + layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBER; + break; + case WL_TEXT_INPUT_CONTENT_PURPOSE_PHONE: + layout = ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER; + break; + case WL_TEXT_INPUT_CONTENT_PURPOSE_URL: + layout = ECORE_IMF_INPUT_PANEL_LAYOUT_URL; + break; + case WL_TEXT_INPUT_CONTENT_PURPOSE_EMAIL: + layout = ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL; + break; + case WL_TEXT_INPUT_CONTENT_PURPOSE_PASSWORD: + layout = ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD; + break; + default: + layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL; + break; + } + + return layout; +} + +bool wsc_context_input_panel_caps_lock_mode_get(weescim *ctx) +{ + if (ctx->content_hint & WL_TEXT_INPUT_CONTENT_HINT_UPPERCASE) + return true; + + return false; +} + +void wsc_context_delete_surrounding (weescim *ctx, int offset, int len) +{ + if (!ctx) + return; + + wl_input_method_context_delete_surrounding_text(ctx->im_ctx, offset, len); +} + +void wsc_context_commit_string(weescim *ctx, const char *str) +{ + if (ctx->preedit_str) { + free(ctx->preedit_str); + ctx->preedit_str = NULL; + } + + ctx->preedit_str = strdup (str); + wsc_commit_preedit(ctx); +} + +void wsc_context_commit_preedit_string(weescim *ctx) +{ + char *preedit_str = NULL; + int cursor_pos = 0; + + isf_wsc_context_preedit_string_get(ctx->wsc_ctx, &preedit_str, &cursor_pos); + if (ctx->preedit_str) { + free(ctx->preedit_str); + ctx->preedit_str = NULL; + } + + ctx->preedit_str = preedit_str; + wsc_commit_preedit(ctx); +} + +void wsc_context_send_preedit_string(weescim *ctx) +{ + char *preedit_str = NULL; + int cursor_pos = 0; + + isf_wsc_context_preedit_string_get(ctx->wsc_ctx, &preedit_str, &cursor_pos); + if (ctx->preedit_str) { + free(ctx->preedit_str); + ctx->preedit_str = NULL; + } + + ctx->preedit_str = preedit_str; + wsc_send_preedit(ctx, cursor_pos); +} + +void wsc_context_send_key(weescim *ctx, uint32_t keysym, uint32_t modifiers, uint32_t time, bool press) +{ + uint32_t keycode; + KeycodeRepository::iterator it = _keysym2keycode.find(keysym); + + if(it == _keysym2keycode.end()) + return; + + keycode = it->second; + ctx->modifiers = modifiers; + + if (press) { + if (ctx->modifiers) { + wl_input_method_context_modifiers(ctx->im_ctx, ctx->serial, + ctx->modifiers, 0, 0, 0); + } + + wl_input_method_context_key(ctx->im_ctx, ctx->serial, time, + keycode, WL_KEYBOARD_KEY_STATE_PRESSED); + } + else { + wl_input_method_context_key(ctx->im_ctx, ctx->serial, time, + keycode, WL_KEYBOARD_KEY_STATE_RELEASED); + + if (ctx->modifiers) { + wl_input_method_context_modifiers(ctx->im_ctx, ctx->serial, + 0, 0, 0, 0); + } + } +} + +///////////////////////////////////////////////////////////////////////////// +// Implementation of Wayland Input Method functions. +///////////////////////////////////////////////////////////////////////////// +static void +_wsc_im_ctx_surrounding_text(void *data, struct wl_input_method_context *im_ctx, const char *text, uint32_t cursor, uint32_t anchor) +{ + struct weescim *wsc = (weescim*)data; + + free (wsc->surrounding_text); + wsc->surrounding_text = strdup (text); + wsc->surrounding_cursor = cursor; +} + +static void +_wsc_im_ctx_reset(void *data, struct wl_input_method_context *im_ctx) +{ + struct weescim *wsc = (weescim*)data; + + isf_wsc_context_reset(wsc->wsc_ctx); +} + +static void +_wsc_im_ctx_content_type(void *data, struct wl_input_method_context *im_ctx, uint32_t hint, uint32_t purpose) +{ + struct weescim *wsc = (weescim*)data; + Ecore_IMF_Input_Panel_Layout layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL; + + ISF_LOG ("im_context = %p hint = %d purpose = %d", im_ctx, hint, purpose); + + if (!wsc->context_changed) + return; + + wsc->content_hint = hint; + wsc->content_purpose = purpose; + + isf_wsc_context_input_panel_layout_set (wsc->wsc_ctx, + wsc_context_input_panel_layout_get (wsc)); + + caps_mode_check(wsc->wsc_ctx, EINA_TRUE, EINA_TRUE); + + //FIXME: process hint like layout. + + wsc->context_changed = EINA_FALSE; +} + +static void +_wsc_im_ctx_invoke_action(void *data, struct wl_input_method_context *im_ctx, uint32_t button, uint32_t index) +{ + struct weescim *wsc = (weescim*)data; + + if (button != BTN_LEFT) + return; + + wsc_context_send_preedit_string (wsc); +} + +static void +_wsc_im_ctx_commit_state(void *data, struct wl_input_method_context *im_ctx, uint32_t serial) +{ + struct weescim *wsc = (weescim*)data; + + wsc->serial = serial; + + if (wsc->surrounding_text) + ISF_LOG ("Surrounding text updated: %s", wsc->surrounding_text); + + if(wsc->language) + wl_input_method_context_language (im_ctx, wsc->serial, wsc->language); + + wl_input_method_context_text_direction (im_ctx, wsc->serial, wsc->text_direction); +} + +static void +_wsc_im_ctx_preferred_language(void *data, struct wl_input_method_context *im_ctx, const char *language) +{ + struct weescim *wsc = (weescim*)data; + + if (language && wsc->language && !strcmp (language, wsc->language)) + return; + + if (wsc->language) { + free (wsc->language); + wsc->language = NULL; + } + + if (language) { + wsc->language = strdup (language); + ISF_LOG ("Language changed, new: '%s'", language); + } +} + +static const struct wl_input_method_context_listener wsc_im_context_listener = { + _wsc_im_ctx_surrounding_text, + _wsc_im_ctx_reset, + _wsc_im_ctx_content_type, + _wsc_im_ctx_invoke_action, + _wsc_im_ctx_commit_state, + _wsc_im_ctx_preferred_language, +}; + +static void +_init_keysym2keycode(struct weescim *wsc) +{ + uint32_t i = 0; + uint32_t code; + uint32_t num_syms; + const xkb_keysym_t *syms; + + if (!wsc->state) + return; + + for (i = 0; i < 256; i++) { + code = i + 8; + num_syms = xkb_key_get_syms(wsc->state, code, &syms); + + if (num_syms == 1) + _keysym2keycode[syms[0]] = i; + } +} + +static void +_fini_keysym2keycode(struct weescim *wsc) +{ + _keysym2keycode.clear(); +} + +static void +_wsc_im_keyboard_keymap(void *data, + struct wl_keyboard *wl_keyboard, + uint32_t format, + int32_t fd, + uint32_t size) +{ + struct weescim *wsc = (weescim*)data; + char *map_str; + + _fini_keysym2keycode(wsc); + + if (wsc->state) { + xkb_state_unref(wsc->state); + wsc->state = NULL; + } + + if (wsc->keymap) { + xkb_map_unref(wsc->keymap); + wsc->keymap = NULL; + } + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + close(fd); + return; + } + + map_str = (char*)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (map_str == MAP_FAILED) { + close(fd); + return; + } + + wsc->keymap = + xkb_map_new_from_string(wsc->xkb_context, + map_str, + XKB_KEYMAP_FORMAT_TEXT_V1, + (xkb_keymap_compile_flags)0); + + munmap(map_str, size); + close(fd); + + if (!wsc->keymap) { + fprintf(stderr, "failed to compile keymap\n"); + return; + } + + wsc->state = xkb_state_new(wsc->keymap); + if (!wsc->state) { + fprintf(stderr, "failed to create XKB state\n"); + xkb_map_unref(wsc->keymap); + return; + } + + wsc->control_mask = + 1 << xkb_map_mod_get_index(wsc->keymap, "Control"); + wsc->alt_mask = + 1 << xkb_map_mod_get_index(wsc->keymap, "Mod1"); + wsc->shift_mask = + 1 << xkb_map_mod_get_index(wsc->keymap, "Shift"); + + fprintf(stderr, "create _keysym2keycode\n"); + _init_keysym2keycode(wsc); +} + +static void +_wsc_im_keyboard_key(void *data, + struct wl_keyboard *wl_keyboard, + uint32_t serial, + uint32_t time, + uint32_t key, + uint32_t state_w) +{ + struct weescim *wsc = (weescim*)data; + uint32_t code; + uint32_t num_syms; + const xkb_keysym_t *syms; + xkb_keysym_t sym; + enum wl_keyboard_key_state state = (wl_keyboard_key_state)state_w; + + if (!wsc->state) + return; + + code = key + 8; + num_syms = xkb_key_get_syms(wsc->state, code, &syms); + + sym = XKB_KEY_NoSymbol; + if (num_syms == 1) + sym = syms[0]; + + if (wsc->key_handler) + (*wsc->key_handler)(wsc, serial, time, key, sym, + state); +} + +static void +_wsc_im_keyboard_modifiers(void *data, + struct wl_keyboard *wl_keyboard, + uint32_t serial, + uint32_t mods_depressed, + uint32_t mods_latched, + uint32_t mods_locked, + uint32_t group) +{ + struct weescim *wsc = (weescim*)data; + struct wl_input_method_context *context = wsc->im_ctx; + xkb_mod_mask_t mask; + + if (!wsc->state) + return; + + xkb_state_update_mask(wsc->state, mods_depressed, + mods_latched, mods_locked, 0, 0, group); + mask = xkb_state_serialize_mods(wsc->state, + (xkb_state_component)(XKB_STATE_DEPRESSED | XKB_STATE_LATCHED)); + + wsc->modifiers = 0; + if (mask & wsc->control_mask) + wsc->modifiers |= MOD_CONTROL_MASK; + if (mask & wsc->alt_mask) + wsc->modifiers |= MOD_ALT_MASK; + if (mask & wsc->shift_mask) + wsc->modifiers |= MOD_SHIFT_MASK; + + wl_input_method_context_modifiers(context, serial, + mods_depressed, mods_depressed, + mods_latched, group); +} + +static const struct wl_keyboard_listener wsc_im_keyboard_listener = { + _wsc_im_keyboard_keymap, + NULL, /* enter */ + NULL, /* leave */ + _wsc_im_keyboard_key, + _wsc_im_keyboard_modifiers +}; + +static void +_wsc_im_activate(void *data, struct wl_input_method *input_method, struct wl_input_method_context *im_ctx) +{ + struct weescim *wsc = (weescim*)data; + + if (wsc->im_ctx) + wl_input_method_context_destroy (wsc->im_ctx); + + if (wsc->preedit_str) + free (wsc->preedit_str); + + wsc->preedit_str = strdup (""); + wsc->content_hint = WL_TEXT_INPUT_CONTENT_HINT_NONE; + wsc->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NORMAL; + + free (wsc->language); + wsc->language = NULL; + + free (wsc->surrounding_text); + wsc->surrounding_text = NULL; + + wsc->im_ctx = im_ctx; + wl_input_method_context_add_listener (im_ctx, &wsc_im_context_listener, wsc); + + wsc->keyboard = wl_input_method_context_grab_keyboard(im_ctx); + wl_keyboard_add_listener(wsc->keyboard, &wsc_im_keyboard_listener, wsc); + + wsc->context_changed = EINA_TRUE; + isf_wsc_context_focus_in (wsc->wsc_ctx); + isf_wsc_context_input_panel_show (wsc->wsc_ctx); +} + +static void +_wsc_im_deactivate(void *data, struct wl_input_method *input_method, struct wl_input_method_context *im_ctx) +{ + struct weescim *wsc = (weescim*)data; + + isf_wsc_context_input_panel_hide (wsc->wsc_ctx); + isf_wsc_context_focus_out (wsc->wsc_ctx); + + if (wsc->im_ctx) { + wl_input_method_context_destroy(wsc->im_ctx); + wsc->im_ctx = NULL; + } +} + +static const struct wl_input_method_listener wsc_im_listener = { + _wsc_im_activate, + _wsc_im_deactivate +}; + +static void +_wsc_seat_handle_capabilities(void *data, struct wl_seat *seat, + uint32_t caps) +{ + struct weescim *wsc = (weescim*)data; + + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD)) { + wsc->hw_kbd = true; + } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD)) { + wsc->hw_kbd = false; + } +} + +static const struct wl_seat_listener wsc_seat_listener = { + _wsc_seat_handle_capabilities, +}; + +static void +_wsc_im_key_handler(struct weescim *wsc, + uint32_t serial, uint32_t time, uint32_t key, uint32_t sym, + enum wl_keyboard_key_state state) +{ +} + +static void +_wsc_setup(struct weescim *wsc) +{ + struct wl_list *globals; + struct wl_registry *registry; + Ecore_Wl_Global *global; + + wsc->xkb_context = xkb_context_new((xkb_context_flags)0); + if (wsc->xkb_context == NULL) { + fprintf(stderr, "Failed to create XKB context\n"); + return; + } + + wsc->key_handler = _wsc_im_key_handler; + + wsc->wsc_ctx = isf_wsc_context_new (); + wsc->wsc_ctx->ctx = wsc; + + get_language(&wsc->language); + + if (!(registry = ecore_wl_registry_get())) + return; + + if (!(globals = (wl_list*)ecore_wl_globals_get())) + return; + + EINA_INLIST_FOREACH(globals, global) { + if (strcmp (global->interface, "wl_input_method") == 0) + wsc->im = (wl_input_method*)wl_registry_bind (registry, global->id, &wl_input_method_interface, 1); + else if (strcmp (global->interface, "wl_seat") == 0) + wsc->seat = (wl_seat*)wl_registry_bind (registry, global->id, &wl_seat_interface, 1); + } + + /* Input method listener */ + ISF_LOG ("Adding wl_input_method listener"); + wl_input_method_add_listener (wsc->im, &wsc_im_listener, wsc); + + wl_seat_add_listener(wsc->seat, &wsc_seat_listener, wsc); + + isf_wsc_context_add (wsc->wsc_ctx); +} + +static void +_wsc_free(struct weescim *wsc) +{ + _fini_keysym2keycode(wsc); + + if (wsc->state) { + xkb_state_unref(wsc->state); + wsc->state = NULL; + } + + if (wsc->keymap) { + xkb_map_unref(wsc->keymap); + wsc->keymap = NULL; + } + + if (wsc->im_ctx) + wl_input_method_context_destroy (wsc->im_ctx); + + isf_wsc_context_del(wsc->wsc_ctx); + isf_wsc_context_shutdown (); + + free (wsc->preedit_str); + free (wsc->surrounding_text); +} + +int main (int argc EINA_UNUSED, char **argv EINA_UNUSED) +{ + sleep(1); + + _wsc_setup(&_wsc); + + ecore_main_loop_begin(); + + _wsc_free(&_wsc); + + return 0; +} + +/* +vi:ts=4:nowrap:expandtab +*/ diff --git a/ism/extras/efl_wsc/text-client-protocol.h b/ism/extras/efl_wsc/text-client-protocol.h new file mode 100644 index 0000000..b8da964 --- /dev/null +++ b/ism/extras/efl_wsc/text-client-protocol.h @@ -0,0 +1,543 @@ +/* + * Copyright © 2012, 2013 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this + * software and its documentation for any purpose is hereby granted + * without fee, provided that the above copyright notice appear in + * all copies and that both that copyright notice and this permission + * notice appear in supporting documentation, and that the name of + * the copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + * THIS SOFTWARE. + */ + +#ifndef TEXT_CLIENT_PROTOCOL_H +#define TEXT_CLIENT_PROTOCOL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "wayland-client.h" + +struct wl_client; +struct wl_resource; + +struct wl_text_input; +struct wl_text_input_manager; + +extern const struct wl_interface wl_text_input_interface; +extern const struct wl_interface wl_text_input_manager_interface; + +#ifndef WL_TEXT_INPUT_CONTENT_HINT_ENUM +#define WL_TEXT_INPUT_CONTENT_HINT_ENUM +/** + * wl_text_input_content_hint - content hint + * @WL_TEXT_INPUT_CONTENT_HINT_NONE: no special behaviour + * @WL_TEXT_INPUT_CONTENT_HINT_DEFAULT: auto completion, correction and + * capitalization + * @WL_TEXT_INPUT_CONTENT_HINT_PASSWORD: hidden and sensitive text + * @WL_TEXT_INPUT_CONTENT_HINT_AUTO_COMPLETION: suggest word completions + * @WL_TEXT_INPUT_CONTENT_HINT_AUTO_CORRECTION: suggest word corrections + * @WL_TEXT_INPUT_CONTENT_HINT_AUTO_CAPITALIZATION: switch to uppercase + * letters at the start of a sentence + * @WL_TEXT_INPUT_CONTENT_HINT_LOWERCASE: prefer lowercase letters + * @WL_TEXT_INPUT_CONTENT_HINT_UPPERCASE: prefer uppercase letters + * @WL_TEXT_INPUT_CONTENT_HINT_TITLECASE: prefer casing for titles and + * headings (can be language dependent) + * @WL_TEXT_INPUT_CONTENT_HINT_HIDDEN_TEXT: characters should be hidden + * @WL_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA: typed text should not be + * stored + * @WL_TEXT_INPUT_CONTENT_HINT_LATIN: just latin characters should be + * entered + * @WL_TEXT_INPUT_CONTENT_HINT_MULTILINE: the text input is multiline + * + * Content hint is a bitmask to allow to modify the behavior of the text + * input. + */ +enum wl_text_input_content_hint { + WL_TEXT_INPUT_CONTENT_HINT_NONE = 0x0, + WL_TEXT_INPUT_CONTENT_HINT_DEFAULT = 0x7, + WL_TEXT_INPUT_CONTENT_HINT_PASSWORD = 0xc0, + WL_TEXT_INPUT_CONTENT_HINT_AUTO_COMPLETION = 0x1, + WL_TEXT_INPUT_CONTENT_HINT_AUTO_CORRECTION = 0x2, + WL_TEXT_INPUT_CONTENT_HINT_AUTO_CAPITALIZATION = 0x4, + WL_TEXT_INPUT_CONTENT_HINT_LOWERCASE = 0x8, + WL_TEXT_INPUT_CONTENT_HINT_UPPERCASE = 0x10, + WL_TEXT_INPUT_CONTENT_HINT_TITLECASE = 0x20, + WL_TEXT_INPUT_CONTENT_HINT_HIDDEN_TEXT = 0x40, + WL_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA = 0x80, + WL_TEXT_INPUT_CONTENT_HINT_LATIN = 0x100, + WL_TEXT_INPUT_CONTENT_HINT_MULTILINE = 0x200, +}; +#endif /* WL_TEXT_INPUT_CONTENT_HINT_ENUM */ + +#ifndef WL_TEXT_INPUT_CONTENT_PURPOSE_ENUM +#define WL_TEXT_INPUT_CONTENT_PURPOSE_ENUM +/** + * wl_text_input_content_purpose - content purpose + * @WL_TEXT_INPUT_CONTENT_PURPOSE_NORMAL: default input, allowing all + * characters + * @WL_TEXT_INPUT_CONTENT_PURPOSE_ALPHA: allow only alphabetic characters + * @WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS: allow only digits + * @WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER: input a number (including + * decimal separator and sign) + * @WL_TEXT_INPUT_CONTENT_PURPOSE_PHONE: input a phone number + * @WL_TEXT_INPUT_CONTENT_PURPOSE_URL: input an URL + * @WL_TEXT_INPUT_CONTENT_PURPOSE_EMAIL: input an email address + * @WL_TEXT_INPUT_CONTENT_PURPOSE_NAME: input a name of a person + * @WL_TEXT_INPUT_CONTENT_PURPOSE_PASSWORD: input a password (combine + * with password or sensitive_data hint) + * @WL_TEXT_INPUT_CONTENT_PURPOSE_DATE: input a date + * @WL_TEXT_INPUT_CONTENT_PURPOSE_TIME: input a time + * @WL_TEXT_INPUT_CONTENT_PURPOSE_DATETIME: input a date and time + * @WL_TEXT_INPUT_CONTENT_PURPOSE_TERMINAL: input for a terminal + * + * The content purpose allows to specify the primary purpose of a text + * input. + * + * This allows an input method to show special purpose input panels with + * extra characters or to disallow some characters. + */ +enum wl_text_input_content_purpose { + WL_TEXT_INPUT_CONTENT_PURPOSE_NORMAL = 0, + WL_TEXT_INPUT_CONTENT_PURPOSE_ALPHA = 1, + WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS = 2, + WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER = 3, + WL_TEXT_INPUT_CONTENT_PURPOSE_PHONE = 4, + WL_TEXT_INPUT_CONTENT_PURPOSE_URL = 5, + WL_TEXT_INPUT_CONTENT_PURPOSE_EMAIL = 6, + WL_TEXT_INPUT_CONTENT_PURPOSE_NAME = 7, + WL_TEXT_INPUT_CONTENT_PURPOSE_PASSWORD = 8, + WL_TEXT_INPUT_CONTENT_PURPOSE_DATE = 9, + WL_TEXT_INPUT_CONTENT_PURPOSE_TIME = 10, + WL_TEXT_INPUT_CONTENT_PURPOSE_DATETIME = 11, + WL_TEXT_INPUT_CONTENT_PURPOSE_TERMINAL = 12, +}; +#endif /* WL_TEXT_INPUT_CONTENT_PURPOSE_ENUM */ + +#ifndef WL_TEXT_INPUT_PREEDIT_STYLE_ENUM +#define WL_TEXT_INPUT_PREEDIT_STYLE_ENUM +enum wl_text_input_preedit_style { + WL_TEXT_INPUT_PREEDIT_STYLE_DEFAULT = 0, + WL_TEXT_INPUT_PREEDIT_STYLE_NONE = 1, + WL_TEXT_INPUT_PREEDIT_STYLE_ACTIVE = 2, + WL_TEXT_INPUT_PREEDIT_STYLE_INACTIVE = 3, + WL_TEXT_INPUT_PREEDIT_STYLE_HIGHLIGHT = 4, + WL_TEXT_INPUT_PREEDIT_STYLE_UNDERLINE = 5, + WL_TEXT_INPUT_PREEDIT_STYLE_SELECTION = 6, + WL_TEXT_INPUT_PREEDIT_STYLE_INCORRECT = 7, +}; +#endif /* WL_TEXT_INPUT_PREEDIT_STYLE_ENUM */ + +#ifndef WL_TEXT_INPUT_TEXT_DIRECTION_ENUM +#define WL_TEXT_INPUT_TEXT_DIRECTION_ENUM +enum wl_text_input_text_direction { + WL_TEXT_INPUT_TEXT_DIRECTION_AUTO = 0, + WL_TEXT_INPUT_TEXT_DIRECTION_LTR = 1, + WL_TEXT_INPUT_TEXT_DIRECTION_RTL = 2, +}; +#endif /* WL_TEXT_INPUT_TEXT_DIRECTION_ENUM */ + +/** + * wl_text_input - text input + * @enter: enter event + * @leave: leave event + * @modifiers_map: modifiers map + * @input_panel_state: state of the input panel + * @preedit_string: pre-edit + * @preedit_styling: pre-edit styling + * @preedit_cursor: pre-edit cursor + * @commit_string: commit + * @cursor_position: set cursor to new position + * @delete_surrounding_text: delete surrounding text + * @keysym: keysym + * @language: language + * @text_direction: text direction + * + * An object used for text input. Adds support for text input and input + * methods to applications. A text-input object is created from a + * wl_text_input_manager and corresponds typically to a text entry in an + * application. Requests are used to activate/deactivate the text-input + * object and set state information like surrounding and selected text or + * the content type. The information about entered text is sent to the + * text-input object via the pre-edit and commit events. Using this + * interface removes the need for applications to directly process hardware + * key events and compose text out of them. + * + * Text is generally UTF-8 encoded, indices and lengths are in bytes. + * + * Serials are used to synchronize the state between the text input and an + * input method. New serials are sent by the text input in the commit_state + * request and are used by the input method to indicate the known text + * input state in events like preedit_string, commit_string, and keysym. + * The text input can then ignore events from the input method which are + * based on an outdated state (for example after a reset). + */ +struct wl_text_input_listener { + /** + * enter - enter event + * @surface: (none) + * + * Notify the text-input object when it received focus. Typically + * in response to an activate request. + */ + void (*enter)(void *data, + struct wl_text_input *wl_text_input, + struct wl_surface *surface); + /** + * leave - leave event + * + * Notify the text-input object when it lost focus. Either in + * response to a deactivate request or when the assigned surface + * lost focus or was destroyed. + */ + void (*leave)(void *data, + struct wl_text_input *wl_text_input); + /** + * modifiers_map - modifiers map + * @map: (none) + * + * Transfer an array of 0-terminated modifiers names. The + * position in the array is the index of the modifier as used in + * the modifiers bitmask in the keysym event. + */ + void (*modifiers_map)(void *data, + struct wl_text_input *wl_text_input, + struct wl_array *map); + /** + * input_panel_state - state of the input panel + * @state: (none) + * + * Notify when the visibility state of the input panel changed. + */ + void (*input_panel_state)(void *data, + struct wl_text_input *wl_text_input, + uint32_t state); + /** + * preedit_string - pre-edit + * @serial: serial of the latest known text input state + * @text: (none) + * @commit: (none) + * + * Notify when a new composing text (pre-edit) should be set + * around the current cursor position. Any previously set composing + * text should be removed. + * + * The commit text can be used to replace the preedit text on reset + * (for example on unfocus). + * + * The text input should also handle all preedit_style and + * preedit_cursor events occuring directly before preedit_string. + */ + void (*preedit_string)(void *data, + struct wl_text_input *wl_text_input, + uint32_t serial, + const char *text, + const char *commit); + /** + * preedit_styling - pre-edit styling + * @index: (none) + * @length: (none) + * @style: (none) + * + * Sets styling information on composing text. The style is + * applied for length bytes from index relative to the beginning of + * the composing text (as byte offset). Multiple styles can be + * applied to a composing text by sending multiple preedit_styling + * events. + * + * This event is handled as part of a following preedit_string + * event. + */ + void (*preedit_styling)(void *data, + struct wl_text_input *wl_text_input, + uint32_t index, + uint32_t length, + uint32_t style); + /** + * preedit_cursor - pre-edit cursor + * @index: (none) + * + * Sets the cursor position inside the composing text (as byte + * offset) relative to the start of the composing text. When index + * is a negative number no cursor is shown. + * + * This event is handled as part of a following preedit_string + * event. + */ + void (*preedit_cursor)(void *data, + struct wl_text_input *wl_text_input, + int32_t index); + /** + * commit_string - commit + * @serial: serial of the latest known text input state + * @text: (none) + * + * Notify when text should be inserted into the editor widget. + * The text to commit could be either just a single character after + * a key press or the result of some composing (pre-edit). It could + * be also an empty text when some text should be removed (see + * delete_surrounding_text) or when the input cursor should be + * moved (see cursor_position). + * + * Any previously set composing text should be removed. + */ + void (*commit_string)(void *data, + struct wl_text_input *wl_text_input, + uint32_t serial, + const char *text); + /** + * cursor_position - set cursor to new position + * @index: (none) + * @anchor: (none) + * + * Notify when the cursor or anchor position should be modified. + * + * This event should be handled as part of a following + * commit_string event. + */ + void (*cursor_position)(void *data, + struct wl_text_input *wl_text_input, + int32_t index, + int32_t anchor); + /** + * delete_surrounding_text - delete surrounding text + * @index: (none) + * @length: (none) + * + * Notify when the text around the current cursor position should + * be deleted. + * + * Index is relative to the current cursor (in bytes). Length is + * the length of deleted text (in bytes). + * + * This event should be handled as part of a following + * commit_string event. + */ + void (*delete_surrounding_text)(void *data, + struct wl_text_input *wl_text_input, + int32_t index, + uint32_t length); + /** + * keysym - keysym + * @serial: serial of the latest known text input state + * @time: (none) + * @sym: (none) + * @state: (none) + * @modifiers: (none) + * + * Notify when a key event was sent. Key events should not be + * used for normal text input operations, which should be done with + * commit_string, delete_surrounding_text, etc. The key event + * follows the wl_keyboard key event convention. Sym is a XKB + * keysym, state a wl_keyboard key_state. Modifiers are a mask for + * effective modifiers (where the modifier indices are set by the + * modifiers_map event) + */ + void (*keysym)(void *data, + struct wl_text_input *wl_text_input, + uint32_t serial, + uint32_t time, + uint32_t sym, + uint32_t state, + uint32_t modifiers); + /** + * language - language + * @serial: serial of the latest known text input state + * @language: (none) + * + * Sets the language of the input text. The "language" argument + * is a RFC-3066 format language tag. + */ + void (*language)(void *data, + struct wl_text_input *wl_text_input, + uint32_t serial, + const char *language); + /** + * text_direction - text direction + * @serial: serial of the latest known text input state + * @direction: (none) + * + * Sets the text direction of input text. + * + * It is mainly needed for showing input cursor on correct side of + * the editor when there is no input yet done and making sure + * neutral direction text is laid out properly. + */ + void (*text_direction)(void *data, + struct wl_text_input *wl_text_input, + uint32_t serial, + uint32_t direction); +}; + +static inline int +wl_text_input_add_listener(struct wl_text_input *wl_text_input, + const struct wl_text_input_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wl_text_input, + (void (**)(void)) listener, data); +} + +#define WL_TEXT_INPUT_ACTIVATE 0 +#define WL_TEXT_INPUT_DEACTIVATE 1 +#define WL_TEXT_INPUT_SHOW_INPUT_PANEL 2 +#define WL_TEXT_INPUT_HIDE_INPUT_PANEL 3 +#define WL_TEXT_INPUT_RESET 4 +#define WL_TEXT_INPUT_SET_SURROUNDING_TEXT 5 +#define WL_TEXT_INPUT_SET_CONTENT_TYPE 6 +#define WL_TEXT_INPUT_SET_CURSOR_RECTANGLE 7 +#define WL_TEXT_INPUT_SET_PREFERRED_LANGUAGE 8 +#define WL_TEXT_INPUT_COMMIT_STATE 9 +#define WL_TEXT_INPUT_INVOKE_ACTION 10 + +static inline void +wl_text_input_set_user_data(struct wl_text_input *wl_text_input, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_text_input, user_data); +} + +static inline void * +wl_text_input_get_user_data(struct wl_text_input *wl_text_input) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_text_input); +} + +static inline void +wl_text_input_destroy(struct wl_text_input *wl_text_input) +{ + wl_proxy_destroy((struct wl_proxy *) wl_text_input); +} + +static inline void +wl_text_input_activate(struct wl_text_input *wl_text_input, struct wl_seat *seat, struct wl_surface *surface) +{ + wl_proxy_marshal((struct wl_proxy *) wl_text_input, + WL_TEXT_INPUT_ACTIVATE, seat, surface); +} + +static inline void +wl_text_input_deactivate(struct wl_text_input *wl_text_input, struct wl_seat *seat) +{ + wl_proxy_marshal((struct wl_proxy *) wl_text_input, + WL_TEXT_INPUT_DEACTIVATE, seat); +} + +static inline void +wl_text_input_show_input_panel(struct wl_text_input *wl_text_input) +{ + wl_proxy_marshal((struct wl_proxy *) wl_text_input, + WL_TEXT_INPUT_SHOW_INPUT_PANEL); +} + +static inline void +wl_text_input_hide_input_panel(struct wl_text_input *wl_text_input) +{ + wl_proxy_marshal((struct wl_proxy *) wl_text_input, + WL_TEXT_INPUT_HIDE_INPUT_PANEL); +} + +static inline void +wl_text_input_reset(struct wl_text_input *wl_text_input) +{ + wl_proxy_marshal((struct wl_proxy *) wl_text_input, + WL_TEXT_INPUT_RESET); +} + +static inline void +wl_text_input_set_surrounding_text(struct wl_text_input *wl_text_input, const char *text, uint32_t cursor, uint32_t anchor) +{ + wl_proxy_marshal((struct wl_proxy *) wl_text_input, + WL_TEXT_INPUT_SET_SURROUNDING_TEXT, text, cursor, anchor); +} + +static inline void +wl_text_input_set_content_type(struct wl_text_input *wl_text_input, uint32_t hint, uint32_t purpose) +{ + wl_proxy_marshal((struct wl_proxy *) wl_text_input, + WL_TEXT_INPUT_SET_CONTENT_TYPE, hint, purpose); +} + +static inline void +wl_text_input_set_cursor_rectangle(struct wl_text_input *wl_text_input, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal((struct wl_proxy *) wl_text_input, + WL_TEXT_INPUT_SET_CURSOR_RECTANGLE, x, y, width, height); +} + +static inline void +wl_text_input_set_preferred_language(struct wl_text_input *wl_text_input, const char *language) +{ + wl_proxy_marshal((struct wl_proxy *) wl_text_input, + WL_TEXT_INPUT_SET_PREFERRED_LANGUAGE, language); +} + +static inline void +wl_text_input_commit_state(struct wl_text_input *wl_text_input, uint32_t serial) +{ + wl_proxy_marshal((struct wl_proxy *) wl_text_input, + WL_TEXT_INPUT_COMMIT_STATE, serial); +} + +static inline void +wl_text_input_invoke_action(struct wl_text_input *wl_text_input, uint32_t button, uint32_t index) +{ + wl_proxy_marshal((struct wl_proxy *) wl_text_input, + WL_TEXT_INPUT_INVOKE_ACTION, button, index); +} + +#define WL_TEXT_INPUT_MANAGER_CREATE_TEXT_INPUT 0 + +static inline void +wl_text_input_manager_set_user_data(struct wl_text_input_manager *wl_text_input_manager, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_text_input_manager, user_data); +} + +static inline void * +wl_text_input_manager_get_user_data(struct wl_text_input_manager *wl_text_input_manager) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_text_input_manager); +} + +static inline void +wl_text_input_manager_destroy(struct wl_text_input_manager *wl_text_input_manager) +{ + wl_proxy_destroy((struct wl_proxy *) wl_text_input_manager); +} + +static inline struct wl_text_input * +wl_text_input_manager_create_text_input(struct wl_text_input_manager *wl_text_input_manager) +{ + struct wl_proxy *id; + + id = wl_proxy_create((struct wl_proxy *) wl_text_input_manager, + &wl_text_input_interface); + if (!id) + return NULL; + + wl_proxy_marshal((struct wl_proxy *) wl_text_input_manager, + WL_TEXT_INPUT_MANAGER_CREATE_TEXT_INPUT, id); + + return (struct wl_text_input *) id; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ism/extras/efl_wsc/text-protocol.c b/ism/extras/efl_wsc/text-protocol.c new file mode 100644 index 0000000..3906811 --- /dev/null +++ b/ism/extras/efl_wsc/text-protocol.c @@ -0,0 +1,94 @@ +/* + * Copyright © 2012, 2013 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this + * software and its documentation for any purpose is hereby granted + * without fee, provided that the above copyright notice appear in + * all copies and that both that copyright notice and this permission + * notice appear in supporting documentation, and that the name of + * the copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + * THIS SOFTWARE. + */ + +#include +#include +#include "wayland-util.h" + +extern const struct wl_interface wl_seat_interface; +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface wl_seat_interface; +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface wl_text_input_interface; + +static const struct wl_interface *types[] = { + NULL, + NULL, + NULL, + NULL, + NULL, + &wl_seat_interface, + &wl_surface_interface, + &wl_seat_interface, + &wl_surface_interface, + &wl_text_input_interface, +}; + +static const struct wl_message wl_text_input_requests[] = { + { "activate", "oo", types + 5 }, + { "deactivate", "o", types + 7 }, + { "show_input_panel", "", types + 0 }, + { "hide_input_panel", "", types + 0 }, + { "reset", "", types + 0 }, + { "set_surrounding_text", "suu", types + 0 }, + { "set_content_type", "uu", types + 0 }, + { "set_cursor_rectangle", "iiii", types + 0 }, + { "set_preferred_language", "s", types + 0 }, + { "commit_state", "u", types + 0 }, + { "invoke_action", "uu", types + 0 }, +}; + +static const struct wl_message wl_text_input_events[] = { + { "enter", "o", types + 8 }, + { "leave", "", types + 0 }, + { "modifiers_map", "a", types + 0 }, + { "input_panel_state", "u", types + 0 }, + { "preedit_string", "uss", types + 0 }, + { "preedit_styling", "uuu", types + 0 }, + { "preedit_cursor", "i", types + 0 }, + { "commit_string", "us", types + 0 }, + { "cursor_position", "ii", types + 0 }, + { "delete_surrounding_text", "iu", types + 0 }, + { "keysym", "uuuuu", types + 0 }, + { "language", "us", types + 0 }, + { "text_direction", "uu", types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_text_input_interface = { + "wl_text_input", 1, + 11, wl_text_input_requests, + 13, wl_text_input_events, +}; + +static const struct wl_message wl_text_input_manager_requests[] = { + { "create_text_input", "n", types + 9 }, +}; + +WL_EXPORT const struct wl_interface wl_text_input_manager_interface = { + "wl_text_input_manager", 1, + 1, wl_text_input_manager_requests, + 0, NULL, +}; + diff --git a/ism/extras/efl_wsm/Makefile.am b/ism/extras/efl_wsm/Makefile.am new file mode 100644 index 0000000..65a7033 --- /dev/null +++ b/ism/extras/efl_wsm/Makefile.am @@ -0,0 +1,41 @@ +MAINTAINERCLEANFILES = Makefile.in +CLEANFILES = *.bak *.edj + +INCLUDES = -I$(top_builddir) \ + -I$(top_builddir)/ism/src \ + -I$(top_srcdir) \ + -I$(top_srcdir)/ism/src \ + -I$(top_srcdir)/ism/intl \ + -I$(top_srcdir)/ism/data \ + -I$(top_srcdir)/ism/utils \ + -I$(includedir) \ + -DSCIM_DATADIR=\"@SCIM_DATADIR@\" \ + -DSCIM_LOCALEDIR=\"@SCIM_LOCALEDIR@\" \ + -DSCIM_SYSCONFDIR=\"@SCIM_SYSCONFDIR@\" \ + -DSCIM_LIBEXECDIR=\"@SCIM_LIBEXECDIR@\" \ + -DSCIM_ICONDIR=\"@SCIM_ICONDIR@\" \ + -DSCIM_MODULE_PATH=\"@SCIM_MODULE_PATH@\" \ + -DSCIM_TEMPDIR=\"@SCIM_TEMPDIR@\" + +noinst_HEADERS = isf_wsm_utility.h + +if ISF_BUILD_WSM_EFL +CONFIG_WSM_EFL = isf-wsm-efl +endif + +bin_PROGRAMS = $(CONFIG_WSM_EFL) + +isf_wsm_efl_SOURCES = isf_wsm_efl.cpp \ + isf_wsm_utility.cpp + +isf_wsm_efl_CXXFLAGS = @EFL_CFLAGS@ @VCONF_CFLAGS@ @DLOG_CFLAGS@ @TTS_CFLAGS@ @FEEDBACK_CFLAGS@ + +isf_wsm_efl_LDFLAGS = @EFL_LIBS@ @LTLIBINTL@ -rpath $(libdir) \ + @VCONF_LIBS@ \ + @WAYLAND_LIBS@ \ + @DLOG_LIBS@ \ + @TTS_LIBS@ \ + @FEEDBACK_LIBS@ + +isf_wsm_efl_LDADD = $(top_builddir)/ism/src/libscim@SCIM_EPOCH@.la + diff --git a/ism/extras/efl_wsm/isf_wsm_efl.cpp b/ism/extras/efl_wsm/isf_wsm_efl.cpp new file mode 100644 index 0000000..2120f54 --- /dev/null +++ b/ism/extras/efl_wsm/isf_wsm_efl.cpp @@ -0,0 +1,4537 @@ +/* + * ISF(Input Service Framework) + * + * ISF is based on SCIM 1.4.7 and extended for supporting more fitable. + * Copyright (c) 2012-2014 Intel Co., Ltd. + * + * Contact: Yan Wang + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define Uses_SCIM_CONFIG_PATH +#define Uses_SCIM_HELPER_MODULE +#define Uses_SCIM_PANEL_AGENT +#define Uses_SCIM_COMPOSE_KEY +#define Uses_SCIM_IMENGINE_MODULE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scim_private.h" +#include "scim.h" +#include "scim_stl_map.h" +#if HAVE_VCONF +#include +#include +#endif +#include +#include "isf_wsm_utility.h" +#include +#if HAVE_TTS +#include +#endif +#if HAVE_FEEDBACK +#include +#endif + +using namespace scim; + + +///////////////////////////////////////////////////////////////////////////// +// Declaration of macro. +///////////////////////////////////////////////////////////////////////////// +#define EFL_CANDIDATE_THEME1 (SCIM_DATADIR "/isf_candidate_theme1.edj") + +#define ISF_CANDIDATE_TABLE 0 + +#define ISF_EFL_AUX 1 +#define ISF_EFL_CANDIDATE_0 2 +#define ISF_EFL_CANDIDATE_ITEMS 3 + +#define ISE_DEFAULT_HEIGHT_PORTRAIT 444 +#define ISE_DEFAULT_HEIGHT_LANDSCAPE 316 + +#define ISF_SYSTEM_APPSERVICE_READY_VCONF "memory/appservice/status" +#define ISF_SYSTEM_APPSERVICE_READY_STATE 1 +#define ISF_SYSTEM_WM_WAIT_COUNT 200 +#define ISF_SYSTEM_WAIT_DELAY 100 * 1000 +#define ISF_CANDIDATE_DESTROY_DELAY 3 + +#define ISF_PREEDIT_BORDER 16 + +#define LOG_TAG "ISF_WSM_EFL" + +///////////////////////////////////////////////////////////////////////////// +// Declaration of external variables. +///////////////////////////////////////////////////////////////////////////// +extern MapStringVectorSizeT _groups; +extern std::vector _uuids; +extern std::vector _names; +extern std::vector _module_names; +extern std::vector _langs; +extern std::vector _icons; +extern std::vector _options; +extern std::vector _modes; + +extern EAPI CommonLookupTable g_isf_candidate_table; + + +///////////////////////////////////////////////////////////////////////////// +// Declaration of internal data types. +///////////////////////////////////////////////////////////////////////////// +typedef enum _WINDOW_STATE { + WINDOW_STATE_HIDE = 0, + WINDOW_STATE_WILL_HIDE, + WINDOW_STATE_WILL_SHOW, + WINDOW_STATE_SHOW, + WINDOW_STATE_ON, +} WINDOW_STATE; + +typedef std::map OSPEmRepository; + + +///////////////////////////////////////////////////////////////////////////// +// Declaration of internal functions. +///////////////////////////////////////////////////////////////////////////// +static Evas_Object *efl_create_window (const char *strWinName, const char *strEffect); +static void efl_set_transient_for_app_window (Ecore_X_Window window); +static int efl_get_angle_for_app_window (void); +static int efl_get_angle_for_ise_window (void); + +static int ui_candidate_get_valid_height (void); +static void ui_candidate_hide (bool bForce, bool bSetVirtualKbd = true, bool will_hide = false); +static void ui_destroy_candidate_window (void); +static void ui_settle_candidate_window (void); +static void ui_candidate_show (bool bSetVirtualKbd = true); +static void ui_create_candidate_window (void); +static void update_table (int table_type, const LookupTable &table); +static void ui_candidate_window_close_button_cb (void *data, Evas *e, Evas_Object *button, void *event_info); + +static bool check_wm_ready (void); +static bool check_system_ready (void); +static void launch_default_soft_keyboard (keynode_t *key = NULL, void* data = NULL); + +/* PanelAgent related functions */ +static bool initialize_panel_agent (const String &config, const String &display, bool resident); + +static void slot_reload_config (void); +static void slot_focus_in (void); +static void slot_focus_out (void); +static void slot_expand_candidate (void); +static void slot_contract_candidate (void); +static void slot_set_candidate_style (int portrait_line, int mode); +static void slot_update_input_context (int type, int value); +static void slot_update_ise_geometry (int x, int y, int width, int height); +static void slot_update_spot_location (int x, int y, int top_y); +static void slot_update_factory_info (const PanelFactoryInfo &info); +static void slot_show_preedit_string (void); +static void slot_show_aux_string (void); +static void slot_show_candidate_table (void); +static void slot_hide_preedit_string (void); +static void slot_hide_aux_string (void); +static void slot_hide_candidate_table (void); +static void slot_update_preedit_string (const String &str, const AttributeList &attrs, int caret); +static void slot_update_preedit_caret (int caret); +static void slot_update_aux_string (const String &str, const AttributeList &attrs); +static void slot_update_candidate_table (const LookupTable &table); +static void slot_select_candidate (int index); +static void slot_set_active_ise (const String &uuid, bool changeDefault); +static bool slot_get_ise_list (std::vector &list); +static bool slot_get_ise_information (String uuid, String &name, String &language, int &type, int &option, String &module_name); +static bool slot_get_keyboard_ise_list (std::vector &name_list); +static void slot_get_language_list (std::vector &name); +static void slot_get_all_language (std::vector &lang); +static void slot_get_ise_language (char *name, std::vector &list); +static bool slot_get_ise_info (const String &uuid, ISE_INFO &info); +static void slot_get_candidate_geometry (struct rectinfo &info); +static void slot_get_input_panel_geometry (struct rectinfo &info); +static void slot_set_keyboard_ise (const String &uuid); +static void slot_get_keyboard_ise (String &ise_name, String &ise_uuid); +static void slot_accept_connection (int fd); +static void slot_close_connection (int fd); +static void slot_exit (void); + +static void slot_register_helper_properties (int id, const PropertyList &props); +static void slot_show_ise (void); +static void slot_hide_ise (void); + +static void slot_will_hide_ack (void); +static void slot_candidate_will_hide_ack (void); + +static void slot_get_ise_state (int &state); + +static Eina_Bool panel_agent_handler (void *data, Ecore_Fd_Handler *fd_handler); + +static Eina_Bool efl_create_control_window (void); +static void _launch_default_soft_keyboard (void); + +///////////////////////////////////////////////////////////////////////////// +// Declaration of internal variables. +///////////////////////////////////////////////////////////////////////////// +static Evas_Object *_candidate_window = 0; +static Evas_Object *_candidate_area_1 = 0; +static Evas_Object *_candidate_area_2 = 0; +static Evas_Object *_candidate_bg = 0; +static Evas_Object *_candidate_0_scroll = 0; +static Evas_Object *_candidate_scroll = 0; +static Evas_Object *_scroller_bg = 0; +static Evas_Object *_candidate_0_table = 0; +static Evas_Object *_candidate_table = 0; +static Evas_Object *_candidate_0 [SCIM_LOOKUP_TABLE_MAX_PAGESIZE]; +static Evas_Object *_candidate_items [SCIM_LOOKUP_TABLE_MAX_PAGESIZE]; +static Evas_Object *_seperate_0 [SCIM_LOOKUP_TABLE_MAX_PAGESIZE]; +static Evas_Object *_seperate_items [SCIM_LOOKUP_TABLE_MAX_PAGESIZE]; +static Evas_Object *_line_0 [SCIM_LOOKUP_TABLE_MAX_PAGESIZE]; +static Evas_Object *_line_items [SCIM_LOOKUP_TABLE_MAX_PAGESIZE]; +static Evas_Object *_more_btn = 0; +static Evas_Object *_close_btn = 0; +static bool _candidate_show_requested = false; + +static int _candidate_x = 0; +static int _candidate_y = 0; +static int _candidate_width = 0; +static int _candidate_height = 0; +static int _candidate_valid_height = 0; + +static bool _candidate_area_1_visible = false; +static bool _candidate_area_2_visible = false; +static bool _aux_area_visible = false; + +static ISF_CANDIDATE_MODE_T _candidate_mode = SOFT_CANDIDATE_WINDOW; +static ISF_CANDIDATE_PORTRAIT_LINE_T _candidate_port_line = ONE_LINE_CANDIDATE; + +static int _candidate_port_width = 480; +static int _candidate_port_height_min = 76; +static int _candidate_port_height_min_2 = 150; +static int _candidate_port_height_max = 286; +static int _candidate_port_height_max_2 = 350; +static int _candidate_land_width = 784; +static int _candidate_land_height_min = 84; +static int _candidate_land_height_min_2 = 168; +static int _candidate_land_height_max = 150; +static int _candidate_land_height_max_2 = 214; +static int _candidate_area_1_pos [2] = {0, 2}; +static int _more_btn_pos [4] = {369, 11, 689, 11}; +static int _close_btn_pos [4] = {362, 211, 682, 75}; + +static int _v_padding = 2; +static int _item_min_width = 99; +static int _item_min_height = 82; + +static int _candidate_scroll_0_width_min = 350; +static int _candidate_scroll_0_width_max = 670; + +static int _candidate_scroll_width = 453; +static int _candidate_scroll_width_min = 453; +static int _candidate_scroll_width_max = 663; +static int _candidate_scroll_height_min = 124; +static int _candidate_scroll_height_max = 190; + +static Evas_Object *_preedit_window = 0; +static Evas_Object *_preedit_text = 0; +static int _preedit_width = 100; +static int _preedit_height = 54; + +static Evas_Object *_aux_area = 0; +static Evas_Object *_aux_line = 0; +static Evas_Object *_aux_table = 0; +static int _aux_height = 0; +static int _aux_port_width = 444; +static int _aux_land_width = 764; +static std::vector _aux_items; +static std::vector _aux_seperates; + +static Evas_Object *_tmp_preedit_text = 0; +static Evas_Object *_tmp_aux_text = 0; +static Evas_Object *_tmp_candidate_text = 0; + +static int _spot_location_x = -1; +static int _spot_location_y = -1; +static int _spot_location_top_y = -1; +static int _candidate_angle = 0; +static int _window_angle = -1; + +static int _ise_width = 0; +static int _ise_height = 0; +static WINDOW_STATE _ise_state = WINDOW_STATE_HIDE; +static WINDOW_STATE _candidate_state = WINDOW_STATE_HIDE; + +static int _indicator_height = 0;//24; +static int _screen_width = 720; +static int _screen_height = 1280; +static float _width_rate = 1.0; +static float _height_rate = 1.0; +static int _blank_width = 30; + +static String _candidate_name = String ("candidate"); +static String _candidate_edje_file = String (EFL_CANDIDATE_THEME1); + +static String _candidate_font_name = String ("Tizen"); +static int _candidate_font_size = 38; +static int _aux_font_size = 38; +static int _click_object = 0; +static int _click_down_pos [2] = {0, 0}; +static int _click_up_pos [2] = {0, 0}; +static bool _is_click = true; +static bool _appsvc_callback_regist = false; +static String _initial_ise_uuid = String (""); +static ConfigPointer _config; +static PanelAgent *_panel_agent = 0; +static std::vector _read_handler_list; + +static clock_t _clock_start; + +static Ecore_Timer *_check_size_timer = NULL; +static Ecore_Timer *_longpress_timer = NULL; +static Ecore_Timer *_destroy_timer = NULL; +static Ecore_Timer *_system_ready_timer = NULL; +static Ecore_Timer *_off_prepare_done_timer = NULL; +static Ecore_Timer *_candidate_hide_timer = NULL; + +static Ecore_X_Window _ise_window = 0; +static Ecore_X_Window _app_window = 0; +static Ecore_X_Window _control_window = 0; + +static Ecore_File_Monitor *_inh_helper_ise_em = NULL; +static Ecore_File_Monitor *_inh_keyboard_ise_em = NULL; +static Ecore_File_Monitor *_osp_helper_ise_em = NULL; +static Ecore_File_Monitor *_osp_keyboard_ise_em = NULL; +static OSPEmRepository _osp_bin_em; +static OSPEmRepository _osp_info_em; + +static bool hw_kbd_mode = false; + +#if HAVE_TTS +static tts_h _tts = NULL; +#endif + +#if HAVE_FEEDBACK +static bool feedback_initialized = false; +#endif + +static Ecore_Event_Handler *_candidate_show_handler = NULL; + +/* This structure stores the geometry information reported by ISE */ +struct GeometryCache +{ + bool valid; /* Whether this information is currently valid */ + int angle; /* For which angle this information is useful */ + struct rectinfo geometry; /* Geometry information */ +}; +static struct GeometryCache _ise_reported_geometry = {0}; + +///////////////////////////////////////////////////////////////////////////// +// Implementation of internal functions. +///////////////////////////////////////////////////////////////////////////// +/** + * @brief Print system time point for panel performance. + * + * @param strInfo The output information. + */ +static void check_time (const char *strInfo) +{ + gettime (_clock_start, strInfo); + ISF_LOG ("%s ppid=%d pid=%d\n", strInfo, getppid (), getpid ()); +} + +/** + * @brief Check the specific file. + * + * @param strFile The file path. + * + * @return true if the file is existed, otherwise false. + */ +static bool check_file (const char* strFile) +{ + struct stat st; + + /* Workaround so that "/" returns a true, otherwise we can't monitor "/" in ecore_file_monitor */ + if (stat (strFile, &st) < 0 && strcmp (strFile, "/")) + return false; + else + return true; +} + +/** + * @brief Flush memory for elm. + * + * @return void + */ +static void flush_memory (void) +{ + elm_cache_all_flush (); + malloc_trim (0); +} + +/** + * @brief Get ISE geometry information. + * Returns the "expected" ISE geometry when kbd_state is ON, otherwise w/h set to 0 + * + * @param info The data is used to store ISE position and size. + * @param kbd_state The keyboard state. + */ +static struct rectinfo get_ise_geometry () +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + struct rectinfo info = {0, 0, 0, 0}; + + int win_w = _screen_width, win_h = _screen_height; + int angle = (_window_angle == -1) ? efl_get_angle_for_app_window () : _window_angle; + + if (angle == 90 || angle == 270) { + win_w = _screen_height; + win_h = _screen_width; + } + + /* If we have geometry reported by ISE, use the geometry information */ + if (_ise_reported_geometry.valid && _ise_reported_geometry.angle == angle) { + info = _ise_reported_geometry.geometry; + } else { + /* READ ISE's SIZE HINT HERE */ + int pos_x, pos_y, width, height; + + // FIXME: Get the ISE's SIZE. + pos_x = 0; + pos_y = 0; + width = 0; + height = 0; + + info.pos_x = pos_x; + info.pos_y = pos_y; + info.width = width; + info.height = height; + } + _ise_width = info.width; + _ise_height = info.height; + + return info; +} + +/** + * @brief Set keyboard geometry for autoscroll. + * This includes the ISE geometry together with candidate window + * + * @param kbd_state The keyboard state. + */ +static void set_keyboard_geometry_atom_info (Ecore_X_Window window, struct rectinfo ise_rect) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + if (hw_kbd_mode) { + ise_rect.pos_x = 0; + if (_candidate_window && _candidate_state == WINDOW_STATE_SHOW) { + ise_rect.width = _candidate_width; + ise_rect.height = _candidate_height; + } + int angle = efl_get_angle_for_app_window (); + if (angle == 90 || angle == 270) + ise_rect.pos_y = _screen_width - ise_rect.height; + else + ise_rect.pos_y = _screen_height - ise_rect.height; + } else { + if (_candidate_mode == FIXED_CANDIDATE_WINDOW) { + if (_candidate_window && _candidate_state == WINDOW_STATE_SHOW) { + _candidate_valid_height = ui_candidate_get_valid_height (); + if ((_candidate_height - _candidate_valid_height) > _ise_height) { + _candidate_valid_height = _candidate_height; + ise_rect.pos_y = ise_rect.pos_y + ise_rect.height - _candidate_height; + ise_rect.height = _candidate_height; + } else { + ise_rect.pos_y -= _candidate_valid_height; + ise_rect.height += _candidate_valid_height; + } + } + } + } + + // FIXME: Ecore_X dependency. +} + +/** + * @brief Get ISE index according to uuid. + * + * @param uuid The ISE uuid. + * + * @return The ISE index + */ +static int get_ise_index (const String uuid) +{ + int index = 0; + if (uuid.length () > 0) { + for (unsigned int i = 0; i < _uuids.size (); i++) { + if (uuid == _uuids[i]) { + index = i; + break; + } + } + } + + return index; +} + +/** + * @brief Get ISE module file path. + * + * @param module_name The ISE's module name. + * @param type The ISE's type. + * + * @return ISE module file path if successfully, otherwise return empty string. + */ +static String get_module_file_path (const String &module_name, const String &type) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + String strFile; + if (module_name.substr (0, 1) == String ("/")) { + strFile = module_name + String (".so"); + if (access (strFile.c_str (), R_OK) == 0) + return strFile; + } + + /* Check inhouse path */ + strFile = String (SCIM_MODULE_PATH) + + String (SCIM_PATH_DELIM_STRING) + String (SCIM_BINARY_VERSION) + + String (SCIM_PATH_DELIM_STRING) + type + + String (SCIM_PATH_DELIM_STRING) + module_name + String (".so"); + if (access (strFile.c_str (), R_OK) == 0) + return strFile; + + const char *module_path_env = getenv ("SCIM_MODULE_PATH"); + if (module_path_env) { + strFile = String (module_path_env) + + String (SCIM_PATH_DELIM_STRING) + String (SCIM_BINARY_VERSION) + + String (SCIM_PATH_DELIM_STRING) + type + + String (SCIM_PATH_DELIM_STRING) + module_name + String (".so"); + if (access (strFile.c_str (), R_OK) == 0) + return strFile; + } + + return String (""); +} + +/** + * @brief Get module names for all 3rd party's IMEs. + * @param ops_module_names The list to store module names for all 3rd party's IMEs. + * @return module name list size + */ +static int osp_module_list_get (std::vector &ops_module_names) +{ + const char *module_path_env = getenv ("SCIM_MODULE_PATH"); + if (module_path_env) { + String path = String (module_path_env) + + String (SCIM_PATH_DELIM_STRING) + String (SCIM_BINARY_VERSION) + + String (SCIM_PATH_DELIM_STRING) + String ("Helper"); + ops_module_names.clear (); + + DIR *dir = opendir (path.c_str ()); + if (dir) { + struct dirent *file = readdir (dir); + while (file) { + struct stat filestat; + String absfn = path + String (SCIM_PATH_DELIM_STRING) + file->d_name; + stat (absfn.c_str (), &filestat); + if (S_ISREG (filestat.st_mode)) { + String link_name = String (file->d_name); + ops_module_names.push_back (link_name.substr (0, link_name.find_last_of ('.'))); + } + + file = readdir (dir); + } + closedir (dir); + } + } + + std::sort (ops_module_names.begin (), ops_module_names.end ()); + ops_module_names.erase (std::unique (ops_module_names.begin (), ops_module_names.end ()), ops_module_names.end ()); + + return ops_module_names.size (); +} + +static String osp_module_name_get (const String &path) +{ + String pkg_id = path.substr (path.find_last_of (SCIM_PATH_DELIM) + 1); + String ise_name = String (""); + String bin_path = path + String ("/bin"); + DIR *dir = opendir (bin_path.c_str ()); + if (dir) { + struct dirent *file = readdir (dir); + while (file) { + struct stat filestat; + String absfn = bin_path + String (SCIM_PATH_DELIM_STRING) + file->d_name; + stat (absfn.c_str (), &filestat); + if (S_ISREG (filestat.st_mode)) { + String ext = absfn.substr (absfn.length () - 4); + if (ext == String (".exe")) { + int begin = absfn.find_last_of (SCIM_PATH_DELIM) + 1; + ise_name = absfn.substr (begin, absfn.find_last_of ('.') - begin); + break; + } + } + + file = readdir (dir); + } + closedir (dir); + } else { + LOGD ("open (%s) is failed!!!", bin_path.c_str ()); + } + String module_name = String (""); + if (ise_name.length () > 0) + module_name = pkg_id + String (".") + ise_name; + + LOGD ("module name = %s", module_name.c_str ()); + return module_name; +} + +static void osp_engine_dir_monitor_cb (void *data, Ecore_File_Monitor *em, Ecore_File_Event event, const char *path) +{ + String em_path = String (ecore_file_monitor_path_get (em)); + String manifest_file = em_path.substr (0, em_path.find_last_of (SCIM_PATH_DELIM)) + String ("/info/manifest.xml"); + String ext = String (path).substr (String (path).length () - 4); + + if (event == ECORE_FILE_EVENT_CLOSED) { + if (String (path) == manifest_file || ext == String (".exe")) { + LOGD ("path = %s, event = %d", path, event); + String pkg_path = em_path.substr (0, em_path.find_last_of (SCIM_PATH_DELIM)); + String module_name = osp_module_name_get (pkg_path); + const char *module_path_env = getenv ("SCIM_MODULE_PATH"); + if (module_path_env && module_name.length () > 0) { + String module_path = String (module_path_env) + + String (SCIM_PATH_DELIM_STRING) + String (SCIM_BINARY_VERSION) + + String (SCIM_PATH_DELIM_STRING) + String ("Helper") + String (SCIM_PATH_DELIM_STRING) + module_name + String (".so"); + isf_update_ise_module (String (module_path), _config); + _panel_agent->update_ise_list (_uuids); + _panel_agent->reload_config (); +#if 0 + String uuid = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), _initial_ise_uuid); + int index = get_ise_index (uuid); + if (_modes[index] == TOOLBAR_HELPER_MODE) { + String active_module = get_module_file_path (_module_names[index], String ("Helper")); + if (String (module_path) == active_module) { + /* Restart helper ISE */ + _panel_agent->hide_helper (uuid); + _panel_agent->stop_helper (uuid); + _panel_agent->start_helper (uuid); + } + } +#endif + } + } + } +} + +static void add_monitor_for_osp_module (const String &module_name) +{ + String rpath = String ("/opt/apps/") + module_name.substr (0, module_name.find_first_of ('.')); + String exe_path = rpath + String ("/bin"); + String manifest_path = rpath + String ("/info"); + + if (_osp_bin_em.find (module_name) == _osp_bin_em.end () || _osp_bin_em[module_name] == NULL) { + _osp_bin_em[module_name] = ecore_file_monitor_add (exe_path.c_str (), osp_engine_dir_monitor_cb, NULL); + LOGD ("add %s", module_name.c_str ()); + } + if (_osp_info_em.find (module_name) == _osp_info_em.end () || _osp_info_em[module_name] == NULL) { + _osp_info_em[module_name] = ecore_file_monitor_add (manifest_path.c_str (), osp_engine_dir_monitor_cb, NULL); + } +} + +/** + * @brief : add monitor for engine file and info file update of 3rd party's IMEs + */ +static void add_monitor_for_all_osp_modules (void) +{ + std::vector osp_module_list; + osp_module_list_get (osp_module_list); + + if (osp_module_list.size () > 0) { + for (unsigned int i = 0; i < osp_module_list.size (); i++) + add_monitor_for_osp_module (osp_module_list[i]); + } +} + +/** + * @brief Callback function for ISE file monitor. + * + * @param data Data to pass when it is called. + * @param em The handle of Ecore_File_Monitor. + * @param event The event type. + * @param path The path for current event. + */ +static void ise_file_monitor_cb (void *data, Ecore_File_Monitor *em, Ecore_File_Event event, const char *path) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " path=" << path << "\n"; + LOGD ("path = %s, event = %d", path, event); + + String directory = String (path); + directory = directory.substr (0, 4); + if (event == ECORE_FILE_EVENT_DELETED_FILE || event == ECORE_FILE_EVENT_CLOSED || + (event == ECORE_FILE_EVENT_CREATED_FILE && directory == String ("/opt"))) { + String file_path = String (path); + String file_ext = file_path.substr (file_path.length () - 3); + if (file_ext != String (".so")) { + LOGD ("%s is not valid so file!!!", path); + return; + } + + int begin = String (path).find_last_of (SCIM_PATH_DELIM) + 1; + String module_name = String (path).substr (begin, String (path).find_last_of ('.') - begin); + + if (event == ECORE_FILE_EVENT_DELETED_FILE) { + /* Update ISE list */ + std::vector list; + slot_get_ise_list (list); + + /* delete osp monitor */ + OSPEmRepository::iterator iter = _osp_bin_em.find (module_name); + if (iter != _osp_bin_em.end ()) { + ecore_file_monitor_del (iter->second); + _osp_bin_em.erase (iter); + LOGD ("delete %s", module_name.c_str ()); + } + iter = _osp_info_em.find (module_name); + if (iter != _osp_info_em.end ()) { + ecore_file_monitor_del (iter->second); + _osp_info_em.erase (iter); + } + } else if (event == ECORE_FILE_EVENT_CLOSED) { + isf_update_ise_module (String (path), _config); + _panel_agent->update_ise_list (_uuids); + _panel_agent->reload_config (); +#if 0 + String uuid = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), _initial_ise_uuid); + int index = get_ise_index (uuid); + String strFile = String (ecore_file_monitor_path_get (em)) + + String (SCIM_PATH_DELIM_STRING) + _module_names[index] + String (".so"); + + if (String (path) == strFile && _modes[index] == TOOLBAR_HELPER_MODE) { + /* Restart helper ISE */ + _panel_agent->hide_helper (uuid); + _panel_agent->stop_helper (uuid); + _panel_agent->start_helper (uuid); + } + + /* add osp monitor */ + if (event == ECORE_FILE_EVENT_CREATED_FILE && directory == String ("/opt")) { + add_monitor_for_osp_module (module_name); + LOGD ("add %s", module_name.c_str ()); + } +#endif + } + } +} + +/** + * @brief Delete keyboard ISE file monitor. + */ +static void delete_ise_directory_em (void) { + if (_inh_keyboard_ise_em) { + ecore_file_monitor_del (_inh_keyboard_ise_em); + _inh_keyboard_ise_em = NULL; + } + if (_inh_helper_ise_em) { + ecore_file_monitor_del (_inh_helper_ise_em); + _inh_helper_ise_em = NULL; + } + + if (_osp_keyboard_ise_em) { + ecore_file_monitor_del (_osp_keyboard_ise_em); + _osp_keyboard_ise_em = NULL; + } + if (_osp_helper_ise_em) { + ecore_file_monitor_del (_osp_helper_ise_em); + _osp_helper_ise_em = NULL; + } + + OSPEmRepository::iterator iter; + for (iter = _osp_bin_em.begin (); iter != _osp_bin_em.end (); iter++) { + if (iter->second) { + ecore_file_monitor_del (iter->second); + iter->second = NULL; + } + } + for (iter = _osp_info_em.begin (); iter != _osp_info_em.end (); iter++) { + if (iter->second) { + ecore_file_monitor_del (iter->second); + iter->second = NULL; + } + } + _osp_bin_em.clear (); + _osp_info_em.clear (); +} + +/** + * @brief Add inhouse ISEs and OSP ISEs directory monitor. + */ +static void add_ise_directory_em (void) { + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + // inhouse IMEngine path + String path = String (SCIM_MODULE_PATH) + + String (SCIM_PATH_DELIM_STRING) + String (SCIM_BINARY_VERSION) + + String (SCIM_PATH_DELIM_STRING) + String ("IMEngine"); + if (_inh_keyboard_ise_em == NULL) + _inh_keyboard_ise_em = ecore_file_monitor_add (path.c_str (), ise_file_monitor_cb, NULL); + + // inhouse Helper path + path = String (SCIM_MODULE_PATH) + + String (SCIM_PATH_DELIM_STRING) + String (SCIM_BINARY_VERSION) + + String (SCIM_PATH_DELIM_STRING) + String ("Helper"); + if (_inh_helper_ise_em == NULL) + _inh_helper_ise_em = ecore_file_monitor_add (path.c_str (), ise_file_monitor_cb, NULL); + + const char *module_path_env = getenv ("SCIM_MODULE_PATH"); + if (module_path_env) { + // OSP IMEngine path + path = String (module_path_env) + + String (SCIM_PATH_DELIM_STRING) + String (SCIM_BINARY_VERSION) + + String (SCIM_PATH_DELIM_STRING) + String ("IMEngine"); + if (access (path.c_str (), R_OK) == 0) { + if (_osp_keyboard_ise_em == NULL) { + _osp_keyboard_ise_em = ecore_file_monitor_add (path.c_str (), ise_file_monitor_cb, NULL); + LOGD ("ecore_file_monitor_add path=%s", path.c_str ()); + } + } else { + LOGD ("access path=%s is failed!!!", path.c_str ()); + } + + // OSP Helper path + path = String (module_path_env) + + String (SCIM_PATH_DELIM_STRING) + String (SCIM_BINARY_VERSION) + + String (SCIM_PATH_DELIM_STRING) + String ("Helper"); + if (access (path.c_str (), R_OK) == 0) { + if (_osp_helper_ise_em == NULL) { + _osp_helper_ise_em = ecore_file_monitor_add (path.c_str (), ise_file_monitor_cb, NULL); + LOGD ("ecore_file_monitor_add path=%s", path.c_str ()); + } + } else { + LOGD ("access path=%s is failed!!!", path.c_str ()); + } + } else { + LOGD ("getenv (\"SCIM_MODULE_PATH\") is failed!!!"); + } + + add_monitor_for_all_osp_modules (); +} + +/** + * @brief Set keyboard ISE. + * + * @param uuid The keyboard ISE's uuid. + * @param module_name The keyboard ISE's module name. + * + * @return false if keyboard ISE change is failed, otherwise return true. + */ +static bool set_keyboard_ise (const String &uuid, const String &module_name) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + TOOLBAR_MODE_T mode = _panel_agent->get_current_toolbar_mode (); + + if (TOOLBAR_HELPER_MODE == mode) { + String pre_uuid = _panel_agent->get_current_helper_uuid (); + _panel_agent->hide_helper (pre_uuid); + _panel_agent->stop_helper (pre_uuid); + } else if (TOOLBAR_KEYBOARD_MODE == mode) { + uint32 kbd_option = 0; + String kbd_uuid, kbd_name; + isf_get_keyboard_ise (_config, kbd_uuid, kbd_name, kbd_option); + if (kbd_uuid == uuid) + return false; + } + + _panel_agent->change_factory (uuid); + + String language = String ("~other");/*scim_get_locale_language (scim_get_current_locale ());*/ + _config->write (String (SCIM_CONFIG_DEFAULT_IMENGINE_FACTORY) + String ("/") + language, uuid); + + return true; +} + +/** + * @brief Set helper ISE. + * + * @param uuid The helper ISE's uuid. + * @param module_name The helper ISE's module name. + * + * @return false if helper ISE change is failed, otherwise return true. + */ +static bool set_helper_ise (const String &uuid, const String &module_name) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + TOOLBAR_MODE_T mode = _panel_agent->get_current_toolbar_mode (); + String pre_uuid = _panel_agent->get_current_helper_uuid (); + if (pre_uuid == uuid) + return false; + + if (TOOLBAR_HELPER_MODE == mode) { + _panel_agent->hide_helper (pre_uuid); + _panel_agent->stop_helper (pre_uuid); + char buf[256] = {0}; + snprintf (buf, sizeof (buf), "time:%ld pid:%d %s %s stop helper(%s)\n", + time (0), getpid (), __FILE__, __func__, pre_uuid.c_str ()); + isf_save_log (buf); + } + + /* Set ComposeKey as keyboard ISE */ + uint32 kbd_option = 0; + String kbd_uuid, kbd_name; + isf_get_keyboard_ise (_config, kbd_uuid, kbd_name, kbd_option); + if (kbd_uuid != String (SCIM_COMPOSE_KEY_FACTORY_UUID)) { + kbd_uuid = String (SCIM_COMPOSE_KEY_FACTORY_UUID); + _panel_agent->change_factory (kbd_uuid); + + String language = String ("~other");/*scim_get_locale_language (scim_get_current_locale ());*/ + _config->write (String (SCIM_CONFIG_DEFAULT_IMENGINE_FACTORY) + String ("/") + language, kbd_uuid); + } + char buf[256] = {0}; + snprintf (buf, sizeof (buf), "time:%ld pid:%d %s %s Start helper(%s)\n", + time (0), getpid (), __FILE__, __func__, uuid.c_str ()); + isf_save_log (buf); + + _panel_agent->start_helper (uuid); + _config->write (String (SCIM_CONFIG_DEFAULT_HELPER_ISE), uuid); + + return true; +} + +/** + * @brief Set active ISE. + * + * @param uuid The ISE's uuid. + * + * @return false if ISE change is failed, otherwise return true. + */ +static bool set_active_ise (const String &uuid) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + char buf[256] = {0}; + snprintf (buf, sizeof (buf), "time:%ld pid:%d %s %s set ISE(%s)\n", + time (0), getpid (), __FILE__, __func__, uuid.c_str ()); + isf_save_log (buf); + + if (uuid.length () <= 0) + return false; + + bool ise_changed = false; + + for (unsigned int i = 0; i < _uuids.size (); i++) { + if (!uuid.compare (_uuids[i])) { + if (TOOLBAR_KEYBOARD_MODE == _modes[i]) + ise_changed = set_keyboard_ise (_uuids[i], _module_names[i]); + else if (TOOLBAR_HELPER_MODE == _modes[i]) + ise_changed = set_helper_ise (_uuids[i], _module_names[i]); + + if (ise_changed) { + _panel_agent->set_current_toolbar_mode (_modes[i]); + _panel_agent->set_current_ise_name (_names[i]); + + _ise_width = 0; + _ise_height = 0; + _ise_state = WINDOW_STATE_HIDE; + _candidate_mode = SOFT_CANDIDATE_WINDOW; + _candidate_port_line = ONE_LINE_CANDIDATE; + if (_candidate_window) + ui_create_candidate_window (); + + scim_global_config_write (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), _uuids[i]); + scim_global_config_flush (); + + _config->flush (); + _config->reload (); + _panel_agent->reload_config (); + } + + return true; + } + } + + return false; +} + +/** + * @brief Load ISF configuration and ISEs information. + */ +static void load_config (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + /* Read configurations. */ + if (!_config.null ()) { + bool shared_ise = _config->read (String (SCIM_CONFIG_FRONTEND_SHARED_INPUT_METHOD), false); + _panel_agent->set_should_shared_ise (shared_ise); + } + + isf_load_ise_information (ALL_ISE, _config); +} + +/** + * @brief Reload config callback function for ISF panel. + * + * @param config The config pointer. + */ +static void config_reload_cb (const ConfigPointer &config) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + /* load_config (); */ +} + +static Eina_Bool system_ready_timeout_cb (void *data) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + LOGW ("Launching IME because of appservice ready timeout\n"); + + _launch_default_soft_keyboard (); + + return ECORE_CALLBACK_CANCEL; +} + +////////////////////////////////////////////////////////////////////// +// Start of Candidate Functions +////////////////////////////////////////////////////////////////////// +/** + * @brief Get candidate window valid height for autoscroll. + * + * @return The valid height. + */ +static int ui_candidate_get_valid_height (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "\n"; + + int height = 0; + int angle = 0; + + if (_candidate_window) { + if (_candidate_state == WINDOW_STATE_SHOW) + angle = _candidate_angle; + else + angle = efl_get_angle_for_app_window (); + + if (_aux_area_visible && _candidate_area_1_visible) { + if (angle == 90 || angle == 270) + height = _candidate_land_height_min_2; + else + height = _candidate_port_height_min_2; + } else { + if (angle == 90 || angle == 270) + height = _candidate_land_height_min; + else + height = _candidate_port_height_min; + } + } + return height; +} + +/** + * @brief Resize candidate window size. + * + * @param new_width New width for candidate window. + * @param new_height New height for candidate window. + */ +static void ui_candidate_window_resize (int new_width, int new_height) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " width:" << new_width << " height:" << new_height << "\n"; + + if (!_candidate_window) + return; + + int height; + + LOGD ("%s (w: %d, h: %d)\n", __func__, new_width, new_height); + evas_object_resize (_aux_line, new_width, 2); + _candidate_width = new_width; + _candidate_height = new_height; + if (_candidate_state == WINDOW_STATE_SHOW) + _panel_agent->update_candidate_panel_event ((uint32)ECORE_IMF_CANDIDATE_PANEL_GEOMETRY_EVENT, 0); + + if (_candidate_state == WINDOW_STATE_SHOW && _candidate_mode == FIXED_CANDIDATE_WINDOW) { + height = ui_candidate_get_valid_height (); + if ((_ise_width == 0 && _ise_height == 0) || + (_ise_height > 0 && _candidate_valid_height != height) || + (_ise_height > 0 && (_candidate_height - height) > _ise_height)) { + set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ()); + _panel_agent->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0); + } + } + + /* Get height for portrait and landscape */ + int port_width = _candidate_port_width; + int port_height = _candidate_port_height_min; + int land_width = _candidate_land_width; + int land_height = _candidate_land_height_min; + if (_candidate_angle == 90 || _candidate_angle == 270) { + land_height = new_height; + if (land_height == _candidate_land_height_min_2) { + port_height = _candidate_port_height_min_2; + } else if (land_height == _candidate_land_height_max) { + port_height = _candidate_port_height_max; + } else if (land_height == _candidate_land_height_max_2) { + port_height = _candidate_port_height_max_2; + } + } else { + port_height = new_height; + if (port_height == _candidate_port_height_min_2) { + land_height = _candidate_land_height_min_2; + } else if (port_height == _candidate_port_height_max) { + land_height = _candidate_land_height_max; + } else if (port_height == _candidate_port_height_max_2) { + land_height = _candidate_land_height_max_2; + } + } + + // FIXME: ECORE_X dependency. +} + +/** + * @brief This function will show/hide widgets of candidate window, + * and resize candidate window size according to aux_area/candidate_area. + */ +static void ui_candidate_window_adjust (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + if (!_candidate_window) + return; + + int x, y, width, height; + + /* Get candidate window size */ + // FIXME: + x = y = 0; + width = _candidate_width; + height = _candidate_height; + + if (_aux_area_visible && _candidate_area_2_visible) { + evas_object_show (_aux_line); + evas_object_move (_candidate_area_1, _candidate_area_1_pos[0], _candidate_area_1_pos[1] + _candidate_port_height_min_2 - _candidate_port_height_min); + if (_candidate_angle == 90 || _candidate_angle == 270) { + ui_candidate_window_resize (width, _candidate_land_height_max_2); + evas_object_move (_close_btn, _close_btn_pos[2], _close_btn_pos[3] + _candidate_port_height_min_2 - _candidate_port_height_min); + evas_object_move (_candidate_area_2, 0, _candidate_land_height_min_2); + evas_object_move (_scroller_bg, 0, _candidate_land_height_min_2); + } else { + ui_candidate_window_resize (width, _candidate_port_height_max_2); + evas_object_move (_close_btn, _close_btn_pos[0], _close_btn_pos[1] + _candidate_port_height_min_2 - _candidate_port_height_min); + evas_object_move (_candidate_area_2, 0, _candidate_port_height_min_2); + evas_object_move (_scroller_bg, 0, _candidate_port_height_min_2); + } + } else if (_aux_area_visible && _candidate_area_1_visible) { + evas_object_show (_aux_line); + evas_object_move (_candidate_area_1, _candidate_area_1_pos[0], _candidate_area_1_pos[1] + _candidate_port_height_min_2 - _candidate_port_height_min); + if (_candidate_angle == 90 || _candidate_angle == 270) { + ui_candidate_window_resize (width, _candidate_land_height_min_2); + evas_object_move (_more_btn, _more_btn_pos[2], _more_btn_pos[3] + _candidate_port_height_min_2 - _candidate_port_height_min); + } else { + ui_candidate_window_resize (width, _candidate_port_height_min_2); + evas_object_move (_more_btn, _more_btn_pos[0], _more_btn_pos[1] + _candidate_port_height_min_2 - _candidate_port_height_min); + } + } else if (_aux_area_visible) { + evas_object_hide (_aux_line); + ui_candidate_window_resize (width, _aux_height + 2); + } else if (_candidate_area_2_visible) { + evas_object_hide (_aux_line); + evas_object_move (_candidate_area_1, _candidate_area_1_pos[0], _candidate_area_1_pos[1]); + if (_candidate_angle == 90 || _candidate_angle == 270) { + ui_candidate_window_resize (width, _candidate_land_height_max); + evas_object_move (_close_btn, _close_btn_pos[2], _close_btn_pos[3]); + evas_object_move (_candidate_area_2, 0, _candidate_land_height_min); + evas_object_move (_scroller_bg, 0, _candidate_land_height_min); + } else { + ui_candidate_window_resize (width, _candidate_port_height_max); + evas_object_move (_close_btn, _close_btn_pos[0], _close_btn_pos[1]); + evas_object_move (_candidate_area_2, 0, _candidate_port_height_min); + evas_object_move (_scroller_bg, 0, _candidate_port_height_min); + } + } else { + evas_object_hide (_aux_line); + evas_object_move (_candidate_area_1, _candidate_area_1_pos[0], _candidate_area_1_pos[1]); + if (_candidate_angle == 90 || _candidate_angle == 270) { + ui_candidate_window_resize (width, _candidate_land_height_min); + evas_object_move (_more_btn, _more_btn_pos[2], _more_btn_pos[3]); + } else { + ui_candidate_window_resize (width, _candidate_port_height_min); + evas_object_move (_more_btn, _more_btn_pos[0], _more_btn_pos[1]); + } + } +} + +/** + * @brief Rotate candidate window. + * + * @param angle The angle of candidate window. + */ +static void ui_candidate_window_rotate (int angle) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + if (!_candidate_window) + return; + + ui_candidate_window_close_button_cb (NULL, NULL, NULL, NULL); + + if (angle == 90 || angle == 270) { + _candidate_scroll_width = _candidate_scroll_width_max; + ui_candidate_window_resize (_candidate_land_width, _candidate_land_height_min); + evas_object_resize (_aux_area, _aux_land_width, _aux_height); + evas_object_resize (_candidate_area_1, _candidate_scroll_0_width_max, _item_min_height); + evas_object_resize (_candidate_area_2, _candidate_scroll_width, _candidate_scroll_height_min); + evas_object_resize (_scroller_bg, _candidate_scroll_width, _candidate_scroll_height_min + 6); + } else { + _candidate_scroll_width = _candidate_scroll_width_min; + ui_candidate_window_resize (_candidate_port_width, _candidate_port_height_min); + evas_object_resize (_aux_area, _aux_port_width, _aux_height); + evas_object_resize (_candidate_area_1, _candidate_scroll_0_width_min, (_item_min_height+2)*_candidate_port_line-2); + evas_object_resize (_candidate_area_2, _candidate_scroll_width, _candidate_scroll_height_max); + evas_object_resize (_scroller_bg, _candidate_scroll_width, _candidate_scroll_height_max + 6); + } + + evas_object_hide (_candidate_area_2); + _candidate_area_2_visible = false; + ui_candidate_window_adjust (); + if (_candidate_area_1_visible) { + update_table (ISF_CANDIDATE_TABLE, g_isf_candidate_table); + } + flush_memory (); + + LOGD ("elm_win_rotation_with_resize_set (window : %p, angle : %d)\n", _candidate_window, angle); + elm_win_rotation_with_resize_set (_candidate_window, angle); + if (_preedit_window) + elm_win_rotation_with_resize_set (_preedit_window, angle); +} + +/** + * @brief This function is used to judge whether candidate window should be hidden. + * + * @return true if candidate window should be hidden, otherwise return false. + */ +static bool ui_candidate_can_be_hide (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + if (_aux_area_visible || _candidate_area_1_visible || _candidate_area_2_visible) + return false; + else + return true; +} + +/** + * @brief Delete check candidate window size timer. + * + * @return void + */ +static void ui_candidate_delete_check_size_timer (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + if (_check_size_timer != NULL) { + ecore_timer_del (_check_size_timer); + _check_size_timer = NULL; + } +} + +/** + * @brief Callback function for check candidate window size timer. + * + * @param data Data to pass when it is called. + * + * @return ECORE_CALLBACK_CANCEL + */ +static Eina_Bool ui_candidate_check_size_timeout (void *data) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + ui_candidate_delete_check_size_timer (); + ui_candidate_window_resize (_candidate_width, _candidate_height); + ui_settle_candidate_window (); + return ECORE_CALLBACK_CANCEL; +} + +/** + * @brief Delete longpress timer. + * + * @return void + */ +static void ui_candidate_delete_longpress_timer (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + if (_longpress_timer != NULL) { + ecore_timer_del (_longpress_timer); + _longpress_timer = NULL; + } +} + +/** + * @brief Callback function for candidate longpress timer. + * + * @param data Data to pass when it is called. + * + * @return ECORE_CALLBACK_CANCEL + */ +static Eina_Bool ui_candidate_longpress_timeout (void *data) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + int index = (int)GPOINTER_TO_INT(data); + ui_candidate_delete_longpress_timer (); + _is_click = false; + _panel_agent->send_longpress_event (_click_object, index); + return ECORE_CALLBACK_CANCEL; +} + +/** + * @brief Delete destroy timer. + * + * @return void + */ +static void ui_candidate_delete_destroy_timer (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + if (_destroy_timer != NULL) { + ecore_timer_del (_destroy_timer); + _destroy_timer = NULL; + } +} + +/** + * @brief Callback function for destroy timer. + * + * @param data Data to pass when it is called. + * + * @return ECORE_CALLBACK_CANCEL + */ +static Eina_Bool ui_candidate_destroy_timeout (void *data) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + ui_candidate_delete_destroy_timer (); + ui_destroy_candidate_window (); + return ECORE_CALLBACK_CANCEL; +} + +/** + * @brief Callback function for off_prepare_done. + * + * @param data Data to pass when it is called. + * + * @return ECORE_CALLBACK_CANCEL + */ +static Eina_Bool off_prepare_done_timeout (void *data) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + /* WMSYNC, #8 Let the Window Manager to actually hide keyboard window */ + // WILL_HIDE_REQUEST_DONE Ack to WM + // FIXME: + + _off_prepare_done_timer = NULL; + + return ECORE_CALLBACK_CANCEL; +} + +/** + * @brief Delete candidate hide timer. + * + * @return void + */ +static void delete_candidate_hide_timer (void) +{ + LOGD ("deleting candidate_hide_timer"); + if (_candidate_hide_timer) { + ecore_timer_del (_candidate_hide_timer); + _candidate_hide_timer = NULL; + } +} + +static void candidate_window_hide (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "\n"; + + delete_candidate_hide_timer (); + _candidate_state = WINDOW_STATE_HIDE; + + LOGD ("evas_object_hide (_candidate_window, %p)\n", elm_win_xwindow_get (_candidate_window)); + + if (_candidate_window) { + /* There are cases that when there are rapid ISE_HIDE and ISE_SHOW requests, + candidate window should be displayed but STATE_OFF for the first ISE_HIDE + calls this function, so when the candidate window is shown by the following + STATE_ON message, a blank area is displayed in candidate window - + so we let the _cnadidate_area_1 as the default area that would be displayed */ + //evas_object_hide (_candidate_area_1); + //evas_object_hide (_more_btn); + _candidate_area_1_visible = false; + + evas_object_hide (_candidate_window); + SCIM_DEBUG_MAIN (3) << " Hide candidate window\n"; + } +} + +/** + * @brief Callback function for candidate hide timer + * + * @param data Data to pass when it is called. + * + * @return ECORE_CALLBACK_CANCEL + */ +static Eina_Bool candidate_hide_timer (void *data) +{ + LOGD ("calling candidate_window_hide()"); + candidate_window_hide (); + + return ECORE_CALLBACK_CANCEL; +} + +/** + * @brief Delete candidate show handler. + * + * @return void + */ +static void delete_candidate_show_handler (void) +{ + if (_candidate_show_handler) { + ecore_event_handler_del (_candidate_show_handler); + _candidate_show_handler = NULL; + } +} + + +/** + * @brief Show candidate window. + * + * @param bSetVirtualKbd The flag for set_keyboard_geometry_atom_info () calling. + */ +static void ui_candidate_show (bool bSetVirtualKbd) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + int hw_kbd_detect = _config->read (ISF_CONFIG_HARDWARE_KEYBOARD_DETECT, 0); + + delete_candidate_hide_timer (); + + if (!_candidate_window) return; + + /* FIXME : SHOULD UNIFY THE METHOD FOR CHECKING THE HW KEYBOARD EXISTENCE */ + /* If the ISE is not visible currently, wait for the ISE to be opened and then show our candidate window */ + _candidate_show_requested = true; + if( (hw_kbd_detect == 0 && _ise_state != WINDOW_STATE_SHOW)) { + LOGD ("setting _show_can didate_requested to TRUE"); + return; + } + + ui_candidate_window_rotate (_candidate_angle); + + /* If the candidate window was about to hide, turn it back to SHOW state now */ + if (_candidate_state == WINDOW_STATE_WILL_HIDE) { + _candidate_state = WINDOW_STATE_SHOW; + } + + /* Change to WILL_SHOW state only when we are not currently in SHOW state */ + if (_candidate_state != WINDOW_STATE_SHOW) { + _candidate_state = WINDOW_STATE_WILL_SHOW; + } + + if (_candidate_mode == FIXED_CANDIDATE_WINDOW) { + if (bSetVirtualKbd) { + set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ()); + } + } + + ui_candidate_delete_check_size_timer (); + _check_size_timer = ecore_timer_add (0.02, ui_candidate_check_size_timeout, NULL); + + SCIM_DEBUG_MAIN (3) << " Show candidate window\n"; + if (_ise_state == WINDOW_STATE_SHOW) { + edje_object_file_set (_more_btn, _candidate_edje_file.c_str (), "more_button"); + edje_object_file_set (_close_btn, _candidate_edje_file.c_str (), "close_button"); + } else { + edje_object_file_set (_more_btn, _candidate_edje_file.c_str (), "close_button"); + edje_object_file_set (_close_btn, _candidate_edje_file.c_str (), "more_button"); + } + + /* If we are in hardward keyboard mode, this candidate window is now considered to be a input panel */ + if (_candidate_mode == FIXED_CANDIDATE_WINDOW) { + if (hw_kbd_mode) { + LOGD ("sending ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW"); + _panel_agent->update_input_panel_event ((uint32)ECORE_IMF_INPUT_PANEL_STATE_EVENT, (uint32)ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW); + } + } + + evas_object_show (_candidate_window); +} + +/** + * @brief Hide candidate window. + * + * @param bForce The flag to hide candidate window by force. + * @param bSetVirtualKbd The flag for set_keyboard_geometry_atom_info () calling. + */ +static void ui_candidate_hide (bool bForce, bool bSetVirtualKbd, bool will_hide) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " bForce:" << bForce << " bSetVirtualKbd:" << bSetVirtualKbd << " will_hide:" << will_hide << "...\n"; + + if (!_candidate_window) + return; + + if (bForce) { + if (_candidate_area_2 && _candidate_area_2_visible) { + evas_object_hide (_candidate_area_2); + _candidate_area_2_visible = false; + evas_object_hide (_scroller_bg); + evas_object_hide (_close_btn); + _panel_agent->candidate_more_window_hide (); + ui_candidate_window_adjust (); + } + } + + if (bForce || ui_candidate_can_be_hide ()) { + if (will_hide) { + LOGD ("candidate_state = WILL_HIDE"); + _candidate_state = WINDOW_STATE_WILL_HIDE; + + delete_candidate_hide_timer (); + _candidate_hide_timer = ecore_timer_add (2.0, candidate_hide_timer, NULL); + } + + if (_candidate_mode == FIXED_CANDIDATE_WINDOW) { + /* FIXME : should check if bSetVirtualKbd flag is really needed in this case */ + if (_ise_state == WINDOW_STATE_SHOW) { + set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ()); + } else { + if (bSetVirtualKbd) { + set_keyboard_geometry_atom_info (_app_window, get_ise_geometry ()); + } + } + } + + if (!will_hide) { + /* If we are not in will_hide state, hide the candidate window immediately */ + candidate_window_hide (); + evas_object_hide (_preedit_window); + } + } +} + +/** + * @brief Callback function for more button. + * + * @param data Data to pass when it is called. + * @param e The evas for current event. + * @param button The evas object for current event. + * @param event_info The information for current event. + */ +static void ui_candidate_window_more_button_cb (void *data, Evas *e, Evas_Object *button, void *event_info) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + _panel_agent->candidate_more_window_show (); + + if (_candidate_angle == 180 || _candidate_angle == 270) { + Ecore_Evas *ee = ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window)); + ecore_evas_move_resize (ee, 0, 0, 0, 0); + } + + evas_object_show (_candidate_area_2); + _candidate_area_2_visible = true; + evas_object_show (_scroller_bg); + evas_object_hide (_more_btn); + evas_object_show (_close_btn); + + ui_candidate_window_adjust (); + ui_settle_candidate_window (); + flush_memory (); +} + +/** + * @brief Callback function for close button. + * + * @param data Data to pass when it is called. + * @param e The evas for current event. + * @param button The evas object for current event. + * @param event_info The information for current event. + */ +static void ui_candidate_window_close_button_cb (void *data, Evas *e, Evas_Object *button, void *event_info) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + if (_candidate_area_2 == NULL || !_candidate_area_2_visible) + return; + + evas_object_hide (_candidate_area_2); + _candidate_area_2_visible = false; + evas_object_hide (_scroller_bg); + evas_object_hide (_close_btn); + _panel_agent->candidate_more_window_hide (); + + evas_object_show (_candidate_area_1); + _candidate_area_1_visible = true; + evas_object_show (_more_btn); + + elm_scroller_region_show (_candidate_area_2, 0, 0, _candidate_scroll_width, 100); + if (_candidate_angle == 180 || _candidate_angle == 270) { + Ecore_Evas *ee= ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window)); + ecore_evas_move_resize (ee, 0, 0, 0, 0); + } + + ui_candidate_window_adjust (); + ui_settle_candidate_window (); + flush_memory (); +} + +/** + * @brief Callback function for mouse button press. + * + * @param data Data to pass when it is called. + * @param e The evas for current event. + * @param button The evas object for current event. + * @param event_info The information for current event. + */ +static void ui_mouse_button_pressed_cb (void *data, Evas *e, Evas_Object *button, void *event_info) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + _click_object = GPOINTER_TO_INT (data) & 0xFF; + _is_click = true; + + Evas_Event_Mouse_Down *ev = (Evas_Event_Mouse_Down *)event_info; + _click_down_pos [0] = ev->canvas.x; + _click_down_pos [1] = ev->canvas.y; + + if (_click_object == ISF_EFL_CANDIDATE_0 || _click_object == ISF_EFL_CANDIDATE_ITEMS) { + int index = GPOINTER_TO_INT (data) >> 8; + +#if HAVE_FEEDBACK + if (feedback_initialized) { + int feedback_result = 0; + + feedback_result = feedback_play_type (FEEDBACK_TYPE_SOUND, FEEDBACK_PATTERN_SIP); + + if (FEEDBACK_ERROR_NONE == feedback_result) + LOGD ("Sound play successful"); + else + LOGW ("Cannot play feedback sound : %d", feedback_result); + + feedback_result = feedback_play_type (FEEDBACK_TYPE_VIBRATION, FEEDBACK_PATTERN_SIP); + + if (FEEDBACK_ERROR_NONE == feedback_result) + LOGD ("Vibration play successful"); + else + LOGW ("Cannot play feedback vibration : %d", feedback_result); + } +#endif + + ui_candidate_delete_longpress_timer (); + _longpress_timer = ecore_timer_add (1.0, ui_candidate_longpress_timeout, (void *)index); + } +} + +/** + * @brief Callback function for mouse button release. + * + * @param data Data to pass when it is called. + * @param e The evas for current event. + * @param button The evas object for current event. + * @param event_info The information for current event. + */ +static void ui_mouse_button_released_cb (void *data, Evas *e, Evas_Object *button, void *event_info) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " index:" << GPOINTER_TO_INT (data) << "...\n"; + + ui_candidate_delete_longpress_timer (); + + int index = GPOINTER_TO_INT (data); + if (_click_object == ISF_EFL_AUX && _is_click) { +/* double ret = 0; + const char *buf = edje_object_part_state_get (button, "aux", &ret); + if (strcmp ("selected", buf)) { + for (unsigned int i = 0; i < _aux_items.size (); i++) { + buf = edje_object_part_state_get (_aux_items [i], "aux", &ret); + if (!strcmp ("selected", buf)) + edje_object_signal_emit (_aux_items [i], "aux,state,unselected", "aux"); + } + edje_object_signal_emit (button, "aux,state,selected", "aux"); + _panel_agent->select_aux (index); + }*/ + int r, g, b, a, r2, g2, b2, a2, r3, g3, b3, a3; + edje_object_color_class_get (_aux_items [index], "text_color", &r, &g, &b, &a, &r2, &g2, &b2, &a2, &r3, &g3, &b3, &a3); + // Normal item is clicked + if (!(r == 62 && g == 207 && b == 255)) { + for (unsigned int i = 0; i < _aux_items.size (); i++) { + edje_object_color_class_set (_aux_items [i], "text_color", 249, 249, 249, 255, r2, g2, b2, a2, r3, g3, b3, a3); + } + edje_object_color_class_set (_aux_items [index], "text_color", 62, 207, 255, 255, r2, g2, b2, a2, r3, g3, b3, a3); + _panel_agent->select_aux (index); + } + } else if (_click_object == ISF_EFL_CANDIDATE_0 && _is_click) { + ui_candidate_window_close_button_cb (NULL, NULL, _close_btn, NULL); + _panel_agent->select_candidate (index); + } else if (_click_object == ISF_EFL_CANDIDATE_ITEMS && _is_click) { + ui_candidate_window_close_button_cb (NULL, NULL, _close_btn, NULL); + _panel_agent->select_candidate (index); + } +} + +/** + * @brief Callback function for mouse move. + * + * @param data Data to pass when it is called. + * @param e The evas for current event. + * @param button The evas object for current event. + * @param event_info The information for current event. + */ +static void ui_mouse_moved_cb (void *data, Evas *e, Evas_Object *button, void *event_info) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + Evas_Event_Mouse_Down *ev = (Evas_Event_Mouse_Down *)event_info; + _click_up_pos [0] = ev->canvas.x; + _click_up_pos [1] = ev->canvas.y; + + if (abs (_click_up_pos [0] - _click_down_pos [0]) >= (int)(15 * _height_rate) || + abs (_click_up_pos [1] - _click_down_pos [1]) >= (int)(15 * _height_rate)) { + _is_click = false; + ui_candidate_delete_longpress_timer (); + } +} + +/** + * @brief Open TTS device. + * + * @return false if open is failed, otherwise return true. + */ +static bool ui_open_tts (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + +#if HAVE_TTS + int r = tts_create (&_tts); + if (TTS_ERROR_NONE != r) { + LOGW ("tts_create FAILED : result(%d)\n", r); + _tts = NULL; + return false; + } + + r = tts_set_mode (_tts, TTS_MODE_SCREEN_READER); + if (TTS_ERROR_NONE != r) { + LOGW ("tts_set_mode FAILED : result(%d)\n", r); + } + + tts_state_e current_state; + r = tts_get_state (_tts, ¤t_state); + if (TTS_ERROR_NONE != r) { + LOGW ("tts_get_state FAILED : result(%d)\n", r); + } + + if (TTS_STATE_CREATED == current_state) { + r = tts_prepare (_tts); + if (TTS_ERROR_NONE != r) { + LOGW ("tts_prepare FAILED : ret(%d)\n", r); + } + } + return true; +#else + return false; +#endif +} + +/** + * @brief Close TTS device. + */ +static void ui_close_tts (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + +#if HAVE_TTS + if (_tts) { + int r = tts_unprepare (_tts); + if (TTS_ERROR_NONE != r) { + LOGW ("tts_unprepare FAILED : result(%d)\n", r); + } + + r = tts_destroy (_tts); + if (TTS_ERROR_NONE != r) { + LOGW ("tts_destroy FAILED : result(%d)\n", r); + } + } +#endif +} + +/** + * @brief Play string by TTS. + * + * @param str The string for playing. + */ +static void ui_play_tts (const char* str) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " str=" << str << "\n"; + +#if HAVE_TTS + if (_tts == NULL) { + if (!ui_open_tts ()) + return; + } + + if (str) { + int r; + int utt_id = 0; + tts_state_e current_state; + + r = tts_get_state (_tts, ¤t_state); + if (TTS_ERROR_NONE != r) { + LOGW ("Fail to get state from TTS : ret(%d)\n", r); + } + + if (TTS_STATE_PLAYING == current_state) { + r = tts_stop (_tts); + if (TTS_ERROR_NONE != r) { + LOGW ("Fail to stop TTS : ret(%d)\n", r); + } + } + /* FIXME: Should support for all languages */ + r = tts_add_text (_tts, str, "en_US", TTS_VOICE_TYPE_FEMALE, TTS_SPEED_NORMAL, &utt_id); + if (TTS_ERROR_NONE == r) { + r = tts_play (_tts); + if (TTS_ERROR_NONE != r) { + LOGW ("Fail to play TTS : ret(%d)\n", r); + } + } + } +#endif +} + +/** + * @brief Mouse over (find focus object and play text by TTS) when screen reader is enabled. + * + * @param mouse_x Mouse X position. + * @param mouse_y Mouse Y position. + */ +static void ui_mouse_over (int mouse_x, int mouse_y) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + if (_candidate_window == NULL || _candidate_state != WINDOW_STATE_SHOW) + return; + + int x, y, width, height; + for (int i = 0; i < SCIM_LOOKUP_TABLE_MAX_PAGESIZE; ++i) { + if (_candidate_0 [i]) { + evas_object_geometry_get (_candidate_0 [i], &x, &y, &width, &height); + if (mouse_x >= x && mouse_x <= x + width && mouse_y >= y && mouse_y <= y + height) { + /* FIXME: Should consider emoji case */ + String mbs = utf8_wcstombs (g_isf_candidate_table.get_candidate_in_current_page (i)); + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " play candidate string: " << mbs << "\n"; + ui_play_tts (mbs.c_str ()); + return; + } + } + } + + String strTts = String (""); + if (_candidate_area_2_visible) { + evas_object_geometry_get (_close_btn, &x, &y, &width, &height); + if (mouse_x >= x && mouse_x <= x + width && mouse_y >= y && mouse_y <= y + height) + strTts = String ("close button"); + } else { + evas_object_geometry_get (_more_btn, &x, &y, &width, &height); + if (mouse_x >= x && mouse_x <= x + width && mouse_y >= y && mouse_y <= y + height) + strTts = String ("more button"); + } + if (strTts.length () > 0) + ui_play_tts (strTts.c_str ()); +} + +/** + * @brief Mouse click (find focus object and do click event) when screen reader is enabled. + * + * @param mouse_x Mouse X position. + * @param mouse_y Mouse Y position. + */ +static void ui_mouse_click (int mouse_x, int mouse_y) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + if (_candidate_window == NULL || _candidate_state != WINDOW_STATE_SHOW) + return; + + int x, y, width, height; + for (int i = 0; i < SCIM_LOOKUP_TABLE_MAX_PAGESIZE; ++i) { + if (_candidate_0 [i]) { + evas_object_geometry_get (_candidate_0 [i], &x, &y, &width, &height); + if (mouse_x >= x && mouse_x <= x + width && mouse_y >= y && mouse_y <= y + height) { + Evas_Event_Mouse_Down event_info; + event_info.canvas.x = mouse_x; + event_info.canvas.y = mouse_y; + ui_mouse_button_pressed_cb (GINT_TO_POINTER ((i << 8) + ISF_EFL_CANDIDATE_0), NULL, NULL, &event_info); + ui_mouse_button_released_cb (GINT_TO_POINTER (i), NULL, NULL, &event_info); + return; + } + } + } + + if (_candidate_area_2_visible) { + evas_object_geometry_get (_close_btn, &x, &y, &width, &height); + if (mouse_x >= x && mouse_x <= x + width && mouse_y >= y && mouse_y <= y + height) { + ui_candidate_window_close_button_cb (NULL, NULL, NULL, NULL); + } + } else { + evas_object_geometry_get (_more_btn, &x, &y, &width, &height); + if (mouse_x >= x && mouse_x <= x + width && mouse_y >= y && mouse_y <= y + height) { + ui_candidate_window_more_button_cb (NULL, NULL, NULL, NULL); + } + } +} + +/** + * @brief Create preedit window. + */ +static void ui_create_preedit_window (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + _preedit_width = 100; + _preedit_height = _preedit_height * _height_rate; + if (_preedit_window == NULL) { + _preedit_window = efl_create_window ("preedit", "Preedit Window"); + evas_object_resize (_preedit_window, _preedit_width, _preedit_height); + + int preedit_font_size = (int)(32 * _width_rate); + + _preedit_text = edje_object_add (evas_object_evas_get (_preedit_window)); + edje_object_file_set (_preedit_text, _candidate_edje_file.c_str (), "preedit_text"); + edje_object_text_class_set (_preedit_text, "preedit_text_class", _candidate_font_name.c_str (), preedit_font_size); + evas_object_size_hint_fill_set (_preedit_text, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_size_hint_weight_set (_preedit_text, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_resize_object_add (_preedit_window, _preedit_text); + evas_object_show (_preedit_text); + + _tmp_preedit_text = evas_object_text_add (evas_object_evas_get (_preedit_window)); + evas_object_text_font_set (_tmp_preedit_text, _candidate_font_name.c_str (), preedit_font_size); + } +} + +/** + * @brief Create native style candidate window. + */ +static void ui_create_native_candidate_window (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + _candidate_port_width = _screen_width; + _candidate_port_height_min = 84 * _height_rate * _candidate_port_line; + _candidate_port_height_min_2 = 84 * _height_rate + _candidate_port_height_min; + _candidate_port_height_max = 444 * _height_rate + _candidate_port_height_min; + _candidate_port_height_max_2 = 84 * _height_rate + _candidate_port_height_max; + _candidate_land_width = _screen_height; + _candidate_land_height_min = 84 * _width_rate; + _candidate_land_height_min_2 = 168 * _width_rate; + _candidate_land_height_max = 316 * _width_rate + _candidate_land_height_min; + _candidate_land_height_max_2 = 426 * _width_rate; + + _candidate_scroll_0_width_min= _screen_width; + _candidate_scroll_0_width_max= _screen_height; + _candidate_scroll_width_min = _screen_width; + _candidate_scroll_width_max = _screen_height; + _candidate_scroll_height_min = 252 * _width_rate; + _candidate_scroll_height_max = 420 * _height_rate; + + _candidate_area_1_pos [0] = 0 * _width_rate; + _candidate_area_1_pos [1] = 2 * _height_rate; + _more_btn_pos [0] = 628 * _width_rate; + _more_btn_pos [1] = 12 * _height_rate; + _more_btn_pos [2] = 1188 * _height_rate; + _more_btn_pos [3] = 12 * _width_rate; + _close_btn_pos [0] = 628 * _width_rate; + _close_btn_pos [1] = 12 * _height_rate; + _close_btn_pos [2] = 1188 * _height_rate; + _close_btn_pos [3] = 12 * _width_rate; + + _aux_height = 84 * _height_rate - 2; + _aux_port_width = _screen_width; + _aux_land_width = _screen_height; + + _item_min_height = 84 * _height_rate - 2; + + /* Create candidate window */ + if (_candidate_window == NULL) { + _candidate_window = efl_create_window ("candidate", "Prediction Window"); + if (_candidate_angle == 90 || _candidate_angle == 270) { + _candidate_width = _candidate_land_width; + _candidate_height = _candidate_land_height_min; + } else { + _candidate_width = _candidate_port_width; + _candidate_height = _candidate_port_height_min; + } + + // FIXME: Ecore_X dependency. + + /* Add background */ + _candidate_bg = edje_object_add (evas_object_evas_get (_candidate_window)); + edje_object_file_set (_candidate_bg, _candidate_edje_file.c_str (), "candidate_bg"); + evas_object_size_hint_weight_set (_candidate_bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_resize_object_add (_candidate_window, _candidate_bg); + evas_object_show (_candidate_bg); + + /* Create _candidate_0 scroller */ + _candidate_0_scroll = elm_scroller_add (_candidate_window); + elm_scroller_bounce_set (_candidate_0_scroll, EINA_TRUE, EINA_FALSE); + elm_scroller_policy_set (_candidate_0_scroll, ELM_SCROLLER_POLICY_AUTO, ELM_SCROLLER_POLICY_OFF); + evas_object_resize (_candidate_0_scroll, _candidate_scroll_0_width_min, (_item_min_height+2)*_candidate_port_line-2); + evas_object_move (_candidate_0_scroll, _candidate_area_1_pos[0], _candidate_area_1_pos[1]); + _candidate_0_table = elm_table_add (_candidate_window); + evas_object_size_hint_weight_set (_candidate_0_table, 0.0, 0.0); + evas_object_size_hint_align_set (_candidate_0_table, 0.0, 0.0); + elm_table_padding_set (_candidate_0_table, 0, 0); + elm_object_content_set (_candidate_0_scroll, _candidate_0_table); + evas_object_show (_candidate_0_table); + _candidate_area_1 = _candidate_0_scroll; + + /* Create more button */ + _more_btn = edje_object_add (evas_object_evas_get (_candidate_window)); + if (_ise_width == 0 && _ise_height == 0) + edje_object_file_set (_more_btn, _candidate_edje_file.c_str (), "close_button"); + else + edje_object_file_set (_more_btn, _candidate_edje_file.c_str (), "more_button"); + evas_object_move (_more_btn, _more_btn_pos[0], _more_btn_pos[1]); + evas_object_resize (_more_btn, 80 * _width_rate, 64 * _height_rate); + evas_object_event_callback_add (_more_btn, EVAS_CALLBACK_MOUSE_UP, ui_candidate_window_more_button_cb, NULL); + + /* Add scroller background */ + _candidate_scroll_width = _candidate_scroll_width_min; + _scroller_bg = edje_object_add (evas_object_evas_get (_candidate_window)); + edje_object_file_set (_scroller_bg, _candidate_edje_file.c_str (), "scroller_bg"); + evas_object_size_hint_weight_set (_scroller_bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_resize (_scroller_bg, _candidate_scroll_width, _candidate_scroll_height_max + 6); + evas_object_move (_scroller_bg, 0, _candidate_port_height_min); + + /* Create vertical scroller */ + _candidate_scroll = elm_scroller_add (_candidate_window); + elm_scroller_bounce_set (_candidate_scroll, 0, 1); + elm_scroller_policy_set (_candidate_scroll, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO); + evas_object_resize (_candidate_scroll, _candidate_scroll_width, _candidate_scroll_height_max); + evas_object_resize (_scroller_bg, _candidate_scroll_width, _candidate_scroll_height_max + 6); + elm_scroller_page_size_set (_candidate_scroll, 0, _item_min_height+_v_padding); + evas_object_move (_candidate_scroll, 0, _candidate_port_height_min); + _candidate_table = elm_table_add (_candidate_window); + evas_object_size_hint_weight_set (_candidate_table, 0.0, 0.0); + evas_object_size_hint_align_set (_candidate_table, 0.0, 0.0); + elm_table_padding_set (_candidate_table, 0, 0); + elm_object_content_set (_candidate_scroll, _candidate_table); + evas_object_show (_candidate_table); + _candidate_area_2 = _candidate_scroll; + + /* Create close button */ + _close_btn = edje_object_add (evas_object_evas_get (_candidate_window)); + if (_ise_width == 0 && _ise_height == 0) + edje_object_file_set (_close_btn, _candidate_edje_file.c_str (), "more_button"); + else + edje_object_file_set (_close_btn, _candidate_edje_file.c_str (), "close_button"); + evas_object_move (_close_btn, _close_btn_pos[0], _close_btn_pos[1]); + evas_object_resize (_close_btn, 80 * _width_rate, 64 * _height_rate); + evas_object_event_callback_add (_close_btn, EVAS_CALLBACK_MOUSE_UP, ui_candidate_window_close_button_cb, NULL); + + _tmp_candidate_text = evas_object_text_add (evas_object_evas_get (_candidate_window)); + evas_object_text_font_set (_tmp_candidate_text, _candidate_font_name.c_str (), _candidate_font_size); + + /* Create aux */ + _aux_area = elm_scroller_add (_candidate_window); + elm_scroller_bounce_set (_aux_area, 1, 0); + elm_scroller_policy_set (_aux_area, ELM_SCROLLER_POLICY_AUTO, ELM_SCROLLER_POLICY_OFF); + evas_object_resize (_aux_area, _aux_port_width, _aux_height); + evas_object_move (_aux_area, _candidate_area_1_pos[0], _candidate_area_1_pos[1]); + + _aux_table = elm_table_add (_candidate_window); + elm_object_content_set (_aux_area, _aux_table); + elm_table_padding_set (_aux_table, 0, 0); + evas_object_size_hint_weight_set (_aux_table, 0.0, 0.0); + evas_object_size_hint_align_set (_aux_table, 0.0, 0.0); + evas_object_show (_aux_table); + + _aux_line = edje_object_add (evas_object_evas_get (_candidate_window)); + edje_object_file_set (_aux_line, _candidate_edje_file.c_str (), "popup_line"); + evas_object_resize (_aux_line, _candidate_port_width, 2); + evas_object_move (_aux_line, 0, _aux_height + 2); + + _tmp_aux_text = evas_object_text_add (evas_object_evas_get (_candidate_window)); + evas_object_text_font_set (_tmp_aux_text, _candidate_font_name.c_str (), _aux_font_size); + } + + flush_memory (); +} + +/** + * @brief Create candidate window. + * + * @return void + */ +static void ui_create_candidate_window (void) +{ + check_time ("\nEnter ui_create_candidate_window"); + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + ui_destroy_candidate_window (); + + _candidate_x = 0; + _candidate_y = 0; + _candidate_angle = 0; + + ui_create_native_candidate_window (); + + unsigned int set = 1; + // FIXME: + + int angle = efl_get_angle_for_app_window (); + if (_candidate_angle != angle) { + _candidate_angle = angle; + ui_candidate_window_rotate (angle); + } else { + ui_settle_candidate_window (); + } + + check_time ("Exit ui_create_candidate_window"); +} + +/** + * @brief Destroy candidate window. + * + * @return void + */ +static void ui_destroy_candidate_window (void) +{ + check_time ("Enter ui_destroy_candidate_window"); + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + /* Delete candidate items, popup lines and seperator items */ + for (int i = 0; i < SCIM_LOOKUP_TABLE_MAX_PAGESIZE; ++i) { + if (_candidate_0 [i]) { + evas_object_del (_candidate_0 [i]); + _candidate_0 [i] = NULL; + } + if (_candidate_items [i]) { + evas_object_del (_candidate_items [i]); + _candidate_items [i] = NULL; + } + + if (_seperate_0 [i]) { + evas_object_del (_seperate_0 [i]); + _seperate_0 [i] = NULL; + } + if (_seperate_items [i]) { + evas_object_del (_seperate_items [i]); + _seperate_items [i] = NULL; + } + + if (_line_0 [i]) { + evas_object_del (_line_0 [i]); + _line_0 [i] = NULL; + } + if (_line_items [i]) { + evas_object_del (_line_items [i]); + _line_items [i] = NULL; + } + } + + _aux_items.clear (); + _aux_seperates.clear (); + /* Delete candidate window */ + if (_candidate_window) { + LOGD ("calling ui_candidate_hide (true)"); + ui_candidate_hide (true); + + evas_object_del (_candidate_window); + _candidate_window = NULL; + _aux_area = NULL; + _candidate_area_1 = NULL; + _candidate_area_2 = NULL; + _scroller_bg = NULL; + } + + if (_preedit_window) { + evas_object_del (_preedit_text); + _preedit_text = NULL; + + evas_object_hide (_preedit_window); + evas_object_del (_preedit_window); + _preedit_window = NULL; + } + + flush_memory (); + check_time ("Exit ui_destroy_candidate_window"); +} + +/** + * @brief Settle candidate window position. + */ +static void ui_settle_candidate_window (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + if (!_candidate_window) + return; + + /* If both ISE and candidate window are going to be hidden, + let's just not move our candidate window */ + if (_ise_state == WINDOW_STATE_WILL_HIDE && _candidate_state == WINDOW_STATE_WILL_HIDE) + return; + + int spot_x, spot_y; + int x, y, width, height; + int pos_x = 0, pos_y = 0, ise_width = 0, ise_height = 0; + bool get_geometry_result = false; + bool reverse = false; + + /* Get candidate window position */ + ecore_evas_geometry_get (ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window)), &x, &y, &width, &height); + + //FIXME: Ecore_X dependency. + + if ((_ise_state != WINDOW_STATE_SHOW && _ise_state != WINDOW_STATE_WILL_HIDE) || + get_geometry_result == false) { + ise_height = 0; + ise_width = 0; + } + + int height2 = ui_candidate_get_valid_height (); + + if (_candidate_mode == FIXED_CANDIDATE_WINDOW) { + if (_candidate_angle == 90) { + spot_x = _screen_width - ise_height - height2; + spot_y = 0; + } else if (_candidate_angle == 270) { + spot_x = ise_height - (_candidate_height - height2); + spot_y = 0; + } else if (_candidate_angle == 180) { + spot_x = 0; + spot_y = ise_height - (_candidate_height - height2); + } else { + spot_x = 0; + spot_y = _screen_height - ise_height - height2; + } + } else { + spot_x = _spot_location_x; + spot_y = _spot_location_y; + + rectinfo ise_rect = {0, 0, ise_width, ise_height}; + if (_candidate_angle == 90 || _candidate_angle == 270) { + if (ise_rect.height <= (uint32)0 || ise_rect.height >= (uint32)_screen_width) + ise_rect.height = ISE_DEFAULT_HEIGHT_LANDSCAPE * _width_rate; + } else { + if (ise_rect.height <= (uint32)0 || ise_rect.height >= (uint32) _screen_height) + ise_rect.height = ISE_DEFAULT_HEIGHT_PORTRAIT * _height_rate; + } + + int nOffset = _candidate_port_height_min / 3; + if (_candidate_angle == 270) { + if (ise_rect.height > 0 && spot_y + height2 > _screen_width - (int)ise_rect.height + nOffset) { + reverse = true; + spot_x = _screen_width - _spot_location_top_y - (_candidate_height - height2); + } else { + spot_x = _screen_width - _spot_location_y - _candidate_height; + } + } else if (_candidate_angle == 90) { + if (ise_rect.height > 0 && spot_y + height2 > _screen_width - (int)ise_rect.height + nOffset) { + reverse = true; + spot_x = _spot_location_top_y - height2; + } else { + spot_x = spot_y; + } + } else if (_candidate_angle == 180) { + if (ise_rect.height > 0 && spot_y + height2 > _screen_height - (int)ise_rect.height + nOffset) { + reverse = true; + spot_y = _screen_height - _spot_location_top_y - (_candidate_height - height2); + } else { + spot_y = _screen_height - _spot_location_y - _candidate_height; + } + } else { + if (ise_rect.height > 0 && spot_y + height2 > _screen_height - (int)ise_rect.height + nOffset) { + reverse = true; + spot_y = _spot_location_top_y - height2; + } else { + spot_y = spot_y; + } + } + } + if (_candidate_angle == 90) { + spot_y = (_screen_height - _candidate_width) / 2; + spot_x = spot_x < _indicator_height ? _indicator_height : spot_x; + if (spot_x > _screen_width - _candidate_height) + spot_x = _screen_width - _candidate_height; + } else if (_candidate_angle == 270) { + spot_y = (_screen_height - _candidate_width) / 2; + spot_x = spot_x < 0 ? 0 : spot_x; + if (spot_x > _screen_width - (_indicator_height+_candidate_height)) + spot_x = _screen_width - (_indicator_height+_candidate_height); + } else if (_candidate_angle == 180) { + spot_x = (_screen_width - _candidate_width) / 2; + spot_y = spot_y < 0 ? 0 : spot_y; + if (spot_y > _screen_height - (_indicator_height+_candidate_height)) + spot_y = _screen_height - (_indicator_height+_candidate_height); + } else { + spot_x = (_screen_width - _candidate_width) / 2; + spot_y = spot_y < _indicator_height ? _indicator_height : spot_y; + if (spot_y > _screen_height - _candidate_height) + spot_y = _screen_height - _candidate_height; + } + + if (spot_x != x || spot_y != y) { + _candidate_x = spot_x; + _candidate_y = spot_y; + evas_object_move (_candidate_window, spot_x, spot_y); + LOGD ("Moving candidate window to : %d %d", spot_x, spot_y); + if (_preedit_window) { + if (_candidate_angle == 90) { + spot_x -= _preedit_height; + spot_y = _screen_height - _preedit_width; + } else if (_candidate_angle == 270) { + spot_x += height2; + } else if (_candidate_angle == 180) { + spot_x = _screen_width - _preedit_width; + spot_y += height2; + } else { + spot_y -= _preedit_height; + } + evas_object_move (_preedit_window, spot_x, spot_y); + } + } +} + +////////////////////////////////////////////////////////////////////// +// End of Candidate Functions +////////////////////////////////////////////////////////////////////// + +/** + * @brief Set transient for app window. + * + * @param window The Ecore_X_Window handler of app window. + */ +static void efl_set_transient_for_app_window (Ecore_X_Window window) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + /* Set a transient window for window stack */ + //FIXME: +} + +/** + * @brief Get angle for app window. + * + * @param win_obj The Evas_Object handler of application window. + * + * @return The angle of app window. + */ +static int efl_get_angle_for_app_window () +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + int ret; + int count; + int angle = 0; + unsigned char *prop_data = NULL; + + //FIXME: + + return angle; +} + +/** + * @brief Get angle for ise window. + * + * @param win_obj The Evas_Object handler of ise window. + * + * @return The angle of ise window. + */ +static int efl_get_angle_for_ise_window () +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + int ret; + int count; + int angle = 0; + unsigned char *prop_data = NULL; + + //FIXME: + + return angle; +} + +/** + * @brief Set showing effect for application window. + * + * @param win The Evas_Object handler of application window. + * @param strEffect The pointer of effect string. + */ +static void efl_set_showing_effect_for_app_window (Evas_Object *win, const char* strEffect) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + //FIXME: +} + +/** + * @brief Create elementary window. + * + * @param strWinName The window name. + * @param strEffect The window effect string. + * + * @return The window pointer + */ +static Evas_Object *efl_create_window (const char *strWinName, const char *strEffect) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + Evas_Object *win = elm_win_add (NULL, strWinName, ELM_WIN_UTILITY); + elm_win_title_set (win, strWinName); + + /* set window properties */ + elm_win_autodel_set (win, EINA_TRUE); + elm_object_focus_allow_set (win, EINA_FALSE); + elm_win_borderless_set (win, EINA_TRUE); + elm_win_alpha_set (win, EINA_TRUE); + elm_win_prop_focus_skip_set (win, EINA_TRUE); + efl_set_showing_effect_for_app_window (win, strEffect); + + //const char *szProfile[] = {"mobile", ""}; + //elm_win_profiles_set (win, szProfile, 1); + + return win; +} + +/** + * @brief Create elementary control window. + * + * @return EINA_TRUE if successful, otherwise return EINA_FALSE + */ +static Eina_Bool efl_create_control_window (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + /* WMSYNC, #1 Creating and registering control window */ + // FIXME: + return EINA_TRUE; +} + +/** + * @brief Get screen resolution. + * + * @param width The screen width. + * @param height The screen height. + */ +static void efl_get_screen_resolution (int &width, int &height) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + width = 720; + height = 1280; +} + +////////////////////////////////////////////////////////////////////// +// Start of PanelAgent Functions +////////////////////////////////////////////////////////////////////// + +/** + * @brief Initialize panel agent. + * + * @param config The config string for PanelAgent. + * @param display The current display. + * @param resident The variable indicates whether panel will be resident. + * + * @return true if initialize is successful, otherwise return false. + */ +static bool initialize_panel_agent (const String &config, const String &display, bool resident) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + _panel_agent = new PanelAgent (); + + if (!_panel_agent || !_panel_agent->initialize (config, display, resident)) + return false; + + _panel_agent->signal_connect_reload_config (slot (slot_reload_config)); + _panel_agent->signal_connect_focus_in (slot (slot_focus_in)); + _panel_agent->signal_connect_focus_out (slot (slot_focus_out)); + _panel_agent->signal_connect_expand_candidate (slot (slot_expand_candidate)); + _panel_agent->signal_connect_contract_candidate (slot (slot_contract_candidate)); + _panel_agent->signal_connect_set_candidate_ui (slot (slot_set_candidate_style)); + _panel_agent->signal_connect_update_factory_info (slot (slot_update_factory_info)); + _panel_agent->signal_connect_update_spot_location (slot (slot_update_spot_location)); + _panel_agent->signal_connect_update_input_context (slot (slot_update_input_context)); + _panel_agent->signal_connect_update_ise_geometry (slot (slot_update_ise_geometry)); + _panel_agent->signal_connect_show_preedit_string (slot (slot_show_preedit_string)); + _panel_agent->signal_connect_show_aux_string (slot (slot_show_aux_string)); + _panel_agent->signal_connect_show_lookup_table (slot (slot_show_candidate_table)); + _panel_agent->signal_connect_hide_preedit_string (slot (slot_hide_preedit_string)); + _panel_agent->signal_connect_hide_aux_string (slot (slot_hide_aux_string)); + _panel_agent->signal_connect_hide_lookup_table (slot (slot_hide_candidate_table)); + _panel_agent->signal_connect_update_preedit_string (slot (slot_update_preedit_string)); + _panel_agent->signal_connect_update_preedit_caret (slot (slot_update_preedit_caret)); + _panel_agent->signal_connect_update_aux_string (slot (slot_update_aux_string)); + _panel_agent->signal_connect_update_lookup_table (slot (slot_update_candidate_table)); + _panel_agent->signal_connect_select_candidate (slot (slot_select_candidate)); + _panel_agent->signal_connect_get_candidate_geometry (slot (slot_get_candidate_geometry)); + _panel_agent->signal_connect_get_input_panel_geometry (slot (slot_get_input_panel_geometry)); + _panel_agent->signal_connect_set_active_ise_by_uuid (slot (slot_set_active_ise)); + _panel_agent->signal_connect_get_ise_list (slot (slot_get_ise_list)); + _panel_agent->signal_connect_get_ise_information (slot (slot_get_ise_information)); + _panel_agent->signal_connect_get_keyboard_ise_list (slot (slot_get_keyboard_ise_list)); + _panel_agent->signal_connect_get_language_list (slot (slot_get_language_list)); + _panel_agent->signal_connect_get_all_language (slot (slot_get_all_language)); + _panel_agent->signal_connect_get_ise_language (slot (slot_get_ise_language)); + _panel_agent->signal_connect_get_ise_info_by_uuid (slot (slot_get_ise_info)); + _panel_agent->signal_connect_set_keyboard_ise (slot (slot_set_keyboard_ise)); + _panel_agent->signal_connect_get_keyboard_ise (slot (slot_get_keyboard_ise)); + _panel_agent->signal_connect_accept_connection (slot (slot_accept_connection)); + _panel_agent->signal_connect_close_connection (slot (slot_close_connection)); + _panel_agent->signal_connect_exit (slot (slot_exit)); + + _panel_agent->signal_connect_register_helper_properties (slot (slot_register_helper_properties)); + _panel_agent->signal_connect_show_ise (slot (slot_show_ise)); + _panel_agent->signal_connect_hide_ise (slot (slot_hide_ise)); + + _panel_agent->signal_connect_will_hide_ack (slot (slot_will_hide_ack)); + + _panel_agent->signal_connect_candidate_will_hide_ack (slot (slot_candidate_will_hide_ack)); + _panel_agent->signal_connect_get_ise_state (slot (slot_get_ise_state)); + + std::vector load_ise_list; + _panel_agent->get_active_ise_list (load_ise_list); + + return true; +} + +/** + * @brief Reload config slot function for PanelAgent. + */ +static void slot_reload_config (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + if (!_config.null ()) + _config->reload (); +} + +/** + * @brief Focus in slot function for PanelAgent. + */ +static void slot_focus_in (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + ui_candidate_delete_destroy_timer (); +} + +/** + * @brief Focus out slot function for PanelAgent. + */ +static void slot_focus_out (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + ui_candidate_delete_destroy_timer (); + _destroy_timer = ecore_timer_add (ISF_CANDIDATE_DESTROY_DELAY, ui_candidate_destroy_timeout, NULL); +} + +/** + * @brief Expand candidate slot function for PanelAgent. + */ +static void slot_expand_candidate (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + if (_candidate_mode == SOFT_CANDIDATE_WINDOW) + return; + + if (_candidate_area_2 && !_candidate_area_2_visible) + ui_candidate_window_more_button_cb (NULL, NULL, NULL, NULL); +} + +/** + * @brief Contract candidate slot function for PanelAgent. + */ +static void slot_contract_candidate (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + if (_candidate_mode == SOFT_CANDIDATE_WINDOW) + return; + + ui_candidate_window_close_button_cb (NULL, NULL, NULL, NULL); +} + +/** + * @brief Set candidate style slot function for PanelAgent. + * + * @param portrait_line The displayed line number for portrait. + * @param mode The candidate mode. + */ +static void slot_set_candidate_style (int portrait_line, int mode) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " display_line:" << portrait_line << " mode:" << mode << "\n"; + if ((portrait_line != _candidate_port_line) || (mode != _candidate_mode)) { + _candidate_mode = (ISF_CANDIDATE_MODE_T)mode; + _candidate_port_line = (ISF_CANDIDATE_PORTRAIT_LINE_T)portrait_line; + + if (_candidate_mode == SOFT_CANDIDATE_WINDOW) { + if (_candidate_window) + ui_destroy_candidate_window (); + + return; + } + + if (_candidate_window) + ui_create_candidate_window (); + } +} + +/** + * @brief Update keyboard ISE information slot function for PanelAgent. + * + * @param info The information of current Keyboard ISE. + */ +static void slot_update_factory_info (const PanelFactoryInfo &info) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + String ise_name = info.name; + String ise_icon = info.icon; + + String old_ise = _panel_agent->get_current_ise_name (); + if (old_ise != ise_name) { + int hw_kbd_detect = _config->read (ISF_CONFIG_HARDWARE_KEYBOARD_DETECT, 0); + if (hw_kbd_detect && _candidate_window) { + ui_destroy_candidate_window (); + } + } + + TOOLBAR_MODE_T mode = _panel_agent->get_current_toolbar_mode (); + + if (TOOLBAR_HELPER_MODE == mode) + ise_name = _names[get_ise_index (_panel_agent->get_current_helper_uuid ())]; + + if (ise_name.length () > 0) + _panel_agent->set_current_ise_name (ise_name); +} + +/** + * @brief Update cursor position slot function for PanelAgent. + * + * @param x The x position of current cursor. + * @param y The bottom y position of current cursor. + * @param top_y The top y position of current cursor. + */ +static void slot_update_spot_location (int x, int y, int top_y) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + if (x >= 0 && x < _screen_height && y >= 0 && y < _screen_height) { + _spot_location_x = x; + _spot_location_y = y; + _spot_location_top_y = top_y; + + ui_settle_candidate_window (); + } +} + +/** + * @brief The input context of ISE is changed. + * + * @param type The event type. + * @param value The event value. + */ +static void slot_update_input_context (int type, int value) +{ +} + +/** + * @brief Update ise geometry. + * + * @param x The x position in screen. + * @param y The y position in screen. + * @param width The ISE window width. + * @param height The ISE window height. + */ +static void slot_update_ise_geometry (int x, int y, int width, int height) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " x:" << x << " y:" << y << " width:" << width << " height:" << height << "...\n"; + + LOGD ("x : %d , y : %d , width : %d , height : %d", x, y, width, height); + + int hw_kbd_detect = _config->read (ISF_CONFIG_HARDWARE_KEYBOARD_DETECT, 0); + if (hw_kbd_detect) + return; + + int old_height = _ise_height; + + _ise_width = width; + _ise_height = height; + + if (_candidate_window && _candidate_state == WINDOW_STATE_SHOW) { + if (old_height != height) { + ui_settle_candidate_window (); + } + } + + if (old_height != height && _ise_state == WINDOW_STATE_SHOW) { + _ise_reported_geometry.valid = true; + _ise_reported_geometry.angle = efl_get_angle_for_ise_window (); + _ise_reported_geometry.geometry.pos_x = x; + _ise_reported_geometry.geometry.pos_y = y; + _ise_reported_geometry.geometry.width = width; + _ise_reported_geometry.geometry.height = height; + set_keyboard_geometry_atom_info (_app_window, _ise_reported_geometry.geometry); + _panel_agent->update_input_panel_event (ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, 0); + } +} + +/** + * @brief Show preedit slot function for PanelAgent. + */ +static void slot_show_preedit_string (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + if (_preedit_window == NULL) { + ui_create_preedit_window (); + int angle = efl_get_angle_for_app_window (); + elm_win_rotation_with_resize_set (_preedit_window, angle); + + /* Move preedit window according to candidate window position */ + if (_candidate_window) { + /* Get candidate window position */ + int x, y, width, height; + ecore_evas_geometry_get (ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window)), &x, &y, &width, &height); + + int height2 = ui_candidate_get_valid_height (); + if (angle == 90) { + x -= _preedit_height; + y = _screen_height - _preedit_width; + } else if (_candidate_angle == 270) { + x += height2; + } else if (_candidate_angle == 180) { + x = _screen_width - _preedit_width; + y += height2; + } else { + y -= _preedit_height; + } + evas_object_move (_preedit_window, x, y); + } + } + + if (evas_object_visible_get (_preedit_window)) + return; + + slot_show_candidate_table (); + evas_object_show (_preedit_window); +} + +/** + * @brief Show aux slot function for PanelAgent. + */ +static void slot_show_aux_string (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + if (_candidate_window == NULL) + ui_create_candidate_window (); + + if (_aux_area == NULL || _aux_area_visible) + return; + + evas_object_show (_aux_area); + _aux_area_visible = true; + ui_candidate_window_adjust (); + + LOGD ("calling ui_candidate_show ()"); + ui_candidate_show (); + ui_settle_candidate_window (); +} + +/** + * @brief Show candidate table slot function for PanelAgent. + */ +static void slot_show_candidate_table (void) +{ + int feedback_result = 0; + + if (_candidate_mode == SOFT_CANDIDATE_WINDOW) { + _panel_agent->helper_candidate_show (); + return; + } + + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + if (_candidate_window == NULL) + ui_create_candidate_window (); + + if (_candidate_state == WINDOW_STATE_SHOW && + (_candidate_area_1_visible || _candidate_area_2_visible)) { + efl_set_transient_for_app_window (elm_win_xwindow_get (_candidate_window)); + return; + } + + evas_object_show (_candidate_area_1); + _candidate_area_1_visible = true; + ui_candidate_window_adjust (); + + LOGD ("calling ui_candidate_show ()"); + ui_candidate_show (); + ui_settle_candidate_window (); + +#if HAVE_FEEDBACK + feedback_result = feedback_initialize (); + + if (FEEDBACK_ERROR_NONE == feedback_result) { + LOGD ("Feedback initialize successful"); + feedback_initialized = true; + } else { + LOGW ("Feedback initialize fail : %d",feedback_result); + feedback_initialized = false; + } +#endif +} + +/** + * @brief Hide preedit slot function for PanelAgent. + */ +static void slot_hide_preedit_string (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + if (!_preedit_window || !evas_object_visible_get (_preedit_window)) + return; + + evas_object_hide (_preedit_window); +} + +/** + * @brief Hide aux slot function for PanelAgent. + */ +static void slot_hide_aux_string (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + if (!_aux_area || !_aux_area_visible) + return; + + evas_object_hide (_aux_area); + _aux_area_visible = false; + elm_scroller_region_show (_aux_area, 0, 0, 10, 10); + ui_candidate_window_adjust (); + + LOGD ("calling ui_candidate_hide (false)"); + ui_candidate_hide (false); + ui_settle_candidate_window (); + + if (ui_candidate_can_be_hide ()) { + _candidate_show_requested = false; + LOGD ("setting _show_can didate_requested to FALSE"); + } +} + +/** + * @brief Hide candidate table slot function for PanelAgent. + */ +static void slot_hide_candidate_table (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + int feedback_result = 0; + + if (_candidate_mode == SOFT_CANDIDATE_WINDOW) { + _panel_agent->helper_candidate_hide (); + return; + } + + if (!_candidate_area_1 || _candidate_state == WINDOW_STATE_WILL_HIDE) + return; + + if (_candidate_area_1_visible || _candidate_area_2_visible) { + bool bForce = false; + if (_candidate_area_1_visible) { + if (_aux_area_visible) { + evas_object_hide (_candidate_area_1); + _candidate_area_1_visible = false; + evas_object_hide (_more_btn); + } else { + /* Let's not actually hide the _candidate_area_1 object, for the case that + even if the application replies CANDIDATE_WILL_HIDE_ACK a little late, + it is better to display the previous candidates instead of blank screen */ + _candidate_area_1_visible = false; + bForce = true; + } + } + if (_candidate_area_2_visible) { + evas_object_hide (_candidate_area_2); + _candidate_area_2_visible = false; + evas_object_hide (_scroller_bg); + evas_object_hide (_close_btn); + _panel_agent->candidate_more_window_hide (); + } + ui_candidate_window_adjust (); + + LOGD ("calling ui_candidate_hide (%d, true, true)", bForce); + ui_candidate_hide (bForce, true, true); + ui_settle_candidate_window (); + } + +#if HAVE_FEEDBACK + feedback_result = feedback_deinitialize (); + + if (FEEDBACK_ERROR_NONE == feedback_result) + LOGD ("Feedback deinitialize successful"); + else + LOGW ("Feedback deinitialize fail : %d", feedback_result); + + feedback_initialized = false; +#endif + + if (ui_candidate_can_be_hide ()) { + _candidate_show_requested = false; + LOGD ("setting _show_can didate_requested to FALSE"); + } +} + +/** + * @brief Update preedit slot function for PanelAgent. + * + * @param str The new preedit string. + * @param attrs The attribute list of new preedit string. + */ +static void slot_update_preedit_string (const String &str, const AttributeList &attrs, int caret) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " string=" << str << "\n"; + + if (str.length () <= 0) + return; + + if (_preedit_window == NULL || !evas_object_visible_get (_preedit_window)) { + slot_show_preedit_string (); + } + + int x, y, width, height, candidate_width; + evas_object_text_text_set (_tmp_preedit_text, str.c_str ()); + evas_object_geometry_get (_tmp_preedit_text, &x, &y, &width, &height); + ecore_evas_geometry_get (ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window)), &x, &y, &candidate_width, &height); + _preedit_width = (width + ISF_PREEDIT_BORDER * 2) < candidate_width ? (width + ISF_PREEDIT_BORDER * 2) : candidate_width; + + /* Resize preedit window and avoid text blink */ + int old_width, old_height; + evas_object_geometry_get (_preedit_window, &x, &y, &old_width, &old_height); + if (old_width < _preedit_width) { + evas_object_resize (_preedit_window, _preedit_width, _preedit_height); + edje_object_part_text_set (_preedit_text, "preedit", str.c_str ()); + } else { + edje_object_part_text_set (_preedit_text, "preedit", str.c_str ()); + evas_object_resize (_preedit_window, _preedit_width, _preedit_height); + } + + /* Move preedit window */ + if (_candidate_angle == 90 || _candidate_angle == 180) { + ecore_evas_geometry_get (ecore_evas_ecore_evas_get (evas_object_evas_get (_preedit_window)), &x, &y, &width, &height); + if (_candidate_angle == 90) { + y = _screen_height - _preedit_width; + } else if (_candidate_angle == 180) { + x = _screen_width - _preedit_width; + } + evas_object_move (_preedit_window, x, y); + } +} + +/** + * @brief Update caret slot function for PanelAgent. + * + * @param caret The caret position. + */ +static void slot_update_preedit_caret (int caret) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " caret=" << caret << "\n"; +} + +/** + * @brief Set hightlight text color and background color for edje object. + * + * @param item The edje object pointer. + * @param nForeGround The text color. + * @param nBackGround The background color. + * @param bSetBack The flag for background color. + */ +static void set_highlight_color (Evas_Object *item, uint32 nForeGround, uint32 nBackGround, bool bSetBack) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + int r, g, b, a, r2, g2, b2, a2, r3, g3, b3, a3; + if (edje_object_color_class_get (item, "text_color", &r, &g, &b, &a, &r2, &g2, &b2, &a2, &r3, &g3, &b3, &a3)) { + r = SCIM_RGB_COLOR_RED(nForeGround); + g = SCIM_RGB_COLOR_GREEN(nForeGround); + b = SCIM_RGB_COLOR_BLUE(nForeGround); + edje_object_color_class_set (item, "text_color", r, g, b, a, r2, g2, b2, a2, r3, g3, b3, a3); + } + if (bSetBack && edje_object_color_class_get (item, "rect_color", &r, &g, &b, &a, &r2, &g2, &b2, &a2, &r3, &g3, &b3, &a3)) { + r = SCIM_RGB_COLOR_RED(nBackGround); + g = SCIM_RGB_COLOR_GREEN(nBackGround); + b = SCIM_RGB_COLOR_BLUE(nBackGround); + edje_object_color_class_set (item, "rect_color", r, g, b, 255, r2, g2, b2, a2, r3, g3, b3, a3); + } +} + +/** + * @brief Update aux slot function for PanelAgent. + * + * @param str The new aux string. + * @param attrs The attribute list of new aux string. + */ +static void slot_update_aux_string (const String &str, const AttributeList &attrs) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + if (_candidate_window == NULL) + ui_create_candidate_window (); + + if (!_aux_area || (str.length () <= 0)) + return; + + if (!_aux_area_visible) { + LOGD ("calling ui_candidate_show ()"); + ui_candidate_show (); + slot_show_aux_string (); + } + + int x, y, width, height, item_width = 0; + unsigned int window_width = 0, count = 0, i; + + Evas_Object *aux_edje = NULL; + + /* Get highlight item index */ + int aux_index = -1, aux_start = 0, aux_end = 0; + String strAux = str; + bool bSetBack = false; + uint32 nForeGround = SCIM_RGB_COLOR(62, 207, 255); + uint32 nBackGround = SCIM_RGB_COLOR(0, 0, 0); + for (AttributeList::const_iterator ait = attrs.begin (); ait != attrs.end (); ++ait) { + if (aux_index == -1 && ait->get_type () == SCIM_ATTR_DECORATE) { + aux_index = ait->get_value (); + } else if (ait->get_type () == SCIM_ATTR_FOREGROUND) { + nForeGround = ait->get_value (); + } else if (ait->get_type () == SCIM_ATTR_BACKGROUND) { + nBackGround = ait->get_value (); + bSetBack = true; + } + } + + std::vector aux_list; + scim_split_string_list (aux_list, strAux, '|'); + + if (_aux_items.size () > 0) { + for (i = 0; i < _aux_items.size (); i++) + evas_object_del (_aux_items [i]); + _aux_items.clear (); + } + if (_aux_seperates.size () > 0) { + for (i = 0; i < _aux_seperates.size (); i++) + evas_object_del (_aux_seperates [i]); + _aux_seperates.clear (); + } + + int seperate_width = 4; + int seperate_height = 52 * _height_rate; + Evas *evas = evas_object_evas_get (_candidate_window); + for (i = 0; i < aux_list.size (); i++) { + if (i > 0) { + Evas_Object *seperate_item = edje_object_add (evas); + edje_object_file_set (seperate_item, _candidate_edje_file.c_str (), "seperate_line"); + evas_object_size_hint_min_set (seperate_item, seperate_width, seperate_height); + elm_table_pack (_aux_table, seperate_item, 2 * i - 1, 0, 1, 1); + evas_object_show (seperate_item); + _aux_seperates.push_back (seperate_item); + } + + count++; + aux_edje = edje_object_add (evas); + edje_object_file_set (aux_edje, _candidate_edje_file.c_str (), "aux"); + edje_object_text_class_set (aux_edje, "aux_text_class", _candidate_font_name.c_str (), _aux_font_size); + edje_object_part_text_set (aux_edje, "aux", aux_list [i].c_str ()); + elm_table_pack (_aux_table, aux_edje, 2 * i, 0, 1, 1); + evas_object_event_callback_add (aux_edje, EVAS_CALLBACK_MOUSE_DOWN, ui_mouse_button_pressed_cb, GINT_TO_POINTER ((i << 8) + ISF_EFL_AUX)); + evas_object_event_callback_add (aux_edje, EVAS_CALLBACK_MOUSE_UP, ui_mouse_button_released_cb, GINT_TO_POINTER (i)); + evas_object_event_callback_add (aux_edje, EVAS_CALLBACK_MOUSE_MOVE, ui_mouse_moved_cb, GINT_TO_POINTER (ISF_EFL_AUX)); + evas_object_show (aux_edje); + _aux_items.push_back (aux_edje); +/* if (i == (unsigned int)aux_index) + edje_object_signal_emit (aux_edje, "aux,state,selected", "aux"); + else + edje_object_signal_emit (aux_edje, "aux,state,unselected", "aux"); +*/ + evas_object_text_text_set (_tmp_aux_text, aux_list [i].c_str ()); + evas_object_geometry_get (_tmp_aux_text, &x, &y, &width, &height); + item_width = width + 2*_blank_width; + item_width = item_width > _item_min_width ? item_width : _item_min_width; + evas_object_size_hint_min_set (aux_edje, item_width, _aux_height); + if (aux_index == (int)i || (aux_index == -1 && i == 0)) { + aux_start = window_width; + aux_end = window_width + item_width; + } + window_width = window_width + item_width + 4; + } + + // Set highlight item + for (AttributeList::const_iterator ait = attrs.begin (); ait != attrs.end (); ++ait) { + if (ait->get_type () == SCIM_ATTR_DECORATE) { + unsigned int index = ait->get_value (); + if (index < _aux_items.size ()) + set_highlight_color (_aux_items [index], nForeGround, nBackGround, bSetBack); + } + } + + int w, h; + elm_scroller_region_get (_aux_area, &x, &y, &w, &h); + item_width = aux_end - aux_start; + if (item_width > 0) { + if (item_width >= w) + elm_scroller_region_show (_aux_area, aux_end - w, y, w, h); + else if (aux_end > x + w) + elm_scroller_region_show (_aux_area, aux_end - w, y, w, h); + else if (aux_start < x) + elm_scroller_region_show (_aux_area, aux_start, y, w, h); + } + flush_memory (); +} + +/** + * @brief Update candidate/associate table. + * + * @param table_type The table type. + * @param table The lookup table for candidate or associate. + */ +static void update_table (int table_type, const LookupTable &table) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " (" << table.get_current_page_size () << ")\n"; + + int item_num = table.get_current_page_size (); + if (item_num < 0) + return; + + String mbs; + WideString wcs; + + AttributeList attrs; + int i, x, y, width, height, item_0_width = 0; + + int nLast = 0; + std::vector row_items; + + int seperate_width = 4; + int seperate_height = 52 * _height_rate; + int line_width = _candidate_scroll_width; + int line_height = _v_padding; + int total_width = 0; + int current_width = 0; + int line_0 = 0; + int line_count = 0; + int more_item_count = 0; + int scroll_0_width = _candidate_scroll_0_width_min; + int cursor_pos = table.get_cursor_pos (); + int cursor_line = 0; + + if (_candidate_angle == 90 || _candidate_angle == 270) + scroll_0_width = 1176 * _height_rate; + else + scroll_0_width = 618 * _width_rate; + + Evas *evas = evas_object_evas_get (_candidate_window); + for (i = 0; i < SCIM_LOOKUP_TABLE_MAX_PAGESIZE; ++i) { + if (_candidate_0 [i]) { + evas_object_del (_candidate_0 [i]); + _candidate_0 [i] = NULL; + } + if (_seperate_0 [i]) { + evas_object_del (_seperate_0 [i]); + _seperate_0 [i] = NULL; + } + if (_candidate_items [i]) { + evas_object_del (_candidate_items [i]); + _candidate_items [i] = NULL; + } + if (_seperate_items [i]) { + evas_object_del (_seperate_items [i]); + _seperate_items [i] = NULL; + } + if (_line_items [i]) { + evas_object_del (_line_items [i]); + _line_items [i] = NULL; + } + + if (i < item_num) { + bool bHighLight = false; + bool bSetBack = false; + uint32 nForeGround = SCIM_RGB_COLOR(249, 249, 249); + uint32 nBackGround = SCIM_RGB_COLOR(0, 0, 0); + attrs = table.get_attributes_in_current_page (i); + for (AttributeList::const_iterator ait = attrs.begin (); ait != attrs.end (); ++ait) { + if (ait->get_type () == SCIM_ATTR_DECORATE && ait->get_value () == SCIM_ATTR_DECORATE_HIGHLIGHT) { + bHighLight = true; + nForeGround = SCIM_RGB_COLOR(62, 207, 255); + } else if (ait->get_type () == SCIM_ATTR_FOREGROUND) { + bHighLight = true; + nForeGround = ait->get_value (); + } else if (ait->get_type () == SCIM_ATTR_BACKGROUND) { + bSetBack = true; + nBackGround = ait->get_value (); + } + } + + wcs = table.get_candidate_in_current_page (i); + mbs = utf8_wcstombs (wcs); + + if (!_candidate_0 [i] && total_width <= scroll_0_width) { + _candidate_0 [i] = edje_object_add (evas); + edje_object_file_set (_candidate_0 [i], _candidate_edje_file.c_str (), _candidate_name.c_str ()); + edje_object_text_class_set (_candidate_0 [i], "candidate_text_class", _candidate_font_name.c_str (), _candidate_font_size); + evas_object_event_callback_add (_candidate_0 [i], EVAS_CALLBACK_MOUSE_DOWN, ui_mouse_button_pressed_cb, GINT_TO_POINTER ((i << 8) + ISF_EFL_CANDIDATE_0)); + evas_object_event_callback_add (_candidate_0 [i], EVAS_CALLBACK_MOUSE_UP, ui_mouse_button_released_cb, GINT_TO_POINTER (i)); + evas_object_event_callback_add (_candidate_0 [i], EVAS_CALLBACK_MOUSE_MOVE, ui_mouse_moved_cb, GINT_TO_POINTER (ISF_EFL_CANDIDATE_0)); + evas_object_show (_candidate_0 [i]); + + edje_object_part_text_set (_candidate_0 [i], "candidate", mbs.c_str ()); + /* Resize _candidate_0 [i] display width */ + evas_object_text_text_set (_tmp_candidate_text, mbs.c_str ()); + evas_object_geometry_get (_tmp_candidate_text, &x, &y, &width, &height); + item_0_width = width + 2*_blank_width; + item_0_width = item_0_width > _item_min_width ? item_0_width : _item_min_width; + evas_object_size_hint_min_set (_candidate_0 [i], item_0_width, _item_min_height); + if (bHighLight || bSetBack) { + set_highlight_color (_candidate_0 [i], nForeGround, nBackGround, bSetBack); + } + + /* Check whether this item is the last one */ + if (i == item_num - 1) { + if (_candidate_angle == 90 || _candidate_angle == 270) + scroll_0_width = _candidate_land_width; + else + scroll_0_width = _candidate_port_width; + } + + /* Add first item */ + if (i == 0) { + item_0_width = item_0_width > scroll_0_width ? scroll_0_width : item_0_width; + evas_object_size_hint_min_set (_candidate_0 [i], item_0_width, _item_min_height); + elm_table_pack (_candidate_0_table, _candidate_0 [i], 0, 0, item_0_width, _item_min_height); + total_width += item_0_width; + continue; + } else { + total_width += (item_0_width + seperate_width); + if (total_width <= scroll_0_width) { + _seperate_0 [i] = edje_object_add (evas); + edje_object_file_set (_seperate_0 [i], _candidate_edje_file.c_str (), "seperate_line"); + evas_object_size_hint_min_set (_seperate_0 [i], seperate_width, seperate_height); + elm_table_pack (_candidate_0_table, _seperate_0 [i], + total_width - item_0_width - seperate_width, + line_0*(_item_min_height+line_height) + (_item_min_height - seperate_height)/2, + seperate_width, seperate_height); + evas_object_show (_seperate_0 [i]); + + elm_table_pack (_candidate_0_table, _candidate_0 [i], total_width - item_0_width, line_0*(_item_min_height+line_height), item_0_width, _item_min_height); + continue; + } else if ((_candidate_angle == 0 || _candidate_angle == 180) && + (_candidate_port_line > 1 && (line_0 + 1) < _candidate_port_line)) { + line_0++; + scroll_0_width = _candidate_scroll_0_width_min; + item_0_width = item_0_width > scroll_0_width ? scroll_0_width : item_0_width; + evas_object_size_hint_min_set (_candidate_0 [i], item_0_width, _item_min_height); + elm_table_pack (_candidate_0_table, _candidate_0 [i], 0, line_0*(_item_min_height+line_height), item_0_width, _item_min_height); + total_width = item_0_width; + + row_items.push_back (i - nLast); + nLast = i; + continue; + } else { + row_items.push_back (i - nLast); + nLast = i; + } + } + } + + if (!_candidate_items [i]) { + _candidate_items [i] = edje_object_add (evas); + edje_object_file_set (_candidate_items [i], _candidate_edje_file.c_str (), _candidate_name.c_str ()); + edje_object_text_class_set (_candidate_items [i], "candidate_text_class", _candidate_font_name.c_str (), _candidate_font_size); + evas_object_event_callback_add (_candidate_items [i], EVAS_CALLBACK_MOUSE_DOWN, ui_mouse_button_pressed_cb, GINT_TO_POINTER ((i << 8) + ISF_EFL_CANDIDATE_ITEMS)); + evas_object_event_callback_add (_candidate_items [i], EVAS_CALLBACK_MOUSE_UP, ui_mouse_button_released_cb, GINT_TO_POINTER (i)); + evas_object_event_callback_add (_candidate_items [i], EVAS_CALLBACK_MOUSE_MOVE, ui_mouse_moved_cb, GINT_TO_POINTER (ISF_EFL_CANDIDATE_ITEMS)); + evas_object_show (_candidate_items [i]); + } + if (bHighLight || bSetBack) { + set_highlight_color (_candidate_items [i], nForeGround, nBackGround, bSetBack); + } + edje_object_part_text_set (_candidate_items [i], "candidate", mbs.c_str ()); + /* Resize _candidate_items [i] display width */ + evas_object_text_text_set (_tmp_candidate_text, mbs.c_str ()); + evas_object_geometry_get (_tmp_candidate_text, &x, &y, &width, &height); + item_0_width = width + 2*_blank_width; + item_0_width = item_0_width > _item_min_width ? item_0_width : _item_min_width; + evas_object_size_hint_min_set (_candidate_items [i], item_0_width, _item_min_height); + if (current_width > 0 && current_width + item_0_width > _candidate_scroll_width) { + current_width = 0; + line_count++; + + row_items.push_back (i - nLast); + nLast = i; + if (cursor_pos >= i) + cursor_line++; + } + if (current_width == 0 && !_line_items [i]) { + _line_items [i] = edje_object_add (evas); + edje_object_file_set (_line_items [i], _candidate_edje_file.c_str (), "popup_line"); + evas_object_size_hint_min_set (_line_items [i], line_width, line_height); + x = 0; + y = line_count*(_item_min_height+line_height); + elm_table_pack (_candidate_table, _line_items [i], x, y, line_width, line_height); + evas_object_show (_line_items [i]); + } + if (current_width != 0 && !_seperate_items [i]) { + _seperate_items [i] = edje_object_add (evas); + edje_object_file_set (_seperate_items [i], _candidate_edje_file.c_str (), "seperate_line"); + evas_object_size_hint_min_set (_seperate_items [i], seperate_width, seperate_height); + x = current_width; + y = line_count*(_item_min_height+line_height) + line_height + (_item_min_height - seperate_height)/2; + elm_table_pack (_candidate_table, _seperate_items [i], x, y, seperate_width, seperate_height); + evas_object_show (_seperate_items [i]); + current_width += seperate_width; + } + x = current_width; + y = line_count*(_item_min_height+line_height) + line_height; + elm_table_pack (_candidate_table, _candidate_items [i], x, y, item_0_width, _item_min_height); + current_width += item_0_width; + more_item_count++; + } + } + + for (i = 1; i < _candidate_port_line; i++) { + if ((_candidate_angle == 0 || _candidate_angle == 180)) { + if (_line_0 [i] == NULL) { + _line_0 [i] = edje_object_add (evas); + edje_object_file_set (_line_0 [i], _candidate_edje_file.c_str (), "popup_line"); + evas_object_size_hint_min_set (_line_0 [i], line_width, line_height); + x = 0; + y = i * (_item_min_height + line_height) - line_height; + elm_table_pack (_candidate_0_table, _line_0 [i], x, y, line_width, line_height); + evas_object_show (_line_0 [i]); + } + + // Create blank line + if (line_0 + 1 < _candidate_port_line && i > line_0) { + int nIndex = item_num + i; + nIndex = nIndex < SCIM_LOOKUP_TABLE_MAX_PAGESIZE ? nIndex : SCIM_LOOKUP_TABLE_MAX_PAGESIZE - 1; + _seperate_0 [nIndex] = edje_object_add (evas); + edje_object_file_set (_seperate_0 [nIndex], _candidate_edje_file.c_str (), "seperate_line"); + evas_object_size_hint_min_set (_seperate_0 [nIndex], seperate_width, _item_min_height); + elm_table_pack (_candidate_0_table, _seperate_0 [nIndex], + 0, i*(_item_min_height+line_height), seperate_width, _item_min_height); + } + } else if (_line_0 [i]) { + evas_object_del (_line_0 [i]); + _line_0 [i] = NULL; + } + } + + row_items.push_back (item_num - nLast); /* Add the number of last row */ + _panel_agent->update_candidate_item_layout (row_items); + _panel_agent->update_displayed_candidate_number (item_num - more_item_count); + if (more_item_count == 0) { + ui_candidate_window_close_button_cb (NULL, NULL, NULL, NULL); + evas_object_hide (_more_btn); + evas_object_hide (_close_btn); + } else if (!_candidate_area_2_visible) { + evas_object_show (_more_btn); + evas_object_hide (_close_btn); + } else { + evas_object_hide (_more_btn); + evas_object_show (_close_btn); + } + + int w, h; + elm_scroller_region_get (_candidate_area_2, &x, &y, &w, &h); + + int line_h = _item_min_height + _v_padding; + int cursor_y = cursor_line * line_h; + if (cursor_y < y) { + elm_scroller_region_show (_candidate_area_2, 0, cursor_y, w, h); + } else if (cursor_y >= y + h) { + elm_scroller_region_show (_candidate_area_2, 0, cursor_y + line_h - h, w, h); + } + + flush_memory (); +} + +/** + * @brief Update candidate table slot function for PanelAgent. + * + * @param table The lookup table for candidate. + */ +static void slot_update_candidate_table (const LookupTable &table) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + if (_candidate_mode == SOFT_CANDIDATE_WINDOW){ + _panel_agent->update_helper_lookup_table (table); + return ; + } + + if (_candidate_window == NULL) + ui_create_candidate_window (); + + if (!_candidate_window || table.get_current_page_size () < 0) + return; + + update_table (ISF_CANDIDATE_TABLE, table); +} + +/** + * @brief Send selected candidate index. + * + * @param selected candidate string index number. + */ +static void slot_select_candidate (int index) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + _panel_agent->select_candidate (index); +} + +/** + * @brief Get candidate geometry slot function for PanelAgent. + * + * @param info The data is used to store candidate position and size. + */ +static void slot_get_candidate_geometry (struct rectinfo &info) +{ + int x = 0; + int y = 0; + int width = 0; + int height = 0; + + if (_candidate_mode == SOFT_CANDIDATE_WINDOW) { + info.pos_x = x; + info.pos_y = y; + info.width = width; + info.height = height; + return; + } + + if (_candidate_window && _candidate_state == WINDOW_STATE_SHOW) { + /* Get candidate window position */ + /*ecore_evas_geometry_get (ecore_evas_ecore_evas_get (evas_object_evas_get (_candidate_window)), &x, &y, &width, &height);*/ + /* Get exact candidate window size */ + /*int x2, y2; + evas_object_geometry_get (_candidate_window, &x2, &y2, &width, &height);*/ + + x = _candidate_x; + y = _candidate_y; + width = _candidate_width; + height = _candidate_height; + } + info.pos_x = x; + info.pos_y = y; + info.width = width; + info.height = height; + + LOGD ("%d %d %d %d", info.pos_x, info.pos_y, info.width, info.height); + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " x:" << info.pos_x << " y:" << info.pos_y + << " width:" << info.width << " height:" << info.height << "\n"; +} + +/** + * @brief Get input panel geometry slot function for PanelAgent. + * + * @param info The data is used to store input panel position and size. + */ +static void slot_get_input_panel_geometry (struct rectinfo &info) +{ + int hw_kbd_detect = _config->read (ISF_CONFIG_HARDWARE_KEYBOARD_DETECT, 0); + if (hw_kbd_detect) { + info.pos_x = 0; + info.width = 0; + info.height = 0; + if (_candidate_window && _candidate_state == WINDOW_STATE_SHOW) { + info.width = _candidate_width; + info.height = _candidate_height; + } + int angle = efl_get_angle_for_app_window (); + if (angle == 90 || angle == 270) + info.pos_y = _screen_width - info.height; + else + info.pos_y = _screen_height - info.height; + } else { + info = get_ise_geometry (); + if (_ise_state != WINDOW_STATE_SHOW) { + info.width = 0; + info.height = 0; + } else { + if (_candidate_mode == FIXED_CANDIDATE_WINDOW) { + if (_candidate_window && _candidate_state == WINDOW_STATE_SHOW) { + int height = ui_candidate_get_valid_height (); + + if ((_candidate_height - height) > _ise_height) { + info.pos_y = info.pos_y + info.height - _candidate_height; + info.height = _candidate_height; + } else { + info.pos_y -= height; + info.height += height; + } + } + } + } + } + + LOGD ("%d %d %d %d", info.pos_x, info.pos_y, info.width, info.height); + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " x:" << info.pos_x << " y:" << info.pos_y + << " width:" << info.width << " height:" << info.height << "\n"; +} + +/** + * @brief Set active ISE slot function for PanelAgent. + * + * @param uuid The active ISE's uuid. + * @param changeDefault The flag for changeing default ISE. + */ +static void slot_set_active_ise (const String &uuid, bool changeDefault) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " (" << uuid << ")\n"; + + set_active_ise (uuid); +} + +/** + * @brief Get all ISEs list slot function for PanelAgent. + * + * @param list The list is used to store all ISEs. + * + * @return true if this operation is successful, otherwise return false. + */ +static bool slot_get_ise_list (std::vector &list) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + /* update ise list */ + bool ret = isf_update_ise_list (ALL_ISE, _config); + + list.clear (); + list = _uuids; + + _panel_agent->update_ise_list (list); + + if (ret && _initial_ise_uuid.length () > 0) { + String active_uuid = _initial_ise_uuid; + String default_uuid = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), String ("")); + int hw_kbd_detect = _config->read (ISF_CONFIG_HARDWARE_KEYBOARD_DETECT, 0); + if (std::find (_uuids.begin (), _uuids.end (), default_uuid) == _uuids.end ()) { + if (hw_kbd_detect && _modes[get_ise_index (_initial_ise_uuid)] != TOOLBAR_KEYBOARD_MODE) { + active_uuid = String (SCIM_COMPOSE_KEY_FACTORY_UUID); + } + set_active_ise (active_uuid); + } else if (!hw_kbd_detect) { // Check whether keyboard engine is installed + String IMENGINE_KEY = String (SCIM_CONFIG_DEFAULT_IMENGINE_FACTORY) + String ("/") + String ("~other"); + String keyboard_uuid = _config->read (IMENGINE_KEY, String ("")); + if (std::find (_uuids.begin (), _uuids.end (), keyboard_uuid) == _uuids.end ()) { + active_uuid = String (SCIM_COMPOSE_KEY_FACTORY_UUID); + _panel_agent->change_factory (active_uuid); + _config->write (IMENGINE_KEY, active_uuid); + _config->flush (); + } + } + } + + add_ise_directory_em (); + return ret; +} + +/** + * @brief Get the ISE's information. + * + * @param uuid The ISE's uuid. + * @param name The ISE's name. + * @param language The ISE's language. + * @param type The ISE's type. + * @param option The ISE's option. + * + * @return true if this operation is successful, otherwise return false. + */ +static bool slot_get_ise_information (String uuid, String &name, String &language, int &type, int &option, String &module_name) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + if (uuid.length () > 0) { + for (unsigned int i = 0; i < _uuids.size (); i++) { + if (uuid == _uuids[i]) { + name = _names[i]; + language = _langs[i]; + type = _modes[i]; + option = _options[i]; + module_name = ""; + return true; + } + } + } + + std::cerr << __func__ << " is failed!!!\n"; + return false; +} + +/** + * @brief Get keyboard ISEs list slot function for PanelAgent. + * + * @param name_list The list is used to store keyboard ISEs. + * + * @return true if this operation is successful, otherwise return false. + */ +static bool slot_get_keyboard_ise_list (std::vector &name_list) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + /* update ise list */ + bool ret = isf_update_ise_list (ALL_ISE, _config); + + std::vector lang_list, uuid_list; + isf_get_all_languages (lang_list); + isf_get_keyboard_ises_in_languages (lang_list, uuid_list, name_list, false); + + if (ret) + _panel_agent->update_ise_list (uuid_list); + return ret; +} + +/** + * @brief Get enable languages list slot function for PanelAgent. + * + * @param list The list is used to store languages. + */ +static void slot_get_language_list (std::vector &list) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + String lang_name; + MapStringVectorSizeT::iterator iter = _groups.begin (); + + for (; iter != _groups.end (); iter++) { + lang_name = scim_get_language_name (iter->first); + list.push_back (lang_name); + } +} + +/** + * @brief Get all languages list slot function for PanelAgent. + * + * @param lang The list is used to store languages. + */ +static void slot_get_all_language (std::vector &lang) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + isf_get_all_languages (lang); +} + +/** + * @brief Get specific ISE language list slot function for PanelAgent. + * + * @param name The ISE name. + * @param list The list is used to store ISE languages. + */ +static void slot_get_ise_language (char *name, std::vector &list) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + if (name == NULL) + return; + + unsigned int num = _names.size (); + std::vector list_tmp; + list_tmp.clear (); + for (unsigned int i = 0; i < num; i++) { + if (!strcmp (_names[i].c_str (), name)) { + scim_split_string_list (list_tmp, _langs[i], ','); + for (i = 0; i < list_tmp.size (); i++) + list.push_back (scim_get_language_name (list_tmp[i])); + return; + } + } +} + +/** + * @brief Get ISE information slot function for PanelAgent. + * + * @param uuid The ISE uuid. + * @param info The variable is used to store ISE information. + * + * @return true if this operation is successful, otherwise return false. + */ +static bool slot_get_ise_info (const String &uuid, ISE_INFO &info) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + for (unsigned int i = 0; i < _uuids.size (); i++) { + if (!uuid.compare (_uuids[i])) { + info.uuid = _uuids[i]; + info.name = _names[i]; + info.icon = _icons[i]; + info.lang = _langs[i]; + info.option = _options[i]; + info.type = _modes[i]; + return true; + } + } + + return false; +} + +/** + * @brief Set keyboard ISE slot function for PanelAgent. + * + * @param uuid The variable is ISE uuid. + */ +static void slot_set_keyboard_ise (const String &uuid) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " uuid = " << uuid << "\n"; + + if (uuid.length () <= 0 || std::find (_uuids.begin (), _uuids.end (), uuid) == _uuids.end ()) + return; + + String default_uuid = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), String ("")); + if (_modes[get_ise_index (default_uuid)] == TOOLBAR_KEYBOARD_MODE) + return; + + uint32 ise_option = 0; + String ise_uuid, ise_name; + isf_get_keyboard_ise (_config, ise_uuid, ise_name, ise_option); + if (ise_uuid == uuid) + return; + + String language = String ("~other");/*scim_get_locale_language (scim_get_current_locale ());*/ + _config->write (String (SCIM_CONFIG_DEFAULT_IMENGINE_FACTORY) + String ("/") + language, uuid); + _config->flush (); + _config->reload (); + + _panel_agent->change_factory (uuid); + _panel_agent->reload_config (); +} + +/** + * @brief Get current keyboard ISE name and uuid slot function for PanelAgent. + * + * @param ise_name The variable is used to store ISE name. + * @param ise_uuid The variable is used to store ISE uuid. + */ +static void slot_get_keyboard_ise (String &ise_name, String &ise_uuid) +{ + uint32 ise_option = 0; + isf_get_keyboard_ise (_config, ise_uuid, ise_name, ise_option); + + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " uuid = " << ise_uuid << "\n"; +} + +/** + * @brief Accept connection slot function for PanelAgent. + * + * @param fd The file descriptor to connect. + */ +static void slot_accept_connection (int fd) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + Ecore_Fd_Handler *panel_agent_read_handler = ecore_main_fd_handler_add (fd, ECORE_FD_READ, panel_agent_handler, NULL, NULL, NULL); + _read_handler_list.push_back (panel_agent_read_handler); +} + +/** + * @brief Close connection slot function for PanelAgent. + * + * @param fd The file descriptor to connect. + */ +static void slot_close_connection (int fd) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + int i = 0; + std::vector::iterator IterPos; + + for (IterPos = _read_handler_list.begin (); IterPos != _read_handler_list.end (); ++IterPos,++i) { + if (ecore_main_fd_handler_fd_get (_read_handler_list[i]) == fd) { + ecore_main_fd_handler_del (_read_handler_list[i]); + _read_handler_list.erase (IterPos); + break; + } + } +} + +/** + * @brief Exit panel process slot function for PanelAgent. + */ +static void slot_exit (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + elm_exit (); +} + +static void slot_register_helper_properties (int id, const PropertyList &props) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + /* WMSYNC, #2 Receiving X window ID from ISE */ + /* FIXME : We should add an API to set window id of ISE */ +} + +static void slot_show_ise (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + /* If the candidate was already in SHOW state, respect the current angle */ + if (_candidate_state != WINDOW_STATE_SHOW) { + /* FIXME : Need to check if candidate_angle and window_angle should be left as separated */ + _candidate_angle = efl_get_angle_for_app_window (); + _window_angle = efl_get_angle_for_app_window (); + } + + efl_set_transient_for_app_window (_ise_window); + + /* If our ISE was already in SHOW state, skip state transition to WILL_SHOW */ + if (_ise_state != WINDOW_STATE_SHOW) { + _ise_state = WINDOW_STATE_WILL_SHOW; + } +} + +static void slot_hide_ise (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + /* Only if we are not already in HIDE state */ + if (_ise_state != WINDOW_STATE_HIDE) { + _ise_state = WINDOW_STATE_WILL_HIDE; + } + _window_angle = -1; + + if (_candidate_window) { + int hw_kbd_detect = _config->read (ISF_CONFIG_HARDWARE_KEYBOARD_DETECT, 0); + if (hw_kbd_detect) + ui_candidate_hide (true, true, true); + } +} + +static void slot_will_hide_ack (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + /* WMSYNC, #8 Let the Window Manager to actually hide keyboard window */ + // WILL_HIDE_REQUEST_DONE Ack to WM + // FIXME: +} + +static void slot_candidate_will_hide_ack (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + // FIXME: +} + +static void slot_get_ise_state (int &state) +{ + if (_ise_state == WINDOW_STATE_SHOW || + (hw_kbd_mode && _candidate_state == WINDOW_STATE_SHOW)) { + state = ECORE_IMF_INPUT_PANEL_STATE_SHOW; + } else { + /* Currently we don't have WILL_HIDE / HIDE state distinction in Ecore_IMF */ + switch (_ise_state) { + case WINDOW_STATE_SHOW : + state = ECORE_IMF_INPUT_PANEL_STATE_SHOW; + break; + case WINDOW_STATE_WILL_SHOW : + state = ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW; + break; + case WINDOW_STATE_WILL_HIDE : + state = ECORE_IMF_INPUT_PANEL_STATE_HIDE; + break; + case WINDOW_STATE_HIDE : + state = ECORE_IMF_INPUT_PANEL_STATE_HIDE; + break; + default : + state = ECORE_IMF_INPUT_PANEL_STATE_HIDE; + }; + } + LOGD ("state = %d", state); + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << " state = " << state << "\n"; +} + +////////////////////////////////////////////////////////////////////// +// End of PanelAgent-Functions +////////////////////////////////////////////////////////////////////// + + +/** + * @brief Callback function for ecore fd handler. + * + * @param data The data to pass to this callback. + * @param fd_handler The ecore fd handler. + * + * @return ECORE_CALLBACK_RENEW + */ +static Eina_Bool panel_agent_handler (void *data, Ecore_Fd_Handler *fd_handler) +{ + if (fd_handler == NULL) + return ECORE_CALLBACK_RENEW; + + int fd = ecore_main_fd_handler_fd_get (fd_handler); + for (unsigned int i = 0; i < _read_handler_list.size (); i++) { + if (fd_handler == _read_handler_list [i]) { + if (!_panel_agent->filter_event (fd)) { + std::cerr << "_panel_agent->filter_event () is failed!!!\n"; + ecore_main_fd_handler_del (fd_handler); + } + return ECORE_CALLBACK_RENEW; + } + } + std::cerr << "panel_agent_handler () has received exception event!!!\n"; + _panel_agent->filter_exception_event (fd); + ecore_main_fd_handler_del (fd_handler); + return ECORE_CALLBACK_RENEW; +} + +/** + * @brief Handler function for HelperManager input. + * + * @param data The data to pass to this callback. + * @param fd_handler The Ecore Fd handler. + * + * @return ECORE_CALLBACK_RENEW + */ +static Eina_Bool helper_manager_input_handler (void *data, Ecore_Fd_Handler *fd_handler) +{ + if (_panel_agent->has_helper_manager_pending_event ()) { + if (!_panel_agent->filter_helper_manager_event ()) { + std::cerr << "_panel_agent->filter_helper_manager_event () is failed!!!\n"; + elm_exit (); + } + } else { + std::cerr << "_panel_agent->has_helper_manager_pending_event () is failed!!!\n"; + elm_exit (); + } + + return ECORE_CALLBACK_RENEW; +} + +/** + * @brief Callback function for abnormal signal. + * + * @param sig The signal. + */ +static void signalhandler (int sig) +{ + SCIM_DEBUG_MAIN (1) << __FUNCTION__ << " Signal=" << sig << "\n"; + + elm_exit (); +} + +#if HAVE_VCONF +/** + * @brief Update keyboard ISE name when display language is changed. + * + * @param module_name The keyboard ISE module name. + * @param index The index of _module_names. + * + * @return true if successful, otherwise return false. + */ +static bool update_keyboard_ise_locale (const String module_name, int index) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + if (module_name.length () <= 0 || module_name == "socket") + return false; + + IMEngineFactoryPointer factory; + IMEngineModule ime_module; + ime_module.load (module_name, _config); + + if (ime_module.valid ()) { + for (size_t j = 0; j < ime_module.number_of_factories (); ++j) { + try { + factory = ime_module.create_factory (j); + } catch (...) { + factory.reset (); + } + if (!factory.null ()) { + _names[index+j] = utf8_wcstombs (factory->get_name ()); + factory.reset (); + } + } + ime_module.unload (); + } else { + std::cerr << module_name << " can not be loaded!!!\n"; + } + + return true; +} + +/** + * @brief Update helper ISE name when display language is changed. + * + * @param module_name The helper ISE module name. + * @param index The index of _module_names. + * + * @return true if successful, otherwise return false. + */ +static bool update_helper_ise_locale (const String module_name, int index) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + if (module_name.length () <= 0) + return false; + + HelperModule helper_module; + HelperInfo helper_info; + helper_module.load (module_name); + if (helper_module.valid ()) { + for (size_t j = 0; j < helper_module.number_of_helpers (); ++j) { + helper_module.get_helper_info (j, helper_info); + _names[index+j] = helper_info.name; + } + helper_module.unload (); + } else { + std::cerr << module_name << " can not be loaded!!!\n"; + } + + return true; +} + +/** + * @brief Set language and locale. + * + * @return void + */ +static void set_language_and_locale (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + char *lang_str = vconf_get_str (VCONFKEY_LANGSET); + + if (lang_str) { + setenv ("LANG", lang_str, 1); + setlocale (LC_MESSAGES, lang_str); + free (lang_str); + } else { + setenv ("LANG", "en_US.utf8", 1); + setlocale (LC_MESSAGES, "en_US.utf8"); + } +} + +/** + * @brief Callback function for display language change. + * + * @param key The key node. + * @param data The data to pass to this callback. + * + * @return void + */ +static void display_language_changed_cb (keynode_t *key, void* data) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + set_language_and_locale (); + + /* Update all ISE names according to display language */ + std::vector module_list; + for (unsigned int i = 0; i < _module_names.size (); i++) { + if (std::find (module_list.begin (), module_list.end (), _module_names[i]) != module_list.end ()) + continue; + module_list.push_back (_module_names[i]); + if (_module_names[i] == String (COMPOSE_KEY_MODULE)) { + IMEngineFactoryPointer factory; + factory = new ComposeKeyFactory (); + _names[i] = utf8_wcstombs (factory->get_name ()); + factory.reset (); + } else if (_modes[i] == TOOLBAR_KEYBOARD_MODE) { + update_keyboard_ise_locale (_module_names[i], i); + } else if (_modes[i] == TOOLBAR_HELPER_MODE) { + update_helper_ise_locale (_module_names[i], i); + } + } + isf_save_ise_information (); + + String default_uuid = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), _initial_ise_uuid); + String default_name = _names[get_ise_index (default_uuid)]; + _panel_agent->set_current_ise_name (default_name); + _config->reload (); +} +#endif + +/** + * @brief Start default ISE. + * + * @return void + */ +static void start_default_ise (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + String default_uuid = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), _initial_ise_uuid); + if (!set_active_ise (default_uuid)) { + std::cerr << __FUNCTION__ << " Failed to launch default ISE(" << default_uuid << ")\n"; + LOGW ("Failed to launch default ISE (%s)\n", default_uuid.c_str ()); + + if (default_uuid != _initial_ise_uuid) { + std::cerr << __FUNCTION__ << " Launch initial ISE(" << _initial_ise_uuid << ")\n"; + if (!set_active_ise (_initial_ise_uuid)) { + LOGW ("Failed to launch initial ISE (%s)\n", _initial_ise_uuid.c_str ()); + } else { + LOGD ("Succeed to launch initial ISE (%s)\n", _initial_ise_uuid.c_str ()); + } + } + } else { + LOGD ("Succeed to launch default ISE (%s)\n", default_uuid.c_str ()); + } +} + +/** + * @brief Check hardware keyboard. + * + * @return void + */ +static void check_hardware_keyboard (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + if (_off_prepare_done_timer) { + ecore_timer_del (_off_prepare_done_timer); + _off_prepare_done_timer = NULL; + } + + unsigned int val = 0; + + _config->write (ISF_CONFIG_HARDWARE_KEYBOARD_DETECT, 0); + + //FIXME: + uint32 option = 0; + String uuid, name; + String helper_uuid = _config->read (SCIM_CONFIG_DEFAULT_HELPER_ISE, String ("")); + String default_uuid = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_DEFAULT_ISE_UUID), String ("")); + + /* When switching back to S/W keyboard mode, let's hide candidate window first */ + LOGD ("calling ui_candidate_hide (true, true, true)"); + ui_candidate_hide (true, true, true); + uuid = helper_uuid.length () > 0 ? helper_uuid : _initial_ise_uuid; + hw_kbd_mode = false; + _panel_agent->reset_keyboard_ise (); + + set_active_ise (uuid); +} + +/** + * @brief : Checks whether the window manager is launched or not + * @return true if window manager launched, else false + */ +static bool check_wm_ready (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + return true; +} + +/** + * @brief : Checks whether the system service is ready or not + * @return true if all system service are ready, else false + */ +static bool check_system_ready (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + int ret = 0; + int val = 0; + ret = vconf_get_int (ISF_SYSTEM_APPSERVICE_READY_VCONF, &val); + + LOGD ("ret : %d, val : %d\n", ret, val); + + if (ret == 0 && val >= ISF_SYSTEM_APPSERVICE_READY_STATE) { + LOGD ("Appservice was ready\n"); + return true; + } else { + /* Register a call back function for checking system ready */ + if (!_appsvc_callback_regist) { + if (vconf_notify_key_changed (ISF_SYSTEM_APPSERVICE_READY_VCONF, launch_default_soft_keyboard, NULL)) { + _appsvc_callback_regist = true; + } + + if (!_system_ready_timer) { + _system_ready_timer = ecore_timer_add (5.0, system_ready_timeout_cb, NULL); + } + } + + return false; + } +} + +static void _launch_default_soft_keyboard (void) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + if (_appsvc_callback_regist) + vconf_ignore_key_changed (ISF_SYSTEM_APPSERVICE_READY_VCONF, launch_default_soft_keyboard); + + if (_system_ready_timer) { + ecore_timer_del (_system_ready_timer); + _system_ready_timer = NULL; + } + + /* Start default ISE */ + start_default_ise (); + check_hardware_keyboard (); +} + +/** + * @brief : Launches default soft keyboard for performance enhancement (It's not mandatory) + */ +static void launch_default_soft_keyboard (keynode_t *key, void* data) +{ + SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; + + /* Soft keyboard will be started when all system service are ready */ + if (check_system_ready ()) { + _launch_default_soft_keyboard (); + } +} + +int main (int argc, char *argv []) +{ + struct tms tiks_buf; + _clock_start = times (&tiks_buf); + + int i; + int ret = 0; + + bool daemon = false; + bool should_resident = true; + + int new_argc = 0; + char **new_argv = new char * [40]; + ConfigModule *config_module = NULL; + String config_name = String ("socket"); + String display_name = String (); + + Ecore_Fd_Handler *panel_agent_read_handler = NULL; + Ecore_Fd_Handler *helper_manager_handler = NULL; + + check_time ("\nStarting ISF WSM EFL...... "); + LOGD ("Starting ISF WSM EFL...... \n"); + + DebugOutput::disable_debug (SCIM_DEBUG_AllMask); + DebugOutput::enable_debug (SCIM_DEBUG_MainMask); + + /* Parse command options */ + i = 0; + while (i < argc) { + if (++i >= argc) + break; + + if (String ("-c") == argv [i] || String ("--config") == argv [i]) { + if (++i >= argc) { + std::cerr << "no argument for option " << argv [i-1] << "\n"; + ret = -1; + goto cleanup; + } + config_name = argv [i]; + continue; + } + + if (String ("-h") == argv [i] || String ("--help") == argv [i]) { + std::cout << "Usage: " << argv [0] << " [option]...\n\n" + << "The options are: \n" + << " --display DISPLAY Run on display DISPLAY.\n" + << " -c, --config NAME Uses specified Config module.\n" + << " -d, --daemon Run " << argv [0] << " as a daemon.\n" + << " -ns, --no-stay Quit if no connected client.\n" +#if ENABLE_DEBUG + << " -v, --verbose LEVEL Enable debug info, to specific LEVEL.\n" + << " -o, --output FILE Output debug information into FILE.\n" +#endif + << " -h, --help Show this help message.\n"; + delete []new_argv; + return 0; + } + + if (String ("-d") == argv [i] || String ("--daemon") == argv [i]) { + daemon = true; + continue; + } + + if (String ("-ns") == argv [i] || String ("--no-stay") == argv [i]) { + should_resident = false; + continue; + } + + if (String ("-v") == argv [i] || String ("--verbose") == argv [i]) { + if (++i >= argc) { + std::cerr << "no argument for option " << argv [i-1] << "\n"; + ret = -1; + goto cleanup; + } + DebugOutput::set_verbose_level (atoi (argv [i])); + continue; + } + + if (String ("-o") == argv [i] || String ("--output") == argv [i]) { + if (++i >= argc) { + std::cerr << "No argument for option " << argv [i-1] << "\n"; + ret = -1; + goto cleanup; + } + DebugOutput::set_output (argv [i]); + continue; + } + + if (String ("--display") == argv [i]) { + if (++i >= argc) { + std::cerr << "No argument for option " << argv [i-1] << "\n"; + ret = -1; + goto cleanup; + } + display_name = argv [i]; + continue; + } + + if (String ("--") == argv [i]) + break; + + std::cerr << "Invalid command line option: " << argv [i] << "\n"; + delete []new_argv; + return 0; + } /* End of command line parsing. */ + + new_argv [new_argc ++] = argv [0]; + + /* Store the rest argvs into new_argv. */ + for (++i; i < argc && new_argc < 37; ++i) { + new_argv [new_argc ++] = argv [i]; + } + + /* Make up DISPLAY env. */ + if (display_name.length ()) { + new_argv [new_argc ++] = const_cast ("--display"); + new_argv [new_argc ++] = const_cast (display_name.c_str ()); + + setenv ("DISPLAY", display_name.c_str (), 1); + } + + new_argv [new_argc] = 0; + + if (!config_name.length ()) { + std::cerr << "No Config module is available!\n"; + ret = -1; + goto cleanup; + } + + if (config_name != "dummy") { + /* Load config module */ + config_module = new ConfigModule (config_name); + + if (!config_module || !config_module->valid ()) { + std::cerr << "Can not load " << config_name << " Config module.\n"; + ret = -1; + goto cleanup; + } + } else { + _config = new DummyConfig (); + } + + /* Get current display. */ + { + const char *p = getenv ("DISPLAY"); + if (p) + display_name = String (p); + } + + char buf [256]; + snprintf (buf, sizeof (buf), "config_name=%s display_name=%s", config_name.c_str (), display_name.c_str ()); + check_time (buf); + try { + if (!initialize_panel_agent (config_name, display_name, should_resident)) { + check_time ("Failed to initialize Panel Agent!"); + std::cerr << "Failed to initialize Panel Agent!\n"; + ret = -1; + goto cleanup; + } + } catch (scim::Exception & e) { + std::cerr << e.what() << "\n"; + ret = -1; + goto cleanup; + } + check_time ("initialize_panel_agent"); + + /* Create config instance */ + if (_config.null () && config_module && config_module->valid ()) + _config = config_module->create_config (); + if (_config.null ()) { + std::cerr << "Failed to create Config instance from " << config_name << " Config module.\n"; + ret = -1; + goto cleanup; + } + check_time ("create config instance"); + + /* Initialize global variables and pointers for candidate items and etc. */ + for (i = 0; i < SCIM_LOOKUP_TABLE_MAX_PAGESIZE; i++) { + _candidate_0 [i] = NULL; + _candidate_items [i] = NULL; + _seperate_0 [i] = NULL; + _seperate_items [i] = NULL; + _line_0 [i] = NULL; + _line_items [i] = NULL; + } + + try { + _panel_agent->send_display_name (display_name); + } catch (scim::Exception & e) { + std::cerr << e.what() << "\n"; + ret = -1; + goto cleanup; + } + + if (daemon) { + check_time ("ISF WSM EFL run as daemon"); + scim_daemon (); + } + + /* Connect the configuration reload signal. */ + _config->signal_connect_reload (slot (config_reload_cb)); + + if (!check_wm_ready ()) { + std::cerr << "[ISF-PANEL-EFL] WM ready timeout\n"; + LOGW ("Window Manager ready timeout\n"); + } else { + LOGD ("Window Manager is in ready state\n"); + } + + elm_init (argc, argv); + check_time ("elm_init"); + + //elm_policy_set (ELM_POLICY_THROTTLE, ELM_POLICY_THROTTLE_NEVER); + + if (!efl_create_control_window ()) { + LOGW ("Failed to create control window\n"); + goto cleanup; + } + + efl_get_screen_resolution (_screen_width, _screen_height); + + _width_rate = (float)(_screen_width / 720.0); + _height_rate = (float)(_screen_height / 1280.0); + _blank_width = (int)(_blank_width * _width_rate); + _item_min_width = (int)(_item_min_width * _width_rate); + _item_min_height = (int)(_item_min_height * _height_rate); + _candidate_width = (int)(_candidate_port_width * _width_rate); + _candidate_height = (int)(_candidate_port_height_min * _height_rate); + _indicator_height = (int)(_indicator_height * _height_rate); + + _aux_font_size = (int)(_aux_font_size * _width_rate); + _candidate_font_size = (int)(_candidate_font_size * _width_rate); + + /* Load ISF configuration */ + load_config (); + check_time ("load_config"); + + helper_manager_handler = ecore_main_fd_handler_add (_panel_agent->get_helper_manager_id (), ECORE_FD_READ, helper_manager_input_handler, NULL, NULL, NULL); + panel_agent_read_handler = ecore_main_fd_handler_add (_panel_agent->get_server_id (), ECORE_FD_READ, panel_agent_handler, NULL, NULL, NULL); + _read_handler_list.push_back (panel_agent_read_handler); + check_time ("run_panel_agent"); + + set_language_and_locale (); + +#if HAVE_VCONF + /* Add callback function for input language and display language */ + vconf_notify_key_changed (VCONFKEY_LANGSET, display_language_changed_cb, NULL); +#endif + + try { + /* Update ISE list */ + std::vector list; + slot_get_ise_list (list); + + /* Load initial ISE information */ + _initial_ise_uuid = scim_global_config_read (String (SCIM_GLOBAL_CONFIG_INITIAL_ISE_UUID), String (SCIM_COMPOSE_KEY_FACTORY_UUID)); + + /* Launches default soft keyboard when all conditions are satisfied */ + launch_default_soft_keyboard (); + } catch (scim::Exception & e) { + std::cerr << e.what () << "\n"; + } + + // FIXME: + + /* Set elementary scale */ + if (_screen_width) + elm_config_scale_set (_screen_width / 720.0f); + + signal (SIGQUIT, signalhandler); + signal (SIGTERM, signalhandler); + signal (SIGINT, signalhandler); + signal (SIGHUP, signalhandler); + signal (SIGABRT, signalhandler); + + check_time ("EFL WSM launch time"); + + elm_run (); + + _config->flush (); + ret = 0; + + if (helper_manager_handler) + ecore_main_fd_handler_del (helper_manager_handler); + for (unsigned int ii = 0; ii < _read_handler_list.size (); ++ii) { + ecore_main_fd_handler_del (_read_handler_list[ii]); + } + _read_handler_list.clear (); + +#if HAVE_VCONF + /* Remove callback function for input language and display language */ + vconf_ignore_key_changed (VCONFKEY_LANGSET, display_language_changed_cb); +#endif + +cleanup: + ui_candidate_delete_check_size_timer (); + ui_candidate_delete_longpress_timer (); + ui_candidate_delete_destroy_timer (); + delete_ise_directory_em (); + ui_close_tts (); + + if (!_config.null ()) + _config.reset (); + if (config_module) + delete config_module; + if (_panel_agent) { + try { + _panel_agent->stop (); + } catch (scim::Exception & e) { + std::cerr << "Exception is thrown from _panel_agent->stop (), error is " << e.what () << "\n"; + } + delete _panel_agent; + } + + delete []new_argv; + + if (ret == 0) { + std::cerr << "Successfully exited.\n"; + return 0; + } else { + std::cerr << "Abnormally exited.\n"; + return -1; + } +} + +/* +vi:ts=4:nowrap:expandtab +*/ diff --git a/ism/extras/efl_wsm/isf_wsm_utility.cpp b/ism/extras/efl_wsm/isf_wsm_utility.cpp new file mode 100644 index 0000000..b16dcb8 --- /dev/null +++ b/ism/extras/efl_wsm/isf_wsm_utility.cpp @@ -0,0 +1,639 @@ +/* + * ISF(Input Service Framework) + * + * ISF is based on SCIM 1.4.7 and extended for supporting more mobile fitable. + * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. + * + * Contact: Yan Wang + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define Uses_SCIM_CONFIG_PATH +#define Uses_SCIM_PANEL_AGENT +#define Uses_SCIM_IMENGINE_MODULE +#define Uses_SCIM_HELPER_MODULE +#define Uses_SCIM_COMPOSE_KEY + + +#include +#include "scim.h" +#include "scim_stl_map.h" +#include "isf_wsm_utility.h" +#include "isf_query_utility.h" +#include +#include +#include + + +///////////////////////////////////////////////////////////////////////////// +// Declaration of macro. +///////////////////////////////////////////////////////////////////////////// +#ifdef LOG_TAG +# undef LOG_TAG +#endif +#define LOG_TAG "ISF_WSM_EFL" + + +///////////////////////////////////////////////////////////////////////////// +// Declaration of global variables. +///////////////////////////////////////////////////////////////////////////// +MapStringVectorSizeT _groups; +std::vector _uuids; +std::vector _names; +std::vector _module_names; +std::vector _langs; +std::vector _icons; +std::vector _options; +std::vector _modes; + + +///////////////////////////////////////////////////////////////////////////// +// Declaration of internal variables. +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Declaration of internal functions. +///////////////////////////////////////////////////////////////////////////// +static bool add_keyboard_ise_module (const String ise_name, const ConfigPointer &config); +static bool add_helper_ise_module (const String ise_name); + + +/** + * @brief Get all ISEs support languages. + * + * @param all_langs The list to store all languages. + */ +void isf_get_all_languages (std::vector &all_langs) +{ + String lang_name; + + for (MapStringVectorSizeT::iterator it = _groups.begin (); it != _groups.end (); ++it) { + lang_name = scim_get_language_name_english (it->first); + all_langs.push_back (lang_name); + } +} + +/** + * @brief Get all ISEs for the specific languages. + * + * @param lang_list The specific languages list. + * @param uuid_list The list to store ISEs' UUID. + * @param name_list The list to store ISEs' name. + */ +void isf_get_all_ises_in_languages (std::vector lang_list, std::vector &uuid_list, std::vector &name_list) +{ + String lang_name; + + for (MapStringVectorSizeT::iterator it = _groups.begin (); it != _groups.end (); ++it) { + lang_name = scim_get_language_name_english (it->first); + if (std::find (lang_list.begin (), lang_list.end (), lang_name) != lang_list.end ()) { + for (size_t i = 0; i < it->second.size (); i++) { + // Avoid to add the same ISE + if (std::find (uuid_list.begin (), uuid_list.end (), _uuids[it->second[i]]) == uuid_list.end ()) { + uuid_list.push_back (_uuids[it->second[i]]); + name_list.push_back (_names[it->second[i]]); + } + } + } + } +} + +/** + * @brief Get keyboard ISE + * + * @param config The config pointer for loading keyboard ISE. + * @param ise_uuid The keyboard ISE uuid. + * @param ise_name The keyboard ISE name. + * @param ise_option The keyboard ISE option. + */ +void isf_get_keyboard_ise (const ConfigPointer &config, String &ise_uuid, String &ise_name, uint32 &ise_option) +{ + String uuid = config->read (String (SCIM_CONFIG_DEFAULT_IMENGINE_FACTORY) + String ("/") + String ("~other"), String ("")); + if (ise_uuid.length () > 0) + uuid = ise_uuid; + for (unsigned int i = 0; i < _uuids.size (); i++) { + if (uuid == _uuids[i]) { + ise_uuid = _uuids[i]; + ise_name = _names[i]; + ise_option = _options[i]; + return; + } + } + ise_name = String (""); + ise_uuid = String (""); +} + +/** + * @brief Get all keyboard ISEs for the specific languages. + * + * @param lang_list The specific languages list. + * @param uuid_list The list to store keyboard ISEs' UUID. + * @param name_list The list to store keyboard ISEs' name. + * @param bCheckOption The flag to check whether support hardware keyboard. + */ +void isf_get_keyboard_ises_in_languages (const std::vector &lang_list, + std::vector &uuid_list, + std::vector &name_list, + bool bCheckOption) +{ + String lang_name; + + for (MapStringVectorSizeT::iterator it = _groups.begin (); it != _groups.end (); ++it) { + lang_name = scim_get_language_name_english (it->first); + + if (std::find (lang_list.begin (), lang_list.end (), lang_name) != lang_list.end ()) { + for (size_t i = 0; i < it->second.size (); i++) { + if (_modes[it->second[i]] != TOOLBAR_KEYBOARD_MODE) + continue; + if (bCheckOption && (_options[it->second[i]] & SCIM_IME_NOT_SUPPORT_HARDWARE_KEYBOARD)) + continue; + if (std::find (uuid_list.begin (), uuid_list.end (), _uuids[it->second[i]]) == uuid_list.end ()) { + uuid_list.push_back (_uuids[it->second[i]]); + name_list.push_back (_names[it->second[i]]); + } + } + } + } +} + +/** + * @brief Get all helper ISEs for the specific languages. + * + * @param lang_list The specific languages list. + * @param uuid_list The list to store helper ISEs' UUID. + * @param name_list The list to store helper ISEs' name. + */ +void isf_get_helper_ises_in_languages (const std::vector &lang_list, std::vector &uuid_list, std::vector &name_list) +{ + String lang_name; + + for (MapStringVectorSizeT::iterator it = _groups.begin (); it != _groups.end (); ++it) { + lang_name = scim_get_language_name_english (it->first); + if (std::find (lang_list.begin (), lang_list.end (), lang_name) != lang_list.end ()) { + for (size_t i = 0; i < it->second.size (); i++) { + + if (_modes[it->second[i]]!= TOOLBAR_HELPER_MODE) + continue; + // Avoid to add the same ISE + if (std::find (uuid_list.begin (), uuid_list.end (), _uuids[it->second[i]]) == uuid_list.end ()) { + uuid_list.push_back (_uuids[it->second[i]]); + name_list.push_back (_names[it->second[i]]); + } + } + } + } +} + +/** + * @brief Save all ISEs information into cache file. + * + * @return void + */ +void isf_save_ise_information (void) +{ + if (_module_names.size () <= 0) + return; + + std::vector info_list; + for (size_t i = 0; i < _module_names.size (); ++i) { + if (_module_names[i] == COMPOSE_KEY_MODULE) + continue; + ISEINFO info; + info.name = _names[i]; + info.uuid = _uuids[i]; + info.module = _module_names[i]; + info.language = _langs[i]; + info.icon = _icons[i]; + info.mode = _modes[i]; + info.option = _options[i]; + info.locales = ""; + info_list.push_back (info); + } + + String user_file_name = String (USER_ENGINE_FILE_NAME); + isf_write_ise_info_list (user_file_name.c_str (), info_list); +} + +/** + * @brief Load all ISEs to initialize. + * + * @param type The loading ISE type. + * @param config The config pointer for loading keyboard ISE. + * @param uuids The ISE uuid list. + * @param names The ISE name list. + * @param module_names The ISE module name list. + * @param langs The ISE language list. + * @param icons The ISE icon list. + * @param modes The ISE type list. + * @param options The ISE option list. + */ +void isf_get_factory_list (LOAD_ISE_TYPE type, + const ConfigPointer &config, + std::vector &uuids, + std::vector &names, + std::vector &module_names, + std::vector &langs, + std::vector &icons, + std::vector &modes, + std::vector &options) +{ + uuids.clear (); + names.clear (); + module_names.clear (); + langs.clear (); + icons.clear (); + modes.clear (); + options.clear (); + _groups.clear (); + + if (type != HELPER_ONLY) { + /* Add ComposeKeyFactory first. */ + IMEngineFactoryPointer factory = new ComposeKeyFactory (); + uuids.push_back (factory->get_uuid ()); + names.push_back (utf8_wcstombs (factory->get_name ())); + module_names.push_back (COMPOSE_KEY_MODULE); + langs.push_back (isf_get_normalized_language (factory->get_language ())); + icons.push_back (factory->get_icon_file ()); + modes.push_back (TOOLBAR_KEYBOARD_MODE); + options.push_back (factory->get_option ()); + factory.reset (); + } + + String user_file_name = String (USER_ENGINE_FILE_NAME); + FILE *engine_list_file = fopen (user_file_name.c_str (), "r"); + if (engine_list_file == NULL) { + std::cerr << __func__ << " Failed to open(" << user_file_name << ")\n"; + return; + } + + char buf[MAXLINE]; + while (fgets (buf, MAXLINE, engine_list_file) != NULL) { + ISEINFO info; + isf_get_ise_info_from_string (buf, info); + if (info.mode == TOOLBAR_HELPER_MODE || type != HELPER_ONLY) { + names.push_back (info.name); + uuids.push_back (info.uuid); + module_names.push_back (info.module); + langs.push_back (info.language); + icons.push_back (info.icon); + modes.push_back (info.mode); + options.push_back (info.option); + } + } + + fclose (engine_list_file); +} + +/** + * @brief Load all ISEs information and ISF default languages. + * + * @param type The load ISE type. + * @param config The config pointer for loading keyboard ISE. + */ +void isf_load_ise_information (LOAD_ISE_TYPE type, const ConfigPointer &config) +{ + /* Load ISE engine info */ + isf_get_factory_list (type, config, _uuids, _names, _module_names, _langs, _icons, _modes, _options); + + /* Update _groups */ + std::vector ise_langs; + for (size_t i = 0; i < _uuids.size (); ++i) { + scim_split_string_list (ise_langs, _langs[i]); + for (size_t j = 0; j < ise_langs.size (); j++) { + if (std::find (_groups[ise_langs[j]].begin (), _groups[ise_langs[j]].end (), i) == _groups[ise_langs[j]].end ()) + _groups[ise_langs[j]].push_back (i); + } + ise_langs.clear (); + } +} + +/** + * @brief Load one keyboard ISE module. + * + * @param module_name The keboard ISE module name. + * @param config The config pointer for loading keyboard ISE. + * + * @return true if load module is successful, otherwise return false. + */ +static bool add_keyboard_ise_module (const String module_name, const ConfigPointer &config) +{ + if (module_name.length () <= 0 || module_name == "socket") + return false; + + IMEngineFactoryPointer factory; + IMEngineModule ime_module; + + String filename = String (USER_ENGINE_FILE_NAME); + FILE *engine_list_file = fopen (filename.c_str (), "a"); + if (engine_list_file == NULL) { + LOGD ("Failed to open %s!!!\n", filename.c_str ()); + return false; + } + + ime_module.load (module_name, config); + if (ime_module.valid ()) { + for (size_t j = 0; j < ime_module.number_of_factories (); ++j) { + try { + factory = ime_module.create_factory (j); + } catch (...) { + factory.reset (); + } + + if (!factory.null ()) { + if (std::find (_uuids.begin (), _uuids.end (), factory->get_uuid ()) == _uuids.end ()) { + String uuid = factory->get_uuid (); + String name = utf8_wcstombs (factory->get_name ()); + String language = isf_get_normalized_language (factory->get_language ()); + String icon = factory->get_icon_file (); + char mode[12]; + char option[12]; + + _uuids.push_back (uuid); + _names.push_back (name); + _module_names.push_back (module_name); + _langs.push_back (language); + _icons.push_back (icon); + _modes.push_back (TOOLBAR_KEYBOARD_MODE); + _options.push_back (factory->get_option ()); + + snprintf (mode, sizeof (mode), "%d", (int)TOOLBAR_KEYBOARD_MODE); + snprintf (option, sizeof (option), "%d", factory->get_option ()); + + String line = isf_combine_ise_info_string (name, uuid, module_name, language, + icon, String (mode), String (option), factory->get_locales ()); + if (fputs (line.c_str (), engine_list_file) < 0) { + LOGD ("Failed to write (%s)!!!\n", line.c_str ()); + break; + } + } + factory.reset (); + } + } + ime_module.unload (); + } else { + LOGD ("Failed to load (%s)!!!", module_name.c_str ()); + fclose (engine_list_file); + return false; + } + + int ret = fclose (engine_list_file); + if (ret != 0) + LOGD ("Failed to fclose %s!!!\n", filename.c_str ()); + + return true; +} + +/** + * @brief Load one helper ISE module. + * + * @param module_name The helper ISE module name. + * + * @return true if load module is successful, otherwise return false. + */ +static bool add_helper_ise_module (const String module_name) +{ + if (module_name.length () <= 0) + return false; + + HelperModule helper_module; + HelperInfo helper_info; + + String filename = String (USER_ENGINE_FILE_NAME); + FILE *engine_list_file = fopen (filename.c_str (), "a"); + if (engine_list_file == NULL) { + LOGD ("Failed to open %s!!!\n", filename.c_str ()); + return false; + } + + helper_module.load (module_name); + if (helper_module.valid ()) { + for (size_t j = 0; j < helper_module.number_of_helpers (); ++j) { + helper_module.get_helper_info (j, helper_info); + _uuids.push_back (helper_info.uuid); + _names.push_back (helper_info.name); + _langs.push_back (isf_get_normalized_language (helper_module.get_helper_lang (j))); + _module_names.push_back (module_name); + _icons.push_back (helper_info.icon); + _modes.push_back (TOOLBAR_HELPER_MODE); + _options.push_back (helper_info.option); + + char mode[12]; + char option[12]; + snprintf (mode, sizeof (mode), "%d", (int)TOOLBAR_HELPER_MODE); + snprintf (option, sizeof (option), "%d", helper_info.option); + + String line = isf_combine_ise_info_string (helper_info.name, helper_info.uuid, module_name, isf_get_normalized_language (helper_module.get_helper_lang (j)), + helper_info.icon, String (mode), String (option), String ("")); + if (fputs (line.c_str (), engine_list_file) < 0) { + LOGD ("Failed to write (%s)!!!\n", line.c_str ()); + break; + } + } + helper_module.unload (); + } else { + LOGD ("Failed to load (%s)!!!", module_name.c_str ()); + fclose (engine_list_file); + return false; + } + + int ret = fclose (engine_list_file); + if (ret != 0) + LOGD ("Failed to fclose %s!!!\n", filename.c_str ()); + + return true; +} + +/** + * @brief Update ISEs information for ISE is added or removed. + * + * @param type The load ISE type. + * @param config The config pointer for loading keyboard ISE. + * + * @return true if ISEs list is changed, otherwise return false. + */ +bool isf_update_ise_list (LOAD_ISE_TYPE type, const ConfigPointer &config) +{ + bool ret = false; + + std::vector helper_list; + scim_get_helper_module_list (helper_list); + + std::vector install_modules, uninstall_modules; + + /* Check keyboard ISEs */ + if (type != HELPER_ONLY) { + install_modules.push_back (COMPOSE_KEY_MODULE); + std::vector imengine_list; + scim_get_imengine_module_list (imengine_list); + for (size_t i = 0; i < imengine_list.size (); ++i) { + install_modules.push_back (imengine_list [i]); + if (std::find (_module_names.begin (), _module_names.end (), imengine_list [i]) == _module_names.end ()) { + if (add_keyboard_ise_module (imengine_list [i], config)) + ret = true; + } + } + } + + /* Check helper ISEs */ + for (size_t i = 0; i < helper_list.size (); ++i) { + install_modules.push_back (helper_list [i]); + if (std::find (_module_names.begin (), _module_names.end (), helper_list [i]) == _module_names.end ()) { + if (add_helper_ise_module (helper_list [i])) + ret = true; + } + } + + /* Try to find uninstall ISEs */ + bool bFindUninstall = false; + for (size_t i = 0; i < _module_names.size (); ++i) { + if (std::find (install_modules.begin (), install_modules.end (), _module_names [i]) == install_modules.end ()) { + ret = true; + bFindUninstall = true; + /* Avoid to add the same module */ + if (std::find (uninstall_modules.begin (), uninstall_modules.end (), _module_names [i]) == uninstall_modules.end ()) { + uninstall_modules.push_back (_module_names [i]); + String filename = String (USER_ENGINE_FILE_NAME); + if (isf_remove_ise_info_from_file (filename.c_str (), _module_names [i].c_str ()) == false) + LOGD ("Failed to remove %s from cache file : %s!!!", _module_names [i].c_str (), filename.c_str ()); + } + } + } + if (bFindUninstall) { + std::vector tmp_uuids = _uuids; + std::vector tmp_names = _names; + std::vector tmp_module_names = _module_names; + std::vector tmp_langs = _langs; + std::vector tmp_icons = _icons; + std::vector tmp_options = _options; + std::vector tmp_modes = _modes; + + _uuids.clear (); + _names.clear (); + _module_names.clear (); + _langs.clear (); + _icons.clear (); + _options.clear (); + _modes.clear (); + _groups.clear (); + + for (size_t i = 0; i < tmp_module_names.size (); ++i) { + if (std::find (uninstall_modules.begin (), uninstall_modules.end (), tmp_module_names [i]) == uninstall_modules.end ()) { + _uuids.push_back (tmp_uuids [i]); + _names.push_back (tmp_names [i]); + _module_names.push_back (tmp_module_names [i]); + _langs.push_back (tmp_langs [i]); + _icons.push_back (tmp_icons [i]); + _options.push_back (tmp_options [i]); + _modes.push_back (tmp_modes [i]); + } + } + } + + /* Update _groups */ + if (ret) { + std::vector ise_langs; + for (size_t i = 0; i < _uuids.size (); ++i) { + scim_split_string_list (ise_langs, _langs[i]); + for (size_t j = 0; j < ise_langs.size (); j++) { + if (std::find (_groups[ise_langs[j]].begin (), _groups[ise_langs[j]].end (), i) == _groups[ise_langs[j]].end ()) + _groups[ise_langs[j]].push_back (i); + } + ise_langs.clear (); + } + } + + return ret; +} + +bool isf_remove_ise_module (const String module_name, const ConfigPointer &config) +{ + if (std::find (_module_names.begin (), _module_names.end (), module_name) == _module_names.end ()) { + LOGD ("Cannot to find %s!!!", module_name.c_str ()); + return true; + } + + String filename = String (USER_ENGINE_FILE_NAME); + if (isf_remove_ise_info_from_file (filename.c_str (), module_name.c_str ())) { + isf_get_factory_list (ALL_ISE, config, _uuids, _names, _module_names, _langs, _icons, _modes, _options); + + /* Update _groups */ + _groups.clear (); + std::vector ise_langs; + for (size_t i = 0; i < _uuids.size (); ++i) { + scim_split_string_list (ise_langs, _langs[i]); + for (size_t j = 0; j < ise_langs.size (); j++) { + if (std::find (_groups[ise_langs[j]].begin (), _groups[ise_langs[j]].end (), i) == _groups[ise_langs[j]].end ()) + _groups[ise_langs[j]].push_back (i); + } + ise_langs.clear (); + } + return true; + } else { + LOGD ("Failed to remove %s from cache file : %s!!!", module_name.c_str (), filename.c_str ()); + return false; + } +} + +bool isf_update_ise_module (const String strModulePath, const ConfigPointer &config) +{ + bool ret = false; + struct stat filestat; + stat (strModulePath.c_str (), &filestat); + if (!S_ISDIR (filestat.st_mode)) { + int begin = strModulePath.find_last_of (SCIM_PATH_DELIM) + 1; + String mod_name = strModulePath.substr (begin, strModulePath.find_last_of ('.') - begin); + String path = strModulePath.substr (0, strModulePath.find_last_of (SCIM_PATH_DELIM)); + LOGD ("module_name = %s, path = %s", mod_name.c_str (), path.c_str ()); + + if (mod_name.length () > 0 && path.length () > 1) { + if (isf_remove_ise_module (mod_name, config)) { + String type = path.substr (path.find_last_of (SCIM_PATH_DELIM) + 1); + LOGD ("type = %s", type.c_str ()); + if (type == String ("Helper")) { + if (add_helper_ise_module (mod_name)) + ret = true; + } else if (type == String ("IMEngine")) { + if (add_keyboard_ise_module (mod_name, config)) + ret = true; + } + } + } else { + LOGD ("%s is not valid so file!!!", strModulePath.c_str ()); + } + } + + /* Update _groups */ + if (ret) { + _groups.clear (); + std::vector ise_langs; + for (size_t i = 0; i < _uuids.size (); ++i) { + scim_split_string_list (ise_langs, _langs[i]); + for (size_t j = 0; j < ise_langs.size (); j++) { + if (std::find (_groups[ise_langs[j]].begin (), _groups[ise_langs[j]].end (), i) == _groups[ise_langs[j]].end ()) + _groups[ise_langs[j]].push_back (i); + } + ise_langs.clear (); + } + } + + return ret; +} + +/* +vi:ts=4:nowrap:ai:expandtab +*/ diff --git a/ism/extras/efl_wsm/isf_wsm_utility.h b/ism/extras/efl_wsm/isf_wsm_utility.h new file mode 100644 index 0000000..ba2d660 --- /dev/null +++ b/ism/extras/efl_wsm/isf_wsm_utility.h @@ -0,0 +1,73 @@ +/* + * ISF(Input Service Framework) + * + * ISF is based on SCIM 1.4.7 and extended for supporting more mobile fitable. + * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. + * + * Contact: Yan Wang + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __ISF_WSM_UTILITY_H +#define __ISF_WSM_UTILITY_H + +using namespace scim; + + +///////////////////////////////////////////////////////////////////////////// +// Declaration of macro. +///////////////////////////////////////////////////////////////////////////// +#define COMPOSE_KEY_MODULE "COMPOSE_KEY_MODULE" + + +#if SCIM_USE_STL_EXT_HASH_MAP +typedef __gnu_cxx::hash_map , scim_hash_string> MapStringVectorSizeT; +typedef std::map > MapStringVectorString; +typedef std::map MapStringString; +#elif SCIM_USE_STL_HASH_MAP +typedef std::hash_map , scim_hash_string> MapStringVectorSizeT; +typedef std::map > MapStringVectorString; +typedef std::map MapStringString; +#else +typedef std::map > MapStringVectorSizeT; +typedef std::map > MapStringVectorString; +typedef std::map MapStringString; +#endif + +typedef enum { + ALL_ISE = 0, + HELPER_ONLY, + TYPE_END +} LOAD_ISE_TYPE; + +void isf_get_all_languages (std::vector &all_langs); +void isf_get_all_ises_in_languages (std::vector lang_list, std::vector &uuid_list, std::vector &name_list); + +void isf_get_keyboard_ise (const ConfigPointer &config, String &ise_uuid, String &ise_name, uint32 &ise_option); +void isf_get_keyboard_ises_in_languages (const std::vector &lang_list, std::vector &uuid_list, std::vector &name_list, bool bCheckOption = true); +void isf_get_helper_ises_in_languages (const std::vector &lang_list, std::vector &uuid_list, std::vector &name_list); + +void isf_save_ise_information (void); +void isf_load_ise_information (LOAD_ISE_TYPE type, const ConfigPointer &config); +bool isf_update_ise_list (LOAD_ISE_TYPE type, const ConfigPointer &config); +bool isf_update_ise_module (const String strModulePath, const ConfigPointer &config); + +#endif /* __ISF_WSM_UTILITY_H */ + +/* +vi:ts=4:ai:nowrap:expandtab +*/ diff --git a/ism/src/Makefile.am b/ism/src/Makefile.am index 6b56699..558dc8d 100644 --- a/ism/src/Makefile.am +++ b/ism/src/Makefile.am @@ -155,6 +155,10 @@ libscim@SCIM_EPOCH@_la_LDFLAGS = -version-info $(SCIM_CURRENT):$(SCIM_REVISION) @EFL_LIBS@ \ -lstdc++ \ -ltzplatform-config-1.0 +if HAVE_X +libscim@SCIM_EPOCH@_la_CXXFLAGS += @ECOREX_CFLAGS@ +libscim@SCIM_EPOCH@_la_LDFLAGS += @ECOREX_LIBS@ +endif libscim@SCIM_EPOCH@_la_LIBADD = libltdlc.la @@ -166,6 +170,11 @@ scim_CXXFLAGS = @EFL_CFLAGS@ @PRIVILEGE_CONTROL_CFLAGS@ @VCONF_CFLAGS@ scim_LDADD = libscim@SCIM_EPOCH@.la scim_LDFLAGS = @LTLIBINTL@ @EFL_LIBS@ @PRIVILEGE_CONTROL_LIBS@ @VCONF_LIBS@ +if HAVE_X +scim_CXXFLAGS += @ECOREX_CFLAGS@ +scim_LDFLAGS += @ECOREX_LIBS@ +endif + isf_log_SOURCES = isf_log.cpp isf_log_LDADD = libscim@SCIM_EPOCH@.la if SCIM_BUILD_GTK_UTILS @@ -193,5 +202,10 @@ scim_helper_launcher_CXXFLAGS = @PRIVILEGE_CONTROL_CFLAGS@ @AIL_CFLAGS@ @EFL_CFL scim_helper_launcher_LDADD = libscim@SCIM_EPOCH@.la scim_helper_launcher_LDFLAGS = @LTLIBINTL@ @PRIVILEGE_CONTROL_LIBS@ @AIL_LIBS@ @EFL_LIBS@ +if HAVE_X +scim_helper_launcher_CXXFLAGS += @ECOREX_CFLAGS@ +scim_helper_launcher_LDFLAGS += @ECOREX_LIBS@ +endif + diff --git a/ism/src/ise_context.h b/ism/src/ise_context.h index b56f7e2..7d3febd 100644 --- a/ism/src/ise_context.h +++ b/ism/src/ise_context.h @@ -26,13 +26,17 @@ #define __ISE_CONTEXT_H #include +#ifndef WAYLAND #include +#endif typedef struct { Ecore_IMF_Input_Panel_Lang language; Ecore_IMF_Input_Panel_Layout layout; Ecore_IMF_Input_Panel_Return_Key_Type return_key_type; +#ifndef WAYLAND Ecore_X_Window client_window; +#endif int imdata_size; int cursor_pos; Eina_Bool return_key_disabled; diff --git a/ism/src/ise_preexec.cpp b/ism/src/ise_preexec.cpp index 50323a6..39375a2 100644 --- a/ism/src/ise_preexec.cpp +++ b/ism/src/ise_preexec.cpp @@ -291,7 +291,11 @@ static void __set_oom () static inline int __set_dac () { +#ifdef WAYLAND + return 0; +#else return perm_app_set_privilege("isf", NULL, NULL); +#endif } static inline int __set_smack (char* path) diff --git a/ism/src/scim.cpp b/ism/src/scim.cpp index 6a0703e..a647437 100644 --- a/ism/src/scim.cpp +++ b/ism/src/scim.cpp @@ -126,6 +126,7 @@ static bool check_wm_ready (void) { SCIM_DEBUG_MAIN (3) << __FUNCTION__ << "...\n"; +#ifndef WAYLAND #ifdef WAIT_WM int try_count = 0; while (check_file (ISF_SYSTEM_WM_READY_FILE) == false) { @@ -133,6 +134,7 @@ static bool check_wm_ready (void) usleep (ISF_SYSTEM_WAIT_DELAY); } #endif +#endif return true; } diff --git a/ism/src/scim_config_path.h b/ism/src/scim_config_path.h index 7425eb3..dd11aab 100644 --- a/ism/src/scim_config_path.h +++ b/ism/src/scim_config_path.h @@ -72,7 +72,11 @@ namespace scim { #define SCIM_GLOBAL_CONFIG_DISABLED_IMENGINE_FACTORIES "/DisabledIMEngineFactories" #define SCIM_GLOBAL_CONFIG_SUPPORTED_UNICODE_LOCALES "/SupportedUnicodeLocales" #define SCIM_GLOBAL_CONFIG_DEFAULT_KEYBOARD_LAYOUT "/DefaultKeyboardLayout" +#ifdef WAYLAND +#define SCIM_GLOBAL_CONFIG_DEFAULT_PANEL_PROGRAM "/DefaultPanelProgram2" +#else #define SCIM_GLOBAL_CONFIG_DEFAULT_PANEL_PROGRAM "/DefaultPanelProgram" +#endif #define SCIM_GLOBAL_CONFIG_DEFAULT_CONFIG_MODULE "/DefaultConfigModule" #define SCIM_GLOBAL_CONFIG_DEFAULT_SOCKET_FRONTEND_ADDRESS "/DefaultSocketFrontEndAddress" #define SCIM_GLOBAL_CONFIG_DEFAULT_SOCKET_IMENGINE_ADDRESS "/DefaultSocketIMEngineAddress" diff --git a/packaging/isf.spec b/packaging/isf.spec index f8638e6..60066b5 100644 --- a/packaging/isf.spec +++ b/packaging/isf.spec @@ -1,3 +1,4 @@ +%bcond_with wayland Name: isf Summary: Input Service Framework Version: 2.4.7424 @@ -15,15 +16,20 @@ BuildRequires: gettext-tools BuildRequires: pkgconfig(appcore-efl) BuildRequires: pkgconfig(libprivilege-control) BuildRequires: pkgconfig(elementary) -BuildRequires: pkgconfig(utilX) BuildRequires: pkgconfig(vconf) +%if %{with wayland} +BuildRequires: pkgconfig(ecore-wayland) +BuildRequires: pkgconfig(xkbcommon) >= 0.3.0 +%else +BuildRequires: pkgconfig(utilX) %if "%{_repository}" != "wearable" BuildRequires: pkgconfig(ui-gadget-1) BuildRequires: pkgconfig(minicontrol-provider) %endif +BuildRequires: pkgconfig(x11) +%endif BuildRequires: pkgconfig(ecore) BuildRequires: pkgconfig(edje) -BuildRequires: pkgconfig(x11) BuildRequires: pkgconfig(notification) BuildRequires: pkgconfig(dlog) BuildRequires: pkgconfig(tts) @@ -67,14 +73,37 @@ CFLAGS+=" -D_MOBILE"; CXXFLAGS+=" -D_MOBILE"; %endif +%if %{with wayland} +CFLAGS+=" -DWAYLAND" +CXXFLAGS+=" -DWAYLAND" +%endif + export GC_SECTIONS_FLAGS="-fdata-sections -ffunction-sections -Wl,--gc-sections" + +CFLAGS+=" -I/usr/include/elementary-1 -I/usr/include/eina-1 -I/usr/include/eina-1/eina -I/usr/include/ecore-1 " +CFLAGS+=" -I/usr/include/evas-1 -I/usr/include/eet-1 -I/usr/include/edje-1 -I/usr/include/e_dbus-1 " +CFLAGS+=" -I/usr/include/eio-1 -I/usr/include/ethumb-1 -I/usr/include/efreet-1 -I/usr/include/emotion-1 -I/usr/include/embryo-1 " +CFLAGS+=" -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include/ " CFLAGS+=" -fvisibility=hidden ${GC_SECTIONS_FLAGS} "; export CFLAGS + +CXXFLAGS+=" -I/usr/include/elementary-1 -I/usr/include/eina-1 -I/usr/include/eina-1/eina -I/usr/include/ecore-1 " +CXXFLAGS+=" -I/usr/include/evas-1 -I/usr/include/eet-1 -I/usr/include/edje-1 -I/usr/include/e_dbus-1 " +CXXFLAGS+=" -I/usr/include/eio-1 -I/usr/include/ethumb-1 -I/usr/include/efreet-1 -I/usr/include/emotion-1 -I/usr/include/embryo-1 " +CXXFLAGS+=" -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include/ " CXXFLAGS+=" -fvisibility=hidden -fvisibility-inlines-hidden ${GC_SECTIONS_FLAGS} ";export CXXFLAGS %autogen %configure --disable-static \ --disable-tray-icon \ --disable-filter-sctc \ +%if %{with wayland} + --disable-panel-efl \ + --disable-setting-efl \ + --disable-efl-immodule \ +%else + --disable-wsm-efl \ + --disable-wsc-efl \ +%endif --disable-frontend-x11 make %{?_smp_mflags} @@ -87,12 +116,15 @@ mkdir -p %{buildroot}/opt/apps/scim/lib/scim-1.0/1.4.0/Helper mkdir -p %{buildroot}/opt/apps/scim/lib/scim-1.0/1.4.0/SetupUI mkdir -p %{buildroot}/opt/apps/scim/lib/scim-1.0/1.4.0/IMEngine +%if %{with wayland} +%else %if "%{_repository}" != "wearable" install -d %{buildroot}%{_libdir}/systemd/system/graphical.target.wants install -d %{buildroot}%{_libdir}/systemd/system install -m0644 %{SOURCE1} %{buildroot}%{_libdir}/systemd/system/ ln -sf ../../system/scim.service %{buildroot}%{_libdir}/systemd/system/graphical.target.wants/scim.service %endif +%endif %find_lang scim @@ -115,7 +147,7 @@ cat scim.lang > isf.lang %dir /opt/apps/scim/lib/scim-1.0/1.4.0/Helper %dir /opt/apps/scim/lib/scim-1.0/1.4.0/SetupUI %dir /opt/apps/scim/lib/scim-1.0/1.4.0/IMEngine -%if "%{_repository}" == "wearable" +%if "%{_repository}" == "wearable" || %{with wayland} %dir /etc/scim/conf %{_libdir}/systemd/user/core-efl.target.wants/scim.service %{_libdir}/systemd/user/scim.service @@ -128,12 +160,17 @@ cat scim.lang > isf.lang %{_sysconfdir}/scim/config %{_datadir}/scim/isf_candidate_theme1.edj %{_datadir}/scim/icons/* +%if %{with wayland} +%{_bindir}/isf-wsm-efl +%{_bindir}/isf-wsc-efl +%else %{_bindir}/isf-demo-efl +%{_bindir}/isf-panel-efl +%{_libdir}/*/immodules/*.so +%endif %{_bindir}/scim %{_bindir}/isf-log -%{_bindir}/isf-panel-efl %{_bindir}/isf-query-engines -%{_libdir}/*/immodules/*.so %{_libdir}/scim-1.0/1.4.0/IMEngine/socket.so %{_libdir}/scim-1.0/1.4.0/Config/simple.so %{_libdir}/scim-1.0/1.4.0/Config/socket.so