From 562d8297a8a6099541b41bc9f98f12ff6b06d996 Mon Sep 17 00:00:00 2001 From: "Eduardo Lima (Etrunko)" Date: Fri, 16 Aug 2013 17:08:23 -0300 Subject: [PATCH] Initial commit Signed-off-by: Eduardo Lima (Etrunko) --- .gitignore | 33 + AUTHORS | 1 + COPYING | 202 ++++ INSTALL | 0 Makefile.am | 9 + README | 0 autogen.sh | 9 + configure.ac | 66 ++ data/.gitignore | 1 + data/themes/Makefile.am | 51 + data/themes/default/default.edc | 1050 ++++++++++++++++++++ data/themes/default/default_600.edc | 26 + data/themes/default/default_720.edc | 26 + data/themes/default/fonts/DroidSans-Bold.ttf | Bin 0 -> 42480 bytes data/themes/default/fonts/DroidSans.ttf | Bin 0 -> 41028 bytes data/themes/default/fonts/LICENSE.txt | 202 ++++ data/themes/default/ignorekeys.txt | 5 + data/themes/default/images/icon-backspace.png | Bin 0 -> 1285 bytes data/themes/default/images/icon-enter.png | Bin 0 -> 1018 bytes data/themes/default/images/icon-language.png | Bin 0 -> 2596 bytes data/themes/default/images/icon-shift-active.png | Bin 0 -> 734 bytes data/themes/default/images/icon-shift.png | Bin 0 -> 890 bytes data/themes/default/images/icon-space.png | Bin 0 -> 312 bytes data/themes/default/images/key-default-pressed.png | Bin 0 -> 1679 bytes data/themes/default/images/key-default.png | Bin 0 -> 1837 bytes data/themes/default/images/key-hint-bg.png | Bin 0 -> 1515 bytes data/themes/default/images/key-hint.png | Bin 0 -> 1716 bytes data/themes/default/images/key-special-pressed.png | Bin 0 -> 1681 bytes data/themes/default/images/key-special.png | Bin 0 -> 1819 bytes protocol/Makefile.am | 3 + protocol/input-method.xml | 283 ++++++ protocol/text.xml | 346 +++++++ src/Makefile.am | 51 + src/wkb-ibus-config-eet-test.c | 46 + src/wkb-ibus-config-eet.c | 962 ++++++++++++++++++ src/wkb-ibus-config-eet.h | 34 + src/wkb-ibus-config.c | 170 ++++ src/wkb-ibus-panel.c | 831 ++++++++++++++++ src/wkb-ibus-test.c | 69 ++ src/wkb-ibus.c | 507 ++++++++++ src/wkb-ibus.h | 69 ++ src/wkb-main.c | 601 +++++++++++ 42 files changed, 5653 insertions(+) create mode 100644 .gitignore create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 README create mode 100755 autogen.sh create mode 100644 configure.ac create mode 100644 data/.gitignore create mode 100644 data/themes/Makefile.am create mode 100644 data/themes/default/default.edc create mode 100644 data/themes/default/default_600.edc create mode 100644 data/themes/default/default_720.edc create mode 100644 data/themes/default/fonts/DroidSans-Bold.ttf create mode 100644 data/themes/default/fonts/DroidSans.ttf create mode 100644 data/themes/default/fonts/LICENSE.txt create mode 100644 data/themes/default/ignorekeys.txt create mode 100644 data/themes/default/images/icon-backspace.png create mode 100644 data/themes/default/images/icon-enter.png create mode 100644 data/themes/default/images/icon-language.png create mode 100644 data/themes/default/images/icon-shift-active.png create mode 100644 data/themes/default/images/icon-shift.png create mode 100644 data/themes/default/images/icon-space.png create mode 100644 data/themes/default/images/key-default-pressed.png create mode 100644 data/themes/default/images/key-default.png create mode 100644 data/themes/default/images/key-hint-bg.png create mode 100644 data/themes/default/images/key-hint.png create mode 100644 data/themes/default/images/key-special-pressed.png create mode 100644 data/themes/default/images/key-special.png create mode 100644 protocol/Makefile.am create mode 100644 protocol/input-method.xml create mode 100644 protocol/text.xml create mode 100644 src/Makefile.am create mode 100644 src/wkb-ibus-config-eet-test.c create mode 100644 src/wkb-ibus-config-eet.c create mode 100644 src/wkb-ibus-config-eet.h create mode 100644 src/wkb-ibus-config.c create mode 100644 src/wkb-ibus-panel.c create mode 100644 src/wkb-ibus-test.c create mode 100644 src/wkb-ibus.c create mode 100644 src/wkb-ibus.h create mode 100644 src/wkb-main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d005cda --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +aclocal.m4 +libtool.m4 +ltoptions.m4 +ltsugar.m4 +ltversion.m4 +lt~obsolete.m4 +autom4te.cache +config.* +configure +depcomp +install-sh +libtool +ltmain.sh +Makefile +Makefile.in +missing +patch +weekeyboard +stamp-h1 +*.o +*.lo +.deps +.libs +*.orig +*.rej +*.bak +*~ +input-method-client-protocol.h +input-method-protocol.c +text-client-protocol.h +text-protocol.c +weekeyboard-ibus-test +weekeyboard-config-eet-test diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..5e00638 --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Eduardo Lima (Etrunko) diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/COPYING @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..e69de29 diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..3cdce98 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,9 @@ +SUBDIRS=protocol src data/themes + +clean-local: + rm -f $(top_builddir)/install-sh + rm -f $(top_builddir)/missing + rm -f $(top_builddir)/config.guess + rm -f $(top_builddir)/ltmain.sh + rm -f $(top_builddir)/depcomp + rm -f $(top_builddir)/config.sub diff --git a/README b/README new file mode 100644 index 0000000..e69de29 diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..916169a --- /dev/null +++ b/autogen.sh @@ -0,0 +1,9 @@ +#! /bin/sh + +test -n "$srcdir" || srcdir=`dirname "$0"` +test -n "$srcdir" || srcdir=. +( + cd "$srcdir" && + autoreconf --force -v --install +) || exit +test -n "$NOCONFIGURE" || "$srcdir/configure" "$@" diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..e114d0d --- /dev/null +++ b/configure.ac @@ -0,0 +1,66 @@ +m4_define([wkb_major], [0]) +m4_define([wkb_minor], [0]) +m4_define([wkb_micro], [1]) +m4_define([wkb_version], [wkb_major.wkb_minor.wkb_micro]) + +AC_PREREQ([2.64]) +AC_INIT([weekeyboard], [wkb_version]) + +AC_SUBST([weekeyboard_MAJOR], [wkb_major]) +AC_SUBST([weekeyboard_MINOR], [wkb_minor]) +AC_SUBST([weekeyboard_MICRO], [wkb_micro]) +AC_SUBST([weekeyboard_VERSION], [wkb_version]) + +AC_CONFIG_HEADERS([config.h]) + +AM_INIT_AUTOMAKE([1.11 -Wall -Wextra parallel-tests foreign color-tests]) + +AM_SILENT_RULES([yes]) + +# Check for programs +AC_PROG_CC +AC_PROG_SED + +# Initialize libtool +LT_PREREQ([2.2]) +LT_INIT([disable-static]) + +PKG_PROG_PKG_CONFIG() + +PKG_CHECK_MODULES(WAYLAND, [wayland-client >= 1.2.0]) +PKG_CHECK_MODULES(EFL, [eina eet evas ecore ecore-evas ecore-wayland edje]) + +AC_ARG_WITH(edje-cc, + AS_HELP_STRING([--with-edje-cc=PATH], [Path to edje_cc binary]), + [EDJE_CC_PATH=${withval}], [EDJE_CC_PATH=$($PKG_CONFIG --variable=prefix edje)/bin/edje_cc]) +AC_SUBST([EDJE_CC_PATH]) + + +AC_ARG_ENABLE([ibus], + [AC_HELP_STRING([--disable-ibus], + [Disable integration with IBus input method system])], + [], [enable_ibus=yes]) + +AM_CONDITIONAL(ENABLE_IBUS, test "x$enable_ibus" = "xyes") + +if test "x$enable_ibus" = "xyes"; then + PKG_CHECK_MODULES(ELDBUS, [eldbus]) + AC_CHECK_PROG([have_ibus], [ibus], [yes], [no]) + + AS_IF([ test "x$have ibus" = "xno" ], + [ AC_MSG_ERROR([The ibus executable was not found.]) ]) + + IBUS_ADDR=`ibus address > /dev/null 2>&1` + AS_IF([ test $? -ne 0 ], + [ AC_MSG_WARN([The ibus executable does not support 'address' argument.]) ]) + + AC_DEFINE(BUILD_IBUS, [1], [Build integration with IBus input method system]) +fi + +WAYLAND_SCANNER_RULES(['$(top_srcdir)/protocol']) + +AC_CONFIG_FILES([Makefile + src/Makefile + data/themes/Makefile + protocol/Makefile]) +AC_OUTPUT diff --git a/data/.gitignore b/data/.gitignore new file mode 100644 index 0000000..2f69ae5 --- /dev/null +++ b/data/.gitignore @@ -0,0 +1 @@ +*.edj diff --git a/data/themes/Makefile.am b/data/themes/Makefile.am new file mode 100644 index 0000000..fd143f5 --- /dev/null +++ b/data/themes/Makefile.am @@ -0,0 +1,51 @@ +MAINTAINERCLEANFILES = Makefile.in + +EDJE_CC = @EDJE_CC_PATH@ +EDJE_FLAGS_VERBOSE_ = +EDJE_FLAGS_VERBOSE_0 = +EDJE_FLAGS_VERBOSE_1 = -v +EDJE_FLAGS = $(EDJE_FLAGS_VERBOSE_$(V)) + +filesdir = $(pkgdatadir) +files_DATA = default_600.edj \ + default_720.edj + +DEFAULT_FILES = default/default.edc \ + default/default_600.edc \ + default/default_720.edc \ + default/ignorekeys.txt \ + default/fonts/DroidSans-Bold.ttf \ + default/fonts/DroidSans.ttf \ + default/images/key-hint-bg.png \ + default/images/icon-language.png \ + default/images/icon-backspace.png \ + default/images/key-special.png \ + default/images/icon-space.png \ + default/images/key-hint.png \ + default/images/icon-shift.png \ + default/images/icon-shift-active.png \ + default/images/icon-enter.png \ + default/images/key-special-pressed.png \ + default/images/key-default.png \ + default/images/key-default-pressed.png + +EXTRA_DIST = $(DEFAULT_FILES) + +default_600.edj: Makefile default/default_600.edc $(default_FILES) + $(EDJE_CC) $(EDJE_FLAGS) \ + -dd $(top_srcdir)/data/themes/default \ + -id $(top_srcdir)/data/themes/default/images \ + -fd $(top_srcdir)/data/themes/default/fonts \ + $(top_srcdir)/data/themes/default/default_600.edc \ + $(top_builddir)/data/themes/default_600.edj + +default_720.edj: Makefile default/default_720.edc $(default_FILES) + $(EDJE_CC) $(EDJE_FLAGS) \ + -dd $(top_srcdir)/data/themes/default \ + -id $(top_srcdir)/data/themes/default/images \ + -fd $(top_srcdir)/data/themes/default/fonts \ + $(top_srcdir)/data/themes/default/default_720.edc \ + $(top_builddir)/data/themes/default_720.edj + +clean-local: + rm -f $(top_builddir)/data/themes/*.edj diff --git a/data/themes/default/default.edc b/data/themes/default/default.edc new file mode 100644 index 0000000..7275787 --- /dev/null +++ b/data/themes/default/default.edc @@ -0,0 +1,1050 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +images { + image: "icon-backspace.png" COMP; + image: "icon-enter.png" COMP; + image: "icon-language.png" COMP; + image: "icon-shift-active.png" COMP; + image: "icon-shift.png" COMP; + image: "icon-space.png" COMP; + + image: "key-default.png" COMP; + image: "key-default-pressed.png" COMP; + image: "key-hint.png" COMP; + image: "key-hint-bg.png" COMP; + image: "key-special.png" COMP; + image: "key-special-pressed.png" COMP; +} + +fonts { + font: "DroidSans.ttf" "DroidSans"; + font: "DroidSans-Bold.ttf" "DroidSansBold"; +} + +data { + file: "ignore-keys" "ignorekeys.txt"; +} + +collections { + group { + name: "main"; + + min: MIN_WIDTH MIN_HEIGHT; + max: MAX_WIDTH MAX_HEIGHT; + + parts { + part { + name: "rect_bg"; + mouse_events: 0; + type: RECT; + description { + state: "default" 0.0; + color: 255 255 255 0; + rel1 { + relative: 0.0 0.0; + offset: 0 0; + } + rel2 { + relative: 1.0 1.0; + offset: -1 -1; + } + } + } + + part { + name: "background"; + mouse_events: 1; + pointer_mode: NOGRAB; + type: RECT; + description { + state: "default" 0.0; + color: 214 215 218 255; + rel1 { + relative: 0.0 0.0; + offset: 0 (150*SCALE); + } + rel2 { + relative: 1.0 1.0; + offset: -1 -1; + } + } + } + } + +#define KEY_GROUP(_name) \ + parts { \ + part { \ + name: _name"_clip"; \ + type: RECT; \ + description { \ + state: "default" 0.0; \ + rel1 { \ + relative: 0.0 0.0; \ + offset: 0 0; \ + } \ + rel2 { \ + relative: 1.0 1.0; \ + offset: -1 -1; \ + } \ + } \ + description { \ + state: "hidden" 0.0; \ + inherit: "default" 0.0; \ + visible: 0; \ + } \ + } \ + part { \ + name: _name; \ + type: GROUP; \ + source: _name; \ + clip_to: _name"_clip"; \ + description { \ + state: "default" 0.0; \ + rel1 { \ + to: "background"; \ + relative: 0.0 0.0; \ + offset: (5*SCALE) (10*SCALE); \ + } \ + rel2 { \ + to: "background"; \ + relative: 1.0 1.0; \ + offset: -1 -1; \ + } \ + } \ + } \ + } \ + programs { \ + program { \ + name: "show-"_name; \ + action: STATE_SET "default" 0.0; \ + target: _name"_clip"; \ + } \ + program { \ + name: "hide-"_name; \ + action: STATE_SET "hidden" 0.0; \ + target: _name"_clip"; \ + } \ + } + + KEY_GROUP("alphanum") + KEY_GROUP("numeric") + KEY_GROUP("special-1") + KEY_GROUP("special-2") + KEY_GROUP("fixed") + + programs { + program { + name: "alphanum_show"; + signal: "show,alphanumeric"; + after: "show-alphanum"; + after: "hide-numeric"; + after: "hide-special-1"; + after: "hide-special-2"; + after: "show-fixed"; + } + + program { + name: "numeric_show"; + signal: "show,numeric"; + after: "show-numeric"; + after: "hide-alphanum"; + after: "hide-special-1"; + after: "hide-special-2"; + after: "hide-fixed"; + } + + program { + name: "special-1_show"; + signal: "show,special,1"; + after: "show-special-1"; + after: "hide-numeric"; + after: "hide-alphanum"; + after: "hide-special-2"; + after: "show-fixed"; + } + + program { + name: "special-2_show"; + signal: "show,special,2"; + after: "show-special-2"; + after: "hide-numeric"; + after: "hide-alphanum"; + after: "hide-special-1"; + after: "show-fixed"; + } + + program { + name: "?123_clicked"; + signal: "key_down"; + source: "alphanum:?123"; + after: "special-1_show"; + } + program { + name: "special-1_abc_clicked"; + signal: "key_down"; + source: "special-1:abc"; + after: "alphanum_show"; + } + program { + name: "special-2_abc_clicked"; + signal: "key_down"; + source: "special-2:abc"; + after: "alphanum_show"; + } + program { + name: "1/2_clicked"; + signal: "key_down"; + source: "special-1:1/2"; + after: "special-2_show"; + } + program { + name: "2/2_clicked"; + signal: "key_down"; + source: "special-2:2/2"; + after: "special-1_show"; + } + program { + name: "init"; + signal: "show"; + after: "alphanum_show"; + } + } + } + + group { + name: "alphanum"; + +#define MOUSE_DOWN_UP_PROGRAMS \ + script { \ + public shift_pressed = 0; \ + public mouse_down = 0; \ + public long_press_timer = 0; \ + public long_press = 0; \ + public pressed_key; \ + \ + public _set_long_press(val) { \ + new _cur[20]; \ + new _timer; \ + _timer = get_int(long_press_timer); \ + if (_timer) { \ + cancel_timer(_timer); \ + set_int(long_press_timer, 0); \ + } \ + set_int(long_press, val); \ + if (!val) \ + return; \ + get_str(pressed_key, _cur, 20); \ + if (strlen(_cur) > 0) { \ + emit("long_press", _cur); \ + } \ + } \ + \ + _set_key_pressed(_key[]) { \ + new _cur[20]; \ + new _prg[30]; \ + new _timer; \ + get_str(pressed_key, _cur, 20); \ + if (strlen(_cur) > 0) { \ + _set_key_released(_cur); \ + } \ + set_str(pressed_key, _key); \ + _timer = timer(1.0, "_set_long_press", 1); \ + set_int(long_press_timer, _timer); \ + snprintf(_prg, 30, "key-press-%s", _key); \ + run_program(get_program_id(_prg)); \ + } \ + \ + _set_key_released(_key[]) { \ + new _prg[30]; \ + _set_long_press(0); \ + set_str(pressed_key, ""); \ + snprintf(_prg, 30, "key-release-%s", _key); \ + run_program(get_program_id(_prg)); \ + } \ + } \ + programs { \ + program { \ + name: "mouse-down"; \ + signal: "mouse,down,1"; \ + source: "*"; \ + script { \ + set_int(mouse_down, 1); \ + } \ + } \ + program { \ + name: "mouse-up"; \ + signal: "mouse,up,1"; \ + source: "*"; \ + script { \ + set_int(mouse_down, 0); \ + } \ + } \ + } + + MOUSE_DOWN_UP_PROGRAMS + parts { +#undef INIT_HSPACE +#define INIT_HSPACE 5 +#define KEY_WIDTH (65*SCALE) +#define KEY_HEIGHT (90*SCALE) +#define COL_SPACE 5 +#define KEY_OFFSET(index) ((COL_SPACE+KEY_WIDTH)*index)+INIT_HSPACE + +#define FIRST_ROW 0 +#define ROW_SPACE (20*SCALE) + +#define SKEY_FULL(key_low, key_up, key_name, key_alt, x, y) \ + part { \ + name: "key-img-"key_name; \ + type: IMAGE; \ + mouse_events: 0; \ + description { \ + state: "default" 0.0; \ + min: KEY_WIDTH KEY_HEIGHT; \ + max: KEY_WIDTH KEY_HEIGHT; \ + fixed: 1 1; \ + rel1 { \ + relative: 0.0 0.0; \ + offset: (x) (y); \ + } \ + rel2 { \ + relative: 0.0 0.0; \ + offset: (x+KEY_WIDTH-1) (y+KEY_HEIGHT-1); \ + } \ + image { \ + normal: "key-default.png"; \ + border: 8 8 10 10; \ + } \ + } \ + description { \ + state: "down" 0.0; \ + inherit: "default" 0.0; \ + rel1.offset: (x+1) (y+1); \ + rel2.offset: (x+1+KEY_WIDTH-1) (y+1+KEY_HEIGHT-1); \ + image.normal: "key-default-pressed.png"; \ + } \ + } \ + part { \ + name: "key-bg-"key_name; \ + type: RECT; \ + pointer_mode: NOGRAB; \ + description { \ + state: "default" 0.0; \ + color: 0 0 0 0; \ + rel1 { \ + to: "key-img-"key_name; \ + relative: 0.0 0.0; \ + offset: 3 2; \ + } \ + rel2 { \ + to: "key-img-"key_name; \ + relative: 1.0 1.0; \ + offset: -4 -6; \ + } \ + } \ + } \ + part { \ + name: "key-lbl-"key_name; \ + type: TEXT; \ + mouse_events: 0; \ + effect: SHADOW BOTTOM; \ + description { \ + state: "default" 0.0; \ + color: 63 67 72 255; \ + color2: 240 240 240 255; \ + color3: 240 240 240 255; \ + rel1 { \ + to: "key-bg-"key_name; \ + relative: 0.0 0.4; \ + } \ + rel2 { \ + to: "key-bg-"key_name; \ + relative: 1.0 0.9; \ + } \ + text { \ + font: "DroidSans"; \ + size: (40*SCALE); \ + text: key_low; \ + } \ + } \ + } \ + part { \ + name: "key-lbl-alt-"key_name; \ + type: TEXT; \ + mouse_events: 0; \ + effect: SHADOW BOTTOM; \ + description { \ + state: "default" 0.0; \ + color: 63 67 72 255; \ + color2: 240 240 240 255; \ + color3: 240 240 240 255; \ + rel1 { \ + to: "key-bg-"key_name; \ + relative: 0.0 0.1; \ + } \ + rel2 { \ + to: "key-bg-"key_name; \ + relative: 1.0 0.4; \ + } \ + text { \ + font: "DroidSans"; \ + size: (20*SCALE); \ + align: 0.8 0.0; \ + text: key_alt; \ + } \ + } \ + } \ + part { \ + name: "key-img-hint-"key_name; \ + type: IMAGE; \ + mouse_events: 0; \ + description { \ + state: "default" 0.0; \ + min: KEY_WIDTH KEY_HEIGHT; \ + max: KEY_WIDTH KEY_HEIGHT; \ + fixed: 1 1; \ + rel1 { \ + to: "key-img-"key_name; \ + relative: 0.0 0.0; \ + offset: 0 ((-20*SCALE)-KEY_HEIGHT); \ + } \ + rel2 { \ + to: "key-img-"key_name; \ + relative: 1.0 0.0; \ + offset: 0 (-20*SCALE); \ + } \ + image { \ + normal: "key-hint.png"; \ + border: 8 8 10 10; \ + } \ + visible: 0; \ + } \ + description { \ + state: "down" 0.0; \ + inherit: "default" 0.0; \ + visible: 1; \ + } \ + } \ + part { \ + name: "key-lbl-hint-"key_name; \ + type: TEXT; \ + mouse_events: 0; \ + effect: SHADOW BOTTOM; \ + description { \ + state: "default" 0.0; \ + color: 63 67 72 255; \ + color2: 240 240 240 255; \ + color3: 240 240 240 255; \ + rel1 { \ + to: "key-img-hint-"key_name; \ + relative: 0.0 0.0; \ + } \ + rel2 { \ + to: "key-img-hint-"key_name; \ + relative: 1.0 1.0; \ + } \ + text { \ + font: "DroidSans"; \ + size: (44*SCALE); \ + text: key_low; \ + } \ + visible: 0; \ + } \ + description { \ + state: "down" 0.0; \ + inherit: "default" 0.0; \ + visible: 1; \ + } \ + } \ + programs { \ + program { \ + name: "key-mouse-in-"key_name; \ + signal: "mouse,in"; \ + source: "key-bg-"key_name; \ + script { \ + if (get_int(mouse_down) == 0) \ + return; \ + _set_key_pressed(key_name); \ + } \ + } \ + program { \ + name: "key-mouse-out-"key_name; \ + signal: "mouse,out"; \ + source: "key-bg-"key_name; \ + script { \ + if (get_int(mouse_down) == 0) \ + return; \ + _set_key_released(key_name); \ + } \ + } \ + program { \ + name: "key-mouse-down-"key_name; \ + signal: "mouse,down,1"; \ + source: "key-bg-"key_name; \ + script { \ + _set_key_pressed(key_name); \ + } \ + } \ + program { \ + name: "key-mouse-up-"key_name; \ + signal: "mouse,up,1"; \ + source: "key-bg-"key_name; \ + script { \ + if (get_int(long_press) == 0) { \ + if (get_int(shift_pressed) == 0) \ + emit("key_down", key_low); \ + else \ + emit("key_down", key_up); \ + } else { \ + if (strcmp(key_alt, " ")) \ + emit("key_down", key_alt); \ + else if (get_int(shift_pressed) == 0) \ + emit("key_down", key_low); \ + else \ + emit("key_down", key_up); \ + } \ + _set_key_released(key_name); \ + } \ + } \ + program { \ + name: "key-press-"key_name; \ + action: STATE_SET "down" 0.0; \ + target: "key-img-"key_name; \ + target: "key-img-hint-"key_name; \ + target: "key-lbl-hint-"key_name; \ + } \ + program { \ + name: "key-release-"key_name; \ + action: STATE_SET "default" 0.0; \ + transition: LINEAR 0.2; \ + target: "key-img-"key_name; \ + target: "key-img-hint-"key_name; \ + target: "key-lbl-hint-"key_name; \ + after: "shift-pressed-"key_name; \ + } \ + program { \ + name: "long-press-"key_name; \ + signal: "long_press"; \ + source: key_name; \ + script { \ + if (strcmp(key_alt, " ")) \ + set_text(PART:"key-lbl-hint-"key_name, key_alt); \ + } \ + } \ + program { \ + name: "shift-pressed-"key_name; \ + signal: "key_down"; \ + source: "shift"; \ + script { \ + if (get_int(shift_pressed) == 0) { \ + set_text(PART:"key-lbl-"key_name, key_low); \ + set_text(PART:"key-lbl-hint-"key_name, key_low); \ + } else { \ + set_text(PART:"key-lbl-"key_name, key_up); \ + set_text(PART:"key-lbl-hint-"key_name, key_up); \ + } \ + } \ + } \ + } +#define KEY_FULL(low, up, alt, x, y) SKEY_FULL(low, up, low, alt, x, y) +#define SKEY(name, text, alt, x, y) SKEY_FULL(name, name, text, alt, x, y) +#define KEY(v, alt, x, y) SKEY(v, v, alt, x, y) + + KEY_FULL("q", "Q", "1", KEY_OFFSET(0), FIRST_ROW) + KEY_FULL("w", "W", "2", KEY_OFFSET(1), FIRST_ROW) + KEY_FULL("e", "E", "3", KEY_OFFSET(2), FIRST_ROW) + KEY_FULL("r", "R", "4", KEY_OFFSET(3), FIRST_ROW) + KEY_FULL("t", "T", "5", KEY_OFFSET(4), FIRST_ROW) + KEY_FULL("y", "Y", "6", KEY_OFFSET(5), FIRST_ROW) + KEY_FULL("u", "U", "7", KEY_OFFSET(6), FIRST_ROW) + KEY_FULL("i", "I", "8", KEY_OFFSET(7), FIRST_ROW) + KEY_FULL("o", "O", "9", KEY_OFFSET(8), FIRST_ROW) + KEY_FULL("p", "P", "0", KEY_OFFSET(9), FIRST_ROW) + +#undef INIT_HSPACE +#define INIT_HSPACE (45*SCALE) +#define SECOND_ROW FIRST_ROW+KEY_HEIGHT+ROW_SPACE + + KEY_FULL("a", "A", "-", KEY_OFFSET(0), SECOND_ROW) + KEY_FULL("s", "S", "@", KEY_OFFSET(1), SECOND_ROW) + KEY_FULL("d", "D", "*", KEY_OFFSET(2), SECOND_ROW) + KEY_FULL("f", "F", "^", KEY_OFFSET(3), SECOND_ROW) + KEY_FULL("g", "G", ":", KEY_OFFSET(4), SECOND_ROW) + KEY_FULL("h", "H", ";", KEY_OFFSET(5), SECOND_ROW) + KEY_FULL("j", "J", "(", KEY_OFFSET(6), SECOND_ROW) + KEY_FULL("k", "K", ")", KEY_OFFSET(7), SECOND_ROW) + KEY_FULL("l", "L", "~", KEY_OFFSET(8), SECOND_ROW) + +#undef INIT_HSPACE +#define INIT_HSPACE (110*SCALE) +#define THIRD_ROW SECOND_ROW+KEY_HEIGHT+ROW_SPACE + + KEY_FULL("z", "Z", "/", KEY_OFFSET(0), THIRD_ROW) + KEY_FULL("x", "X", "'", KEY_OFFSET(1), THIRD_ROW) + KEY_FULL("c", "C", "\"", KEY_OFFSET(2), THIRD_ROW) + KEY_FULL("v", "V", ".", KEY_OFFSET(3), THIRD_ROW) + KEY_FULL("b", "B", ",", KEY_OFFSET(4), THIRD_ROW) + KEY_FULL("n", "N", "?", KEY_OFFSET(5), THIRD_ROW) + KEY_FULL("m", "M", "!", KEY_OFFSET(6), THIRD_ROW) + +#define KEY_SPECIAL(val, x, y, w) \ + part { \ + name: "key-img-"val; \ + type: IMAGE; \ + mouse_events: 0; \ + description { \ + state: "default" 0.0; \ + min: w KEY_HEIGHT; \ + max: w KEY_HEIGHT; \ + fixed: 1 1; \ + rel1 { \ + relative: 0.0 0.0; \ + offset: (x) (y); \ + } \ + rel2 { \ + relative: 0.0 0.0; \ + offset: (x+w-1) (y+KEY_HEIGHT-1); \ + } \ + image { \ + normal: "key-special.png"; \ + border: 8 8 10 10; \ + } \ + } \ + description { \ + state: "down" 0.0; \ + inherit: "default" 0.0; \ + rel1.offset: (x+1) (y+1); \ + rel2.offset: (x+1+w-1) (y+1+KEY_HEIGHT-1); \ + image.normal: "key-special-pressed.png"; \ + } \ + } \ + part { \ + name: "key-bg-"val; \ + type: RECT; \ + pointer_mode: NOGRAB; \ + description { \ + state: "default" 0.0; \ + rel1 { \ + to: "key-img-"val; \ + relative: 0.0 0.0; \ + offset: 3 2; \ + } \ + rel2 { \ + to: "key-img-"val; \ + relative: 1.0 1.0; \ + offset: -4 -6; \ + } \ + color: 0 0 0 0; \ + } \ + } \ + programs { \ + program { \ + name: "key-down-"val; \ + signal: "mouse,up,1"; \ + source: "key-bg-"val; \ + script { \ + emit("key_down", val); \ + run_program(PROGRAM:"key-release-"val); \ + } \ + } \ + program { \ + name: "key-mouse-in-"val; \ + signal: "mouse,in"; \ + source: "key-bg-"val; \ + script { \ + if (get_int(mouse_down) == 0) \ + return; \ + run_program(PROGRAM:"key-press-"val); \ + } \ + } \ + program { \ + name: "key-mouse-out-"val; \ + signal: "mouse,out"; \ + source: "key-bg-"val; \ + script { \ + if (get_int(mouse_down) == 0) \ + return; \ + run_program(PROGRAM:"key-release-"val); \ + } \ + } \ + program { \ + name: "key-press-"val; \ + signal: "mouse,down,1"; \ + source: "key-bg-"val; \ + action: STATE_SET "down" 0.0; \ + target: "key-img-"val; \ + target: "key-lbl-"val; \ + } \ + program { \ + name: "key-release-"val; \ + action: STATE_SET "default" 0.0; \ + transition: LINEAR 0.2; \ + target: "key-img-"val; \ + target: "key-lbl-"val; \ + } \ + } + +#define KEY_SPECIAL_TEXT(val, x, y, w) \ + KEY_SPECIAL(val, x, y, w) \ + part { \ + name: "key-lbl-"val; \ + type: TEXT; \ + mouse_events: 0; \ + effect: SHADOW BOTTOM; \ + description { \ + state: "default" 0.0; \ + color: 63 67 72 255; \ + color2: 240 240 240 255; \ + color3: 240 240 240 255; \ + rel1 { \ + to: "key-bg-"val; \ + relative: 0.0 0.4; \ + } \ + rel2 { \ + to: "key-bg-"val; \ + relative: 1.0 1.0; \ + } \ + text { \ + font: "DroidSans"; \ + size: (28*SCALE); \ + text: val; \ + } \ + } \ + } + +#define KEY_SPECIAL_ICON(val, x, y, w, icon_size) \ + KEY_SPECIAL(val, x, y, w) \ + part { \ + name: "key-lbl-"val; \ + type: IMAGE; \ + mouse_events: 0; \ + description { \ + state: "default" 0.0; \ + min: icon_size icon_size; \ + max: icon_size icon_size; \ + fixed: 1 1; \ + rel1 { \ + to: "key-bg-"val; \ + relative: 0.5 0.4; \ + } \ + rel2 { \ + to: "key-bg-"val; \ + relative: 0.5 0.8; \ + } \ + image.normal: "icon-"val".png"; \ + } \ + } \ + +#define FOURTH_ROW THIRD_ROW+KEY_HEIGHT+ROW_SPACE + KEY_SPECIAL_TEXT("?123", (5*SCALE), FOURTH_ROW, (95*SCALE)) + + part { + name: "key-img-shift"; + type: IMAGE; + mouse_events: 0; + description { + state: "default" 0.0; + min: (85*SCALE) KEY_HEIGHT; + max: (85*SCALE) KEY_HEIGHT; + fixed: 1 1; + rel1 { + relative: 0.0 0.0; + offset: (5*SCALE) (THIRD_ROW); + } + rel2 { + relative: 0.0 0.0; + offset: (((5+85)*SCALE)-1) (THIRD_ROW+KEY_HEIGHT-1); + } + image { + normal: "key-special.png"; + border: 8 8 10 10; + } + } + description { + state: "down" 0.0; + inherit: "default" 0.0; + rel1.offset: ((5*SCALE)+2) (THIRD_ROW+2); + rel2.offset: ((((5+85)*SCALE)+2)-1) (THIRD_ROW+2+KEY_HEIGHT-1); + image.normal: "key-special-pressed.png"; + } + } + part { + name: "key-bg-shift"; + type: RECT; + pointer_mode: NOGRAB; + description { + state: "default" 0.0; + rel1 { + to: "key-img-shift"; + relative: 0.0 0.0; + offset: 3 2; + } + rel2 { + to: "key-img-shift"; + relative: 1.0 1.0; + offset: -4 -6; + } + color: 0 0 0 0; + } + } + part { + name: "key-lbl-shift"; + type: IMAGE; + mouse_events: 0; + description { + state: "default" 0.0; + max: (50*SCALE) (50*SCALE); + min: (50*SCALE) (50*SCALE); + fixed: 1 1; + rel1 { + to: "key-bg-shift"; + relative: 0.5 0.4; + } + rel2 { + to: "key-bg-shift"; + relative: 0.5 0.8; + } + image.normal: "icon-shift.png"; + } + description { + state: "down" 0.0; + inherit: "default" 0.0; + image.normal: "icon-shift-active.png"; + } + } + programs { + program { + name: "key-press-shift"; + signal: "mouse,down,1"; + source: "key-bg-shift"; + action: STATE_SET "down" 0.0; + target: "key-img-shift"; + target: "key-lbl-shift"; + } + program { + name: "key-release-shift"; + action: STATE_SET "default" 0.0; + transition: LINEAR 0.2; + target: "key-img-shift"; + target: "key-lbl-shift"; + } + program { + name: "key-mouse-in-shift"; + signal: "mouse,in"; + source: "key-bg-shift"; + script { + if (get_int(mouse_down) == 0) + return; + run_program(PROGRAM:"key-press-shift"); + } + } + program { + name: "key-mouse-out-shift"; + signal: "mouse,out"; + source: "key-bg-shift"; + script { + if (get_int(mouse_down) == 0) + return; + run_program(PROGRAM:"key-release-shift"); + } + } + program { + name: "key-down-shift"; + signal: "mouse,up,1"; + source: "key-bg-shift"; + script { + emit("key_down", "shift"); + if (get_int(shift_pressed) == 0) { + run_program(PROGRAM:"key-press-shift"); + set_int(shift_pressed, 1); + } else { + run_program(PROGRAM:"key-release-shift"); + set_int(shift_pressed, 0); + } + } + } + } + } + } + + group { + name: "special-1"; + + MOUSE_DOWN_UP_PROGRAMS + parts { +#undef INIT_HSPACE +#define INIT_HSPACE 5 + + KEY("1", "#", KEY_OFFSET(0), FIRST_ROW) + KEY("2", "&", KEY_OFFSET(1), FIRST_ROW) + KEY("3", "%", KEY_OFFSET(2), FIRST_ROW) + KEY("4", "+", KEY_OFFSET(3), FIRST_ROW) + KEY("5", "=", KEY_OFFSET(4), FIRST_ROW) + KEY("6", "_", KEY_OFFSET(5), FIRST_ROW) + KEY("7", "\\", KEY_OFFSET(6), FIRST_ROW) + KEY("8", "|", KEY_OFFSET(7), FIRST_ROW) + KEY("9", "<", KEY_OFFSET(8), FIRST_ROW) + KEY("0", ">", KEY_OFFSET(9), FIRST_ROW) + +#undef INIT_HSPACE +#define INIT_HSPACE (45*SCALE) + + SKEY("-", "dash", "{", KEY_OFFSET(0), SECOND_ROW) + SKEY("@", "at", "}", KEY_OFFSET(1), SECOND_ROW) + SKEY("*", "star", "[", KEY_OFFSET(2), SECOND_ROW) + SKEY("^", "circumflex", "]", KEY_OFFSET(3), SECOND_ROW) + SKEY(":", "colon", "$", KEY_OFFSET(4), SECOND_ROW) + SKEY(";", "semi_colon", "£", KEY_OFFSET(5), SECOND_ROW) + SKEY("(", "open_par", "Â¥", KEY_OFFSET(6), SECOND_ROW) + SKEY(")", "close_par", "€", KEY_OFFSET(7), SECOND_ROW) + SKEY("~", "tilde", "₩", KEY_OFFSET(8), SECOND_ROW) + +#undef INIT_HSPACE +#define INIT_HSPACE (110*SCALE) + + SKEY("/", "slash", "¢", KEY_OFFSET(0), THIRD_ROW) + SKEY("'", "single_quote", "`", KEY_OFFSET(1), THIRD_ROW) + SKEY("\"", "double_quote", "°", KEY_OFFSET(2), THIRD_ROW) + SKEY(".", "dot", "˙", KEY_OFFSET(3), THIRD_ROW) + SKEY(",", "comma", "®", KEY_OFFSET(4), THIRD_ROW) + SKEY("?", "question", "©", KEY_OFFSET(5), THIRD_ROW) + SKEY("!", "exclamation", "¿", KEY_OFFSET(6), THIRD_ROW) + + KEY_SPECIAL_TEXT("1/2", (5*SCALE), THIRD_ROW, (85*SCALE)) + KEY_SPECIAL_TEXT("abc", (5*SCALE), FOURTH_ROW, (95*SCALE)) + } + } + + group { + name: "special-2"; + + MOUSE_DOWN_UP_PROGRAMS + parts { +#undef INIT_HSPACE +#define INIT_HSPACE 5 + + SKEY("#", "hash", "1", KEY_OFFSET(0), FIRST_ROW) + SKEY("&", "amp", "2", KEY_OFFSET(1), FIRST_ROW) + SKEY("%", "percent", "3", KEY_OFFSET(2), FIRST_ROW) + SKEY("+", "plus", "4", KEY_OFFSET(3), FIRST_ROW) + SKEY("=", "equal", "5", KEY_OFFSET(4), FIRST_ROW) + SKEY("_", "underline", "6", KEY_OFFSET(5), FIRST_ROW) + SKEY("\\", "backslash", "7", KEY_OFFSET(6), FIRST_ROW) + SKEY("|", "vert_bar", "8", KEY_OFFSET(7), FIRST_ROW) + SKEY("<", "less", "9", KEY_OFFSET(8), FIRST_ROW) + SKEY(">", "greater", "0", KEY_OFFSET(9), FIRST_ROW) + +#undef INIT_HSPACE +#define INIT_HSPACE (45*SCALE) + + SKEY("{", "open_brace", "-", KEY_OFFSET(0), SECOND_ROW) + SKEY("}", "close_brace", "@", KEY_OFFSET(1), SECOND_ROW) + SKEY("[", "open_bracket", "*", KEY_OFFSET(2), SECOND_ROW) + SKEY("]", "close_bracket", "^", KEY_OFFSET(3), SECOND_ROW) + SKEY("$", "dollar", ":", KEY_OFFSET(4), SECOND_ROW) + SKEY("£", "pound", ";", KEY_OFFSET(5), SECOND_ROW) + SKEY("Â¥", "yen", "(", KEY_OFFSET(6), SECOND_ROW) + SKEY("€", "euro", ")", KEY_OFFSET(7), SECOND_ROW) + SKEY("₩", "won", "~", KEY_OFFSET(8), SECOND_ROW) + +#undef INIT_HSPACE +#define INIT_HSPACE (110*SCALE) + + SKEY("¢", "cent" , "/", KEY_OFFSET(0), THIRD_ROW) + SKEY("`", "back_quote", "'", KEY_OFFSET(1), THIRD_ROW) + SKEY("°", "ring", "\"", KEY_OFFSET(2), THIRD_ROW) + SKEY("˙", "dot", ".", KEY_OFFSET(3), THIRD_ROW) + SKEY("®", "registered", ",", KEY_OFFSET(4), THIRD_ROW) + SKEY("©", "copyright", "?", KEY_OFFSET(5), THIRD_ROW) + SKEY("¿", "inv_question", "!", KEY_OFFSET(6), THIRD_ROW) + + KEY_SPECIAL_TEXT("2/2", (5*SCALE), THIRD_ROW, (85*SCALE)) + KEY_SPECIAL_TEXT("abc", (5*SCALE), FOURTH_ROW, (95*SCALE)) + } + } + + group { + name: "fixed"; + + script { + public mouse_down = 0; + } + + programs { + program { + name: "mouse-down"; + signal: "mouse,down,1"; + source: "*"; + script { + set_int(mouse_down, 1); + } + } + program { + name: "mouse-up"; + signal: "mouse,up,1"; + source: "*"; + script { + set_int(mouse_down, 0); + } + } + } + + parts { + KEY_SPECIAL_ICON("backspace", (620*SCALE), THIRD_ROW, (85*SCALE), (60*SCALE)) + KEY_SPECIAL_ICON("enter", (610*SCALE), FOURTH_ROW, (95*SCALE), (60*SCALE)) + +#undef INIT_HSPACE +#define INIT_HSPACE (120*SCALE) + /*KEY_SPECIAL_ICON("space", (KEY_OFFSET(0)), FOURTH_ROW, (KEY_OFFSET(5)), 82);*/ + KEY_SPECIAL_ICON("space", KEY_OFFSET(0), FOURTH_ROW, KEY_OFFSET(5), (64*SCALE)); + } + } + + group { + name: "numeric"; + MOUSE_DOWN_UP_PROGRAMS + + parts { +#undef KEY_WIDTH +#define KEY_WIDTH (200*SCALE) +#undef KEY_HEIGHT +#define KEY_HEIGHT NUMERIC_KEY_HEIGHT +#undef INIT_HSPACE +#define INIT_HSPACE (45*SCALE) +#undef ROW_SPACE +#define ROW_SPACE (10*SCALE) +#undef COL_SPACE +#define COL_SPACE (10*SCALE) + KEY("1", " ", KEY_OFFSET(0), FIRST_ROW) + KEY("2", " ", KEY_OFFSET(1), FIRST_ROW) + KEY("3", " ", KEY_OFFSET(2), FIRST_ROW) + + KEY("4", " ", KEY_OFFSET(0), SECOND_ROW) + KEY("5", " ", KEY_OFFSET(1), SECOND_ROW) + KEY("6", " ", KEY_OFFSET(2), SECOND_ROW) + + KEY("7", " ", KEY_OFFSET(0), THIRD_ROW) + KEY("8", " ", KEY_OFFSET(1), THIRD_ROW) + KEY("9", " ", KEY_OFFSET(2), THIRD_ROW) + + KEY_SPECIAL_ICON("backspace", KEY_OFFSET(0), FOURTH_ROW, KEY_WIDTH, (50*SCALE)) + KEY("0", " ", KEY_OFFSET(1), FOURTH_ROW) + KEY_SPECIAL_ICON("enter", KEY_OFFSET(2), FOURTH_ROW, KEY_WIDTH, (60*SCALE)) + + } + } +} diff --git a/data/themes/default/default_600.edc b/data/themes/default/default_600.edc new file mode 100644 index 0000000..b5ef5e4 --- /dev/null +++ b/data/themes/default/default_600.edc @@ -0,0 +1,26 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define SCALE 0.83 + +#define MIN_WIDTH 600 +#define MAX_WIDTH 1024 +#define MIN_HEIGHT 480 +#define MAX_HEIGHT 480 + +#define NUMERIC_KEY_HEIGHT 80 + +#include "default.edc" diff --git a/data/themes/default/default_720.edc b/data/themes/default/default_720.edc new file mode 100644 index 0000000..476f405 --- /dev/null +++ b/data/themes/default/default_720.edc @@ -0,0 +1,26 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define SCALE 1.0 + +#define MIN_WIDTH 720 +#define MAX_WIDTH 1280 +#define MIN_HEIGHT 600 +#define MAX_HEIGHT 600 + +#define NUMERIC_KEY_HEIGHT 100 + +#include "default.edc" diff --git a/data/themes/default/fonts/DroidSans-Bold.ttf b/data/themes/default/fonts/DroidSans-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..942bbf5ba3aa04288175d094bc9c11d109c5726c GIT binary patch literal 42480 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 literal 0 HcmV?d00001 diff --git a/data/themes/default/fonts/DroidSans.ttf b/data/themes/default/fonts/DroidSans.ttf new file mode 100644 index 0000000000000000000000000000000000000000..efd1f8bbd882a6a434159fa1da7238babbaa2fb3 GIT binary patch literal 41028 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 literal 0 HcmV?d00001 diff --git a/data/themes/default/fonts/LICENSE.txt b/data/themes/default/fonts/LICENSE.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/data/themes/default/fonts/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/data/themes/default/ignorekeys.txt b/data/themes/default/ignorekeys.txt new file mode 100644 index 0000000..875ddfa --- /dev/null +++ b/data/themes/default/ignorekeys.txt @@ -0,0 +1,5 @@ +shift +abc +?123 +1/2 +2/2 diff --git a/data/themes/default/images/icon-backspace.png b/data/themes/default/images/icon-backspace.png new file mode 100644 index 0000000000000000000000000000000000000000..32a1c3f139ef5f8017a50106f5853cc557038d4c GIT binary patch literal 1285 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 literal 0 HcmV?d00001 diff --git a/data/themes/default/images/icon-shift-active.png b/data/themes/default/images/icon-shift-active.png new file mode 100644 index 0000000000000000000000000000000000000000..17a91c4e39ddd894e6a14a6f0d562b55a1dcbe5c GIT binary patch literal 734 zcmV<40wMj0P)%e_kx<6kfPoyzf9D5C{YUfk2=? zm@GdgDF*ffKY(TDTr+FoC?ioL=_c?Qcn!P-RwZ5BmcqacFbC{xyEXyTB%R(?AuZ_y z@bV9nE8u{0Zmsmfl170gVC*lCz5-4<=e9~4(vl+JQ3tXB$AP^4C&TSMXq+5Ag>w_%7;Z{jns2sir z9PQ)Qc|FZ0!}Pei=YXdf)a2h<`MjE&u%roK5!jtkqq7Jc={29DE@dmge1@_Blfc8g za`*voi0rv0>1yU7U9Zv@G$y?Fw*6kS*-TQYh@z+g__me(X|4TWt-YPg zKJ2}p0KU?P{zgv(M`NJRh!09*x7UpV{$Kz}Zq8H-Zbi=+{vK>$PZ zWC5Ush|)qTxvY9vNVSKEo?B}de7KzRX|45^TsHG5_B|}5YUZ4e{!SJEwAM+V^HCuc zi?y(j%Hy05YpvJ)?b<-=-5$~PSPOeZSG3lP&Sz-tppZ(%GQ&cueMB_=r=h$MjIkMG z%+_2s^D#C(ETme`IUo5~SpYD`Bz(@(LMk2$VIdXseSbu2-B@gmKX0J)&zt z5VV(CC$x4zNR_JU3=63a5K*R>q5PXXe>KLm=CYahRVOT@+Q=AtZH!5l^X7ccUj|z5 z%4IWiRWqc8RLti*U2fSzp0_i`hN>#V9?^|J>zzyWk}<|y5K{G4#gG=h|n=W{+5m24r;t)A!IsYr%7=eGl` zw?(~M5r*LzA=T-~h3jf-`%ocjYE}$IEFNmlj!bkfKzagTcA9zuBZLMt|fBNjs-FxYlnVBy&^Ur;rnyM{_SYt9d zOGNfp&o99voGRZ7Z5W1&YQyt9+tk=N zo9a@Nr%s-@Ohlux5H3h}0XPO=1AxW;**5?_0Z0?k7#t3V!{Kl^9FFSdCt1k^Z1+ef Q0000007*qoM6N<$g3C&lSpWb4 literal 0 HcmV?d00001 diff --git a/data/themes/default/images/icon-space.png b/data/themes/default/images/icon-space.png new file mode 100644 index 0000000000000000000000000000000000000000..b1b5bd3cd9e3a2d73f4a29b8446ee7bd6f16d25b GIT binary patch literal 312 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=Y)RhkEXl0tFKJz}e97U*b=AvvK-G_z@2{0tjr&b_lY=h(!V zb2ked+ElyJdbvu=hRpNt>`o{3ME>3Y~N4;|O=;5)DA+Fw(;`<&Eeb+u11->`HUSEg1LsC{ z!)>~gli>&GRK|dbipn7$9>{c{!VtJqoCr=>LDX>y9;izZ-2U+VW4R>n`#yPozvuh1 zD>Otg*LATg0047?gJddt^{1cBvs~!+no+crUKUYuEfq$@QK>pB28azrECvRfb@7-A z(;3pXUcvkTV2078)>2yKdZC^$Gj&cKrp;`j(E#8VV6*7-i5LaOV(}(i1U;;(g+P-* z1a0IhSxSo(Gn#_Ztyoxkh+3bXs23QZ0DsWWCZq|>7^MSk<|LdH+C1+&~TrtHU!$`f= zWT8w14mufiu|zT@f@n`)gn9W7`2*MYmGC7ySK{!%5kHwQual8@hBSBem0V`07`XGp$EszBA1ag!oka1WX z9-lph4aP}IhwHH^yC$dI2`oSGtyrPdis>lAswRk}sSXG=5)?ri2@5CS4j!n*=Zohx zrgjdT-chjf)H~nC9CMxSIzp{=TldJNZ{yA{_Cb52fvV|3s0m)HxXTV2|9YjT`lxLWJft5+Nc5!{n>K5H zYX2j=zr{|j9vT^2UiyovRC;x|wqGx`M|t+=BzN-rhCEMRY<}vKq&wBT~XUzRV)`9i0)R}v25j8iO+!(~VJoIj{?_nU$ zpozQxz`N*&8n;8*Ia__6sn!DV*Cbu)Ei)Is__)_FW5@kybdkd9NDRrxmdwcr>(zF~ zsd|q%LKnex+-{Yk>zb^qrGYU}m&JH8(BtwW-qYTi&@}?e+U4zg)JtUDk$AYDX>2JsrNj zqT4spx-XVACmr(t%zuB#2}N{3rq|hu(CFsNB?m*|yThwnjTe@^XHW23R$J6L;23&( zHnSnZlPmHM*tlxdo$$RY70nL$(A8V1j>kvsBYzE-;^)Q;oW<4a+bDZ(y=LC(vM1OF r@;eC?H^($TKiPi#MdzVF@ldER?=yFAcu zypxL)g+dwczeJ=US0D0O?GAUP$>!>Qb4mDn9Akh?xw{N^brCyH`KqMN4>3QI@bCn=~X?S2L zTSk`|glIIjB+-b5BnB$giR;xI4e09wc*k=|0v$@IfOuVu-o%aPfkV7pa&H&YKwwCP zSkD9BIu$09147)00&FVNQ%#2;0EVd$iw(ojLV!Vs7&JP0!=4a}%Z9lO1bBCWq&1^P z%TaZo>>B)TB0I z1_HzNfSpkliN_K=ko5Fz2s(pI_MTX8dY33NWwdyefd*0OG@Z^K*O0b}P@sRi@j-2q zGQoh-6sQT0HLA&aXx)avWbXdkkX@1Vh8twW$fBrXM7TOuhw2G`5f3E4P&Jr_>xD>I z5X=&I@fmE`3xd4(ut>~iu^^UEjL;GBFvkb6OaV+6dkG~%m8%o`s+=EO0PzT?P8=|gfEiNIV?JfW&A6aD>R}i0yipgJZ889WXF2f?S2kqPU%}*ZQj}NLRXU0elNBY1bKXT?)`HT3<_?GUh z%Ak)e_ zkl^U}MCXzE#@cHQ4Ya=L!f}CBt6wG*S5_i>1Ha$1WNyS=cwhPL>fA~4lIGxr(@vg# zHSOHFwWo+TzgVr(Yx@3%dp$kTT7$vSW@9T0W3vw5`oUoS{MSX?V)eRpPIvDjq^YUN_e2fz(j_db*|8-yrx2Rq zz-;W8)7{;zbxyXFmhLrf_Abgf&8eLdH#OGV5gF-oZpLIg41RjS zTM>C?#sgr>qKD&_);=9;(=LcN6qB?OnWV`l_?+ zvP=h8mqR=RYdv_j%l~?!yE$`Ncdn{*d1k3iYrOZ^QgBb&uAPrOosaw+71h}L;y}AJ z!j~GC$$ow&hgSyNtiN+`(ykfHkYjq~>P^csH%=+xu=bT^9lU#fOY3iFb$!3HALZY0x0qn(ml8OPQacYbq@SySLPa{|_2-LbQcB|I-*2)JY ztL*B?;IIP~SGlE-TWRk@-=%r8ZzuoZ()>tgNxrgm`m3U+oer+ni&E=PJFEe57jrB2 zOY__j_`Vu{w!qz8vPbHUZS5XAST%0r8n>>{TzOSp-Ply05huaSzB5<$uX>%M%=(c{ zPf7OKm6vDp^6~jyw0PH~vg`L20>4*>`eRj9yFK9}v{`qNi2aIaP8>0E`#5jES};w2v+D^g0xXlN8U`|G?q^3cUu#;X?x2G`wz@t94IOlM5O)& DOp52y literal 0 HcmV?d00001 diff --git a/data/themes/default/images/key-hint-bg.png b/data/themes/default/images/key-hint-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..b72b876a1a4e66ed1570fca3ed8c2b2dbab6161e GIT binary patch literal 1515 zcmb_cZ%i9y7(d412ob4SWCJsE++4(2dVjdy^$xnx_O8-pElt}+%w&38U+4wy4|i8v zh{i?vvdqLp+~Q)KF=JV>3}a&S12wP@F2wk6f*}i26QX8D5sib**^T)gP}BtdFugSQ zyzg_*@Av$k=Y8HDiN_wTs;sL-5Tq*7CL|D~tRAklio4)DlRjMoO|30<*h#(H&PgUf z0%^Sqpb=H-0SO?b2l_t*EeKMcQBoatM|3|g>#9d`Vmx`(fM^71*_$^cxfj@I7wAzm zKlXEB0z;LwAA8IjC89exK!_wMQd}_1aw5ZW0!`4Yk1Am!nq^Cx z3`%(wn3o99f{)~=aLC8}BbE=DK(ci+rR#mA35aKOTemX0frgR{+7OjwMRObvI|sB{ zuK-NtX^;+^x{9uJm{&GX;0F* zj7!M{XV6)$4?oWd$*QtpPc*X*dc1@1;I^8uVlE{IE--r3~_^x|5 z2^Fq-#4)Wy(75WMxntLV#s59=|02nuY#pjw8eF)$^}ZjL-0jV;Z`lev@ypxOCq~+< z2j$hS_#b$`ZoK80<;&dR?C!DTVvkHO_ZM$WPb!74z8)(ShofiS`K0BuTT+#~^EkM1 z?bPVRwktgovGzmN-+T^6FaLP^Ic{ux_UIdd`TlcrPn@s(a#HJh@>=!DXJ1-)@b>2I YNa1Fi=HGGA`S(U5VoZ1|_|)@%0DMj3{r~^~ literal 0 HcmV?d00001 diff --git a/data/themes/default/images/key-hint.png b/data/themes/default/images/key-hint.png new file mode 100644 index 0000000000000000000000000000000000000000..d051c98bd63223e964e0a8ca4fce426aa5ea571b GIT binary patch literal 1716 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 Yb#w0Lb + + + Copyright © 2012, 2013 Intel Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + + + Corresponds to a text model on input method side. An input method context + is created on text mode activation on the input method side. It allows to + receive information about the text model from the application via events. + Input method contexts do not keep state after deactivation and should be + destroyed after deactivation is handled. + + Text is generally UTF-8 encoded, indices and lengths are in bytes. + + Serials are used to synchronize the state between the text input and + an input method. New serials are sent by the text input in the + commit_state request and are used by the input method to indicate + the known text input state in events like preedit_string, commit_string, + and keysym. The text input can then ignore events from the input method + which are based on an outdated state (for example after a reset). + + + + + Send the commit string text for insertion to the application. + + The text to commit could be either just a single character after a key + press or the result of some composing (pre-edit). It could be also an + empty text when some text should be removed (see + delete_surrounding_text) or when the input cursor should be moved (see + cursor_position). + + Any previously set composing text will be removed. + + + + + + + Send the pre-edit string text to the application text input. + + The commit text can be used to replace the preedit text on reset (for + example on unfocus). + + Also previously sent preedit_style and preedit_cursor requests are + processed bt the text_input also. + + + + + + + + Sets styling information on composing text. The style is applied for + length in bytes from index relative to the beginning of + the composing text (as byte offset). Multiple styles can + be applied to a composing text. + + This request should be sent before sending preedit_string request. + + + + + + + + Sets the cursor position inside the composing text (as byte offset) + relative to the start of the composing text. + + When index is negative no cursor should be displayed. + + This request should be sent before sending preedit_string request. + + + + + + + + This request will be handled on text_input side as part of a directly + following commit_string request. + + + + + + + Sets the cursor and anchor to a new position. Index is the new cursor + position in bytess (when >= 0 relative to the end of inserted text + else relative to beginning of inserted text). Anchor is the new anchor + position in bytes (when >= 0 relative to the end of inserted text, else + relative to beginning of inserted text). When there should be no + selected text anchor should be the same as index. + + This request will be handled on text_input side as part of a directly + following commit_string request. + + + + + + + + + + Notify when a key event was sent. Key events should not be used for + normal text input operations, which should be done with commit_string, + delete_surrounfing_text, etc. The key event follows the wl_keyboard key + event convention. Sym is a XKB keysym, state a wl_keyboard key_state. + + + + + + + + + + Allows an input method to receive hardware keyboard input and process + key events to generate text events (with pre-edit) over the wire. This + allows input methods which compose multiple key events for inputting + text like it is done for CJK languages. + + + + + + Should be used when filtering key events with grab_keyboard. + + When the wl_keyboard::key event is not processed by the input + method itself and should be sent to the client instead, forward it + with this request. The arguments should be the ones from the + wl_keyboard::key event. + + For generating custom key events use the keysym request instead. + + + + + + + + + Should be used when filtering key events with grab_keyboard. + + When the wl_keyboard::modifiers event should be also send to the + client, forward it with this request. The arguments should be the ones + from the wl_keyboard::modifiers event. + + + + + + + + + + + + + + + + + + The plain surrounding text around the input position. Cursor is the + position in bytes within the surrounding text relative to the beginning + of the text. Anchor is the position in bytes of the selection anchor + within the surrounding text relative to the beginning of the text. If + there is no selected text anchor is the same as cursor. + + + + + + + + + + + + + + + + + + + + + + + + + + An input method object is responsible to compose text in response to + input from hardware or virtual keyboards. There is one input method + object per seat. On activate there is a new input method context object + created which allows the input method to communicate with the text model. + + + + A text model was activated. Creates an input method context object + which allows communication with the text model. + + + + + + The text model corresponding to the context argument was deactivated. + The input method context should be destroyed after deactivation is + handled. + + + + + + + + Only one client can bind this interface at a time. + + + + + + + + + + + + + + + + A keybaord surface is only shown, when a text model is active + + + + + + + + An overlay panel is shown near the input cursor above the application + window hwne a text model is active. + + + + + + Notify when the cursor rectangle relative to the input panel surface change. + + + + + + + + diff --git a/protocol/text.xml b/protocol/text.xml new file mode 100644 index 0000000..7cd3a4d --- /dev/null +++ b/protocol/text.xml @@ -0,0 +1,346 @@ + + + + + Copyright © 2012, 2013 Intel Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + + An object used for text input. Adds support for text input and input + methods to applications. A text-input object is created from a + wl_text_input_manager and corresponds typically to a text entry in an + application. + Requests are used to activate/deactivate the text-input object and set + state information like surrounding and selected text or the content type. + The information about entered text is sent to the text-input object via + the pre-edit and commit events. Using this interface removes the need + for applications to directly process hardware key events and compose text + out of them. + + Text is generally UTF-8 encoded, indices and lengths are in bytes. + + Serials are used to synchronize the state between the text input and + an input method. New serials are sent by the text input in the + commit_state request and are used by the input method to indicate + the known text input state in events like preedit_string, commit_string, + and keysym. The text input can then ignore events from the input method + which are based on an outdated state (for example after a reset). + + + + Requests the text-input object to be activated (typically when the + text entry gets focus). + The seat argument is a wl_seat which maintains the focus for this + activation. The surface argument is a wl_surface assigned to the + text-input object and tracked for focus lost. The enter event + is emitted on successful activation. + + + + + + + Requests the text-input object to be deactivated (typically when the + text entry lost focus). The seat argument is a wl_seat which was used + for activation. + + + + + + Requests input panels (virtual keyboard) to show. + + + + + Requests input panels (virtual keyboard) to hide. + + + + + Should be called by an editor widget when the input state should be + reset, for example after the text was changed outside of the normal + input method flow. + + + + + Sets the plain surrounding text around the input position. Text is + UTF-8 encoded. Cursor is the byte offset within the + surrounding text. Anchor is the byte offset of the + selection anchor within the surrounding text. If there is no selected + text anchor is the same as cursor. + + + + + + + + Content hint is a bitmask to allow to modify the behavior of the text + input. + + + + + + + + + + + + + + + + + + The content purpose allows to specify the primary purpose of a text + input. + + This allows an input method to show special purpose input panels with + extra characters or to disallow some characters. + + + + + + + + + + + + + + + + + + Sets the content purpose and content hint. While the purpose is the + basic purpose of an input field, the hint flags allow to modify some + of the behavior. + + When no content type is explicitly set, a normal content purpose with + default hints (auto completion, auto correction, auto capitalization) + should be assumed. + + + + + + + + + + + + + Sets a specific language. This allows for example a virtual keyboard to + show a language specific layout. The "language" argument is a RFC-3066 + format language tag. + + It could be used for example in a word processor to indicate language of + currently edited document or in an instant message application which tracks + languages of contacts. + + + + + + + + + + + + + Notify the text-input object when it received focus. Typically in + response to an activate request. + + + + + + Notify the text-input object when it lost focus. Either in response + to a deactivate request or when the assigned surface lost focus or was + destroyed. + + + + + Transfer an array of 0-terminated modifiers names. The position in + the array is the index of the modifier as used in the modifiers + bitmask in the keysym event. + + + + + + Notify when the visibility state of the input panel changed. + + + + + + Notify when a new composing text (pre-edit) should be set around the + current cursor position. Any previously set composing text should + be removed. + + The commit text can be used to replace the preedit text on reset + (for example on unfocus). + + The text input should also handle all preedit_style and preedit_cursor + events occuring directly before preedit_string. + + + + + + + + + + + + + + + + + + Sets styling information on composing text. The style is applied for + length bytes from index relative to the beginning of the composing + text (as byte offset). Multiple styles can + be applied to a composing text by sending multiple preedit_styling + events. + + This event is handled as part of a following preedit_string event. + + + + + + + + Sets the cursor position inside the composing text (as byte + offset) relative to the start of the composing text. When index is a + negative number no cursor is shown. + + This event is handled as part of a following preedit_string event. + + + + + + Notify when text should be inserted into the editor widget. The text to + commit could be either just a single character after a key press or the + result of some composing (pre-edit). It could be also an empty text + when some text should be removed (see delete_surrounding_text) or when + the input cursor should be moved (see cursor_position). + + Any previously set composing text should be removed. + + + + + + + Notify when the cursor or anchor position should be modified. + + This event should be handled as part of a following commit_string + event. + + + + + + + Notify when the text around the current cursor position should be + deleted. + + Index is relative to the current cursor (in bytes). + Length is the length of deleted text (in bytes). + + This event should be handled as part of a following commit_string + event. + + + + + + + Notify when a key event was sent. Key events should not be used + for normal text input operations, which should be done with + commit_string, delete_surrounding_text, etc. The key event follows + the wl_keyboard key event convention. Sym is a XKB keysym, state a + wl_keyboard key_state. Modifiers are a mask for effective modifiers + (where the modifier indices are set by the modifiers_map event) + + + + + + + + + + Sets the language of the input text. The "language" argument is a RFC-3066 + format language tag. + + + + + + + + + + + + Sets the text direction of input text. + + It is mainly needed for showing input cursor on correct side of the + editor when there is no input yet done and making sure neutral + direction text is laid out properly. + + + + + + + + + A factory for text-input objects. This object is a global singleton. + + + + Creates a new text-input object. + + + + + diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..5d53bff --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,51 @@ +bin_PROGRAMS = \ + weekeyboard + +AM_CFLAGS= \ + @WAYLAND_CFLAGS@ \ + @EFL_CFLAGS@ \ + @ELDBUS_CFLAGS@ \ + -DPKGDATADIR='"$(pkgdatadir)"' + +AM_LDFLAGS= \ + @WAYLAND_LIBS@ \ + @EFL_LIBS@ \ + @ELDBUS_LIBS@ + +weekeyboard_SOURCES= \ + wkb-main.c \ + input-method-protocol.c \ + input-method-client-protocol.h \ + text-protocol.c \ + text-client-protocol.h + + +if ENABLE_IBUS +noinst_PROGRAMS = \ + weekeyboard-config-eet-test + +weekeyboard_config_eet_test_SOURCES = \ + wkb-ibus-config-eet.c \ + wkb-ibus-config-eet.h \ + wkb-ibus-config-eet-test.c + +noinst_PROGRAMS += \ + weekeyboard-ibus-test + +weekeyboard_ibus_test_SOURCES = \ + wkb-ibus.h \ + wkb-ibus.c \ + wkb-ibus-panel.c \ + wkb-ibus-config.c \ + wkb-ibus-config-eet.c \ + wkb-ibus-config-eet.h \ + wkb-ibus-test.c +endif + +@wayland_scanner_rules@ + +BUILT_SOURCES= \ + input-method-protocol.c \ + input-method-client-protocol.h \ + text-protocol.c \ + text-client-protocol.h diff --git a/src/wkb-ibus-config-eet-test.c b/src/wkb-ibus-config-eet-test.c new file mode 100644 index 0000000..a4f0ced --- /dev/null +++ b/src/wkb-ibus-config-eet-test.c @@ -0,0 +1,46 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wkb-ibus-config-eet.h" + +#include +#include + +int +main (int argc, char *argv[]) +{ + struct wkb_ibus_config_eet *cfg; + + if (!eina_init()) + { + printf("Error initializing eina"); + return 1; + } + + if (!eet_init()) + { + printf("Error initializing eet"); + return 1; + } + + cfg = wkb_ibus_config_eet_new("ibus-cfg.eet"); + wkb_ibus_config_eet_free(cfg); + + eet_shutdown(); + eina_shutdown(); + + return 0; +} diff --git a/src/wkb-ibus-config-eet.c b/src/wkb-ibus-config-eet.c new file mode 100644 index 0000000..ad9bc5e --- /dev/null +++ b/src/wkb-ibus-config-eet.c @@ -0,0 +1,962 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the eetific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include +#include + +#include "wkb-ibus-config-eet.h" + +/* + * Base struct for all config types + */ +struct _config_section +{ + const char *id; + + void (*free)(struct _config_section *); + void (*set_defaults)(struct _config_section *); + Eina_Bool (*set_value)(struct _config_section *, const char *, const char *, Eldbus_Message_Iter *); + void *(*get_value)(struct _config_section *, const char *, const char *); + void *(*get_values)(struct _config_section *, const char *); +}; + +static void +_config_section_free(struct _config_section *base) +{ + eina_stringshare_del(base->id); + base->free(base); +} + +static void +_config_section_set_defaults(struct _config_section *base) +{ + base->set_defaults(base); +} + +static Eina_Bool +_config_section_set_value(struct _config_section *base, const char *section, const char *name, Eldbus_Message_Iter *value) +{ + return base->set_value(base, section, name, value); +} + +static void * +_config_section_get_value(struct _config_section *base, const char *section, const char *name) +{ + return base->get_value(base, section, name); +} + +static void * +_config_section_get_values(struct _config_section *base, const char *section) +{ + return base->get_values(base, section); +} + +/* + * Helpers for manipulating list of strings + */ +static void +_config_string_list_free(Eina_List *list) +{ + const char *str; + + EINA_LIST_FREE(list, str) + eina_stringshare_del(str); + + eina_list_free(list); +} + +static Eina_List * +_config_string_list_new(const char **strs) +{ + Eina_List *list = NULL; + const char *str; + + for (str = *strs; str != NULL; str = *++strs) + list = eina_list_append(list, eina_stringshare_add(str)); + + return list; +} + +/* + * + * + * [ 'Control+space', 'Zenkaku_Hankaku', 'Alt+Kanji', 'Alt+grave', 'Hangul', 'Alt+Release+Alt_R' ] + * Trigger shortcut keys + * The shortcut keys for turning input method on or off + * + * + * [ '<Super>space' ] + * Trigger shortcut keys for gtk_accelerator_parse + * The shortcut keys for turning input method on or off + * + * + * [] + * Enable shortcut keys + * The shortcut keys for turning input method on + * + * + * [] + * Disable shortcut keys + * The shortcut keys for turning input method off + * + * + * [ 'Alt+Shift_L' ] + * Next engine shortcut keys + * The shortcut keys for switching to the next input method in the list + * + * + * [ 'Alt+Shift_L' ] + * Next engine shortcut keys + * The shortcut keys for switching to the next input method in the list + * + * + * [] + * Prev engine shortcut keys + * The shortcut keys for switching to the previous input method + * + * + * [] + * Prev engine shortcut keys + * The shortcut keys for switching to the previous input method + * + * + */ +struct _config_hotkey +{ + struct _config_section base; + + Eina_List *trigger; + Eina_List *triggers; + Eina_List *enable_unconditional; + Eina_List *disable_unconditional; + Eina_List *next_engine; + Eina_List *next_engine_in_menu; + Eina_List *prev_engine; + Eina_List *previous_engine; +}; + +static Eet_Data_Descriptor * +_config_hotkey_edd_new(void) +{ + Eet_Data_Descriptor *edd; + Eet_Data_Descriptor_Class eddc; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, struct _config_hotkey); + edd = eet_data_descriptor_stream_new(&eddc); + + EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "trigger", trigger); + EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "triggers", triggers); + EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "enable-unconditional", enable_unconditional); + EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "disable-unconditional", disable_unconditional); + EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "next-engine", next_engine); + EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "next-engine-in-menu", next_engine_in_menu); + EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "prev-engine", prev_engine); + EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hotkey, "previous-engine", previous_engine); + + return edd; +} + +static void +_config_hotkey_set_defaults(struct _config_section *base) +{ + struct _config_hotkey *hotkey = (struct _config_hotkey *) base; + + const char *trigger[] = { "Control+space", "Zenkaku_Hankaku", "Alt+Kanji", "Alt+grave", "Hangul", "Alt+Release+Alt_R", NULL }; + const char *triggers[] = { "space", NULL }; + const char *enable_unconditional[] = { NULL }; + const char *disable_unconditional[] = { NULL }; + const char *next_engine[] = { NULL }; + const char *next_engine_in_menu[] = { NULL }; + const char *prev_engine[] = { NULL }; + const char *previous_engine[] = { NULL }; + + hotkey->trigger = _config_string_list_new(trigger); + hotkey->triggers = _config_string_list_new(triggers); + hotkey->enable_unconditional = _config_string_list_new(enable_unconditional); + hotkey->disable_unconditional = _config_string_list_new(disable_unconditional); + hotkey->next_engine = _config_string_list_new(next_engine); + hotkey->next_engine_in_menu = _config_string_list_new(next_engine_in_menu); + hotkey->prev_engine = _config_string_list_new(prev_engine); + hotkey->previous_engine = _config_string_list_new(previous_engine); +} + +static void +_config_hotkey_free(struct _config_section *base) +{ + struct _config_hotkey *hotkey = (struct _config_hotkey *) base; + + _config_string_list_free(hotkey->trigger); + _config_string_list_free(hotkey->triggers); + _config_string_list_free(hotkey->enable_unconditional); + _config_string_list_free(hotkey->disable_unconditional); + _config_string_list_free(hotkey->next_engine); + _config_string_list_free(hotkey->next_engine_in_menu); + _config_string_list_free(hotkey->prev_engine); + _config_string_list_free(hotkey->previous_engine); + + free(hotkey); +} + +static Eina_Bool +_config_hotkey_set_value(struct _config_section *base, const char *section, const char *name, Eldbus_Message_Iter *value) +{ + return EINA_FALSE; +} + +static void * +_config_hotkey_get_value(struct _config_section *base, const char *section, const char *name) +{ + return NULL; +} + +static void * +_config_hotkey_get_values(struct _config_section *base, const char *section) +{ + return NULL; +} + +static void +_config_hotkey_section_init(struct _config_section *base) +{ + base->id = eina_stringshare_add("hotkey"); + base->free = _config_hotkey_free; + base->set_defaults = _config_hotkey_set_defaults; + base->set_value = _config_hotkey_set_value; + base->get_value = _config_hotkey_get_value; + base->get_values = _config_hotkey_get_values; +} + +static struct _config_section * +_config_hotkey_new(void) +{ + struct _config_hotkey *conf = calloc(1, sizeof(*conf)); + _config_hotkey_section_init((struct _config_section *) conf); + return (struct _config_section *) conf; +} + +/* + * + * + * [] + * Preload engines + * Preload engines during ibus starts up + * + * + * [] + * Engines order + * Saved engines order in input method list + * + * + * 400 + * Popup delay milliseconds for IME switcher window + * Set popup delay milliseconds to show IME switcher window. The default is 400. 0 = Show the window immediately. 0 < Delay milliseconds. 0 > Do not show the + * + * + * '' + * Saved version number + * The saved version number will be used to check the difference between the version of the previous installed ibus and one of the current ibus. + * + * + * false + * Use system keyboard layout + * Use system keyboard (XKB) layout + * + * + * true + * Embed Preedit Text + * Embed Preedit Text in Application Window + * + * + * false + * Use global input method + * Share the same input method among all applications + * + * + * false + * Enable input method by default + * Enable input method by default when the application gets input focus + * + * + * [ '/desktop/ibus/engine/pinyin', '/desktop/ibus/engine/bopomofo', '/desktop/ibus/engine/hangul' ] + * DConf preserve name prefixes + * Prefixes of DConf keys to stop name conversion + * + * + * + */ +struct _config_general +{ + struct _config_section base; + + struct _config_section *hotkey; + + Eina_List *preload_engines; + Eina_List *engines_order; + Eina_List *dconf_preserve_name_prefixes; + + const char *version; + + int switcher_delay_time; + + Eina_Bool use_system_keyboard_layout; + Eina_Bool embed_preedit_text; + Eina_Bool use_global_engine; + Eina_Bool enable_by_default; +}; + +static Eet_Data_Descriptor * +_config_general_edd_new(Eet_Data_Descriptor *hotkey_edd) +{ + Eet_Data_Descriptor *edd; + Eet_Data_Descriptor_Class eddc; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, struct _config_general); + edd = eet_data_descriptor_stream_new(&eddc); + + EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_general, "preload-engines", preload_engines); + EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_general, "engines-order", engines_order); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_general, "switcher-delay-time", switcher_delay_time, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_general, "version", version, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_general, "use-system-keyboard-layout", use_system_keyboard_layout, EET_T_UCHAR); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_general, "embed-preedit-text", embed_preedit_text, EET_T_UCHAR); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_general, "use-global-engine", use_global_engine, EET_T_UCHAR); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_general, "enable-by-default", enable_by_default, EET_T_UCHAR); + EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_general, "dconf-preserve-name-prefixes", dconf_preserve_name_prefixes); + EET_DATA_DESCRIPTOR_ADD_SUB(edd, struct _config_general, "hotkey", hotkey, hotkey_edd); + + return edd; +} + +static void +_config_general_set_defaults(struct _config_section *base) +{ + struct _config_general *general = (struct _config_general *) base; + + const char *preload_engines[] = { NULL }; + const char *engines_order[] = { NULL }; + const char *dconf_preserve_name_prefixes[] = { "/desktop/ibus/engine/pinyin", "/desktop/ibus/engine/bopomofo", "/desktop/ibus/engine/hangul", NULL }; + + _config_section_set_defaults(general->hotkey); + + general->preload_engines = _config_string_list_new(preload_engines); + general->engines_order = _config_string_list_new(engines_order); + general->switcher_delay_time = 400; + general->version = eina_stringshare_add(""); + general->use_system_keyboard_layout = EINA_FALSE; + general->embed_preedit_text = EINA_TRUE; + general->use_global_engine = EINA_FALSE; + general->enable_by_default = EINA_FALSE; + general->dconf_preserve_name_prefixes = _config_string_list_new(dconf_preserve_name_prefixes); + +} + +static void +_config_general_free(struct _config_section *base) +{ + struct _config_general *general = (struct _config_general *) base; + + _config_section_free(general->hotkey); + + _config_string_list_free(general->preload_engines); + _config_string_list_free(general->engines_order); + _config_string_list_free(general->dconf_preserve_name_prefixes); + + eina_stringshare_del(general->version); + free(general); +} + +static Eina_Bool +_config_general_set_value(struct _config_section *base, const char *section, const char *name, Eldbus_Message_Iter *value) +{ + return EINA_FALSE; +} + +static void * +_config_general_get_value(struct _config_section *base, const char *section, const char *name) +{ + return NULL; +} + +static void * +_config_general_get_values(struct _config_section *base, const char *section) +{ + return NULL; +} + +static void +_config_general_section_init(struct _config_section *base) +{ + struct _config_general *general = (struct _config_general *) base; + + base->id = eina_stringshare_add("general"); + base->free = _config_general_free; + base->set_defaults = _config_general_set_defaults; + base->set_value = _config_general_set_value; + base->get_value = _config_general_get_value; + base->get_values = _config_general_get_values; + + if (general->hotkey) + _config_hotkey_section_init(general->hotkey); +} + +static struct _config_section * +_config_general_new(void) +{ + struct _config_general *conf = calloc(1, sizeof(*conf)); + _config_general_section_init((struct _config_section *) conf); + conf->hotkey = _config_hotkey_new(); + return (struct _config_section *) conf; +} + +/* + * + * + * 0 + * Auto hide + * The behavior of language panel. 0 = Embedded in menu, 1 = Auto hide, 2 = Always show + * + * + * -1 + * Language panel position + * + * + * -1 + * Language panel position + * + * + * 1 + * Orientation of lookup table + * Orientation of lookup table. 0 = Horizontal, 1 = Vertical + * + * + * true + * Show icon on system tray + * Show icon on system tray + * + * + * false + * Show input method name + * Show input method name on language bar + * + * + * false + * Use custom font + * Use custom font name for language panel + * + * + * 'Sans 10' + * Custom font + * Custom font name for language panel + * + * + */ +struct _config_panel +{ + struct _config_section base; + + const char *custom_font; + int show; + int x; + int y; + int lookup_table_orientation; + Eina_Bool show_icon_in_systray; + Eina_Bool show_im_name; + Eina_Bool use_custom_font; +}; + +static Eet_Data_Descriptor * +_config_panel_edd_new(void) +{ + Eet_Data_Descriptor *edd; + Eet_Data_Descriptor_Class eddc; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, struct _config_panel); + edd = eet_data_descriptor_stream_new(&eddc); + + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "show", show, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "x", x, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "y", y, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "lookup-table-orientation", lookup_table_orientation, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "show-icon-in-systray", show_icon_in_systray, EET_T_UCHAR); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "show-im-name", show_im_name, EET_T_UCHAR); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "use-custom-font", use_custom_font, EET_T_UCHAR); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_panel, "custom-font", custom_font, EET_T_STRING); + + return edd; +} + +static void +_config_panel_set_defaults(struct _config_section *base) +{ + struct _config_panel *panel = (struct _config_panel *) base; + + panel->show = 0; + panel->x = -1; + panel->y = -1; + panel->lookup_table_orientation = 1; + panel->show_icon_in_systray = EINA_TRUE; + panel->show_im_name = EINA_FALSE; + panel->use_custom_font = EINA_FALSE; + panel->custom_font = eina_stringshare_add("Sans 10"); +} + +static void +_config_panel_free(struct _config_section *base) +{ + struct _config_panel *panel = (struct _config_panel *) base; + + eina_stringshare_del(panel->custom_font); + free(panel); +} + +static Eina_Bool +_config_panel_set_value(struct _config_section *base, const char *section, const char *name, Eldbus_Message_Iter *value) +{ + return EINA_FALSE; +} + +static void * +_config_panel_get_value(struct _config_section *base, const char *section, const char *name) +{ + return NULL; +} + +static void * +_config_panel_get_values(struct _config_section *base, const char *section) +{ + return NULL; +} + +static void +_config_panel_section_init(struct _config_section *base) +{ + base->id = eina_stringshare_add("panel"); + base->free = _config_panel_free; + base->set_defaults = _config_panel_set_defaults; + base->set_value = _config_panel_set_value; + base->get_value = _config_panel_get_value; + base->get_values = _config_panel_get_values; +} + +static struct _config_section * +_config_panel_new(void) +{ + struct _config_panel *conf = calloc(1, sizeof(*conf)); + _config_panel_section_init((struct _config_section *) conf); + return (struct _config_section *) conf; +} + +/* + * NO SCHEMA AVAILABLE. BASED ON THE SOURCE CODE + */ +struct _config_hangul +{ + struct _config_section base; + + const char *hangul_keyboard; + Eina_List *hanja_keys; + Eina_Bool word_commit; + Eina_Bool auto_reorder; +}; + +static Eet_Data_Descriptor * +_config_hangul_edd_new(void) +{ + Eet_Data_Descriptor *edd; + Eet_Data_Descriptor_Class eddc; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, struct _config_hangul); + edd = eet_data_descriptor_stream_new(&eddc); + + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_hangul, "HangulKeyboard", hangul_keyboard, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd, struct _config_hangul, "HanjaKeys", hanja_keys); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_hangul, "WordCommit", word_commit, EET_T_UCHAR); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct _config_hangul, "AutoReorder", auto_reorder, EET_T_UCHAR); + + return edd; +} + +static void +_config_hangul_set_defaults(struct _config_section *base) +{ + struct _config_hangul *hangul = (struct _config_hangul *) base; + const char *hanja_keys[] = { "Hangul_Hanja", "F9", NULL }; + + hangul->hangul_keyboard = eina_stringshare_add("2"); + hangul->hanja_keys = _config_string_list_new(hanja_keys); + hangul->word_commit = EINA_FALSE; + hangul->auto_reorder = EINA_TRUE; +} + +static void +_config_hangul_free(struct _config_section *base) +{ + struct _config_hangul *hangul = (struct _config_hangul *) base; + + eina_stringshare_del(hangul->hangul_keyboard); + _config_string_list_free(hangul->hanja_keys); + free(hangul); +} + +static Eina_Bool +_config_hangul_set_value(struct _config_section *base, const char *section, const char *name, Eldbus_Message_Iter *value) +{ + return EINA_FALSE; +} + +static void * +_config_hangul_get_value(struct _config_section *base, const char *section, const char *name) +{ + return NULL; +} + +static void * +_config_hangul_get_values(struct _config_section *base, const char *section) +{ + return NULL; +} + +static void +_config_hangul_section_init(struct _config_section *base) +{ + base->id = eina_stringshare_add("hangul"); + base->free = _config_hangul_free; + base->set_defaults = _config_hangul_set_defaults; + base->set_value = _config_hangul_set_value; + base->get_value = _config_hangul_get_value; + base->get_values = _config_hangul_get_values; +} + +static struct _config_section * +_config_hangul_new(void) +{ + struct _config_hangul *conf = calloc(1, sizeof(*conf)); + _config_hangul_section_init((struct _config_section *) conf); + return (struct _config_section *) conf; +} + +/* + * NO SCHEMA AVAILABLE. BASED ON THE SOURCE CODE + */ +struct _config_engine +{ + struct _config_section base; + + struct _config_section *hangul; +}; + +static Eet_Data_Descriptor * +_config_engine_edd_new(Eet_Data_Descriptor *hangul_edd) +{ + Eet_Data_Descriptor *edd; + Eet_Data_Descriptor_Class eddc; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, struct _config_engine); + edd = eet_data_descriptor_stream_new(&eddc); + + EET_DATA_DESCRIPTOR_ADD_SUB(edd, struct _config_engine, "Hangul", hangul, hangul_edd); + + return edd; +} + +static void +_config_engine_set_defaults(struct _config_section *base) +{ + struct _config_engine *engine = (struct _config_engine *) base; + + _config_section_set_defaults(engine->hangul); +} + +static void +_config_engine_free(struct _config_section *base) +{ + struct _config_engine *engine = (struct _config_engine *) base; + + _config_section_free(engine->hangul); + free(engine); +} + +static Eina_Bool +_config_engine_set_value(struct _config_section *base, const char *section, const char *name, Eldbus_Message_Iter *value) +{ + return EINA_FALSE; +} + +static void * +_config_engine_get_value(struct _config_section *base, const char *section, const char *name) +{ + return NULL; +} + +static void * +_config_engine_get_values(struct _config_section *base, const char *section) +{ + return NULL; +} + +static void +_config_engine_section_init(struct _config_section *base) +{ + struct _config_engine *engine = (struct _config_engine *) base; + + base->id = eina_stringshare_add("engine"); + base->free = _config_engine_free; + base->set_defaults = _config_engine_set_defaults; + base->set_value = _config_engine_set_value; + base->get_value = _config_engine_get_value; + base->get_values = _config_engine_get_values; + + if (engine->hangul) + _config_hangul_section_init(engine->hangul); +} + +static struct _config_section * +_config_engine_new(void) +{ + struct _config_engine *conf = calloc(1, sizeof(*conf)); + _config_engine_section_init((struct _config_section *) conf); + conf->hangul = _config_hangul_new(); + return (struct _config_section *) conf; +} + +/* + * + * + * + * + */ +struct _config_ibus +{ + struct _config_section base; + + struct _config_section *general; + struct _config_section *panel; + struct _config_section *engine; +}; + +static Eet_Data_Descriptor * +_config_ibus_edd_new(Eet_Data_Descriptor *general_edd, Eet_Data_Descriptor *panel_edd, Eet_Data_Descriptor *engine_edd) +{ + Eet_Data_Descriptor *edd; + Eet_Data_Descriptor_Class eddc; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, struct _config_ibus); + edd = eet_data_descriptor_stream_new(&eddc); + + EET_DATA_DESCRIPTOR_ADD_SUB(edd, struct _config_ibus, "general", general, general_edd); + EET_DATA_DESCRIPTOR_ADD_SUB(edd, struct _config_ibus, "panel", panel, panel_edd); + EET_DATA_DESCRIPTOR_ADD_SUB(edd, struct _config_ibus, "engine", engine, engine_edd); + + return edd; +} + +static void +_config_ibus_set_defaults(struct _config_section *base) +{ + struct _config_ibus *ibus = (struct _config_ibus *) base; + + _config_section_set_defaults(ibus->general); + _config_section_set_defaults(ibus->panel); + _config_section_set_defaults(ibus->engine); +} + +static void +_config_ibus_free(struct _config_section *base) +{ + struct _config_ibus *ibus = (struct _config_ibus *) base; + + _config_section_free(ibus->general); + _config_section_free(ibus->panel); + _config_section_free(ibus->engine); + + free(ibus); +} + +static Eina_Bool +_config_ibus_set_value(struct _config_section *base, const char *section, const char *name, Eldbus_Message_Iter *value) +{ + return EINA_FALSE; +} + +static void * +_config_ibus_get_value(struct _config_section *base, const char *section, const char *name) +{ + return NULL; +} + +static void * +_config_ibus_get_values(struct _config_section *base, const char *section) +{ + return NULL; +} + +static void +_config_ibus_section_init(struct _config_section *base) +{ + struct _config_ibus *ibus = (struct _config_ibus *) base; + base->id = eina_stringshare_add("ibus"); + base->free = _config_ibus_free; + base->set_defaults = _config_ibus_set_defaults; + base->set_value = _config_ibus_set_value; + base->get_value = _config_ibus_get_value; + base->get_values = _config_ibus_get_values; + + if (ibus->general) + _config_general_section_init(ibus->general); + + if (ibus->panel) + _config_panel_section_init(ibus->panel); + + if (ibus->engine) + _config_engine_section_init(ibus->engine); +} + +static struct _config_section * +_config_ibus_new(void) +{ + struct _config_ibus *conf = calloc(1, sizeof(*conf)); + _config_ibus_section_init((struct _config_section *) conf); + conf->general = _config_general_new(); + conf->panel = _config_panel_new(); + conf->engine = _config_engine_new(); + return (struct _config_section *) conf; +} + +/* + * MAIN + */ +struct wkb_ibus_config_eet +{ + const char *path; + struct _config_section *ibus_config; + + Eet_Data_Descriptor *hotkey_edd; + Eet_Data_Descriptor *general_edd; + Eet_Data_Descriptor *panel_edd; + Eet_Data_Descriptor *hangul_edd; + Eet_Data_Descriptor *engine_edd; + Eet_Data_Descriptor *ibus_edd; +}; + +Eina_Bool +wkb_ibus_config_eet_set_value(struct wkb_ibus_config_eet *config_eet, const char *section, const char *name, Eldbus_Message_Iter *value) +{ + return _config_section_set_value(config_eet->ibus_config, section, name, value); +} + +void * +wkb_ibus_config_eet_get_value(struct wkb_ibus_config_eet *config_eet, const char *section, const char *name) +{ + return _config_section_get_value(config_eet->ibus_config, section, name); +} + +void * +wkb_ibus_config_eet_get_values(struct wkb_ibus_config_eet *config_eet, const char *section) +{ + return _config_section_get_values(config_eet->ibus_config, section); +} + +void +wkb_ibus_config_eet_set_defaults(struct wkb_ibus_config_eet *config_eet) +{ + + if (config_eet->ibus_config) + _config_section_free(config_eet->ibus_config); + + config_eet->ibus_config = _config_ibus_new(); + _config_ibus_set_defaults(config_eet->ibus_config); +} + +static struct wkb_ibus_config_eet * +_config_eet_section_init(const char *path) +{ + struct wkb_ibus_config_eet *eet = calloc(1, sizeof(*eet)); + eet->path = eina_stringshare_add(path); + + eet->hotkey_edd = _config_hotkey_edd_new(); + eet->general_edd = _config_general_edd_new(eet->hotkey_edd); + eet->panel_edd = _config_panel_edd_new(); + eet->hangul_edd = _config_hangul_edd_new(); + eet->engine_edd = _config_engine_edd_new(eet->hangul_edd); + eet->ibus_edd = _config_ibus_edd_new(eet->general_edd, eet->panel_edd, eet->engine_edd); + + return eet; +} + +static Eina_Bool +_config_eet_exists(const char *path) +{ + struct stat buf; + return stat(path, &buf) == 0; +} + +struct wkb_ibus_config_eet * +wkb_ibus_config_eet_new(const char *path) +{ + struct wkb_ibus_config_eet *eet = _config_eet_section_init(path); + Eet_File *ef = NULL; + Eet_File_Mode mode = EET_FILE_MODE_READ_WRITE; + + if (_config_eet_exists(path)) + mode = EET_FILE_MODE_READ; + + if (!(ef = eet_open(path, mode))) + { + printf("Error opening eet file '%s' for %s\n", path, mode == EET_FILE_MODE_READ ? "read" : "write"); + wkb_ibus_config_eet_free(eet); + return NULL; + } + + if (mode == EET_FILE_MODE_READ) + { + eet->ibus_config = eet_data_read(ef, eet->ibus_edd, "ibus"); + _config_ibus_section_init(eet->ibus_config); + goto end; + } + + wkb_ibus_config_eet_set_defaults(eet); + if (!eet_data_write(ef, eet->ibus_edd, "ibus", eet->ibus_config, EINA_TRUE)) + { + printf("Error creating eet file '%s'\n", path); + wkb_ibus_config_eet_free(eet); + eet = NULL; + } + +end: + eet_close(ef); + return eet; +} + +void +wkb_ibus_config_eet_free(struct wkb_ibus_config_eet *config_eet) +{ + _config_ibus_free(config_eet->ibus_config); + eina_stringshare_del(config_eet->path); + + eet_data_descriptor_free(config_eet->hotkey_edd); + eet_data_descriptor_free(config_eet->general_edd); + eet_data_descriptor_free(config_eet->panel_edd); + eet_data_descriptor_free(config_eet->hangul_edd); + eet_data_descriptor_free(config_eet->engine_edd); + eet_data_descriptor_free(config_eet->ibus_edd); + + free(config_eet); +} diff --git a/src/wkb-ibus-config-eet.h b/src/wkb-ibus-config-eet.h new file mode 100644 index 0000000..a7e7970 --- /dev/null +++ b/src/wkb-ibus-config-eet.h @@ -0,0 +1,34 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _WKB_IBUS_CONFIG_EET_H_ +#define _WKB_IBUS_CONFIG_EET_H_ + +#include +#include + +struct wkb_ibus_config_eet; + +Eina_Bool wkb_ibus_config_eet_set_value(struct wkb_ibus_config_eet *config_eet, const char *section, const char *name, Eldbus_Message_Iter *value); +void *wkb_ibus_config_eet_get_value(struct wkb_ibus_config_eet *config_eet, const char *section, const char *name); +void *wkb_ibus_config_eet_get_values(struct wkb_ibus_config_eet *config_eet, const char *section); + +void wkb_ibus_config_eet_set_defaults(struct wkb_ibus_config_eet *config_eet); + +struct wkb_ibus_config_eet *wkb_ibus_config_eet_new(const char *path); +void wkb_ibus_config_eet_free(struct wkb_ibus_config_eet *config_eet); + +#endif /* _WKB_IBUS_CONFIG_EET_H_ */ diff --git a/src/wkb-ibus-config.c b/src/wkb-ibus-config.c new file mode 100644 index 0000000..7c698fe --- /dev/null +++ b/src/wkb-ibus-config.c @@ -0,0 +1,170 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include "wkb-ibus.h" + +#define CONFIG_CHECK_MESSAGE_ERRORS(_msg) \ + do \ + { \ + const char *error, *error_msg; \ + if (eldbus_message_error_get(_msg, &error, &error_msg)) \ + { \ + ERR("DBus message error: %s: %s", error, error_msg); \ + return NULL; \ + } \ + DBG("Message '%s' with signature '%s'", eldbus_message_member_get(_msg), eldbus_message_signature_get(_msg)); \ + } while (0); + +static Eldbus_Message * +_config_set_value(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + const char *section, *name; + Eldbus_Message_Iter *value; + + CONFIG_CHECK_MESSAGE_ERRORS(msg) + + if (!eldbus_message_arguments_get(msg, "ssv", §ion, &name, &value)) + { + ERR("Error reading message arguments"); + return NULL; + } + + DBG("section: '%s', name: '%s', value: '%p'", section, name, value); + + return NULL; +} + +static Eldbus_Message * +_config_get_value(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + const char *section, *name; + + CONFIG_CHECK_MESSAGE_ERRORS(msg) + + if (!eldbus_message_arguments_get(msg, "ss", §ion, &name)) + { + ERR("Error reading message arguments"); + return NULL; + } + + DBG("section: '%s', name: '%s'", section, name); + + return NULL; +} + +static Eldbus_Message * +_config_get_values(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + const char *section; + + CONFIG_CHECK_MESSAGE_ERRORS(msg) + + if (!eldbus_message_arguments_get(msg, "s", §ion)) + { + ERR("Error reading message arguments"); + return NULL; + } + + DBG("section: '%s'", section); + + return NULL; +} + +static Eldbus_Message * +_config_unset_value(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + const char *section, *name; + + CONFIG_CHECK_MESSAGE_ERRORS(msg) + + if (!eldbus_message_arguments_get(msg, "ss", §ion, &name)) + { + ERR("Error reading message arguments"); + return NULL; + } + + DBG("section: '%s', name: '%s'", section, name); + + return NULL; +} + +static const Eldbus_Method _wkb_ibus_config_methods[] = +{ +/* typedef struct _Eldbus_Method + * { + * const char *member; + * const Eldbus_Arg_Info *in; + * const Eldbus_Arg_Info *out; + * Eldbus_Method_Cb cb; + * unsigned int flags; + * } Eldbus_Method; + */ + { .member = "SetValue", + .in = ELDBUS_ARGS({"s", "section"}, {"s", "name"}, {"v", "value"}), + .cb = _config_set_value, }, + + { .member = "GetValue", + .in = ELDBUS_ARGS({"s", "section"}, {"s", "name"}), + .out = ELDBUS_ARGS({"v", "value"}), + .cb = _config_get_value, }, + + { .member = "GetValues", + .in = ELDBUS_ARGS({"s", "section"}), + .out = ELDBUS_ARGS({"a{sv}", "values"}), + .cb = _config_get_values, }, + + { .member = "UnsetValue", + .in = ELDBUS_ARGS({"s", "section"}, {"s", "name"}), + .cb = _config_unset_value, }, + + { NULL }, +}; + +static const Eldbus_Signal _wkb_ibus_config_signals[] = +{ +/* typedef struct _Eldbus_Signal + * { + * const char *name; + * const Eldbus_Arg_Info *args; + * unsigned int flags; + * } Eldbus_Signal; + */ + { .name = "ValueChanged", + .args = ELDBUS_ARGS({"s", "section"}, {"s", "name"}, {"v", "value"}), + .flags = 0, }, + + { NULL }, +}; + +static const Eldbus_Service_Interface_Desc _wkb_ibus_config_interface = +{ + .interface = IBUS_INTERFACE_CONFIG, + .methods = _wkb_ibus_config_methods, + .signals = _wkb_ibus_config_signals, +}; + +Eldbus_Service_Interface * +wkb_ibus_config_register(Eldbus_Connection *conn) +{ + return eldbus_service_interface_register(conn, IBUS_PATH_CONFIG, &_wkb_ibus_config_interface); +} + diff --git a/src/wkb-ibus-panel.c b/src/wkb-ibus-panel.c new file mode 100644 index 0000000..62e437f --- /dev/null +++ b/src/wkb-ibus-panel.c @@ -0,0 +1,831 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include "wkb-ibus.h" + +#define PANEL_CHECK_MESSAGE_ERRORS(_msg) \ + do \ + { \ + const char *error, *error_msg; \ + if (eldbus_message_error_get(_msg, &error, &error_msg)) \ + { \ + ERR("DBus message error: %s: %s", error, error_msg); \ + return NULL; \ + } \ + DBG("Message '%s' with signature '%s'", eldbus_message_member_get(_msg), eldbus_message_signature_get(_msg)); \ + } while (0); + +static Eina_Array *_get_properties_from_message_iter(Eldbus_Message_Iter *iter); + +struct _ibus_serializable +{ + /* + * All messages sent by IBus will start with the sa{sv} signature, but + * those fields don't seem useful for us, this struct is used to help + * on deserializing those fields + */ + char *text; + Eldbus_Message_Iter *variant; +}; + +struct _ibus_attr +{ + unsigned int type; + unsigned int value; + unsigned int start_idx; + unsigned int end_idx; +}; + +struct _ibus_text +{ + char *text; + Eina_Array *attrs; +}; + +struct _ibus_lookup_table +{ + unsigned int page_size; + unsigned int cursor_pos; + Eina_Bool cursor_visible; + Eina_Bool round; + int orientation; + Eina_Array *candidates; + Eina_Array *labels; +}; + +struct _ibus_property +{ + char *key; + char *icon; + struct _ibus_text *label; + struct _ibus_text *symbol; + struct _ibus_text *tooltip; + Eina_Bool sensitive; + Eina_Bool visible; + unsigned int type; + unsigned int state; + Eina_Array *sub_properties; +}; + +static struct _ibus_attr * +_get_attr_from_message_iter(Eldbus_Message_Iter *iter) +{ + struct _ibus_attr *attr = calloc(1, sizeof(*attr)); + + EINA_SAFETY_ON_NULL_RETURN_VAL(attr, NULL); + + DBG("Attribute iter signature '%s'", eldbus_message_iter_signature_get(iter)); + + if (!eldbus_message_iter_arguments_get(iter, "uuuu", &attr->type, + &attr->value, &attr->start_idx, + &attr->end_idx)) + { + ERR("Error deserializing IBusAttribute"); + free(attr); + attr = NULL; + } + + return attr; +} + +static void +_free_eina_array(Eina_Array *array, void (* free_func)(void *)) +{ + if (!array) + return; + + while (eina_array_count(array)) + free_func(eina_array_pop(array)); + + eina_array_free(array); +} + +static void +_free_text(struct _ibus_text *text) +{ + if (!text) + return; + + _free_eina_array(text->attrs, free); + free(text->text); + free(text); +} + +static struct _ibus_text * +_get_text_from_message_iter(Eldbus_Message_Iter *iter) +{ + struct _ibus_serializable ignore = { 0 }; + struct _ibus_text *text = calloc(1, sizeof(*text)); + struct _ibus_attr *attr = NULL; + Eldbus_Message_Iter *attrs = NULL, *a = NULL; + + EINA_SAFETY_ON_NULL_RETURN_VAL(text, NULL); + + DBG("Text iter signature '%s'", eldbus_message_iter_signature_get(iter)); + + if (!eldbus_message_iter_arguments_get(iter, "(sa{sv}sv)", &ignore.text, + &ignore.variant, &text->text, &attrs)) + { + ERR("Error deserializing IBusText"); + free(text); + text = NULL; + goto end; + } + + /* Check for attributes */ + if (attrs == NULL) + { + INF("Text has no attributes"); + goto end; + } + + while (eldbus_message_iter_get_and_next(attrs, 'v', &a)) + { + if (!text->attrs) + text->attrs = eina_array_new(10); + + if (!(attr = _get_attr_from_message_iter(a))) + { + _free_text(text); + text = NULL; + goto end; + } + + eina_array_push(text->attrs, attr); + } + +end: + return text; +} + +static void +_free_lookup_table(struct _ibus_lookup_table *table) +{ + if (!table) + return; + + _free_eina_array(table->candidates, _free_text); + _free_eina_array(table->labels, _free_text); + free(table); +} + +static struct _ibus_lookup_table * +_get_lookup_table_from_message_iter(Eldbus_Message_Iter *iter) +{ + struct _ibus_serializable ignore = { 0 }; + struct _ibus_lookup_table *table = calloc(1, sizeof(*table)); + struct _ibus_text *text = NULL; + Eldbus_Message_Iter *candidates = NULL, *labels = NULL, *t = NULL; + + EINA_SAFETY_ON_NULL_RETURN_VAL(table, NULL); + + DBG("LookupTable iter signature '%s'", eldbus_message_iter_signature_get(iter)); + + if (!eldbus_message_iter_arguments_get(iter, "(sa{sv}uubbiavav)", + &ignore.text, &ignore.variant, + &table->page_size, &table->cursor_pos, + &table->cursor_visible, &table->round, + &table->orientation, &candidates, + &labels)) + { + ERR("Error deserializing IBusLookupTable"); + free(table); + table = NULL; + goto end; + } + + DBG("Lookup table:"); + DBG("\tPage size.......: '%d'", table->page_size); + DBG("\tCursor position.: '%d'", table->cursor_pos); + DBG("\tCursor visible..: '%d'", table->cursor_visible); + DBG("\tRound...........: '%d'", table->round); + DBG("\tOrientation.....: '%d'", table->orientation); + DBG("\tCandidates......: '%p'", candidates); + DBG("\tLabels..........: '%p'", labels); + + if (!candidates) + { + INF("Lookup table has no candidates"); + goto labels; + } + + while (eldbus_message_iter_get_and_next(candidates, 'v', &t)) + { + if (!table->candidates) + table->candidates = eina_array_new(10); + + if (!(text = _get_text_from_message_iter(t))) + { + _free_lookup_table(table); + table = NULL; + goto end; + } + + DBG("Appending new candidate %s", text->text); + eina_array_push(table->candidates, text); + } + +labels: + if (!labels) + { + INF("Lookup table has no labels"); + goto end; + } + + while (eldbus_message_iter_get_and_next(labels, 'v', &t)) + { + if (!table->labels) + table->labels = eina_array_new(10); + + if (!(text = _get_text_from_message_iter(t))) + { + _free_lookup_table(table); + table = NULL; + goto end; + } + + DBG("Appending new label %s", text->text); + eina_array_push(table->labels, text); + } + +end: + return table; +} + +static void +_free_property(struct _ibus_property *property) +{ + if (!property) + return; + + free(property->key); + free(property->icon); + _free_text(property->label); + _free_text(property->symbol); + _free_text(property->tooltip); + _free_eina_array(property->sub_properties, _free_property); + free(property); +} + +static struct _ibus_property * +_get_property_from_message_iter(Eldbus_Message_Iter *iter) +{ + struct _ibus_serializable ignore = { 0 }; + struct _ibus_property *prop = calloc(1, sizeof(*prop)); + Eldbus_Message_Iter *label = NULL, *symbol = NULL, *tooltip = NULL, *sub_props = NULL; + + EINA_SAFETY_ON_NULL_RETURN_VAL(prop, NULL); + + DBG("Property iter signature '%s'", eldbus_message_iter_signature_get(iter)); + + if (!eldbus_message_iter_arguments_get(iter, "(sa{sv}suvsvbbuvv)", + &ignore.text, &ignore.variant, + &prop->key, &prop->type, + &label, &prop->icon, &tooltip, + &prop->sensitive, &prop->visible, + &prop->state, &sub_props, &symbol)) + { + ERR("Error deserializing IBusProperty"); + free(prop); + prop = NULL; + goto end; + } + + DBG("Property :"); + DBG("\tKey.............: '%s'", prop->key); + DBG("\tType............: '%d'", prop->type); + DBG("\tLabel...........: '%p'", label); + DBG("\tIcon............: '%s'", prop->icon); + DBG("\tTooltip.........: '%p'", tooltip); + DBG("\tSensitive.......: '%d'", prop->sensitive); + DBG("\tVisible.........: '%d'", prop->visible); + DBG("\tState...........: '%d'", prop->state); + DBG("\tSub Properties..: '%p'", sub_props); + DBG("\tSymbol..........: '%p'", symbol); + + if (!label) + { + INF("Property has no label"); + goto symbol; + } + + if (!(prop->label = _get_text_from_message_iter(label))) + { + _free_property(prop); + prop = NULL; + goto end; + } + +symbol: + if (!symbol) + { + INF("Property has no symbol"); + goto tooltip; + } + + if (!(prop->symbol = _get_text_from_message_iter(symbol))) + { + _free_property(prop); + prop = NULL; + goto end; + } + +tooltip: + if (!tooltip) + { + INF("Property has no tooltip"); + goto sub_props; + } + + if (!(prop->tooltip = _get_text_from_message_iter(tooltip))) + { + _free_property(prop); + prop = NULL; + goto end; + } + +sub_props: + if (!sub_props) + { + INF("Property has no sub properties"); + goto end; + } + + prop->sub_properties = _get_properties_from_message_iter(sub_props); + +end: + return prop; +} + +static Eina_Array * +_get_properties_from_message_iter(Eldbus_Message_Iter *iter) +{ + Eina_Array *properties = NULL; + Eldbus_Message_Iter *props = NULL, *prop = NULL; + struct _ibus_serializable ignore = { 0 }; + struct _ibus_property *property = NULL; + + DBG("PropList iter signature '%s'", eldbus_message_iter_signature_get(iter)); + + if (!eldbus_message_iter_arguments_get(iter, "(sa{sv}av)", &ignore.text, &ignore.variant, &props)) + { + ERR("Error deserializing IBusPropList"); + goto end; + } + + if (!props) + { + INF("PropList has no property"); + goto end; + } + + while (eldbus_message_iter_get_and_next(props, 'v', &prop)) + { + if (!properties) + properties = eina_array_new(10); + + if (!(property = _get_property_from_message_iter(prop))) + { + _free_eina_array(properties, _free_property); + properties = NULL; + goto end; + } + + DBG("Appending new property %p", property); + eina_array_push(properties, property); + } + +end: + return properties; +} + +static Eldbus_Message * +_panel_update_preedit_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + Eldbus_Message_Iter *text = NULL; + unsigned int cursor_pos = 0; + Eina_Bool visible = 0; + struct _ibus_text *ibus_text; + + PANEL_CHECK_MESSAGE_ERRORS(msg) + + if (!eldbus_message_arguments_get(msg, "vub", &text, &cursor_pos, &visible)) + { + ERR("Error reading message arguments"); + return NULL; + } + + DBG("text: '%p', cursor_pos: '%d', visible: '%d')", text, cursor_pos, visible); + + ibus_text = _get_text_from_message_iter(text); + DBG("Preedit text = '%s'", ibus_text->text); + _free_text(ibus_text); + + return NULL; +} + +static Eldbus_Message * +_panel_show_preedit_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + PANEL_CHECK_MESSAGE_ERRORS(msg) + + return NULL; +} + +static Eldbus_Message * +_panel_hide_preedit_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + PANEL_CHECK_MESSAGE_ERRORS(msg) + + return NULL; +} + +static Eldbus_Message * +_panel_update_auxiliary_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + Eldbus_Message_Iter *text = NULL; + Eina_Bool visible = 0; + struct _ibus_text *ibus_text; + + PANEL_CHECK_MESSAGE_ERRORS(msg) + + if (!eldbus_message_arguments_get(msg, "vb", &text, &visible)) + { + ERR("Error reading message arguments"); + return NULL; + } + + DBG("text: '%p', visible: '%d'", text, visible); + + ibus_text = _get_text_from_message_iter(text); + DBG("Auxiliary text = '%s'", ibus_text->text); + _free_text(ibus_text); + + return NULL; +} + +static Eldbus_Message * +_panel_show_auxiliary_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + PANEL_CHECK_MESSAGE_ERRORS(msg) + + return NULL; +} + +static Eldbus_Message * +_panel_hide_auxiliary_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + PANEL_CHECK_MESSAGE_ERRORS(msg) + + return NULL; +} + +static Eldbus_Message * +_panel_update_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + Eldbus_Message_Iter *table = NULL; + Eina_Bool visible = 0; + struct _ibus_lookup_table *ibus_lookup_table; + + PANEL_CHECK_MESSAGE_ERRORS(msg) + + if (!eldbus_message_arguments_get(msg, "vb", &table, &visible)) + { + ERR("Error reading message arguments"); + return NULL; + } + + DBG("table: '%p', visible: '%d'", table, visible); + + ibus_lookup_table = _get_lookup_table_from_message_iter(table); + _free_lookup_table(ibus_lookup_table); + + return NULL; +} + +static Eldbus_Message * +_panel_show_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + PANEL_CHECK_MESSAGE_ERRORS(msg) + + return NULL; +} + +static Eldbus_Message * +_panel_hide_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + PANEL_CHECK_MESSAGE_ERRORS(msg) + + DBG("here"); + + return NULL; +} + +static Eldbus_Message * +_panel_cursor_up_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + PANEL_CHECK_MESSAGE_ERRORS(msg) + + DBG("here"); + + return NULL; +} + +static Eldbus_Message * +_panel_cursor_down_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + PANEL_CHECK_MESSAGE_ERRORS(msg) + + return NULL; +} + +static Eldbus_Message * +_panel_page_up_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + PANEL_CHECK_MESSAGE_ERRORS(msg) + + return NULL; +} + +static Eldbus_Message * +_panel_page_down_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + PANEL_CHECK_MESSAGE_ERRORS(msg) + + return NULL; +} + +static Eldbus_Message * +_panel_register_properties(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + Eldbus_Message_Iter *props = NULL; + Eina_Array *properties = NULL; + + PANEL_CHECK_MESSAGE_ERRORS(msg) + + if (!eldbus_message_arguments_get(msg, "v", &props)) + { + ERR("Error reading message arguments"); + return NULL; + } + + DBG("properties: '%p'", props); + + properties = _get_properties_from_message_iter(props); + _free_eina_array(properties, _free_property); + + return NULL; +} + +static Eldbus_Message * +_panel_update_property(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + Eldbus_Message_Iter *prop = NULL; + + PANEL_CHECK_MESSAGE_ERRORS(msg) + + if (!eldbus_message_arguments_get(msg, "v", &prop)) + { + ERR("Error reading message arguments"); + return NULL; + } + + DBG("property : '%p'", prop); + DBG("Property iter signature: %s", eldbus_message_iter_signature_get(prop)); + + return NULL; +} + +static Eldbus_Message * +_panel_focus_in(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + PANEL_CHECK_MESSAGE_ERRORS(msg) + + return NULL; +} + +static Eldbus_Message * +_panel_focus_out(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + PANEL_CHECK_MESSAGE_ERRORS(msg) + + return NULL; +} + +static Eldbus_Message * +_panel_set_cursor_location(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + int x = 0, y = 0, w = 0, h = 0; + + PANEL_CHECK_MESSAGE_ERRORS(msg) + + if (!eldbus_message_arguments_get(msg, "iiii", &x, &y, &w, &h)) + { + ERR("Error reading message arguments"); + return NULL; + } + + DBG("x: %d, y: %d, w: %d, h: %d", x, y, w, h); + + return NULL; +} + +static Eldbus_Message * +_panel_reset(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + PANEL_CHECK_MESSAGE_ERRORS(msg) + + return NULL; +} + +static Eldbus_Message * +_panel_start_setup(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + PANEL_CHECK_MESSAGE_ERRORS(msg) + + return NULL; +} + +static Eldbus_Message * +_panel_state_changed(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + PANEL_CHECK_MESSAGE_ERRORS(msg) + + return NULL; +} + +static Eldbus_Message * +_panel_hide_language_bar(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + PANEL_CHECK_MESSAGE_ERRORS(msg) + + return NULL; +} + +static Eldbus_Message * +_panel_show_language_bar(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg) +{ + PANEL_CHECK_MESSAGE_ERRORS(msg) + + return NULL; +} + +static const Eldbus_Method _wkb_ibus_panel_methods[] = +{ +/* typedef struct _Eldbus_Method + * { + * const char *member; + * const Eldbus_Arg_Info *in; + * const Eldbus_Arg_Info *out; + * Eldbus_Method_Cb cb; + * unsigned int flags; + * } Eldbus_Method; + */ + { .member = "UpdatePreeditText", + .in = ELDBUS_ARGS({"v", "text"}, {"u", "cursor_pos"}, {"b", "visible"}), + .cb = _panel_update_preedit_text, }, + + { .member = "ShowPreeditText", + .cb = _panel_show_preedit_text, }, + + { .member = "HidePreeditText", + .cb = _panel_hide_preedit_text, }, + + { .member = "UpdateAuxiliaryText", + .in = ELDBUS_ARGS({"v", "text"}, {"b", "visible"}), + .cb = _panel_update_auxiliary_text, }, + + { .member = "ShowAuxiliaryText", + .cb = _panel_show_auxiliary_text, }, + + { .member = "HideAuxiliaryText", + .cb = _panel_hide_auxiliary_text, }, + + { .member = "UpdateLookupTable", + .in = ELDBUS_ARGS({"v", "table"}, {"b", "visible"}), + .cb = _panel_update_lookup_table, }, + + { .member = "ShowLookupTable", + .cb = _panel_show_lookup_table, }, + + { .member = "HideLookupTable", + .cb = _panel_hide_lookup_table, }, + + { .member = "CursorUpLookupTable", + .cb = _panel_cursor_up_lookup_table, }, + + { .member = "CursorDownLookupTable", + .cb = _panel_cursor_down_lookup_table, }, + + { .member = "PageUpLookupTable", + .cb = _panel_page_up_lookup_table, }, + + { .member = "PageDownLookupTable", + .cb = _panel_page_down_lookup_table, }, + + { .member = "RegisterProperties", + .in = ELDBUS_ARGS({"v", "props"}), + .cb = _panel_register_properties, }, + + { .member = "UpdateProperty", + .in = ELDBUS_ARGS({"v", "prop"}), + .cb = _panel_update_property, }, + + { .member = "FocusIn", + .in = ELDBUS_ARGS({"o", "ic"}), + .cb = _panel_focus_in, }, + + { .member = "FocusOut", + .in = ELDBUS_ARGS({"o", "ic"}), + .cb = _panel_focus_out, }, + + { .member = "SetCursorLocation", + .in = ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"i", "w"}, {"i", "h"}), + .cb = _panel_set_cursor_location, }, + + { .member = "Reset", + .cb = _panel_reset, }, + + { .member = "StartSetup", + .cb = _panel_start_setup, }, + + { .member = "StateChanged", + .cb = _panel_state_changed, }, + + { .member = "HideLanguageBar", + .cb = _panel_hide_language_bar, }, + + { .member = "ShowLanguageBar", + .cb = _panel_show_language_bar, }, + + { NULL }, +}; + +static const Eldbus_Signal _wkb_ibus_panel_signals[] = +{ +/* typedef struct _Eldbus_Signal + * { + * const char *name; + * const Eldbus_Arg_Info *args; + * unsigned int flags; + * } Eldbus_Signal; + */ + { .name = "CursorUp", }, + + { .name = "CursorDown", }, + + { .name = "PageUp", }, + + { .name = "PageDown", }, + + { .name = "PropertyActivate", + .args = ELDBUS_ARGS({"s", "prop_name"}, {"i", "prop_state"}), + .flags = 0, }, + + { .name = "PropertyShow", + .args = ELDBUS_ARGS({"s", "prop_name"}), + .flags = 0, }, + + { .name = "PropertyHide", + .args = ELDBUS_ARGS({"s", "prop_name"}), + .flags = 0, }, + + { .name = "CandidateClicked", + .args = ELDBUS_ARGS({"u", "index"}, {"u", "button"}, {"u", "state"}), + .flags = 0, }, + + { NULL }, +}; + +static const Eldbus_Service_Interface_Desc _wkb_ibus_panel_interface = +{ + .interface = IBUS_INTERFACE_PANEL, + .methods = _wkb_ibus_panel_methods, + .signals = _wkb_ibus_panel_signals, +}; + +Eldbus_Service_Interface * +wkb_ibus_panel_register(Eldbus_Connection *conn) +{ + return eldbus_service_interface_register(conn, IBUS_PATH_PANEL, &_wkb_ibus_panel_interface); +} + diff --git a/src/wkb-ibus-test.c b/src/wkb-ibus-test.c new file mode 100644 index 0000000..ced4700 --- /dev/null +++ b/src/wkb-ibus-test.c @@ -0,0 +1,69 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wkb-ibus.h" + +#define _GNU_SOURCE +#include + +#include +#include + +static void +_finish(int foo) +{ + printf("FINISH\n"); + wkb_ibus_shutdown(); +} + +static Eina_Bool +_connect_timer(void *data) +{ + return !wkb_ibus_connect(); +} + +int +main (int argc, char *argv[]) +{ + if (!ecore_init()) + { + printf("Error initializing ecore"); + return 1; + } + + if (!eldbus_init()) + { + printf("Error initializing eldbus"); + return 1; + } + + if (!wkb_ibus_init()) + { + printf("Error initializing ibus"); + return 1; + } + + ecore_timer_add(1, _connect_timer, NULL); + + signal(SIGTERM, _finish); + signal(SIGINT, _finish); + + ecore_main_loop_begin(); + + eldbus_shutdown(); + ecore_shutdown(); + return 0; +} diff --git a/src/wkb-ibus.c b/src/wkb-ibus.c new file mode 100644 index 0000000..60cdac2 --- /dev/null +++ b/src/wkb-ibus.c @@ -0,0 +1,507 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include +#include + +#include "wkb-ibus.h" + +int _wkb_ibus_log_dom = -1; + +#define CHECK_MESSAGE_ERRORS(_msg) \ + do \ + { \ + const char *error, *error_msg; \ + if (eldbus_message_error_get(_msg, &error, &error_msg)) \ + { \ + ERR("Dbus message error: %s: %s", error, error_msg); \ + return; \ + } \ + DBG("Message '%s' with signature '%s'", eldbus_message_member_get(_msg), eldbus_message_signature_get(_msg)); \ + } while (0); + +struct _wkb_ibus_service +{ + Eldbus_Service_Interface *interface; + + Eldbus_Signal_Handler *name_acquired; + Eldbus_Signal_Handler *name_lost; +}; + +struct _wkb_ibus_context +{ + char *address; + Eldbus_Connection *conn; + Ecore_Exe *ibus_daemon; +#if 0 + struct _wkb_ibus_service config; +#else + Eldbus_Proxy *config; +#endif + struct _wkb_ibus_service panel; + int refcount; + Eina_Bool address_pending; +}; + +static struct _wkb_ibus_context *ctx = NULL; + +static void +_wkb_config_value_changed_cb(void *data, const Eldbus_Message *msg) +{ + const char *section, name; + Eldbus_Message_Iter *value; + + CHECK_MESSAGE_ERRORS(msg) + + if (!eldbus_message_arguments_get(msg, "ssv", §ion, &name, &value)) + { + ERR("Error reading message arguments"); + return; + } + + DBG("section: '%s', name: '%s', value: '%p", section, name, value); +} + +static void +_wkb_name_owner_changed_cb(void *data, const char *bus, const char *old_id, const char *new_id) +{ + DBG("NameOwnerChanged Bus=%s | old=%s | new=%s", bus, old_id, new_id); + +#if 0 +#else + if (strcmp(bus, IBUS_SERVICE_CONFIG) == 0) + { + if (*new_id) + { + Eldbus_Object *obj; + + if (ctx->config) + return; + + ecore_main_loop_glib_integrate(); + obj = eldbus_object_get(ctx->conn, IBUS_SERVICE_CONFIG, IBUS_PATH_CONFIG); + ctx->config = eldbus_proxy_get(obj, IBUS_INTERFACE_CONFIG); + eldbus_proxy_signal_handler_add(ctx->config, "ValueChanged", _wkb_config_value_changed_cb, ctx); + + INF("Got config proxy"); + } + else + { + if (!ctx->config) + return; + + eldbus_proxy_unref(ctx->config); + ctx->config = NULL; + } + } +#endif +} + +static void +_wkb_name_acquired_cb(void *data, const Eldbus_Message *msg) +{ + const char *name; + + DBG("NameAcquired"); + + CHECK_MESSAGE_ERRORS(msg) + + if (!eldbus_message_arguments_get(msg, "s", &name)) + { + ERR("Error reading message arguments"); + return; + } + + if (strcmp(name, IBUS_INTERFACE_PANEL) == 0) + { + if (!ctx->panel.interface) + { + ctx->panel.interface = wkb_ibus_panel_register(ctx->conn); + INF("Registering Panel Interface: %s", ctx->panel.interface ? "Success" : "Fail"); + } + else + { + INF("Panel Interface already registered"); + } + } +#if 0 + else if (strcmp(name, IBUS_INTERFACE_CONFIG) == 0) + { + if (!ctx->config.interface) + { + ctx->config.interface = wkb_ibus_config_register(ctx->conn); + INF("Registering Config Interface: %s", ctx->config.interface ? "Success" : "Fail"); + } + else + { + INF("Config Interface already registered"); + } + } +#endif + else + { + WRN("Unexpected name %s", name); + } +} + +static void +_wkb_name_lost_cb(void *data, const Eldbus_Message *msg) +{ + const char *name; + + DBG("NameLost"); + + CHECK_MESSAGE_ERRORS(msg) + + if (!eldbus_message_arguments_get(msg, "s", &name)) + { + ERR("Error reading message arguments"); + return; + } + + DBG("Name = %s", name); +} + +static Eina_Bool +_wkb_ibus_shutdown_idler(void *data) +{ + wkb_ibus_shutdown(); + return ECORE_CALLBACK_CANCEL; +} + +static void +_wkb_name_request_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending) +{ + const char *error, *error_msg; + unsigned int reply; + + DBG("NameRequest callback"); + + if (eldbus_message_error_get(msg, &error, &error_msg)) + { + ERR("DBus message error: %s: %s", error, error_msg); + goto error; + } + + if (!eldbus_message_arguments_get(msg, "u", &reply)) + { + ERR("Error reading message arguments"); + goto error; + } + + if (reply != ELDBUS_NAME_REQUEST_REPLY_PRIMARY_OWNER && + reply != ELDBUS_NAME_REQUEST_REPLY_ALREADY_OWNER) + { + ERR("Not primary owner: reply=%d", reply); + goto error; + } + + return; + +error: + ecore_idler_add(_wkb_ibus_shutdown_idler, NULL); +} + +static void +_wkb_name_release_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending) +{ + unsigned int reply; + + CHECK_MESSAGE_ERRORS(msg) + + if (!eldbus_message_arguments_get(msg, "u", &reply)) + { + ERR("Error reading message arguments"); + return; + } + + if (reply != ELDBUS_NAME_RELEASE_REPLY_RELEASED) + { + ERR("Unexpected name release reply: %d", reply); + return; + } +} + +static void +_wkb_ibus_launch_daemon(void) +{ + DBG("Launching ibus-daemon"); + ctx->ibus_daemon = ecore_exe_run("ibus-daemon -s", NULL); + if (!ctx->ibus_daemon) + { + ERR("Error launching ibus-daemon process"); + return; + } +} + +static Eina_Bool +_wkb_ibus_query_address_cb(void *data, int type, void *event) +{ + Ecore_Exe_Event_Data *exe_data = (Ecore_Exe_Event_Data *)event; + + if (strncmp(exe_data->data, "(null)", exe_data->size) == 0) + { + INF("IBus daemon is not running."); + _wkb_ibus_launch_daemon(); + goto end; + } + else if (strstr(exe_data->data, "unknown command") != NULL) + { + ERR("ibus command does not support the 'address' argument"); + goto end; + } + + free(ctx->address); + ctx->address = strndup(exe_data->data, exe_data->size); + +end: + ecore_idler_add(ecore_exe_free, exe_data->exe); + ctx->address_pending = EINA_FALSE; + return ECORE_CALLBACK_DONE; +} + + +static void +_wkb_ibus_query_address(void) +{ + const char *ibus_addr; + Ecore_Exe *ibus_exec = NULL; + + /* Check for IBUS_ADDRESS environment variable */ + if ((ibus_addr = getenv("IBUS_ADDRESS")) != NULL) + { + DBG("Got IBus address from IBUS_ADDRESS environment variable %s", ibus_addr); + ctx->address = strdup(ibus_addr); + return; + } + + /* Get IBus address by invoking 'ibus address' from command line */ + DBG("Querying IBus address from using 'ibus address' command"); + ibus_exec = ecore_exe_pipe_run("ibus address", + ECORE_EXE_PIPE_READ | + ECORE_EXE_PIPE_READ_LINE_BUFFERED, + NULL); + if (!ibus_exec) + { + ERR("Unable to retrieve IBus address"); + return; + } + + ctx->address_pending = EINA_TRUE; + ecore_event_handler_add(ECORE_EXE_EVENT_DATA, _wkb_ibus_query_address_cb, NULL); +} + +Eina_Bool +wkb_ibus_connect(void) +{ + if (ctx->conn) + return EINA_TRUE; + + if (!ctx->address) + { + INF("IBus address is not set.", ctx->address_pending); + if (!ctx->address_pending) + _wkb_ibus_query_address(); + + return EINA_FALSE; + } + + INF("Connecting to IBus at address '%s'", ctx->address); + ctx->conn = eldbus_address_connection_get(ctx->address); + + if (!ctx->conn) + { + ERR("Error connecting to IBus"); + return EINA_FALSE; + } + + /* Panel */ + eldbus_name_owner_changed_callback_add(ctx->conn, + IBUS_SERVICE_PANEL, + _wkb_name_owner_changed_cb, + ctx, EINA_TRUE); + + ctx->panel.name_acquired = eldbus_signal_handler_add(ctx->conn, + ELDBUS_FDO_BUS, + ELDBUS_FDO_PATH, + IBUS_INTERFACE_PANEL, + "NameAcquired", + _wkb_name_acquired_cb, + ctx); + + ctx->panel.name_lost = eldbus_signal_handler_add(ctx->conn, + ELDBUS_FDO_BUS, + ELDBUS_FDO_PATH, + IBUS_INTERFACE_PANEL, + "NameLost", + _wkb_name_lost_cb, + ctx); + + eldbus_name_request(ctx->conn, IBUS_SERVICE_PANEL, + ELDBUS_NAME_REQUEST_FLAG_REPLACE_EXISTING | ELDBUS_NAME_REQUEST_FLAG_DO_NOT_QUEUE, + _wkb_name_request_cb, ctx); + + /* Config */ + eldbus_name_owner_changed_callback_add(ctx->conn, + IBUS_SERVICE_CONFIG, + _wkb_name_owner_changed_cb, + ctx, EINA_TRUE); + +#if 0 + ctx->config.name_acquired = eldbus_signal_handler_add(ctx->conn, + ELDBUS_FDO_BUS, + ELDBUS_FDO_PATH, + IBUS_INTERFACE_CONFIG, + "NameAcquired", + _wkb_name_acquired_cb, + ctx); + + ctx->config.name_lost = eldbus_signal_handler_add(ctx->conn, + ELDBUS_FDO_BUS, + ELDBUS_FDO_PATH, + IBUS_INTERFACE_CONFIG, + "NameLost", + _wkb_name_lost_cb, + ctx); + + eldbus_name_request(ctx->conn, IBUS_SERVICE_CONFIG, + ELDBUS_NAME_REQUEST_FLAG_REPLACE_EXISTING | ELDBUS_NAME_REQUEST_FLAG_DO_NOT_QUEUE, + _wkb_name_request_cb, ctx); +#endif + return EINA_TRUE; +} + + +int +wkb_ibus_init(void) +{ + if (ctx && ctx->refcount > 0) + goto end; + + if (!eina_init()) + { + fprintf(stderr, "Error initializing Eina\n"); + return 0; + } + + _wkb_ibus_log_dom = eina_log_domain_register("wkb-ibus", EINA_COLOR_LIGHTCYAN); + if (_wkb_ibus_log_dom < 0) + { + EINA_LOG_ERR("Unable to register 'wkb-ibus' log domain"); + eina_shutdown(); + return 0; + } + + if (!ctx && !(ctx = calloc(1, sizeof(*ctx)))) + { + ERR("Error calloc\n"); + eina_shutdown(); + return 0; + } + + _wkb_ibus_query_address(); + +end: + return ++ctx->refcount; +} + +void +wkb_ibus_shutdown(void) +{ + if (!ctx) + { + fprintf(stderr, "Not initialized\n"); + return; + } + + if (ctx->refcount == 0) + { + ERR("Refcount already 0"); + goto end; + } + + if (--(ctx->refcount) != 0) + return; + + DBG("Shutting down"); + wkb_ibus_disconnect(); + + free(ctx->address); + + if (ctx->ibus_daemon) + { + DBG("Terminating ibus-daemon"); + ecore_exe_terminate(ctx->ibus_daemon); + ecore_exe_free(ctx->ibus_daemon); + } + +end: + free(ctx); + ctx = NULL; + + ecore_main_loop_quit(); + DBG("Main loop quit"); +} + +void +wkb_ibus_disconnect(void) +{ + if (!ctx->conn) + { + ERR("Not connected"); + return; + } + + DBG("Disconnect"); + + if (ctx->panel.interface) + { + eldbus_name_release(ctx->conn, IBUS_SERVICE_PANEL, _wkb_name_release_cb, ctx); + eldbus_signal_handler_del(ctx->panel.name_acquired); + eldbus_signal_handler_del(ctx->panel.name_lost); + eldbus_service_interface_unregister(ctx->panel.interface); + ctx->panel.interface = NULL; + } + + if (ctx->config) + { + eldbus_proxy_unref(ctx->config); + ctx->config = NULL; + } +#if 0 + if (ctx->config.interface) + { + eldbus_name_release(ctx->conn, IBUS_SERVICE_CONFIG, _wkb_name_release_cb, ctx); + eldbus_signal_handler_del(ctx->config.name_acquired); + eldbus_signal_handler_del(ctx->config.name_lost); + eldbus_service_interface_unregister(ctx->config.interface); + ctx->config.interface = NULL; + } +#endif + + eldbus_connection_unref(ctx->conn); +} + +Eina_Bool +wkb_ibus_is_connected(void) +{ + return ctx->conn != NULL; +} diff --git a/src/wkb-ibus.h b/src/wkb-ibus.h new file mode 100644 index 0000000..f3b0a1f --- /dev/null +++ b/src/wkb-ibus.h @@ -0,0 +1,69 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _WKB_IBUS_H_ +#define _WKB_IBUS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern int _wkb_ibus_log_dom; +#define DBG(...) EINA_LOG_DOM_DBG(_wkb_ibus_log_dom, __VA_ARGS__) +#define INF(...) EINA_LOG_DOM_INFO(_wkb_ibus_log_dom, __VA_ARGS__) +#define WRN(...) EINA_LOG_DOM_WARN(_wkb_ibus_log_dom, __VA_ARGS__) +#define ERR(...) EINA_LOG_DOM_ERR(_wkb_ibus_log_dom, __VA_ARGS__) +#define CRITICAL(...) EINA_LOG_DOM_CRIT(_wkb_ibus_log_dom, __VA_ARGS__) + + +/* from ibusshare.h */ +#define IBUS_SERVICE_IBUS "org.freedesktop.IBus" +#define IBUS_SERVICE_PANEL "org.freedesktop.IBus.Panel" +#define IBUS_SERVICE_CONFIG "org.freedesktop.IBus.Config" + +#define IBUS_PATH_IBUS "/org/freedesktop/IBus" +#define IBUS_PATH_PANEL "/org/freedesktop/IBus/Panel" +#define IBUS_PATH_CONFIG "/org/freedesktop/IBus/Config" + +#define IBUS_INTERFACE_IBUS "org.freedesktop.IBus" +#define IBUS_INTERFACE_PANEL "org.freedesktop.IBus.Panel" +#define IBUS_INTERFACE_CONFIG "org.freedesktop.IBus.Config" + + +int wkb_ibus_init(void); +void wkb_ibus_shutdown(void); + +Eina_Bool wkb_ibus_connect(void); +void wkb_ibus_disconnect(void); + +Eina_Bool wkb_ibus_is_connected(void); + +/* Panel */ +Eldbus_Service_Interface * wkb_ibus_panel_register(Eldbus_Connection *conn); + +/* Config */ +#if 0 +Eldbus_Service_Interface * wkb_ibus_config_register(Eldbus_Connection *conn); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _WKB_IBUS_H_ */ diff --git a/src/wkb-main.c b/src/wkb-main.c new file mode 100644 index 0000000..953b283 --- /dev/null +++ b/src/wkb-main.c @@ -0,0 +1,601 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "input-method-client-protocol.h" +#include "text-client-protocol.h" + +struct weekeyboard +{ + Ecore_Evas *ee; + Ecore_Wl_Window *win; + Evas_Object *edje_obj; + const char *ee_engine; + char **ignore_keys; + + struct wl_surface *surface; + struct wl_input_panel *ip; + struct wl_input_method *im; + struct wl_output *output; + struct wl_input_method_context *im_ctx; + + char *surrounding_text; + char *preedit_str; + char *language; + + uint32_t text_direction; + uint32_t preedit_style; + uint32_t content_hint; + uint32_t content_purpose; + uint32_t serial; + uint32_t surrounding_cursor; + + Eina_Bool context_changed; +}; + +static void +_cb_wkb_delete_request(Ecore_Evas *ee EINA_UNUSED) +{ + ecore_main_loop_quit(); +} + +static char * +_wkb_insert_text(const char *text, uint32_t offset, const char *insert) +{ + char *new_text = malloc(strlen(text) + strlen(insert) + 1); + + strncat(new_text, text, offset); + new_text[offset] = '\0'; + strcat(new_text, insert); + strcat(new_text, text + offset); + + return new_text; +} + +static void +_wkb_commit_preedit_str(struct weekeyboard *wkb) +{ + char *surrounding_text; + + if (!wkb->preedit_str || !strlen(wkb->preedit_str) == 0) + return; + + wl_input_method_context_cursor_position(wkb->im_ctx, 0, 0); + wl_input_method_context_commit_string(wkb->im_ctx, wkb->serial, wkb->preedit_str); + + if (wkb->surrounding_text) + { + surrounding_text = _wkb_insert_text(wkb->surrounding_text, wkb->surrounding_cursor, wkb->preedit_str); + free(wkb->surrounding_text); + wkb->surrounding_text = surrounding_text; + wkb->surrounding_cursor += strlen(wkb->preedit_str); + } + else + { + wkb->surrounding_text = strdup(wkb->preedit_str); + wkb->surrounding_cursor = strlen(wkb->preedit_str); + } + + free(wkb->preedit_str); + wkb->preedit_str = strdup(""); +} + +static void +_wkb_send_preedit_str(struct weekeyboard *wkb, int cursor) +{ + unsigned int index = strlen(wkb->preedit_str); + + if (wkb->preedit_style) + wl_input_method_context_preedit_styling(wkb->im_ctx, 0, strlen(wkb->preedit_str), wkb->preedit_style); + + if (cursor > 0) + index = cursor; + + wl_input_method_context_preedit_cursor(wkb->im_ctx, index); + wl_input_method_context_preedit_string(wkb->im_ctx, wkb->serial, wkb->preedit_str, wkb->preedit_str); +} + +static void +_wkb_update_preedit_str(struct weekeyboard *wkb, const char *key) +{ + char *tmp; + + if (!wkb->preedit_str) + wkb->preedit_str = strdup(""); + + tmp = calloc(1, strlen(wkb->preedit_str) + strlen(key) + 1); + sprintf(tmp, "%s%s", wkb->preedit_str, key); + free(wkb->preedit_str); + wkb->preedit_str = tmp; + + if (strcmp(key, " ") == 0) + _wkb_commit_preedit_str(wkb); + else + _wkb_send_preedit_str(wkb, -1); +} + +static Eina_Bool +_wkb_ignore_key(struct weekeyboard *wkb, const char *key) +{ + int i; + + if (!wkb->ignore_keys) + return EINA_FALSE; + + for (i = 0; wkb->ignore_keys[i] != NULL; i++) + if (!strcmp(key, wkb->ignore_keys[i])) + return EINA_TRUE; + + return EINA_FALSE; +} + +static void +_cb_wkb_on_key_down(void *data, Evas_Object *obj, const char *emission EINA_UNUSED, const char *source) +{ + struct weekeyboard *wkb = data; + char *src; + const char *key; + + src = strdup(source); + key = strtok(src, ":"); /* ignore group */ + key = strtok(NULL, ":"); + if (key == NULL) + key = ":"; + + if (_wkb_ignore_key(wkb, key)) + { + printf("Ignoring key '%s'\n", key); + goto end; + } + else if (strcmp(key, "backspace") == 0) + { + if (strlen(wkb->preedit_str) == 0) + wl_input_method_context_delete_surrounding_text(wkb->im_ctx, -1, 1); + else + { + wkb->preedit_str[strlen(wkb->preedit_str) - 1] = '\0'; + _wkb_send_preedit_str(wkb, -1); + } + + goto end; + } + else if (strcmp(key, "enter") == 0) + { + _wkb_commit_preedit_str(wkb); + /* wl_input_method_context_keysym(wkb->im_ctx, wkb->serial, time, XKB_KEY_Return, key_state, mod_mask); */ + goto end; + } + else if (strcmp(key, "space") == 0) + { + key = " "; + } + + printf("KEY = '%s'\n", key); + + _wkb_update_preedit_str(wkb, key); + +end: + free(src); +} + +static void +_wkb_im_ctx_surrounding_text(void *data, struct wl_input_method_context *im_ctx, const char *text, uint32_t cursor, uint32_t anchor) +{ + struct weekeyboard *wkb = data; + + printf("%s()\n", __FUNCTION__); + free(wkb->surrounding_text); + wkb->surrounding_text = strdup(text); + wkb->surrounding_cursor = cursor; +} + +static void +_wkb_im_ctx_reset(void *data, struct wl_input_method_context *im_ctx) +{ + struct weekeyboard *wkb = data; + + printf("%s()\n", __FUNCTION__); + + if (strlen(wkb->preedit_str)) + { + free(wkb->preedit_str); + wkb->preedit_str = strdup(""); + } +} + +static void +_wkb_im_ctx_content_type(void *data, struct wl_input_method_context *im_ctx, uint32_t hint, uint32_t purpose) +{ + struct weekeyboard *wkb = data; + + printf("%s(): im_context = %p hint = %d purpose = %d\n", __FUNCTION__, im_ctx, hint, purpose); + + if (!wkb->context_changed) + return; + + switch (purpose) + { + case WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS: + case WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER: + { + edje_object_signal_emit(wkb->edje_obj, "show,numeric", ""); + break; + } + default: + { + edje_object_signal_emit(wkb->edje_obj, "show,alphanumeric", ""); + break; + } + } + + wkb->content_hint = hint; + wkb->content_purpose = purpose; + + wkb->context_changed = EINA_FALSE; +} + +static void +_wkb_im_ctx_invoke_action(void *data, struct wl_input_method_context *im_ctx, uint32_t button, uint32_t index) +{ + struct weekeyboard *wkb = data; + + printf("%s()\n", __FUNCTION__); + if (button != BTN_LEFT) + return; + + _wkb_send_preedit_str(wkb, index); +} + +static void +_wkb_im_ctx_commit_state(void *data, struct wl_input_method_context *im_ctx, uint32_t serial) +{ + struct weekeyboard *wkb = data; + + printf("%s()\n", __FUNCTION__); + if (wkb->surrounding_text) + fprintf(stderr, "Surrounding text updated: %s\n", wkb->surrounding_text); + + wkb->serial = serial; + /* FIXME */ + wl_input_method_context_language(im_ctx, wkb->serial, "en");//wkb->language); + wl_input_method_context_text_direction(im_ctx, wkb->serial, WL_TEXT_INPUT_TEXT_DIRECTION_LTR);//wkb->text_direction); +} + +static void +_wkb_im_ctx_preferred_language(void *data, struct wl_input_method_context *im_ctx, const char *language) +{ + struct weekeyboard *wkb = data; + + if (language && wkb->language && !strcmp(language, wkb->language)) + return; + + if (wkb->language) + { + free(wkb->language); + wkb->language = NULL; + } + + if (language) + { + wkb->language = strdup(language); + printf("Language changed, new: '%s\n", language); + } +} + +static const struct wl_input_method_context_listener wkb_im_context_listener = { + _wkb_im_ctx_surrounding_text, + _wkb_im_ctx_reset, + _wkb_im_ctx_content_type, + _wkb_im_ctx_invoke_action, + _wkb_im_ctx_commit_state, + _wkb_im_ctx_preferred_language, +}; + +static void +_wkb_im_activate(void *data, struct wl_input_method *input_method, struct wl_input_method_context *im_ctx) +{ + struct weekeyboard *wkb = data; + struct wl_array modifiers_map; + + if (wkb->im_ctx) + wl_input_method_context_destroy(wkb->im_ctx); + + if (wkb->preedit_str) + free(wkb->preedit_str); + + wkb->preedit_str = strdup(""); + wkb->content_hint = WL_TEXT_INPUT_CONTENT_HINT_NONE; + wkb->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NORMAL; + free(wkb->language); + wkb->language = NULL; + free(wkb->surrounding_text); + wkb->surrounding_text = NULL; + wkb->serial = 0; + + wkb->im_ctx = im_ctx; + wl_input_method_context_add_listener(im_ctx, &wkb_im_context_listener, wkb); + + /* + wl_array_init(&modifiers_map); + + keysym_modifiers_add(&modifiers_map, "Shift"); + keysym_modifiers_add(&modifiers_map, "Control"); + keysym_modifiers_add(&modifiers_map, "Mod1"); + + wl_input_method_context_modifiers_map(im_ctx, &modifiers_map); + + wkb->keysym.shift_mask = keysym_modifiers_get_mask(&modifiers_map, "Shift"); + + wl_array_release(&modifiers_map); + */ + + /* FIXME */ + wl_input_method_context_language(im_ctx, wkb->serial, "en");//wkb->language); + wl_input_method_context_text_direction(im_ctx, wkb->serial, WL_TEXT_INPUT_TEXT_DIRECTION_LTR);//wkb->text_direction); + + wkb->context_changed = EINA_TRUE; + evas_object_show(wkb->edje_obj); +} + +static void +_wkb_im_deactivate(void *data, struct wl_input_method *input_method, struct wl_input_method_context *im_ctx) +{ + struct weekeyboard *wkb = data; + + if (!wkb->im_ctx) + return; + + wl_input_method_context_destroy(wkb->im_ctx); + wkb->im_ctx = NULL; + evas_object_hide(wkb->edje_obj); +} + +static const struct wl_input_method_listener wkb_im_listener = { + _wkb_im_activate, + _wkb_im_deactivate +}; + + +static Eina_Bool +_wkb_ui_setup(struct weekeyboard *wkb) +{ + char path[PATH_MAX]; + Evas *evas; + Evas_Coord w, h; + char *ignore_keys; + + ecore_evas_alpha_set(wkb->ee, EINA_TRUE); + ecore_evas_title_set(wkb->ee, "EFL virtual keyboard"); + + evas = ecore_evas_get(wkb->ee); + wkb->edje_obj = edje_object_add(evas); + /*ecore_evas_object_associate(wkb->ee, edje_obj, ECORE_EVAS_OBJECT_ASSOCIATE_BASE);*/ + + /* Check which theme we should use according to the screen width */ + ecore_wl_screen_size_get(&w, &h); + if (w >= 720) + w = 720; + else + w = 600; + + sprintf(path, PKGDATADIR"/default_%d.edj", w); + printf("Loading edje file: '%s'\n", path); + + if (!edje_object_file_set(wkb->edje_obj, path, "main")) + { + int err = edje_object_load_error_get(wkb->edje_obj); + fprintf(stderr, "error loading the edje file:%s\n", edje_load_error_str(err)); + return EINA_FALSE; + } + + edje_object_size_min_get(wkb->edje_obj, &w, &h); + if (w == 0 || h == 0) + { + edje_object_size_min_restricted_calc(wkb->edje_obj, &w, &h, w, h); + if (w == 0 || h == 0) + edje_object_parts_extends_calc(wkb->edje_obj, NULL, NULL, &w, &h); + } + + ecore_evas_move_resize(wkb->ee, 0, 0, w, h); + evas_object_move(wkb->edje_obj, 0, 0); + evas_object_resize(wkb->edje_obj, w, h); + evas_object_size_hint_min_set(wkb->edje_obj, w, h); + evas_object_size_hint_max_set(wkb->edje_obj, w, h); + + edje_object_signal_callback_add(wkb->edje_obj, "key_down", "*", _cb_wkb_on_key_down, wkb); + ecore_evas_callback_delete_request_set(wkb->ee, _cb_wkb_delete_request); + + /* + * The keyboard surface is bigger than it appears so that we can show the + * key pressed animation without requiring the use of subsurfaces. Here we + * resize the input region of the surface to match the keyboard background + * image, so that we can pass mouse events to the surfaces that may be + * located below the keyboard. + */ + if (wkb->win) + { + int x, y, w, h; + struct wl_region *input = wl_compositor_create_region(wkb->win->display->wl.compositor); + + edje_object_part_geometry_get(wkb->edje_obj, "background", &x, &y, &w, &h); + wl_region_add(input, x, y, w, h); + wl_surface_set_input_region(wkb->surface, input); + wl_region_destroy(input); + } + + /* special keys */ + ignore_keys = edje_file_data_get(path, "ignore-keys"); + if (!ignore_keys) + { + printf("Special keys file not found in '%s'\n", path); + goto end; + } + + printf("Got ignore keys = %s\n", ignore_keys); + wkb->ignore_keys = eina_str_split(ignore_keys, "\n", 0); + free(ignore_keys); + +end: + ecore_evas_show(wkb->ee); + return EINA_TRUE; +} + +static void +_wkb_setup(struct weekeyboard *wkb) +{ + struct wl_list *globals; + struct wl_registry *registry; + Ecore_Wl_Global *global; + + struct wl_input_panel_surface *ips; + + globals = ecore_wl_globals_get(); + registry = ecore_wl_registry_get(); + wl_list_for_each(global, globals, link) + { + if (strcmp(global->interface, "wl_input_panel") == 0) + wkb->ip = wl_registry_bind(registry, global->id, &wl_input_panel_interface, 1); + else if (strcmp(global->interface, "wl_input_method") == 0) + wkb->im = wl_registry_bind(registry, global->id, &wl_input_method_interface, 1); + else if (strcmp(global->interface, "wl_output") == 0) + wkb->output = wl_registry_bind(registry, global->id, &wl_output_interface, 1); + } + + /* Set input panel surface */ + wkb->win = ecore_evas_wayland_window_get(wkb->ee); + ecore_wl_window_type_set(wkb->win, ECORE_WL_WINDOW_TYPE_NONE); + wkb->surface = ecore_wl_window_surface_create(wkb->win); + ips = wl_input_panel_get_input_panel_surface(wkb->ip, wkb->surface); + wl_input_panel_surface_set_toplevel(ips, wkb->output, WL_INPUT_PANEL_SURFACE_POSITION_CENTER_BOTTOM); + + /* Input method listener */ + wl_input_method_add_listener(wkb->im, &wkb_im_listener, wkb); +} + +static void +_wkb_free(struct weekeyboard *wkb) +{ + if (wkb->im_ctx) + wl_input_method_context_destroy(wkb->im_ctx); + + if (wkb->ignore_keys) + { + free(*wkb->ignore_keys); + free(wkb->ignore_keys); + } + + evas_object_del(wkb->edje_obj); + free(wkb->preedit_str); + free(wkb->surrounding_text); +} + +static Eina_Bool +_wkb_check_evas_engine(struct weekeyboard *wkb) +{ + Eina_Bool ret = EINA_FALSE; + char *env = getenv("ECORE_EVAS_ENGINE"); + + if (!env) + { + if (ecore_evas_engine_type_supported_get(ECORE_EVAS_ENGINE_WAYLAND_SHM)) + env = "wayland_shm"; + else if (ecore_evas_engine_type_supported_get(ECORE_EVAS_ENGINE_WAYLAND_EGL)) + env = "wayland_egl"; + else + { + printf("ERROR: Ecore_Evas does must be compiled with support for Wayland engines\n"); + goto err; + } + } + else if (strcmp(env, "wayland_shm") != 0 && strcmp(env, "wayland_egl") != 0) + { + printf("ERROR: ECORE_EVAS_ENGINE must be set to either 'wayland_shm' or 'wayland_egl'\n"); + goto err; + } + + wkb->ee_engine = env; + ret = EINA_TRUE; + +err: + return ret; +} + +int +main(int argc EINA_UNUSED, char **argv EINA_UNUSED) +{ + struct weekeyboard wkb = {0}; + int ret = EXIT_FAILURE; + + if (!ecore_init()) + return ret; + + if (!ecore_evas_init()) + goto ecore_err; + + if (!edje_init()) + goto ee_err; + + if (!_wkb_check_evas_engine(&wkb)) + goto edj_err; + + printf("SELECTED ENGINE = %s\n", wkb.ee_engine); + wkb.ee = ecore_evas_new(wkb.ee_engine, 0, 0, 1, 1, "frame=0"); + + if (!wkb.ee) + { + printf("ERROR: Unable to create Ecore_Evas object\n"); + goto edj_err; + } + + _wkb_setup(&wkb); + + if (!_wkb_ui_setup(&wkb)) + goto end; + + ecore_main_loop_begin(); + + ret = EXIT_SUCCESS; + + _wkb_free(&wkb); + +end: + ecore_evas_free(wkb.ee); + +edj_err: + edje_shutdown(); + +ee_err: + ecore_evas_shutdown(); + +ecore_err: + ecore_shutdown(); + + return ret; +} -- 2.7.4