From: Eduardo Lima (Etrunko) Date: Fri, 16 Aug 2013 20:08:23 +0000 (-0300) Subject: Initial commit X-Git-Tag: v0.0.1~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=562d8297a8a6099541b41bc9f98f12ff6b06d996;p=platform%2Fupstream%2Fweekeyboard.git Initial commit Signed-off-by: Eduardo Lima (Etrunko) --- 562d8297a8a6099541b41bc9f98f12ff6b06d996 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d005cda --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +aclocal.m4 +libtool.m4 +ltoptions.m4 +ltsugar.m4 +ltversion.m4 +lt~obsolete.m4 +autom4te.cache +config.* +configure +depcomp +install-sh +libtool +ltmain.sh +Makefile +Makefile.in +missing +patch +weekeyboard +stamp-h1 +*.o +*.lo +.deps +.libs +*.orig +*.rej +*.bak +*~ +input-method-client-protocol.h +input-method-protocol.c +text-client-protocol.h +text-protocol.c +weekeyboard-ibus-test +weekeyboard-config-eet-test diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..5e00638 --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Eduardo Lima (Etrunko) diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/COPYING @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..e69de29 diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..3cdce98 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,9 @@ +SUBDIRS=protocol src data/themes + +clean-local: + rm -f $(top_builddir)/install-sh + rm -f $(top_builddir)/missing + rm -f $(top_builddir)/config.guess + rm -f $(top_builddir)/ltmain.sh + rm -f $(top_builddir)/depcomp + rm -f $(top_builddir)/config.sub diff --git a/README b/README new file mode 100644 index 0000000..e69de29 diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..916169a --- /dev/null +++ b/autogen.sh @@ -0,0 +1,9 @@ +#! /bin/sh + +test -n "$srcdir" || srcdir=`dirname "$0"` +test -n "$srcdir" || srcdir=. +( + cd "$srcdir" && + autoreconf --force -v --install +) || exit +test -n "$NOCONFIGURE" || "$srcdir/configure" "$@" diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..e114d0d --- /dev/null +++ b/configure.ac @@ -0,0 +1,66 @@ +m4_define([wkb_major], [0]) +m4_define([wkb_minor], [0]) +m4_define([wkb_micro], [1]) +m4_define([wkb_version], [wkb_major.wkb_minor.wkb_micro]) + +AC_PREREQ([2.64]) +AC_INIT([weekeyboard], [wkb_version]) + +AC_SUBST([weekeyboard_MAJOR], [wkb_major]) +AC_SUBST([weekeyboard_MINOR], [wkb_minor]) +AC_SUBST([weekeyboard_MICRO], [wkb_micro]) +AC_SUBST([weekeyboard_VERSION], [wkb_version]) + +AC_CONFIG_HEADERS([config.h]) + +AM_INIT_AUTOMAKE([1.11 -Wall -Wextra parallel-tests foreign color-tests]) + +AM_SILENT_RULES([yes]) + +# Check for programs +AC_PROG_CC +AC_PROG_SED + +# Initialize libtool +LT_PREREQ([2.2]) +LT_INIT([disable-static]) + +PKG_PROG_PKG_CONFIG() + +PKG_CHECK_MODULES(WAYLAND, [wayland-client >= 1.2.0]) +PKG_CHECK_MODULES(EFL, [eina eet evas ecore ecore-evas ecore-wayland edje]) + +AC_ARG_WITH(edje-cc, + AS_HELP_STRING([--with-edje-cc=PATH], [Path to edje_cc binary]), + [EDJE_CC_PATH=${withval}], [EDJE_CC_PATH=$($PKG_CONFIG --variable=prefix edje)/bin/edje_cc]) +AC_SUBST([EDJE_CC_PATH]) + + +AC_ARG_ENABLE([ibus], + [AC_HELP_STRING([--disable-ibus], + [Disable integration with IBus input method system])], + [], [enable_ibus=yes]) + +AM_CONDITIONAL(ENABLE_IBUS, test "x$enable_ibus" = "xyes") + +if test "x$enable_ibus" = "xyes"; then + PKG_CHECK_MODULES(ELDBUS, [eldbus]) + AC_CHECK_PROG([have_ibus], [ibus], [yes], [no]) + + AS_IF([ test "x$have ibus" = "xno" ], + [ AC_MSG_ERROR([The ibus executable was not found.]) ]) + + IBUS_ADDR=`ibus address > /dev/null 2>&1` + AS_IF([ test $? -ne 0 ], + [ AC_MSG_WARN([The ibus executable does not support 'address' argument.]) ]) + + AC_DEFINE(BUILD_IBUS, [1], [Build integration with IBus input method system]) +fi + +WAYLAND_SCANNER_RULES(['$(top_srcdir)/protocol']) + +AC_CONFIG_FILES([Makefile + src/Makefile + data/themes/Makefile + protocol/Makefile]) +AC_OUTPUT diff --git a/data/.gitignore b/data/.gitignore new file mode 100644 index 0000000..2f69ae5 --- /dev/null +++ b/data/.gitignore @@ -0,0 +1 @@ +*.edj diff --git a/data/themes/Makefile.am b/data/themes/Makefile.am new file mode 100644 index 0000000..fd143f5 --- /dev/null +++ b/data/themes/Makefile.am @@ -0,0 +1,51 @@ +MAINTAINERCLEANFILES = Makefile.in + +EDJE_CC = @EDJE_CC_PATH@ +EDJE_FLAGS_VERBOSE_ = +EDJE_FLAGS_VERBOSE_0 = +EDJE_FLAGS_VERBOSE_1 = -v +EDJE_FLAGS = $(EDJE_FLAGS_VERBOSE_$(V)) + +filesdir = $(pkgdatadir) +files_DATA = default_600.edj \ + default_720.edj + +DEFAULT_FILES = default/default.edc \ + default/default_600.edc \ + default/default_720.edc \ + default/ignorekeys.txt \ + default/fonts/DroidSans-Bold.ttf \ + default/fonts/DroidSans.ttf \ + default/images/key-hint-bg.png \ + default/images/icon-language.png \ + default/images/icon-backspace.png \ + default/images/key-special.png \ + default/images/icon-space.png \ + default/images/key-hint.png \ + default/images/icon-shift.png \ + default/images/icon-shift-active.png \ + default/images/icon-enter.png \ + default/images/key-special-pressed.png \ + default/images/key-default.png \ + default/images/key-default-pressed.png + +EXTRA_DIST = $(DEFAULT_FILES) + +default_600.edj: Makefile default/default_600.edc $(default_FILES) + $(EDJE_CC) $(EDJE_FLAGS) \ + -dd $(top_srcdir)/data/themes/default \ + -id $(top_srcdir)/data/themes/default/images \ + -fd $(top_srcdir)/data/themes/default/fonts \ + $(top_srcdir)/data/themes/default/default_600.edc \ + $(top_builddir)/data/themes/default_600.edj + +default_720.edj: Makefile default/default_720.edc $(default_FILES) + $(EDJE_CC) $(EDJE_FLAGS) \ + -dd $(top_srcdir)/data/themes/default \ + -id $(top_srcdir)/data/themes/default/images \ + -fd $(top_srcdir)/data/themes/default/fonts \ + $(top_srcdir)/data/themes/default/default_720.edc \ + $(top_builddir)/data/themes/default_720.edj + +clean-local: + rm -f $(top_builddir)/data/themes/*.edj diff --git a/data/themes/default/default.edc b/data/themes/default/default.edc new file mode 100644 index 0000000..7275787 --- /dev/null +++ b/data/themes/default/default.edc @@ -0,0 +1,1050 @@ +/* + * 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. + */ + +images { + image: "icon-backspace.png" COMP; + image: "icon-enter.png" COMP; + image: "icon-language.png" COMP; + image: "icon-shift-active.png" COMP; + image: "icon-shift.png" COMP; + image: "icon-space.png" COMP; + + image: "key-default.png" COMP; + image: "key-default-pressed.png" COMP; + image: "key-hint.png" COMP; + image: "key-hint-bg.png" COMP; + image: "key-special.png" COMP; + image: "key-special-pressed.png" COMP; +} + +fonts { + font: "DroidSans.ttf" "DroidSans"; + font: "DroidSans-Bold.ttf" "DroidSansBold"; +} + +data { + file: "ignore-keys" "ignorekeys.txt"; +} + +collections { + group { + name: "main"; + + min: MIN_WIDTH MIN_HEIGHT; + max: MAX_WIDTH MAX_HEIGHT; + + parts { + part { + name: "rect_bg"; + mouse_events: 0; + type: RECT; + description { + state: "default" 0.0; + color: 255 255 255 0; + rel1 { + relative: 0.0 0.0; + offset: 0 0; + } + rel2 { + relative: 1.0 1.0; + offset: -1 -1; + } + } + } + + part { + name: "background"; + mouse_events: 1; + pointer_mode: NOGRAB; + type: RECT; + description { + state: "default" 0.0; + color: 214 215 218 255; + rel1 { + relative: 0.0 0.0; + offset: 0 (150*SCALE); + } + rel2 { + relative: 1.0 1.0; + offset: -1 -1; + } + } + } + } + +#define KEY_GROUP(_name) \ + parts { \ + part { \ + name: _name"_clip"; \ + type: RECT; \ + description { \ + state: "default" 0.0; \ + rel1 { \ + relative: 0.0 0.0; \ + offset: 0 0; \ + } \ + rel2 { \ + relative: 1.0 1.0; \ + offset: -1 -1; \ + } \ + } \ + description { \ + state: "hidden" 0.0; \ + inherit: "default" 0.0; \ + visible: 0; \ + } \ + } \ + part { \ + name: _name; \ + type: GROUP; \ + source: _name; \ + clip_to: _name"_clip"; \ + description { \ + state: "default" 0.0; \ + rel1 { \ + to: "background"; \ + relative: 0.0 0.0; \ + offset: (5*SCALE) (10*SCALE); \ + } \ + rel2 { \ + to: "background"; \ + relative: 1.0 1.0; \ + offset: -1 -1; \ + } \ + } \ + } \ + } \ + programs { \ + program { \ + name: "show-"_name; \ + action: STATE_SET "default" 0.0; \ + target: _name"_clip"; \ + } \ + program { \ + name: "hide-"_name; \ + action: STATE_SET "hidden" 0.0; \ + target: _name"_clip"; \ + } \ + } + + KEY_GROUP("alphanum") + KEY_GROUP("numeric") + KEY_GROUP("special-1") + KEY_GROUP("special-2") + KEY_GROUP("fixed") + + programs { + program { + name: "alphanum_show"; + signal: "show,alphanumeric"; + after: "show-alphanum"; + after: "hide-numeric"; + after: "hide-special-1"; + after: "hide-special-2"; + after: "show-fixed"; + } + + program { + name: "numeric_show"; + signal: "show,numeric"; + after: "show-numeric"; + after: "hide-alphanum"; + after: "hide-special-1"; + after: "hide-special-2"; + after: "hide-fixed"; + } + + program { + name: "special-1_show"; + signal: "show,special,1"; + after: "show-special-1"; + after: "hide-numeric"; + after: "hide-alphanum"; + after: "hide-special-2"; + after: "show-fixed"; + } + + program { + name: "special-2_show"; + signal: "show,special,2"; + after: "show-special-2"; + after: "hide-numeric"; + after: "hide-alphanum"; + after: "hide-special-1"; + after: "show-fixed"; + } + + program { + name: "?123_clicked"; + signal: "key_down"; + source: "alphanum:?123"; + after: "special-1_show"; + } + program { + name: "special-1_abc_clicked"; + signal: "key_down"; + source: "special-1:abc"; + after: "alphanum_show"; + } + program { + name: "special-2_abc_clicked"; + signal: "key_down"; + source: "special-2:abc"; + after: "alphanum_show"; + } + program { + name: "1/2_clicked"; + signal: "key_down"; + source: "special-1:1/2"; + after: "special-2_show"; + } + program { + name: "2/2_clicked"; + signal: "key_down"; + source: "special-2:2/2"; + after: "special-1_show"; + } + program { + name: "init"; + signal: "show"; + after: "alphanum_show"; + } + } + } + + group { + name: "alphanum"; + +#define MOUSE_DOWN_UP_PROGRAMS \ + script { \ + public shift_pressed = 0; \ + public mouse_down = 0; \ + public long_press_timer = 0; \ + public long_press = 0; \ + public pressed_key; \ + \ + public _set_long_press(val) { \ + new _cur[20]; \ + new _timer; \ + _timer = get_int(long_press_timer); \ + if (_timer) { \ + cancel_timer(_timer); \ + set_int(long_press_timer, 0); \ + } \ + set_int(long_press, val); \ + if (!val) \ + return; \ + get_str(pressed_key, _cur, 20); \ + if (strlen(_cur) > 0) { \ + emit("long_press", _cur); \ + } \ + } \ + \ + _set_key_pressed(_key[]) { \ + new _cur[20]; \ + new _prg[30]; \ + new _timer; \ + get_str(pressed_key, _cur, 20); \ + if (strlen(_cur) > 0) { \ + _set_key_released(_cur); \ + } \ + set_str(pressed_key, _key); \ + _timer = timer(1.0, "_set_long_press", 1); \ + set_int(long_press_timer, _timer); \ + snprintf(_prg, 30, "key-press-%s", _key); \ + run_program(get_program_id(_prg)); \ + } \ + \ + _set_key_released(_key[]) { \ + new _prg[30]; \ + _set_long_press(0); \ + set_str(pressed_key, ""); \ + snprintf(_prg, 30, "key-release-%s", _key); \ + run_program(get_program_id(_prg)); \ + } \ + } \ + programs { \ + program { \ + name: "mouse-down"; \ + signal: "mouse,down,1"; \ + source: "*"; \ + script { \ + set_int(mouse_down, 1); \ + } \ + } \ + program { \ + name: "mouse-up"; \ + signal: "mouse,up,1"; \ + source: "*"; \ + script { \ + set_int(mouse_down, 0); \ + } \ + } \ + } + + MOUSE_DOWN_UP_PROGRAMS + parts { +#undef INIT_HSPACE +#define INIT_HSPACE 5 +#define KEY_WIDTH (65*SCALE) +#define KEY_HEIGHT (90*SCALE) +#define COL_SPACE 5 +#define KEY_OFFSET(index) ((COL_SPACE+KEY_WIDTH)*index)+INIT_HSPACE + +#define FIRST_ROW 0 +#define ROW_SPACE (20*SCALE) + +#define SKEY_FULL(key_low, key_up, key_name, key_alt, x, y) \ + part { \ + name: "key-img-"key_name; \ + type: IMAGE; \ + mouse_events: 0; \ + description { \ + state: "default" 0.0; \ + min: KEY_WIDTH KEY_HEIGHT; \ + max: KEY_WIDTH KEY_HEIGHT; \ + fixed: 1 1; \ + rel1 { \ + relative: 0.0 0.0; \ + offset: (x) (y); \ + } \ + rel2 { \ + relative: 0.0 0.0; \ + offset: (x+KEY_WIDTH-1) (y+KEY_HEIGHT-1); \ + } \ + image { \ + normal: "key-default.png"; \ + border: 8 8 10 10; \ + } \ + } \ + description { \ + state: "down" 0.0; \ + inherit: "default" 0.0; \ + rel1.offset: (x+1) (y+1); \ + rel2.offset: (x+1+KEY_WIDTH-1) (y+1+KEY_HEIGHT-1); \ + image.normal: "key-default-pressed.png"; \ + } \ + } \ + part { \ + name: "key-bg-"key_name; \ + type: RECT; \ + pointer_mode: NOGRAB; \ + description { \ + state: "default" 0.0; \ + color: 0 0 0 0; \ + rel1 { \ + to: "key-img-"key_name; \ + relative: 0.0 0.0; \ + offset: 3 2; \ + } \ + rel2 { \ + to: "key-img-"key_name; \ + relative: 1.0 1.0; \ + offset: -4 -6; \ + } \ + } \ + } \ + part { \ + name: "key-lbl-"key_name; \ + type: TEXT; \ + mouse_events: 0; \ + effect: SHADOW BOTTOM; \ + description { \ + state: "default" 0.0; \ + color: 63 67 72 255; \ + color2: 240 240 240 255; \ + color3: 240 240 240 255; \ + rel1 { \ + to: "key-bg-"key_name; \ + relative: 0.0 0.4; \ + } \ + rel2 { \ + to: "key-bg-"key_name; \ + relative: 1.0 0.9; \ + } \ + text { \ + font: "DroidSans"; \ + size: (40*SCALE); \ + text: key_low; \ + } \ + } \ + } \ + part { \ + name: "key-lbl-alt-"key_name; \ + type: TEXT; \ + mouse_events: 0; \ + effect: SHADOW BOTTOM; \ + description { \ + state: "default" 0.0; \ + color: 63 67 72 255; \ + color2: 240 240 240 255; \ + color3: 240 240 240 255; \ + rel1 { \ + to: "key-bg-"key_name; \ + relative: 0.0 0.1; \ + } \ + rel2 { \ + to: "key-bg-"key_name; \ + relative: 1.0 0.4; \ + } \ + text { \ + font: "DroidSans"; \ + size: (20*SCALE); \ + align: 0.8 0.0; \ + text: key_alt; \ + } \ + } \ + } \ + part { \ + name: "key-img-hint-"key_name; \ + type: IMAGE; \ + mouse_events: 0; \ + description { \ + state: "default" 0.0; \ + min: KEY_WIDTH KEY_HEIGHT; \ + max: KEY_WIDTH KEY_HEIGHT; \ + fixed: 1 1; \ + rel1 { \ + to: "key-img-"key_name; \ + relative: 0.0 0.0; \ + offset: 0 ((-20*SCALE)-KEY_HEIGHT); \ + } \ + rel2 { \ + to: "key-img-"key_name; \ + relative: 1.0 0.0; \ + offset: 0 (-20*SCALE); \ + } \ + image { \ + normal: "key-hint.png"; \ + border: 8 8 10 10; \ + } \ + visible: 0; \ + } \ + description { \ + state: "down" 0.0; \ + inherit: "default" 0.0; \ + visible: 1; \ + } \ + } \ + part { \ + name: "key-lbl-hint-"key_name; \ + type: TEXT; \ + mouse_events: 0; \ + effect: SHADOW BOTTOM; \ + description { \ + state: "default" 0.0; \ + color: 63 67 72 255; \ + color2: 240 240 240 255; \ + color3: 240 240 240 255; \ + rel1 { \ + to: "key-img-hint-"key_name; \ + relative: 0.0 0.0; \ + } \ + rel2 { \ + to: "key-img-hint-"key_name; \ + relative: 1.0 1.0; \ + } \ + text { \ + font: "DroidSans"; \ + size: (44*SCALE); \ + text: key_low; \ + } \ + visible: 0; \ + } \ + description { \ + state: "down" 0.0; \ + inherit: "default" 0.0; \ + visible: 1; \ + } \ + } \ + programs { \ + program { \ + name: "key-mouse-in-"key_name; \ + signal: "mouse,in"; \ + source: "key-bg-"key_name; \ + script { \ + if (get_int(mouse_down) == 0) \ + return; \ + _set_key_pressed(key_name); \ + } \ + } \ + program { \ + name: "key-mouse-out-"key_name; \ + signal: "mouse,out"; \ + source: "key-bg-"key_name; \ + script { \ + if (get_int(mouse_down) == 0) \ + return; \ + _set_key_released(key_name); \ + } \ + } \ + program { \ + name: "key-mouse-down-"key_name; \ + signal: "mouse,down,1"; \ + source: "key-bg-"key_name; \ + script { \ + _set_key_pressed(key_name); \ + } \ + } \ + program { \ + name: "key-mouse-up-"key_name; \ + signal: "mouse,up,1"; \ + source: "key-bg-"key_name; \ + script { \ + if (get_int(long_press) == 0) { \ + if (get_int(shift_pressed) == 0) \ + emit("key_down", key_low); \ + else \ + emit("key_down", key_up); \ + } else { \ + if (strcmp(key_alt, " ")) \ + emit("key_down", key_alt); \ + else if (get_int(shift_pressed) == 0) \ + emit("key_down", key_low); \ + else \ + emit("key_down", key_up); \ + } \ + _set_key_released(key_name); \ + } \ + } \ + program { \ + name: "key-press-"key_name; \ + action: STATE_SET "down" 0.0; \ + target: "key-img-"key_name; \ + target: "key-img-hint-"key_name; \ + target: "key-lbl-hint-"key_name; \ + } \ + program { \ + name: "key-release-"key_name; \ + action: STATE_SET "default" 0.0; \ + transition: LINEAR 0.2; \ + target: "key-img-"key_name; \ + target: "key-img-hint-"key_name; \ + target: "key-lbl-hint-"key_name; \ + after: "shift-pressed-"key_name; \ + } \ + program { \ + name: "long-press-"key_name; \ + signal: "long_press"; \ + source: key_name; \ + script { \ + if (strcmp(key_alt, " ")) \ + set_text(PART:"key-lbl-hint-"key_name, key_alt); \ + } \ + } \ + program { \ + name: "shift-pressed-"key_name; \ + signal: "key_down"; \ + source: "shift"; \ + script { \ + if (get_int(shift_pressed) == 0) { \ + set_text(PART:"key-lbl-"key_name, key_low); \ + set_text(PART:"key-lbl-hint-"key_name, key_low); \ + } else { \ + set_text(PART:"key-lbl-"key_name, key_up); \ + set_text(PART:"key-lbl-hint-"key_name, key_up); \ + } \ + } \ + } \ + } +#define KEY_FULL(low, up, alt, x, y) SKEY_FULL(low, up, low, alt, x, y) +#define SKEY(name, text, alt, x, y) SKEY_FULL(name, name, text, alt, x, y) +#define KEY(v, alt, x, y) SKEY(v, v, alt, x, y) + + KEY_FULL("q", "Q", "1", KEY_OFFSET(0), FIRST_ROW) + KEY_FULL("w", "W", "2", KEY_OFFSET(1), FIRST_ROW) + KEY_FULL("e", "E", "3", KEY_OFFSET(2), FIRST_ROW) + KEY_FULL("r", "R", "4", KEY_OFFSET(3), FIRST_ROW) + KEY_FULL("t", "T", "5", KEY_OFFSET(4), FIRST_ROW) + KEY_FULL("y", "Y", "6", KEY_OFFSET(5), FIRST_ROW) + KEY_FULL("u", "U", "7", KEY_OFFSET(6), FIRST_ROW) + KEY_FULL("i", "I", "8", KEY_OFFSET(7), FIRST_ROW) + KEY_FULL("o", "O", "9", KEY_OFFSET(8), FIRST_ROW) + KEY_FULL("p", "P", "0", KEY_OFFSET(9), FIRST_ROW) + +#undef INIT_HSPACE +#define INIT_HSPACE (45*SCALE) +#define SECOND_ROW FIRST_ROW+KEY_HEIGHT+ROW_SPACE + + KEY_FULL("a", "A", "-", KEY_OFFSET(0), SECOND_ROW) + KEY_FULL("s", "S", "@", KEY_OFFSET(1), SECOND_ROW) + KEY_FULL("d", "D", "*", KEY_OFFSET(2), SECOND_ROW) + KEY_FULL("f", "F", "^", KEY_OFFSET(3), SECOND_ROW) + KEY_FULL("g", "G", ":", KEY_OFFSET(4), SECOND_ROW) + KEY_FULL("h", "H", ";", KEY_OFFSET(5), SECOND_ROW) + KEY_FULL("j", "J", "(", KEY_OFFSET(6), SECOND_ROW) + KEY_FULL("k", "K", ")", KEY_OFFSET(7), SECOND_ROW) + KEY_FULL("l", "L", "~", KEY_OFFSET(8), SECOND_ROW) + +#undef INIT_HSPACE +#define INIT_HSPACE (110*SCALE) +#define THIRD_ROW SECOND_ROW+KEY_HEIGHT+ROW_SPACE + + KEY_FULL("z", "Z", "/", KEY_OFFSET(0), THIRD_ROW) + KEY_FULL("x", "X", "'", KEY_OFFSET(1), THIRD_ROW) + KEY_FULL("c", "C", "\"", KEY_OFFSET(2), THIRD_ROW) + KEY_FULL("v", "V", ".", KEY_OFFSET(3), THIRD_ROW) + KEY_FULL("b", "B", ",", KEY_OFFSET(4), THIRD_ROW) + KEY_FULL("n", "N", "?", KEY_OFFSET(5), THIRD_ROW) + KEY_FULL("m", "M", "!", KEY_OFFSET(6), THIRD_ROW) + +#define KEY_SPECIAL(val, x, y, w) \ + part { \ + name: "key-img-"val; \ + type: IMAGE; \ + mouse_events: 0; \ + description { \ + state: "default" 0.0; \ + min: w KEY_HEIGHT; \ + max: w KEY_HEIGHT; \ + fixed: 1 1; \ + rel1 { \ + relative: 0.0 0.0; \ + offset: (x) (y); \ + } \ + rel2 { \ + relative: 0.0 0.0; \ + offset: (x+w-1) (y+KEY_HEIGHT-1); \ + } \ + image { \ + normal: "key-special.png"; \ + border: 8 8 10 10; \ + } \ + } \ + description { \ + state: "down" 0.0; \ + inherit: "default" 0.0; \ + rel1.offset: (x+1) (y+1); \ + rel2.offset: (x+1+w-1) (y+1+KEY_HEIGHT-1); \ + image.normal: "key-special-pressed.png"; \ + } \ + } \ + part { \ + name: "key-bg-"val; \ + type: RECT; \ + pointer_mode: NOGRAB; \ + description { \ + state: "default" 0.0; \ + rel1 { \ + to: "key-img-"val; \ + relative: 0.0 0.0; \ + offset: 3 2; \ + } \ + rel2 { \ + to: "key-img-"val; \ + relative: 1.0 1.0; \ + offset: -4 -6; \ + } \ + color: 0 0 0 0; \ + } \ + } \ + programs { \ + program { \ + name: "key-down-"val; \ + signal: "mouse,up,1"; \ + source: "key-bg-"val; \ + script { \ + emit("key_down", val); \ + run_program(PROGRAM:"key-release-"val); \ + } \ + } \ + program { \ + name: "key-mouse-in-"val; \ + signal: "mouse,in"; \ + source: "key-bg-"val; \ + script { \ + if (get_int(mouse_down) == 0) \ + return; \ + run_program(PROGRAM:"key-press-"val); \ + } \ + } \ + program { \ + name: "key-mouse-out-"val; \ + signal: "mouse,out"; \ + source: "key-bg-"val; \ + script { \ + if (get_int(mouse_down) == 0) \ + return; \ + run_program(PROGRAM:"key-release-"val); \ + } \ + } \ + program { \ + name: "key-press-"val; \ + signal: "mouse,down,1"; \ + source: "key-bg-"val; \ + action: STATE_SET "down" 0.0; \ + target: "key-img-"val; \ + target: "key-lbl-"val; \ + } \ + program { \ + name: "key-release-"val; \ + action: STATE_SET "default" 0.0; \ + transition: LINEAR 0.2; \ + target: "key-img-"val; \ + target: "key-lbl-"val; \ + } \ + } + +#define KEY_SPECIAL_TEXT(val, x, y, w) \ + KEY_SPECIAL(val, x, y, w) \ + part { \ + name: "key-lbl-"val; \ + type: TEXT; \ + mouse_events: 0; \ + effect: SHADOW BOTTOM; \ + description { \ + state: "default" 0.0; \ + color: 63 67 72 255; \ + color2: 240 240 240 255; \ + color3: 240 240 240 255; \ + rel1 { \ + to: "key-bg-"val; \ + relative: 0.0 0.4; \ + } \ + rel2 { \ + to: "key-bg-"val; \ + relative: 1.0 1.0; \ + } \ + text { \ + font: "DroidSans"; \ + size: (28*SCALE); \ + text: val; \ + } \ + } \ + } + +#define KEY_SPECIAL_ICON(val, x, y, w, icon_size) \ + KEY_SPECIAL(val, x, y, w) \ + part { \ + name: "key-lbl-"val; \ + type: IMAGE; \ + mouse_events: 0; \ + description { \ + state: "default" 0.0; \ + min: icon_size icon_size; \ + max: icon_size icon_size; \ + fixed: 1 1; \ + rel1 { \ + to: "key-bg-"val; \ + relative: 0.5 0.4; \ + } \ + rel2 { \ + to: "key-bg-"val; \ + relative: 0.5 0.8; \ + } \ + image.normal: "icon-"val".png"; \ + } \ + } \ + +#define FOURTH_ROW THIRD_ROW+KEY_HEIGHT+ROW_SPACE + KEY_SPECIAL_TEXT("?123", (5*SCALE), FOURTH_ROW, (95*SCALE)) + + part { + name: "key-img-shift"; + type: IMAGE; + mouse_events: 0; + description { + state: "default" 0.0; + min: (85*SCALE) KEY_HEIGHT; + max: (85*SCALE) KEY_HEIGHT; + fixed: 1 1; + rel1 { + relative: 0.0 0.0; + offset: (5*SCALE) (THIRD_ROW); + } + rel2 { + relative: 0.0 0.0; + offset: (((5+85)*SCALE)-1) (THIRD_ROW+KEY_HEIGHT-1); + } + image { + normal: "key-special.png"; + border: 8 8 10 10; + } + } + description { + state: "down" 0.0; + inherit: "default" 0.0; + rel1.offset: ((5*SCALE)+2) (THIRD_ROW+2); + rel2.offset: ((((5+85)*SCALE)+2)-1) (THIRD_ROW+2+KEY_HEIGHT-1); + image.normal: "key-special-pressed.png"; + } + } + part { + name: "key-bg-shift"; + type: RECT; + pointer_mode: NOGRAB; + description { + state: "default" 0.0; + rel1 { + to: "key-img-shift"; + relative: 0.0 0.0; + offset: 3 2; + } + rel2 { + to: "key-img-shift"; + relative: 1.0 1.0; + offset: -4 -6; + } + color: 0 0 0 0; + } + } + part { + name: "key-lbl-shift"; + type: IMAGE; + mouse_events: 0; + description { + state: "default" 0.0; + max: (50*SCALE) (50*SCALE); + min: (50*SCALE) (50*SCALE); + fixed: 1 1; + rel1 { + to: "key-bg-shift"; + relative: 0.5 0.4; + } + rel2 { + to: "key-bg-shift"; + relative: 0.5 0.8; + } + image.normal: "icon-shift.png"; + } + description { + state: "down" 0.0; + inherit: "default" 0.0; + image.normal: "icon-shift-active.png"; + } + } + programs { + program { + name: "key-press-shift"; + signal: "mouse,down,1"; + source: "key-bg-shift"; + action: STATE_SET "down" 0.0; + target: "key-img-shift"; + target: "key-lbl-shift"; + } + program { + name: "key-release-shift"; + action: STATE_SET "default" 0.0; + transition: LINEAR 0.2; + target: "key-img-shift"; + target: "key-lbl-shift"; + } + program { + name: "key-mouse-in-shift"; + signal: "mouse,in"; + source: "key-bg-shift"; + script { + if (get_int(mouse_down) == 0) + return; + run_program(PROGRAM:"key-press-shift"); + } + } + program { + name: "key-mouse-out-shift"; + signal: "mouse,out"; + source: "key-bg-shift"; + script { + if (get_int(mouse_down) == 0) + return; + run_program(PROGRAM:"key-release-shift"); + } + } + program { + name: "key-down-shift"; + signal: "mouse,up,1"; + source: "key-bg-shift"; + script { + emit("key_down", "shift"); + if (get_int(shift_pressed) == 0) { + run_program(PROGRAM:"key-press-shift"); + set_int(shift_pressed, 1); + } else { + run_program(PROGRAM:"key-release-shift"); + set_int(shift_pressed, 0); + } + } + } + } + } + } + + group { + name: "special-1"; + + MOUSE_DOWN_UP_PROGRAMS + parts { +#undef INIT_HSPACE +#define INIT_HSPACE 5 + + KEY("1", "#", KEY_OFFSET(0), FIRST_ROW) + KEY("2", "&", KEY_OFFSET(1), FIRST_ROW) + KEY("3", "%", KEY_OFFSET(2), FIRST_ROW) + KEY("4", "+", KEY_OFFSET(3), FIRST_ROW) + KEY("5", "=", KEY_OFFSET(4), FIRST_ROW) + KEY("6", "_", KEY_OFFSET(5), FIRST_ROW) + KEY("7", "\\", KEY_OFFSET(6), FIRST_ROW) + KEY("8", "|", KEY_OFFSET(7), FIRST_ROW) + KEY("9", "<", KEY_OFFSET(8), FIRST_ROW) + KEY("0", ">", KEY_OFFSET(9), FIRST_ROW) + +#undef INIT_HSPACE +#define INIT_HSPACE (45*SCALE) + + SKEY("-", "dash", "{", KEY_OFFSET(0), SECOND_ROW) + SKEY("@", "at", "}", KEY_OFFSET(1), SECOND_ROW) + SKEY("*", "star", "[", KEY_OFFSET(2), SECOND_ROW) + SKEY("^", "circumflex", "]", KEY_OFFSET(3), SECOND_ROW) + SKEY(":", "colon", "$", KEY_OFFSET(4), SECOND_ROW) + SKEY(";", "semi_colon", "£", KEY_OFFSET(5), SECOND_ROW) + SKEY("(", "open_par", "Â¥", KEY_OFFSET(6), SECOND_ROW) + SKEY(")", "close_par", "€", KEY_OFFSET(7), SECOND_ROW) + SKEY("~", "tilde", "₩", KEY_OFFSET(8), SECOND_ROW) + +#undef INIT_HSPACE +#define INIT_HSPACE (110*SCALE) + + SKEY("/", "slash", "¢", KEY_OFFSET(0), THIRD_ROW) + SKEY("'", "single_quote", "`", KEY_OFFSET(1), THIRD_ROW) + SKEY("\"", "double_quote", "°", KEY_OFFSET(2), THIRD_ROW) + SKEY(".", "dot", "˙", KEY_OFFSET(3), THIRD_ROW) + SKEY(",", "comma", "®", KEY_OFFSET(4), THIRD_ROW) + SKEY("?", "question", "©", KEY_OFFSET(5), THIRD_ROW) + SKEY("!", "exclamation", "¿", KEY_OFFSET(6), THIRD_ROW) + + KEY_SPECIAL_TEXT("1/2", (5*SCALE), THIRD_ROW, (85*SCALE)) + KEY_SPECIAL_TEXT("abc", (5*SCALE), FOURTH_ROW, (95*SCALE)) + } + } + + group { + name: "special-2"; + + MOUSE_DOWN_UP_PROGRAMS + parts { +#undef INIT_HSPACE +#define INIT_HSPACE 5 + + SKEY("#", "hash", "1", KEY_OFFSET(0), FIRST_ROW) + SKEY("&", "amp", "2", KEY_OFFSET(1), FIRST_ROW) + SKEY("%", "percent", "3", KEY_OFFSET(2), FIRST_ROW) + SKEY("+", "plus", "4", KEY_OFFSET(3), FIRST_ROW) + SKEY("=", "equal", "5", KEY_OFFSET(4), FIRST_ROW) + SKEY("_", "underline", "6", KEY_OFFSET(5), FIRST_ROW) + SKEY("\\", "backslash", "7", KEY_OFFSET(6), FIRST_ROW) + SKEY("|", "vert_bar", "8", KEY_OFFSET(7), FIRST_ROW) + SKEY("<", "less", "9", KEY_OFFSET(8), FIRST_ROW) + SKEY(">", "greater", "0", KEY_OFFSET(9), FIRST_ROW) + +#undef INIT_HSPACE +#define INIT_HSPACE (45*SCALE) + + SKEY("{", "open_brace", "-", KEY_OFFSET(0), SECOND_ROW) + SKEY("}", "close_brace", "@", KEY_OFFSET(1), SECOND_ROW) + SKEY("[", "open_bracket", "*", KEY_OFFSET(2), SECOND_ROW) + SKEY("]", "close_bracket", "^", KEY_OFFSET(3), SECOND_ROW) + SKEY("$", "dollar", ":", KEY_OFFSET(4), SECOND_ROW) + SKEY("£", "pound", ";", KEY_OFFSET(5), SECOND_ROW) + SKEY("Â¥", "yen", "(", KEY_OFFSET(6), SECOND_ROW) + SKEY("€", "euro", ")", KEY_OFFSET(7), SECOND_ROW) + SKEY("₩", "won", "~", KEY_OFFSET(8), SECOND_ROW) + +#undef INIT_HSPACE +#define INIT_HSPACE (110*SCALE) + + SKEY("¢", "cent" , "/", KEY_OFFSET(0), THIRD_ROW) + SKEY("`", "back_quote", "'", KEY_OFFSET(1), THIRD_ROW) + SKEY("°", "ring", "\"", KEY_OFFSET(2), THIRD_ROW) + SKEY("˙", "dot", ".", KEY_OFFSET(3), THIRD_ROW) + SKEY("®", "registered", ",", KEY_OFFSET(4), THIRD_ROW) + SKEY("©", "copyright", "?", KEY_OFFSET(5), THIRD_ROW) + SKEY("¿", "inv_question", "!", KEY_OFFSET(6), THIRD_ROW) + + KEY_SPECIAL_TEXT("2/2", (5*SCALE), THIRD_ROW, (85*SCALE)) + KEY_SPECIAL_TEXT("abc", (5*SCALE), FOURTH_ROW, (95*SCALE)) + } + } + + group { + name: "fixed"; + + script { + public mouse_down = 0; + } + + programs { + program { + name: "mouse-down"; + signal: "mouse,down,1"; + source: "*"; + script { + set_int(mouse_down, 1); + } + } + program { + name: "mouse-up"; + signal: "mouse,up,1"; + source: "*"; + script { + set_int(mouse_down, 0); + } + } + } + + parts { + KEY_SPECIAL_ICON("backspace", (620*SCALE), THIRD_ROW, (85*SCALE), (60*SCALE)) + KEY_SPECIAL_ICON("enter", (610*SCALE), FOURTH_ROW, (95*SCALE), (60*SCALE)) + +#undef INIT_HSPACE +#define INIT_HSPACE (120*SCALE) + /*KEY_SPECIAL_ICON("space", (KEY_OFFSET(0)), FOURTH_ROW, (KEY_OFFSET(5)), 82);*/ + KEY_SPECIAL_ICON("space", KEY_OFFSET(0), FOURTH_ROW, KEY_OFFSET(5), (64*SCALE)); + } + } + + group { + name: "numeric"; + MOUSE_DOWN_UP_PROGRAMS + + parts { +#undef KEY_WIDTH +#define KEY_WIDTH (200*SCALE) +#undef KEY_HEIGHT +#define KEY_HEIGHT NUMERIC_KEY_HEIGHT +#undef INIT_HSPACE +#define INIT_HSPACE (45*SCALE) +#undef ROW_SPACE +#define ROW_SPACE (10*SCALE) +#undef COL_SPACE +#define COL_SPACE (10*SCALE) + KEY("1", " ", KEY_OFFSET(0), FIRST_ROW) + KEY("2", " ", KEY_OFFSET(1), FIRST_ROW) + KEY("3", " ", KEY_OFFSET(2), FIRST_ROW) + + KEY("4", " ", KEY_OFFSET(0), SECOND_ROW) + KEY("5", " ", KEY_OFFSET(1), SECOND_ROW) + KEY("6", " ", KEY_OFFSET(2), SECOND_ROW) + + KEY("7", " ", KEY_OFFSET(0), THIRD_ROW) + KEY("8", " ", KEY_OFFSET(1), THIRD_ROW) + KEY("9", " ", KEY_OFFSET(2), THIRD_ROW) + + KEY_SPECIAL_ICON("backspace", KEY_OFFSET(0), FOURTH_ROW, KEY_WIDTH, (50*SCALE)) + KEY("0", " ", KEY_OFFSET(1), FOURTH_ROW) + KEY_SPECIAL_ICON("enter", KEY_OFFSET(2), FOURTH_ROW, KEY_WIDTH, (60*SCALE)) + + } + } +} diff --git a/data/themes/default/default_600.edc b/data/themes/default/default_600.edc new file mode 100644 index 0000000..b5ef5e4 --- /dev/null +++ b/data/themes/default/default_600.edc @@ -0,0 +1,26 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define SCALE 0.83 + +#define MIN_WIDTH 600 +#define MAX_WIDTH 1024 +#define MIN_HEIGHT 480 +#define MAX_HEIGHT 480 + +#define NUMERIC_KEY_HEIGHT 80 + +#include "default.edc" diff --git a/data/themes/default/default_720.edc b/data/themes/default/default_720.edc new file mode 100644 index 0000000..476f405 --- /dev/null +++ b/data/themes/default/default_720.edc @@ -0,0 +1,26 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define SCALE 1.0 + +#define MIN_WIDTH 720 +#define MAX_WIDTH 1280 +#define MIN_HEIGHT 600 +#define MAX_HEIGHT 600 + +#define NUMERIC_KEY_HEIGHT 100 + +#include "default.edc" diff --git a/data/themes/default/fonts/DroidSans-Bold.ttf b/data/themes/default/fonts/DroidSans-Bold.ttf new file mode 100644 index 0000000..942bbf5 Binary files /dev/null and b/data/themes/default/fonts/DroidSans-Bold.ttf differ diff --git a/data/themes/default/fonts/DroidSans.ttf b/data/themes/default/fonts/DroidSans.ttf new file mode 100644 index 0000000..efd1f8b Binary files /dev/null and b/data/themes/default/fonts/DroidSans.ttf differ diff --git a/data/themes/default/fonts/LICENSE.txt b/data/themes/default/fonts/LICENSE.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/data/themes/default/fonts/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/data/themes/default/ignorekeys.txt b/data/themes/default/ignorekeys.txt new file mode 100644 index 0000000..875ddfa --- /dev/null +++ b/data/themes/default/ignorekeys.txt @@ -0,0 +1,5 @@ +shift +abc +?123 +1/2 +2/2 diff --git a/data/themes/default/images/icon-backspace.png b/data/themes/default/images/icon-backspace.png new file mode 100644 index 0000000..32a1c3f Binary files /dev/null and b/data/themes/default/images/icon-backspace.png differ diff --git a/data/themes/default/images/icon-enter.png b/data/themes/default/images/icon-enter.png new file mode 100644 index 0000000..66b2d4d Binary files /dev/null and b/data/themes/default/images/icon-enter.png differ diff --git a/data/themes/default/images/icon-language.png b/data/themes/default/images/icon-language.png new file mode 100644 index 0000000..d3d754b Binary files /dev/null and b/data/themes/default/images/icon-language.png differ diff --git a/data/themes/default/images/icon-shift-active.png b/data/themes/default/images/icon-shift-active.png new file mode 100644 index 0000000..17a91c4 Binary files /dev/null and b/data/themes/default/images/icon-shift-active.png differ diff --git a/data/themes/default/images/icon-shift.png b/data/themes/default/images/icon-shift.png new file mode 100644 index 0000000..b59d6a2 Binary files /dev/null and b/data/themes/default/images/icon-shift.png differ diff --git a/data/themes/default/images/icon-space.png b/data/themes/default/images/icon-space.png new file mode 100644 index 0000000..b1b5bd3 Binary files /dev/null and b/data/themes/default/images/icon-space.png differ diff --git a/data/themes/default/images/key-default-pressed.png b/data/themes/default/images/key-default-pressed.png new file mode 100644 index 0000000..bcc0f7d Binary files /dev/null and b/data/themes/default/images/key-default-pressed.png differ diff --git a/data/themes/default/images/key-default.png b/data/themes/default/images/key-default.png new file mode 100644 index 0000000..a4f5ba2 Binary files /dev/null and b/data/themes/default/images/key-default.png differ diff --git a/data/themes/default/images/key-hint-bg.png b/data/themes/default/images/key-hint-bg.png new file mode 100644 index 0000000..b72b876 Binary files /dev/null and b/data/themes/default/images/key-hint-bg.png differ diff --git a/data/themes/default/images/key-hint.png b/data/themes/default/images/key-hint.png new file mode 100644 index 0000000..d051c98 Binary files /dev/null and b/data/themes/default/images/key-hint.png differ diff --git a/data/themes/default/images/key-special-pressed.png b/data/themes/default/images/key-special-pressed.png new file mode 100644 index 0000000..ae0a76c Binary files /dev/null and b/data/themes/default/images/key-special-pressed.png differ diff --git a/data/themes/default/images/key-special.png b/data/themes/default/images/key-special.png new file mode 100644 index 0000000..1cf53fe Binary files /dev/null and b/data/themes/default/images/key-special.png differ diff --git a/protocol/Makefile.am b/protocol/Makefile.am new file mode 100644 index 0000000..7642946 --- /dev/null +++ b/protocol/Makefile.am @@ -0,0 +1,3 @@ +EXTRA_DIST = \ + input-method.xml \ + text.xml diff --git a/protocol/input-method.xml b/protocol/input-method.xml new file mode 100644 index 0000000..5666e7b --- /dev/null +++ b/protocol/input-method.xml @@ -0,0 +1,283 @@ + + + + Copyright © 2012, 2013 Intel Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + + + Corresponds to a text model on input method side. An input method context + is created on text mode activation on the input method side. It allows to + receive information about the text model from the application via events. + Input method contexts do not keep state after deactivation and should be + destroyed after deactivation is handled. + + Text is generally UTF-8 encoded, indices and lengths are in bytes. + + Serials are used to synchronize the state between the text input and + an input method. New serials are sent by the text input in the + commit_state request and are used by the input method to indicate + the known text input state in events like preedit_string, commit_string, + and keysym. The text input can then ignore events from the input method + which are based on an outdated state (for example after a reset). + + + + + Send the commit string text for insertion to the application. + + The text to commit could be either just a single character after a key + press or the result of some composing (pre-edit). It could be also an + empty text when some text should be removed (see + delete_surrounding_text) or when the input cursor should be moved (see + cursor_position). + + Any previously set composing text will be removed. + + + + + + + Send the pre-edit string text to the application text input. + + The commit text can be used to replace the preedit text on reset (for + example on unfocus). + + Also previously sent preedit_style and preedit_cursor requests are + processed bt the text_input also. + + + + + + + + Sets styling information on composing text. The style is applied for + length in bytes from index relative to the beginning of + the composing text (as byte offset). Multiple styles can + be applied to a composing text. + + This request should be sent before sending preedit_string request. + + + + + + + + Sets the cursor position inside the composing text (as byte offset) + relative to the start of the composing text. + + When index is negative no cursor should be displayed. + + This request should be sent before sending preedit_string request. + + + + + + + + This request will be handled on text_input side as part of a directly + following commit_string request. + + + + + + + Sets the cursor and anchor to a new position. Index is the new cursor + position in bytess (when >= 0 relative to the end of inserted text + else relative to beginning of inserted text). Anchor is the new anchor + position in bytes (when >= 0 relative to the end of inserted text, else + relative to beginning of inserted text). When there should be no + selected text anchor should be the same as index. + + This request will be handled on text_input side as part of a directly + following commit_string request. + + + + + + + + + + Notify when a key event was sent. Key events should not be used for + normal text input operations, which should be done with commit_string, + delete_surrounfing_text, etc. The key event follows the wl_keyboard key + event convention. Sym is a XKB keysym, state a wl_keyboard key_state. + + + + + + + + + + Allows an input method to receive hardware keyboard input and process + key events to generate text events (with pre-edit) over the wire. This + allows input methods which compose multiple key events for inputting + text like it is done for CJK languages. + + + + + + Should be used when filtering key events with grab_keyboard. + + When the wl_keyboard::key event is not processed by the input + method itself and should be sent to the client instead, forward it + with this request. The arguments should be the ones from the + wl_keyboard::key event. + + For generating custom key events use the keysym request instead. + + + + + + + + + Should be used when filtering key events with grab_keyboard. + + When the wl_keyboard::modifiers event should be also send to the + client, forward it with this request. The arguments should be the ones + from the wl_keyboard::modifiers event. + + + + + + + + + + + + + + + + + + The plain surrounding text around the input position. Cursor is the + position in bytes within the surrounding text relative to the beginning + of the text. Anchor is the position in bytes of the selection anchor + within the surrounding text relative to the beginning of the text. If + there is no selected text anchor is the same as cursor. + + + + + + + + + + + + + + + + + + + + + + + + + + An input method object is responsible to compose text in response to + input from hardware or virtual keyboards. There is one input method + object per seat. On activate there is a new input method context object + created which allows the input method to communicate with the text model. + + + + A text model was activated. Creates an input method context object + which allows communication with the text model. + + + + + + The text model corresponding to the context argument was deactivated. + The input method context should be destroyed after deactivation is + handled. + + + + + + + + Only one client can bind this interface at a time. + + + + + + + + + + + + + + + + A keybaord surface is only shown, when a text model is active + + + + + + + + An overlay panel is shown near the input cursor above the application + window hwne a text model is active. + + + + + + Notify when the cursor rectangle relative to the input panel surface change. + + + + + + + + diff --git a/protocol/text.xml b/protocol/text.xml new file mode 100644 index 0000000..7cd3a4d --- /dev/null +++ b/protocol/text.xml @@ -0,0 +1,346 @@ + + + + + Copyright © 2012, 2013 Intel Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + + An object used for text input. Adds support for text input and input + methods to applications. A text-input object is created from a + wl_text_input_manager and corresponds typically to a text entry in an + application. + Requests are used to activate/deactivate the text-input object and set + state information like surrounding and selected text or the content type. + The information about entered text is sent to the text-input object via + the pre-edit and commit events. Using this interface removes the need + for applications to directly process hardware key events and compose text + out of them. + + Text is generally UTF-8 encoded, indices and lengths are in bytes. + + Serials are used to synchronize the state between the text input and + an input method. New serials are sent by the text input in the + commit_state request and are used by the input method to indicate + the known text input state in events like preedit_string, commit_string, + and keysym. The text input can then ignore events from the input method + which are based on an outdated state (for example after a reset). + + + + Requests the text-input object to be activated (typically when the + text entry gets focus). + The seat argument is a wl_seat which maintains the focus for this + activation. The surface argument is a wl_surface assigned to the + text-input object and tracked for focus lost. The enter event + is emitted on successful activation. + + + + + + + Requests the text-input object to be deactivated (typically when the + text entry lost focus). The seat argument is a wl_seat which was used + for activation. + + + + + + Requests input panels (virtual keyboard) to show. + + + + + Requests input panels (virtual keyboard) to hide. + + + + + Should be called by an editor widget when the input state should be + reset, for example after the text was changed outside of the normal + input method flow. + + + + + Sets the plain surrounding text around the input position. Text is + UTF-8 encoded. Cursor is the byte offset within the + surrounding text. Anchor is the byte offset of the + selection anchor within the surrounding text. If there is no selected + text anchor is the same as cursor. + + + + + + + + Content hint is a bitmask to allow to modify the behavior of the text + input. + + + + + + + + + + + + + + + + + + The content purpose allows to specify the primary purpose of a text + input. + + This allows an input method to show special purpose input panels with + extra characters or to disallow some characters. + + + + + + + + + + + + + + + + + + Sets the content purpose and content hint. While the purpose is the + basic purpose of an input field, the hint flags allow to modify some + of the behavior. + + When no content type is explicitly set, a normal content purpose with + default hints (auto completion, auto correction, auto capitalization) + should be assumed. + + + + + + + + + + + + + Sets a specific language. This allows for example a virtual keyboard to + show a language specific layout. The "language" argument is a RFC-3066 + format language tag. + + It could be used for example in a word processor to indicate language of + currently edited document or in an instant message application which tracks + languages of contacts. + + + + + + + + + + + + + Notify the text-input object when it received focus. Typically in + response to an activate request. + + + + + + Notify the text-input object when it lost focus. Either in response + to a deactivate request or when the assigned surface lost focus or was + destroyed. + + + + + Transfer an array of 0-terminated modifiers names. The position in + the array is the index of the modifier as used in the modifiers + bitmask in the keysym event. + + + + + + Notify when the visibility state of the input panel changed. + + + + + + Notify when a new composing text (pre-edit) should be set around the + current cursor position. Any previously set composing text should + be removed. + + The commit text can be used to replace the preedit text on reset + (for example on unfocus). + + The text input should also handle all preedit_style and preedit_cursor + events occuring directly before preedit_string. + + + + + + + + + + + + + + + + + + Sets styling information on composing text. The style is applied for + length bytes from index relative to the beginning of the composing + text (as byte offset). Multiple styles can + be applied to a composing text by sending multiple preedit_styling + events. + + This event is handled as part of a following preedit_string event. + + + + + + + + Sets the cursor position inside the composing text (as byte + offset) relative to the start of the composing text. When index is a + negative number no cursor is shown. + + This event is handled as part of a following preedit_string event. + + + + + + Notify when text should be inserted into the editor widget. The text to + commit could be either just a single character after a key press or the + result of some composing (pre-edit). It could be also an empty text + when some text should be removed (see delete_surrounding_text) or when + the input cursor should be moved (see cursor_position). + + Any previously set composing text should be removed. + + + + + + + Notify when the cursor or anchor position should be modified. + + This event should be handled as part of a following commit_string + event. + + + + + + + Notify when the text around the current cursor position should be + deleted. + + Index is relative to the current cursor (in bytes). + Length is the length of deleted text (in bytes). + + This event should be handled as part of a following commit_string + event. + + + + + + + Notify when a key event was sent. Key events should not be used + for normal text input operations, which should be done with + commit_string, delete_surrounding_text, etc. The key event follows + the wl_keyboard key event convention. Sym is a XKB keysym, state a + wl_keyboard key_state. Modifiers are a mask for effective modifiers + (where the modifier indices are set by the modifiers_map event) + + + + + + + + + + Sets the language of the input text. The "language" argument is a RFC-3066 + format language tag. + + + + + + + + + + + + Sets the text direction of input text. + + It is mainly needed for showing input cursor on correct side of the + editor when there is no input yet done and making sure neutral + direction text is laid out properly. + + + + + + + + + A factory for text-input objects. This object is a global singleton. + + + + Creates a new text-input object. + + + + + 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 +#include + +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 +#include +#include +#include + +#include +#include + +#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; +} + +/* + * + * + * [ 'Control+space', 'Zenkaku_Hankaku', 'Alt+Kanji', 'Alt+grave', 'Hangul', 'Alt+Release+Alt_R' ] + * Trigger shortcut keys + * The shortcut keys for turning input method on or off + * + * + * [ '<Super>space' ] + * Trigger shortcut keys for gtk_accelerator_parse + * The shortcut keys for turning input method on or off + * + * + * [] + * Enable shortcut keys + * The shortcut keys for turning input method on + * + * + * [] + * Disable shortcut keys + * The shortcut keys for turning input method off + * + * + * [ 'Alt+Shift_L' ] + * Next engine shortcut keys + * The shortcut keys for switching to the next input method in the list + * + * + * [ 'Alt+Shift_L' ] + * Next engine shortcut keys + * The shortcut keys for switching to the next input method in the list + * + * + * [] + * Prev engine shortcut keys + * The shortcut keys for switching to the previous input method + * + * + * [] + * Prev engine shortcut keys + * The shortcut keys for switching to the previous input method + * + * + */ +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[] = { "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; +} + +/* + * + * + * [] + * Preload engines + * Preload engines during ibus starts up + * + * + * [] + * Engines order + * Saved engines order in input method list + * + * + * 400 + * Popup delay milliseconds for IME switcher window + * 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 + * + * + * '' + * Saved version number + * 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. + * + * + * false + * Use system keyboard layout + * Use system keyboard (XKB) layout + * + * + * true + * Embed Preedit Text + * Embed Preedit Text in Application Window + * + * + * false + * Use global input method + * Share the same input method among all applications + * + * + * false + * Enable input method by default + * Enable input method by default when the application gets input focus + * + * + * [ '/desktop/ibus/engine/pinyin', '/desktop/ibus/engine/bopomofo', '/desktop/ibus/engine/hangul' ] + * DConf preserve name prefixes + * Prefixes of DConf keys to stop name conversion + * + * + * + */ +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; +} + +/* + * + * + * 0 + * Auto hide + * The behavior of language panel. 0 = Embedded in menu, 1 = Auto hide, 2 = Always show + * + * + * -1 + * Language panel position + * + * + * -1 + * Language panel position + * + * + * 1 + * Orientation of lookup table + * Orientation of lookup table. 0 = Horizontal, 1 = Vertical + * + * + * true + * Show icon on system tray + * Show icon on system tray + * + * + * false + * Show input method name + * Show input method name on language bar + * + * + * false + * Use custom font + * Use custom font name for language panel + * + * + * 'Sans 10' + * Custom font + * Custom font name for language panel + * + * + */ +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; +} + +/* + * + * + * + * + */ +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 +#include + +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 +#include +#include + +#include + +#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 +#include +#include + +#include + +#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 + +#include +#include + +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 +#include +#include +#include + +#include +#include + +#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 +#include + +#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 +#include +#include +#include +#include + +#include +#include +#include +#include + +#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; +}