Initial commit
authorEduardo Lima (Etrunko) <eduardo.lima@intel.com>
Fri, 16 Aug 2013 20:08:23 +0000 (17:08 -0300)
committerEduardo Lima (Etrunko) <eduardo.lima@intel.com>
Fri, 16 Aug 2013 20:08:23 +0000 (17:08 -0300)
Signed-off-by: Eduardo Lima (Etrunko) <eduardo.lima@intel.com>
42 files changed:
.gitignore [new file with mode: 0644]
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
README [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
data/.gitignore [new file with mode: 0644]
data/themes/Makefile.am [new file with mode: 0644]
data/themes/default/default.edc [new file with mode: 0644]
data/themes/default/default_600.edc [new file with mode: 0644]
data/themes/default/default_720.edc [new file with mode: 0644]
data/themes/default/fonts/DroidSans-Bold.ttf [new file with mode: 0644]
data/themes/default/fonts/DroidSans.ttf [new file with mode: 0644]
data/themes/default/fonts/LICENSE.txt [new file with mode: 0644]
data/themes/default/ignorekeys.txt [new file with mode: 0644]
data/themes/default/images/icon-backspace.png [new file with mode: 0644]
data/themes/default/images/icon-enter.png [new file with mode: 0644]
data/themes/default/images/icon-language.png [new file with mode: 0644]
data/themes/default/images/icon-shift-active.png [new file with mode: 0644]
data/themes/default/images/icon-shift.png [new file with mode: 0644]
data/themes/default/images/icon-space.png [new file with mode: 0644]
data/themes/default/images/key-default-pressed.png [new file with mode: 0644]
data/themes/default/images/key-default.png [new file with mode: 0644]
data/themes/default/images/key-hint-bg.png [new file with mode: 0644]
data/themes/default/images/key-hint.png [new file with mode: 0644]
data/themes/default/images/key-special-pressed.png [new file with mode: 0644]
data/themes/default/images/key-special.png [new file with mode: 0644]
protocol/Makefile.am [new file with mode: 0644]
protocol/input-method.xml [new file with mode: 0644]
protocol/text.xml [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/wkb-ibus-config-eet-test.c [new file with mode: 0644]
src/wkb-ibus-config-eet.c [new file with mode: 0644]
src/wkb-ibus-config-eet.h [new file with mode: 0644]
src/wkb-ibus-config.c [new file with mode: 0644]
src/wkb-ibus-panel.c [new file with mode: 0644]
src/wkb-ibus-test.c [new file with mode: 0644]
src/wkb-ibus.c [new file with mode: 0644]
src/wkb-ibus.h [new file with mode: 0644]
src/wkb-main.c [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..d005cda
--- /dev/null
@@ -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 (file)
index 0000000..5e00638
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Eduardo Lima (Etrunko) <eduardo.lima@intel.com>
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
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 (file)
index 0000000..e69de29
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..3cdce98
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..916169a
--- /dev/null
@@ -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 (file)
index 0000000..e114d0d
--- /dev/null
@@ -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 (file)
index 0000000..2f69ae5
--- /dev/null
@@ -0,0 +1 @@
+*.edj
diff --git a/data/themes/Makefile.am b/data/themes/Makefile.am
new file mode 100644 (file)
index 0000000..fd143f5
--- /dev/null
@@ -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 (file)
index 0000000..7275787
--- /dev/null
@@ -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 (file)
index 0000000..b5ef5e4
--- /dev/null
@@ -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 (file)
index 0000000..476f405
--- /dev/null
@@ -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 (file)
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 (file)
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 (file)
index 0000000..d645695
--- /dev/null
@@ -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 (file)
index 0000000..875ddfa
--- /dev/null
@@ -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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
index 0000000..7642946
--- /dev/null
@@ -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 (file)
index 0000000..5666e7b
--- /dev/null
@@ -0,0 +1,283 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="input_method">
+  <copyright>
+    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.
+  </copyright>
+
+
+  <interface name="wl_input_method_context" version="1">
+    <description summary="input method context">
+      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).
+    </description>
+    <request name="destroy" type="destructor"/>
+    <request name="commit_string">
+      <description summary="commit string">
+        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.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
+      <arg name="text" type="string"/>
+    </request>
+    <request name="preedit_string">
+      <description summary="pre-edit string">
+        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.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
+      <arg name="text" type="string"/>
+      <arg name="commit" type="string"/>
+    </request>
+    <request name="preedit_styling">
+      <description summary="pre-edit styling">
+        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.
+      </description>
+      <arg name="index" type="uint"/>
+      <arg name="length" type="uint"/>
+      <arg name="style" type="uint"/>
+    </request>
+    <request name="preedit_cursor">
+      <description summary="pre-edit cursor">
+        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.
+      </description>
+      <arg name="index" type="int"/>
+    </request>
+    <request name="delete_surrounding_text">
+      <description summary="delete text">
+
+
+        This request will be handled on text_input side as part of a directly
+        following commit_string request.
+      </description>
+      <arg name="index" type="int"/>
+      <arg name="length" type="uint"/>
+    </request>
+    <request name="cursor_position">
+      <description summary="set cursor to a new position">
+        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.
+      </description>
+      <arg name="index" type="int"/>
+      <arg name="anchor" type="int"/>
+    </request>
+    <request name="modifiers_map">
+      <arg name="map" type="array"/>
+    </request>
+    <request name="keysym">
+      <description summary="keysym">
+        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.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
+      <arg name="time" type="uint"/>
+      <arg name="sym" type="uint"/>
+      <arg name="state" type="uint"/>
+      <arg name="modifiers" type="uint"/>
+    </request>
+    <request name="grab_keyboard">
+      <description summary="grab hardware keyboard">
+        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.
+      </description>
+       <arg name="keyboard" type="new_id" interface="wl_keyboard"/>
+    </request>
+    <request name="key">
+      <description summary="forward key event">
+        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.
+      </description>
+      <arg name="serial" type="uint" summary="serial from wl_keyboard::key"/>
+      <arg name="time" type="uint" summary="time from wl_keyboard::key"/>
+      <arg name="key" type="uint" summary="key from wl_keyboard::key"/>
+      <arg name="state" type="uint" summary="state from wl_keyboard::key"/>
+    </request>
+    <request name="modifiers">
+      <description summary="forward modifiers event">
+        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.
+      </description>
+      <arg name="serial" type="uint" summary="serial from wl_keyboard::modifiers"/>
+      <arg name="mods_depressed" type="uint" summary="mods_depressed from wl_keyboard::modifiers"/>
+      <arg name="mods_latched" type="uint" summary="mods_latched from wl_keyboard::modifiers"/>
+      <arg name="mods_locked" type="uint" summary="mods_locked from wl_keyboard::modifiers"/>
+      <arg name="group" type="uint" summary="group from wl_keyboard::modifiers"/>
+    </request>
+    <request name="language">
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
+      <arg name="language" type="string"/>
+    </request>
+    <request name="text_direction">
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
+      <arg name="direction" type="uint"/>
+    </request>
+    <event name="surrounding_text">
+      <description summary="surrounding text 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.
+      </description>
+      <arg name="text" type="string"/>
+      <arg name="cursor" type="uint"/>
+      <arg name="anchor" type="uint"/>
+    </event>
+    <event name="reset">
+    </event>
+    <event name="content_type">
+      <arg name="hint" type="uint"/>
+      <arg name="purpose" type="uint"/>
+    </event>
+    <event name="invoke_action">
+      <arg name="button" type="uint"/>
+      <arg name="index" type="uint"/>
+    </event>
+    <event name="commit_state">
+      <arg name="serial" type="uint" summary="serial of text input state"/>
+    </event>
+    <event name="preferred_language">
+      <arg name="language" type="string"/>
+    </event>
+  </interface>
+
+  <interface name="wl_input_method" version="1">
+    <description summary="input method">
+      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.
+    </description>
+    <event name="activate">
+      <description summary="activate event">
+        A text model was activated. Creates an input method context object
+        which allows communication with the text model.
+      </description>
+      <arg name="id" type="new_id" interface="wl_input_method_context"/>
+    </event>
+    <event name="deactivate">
+      <description summary="activate event">
+        The text model corresponding to the context argument was deactivated.
+        The input method context should be destroyed after deactivation is
+        handled.
+      </description>
+      <arg name="context" type="object" interface="wl_input_method_context"/>
+    </event>
+  </interface>
+
+  <interface name="wl_input_panel" version="1">
+    <description summary="interface for implementing keyboards">
+      Only one client can bind this interface at a time.
+    </description>
+
+    <request name="get_input_panel_surface">
+      <arg name="id" type="new_id" interface="wl_input_panel_surface"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </request>
+  </interface>
+
+  <interface name="wl_input_panel_surface" version="1">
+    <enum name="position">
+      <entry name="center_bottom" value="0"/>
+    </enum>
+
+    <request name="set_toplevel">
+      <description summary="set the surface type as a keyboard">
+       A keybaord surface is only shown, when a text model is active
+      </description>
+      <arg name="output" type="object" interface="wl_output"/>
+      <arg name="position" type="uint"/>
+    </request>
+
+    <request name="set_overlay_panel">
+      <description summary="set the surface type as an overlay panel">
+        An overlay panel is shown near the input cursor above the application
+        window hwne a text model is active.
+      </description>
+    </request>
+
+    <event name="cursor_rectangle">
+      <description summary="cursor rectangle">
+        Notify when the cursor rectangle relative to the input panel surface change.
+      </description>
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </event>
+  </interface>
+</protocol>
diff --git a/protocol/text.xml b/protocol/text.xml
new file mode 100644 (file)
index 0000000..7cd3a4d
--- /dev/null
@@ -0,0 +1,346 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="text">
+
+  <copyright>
+    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.
+  </copyright>
+
+  <interface name="wl_text_input" version="1">
+    <description summary="text input">
+      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).
+    </description>
+    <request name="activate">
+      <description summary="request activation">
+        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.
+      </description>
+      <arg name="seat" type="object" interface="wl_seat"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </request>
+    <request name="deactivate">
+      <description summary="request deactivation">
+        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.
+      </description>
+      <arg name="seat" type="object" interface="wl_seat"/>
+    </request>
+    <request name="show_input_panel">
+      <description summary="show input panels">
+        Requests input panels (virtual keyboard) to show.
+      </description>
+    </request>
+    <request name="hide_input_panel">
+      <description summary="hide input panels">
+        Requests input panels (virtual keyboard) to hide.
+      </description>
+    </request>
+    <request name="reset">
+      <description summary="reset">
+        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.
+      </description>
+    </request>
+    <request name="set_surrounding_text">
+      <description summary="sets the surrounding text">
+        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.
+      </description>
+      <arg name="text" type="string"/>
+      <arg name="cursor" type="uint"/>
+      <arg name="anchor" type="uint"/>
+    </request>
+    <enum name="content_hint">
+      <description summary="content hint">
+        Content hint is a bitmask to allow to modify the behavior of the text
+        input.
+      </description>
+      <entry name="none" value="0x0" summary="no special behaviour"/>
+      <entry name="default" value="0x7" summary="auto completion, correction and capitalization"/>
+      <entry name="password" value="0xc0" summary="hidden and sensitive text"/>
+      <entry name="auto_completion" value="0x1" summary="suggest word completions"/>
+      <entry name="auto_correction" value="0x2" summary="suggest word corrections"/>
+      <entry name="auto_capitalization" value="0x4" summary="switch to uppercase letters at the start of a sentence"/>
+      <entry name="lowercase" value="0x8" summary="prefer lowercase letters"/>
+      <entry name="uppercase" value="0x10" summary="prefer uppercase letters"/>
+      <entry name="titlecase" value="0x20" summary="prefer casing for titles and headings (can be language dependent)"/>
+      <entry name="hidden_text" value="0x40" summary="characters should be hidden"/>
+      <entry name="sensitive_data" value="0x80" summary="typed text should not be stored"/>
+      <entry name="latin" value="0x100" summary="just latin characters should be entered"/>
+      <entry name="multiline" value="0x200" summary="the text input is multiline"/>
+    </enum>
+    <enum name="content_purpose">
+      <description summary="content purpose">
+        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.
+      </description>
+      <entry name="normal" value="0" summary="default input, allowing all characters"/>
+      <entry name="alpha" value="1" summary="allow only alphabetic characters"/>
+      <entry name="digits" value="2" summary="allow only digits"/>
+      <entry name="number" value="3" summary="input a number (including decimal separator and sign)"/>
+      <entry name="phone" value="4" summary="input a phone number"/>
+      <entry name="url" value="5" summary="input an URL"/>
+      <entry name="email" value="6" summary="input an email address"/>
+      <entry name="name" value="7" summary="input a name of a person"/>
+      <entry name="password" value="8" summary="input a password (combine with password or sensitive_data hint)"/>
+      <entry name="date" value="9" summary="input a date"/>
+      <entry name="time" value="10" summary="input a time"/>
+      <entry name="datetime" value="11" summary="input a date and time"/>
+      <entry name="terminal" value="12" summary="input for a terminal"/>
+    </enum>
+    <request name="set_content_type">
+      <description summary="set content purpose and hint">
+        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.
+      </description>
+      <arg name="hint" type="uint"/>
+      <arg name="purpose" type="uint"/>
+    </request>
+    <request name="set_cursor_rectangle">
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+    <request name="set_preferred_language">
+      <description summary="sets preferred language">
+        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.
+      </description>
+      <arg name="language" type="string"/>
+    </request>
+    <request name="commit_state">
+      <arg name="serial" type="uint" summary="used to identify the known state"/>
+    </request>
+    <request name="invoke_action">
+      <arg name="button" type="uint"/>
+      <arg name="index" type="uint"/>
+    </request>
+    <event name="enter">
+      <description summary="enter event">
+        Notify the text-input object when it received focus. Typically in
+        response to an activate request.
+      </description>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </event>
+    <event name="leave">
+      <description summary="leave event">
+        Notify the text-input object when it lost focus. Either in response
+        to a deactivate request or when the assigned surface lost focus or was
+        destroyed.
+      </description>
+    </event>
+    <event name="modifiers_map">
+      <description summary="modifiers map">
+        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.
+      </description>
+      <arg name="map" type="array"/>
+    </event>
+    <event name="input_panel_state">
+      <description summary="state of the input panel">
+        Notify when the visibility state of the input panel changed.
+      </description>
+      <arg name="state" type="uint"/>
+    </event>
+    <event name="preedit_string">
+      <description summary="pre-edit">
+        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.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
+      <arg name="text" type="string"/>
+      <arg name="commit" type="string"/>
+    </event>
+    <enum name="preedit_style">
+      <entry name="default" value="0" summary="default style for composing text"/>
+      <entry name="none" value="1" summary="style should be the same as in non-composing text"/>
+      <entry name="active" value="2"/>
+      <entry name="inactive" value="3"/>
+      <entry name="highlight" value="4"/>
+      <entry name="underline" value="5"/>
+      <entry name="selection" value="6"/>
+      <entry name="incorrect" value="7"/>
+    </enum>
+    <event name="preedit_styling">
+      <description summary="pre-edit styling">
+        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.
+      </description>
+      <arg name="index" type="uint"/>
+      <arg name="length" type="uint"/>
+      <arg name="style" type="uint"/>
+    </event>
+    <event name="preedit_cursor">
+      <description summary="pre-edit cursor">
+        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.
+      </description>
+      <arg name="index" type="int"/>
+    </event>
+    <event name="commit_string">
+      <description summary="commit">
+        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.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
+      <arg name="text" type="string"/>
+    </event>
+    <event name="cursor_position">
+      <description summary="set cursor to new position">
+        Notify when the cursor or anchor position should be modified.
+
+        This event should be handled as part of a following commit_string
+        event.
+      </description>
+      <arg name="index" type="int"/>
+      <arg name="anchor" type="int"/>
+    </event>
+    <event name="delete_surrounding_text">
+      <description summary="delete surrounding text">
+        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.
+      </description>
+      <arg name="index" type="int"/>
+      <arg name="length" type="uint"/>
+    </event>
+    <event name="keysym">
+      <description summary="keysym">
+        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)
+      </description>
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
+      <arg name="time" type="uint"/>
+      <arg name="sym" type="uint"/>
+      <arg name="state" type="uint"/>
+      <arg name="modifiers" type="uint"/>
+    </event>
+    <event name="language">
+      <description summary="language">
+        Sets the language of the input text. The "language" argument is a RFC-3066
+        format language tag.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
+      <arg name="language" type="string"/>
+    </event>
+    <enum name="text_direction">
+      <entry name="auto" value="0" summary="automatic text direction based on text and language"/>
+      <entry name="ltr" value="1" summary="left-to-right"/>
+      <entry name="rtl" value="2" summary="right-to-left"/>
+    </enum>
+    <event name="text_direction">
+      <description summary="text direction">
+        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.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
+      <arg name="direction" type="uint"/>
+    </event>
+  </interface>
+
+  <interface name="wl_text_input_manager" version="1">
+    <description summary="text input manager">
+      A factory for text-input objects. This object is a global singleton.
+    </description>
+    <request name="create_text_input">
+      <description summary="create text input">
+        Creates a new text-input object.
+      </description>
+      <arg name="id" type="new_id" interface="wl_text_input"/>
+    </request>
+  </interface>
+</protocol>
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..5d53bff
--- /dev/null
@@ -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 (file)
index 0000000..a4f0ced
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "wkb-ibus-config-eet.h"
+
+#include <Eina.h>
+#include <Eet.h>
+
+int
+main (int argc, char *argv[])
+{
+   struct wkb_ibus_config_eet *cfg;
+
+   if (!eina_init())
+     {
+        printf("Error initializing eina");
+        return 1;
+     }
+
+   if (!eet_init())
+     {
+        printf("Error initializing eet");
+        return 1;
+     }
+
+   cfg = wkb_ibus_config_eet_new("ibus-cfg.eet");
+   wkb_ibus_config_eet_free(cfg);
+
+   eet_shutdown();
+   eina_shutdown();
+
+   return 0;
+}
diff --git a/src/wkb-ibus-config-eet.c b/src/wkb-ibus-config-eet.c
new file mode 100644 (file)
index 0000000..ad9bc5e
--- /dev/null
@@ -0,0 +1,962 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the eetific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <Eina.h>
+#include <Eet.h>
+
+#include "wkb-ibus-config-eet.h"
+
+/*
+ * Base struct for all config types
+ */
+struct _config_section
+{
+   const char *id;
+
+   void (*free)(struct _config_section *);
+   void (*set_defaults)(struct _config_section *);
+   Eina_Bool (*set_value)(struct _config_section *, const char *, const char *, Eldbus_Message_Iter *);
+   void *(*get_value)(struct _config_section *, const char *, const char *);
+   void *(*get_values)(struct _config_section *, const char *);
+};
+
+static void
+_config_section_free(struct _config_section *base)
+{
+   eina_stringshare_del(base->id);
+   base->free(base);
+}
+
+static void
+_config_section_set_defaults(struct _config_section *base)
+{
+   base->set_defaults(base);
+}
+
+static Eina_Bool
+_config_section_set_value(struct _config_section *base, const char *section, const char *name, Eldbus_Message_Iter *value)
+{
+   return base->set_value(base, section, name, value);
+}
+
+static void *
+_config_section_get_value(struct _config_section *base, const char *section, const char *name)
+{
+   return base->get_value(base, section, name);
+}
+
+static void *
+_config_section_get_values(struct _config_section *base, const char *section)
+{
+   return base->get_values(base, section);
+}
+
+/*
+ * Helpers for manipulating list of strings
+ */
+static void
+_config_string_list_free(Eina_List *list)
+{
+   const char *str;
+
+   EINA_LIST_FREE(list, str)
+      eina_stringshare_del(str);
+
+   eina_list_free(list);
+}
+
+static Eina_List *
+_config_string_list_new(const char **strs)
+{
+   Eina_List *list = NULL;
+   const char *str;
+
+   for (str = *strs; str != NULL; str = *++strs)
+      list = eina_list_append(list, eina_stringshare_add(str));
+
+   return list;
+}
+
+/*
+ * <schema path="/desktop/ibus/general/hotkey/" id="org.freedesktop.ibus.general.hotkey">
+ *   <key type="as" name="trigger">
+ *     <default>[ 'Control+space', 'Zenkaku_Hankaku', 'Alt+Kanji', 'Alt+grave', 'Hangul', 'Alt+Release+Alt_R' ]</default>
+ *     <summary>Trigger shortcut keys</summary>
+ *     <description>The shortcut keys for turning input method on or off</description>
+ *   </key>
+ *   <key type="as" name="triggers">
+ *     <default>[ '&lt;Super&gt;space' ]</default>
+ *     <summary>Trigger shortcut keys for gtk_accelerator_parse</summary>
+ *     <description>The shortcut keys for turning input method on or off</description>
+ *   </key>
+ *   <key type="as" name="enable-unconditional">
+ *     <default>[]</default>
+ *     <summary>Enable shortcut keys</summary>
+ *     <description>The shortcut keys for turning input method on</description>
+ *   </key>
+ *   <key type="as" name="disable-unconditional">
+ *     <default>[]</default>
+ *     <summary>Disable shortcut keys</summary>
+ *     <description>The shortcut keys for turning input method off</description>
+ *   </key>
+ *   <key type="as" name="next-engine">
+ *     <default>[ 'Alt+Shift_L' ]</default>
+ *     <summary>Next engine shortcut keys</summary>
+ *     <description>The shortcut keys for switching to the next input method in the list</description>
+ *   </key>
+ *   <key type="as" name="next-engine-in-menu">
+ *     <default>[ 'Alt+Shift_L' ]</default>
+ *     <summary>Next engine shortcut keys</summary>
+ *     <description>The shortcut keys for switching to the next input method in the list</description>
+ *   </key>
+ *   <key type="as" name="prev-engine">
+ *     <default>[]</default>
+ *     <summary>Prev engine shortcut keys</summary>
+ *     <description>The shortcut keys for switching to the previous input method</description>
+ *   </key>
+ *   <key type="as" name="previous-engine">
+ *     <default>[]</default>
+ *     <summary>Prev engine shortcut keys</summary>
+ *     <description>The shortcut keys for switching to the previous input method</description>
+ *   </key>
+ * </schema>
+ */
+struct _config_hotkey
+{
+   struct _config_section base;
+
+   Eina_List *trigger;
+   Eina_List *triggers;
+   Eina_List *enable_unconditional;
+   Eina_List *disable_unconditional;
+   Eina_List *next_engine;
+   Eina_List *next_engine_in_menu;
+   Eina_List *prev_engine;
+   Eina_List *previous_engine;
+};
+
+static Eet_Data_Descriptor *
+_config_hotkey_edd_new(void)
+{
+   Eet_Data_Descriptor *edd;
+   Eet_Data_Descriptor_Class eddc;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, struct _config_hotkey);
+   edd = eet_data_descriptor_stream_new(&eddc);
+
+   EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "trigger", trigger);
+   EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "triggers", triggers);
+   EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "enable-unconditional", enable_unconditional);
+   EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "disable-unconditional", disable_unconditional);
+   EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "next-engine", next_engine);
+   EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "next-engine-in-menu", next_engine_in_menu);
+   EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "prev-engine", prev_engine);
+   EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "previous-engine", previous_engine);
+
+   return edd;
+}
+
+static void
+_config_hotkey_set_defaults(struct _config_section *base)
+{
+   struct _config_hotkey *hotkey = (struct _config_hotkey *) base;
+
+   const char *trigger[] = { "Control+space", "Zenkaku_Hankaku", "Alt+Kanji", "Alt+grave", "Hangul", "Alt+Release+Alt_R", NULL };
+   const char *triggers[] = { "<Super>space", NULL };
+   const char *enable_unconditional[] = { NULL };
+   const char *disable_unconditional[] = { NULL };
+   const char *next_engine[] = { NULL };
+   const char *next_engine_in_menu[] = { NULL };
+   const char *prev_engine[] = { NULL };
+   const char *previous_engine[] = { NULL };
+
+   hotkey->trigger = _config_string_list_new(trigger);
+   hotkey->triggers = _config_string_list_new(triggers);
+   hotkey->enable_unconditional = _config_string_list_new(enable_unconditional);
+   hotkey->disable_unconditional = _config_string_list_new(disable_unconditional);
+   hotkey->next_engine = _config_string_list_new(next_engine);
+   hotkey->next_engine_in_menu = _config_string_list_new(next_engine_in_menu);
+   hotkey->prev_engine = _config_string_list_new(prev_engine);
+   hotkey->previous_engine = _config_string_list_new(previous_engine);
+}
+
+static void
+_config_hotkey_free(struct _config_section *base)
+{
+   struct _config_hotkey *hotkey = (struct _config_hotkey *) base;
+
+   _config_string_list_free(hotkey->trigger);
+   _config_string_list_free(hotkey->triggers);
+   _config_string_list_free(hotkey->enable_unconditional);
+   _config_string_list_free(hotkey->disable_unconditional);
+   _config_string_list_free(hotkey->next_engine);
+   _config_string_list_free(hotkey->next_engine_in_menu);
+   _config_string_list_free(hotkey->prev_engine);
+   _config_string_list_free(hotkey->previous_engine);
+
+   free(hotkey);
+}
+
+static Eina_Bool
+_config_hotkey_set_value(struct _config_section *base, const char *section, const char *name, Eldbus_Message_Iter *value)
+{
+   return EINA_FALSE;
+}
+
+static void *
+_config_hotkey_get_value(struct _config_section *base, const char *section, const char *name)
+{
+   return NULL;
+}
+
+static void *
+_config_hotkey_get_values(struct _config_section *base, const char *section)
+{
+   return NULL;
+}
+
+static void
+_config_hotkey_section_init(struct _config_section *base)
+{
+   base->id = eina_stringshare_add("hotkey");
+   base->free = _config_hotkey_free;
+   base->set_defaults = _config_hotkey_set_defaults;
+   base->set_value = _config_hotkey_set_value;
+   base->get_value = _config_hotkey_get_value;
+   base->get_values = _config_hotkey_get_values;
+}
+
+static struct _config_section *
+_config_hotkey_new(void)
+{
+   struct _config_hotkey *conf = calloc(1, sizeof(*conf));
+   _config_hotkey_section_init((struct _config_section *) conf);
+   return (struct _config_section *) conf;
+}
+
+/*
+ * <schema path="/desktop/ibus/general/" id="org.freedesktop.ibus.general">
+ *    <key type="as" name="preload-engines">
+ *      <default>[]</default>
+ *      <summary>Preload engines</summary>
+ *      <description>Preload engines during ibus starts up</description>
+ *    </key>
+ *    <key type="as" name="engines-order">
+ *      <default>[]</default>
+ *      <summary>Engines order</summary>
+ *      <description>Saved engines order in input method list</description>
+ *    </key>
+ *    <key type="i" name="switcher-delay-time">
+ *      <default>400</default>
+ *      <summary>Popup delay milliseconds for IME switcher window</summary>
+ *      <description>Set popup delay milliseconds to show IME switcher window. The default is 400. 0 = Show the window immediately. 0 &lt; Delay milliseconds. 0 &gt; Do not show the
+ *    </key>
+ *    <key type="s" name="version">
+ *      <default>''</default>
+ *      <summary>Saved version number</summary>
+ *      <description>The saved version number will be used to check the difference between the version of the previous installed ibus and one of the current ibus.</description>
+ *    </key>
+ *    <key type="b" name="use-system-keyboard-layout">
+ *      <default>false</default>
+ *      <summary>Use system keyboard layout</summary>
+ *      <description>Use system keyboard (XKB) layout</description>
+ *    </key>
+ *    <key type="b" name="embed-preedit-text">
+ *      <default>true</default>
+ *      <summary>Embed Preedit Text</summary>
+ *      <description>Embed Preedit Text in Application Window</description>
+ *    </key>
+ *    <key type="b" name="use-global-engine">
+ *      <default>false</default>
+ *      <summary>Use global input method</summary>
+ *     <description>Share the same input method among all applications</description>
+ *    </key>
+ *    <key type="b" name="enable-by-default">
+ *      <default>false</default>
+ *      <summary>Enable input method by default</summary>
+ *      <description>Enable input method by default when the application gets input focus</description>
+ *    </key>
+ *    <key type="as" name="dconf-preserve-name-prefixes">
+ *      <default>[ '/desktop/ibus/engine/pinyin', '/desktop/ibus/engine/bopomofo', '/desktop/ibus/engine/hangul' ]</default>
+ *      <summary>DConf preserve name prefixes</summary>
+ *      <description>Prefixes of DConf keys to stop name conversion</description>
+ *    </key>
+ *    <child schema="org.freedesktop.ibus.general.hotkey" name="hotkey"/>
+ * </schema>
+ */
+struct _config_general
+{
+   struct _config_section base;
+
+   struct _config_section *hotkey;
+
+   Eina_List *preload_engines;
+   Eina_List *engines_order;
+   Eina_List *dconf_preserve_name_prefixes;
+
+   const char *version;
+
+   int switcher_delay_time;
+
+   Eina_Bool use_system_keyboard_layout;
+   Eina_Bool embed_preedit_text;
+   Eina_Bool use_global_engine;
+   Eina_Bool enable_by_default;
+};
+
+static Eet_Data_Descriptor *
+_config_general_edd_new(Eet_Data_Descriptor *hotkey_edd)
+{
+   Eet_Data_Descriptor *edd;
+   Eet_Data_Descriptor_Class eddc;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, struct _config_general);
+   edd = eet_data_descriptor_stream_new(&eddc);
+
+   EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_general, "preload-engines", preload_engines);
+   EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_general, "engines-order", engines_order);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_general, "switcher-delay-time", switcher_delay_time, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_general, "version", version, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_general, "use-system-keyboard-layout", use_system_keyboard_layout, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_general, "embed-preedit-text", embed_preedit_text, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_general, "use-global-engine", use_global_engine, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_general, "enable-by-default", enable_by_default, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_general, "dconf-preserve-name-prefixes", dconf_preserve_name_prefixes);
+   EET_DATA_DESCRIPTOR_ADD_SUB(edd, struct _config_general, "hotkey", hotkey, hotkey_edd);
+
+   return edd;
+}
+
+static void
+_config_general_set_defaults(struct _config_section *base)
+{
+   struct _config_general *general = (struct _config_general *) base;
+
+   const char *preload_engines[] = { NULL };
+   const char *engines_order[] = { NULL };
+   const char *dconf_preserve_name_prefixes[] = { "/desktop/ibus/engine/pinyin", "/desktop/ibus/engine/bopomofo", "/desktop/ibus/engine/hangul", NULL };
+
+   _config_section_set_defaults(general->hotkey);
+
+   general->preload_engines = _config_string_list_new(preload_engines);
+   general->engines_order = _config_string_list_new(engines_order);
+   general->switcher_delay_time = 400;
+   general->version = eina_stringshare_add("");
+   general->use_system_keyboard_layout = EINA_FALSE;
+   general->embed_preedit_text = EINA_TRUE;
+   general->use_global_engine = EINA_FALSE;
+   general->enable_by_default = EINA_FALSE;
+   general->dconf_preserve_name_prefixes = _config_string_list_new(dconf_preserve_name_prefixes);
+
+}
+
+static void
+_config_general_free(struct _config_section *base)
+{
+   struct _config_general *general = (struct _config_general *) base;
+
+   _config_section_free(general->hotkey);
+
+   _config_string_list_free(general->preload_engines);
+   _config_string_list_free(general->engines_order);
+   _config_string_list_free(general->dconf_preserve_name_prefixes);
+
+   eina_stringshare_del(general->version);
+   free(general);
+}
+
+static Eina_Bool
+_config_general_set_value(struct _config_section *base, const char *section, const char *name, Eldbus_Message_Iter *value)
+{
+   return EINA_FALSE;
+}
+
+static void *
+_config_general_get_value(struct _config_section *base, const char *section, const char *name)
+{
+   return NULL;
+}
+
+static void *
+_config_general_get_values(struct _config_section *base, const char *section)
+{
+   return NULL;
+}
+
+static void
+_config_general_section_init(struct _config_section *base)
+{
+   struct _config_general *general = (struct _config_general *) base;
+
+   base->id = eina_stringshare_add("general");
+   base->free = _config_general_free;
+   base->set_defaults = _config_general_set_defaults;
+   base->set_value = _config_general_set_value;
+   base->get_value = _config_general_get_value;
+   base->get_values = _config_general_get_values;
+
+   if (general->hotkey)
+      _config_hotkey_section_init(general->hotkey);
+}
+
+static struct _config_section *
+_config_general_new(void)
+{
+   struct _config_general *conf = calloc(1, sizeof(*conf));
+   _config_general_section_init((struct _config_section *) conf);
+   conf->hotkey = _config_hotkey_new();
+   return (struct _config_section *) conf;
+}
+
+/*
+ * <schema path="/desktop/ibus/panel/" id="org.freedesktop.ibus.panel">
+ *    <key type="i" name="show">
+ *      <default>0</default>
+ *      <summary>Auto hide</summary>
+ *      <description>The behavior of language panel. 0 = Embedded in menu, 1 = Auto hide, 2 = Always show</description>
+ *    </key>
+ *    <key type="i" name="x">
+ *      <default>-1</default>
+ *      <summary>Language panel position</summary>
+ *    </key>
+ *    <key type="i" name="y">
+ *      <default>-1</default>
+ *      <summary>Language panel position</summary>
+ *    </key>
+ *    <key type="i" name="lookup-table-orientation">
+ *      <default>1</default>
+ *      <summary>Orientation of lookup table</summary>
+ *      <description>Orientation of lookup table. 0 = Horizontal, 1 = Vertical</description>
+ *    </key>
+ *    <key type="b" name="show-icon-on-systray">
+ *      <default>true</default>
+ *      <summary>Show icon on system tray</summary>
+ *      <description>Show icon on system tray</description>
+ *    </key>
+ *    <key type="b" name="show-im-name">
+ *      <default>false</default>
+ *      <summary>Show input method name</summary>
+ *      <description>Show input method name on language bar</description>
+ *    </key>
+ *    <key type="b" name="use-custom-font">
+ *      <default>false</default>
+ *      <summary>Use custom font</summary>
+ *      <description>Use custom font name for language panel</description>
+ *    </key>
+ *    <key type="s" name="custom-font">
+ *      <default>'Sans 10'</default>
+ *      <summary>Custom font</summary>
+ *      <description>Custom font name for language panel</description>
+ *    </key>
+ * </schema>
+ */
+struct _config_panel
+{
+   struct _config_section base;
+
+   const char *custom_font;
+   int show;
+   int x;
+   int y;
+   int lookup_table_orientation;
+   Eina_Bool show_icon_in_systray;
+   Eina_Bool show_im_name;
+   Eina_Bool use_custom_font;
+};
+
+static Eet_Data_Descriptor *
+_config_panel_edd_new(void)
+{
+   Eet_Data_Descriptor *edd;
+   Eet_Data_Descriptor_Class eddc;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, struct _config_panel);
+   edd = eet_data_descriptor_stream_new(&eddc);
+
+   EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "show", show, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "x", x, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "y", y, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "lookup-table-orientation", lookup_table_orientation, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "show-icon-in-systray", show_icon_in_systray, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "show-im-name", show_im_name, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "use-custom-font", use_custom_font, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "custom-font", custom_font, EET_T_STRING);
+
+   return edd;
+}
+
+static void
+_config_panel_set_defaults(struct _config_section *base)
+{
+   struct _config_panel *panel = (struct _config_panel *) base;
+
+   panel->show = 0;
+   panel->x = -1;
+   panel->y = -1;
+   panel->lookup_table_orientation = 1;
+   panel->show_icon_in_systray = EINA_TRUE;
+   panel->show_im_name = EINA_FALSE;
+   panel->use_custom_font = EINA_FALSE;
+   panel->custom_font = eina_stringshare_add("Sans 10");
+}
+
+static void
+_config_panel_free(struct _config_section *base)
+{
+   struct _config_panel *panel = (struct _config_panel *) base;
+
+   eina_stringshare_del(panel->custom_font);
+   free(panel);
+}
+
+static Eina_Bool
+_config_panel_set_value(struct _config_section *base, const char *section, const char *name, Eldbus_Message_Iter *value)
+{
+   return EINA_FALSE;
+}
+
+static void *
+_config_panel_get_value(struct _config_section *base, const char *section, const char *name)
+{
+   return NULL;
+}
+
+static void *
+_config_panel_get_values(struct _config_section *base, const char *section)
+{
+   return NULL;
+}
+
+static void
+_config_panel_section_init(struct _config_section *base)
+{
+   base->id = eina_stringshare_add("panel");
+   base->free = _config_panel_free;
+   base->set_defaults = _config_panel_set_defaults;
+   base->set_value = _config_panel_set_value;
+   base->get_value = _config_panel_get_value;
+   base->get_values = _config_panel_get_values;
+}
+
+static struct _config_section *
+_config_panel_new(void)
+{
+   struct _config_panel *conf = calloc(1, sizeof(*conf));
+   _config_panel_section_init((struct _config_section *) conf);
+   return (struct _config_section *) conf;
+}
+
+/*
+ * NO SCHEMA AVAILABLE. BASED ON THE SOURCE CODE
+ */
+struct _config_hangul
+{
+   struct _config_section base;
+
+   const char *hangul_keyboard;
+   Eina_List *hanja_keys;
+   Eina_Bool word_commit;
+   Eina_Bool auto_reorder;
+};
+
+static Eet_Data_Descriptor *
+_config_hangul_edd_new(void)
+{
+   Eet_Data_Descriptor *edd;
+   Eet_Data_Descriptor_Class eddc;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, struct _config_hangul);
+   edd = eet_data_descriptor_stream_new(&eddc);
+
+   EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_hangul, "HangulKeyboard", hangul_keyboard, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hangul, "HanjaKeys", hanja_keys);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_hangul, "WordCommit", word_commit, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_hangul, "AutoReorder", auto_reorder, EET_T_UCHAR);
+
+   return edd;
+}
+
+static void
+_config_hangul_set_defaults(struct _config_section *base)
+{
+   struct _config_hangul *hangul = (struct _config_hangul *) base;
+   const char *hanja_keys[] = { "Hangul_Hanja", "F9", NULL };
+
+   hangul->hangul_keyboard = eina_stringshare_add("2");
+   hangul->hanja_keys = _config_string_list_new(hanja_keys);
+   hangul->word_commit = EINA_FALSE;
+   hangul->auto_reorder = EINA_TRUE;
+}
+
+static void
+_config_hangul_free(struct _config_section *base)
+{
+   struct _config_hangul *hangul = (struct _config_hangul *) base;
+
+   eina_stringshare_del(hangul->hangul_keyboard);
+   _config_string_list_free(hangul->hanja_keys);
+   free(hangul);
+}
+
+static Eina_Bool
+_config_hangul_set_value(struct _config_section *base, const char *section, const char *name, Eldbus_Message_Iter *value)
+{
+   return EINA_FALSE;
+}
+
+static void *
+_config_hangul_get_value(struct _config_section *base, const char *section, const char *name)
+{
+   return NULL;
+}
+
+static void *
+_config_hangul_get_values(struct _config_section *base, const char *section)
+{
+   return NULL;
+}
+
+static void
+_config_hangul_section_init(struct _config_section *base)
+{
+   base->id = eina_stringshare_add("hangul");
+   base->free = _config_hangul_free;
+   base->set_defaults = _config_hangul_set_defaults;
+   base->set_value = _config_hangul_set_value;
+   base->get_value = _config_hangul_get_value;
+   base->get_values = _config_hangul_get_values;
+}
+
+static struct _config_section *
+_config_hangul_new(void)
+{
+   struct _config_hangul *conf = calloc(1, sizeof(*conf));
+   _config_hangul_section_init((struct _config_section *) conf);
+   return (struct _config_section *) conf;
+}
+
+/*
+ * NO SCHEMA AVAILABLE. BASED ON THE SOURCE CODE
+ */
+struct _config_engine
+{
+   struct _config_section base;
+
+   struct _config_section *hangul;
+};
+
+static Eet_Data_Descriptor *
+_config_engine_edd_new(Eet_Data_Descriptor *hangul_edd)
+{
+   Eet_Data_Descriptor *edd;
+   Eet_Data_Descriptor_Class eddc;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, struct _config_engine);
+   edd = eet_data_descriptor_stream_new(&eddc);
+
+   EET_DATA_DESCRIPTOR_ADD_SUB(edd, struct _config_engine, "Hangul", hangul, hangul_edd);
+
+   return edd;
+}
+
+static void
+_config_engine_set_defaults(struct _config_section *base)
+{
+   struct _config_engine *engine = (struct _config_engine *) base;
+
+   _config_section_set_defaults(engine->hangul);
+}
+
+static void
+_config_engine_free(struct _config_section *base)
+{
+   struct _config_engine *engine = (struct _config_engine *) base;
+
+   _config_section_free(engine->hangul);
+   free(engine);
+}
+
+static Eina_Bool
+_config_engine_set_value(struct _config_section *base, const char *section, const char *name, Eldbus_Message_Iter *value)
+{
+   return EINA_FALSE;
+}
+
+static void *
+_config_engine_get_value(struct _config_section *base, const char *section, const char *name)
+{
+   return NULL;
+}
+
+static void *
+_config_engine_get_values(struct _config_section *base, const char *section)
+{
+   return NULL;
+}
+
+static void
+_config_engine_section_init(struct _config_section *base)
+{
+   struct _config_engine *engine = (struct _config_engine *) base;
+
+   base->id = eina_stringshare_add("engine");
+   base->free = _config_engine_free;
+   base->set_defaults = _config_engine_set_defaults;
+   base->set_value = _config_engine_set_value;
+   base->get_value = _config_engine_get_value;
+   base->get_values = _config_engine_get_values;
+
+   if (engine->hangul)
+      _config_hangul_section_init(engine->hangul);
+}
+
+static struct _config_section *
+_config_engine_new(void)
+{
+   struct _config_engine *conf = calloc(1, sizeof(*conf));
+   _config_engine_section_init((struct _config_section *) conf);
+   conf->hangul = _config_hangul_new();
+   return (struct _config_section *) conf;
+}
+
+/*
+ * <schema path="/desktop/ibus/" id="org.freedesktop.ibus">
+ *    <child schema="org.freedesktop.ibus.general" name="general"/>
+ *    <child schema="org.freedesktop.ibus.panel" name="panel"/>
+ * </schema>
+ */
+struct _config_ibus
+{
+   struct _config_section base;
+
+   struct _config_section *general;
+   struct _config_section *panel;
+   struct _config_section *engine;
+};
+
+static Eet_Data_Descriptor *
+_config_ibus_edd_new(Eet_Data_Descriptor *general_edd, Eet_Data_Descriptor *panel_edd, Eet_Data_Descriptor *engine_edd)
+{
+   Eet_Data_Descriptor *edd;
+   Eet_Data_Descriptor_Class eddc;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, struct _config_ibus);
+   edd = eet_data_descriptor_stream_new(&eddc);
+
+   EET_DATA_DESCRIPTOR_ADD_SUB(edd, struct _config_ibus, "general", general, general_edd);
+   EET_DATA_DESCRIPTOR_ADD_SUB(edd, struct _config_ibus, "panel", panel, panel_edd);
+   EET_DATA_DESCRIPTOR_ADD_SUB(edd, struct _config_ibus, "engine", engine, engine_edd);
+
+   return edd;
+}
+
+static void
+_config_ibus_set_defaults(struct _config_section *base)
+{
+   struct _config_ibus *ibus = (struct _config_ibus *) base;
+
+   _config_section_set_defaults(ibus->general);
+   _config_section_set_defaults(ibus->panel);
+   _config_section_set_defaults(ibus->engine);
+}
+
+static void
+_config_ibus_free(struct _config_section *base)
+{
+   struct _config_ibus *ibus = (struct _config_ibus *) base;
+
+   _config_section_free(ibus->general);
+   _config_section_free(ibus->panel);
+   _config_section_free(ibus->engine);
+
+   free(ibus);
+}
+
+static Eina_Bool
+_config_ibus_set_value(struct _config_section *base, const char *section, const char *name, Eldbus_Message_Iter *value)
+{
+   return EINA_FALSE;
+}
+
+static void *
+_config_ibus_get_value(struct _config_section *base, const char *section, const char *name)
+{
+   return NULL;
+}
+
+static void *
+_config_ibus_get_values(struct _config_section *base, const char *section)
+{
+   return NULL;
+}
+
+static void
+_config_ibus_section_init(struct _config_section *base)
+{
+   struct _config_ibus *ibus = (struct _config_ibus *) base;
+   base->id = eina_stringshare_add("ibus");
+   base->free = _config_ibus_free;
+   base->set_defaults = _config_ibus_set_defaults;
+   base->set_value = _config_ibus_set_value;
+   base->get_value = _config_ibus_get_value;
+   base->get_values = _config_ibus_get_values;
+
+   if (ibus->general)
+      _config_general_section_init(ibus->general);
+
+   if (ibus->panel)
+      _config_panel_section_init(ibus->panel);
+
+   if (ibus->engine)
+      _config_engine_section_init(ibus->engine);
+}
+
+static struct _config_section *
+_config_ibus_new(void)
+{
+   struct _config_ibus *conf = calloc(1, sizeof(*conf));
+   _config_ibus_section_init((struct _config_section *) conf);
+   conf->general = _config_general_new();
+   conf->panel = _config_panel_new();
+   conf->engine = _config_engine_new();
+   return (struct _config_section *) conf;
+}
+
+/*
+ * MAIN
+ */
+struct wkb_ibus_config_eet
+{
+   const char *path;
+   struct _config_section *ibus_config;
+
+   Eet_Data_Descriptor *hotkey_edd;
+   Eet_Data_Descriptor *general_edd;
+   Eet_Data_Descriptor *panel_edd;
+   Eet_Data_Descriptor *hangul_edd;
+   Eet_Data_Descriptor *engine_edd;
+   Eet_Data_Descriptor *ibus_edd;
+};
+
+Eina_Bool
+wkb_ibus_config_eet_set_value(struct wkb_ibus_config_eet *config_eet, const char *section, const char *name, Eldbus_Message_Iter *value)
+{
+   return _config_section_set_value(config_eet->ibus_config, section, name, value);
+}
+
+void *
+wkb_ibus_config_eet_get_value(struct wkb_ibus_config_eet *config_eet, const char *section, const char *name)
+{
+   return _config_section_get_value(config_eet->ibus_config, section, name);
+}
+
+void *
+wkb_ibus_config_eet_get_values(struct wkb_ibus_config_eet *config_eet, const char *section)
+{
+   return _config_section_get_values(config_eet->ibus_config, section);
+}
+
+void
+wkb_ibus_config_eet_set_defaults(struct wkb_ibus_config_eet *config_eet)
+{
+
+   if (config_eet->ibus_config)
+      _config_section_free(config_eet->ibus_config);
+
+   config_eet->ibus_config = _config_ibus_new();
+   _config_ibus_set_defaults(config_eet->ibus_config);
+}
+
+static struct wkb_ibus_config_eet *
+_config_eet_section_init(const char *path)
+{
+   struct wkb_ibus_config_eet *eet = calloc(1, sizeof(*eet));
+   eet->path = eina_stringshare_add(path);
+
+   eet->hotkey_edd = _config_hotkey_edd_new();
+   eet->general_edd = _config_general_edd_new(eet->hotkey_edd);
+   eet->panel_edd = _config_panel_edd_new();
+   eet->hangul_edd = _config_hangul_edd_new();
+   eet->engine_edd = _config_engine_edd_new(eet->hangul_edd);
+   eet->ibus_edd = _config_ibus_edd_new(eet->general_edd, eet->panel_edd, eet->engine_edd);
+
+   return eet;
+}
+
+static Eina_Bool
+_config_eet_exists(const char *path)
+{
+   struct stat buf;
+   return stat(path, &buf) == 0;
+}
+
+struct wkb_ibus_config_eet *
+wkb_ibus_config_eet_new(const char *path)
+{
+   struct wkb_ibus_config_eet *eet = _config_eet_section_init(path);
+   Eet_File *ef = NULL;
+   Eet_File_Mode mode = EET_FILE_MODE_READ_WRITE;
+
+   if (_config_eet_exists(path))
+      mode = EET_FILE_MODE_READ;
+
+   if (!(ef = eet_open(path, mode)))
+     {
+        printf("Error opening eet file '%s' for %s\n", path, mode == EET_FILE_MODE_READ ? "read" : "write");
+        wkb_ibus_config_eet_free(eet);
+        return NULL;
+     }
+
+   if (mode == EET_FILE_MODE_READ)
+     {
+        eet->ibus_config = eet_data_read(ef, eet->ibus_edd, "ibus");
+        _config_ibus_section_init(eet->ibus_config);
+        goto end;
+     }
+
+   wkb_ibus_config_eet_set_defaults(eet);
+   if (!eet_data_write(ef, eet->ibus_edd, "ibus", eet->ibus_config, EINA_TRUE))
+     {
+        printf("Error creating eet file '%s'\n", path);
+        wkb_ibus_config_eet_free(eet);
+        eet = NULL;
+     }
+
+end:
+   eet_close(ef);
+   return eet;
+}
+
+void
+wkb_ibus_config_eet_free(struct wkb_ibus_config_eet *config_eet)
+{
+   _config_ibus_free(config_eet->ibus_config);
+   eina_stringshare_del(config_eet->path);
+
+   eet_data_descriptor_free(config_eet->hotkey_edd);
+   eet_data_descriptor_free(config_eet->general_edd);
+   eet_data_descriptor_free(config_eet->panel_edd);
+   eet_data_descriptor_free(config_eet->hangul_edd);
+   eet_data_descriptor_free(config_eet->engine_edd);
+   eet_data_descriptor_free(config_eet->ibus_edd);
+
+   free(config_eet);
+}
diff --git a/src/wkb-ibus-config-eet.h b/src/wkb-ibus-config-eet.h
new file mode 100644 (file)
index 0000000..a7e7970
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _WKB_IBUS_CONFIG_EET_H_
+#define _WKB_IBUS_CONFIG_EET_H_
+
+#include <Eina.h>
+#include <Eldbus.h>
+
+struct wkb_ibus_config_eet;
+
+Eina_Bool wkb_ibus_config_eet_set_value(struct wkb_ibus_config_eet *config_eet, const char *section, const char *name, Eldbus_Message_Iter *value);
+void *wkb_ibus_config_eet_get_value(struct wkb_ibus_config_eet *config_eet, const char *section, const char *name);
+void *wkb_ibus_config_eet_get_values(struct wkb_ibus_config_eet *config_eet, const char *section);
+
+void wkb_ibus_config_eet_set_defaults(struct wkb_ibus_config_eet *config_eet);
+
+struct wkb_ibus_config_eet *wkb_ibus_config_eet_new(const char *path);
+void wkb_ibus_config_eet_free(struct wkb_ibus_config_eet *config_eet);
+
+#endif  /* _WKB_IBUS_CONFIG_EET_H_ */
diff --git a/src/wkb-ibus-config.c b/src/wkb-ibus-config.c
new file mode 100644 (file)
index 0000000..7c698fe
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <Eldbus.h>
+
+#include "wkb-ibus.h"
+
+#define CONFIG_CHECK_MESSAGE_ERRORS(_msg) \
+   do \
+     { \
+        const char *error, *error_msg; \
+        if (eldbus_message_error_get(_msg, &error, &error_msg)) \
+          { \
+             ERR("DBus message error: %s: %s", error, error_msg); \
+             return NULL; \
+          } \
+        DBG("Message '%s' with signature '%s'", eldbus_message_member_get(_msg), eldbus_message_signature_get(_msg)); \
+     } while (0);
+
+static Eldbus_Message *
+_config_set_value(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   const char *section, *name;
+   Eldbus_Message_Iter *value;
+
+   CONFIG_CHECK_MESSAGE_ERRORS(msg)
+
+   if (!eldbus_message_arguments_get(msg, "ssv", &section, &name, &value))
+     {
+        ERR("Error reading message arguments");
+        return NULL;
+     }
+
+   DBG("section: '%s', name: '%s', value: '%p'", section, name, value);
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_config_get_value(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   const char *section, *name;
+
+   CONFIG_CHECK_MESSAGE_ERRORS(msg)
+
+   if (!eldbus_message_arguments_get(msg, "ss", &section, &name))
+     {
+        ERR("Error reading message arguments");
+        return NULL;
+     }
+
+   DBG("section: '%s', name: '%s'", section, name);
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_config_get_values(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   const char *section;
+
+   CONFIG_CHECK_MESSAGE_ERRORS(msg)
+
+   if (!eldbus_message_arguments_get(msg, "s", &section))
+     {
+        ERR("Error reading message arguments");
+        return NULL;
+     }
+
+   DBG("section: '%s'", section);
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_config_unset_value(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   const char *section, *name;
+
+   CONFIG_CHECK_MESSAGE_ERRORS(msg)
+
+   if (!eldbus_message_arguments_get(msg, "ss", &section, &name))
+     {
+        ERR("Error reading message arguments");
+        return NULL;
+     }
+
+   DBG("section: '%s', name: '%s'", section, name);
+
+   return NULL;
+}
+
+static const Eldbus_Method _wkb_ibus_config_methods[] =
+{
+/* typedef struct _Eldbus_Method
+ * {
+ *    const char *member;
+ *    const Eldbus_Arg_Info *in;
+ *    const Eldbus_Arg_Info *out;
+ *    Eldbus_Method_Cb cb;
+ *    unsigned int flags;
+ * } Eldbus_Method;
+ */
+   { .member = "SetValue",
+     .in = ELDBUS_ARGS({"s", "section"}, {"s", "name"}, {"v", "value"}),
+     .cb = _config_set_value, },
+
+   { .member = "GetValue",
+     .in = ELDBUS_ARGS({"s", "section"}, {"s", "name"}),
+     .out = ELDBUS_ARGS({"v", "value"}),
+     .cb = _config_get_value, },
+
+   { .member = "GetValues",
+     .in = ELDBUS_ARGS({"s", "section"}),
+     .out = ELDBUS_ARGS({"a{sv}", "values"}),
+     .cb = _config_get_values, },
+
+   { .member = "UnsetValue",
+     .in = ELDBUS_ARGS({"s", "section"}, {"s", "name"}),
+     .cb = _config_unset_value, },
+
+   { NULL },
+};
+
+static const Eldbus_Signal _wkb_ibus_config_signals[] =
+{
+/* typedef struct _Eldbus_Signal
+ * {
+ *    const char *name;
+ *    const Eldbus_Arg_Info *args;
+ *    unsigned int flags;
+ * } Eldbus_Signal;
+ */
+   { .name = "ValueChanged",
+     .args = ELDBUS_ARGS({"s", "section"}, {"s", "name"}, {"v", "value"}),
+     .flags = 0, },
+
+   { NULL },
+};
+
+static const Eldbus_Service_Interface_Desc _wkb_ibus_config_interface =
+{
+   .interface = IBUS_INTERFACE_CONFIG,
+   .methods = _wkb_ibus_config_methods,
+   .signals = _wkb_ibus_config_signals,
+};
+
+Eldbus_Service_Interface *
+wkb_ibus_config_register(Eldbus_Connection *conn)
+{
+   return eldbus_service_interface_register(conn, IBUS_PATH_CONFIG, &_wkb_ibus_config_interface);
+}
+
diff --git a/src/wkb-ibus-panel.c b/src/wkb-ibus-panel.c
new file mode 100644 (file)
index 0000000..62e437f
--- /dev/null
@@ -0,0 +1,831 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <Eldbus.h>
+
+#include "wkb-ibus.h"
+
+#define PANEL_CHECK_MESSAGE_ERRORS(_msg) \
+   do \
+     { \
+        const char *error, *error_msg; \
+        if (eldbus_message_error_get(_msg, &error, &error_msg)) \
+          { \
+             ERR("DBus message error: %s: %s", error, error_msg); \
+             return NULL; \
+          } \
+        DBG("Message '%s' with signature '%s'", eldbus_message_member_get(_msg), eldbus_message_signature_get(_msg)); \
+     } while (0);
+
+static Eina_Array *_get_properties_from_message_iter(Eldbus_Message_Iter *iter);
+
+struct _ibus_serializable
+{
+   /*
+    * All messages sent by IBus will start with the sa{sv} signature, but
+    * those fields don't seem useful for us, this struct is used to help
+    * on deserializing those fields
+    */
+   char *text;
+   Eldbus_Message_Iter *variant;
+};
+
+struct _ibus_attr
+{
+   unsigned int type;
+   unsigned int value;
+   unsigned int start_idx;
+   unsigned int end_idx;
+};
+
+struct _ibus_text
+{
+   char *text;
+   Eina_Array *attrs;
+};
+
+struct _ibus_lookup_table
+{
+   unsigned int page_size;
+   unsigned int cursor_pos;
+   Eina_Bool cursor_visible;
+   Eina_Bool round;
+   int orientation;
+   Eina_Array *candidates;
+   Eina_Array *labels;
+};
+
+struct _ibus_property
+{
+   char *key;
+   char *icon;
+   struct _ibus_text *label;
+   struct _ibus_text *symbol;
+   struct _ibus_text *tooltip;
+   Eina_Bool sensitive;
+   Eina_Bool visible;
+   unsigned int type;
+   unsigned int state;
+   Eina_Array *sub_properties;
+};
+
+static struct _ibus_attr *
+_get_attr_from_message_iter(Eldbus_Message_Iter *iter)
+{
+   struct _ibus_attr *attr = calloc(1, sizeof(*attr));
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(attr, NULL);
+
+   DBG("Attribute iter signature '%s'", eldbus_message_iter_signature_get(iter));
+
+   if (!eldbus_message_iter_arguments_get(iter, "uuuu", &attr->type,
+                                          &attr->value, &attr->start_idx,
+                                          &attr->end_idx))
+     {
+        ERR("Error deserializing IBusAttribute");
+        free(attr);
+        attr = NULL;
+     }
+
+   return attr;
+}
+
+static void
+_free_eina_array(Eina_Array *array, void (* free_func)(void *))
+{
+   if (!array)
+      return;
+
+   while (eina_array_count(array))
+      free_func(eina_array_pop(array));
+
+   eina_array_free(array);
+}
+
+static void
+_free_text(struct _ibus_text *text)
+{
+   if (!text)
+      return;
+
+   _free_eina_array(text->attrs, free);
+   free(text->text);
+   free(text);
+}
+
+static struct _ibus_text *
+_get_text_from_message_iter(Eldbus_Message_Iter *iter)
+{
+   struct _ibus_serializable ignore = { 0 };
+   struct _ibus_text *text = calloc(1, sizeof(*text));
+   struct _ibus_attr *attr = NULL;
+   Eldbus_Message_Iter *attrs = NULL, *a = NULL;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(text, NULL);
+
+   DBG("Text iter signature '%s'", eldbus_message_iter_signature_get(iter));
+
+   if (!eldbus_message_iter_arguments_get(iter, "(sa{sv}sv)", &ignore.text,
+                                          &ignore.variant, &text->text, &attrs))
+     {
+        ERR("Error deserializing IBusText");
+        free(text);
+        text = NULL;
+        goto end;
+     }
+
+   /* Check for attributes */
+   if (attrs == NULL)
+     {
+        INF("Text has no attributes");
+        goto end;
+     }
+
+   while (eldbus_message_iter_get_and_next(attrs, 'v', &a))
+     {
+        if (!text->attrs)
+           text->attrs = eina_array_new(10);
+
+        if (!(attr = _get_attr_from_message_iter(a)))
+          {
+             _free_text(text);
+             text = NULL;
+             goto end;
+          }
+
+        eina_array_push(text->attrs, attr);
+     }
+
+end:
+   return text;
+}
+
+static void
+_free_lookup_table(struct _ibus_lookup_table *table)
+{
+   if (!table)
+      return;
+
+   _free_eina_array(table->candidates, _free_text);
+   _free_eina_array(table->labels, _free_text);
+   free(table);
+}
+
+static struct _ibus_lookup_table *
+_get_lookup_table_from_message_iter(Eldbus_Message_Iter *iter)
+{
+   struct _ibus_serializable ignore = { 0 };
+   struct _ibus_lookup_table *table = calloc(1, sizeof(*table));
+   struct _ibus_text *text = NULL;
+   Eldbus_Message_Iter *candidates = NULL, *labels = NULL, *t = NULL;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(table, NULL);
+
+   DBG("LookupTable iter signature '%s'", eldbus_message_iter_signature_get(iter));
+
+   if (!eldbus_message_iter_arguments_get(iter, "(sa{sv}uubbiavav)",
+                                          &ignore.text, &ignore.variant,
+                                          &table->page_size, &table->cursor_pos,
+                                          &table->cursor_visible, &table->round,
+                                          &table->orientation, &candidates,
+                                          &labels))
+     {
+        ERR("Error deserializing IBusLookupTable");
+        free(table);
+        table = NULL;
+        goto end;
+     }
+
+   DBG("Lookup table:");
+   DBG("\tPage size.......: '%d'", table->page_size);
+   DBG("\tCursor position.: '%d'", table->cursor_pos);
+   DBG("\tCursor visible..: '%d'", table->cursor_visible);
+   DBG("\tRound...........: '%d'", table->round);
+   DBG("\tOrientation.....: '%d'", table->orientation);
+   DBG("\tCandidates......: '%p'", candidates);
+   DBG("\tLabels..........: '%p'", labels);
+
+   if (!candidates)
+     {
+        INF("Lookup table has no candidates");
+        goto labels;
+     }
+
+   while (eldbus_message_iter_get_and_next(candidates, 'v', &t))
+     {
+        if (!table->candidates)
+           table->candidates = eina_array_new(10);
+
+        if (!(text = _get_text_from_message_iter(t)))
+          {
+             _free_lookup_table(table);
+             table = NULL;
+             goto end;
+          }
+
+        DBG("Appending new candidate %s", text->text);
+        eina_array_push(table->candidates, text);
+     }
+
+labels:
+   if (!labels)
+     {
+        INF("Lookup table has no labels");
+        goto end;
+     }
+
+   while (eldbus_message_iter_get_and_next(labels, 'v', &t))
+     {
+        if (!table->labels)
+           table->labels = eina_array_new(10);
+
+        if (!(text = _get_text_from_message_iter(t)))
+          {
+             _free_lookup_table(table);
+             table = NULL;
+             goto end;
+          }
+
+        DBG("Appending new label %s", text->text);
+        eina_array_push(table->labels, text);
+     }
+
+end:
+   return table;
+}
+
+static void
+_free_property(struct _ibus_property *property)
+{
+   if (!property)
+      return;
+
+   free(property->key);
+   free(property->icon);
+   _free_text(property->label);
+   _free_text(property->symbol);
+   _free_text(property->tooltip);
+   _free_eina_array(property->sub_properties, _free_property);
+   free(property);
+}
+
+static struct _ibus_property *
+_get_property_from_message_iter(Eldbus_Message_Iter *iter)
+{
+   struct _ibus_serializable ignore = { 0 };
+   struct _ibus_property *prop = calloc(1, sizeof(*prop));
+   Eldbus_Message_Iter *label = NULL, *symbol = NULL, *tooltip = NULL, *sub_props = NULL;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(prop, NULL);
+
+   DBG("Property iter signature '%s'", eldbus_message_iter_signature_get(iter));
+
+   if (!eldbus_message_iter_arguments_get(iter, "(sa{sv}suvsvbbuvv)",
+                                          &ignore.text, &ignore.variant,
+                                          &prop->key, &prop->type,
+                                          &label, &prop->icon, &tooltip,
+                                          &prop->sensitive, &prop->visible,
+                                          &prop->state, &sub_props, &symbol))
+     {
+        ERR("Error deserializing IBusProperty");
+        free(prop);
+        prop = NULL;
+        goto end;
+     }
+
+   DBG("Property :");
+   DBG("\tKey.............: '%s'", prop->key);
+   DBG("\tType............: '%d'", prop->type);
+   DBG("\tLabel...........: '%p'", label);
+   DBG("\tIcon............: '%s'", prop->icon);
+   DBG("\tTooltip.........: '%p'", tooltip);
+   DBG("\tSensitive.......: '%d'", prop->sensitive);
+   DBG("\tVisible.........: '%d'", prop->visible);
+   DBG("\tState...........: '%d'", prop->state);
+   DBG("\tSub Properties..: '%p'", sub_props);
+   DBG("\tSymbol..........: '%p'", symbol);
+
+   if (!label)
+     {
+        INF("Property has no label");
+        goto symbol;
+     }
+
+   if (!(prop->label = _get_text_from_message_iter(label)))
+     {
+        _free_property(prop);
+        prop = NULL;
+        goto end;
+     }
+
+symbol:
+   if (!symbol)
+     {
+        INF("Property has no symbol");
+        goto tooltip;
+     }
+
+   if (!(prop->symbol = _get_text_from_message_iter(symbol)))
+     {
+        _free_property(prop);
+        prop = NULL;
+        goto end;
+     }
+
+tooltip:
+   if (!tooltip)
+     {
+        INF("Property has no tooltip");
+        goto sub_props;
+     }
+
+   if (!(prop->tooltip = _get_text_from_message_iter(tooltip)))
+     {
+        _free_property(prop);
+        prop = NULL;
+        goto end;
+     }
+
+sub_props:
+   if (!sub_props)
+     {
+        INF("Property has no sub properties");
+        goto end;
+     }
+
+   prop->sub_properties = _get_properties_from_message_iter(sub_props);
+
+end:
+   return prop;
+}
+
+static Eina_Array *
+_get_properties_from_message_iter(Eldbus_Message_Iter *iter)
+{
+   Eina_Array *properties = NULL;
+   Eldbus_Message_Iter *props = NULL, *prop = NULL;
+   struct _ibus_serializable ignore = { 0 };
+   struct _ibus_property *property = NULL;
+
+   DBG("PropList iter signature '%s'", eldbus_message_iter_signature_get(iter));
+
+   if (!eldbus_message_iter_arguments_get(iter, "(sa{sv}av)", &ignore.text, &ignore.variant, &props))
+     {
+        ERR("Error deserializing IBusPropList");
+        goto end;
+     }
+
+   if (!props)
+     {
+        INF("PropList has no property");
+        goto end;
+     }
+
+   while (eldbus_message_iter_get_and_next(props, 'v', &prop))
+     {
+        if (!properties)
+           properties = eina_array_new(10);
+
+        if (!(property = _get_property_from_message_iter(prop)))
+          {
+             _free_eina_array(properties, _free_property);
+             properties = NULL;
+             goto end;
+          }
+
+        DBG("Appending new property %p", property);
+        eina_array_push(properties, property);
+     }
+
+end:
+   return properties;
+}
+
+static Eldbus_Message *
+_panel_update_preedit_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   Eldbus_Message_Iter *text = NULL;
+   unsigned int cursor_pos = 0;
+   Eina_Bool visible = 0;
+   struct _ibus_text *ibus_text;
+
+   PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+   if (!eldbus_message_arguments_get(msg, "vub", &text, &cursor_pos, &visible))
+     {
+        ERR("Error reading message arguments");
+        return NULL;
+     }
+
+   DBG("text: '%p', cursor_pos: '%d', visible: '%d')", text, cursor_pos, visible);
+
+   ibus_text = _get_text_from_message_iter(text);
+   DBG("Preedit text = '%s'", ibus_text->text);
+   _free_text(ibus_text);
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_panel_show_preedit_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_panel_hide_preedit_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_panel_update_auxiliary_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   Eldbus_Message_Iter *text = NULL;
+   Eina_Bool visible = 0;
+   struct _ibus_text *ibus_text;
+
+   PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+   if (!eldbus_message_arguments_get(msg, "vb", &text, &visible))
+     {
+        ERR("Error reading message arguments");
+        return NULL;
+     }
+
+   DBG("text: '%p', visible: '%d'", text, visible);
+
+   ibus_text = _get_text_from_message_iter(text);
+   DBG("Auxiliary text = '%s'", ibus_text->text);
+   _free_text(ibus_text);
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_panel_show_auxiliary_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_panel_hide_auxiliary_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_panel_update_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   Eldbus_Message_Iter *table = NULL;
+   Eina_Bool visible =  0;
+   struct _ibus_lookup_table *ibus_lookup_table;
+
+   PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+   if (!eldbus_message_arguments_get(msg, "vb", &table, &visible))
+     {
+        ERR("Error reading message arguments");
+        return NULL;
+     }
+
+   DBG("table: '%p', visible: '%d'", table, visible);
+
+   ibus_lookup_table = _get_lookup_table_from_message_iter(table);
+   _free_lookup_table(ibus_lookup_table);
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_panel_show_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_panel_hide_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+   DBG("here");
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_panel_cursor_up_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+   DBG("here");
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_panel_cursor_down_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_panel_page_up_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_panel_page_down_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_panel_register_properties(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   Eldbus_Message_Iter *props = NULL;
+   Eina_Array *properties = NULL;
+
+   PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+   if (!eldbus_message_arguments_get(msg, "v", &props))
+     {
+        ERR("Error reading message arguments");
+        return NULL;
+     }
+
+   DBG("properties: '%p'", props);
+
+   properties = _get_properties_from_message_iter(props);
+   _free_eina_array(properties, _free_property);
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_panel_update_property(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   Eldbus_Message_Iter *prop = NULL;
+
+   PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+   if (!eldbus_message_arguments_get(msg, "v", &prop))
+     {
+        ERR("Error reading message arguments");
+        return NULL;
+     }
+
+   DBG("property : '%p'", prop);
+   DBG("Property iter signature: %s", eldbus_message_iter_signature_get(prop));
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_panel_focus_in(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_panel_focus_out(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_panel_set_cursor_location(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   int x = 0, y = 0, w = 0, h = 0;
+
+   PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+   if (!eldbus_message_arguments_get(msg, "iiii", &x, &y, &w, &h))
+     {
+        ERR("Error reading message arguments");
+        return NULL;
+     }
+
+   DBG("x: %d, y: %d, w: %d, h: %d", x, y, w, h);
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_panel_reset(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_panel_start_setup(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_panel_state_changed(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_panel_hide_language_bar(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+   return NULL;
+}
+
+static Eldbus_Message *
+_panel_show_language_bar(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   PANEL_CHECK_MESSAGE_ERRORS(msg)
+
+   return NULL;
+}
+
+static const Eldbus_Method _wkb_ibus_panel_methods[] =
+{
+/* typedef struct _Eldbus_Method
+ * {
+ *    const char *member;
+ *    const Eldbus_Arg_Info *in;
+ *    const Eldbus_Arg_Info *out;
+ *    Eldbus_Method_Cb cb;
+ *    unsigned int flags;
+ * } Eldbus_Method;
+ */
+   { .member = "UpdatePreeditText",
+     .in = ELDBUS_ARGS({"v", "text"}, {"u", "cursor_pos"}, {"b", "visible"}),
+     .cb = _panel_update_preedit_text, },
+
+   { .member = "ShowPreeditText",
+     .cb = _panel_show_preedit_text, },
+
+   { .member = "HidePreeditText",
+     .cb = _panel_hide_preedit_text, },
+
+   { .member = "UpdateAuxiliaryText",
+     .in = ELDBUS_ARGS({"v", "text"}, {"b", "visible"}),
+     .cb = _panel_update_auxiliary_text, },
+
+   { .member = "ShowAuxiliaryText",
+     .cb = _panel_show_auxiliary_text, },
+
+   { .member = "HideAuxiliaryText",
+     .cb = _panel_hide_auxiliary_text, },
+
+   { .member = "UpdateLookupTable",
+     .in = ELDBUS_ARGS({"v", "table"}, {"b", "visible"}),
+     .cb = _panel_update_lookup_table, },
+
+   { .member = "ShowLookupTable",
+     .cb = _panel_show_lookup_table, },
+
+   { .member = "HideLookupTable",
+     .cb = _panel_hide_lookup_table, },
+
+   { .member = "CursorUpLookupTable",
+     .cb = _panel_cursor_up_lookup_table, },
+
+   { .member = "CursorDownLookupTable",
+     .cb = _panel_cursor_down_lookup_table, },
+
+   { .member = "PageUpLookupTable",
+     .cb = _panel_page_up_lookup_table, },
+
+   { .member = "PageDownLookupTable",
+     .cb = _panel_page_down_lookup_table, },
+
+   { .member = "RegisterProperties",
+     .in = ELDBUS_ARGS({"v", "props"}),
+     .cb = _panel_register_properties, },
+
+   { .member = "UpdateProperty",
+     .in = ELDBUS_ARGS({"v", "prop"}),
+     .cb = _panel_update_property, },
+
+   { .member = "FocusIn",
+     .in = ELDBUS_ARGS({"o", "ic"}),
+     .cb = _panel_focus_in, },
+
+   { .member = "FocusOut",
+     .in = ELDBUS_ARGS({"o", "ic"}),
+     .cb = _panel_focus_out, },
+
+   { .member = "SetCursorLocation",
+     .in = ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"i", "w"}, {"i", "h"}),
+     .cb = _panel_set_cursor_location, },
+
+   { .member = "Reset",
+     .cb = _panel_reset, },
+
+   { .member = "StartSetup",
+     .cb = _panel_start_setup, },
+
+   { .member = "StateChanged",
+     .cb = _panel_state_changed, },
+
+   { .member = "HideLanguageBar",
+     .cb = _panel_hide_language_bar, },
+
+   { .member = "ShowLanguageBar",
+     .cb = _panel_show_language_bar, },
+
+   { NULL },
+};
+
+static const Eldbus_Signal _wkb_ibus_panel_signals[] =
+{
+/* typedef struct _Eldbus_Signal
+ * {
+ *    const char *name;
+ *    const Eldbus_Arg_Info *args;
+ *    unsigned int flags;
+ * } Eldbus_Signal;
+ */
+   { .name = "CursorUp", },
+
+   { .name = "CursorDown", },
+
+   { .name = "PageUp", },
+
+   { .name = "PageDown", },
+
+   { .name = "PropertyActivate",
+     .args = ELDBUS_ARGS({"s", "prop_name"}, {"i", "prop_state"}),
+     .flags = 0, },
+
+   { .name = "PropertyShow",
+     .args = ELDBUS_ARGS({"s", "prop_name"}),
+     .flags = 0, },
+
+   { .name = "PropertyHide",
+     .args = ELDBUS_ARGS({"s", "prop_name"}),
+     .flags = 0, },
+
+   { .name = "CandidateClicked",
+     .args = ELDBUS_ARGS({"u", "index"}, {"u", "button"}, {"u", "state"}),
+     .flags = 0, },
+
+   { NULL },
+};
+
+static const Eldbus_Service_Interface_Desc _wkb_ibus_panel_interface =
+{
+   .interface = IBUS_INTERFACE_PANEL,
+   .methods = _wkb_ibus_panel_methods,
+   .signals = _wkb_ibus_panel_signals,
+};
+
+Eldbus_Service_Interface *
+wkb_ibus_panel_register(Eldbus_Connection *conn)
+{
+   return eldbus_service_interface_register(conn, IBUS_PATH_PANEL, &_wkb_ibus_panel_interface);
+}
+
diff --git a/src/wkb-ibus-test.c b/src/wkb-ibus-test.c
new file mode 100644 (file)
index 0000000..ced4700
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "wkb-ibus.h"
+
+#define _GNU_SOURCE
+#include <signal.h>
+
+#include <Ecore.h>
+#include <Eldbus.h>
+
+static void
+_finish(int foo)
+{
+   printf("FINISH\n");
+   wkb_ibus_shutdown();
+}
+
+static Eina_Bool
+_connect_timer(void *data)
+{
+   return !wkb_ibus_connect();
+}
+
+int
+main (int argc, char *argv[])
+{
+   if (!ecore_init())
+     {
+        printf("Error initializing ecore");
+        return 1;
+     }
+
+   if (!eldbus_init())
+     {
+        printf("Error initializing eldbus");
+        return 1;
+     }
+
+   if (!wkb_ibus_init())
+     {
+        printf("Error initializing ibus");
+        return 1;
+     }
+
+   ecore_timer_add(1, _connect_timer, NULL);
+
+   signal(SIGTERM, _finish);
+   signal(SIGINT, _finish);
+
+   ecore_main_loop_begin();
+
+   eldbus_shutdown();
+   ecore_shutdown();
+   return 0;
+}
diff --git a/src/wkb-ibus.c b/src/wkb-ibus.c
new file mode 100644 (file)
index 0000000..60cdac2
--- /dev/null
@@ -0,0 +1,507 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <Ecore.h>
+#include <Eldbus.h>
+
+#include "wkb-ibus.h"
+
+int _wkb_ibus_log_dom = -1;
+
+#define CHECK_MESSAGE_ERRORS(_msg) \
+   do \
+     { \
+        const char *error, *error_msg; \
+        if (eldbus_message_error_get(_msg, &error, &error_msg)) \
+          { \
+             ERR("Dbus message error: %s: %s", error, error_msg); \
+             return; \
+          } \
+        DBG("Message '%s' with signature '%s'", eldbus_message_member_get(_msg), eldbus_message_signature_get(_msg)); \
+     } while (0);
+
+struct _wkb_ibus_service
+{
+   Eldbus_Service_Interface *interface;
+
+   Eldbus_Signal_Handler *name_acquired;
+   Eldbus_Signal_Handler *name_lost;
+};
+
+struct _wkb_ibus_context
+{
+   char *address;
+   Eldbus_Connection *conn;
+   Ecore_Exe *ibus_daemon;
+#if 0
+   struct _wkb_ibus_service config;
+#else
+   Eldbus_Proxy *config;
+#endif
+   struct _wkb_ibus_service panel;
+   int refcount;
+   Eina_Bool address_pending;
+};
+
+static struct _wkb_ibus_context *ctx = NULL;
+
+static void
+_wkb_config_value_changed_cb(void *data, const Eldbus_Message *msg)
+{
+   const char *section, name;
+   Eldbus_Message_Iter *value;
+
+   CHECK_MESSAGE_ERRORS(msg)
+
+   if (!eldbus_message_arguments_get(msg, "ssv", &section, &name, &value))
+     {
+        ERR("Error reading message arguments");
+        return;
+     }
+
+   DBG("section: '%s', name: '%s', value: '%p", section, name, value);
+}
+
+static void
+_wkb_name_owner_changed_cb(void *data, const char *bus, const char *old_id, const char *new_id)
+{
+   DBG("NameOwnerChanged Bus=%s | old=%s | new=%s", bus, old_id, new_id);
+
+#if 0
+#else
+   if (strcmp(bus, IBUS_SERVICE_CONFIG) == 0)
+     {
+        if (*new_id)
+          {
+             Eldbus_Object *obj;
+
+             if (ctx->config)
+                return;
+
+             ecore_main_loop_glib_integrate();
+             obj = eldbus_object_get(ctx->conn, IBUS_SERVICE_CONFIG, IBUS_PATH_CONFIG);
+             ctx->config = eldbus_proxy_get(obj, IBUS_INTERFACE_CONFIG);
+             eldbus_proxy_signal_handler_add(ctx->config, "ValueChanged", _wkb_config_value_changed_cb, ctx);
+
+             INF("Got config proxy");
+          }
+        else
+          {
+             if (!ctx->config)
+                return;
+
+             eldbus_proxy_unref(ctx->config);
+             ctx->config = NULL;
+          }
+     }
+#endif
+}
+
+static void
+_wkb_name_acquired_cb(void *data, const Eldbus_Message *msg)
+{
+   const char *name;
+
+   DBG("NameAcquired");
+
+   CHECK_MESSAGE_ERRORS(msg)
+
+   if (!eldbus_message_arguments_get(msg, "s", &name))
+     {
+        ERR("Error reading message arguments");
+        return;
+     }
+
+   if (strcmp(name, IBUS_INTERFACE_PANEL) == 0)
+     {
+        if (!ctx->panel.interface)
+          {
+             ctx->panel.interface = wkb_ibus_panel_register(ctx->conn);
+             INF("Registering Panel Interface: %s", ctx->panel.interface ? "Success" : "Fail");
+          }
+        else
+          {
+             INF("Panel Interface already registered");
+          }
+     }
+#if 0
+   else if (strcmp(name, IBUS_INTERFACE_CONFIG) == 0)
+     {
+        if (!ctx->config.interface)
+          {
+             ctx->config.interface = wkb_ibus_config_register(ctx->conn);
+             INF("Registering Config Interface: %s", ctx->config.interface ? "Success" : "Fail");
+          }
+        else
+          {
+             INF("Config Interface already registered");
+          }
+     }
+#endif
+   else
+     {
+        WRN("Unexpected name %s", name);
+     }
+}
+
+static void
+_wkb_name_lost_cb(void *data, const Eldbus_Message *msg)
+{
+   const char *name;
+
+   DBG("NameLost");
+
+   CHECK_MESSAGE_ERRORS(msg)
+
+   if (!eldbus_message_arguments_get(msg, "s", &name))
+     {
+        ERR("Error reading message arguments");
+        return;
+     }
+
+   DBG("Name = %s", name);
+}
+
+static Eina_Bool
+_wkb_ibus_shutdown_idler(void *data)
+{
+   wkb_ibus_shutdown();
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_wkb_name_request_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
+{
+   const char *error, *error_msg;
+   unsigned int reply;
+
+   DBG("NameRequest callback");
+
+   if (eldbus_message_error_get(msg, &error, &error_msg))
+     {
+        ERR("DBus message error: %s: %s", error, error_msg);
+        goto error;
+     }
+
+   if (!eldbus_message_arguments_get(msg, "u", &reply))
+     {
+        ERR("Error reading message arguments");
+        goto error;
+     }
+
+   if (reply != ELDBUS_NAME_REQUEST_REPLY_PRIMARY_OWNER &&
+       reply != ELDBUS_NAME_REQUEST_REPLY_ALREADY_OWNER)
+     {
+        ERR("Not primary owner: reply=%d", reply);
+        goto error;
+     }
+
+   return;
+
+error:
+   ecore_idler_add(_wkb_ibus_shutdown_idler, NULL);
+}
+
+static void
+_wkb_name_release_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
+{
+   unsigned int reply;
+
+   CHECK_MESSAGE_ERRORS(msg)
+
+   if (!eldbus_message_arguments_get(msg, "u", &reply))
+     {
+        ERR("Error reading message arguments");
+        return;
+     }
+
+   if (reply != ELDBUS_NAME_RELEASE_REPLY_RELEASED)
+     {
+        ERR("Unexpected name release reply: %d", reply);
+        return;
+     }
+}
+
+static void
+_wkb_ibus_launch_daemon(void)
+{
+    DBG("Launching ibus-daemon");
+    ctx->ibus_daemon = ecore_exe_run("ibus-daemon -s", NULL);
+    if (!ctx->ibus_daemon)
+      {
+         ERR("Error launching ibus-daemon process");
+         return;
+      }
+}
+
+static Eina_Bool
+_wkb_ibus_query_address_cb(void *data, int type, void *event)
+{
+   Ecore_Exe_Event_Data *exe_data = (Ecore_Exe_Event_Data *)event;
+
+   if (strncmp(exe_data->data, "(null)", exe_data->size) == 0)
+     {
+        INF("IBus daemon is not running.");
+        _wkb_ibus_launch_daemon();
+        goto end;
+     }
+   else if (strstr(exe_data->data, "unknown command") != NULL)
+     {
+        ERR("ibus command does not support the 'address' argument");
+        goto end;
+     }
+
+   free(ctx->address);
+   ctx->address = strndup(exe_data->data, exe_data->size);
+
+end:
+   ecore_idler_add(ecore_exe_free, exe_data->exe);
+   ctx->address_pending = EINA_FALSE;
+   return ECORE_CALLBACK_DONE;
+}
+
+
+static void
+_wkb_ibus_query_address(void)
+{
+   const char *ibus_addr;
+   Ecore_Exe *ibus_exec = NULL;
+
+   /* Check for IBUS_ADDRESS environment variable */
+   if ((ibus_addr = getenv("IBUS_ADDRESS")) != NULL)
+     {
+        DBG("Got IBus address from IBUS_ADDRESS environment variable %s", ibus_addr);
+        ctx->address = strdup(ibus_addr);
+        return;
+     }
+
+   /* Get IBus address by invoking 'ibus address' from command line */
+   DBG("Querying IBus address from using 'ibus address' command");
+   ibus_exec = ecore_exe_pipe_run("ibus address",
+                                  ECORE_EXE_PIPE_READ |
+                                  ECORE_EXE_PIPE_READ_LINE_BUFFERED,
+                                  NULL);
+   if (!ibus_exec)
+     {
+        ERR("Unable to retrieve IBus address");
+        return;
+     }
+
+   ctx->address_pending = EINA_TRUE;
+   ecore_event_handler_add(ECORE_EXE_EVENT_DATA, _wkb_ibus_query_address_cb, NULL);
+}
+
+Eina_Bool
+wkb_ibus_connect(void)
+{
+   if (ctx->conn)
+      return EINA_TRUE;
+
+   if (!ctx->address)
+     {
+        INF("IBus address is not set.", ctx->address_pending);
+        if (!ctx->address_pending)
+            _wkb_ibus_query_address();
+
+        return EINA_FALSE;
+    }
+
+   INF("Connecting to IBus at address '%s'", ctx->address);
+   ctx->conn = eldbus_address_connection_get(ctx->address);
+
+   if (!ctx->conn)
+     {
+        ERR("Error connecting to IBus");
+        return EINA_FALSE;
+     }
+
+   /* Panel */
+   eldbus_name_owner_changed_callback_add(ctx->conn,
+                                          IBUS_SERVICE_PANEL,
+                                          _wkb_name_owner_changed_cb,
+                                          ctx, EINA_TRUE);
+
+   ctx->panel.name_acquired = eldbus_signal_handler_add(ctx->conn,
+                                                        ELDBUS_FDO_BUS,
+                                                        ELDBUS_FDO_PATH,
+                                                        IBUS_INTERFACE_PANEL,
+                                                        "NameAcquired",
+                                                        _wkb_name_acquired_cb,
+                                                        ctx);
+
+   ctx->panel.name_lost = eldbus_signal_handler_add(ctx->conn,
+                                                    ELDBUS_FDO_BUS,
+                                                    ELDBUS_FDO_PATH,
+                                                    IBUS_INTERFACE_PANEL,
+                                                    "NameLost",
+                                                    _wkb_name_lost_cb,
+                                                    ctx);
+
+   eldbus_name_request(ctx->conn, IBUS_SERVICE_PANEL,
+                       ELDBUS_NAME_REQUEST_FLAG_REPLACE_EXISTING | ELDBUS_NAME_REQUEST_FLAG_DO_NOT_QUEUE,
+                       _wkb_name_request_cb, ctx);
+
+   /* Config */
+   eldbus_name_owner_changed_callback_add(ctx->conn,
+                                          IBUS_SERVICE_CONFIG,
+                                          _wkb_name_owner_changed_cb,
+                                          ctx, EINA_TRUE);
+
+#if 0
+   ctx->config.name_acquired = eldbus_signal_handler_add(ctx->conn,
+                                                         ELDBUS_FDO_BUS,
+                                                         ELDBUS_FDO_PATH,
+                                                         IBUS_INTERFACE_CONFIG,
+                                                         "NameAcquired",
+                                                         _wkb_name_acquired_cb,
+                                                         ctx);
+
+   ctx->config.name_lost = eldbus_signal_handler_add(ctx->conn,
+                                                     ELDBUS_FDO_BUS,
+                                                     ELDBUS_FDO_PATH,
+                                                     IBUS_INTERFACE_CONFIG,
+                                                     "NameLost",
+                                                     _wkb_name_lost_cb,
+                                                     ctx);
+
+   eldbus_name_request(ctx->conn, IBUS_SERVICE_CONFIG,
+                       ELDBUS_NAME_REQUEST_FLAG_REPLACE_EXISTING | ELDBUS_NAME_REQUEST_FLAG_DO_NOT_QUEUE,
+                       _wkb_name_request_cb, ctx);
+#endif
+   return EINA_TRUE;
+}
+
+
+int
+wkb_ibus_init(void)
+{
+   if (ctx && ctx->refcount > 0)
+      goto end;
+
+   if (!eina_init())
+     {
+        fprintf(stderr, "Error initializing Eina\n");
+        return 0;
+     }
+
+   _wkb_ibus_log_dom = eina_log_domain_register("wkb-ibus", EINA_COLOR_LIGHTCYAN);
+   if (_wkb_ibus_log_dom < 0)
+      {
+         EINA_LOG_ERR("Unable to register 'wkb-ibus' log domain");
+         eina_shutdown();
+         return 0;
+      }
+
+   if (!ctx && !(ctx = calloc(1, sizeof(*ctx))))
+     {
+        ERR("Error calloc\n");
+        eina_shutdown();
+        return 0;
+     }
+
+   _wkb_ibus_query_address();
+
+end:
+   return ++ctx->refcount;
+}
+
+void
+wkb_ibus_shutdown(void)
+{
+   if (!ctx)
+     {
+        fprintf(stderr, "Not initialized\n");
+        return;
+     }
+
+   if (ctx->refcount == 0)
+     {
+        ERR("Refcount already 0");
+        goto end;
+     }
+
+   if (--(ctx->refcount) != 0)
+      return;
+
+   DBG("Shutting down");
+   wkb_ibus_disconnect();
+
+   free(ctx->address);
+
+   if (ctx->ibus_daemon)
+     {
+        DBG("Terminating ibus-daemon");
+        ecore_exe_terminate(ctx->ibus_daemon);
+        ecore_exe_free(ctx->ibus_daemon);
+     }
+
+end:
+   free(ctx);
+   ctx = NULL;
+
+   ecore_main_loop_quit();
+   DBG("Main loop quit");
+}
+
+void
+wkb_ibus_disconnect(void)
+{
+   if (!ctx->conn)
+     {
+        ERR("Not connected");
+        return;
+     }
+
+   DBG("Disconnect");
+
+   if (ctx->panel.interface)
+     {
+        eldbus_name_release(ctx->conn, IBUS_SERVICE_PANEL, _wkb_name_release_cb, ctx);
+        eldbus_signal_handler_del(ctx->panel.name_acquired);
+        eldbus_signal_handler_del(ctx->panel.name_lost);
+        eldbus_service_interface_unregister(ctx->panel.interface);
+        ctx->panel.interface = NULL;
+     }
+
+   if (ctx->config)
+     {
+        eldbus_proxy_unref(ctx->config);
+        ctx->config = NULL;
+     }
+#if 0
+   if (ctx->config.interface)
+     {
+        eldbus_name_release(ctx->conn, IBUS_SERVICE_CONFIG, _wkb_name_release_cb, ctx);
+        eldbus_signal_handler_del(ctx->config.name_acquired);
+        eldbus_signal_handler_del(ctx->config.name_lost);
+        eldbus_service_interface_unregister(ctx->config.interface);
+        ctx->config.interface = NULL;
+     }
+#endif
+
+   eldbus_connection_unref(ctx->conn);
+}
+
+Eina_Bool
+wkb_ibus_is_connected(void)
+{
+    return ctx->conn != NULL;
+}
diff --git a/src/wkb-ibus.h b/src/wkb-ibus.h
new file mode 100644 (file)
index 0000000..f3b0a1f
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _WKB_IBUS_H_
+#define _WKB_IBUS_H_
+
+#include <Eina.h>
+#include <Eldbus.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int _wkb_ibus_log_dom;
+#define DBG(...)      EINA_LOG_DOM_DBG(_wkb_ibus_log_dom, __VA_ARGS__)
+#define INF(...)      EINA_LOG_DOM_INFO(_wkb_ibus_log_dom, __VA_ARGS__)
+#define WRN(...)      EINA_LOG_DOM_WARN(_wkb_ibus_log_dom, __VA_ARGS__)
+#define ERR(...)      EINA_LOG_DOM_ERR(_wkb_ibus_log_dom, __VA_ARGS__)
+#define CRITICAL(...) EINA_LOG_DOM_CRIT(_wkb_ibus_log_dom, __VA_ARGS__)
+
+
+/* from ibusshare.h */
+#define IBUS_SERVICE_IBUS       "org.freedesktop.IBus"
+#define IBUS_SERVICE_PANEL      "org.freedesktop.IBus.Panel"
+#define IBUS_SERVICE_CONFIG     "org.freedesktop.IBus.Config"
+
+#define IBUS_PATH_IBUS          "/org/freedesktop/IBus"
+#define IBUS_PATH_PANEL         "/org/freedesktop/IBus/Panel"
+#define IBUS_PATH_CONFIG        "/org/freedesktop/IBus/Config"
+
+#define IBUS_INTERFACE_IBUS     "org.freedesktop.IBus"
+#define IBUS_INTERFACE_PANEL    "org.freedesktop.IBus.Panel"
+#define IBUS_INTERFACE_CONFIG   "org.freedesktop.IBus.Config"
+
+
+int wkb_ibus_init(void);
+void wkb_ibus_shutdown(void);
+
+Eina_Bool wkb_ibus_connect(void);
+void wkb_ibus_disconnect(void);
+
+Eina_Bool wkb_ibus_is_connected(void);
+
+/* Panel */
+Eldbus_Service_Interface * wkb_ibus_panel_register(Eldbus_Connection *conn);
+
+/* Config */
+#if 0
+Eldbus_Service_Interface * wkb_ibus_config_register(Eldbus_Connection *conn);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _WKB_IBUS_H_ */
diff --git a/src/wkb-main.c b/src/wkb-main.c
new file mode 100644 (file)
index 0000000..953b283
--- /dev/null
@@ -0,0 +1,601 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <Eina.h>
+#include <Ecore.h>
+#include <Ecore_Wayland.h>
+#include <Ecore_Evas.h>
+#include <Edje.h>
+
+#include <linux/input.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "input-method-client-protocol.h"
+#include "text-client-protocol.h"
+
+struct weekeyboard
+{
+   Ecore_Evas *ee;
+   Ecore_Wl_Window *win;
+   Evas_Object *edje_obj;
+   const char *ee_engine;
+   char **ignore_keys;
+
+   struct wl_surface *surface;
+   struct wl_input_panel *ip;
+   struct wl_input_method *im;
+   struct wl_output *output;
+   struct wl_input_method_context *im_ctx;
+
+   char *surrounding_text;
+   char *preedit_str;
+   char *language;
+
+   uint32_t text_direction;
+   uint32_t preedit_style;
+   uint32_t content_hint;
+   uint32_t content_purpose;
+   uint32_t serial;
+   uint32_t surrounding_cursor;
+
+   Eina_Bool context_changed;
+};
+
+static void
+_cb_wkb_delete_request(Ecore_Evas *ee EINA_UNUSED)
+{
+   ecore_main_loop_quit();
+}
+
+static char *
+_wkb_insert_text(const char *text, uint32_t offset, const char *insert)
+{
+   char *new_text = malloc(strlen(text) + strlen(insert) + 1);
+
+   strncat(new_text, text, offset);
+   new_text[offset] = '\0';
+   strcat(new_text, insert);
+   strcat(new_text, text + offset);
+
+   return new_text;
+}
+
+static void
+_wkb_commit_preedit_str(struct weekeyboard *wkb)
+{
+   char *surrounding_text;
+
+   if (!wkb->preedit_str || !strlen(wkb->preedit_str) == 0)
+      return;
+
+   wl_input_method_context_cursor_position(wkb->im_ctx, 0, 0);
+   wl_input_method_context_commit_string(wkb->im_ctx, wkb->serial, wkb->preedit_str);
+
+   if (wkb->surrounding_text)
+     {
+        surrounding_text = _wkb_insert_text(wkb->surrounding_text, wkb->surrounding_cursor, wkb->preedit_str);
+        free(wkb->surrounding_text);
+        wkb->surrounding_text = surrounding_text;
+        wkb->surrounding_cursor += strlen(wkb->preedit_str);
+     }
+   else
+     {
+        wkb->surrounding_text = strdup(wkb->preedit_str);
+        wkb->surrounding_cursor = strlen(wkb->preedit_str);
+     }
+
+   free(wkb->preedit_str);
+   wkb->preedit_str = strdup("");
+}
+
+static void
+_wkb_send_preedit_str(struct weekeyboard *wkb, int cursor)
+{
+   unsigned int index = strlen(wkb->preedit_str);
+
+   if (wkb->preedit_style)
+      wl_input_method_context_preedit_styling(wkb->im_ctx, 0, strlen(wkb->preedit_str), wkb->preedit_style);
+
+   if (cursor > 0)
+      index = cursor;
+
+   wl_input_method_context_preedit_cursor(wkb->im_ctx, index);
+   wl_input_method_context_preedit_string(wkb->im_ctx, wkb->serial, wkb->preedit_str, wkb->preedit_str);
+}
+
+static void
+_wkb_update_preedit_str(struct weekeyboard *wkb, const char *key)
+{
+   char *tmp;
+
+   if (!wkb->preedit_str)
+      wkb->preedit_str = strdup("");
+
+   tmp = calloc(1, strlen(wkb->preedit_str) + strlen(key) + 1);
+   sprintf(tmp, "%s%s", wkb->preedit_str, key);
+   free(wkb->preedit_str);
+   wkb->preedit_str = tmp;
+
+   if (strcmp(key, " ") == 0)
+      _wkb_commit_preedit_str(wkb);
+   else
+      _wkb_send_preedit_str(wkb, -1);
+}
+
+static Eina_Bool
+_wkb_ignore_key(struct weekeyboard *wkb, const char *key)
+{
+   int i;
+
+   if (!wkb->ignore_keys)
+       return EINA_FALSE;
+
+   for (i = 0; wkb->ignore_keys[i] != NULL; i++)
+      if (!strcmp(key, wkb->ignore_keys[i]))
+         return EINA_TRUE;
+
+   return EINA_FALSE;
+}
+
+static void
+_cb_wkb_on_key_down(void *data, Evas_Object *obj, const char *emission EINA_UNUSED, const char *source)
+{
+   struct weekeyboard *wkb = data;
+   char *src;
+   const char *key;
+
+   src = strdup(source);
+   key = strtok(src, ":"); /* ignore group */
+   key = strtok(NULL, ":");
+   if (key == NULL)
+       key = ":";
+
+   if (_wkb_ignore_key(wkb, key))
+     {
+        printf("Ignoring key '%s'\n", key);
+        goto end;
+     }
+   else if (strcmp(key, "backspace") == 0)
+     {
+        if (strlen(wkb->preedit_str) == 0)
+             wl_input_method_context_delete_surrounding_text(wkb->im_ctx, -1, 1);
+        else
+          {
+             wkb->preedit_str[strlen(wkb->preedit_str) - 1] = '\0';
+             _wkb_send_preedit_str(wkb, -1);
+          }
+
+        goto end;
+     }
+   else if (strcmp(key, "enter") == 0)
+     {
+        _wkb_commit_preedit_str(wkb);
+        /* wl_input_method_context_keysym(wkb->im_ctx, wkb->serial, time, XKB_KEY_Return, key_state, mod_mask); */
+        goto end;
+     }
+   else if (strcmp(key, "space") == 0)
+     {
+        key = " ";
+     }
+
+   printf("KEY = '%s'\n", key);
+
+   _wkb_update_preedit_str(wkb, key);
+
+end:
+   free(src);
+}
+
+static void
+_wkb_im_ctx_surrounding_text(void *data, struct wl_input_method_context *im_ctx, const char *text, uint32_t cursor, uint32_t anchor)
+{
+   struct weekeyboard *wkb = data;
+
+   printf("%s()\n", __FUNCTION__);
+   free(wkb->surrounding_text);
+   wkb->surrounding_text = strdup(text);
+   wkb->surrounding_cursor = cursor;
+}
+
+static void
+_wkb_im_ctx_reset(void *data, struct wl_input_method_context *im_ctx)
+{
+   struct weekeyboard *wkb = data;
+
+   printf("%s()\n", __FUNCTION__);
+
+   if (strlen(wkb->preedit_str))
+     {
+        free(wkb->preedit_str);
+        wkb->preedit_str = strdup("");
+     }
+}
+
+static void
+_wkb_im_ctx_content_type(void *data, struct wl_input_method_context *im_ctx, uint32_t hint, uint32_t purpose)
+{
+   struct weekeyboard *wkb = data;
+
+   printf("%s(): im_context = %p hint = %d purpose = %d\n", __FUNCTION__, im_ctx, hint, purpose);
+
+   if (!wkb->context_changed)
+      return;
+
+   switch (purpose)
+     {
+      case WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS:
+      case WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER:
+           {
+              edje_object_signal_emit(wkb->edje_obj, "show,numeric", "");
+              break;
+           }
+      default:
+           {
+              edje_object_signal_emit(wkb->edje_obj, "show,alphanumeric", "");
+              break;
+           }
+     }
+
+   wkb->content_hint = hint;
+   wkb->content_purpose = purpose;
+
+   wkb->context_changed = EINA_FALSE;
+}
+
+static void
+_wkb_im_ctx_invoke_action(void *data, struct wl_input_method_context *im_ctx, uint32_t button, uint32_t index)
+{
+   struct weekeyboard *wkb = data;
+
+   printf("%s()\n", __FUNCTION__);
+   if (button != BTN_LEFT)
+      return;
+
+   _wkb_send_preedit_str(wkb, index);
+}
+
+static void
+_wkb_im_ctx_commit_state(void *data, struct wl_input_method_context *im_ctx, uint32_t serial)
+{
+   struct weekeyboard *wkb = data;
+
+   printf("%s()\n", __FUNCTION__);
+   if (wkb->surrounding_text)
+      fprintf(stderr, "Surrounding text updated: %s\n", wkb->surrounding_text);
+
+   wkb->serial = serial;
+   /* FIXME */
+   wl_input_method_context_language(im_ctx, wkb->serial, "en");//wkb->language);
+   wl_input_method_context_text_direction(im_ctx, wkb->serial, WL_TEXT_INPUT_TEXT_DIRECTION_LTR);//wkb->text_direction);
+}
+
+static void
+_wkb_im_ctx_preferred_language(void *data, struct wl_input_method_context *im_ctx, const char *language)
+{
+   struct weekeyboard *wkb = data;
+
+   if (language && wkb->language && !strcmp(language, wkb->language))
+      return;
+
+   if (wkb->language)
+     {
+        free(wkb->language);
+        wkb->language = NULL;
+     }
+
+   if (language)
+     {
+        wkb->language = strdup(language);
+        printf("Language changed, new: '%s\n", language);
+     }
+}
+
+static const struct wl_input_method_context_listener wkb_im_context_listener = {
+     _wkb_im_ctx_surrounding_text,
+     _wkb_im_ctx_reset,
+     _wkb_im_ctx_content_type,
+     _wkb_im_ctx_invoke_action,
+     _wkb_im_ctx_commit_state,
+     _wkb_im_ctx_preferred_language,
+};
+
+static void
+_wkb_im_activate(void *data, struct wl_input_method *input_method, struct wl_input_method_context *im_ctx)
+{
+   struct weekeyboard *wkb = data;
+   struct wl_array modifiers_map;
+
+   if (wkb->im_ctx)
+      wl_input_method_context_destroy(wkb->im_ctx);
+
+   if (wkb->preedit_str)
+      free(wkb->preedit_str);
+
+   wkb->preedit_str = strdup("");
+   wkb->content_hint = WL_TEXT_INPUT_CONTENT_HINT_NONE;
+   wkb->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NORMAL;
+   free(wkb->language);
+   wkb->language = NULL;
+   free(wkb->surrounding_text);
+   wkb->surrounding_text = NULL;
+   wkb->serial = 0;
+
+   wkb->im_ctx = im_ctx;
+   wl_input_method_context_add_listener(im_ctx, &wkb_im_context_listener, wkb);
+
+   /*
+   wl_array_init(&modifiers_map);
+
+   keysym_modifiers_add(&modifiers_map, "Shift");
+   keysym_modifiers_add(&modifiers_map, "Control");
+   keysym_modifiers_add(&modifiers_map, "Mod1");
+
+   wl_input_method_context_modifiers_map(im_ctx, &modifiers_map);
+
+   wkb->keysym.shift_mask = keysym_modifiers_get_mask(&modifiers_map, "Shift");
+
+   wl_array_release(&modifiers_map);
+   */
+
+   /* FIXME */
+   wl_input_method_context_language(im_ctx, wkb->serial, "en");//wkb->language);
+   wl_input_method_context_text_direction(im_ctx, wkb->serial, WL_TEXT_INPUT_TEXT_DIRECTION_LTR);//wkb->text_direction);
+
+   wkb->context_changed = EINA_TRUE;
+   evas_object_show(wkb->edje_obj);
+}
+
+static void
+_wkb_im_deactivate(void *data, struct wl_input_method *input_method, struct wl_input_method_context *im_ctx)
+{
+   struct weekeyboard *wkb = data;
+
+   if (!wkb->im_ctx)
+      return;
+
+   wl_input_method_context_destroy(wkb->im_ctx);
+   wkb->im_ctx = NULL;
+   evas_object_hide(wkb->edje_obj);
+}
+
+static const struct wl_input_method_listener wkb_im_listener = {
+     _wkb_im_activate,
+     _wkb_im_deactivate
+};
+
+
+static Eina_Bool
+_wkb_ui_setup(struct weekeyboard *wkb)
+{
+   char path[PATH_MAX];
+   Evas *evas;
+   Evas_Coord w, h;
+   char *ignore_keys;
+
+   ecore_evas_alpha_set(wkb->ee, EINA_TRUE);
+   ecore_evas_title_set(wkb->ee, "EFL virtual keyboard");
+
+   evas = ecore_evas_get(wkb->ee);
+   wkb->edje_obj = edje_object_add(evas);
+   /*ecore_evas_object_associate(wkb->ee, edje_obj, ECORE_EVAS_OBJECT_ASSOCIATE_BASE);*/
+
+   /* Check which theme we should use according to the screen width */
+   ecore_wl_screen_size_get(&w, &h);
+   if (w >= 720)
+      w = 720;
+   else
+      w = 600;
+
+   sprintf(path, PKGDATADIR"/default_%d.edj", w);
+   printf("Loading edje file: '%s'\n", path);
+
+   if (!edje_object_file_set(wkb->edje_obj, path, "main"))
+     {
+        int err = edje_object_load_error_get(wkb->edje_obj);
+        fprintf(stderr, "error loading the edje file:%s\n", edje_load_error_str(err));
+        return EINA_FALSE;
+     }
+
+   edje_object_size_min_get(wkb->edje_obj, &w, &h);
+   if (w == 0 || h == 0)
+     {
+        edje_object_size_min_restricted_calc(wkb->edje_obj, &w, &h, w, h);
+        if (w == 0 || h == 0)
+           edje_object_parts_extends_calc(wkb->edje_obj, NULL, NULL, &w, &h);
+     }
+
+   ecore_evas_move_resize(wkb->ee, 0, 0, w, h);
+   evas_object_move(wkb->edje_obj, 0, 0);
+   evas_object_resize(wkb->edje_obj, w, h);
+   evas_object_size_hint_min_set(wkb->edje_obj, w, h);
+   evas_object_size_hint_max_set(wkb->edje_obj, w, h);
+
+   edje_object_signal_callback_add(wkb->edje_obj, "key_down", "*", _cb_wkb_on_key_down, wkb);
+   ecore_evas_callback_delete_request_set(wkb->ee, _cb_wkb_delete_request);
+
+   /*
+    * The keyboard surface is bigger than it appears so that we can show the
+    * key pressed animation without requiring the use of subsurfaces. Here we
+    * resize the input region of the surface to match the keyboard background
+    * image, so that we can pass mouse events to the surfaces that may be
+    * located below the keyboard.
+    */
+   if (wkb->win)
+     {
+        int x, y, w, h;
+        struct wl_region *input = wl_compositor_create_region(wkb->win->display->wl.compositor);
+
+        edje_object_part_geometry_get(wkb->edje_obj, "background", &x, &y, &w, &h);
+        wl_region_add(input, x, y, w, h);
+        wl_surface_set_input_region(wkb->surface, input);
+        wl_region_destroy(input);
+     }
+
+   /* special keys */
+   ignore_keys = edje_file_data_get(path, "ignore-keys");
+   if (!ignore_keys)
+     {
+        printf("Special keys file not found in '%s'\n", path);
+        goto end;
+     }
+
+   printf("Got ignore keys = %s\n", ignore_keys);
+   wkb->ignore_keys = eina_str_split(ignore_keys, "\n", 0);
+   free(ignore_keys);
+
+end:
+   ecore_evas_show(wkb->ee);
+   return EINA_TRUE;
+}
+
+static void
+_wkb_setup(struct weekeyboard *wkb)
+{
+   struct wl_list *globals;
+   struct wl_registry *registry;
+   Ecore_Wl_Global *global;
+
+   struct wl_input_panel_surface *ips;
+
+   globals = ecore_wl_globals_get();
+   registry = ecore_wl_registry_get();
+   wl_list_for_each(global, globals, link)
+     {
+        if (strcmp(global->interface, "wl_input_panel") == 0)
+           wkb->ip = wl_registry_bind(registry, global->id, &wl_input_panel_interface, 1);
+        else if (strcmp(global->interface, "wl_input_method") == 0)
+           wkb->im = wl_registry_bind(registry, global->id, &wl_input_method_interface, 1);
+        else if (strcmp(global->interface, "wl_output") == 0)
+           wkb->output = wl_registry_bind(registry, global->id, &wl_output_interface, 1);
+     }
+
+   /* Set input panel surface */
+   wkb->win = ecore_evas_wayland_window_get(wkb->ee);
+   ecore_wl_window_type_set(wkb->win, ECORE_WL_WINDOW_TYPE_NONE);
+   wkb->surface = ecore_wl_window_surface_create(wkb->win);
+   ips = wl_input_panel_get_input_panel_surface(wkb->ip, wkb->surface);
+   wl_input_panel_surface_set_toplevel(ips, wkb->output, WL_INPUT_PANEL_SURFACE_POSITION_CENTER_BOTTOM);
+
+   /* Input method listener */
+   wl_input_method_add_listener(wkb->im, &wkb_im_listener, wkb);
+}
+
+static void
+_wkb_free(struct weekeyboard *wkb)
+{
+   if (wkb->im_ctx)
+      wl_input_method_context_destroy(wkb->im_ctx);
+
+   if (wkb->ignore_keys)
+     {
+        free(*wkb->ignore_keys);
+        free(wkb->ignore_keys);
+     }
+
+   evas_object_del(wkb->edje_obj);
+   free(wkb->preedit_str);
+   free(wkb->surrounding_text);
+}
+
+static Eina_Bool
+_wkb_check_evas_engine(struct weekeyboard *wkb)
+{
+   Eina_Bool ret = EINA_FALSE;
+   char *env = getenv("ECORE_EVAS_ENGINE");
+
+   if (!env)
+     {
+        if (ecore_evas_engine_type_supported_get(ECORE_EVAS_ENGINE_WAYLAND_SHM))
+           env = "wayland_shm";
+        else if (ecore_evas_engine_type_supported_get(ECORE_EVAS_ENGINE_WAYLAND_EGL))
+           env = "wayland_egl";
+        else
+          {
+             printf("ERROR: Ecore_Evas does must be compiled with support for Wayland engines\n");
+             goto err;
+          }
+     }
+   else if (strcmp(env, "wayland_shm") != 0 && strcmp(env, "wayland_egl") != 0)
+     {
+        printf("ERROR: ECORE_EVAS_ENGINE must be set to either 'wayland_shm' or 'wayland_egl'\n");
+        goto err;
+     }
+
+   wkb->ee_engine = env;
+   ret = EINA_TRUE;
+
+err:
+   return ret;
+}
+
+int
+main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
+{
+   struct weekeyboard wkb = {0};
+   int ret = EXIT_FAILURE;
+
+   if (!ecore_init())
+      return ret;
+
+   if (!ecore_evas_init())
+      goto ecore_err;
+
+   if (!edje_init())
+      goto ee_err;
+
+   if (!_wkb_check_evas_engine(&wkb))
+      goto edj_err;
+
+   printf("SELECTED ENGINE = %s\n", wkb.ee_engine);
+   wkb.ee = ecore_evas_new(wkb.ee_engine, 0, 0, 1, 1, "frame=0");
+
+   if (!wkb.ee)
+     {
+        printf("ERROR: Unable to create Ecore_Evas object\n");
+        goto edj_err;
+     }
+
+   _wkb_setup(&wkb);
+
+   if (!_wkb_ui_setup(&wkb))
+      goto end;
+
+   ecore_main_loop_begin();
+
+   ret = EXIT_SUCCESS;
+
+   _wkb_free(&wkb);
+
+end:
+   ecore_evas_free(wkb.ee);
+
+edj_err:
+   edje_shutdown();
+
+ee_err:
+   ecore_evas_shutdown();
+
+ecore_err:
+   ecore_shutdown();
+
+   return ret;
+}