diff options
author | Eduardo Lima (Etrunko) <eduardo.lima@intel.com> | 2013-08-16 17:08:23 -0300 |
---|---|---|
committer | Eduardo Lima (Etrunko) <eduardo.lima@intel.com> | 2013-08-16 17:08:23 -0300 |
commit | 562d8297a8a6099541b41bc9f98f12ff6b06d996 (patch) | |
tree | 3667bb272a7f79c632fbc87b95b0bd1fa2bcf13a /src | |
download | weekeyboard-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.am | 51 | ||||
-rw-r--r-- | src/wkb-ibus-config-eet-test.c | 46 | ||||
-rw-r--r-- | src/wkb-ibus-config-eet.c | 962 | ||||
-rw-r--r-- | src/wkb-ibus-config-eet.h | 34 | ||||
-rw-r--r-- | src/wkb-ibus-config.c | 170 | ||||
-rw-r--r-- | src/wkb-ibus-panel.c | 831 | ||||
-rw-r--r-- | src/wkb-ibus-test.c | 69 | ||||
-rw-r--r-- | src/wkb-ibus.c | 507 | ||||
-rw-r--r-- | src/wkb-ibus.h | 69 | ||||
-rw-r--r-- | src/wkb-main.c | 601 |
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>[ '<Super>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 < Delay milliseconds. 0 > 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", §ion, &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", §ion, &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", §ion)) + { + 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", §ion, &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", §ion, &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; +} |