summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEduardo Lima (Etrunko) <eduardo.lima@intel.com>2013-08-16 17:08:23 -0300
committerEduardo Lima (Etrunko) <eduardo.lima@intel.com>2013-08-16 17:08:23 -0300
commit562d8297a8a6099541b41bc9f98f12ff6b06d996 (patch)
tree3667bb272a7f79c632fbc87b95b0bd1fa2bcf13a /src
downloadweekeyboard-562d8297a8a6099541b41bc9f98f12ff6b06d996.tar.gz
weekeyboard-562d8297a8a6099541b41bc9f98f12ff6b06d996.tar.bz2
weekeyboard-562d8297a8a6099541b41bc9f98f12ff6b06d996.zip
Initial commit
Signed-off-by: Eduardo Lima (Etrunko) <eduardo.lima@intel.com>
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am51
-rw-r--r--src/wkb-ibus-config-eet-test.c46
-rw-r--r--src/wkb-ibus-config-eet.c962
-rw-r--r--src/wkb-ibus-config-eet.h34
-rw-r--r--src/wkb-ibus-config.c170
-rw-r--r--src/wkb-ibus-panel.c831
-rw-r--r--src/wkb-ibus-test.c69
-rw-r--r--src/wkb-ibus.c507
-rw-r--r--src/wkb-ibus.h69
-rw-r--r--src/wkb-main.c601
10 files changed, 3340 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..5d53bff
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,51 @@
+bin_PROGRAMS = \
+ weekeyboard
+
+AM_CFLAGS= \
+ @WAYLAND_CFLAGS@ \
+ @EFL_CFLAGS@ \
+ @ELDBUS_CFLAGS@ \
+ -DPKGDATADIR='"$(pkgdatadir)"'
+
+AM_LDFLAGS= \
+ @WAYLAND_LIBS@ \
+ @EFL_LIBS@ \
+ @ELDBUS_LIBS@
+
+weekeyboard_SOURCES= \
+ wkb-main.c \
+ input-method-protocol.c \
+ input-method-client-protocol.h \
+ text-protocol.c \
+ text-client-protocol.h
+
+
+if ENABLE_IBUS
+noinst_PROGRAMS = \
+ weekeyboard-config-eet-test
+
+weekeyboard_config_eet_test_SOURCES = \
+ wkb-ibus-config-eet.c \
+ wkb-ibus-config-eet.h \
+ wkb-ibus-config-eet-test.c
+
+noinst_PROGRAMS += \
+ weekeyboard-ibus-test
+
+weekeyboard_ibus_test_SOURCES = \
+ wkb-ibus.h \
+ wkb-ibus.c \
+ wkb-ibus-panel.c \
+ wkb-ibus-config.c \
+ wkb-ibus-config-eet.c \
+ wkb-ibus-config-eet.h \
+ wkb-ibus-test.c
+endif
+
+@wayland_scanner_rules@
+
+BUILT_SOURCES= \
+ input-method-protocol.c \
+ input-method-client-protocol.h \
+ text-protocol.c \
+ text-client-protocol.h
diff --git a/src/wkb-ibus-config-eet-test.c b/src/wkb-ibus-config-eet-test.c
new file mode 100644
index 0000000..a4f0ced
--- /dev/null
+++ b/src/wkb-ibus-config-eet-test.c
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+#include "wkb-ibus-config-eet.h"
+
+#include <Eina.h>
+#include <Eet.h>
+
+int
+main (int argc, char *argv[])
+{
+ struct wkb_ibus_config_eet *cfg;
+
+ if (!eina_init())
+ {
+ printf("Error initializing eina");
+ return 1;
+ }
+
+ if (!eet_init())
+ {
+ printf("Error initializing eet");
+ return 1;
+ }
+
+ cfg = wkb_ibus_config_eet_new("ibus-cfg.eet");
+ wkb_ibus_config_eet_free(cfg);
+
+ eet_shutdown();
+ eina_shutdown();
+
+ return 0;
+}
diff --git a/src/wkb-ibus-config-eet.c b/src/wkb-ibus-config-eet.c
new file mode 100644
index 0000000..ad9bc5e
--- /dev/null
+++ b/src/wkb-ibus-config-eet.c
@@ -0,0 +1,962 @@
+/*
+ * 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 eetific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <Eina.h>
+#include <Eet.h>
+
+#include "wkb-ibus-config-eet.h"
+
+/*
+ * Base struct for all config types
+ */
+struct _config_section
+{
+ const char *id;
+
+ void (*free)(struct _config_section *);
+ void (*set_defaults)(struct _config_section *);
+ Eina_Bool (*set_value)(struct _config_section *, const char *, const char *, Eldbus_Message_Iter *);
+ void *(*get_value)(struct _config_section *, const char *, const char *);
+ void *(*get_values)(struct _config_section *, const char *);
+};
+
+static void
+_config_section_free(struct _config_section *base)
+{
+ eina_stringshare_del(base->id);
+ base->free(base);
+}
+
+static void
+_config_section_set_defaults(struct _config_section *base)
+{
+ base->set_defaults(base);
+}
+
+static Eina_Bool
+_config_section_set_value(struct _config_section *base, const char *section, const char *name, Eldbus_Message_Iter *value)
+{
+ return base->set_value(base, section, name, value);
+}
+
+static void *
+_config_section_get_value(struct _config_section *base, const char *section, const char *name)
+{
+ return base->get_value(base, section, name);
+}
+
+static void *
+_config_section_get_values(struct _config_section *base, const char *section)
+{
+ return base->get_values(base, section);
+}
+
+/*
+ * Helpers for manipulating list of strings
+ */
+static void
+_config_string_list_free(Eina_List *list)
+{
+ const char *str;
+
+ EINA_LIST_FREE(list, str)
+ eina_stringshare_del(str);
+
+ eina_list_free(list);
+}
+
+static Eina_List *
+_config_string_list_new(const char **strs)
+{
+ Eina_List *list = NULL;
+ const char *str;
+
+ for (str = *strs; str != NULL; str = *++strs)
+ list = eina_list_append(list, eina_stringshare_add(str));
+
+ return list;
+}
+
+/*
+ * <schema path="/desktop/ibus/general/hotkey/" id="org.freedesktop.ibus.general.hotkey">
+ * <key type="as" name="trigger">
+ * <default>[ 'Control+space', 'Zenkaku_Hankaku', 'Alt+Kanji', 'Alt+grave', 'Hangul', 'Alt+Release+Alt_R' ]</default>
+ * <summary>Trigger shortcut keys</summary>
+ * <description>The shortcut keys for turning input method on or off</description>
+ * </key>
+ * <key type="as" name="triggers">
+ * <default>[ '&lt;Super&gt;space' ]</default>
+ * <summary>Trigger shortcut keys for gtk_accelerator_parse</summary>
+ * <description>The shortcut keys for turning input method on or off</description>
+ * </key>
+ * <key type="as" name="enable-unconditional">
+ * <default>[]</default>
+ * <summary>Enable shortcut keys</summary>
+ * <description>The shortcut keys for turning input method on</description>
+ * </key>
+ * <key type="as" name="disable-unconditional">
+ * <default>[]</default>
+ * <summary>Disable shortcut keys</summary>
+ * <description>The shortcut keys for turning input method off</description>
+ * </key>
+ * <key type="as" name="next-engine">
+ * <default>[ 'Alt+Shift_L' ]</default>
+ * <summary>Next engine shortcut keys</summary>
+ * <description>The shortcut keys for switching to the next input method in the list</description>
+ * </key>
+ * <key type="as" name="next-engine-in-menu">
+ * <default>[ 'Alt+Shift_L' ]</default>
+ * <summary>Next engine shortcut keys</summary>
+ * <description>The shortcut keys for switching to the next input method in the list</description>
+ * </key>
+ * <key type="as" name="prev-engine">
+ * <default>[]</default>
+ * <summary>Prev engine shortcut keys</summary>
+ * <description>The shortcut keys for switching to the previous input method</description>
+ * </key>
+ * <key type="as" name="previous-engine">
+ * <default>[]</default>
+ * <summary>Prev engine shortcut keys</summary>
+ * <description>The shortcut keys for switching to the previous input method</description>
+ * </key>
+ * </schema>
+ */
+struct _config_hotkey
+{
+ struct _config_section base;
+
+ Eina_List *trigger;
+ Eina_List *triggers;
+ Eina_List *enable_unconditional;
+ Eina_List *disable_unconditional;
+ Eina_List *next_engine;
+ Eina_List *next_engine_in_menu;
+ Eina_List *prev_engine;
+ Eina_List *previous_engine;
+};
+
+static Eet_Data_Descriptor *
+_config_hotkey_edd_new(void)
+{
+ Eet_Data_Descriptor *edd;
+ Eet_Data_Descriptor_Class eddc;
+
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, struct _config_hotkey);
+ edd = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "trigger", trigger);
+ EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "triggers", triggers);
+ EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "enable-unconditional", enable_unconditional);
+ EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "disable-unconditional", disable_unconditional);
+ EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "next-engine", next_engine);
+ EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "next-engine-in-menu", next_engine_in_menu);
+ EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "prev-engine", prev_engine);
+ EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "previous-engine", previous_engine);
+
+ return edd;
+}
+
+static void
+_config_hotkey_set_defaults(struct _config_section *base)
+{
+ struct _config_hotkey *hotkey = (struct _config_hotkey *) base;
+
+ const char *trigger[] = { "Control+space", "Zenkaku_Hankaku", "Alt+Kanji", "Alt+grave", "Hangul", "Alt+Release+Alt_R", NULL };
+ const char *triggers[] = { "<Super>space", NULL };
+ const char *enable_unconditional[] = { NULL };
+ const char *disable_unconditional[] = { NULL };
+ const char *next_engine[] = { NULL };
+ const char *next_engine_in_menu[] = { NULL };
+ const char *prev_engine[] = { NULL };
+ const char *previous_engine[] = { NULL };
+
+ hotkey->trigger = _config_string_list_new(trigger);
+ hotkey->triggers = _config_string_list_new(triggers);
+ hotkey->enable_unconditional = _config_string_list_new(enable_unconditional);
+ hotkey->disable_unconditional = _config_string_list_new(disable_unconditional);
+ hotkey->next_engine = _config_string_list_new(next_engine);
+ hotkey->next_engine_in_menu = _config_string_list_new(next_engine_in_menu);
+ hotkey->prev_engine = _config_string_list_new(prev_engine);
+ hotkey->previous_engine = _config_string_list_new(previous_engine);
+}
+
+static void
+_config_hotkey_free(struct _config_section *base)
+{
+ struct _config_hotkey *hotkey = (struct _config_hotkey *) base;
+
+ _config_string_list_free(hotkey->trigger);
+ _config_string_list_free(hotkey->triggers);
+ _config_string_list_free(hotkey->enable_unconditional);
+ _config_string_list_free(hotkey->disable_unconditional);
+ _config_string_list_free(hotkey->next_engine);
+ _config_string_list_free(hotkey->next_engine_in_menu);
+ _config_string_list_free(hotkey->prev_engine);
+ _config_string_list_free(hotkey->previous_engine);
+
+ free(hotkey);
+}
+
+static Eina_Bool
+_config_hotkey_set_value(struct _config_section *base, const char *section, const char *name, Eldbus_Message_Iter *value)
+{
+ return EINA_FALSE;
+}
+
+static void *
+_config_hotkey_get_value(struct _config_section *base, const char *section, const char *name)
+{
+ return NULL;
+}
+
+static void *
+_config_hotkey_get_values(struct _config_section *base, const char *section)
+{
+ return NULL;
+}
+
+static void
+_config_hotkey_section_init(struct _config_section *base)
+{
+ base->id = eina_stringshare_add("hotkey");
+ base->free = _config_hotkey_free;
+ base->set_defaults = _config_hotkey_set_defaults;
+ base->set_value = _config_hotkey_set_value;
+ base->get_value = _config_hotkey_get_value;
+ base->get_values = _config_hotkey_get_values;
+}
+
+static struct _config_section *
+_config_hotkey_new(void)
+{
+ struct _config_hotkey *conf = calloc(1, sizeof(*conf));
+ _config_hotkey_section_init((struct _config_section *) conf);
+ return (struct _config_section *) conf;
+}
+
+/*
+ * <schema path="/desktop/ibus/general/" id="org.freedesktop.ibus.general">
+ * <key type="as" name="preload-engines">
+ * <default>[]</default>
+ * <summary>Preload engines</summary>
+ * <description>Preload engines during ibus starts up</description>
+ * </key>
+ * <key type="as" name="engines-order">
+ * <default>[]</default>
+ * <summary>Engines order</summary>
+ * <description>Saved engines order in input method list</description>
+ * </key>
+ * <key type="i" name="switcher-delay-time">
+ * <default>400</default>
+ * <summary>Popup delay milliseconds for IME switcher window</summary>
+ * <description>Set popup delay milliseconds to show IME switcher window. The default is 400. 0 = Show the window immediately. 0 &lt; Delay milliseconds. 0 &gt; Do not show the
+ * </key>
+ * <key type="s" name="version">
+ * <default>''</default>
+ * <summary>Saved version number</summary>
+ * <description>The saved version number will be used to check the difference between the version of the previous installed ibus and one of the current ibus.</description>
+ * </key>
+ * <key type="b" name="use-system-keyboard-layout">
+ * <default>false</default>
+ * <summary>Use system keyboard layout</summary>
+ * <description>Use system keyboard (XKB) layout</description>
+ * </key>
+ * <key type="b" name="embed-preedit-text">
+ * <default>true</default>
+ * <summary>Embed Preedit Text</summary>
+ * <description>Embed Preedit Text in Application Window</description>
+ * </key>
+ * <key type="b" name="use-global-engine">
+ * <default>false</default>
+ * <summary>Use global input method</summary>
+ * <description>Share the same input method among all applications</description>
+ * </key>
+ * <key type="b" name="enable-by-default">
+ * <default>false</default>
+ * <summary>Enable input method by default</summary>
+ * <description>Enable input method by default when the application gets input focus</description>
+ * </key>
+ * <key type="as" name="dconf-preserve-name-prefixes">
+ * <default>[ '/desktop/ibus/engine/pinyin', '/desktop/ibus/engine/bopomofo', '/desktop/ibus/engine/hangul' ]</default>
+ * <summary>DConf preserve name prefixes</summary>
+ * <description>Prefixes of DConf keys to stop name conversion</description>
+ * </key>
+ * <child schema="org.freedesktop.ibus.general.hotkey" name="hotkey"/>
+ * </schema>
+ */
+struct _config_general
+{
+ struct _config_section base;
+
+ struct _config_section *hotkey;
+
+ Eina_List *preload_engines;
+ Eina_List *engines_order;
+ Eina_List *dconf_preserve_name_prefixes;
+
+ const char *version;
+
+ int switcher_delay_time;
+
+ Eina_Bool use_system_keyboard_layout;
+ Eina_Bool embed_preedit_text;
+ Eina_Bool use_global_engine;
+ Eina_Bool enable_by_default;
+};
+
+static Eet_Data_Descriptor *
+_config_general_edd_new(Eet_Data_Descriptor *hotkey_edd)
+{
+ Eet_Data_Descriptor *edd;
+ Eet_Data_Descriptor_Class eddc;
+
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, struct _config_general);
+ edd = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_general, "preload-engines", preload_engines);
+ EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_general, "engines-order", engines_order);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_general, "switcher-delay-time", switcher_delay_time, EET_T_INT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_general, "version", version, EET_T_STRING);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_general, "use-system-keyboard-layout", use_system_keyboard_layout, EET_T_UCHAR);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_general, "embed-preedit-text", embed_preedit_text, EET_T_UCHAR);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_general, "use-global-engine", use_global_engine, EET_T_UCHAR);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_general, "enable-by-default", enable_by_default, EET_T_UCHAR);
+ EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_general, "dconf-preserve-name-prefixes", dconf_preserve_name_prefixes);
+ EET_DATA_DESCRIPTOR_ADD_SUB(edd, struct _config_general, "hotkey", hotkey, hotkey_edd);
+
+ return edd;
+}
+
+static void
+_config_general_set_defaults(struct _config_section *base)
+{
+ struct _config_general *general = (struct _config_general *) base;
+
+ const char *preload_engines[] = { NULL };
+ const char *engines_order[] = { NULL };
+ const char *dconf_preserve_name_prefixes[] = { "/desktop/ibus/engine/pinyin", "/desktop/ibus/engine/bopomofo", "/desktop/ibus/engine/hangul", NULL };
+
+ _config_section_set_defaults(general->hotkey);
+
+ general->preload_engines = _config_string_list_new(preload_engines);
+ general->engines_order = _config_string_list_new(engines_order);
+ general->switcher_delay_time = 400;
+ general->version = eina_stringshare_add("");
+ general->use_system_keyboard_layout = EINA_FALSE;
+ general->embed_preedit_text = EINA_TRUE;
+ general->use_global_engine = EINA_FALSE;
+ general->enable_by_default = EINA_FALSE;
+ general->dconf_preserve_name_prefixes = _config_string_list_new(dconf_preserve_name_prefixes);
+
+}
+
+static void
+_config_general_free(struct _config_section *base)
+{
+ struct _config_general *general = (struct _config_general *) base;
+
+ _config_section_free(general->hotkey);
+
+ _config_string_list_free(general->preload_engines);
+ _config_string_list_free(general->engines_order);
+ _config_string_list_free(general->dconf_preserve_name_prefixes);
+
+ eina_stringshare_del(general->version);
+ free(general);
+}
+
+static Eina_Bool
+_config_general_set_value(struct _config_section *base, const char *section, const char *name, Eldbus_Message_Iter *value)
+{
+ return EINA_FALSE;
+}
+
+static void *
+_config_general_get_value(struct _config_section *base, const char *section, const char *name)
+{
+ return NULL;
+}
+
+static void *
+_config_general_get_values(struct _config_section *base, const char *section)
+{
+ return NULL;
+}
+
+static void
+_config_general_section_init(struct _config_section *base)
+{
+ struct _config_general *general = (struct _config_general *) base;
+
+ base->id = eina_stringshare_add("general");
+ base->free = _config_general_free;
+ base->set_defaults = _config_general_set_defaults;
+ base->set_value = _config_general_set_value;
+ base->get_value = _config_general_get_value;
+ base->get_values = _config_general_get_values;
+
+ if (general->hotkey)
+ _config_hotkey_section_init(general->hotkey);
+}
+
+static struct _config_section *
+_config_general_new(void)
+{
+ struct _config_general *conf = calloc(1, sizeof(*conf));
+ _config_general_section_init((struct _config_section *) conf);
+ conf->hotkey = _config_hotkey_new();
+ return (struct _config_section *) conf;
+}
+
+/*
+ * <schema path="/desktop/ibus/panel/" id="org.freedesktop.ibus.panel">
+ * <key type="i" name="show">
+ * <default>0</default>
+ * <summary>Auto hide</summary>
+ * <description>The behavior of language panel. 0 = Embedded in menu, 1 = Auto hide, 2 = Always show</description>
+ * </key>
+ * <key type="i" name="x">
+ * <default>-1</default>
+ * <summary>Language panel position</summary>
+ * </key>
+ * <key type="i" name="y">
+ * <default>-1</default>
+ * <summary>Language panel position</summary>
+ * </key>
+ * <key type="i" name="lookup-table-orientation">
+ * <default>1</default>
+ * <summary>Orientation of lookup table</summary>
+ * <description>Orientation of lookup table. 0 = Horizontal, 1 = Vertical</description>
+ * </key>
+ * <key type="b" name="show-icon-on-systray">
+ * <default>true</default>
+ * <summary>Show icon on system tray</summary>
+ * <description>Show icon on system tray</description>
+ * </key>
+ * <key type="b" name="show-im-name">
+ * <default>false</default>
+ * <summary>Show input method name</summary>
+ * <description>Show input method name on language bar</description>
+ * </key>
+ * <key type="b" name="use-custom-font">
+ * <default>false</default>
+ * <summary>Use custom font</summary>
+ * <description>Use custom font name for language panel</description>
+ * </key>
+ * <key type="s" name="custom-font">
+ * <default>'Sans 10'</default>
+ * <summary>Custom font</summary>
+ * <description>Custom font name for language panel</description>
+ * </key>
+ * </schema>
+ */
+struct _config_panel
+{
+ struct _config_section base;
+
+ const char *custom_font;
+ int show;
+ int x;
+ int y;
+ int lookup_table_orientation;
+ Eina_Bool show_icon_in_systray;
+ Eina_Bool show_im_name;
+ Eina_Bool use_custom_font;
+};
+
+static Eet_Data_Descriptor *
+_config_panel_edd_new(void)
+{
+ Eet_Data_Descriptor *edd;
+ Eet_Data_Descriptor_Class eddc;
+
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, struct _config_panel);
+ edd = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "show", show, EET_T_INT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "x", x, EET_T_INT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "y", y, EET_T_INT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "lookup-table-orientation", lookup_table_orientation, EET_T_INT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "show-icon-in-systray", show_icon_in_systray, EET_T_UCHAR);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "show-im-name", show_im_name, EET_T_UCHAR);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "use-custom-font", use_custom_font, EET_T_UCHAR);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "custom-font", custom_font, EET_T_STRING);
+
+ return edd;
+}
+
+static void
+_config_panel_set_defaults(struct _config_section *base)
+{
+ struct _config_panel *panel = (struct _config_panel *) base;
+
+ panel->show = 0;
+ panel->x = -1;
+ panel->y = -1;
+ panel->lookup_table_orientation = 1;
+ panel->show_icon_in_systray = EINA_TRUE;
+ panel->show_im_name = EINA_FALSE;
+ panel->use_custom_font = EINA_FALSE;
+ panel->custom_font = eina_stringshare_add("Sans 10");
+}
+
+static void
+_config_panel_free(struct _config_section *base)
+{
+ struct _config_panel *panel = (struct _config_panel *) base;
+
+ eina_stringshare_del(panel->custom_font);
+ free(panel);
+}
+
+static Eina_Bool
+_config_panel_set_value(struct _config_section *base, const char *section, const char *name, Eldbus_Message_Iter *value)
+{
+ return EINA_FALSE;
+}
+
+static void *
+_config_panel_get_value(struct _config_section *base, const char *section, const char *name)
+{
+ return NULL;
+}
+
+static void *
+_config_panel_get_values(struct _config_section *base, const char *section)
+{
+ return NULL;
+}
+
+static void
+_config_panel_section_init(struct _config_section *base)
+{
+ base->id = eina_stringshare_add("panel");
+ base->free = _config_panel_free;
+ base->set_defaults = _config_panel_set_defaults;
+ base->set_value = _config_panel_set_value;
+ base->get_value = _config_panel_get_value;
+ base->get_values = _config_panel_get_values;
+}
+
+static struct _config_section *
+_config_panel_new(void)
+{
+ struct _config_panel *conf = calloc(1, sizeof(*conf));
+ _config_panel_section_init((struct _config_section *) conf);
+ return (struct _config_section *) conf;
+}
+
+/*
+ * NO SCHEMA AVAILABLE. BASED ON THE SOURCE CODE
+ */
+struct _config_hangul
+{
+ struct _config_section base;
+
+ const char *hangul_keyboard;
+ Eina_List *hanja_keys;
+ Eina_Bool word_commit;
+ Eina_Bool auto_reorder;
+};
+
+static Eet_Data_Descriptor *
+_config_hangul_edd_new(void)
+{
+ Eet_Data_Descriptor *edd;
+ Eet_Data_Descriptor_Class eddc;
+
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, struct _config_hangul);
+ edd = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_hangul, "HangulKeyboard", hangul_keyboard, EET_T_STRING);
+ EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hangul, "HanjaKeys", hanja_keys);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_hangul, "WordCommit", word_commit, EET_T_UCHAR);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_hangul, "AutoReorder", auto_reorder, EET_T_UCHAR);
+
+ return edd;
+}
+
+static void
+_config_hangul_set_defaults(struct _config_section *base)
+{
+ struct _config_hangul *hangul = (struct _config_hangul *) base;
+ const char *hanja_keys[] = { "Hangul_Hanja", "F9", NULL };
+
+ hangul->hangul_keyboard = eina_stringshare_add("2");
+ hangul->hanja_keys = _config_string_list_new(hanja_keys);
+ hangul->word_commit = EINA_FALSE;
+ hangul->auto_reorder = EINA_TRUE;
+}
+
+static void
+_config_hangul_free(struct _config_section *base)
+{
+ struct _config_hangul *hangul = (struct _config_hangul *) base;
+
+ eina_stringshare_del(hangul->hangul_keyboard);
+ _config_string_list_free(hangul->hanja_keys);
+ free(hangul);
+}
+
+static Eina_Bool
+_config_hangul_set_value(struct _config_section *base, const char *section, const char *name, Eldbus_Message_Iter *value)
+{
+ return EINA_FALSE;
+}
+
+static void *
+_config_hangul_get_value(struct _config_section *base, const char *section, const char *name)
+{
+ return NULL;
+}
+
+static void *
+_config_hangul_get_values(struct _config_section *base, const char *section)
+{
+ return NULL;
+}
+
+static void
+_config_hangul_section_init(struct _config_section *base)
+{
+ base->id = eina_stringshare_add("hangul");
+ base->free = _config_hangul_free;
+ base->set_defaults = _config_hangul_set_defaults;
+ base->set_value = _config_hangul_set_value;
+ base->get_value = _config_hangul_get_value;
+ base->get_values = _config_hangul_get_values;
+}
+
+static struct _config_section *
+_config_hangul_new(void)
+{
+ struct _config_hangul *conf = calloc(1, sizeof(*conf));
+ _config_hangul_section_init((struct _config_section *) conf);
+ return (struct _config_section *) conf;
+}
+
+/*
+ * NO SCHEMA AVAILABLE. BASED ON THE SOURCE CODE
+ */
+struct _config_engine
+{
+ struct _config_section base;
+
+ struct _config_section *hangul;
+};
+
+static Eet_Data_Descriptor *
+_config_engine_edd_new(Eet_Data_Descriptor *hangul_edd)
+{
+ Eet_Data_Descriptor *edd;
+ Eet_Data_Descriptor_Class eddc;
+
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, struct _config_engine);
+ edd = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_SUB(edd, struct _config_engine, "Hangul", hangul, hangul_edd);
+
+ return edd;
+}
+
+static void
+_config_engine_set_defaults(struct _config_section *base)
+{
+ struct _config_engine *engine = (struct _config_engine *) base;
+
+ _config_section_set_defaults(engine->hangul);
+}
+
+static void
+_config_engine_free(struct _config_section *base)
+{
+ struct _config_engine *engine = (struct _config_engine *) base;
+
+ _config_section_free(engine->hangul);
+ free(engine);
+}
+
+static Eina_Bool
+_config_engine_set_value(struct _config_section *base, const char *section, const char *name, Eldbus_Message_Iter *value)
+{
+ return EINA_FALSE;
+}
+
+static void *
+_config_engine_get_value(struct _config_section *base, const char *section, const char *name)
+{
+ return NULL;
+}
+
+static void *
+_config_engine_get_values(struct _config_section *base, const char *section)
+{
+ return NULL;
+}
+
+static void
+_config_engine_section_init(struct _config_section *base)
+{
+ struct _config_engine *engine = (struct _config_engine *) base;
+
+ base->id = eina_stringshare_add("engine");
+ base->free = _config_engine_free;
+ base->set_defaults = _config_engine_set_defaults;
+ base->set_value = _config_engine_set_value;
+ base->get_value = _config_engine_get_value;
+ base->get_values = _config_engine_get_values;
+
+ if (engine->hangul)
+ _config_hangul_section_init(engine->hangul);
+}
+
+static struct _config_section *
+_config_engine_new(void)
+{
+ struct _config_engine *conf = calloc(1, sizeof(*conf));
+ _config_engine_section_init((struct _config_section *) conf);
+ conf->hangul = _config_hangul_new();
+ return (struct _config_section *) conf;
+}
+
+/*
+ * <schema path="/desktop/ibus/" id="org.freedesktop.ibus">
+ * <child schema="org.freedesktop.ibus.general" name="general"/>
+ * <child schema="org.freedesktop.ibus.panel" name="panel"/>
+ * </schema>
+ */
+struct _config_ibus
+{
+ struct _config_section base;
+
+ struct _config_section *general;
+ struct _config_section *panel;
+ struct _config_section *engine;
+};
+
+static Eet_Data_Descriptor *
+_config_ibus_edd_new(Eet_Data_Descriptor *general_edd, Eet_Data_Descriptor *panel_edd, Eet_Data_Descriptor *engine_edd)
+{
+ Eet_Data_Descriptor *edd;
+ Eet_Data_Descriptor_Class eddc;
+
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, struct _config_ibus);
+ edd = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_SUB(edd, struct _config_ibus, "general", general, general_edd);
+ EET_DATA_DESCRIPTOR_ADD_SUB(edd, struct _config_ibus, "panel", panel, panel_edd);
+ EET_DATA_DESCRIPTOR_ADD_SUB(edd, struct _config_ibus, "engine", engine, engine_edd);
+
+ return edd;
+}
+
+static void
+_config_ibus_set_defaults(struct _config_section *base)
+{
+ struct _config_ibus *ibus = (struct _config_ibus *) base;
+
+ _config_section_set_defaults(ibus->general);
+ _config_section_set_defaults(ibus->panel);
+ _config_section_set_defaults(ibus->engine);
+}
+
+static void
+_config_ibus_free(struct _config_section *base)
+{
+ struct _config_ibus *ibus = (struct _config_ibus *) base;
+
+ _config_section_free(ibus->general);
+ _config_section_free(ibus->panel);
+ _config_section_free(ibus->engine);
+
+ free(ibus);
+}
+
+static Eina_Bool
+_config_ibus_set_value(struct _config_section *base, const char *section, const char *name, Eldbus_Message_Iter *value)
+{
+ return EINA_FALSE;
+}
+
+static void *
+_config_ibus_get_value(struct _config_section *base, const char *section, const char *name)
+{
+ return NULL;
+}
+
+static void *
+_config_ibus_get_values(struct _config_section *base, const char *section)
+{
+ return NULL;
+}
+
+static void
+_config_ibus_section_init(struct _config_section *base)
+{
+ struct _config_ibus *ibus = (struct _config_ibus *) base;
+ base->id = eina_stringshare_add("ibus");
+ base->free = _config_ibus_free;
+ base->set_defaults = _config_ibus_set_defaults;
+ base->set_value = _config_ibus_set_value;
+ base->get_value = _config_ibus_get_value;
+ base->get_values = _config_ibus_get_values;
+
+ if (ibus->general)
+ _config_general_section_init(ibus->general);
+
+ if (ibus->panel)
+ _config_panel_section_init(ibus->panel);
+
+ if (ibus->engine)
+ _config_engine_section_init(ibus->engine);
+}
+
+static struct _config_section *
+_config_ibus_new(void)
+{
+ struct _config_ibus *conf = calloc(1, sizeof(*conf));
+ _config_ibus_section_init((struct _config_section *) conf);
+ conf->general = _config_general_new();
+ conf->panel = _config_panel_new();
+ conf->engine = _config_engine_new();
+ return (struct _config_section *) conf;
+}
+
+/*
+ * MAIN
+ */
+struct wkb_ibus_config_eet
+{
+ const char *path;
+ struct _config_section *ibus_config;
+
+ Eet_Data_Descriptor *hotkey_edd;
+ Eet_Data_Descriptor *general_edd;
+ Eet_Data_Descriptor *panel_edd;
+ Eet_Data_Descriptor *hangul_edd;
+ Eet_Data_Descriptor *engine_edd;
+ Eet_Data_Descriptor *ibus_edd;
+};
+
+Eina_Bool
+wkb_ibus_config_eet_set_value(struct wkb_ibus_config_eet *config_eet, const char *section, const char *name, Eldbus_Message_Iter *value)
+{
+ return _config_section_set_value(config_eet->ibus_config, section, name, value);
+}
+
+void *
+wkb_ibus_config_eet_get_value(struct wkb_ibus_config_eet *config_eet, const char *section, const char *name)
+{
+ return _config_section_get_value(config_eet->ibus_config, section, name);
+}
+
+void *
+wkb_ibus_config_eet_get_values(struct wkb_ibus_config_eet *config_eet, const char *section)
+{
+ return _config_section_get_values(config_eet->ibus_config, section);
+}
+
+void
+wkb_ibus_config_eet_set_defaults(struct wkb_ibus_config_eet *config_eet)
+{
+
+ if (config_eet->ibus_config)
+ _config_section_free(config_eet->ibus_config);
+
+ config_eet->ibus_config = _config_ibus_new();
+ _config_ibus_set_defaults(config_eet->ibus_config);
+}
+
+static struct wkb_ibus_config_eet *
+_config_eet_section_init(const char *path)
+{
+ struct wkb_ibus_config_eet *eet = calloc(1, sizeof(*eet));
+ eet->path = eina_stringshare_add(path);
+
+ eet->hotkey_edd = _config_hotkey_edd_new();
+ eet->general_edd = _config_general_edd_new(eet->hotkey_edd);
+ eet->panel_edd = _config_panel_edd_new();
+ eet->hangul_edd = _config_hangul_edd_new();
+ eet->engine_edd = _config_engine_edd_new(eet->hangul_edd);
+ eet->ibus_edd = _config_ibus_edd_new(eet->general_edd, eet->panel_edd, eet->engine_edd);
+
+ return eet;
+}
+
+static Eina_Bool
+_config_eet_exists(const char *path)
+{
+ struct stat buf;
+ return stat(path, &buf) == 0;
+}
+
+struct wkb_ibus_config_eet *
+wkb_ibus_config_eet_new(const char *path)
+{
+ struct wkb_ibus_config_eet *eet = _config_eet_section_init(path);
+ Eet_File *ef = NULL;
+ Eet_File_Mode mode = EET_FILE_MODE_READ_WRITE;
+
+ if (_config_eet_exists(path))
+ mode = EET_FILE_MODE_READ;
+
+ if (!(ef = eet_open(path, mode)))
+ {
+ printf("Error opening eet file '%s' for %s\n", path, mode == EET_FILE_MODE_READ ? "read" : "write");
+ wkb_ibus_config_eet_free(eet);
+ return NULL;
+ }
+
+ if (mode == EET_FILE_MODE_READ)
+ {
+ eet->ibus_config = eet_data_read(ef, eet->ibus_edd, "ibus");
+ _config_ibus_section_init(eet->ibus_config);
+ goto end;
+ }
+
+ wkb_ibus_config_eet_set_defaults(eet);
+ if (!eet_data_write(ef, eet->ibus_edd, "ibus", eet->ibus_config, EINA_TRUE))
+ {
+ printf("Error creating eet file '%s'\n", path);
+ wkb_ibus_config_eet_free(eet);
+ eet = NULL;
+ }
+
+end:
+ eet_close(ef);
+ return eet;
+}
+
+void
+wkb_ibus_config_eet_free(struct wkb_ibus_config_eet *config_eet)
+{
+ _config_ibus_free(config_eet->ibus_config);
+ eina_stringshare_del(config_eet->path);
+
+ eet_data_descriptor_free(config_eet->hotkey_edd);
+ eet_data_descriptor_free(config_eet->general_edd);
+ eet_data_descriptor_free(config_eet->panel_edd);
+ eet_data_descriptor_free(config_eet->hangul_edd);
+ eet_data_descriptor_free(config_eet->engine_edd);
+ eet_data_descriptor_free(config_eet->ibus_edd);
+
+ free(config_eet);
+}
diff --git a/src/wkb-ibus-config-eet.h b/src/wkb-ibus-config-eet.h
new file mode 100644
index 0000000..a7e7970
--- /dev/null
+++ b/src/wkb-ibus-config-eet.h
@@ -0,0 +1,34 @@
+/*
+ * 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 _WKB_IBUS_CONFIG_EET_H_
+#define _WKB_IBUS_CONFIG_EET_H_
+
+#include <Eina.h>
+#include <Eldbus.h>
+
+struct wkb_ibus_config_eet;
+
+Eina_Bool wkb_ibus_config_eet_set_value(struct wkb_ibus_config_eet *config_eet, const char *section, const char *name, Eldbus_Message_Iter *value);
+void *wkb_ibus_config_eet_get_value(struct wkb_ibus_config_eet *config_eet, const char *section, const char *name);
+void *wkb_ibus_config_eet_get_values(struct wkb_ibus_config_eet *config_eet, const char *section);
+
+void wkb_ibus_config_eet_set_defaults(struct wkb_ibus_config_eet *config_eet);
+
+struct wkb_ibus_config_eet *wkb_ibus_config_eet_new(const char *path);
+void wkb_ibus_config_eet_free(struct wkb_ibus_config_eet *config_eet);
+
+#endif /* _WKB_IBUS_CONFIG_EET_H_ */
diff --git a/src/wkb-ibus-config.c b/src/wkb-ibus-config.c
new file mode 100644
index 0000000..7c698fe
--- /dev/null
+++ b/src/wkb-ibus-config.c
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <Eldbus.h>
+
+#include "wkb-ibus.h"
+
+#define CONFIG_CHECK_MESSAGE_ERRORS(_msg) \
+ do \
+ { \
+ const char *error, *error_msg; \
+ if (eldbus_message_error_get(_msg, &error, &error_msg)) \
+ { \
+ ERR("DBus message error: %s: %s", error, error_msg); \
+ return NULL; \
+ } \
+ DBG("Message '%s' with signature '%s'", eldbus_message_member_get(_msg), eldbus_message_signature_get(_msg)); \
+ } while (0);
+
+static Eldbus_Message *
+_config_set_value(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ const char *section, *name;
+ Eldbus_Message_Iter *value;
+
+ CONFIG_CHECK_MESSAGE_ERRORS(msg)
+
+ if (!eldbus_message_arguments_get(msg, "ssv", &section, &name, &value))
+ {
+ ERR("Error reading message arguments");
+ return NULL;
+ }
+
+ DBG("section: '%s', name: '%s', value: '%p'", section, name, value);
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_config_get_value(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ const char *section, *name;
+
+ CONFIG_CHECK_MESSAGE_ERRORS(msg)
+
+ if (!eldbus_message_arguments_get(msg, "ss", &section, &name))
+ {
+ ERR("Error reading message arguments");
+ return NULL;
+ }
+
+ DBG("section: '%s', name: '%s'", section, name);
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_config_get_values(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ const char *section;
+
+ CONFIG_CHECK_MESSAGE_ERRORS(msg)
+
+ if (!eldbus_message_arguments_get(msg, "s", &section))
+ {
+ ERR("Error reading message arguments");
+ return NULL;
+ }
+
+ DBG("section: '%s'", section);
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_config_unset_value(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ const char *section, *name;
+
+ CONFIG_CHECK_MESSAGE_ERRORS(msg)
+
+ if (!eldbus_message_arguments_get(msg, "ss", &section, &name))
+ {
+ ERR("Error reading message arguments");
+ return NULL;
+ }
+
+ DBG("section: '%s', name: '%s'", section, name);
+
+ return NULL;
+}
+
+static const Eldbus_Method _wkb_ibus_config_methods[] =
+{
+/* typedef struct _Eldbus_Method
+ * {
+ * const char *member;
+ * const Eldbus_Arg_Info *in;
+ * const Eldbus_Arg_Info *out;
+ * Eldbus_Method_Cb cb;
+ * unsigned int flags;
+ * } Eldbus_Method;
+ */
+ { .member = "SetValue",
+ .in = ELDBUS_ARGS({"s", "section"}, {"s", "name"}, {"v", "value"}),
+ .cb = _config_set_value, },
+
+ { .member = "GetValue",
+ .in = ELDBUS_ARGS({"s", "section"}, {"s", "name"}),
+ .out = ELDBUS_ARGS({"v", "value"}),
+ .cb = _config_get_value, },
+
+ { .member = "GetValues",
+ .in = ELDBUS_ARGS({"s", "section"}),
+ .out = ELDBUS_ARGS({"a{sv}", "values"}),
+ .cb = _config_get_values, },
+
+ { .member = "UnsetValue",
+ .in = ELDBUS_ARGS({"s", "section"}, {"s", "name"}),
+ .cb = _config_unset_value, },
+
+ { NULL },
+};
+
+static const Eldbus_Signal _wkb_ibus_config_signals[] =
+{
+/* typedef struct _Eldbus_Signal
+ * {
+ * const char *name;
+ * const Eldbus_Arg_Info *args;
+ * unsigned int flags;
+ * } Eldbus_Signal;
+ */
+ { .name = "ValueChanged",
+ .args = ELDBUS_ARGS({"s", "section"}, {"s", "name"}, {"v", "value"}),
+ .flags = 0, },
+
+ { NULL },
+};
+
+static const Eldbus_Service_Interface_Desc _wkb_ibus_config_interface =
+{
+ .interface = IBUS_INTERFACE_CONFIG,
+ .methods = _wkb_ibus_config_methods,
+ .signals = _wkb_ibus_config_signals,
+};
+
+Eldbus_Service_Interface *
+wkb_ibus_config_register(Eldbus_Connection *conn)
+{
+ return eldbus_service_interface_register(conn, IBUS_PATH_CONFIG, &_wkb_ibus_config_interface);
+}
+
diff --git a/src/wkb-ibus-panel.c b/src/wkb-ibus-panel.c
new file mode 100644
index 0000000..62e437f
--- /dev/null
+++ b/src/wkb-ibus-panel.c
@@ -0,0 +1,831 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <Eldbus.h>
+
+#include "wkb-ibus.h"
+
+#define PANEL_CHECK_MESSAGE_ERRORS(_msg) \
+ do \
+ { \
+ const char *error, *error_msg; \
+ if (eldbus_message_error_get(_msg, &error, &error_msg)) \
+ { \
+ ERR("DBus message error: %s: %s", error, error_msg); \
+ return NULL; \
+ } \
+ DBG("Message '%s' with signature '%s'", eldbus_message_member_get(_msg), eldbus_message_signature_get(_msg)); \
+ } while (0);
+
+static Eina_Array *_get_properties_from_message_iter(Eldbus_Message_Iter *iter);
+
+struct _ibus_serializable
+{
+ /*
+ * All messages sent by IBus will start with the sa{sv} signature, but
+ * those fields don't seem useful for us, this struct is used to help
+ * on deserializing those fields
+ */
+ char *text;
+ Eldbus_Message_Iter *variant;
+};
+
+struct _ibus_attr
+{
+ unsigned int type;
+ unsigned int value;
+ unsigned int start_idx;
+ unsigned int end_idx;
+};
+
+struct _ibus_text
+{
+ char *text;
+ Eina_Array *attrs;
+};
+
+struct _ibus_lookup_table
+{
+ unsigned int page_size;
+ unsigned int cursor_pos;
+ Eina_Bool cursor_visible;
+ Eina_Bool round;
+ int orientation;
+ Eina_Array *candidates;
+ Eina_Array *labels;
+};
+
+struct _ibus_property
+{
+ char *key;
+ char *icon;
+ struct _ibus_text *label;
+ struct _ibus_text *symbol;
+ struct _ibus_text *tooltip;
+ Eina_Bool sensitive;
+ Eina_Bool visible;
+ unsigned int type;
+ unsigned int state;
+ Eina_Array *sub_properties;
+};
+
+static struct _ibus_attr *
+_get_attr_from_message_iter(Eldbus_Message_Iter *iter)
+{
+ struct _ibus_attr *attr = calloc(1, sizeof(*attr));
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(attr, NULL);
+
+ DBG("Attribute iter signature '%s'", eldbus_message_iter_signature_get(iter));
+
+ if (!eldbus_message_iter_arguments_get(iter, "uuuu", &attr->type,
+ &attr->value, &attr->start_idx,
+ &attr->end_idx))
+ {
+ ERR("Error deserializing IBusAttribute");
+ free(attr);
+ attr = NULL;
+ }
+
+ return attr;
+}
+
+static void
+_free_eina_array(Eina_Array *array, void (* free_func)(void *))
+{
+ if (!array)
+ return;
+
+ while (eina_array_count(array))
+ free_func(eina_array_pop(array));
+
+ eina_array_free(array);
+}
+
+static void
+_free_text(struct _ibus_text *text)
+{
+ if (!text)
+ return;
+
+ _free_eina_array(text->attrs, free);
+ free(text->text);
+ free(text);
+}
+
+static struct _ibus_text *
+_get_text_from_message_iter(Eldbus_Message_Iter *iter)
+{
+ struct _ibus_serializable ignore = { 0 };
+ struct _ibus_text *text = calloc(1, sizeof(*text));
+ struct _ibus_attr *attr = NULL;
+ Eldbus_Message_Iter *attrs = NULL, *a = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(text, NULL);
+
+ DBG("Text iter signature '%s'", eldbus_message_iter_signature_get(iter));
+
+ if (!eldbus_message_iter_arguments_get(iter, "(sa{sv}sv)", &ignore.text,
+ &ignore.variant, &text->text, &attrs))
+ {
+ ERR("Error deserializing IBusText");
+ free(text);
+ text = NULL;
+ goto end;
+ }
+
+ /* Check for attributes */
+ if (attrs == NULL)
+ {
+ INF("Text has no attributes");
+ goto end;
+ }
+
+ while (eldbus_message_iter_get_and_next(attrs, 'v', &a))
+ {
+ if (!text->attrs)
+ text->attrs = eina_array_new(10);
+
+ if (!(attr = _get_attr_from_message_iter(a)))
+ {
+ _free_text(text);
+ text = NULL;
+ goto end;
+ }
+
+ eina_array_push(text->attrs, attr);
+ }
+
+end:
+ return text;
+}
+
+static void
+_free_lookup_table(struct _ibus_lookup_table *table)
+{
+ if (!table)
+ return;
+
+ _free_eina_array(table->candidates, _free_text);
+ _free_eina_array(table->labels, _free_text);
+ free(table);
+}
+
+static struct _ibus_lookup_table *
+_get_lookup_table_from_message_iter(Eldbus_Message_Iter *iter)
+{
+ struct _ibus_serializable ignore = { 0 };
+ struct _ibus_lookup_table *table = calloc(1, sizeof(*table));
+ struct _ibus_text *text = NULL;
+ Eldbus_Message_Iter *candidates = NULL, *labels = NULL, *t = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(table, NULL);
+
+ DBG("LookupTable iter signature '%s'", eldbus_message_iter_signature_get(iter));
+
+ if (!eldbus_message_iter_arguments_get(iter, "(sa{sv}uubbiavav)",
+ &ignore.text, &ignore.variant,
+ &table->page_size, &table->cursor_pos,
+ &table->cursor_visible, &table->round,
+ &table->orientation, &candidates,
+ &labels))
+ {
+ ERR("Error deserializing IBusLookupTable");
+ free(table);
+ table = NULL;
+ goto end;
+ }
+
+ DBG("Lookup table:");
+ DBG("\tPage size.......: '%d'", table->page_size);
+ DBG("\tCursor position.: '%d'", table->cursor_pos);
+ DBG("\tCursor visible..: '%d'", table->cursor_visible);
+ DBG("\tRound...........: '%d'", table->round);
+ DBG("\tOrientation.....: '%d'", table->orientation);
+ DBG("\tCandidates......: '%p'", candidates);
+ DBG("\tLabels..........: '%p'", labels);
+
+ if (!candidates)
+ {
+ INF("Lookup table has no candidates");
+ goto labels;
+ }
+
+ while (eldbus_message_iter_get_and_next(candidates, 'v', &t))
+ {
+ if (!table->candidates)
+ table->candidates = eina_array_new(10);
+
+ if (!(text = _get_text_from_message_iter(t)))
+ {
+ _free_lookup_table(table);
+ table = NULL;
+ goto end;
+ }
+
+ DBG("Appending new candidate %s", text->text);
+ eina_array_push(table->candidates, text);
+ }
+
+labels:
+ if (!labels)
+ {
+ INF("Lookup table has no labels");
+ goto end;
+ }
+
+ while (eldbus_message_iter_get_and_next(labels, 'v', &t))
+ {
+ if (!table->labels)
+ table->labels = eina_array_new(10);
+
+ if (!(text = _get_text_from_message_iter(t)))
+ {
+ _free_lookup_table(table);
+ table = NULL;
+ goto end;
+ }
+
+ DBG("Appending new label %s", text->text);
+ eina_array_push(table->labels, text);
+ }
+
+end:
+ return table;
+}
+
+static void
+_free_property(struct _ibus_property *property)
+{
+ if (!property)
+ return;
+
+ free(property->key);
+ free(property->icon);
+ _free_text(property->label);
+ _free_text(property->symbol);
+ _free_text(property->tooltip);
+ _free_eina_array(property->sub_properties, _free_property);
+ free(property);
+}
+
+static struct _ibus_property *
+_get_property_from_message_iter(Eldbus_Message_Iter *iter)
+{
+ struct _ibus_serializable ignore = { 0 };
+ struct _ibus_property *prop = calloc(1, sizeof(*prop));
+ Eldbus_Message_Iter *label = NULL, *symbol = NULL, *tooltip = NULL, *sub_props = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(prop, NULL);
+
+ DBG("Property iter signature '%s'", eldbus_message_iter_signature_get(iter));
+
+ if (!eldbus_message_iter_arguments_get(iter, "(sa{sv}suvsvbbuvv)",
+ &ignore.text, &ignore.variant,
+ &prop->key, &prop->type,
+ &label, &prop->icon, &tooltip,
+ &prop->sensitive, &prop->visible,
+ &prop->state, &sub_props, &symbol))
+ {
+ ERR("Error deserializing IBusProperty");
+ free(prop);
+ prop = NULL;
+ goto end;
+ }
+
+ DBG("Property :");
+ DBG("\tKey.............: '%s'", prop->key);
+ DBG("\tType............: '%d'", prop->type);
+ DBG("\tLabel...........: '%p'", label);
+ DBG("\tIcon............: '%s'", prop->icon);
+ DBG("\tTooltip.........: '%p'", tooltip);
+ DBG("\tSensitive.......: '%d'", prop->sensitive);
+ DBG("\tVisible.........: '%d'", prop->visible);
+ DBG("\tState...........: '%d'", prop->state);
+ DBG("\tSub Properties..: '%p'", sub_props);
+ DBG("\tSymbol..........: '%p'", symbol);
+
+ if (!label)
+ {
+ INF("Property has no label");
+ goto symbol;
+ }
+
+ if (!(prop->label = _get_text_from_message_iter(label)))
+ {
+ _free_property(prop);
+ prop = NULL;
+ goto end;
+ }
+
+symbol:
+ if (!symbol)
+ {
+ INF("Property has no symbol");
+ goto tooltip;
+ }
+
+ if (!(prop->symbol = _get_text_from_message_iter(symbol)))
+ {
+ _free_property(prop);
+ prop = NULL;
+ goto end;
+ }
+
+tooltip:
+ if (!tooltip)
+ {
+ INF("Property has no tooltip");
+ goto sub_props;
+ }
+
+ if (!(prop->tooltip = _get_text_from_message_iter(tooltip)))
+ {
+ _free_property(prop);
+ prop = NULL;
+ goto end;
+ }
+
+sub_props:
+ if (!sub_props)
+ {
+ INF("Property has no sub properties");
+ goto end;
+ }
+
+ prop->sub_properties = _get_properties_from_message_iter(sub_props);
+
+end:
+ return prop;
+}
+
+static Eina_Array *
+_get_properties_from_message_iter(Eldbus_Message_Iter *iter)
+{
+ Eina_Array *properties = NULL;
+ Eldbus_Message_Iter *props = NULL, *prop = NULL;
+ struct _ibus_serializable ignore = { 0 };
+ struct _ibus_property *property = NULL;
+
+ DBG("PropList iter signature '%s'", eldbus_message_iter_signature_get(iter));
+
+ if (!eldbus_message_iter_arguments_get(iter, "(sa{sv}av)", &ignore.text, &ignore.variant, &props))
+ {
+ ERR("Error deserializing IBusPropList");
+ goto end;
+ }
+
+ if (!props)
+ {
+ INF("PropList has no property");
+ goto end;
+ }
+
+ while (eldbus_message_iter_get_and_next(props, 'v', &prop))
+ {
+ if (!properties)
+ properties = eina_array_new(10);
+
+ if (!(property = _get_property_from_message_iter(prop)))
+ {
+ _free_eina_array(properties, _free_property);
+ properties = NULL;
+ goto end;
+ }
+
+ DBG("Appending new property %p", property);
+ eina_array_push(properties, property);
+ }
+
+end:
+ return properties;
+}
+
+static Eldbus_Message *
+_panel_update_preedit_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ Eldbus_Message_Iter *text = NULL;
+ unsigned int cursor_pos = 0;
+ Eina_Bool visible = 0;
+ struct _ibus_text *ibus_text;
+
+ PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+ if (!eldbus_message_arguments_get(msg, "vub", &text, &cursor_pos, &visible))
+ {
+ ERR("Error reading message arguments");
+ return NULL;
+ }
+
+ DBG("text: '%p', cursor_pos: '%d', visible: '%d')", text, cursor_pos, visible);
+
+ ibus_text = _get_text_from_message_iter(text);
+ DBG("Preedit text = '%s'", ibus_text->text);
+ _free_text(ibus_text);
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_panel_show_preedit_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_panel_hide_preedit_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_panel_update_auxiliary_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ Eldbus_Message_Iter *text = NULL;
+ Eina_Bool visible = 0;
+ struct _ibus_text *ibus_text;
+
+ PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+ if (!eldbus_message_arguments_get(msg, "vb", &text, &visible))
+ {
+ ERR("Error reading message arguments");
+ return NULL;
+ }
+
+ DBG("text: '%p', visible: '%d'", text, visible);
+
+ ibus_text = _get_text_from_message_iter(text);
+ DBG("Auxiliary text = '%s'", ibus_text->text);
+ _free_text(ibus_text);
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_panel_show_auxiliary_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_panel_hide_auxiliary_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_panel_update_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ Eldbus_Message_Iter *table = NULL;
+ Eina_Bool visible = 0;
+ struct _ibus_lookup_table *ibus_lookup_table;
+
+ PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+ if (!eldbus_message_arguments_get(msg, "vb", &table, &visible))
+ {
+ ERR("Error reading message arguments");
+ return NULL;
+ }
+
+ DBG("table: '%p', visible: '%d'", table, visible);
+
+ ibus_lookup_table = _get_lookup_table_from_message_iter(table);
+ _free_lookup_table(ibus_lookup_table);
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_panel_show_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_panel_hide_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+ DBG("here");
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_panel_cursor_up_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+ DBG("here");
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_panel_cursor_down_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_panel_page_up_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_panel_page_down_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_panel_register_properties(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ Eldbus_Message_Iter *props = NULL;
+ Eina_Array *properties = NULL;
+
+ PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+ if (!eldbus_message_arguments_get(msg, "v", &props))
+ {
+ ERR("Error reading message arguments");
+ return NULL;
+ }
+
+ DBG("properties: '%p'", props);
+
+ properties = _get_properties_from_message_iter(props);
+ _free_eina_array(properties, _free_property);
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_panel_update_property(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ Eldbus_Message_Iter *prop = NULL;
+
+ PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+ if (!eldbus_message_arguments_get(msg, "v", &prop))
+ {
+ ERR("Error reading message arguments");
+ return NULL;
+ }
+
+ DBG("property : '%p'", prop);
+ DBG("Property iter signature: %s", eldbus_message_iter_signature_get(prop));
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_panel_focus_in(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_panel_focus_out(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_panel_set_cursor_location(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ int x = 0, y = 0, w = 0, h = 0;
+
+ PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+ if (!eldbus_message_arguments_get(msg, "iiii", &x, &y, &w, &h))
+ {
+ ERR("Error reading message arguments");
+ return NULL;
+ }
+
+ DBG("x: %d, y: %d, w: %d, h: %d", x, y, w, h);
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_panel_reset(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_panel_start_setup(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_panel_state_changed(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_panel_hide_language_bar(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+ return NULL;
+}
+
+static Eldbus_Message *
+_panel_show_language_bar(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+ PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+ return NULL;
+}
+
+static const Eldbus_Method _wkb_ibus_panel_methods[] =
+{
+/* typedef struct _Eldbus_Method
+ * {
+ * const char *member;
+ * const Eldbus_Arg_Info *in;
+ * const Eldbus_Arg_Info *out;
+ * Eldbus_Method_Cb cb;
+ * unsigned int flags;
+ * } Eldbus_Method;
+ */
+ { .member = "UpdatePreeditText",
+ .in = ELDBUS_ARGS({"v", "text"}, {"u", "cursor_pos"}, {"b", "visible"}),
+ .cb = _panel_update_preedit_text, },
+
+ { .member = "ShowPreeditText",
+ .cb = _panel_show_preedit_text, },
+
+ { .member = "HidePreeditText",
+ .cb = _panel_hide_preedit_text, },
+
+ { .member = "UpdateAuxiliaryText",
+ .in = ELDBUS_ARGS({"v", "text"}, {"b", "visible"}),
+ .cb = _panel_update_auxiliary_text, },
+
+ { .member = "ShowAuxiliaryText",
+ .cb = _panel_show_auxiliary_text, },
+
+ { .member = "HideAuxiliaryText",
+ .cb = _panel_hide_auxiliary_text, },
+
+ { .member = "UpdateLookupTable",
+ .in = ELDBUS_ARGS({"v", "table"}, {"b", "visible"}),
+ .cb = _panel_update_lookup_table, },
+
+ { .member = "ShowLookupTable",
+ .cb = _panel_show_lookup_table, },
+
+ { .member = "HideLookupTable",
+ .cb = _panel_hide_lookup_table, },
+
+ { .member = "CursorUpLookupTable",
+ .cb = _panel_cursor_up_lookup_table, },
+
+ { .member = "CursorDownLookupTable",
+ .cb = _panel_cursor_down_lookup_table, },
+
+ { .member = "PageUpLookupTable",
+ .cb = _panel_page_up_lookup_table, },
+
+ { .member = "PageDownLookupTable",
+ .cb = _panel_page_down_lookup_table, },
+
+ { .member = "RegisterProperties",
+ .in = ELDBUS_ARGS({"v", "props"}),
+ .cb = _panel_register_properties, },
+
+ { .member = "UpdateProperty",
+ .in = ELDBUS_ARGS({"v", "prop"}),
+ .cb = _panel_update_property, },
+
+ { .member = "FocusIn",
+ .in = ELDBUS_ARGS({"o", "ic"}),
+ .cb = _panel_focus_in, },
+
+ { .member = "FocusOut",
+ .in = ELDBUS_ARGS({"o", "ic"}),
+ .cb = _panel_focus_out, },
+
+ { .member = "SetCursorLocation",
+ .in = ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"i", "w"}, {"i", "h"}),
+ .cb = _panel_set_cursor_location, },
+
+ { .member = "Reset",
+ .cb = _panel_reset, },
+
+ { .member = "StartSetup",
+ .cb = _panel_start_setup, },
+
+ { .member = "StateChanged",
+ .cb = _panel_state_changed, },
+
+ { .member = "HideLanguageBar",
+ .cb = _panel_hide_language_bar, },
+
+ { .member = "ShowLanguageBar",
+ .cb = _panel_show_language_bar, },
+
+ { NULL },
+};
+
+static const Eldbus_Signal _wkb_ibus_panel_signals[] =
+{
+/* typedef struct _Eldbus_Signal
+ * {
+ * const char *name;
+ * const Eldbus_Arg_Info *args;
+ * unsigned int flags;
+ * } Eldbus_Signal;
+ */
+ { .name = "CursorUp", },
+
+ { .name = "CursorDown", },
+
+ { .name = "PageUp", },
+
+ { .name = "PageDown", },
+
+ { .name = "PropertyActivate",
+ .args = ELDBUS_ARGS({"s", "prop_name"}, {"i", "prop_state"}),
+ .flags = 0, },
+
+ { .name = "PropertyShow",
+ .args = ELDBUS_ARGS({"s", "prop_name"}),
+ .flags = 0, },
+
+ { .name = "PropertyHide",
+ .args = ELDBUS_ARGS({"s", "prop_name"}),
+ .flags = 0, },
+
+ { .name = "CandidateClicked",
+ .args = ELDBUS_ARGS({"u", "index"}, {"u", "button"}, {"u", "state"}),
+ .flags = 0, },
+
+ { NULL },
+};
+
+static const Eldbus_Service_Interface_Desc _wkb_ibus_panel_interface =
+{
+ .interface = IBUS_INTERFACE_PANEL,
+ .methods = _wkb_ibus_panel_methods,
+ .signals = _wkb_ibus_panel_signals,
+};
+
+Eldbus_Service_Interface *
+wkb_ibus_panel_register(Eldbus_Connection *conn)
+{
+ return eldbus_service_interface_register(conn, IBUS_PATH_PANEL, &_wkb_ibus_panel_interface);
+}
+
diff --git a/src/wkb-ibus-test.c b/src/wkb-ibus-test.c
new file mode 100644
index 0000000..ced4700
--- /dev/null
+++ b/src/wkb-ibus-test.c
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#include "wkb-ibus.h"
+
+#define _GNU_SOURCE
+#include <signal.h>
+
+#include <Ecore.h>
+#include <Eldbus.h>
+
+static void
+_finish(int foo)
+{
+ printf("FINISH\n");
+ wkb_ibus_shutdown();
+}
+
+static Eina_Bool
+_connect_timer(void *data)
+{
+ return !wkb_ibus_connect();
+}
+
+int
+main (int argc, char *argv[])
+{
+ if (!ecore_init())
+ {
+ printf("Error initializing ecore");
+ return 1;
+ }
+
+ if (!eldbus_init())
+ {
+ printf("Error initializing eldbus");
+ return 1;
+ }
+
+ if (!wkb_ibus_init())
+ {
+ printf("Error initializing ibus");
+ return 1;
+ }
+
+ ecore_timer_add(1, _connect_timer, NULL);
+
+ signal(SIGTERM, _finish);
+ signal(SIGINT, _finish);
+
+ ecore_main_loop_begin();
+
+ eldbus_shutdown();
+ ecore_shutdown();
+ return 0;
+}
diff --git a/src/wkb-ibus.c b/src/wkb-ibus.c
new file mode 100644
index 0000000..60cdac2
--- /dev/null
+++ b/src/wkb-ibus.c
@@ -0,0 +1,507 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <Ecore.h>
+#include <Eldbus.h>
+
+#include "wkb-ibus.h"
+
+int _wkb_ibus_log_dom = -1;
+
+#define CHECK_MESSAGE_ERRORS(_msg) \
+ do \
+ { \
+ const char *error, *error_msg; \
+ if (eldbus_message_error_get(_msg, &error, &error_msg)) \
+ { \
+ ERR("Dbus message error: %s: %s", error, error_msg); \
+ return; \
+ } \
+ DBG("Message '%s' with signature '%s'", eldbus_message_member_get(_msg), eldbus_message_signature_get(_msg)); \
+ } while (0);
+
+struct _wkb_ibus_service
+{
+ Eldbus_Service_Interface *interface;
+
+ Eldbus_Signal_Handler *name_acquired;
+ Eldbus_Signal_Handler *name_lost;
+};
+
+struct _wkb_ibus_context
+{
+ char *address;
+ Eldbus_Connection *conn;
+ Ecore_Exe *ibus_daemon;
+#if 0
+ struct _wkb_ibus_service config;
+#else
+ Eldbus_Proxy *config;
+#endif
+ struct _wkb_ibus_service panel;
+ int refcount;
+ Eina_Bool address_pending;
+};
+
+static struct _wkb_ibus_context *ctx = NULL;
+
+static void
+_wkb_config_value_changed_cb(void *data, const Eldbus_Message *msg)
+{
+ const char *section, name;
+ Eldbus_Message_Iter *value;
+
+ CHECK_MESSAGE_ERRORS(msg)
+
+ if (!eldbus_message_arguments_get(msg, "ssv", &section, &name, &value))
+ {
+ ERR("Error reading message arguments");
+ return;
+ }
+
+ DBG("section: '%s', name: '%s', value: '%p", section, name, value);
+}
+
+static void
+_wkb_name_owner_changed_cb(void *data, const char *bus, const char *old_id, const char *new_id)
+{
+ DBG("NameOwnerChanged Bus=%s | old=%s | new=%s", bus, old_id, new_id);
+
+#if 0
+#else
+ if (strcmp(bus, IBUS_SERVICE_CONFIG) == 0)
+ {
+ if (*new_id)
+ {
+ Eldbus_Object *obj;
+
+ if (ctx->config)
+ return;
+
+ ecore_main_loop_glib_integrate();
+ obj = eldbus_object_get(ctx->conn, IBUS_SERVICE_CONFIG, IBUS_PATH_CONFIG);
+ ctx->config = eldbus_proxy_get(obj, IBUS_INTERFACE_CONFIG);
+ eldbus_proxy_signal_handler_add(ctx->config, "ValueChanged", _wkb_config_value_changed_cb, ctx);
+
+ INF("Got config proxy");
+ }
+ else
+ {
+ if (!ctx->config)
+ return;
+
+ eldbus_proxy_unref(ctx->config);
+ ctx->config = NULL;
+ }
+ }
+#endif
+}
+
+static void
+_wkb_name_acquired_cb(void *data, const Eldbus_Message *msg)
+{
+ const char *name;
+
+ DBG("NameAcquired");
+
+ CHECK_MESSAGE_ERRORS(msg)
+
+ if (!eldbus_message_arguments_get(msg, "s", &name))
+ {
+ ERR("Error reading message arguments");
+ return;
+ }
+
+ if (strcmp(name, IBUS_INTERFACE_PANEL) == 0)
+ {
+ if (!ctx->panel.interface)
+ {
+ ctx->panel.interface = wkb_ibus_panel_register(ctx->conn);
+ INF("Registering Panel Interface: %s", ctx->panel.interface ? "Success" : "Fail");
+ }
+ else
+ {
+ INF("Panel Interface already registered");
+ }
+ }
+#if 0
+ else if (strcmp(name, IBUS_INTERFACE_CONFIG) == 0)
+ {
+ if (!ctx->config.interface)
+ {
+ ctx->config.interface = wkb_ibus_config_register(ctx->conn);
+ INF("Registering Config Interface: %s", ctx->config.interface ? "Success" : "Fail");
+ }
+ else
+ {
+ INF("Config Interface already registered");
+ }
+ }
+#endif
+ else
+ {
+ WRN("Unexpected name %s", name);
+ }
+}
+
+static void
+_wkb_name_lost_cb(void *data, const Eldbus_Message *msg)
+{
+ const char *name;
+
+ DBG("NameLost");
+
+ CHECK_MESSAGE_ERRORS(msg)
+
+ if (!eldbus_message_arguments_get(msg, "s", &name))
+ {
+ ERR("Error reading message arguments");
+ return;
+ }
+
+ DBG("Name = %s", name);
+}
+
+static Eina_Bool
+_wkb_ibus_shutdown_idler(void *data)
+{
+ wkb_ibus_shutdown();
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_wkb_name_request_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
+{
+ const char *error, *error_msg;
+ unsigned int reply;
+
+ DBG("NameRequest callback");
+
+ if (eldbus_message_error_get(msg, &error, &error_msg))
+ {
+ ERR("DBus message error: %s: %s", error, error_msg);
+ goto error;
+ }
+
+ if (!eldbus_message_arguments_get(msg, "u", &reply))
+ {
+ ERR("Error reading message arguments");
+ goto error;
+ }
+
+ if (reply != ELDBUS_NAME_REQUEST_REPLY_PRIMARY_OWNER &&
+ reply != ELDBUS_NAME_REQUEST_REPLY_ALREADY_OWNER)
+ {
+ ERR("Not primary owner: reply=%d", reply);
+ goto error;
+ }
+
+ return;
+
+error:
+ ecore_idler_add(_wkb_ibus_shutdown_idler, NULL);
+}
+
+static void
+_wkb_name_release_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
+{
+ unsigned int reply;
+
+ CHECK_MESSAGE_ERRORS(msg)
+
+ if (!eldbus_message_arguments_get(msg, "u", &reply))
+ {
+ ERR("Error reading message arguments");
+ return;
+ }
+
+ if (reply != ELDBUS_NAME_RELEASE_REPLY_RELEASED)
+ {
+ ERR("Unexpected name release reply: %d", reply);
+ return;
+ }
+}
+
+static void
+_wkb_ibus_launch_daemon(void)
+{
+ DBG("Launching ibus-daemon");
+ ctx->ibus_daemon = ecore_exe_run("ibus-daemon -s", NULL);
+ if (!ctx->ibus_daemon)
+ {
+ ERR("Error launching ibus-daemon process");
+ return;
+ }
+}
+
+static Eina_Bool
+_wkb_ibus_query_address_cb(void *data, int type, void *event)
+{
+ Ecore_Exe_Event_Data *exe_data = (Ecore_Exe_Event_Data *)event;
+
+ if (strncmp(exe_data->data, "(null)", exe_data->size) == 0)
+ {
+ INF("IBus daemon is not running.");
+ _wkb_ibus_launch_daemon();
+ goto end;
+ }
+ else if (strstr(exe_data->data, "unknown command") != NULL)
+ {
+ ERR("ibus command does not support the 'address' argument");
+ goto end;
+ }
+
+ free(ctx->address);
+ ctx->address = strndup(exe_data->data, exe_data->size);
+
+end:
+ ecore_idler_add(ecore_exe_free, exe_data->exe);
+ ctx->address_pending = EINA_FALSE;
+ return ECORE_CALLBACK_DONE;
+}
+
+
+static void
+_wkb_ibus_query_address(void)
+{
+ const char *ibus_addr;
+ Ecore_Exe *ibus_exec = NULL;
+
+ /* Check for IBUS_ADDRESS environment variable */
+ if ((ibus_addr = getenv("IBUS_ADDRESS")) != NULL)
+ {
+ DBG("Got IBus address from IBUS_ADDRESS environment variable %s", ibus_addr);
+ ctx->address = strdup(ibus_addr);
+ return;
+ }
+
+ /* Get IBus address by invoking 'ibus address' from command line */
+ DBG("Querying IBus address from using 'ibus address' command");
+ ibus_exec = ecore_exe_pipe_run("ibus address",
+ ECORE_EXE_PIPE_READ |
+ ECORE_EXE_PIPE_READ_LINE_BUFFERED,
+ NULL);
+ if (!ibus_exec)
+ {
+ ERR("Unable to retrieve IBus address");
+ return;
+ }
+
+ ctx->address_pending = EINA_TRUE;
+ ecore_event_handler_add(ECORE_EXE_EVENT_DATA, _wkb_ibus_query_address_cb, NULL);
+}
+
+Eina_Bool
+wkb_ibus_connect(void)
+{
+ if (ctx->conn)
+ return EINA_TRUE;
+
+ if (!ctx->address)
+ {
+ INF("IBus address is not set.", ctx->address_pending);
+ if (!ctx->address_pending)
+ _wkb_ibus_query_address();
+
+ return EINA_FALSE;
+ }
+
+ INF("Connecting to IBus at address '%s'", ctx->address);
+ ctx->conn = eldbus_address_connection_get(ctx->address);
+
+ if (!ctx->conn)
+ {
+ ERR("Error connecting to IBus");
+ return EINA_FALSE;
+ }
+
+ /* Panel */
+ eldbus_name_owner_changed_callback_add(ctx->conn,
+ IBUS_SERVICE_PANEL,
+ _wkb_name_owner_changed_cb,
+ ctx, EINA_TRUE);
+
+ ctx->panel.name_acquired = eldbus_signal_handler_add(ctx->conn,
+ ELDBUS_FDO_BUS,
+ ELDBUS_FDO_PATH,
+ IBUS_INTERFACE_PANEL,
+ "NameAcquired",
+ _wkb_name_acquired_cb,
+ ctx);
+
+ ctx->panel.name_lost = eldbus_signal_handler_add(ctx->conn,
+ ELDBUS_FDO_BUS,
+ ELDBUS_FDO_PATH,
+ IBUS_INTERFACE_PANEL,
+ "NameLost",
+ _wkb_name_lost_cb,
+ ctx);
+
+ eldbus_name_request(ctx->conn, IBUS_SERVICE_PANEL,
+ ELDBUS_NAME_REQUEST_FLAG_REPLACE_EXISTING | ELDBUS_NAME_REQUEST_FLAG_DO_NOT_QUEUE,
+ _wkb_name_request_cb, ctx);
+
+ /* Config */
+ eldbus_name_owner_changed_callback_add(ctx->conn,
+ IBUS_SERVICE_CONFIG,
+ _wkb_name_owner_changed_cb,
+ ctx, EINA_TRUE);
+
+#if 0
+ ctx->config.name_acquired = eldbus_signal_handler_add(ctx->conn,
+ ELDBUS_FDO_BUS,
+ ELDBUS_FDO_PATH,
+ IBUS_INTERFACE_CONFIG,
+ "NameAcquired",
+ _wkb_name_acquired_cb,
+ ctx);
+
+ ctx->config.name_lost = eldbus_signal_handler_add(ctx->conn,
+ ELDBUS_FDO_BUS,
+ ELDBUS_FDO_PATH,
+ IBUS_INTERFACE_CONFIG,
+ "NameLost",
+ _wkb_name_lost_cb,
+ ctx);
+
+ eldbus_name_request(ctx->conn, IBUS_SERVICE_CONFIG,
+ ELDBUS_NAME_REQUEST_FLAG_REPLACE_EXISTING | ELDBUS_NAME_REQUEST_FLAG_DO_NOT_QUEUE,
+ _wkb_name_request_cb, ctx);
+#endif
+ return EINA_TRUE;
+}
+
+
+int
+wkb_ibus_init(void)
+{
+ if (ctx && ctx->refcount > 0)
+ goto end;
+
+ if (!eina_init())
+ {
+ fprintf(stderr, "Error initializing Eina\n");
+ return 0;
+ }
+
+ _wkb_ibus_log_dom = eina_log_domain_register("wkb-ibus", EINA_COLOR_LIGHTCYAN);
+ if (_wkb_ibus_log_dom < 0)
+ {
+ EINA_LOG_ERR("Unable to register 'wkb-ibus' log domain");
+ eina_shutdown();
+ return 0;
+ }
+
+ if (!ctx && !(ctx = calloc(1, sizeof(*ctx))))
+ {
+ ERR("Error calloc\n");
+ eina_shutdown();
+ return 0;
+ }
+
+ _wkb_ibus_query_address();
+
+end:
+ return ++ctx->refcount;
+}
+
+void
+wkb_ibus_shutdown(void)
+{
+ if (!ctx)
+ {
+ fprintf(stderr, "Not initialized\n");
+ return;
+ }
+
+ if (ctx->refcount == 0)
+ {
+ ERR("Refcount already 0");
+ goto end;
+ }
+
+ if (--(ctx->refcount) != 0)
+ return;
+
+ DBG("Shutting down");
+ wkb_ibus_disconnect();
+
+ free(ctx->address);
+
+ if (ctx->ibus_daemon)
+ {
+ DBG("Terminating ibus-daemon");
+ ecore_exe_terminate(ctx->ibus_daemon);
+ ecore_exe_free(ctx->ibus_daemon);
+ }
+
+end:
+ free(ctx);
+ ctx = NULL;
+
+ ecore_main_loop_quit();
+ DBG("Main loop quit");
+}
+
+void
+wkb_ibus_disconnect(void)
+{
+ if (!ctx->conn)
+ {
+ ERR("Not connected");
+ return;
+ }
+
+ DBG("Disconnect");
+
+ if (ctx->panel.interface)
+ {
+ eldbus_name_release(ctx->conn, IBUS_SERVICE_PANEL, _wkb_name_release_cb, ctx);
+ eldbus_signal_handler_del(ctx->panel.name_acquired);
+ eldbus_signal_handler_del(ctx->panel.name_lost);
+ eldbus_service_interface_unregister(ctx->panel.interface);
+ ctx->panel.interface = NULL;
+ }
+
+ if (ctx->config)
+ {
+ eldbus_proxy_unref(ctx->config);
+ ctx->config = NULL;
+ }
+#if 0
+ if (ctx->config.interface)
+ {
+ eldbus_name_release(ctx->conn, IBUS_SERVICE_CONFIG, _wkb_name_release_cb, ctx);
+ eldbus_signal_handler_del(ctx->config.name_acquired);
+ eldbus_signal_handler_del(ctx->config.name_lost);
+ eldbus_service_interface_unregister(ctx->config.interface);
+ ctx->config.interface = NULL;
+ }
+#endif
+
+ eldbus_connection_unref(ctx->conn);
+}
+
+Eina_Bool
+wkb_ibus_is_connected(void)
+{
+ return ctx->conn != NULL;
+}
diff --git a/src/wkb-ibus.h b/src/wkb-ibus.h
new file mode 100644
index 0000000..f3b0a1f
--- /dev/null
+++ b/src/wkb-ibus.h
@@ -0,0 +1,69 @@
+/*
+ * 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 _WKB_IBUS_H_
+#define _WKB_IBUS_H_
+
+#include <Eina.h>
+#include <Eldbus.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int _wkb_ibus_log_dom;
+#define DBG(...) EINA_LOG_DOM_DBG(_wkb_ibus_log_dom, __VA_ARGS__)
+#define INF(...) EINA_LOG_DOM_INFO(_wkb_ibus_log_dom, __VA_ARGS__)
+#define WRN(...) EINA_LOG_DOM_WARN(_wkb_ibus_log_dom, __VA_ARGS__)
+#define ERR(...) EINA_LOG_DOM_ERR(_wkb_ibus_log_dom, __VA_ARGS__)
+#define CRITICAL(...) EINA_LOG_DOM_CRIT(_wkb_ibus_log_dom, __VA_ARGS__)
+
+
+/* from ibusshare.h */
+#define IBUS_SERVICE_IBUS "org.freedesktop.IBus"
+#define IBUS_SERVICE_PANEL "org.freedesktop.IBus.Panel"
+#define IBUS_SERVICE_CONFIG "org.freedesktop.IBus.Config"
+
+#define IBUS_PATH_IBUS "/org/freedesktop/IBus"
+#define IBUS_PATH_PANEL "/org/freedesktop/IBus/Panel"
+#define IBUS_PATH_CONFIG "/org/freedesktop/IBus/Config"
+
+#define IBUS_INTERFACE_IBUS "org.freedesktop.IBus"
+#define IBUS_INTERFACE_PANEL "org.freedesktop.IBus.Panel"
+#define IBUS_INTERFACE_CONFIG "org.freedesktop.IBus.Config"
+
+
+int wkb_ibus_init(void);
+void wkb_ibus_shutdown(void);
+
+Eina_Bool wkb_ibus_connect(void);
+void wkb_ibus_disconnect(void);
+
+Eina_Bool wkb_ibus_is_connected(void);
+
+/* Panel */
+Eldbus_Service_Interface * wkb_ibus_panel_register(Eldbus_Connection *conn);
+
+/* Config */
+#if 0
+Eldbus_Service_Interface * wkb_ibus_config_register(Eldbus_Connection *conn);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _WKB_IBUS_H_ */
diff --git a/src/wkb-main.c b/src/wkb-main.c
new file mode 100644
index 0000000..953b283
--- /dev/null
+++ b/src/wkb-main.c
@@ -0,0 +1,601 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <Eina.h>
+#include <Ecore.h>
+#include <Ecore_Wayland.h>
+#include <Ecore_Evas.h>
+#include <Edje.h>
+
+#include <linux/input.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "input-method-client-protocol.h"
+#include "text-client-protocol.h"
+
+struct weekeyboard
+{
+ Ecore_Evas *ee;
+ Ecore_Wl_Window *win;
+ Evas_Object *edje_obj;
+ const char *ee_engine;
+ char **ignore_keys;
+
+ struct wl_surface *surface;
+ struct wl_input_panel *ip;
+ struct wl_input_method *im;
+ struct wl_output *output;
+ struct wl_input_method_context *im_ctx;
+
+ char *surrounding_text;
+ char *preedit_str;
+ char *language;
+
+ uint32_t text_direction;
+ uint32_t preedit_style;
+ uint32_t content_hint;
+ uint32_t content_purpose;
+ uint32_t serial;
+ uint32_t surrounding_cursor;
+
+ Eina_Bool context_changed;
+};
+
+static void
+_cb_wkb_delete_request(Ecore_Evas *ee EINA_UNUSED)
+{
+ ecore_main_loop_quit();
+}
+
+static char *
+_wkb_insert_text(const char *text, uint32_t offset, const char *insert)
+{
+ char *new_text = malloc(strlen(text) + strlen(insert) + 1);
+
+ strncat(new_text, text, offset);
+ new_text[offset] = '\0';
+ strcat(new_text, insert);
+ strcat(new_text, text + offset);
+
+ return new_text;
+}
+
+static void
+_wkb_commit_preedit_str(struct weekeyboard *wkb)
+{
+ char *surrounding_text;
+
+ if (!wkb->preedit_str || !strlen(wkb->preedit_str) == 0)
+ return;
+
+ wl_input_method_context_cursor_position(wkb->im_ctx, 0, 0);
+ wl_input_method_context_commit_string(wkb->im_ctx, wkb->serial, wkb->preedit_str);
+
+ if (wkb->surrounding_text)
+ {
+ surrounding_text = _wkb_insert_text(wkb->surrounding_text, wkb->surrounding_cursor, wkb->preedit_str);
+ free(wkb->surrounding_text);
+ wkb->surrounding_text = surrounding_text;
+ wkb->surrounding_cursor += strlen(wkb->preedit_str);
+ }
+ else
+ {
+ wkb->surrounding_text = strdup(wkb->preedit_str);
+ wkb->surrounding_cursor = strlen(wkb->preedit_str);
+ }
+
+ free(wkb->preedit_str);
+ wkb->preedit_str = strdup("");
+}
+
+static void
+_wkb_send_preedit_str(struct weekeyboard *wkb, int cursor)
+{
+ unsigned int index = strlen(wkb->preedit_str);
+
+ if (wkb->preedit_style)
+ wl_input_method_context_preedit_styling(wkb->im_ctx, 0, strlen(wkb->preedit_str), wkb->preedit_style);
+
+ if (cursor > 0)
+ index = cursor;
+
+ wl_input_method_context_preedit_cursor(wkb->im_ctx, index);
+ wl_input_method_context_preedit_string(wkb->im_ctx, wkb->serial, wkb->preedit_str, wkb->preedit_str);
+}
+
+static void
+_wkb_update_preedit_str(struct weekeyboard *wkb, const char *key)
+{
+ char *tmp;
+
+ if (!wkb->preedit_str)
+ wkb->preedit_str = strdup("");
+
+ tmp = calloc(1, strlen(wkb->preedit_str) + strlen(key) + 1);
+ sprintf(tmp, "%s%s", wkb->preedit_str, key);
+ free(wkb->preedit_str);
+ wkb->preedit_str = tmp;
+
+ if (strcmp(key, " ") == 0)
+ _wkb_commit_preedit_str(wkb);
+ else
+ _wkb_send_preedit_str(wkb, -1);
+}
+
+static Eina_Bool
+_wkb_ignore_key(struct weekeyboard *wkb, const char *key)
+{
+ int i;
+
+ if (!wkb->ignore_keys)
+ return EINA_FALSE;
+
+ for (i = 0; wkb->ignore_keys[i] != NULL; i++)
+ if (!strcmp(key, wkb->ignore_keys[i]))
+ return EINA_TRUE;
+
+ return EINA_FALSE;
+}
+
+static void
+_cb_wkb_on_key_down(void *data, Evas_Object *obj, const char *emission EINA_UNUSED, const char *source)
+{
+ struct weekeyboard *wkb = data;
+ char *src;
+ const char *key;
+
+ src = strdup(source);
+ key = strtok(src, ":"); /* ignore group */
+ key = strtok(NULL, ":");
+ if (key == NULL)
+ key = ":";
+
+ if (_wkb_ignore_key(wkb, key))
+ {
+ printf("Ignoring key '%s'\n", key);
+ goto end;
+ }
+ else if (strcmp(key, "backspace") == 0)
+ {
+ if (strlen(wkb->preedit_str) == 0)
+ wl_input_method_context_delete_surrounding_text(wkb->im_ctx, -1, 1);
+ else
+ {
+ wkb->preedit_str[strlen(wkb->preedit_str) - 1] = '\0';
+ _wkb_send_preedit_str(wkb, -1);
+ }
+
+ goto end;
+ }
+ else if (strcmp(key, "enter") == 0)
+ {
+ _wkb_commit_preedit_str(wkb);
+ /* wl_input_method_context_keysym(wkb->im_ctx, wkb->serial, time, XKB_KEY_Return, key_state, mod_mask); */
+ goto end;
+ }
+ else if (strcmp(key, "space") == 0)
+ {
+ key = " ";
+ }
+
+ printf("KEY = '%s'\n", key);
+
+ _wkb_update_preedit_str(wkb, key);
+
+end:
+ free(src);
+}
+
+static void
+_wkb_im_ctx_surrounding_text(void *data, struct wl_input_method_context *im_ctx, const char *text, uint32_t cursor, uint32_t anchor)
+{
+ struct weekeyboard *wkb = data;
+
+ printf("%s()\n", __FUNCTION__);
+ free(wkb->surrounding_text);
+ wkb->surrounding_text = strdup(text);
+ wkb->surrounding_cursor = cursor;
+}
+
+static void
+_wkb_im_ctx_reset(void *data, struct wl_input_method_context *im_ctx)
+{
+ struct weekeyboard *wkb = data;
+
+ printf("%s()\n", __FUNCTION__);
+
+ if (strlen(wkb->preedit_str))
+ {
+ free(wkb->preedit_str);
+ wkb->preedit_str = strdup("");
+ }
+}
+
+static void
+_wkb_im_ctx_content_type(void *data, struct wl_input_method_context *im_ctx, uint32_t hint, uint32_t purpose)
+{
+ struct weekeyboard *wkb = data;
+
+ printf("%s(): im_context = %p hint = %d purpose = %d\n", __FUNCTION__, im_ctx, hint, purpose);
+
+ if (!wkb->context_changed)
+ return;
+
+ switch (purpose)
+ {
+ case WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS:
+ case WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER:
+ {
+ edje_object_signal_emit(wkb->edje_obj, "show,numeric", "");
+ break;
+ }
+ default:
+ {
+ edje_object_signal_emit(wkb->edje_obj, "show,alphanumeric", "");
+ break;
+ }
+ }
+
+ wkb->content_hint = hint;
+ wkb->content_purpose = purpose;
+
+ wkb->context_changed = EINA_FALSE;
+}
+
+static void
+_wkb_im_ctx_invoke_action(void *data, struct wl_input_method_context *im_ctx, uint32_t button, uint32_t index)
+{
+ struct weekeyboard *wkb = data;
+
+ printf("%s()\n", __FUNCTION__);
+ if (button != BTN_LEFT)
+ return;
+
+ _wkb_send_preedit_str(wkb, index);
+}
+
+static void
+_wkb_im_ctx_commit_state(void *data, struct wl_input_method_context *im_ctx, uint32_t serial)
+{
+ struct weekeyboard *wkb = data;
+
+ printf("%s()\n", __FUNCTION__);
+ if (wkb->surrounding_text)
+ fprintf(stderr, "Surrounding text updated: %s\n", wkb->surrounding_text);
+
+ wkb->serial = serial;
+ /* FIXME */
+ wl_input_method_context_language(im_ctx, wkb->serial, "en");//wkb->language);
+ wl_input_method_context_text_direction(im_ctx, wkb->serial, WL_TEXT_INPUT_TEXT_DIRECTION_LTR);//wkb->text_direction);
+}
+
+static void
+_wkb_im_ctx_preferred_language(void *data, struct wl_input_method_context *im_ctx, const char *language)
+{
+ struct weekeyboard *wkb = data;
+
+ if (language && wkb->language && !strcmp(language, wkb->language))
+ return;
+
+ if (wkb->language)
+ {
+ free(wkb->language);
+ wkb->language = NULL;
+ }
+
+ if (language)
+ {
+ wkb->language = strdup(language);
+ printf("Language changed, new: '%s\n", language);
+ }
+}
+
+static const struct wl_input_method_context_listener wkb_im_context_listener = {
+ _wkb_im_ctx_surrounding_text,
+ _wkb_im_ctx_reset,
+ _wkb_im_ctx_content_type,
+ _wkb_im_ctx_invoke_action,
+ _wkb_im_ctx_commit_state,
+ _wkb_im_ctx_preferred_language,
+};
+
+static void
+_wkb_im_activate(void *data, struct wl_input_method *input_method, struct wl_input_method_context *im_ctx)
+{
+ struct weekeyboard *wkb = data;
+ struct wl_array modifiers_map;
+
+ if (wkb->im_ctx)
+ wl_input_method_context_destroy(wkb->im_ctx);
+
+ if (wkb->preedit_str)
+ free(wkb->preedit_str);
+
+ wkb->preedit_str = strdup("");
+ wkb->content_hint = WL_TEXT_INPUT_CONTENT_HINT_NONE;
+ wkb->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NORMAL;
+ free(wkb->language);
+ wkb->language = NULL;
+ free(wkb->surrounding_text);
+ wkb->surrounding_text = NULL;
+ wkb->serial = 0;
+
+ wkb->im_ctx = im_ctx;
+ wl_input_method_context_add_listener(im_ctx, &wkb_im_context_listener, wkb);
+
+ /*
+ wl_array_init(&modifiers_map);
+
+ keysym_modifiers_add(&modifiers_map, "Shift");
+ keysym_modifiers_add(&modifiers_map, "Control");
+ keysym_modifiers_add(&modifiers_map, "Mod1");
+
+ wl_input_method_context_modifiers_map(im_ctx, &modifiers_map);
+
+ wkb->keysym.shift_mask = keysym_modifiers_get_mask(&modifiers_map, "Shift");
+
+ wl_array_release(&modifiers_map);
+ */
+
+ /* FIXME */
+ wl_input_method_context_language(im_ctx, wkb->serial, "en");//wkb->language);
+ wl_input_method_context_text_direction(im_ctx, wkb->serial, WL_TEXT_INPUT_TEXT_DIRECTION_LTR);//wkb->text_direction);
+
+ wkb->context_changed = EINA_TRUE;
+ evas_object_show(wkb->edje_obj);
+}
+
+static void
+_wkb_im_deactivate(void *data, struct wl_input_method *input_method, struct wl_input_method_context *im_ctx)
+{
+ struct weekeyboard *wkb = data;
+
+ if (!wkb->im_ctx)
+ return;
+
+ wl_input_method_context_destroy(wkb->im_ctx);
+ wkb->im_ctx = NULL;
+ evas_object_hide(wkb->edje_obj);
+}
+
+static const struct wl_input_method_listener wkb_im_listener = {
+ _wkb_im_activate,
+ _wkb_im_deactivate
+};
+
+
+static Eina_Bool
+_wkb_ui_setup(struct weekeyboard *wkb)
+{
+ char path[PATH_MAX];
+ Evas *evas;
+ Evas_Coord w, h;
+ char *ignore_keys;
+
+ ecore_evas_alpha_set(wkb->ee, EINA_TRUE);
+ ecore_evas_title_set(wkb->ee, "EFL virtual keyboard");
+
+ evas = ecore_evas_get(wkb->ee);
+ wkb->edje_obj = edje_object_add(evas);
+ /*ecore_evas_object_associate(wkb->ee, edje_obj, ECORE_EVAS_OBJECT_ASSOCIATE_BASE);*/
+
+ /* Check which theme we should use according to the screen width */
+ ecore_wl_screen_size_get(&w, &h);
+ if (w >= 720)
+ w = 720;
+ else
+ w = 600;
+
+ sprintf(path, PKGDATADIR"/default_%d.edj", w);
+ printf("Loading edje file: '%s'\n", path);
+
+ if (!edje_object_file_set(wkb->edje_obj, path, "main"))
+ {
+ int err = edje_object_load_error_get(wkb->edje_obj);
+ fprintf(stderr, "error loading the edje file:%s\n", edje_load_error_str(err));
+ return EINA_FALSE;
+ }
+
+ edje_object_size_min_get(wkb->edje_obj, &w, &h);
+ if (w == 0 || h == 0)
+ {
+ edje_object_size_min_restricted_calc(wkb->edje_obj, &w, &h, w, h);
+ if (w == 0 || h == 0)
+ edje_object_parts_extends_calc(wkb->edje_obj, NULL, NULL, &w, &h);
+ }
+
+ ecore_evas_move_resize(wkb->ee, 0, 0, w, h);
+ evas_object_move(wkb->edje_obj, 0, 0);
+ evas_object_resize(wkb->edje_obj, w, h);
+ evas_object_size_hint_min_set(wkb->edje_obj, w, h);
+ evas_object_size_hint_max_set(wkb->edje_obj, w, h);
+
+ edje_object_signal_callback_add(wkb->edje_obj, "key_down", "*", _cb_wkb_on_key_down, wkb);
+ ecore_evas_callback_delete_request_set(wkb->ee, _cb_wkb_delete_request);
+
+ /*
+ * The keyboard surface is bigger than it appears so that we can show the
+ * key pressed animation without requiring the use of subsurfaces. Here we
+ * resize the input region of the surface to match the keyboard background
+ * image, so that we can pass mouse events to the surfaces that may be
+ * located below the keyboard.
+ */
+ if (wkb->win)
+ {
+ int x, y, w, h;
+ struct wl_region *input = wl_compositor_create_region(wkb->win->display->wl.compositor);
+
+ edje_object_part_geometry_get(wkb->edje_obj, "background", &x, &y, &w, &h);
+ wl_region_add(input, x, y, w, h);
+ wl_surface_set_input_region(wkb->surface, input);
+ wl_region_destroy(input);
+ }
+
+ /* special keys */
+ ignore_keys = edje_file_data_get(path, "ignore-keys");
+ if (!ignore_keys)
+ {
+ printf("Special keys file not found in '%s'\n", path);
+ goto end;
+ }
+
+ printf("Got ignore keys = %s\n", ignore_keys);
+ wkb->ignore_keys = eina_str_split(ignore_keys, "\n", 0);
+ free(ignore_keys);
+
+end:
+ ecore_evas_show(wkb->ee);
+ return EINA_TRUE;
+}
+
+static void
+_wkb_setup(struct weekeyboard *wkb)
+{
+ struct wl_list *globals;
+ struct wl_registry *registry;
+ Ecore_Wl_Global *global;
+
+ struct wl_input_panel_surface *ips;
+
+ globals = ecore_wl_globals_get();
+ registry = ecore_wl_registry_get();
+ wl_list_for_each(global, globals, link)
+ {
+ if (strcmp(global->interface, "wl_input_panel") == 0)
+ wkb->ip = wl_registry_bind(registry, global->id, &wl_input_panel_interface, 1);
+ else if (strcmp(global->interface, "wl_input_method") == 0)
+ wkb->im = wl_registry_bind(registry, global->id, &wl_input_method_interface, 1);
+ else if (strcmp(global->interface, "wl_output") == 0)
+ wkb->output = wl_registry_bind(registry, global->id, &wl_output_interface, 1);
+ }
+
+ /* Set input panel surface */
+ wkb->win = ecore_evas_wayland_window_get(wkb->ee);
+ ecore_wl_window_type_set(wkb->win, ECORE_WL_WINDOW_TYPE_NONE);
+ wkb->surface = ecore_wl_window_surface_create(wkb->win);
+ ips = wl_input_panel_get_input_panel_surface(wkb->ip, wkb->surface);
+ wl_input_panel_surface_set_toplevel(ips, wkb->output, WL_INPUT_PANEL_SURFACE_POSITION_CENTER_BOTTOM);
+
+ /* Input method listener */
+ wl_input_method_add_listener(wkb->im, &wkb_im_listener, wkb);
+}
+
+static void
+_wkb_free(struct weekeyboard *wkb)
+{
+ if (wkb->im_ctx)
+ wl_input_method_context_destroy(wkb->im_ctx);
+
+ if (wkb->ignore_keys)
+ {
+ free(*wkb->ignore_keys);
+ free(wkb->ignore_keys);
+ }
+
+ evas_object_del(wkb->edje_obj);
+ free(wkb->preedit_str);
+ free(wkb->surrounding_text);
+}
+
+static Eina_Bool
+_wkb_check_evas_engine(struct weekeyboard *wkb)
+{
+ Eina_Bool ret = EINA_FALSE;
+ char *env = getenv("ECORE_EVAS_ENGINE");
+
+ if (!env)
+ {
+ if (ecore_evas_engine_type_supported_get(ECORE_EVAS_ENGINE_WAYLAND_SHM))
+ env = "wayland_shm";
+ else if (ecore_evas_engine_type_supported_get(ECORE_EVAS_ENGINE_WAYLAND_EGL))
+ env = "wayland_egl";
+ else
+ {
+ printf("ERROR: Ecore_Evas does must be compiled with support for Wayland engines\n");
+ goto err;
+ }
+ }
+ else if (strcmp(env, "wayland_shm") != 0 && strcmp(env, "wayland_egl") != 0)
+ {
+ printf("ERROR: ECORE_EVAS_ENGINE must be set to either 'wayland_shm' or 'wayland_egl'\n");
+ goto err;
+ }
+
+ wkb->ee_engine = env;
+ ret = EINA_TRUE;
+
+err:
+ return ret;
+}
+
+int
+main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
+{
+ struct weekeyboard wkb = {0};
+ int ret = EXIT_FAILURE;
+
+ if (!ecore_init())
+ return ret;
+
+ if (!ecore_evas_init())
+ goto ecore_err;
+
+ if (!edje_init())
+ goto ee_err;
+
+ if (!_wkb_check_evas_engine(&wkb))
+ goto edj_err;
+
+ printf("SELECTED ENGINE = %s\n", wkb.ee_engine);
+ wkb.ee = ecore_evas_new(wkb.ee_engine, 0, 0, 1, 1, "frame=0");
+
+ if (!wkb.ee)
+ {
+ printf("ERROR: Unable to create Ecore_Evas object\n");
+ goto edj_err;
+ }
+
+ _wkb_setup(&wkb);
+
+ if (!_wkb_ui_setup(&wkb))
+ goto end;
+
+ ecore_main_loop_begin();
+
+ ret = EXIT_SUCCESS;
+
+ _wkb_free(&wkb);
+
+end:
+ ecore_evas_free(wkb.ee);
+
+edj_err:
+ edje_shutdown();
+
+ee_err:
+ ecore_evas_shutdown();
+
+ecore_err:
+ ecore_shutdown();
+
+ return ret;
+}