Compare commits

..

92 Commits

Author SHA1 Message Date
f167a0e44a Tie the package to a specific version of the Rust standard library
The file for the Rust standard library has a specific file name which
may change.
2019-07-01 17:20:37 +02:00
1804b28a0d Link rslib statically 2019-07-01 16:39:34 +02:00
737d57c1f4 Merge branch 'install-rslib' into 'squeekboard'
Install rslib

See merge request Librem5/squeekboard!12
2019-07-01 12:57:22 +00:00
9985ad7ee1 Fix lintian package-must-activate-ldconfig-trigger error 2019-07-01 01:46:16 +02:00
025b55e1a2 Install rslib 2019-07-01 00:05:42 +02:00
14fbabe8d7 Merge branch 'popup' into 'squeekboard'
Pop up when input requested

See merge request Librem5/squeekboard!10
2019-06-30 19:04:42 +00:00
b746f7a70e input method: Pop up the keyboard 2019-06-30 19:03:24 +00:00
0d3b003aac input method: Initialize the protocol and pretend to handle a few things 2019-06-30 19:03:24 +00:00
9428927879 Merge branch 'build-dep' into 'squeekboard'
ci: Use build-dep instead of a dependency list

See merge request Librem5/squeekboard!11
2019-06-30 19:03:08 +00:00
511b2f7186 ci: Use build-dep instead of a dependency list 2019-06-30 19:01:36 +00:00
d8c83e3c65 Merge branch 'touch' into 'squeekboard'
Touch support

See merge request Librem5/squeekboard!9
2019-06-30 06:11:16 +00:00
050fd6f3ba Touch support
Single stream of touch events.
2019-06-29 12:56:04 +00:00
72d6a8d4e1 Merge branch 'wayland-gen' into 'squeekboard'
build: Use 'client-code' instead of 'code' for protocols

See merge request Librem5/squeekboard!8
2019-06-29 12:47:27 +00:00
30d35216f6 build: Use 'client-code' instead of 'code' for protocols 2019-06-29 12:46:08 +00:00
bcd0d40912 Merge branch 'fixes' into 'squeekboard'
fix: Remove leftover debug print

See merge request Librem5/squeekboard!7
2019-06-29 12:18:59 +00:00
4b8a6bbbe0 fix: Remove leftover debug print 2019-06-29 12:16:34 +00:00
752dc467a8 Merge branch 'desktop-file' into 'squeekboard'
Add a desktop file

See merge request Librem5/squeekboard!5
2019-06-29 10:13:20 +00:00
bde45b262a Merge branch 'debian-files' into 'squeekboard'
Add Debian packaging files

See merge request Librem5/squeekboard!4
2019-06-29 10:10:15 +00:00
fc338f5723 Add Debian packaging files 2019-06-29 10:10:15 +00:00
346ed453ef Start working on a desktop file 2019-06-26 18:17:54 +02:00
664f05edba Remove unnecessary build dependency 2019-06-26 17:45:23 +02:00
edcff44f4b Add another build dependency, add an empty rule to override autoreconf 2019-06-26 17:35:13 +02:00
42ee5d2ddb Update packaging files 2019-06-26 17:35:05 +02:00
54e421d7e6 Add initial Debian packaging 2019-06-26 17:35:00 +02:00
9e5629d1e0 Enable Wayland's virtual-keyboard protocol
This commit includes a little restructuring necessary for keeping wayland objects properly.
It doesn't fix broken modifier functionality yet.
2019-06-25 18:12:15 +00:00
c0fdffac28 Separate keyboards from the dbus handler 2019-06-23 10:59:45 +00:00
e94e64d204 Move dbus setup closer together 2019-06-23 10:42:20 +00:00
e503e35b84 Rename squeak_ to squeek_ for consitency 2019-06-23 10:30:25 +00:00
752592a3d8 Fixed build 2019-06-23 10:29:18 +00:00
2e6d194a6f Remove server-service 2019-06-23 10:26:24 +00:00
63dfb07b51 Simplify the storage of context 2019-06-23 09:54:09 +00:00
02525056d6 Removed X11 header, added some clarifications 2019-06-22 16:20:03 +00:00
8292429648 Context: removing more unused things 2019-06-22 16:04:33 +00:00
765c496068 Removed more unused stuff in context 2019-06-22 15:57:48 +00:00
d6feec8010 Removed d-bus paths from service class 2019-06-22 15:40:20 +00:00
f1fbb37547 Kill connection in context service 2019-06-22 15:31:08 +00:00
5a6386dd24 Fixed rendering deprecation warnings 2019-06-22 13:13:55 +00:00
0809db9e32 Remove some rendering code with no effect and warnings 2019-06-22 12:56:33 +00:00
15a3315854 Fix dragging across the keyboard 2019-06-22 12:34:10 +00:00
82d1f256b2 Remove released and cancelled key events 2019-06-22 12:23:04 +00:00
e7ba2a0eb0 Got rid of signals in the pressed path 2019-06-19 17:00:30 +00:00
eff0449b3a Redrawing key after press is happening directly 2019-06-19 16:51:57 +00:00
3b9e066ec8 Simplify key press handling 2019-06-19 16:05:37 +00:00
260ab42b9e Forward press timestamps 2019-06-19 15:56:19 +00:00
a3d745edd0 Moved key pressing from context to keyboard 2019-06-19 15:27:29 +00:00
40a92fe730 Ignoring section.key-pressed 2019-06-19 14:11:23 +00:00
e30bb23711 build: Add debug/release options 2019-06-18 13:37:10 +00:00
292c1d08d8 fixes: Minor type and include mismatches 2019-06-16 12:55:50 +00:00
be56447614 readme: Update development installation info 2019-06-16 12:13:43 +00:00
70fda8ba64 Fix releasing buttons when dragged 2019-04-06 18:46:33 +00:00
5cc407986b Ignore multi-clicks and non-left-buttons 2019-04-06 18:35:06 +00:00
53af829f46 Send both press and release events 2019-04-06 17:45:06 +00:00
53065a6d95 Fix crash on double click 2019-04-05 18:42:11 +00:00
862cfdb55d Showing and hiding 2019-04-05 18:36:25 +00:00
b065b16bf1 Use layer shell 2019-04-05 15:39:57 +00:00
6ff33b48d1 dbus: Add missing schema 2019-03-27 13:48:53 +00:00
d04020f79c readme: Use language with non-US layout 2019-03-27 13:33:40 +00:00
6b15072764 dbus: Use generated code 2019-03-23 09:36:53 +00:00
f261115ac4 ci: Change job name to meson 2019-03-22 19:06:29 +00:00
116f130c4c readme: Remove settings schema variable 2019-03-22 19:00:03 +00:00
cad1b02482 settings: Switching layouts according to input settings 2019-03-22 17:18:12 +00:00
09fe69f63a cleanup: Remove Context dbus interface remains 2019-03-22 16:35:02 +00:00
8ecd81d51c settings: Fall back to "us" layout when no file found 2019-03-22 16:20:39 +00:00
8f71b010cc settings: Removed custom settings schema 2019-03-22 15:52:35 +00:00
b817c6189d build: Update keysym generator to Python3 2019-03-22 13:09:21 +00:00
a00d41930d readme: Update features 2019-03-22 07:23:17 +00:00
caee942796 build, readme: Update build and run instructions 2019-03-22 07:23:17 +00:00
d3410fdc61 Keyboard shows up on a single ShowKeyboard 2019-03-22 07:23:12 +00:00
8087c3e5d4 build: Use only meson for squeekboard
This breaks autoconf. The only resulting binary is the squeekboard GUI. It still needs the autotools-built eekboard client in order to do anything useful. That one needs to be built using a different branch, making this a WIP.
2019-03-15 20:59:29 +00:00
10bd0ea09e build: Remove eekboard-server 2019-03-14 20:40:27 +00:00
5803222e68 build: Remove libeekboard dependency 2019-03-14 18:03:10 +00:00
a243fce1ae build: Squeekboard build in meson 2019-03-14 17:29:13 +00:00
c8059ebf50 stubbing: Key generation events
Only enabled when Xtest is in use. It's probably always meant to be in use though, as this piece of code also opens the preferences dialog
2019-03-14 11:09:35 +00:00
ce2d270e7c ci: Add config flags relevant for Wayland builds 2019-03-13 18:08:56 +00:00
0c945bdc7e readme: Update build and run instructions 2019-03-13 17:59:59 +00:00
60ec684853 readme: Moved to Markdown 2019-03-13 17:59:54 +00:00
b159625e62 Add gitlab CI 2019-02-14 16:57:39 +00:00
e212262f29 Stop key-repeat when the server receives a new D-Bus event.
Key-repeat timer should be cleared when the server receives a new D-Bus.
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=857977
2012-10-01 11:55:04 +09:00
c71167d893 Fix out-of-tree build. 2012-10-01 11:55:00 +09:00
2d4e4c7a13 Fix compiler warnings. 2012-10-01 11:37:47 +09:00
695f8df5b8 Bump version to 1.0.8. 2012-08-15 17:28:23 +09:00
2e822cb6a6 Don't crash when all the keyboards are removed. 2012-08-15 17:27:20 +09:00
f2a90935a3 Make "visible" property per client instead of per context. 2012-04-24 18:38:32 +09:00
cee741eca0 Fix initial window size. 2012-04-24 12:48:35 +09:00
b5b59e77d6 Check errors when retrieving XKB layout information. 2012-04-24 11:58:41 +09:00
cce883808e Simplify eek-xkb-layout.c. 2012-04-24 11:01:42 +09:00
8faae7ef08 Use git.mk. 2012-04-24 10:38:36 +09:00
4538ef38a1 Revert "Remove eek-xkb*."
This reverts commit ee12d02402.
2012-04-24 10:06:09 +09:00
ee12d02402 Remove eek-xkb*. 2012-04-23 18:35:15 +09:00
7050fa41a0 G_CONST_RETURN -> const. 2012-04-23 17:09:48 +09:00
4a346211b8 Show tooltips. 2012-04-23 16:43:06 +09:00
4df2ecc8ae Don't abort when failed to load keyboard. 2012-04-16 14:37:18 +09:00
97 changed files with 3931 additions and 2454 deletions

84
.gitignore vendored
View File

@ -1,84 +0,0 @@
*.la
*.lo
*.loT
*.o
*.so
*~
*.pyc
Makefile
Makefile.in
.deps
.libs
INSTALL
aclocal.m4
autom4te.cache
compile
config.guess
config.h
config.h.in
config.log
config.rpath
config.status
config.sub
configure
depcomp
install-sh
libtool
ltmain.sh
missing
stamp-h1
libkeyactor*.tar.*
mkinstalldirs
m4/*.m4
gtk-doc.make
eek/eek-special-keysym-entries.h
eek/eek-unicode-keysym-entries.h
eek/eek-xkeysym-keysym-entries.h
eek/eek-enumtypes.[ch]
eek/eek-marshalers.[ch]
eek/*.pc
eek/*.gir
eek/*.typelib
eekboard/*.pc
eekboard/*.gir
eekboard/*.typelib
eekboard/eekboard-marshalers.[ch]
tests/eek-simple-test
tests/eek-xkb-test
tests/eek-xml-test
src/eekboard
src/eekboard-server
docs/reference/eek/*.stamp
docs/reference/eek/*.txt
docs/reference/eek/eek.types
!/docs/reference/eek/eek-sections.txt
docs/reference/eek/xml
docs/reference/eek/html
docs/reference/eek/eek.signals
docs/reference/eek/eek.args
docs/reference/eek/eek.hierarchy
docs/reference/eek/eek.interfaces
docs/reference/eek/eek.prerequisites
docs/reference/eekboard/*.stamp
docs/reference/eekboard/*.txt
!/docs/reference/eekboard/eekboard-sections.txt
docs/reference/eekboard/xml
docs/reference/eekboard/html
docs/reference/eekboard/eekboard.signals
docs/reference/eekboard/eekboard.args
docs/reference/eekboard/eekboard.hierarchy
docs/reference/eekboard/eekboard.interfaces
docs/reference/eekboard/eekboard.prerequisites
po/*.gmo
po/Makefile.in.in
po/POTFILES
po/stamp-it
po/.intltool-merge-cache
bindings/vala/*.vapi
py-compile
data/org.fedorahosted.eekboard.gschema.xml
data/org.fedorahosted.eekboard.gschema.valid
data/eekboard-server.service
data/*.desktop
examples/eekxml/eekxml

19
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,19 @@
image: debian:buster
stages:
- build
before_script:
- apt-get -y update
- apt-get -y build-dep .
build_meson:
stage: build
tags:
- librem5
script:
- mkdir -p ../build
- meson ../build/
- cd ../build
- ninja install

View File

@ -19,3 +19,23 @@
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
SUBDIRS = eek eekboard src tests bindings docs po data examples SUBDIRS = eek eekboard src tests bindings docs po data examples
DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc --enable-introspection DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc --enable-introspection
AUTOMAKE_OPTIONS = foreign # allow README.md to exist
GITIGNOREFILES = \
INSTALL \
aclocal.m4 \
compile \
config.guess \
config.h.in \
config.sub \
depcomp \
gtk-doc.make \
install-sh \
ltmain.sh \
m4 \
missing \
mkinstalldirs \
$(NULL)
-include $(top_srcdir)/git.mk

35
README
View File

@ -1,35 +0,0 @@
eekboard - an easy to use virtual keyboard toolkit -*- outline -*-
eekboard is a virtual keyboard software package, including a set of
tools to implement desktop virtual keyboards.
* Building
** Dependencies
REQUIRED: GLib2, GTK, PangoCairo, libxklavier, libcroco
OPTIONAL: libXtst, at-spi2-core, IBus, Clutter, Clutter-Gtk, Python, Vala, gobject-introspection, libcanberra
** Build from git repo
$ git clone git://github.com/ueno/eekboard.git
$ cd eekboard
$ ./autogen.sh --prefix=/usr --enable-gtk-doc
$ make
$ sudo make install
** Build from tarball
$ ./configure --prefix=/usr
$ make
$ sudo make install
* Running
$ eekboard
$ eekboard -f # show/hide automatically based on focus-in/focus-out events
Even though eekboard -f watches a11y events by default, it currently
works better with IBus. To use IBus, do:
$ gsettings set org.fedorahosted.eekboard focus-listener 'ibus'

68
README.md Normal file
View File

@ -0,0 +1,68 @@
*squeekboard* - a Wayland virtual keyboard
========================================
*Squeekboard* is a virtual keyboard supporting Wayland, built primarily for the *Librem 5* phone.
Features
--------
### Present
- GTK3
- Custom xml-defined keyboards
- DBus interface to show and hide
### Temporarily dropped
- A settings interface
### TODO
- Use Wayland virtual keyboard protocol
- Use Wayland text input protocol
- Use Wayland input method protocol
- Pick up DBus interface files from /usr/share
Building
--------
### Dependencies
See `.gitlab-ci.yml`.
### Build from git repo
```
$ git clone https://source.puri.sm/Librem5/eekboard.git
$ cd eekboard
$ mkdir ../build
$ meson ../build/
$ cd ../build
$ ninja install
```
For development, alter the `meson` call:
```
$ meson ../build/ --prefix=../install
```
and don't skip `ninja install` before running. The last step is necessary in order to find the keyboard definition files.
Running
-------
```
$ rootston
$ cd ../build/
$ src/squeekboard
```
### Testing
```
$ busctl call --user sm.puri.OSK0 /sm/puri/OSK0 sm.puri.OSK0 SetVisible b true
$ busctl call --user sm.puri.OSK0 /sm/puri/OSK0 sm.puri.OSK0 SetVisible b false
$ gsettings set org.gnome.desktop.input-sources sources "[('xkb', 'us'), ('xkb', 'ua')]"
$ gsettings set org.gnome.desktop.input-sources current 1
```

View File

@ -7,17 +7,12 @@ test -z "$srcdir" && srcdir=.
PKG_NAME="eekboard" PKG_NAME="eekboard"
(test -f $srcdir/configure.ac \ (test -f $srcdir/configure.ac \
&& test -f $srcdir/README ) || { && test -f $srcdir/README.md ) || {
echo -n "**Error**: Directory "\`$srcdir\'" does not look like the" echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
echo " top-level $PKG_NAME directory" echo " top-level $PKG_NAME directory"
exit 1 exit 1
} }
which gnome-autogen.sh || {
echo "You need to install gnome-common from the GNOME CVS"
exit 1
}
ACLOCAL_FLAGS="$ACLOCAL_FLAGS -I m4" ACLOCAL_FLAGS="$ACLOCAL_FLAGS -I m4"
REQUIRED_AUTOMAKE_VERSION=1.10 REQUIRED_AUTOMAKE_VERSION=1.10
REQUIRED_AUTOCONF_VERSION=2.60 REQUIRED_AUTOCONF_VERSION=2.60

View File

@ -17,3 +17,5 @@
# 02110-1301 USA # 02110-1301 USA
SUBDIRS = vala SUBDIRS = vala
-include $(top_srcdir)/git.mk

View File

@ -16,6 +16,8 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA # 02110-1301 USA
NULL =
if ENABLE_VALA if ENABLE_VALA
vapidir = $(datadir)/vala/vapi vapidir = $(datadir)/vala/vapi
dist_vapi_DATA = \ dist_vapi_DATA = \
@ -33,51 +35,62 @@ EXTRA_DIST = \
EekXkl-$(EEK_API_VERSION).metadata \ EekXkl-$(EEK_API_VERSION).metadata \
$(NULL) $(NULL)
GITIGNOREFILES = \
eek-$(EEK_API_VERSION).vapi \
eek-gtk-$(EEK_API_VERSION).vapi \
eek-xkl-$(EEK_API_VERSION).vapi \
$(NULL)
maintainer-clean-local: maintainer-clean-local:
rm -f *.vapi rm -f *.vapi
eek_vapi_deps = \ eek_vapi_deps = \
$(srcdir)/Eek-$(EEK_API_VERSION).metadata \ $(srcdir)/Eek-$(EEK_API_VERSION).metadata \
| \ | \
$(top_srcdir)/eek/Eek-$(EEK_API_VERSION).gir \ $(top_builddir)/eek/Eek-$(EEK_API_VERSION).gir \
$(NULL) $(NULL)
eek-$(EEK_API_VERSION).vapi: $(eek_vapi_deps) eek-$(EEK_API_VERSION).vapi: $(eek_vapi_deps)
$(VAPIGEN_V)$(VAPIGEN) \ $(VAPIGEN_V)$(VAPIGEN) \
--library eek-$(EEK_API_VERSION) \ --library eek-$(EEK_API_VERSION) \
--pkg gio-2.0 \ --pkg gio-2.0 \
--metadatadir=$(srcdir) \ --metadatadir=$(srcdir) \
$(top_srcdir)/eek/Eek-$(EEK_API_VERSION).gir $(top_builddir)/eek/Eek-$(EEK_API_VERSION).gir
eek_gtk_vapi_deps = \ eek_gtk_vapi_deps = \
$(srcdir)/EekGtk-$(EEK_API_VERSION).metadata \ $(srcdir)/EekGtk-$(EEK_API_VERSION).metadata \
| \ | \
$(top_srcdir)/eek/EekGtk-$(EEK_API_VERSION).gir \ $(top_builddir)/eek/EekGtk-$(EEK_API_VERSION).gir \
$(NULL) $(NULL)
eek-gtk-$(EEK_API_VERSION).vapi: $(eek_gtk_vapi_deps) eek-gtk-$(EEK_API_VERSION).vapi: $(eek_gtk_vapi_deps)
$(VAPIGEN_V)$(VAPIGEN) --vapidir=$(builddir) \ $(VAPIGEN_V)$(VAPIGEN) --vapidir=$(builddir) \
--library eek-gtk-$(EEK_API_VERSION) \ --library eek-gtk-$(EEK_API_VERSION) \
--pkg eek-$(EEK_API_VERSION) \ --pkg eek-$(EEK_API_VERSION) \
--pkg gtk+-3.0 \ --pkg gio-2.0 \
--metadatadir=$(srcdir) \ --pkg gtk+-3.0 \
$(top_srcdir)/eek/EekGtk-$(EEK_API_VERSION).gir --metadatadir=$(srcdir) \
$(top_builddir)/eek/EekGtk-$(EEK_API_VERSION).gir
eek_xkl_vapi_deps = \ eek_xkl_vapi_deps = \
$(srcdir)/EekXkl-$(EEK_API_VERSION).metadata \ $(srcdir)/EekXkl-$(EEK_API_VERSION).metadata \
| \ | \
$(top_srcdir)/eek/EekXkl-$(EEK_API_VERSION).gir \ $(top_builddir)/eek/EekXkl-$(EEK_API_VERSION).gir \
$(NULL) $(NULL)
eek-xkl-$(EEK_API_VERSION).vapi: $(eek_xkl_vapi_deps) eek-xkl-$(EEK_API_VERSION).vapi: $(eek_xkl_vapi_deps)
$(VAPIGEN_V)$(VAPIGEN) --vapidir=$(builddir) \ $(VAPIGEN_V)$(VAPIGEN) \
--library eek-xkl-$(EEK_API_VERSION) \ --vapidir=$(builddir) \
--pkg eek-$(EEK_API_VERSION) \ --library eek-xkl-$(EEK_API_VERSION) \
--metadatadir=$(srcdir) \ --pkg eek-$(EEK_API_VERSION) \
$(top_srcdir)/eek/EekXkl-$(EEK_API_VERSION).gir --pkg gio-2.0 \
--metadatadir=$(srcdir) \
$(top_builddir)/eek/EekXkl-$(EEK_API_VERSION).gir
# set up the verbosity rules to avoid some build noise # set up the verbosity rules to avoid some build noise
VAPIGEN_V = $(VAPIGEN_V_$(V)) VAPIGEN_V = $(VAPIGEN_V_$(V))
VAPIGEN_V_ = $(VAPIGEN_V_$(AM_DEFAULT_VERBOSITY)) VAPIGEN_V_ = $(VAPIGEN_V_$(AM_DEFAULT_VERBOSITY))
VAPIGEN_V_0 = @echo " VAPIG " $@; VAPIGEN_V_0 = @echo " VAPIG " $@;
endif endif
-include $(top_srcdir)/git.mk

View File

@ -1 +1,2 @@
eek-0.90 eek-0.90
x11

View File

@ -20,7 +20,7 @@ AC_PREREQ(2.63)
dnl AC_CONFIG_SRCDIR([configure.ac]) dnl AC_CONFIG_SRCDIR([configure.ac])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
AC_INIT([eekboard], [1.0.7], [ueno@unixuser.org]) AC_INIT([eekboard], [1.0.8], [ueno@unixuser.org])
dnl Init automake dnl Init automake
AM_INIT_AUTOMAKE AM_INIT_AUTOMAKE

View File

@ -32,3 +32,4 @@ CLEANFILES += $(autostart_DATA)
EXTRA_DIST += $(autostart_in_files) EXTRA_DIST += $(autostart_in_files)
endif endif
-include $(top_srcdir)/git.mk

View File

@ -0,0 +1,20 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
<interface name="sm.puri.OSK0">
<method name="SetVisible">
<arg name="visible" type="b" direction="in"/>
<doc:doc><doc:description>
Switch keyboard visibility
</doc:description></doc:doc>
</method>
<method name="GetVisible">
<arg name="visible" type="b" direction="out"/>
<doc:doc><doc:description>
Get keyboard visibility
</doc:description></doc:doc>
</method>
<property name="Visible" type="b" access="read">
</property>
</interface>
</node>

View File

@ -14,3 +14,4 @@ install-data-hook:
echo "*** $(gtk_update_icon_cache)"; \ echo "*** $(gtk_update_icon_cache)"; \
fi fi
-include $(top_srcdir)/git.mk

View File

@ -14,3 +14,4 @@ install-data-hook:
echo "*** $(gtk_update_icon_cache)"; \ echo "*** $(gtk_update_icon_cache)"; \
fi fi
-include $(top_srcdir)/git.mk

View File

@ -14,3 +14,4 @@ install-data-hook:
echo "*** $(gtk_update_icon_cache)"; \ echo "*** $(gtk_update_icon_cache)"; \
fi fi
-include $(top_srcdir)/git.mk

View File

@ -14,3 +14,4 @@ install-data-hook:
echo "*** $(gtk_update_icon_cache)"; \ echo "*** $(gtk_update_icon_cache)"; \
fi fi
-include $(top_srcdir)/git.mk

View File

@ -14,3 +14,4 @@ install-data-hook:
echo "*** $(gtk_update_icon_cache)"; \ echo "*** $(gtk_update_icon_cache)"; \
fi fi
-include $(top_srcdir)/git.mk

View File

@ -1 +1,3 @@
SUBDIRS = 16x16 22x22 24x24 32x32 48x48 scalable SUBDIRS = 16x16 22x22 24x24 32x32 48x48 scalable
-include $(top_srcdir)/git.mk

View File

@ -12,3 +12,4 @@ install-data-hook:
echo "*** $(gtk_update_icon_cache)"; \ echo "*** $(gtk_update_icon_cache)"; \
fi fi
-include $(top_srcdir)/git.mk

View File

@ -36,3 +36,5 @@ inscript_symbols = \
symbols/ta-inscript.xml \ symbols/ta-inscript.xml \
symbols/te-inscript.xml \ symbols/te-inscript.xml \
$(NULL) $(NULL)
-include $(top_srcdir)/git.mk

View File

@ -248,10 +248,10 @@
<keysym keyval="65506">Shift_R</keysym> <keysym keyval="65506">Shift_R</keysym>
</key> </key>
<key keycode="149" name="I149"> <key keycode="149" name="I149">
<symbol label="⌨" icon="input-keyboard-symbolic">cycle-keyboard</symbol> <symbol label="⌨" icon="input-keyboard-symbolic" tooltip="Change keyboard">cycle-keyboard</symbol>
</key> </key>
<key keycode="150" name="I150"> <key keycode="150" name="I150">
<symbol label="☺" icon="preferences-system-symbolic">preferences</symbol> <symbol label="☺" icon="preferences-system-symbolic" tooltip="Setup">preferences</symbol>
</key> </key>
<key keycode="37" name="LCTL"> <key keycode="37" name="LCTL">
<keysym keyval="65507">Control_L</keysym> <keysym keyval="65507">Control_L</keysym>

68
data/meson.build Normal file
View File

@ -0,0 +1,68 @@
install_data(
'themes/default.css',
install_dir: pkgdatadir + '/themes',
)
install_data(
'keyboards/keyboards.xml',
install_dir: pkgdatadir + '/keyboards/',
)
install_data(
'keyboards/geometry/compact.xml',
install_dir: pkgdatadir + '/keyboards/geometry/',
)
install_data('dbus/sm.puri.OSK0.xml',
install_dir: dbusdir
)
symbols = [
'ar.xml',
'as-inscript.xml',
'be.xml',
'bn-inscript.xml',
'fa.xml',
'gu-inscript.xml',
'he.xml',
'hi-inscript.xml',
'ja-kana.xml',
'kk.xml',
'kn-inscript.xml',
'ks-inscript.xml',
'ks.xml',
'mai-inscript.xml',
'ml-inscript.xml',
'mr-inscript.xml',
'my.xml',
'or-inscript.xml',
'pa-inscript.xml',
'ru.xml',
'sd-inscript.xml',
'ta-inscript.xml',
'te-inscript.xml',
'th.xml',
'ua.xml',
'ug.xml',
'us.xml',
'zh-bopomofo.xml',
]
foreach symbol: symbols
install_data(
'keyboards/symbols/' + symbol,
install_dir: pkgdatadir + '/keyboards/symbols/',
)
endforeach
desktop_file = 'sm.puri.Squeekboard.desktop'
i18n.merge_file('desktop',
input: desktop_file + '.in',
output: desktop_file,
po_dir: '../po',
install: true,
install_dir: join_paths(datadir, 'applications'),
type: 'desktop'
)

View File

@ -1,60 +0,0 @@
<?xml version="1.0"?>
<schemalist>
<schema id="org.fedorahosted.eekboard" path="/org/fedorahosted/eekboard/">
<key name="keyboards" type="as">
<default>['us']</default>
<summary>Keyboard types</summary>
<description>keyboard types.</description>
</key>
<key name="focus-listener" type="s">
<default>'atspi'</default>
<summary>Use the given focus listener</summary>
<description>The name of the focus listener (either 'atspi' or 'ibus') used to detect focus events.</description>
</key>
<key name="auto-hide" type="b">
<default>true</default>
<summary>Hide keyboard automatically when focus is out</summary>
<description>If true, hide keyboard automatically when focus is out.</description>
</key>
<key name="auto-hide-delay" type="u">
<default>500</default>
<summary>Delay before hiding keyboard</summary>
<description>Delay before hiding keyboard in milliseconds. This is useful when focus listener is enabled.</description>
</key>
<key type="b" name="repeat">
<default>true</default>
<summary>Key repeat</summary>
<description>Generate key-press/release event repeatedly while a key is held down</description>
</key>
<key type="u" name="repeat-interval">
<default>100</default>
<summary>Key repeat interval</summary>
<description>Delay between repeats in milliseconds.</description>
</key>
<key type="u" name="repeat-delay">
<default>1000</default>
<summary>Initial key repeat delay</summary>
<description>Initial key repeat delay in milliseconds.</description>
</key>
<key name="start-fullscreen" type="b">
<default>false</default>
<summary>Switch to fullscreen mode when startup</summary>
<description>If true, switch to fullscreen mode when startup.</description>
</key>
<key name="size-constraint-landscape" type="(dd)">
<default>(1.0, 0.3)</default>
<summary>Constraint of the maximum window size on landscape screen</summary>
<description>Constraint of maximum window size on landscape screen</description>
</key>
<key name="size-constraint-portrait" type="(dd)">
<default>(1.0, 0.5)</default>
<summary>Constraint of the maximum window size on portrait screen</summary>
<description>Constraint of maximum window size on portrait screen</description>
</key>
<key name="theme" type="s">
<default>'default'</default>
<summary>Theme</summary>
<description>Base name of the theme to apply.</description>
</key>
</schema>
</schemalist>

View File

@ -0,0 +1,9 @@
[Desktop Entry]
Name=Squeekboard
GenericName=Squeekboard Virtual Keyboard
Comment=Virtual Keyboard
Exec=squeekboard
Icon=squeekboard
Terminal=false
Type=Application
Categories=GTK;Utility;

View File

@ -1,2 +1,4 @@
themedir = $(pkgdatadir)/themes themedir = $(pkgdatadir)/themes
dist_theme_DATA = default.css dist_theme_DATA = default.css
-include $(top_srcdir)/git.mk

5
debian/changelog vendored Normal file
View File

@ -0,0 +1,5 @@
squeekboard (1.0.9) unstable; urgency=medium
* Initial release.
-- David Boddie <david.boddie@puri.sm> Tue, 25 Jun 2019 19:33:00 +0200

1
debian/compat vendored Normal file
View File

@ -0,0 +1 @@
10

25
debian/control vendored Normal file
View File

@ -0,0 +1,25 @@
Source: squeekboard
Section: x11
Priority: optional
Maintainer: Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>
Build-Depends:
debhelper (>= 10),
meson (>=0.43.0),
pkg-config,
libglib2.0-dev,
libgtk-3-dev,
libcroco3-dev,
libwayland-dev (>= 1.16),
rustc,
wayland-protocols (>= 1.14)
Standards-Version: 4.1.3
Homepage: https://source.puri.sm/Librem5/squeekboard
Package: squeekboard
Architecture: linux-any
Depends:
libstd-rust-1.34 (= 1.34.2+dfsg1-1),
${shlibs:Depends}
${misc:Depends}
Description: On-screen keyboard for Wayland
Virtual keyboard supporting Wayland, built primarily for the Librem 5 phone.

22
debian/copyright vendored Normal file
View File

@ -0,0 +1,22 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: evscript
Source: https://source.puri.sm/david.boddie/evscript
Files: *
Copyright: 2019 Purism SPC
License: GPL-3+
This package is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
.
This package is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>
.
On Debian systems, the complete text of the GNU General
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".

8
debian/rules vendored Executable file
View File

@ -0,0 +1,8 @@
#!/usr/bin/make -f
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
%:
dh $@ --builddirectory=_build
override_dh_autoreconf:

View File

@ -16,4 +16,6 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA # 02110-1301 USA
SUBDIRS = reference SUBDIRS = reference
-include $(top_srcdir)/git.mk

View File

@ -17,3 +17,5 @@
# 02110-1301 USA # 02110-1301 USA
SUBDIRS = eek eekboard SUBDIRS = eek eekboard
-include $(top_srcdir)/git.mk

View File

@ -129,3 +129,5 @@ if ENABLE_GTK_DOC
endif endif
-include $(top_srcdir)/gtk-doc.mk -include $(top_srcdir)/gtk-doc.mk
-include $(top_srcdir)/git.mk

View File

@ -118,3 +118,5 @@ if ENABLE_GTK_DOC
endif endif
-include $(top_srcdir)/gtk-doc.mk -include $(top_srcdir)/gtk-doc.mk
-include $(top_srcdir)/git.mk

View File

@ -16,10 +16,13 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA # 02110-1301 USA
NULL =
lib_LTLIBRARIES = \ lib_LTLIBRARIES = \
libeek.la \ libeek.la \
libeek-gtk.la \ libeek-gtk.la \
libeek-xkl.la libeek-xkl.la \
$(NULL)
libeek_public_headers = \ libeek_public_headers = \
$(srcdir)/eek-layout.h \ $(srcdir)/eek-layout.h \
@ -37,17 +40,17 @@ libeek_public_headers = \
$(srcdir)/eek-xml-layout.h \ $(srcdir)/eek-xml-layout.h \
$(srcdir)/eek-serializable.h \ $(srcdir)/eek-serializable.h \
$(srcdir)/eek-theme.h \ $(srcdir)/eek-theme.h \
$(srcdir)/eek.h $(srcdir)/eek.h \
$(NULL)
libeek_private_headers = \ libeek_private_headers = \
$(srcdir)/eek-renderer.h \ $(srcdir)/eek-renderer.h \
$(srcdir)/eek-special-keysym-entries.h \ $(libeek_keysym_headers) \
$(srcdir)/eek-unicode-keysym-entries.h \ $(builddir)/eek-marshalers.h \
$(srcdir)/eek-xkeysym-keysym-entries.h \
$(srcdir)/eek-marshalers.h \
$(srcdir)/eek-theme-context.h \ $(srcdir)/eek-theme-context.h \
$(srcdir)/eek-theme-private.h \ $(srcdir)/eek-theme-private.h \
$(srcdir)/eek-theme-node.h $(srcdir)/eek-theme-node.h \
$(NULL)
libeek_sources = \ libeek_sources = \
$(srcdir)/eek.c \ $(srcdir)/eek.c \
@ -69,30 +72,36 @@ libeek_sources = \
$(srcdir)/eek-keyboard-drawing.c \ $(srcdir)/eek-keyboard-drawing.c \
$(srcdir)/eek-theme.c \ $(srcdir)/eek-theme.c \
$(srcdir)/eek-theme-context.c \ $(srcdir)/eek-theme-context.c \
$(srcdir)/eek-theme-node.c $(srcdir)/eek-theme-node.c \
$(NULL)
libeek_keysym_sources = \ libeek_keysym_headers = \
$(srcdir)/eek-special-keysym-entries.h \ $(builddir)/eek-special-keysym-entries.h \
$(srcdir)/eek-unicode-keysym-entries.h \ $(builddir)/eek-unicode-keysym-entries.h \
$(srcdir)/eek-xkeysym-keysym-entries.h $(builddir)/eek-xkeysym-keysym-entries.h \
$(NULL)
libeek_enumtypes_sources = \ libeek_enumtypes_sources = \
$(srcdir)/eek-enumtypes.c \ $(builddir)/eek-enumtypes.c \
$(srcdir)/eek-enumtypes.h $(builddir)/eek-enumtypes.h \
$(NULL)
libeek_marshalers_sources = \ libeek_marshalers_sources = \
$(srcdir)/eek-marshalers.c \ $(builddir)/eek-marshalers.c \
$(srcdir)/eek-marshalers.h $(builddir)/eek-marshalers.h \
$(NULL)
BUILT_SOURCES = \ BUILT_SOURCES = \
$(libeek_keysym_sources) \ $(libeek_keysym_headers) \
$(libeek_enumtypes_sources) \ $(libeek_enumtypes_sources) \
$(libeek_marshalers_sources) $(libeek_marshalers_sources) \
$(NULL)
libeek_la_SOURCES = \ libeek_la_SOURCES = \
$(libeek_sources) \ $(libeek_sources) \
$(srcdir)/eek-enumtypes.c \ $(builddir)/eek-enumtypes.c \
$(srcdir)/eek-marshalers.c $(builddir)/eek-marshalers.c \
$(NULL)
libeek_la_CFLAGS = \ libeek_la_CFLAGS = \
-DEEK_COMPILATION=1 \ -DEEK_COMPILATION=1 \
@ -111,12 +120,15 @@ libeek_la_LIBADD = \
libeek_gtk_public_headers = \ libeek_gtk_public_headers = \
$(srcdir)/eek-gtk-keyboard.h \ $(srcdir)/eek-gtk-keyboard.h \
$(srcdir)/eek-gtk.h $(srcdir)/eek-gtk.h \
$(NULL)
libeek_gtk_private_headers = \ libeek_gtk_private_headers = \
$(srcdir)/eek-gtk-renderer.h $(srcdir)/eek-gtk-renderer.h \
$(NULL)
libeek_gtk_sources = \ libeek_gtk_sources = \
$(srcdir)/eek-gtk-keyboard.c \ $(srcdir)/eek-gtk-keyboard.c \
$(srcdir)/eek-gtk-renderer.c $(srcdir)/eek-gtk-renderer.c \
$(NULL)
libeek_gtk_la_SOURCES = $(libeek_gtk_sources) libeek_gtk_la_SOURCES = $(libeek_gtk_sources)
libeek_gtk_la_CFLAGS = -DEEK_COMPILATION=1 $(GTK_CFLAGS) $(LIBCANBERRA_CFLAGS) libeek_gtk_la_CFLAGS = -DEEK_COMPILATION=1 $(GTK_CFLAGS) $(LIBCANBERRA_CFLAGS)
@ -126,11 +138,13 @@ libeek_xkl_public_headers = \
$(srcdir)/eek-xkl-layout.h \ $(srcdir)/eek-xkl-layout.h \
$(srcdir)/eek-xkl.h \ $(srcdir)/eek-xkl.h \
$(srcdir)/eek-xkb-layout.h \ $(srcdir)/eek-xkb-layout.h \
$(srcdir)/eek-xkb.h $(srcdir)/eek-xkb.h \
$(NULL)
libeek_xkl_sources = \ libeek_xkl_sources = \
$(srcdir)/eek-xkb-layout.c \ $(srcdir)/eek-xkb-layout.c \
$(srcdir)/eek-xkl-layout.c $(srcdir)/eek-xkl-layout.c \
$(NULL)
libeek_xkl_la_SOURCES = $(libeek_xkl_sources) libeek_xkl_la_SOURCES = $(libeek_xkl_sources)
libeek_xkl_la_CFLAGS = -DEEK_COMPILATION=1 $(LIBXKLAVIER_CFLAGS) libeek_xkl_la_CFLAGS = -DEEK_COMPILATION=1 $(LIBXKLAVIER_CFLAGS)
@ -139,56 +153,68 @@ libeek_xkl_la_LIBADD = libeek.la $(LIBXKLAVIER_LIBS)
eekdir = $(includedir)/eek-$(EEK_API_VERSION)/eek eekdir = $(includedir)/eek-$(EEK_API_VERSION)/eek
eek_HEADERS = \ eek_HEADERS = \
$(libeek_public_headers) \ $(libeek_public_headers) \
$(srcdir)/eek-enumtypes.h \ $(builddir)/eek-enumtypes.h \
$(libeek_gtk_public_headers) \ $(libeek_gtk_public_headers) \
$(libeek_xkl_public_headers) $(libeek_xkl_public_headers) \
$(NULL)
noinst_HEADERS = \ noinst_HEADERS = \
$(libeek_private_headers) \ $(libeek_private_headers) \
$(libeek_gtk_private_headers) \ $(libeek_gtk_private_headers) \
$(libeek_xkl_private_headers) $(libeek_xkl_private_headers) \
$(NULL)
eek-special-keysym-entries.h: special-keysym-entries.txt eek-special-keysym-entries.h: special-keysym-entries.txt
$(AM_V_GEN) $(PYTHON) ./gen-keysym-entries.py special_keysym_entries \ $(AM_V_GEN) $(PYTHON) $(srcdir)/gen-keysym-entries.py \
special_keysym_entries \
< $< > $@ < $< > $@
eek-unicode-keysym-entries.h: unicode-keysym-entries.txt eek-unicode-keysym-entries.h: unicode-keysym-entries.txt
$(AM_V_GEN) $(PYTHON) ./gen-keysym-entries.py unicode_keysym_entries \ $(AM_V_GEN) $(PYTHON) $(srcdir)/gen-keysym-entries.py \
unicode_keysym_entries \
< $< > $@ < $< > $@
eek-xkeysym-keysym-entries.h: xkeysym-keysym-entries.txt eek-xkeysym-keysym-entries.h: xkeysym-keysym-entries.txt
$(AM_V_GEN) $(PYTHON) ./gen-keysym-entries.py xkeysym_keysym_entries \ $(AM_V_GEN) $(PYTHON) $(srcdir)/gen-keysym-entries.py \
xkeysym_keysym_entries \
< $< > $@ < $< > $@
eek-enumtypes.h: $(libeek_public_headers) eek-enumtypes.h.template eek-enumtypes.h: $(libeek_public_headers) eek-enumtypes.h.template
$(AM_V_GEN) $(GLIB_MKENUMS) --template eek-enumtypes.h.template \ $(AM_V_GEN) $(GLIB_MKENUMS) \
--template $(srcdir)/eek-enumtypes.h.template \
$(libeek_public_headers) > eek-enumtypes.h.tmp && \ $(libeek_public_headers) > eek-enumtypes.h.tmp && \
mv eek-enumtypes.h.tmp eek-enumtypes.h mv eek-enumtypes.h.tmp eek-enumtypes.h
eek-enumtypes.c: $(libeek_public_headers) eek-enumtypes.c.template eek-enumtypes.c: $(libeek_public_headers) eek-enumtypes.c.template
$(AM_V_GEN) $(GLIB_MKENUMS) --template eek-enumtypes.c.template \ $(AM_V_GEN) $(GLIB_MKENUMS) \
--template $(srcdir)/eek-enumtypes.c.template \
$(libeek_public_headers) > eek-enumtypes.c.tmp && \ $(libeek_public_headers) > eek-enumtypes.c.tmp && \
mv eek-enumtypes.c.tmp eek-enumtypes.c mv eek-enumtypes.c.tmp eek-enumtypes.c
# gen marshal # gen marshal
eek-marshalers.h: eek-marshalers.list eek-marshalers.h: eek-marshalers.list
$(AM_V_GEN) $(GLIB_GENMARSHAL) --prefix=_eek_marshal $(srcdir)/eek-marshalers.list --header --internal > $@.tmp && \ $(AM_V_GEN) $(GLIB_GENMARSHAL) \
--prefix=_eek_marshal $(srcdir)/eek-marshalers.list \
--header --internal > $@.tmp && \
mv $@.tmp $@ mv $@.tmp $@
eek-marshalers.c: eek-marshalers.list eek-marshalers.h eek-marshalers.c: eek-marshalers.list eek-marshalers.h
$(AM_V_GEN) (echo "#include \"eek-marshalers.h\""; \ $(AM_V_GEN) (echo "#include \"eek-marshalers.h\""; \
$(GLIB_GENMARSHAL) --prefix=_eek_marshal $(srcdir)/eek-marshalers.list --body --internal) > $@.tmp && \ $(GLIB_GENMARSHAL) --prefix=_eek_marshal \
$(srcdir)/eek-marshalers.list --body --internal) > $@.tmp && \
mv $@.tmp $@ mv $@.tmp $@
pkgconfigdir = $(libdir)/pkgconfig pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = \ pkgconfig_DATA = \
eek-$(EEK_API_VERSION).pc \ eek-$(EEK_API_VERSION).pc \
eek-gtk-$(EEK_API_VERSION).pc \ eek-gtk-$(EEK_API_VERSION).pc \
eek-xkl-$(EEK_API_VERSION).pc eek-xkl-$(EEK_API_VERSION).pc \
$(NULL)
CLEANFILES = CLEANFILES =
DISTCLEANFILES = \ DISTCLEANFILES = \
$(BUILT_SOURCES) \ $(BUILT_SOURCES) \
$(pkgconfig_DATA) $(pkgconfig_DATA) \
$(NULL)
EXTRA_DIST = \ EXTRA_DIST = \
gen-keysym-entries.py \ gen-keysym-entries.py \
@ -197,7 +223,8 @@ EXTRA_DIST = \
xkeysym-keysym-entries.txt \ xkeysym-keysym-entries.txt \
eek-enumtypes.h.template \ eek-enumtypes.h.template \
eek-enumtypes.c.template \ eek-enumtypes.c.template \
eek-marshalers.list eek-marshalers.list \
$(NULL)
-include $(INTROSPECTION_MAKEFILE) -include $(INTROSPECTION_MAKEFILE)
INTROSPECTION_GIRS = INTROSPECTION_GIRS =
@ -207,29 +234,57 @@ INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
if HAVE_INTROSPECTION if HAVE_INTROSPECTION
Eek@EEK_LIBRARY_SUFFIX@.gir: libeek.la Eek@EEK_LIBRARY_SUFFIX@.gir: libeek.la
Eek@EEK_LIBRARY_SUFFIX_U@_gir_SCANNERFLAGS = --strip-prefix=Eek --pkg=glib-2.0 --pkg-export=eek-$(EEK_API_VERSION) Eek@EEK_LIBRARY_SUFFIX_U@_gir_SCANNERFLAGS = \
--identifier-prefix=Eek \
--symbol-prefix=eek \
--pkg=glib-2.0 \
--pkg-export=eek-$(EEK_API_VERSION) \
$(NULL)
Eek@EEK_LIBRARY_SUFFIX_U@_gir_INCLUDES = GLib-2.0 GObject-2.0 Gio-2.0 Eek@EEK_LIBRARY_SUFFIX_U@_gir_INCLUDES = GLib-2.0 GObject-2.0 Gio-2.0
Eek@EEK_LIBRARY_SUFFIX_U@_gir_CFLAGS = $(libeek_la_CFLAGS) Eek@EEK_LIBRARY_SUFFIX_U@_gir_CFLAGS = $(libeek_la_CFLAGS)
Eek@EEK_LIBRARY_SUFFIX_U@_gir_LIBS = libeek.la Eek@EEK_LIBRARY_SUFFIX_U@_gir_LIBS = libeek.la
Eek@EEK_LIBRARY_SUFFIX_U@_gir_FILES = $(libeek_sources) $(libeek_public_headers) $(srcdir)/eek-enumtypes.h Eek@EEK_LIBRARY_SUFFIX_U@_gir_FILES = \
$(libeek_sources) \
$(libeek_public_headers) \
$(builddir)/eek-enumtypes.h \
$(NULL)
EekGtk@EEK_LIBRARY_SUFFIX@.gir: libeek-gtk.la Eek@EEK_LIBRARY_SUFFIX@.gir EekGtk@EEK_LIBRARY_SUFFIX@.gir: libeek-gtk.la Eek@EEK_LIBRARY_SUFFIX@.gir
EekGtk@EEK_LIBRARY_SUFFIX_U@_gir_SCANNERFLAGS = --pkg-export=eek-gtk-$(EEK_API_VERSION) EekGtk@EEK_LIBRARY_SUFFIX_U@_gir_SCANNERFLAGS = \
EekGtk@EEK_LIBRARY_SUFFIX_U@_gir_INCLUDES = GObject-2.0 Gtk-@GTK_API_VERSION@ Eek@EEK_LIBRARY_SUFFIX@ --identifier-prefix=Eek \
--symbol-prefix=eek \
--pkg-export=eek-gtk-$(EEK_API_VERSION) \
$(NULL)
EekGtk@EEK_LIBRARY_SUFFIX_U@_gir_INCLUDES = \
GObject-2.0 \
Gtk-@GTK_API_VERSION@ \
Eek@EEK_LIBRARY_SUFFIX@ \
$(NULL)
EekGtk@EEK_LIBRARY_SUFFIX_U@_gir_CFLAGS = $(libeek_gtk_la_CFLAGS) EekGtk@EEK_LIBRARY_SUFFIX_U@_gir_CFLAGS = $(libeek_gtk_la_CFLAGS)
EekGtk@EEK_LIBRARY_SUFFIX_U@_gir_LIBS = libeek-gtk.la EekGtk@EEK_LIBRARY_SUFFIX_U@_gir_LIBS = libeek-gtk.la
EekGtk@EEK_LIBRARY_SUFFIX_U@_gir_FILES = $(libeek_gtk_sources) $(libeek_gtk_public_headers) EekGtk@EEK_LIBRARY_SUFFIX_U@_gir_FILES = \
$(libeek_gtk_sources) \
$(libeek_gtk_public_headers) \
$(NULL)
EekXkl@EEK_LIBRARY_SUFFIX@.gir: libeek-xkl.la Eek@EEK_LIBRARY_SUFFIX@.gir EekXkl@EEK_LIBRARY_SUFFIX@.gir: libeek-xkl.la Eek@EEK_LIBRARY_SUFFIX@.gir
EekXkl@EEK_LIBRARY_SUFFIX_U@_gir_SCANNERFLAGS = \
--identifier-prefix=Eek \
--symbol-prefix=eek \
$(NULL)
EekXkl@EEK_LIBRARY_SUFFIX_U@_gir_INCLUDES = GObject-2.0 Eek@EEK_LIBRARY_SUFFIX@ EekXkl@EEK_LIBRARY_SUFFIX_U@_gir_INCLUDES = GObject-2.0 Eek@EEK_LIBRARY_SUFFIX@
EekXkl@EEK_LIBRARY_SUFFIX_U@_gir_CFLAGS = $(libeek_xkl_la_CFLAGS) EekXkl@EEK_LIBRARY_SUFFIX_U@_gir_CFLAGS = $(libeek_xkl_la_CFLAGS)
EekXkl@EEK_LIBRARY_SUFFIX_U@_gir_LIBS = libeek-xkl.la EekXkl@EEK_LIBRARY_SUFFIX_U@_gir_LIBS = libeek-xkl.la
EekXkl@EEK_LIBRARY_SUFFIX_U@_gir_FILES = $(libeek_xkl_sources) $(libeek_xkl_public_headers) EekXkl@EEK_LIBRARY_SUFFIX_U@_gir_FILES = \
$(libeek_xkl_sources) \
$(libeek_xkl_public_headers) \
$(NULL)
INTROSPECTION_GIRS += \ INTROSPECTION_GIRS += \
Eek@EEK_LIBRARY_SUFFIX@.gir \ Eek@EEK_LIBRARY_SUFFIX@.gir \
EekGtk@EEK_LIBRARY_SUFFIX@.gir \ EekGtk@EEK_LIBRARY_SUFFIX@.gir \
EekXkl@EEK_LIBRARY_SUFFIX@.gir EekXkl@EEK_LIBRARY_SUFFIX@.gir \
$(NULL)
girdir = $(datadir)/gir-1.0 girdir = $(datadir)/gir-1.0
gir_DATA = $(INTROSPECTION_GIRS) gir_DATA = $(INTROSPECTION_GIRS)
@ -239,3 +294,5 @@ typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
CLEANFILES += $(gir_DATA) $(typelib_DATA) CLEANFILES += $(gir_DATA) $(typelib_DATA)
endif endif
-include $(top_srcdir)/git.mk

0
eek/config.h Normal file
View File

View File

@ -311,7 +311,7 @@ eek_element_set_name (EekElement *element,
* Get the name of @element. * Get the name of @element.
* Returns: the name of @element or NULL when the name is not set * Returns: the name of @element or NULL when the name is not set
*/ */
G_CONST_RETURN gchar * const gchar *
eek_element_get_name (EekElement *element) eek_element_get_name (EekElement *element)
{ {
g_return_val_if_fail (EEK_IS_ELEMENT(element), NULL); g_return_val_if_fail (EEK_IS_ELEMENT(element), NULL);

View File

@ -58,45 +58,45 @@ struct _EekElementClass
gint level); gint level);
}; };
GType eek_element_get_type (void) G_GNUC_CONST; GType eek_element_get_type (void) G_GNUC_CONST;
void eek_element_set_parent (EekElement *element, void eek_element_set_parent (EekElement *element,
EekElement *parent); EekElement *parent);
EekElement *eek_element_get_parent (EekElement *element); EekElement *eek_element_get_parent (EekElement *element);
void eek_element_set_name (EekElement *element, void eek_element_set_name (EekElement *element,
const gchar *name); const gchar *name);
G_CONST_RETURN gchar *eek_element_get_name (EekElement *element); const gchar *eek_element_get_name (EekElement *element);
void eek_element_set_bounds (EekElement *element, void eek_element_set_bounds (EekElement *element,
EekBounds *bounds); EekBounds *bounds);
void eek_element_get_bounds (EekElement *element, void eek_element_get_bounds (EekElement *element,
EekBounds *bounds); EekBounds *bounds);
void eek_element_set_position (EekElement *element, void eek_element_set_position (EekElement *element,
gdouble x, gdouble x,
gdouble y); gdouble y);
void eek_element_set_size (EekElement *element, void eek_element_set_size (EekElement *element,
gdouble width, gdouble width,
gdouble height); gdouble height);
void eek_element_get_absolute_position (EekElement *element, void eek_element_get_absolute_position (EekElement *element,
gdouble *x, gdouble *x,
gdouble *y); gdouble *y);
void eek_element_set_symbol_index (EekElement *element, void eek_element_set_symbol_index (EekElement *element,
gint group, gint group,
gint level); gint level);
void eek_element_get_symbol_index (EekElement *element, void eek_element_get_symbol_index (EekElement *element,
gint *group, gint *group,
gint *level); gint *level);
void eek_element_set_group (EekElement *element, void eek_element_set_group (EekElement *element,
gint group); gint group);
void eek_element_set_level (EekElement *element, void eek_element_set_level (EekElement *element,
gint level); gint level);
gint eek_element_get_group (EekElement *element); gint eek_element_get_group (EekElement *element);
gint eek_element_get_level (EekElement *element); gint eek_element_get_level (EekElement *element);
G_END_DECLS G_END_DECLS
#endif /* EEK_ELEMENT_H */ #endif /* EEK_ELEMENT_H */

View File

@ -1,17 +1,17 @@
/* /*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org> * Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc. * Copyright (C) 2010-2011 Red Hat, Inc.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License * modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2 of * as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version. * the License, or (at your option) any later version.
* *
* This library is distributed in the hope that it will be useful, but * This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
@ -61,31 +61,22 @@ struct _EekGtkKeyboardPrivate
{ {
EekRenderer *renderer; EekRenderer *renderer;
EekKeyboard *keyboard; EekKeyboard *keyboard;
gulong key_pressed_handler;
gulong key_released_handler;
gulong key_locked_handler; gulong key_locked_handler;
gulong key_unlocked_handler; gulong key_unlocked_handler;
gulong key_cancelled_handler;
gulong symbol_index_changed_handler; gulong symbol_index_changed_handler;
EekTheme *theme; EekTheme *theme;
}; };
static EekColor * color_from_gdk_color (GdkColor *gdk_color); static void on_key_pressed (EekKey *key,
static void on_key_pressed (EekKeyboard *keyboard, EekGtkKeyboard *self);
EekKey *key, static void on_key_released (EekKey *key,
gpointer user_data); EekGtkKeyboard *self);
static void on_key_released (EekKeyboard *keyboard,
EekKey *key,
gpointer user_data);
static void on_key_locked (EekKeyboard *keyboard, static void on_key_locked (EekKeyboard *keyboard,
EekKey *key, EekKey *key,
gpointer user_data); gpointer user_data);
static void on_key_unlocked (EekKeyboard *keyboard, static void on_key_unlocked (EekKeyboard *keyboard,
EekKey *key, EekKey *key,
gpointer user_data); gpointer user_data);
static void on_key_cancelled (EekKeyboard *keyboard,
EekKey *key,
gpointer user_data);
static void on_symbol_index_changed (EekKeyboard *keyboard, static void on_symbol_index_changed (EekKeyboard *keyboard,
gint group, gint group,
gint level, gint level,
@ -100,7 +91,6 @@ static void render_released_key (GtkWidget *widget,
static void static void
eek_gtk_keyboard_real_realize (GtkWidget *self) eek_gtk_keyboard_real_realize (GtkWidget *self)
{ {
gtk_widget_set_double_buffered (self, FALSE);
gtk_widget_set_events (self, gtk_widget_set_events (self,
GDK_EXPOSURE_MASK | GDK_EXPOSURE_MASK |
GDK_KEY_PRESS_MASK | GDK_KEY_PRESS_MASK |
@ -118,16 +108,12 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
{ {
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self);
GtkAllocation allocation; GtkAllocation allocation;
EekColor background;
GList *list, *head; GList *list, *head;
gtk_widget_get_allocation (self, &allocation); gtk_widget_get_allocation (self, &allocation);
if (!priv->renderer) { if (!priv->renderer) {
GtkStyle *style;
GtkStateType state;
PangoContext *pcontext; PangoContext *pcontext;
EekColor *color;
pcontext = gtk_widget_get_pango_context (self); pcontext = gtk_widget_get_pango_context (self);
priv->renderer = eek_gtk_renderer_new (priv->keyboard, pcontext, self); priv->renderer = eek_gtk_renderer_new (priv->keyboard, pcontext, self);
@ -137,30 +123,8 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
eek_renderer_set_allocation_size (priv->renderer, eek_renderer_set_allocation_size (priv->renderer,
allocation.width, allocation.width,
allocation.height); allocation.height);
style = gtk_widget_get_style (self);
state = gtk_widget_get_state (self);
color = color_from_gdk_color (&style->text[state]);
eek_renderer_set_default_foreground_color (priv->renderer, color);
eek_color_free (color);
color = color_from_gdk_color (&style->base[state]);
eek_renderer_set_default_background_color (priv->renderer, color);
eek_color_free (color);
} }
/* blank background */
eek_renderer_get_background_color (priv->renderer,
EEK_ELEMENT(priv->keyboard),
&background);
cairo_set_source_rgba (cr,
background.red,
background.green,
background.blue,
background.alpha);
cairo_paint (cr);
eek_renderer_render_keyboard (priv->renderer, cr); eek_renderer_render_keyboard (priv->renderer, cr);
/* redraw pressed key */ /* redraw pressed key */
@ -195,46 +159,21 @@ eek_gtk_keyboard_real_size_allocate (GtkWidget *self,
size_allocate (self, allocation); size_allocate (self, allocation);
} }
static gboolean static void depress(EekGtkKeyboard *self,
eek_gtk_keyboard_real_button_press_event (GtkWidget *self, gdouble x, gdouble y, guint32 time) {
GdkEventButton *event)
{
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self);
EekKey *key; EekKey *key = eek_renderer_find_key_by_position (priv->renderer, x, y);
if (key) {
key = eek_renderer_find_key_by_position (priv->renderer, eek_keyboard_press_key(priv->keyboard, key, time);
(gdouble)event->x, on_key_pressed(key, self);
(gdouble)event->y); }
if (key)
g_signal_emit_by_name (key, "pressed", priv->keyboard);
return TRUE;
} }
static gboolean static void drag(EekGtkKeyboard *self,
eek_gtk_keyboard_real_button_release_event (GtkWidget *self, gdouble x, gdouble y, guint32 time) {
GdkEventButton *event)
{
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self);
GList *list, *head; EekKey *key = eek_renderer_find_key_by_position (priv->renderer, x, y);
list = eek_keyboard_get_pressed_keys (priv->keyboard);
for (head = list; head; head = g_list_next (head))
g_signal_emit_by_name (head->data, "released", priv->keyboard);
g_list_free (list);
return TRUE;
}
static gboolean
eek_gtk_keyboard_real_motion_notify_event (GtkWidget *self,
GdkEventMotion *event)
{
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self);
EekKey *key;
key = eek_renderer_find_key_by_position (priv->renderer,
(gdouble)event->x,
(gdouble)event->y);
if (key) { if (key) {
GList *list, *head; GList *list, *head;
gboolean found = FALSE; gboolean found = FALSE;
@ -243,17 +182,95 @@ eek_gtk_keyboard_real_motion_notify_event (GtkWidget *self,
for (head = list; head; head = g_list_next (head)) { for (head = list; head; head = g_list_next (head)) {
if (head->data == key) if (head->data == key)
found = TRUE; found = TRUE;
else else {
g_signal_emit_by_name (head->data, "cancelled", priv->keyboard); eek_keyboard_release_key(priv->keyboard, EEK_KEY(head->data), time);
on_key_released(key, self);
}
} }
g_list_free (list); g_list_free (list);
if (!found) if (!found) {
g_signal_emit_by_name (key, "pressed", priv->keyboard); eek_keyboard_press_key(priv->keyboard, key, time);
on_key_pressed(key, self);
}
}
}
static void release(EekGtkKeyboard *self, guint32 time) {
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self);
GList *list = eek_keyboard_get_pressed_keys (priv->keyboard);
for (GList *head = list; head; head = g_list_next (head)) {
EekKey *key = EEK_KEY(head->data);
eek_keyboard_release_key(priv->keyboard, key, time);
on_key_released(key, self);
}
g_list_free (list);
}
static gboolean
eek_gtk_keyboard_real_button_press_event (GtkWidget *self,
GdkEventButton *event)
{
if (event->type == GDK_BUTTON_PRESS && event->button == 1) {
depress(EEK_GTK_KEYBOARD(self), event->x, event->y, event->time);
} }
return TRUE; return TRUE;
} }
// TODO: this belongs more in gtk_keyboard, with a way to find out which key to re-render
static gboolean
eek_gtk_keyboard_real_button_release_event (GtkWidget *self,
GdkEventButton *event)
{
if (event->type == GDK_BUTTON_RELEASE && event->button == 1) {
// TODO: can the event have different coords than the previous move event?
release(EEK_GTK_KEYBOARD(self), event->time);
}
return TRUE;
}
static gboolean
eek_gtk_keyboard_real_motion_notify_event (GtkWidget *self,
GdkEventMotion *event)
{
if (event->state & GDK_BUTTON1_MASK) {
drag(EEK_GTK_KEYBOARD(self), event->x, event->y, event->time);
}
return TRUE;
}
// Only one touch stream at a time allowed. Others will be completely ignored.
static gboolean
handle_touch_event (GtkWidget *widget,
GdkEventTouch *event) {
EekGtkKeyboard *self = EEK_GTK_KEYBOARD(widget);
if (event->type == GDK_TOUCH_BEGIN) {
if (self->sequence) {
// Ignore second and following touch points
return FALSE;
}
self->sequence = event->sequence;
depress(self, event->x, event->y, event->time);
return TRUE;
}
if (self->sequence != event->sequence) {
return FALSE;
}
if (event->type == GDK_TOUCH_UPDATE) {
drag(self, event->x, event->y, event->time);
}
if (event->type == GDK_TOUCH_END || event->type == GDK_TOUCH_CANCEL) {
// TODO: can the event have different coords than the previous update event?
release(self, event->time);
self->sequence = NULL;
}
return TRUE;
}
static void static void
eek_gtk_keyboard_real_unmap (GtkWidget *self) eek_gtk_keyboard_real_unmap (GtkWidget *self)
{ {
@ -267,14 +284,40 @@ eek_gtk_keyboard_real_unmap (GtkWidget *self)
EekKeyboard::key-released signal can remove elements from its EekKeyboard::key-released signal can remove elements from its
internal copy */ internal copy */
list = eek_keyboard_get_pressed_keys (priv->keyboard); list = eek_keyboard_get_pressed_keys (priv->keyboard);
for (head = list; head; head = g_list_next (head)) for (head = list; head; head = g_list_next (head)) {
g_signal_emit_by_name (head->data, "released", priv->keyboard); g_log("squeek", G_LOG_LEVEL_DEBUG, "emit EekKey released");
g_signal_emit_by_name (head->data, "released");
}
g_list_free (list); g_list_free (list);
} }
GTK_WIDGET_CLASS (eek_gtk_keyboard_parent_class)->unmap (self); GTK_WIDGET_CLASS (eek_gtk_keyboard_parent_class)->unmap (self);
} }
static gboolean
eek_gtk_keyboard_real_query_tooltip (GtkWidget *widget,
gint x,
gint y,
gboolean keyboard_tooltip,
GtkTooltip *tooltip)
{
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget);
EekKey *key;
key = eek_renderer_find_key_by_position (priv->renderer,
(gdouble)x,
(gdouble)y);
if (key) {
EekSymbol *symbol = eek_key_get_symbol (key);
const gchar *text = eek_symbol_get_tooltip (symbol);
if (text) {
gtk_tooltip_set_text (tooltip, text);
return TRUE;
}
}
return FALSE;
}
static void static void
eek_gtk_keyboard_set_keyboard (EekGtkKeyboard *self, eek_gtk_keyboard_set_keyboard (EekGtkKeyboard *self,
EekKeyboard *keyboard) EekKeyboard *keyboard)
@ -282,21 +325,12 @@ eek_gtk_keyboard_set_keyboard (EekGtkKeyboard *self,
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self);
priv->keyboard = g_object_ref (keyboard); priv->keyboard = g_object_ref (keyboard);
priv->key_pressed_handler =
g_signal_connect (priv->keyboard, "key-pressed",
G_CALLBACK(on_key_pressed), self);
priv->key_released_handler =
g_signal_connect (priv->keyboard, "key-released",
G_CALLBACK(on_key_released), self);
priv->key_locked_handler = priv->key_locked_handler =
g_signal_connect (priv->keyboard, "key-locked", g_signal_connect (priv->keyboard, "key-locked",
G_CALLBACK(on_key_locked), self); G_CALLBACK(on_key_locked), self);
priv->key_unlocked_handler = priv->key_unlocked_handler =
g_signal_connect (priv->keyboard, "key-unlocked", g_signal_connect (priv->keyboard, "key-unlocked",
G_CALLBACK(on_key_unlocked), self); G_CALLBACK(on_key_unlocked), self);
priv->key_cancelled_handler =
g_signal_connect (priv->keyboard, "key-cancelled",
G_CALLBACK(on_key_cancelled), self);
priv->symbol_index_changed_handler = priv->symbol_index_changed_handler =
g_signal_connect (priv->keyboard, "symbol-index-changed", g_signal_connect (priv->keyboard, "symbol-index-changed",
G_CALLBACK(on_symbol_index_changed), self); G_CALLBACK(on_symbol_index_changed), self);
@ -332,14 +366,6 @@ eek_gtk_keyboard_dispose (GObject *object)
} }
if (priv->keyboard) { if (priv->keyboard) {
if (g_signal_handler_is_connected (priv->keyboard,
priv->key_pressed_handler))
g_signal_handler_disconnect (priv->keyboard,
priv->key_pressed_handler);
if (g_signal_handler_is_connected (priv->keyboard,
priv->key_released_handler))
g_signal_handler_disconnect (priv->keyboard,
priv->key_released_handler);
if (g_signal_handler_is_connected (priv->keyboard, if (g_signal_handler_is_connected (priv->keyboard,
priv->key_locked_handler)) priv->key_locked_handler))
g_signal_handler_disconnect (priv->keyboard, g_signal_handler_disconnect (priv->keyboard,
@ -348,19 +374,16 @@ eek_gtk_keyboard_dispose (GObject *object)
priv->key_unlocked_handler)) priv->key_unlocked_handler))
g_signal_handler_disconnect (priv->keyboard, g_signal_handler_disconnect (priv->keyboard,
priv->key_unlocked_handler); priv->key_unlocked_handler);
if (g_signal_handler_is_connected (priv->keyboard,
priv->key_cancelled_handler))
g_signal_handler_disconnect (priv->keyboard,
priv->key_cancelled_handler);
if (g_signal_handler_is_connected (priv->keyboard, if (g_signal_handler_is_connected (priv->keyboard,
priv->symbol_index_changed_handler)) priv->symbol_index_changed_handler))
g_signal_handler_disconnect (priv->keyboard, g_signal_handler_disconnect (priv->keyboard,
priv->symbol_index_changed_handler); priv->symbol_index_changed_handler);
GList *list, *head; GList *list, *head;
list = eek_keyboard_get_pressed_keys (priv->keyboard); list = eek_keyboard_get_pressed_keys (priv->keyboard);
for (head = list; head; head = g_list_next (head)) { for (head = list; head; head = g_list_next (head)) {
g_log("squeek", G_LOG_LEVEL_DEBUG, "emit EekKey pressed");
g_signal_emit_by_name (head->data, "released", priv->keyboard); g_signal_emit_by_name (head->data, "released", priv->keyboard);
} }
g_list_free (list); g_list_free (list);
@ -397,6 +420,9 @@ eek_gtk_keyboard_class_init (EekGtkKeyboardClass *klass)
eek_gtk_keyboard_real_button_release_event; eek_gtk_keyboard_real_button_release_event;
widget_class->motion_notify_event = widget_class->motion_notify_event =
eek_gtk_keyboard_real_motion_notify_event; eek_gtk_keyboard_real_motion_notify_event;
widget_class->query_tooltip =
eek_gtk_keyboard_real_query_tooltip;
widget_class->touch_event = handle_touch_event;
gobject_class->set_property = eek_gtk_keyboard_set_property; gobject_class->set_property = eek_gtk_keyboard_set_property;
gobject_class->dispose = eek_gtk_keyboard_dispose; gobject_class->dispose = eek_gtk_keyboard_dispose;
@ -430,15 +456,6 @@ eek_gtk_keyboard_new (EekKeyboard *keyboard)
return g_object_new (EEK_TYPE_GTK_KEYBOARD, "keyboard", keyboard, NULL); return g_object_new (EEK_TYPE_GTK_KEYBOARD, "keyboard", keyboard, NULL);
} }
static EekColor *
color_from_gdk_color (GdkColor *gdk_color)
{
return eek_color_new (gdk_color->red / (gdouble)0xFFFF,
gdk_color->green / (gdouble)0xFFFF,
gdk_color->blue / (gdouble)0xFFFF,
1.0);
}
static void static void
magnify_bounds (GtkWidget *self, magnify_bounds (GtkWidget *self,
EekBounds *bounds, EekBounds *bounds,
@ -468,13 +485,17 @@ render_pressed_key (GtkWidget *widget,
{ {
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget); EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget);
EekBounds bounds, large_bounds; EekBounds bounds, large_bounds;
cairo_t *cr;
cr = gdk_cairo_create (GDK_DRAWABLE (gtk_widget_get_window (widget)));
eek_renderer_get_key_bounds (priv->renderer, key, &bounds, TRUE); eek_renderer_get_key_bounds (priv->renderer, key, &bounds, TRUE);
magnify_bounds (widget, &bounds, &large_bounds, 1.5); magnify_bounds (widget, &bounds, &large_bounds, 1.5);
GdkWindow *window = GDK_DRAWABLE (gtk_widget_get_window (widget));
cairo_region_t *region = gdk_window_get_clip_region (window);
GdkDrawingContext *context = gdk_window_begin_draw_frame(
window, region
);
cairo_t *cr = gdk_drawing_context_get_cairo_context(context);
cairo_save (cr); cairo_save (cr);
cairo_translate (cr, bounds.x, bounds.y); cairo_translate (cr, bounds.x, bounds.y);
eek_renderer_render_key (priv->renderer, cr, key, 1.0, TRUE); eek_renderer_render_key (priv->renderer, cr, key, 1.0, TRUE);
@ -485,7 +506,8 @@ render_pressed_key (GtkWidget *widget,
eek_renderer_render_key (priv->renderer, cr, key, 1.5, TRUE); eek_renderer_render_key (priv->renderer, cr, key, 1.5, TRUE);
cairo_restore (cr); cairo_restore (cr);
cairo_destroy (cr); gdk_window_end_draw_frame(window, context);
cairo_region_destroy(region);
} }
static void static void
@ -534,18 +556,16 @@ render_released_key (GtkWidget *widget,
} }
static void static void
on_key_pressed (EekKeyboard *keyboard, on_key_pressed (EekKey *key,
EekKey *key, EekGtkKeyboard *self)
gpointer user_data)
{ {
GtkWidget *widget = user_data; EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self);
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget);
/* renderer may have not been set yet if the widget is a popup */ /* renderer may have not been set yet if the widget is a popup */
if (!priv->renderer) if (!priv->renderer)
return; return;
render_pressed_key (widget, key); render_pressed_key (GTK_WIDGET(self), key);
#if HAVE_LIBCANBERRA #if HAVE_LIBCANBERRA
ca_gtk_play_for_widget (widget, 0, ca_gtk_play_for_widget (widget, 0,
@ -557,18 +577,16 @@ on_key_pressed (EekKeyboard *keyboard,
} }
static void static void
on_key_released (EekKeyboard *keyboard, on_key_released (EekKey *key,
EekKey *key, EekGtkKeyboard *self)
gpointer user_data)
{ {
GtkWidget *widget = user_data; EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self);
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget);
/* renderer may have not been set yet if the widget is a popup */ /* renderer may have not been set yet if the widget is a popup */
if (!priv->renderer) if (!priv->renderer)
return; return;
render_released_key (widget, key); render_released_key (GTK_WIDGET(self), key);
#if HAVE_LIBCANBERRA #if HAVE_LIBCANBERRA
ca_gtk_play_for_widget (widget, 0, ca_gtk_play_for_widget (widget, 0,
@ -579,21 +597,6 @@ on_key_released (EekKeyboard *keyboard,
#endif #endif
} }
static void
on_key_cancelled (EekKeyboard *keyboard,
EekKey *key,
gpointer user_data)
{
GtkWidget *widget = user_data;
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget);
/* renderer may have not been set yet if the widget is a popup */
if (!priv->renderer)
return;
render_released_key (widget, key);
}
static void static void
on_key_locked (EekKeyboard *keyboard, on_key_locked (EekKeyboard *keyboard,
EekKey *key, EekKey *key,

View File

@ -47,6 +47,8 @@ struct _EekGtkKeyboard
/*< private >*/ /*< private >*/
GtkDrawingArea parent; GtkDrawingArea parent;
GdkEventSequence *sequence; // unowned reference
EekGtkKeyboardPrivate *priv; EekGtkKeyboardPrivate *priv;
}; };

View File

@ -30,10 +30,6 @@
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <string.h> #include <string.h>
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#endif
#include "eek-key.h" #include "eek-key.h"
#include "eek-section.h" #include "eek-section.h"
@ -51,11 +47,8 @@ enum {
}; };
enum { enum {
PRESSED,
RELEASED,
LOCKED, LOCKED,
UNLOCKED, UNLOCKED,
CANCELLED,
LAST_SIGNAL LAST_SIGNAL
}; };
@ -78,28 +71,6 @@ struct _EekKeyPrivate
gboolean is_locked; gboolean is_locked;
}; };
static void
eek_key_real_pressed (EekKey *self)
{
EekKeyPrivate *priv = EEK_KEY_GET_PRIVATE(self);
priv->is_pressed = TRUE;
#if DEBUG
g_debug ("pressed %X", eek_key_get_keycode (self));
#endif
}
static void
eek_key_real_released (EekKey *self)
{
EekKeyPrivate *priv = EEK_KEY_GET_PRIVATE(self);
priv->is_pressed = FALSE;
#if DEBUG
g_debug ("released %X", eek_key_get_keycode (self));
#endif
}
static void static void
eek_key_real_locked (EekKey *self) eek_key_real_locked (EekKey *self)
{ {
@ -122,17 +93,6 @@ eek_key_real_unlocked (EekKey *self)
#endif #endif
} }
static void
eek_key_real_cancelled (EekKey *self)
{
EekKeyPrivate *priv = EEK_KEY_GET_PRIVATE(self);
priv->is_pressed = FALSE;
#if DEBUG
g_debug ("cancelled %X", eek_key_get_keycode (self));
#endif
}
static void static void
eek_key_finalize (GObject *object) eek_key_finalize (GObject *object)
{ {
@ -222,11 +182,8 @@ eek_key_class_init (EekKeyClass *klass)
gobject_class->finalize = eek_key_finalize; gobject_class->finalize = eek_key_finalize;
/* signals */ /* signals */
klass->pressed = eek_key_real_pressed;
klass->released = eek_key_real_released;
klass->locked = eek_key_real_locked; klass->locked = eek_key_real_locked;
klass->unlocked = eek_key_real_unlocked; klass->unlocked = eek_key_real_unlocked;
klass->cancelled = eek_key_real_cancelled;
/** /**
* EekKey:keycode: * EekKey:keycode:
@ -288,42 +245,6 @@ eek_key_class_init (EekKeyClass *klass)
G_PARAM_READWRITE); G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_OREF, pspec); g_object_class_install_property (gobject_class, PROP_OREF, pspec);
/**
* EekKey::pressed:
* @key: an #EekKey
*
* The ::pressed signal is emitted each time @key is shifted to
* the pressed state. The class handler runs before signal
* handlers to allow signal handlers to read the status of @key
* with eek_key_is_pressed().
*/
signals[PRESSED] =
g_signal_new (I_("pressed"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET(EekKeyClass, pressed),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/**
* EekKey::released:
* @key: an #EekKey
*
* The ::released signal is emitted each time @key is shifted to
* the released state.
*/
signals[RELEASED] =
g_signal_new (I_("released"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EekKeyClass, released),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/** /**
* EekKey::locked: * EekKey::locked:
* @key: an #EekKey * @key: an #EekKey
@ -359,23 +280,6 @@ eek_key_class_init (EekKeyClass *klass)
NULL, NULL,
g_cclosure_marshal_VOID__VOID, g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0); G_TYPE_NONE, 0);
/**
* EekKey::cancelled:
* @key: an #EekKey
*
* The ::cancelled signal is emitted each time @key is shifted to
* the cancelled state.
*/
signals[CANCELLED] =
g_signal_new (I_("cancelled"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EekKeyClass, cancelled),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
} }
static void static void
@ -677,3 +581,9 @@ eek_key_is_locked (EekKey *key)
g_return_val_if_fail (EEK_IS_KEY(key), FALSE); g_return_val_if_fail (EEK_IS_KEY(key), FALSE);
return key->priv->is_locked; return key->priv->is_locked;
} }
void eek_key_set_pressed(EekKey *key, gboolean value)
{
g_return_if_fail (EEK_IS_KEY(key));
key->priv->is_pressed = value;
}

View File

@ -43,6 +43,9 @@ typedef struct _EekKeyPrivate EekKeyPrivate;
/** /**
* EekKey: * EekKey:
* *
* Contains information about the state of a key.
* TODO: rewrite as a plain struct
*
* The #EekKey structure contains only private data and should only be * The #EekKey structure contains only private data and should only be
* accessed using the provided API. * accessed using the provided API.
*/ */
@ -71,11 +74,8 @@ struct _EekKeyClass
/*< public >*/ /*< public >*/
/* signals */ /* signals */
void (* pressed) (EekKey *key);
void (* released) (EekKey *key);
void (* locked) (EekKey *key); void (* locked) (EekKey *key);
void (* unlocked) (EekKey *key); void (* unlocked) (EekKey *key);
void (* cancelled) (EekKey *key);
}; };
GType eek_key_get_type (void) G_GNUC_CONST; GType eek_key_get_type (void) G_GNUC_CONST;
@ -110,6 +110,8 @@ guint eek_key_get_oref (EekKey *key);
gboolean eek_key_is_pressed (EekKey *key); gboolean eek_key_is_pressed (EekKey *key);
gboolean eek_key_is_locked (EekKey *key); gboolean eek_key_is_locked (EekKey *key);
void eek_key_set_pressed (EekKey *key,
gboolean value);
G_END_DECLS G_END_DECLS
#endif /* EEK_KEY_H */ #endif /* EEK_KEY_H */

View File

@ -32,10 +32,12 @@
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include "eek-keyboard.h" #include "eek-keyboard.h"
#include "eek-marshalers.h"
#include "eek-section.h" #include "eek-section.h"
#include "eek-key.h" #include "eek-key.h"
#include "eek-symbol.h" #include "eek-symbol.h"
#include "eek-enumtypes.h" #include "eek-enumtypes.h"
#include "eekboard/key-emitter.h"
enum { enum {
PROP_0, PROP_0,
@ -45,11 +47,9 @@ enum {
}; };
enum { enum {
KEY_PRESSED,
KEY_RELEASED, KEY_RELEASED,
KEY_LOCKED, KEY_LOCKED,
KEY_UNLOCKED, KEY_UNLOCKED,
KEY_CANCELLED,
LAST_SIGNAL LAST_SIGNAL
}; };
@ -91,22 +91,6 @@ eek_modifier_key_free (EekModifierKey *modkey)
g_slice_free (EekModifierKey, modkey); g_slice_free (EekModifierKey, modkey);
} }
static void
on_key_pressed (EekSection *section,
EekKey *key,
EekKeyboard *keyboard)
{
g_signal_emit (keyboard, signals[KEY_PRESSED], 0, key);
}
static void
on_key_released (EekSection *section,
EekKey *key,
EekKeyboard *keyboard)
{
g_signal_emit (keyboard, signals[KEY_RELEASED], 0, key);
}
static void static void
on_key_locked (EekSection *section, on_key_locked (EekSection *section,
EekKey *key, EekKey *key,
@ -123,14 +107,6 @@ on_key_unlocked (EekSection *section,
g_signal_emit (keyboard, signals[KEY_UNLOCKED], 0, key); g_signal_emit (keyboard, signals[KEY_UNLOCKED], 0, key);
} }
static void
on_key_cancelled (EekSection *section,
EekKey *key,
EekKeyboard *keyboard)
{
g_signal_emit (keyboard, signals[KEY_CANCELLED], 0, key);
}
static void static void
on_symbol_index_changed (EekSection *section, on_symbol_index_changed (EekSection *section,
gint group, gint group,
@ -278,74 +254,76 @@ set_modifiers_with_key (EekKeyboard *self,
priv->modifiers = modifiers; priv->modifiers = modifiers;
} }
static void void eek_keyboard_press_key(EekKeyboard *keyboard, EekKey *key, guint32 timestamp) {
eek_keyboard_real_key_pressed (EekKeyboard *self, EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(keyboard);
EekKey *key)
{
EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(self);
EekSymbol *symbol;
EekModifierType modifier;
eek_key_set_pressed(key, TRUE);
priv->pressed_keys = g_list_prepend (priv->pressed_keys, key); priv->pressed_keys = g_list_prepend (priv->pressed_keys, key);
symbol = eek_key_get_symbol_with_fallback (key, 0, 0); EekSymbol *symbol = eek_key_get_symbol_with_fallback (key, 0, 0);
if (!symbol) if (!symbol)
return; return;
modifier = eek_symbol_get_modifier_mask (symbol); EekModifierType modifier = eek_symbol_get_modifier_mask (symbol);
if (priv->modifier_behavior == EEK_MODIFIER_BEHAVIOR_NONE) { if (priv->modifier_behavior == EEK_MODIFIER_BEHAVIOR_NONE) {
set_modifiers_with_key (self, key, priv->modifiers | modifier); set_modifiers_with_key (keyboard, key, priv->modifiers | modifier);
set_level_from_modifiers (self); set_level_from_modifiers (keyboard);
} }
// "Borrowed" from eek-context-service; doesn't influence the state but forwards the event
guint keycode = eek_key_get_keycode (key);
guint modifiers = eek_keyboard_get_modifiers (keyboard);
emit_key_activated(keyboard->manager, keyboard, keycode, symbol, modifiers, TRUE, timestamp);
} }
static void void eek_keyboard_release_key( EekKeyboard *keyboard,
eek_keyboard_real_key_released (EekKeyboard *self, EekKey *key,
EekKey *key) guint32 timestamp) {
{ EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(keyboard);
EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(self);
EekSymbol *symbol;
EekModifierType modifier;
EEK_KEYBOARD_GET_CLASS (self)->key_cancelled (self, key); for (GList *head = priv->pressed_keys; head; head = g_list_next (head)) {
symbol = eek_key_get_symbol_with_fallback (key, 0, 0);
if (!symbol)
return;
modifier = eek_symbol_get_modifier_mask (symbol);
switch (priv->modifier_behavior) {
case EEK_MODIFIER_BEHAVIOR_NONE:
set_modifiers_with_key (self, key, priv->modifiers & ~modifier);
break;
case EEK_MODIFIER_BEHAVIOR_LOCK:
priv->modifiers ^= modifier;
break;
case EEK_MODIFIER_BEHAVIOR_LATCH:
if (modifier)
set_modifiers_with_key (self, key, priv->modifiers ^ modifier);
else
set_modifiers_with_key (self, key,
(priv->modifiers ^ modifier) & modifier);
break;
}
set_level_from_modifiers (self);
}
static void
eek_keyboard_real_key_cancelled (EekKeyboard *self,
EekKey *key)
{
EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(self);
GList *head;
for (head = priv->pressed_keys; head; head = g_list_next (head)) {
if (head->data == key) { if (head->data == key) {
priv->pressed_keys = g_list_remove_link (priv->pressed_keys, head); priv->pressed_keys = g_list_remove_link (priv->pressed_keys, head);
g_list_free1 (head); g_list_free1 (head);
break; break;
} }
} }
EekSymbol *symbol = eek_key_get_symbol_with_fallback (key, 0, 0);
if (!symbol)
return;
EekModifierType modifier = eek_symbol_get_modifier_mask (symbol);
if (!symbol)
return;
modifier = eek_symbol_get_modifier_mask (symbol);
switch (priv->modifier_behavior) {
case EEK_MODIFIER_BEHAVIOR_NONE:
set_modifiers_with_key (keyboard, key, priv->modifiers & ~modifier);
break;
case EEK_MODIFIER_BEHAVIOR_LOCK:
priv->modifiers ^= modifier;
break;
case EEK_MODIFIER_BEHAVIOR_LATCH:
if (modifier)
set_modifiers_with_key (keyboard, key, priv->modifiers ^ modifier);
else
set_modifiers_with_key (keyboard, key,
(priv->modifiers ^ modifier) & modifier);
break;
}
set_level_from_modifiers (keyboard);
// "Borrowed" from eek-context-service; doesn't influence the state but forwards the event
guint keycode = eek_key_get_keycode (key);
guint modifiers = eek_keyboard_get_modifiers (keyboard);
emit_key_activated(keyboard->manager, keyboard, keycode, symbol, modifiers, FALSE, timestamp);
} }
static void static void
@ -365,7 +343,7 @@ static void
eek_keyboard_finalize (GObject *object) eek_keyboard_finalize (GObject *object)
{ {
EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(object); EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(object);
gint i; guint i;
g_list_free (priv->pressed_keys); g_list_free (priv->pressed_keys);
g_list_free_full (priv->locked_keys, g_list_free_full (priv->locked_keys,
@ -389,16 +367,10 @@ static void
eek_keyboard_real_child_added (EekContainer *self, eek_keyboard_real_child_added (EekContainer *self,
EekElement *element) EekElement *element)
{ {
g_signal_connect (element, "key-pressed",
G_CALLBACK(on_key_pressed), self);
g_signal_connect (element, "key-released",
G_CALLBACK(on_key_released), self);
g_signal_connect (element, "key-locked", g_signal_connect (element, "key-locked",
G_CALLBACK(on_key_locked), self); G_CALLBACK(on_key_locked), self);
g_signal_connect (element, "key-unlocked", g_signal_connect (element, "key-unlocked",
G_CALLBACK(on_key_unlocked), self); G_CALLBACK(on_key_unlocked), self);
g_signal_connect (element, "key-cancelled",
G_CALLBACK(on_key_cancelled), self);
g_signal_connect (element, "symbol-index-changed", g_signal_connect (element, "symbol-index-changed",
G_CALLBACK(on_symbol_index_changed), self); G_CALLBACK(on_symbol_index_changed), self);
} }
@ -407,11 +379,8 @@ static void
eek_keyboard_real_child_removed (EekContainer *self, eek_keyboard_real_child_removed (EekContainer *self,
EekElement *element) EekElement *element)
{ {
g_signal_handlers_disconnect_by_func (element, on_key_pressed, self);
g_signal_handlers_disconnect_by_func (element, on_key_released, self);
g_signal_handlers_disconnect_by_func (element, on_key_locked, self); g_signal_handlers_disconnect_by_func (element, on_key_locked, self);
g_signal_handlers_disconnect_by_func (element, on_key_unlocked, self); g_signal_handlers_disconnect_by_func (element, on_key_unlocked, self);
g_signal_handlers_disconnect_by_func (element, on_key_cancelled, self);
} }
static void static void
@ -427,10 +396,6 @@ eek_keyboard_class_init (EekKeyboardClass *klass)
klass->create_section = eek_keyboard_real_create_section; klass->create_section = eek_keyboard_real_create_section;
/* signals */ /* signals */
klass->key_pressed = eek_keyboard_real_key_pressed;
klass->key_released = eek_keyboard_real_key_released;
klass->key_cancelled = eek_keyboard_real_key_cancelled;
container_class->child_added = eek_keyboard_real_child_added; container_class->child_added = eek_keyboard_real_child_added;
container_class->child_removed = eek_keyboard_real_child_removed; container_class->child_removed = eek_keyboard_real_child_removed;
@ -468,46 +433,6 @@ eek_keyboard_class_init (EekKeyboardClass *klass)
PROP_MODIFIER_BEHAVIOR, PROP_MODIFIER_BEHAVIOR,
pspec); pspec);
/**
* EekKeyboard::key-pressed:
* @keyboard: an #EekKeyboard
* @key: an #EekKey
*
* The ::key-pressed signal is emitted each time a key in @keyboard
* is shifted to the pressed state.
*/
signals[KEY_PRESSED] =
g_signal_new (I_("key-pressed"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EekKeyboardClass, key_pressed),
NULL,
NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
1,
EEK_TYPE_KEY);
/**
* EekKeyboard::key-released:
* @keyboard: an #EekKeyboard
* @key: an #EekKey
*
* The ::key-released signal is emitted each time a key in @keyboard
* is shifted to the released state.
*/
signals[KEY_RELEASED] =
g_signal_new (I_("key-released"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EekKeyboardClass, key_released),
NULL,
NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
1,
EEK_TYPE_KEY);
/** /**
* EekKeyboard::key-locked: * EekKeyboard::key-locked:
* @keyboard: an #EekKeyboard * @keyboard: an #EekKeyboard
@ -547,26 +472,6 @@ eek_keyboard_class_init (EekKeyboardClass *klass)
G_TYPE_NONE, G_TYPE_NONE,
1, 1,
EEK_TYPE_KEY); EEK_TYPE_KEY);
/**
* EekKeyboard::key-cancelled:
* @keyboard: an #EekKeyboard
* @key: an #EekKey
*
* The ::key-cancelled signal is emitted each time a key in @keyboard
* is shifted to the cancelled state.
*/
signals[KEY_CANCELLED] =
g_signal_new (I_("key-cancelled"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EekKeyboardClass, key_cancelled),
NULL,
NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
1,
EEK_TYPE_KEY);
} }
static void static void

View File

@ -26,6 +26,7 @@
#define EEK_KEYBOARD_H 1 #define EEK_KEYBOARD_H 1
#include <glib-object.h> #include <glib-object.h>
#include <xkbcommon/xkbcommon.h>
#include "eek-container.h" #include "eek-container.h"
#include "eek-types.h" #include "eek-types.h"
#include "eek-layout.h" #include "eek-layout.h"
@ -45,6 +46,8 @@ typedef struct _EekKeyboardPrivate EekKeyboardPrivate;
/** /**
* EekKeyboard: * EekKeyboard:
* *
* Contains the state of the physical keyboard.
*
* The #EekKeyboard structure contains only private data and should * The #EekKeyboard structure contains only private data and should
* only be accessed using the provided API. * only be accessed using the provided API.
*/ */
@ -54,6 +57,11 @@ struct _EekKeyboard
EekContainer parent; EekContainer parent;
EekKeyboardPrivate *priv; EekKeyboardPrivate *priv;
struct xkb_keymap *keymap;
int keymap_fd; // keymap formatted as XKB string
size_t keymap_len; // length of the data inside keymap_fd
EekboardContextService *manager; // unowned reference
}; };
/** /**
@ -82,12 +90,6 @@ struct _EekKeyboardClass
EekKey *(* find_key_by_keycode) (EekKeyboard *self, EekKey *(* find_key_by_keycode) (EekKeyboard *self,
guint keycode); guint keycode);
/* signals */
void (* key_pressed) (EekKeyboard *self,
EekKey *key);
void (* key_released) (EekKeyboard *self,
EekKey *key);
/*< private >*/ /*< private >*/
/* obsolete members moved to EekElement */ /* obsolete members moved to EekElement */
gpointer symbol_index_changed; gpointer symbol_index_changed;
@ -98,8 +100,6 @@ struct _EekKeyboardClass
EekKey *key); EekKey *key);
void (* key_unlocked) (EekKeyboard *self, void (* key_unlocked) (EekKeyboard *self,
EekKey *key); EekKey *key);
void (* key_cancelled) (EekKeyboard *self,
EekKey *key);
/*< private >*/ /*< private >*/
/* padding */ /* padding */
@ -121,12 +121,13 @@ struct _EekModifierKey {
}; };
typedef struct _EekModifierKey EekModifierKey; typedef struct _EekModifierKey EekModifierKey;
GType eek_keyboard_get_type
(void) G_GNUC_CONST;
EekKeyboard *eek_keyboard_new (EekLayout *layout, EekKeyboard *eek_keyboard_new (EekboardContextService *manager,
EekLayout *layout,
gdouble initial_width, gdouble initial_width,
gdouble initial_height); gdouble initial_height);
GType eek_keyboard_get_type
(void) G_GNUC_CONST;
EekLayout *eek_keyboard_get_layout EekLayout *eek_keyboard_get_layout
(EekKeyboard *keyboard); (EekKeyboard *keyboard);
void eek_keyboard_get_size void eek_keyboard_get_size
@ -188,5 +189,8 @@ EekModifierKey *eek_modifier_key_copy
void eek_modifier_key_free void eek_modifier_key_free
(EekModifierKey *modkey); (EekModifierKey *modkey);
void eek_keyboard_press_key(EekKeyboard *keyboard, EekKey *key, guint32 timestamp);
void eek_keyboard_release_key(EekKeyboard *keyboard, EekKey *key, guint32 timestamp);
G_END_DECLS G_END_DECLS
#endif /* EEK_KEYBOARD_H */ #endif /* EEK_KEYBOARD_H */

View File

@ -32,6 +32,7 @@
#include "eek-layout.h" #include "eek-layout.h"
#include "eek-keyboard.h" #include "eek-keyboard.h"
#include "eekboard/eekboard-context-service.h"
G_DEFINE_ABSTRACT_TYPE (EekLayout, eek_layout, G_TYPE_OBJECT); G_DEFINE_ABSTRACT_TYPE (EekLayout, eek_layout, G_TYPE_OBJECT);
@ -55,14 +56,16 @@ eek_layout_init (EekLayout *self)
* Create a new #EekKeyboard based on @layout. * Create a new #EekKeyboard based on @layout.
*/ */
EekKeyboard * EekKeyboard *
eek_keyboard_new (EekLayout *layout, eek_keyboard_new (EekboardContextService *manager,
EekLayout *layout,
gdouble initial_width, gdouble initial_width,
gdouble initial_height) gdouble initial_height)
{ {
g_assert (EEK_IS_LAYOUT(layout)); g_assert (EEK_IS_LAYOUT(layout));
g_assert (EEK_LAYOUT_GET_CLASS(layout)->create_keyboard); g_assert (EEK_LAYOUT_GET_CLASS(layout)->create_keyboard);
return EEK_LAYOUT_GET_CLASS(layout)->create_keyboard (layout, return EEK_LAYOUT_GET_CLASS(layout)->create_keyboard (manager,
layout,
initial_width, initial_width,
initial_height); initial_height);
} }

View File

@ -56,7 +56,8 @@ struct _EekLayoutClass
GObjectClass parent_class; GObjectClass parent_class;
/*< public >*/ /*< public >*/
EekKeyboard* (* create_keyboard) (EekLayout *self, EekKeyboard* (* create_keyboard) (EekboardContextService *manager,
EekLayout *self,
gdouble initial_width, gdouble initial_width,
gdouble initial_height); gdouble initial_height);

View File

@ -166,8 +166,8 @@ create_keyboard_surface (EekRenderer *renderer)
eek_element_get_bounds (EEK_ELEMENT(priv->keyboard), &bounds); eek_element_get_bounds (EEK_ELEMENT(priv->keyboard), &bounds);
keyboard_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, keyboard_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
bounds.width * priv->scale, ceil(bounds.width * priv->scale),
bounds.height * priv->scale); ceil(bounds.height * priv->scale));
data.cr = cairo_create (keyboard_surface); data.cr = cairo_create (keyboard_surface);
data.renderer = renderer; data.renderer = renderer;

View File

@ -45,11 +45,8 @@ enum {
}; };
enum { enum {
KEY_PRESSED,
KEY_RELEASED,
KEY_LOCKED, KEY_LOCKED,
KEY_UNLOCKED, KEY_UNLOCKED,
KEY_CANCELLED,
LAST_SIGNAL LAST_SIGNAL
}; };
@ -114,20 +111,6 @@ eek_section_real_get_row (EekSection *self,
*orientation = row->orientation; *orientation = row->orientation;
} }
static void
on_pressed (EekKey *key,
EekSection *section)
{
g_signal_emit (section, signals[KEY_PRESSED], 0, key);
}
static void
on_released (EekKey *key,
EekSection *section)
{
g_signal_emit (section, signals[KEY_RELEASED], 0, key);
}
static void static void
on_locked (EekKey *key, on_locked (EekKey *key,
EekSection *section) EekSection *section)
@ -142,13 +125,6 @@ on_unlocked (EekKey *key,
g_signal_emit (section, signals[KEY_UNLOCKED], 0, key); g_signal_emit (section, signals[KEY_UNLOCKED], 0, key);
} }
static void
on_cancelled (EekKey *key,
EekSection *section)
{
g_signal_emit (section, signals[KEY_CANCELLED], 0, key);
}
static EekKey * static EekKey *
eek_section_real_create_key (EekSection *self, eek_section_real_create_key (EekSection *self,
guint keycode, guint keycode,
@ -296,22 +272,16 @@ static void
eek_section_real_child_added (EekContainer *self, eek_section_real_child_added (EekContainer *self,
EekElement *element) EekElement *element)
{ {
g_signal_connect (element, "pressed", G_CALLBACK(on_pressed), self);
g_signal_connect (element, "released", G_CALLBACK(on_released), self);
g_signal_connect (element, "locked", G_CALLBACK(on_locked), self); g_signal_connect (element, "locked", G_CALLBACK(on_locked), self);
g_signal_connect (element, "unlocked", G_CALLBACK(on_unlocked), self); g_signal_connect (element, "unlocked", G_CALLBACK(on_unlocked), self);
g_signal_connect (element, "cancelled", G_CALLBACK(on_cancelled), self);
} }
static void static void
eek_section_real_child_removed (EekContainer *self, eek_section_real_child_removed (EekContainer *self,
EekElement *element) EekElement *element)
{ {
g_signal_handlers_disconnect_by_func (element, on_pressed, self);
g_signal_handlers_disconnect_by_func (element, on_released, self);
g_signal_handlers_disconnect_by_func (element, on_locked, self); g_signal_handlers_disconnect_by_func (element, on_locked, self);
g_signal_handlers_disconnect_by_func (element, on_unlocked, self); g_signal_handlers_disconnect_by_func (element, on_unlocked, self);
g_signal_handlers_disconnect_by_func (element, on_cancelled, self);
} }
static void static void
@ -353,46 +323,6 @@ eek_section_class_init (EekSectionClass *klass)
PROP_ANGLE, PROP_ANGLE,
pspec); pspec);
/**
* EekSection::key-pressed:
* @section: an #EekSection
* @key: an #EekKey
*
* The ::key-pressed signal is emitted each time a key in @section
* is shifted to the pressed state.
*/
signals[KEY_PRESSED] =
g_signal_new (I_("key-pressed"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EekSectionClass, key_pressed),
NULL,
NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
1,
EEK_TYPE_KEY);
/**
* EekSection::key-released:
* @section: an #EekSection
* @key: an #EekKey
*
* The ::key-released signal is emitted each time a key in @section
* is shifted to the released state.
*/
signals[KEY_RELEASED] =
g_signal_new (I_("key-released"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EekSectionClass, key_released),
NULL,
NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
1,
EEK_TYPE_KEY);
/** /**
* EekSection::key-locked: * EekSection::key-locked:
* @section: an #EekSection * @section: an #EekSection
@ -432,26 +362,6 @@ eek_section_class_init (EekSectionClass *klass)
G_TYPE_NONE, G_TYPE_NONE,
1, 1,
EEK_TYPE_KEY); EEK_TYPE_KEY);
/**
* EekSection::key-cancelled:
* @section: an #EekSection
* @key: an #EekKey
*
* The ::key-cancelled signal is emitted each time a key in @section
* is shifted to the cancelled state.
*/
signals[KEY_CANCELLED] =
g_signal_new (I_("key-cancelled"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EekSectionClass, key_cancelled),
NULL,
NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
1,
EEK_TYPE_KEY);
} }
static void static void

View File

@ -40,6 +40,7 @@ enum {
PROP_CATEGORY, PROP_CATEGORY,
PROP_MODIFIER_MASK, PROP_MODIFIER_MASK,
PROP_ICON_NAME, PROP_ICON_NAME,
PROP_TOOLTIP,
PROP_LAST PROP_LAST
}; };
@ -49,6 +50,7 @@ struct _EekSymbolPrivate {
EekSymbolCategory category; EekSymbolCategory category;
EekModifierType modifier_mask; EekModifierType modifier_mask;
gchar *icon_name; gchar *icon_name;
gchar *tooltip;
}; };
static void eek_serializable_iface_init (EekSerializableIface *iface); static void eek_serializable_iface_init (EekSerializableIface *iface);
@ -71,6 +73,7 @@ eek_symbol_real_serialize (EekSerializable *self,
g_variant_builder_add (builder, "u", priv->category); g_variant_builder_add (builder, "u", priv->category);
g_variant_builder_add (builder, "u", priv->modifier_mask); g_variant_builder_add (builder, "u", priv->modifier_mask);
g_variant_builder_add (builder, "s", NOTNULL(priv->icon_name)); g_variant_builder_add (builder, "s", NOTNULL(priv->icon_name));
g_variant_builder_add (builder, "s", NOTNULL(priv->tooltip));
#undef NOTNULL #undef NOTNULL
} }
@ -86,6 +89,7 @@ eek_symbol_real_deserialize (EekSerializable *self,
g_variant_get_child (variant, index++, "u", &priv->category); g_variant_get_child (variant, index++, "u", &priv->category);
g_variant_get_child (variant, index++, "u", &priv->modifier_mask); g_variant_get_child (variant, index++, "u", &priv->modifier_mask);
g_variant_get_child (variant, index++, "s", &priv->icon_name); g_variant_get_child (variant, index++, "s", &priv->icon_name);
g_variant_get_child (variant, index++, "s", &priv->tooltip);
return index; return index;
} }
@ -121,6 +125,10 @@ eek_symbol_set_property (GObject *object,
eek_symbol_set_icon_name (EEK_SYMBOL(object), eek_symbol_set_icon_name (EEK_SYMBOL(object),
g_value_get_string (value)); g_value_get_string (value));
break; break;
case PROP_TOOLTIP:
eek_symbol_set_tooltip (EEK_SYMBOL(object),
g_value_get_string (value));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -151,6 +159,10 @@ eek_symbol_get_property (GObject *object,
g_value_set_string (value, g_value_set_string (value,
eek_symbol_get_icon_name (EEK_SYMBOL(object))); eek_symbol_get_icon_name (EEK_SYMBOL(object)));
break; break;
case PROP_TOOLTIP:
g_value_set_string (value,
eek_symbol_get_tooltip (EEK_SYMBOL(object)));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -165,6 +177,7 @@ eek_symbol_finalize (GObject *object)
g_free (priv->name); g_free (priv->name);
g_free (priv->label); g_free (priv->label);
g_free (priv->icon_name); g_free (priv->icon_name);
g_free (priv->tooltip);
G_OBJECT_CLASS (eek_symbol_parent_class)->finalize (object); G_OBJECT_CLASS (eek_symbol_parent_class)->finalize (object);
} }
@ -216,6 +229,13 @@ eek_symbol_class_init (EekSymbolClass *klass)
NULL, NULL,
G_PARAM_CONSTRUCT | G_PARAM_READWRITE); G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_ICON_NAME, pspec); g_object_class_install_property (gobject_class, PROP_ICON_NAME, pspec);
pspec = g_param_spec_string ("tooltip",
"Tooltip",
"Tooltip text",
NULL,
G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_TOOLTIP, pspec);
} }
static void static void
@ -265,7 +285,7 @@ eek_symbol_set_name (EekSymbol *symbol,
* *
* Get the name of @symbol. * Get the name of @symbol.
*/ */
G_CONST_RETURN gchar * const gchar *
eek_symbol_get_name (EekSymbol *symbol) eek_symbol_get_name (EekSymbol *symbol)
{ {
EekSymbolPrivate *priv; EekSymbolPrivate *priv;
@ -304,7 +324,7 @@ eek_symbol_set_label (EekSymbol *symbol,
* *
* Get the label text of @symbol. * Get the label text of @symbol.
*/ */
G_CONST_RETURN gchar * const gchar *
eek_symbol_get_label (EekSymbol *symbol) eek_symbol_get_label (EekSymbol *symbol)
{ {
EekSymbolPrivate *priv; EekSymbolPrivate *priv;
@ -428,7 +448,7 @@ eek_symbol_set_icon_name (EekSymbol *symbol,
* *
* Get the icon name of @symbol. * Get the icon name of @symbol.
*/ */
G_CONST_RETURN gchar * const gchar *
eek_symbol_get_icon_name (EekSymbol *symbol) eek_symbol_get_icon_name (EekSymbol *symbol)
{ {
EekSymbolPrivate *priv; EekSymbolPrivate *priv;
@ -441,6 +461,45 @@ eek_symbol_get_icon_name (EekSymbol *symbol)
return priv->icon_name; return priv->icon_name;
} }
/**
* eek_symbol_set_tooltip:
* @symbol: an #EekSymbol
* @tooltip: icon name of @symbol
*
* Set the tooltip text of @symbol to @tooltip.
*/
void
eek_symbol_set_tooltip (EekSymbol *symbol,
const gchar *tooltip)
{
EekSymbolPrivate *priv;
g_return_if_fail (EEK_IS_SYMBOL(symbol));
priv = EEK_SYMBOL_GET_PRIVATE(symbol);
g_free (priv->tooltip);
priv->tooltip = g_strdup (tooltip);
}
/**
* eek_symbol_get_tooltip:
* @symbol: an #EekSymbol
*
* Get the tooltip text of @symbol.
*/
const gchar *
eek_symbol_get_tooltip (EekSymbol *symbol)
{
EekSymbolPrivate *priv;
g_return_val_if_fail (EEK_IS_SYMBOL(symbol), NULL);
priv = EEK_SYMBOL_GET_PRIVATE(symbol);
if (priv->tooltip == NULL || *priv->tooltip == '\0')
return NULL;
return priv->tooltip;
}
static const struct { static const struct {
EekSymbolCategory category; EekSymbolCategory category;
gchar *name; gchar *name;
@ -456,7 +515,7 @@ static const struct {
{ EEK_SYMBOL_CATEGORY_UNKNOWN, NULL } { EEK_SYMBOL_CATEGORY_UNKNOWN, NULL }
}; };
G_CONST_RETURN gchar * const gchar *
eek_symbol_category_get_name (EekSymbolCategory category) eek_symbol_category_get_name (EekSymbolCategory category)
{ {
gint i; gint i;

View File

@ -89,32 +89,31 @@ struct _EekSymbolClass {
GObjectClass parent_class; GObjectClass parent_class;
}; };
GType eek_symbol_get_type (void) G_GNUC_CONST; GType eek_symbol_get_type (void) G_GNUC_CONST;
EekSymbol *eek_symbol_new (const gchar *name); EekSymbol *eek_symbol_new (const gchar *name);
void eek_symbol_set_name (EekSymbol *symbol, void eek_symbol_set_name (EekSymbol *symbol,
const gchar *name); const gchar *name);
G_CONST_RETURN gchar *eek_symbol_get_name (EekSymbol *symbol); const gchar *eek_symbol_get_name (EekSymbol *symbol);
void eek_symbol_set_label (EekSymbol *symbol, void eek_symbol_set_label (EekSymbol *symbol,
const gchar *label); const gchar *label);
G_CONST_RETURN gchar *eek_symbol_get_label (EekSymbol *symbol); const gchar *eek_symbol_get_label (EekSymbol *symbol);
void eek_symbol_set_category (EekSymbol *symbol, void eek_symbol_set_category (EekSymbol *symbol,
EekSymbolCategory category); EekSymbolCategory category);
EekSymbolCategory eek_symbol_get_category (EekSymbol *symbol); EekSymbolCategory eek_symbol_get_category (EekSymbol *symbol);
EekModifierType eek_symbol_get_modifier_mask EekModifierType eek_symbol_get_modifier_mask (EekSymbol *symbol);
(EekSymbol *symbol); void eek_symbol_set_modifier_mask (EekSymbol *symbol,
void eek_symbol_set_modifier_mask EekModifierType mask);
(EekSymbol *symbol, gboolean eek_symbol_is_modifier (EekSymbol *symbol);
EekModifierType mask); void eek_symbol_set_icon_name (EekSymbol *symbol,
gboolean eek_symbol_is_modifier (EekSymbol *symbol); const gchar *icon_name);
void eek_symbol_set_icon_name (EekSymbol *symbol, const gchar *eek_symbol_get_icon_name (EekSymbol *symbol);
const gchar *icon_name); void eek_symbol_set_tooltip (EekSymbol *symbol,
G_CONST_RETURN gchar *eek_symbol_get_icon_name (EekSymbol *symbol); const gchar *tooltip);
const gchar * eek_symbol_get_tooltip (EekSymbol *symbol);
G_CONST_RETURN gchar *eek_symbol_category_get_name const gchar *eek_symbol_category_get_name (EekSymbolCategory category);
(EekSymbolCategory category); EekSymbolCategory eek_symbol_category_from_name (const gchar *name);
EekSymbolCategory eek_symbol_category_from_name
(const gchar *name);
G_END_DECLS G_END_DECLS

View File

@ -150,6 +150,8 @@ typedef struct _EekBounds EekBounds;
typedef struct _EekOutline EekOutline; typedef struct _EekOutline EekOutline;
typedef struct _EekColor EekColor; typedef struct _EekColor EekColor;
typedef struct _EekboardContextService EekboardContextService;
/** /**
* EekPoint: * EekPoint:
* @x: X coordinate of the point * @x: X coordinate of the point

View File

@ -31,20 +31,24 @@
#include "config.h" #include "config.h"
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include "eek-xkb-layout.h"
#include <X11/keysym.h> #include <X11/keysym.h>
#include <X11/XKBlib.h>
#include <X11/extensions/XKBgeom.h> #include <X11/extensions/XKBgeom.h>
#include <string.h> #include <string.h>
#include <stdarg.h> #include <stdarg.h>
#include <gio/gio.h> #include <gio/gio.h>
#include "eek-xkb-layout.h"
#include "eek-keyboard.h" #include "eek-keyboard.h"
#include "eek-section.h" #include "eek-section.h"
#include "eek-key.h" #include "eek-key.h"
#include "eek-keysym.h" #include "eek-keysym.h"
#define noKBDRAW_DEBUG #define XKB_COMPONENT_MASK (XkbGBN_GeometryMask | \
XkbGBN_KeyNamesMask | \
XkbGBN_OtherNamesMask | \
XkbGBN_SymbolsMask | \
XkbGBN_IndicatorMapMask)
static void initable_iface_init (GInitableIface *initable_iface); static void initable_iface_init (GInitableIface *initable_iface);
@ -58,9 +62,6 @@ G_DEFINE_TYPE_WITH_CODE (EekXkbLayout, eek_xkb_layout, EEK_TYPE_LAYOUT,
enum { enum {
PROP_0, PROP_0,
PROP_DISPLAY, PROP_DISPLAY,
PROP_KEYCODES,
PROP_GEOMETRY,
PROP_SYMBOLS,
PROP_LAST PROP_LAST
}; };
@ -83,19 +84,18 @@ struct _EekXkbLayoutPrivate
gint scale_denominator; gint scale_denominator;
}; };
static guint static guint find_keycode (EekXkbLayout *layout,
find_keycode (EekXkbLayout *layout, gchar *key_name); gchar *key_name);
static void static gboolean get_keyboard_from_server (EekXkbLayout *layout,
get_keyboard (EekXkbLayout *layout); GError **error);
static void static gboolean get_names_from_server (EekXkbLayout *layout,
get_names (EekXkbLayout *layout); GError **error);
static void static void setup_scaling (EekXkbLayout *layout,
setup_scaling (EekXkbLayout *layout, gdouble width,
gdouble width, gdouble height);
gdouble height);
G_INLINE_FUNC gint G_INLINE_FUNC gint
xkb_to_pixmap_coord (EekXkbLayout *layout, xkb_to_pixmap_coord (EekXkbLayout *layout,
@ -149,7 +149,8 @@ create_key (EekXkbLayout *layout,
xkbshape->primary; xkbshape->primary;
outline = g_slice_new (EekOutline); outline = g_slice_new (EekOutline);
outline->corner_radius = xkb_to_pixmap_coord(layout, xkboutline->corner_radius); outline->corner_radius = xkb_to_pixmap_coord(layout,
xkboutline->corner_radius);
if (xkboutline->num_points <= 2) { /* rectangular */ if (xkboutline->num_points <= 2) { /* rectangular */
gdouble x1, y1, x2, y2; gdouble x1, y1, x2, y2;
@ -319,21 +320,24 @@ create_keyboard (EekXkbLayout *layout, EekKeyboard *keyboard)
} }
static EekKeyboard * static EekKeyboard *
eek_xkb_layout_real_create_keyboard (EekLayout *self, eek_xkb_layout_real_create_keyboard (EekboardContextService *manager,
EekLayout *self,
gdouble initial_width, gdouble initial_width,
gdouble initial_height) gdouble initial_height)
{ {
EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (self); EekKeyboard *keyboard = g_object_new (EEK_TYPE_KEYBOARD, "layout", self, NULL);
EekBounds bounds; keyboard->manager = manager;
EekKeyboard *keyboard;
keyboard = g_object_new (EEK_TYPE_KEYBOARD, "layout", self, NULL); EekBounds bounds = {
bounds.x = bounds.y = 0.0; .x = 0.0,
bounds.width = initial_width; .y = 0.0,
bounds.height = initial_height; .width = initial_width,
.height = initial_height
};
eek_element_set_bounds (EEK_ELEMENT(keyboard), &bounds); eek_element_set_bounds (EEK_ELEMENT(keyboard), &bounds);
/* resolve modifiers dynamically assigned at run time */ /* resolve modifiers dynamically assigned at run time */
EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (self);
eek_keyboard_set_num_lock_mask (keyboard, eek_keyboard_set_num_lock_mask (keyboard,
XkbKeysymToModifiers (priv->display, XkbKeysymToModifiers (priv->display,
XK_Num_Lock)); XK_Num_Lock));
@ -370,24 +374,11 @@ eek_xkb_layout_set_property (GObject *object,
GParamSpec *pspec) GParamSpec *pspec)
{ {
EekXkbLayout *layout = EEK_XKB_LAYOUT (object); EekXkbLayout *layout = EEK_XKB_LAYOUT (object);
const gchar *name;
switch (prop_id) { switch (prop_id) {
case PROP_DISPLAY: case PROP_DISPLAY:
layout->priv->display = g_value_get_pointer (value); layout->priv->display = g_value_get_pointer (value);
break; break;
case PROP_KEYCODES:
name = g_value_get_string (value);
eek_xkb_layout_set_keycodes (EEK_XKB_LAYOUT(object), name);
break;
case PROP_GEOMETRY:
name = g_value_get_string (value);
eek_xkb_layout_set_geometry (EEK_XKB_LAYOUT(object), name);
break;
case PROP_SYMBOLS:
name = g_value_get_string (value);
eek_xkb_layout_set_symbols (EEK_XKB_LAYOUT(object), name);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -401,24 +392,11 @@ eek_xkb_layout_get_property (GObject *object,
GParamSpec *pspec) GParamSpec *pspec)
{ {
EekXkbLayout *layout = EEK_XKB_LAYOUT (object); EekXkbLayout *layout = EEK_XKB_LAYOUT (object);
const gchar *name;
switch (prop_id) { switch (prop_id) {
case PROP_DISPLAY: case PROP_DISPLAY:
g_value_set_pointer (value, layout->priv->display); g_value_set_pointer (value, layout->priv->display);
break; break;
case PROP_KEYCODES:
name = eek_xkb_layout_get_keycodes (EEK_XKB_LAYOUT(object));
g_value_set_string (value, name);
break;
case PROP_GEOMETRY:
name = eek_xkb_layout_get_geometry (EEK_XKB_LAYOUT(object));
g_value_set_string (value, name);
break;
case PROP_SYMBOLS:
name = eek_xkb_layout_get_symbols (EEK_XKB_LAYOUT(object));
g_value_set_string (value, name);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -446,27 +424,6 @@ eek_xkb_layout_class_init (EekXkbLayoutClass *klass)
G_PARAM_READWRITE | G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY); G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (gobject_class, PROP_DISPLAY, pspec); g_object_class_install_property (gobject_class, PROP_DISPLAY, pspec);
pspec = g_param_spec_string ("keycodes",
"Keycodes",
"XKB keycodes component name",
NULL,
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_KEYCODES, pspec);
pspec = g_param_spec_string ("geometry",
"Geometry",
"XKB geometry component name",
NULL,
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_GEOMETRY, pspec);
pspec = g_param_spec_string ("symbols",
"Symbols",
"XKB symbols component name",
NULL,
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_SYMBOLS, pspec);
} }
static void static void
@ -475,8 +432,9 @@ eek_xkb_layout_init (EekXkbLayout *self)
self->priv = EEK_XKB_LAYOUT_GET_PRIVATE (self); self->priv = EEK_XKB_LAYOUT_GET_PRIVATE (self);
} }
static void static gboolean
get_names (EekXkbLayout *layout) get_names_from_server (EekXkbLayout *layout,
GError **error)
{ {
EekXkbLayoutPrivate *priv = layout->priv; EekXkbLayoutPrivate *priv = layout->priv;
gchar *name; gchar *name;
@ -524,6 +482,8 @@ get_names (EekXkbLayout *layout)
XFree (name); XFree (name);
} }
} }
return TRUE;
} }
/** /**
@ -546,252 +506,76 @@ eek_xkb_layout_new (Display *display,
* eek_xkb_layout_set_names: (skip) * eek_xkb_layout_set_names: (skip)
* @layout: an #EekXkbLayout * @layout: an #EekXkbLayout
* @names: XKB component names * @names: XKB component names
* @error: a #GError
* *
* Set the XKB component names to @layout. * Set the XKB component names to @layout.
* Returns: %TRUE if any of the component names changed, %FALSE otherwise * Returns: %TRUE if the component names are successfully set, %FALSE otherwise
*/ */
gboolean gboolean
eek_xkb_layout_set_names (EekXkbLayout *layout, XkbComponentNamesRec *names) eek_xkb_layout_set_names (EekXkbLayout *layout,
XkbComponentNamesRec *names,
GError **error)
{ {
EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (layout); if (g_strcmp0 (names->keycodes, layout->priv->names.keycodes)) {
gboolean retval; g_free (layout->priv->names.keycodes);
layout->priv->names.keycodes = g_strdup (names->keycodes);
g_return_val_if_fail (priv, FALSE);
if (g_strcmp0 (names->keycodes, priv->names.keycodes)) {
g_free (priv->names.keycodes);
priv->names.keycodes = g_strdup (names->keycodes);
retval = TRUE;
} }
if (g_strcmp0 (names->geometry, priv->names.geometry)) { if (g_strcmp0 (names->geometry, layout->priv->names.geometry)) {
g_free (priv->names.geometry); g_free (layout->priv->names.geometry);
priv->names.geometry = g_strdup (names->geometry); layout->priv->names.geometry = g_strdup (names->geometry);
retval = TRUE;
} }
if (g_strcmp0 (names->symbols, priv->names.symbols)) { if (g_strcmp0 (names->symbols, layout->priv->names.symbols)) {
g_free (priv->names.symbols); g_free (layout->priv->names.symbols);
priv->names.symbols = g_strdup (names->symbols); layout->priv->names.symbols = g_strdup (names->symbols);
retval = TRUE;
} }
get_keyboard (layout); return get_keyboard_from_server (layout, error);
g_assert (priv->xkb);
return retval;
} }
/** static gboolean
* eek_xkb_layout_set_names_full: get_keyboard_from_server (EekXkbLayout *layout,
* @layout: an #EekXkbLayout GError **error)
* @Varargs: pairs of component name and value, terminated by NULL.
*
* Set the XKB component names to @layout. This function is merely a
* wrapper around eek_xkb_layout_set_names() to avoid passing a
* pointer of XkbComponentNamesRec, which is not currently available
* in the gobject-introspection repository.
*
* Available component names are: keymap, keycodes, types, compat,
* symbols, geometry.
*
* Returns: %TRUE if the component name is successfully set, %FALSE otherwise
* Since: 0.0.2
*/
gboolean
eek_xkb_layout_set_names_full (EekXkbLayout *layout,
...)
{
va_list var_args;
gboolean retval;
va_start (var_args, layout);
retval = eek_xkb_layout_set_names_full_valist (layout, var_args);
va_end (var_args);
return retval;
}
/**
* eek_xkb_layout_set_names_full_valist:
* @layout: an #EekXkbLayout
* @var_args: <type>va_list</type> of pairs of component name and value.
*
* See eek_xkb_layout_set_names_full(), this version takes a
* <type>va_list</type> for language bindings to use.
*
* Since: 0.0.5
*/
gboolean
eek_xkb_layout_set_names_full_valist (EekXkbLayout *layout,
va_list var_args)
{
XkbComponentNamesRec names;
gchar *name, *value;
memset (&names, 0, sizeof names);
name = va_arg (var_args, gchar *);
while (name) {
value = va_arg (var_args, gchar *);
if (g_strcmp0 (name, "keymap") == 0)
names.keymap = (char *)value;
else if (g_strcmp0 (name, "keycodes") == 0)
names.keycodes = (char *)value;
else if (g_strcmp0 (name, "types") == 0)
names.types = (char *)value;
else if (g_strcmp0 (name, "compat") == 0)
names.compat = (char *)value;
else if (g_strcmp0 (name, "symbols") == 0)
names.symbols = (char *)value;
else if (g_strcmp0 (name, "geometry") == 0)
names.geometry = (char *)value;
name = va_arg (var_args, gchar *);
}
return eek_xkb_layout_set_names (layout, &names);
}
/**
* eek_xkb_layout_set_keycodes:
* @layout: an #EekXkbLayout
* @keycodes: component name for keycodes
*
* Set the keycodes component (in the XKB terminology).
* Returns: %TRUE if the component name is successfully set, %FALSE otherwise
*/
gboolean
eek_xkb_layout_set_keycodes (EekXkbLayout *layout, const gchar *keycodes)
{
EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (layout);
XkbComponentNamesRec names;
g_return_val_if_fail (priv, FALSE);
memcpy (&names, &priv->names, sizeof names);
names.keycodes = (gchar *)keycodes;
return eek_xkb_layout_set_names (layout, &names);
}
/**
* eek_xkb_layout_set_geometry:
* @layout: an #EekXkbLayout
* @geometry: component name for geometry
*
* Returns: %TRUE if the component name is successfully set, %FALSE otherwise
*/
gboolean
eek_xkb_layout_set_geometry (EekXkbLayout *layout, const gchar *geometry)
{
EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (layout);
XkbComponentNamesRec names;
g_return_val_if_fail (priv, FALSE);
memcpy (&names, &priv->names, sizeof names);
names.geometry = (gchar *)geometry;
return eek_xkb_layout_set_names (layout, &names);
}
/**
* eek_xkb_layout_set_symbols:
* @layout: an #EekXkbLayout
* @symbols: component name for symbols
*
* Set the symbols component (in the XKB terminology).
* Returns: %TRUE if the component name is successfully set, %FALSE otherwise
*/
gboolean
eek_xkb_layout_set_symbols (EekXkbLayout *layout, const gchar *symbols)
{
EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (layout);
XkbComponentNamesRec names;
g_return_val_if_fail (priv, FALSE);
memcpy (&names, &priv->names, sizeof names);
names.symbols = (gchar *)symbols;
return eek_xkb_layout_set_names (layout, &names);
}
/**
* eek_xkb_layout_get_keycodes:
* @layout: an #EekXkbLayout
*
* Get the keycodes component name (in the XKB terminology).
*/
G_CONST_RETURN gchar *
eek_xkb_layout_get_keycodes (EekXkbLayout *layout)
{
EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (layout);
g_return_val_if_fail (priv, NULL);
return priv->names.keycodes;
}
/**
* eek_xkb_layout_get_geometry:
* @layout: an #EekXkbLayout
*
* Get the geometry component name (in the XKB terminology).
*/
G_CONST_RETURN gchar *
eek_xkb_layout_get_geometry (EekXkbLayout *layout)
{
EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (layout);
g_return_val_if_fail (priv, NULL);
return priv->names.geometry;
}
/**
* eek_xkb_layout_get_symbols:
* @layout: an #EekXkbLayout
*
* Get the symbols component name (in the XKB terminology).
*/
G_CONST_RETURN gchar *
eek_xkb_layout_get_symbols (EekXkbLayout *layout)
{
EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (layout);
g_return_val_if_fail (priv, NULL);
return priv->names.symbols;
}
static void
get_keyboard (EekXkbLayout *layout)
{ {
EekXkbLayoutPrivate *priv = layout->priv; EekXkbLayoutPrivate *priv = layout->priv;
if (priv->xkb) if (priv->xkb) {
XkbFreeKeyboard (priv->xkb, 0, TRUE); /* free_all = TRUE */ XkbFreeKeyboard (priv->xkb, 0, True);
priv->xkb = NULL; priv->xkb = NULL;
}
if (priv->names.keycodes && if (priv->names.keycodes && priv->names.geometry && priv->names.symbols) {
priv->names.geometry && priv->xkb = XkbGetKeyboardByName (priv->display,
priv->names.symbols) { XkbUseCoreKbd,
priv->xkb = XkbGetKeyboardByName (priv->display, XkbUseCoreKbd, &priv->names,
&priv->names, 0, 0,
XkbGBN_GeometryMask | XKB_COMPONENT_MASK,
XkbGBN_KeyNamesMask | False);
XkbGBN_OtherNamesMask |
XkbGBN_ClientSymbolsMask |
XkbGBN_IndicatorMapMask, FALSE);
} else { } else {
priv->xkb = XkbGetKeyboard (priv->display, priv->xkb = XkbGetKeyboard (priv->display,
XkbGBN_GeometryMask | XKB_COMPONENT_MASK,
XkbGBN_KeyNamesMask |
XkbGBN_OtherNamesMask |
XkbGBN_SymbolsMask |
XkbGBN_IndicatorMapMask,
XkbUseCoreKbd); XkbUseCoreKbd);
get_names (layout); if (!get_names_from_server (layout, error)) {
XkbFreeKeyboard (priv->xkb, 0, True);
priv->xkb = NULL;
}
} }
if (priv->xkb == NULL) { if (priv->xkb == NULL) {
g_set_error (error,
EEK_ERROR,
EEK_ERROR_LAYOUT_ERROR,
"can't get keyboard from server");
g_free (priv->names.keycodes); g_free (priv->names.keycodes);
priv->names.keycodes = NULL; priv->names.keycodes = NULL;
g_free (priv->names.geometry); g_free (priv->names.geometry);
priv->names.geometry = NULL; priv->names.geometry = NULL;
g_free (priv->names.symbols); g_free (priv->names.symbols);
priv->names.symbols = NULL; priv->names.symbols = NULL;
return FALSE;
} }
return TRUE;
} }
@ -810,11 +594,6 @@ find_keycode (EekXkbLayout *layout, gchar *key_name)
if (!priv->xkb) if (!priv->xkb)
return EEK_INVALID_KEYCODE; return EEK_INVALID_KEYCODE;
#ifdef KBDRAW_DEBUG
printf (" looking for keycode for (%c%c%c%c)\n",
key_name[0], key_name[1], key_name[2], key_name[3]);
#endif
pkey = priv->xkb->names->keys + priv->xkb->min_key_code; pkey = priv->xkb->names->keys + priv->xkb->min_key_code;
for (keycode = priv->xkb->min_key_code; for (keycode = priv->xkb->min_key_code;
keycode <= priv->xkb->max_key_code; keycode++) { keycode <= priv->xkb->max_key_code; keycode++) {
@ -829,12 +608,8 @@ find_keycode (EekXkbLayout *layout, gchar *key_name)
break; break;
} }
} }
if (is_name_matched) { if (is_name_matched)
#ifdef KBDRAW_DEBUG
printf (" found keycode %u\n", keycode);
#endif
return keycode; return keycode;
}
pkey++; pkey++;
} }
@ -854,9 +629,6 @@ find_keycode (EekXkbLayout *layout, gchar *key_name)
if (is_name_matched) { if (is_name_matched) {
keycode = find_keycode (layout, palias->real); keycode = find_keycode (layout, palias->real);
#ifdef KBDRAW_DEBUG
printf ("found alias keycode %u\n", keycode);
#endif
return keycode; return keycode;
} }
palias++; palias++;
@ -894,34 +666,11 @@ initable_init (GInitable *initable,
{ {
EekXkbLayout *layout = EEK_XKB_LAYOUT (initable); EekXkbLayout *layout = EEK_XKB_LAYOUT (initable);
/* XXX: XkbClientMapMask | XkbIndicatorMapMask | XkbNamesMask | if (!get_keyboard_from_server (layout, error))
XkbGeometryMask */
layout->priv->xkb = XkbGetKeyboard (layout->priv->display,
XkbGBN_GeometryMask |
XkbGBN_KeyNamesMask |
XkbGBN_OtherNamesMask |
XkbGBN_SymbolsMask |
XkbGBN_IndicatorMapMask,
XkbUseCoreKbd);
if (layout->priv->xkb == NULL) {
g_set_error (error,
EEK_ERROR,
EEK_ERROR_LAYOUT_ERROR,
"can't get initial XKB keyboard configuration");
return FALSE; return FALSE;
}
get_names (layout); if (!get_names_from_server (layout, error))
get_keyboard (layout);
if (layout->priv->xkb == NULL) {
g_set_error (error,
EEK_ERROR,
EEK_ERROR_LAYOUT_ERROR,
"can't get XKB keyboard configuration");
return FALSE; return FALSE;
}
return TRUE; return TRUE;
} }

View File

@ -25,7 +25,6 @@
#ifndef EEK_XKB_LAYOUT_H #ifndef EEK_XKB_LAYOUT_H
#define EEK_XKB_LAYOUT_H 1 #define EEK_XKB_LAYOUT_H 1
#include <X11/Xlib.h>
#include <X11/XKBlib.h> #include <X11/XKBlib.h>
#include "eek-layout.h" #include "eek-layout.h"
@ -60,29 +59,13 @@ struct _EekXkbLayoutClass
gpointer pdummy[24]; gpointer pdummy[24];
}; };
GType eek_xkb_layout_get_type (void) G_GNUC_CONST; GType eek_xkb_layout_get_type (void) G_GNUC_CONST;
EekLayout *eek_xkb_layout_new (Display *display, EekLayout *eek_xkb_layout_new (Display *display,
GError **error); GError **error);
gboolean eek_xkb_layout_set_names (EekXkbLayout *layout, gboolean eek_xkb_layout_set_names (EekXkbLayout *layout,
XkbComponentNamesRec *names); XkbComponentNamesRec *names,
GError **error);
gboolean eek_xkb_layout_set_names_full (EekXkbLayout *layout,
...);
gboolean eek_xkb_layout_set_names_full_valist
(EekXkbLayout *layout,
va_list var_args);
gboolean eek_xkb_layout_set_keycodes (EekXkbLayout *layout,
const gchar *keycodes);
gboolean eek_xkb_layout_set_geometry (EekXkbLayout *layout,
const gchar *geometry);
gboolean eek_xkb_layout_set_symbols (EekXkbLayout *layout,
const gchar *symbols);
const gchar *eek_xkb_layout_get_keycodes (EekXkbLayout *layout);
const gchar *eek_xkb_layout_get_geometry (EekXkbLayout *layout);
const gchar *eek_xkb_layout_get_symbols (EekXkbLayout *layout);
G_END_DECLS G_END_DECLS
#endif /* #ifndef EEK_XKB_LAYOUT_H */ #endif /* #ifndef EEK_XKB_LAYOUT_H */

View File

@ -589,7 +589,12 @@ set_xkb_component_names (EekXklLayout *layout, XklConfigRec *config)
#endif #endif
if (xkl_xkb_config_native_prepare (priv->engine, config, &names)) { if (xkl_xkb_config_native_prepare (priv->engine, config, &names)) {
retval = eek_xkb_layout_set_names (EEK_XKB_LAYOUT(layout), &names); GError *error = NULL;
retval = eek_xkb_layout_set_names (EEK_XKB_LAYOUT(layout),
&names,
&error);
if (!retval)
g_warning ("can't set XKB layout");
xkl_xkb_config_native_cleanup (priv->engine, &names); xkl_xkb_config_native_cleanup (priv->engine, &names);
} }
return retval; return retval;

View File

@ -571,6 +571,7 @@ struct _SymbolsParseData {
GSList *symbols; GSList *symbols;
gchar *label; gchar *label;
gchar *icon; gchar *icon;
gchar *tooltip;
EekSymbolCategory category; EekSymbolCategory category;
guint keyval; guint keyval;
gint groups; gint groups;
@ -683,6 +684,11 @@ symbols_start_element_callback (GMarkupParseContext *pcontext,
if (attribute != NULL) if (attribute != NULL)
data->icon = g_strdup (attribute); data->icon = g_strdup (attribute);
attribute = get_attribute (attribute_names, attribute_values,
"tooltip");
if (attribute != NULL)
data->tooltip = g_strdup (attribute);
attribute = get_attribute (attribute_names, attribute_values, attribute = get_attribute (attribute_names, attribute_values,
"category"); "category");
if (attribute != NULL) if (attribute != NULL)
@ -766,6 +772,11 @@ symbols_end_element_callback (GMarkupParseContext *pcontext,
g_free (data->icon); g_free (data->icon);
data->icon = NULL; data->icon = NULL;
} }
if (data->tooltip) {
eek_symbol_set_tooltip (symbol, data->tooltip);
g_free (data->tooltip);
data->tooltip = NULL;
}
data->symbols = g_slist_prepend (data->symbols, symbol); data->symbols = g_slist_prepend (data->symbols, symbol);
goto out; goto out;
@ -885,27 +896,25 @@ static const GMarkupParser prerequisites_parser = {
}; };
static EekKeyboard * static EekKeyboard *
eek_xml_layout_real_create_keyboard (EekLayout *self, eek_xml_layout_real_create_keyboard (EekboardContextService *manager,
EekLayout *self,
gdouble initial_width, gdouble initial_width,
gdouble initial_height) gdouble initial_height)
{ {
EekXmlLayout *layout = EEK_XML_LAYOUT (self); EekXmlLayout *layout = EEK_XML_LAYOUT (self);
EekKeyboard *keyboard;
gchar *filename, *path;
GList *loaded;
GError *error;
gboolean retval; gboolean retval;
/* Create an empty keyboard to which geometry and symbols /* Create an empty keyboard to which geometry and symbols
information are applied. */ information are applied. */
keyboard = g_object_new (EEK_TYPE_KEYBOARD, "layout", layout, NULL); EekKeyboard *keyboard = g_object_new (EEK_TYPE_KEYBOARD, "layout", layout, NULL);
keyboard->manager = manager;
/* Read geometry information. */ /* Read geometry information. */
filename = g_strdup_printf ("%s.xml", layout->priv->desc->geometry); gchar *filename = g_strdup_printf ("%s.xml", layout->priv->desc->geometry);
path = g_build_filename (layout->priv->keyboards_dir, "geometry", filename, NULL); gchar *path = g_build_filename (layout->priv->keyboards_dir, "geometry", filename, NULL);
g_free (filename); g_free (filename);
error = NULL; GError *error = NULL;
retval = parse_geometry (path, keyboard, &error); retval = parse_geometry (path, keyboard, &error);
g_free (path); g_free (path);
if (!retval) { if (!retval) {
@ -918,7 +927,7 @@ eek_xml_layout_real_create_keyboard (EekLayout *self,
} }
/* Read symbols information. */ /* Read symbols information. */
loaded = NULL; GList *loaded = NULL;
retval = parse_symbols_with_prerequisites (layout->priv->keyboards_dir, retval = parse_symbols_with_prerequisites (layout->priv->keyboards_dir,
layout->priv->desc->symbols, layout->priv->desc->symbols,
keyboard, keyboard,

View File

@ -1,7 +1,8 @@
#!/usr/bin/env python #!/usr/bin/env python3
# Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org> # Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
# Copyright (C) 2010-2011 Red Hat, Inc. # Copyright (C) 2010-2011 Red Hat, Inc.
# Copyright (C) 2019 Purism, SPC
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License # modify it under the terms of the GNU Lesser General Public License
@ -21,13 +22,17 @@
import sys import sys
import re import re
if len(sys.argv) != 2: if len(sys.argv) > 3:
print >> sys.stderr, "Usage: %s TABLE-NAME" % sys.argv[0] print("Usage: %s TABLE-NAME [INPUT_FILE]" % sys.argv[0], file=sys.stderr)
sys.exit(-1) sys.exit(-1)
if len(sys.argv) < 3:
in_stream = sys.stdin
else:
in_stream = open(sys.argv[2])
table = dict() table = dict()
for line in sys.stdin: for line in in_stream:
line = line.decode('UTF-8')
match = re.match(r'\s*(0x[0-9A-F]+)\s+(\S*)\s+(\S*)', line, re.I) match = re.match(r'\s*(0x[0-9A-F]+)\s+(\S*)\s+(\S*)', line, re.I)
if match: if match:
table[int(match.group(1), 16)] = (match.group(2), match.group(3)) table[int(match.group(1), 16)] = (match.group(2), match.group(3))
@ -38,7 +43,7 @@ sys.stdout.write("static const EekKeysymEntry %s[] = {\n" %
for index, (keysym, (l, c)) in enumerate([(keysym, table[keysym]) for index, (keysym, (l, c)) in enumerate([(keysym, table[keysym])
for keysym in sorted(table.keys())]): for keysym in sorted(table.keys())]):
sys.stdout.write(" { 0x%X, %s, %s }" % sys.stdout.write(" { 0x%X, %s, %s }" %
(keysym, l.encode('UTF-8'), c.encode('UTF-8'))) (keysym, l, c))
if index < len(table) - 1: if index < len(table) - 1:
sys.stdout.write(",") sys.stdout.write(",")
sys.stdout.write("\n") sys.stdout.write("\n")

374
eek/layersurface.c Normal file
View File

@ -0,0 +1,374 @@
/*
* Copyright (C) 2018 Purism SPC
* SPDX-License-Identifier: GPL-3.0+
* Author: Guido Günther <agx@sigxcpu.org>
*/
/*
WARNING: this file is taken directly from phosh, with no modificaions apart from this message. Please update phosh instead of changing this file. Please copy the file back here afterwards, with the same notice.
*/
#define G_LOG_DOMAIN "phosh-layer-surface"
#include "config.h"
#include "layersurface.h"
#include <gdk/gdkwayland.h>
enum {
PHOSH_LAYER_SURFACE_PROP_0,
PHOSH_LAYER_SURFACE_PROP_LAYER_SHELL,
PHOSH_LAYER_SURFACE_PROP_WL_OUTPUT,
PHOSH_LAYER_SURFACE_PROP_ANCHOR,
PHOSH_LAYER_SURFACE_PROP_LAYER,
PHOSH_LAYER_SURFACE_PROP_KBD_INTERACTIVITY,
PHOSH_LAYER_SURFACE_PROP_EXCLUSIVE_ZONE,
PHOSH_LAYER_SURFACE_PROP_LAYER_WIDTH,
PHOSH_LAYER_SURFACE_PROP_LAYER_HEIGHT,
PHOSH_LAYER_SURFACE_PROP_NAMESPACE,
PHOSH_LAYER_SURFACE_PROP_LAST_PROP
};
static GParamSpec *props[PHOSH_LAYER_SURFACE_PROP_LAST_PROP];
enum {
CONFIGURED,
N_SIGNALS
};
static guint signals [N_SIGNALS];
typedef struct {
struct wl_surface *wl_surface;
struct zwlr_layer_surface_v1 *layer_surface;
/* Properties */
guint anchor;
guint layer;
gboolean kbd_interactivity;
gint exclusive_zone;
gint width, height;
gchar *namespace;
struct zwlr_layer_shell_v1 *layer_shell;
struct wl_output *wl_output;
} PhoshLayerSurfacePrivate;
G_DEFINE_TYPE_WITH_PRIVATE (PhoshLayerSurface, phosh_layer_surface, GTK_TYPE_WINDOW)
static void layer_surface_configure(void *data,
struct zwlr_layer_surface_v1 *surface,
uint32_t serial,
uint32_t width,
uint32_t height)
{
PhoshLayerSurface *self = data;
gtk_window_resize (GTK_WINDOW (self), width, height);
zwlr_layer_surface_v1_ack_configure(surface, serial);
gtk_widget_show_all (GTK_WIDGET (self));
g_signal_emit (self, signals[CONFIGURED], 0);
}
static void layer_surface_closed (void *data,
struct zwlr_layer_surface_v1 *surface)
{
PhoshLayerSurface *self = data;
PhoshLayerSurfacePrivate *priv = phosh_layer_surface_get_instance_private (self);
g_return_if_fail (priv->layer_surface == surface);
zwlr_layer_surface_v1_destroy(priv->layer_surface);
priv->layer_surface = NULL;
gtk_widget_destroy (GTK_WIDGET (self));
}
static struct zwlr_layer_surface_v1_listener layer_surface_listener = {
.configure = layer_surface_configure,
.closed = layer_surface_closed,
};
static void
phosh_layer_surface_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PhoshLayerSurface *self = PHOSH_LAYER_SURFACE (object);
PhoshLayerSurfacePrivate *priv = phosh_layer_surface_get_instance_private (self);
switch (property_id) {
case PHOSH_LAYER_SURFACE_PROP_LAYER_SHELL:
priv->layer_shell = g_value_get_pointer (value);
break;
case PHOSH_LAYER_SURFACE_PROP_WL_OUTPUT:
priv->wl_output = g_value_get_pointer (value);
break;
case PHOSH_LAYER_SURFACE_PROP_ANCHOR:
priv->anchor = g_value_get_uint (value);
break;
case PHOSH_LAYER_SURFACE_PROP_LAYER:
priv->layer = g_value_get_uint (value);
break;
case PHOSH_LAYER_SURFACE_PROP_KBD_INTERACTIVITY:
priv->kbd_interactivity = g_value_get_boolean (value);
break;
case PHOSH_LAYER_SURFACE_PROP_EXCLUSIVE_ZONE:
priv->exclusive_zone = g_value_get_int (value);
break;
case PHOSH_LAYER_SURFACE_PROP_LAYER_WIDTH:
priv->width = g_value_get_uint (value);
break;
case PHOSH_LAYER_SURFACE_PROP_LAYER_HEIGHT:
priv->height = g_value_get_uint (value);
break;
case PHOSH_LAYER_SURFACE_PROP_NAMESPACE:
g_free (priv->namespace);
priv->namespace = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
phosh_layer_surface_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PhoshLayerSurface *self = PHOSH_LAYER_SURFACE (object);
PhoshLayerSurfacePrivate *priv = phosh_layer_surface_get_instance_private (self);
switch (property_id) {
case PHOSH_LAYER_SURFACE_PROP_LAYER_SHELL:
g_value_set_pointer (value, priv->layer_shell);
break;
case PHOSH_LAYER_SURFACE_PROP_WL_OUTPUT:
g_value_set_pointer (value, priv->wl_output);
break;
case PHOSH_LAYER_SURFACE_PROP_ANCHOR:
g_value_set_uint (value, priv->anchor);
break;
case PHOSH_LAYER_SURFACE_PROP_LAYER:
g_value_set_uint (value, priv->layer);
break;
case PHOSH_LAYER_SURFACE_PROP_KBD_INTERACTIVITY:
g_value_set_boolean (value, priv->kbd_interactivity);
break;
case PHOSH_LAYER_SURFACE_PROP_EXCLUSIVE_ZONE:
g_value_set_boolean (value, priv->exclusive_zone);
break;
case PHOSH_LAYER_SURFACE_PROP_LAYER_WIDTH:
g_value_set_uint (value, priv->width);
break;
case PHOSH_LAYER_SURFACE_PROP_LAYER_HEIGHT:
g_value_set_uint (value, priv->height);
break;
case PHOSH_LAYER_SURFACE_PROP_NAMESPACE:
g_value_set_string (value, priv->namespace);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
phosh_layer_surface_constructed (GObject *object)
{
PhoshLayerSurface *self = PHOSH_LAYER_SURFACE (object);
PhoshLayerSurfacePrivate *priv = phosh_layer_surface_get_instance_private (self);
GdkWindow *gdk_window;
G_OBJECT_CLASS (phosh_layer_surface_parent_class)->constructed (object);
gtk_window_set_decorated (GTK_WINDOW (self), FALSE);
/* Realize the window so we can get the GDK window */
gtk_widget_realize(GTK_WIDGET (self));
gdk_window = gtk_widget_get_window (GTK_WIDGET (self));
gdk_wayland_window_set_use_custom_surface (gdk_window);
priv->wl_surface = gdk_wayland_window_get_wl_surface (gdk_window);
priv->layer_surface = zwlr_layer_shell_v1_get_layer_surface(priv->layer_shell,
priv->wl_surface,
priv->wl_output,
priv->layer,
priv->namespace);
zwlr_layer_surface_v1_set_exclusive_zone(priv->layer_surface, priv->exclusive_zone);
zwlr_layer_surface_v1_set_size(priv->layer_surface, priv->width, priv->height);
zwlr_layer_surface_v1_set_anchor(priv->layer_surface, priv->anchor);
zwlr_layer_surface_v1_set_keyboard_interactivity(priv->layer_surface, priv->kbd_interactivity);
zwlr_layer_surface_v1_add_listener(priv->layer_surface,
&layer_surface_listener,
self);
wl_surface_commit(priv->wl_surface);
}
static void
phosh_layer_surface_dispose (GObject *object)
{
PhoshLayerSurface *self = PHOSH_LAYER_SURFACE (object);
PhoshLayerSurfacePrivate *priv = phosh_layer_surface_get_instance_private (self);
if (priv->layer_surface) {
zwlr_layer_surface_v1_destroy(priv->layer_surface);
priv->layer_surface = NULL;
}
g_clear_pointer (&priv->namespace, g_free);
G_OBJECT_CLASS (phosh_layer_surface_parent_class)->dispose (object);
}
static void
phosh_layer_surface_class_init (PhoshLayerSurfaceClass *klass)
{
GObjectClass *object_class = (GObjectClass *)klass;
object_class->constructed = phosh_layer_surface_constructed;
object_class->dispose = phosh_layer_surface_dispose;
object_class->set_property = phosh_layer_surface_set_property;
object_class->get_property = phosh_layer_surface_get_property;
props[PHOSH_LAYER_SURFACE_PROP_LAYER_SHELL] =
g_param_spec_pointer (
"layer-shell",
"Wayland Layer Shell Global",
"The layer shell wayland global",
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
props[PHOSH_LAYER_SURFACE_PROP_WL_OUTPUT] =
g_param_spec_pointer (
"wl-output",
"Wayland Output",
"The wl_output associated with this surface",
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
props[PHOSH_LAYER_SURFACE_PROP_ANCHOR] =
g_param_spec_uint (
"anchor",
"Anchor edges",
"The edges to anchor the surface to",
0,
G_MAXUINT,
0,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
props[PHOSH_LAYER_SURFACE_PROP_LAYER] =
g_param_spec_uint (
"layer",
"Layer",
"The layer the surface should be attached to",
0,
G_MAXUINT,
0,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
props[PHOSH_LAYER_SURFACE_PROP_KBD_INTERACTIVITY] =
g_param_spec_boolean (
"kbd-interactivity",
"Keyboard interactivity",
"Whether the surface interacts with the keyboard",
FALSE,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
props[PHOSH_LAYER_SURFACE_PROP_EXCLUSIVE_ZONE] =
g_param_spec_int (
"exclusive-zone",
"Exclusive Zone",
"Set area that is not occluded with other surfaces",
-1,
G_MAXINT,
0,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
props[PHOSH_LAYER_SURFACE_PROP_LAYER_WIDTH] =
g_param_spec_uint (
"width",
"Width",
"The width of the layer surface",
0,
G_MAXUINT,
0,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
props[PHOSH_LAYER_SURFACE_PROP_LAYER_HEIGHT] =
g_param_spec_uint (
"height",
"Height",
"The height of the layer surface",
0,
G_MAXUINT,
0,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
props[PHOSH_LAYER_SURFACE_PROP_NAMESPACE] =
g_param_spec_string (
"namespace",
"Namespace",
"Namespace of the layer surface",
"",
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, PHOSH_LAYER_SURFACE_PROP_LAST_PROP, props);
/**
* PhoshLayersurface::configured
* @self: The #PhoshLayersurface instance.
*
* This signal is emitted once we received the configure event from the
* compositor.
*/
signals[CONFIGURED] =
g_signal_new ("configured",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (PhoshLayerSurfaceClass, configured),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
}
static void
phosh_layer_surface_init (PhoshLayerSurface *self)
{
}
GtkWidget *
phosh_layer_surface_new (gpointer layer_shell,
gpointer wl_output)
{
return g_object_new (PHOSH_TYPE_LAYER_SURFACE,
"layer-shell", layer_shell,
"wl-output", wl_output);
}
struct zwlr_layer_surface_v1 *
phosh_layer_surface_get_layer_surface(PhoshLayerSurface *self)
{
PhoshLayerSurfacePrivate *priv;
g_return_val_if_fail (PHOSH_IS_LAYER_SURFACE (self), NULL);
priv = phosh_layer_surface_get_instance_private (self);
return priv->layer_surface;
}
struct wl_surface *
phosh_layer_surface_get_wl_surface(PhoshLayerSurface *self)
{
PhoshLayerSurfacePrivate *priv;
g_return_val_if_fail (PHOSH_IS_LAYER_SURFACE (self), NULL);
priv = phosh_layer_surface_get_instance_private (self);
return priv->wl_surface;
}

41
eek/layersurface.h Normal file
View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2018 Purism SPC
*
* SPDX-License-Identifier: GPL-3.0+
*/
/*
WARNING: this file is taken directly from phosh, with no modificaions apart from this message. Please update phosh instead of changing this file. Please copy the file back here afterwards, with the same notice.
*/
#pragma once
#include <gtk/gtk.h>
/* TODO: We use the enum constants from here, use glib-mkenums */
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
#define PHOSH_TYPE_LAYER_SURFACE (phosh_layer_surface_get_type ())
G_DECLARE_DERIVABLE_TYPE (PhoshLayerSurface, phosh_layer_surface, PHOSH, LAYER_SURFACE, GtkWindow)
/**
* PhoshLayerSurfaceClass
* @parent_class: The parent class
*/
struct _PhoshLayerSurfaceClass
{
GtkWindowClass parent_class;
/* Signals
*/
void (*configured) (PhoshLayerSurface *self);
};
GtkWidget *phosh_layer_surface_new (gpointer layer_shell,
gpointer wl_output);
struct zwlr_layer_surface_v1 *phosh_layer_surface_get_layer_surface(PhoshLayerSurface *self);
struct wl_surface *phosh_layer_surface_get_wl_surface(PhoshLayerSurface *self);

44
eek/meson.build Normal file
View File

@ -0,0 +1,44 @@
gnome = import('gnome')
enum_headers = [
'eek-symbol.h',
'eek-types.h',
]
enums = gnome.mkenums_simple('eek-enumtypes', sources: enum_headers)
marshalers = gnome.genmarshal(
'eek-marshalers',
sources: ['eek-marshalers.list'],
prefix: '_eek_marshal',
internal: true,
)
python = find_program('python3')
gen_keysym_entries_special = generator(
python,
arguments: ['@CURRENT_SOURCE_DIR@/gen-keysym-entries.py', 'special_keysym_entries', '@INPUT@'],
capture: true,
output: 'eek-@BASENAME@.h',
)
gen_keysym_entries_unicode = generator(
python,
arguments: ['@CURRENT_SOURCE_DIR@/gen-keysym-entries.py', 'unicode_keysym_entries', '@INPUT@'],
capture: true,
output: 'eek-@BASENAME@.h',
)
gen_keysym_entries_xkeysym = generator(
python,
arguments: ['@CURRENT_SOURCE_DIR@/gen-keysym-entries.py', 'xkeysym_keysym_entries', '@INPUT@'],
capture: true,
output: 'eek-@BASENAME@.h',
)
keysym_entries = [
gen_keysym_entries_special.process('./special-keysym-entries.txt'),
gen_keysym_entries_unicode.process('./unicode-keysym-entries.txt'),
gen_keysym_entries_xkeysym.process('./xkeysym-keysym-entries.txt'),
]

View File

@ -16,55 +16,69 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA # 02110-1301 USA
NULL =
lib_LTLIBRARIES = libeekboard.la lib_LTLIBRARIES = libeekboard.la
libeekboard_headers = \ libeekboard_headers = \
eekboard-service.h \ $(srcdir)/eekboard-service.h \
eekboard-context-service.h \ $(srcdir)/eekboard-context-service.h \
eekboard-client.h \ $(srcdir)/eekboard-client.h \
eekboard-context.h \ $(srcdir)/eekboard-context.h \
eekboard-xklutil.h $(srcdir)/eekboard-xklutil.h \
$(NULL)
libeekboard_private_headers = \ libeekboard_private_headers = \
eekboard-marshalers.h $(builddir)/eekboard-marshalers.h \
$(NULL)
libeekboard_sources = \ libeekboard_sources = \
eekboard-service.c \ $(srcdir)/eekboard-service.c \
eekboard-context-service.c \ $(srcdir)/eekboard-context-service.c \
eekboard-client.c \ $(srcdir)/eekboard-client.c \
eekboard-context.c \ $(srcdir)/eekboard-context.c \
eekboard-xklutil.c $(srcdir)/eekboard-xklutil.c \
$(NULL)
libeekboard_marshalers_sources = \ libeekboard_marshalers_sources = \
eekboard-marshalers.c \ $(builddir)/eekboard-marshalers.c \
eekboard-marshalers.h $(builddir)/eekboard-marshalers.h \
$(NULL)
BUILT_SOURCES = \ BUILT_SOURCES = \
$(libeekboard_marshalers_sources) $(libeekboard_marshalers_sources) \
$(NULL)
libeekboard_la_SOURCES = \ libeekboard_la_SOURCES = \
$(libeekboard_sources) \ $(libeekboard_sources) \
eekboard-marshalers.c $(builddir)/eekboard-marshalers.c \
$(NULL)
libeekboard_la_CFLAGS = \ libeekboard_la_CFLAGS = \
-DEEKBOARD_COMPILATION=1 \ -DEEKBOARD_COMPILATION=1 \
-DKEYBOARDDIR=\"$(pkgdatadir)/keyboards\" \ -DKEYBOARDDIR=\"$(pkgdatadir)/keyboards\" \
-I$(top_srcdir) \ -I$(top_srcdir) \
$(GIO2_CFLAGS) \ $(GIO2_CFLAGS) \
$(LIBXKLAVIER_CFLAGS) $(LIBXKLAVIER_CFLAGS) \
$(NULL)
libeekboard_la_LIBADD = \ libeekboard_la_LIBADD = \
$(top_builddir)/eek/libeek.la \ $(top_builddir)/eek/libeek.la \
$(top_builddir)/eek/libeek-xkl.la \ $(top_builddir)/eek/libeek-xkl.la \
$(GIO2_LIBS) \ $(GIO2_LIBS) \
$(LIBXKLAVIER_LIBS) $(LIBXKLAVIER_LIBS) \
$(NULL)
eekboarddir = $(includedir)/eekboard-$(EEK_API_VERSION)/eekboard eekboarddir = $(includedir)/eekboard-$(EEK_API_VERSION)/eekboard
eekboard_HEADERS = $(libeekboard_headers) eekboard_HEADERS = $(libeekboard_headers)
pkgconfigdir = $(libdir)/pkgconfig pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = \ pkgconfig_DATA = \
eekboard-$(EEK_API_VERSION).pc eekboard-$(EEK_API_VERSION).pc \
$(NULL)
DISTCLEANFILES = \ DISTCLEANFILES = \
$(BUILT_SOURCES) \ $(BUILT_SOURCES) \
$(pkgconfig_DATA) $(pkgconfig_DATA) \
$(NULL)
CLEANFILES = CLEANFILES =
@ -72,22 +86,37 @@ EXTRA_DIST = eekboard-marshalers.list
# gen marshal # gen marshal
eekboard-marshalers.h: eekboard-marshalers.list eekboard-marshalers.h: eekboard-marshalers.list
$(AM_V_GEN) $(GLIB_GENMARSHAL) --prefix=_eekboard_marshal $(srcdir)/eekboard-marshalers.list --header --internal > $@.tmp && \ $(AM_V_GEN) $(GLIB_GENMARSHAL) \
--prefix=_eekboard_marshal \
$(srcdir)/eekboard-marshalers.list --header --internal \
> $@.tmp && \
mv $@.tmp $@ mv $@.tmp $@
eekboard-marshalers.c: eekboard-marshalers.list eekboard-marshalers.h eekboard-marshalers.c: eekboard-marshalers.list eekboard-marshalers.h
$(AM_V_GEN) (echo "#include \"eekboard-marshalers.h\""; \ $(AM_V_GEN) (echo "#include \"eekboard-marshalers.h\""; \
$(GLIB_GENMARSHAL) --prefix=_eekboard_marshal $(srcdir)/eekboard-marshalers.list --body --internal) > $@.tmp && \ $(GLIB_GENMARSHAL) \
--prefix=_eekboard_marshal \
$(srcdir)/eekboard-marshalers.list --body --internal) \
> $@.tmp && \
mv $@.tmp $@ mv $@.tmp $@
-include $(INTROSPECTION_MAKEFILE) -include $(INTROSPECTION_MAKEFILE)
INTROSPECTION_GIRS = INTROSPECTION_GIRS =
INTROSPECTION_SCANNER_ARGS = --add-include-path=$(builddir) --add-include-path=$(top_builddir)/eek INTROSPECTION_SCANNER_ARGS = \
INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir) --includedir=$(top_srcdir)/eek --add-include-path=$(builddir) \
--add-include-path=$(top_builddir)/eek \
$(NULL)
INTROSPECTION_COMPILER_ARGS = \
--includedir=$(builddir) \
--includedir=$(top_builddir)/eek \
$(NULL)
if HAVE_INTROSPECTION if HAVE_INTROSPECTION
Eekboard@EEK_LIBRARY_SUFFIX@.gir: libeekboard.la Eekboard@EEK_LIBRARY_SUFFIX@.gir: libeekboard.la
Eekboard@EEK_LIBRARY_SUFFIX_U@_gir_SCANNERFLAGS = --strip-prefix=Eekboard Eekboard@EEK_LIBRARY_SUFFIX_U@_gir_SCANNERFLAGS = \
--identifier-prefix=Eekboard \
--symbol-prefix=eekboard \
$(NULL)
Eekboard@EEK_LIBRARY_SUFFIX_U@_gir_INCLUDES = Eek@EEK_LIBRARY_SUFFIX@ Eekboard@EEK_LIBRARY_SUFFIX_U@_gir_INCLUDES = Eek@EEK_LIBRARY_SUFFIX@
Eekboard@EEK_LIBRARY_SUFFIX_U@_gir_CFLAGS = $(libeekboard_la_CFLAGS) Eekboard@EEK_LIBRARY_SUFFIX_U@_gir_CFLAGS = $(libeekboard_la_CFLAGS)
Eekboard@EEK_LIBRARY_SUFFIX_U@_gir_LIBS = libeekboard.la Eekboard@EEK_LIBRARY_SUFFIX_U@_gir_LIBS = libeekboard.la
@ -103,3 +132,5 @@ typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
CLEANFILES += $(gir_DATA) $(typelib_DATA) CLEANFILES += $(gir_DATA) $(typelib_DATA)
endif endif
-include $(top_srcdir)/git.mk

View File

@ -325,6 +325,38 @@ eekboard_client_pop_context (EekboardClient *client,
NULL); NULL);
} }
void
eekboard_client_show_keyboard (EekboardClient *client,
GCancellable *cancellable)
{
g_return_if_fail (EEKBOARD_IS_CLIENT(client));
g_dbus_proxy_call (G_DBUS_PROXY(client),
"ShowKeyboard",
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
cancellable,
eekboard_async_ready_callback,
NULL);
}
void
eekboard_client_hide_keyboard (EekboardClient *client,
GCancellable *cancellable)
{
g_return_if_fail (EEKBOARD_IS_CLIENT(client));
g_dbus_proxy_call (G_DBUS_PROXY(client),
"HideKeyboard",
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
cancellable,
eekboard_async_ready_callback,
NULL);
}
static void static void
send_destroy_context (EekboardClient *client, send_destroy_context (EekboardClient *client,
EekboardContext *context, EekboardContext *context,

View File

@ -67,6 +67,10 @@ void eekboard_client_push_context (EekboardClient *eekboard,
GCancellable *cancellable); GCancellable *cancellable);
void eekboard_client_pop_context (EekboardClient *eekboard, void eekboard_client_pop_context (EekboardClient *eekboard,
GCancellable *cancellable); GCancellable *cancellable);
void eekboard_client_show_keyboard (EekboardClient *eekboard,
GCancellable *cancellable);
void eekboard_client_hide_keyboard (EekboardClient *eekboard,
GCancellable *cancellable);
void eekboard_client_destroy_context (EekboardClient *eekboard, void eekboard_client_destroy_context (EekboardClient *eekboard,
EekboardContext *context, EekboardContext *context,
GCancellable *cancellable); GCancellable *cancellable);

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,8 @@
#include <eek/eek.h> #include <eek/eek.h>
#include "virtual-keyboard-unstable-v1-client-protocol.h"
G_BEGIN_DECLS G_BEGIN_DECLS
#define EEKBOARD_CONTEXT_SERVICE_PATH "/org/fedorahosted/Eekboard/Context_%d" #define EEKBOARD_CONTEXT_SERVICE_PATH "/org/fedorahosted/Eekboard/Context_%d"
@ -36,13 +38,16 @@ G_BEGIN_DECLS
#define EEKBOARD_IS_CONTEXT_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEKBOARD_TYPE_CONTEXT_SERVICE)) #define EEKBOARD_IS_CONTEXT_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEKBOARD_TYPE_CONTEXT_SERVICE))
#define EEKBOARD_CONTEXT_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEKBOARD_TYPE_CONTEXT_SERVICE, EekboardContextServiceClass)) #define EEKBOARD_CONTEXT_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEKBOARD_TYPE_CONTEXT_SERVICE, EekboardContextServiceClass))
typedef struct _EekboardContextService EekboardContextService;
typedef struct _EekboardContextServiceClass EekboardContextServiceClass; typedef struct _EekboardContextServiceClass EekboardContextServiceClass;
typedef struct _EekboardContextServicePrivate EekboardContextServicePrivate; typedef struct _EekboardContextServicePrivate EekboardContextServicePrivate;
/** /**
* EekboardContextService: * EekboardContextService:
* *
* TODO: Restrict to managing keyboard layouts, and maybe button repeats,
* and the virtual keyboard protocol.
*
* The #EekboardContextService structure contains only private data * The #EekboardContextService structure contains only private data
* and should only be accessed using the provided API. * and should only be accessed using the provided API.
*/ */
@ -50,6 +55,8 @@ struct _EekboardContextService {
GObject parent; GObject parent;
EekboardContextServicePrivate *priv; EekboardContextServicePrivate *priv;
struct zwp_virtual_keyboard_v1 *virtual_keyboard;
}; };
/** /**
@ -84,13 +91,18 @@ GType eekboard_context_service_get_type
(void) G_GNUC_CONST; (void) G_GNUC_CONST;
void eekboard_context_service_enable (EekboardContextService *context); void eekboard_context_service_enable (EekboardContextService *context);
void eekboard_context_service_disable (EekboardContextService *context); void eekboard_context_service_disable (EekboardContextService *context);
void eekboard_context_service_show_keyboard
(EekboardContextService *context);
void eekboard_context_service_hide_keyboard
(EekboardContextService *context);
void eekboard_context_service_destroy (EekboardContextService *context); void eekboard_context_service_destroy (EekboardContextService *context);
EekKeyboard *eekboard_context_service_get_keyboard EekKeyboard *eekboard_context_service_get_keyboard
(EekboardContextService *context); (EekboardContextService *context);
gboolean eekboard_context_service_get_fullscreen gboolean eekboard_context_service_get_fullscreen
(EekboardContextService *context); (EekboardContextService *context);
const gchar * eekboard_context_service_get_client_name
(EekboardContextService *context); void eekboard_context_service_set_keymap(EekboardContextService *context,
const EekKeyboard *keyboard);
G_END_DECLS G_END_DECLS
#endif /* EEKBOARD_CONTEXT_SERVICE_H */ #endif /* EEKBOARD_CONTEXT_SERVICE_H */

View File

@ -29,7 +29,7 @@
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include "eekboard/eekboard-context.h" #include "eekboard/eekboard-context.h"
#include "eekboard/eekboard-marshalers.h" //#include "eekboard/eekboard-marshalers.h"
#define I_(string) g_intern_static_string (string) #define I_(string) g_intern_static_string (string)
@ -151,7 +151,7 @@ eekboard_context_real_destroyed (EekboardContext *self)
static void static void
eekboard_context_real_key_activated (EekboardContext *self, eekboard_context_real_key_activated (EekboardContext *self,
const gchar *keyname, guint keycode,
EekSymbol *symbol, EekSymbol *symbol,
guint modifiers) guint modifiers)
{ {
@ -251,6 +251,7 @@ eekboard_context_class_init (EekboardContextClass *klass)
* The ::key-activated signal is emitted each time a key is * The ::key-activated signal is emitted each time a key is
* pressed in @context. * pressed in @context.
*/ */
/*
signals[KEY_ACTIVATED] = signals[KEY_ACTIVATED] =
g_signal_new (I_("key-activated"), g_signal_new (I_("key-activated"),
G_TYPE_FROM_CLASS(gobject_class), G_TYPE_FROM_CLASS(gobject_class),
@ -264,7 +265,7 @@ eekboard_context_class_init (EekboardContextClass *klass)
G_TYPE_UINT, G_TYPE_UINT,
G_TYPE_OBJECT, G_TYPE_OBJECT,
G_TYPE_UINT); G_TYPE_UINT);
*/
/** /**
* EekboardContext::destroyed: * EekboardContext::destroyed:
* @context: an #EekboardContext * @context: an #EekboardContext

View File

@ -1 +0,0 @@
VOID:UINT,OBJECT,UINT

View File

@ -1,7 +1,7 @@
/* /*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org> * Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc. * Copyright (C) 2010-2011 Red Hat, Inc.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
@ -18,7 +18,9 @@
/** /**
* SECTION:eekboard-service * SECTION:eekboard-service
* @short_description: base server implementation of eekboard service * @short_description: base implementation of eekboard service
*
* Provides a dbus object, and contains the context.
* *
* The #EekboardService class provides a base server side * The #EekboardService class provides a base server side
* implementation of eekboard service. * implementation of eekboard service.
@ -30,6 +32,10 @@
#include "eekboard/eekboard-service.h" #include "eekboard/eekboard-service.h"
#include "sm.puri.OSK0.h"
#include <stdio.h>
enum { enum {
PROP_0, PROP_0,
PROP_OBJECT_PATH, PROP_OBJECT_PATH,
@ -49,48 +55,16 @@ static guint signals[LAST_SIGNAL] = { 0, };
struct _EekboardServicePrivate { struct _EekboardServicePrivate {
GDBusConnection *connection; GDBusConnection *connection;
SmPuriOSK0 *dbus_interface;
GDBusNodeInfo *introspection_data; GDBusNodeInfo *introspection_data;
guint registration_id; guint registration_id;
char *object_path; char *object_path;
GHashTable *context_hash; EekboardContextService *context; // unowned reference
GSList *context_stack;
}; };
G_DEFINE_TYPE (EekboardService, eekboard_service, G_TYPE_OBJECT); G_DEFINE_TYPE (EekboardService, eekboard_service, G_TYPE_OBJECT);
static const gchar introspection_xml[] =
"<node>"
" <interface name='org.fedorahosted.Eekboard'>"
" <method name='CreateContext'>"
" <arg direction='in' type='s' name='client_name'/>"
" <arg direction='out' type='s' name='object_path'/>"
" </method>"
" <method name='PushContext'>"
" <arg direction='in' type='s' name='object_path'/>"
" </method>"
" <method name='PopContext'/>"
" <method name='Destroy'/>"
/* signals */
" </interface>"
"</node>";
static void handle_method_call (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *method_name,
GVariant *parameters,
GDBusMethodInvocation *invocation,
gpointer user_data);
static const GDBusInterfaceVTable interface_vtable =
{
handle_method_call,
NULL,
NULL
};
static void static void
eekboard_service_set_property (GObject *object, eekboard_service_set_property (GObject *object,
guint prop_id, guint prop_id,
@ -143,19 +117,6 @@ static void
eekboard_service_dispose (GObject *object) eekboard_service_dispose (GObject *object)
{ {
EekboardService *service = EEKBOARD_SERVICE(object); EekboardService *service = EEKBOARD_SERVICE(object);
GSList *head;
if (service->priv->context_hash) {
g_hash_table_destroy (service->priv->context_hash);
service->priv->context_hash = NULL;
}
for (head = service->priv->context_stack; head; head = service->priv->context_stack) {
g_object_unref (head->data);
service->priv->context_stack = g_slist_next (head);
g_slist_free1 (head);
}
if (service->priv->connection) { if (service->priv->connection) {
if (service->priv->registration_id > 0) { if (service->priv->registration_id > 0) {
g_dbus_connection_unregister_object (service->priv->connection, g_dbus_connection_unregister_object (service->priv->connection,
@ -185,26 +146,40 @@ eekboard_service_finalize (GObject *object)
G_OBJECT_CLASS (eekboard_service_parent_class)->finalize (object); G_OBJECT_CLASS (eekboard_service_parent_class)->finalize (object);
} }
static gboolean
handle_set_visible(SmPuriOSK0 *object, GDBusMethodInvocation *invocation,
gboolean arg_visible, gpointer user_data) {
EekboardService *service = user_data;
if (service->priv->context) {
if (arg_visible) {
eekboard_context_service_show_keyboard (service->priv->context);
} else {
eekboard_context_service_hide_keyboard (service->priv->context);
}
}
sm_puri_osk0_complete_set_visible(object, invocation);
return TRUE;
}
static void static void
eekboard_service_constructed (GObject *object) eekboard_service_constructed (GObject *object)
{ {
EekboardService *service = EEKBOARD_SERVICE(object); EekboardService *service = EEKBOARD_SERVICE(object);
service->priv->dbus_interface = sm_puri_osk0_skeleton_new();
sm_puri_osk0_set_visible(service->priv->dbus_interface, FALSE); // TODO: use actual value
g_signal_connect(service->priv->dbus_interface, "handle-set-visible",
G_CALLBACK(handle_set_visible), service);
if (service->priv->connection && service->priv->object_path) { if (service->priv->connection && service->priv->object_path) {
GError *error = NULL; GError *error = NULL;
service->priv->registration_id = g_dbus_connection_register_object if (!g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(service->priv->dbus_interface),
(service->priv->connection, service->priv->connection,
service->priv->object_path, service->priv->object_path,
service->priv->introspection_data->interfaces[0], &error)) {
&interface_vtable, g_warning("Error registering dbus object: %s\n", error->message);
object, g_clear_error(&error);
NULL,
&error);
if (service->priv->registration_id == 0) {
g_warning ("failed to register context object: %s",
error->message);
g_error_free (error);
} }
} }
} }
@ -275,204 +250,14 @@ eekboard_service_class_init (EekboardServiceClass *klass)
static void static void
eekboard_service_init (EekboardService *self) eekboard_service_init (EekboardService *self)
{ {
GError *error;
self->priv = EEKBOARD_SERVICE_GET_PRIVATE(self); self->priv = EEKBOARD_SERVICE_GET_PRIVATE(self);
self->priv->context = NULL;
error = NULL;
self->priv->introspection_data =
g_dbus_node_info_new_for_xml (introspection_xml, &error);
if (self->priv->introspection_data == NULL) {
g_warning ("failed to parse D-Bus XML: %s", error->message);
g_error_free (error);
g_assert_not_reached ();
}
self->priv->context_hash =
g_hash_table_new_full (g_str_hash,
g_str_equal,
(GDestroyNotify)g_free,
(GDestroyNotify)g_object_unref);
}
static void
remove_context_from_stack (EekboardService *service,
EekboardContextService *context)
{
GSList *head;
head = g_slist_find (service->priv->context_stack, context);
if (head) {
service->priv->context_stack = g_slist_remove_link (service->priv->context_stack, head);
g_object_unref (head->data);
g_slist_free1 (head);
}
if (service->priv->context_stack)
eekboard_context_service_enable (service->priv->context_stack->data);
}
static void
service_name_vanished_callback (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
EekboardService *service = user_data;
GSList *head;
GHashTableIter iter;
gpointer k, v;
g_hash_table_iter_init (&iter, service->priv->context_hash);
while (g_hash_table_iter_next (&iter, &k, &v)) {
const gchar *owner = g_object_get_data (G_OBJECT(v), "owner");
if (g_strcmp0 (owner, name) == 0)
g_hash_table_iter_remove (&iter);
}
for (head = service->priv->context_stack; head; ) {
const gchar *owner = g_object_get_data (G_OBJECT(head->data), "owner");
GSList *next = g_slist_next (head);
if (g_strcmp0 (owner, name) == 0) {
service->priv->context_stack =
g_slist_remove_link (service->priv->context_stack, head);
g_object_unref (head->data);
g_slist_free1 (head);
}
head = next;
}
if (service->priv->context_stack)
eekboard_context_service_enable (service->priv->context_stack->data);
}
static void
context_destroyed_cb (EekboardContextService *context, EekboardService *service)
{
gchar *object_path = NULL;
remove_context_from_stack (service, context);
g_object_get (G_OBJECT(context), "object-path", &object_path, NULL);
g_hash_table_remove (service->priv->context_hash, object_path);
g_free (object_path);
}
static void
handle_method_call (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *method_name,
GVariant *parameters,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
EekboardService *service = user_data;
EekboardServiceClass *klass = EEKBOARD_SERVICE_GET_CLASS(service);
if (g_strcmp0 (method_name, "CreateContext") == 0) {
const gchar *client_name;
gchar *object_path;
static gint context_id = 0;
EekboardContextService *context;
g_variant_get (parameters, "(&s)", &client_name);
object_path = g_strdup_printf (EEKBOARD_CONTEXT_SERVICE_PATH, context_id++);
g_assert (klass->create_context);
context = klass->create_context (service, client_name, object_path);
g_object_set_data_full (G_OBJECT(context),
"owner", g_strdup (sender),
(GDestroyNotify)g_free);
g_hash_table_insert (service->priv->context_hash,
object_path,
context);
/* the vanished callback is called when clients are disconnected */
g_bus_watch_name_on_connection (service->priv->connection,
sender,
G_BUS_NAME_WATCHER_FLAGS_NONE,
NULL,
service_name_vanished_callback,
service,
NULL);
g_signal_connect (G_OBJECT(context), "destroyed",
G_CALLBACK(context_destroyed_cb), service);
g_dbus_method_invocation_return_value (invocation,
g_variant_new ("(s)",
object_path));
return;
}
if (g_strcmp0 (method_name, "PushContext") == 0) {
const gchar *object_path;
EekboardContextService *context;
g_variant_get (parameters, "(&s)", &object_path);
context = g_hash_table_lookup (service->priv->context_hash, object_path);
if (!context) {
g_dbus_method_invocation_return_error (invocation,
G_IO_ERROR,
G_IO_ERROR_FAILED_HANDLED,
"context not found");
return;
}
if (service->priv->context_stack)
eekboard_context_service_disable (service->priv->context_stack->data);
service->priv->context_stack = g_slist_prepend (service->priv->context_stack,
g_object_ref (context));
eekboard_context_service_enable (context);
g_dbus_method_invocation_return_value (invocation, NULL);
return;
}
if (g_strcmp0 (method_name, "PopContext") == 0) {
if (service->priv->context_stack) {
EekboardContextService *context = service->priv->context_stack->data;
gchar *object_path;
const gchar *owner;
g_object_get (G_OBJECT(context), "object-path", &object_path, NULL);
owner = g_object_get_data (G_OBJECT(context), "owner");
if (g_strcmp0 (owner, sender) != 0) {
g_dbus_method_invocation_return_error
(invocation,
G_IO_ERROR,
G_IO_ERROR_FAILED_HANDLED,
"context at %s not owned by %s",
object_path, sender);
return;
}
g_free (object_path);
eekboard_context_service_disable (context);
service->priv->context_stack = g_slist_next (service->priv->context_stack);
if (service->priv->context_stack)
eekboard_context_service_enable (service->priv->context_stack->data);
}
g_dbus_method_invocation_return_value (invocation, NULL);
return;
}
if (g_strcmp0 (method_name, "Destroy") == 0) {
g_signal_emit (service, signals[DESTROYED], 0);
g_dbus_method_invocation_return_value (invocation, NULL);
return;
}
g_return_if_reached ();
} }
/** /**
* eekboard_service_new: * eekboard_service_new:
* @connection: a #GDBusConnection * @connection: a #GDBusConnection
* @object_path: object path * @object_path: object path
*
* Create an empty server for testing purpose.
*/ */
EekboardService * EekboardService *
eekboard_service_new (GDBusConnection *connection, eekboard_service_new (GDBusConnection *connection,
@ -483,3 +268,10 @@ eekboard_service_new (GDBusConnection *connection,
"connection", connection, "connection", connection,
NULL); NULL);
} }
void
eekboard_service_set_context(EekboardService *service,
EekboardContextService *context) {
service->priv->context = context;
}

View File

@ -24,8 +24,8 @@
G_BEGIN_DECLS G_BEGIN_DECLS
#define EEKBOARD_SERVICE_PATH "/org/fedorahosted/Eekboard" #define EEKBOARD_SERVICE_PATH "/sm/puri/OSK0"
#define EEKBOARD_SERVICE_INTERFACE "org.fedorahosted.Eekboard" #define EEKBOARD_SERVICE_INTERFACE "sm.puri.OSK0"
#define EEKBOARD_TYPE_SERVICE (eekboard_service_get_type()) #define EEKBOARD_TYPE_SERVICE (eekboard_service_get_type())
#define EEKBOARD_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEKBOARD_TYPE_SERVICE, EekboardService)) #define EEKBOARD_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEKBOARD_TYPE_SERVICE, EekboardService))
@ -41,6 +41,8 @@ typedef struct _EekboardServicePrivate EekboardServicePrivate;
/** /**
* EekboardService: * EekboardService:
* *
* Manages DBus interaction.
*
* The #EekboardService structure contains only private data and * The #EekboardService structure contains only private data and
* should only be accessed using the provided API. * should only be accessed using the provided API.
*/ */
@ -60,9 +62,7 @@ struct _EekboardServiceClass {
GObjectClass parent_class; GObjectClass parent_class;
/*< public >*/ /*< public >*/
EekboardContextService *(*create_context) (EekboardService *self, EekboardContextService *(*create_context) (EekboardService *self);
const gchar *client_name,
const gchar *object_path);
/*< private >*/ /*< private >*/
/* padding */ /* padding */
@ -72,6 +72,7 @@ struct _EekboardServiceClass {
GType eekboard_service_get_type (void) G_GNUC_CONST; GType eekboard_service_get_type (void) G_GNUC_CONST;
EekboardService * eekboard_service_new (GDBusConnection *connection, EekboardService * eekboard_service_new (GDBusConnection *connection,
const gchar *object_path); const gchar *object_path);
void eekboard_service_set_context(EekboardService *service,
EekboardContextService *context);
G_END_DECLS G_END_DECLS
#endif /* EEKBOARD_SERVICE_H */ #endif /* EEKBOARD_SERVICE_H */

363
eekboard/key-emitter.c Normal file
View File

@ -0,0 +1,363 @@
/*
* Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2011 Red Hat, Inc.
* Copyright (C) 2019 Purism, SPC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* This file is responsible for managing keycode data and emitting keycodes. */
#include "eekboard/key-emitter.h"
#include "eekboard/keymap.h"
#include <gdk/gdk.h>
#include "eekboard/eekboard-context-service.h"
// TODO: decide whether it's this struct that carries the keyboard around in key-emitter or if the whole manager should be dragged around
// if this is the carrier, then it should be made part of the manager
// hint: check which fields need to be persisted between keypresses; which between keyboards
typedef struct {
struct zwp_virtual_keyboard_v1 *virtual_keyboard; // unowned copy
struct xkb_keymap *keymap; // unowned copy
XkbDescRec *xkb;
guint modifier_keycodes[8];
gint group;
} SeatEmitter;
/* The following functions for keyboard mapping change are direct
translation of the code in Caribou (in libcaribou/xadapter.vala):
- get_replaced_keycode (Caribou: get_reserved_keycode)
- replace_keycode
- get_keycode_from_gdk_keymap (Caribou: best_keycode_keyval_match)
*/
/* Find an unused keycode where a keysym can be assigned. Restricted to Level 1 */
static guint
get_replaced_keycode (SeatEmitter *client)
{
guint keycode;
return 0; // FIXME: no xkb allocated yet
for (keycode = client->xkb->max_key_code;
keycode >= client->xkb->min_key_code;
--keycode) {
guint offset = client->xkb->map->key_sym_map[keycode].offset;
if (client->xkb->map->key_sym_map[keycode].kt_index[0] == XkbOneLevelIndex &&
client->xkb->map->syms[offset] != NoSymbol) {
return keycode;
}
}
return 0;
}
/* Replace keysym assigned to KEYCODE to KEYSYM. Both args are used
as in-out. If KEYCODE points to 0, this function picks a keycode
from the current map and replace the associated keysym to KEYSYM.
In that case, the replaced keycode is stored in KEYCODE and the old
keysym is stored in KEYSYM. If otherwise (KEYCODE points to
non-zero keycode), it simply changes the current map with the
specified KEYCODE and KEYSYM. */
static gboolean
replace_keycode (SeatEmitter *emitter,
guint keycode,
guint *keysym)
{
GdkDisplay *display = gdk_display_get_default ();
//Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
guint old_keysym;
int keysyms_per_keycode;
KeySym *syms;
return TRUE; // FIXME: no xkb allocated at the moment, pretending all is fine
g_return_val_if_fail (emitter->xkb->min_key_code <= keycode &&
keycode <= emitter->xkb->max_key_code,
FALSE);
g_return_val_if_fail (keysym != NULL, FALSE);
/*
* Update keyboard mapping. Wayland receives keyboard mapping as a string, so XChangeKeyboardMapping needs to translate from the symbol tbale t the string. TODO.
*
syms = XGetKeyboardMapping (xdisplay, keycode, 1, &keysyms_per_keycode);
old_keysym = syms[0];
syms[0] = *keysym;
XChangeKeyboardMapping (xdisplay, keycode, 1, syms, 1);
XSync (xdisplay, False);
XFree (syms);
*keysym = old_keysym;
*/
return TRUE;
}
static gboolean
get_keycode_from_gdk_keymap (SeatEmitter *emitter,
guint keysym,
guint *keycode,
guint *modifiers)
{
GdkKeymapKey *keys, *best_match = NULL;
guint n_keys, i;
if (!squeek_keymap_get_entries_for_keyval (emitter->keymap, keysym, &keys, &n_keys))
return FALSE;
for (i = 0; i < n_keys; i++)
if (keys[i].group == emitter->group)
best_match = &keys[i];
if (!best_match) {
g_free (keys);
return FALSE;
}
*keycode = best_match->keycode;
*modifiers = best_match->level == 1 ? EEK_SHIFT_MASK : 0;
g_free (keys);
return TRUE;
}
int send_virtual_keyboard_key(
struct zwp_virtual_keyboard_v1 *keyboard,
unsigned int keycode,
unsigned is_press,
uint32_t timestamp
) {
zwp_virtual_keyboard_v1_key(keyboard, timestamp, keycode, (unsigned)is_press);
return 0;
}
static void
send_fake_modifier_key_event (SeatEmitter *emitter,
EekModifierType modifiers,
gboolean is_pressed,
uint32_t timestamp)
{
unsigned long i;
for (i = 0; i < G_N_ELEMENTS(emitter->modifier_keycodes); i++) {
if (modifiers & (1 << i)) {
guint keycode = emitter->modifier_keycodes[i];
printf("Trying to send a modifier %ld press %d\n", i, is_pressed);
g_return_if_fail (keycode > 0);
send_virtual_keyboard_key (emitter->virtual_keyboard,
keycode,
is_pressed,
timestamp);
}
}
}
static void
send_fake_key_event (SeatEmitter *emitter,
guint xkeysym,
guint keyboard_modifiers,
gboolean pressed,
uint32_t timestamp)
{
EekModifierType modifiers;
guint old_keysym = xkeysym;
g_return_if_fail (xkeysym > 0);
guint keycode;
if (!get_keycode_from_gdk_keymap (emitter, xkeysym, &keycode, &modifiers)) {
keycode = get_replaced_keycode (emitter);
if (keycode == 0) {
g_warning ("no available keycode to replace");
return;
}
if (!replace_keycode (emitter, keycode, &old_keysym)) {
g_warning ("failed to lookup X keysym %X", xkeysym);
return;
}
}
/* Clear level shift modifiers */
keyboard_modifiers &= (unsigned)~EEK_SHIFT_MASK;
keyboard_modifiers &= (unsigned)~EEK_LOCK_MASK;
/* FIXME: may need to remap ISO_Level3_Shift and NumLock */
#if 0
keyboard_modifiers &= ~EEK_MOD5_MASK;
keyboard_modifiers &= ~client->alt_gr_mask;
keyboard_modifiers &= ~client->num_lock_mask;
#endif
modifiers |= keyboard_modifiers;
send_fake_modifier_key_event (emitter, modifiers, TRUE, timestamp);
// There's something magical about subtracting/adding 8 to keycodes for some reason
send_virtual_keyboard_key (emitter->virtual_keyboard, keycode - 8, (unsigned)pressed, timestamp);
send_fake_modifier_key_event (emitter, modifiers, FALSE, timestamp);
if (old_keysym != xkeysym)
replace_keycode (emitter, keycode, &old_keysym);
}
static void
send_fake_key_events (SeatEmitter *emitter,
EekSymbol *symbol,
guint keyboard_modifiers,
gboolean pressed,
uint32_t timestamp)
{
/* Ignore modifier keys */
if (eek_symbol_is_modifier (symbol))
return;
/* If symbol is a text, convert chars in it to keysym */
if (EEK_IS_TEXT(symbol)) {
const gchar *utf8 = eek_text_get_text (EEK_TEXT(symbol));
printf("Attempting to send text %s\n", utf8);
/* FIXME:
glong items_written;
gunichar *ucs4 = g_utf8_to_ucs4_fast (utf8, -1, &items_written);
gint i;
for (i = 0; i < items_written; i++) {
guint xkeysym;
EekKeysym *keysym;
gchar *name;
name = g_strdup_printf ("U%04X", ucs4[i]);
xkeysym = XStringToKeysym (name); // TODO: use xkb_get_keysym_from_name
g_free (name);
keysym = eek_keysym_new (xkeysym);
send_fake_key_events (client,
EEK_SYMBOL(keysym),
keyboard_modifiers);
}
g_free (ucs4);
*/
return;
}
if (EEK_IS_KEYSYM(symbol)) {
guint xkeysym = eek_keysym_get_xkeysym (EEK_KEYSYM(symbol));
send_fake_key_event (emitter, xkeysym, keyboard_modifiers, pressed, timestamp);
}
}
void
emit_key_activated (EekboardContextService *manager,
EekKeyboard *keyboard,
guint keycode,
EekSymbol *symbol,
guint modifiers,
gboolean pressed,
uint32_t timestamp)
{
/* FIXME: figure out how to deal with Client after key presses go through
if (g_strcmp0 (eek_symbol_get_name (symbol), "cycle-keyboard") == 0) {
client->keyboards_head = g_slist_next (client->keyboards_head);
if (client->keyboards_head == NULL)
client->keyboards_head = client->keyboards;
eekboard_context_set_keyboard (client->context,
GPOINTER_TO_UINT(client->keyboards_head->data),
NULL);
return;
}
if (g_strcmp0 (eek_symbol_get_name (symbol), "preferences") == 0) {
gchar *argv[2];
GError *error;
argv[0] = g_build_filename (LIBEXECDIR, "eekboard-setup", NULL);
argv[1] = NULL;
error = NULL;
if (!g_spawn_async (NULL, argv, NULL, 0, NULL, NULL, NULL, &error)) {
g_warning ("can't spawn %s: %s", argv[0], error->message);
g_error_free (error);
}
g_free (argv[0]);
return;
}
*/
SeatEmitter emitter = {0};
emitter.virtual_keyboard = manager->virtual_keyboard;
emitter.keymap = keyboard->keymap;
send_fake_key_events (&emitter, symbol, modifiers, pressed, timestamp);
}
/* Finds the first key code for each modifier and saves it in modifier_keycodes */
static void
update_modifier_keycodes (SeatEmitter *client)
{
GdkDisplay *display = gdk_display_get_default ();
Display *xdisplay = NULL; // GDK_DISPLAY_XDISPLAY (display);
return; // FIXME: need to get those codes somehow
XModifierKeymap *mods;
gint i, j;
//mods = XGetModifierMapping (xdisplay);
for (i = 0; i < 8; i++) {
client->modifier_keycodes[i] = 0;
for (j = 0; j < mods->max_keypermod; j++) {
KeyCode keycode = mods->modifiermap[mods->max_keypermod * i + j];
if (keycode != 0) {
client->modifier_keycodes[i] = keycode;
break;
}
}
}
//XFreeModifiermap (mods);
}
gboolean
client_enable_xtest (SeatEmitter *client)
{
//GdkDisplay *display = gdk_display_get_default ();
//Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
int opcode, event_base, error_base, major_version, minor_version;
/* FIXME: need at least to fetch an xkb keymap (but what for?)
g_assert (display);
if (!XTestQueryExtension (xdisplay,
&event_base, &error_base,
&major_version, &minor_version)) {
g_warning ("XTest extension is not available");
return FALSE;
}
if (!XkbQueryExtension (xdisplay,
&opcode, &event_base, &error_base,
&major_version, &minor_version)) {
g_warning ("Xkb extension is not available");
return FALSE;
}
if (!client->xkb)
client->xkb = XkbGetMap (xdisplay, XkbKeySymsMask, XkbUseCoreKbd);
g_assert (client->xkb);
*/
update_modifier_keycodes (client);
return TRUE;
}
void
client_disable_xtest (SeatEmitter *client)
{
//if (client->xkb) {
// XkbFreeKeyboard (client->xkb, 0, TRUE); /* free_all = TRUE */
//client->xkb = NULL;
//}
}
//#endif /* HAVE_XTEST */

18
eekboard/key-emitter.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef KEYEMITTER_H
#define KEYEMITTER_H
#include <inttypes.h>
#include <glib.h>
#include <X11/XKBlib.h>
#include "eek/eek.h"
#include "virtual-keyboard-unstable-v1-client-protocol.h"
void
emit_key_activated (EekboardContextService *manager, EekKeyboard *keyboard,
guint keycode,
EekSymbol *symbol,
guint modifiers,
gboolean pressed, uint32_t timestamp);
#endif // KEYEMITTER_H

66
eekboard/keymap.c Normal file
View File

@ -0,0 +1,66 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2000 Red Hat, Inc.
* Copyright (C) 2019 Purism, SPC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Modified for squeekboard based on GTK
*/
#include "keymap.h"
gboolean
squeek_keymap_get_entries_for_keyval (struct xkb_keymap *xkb_keymap,
guint keyval,
GdkKeymapKey **keys,
guint *n_keys)
{
GArray *retval;
guint keycode;
xkb_keycode_t min_keycode, max_keycode;
retval = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
min_keycode = xkb_keymap_min_keycode (xkb_keymap);
max_keycode = xkb_keymap_max_keycode (xkb_keymap);
for (keycode = min_keycode; keycode < max_keycode; keycode++)
{
xkb_layout_index_t num_layouts, layout;
num_layouts = xkb_keymap_num_layouts_for_key (xkb_keymap, keycode);
for (layout = 0; layout < num_layouts; layout++)
{
xkb_layout_index_t num_levels, level;
num_levels = xkb_keymap_num_levels_for_key (xkb_keymap, keycode, layout);
for (level = 0; level < num_levels; level++)
{
const xkb_keysym_t *syms;
gint num_syms, sym;
num_syms = xkb_keymap_key_get_syms_by_level (xkb_keymap, keycode, layout, level, &syms);
for (sym = 0; sym < num_syms; sym++)
{
if (syms[sym] == keyval)
{
GdkKeymapKey key;
key.keycode = keycode;
key.group = (gint)layout;
key.level = (gint)level;
g_array_append_val (retval, key);
}
}
}
}
}
*n_keys = retval->len;
*keys = (GdkKeymapKey*) g_array_free (retval, FALSE);
return TRUE;
}

8
eekboard/keymap.h Normal file
View File

@ -0,0 +1,8 @@
#include <gdk/gdk.h>
#include <xkbcommon/xkbcommon.h>
gboolean
squeek_keymap_get_entries_for_keyval (struct xkb_keymap *xkb_keymap,
guint keyval,
GdkKeymapKey **keys,
guint *n_keys);

View File

@ -1 +1,3 @@
SUBDIRS = simple-client SUBDIRS = simple-client
-include $(top_srcdir)/git.mk

View File

@ -1 +1,3 @@
EXTRA_DIST = simple-client EXTRA_DIST = simple-client
-include $(top_srcdir)/git.mk

218
git.mk Normal file
View File

@ -0,0 +1,218 @@
# git.mk
#
# Copyright 2009, Red Hat, Inc.
# Copyright 2010,2011 Behdad Esfahbod
# Written by Behdad Esfahbod
#
# Copying and distribution of this file, with or without modification,
# is permitted in any medium without royalty provided the copyright
# notice and this notice are preserved.
#
# The canonical source for this file is https://github.com/behdad/git.mk.
#
# To use in your project, import this file in your git repo's toplevel,
# then do "make -f git.mk". This modifies all Makefile.am files in
# your project to -include git.mk. Remember to add that line to new
# Makefile.am files you create in your project, or just rerun the
# "make -f git.mk".
#
# This enables automatic .gitignore generation. If you need to ignore
# more files, add them to the GITIGNOREFILES variable in your Makefile.am.
# But think twice before doing that. If a file has to be in .gitignore,
# chances are very high that it's a generated file and should be in one
# of MOSTLYCLEANFILES, CLEANFILES, DISTCLEANFILES, or MAINTAINERCLEANFILES.
#
# The only case that you need to manually add a file to GITIGNOREFILES is
# when remove files in one of mostlyclean-local, clean-local, distclean-local,
# or maintainer-clean-local make targets.
#
# Note that for files like editor backup, etc, there are better places to
# ignore them. See "man gitignore".
#
# If "make maintainer-clean" removes the files but they are not recognized
# by this script (that is, if "git status" shows untracked files still), send
# me the output of "git status" as well as your Makefile.am and Makefile for
# the directories involved and I'll diagnose.
#
# For a list of toplevel files that should be in MAINTAINERCLEANFILES, see
# Makefile.am.sample in the git.mk git repo.
#
# Don't EXTRA_DIST this file. It is supposed to only live in git clones,
# not tarballs. It serves no useful purpose in tarballs and clutters the
# build dir.
#
# This file knows how to handle autoconf, automake, libtool, gtk-doc,
# gnome-doc-utils, yelp.m4, mallard, intltool, gsettings, dejagnu.
#
#
# KNOWN ISSUES:
#
# - Recursive configure doesn't work as $(top_srcdir)/git.mk inside the
# submodule doesn't find us. If you have configure.{in,ac} files in
# subdirs, add a proxy git.mk file in those dirs that simply does:
# "include $(top_srcdir)/../git.mk". Add more ..'s to your taste.
# And add those files to git. See vte/gnome-pty-helper/git.mk for
# example.
#
git-all: git-mk-install
git-mk-install:
@echo Installing git makefile
@any_failed=; \
find "`test -z "$(top_srcdir)" && echo . || echo "$(top_srcdir)"`" -name Makefile.am | while read x; do \
if grep 'include .*/git.mk' $$x >/dev/null; then \
echo $$x already includes git.mk; \
else \
failed=; \
echo "Updating $$x"; \
{ cat $$x; \
echo ''; \
echo '-include $$(top_srcdir)/git.mk'; \
} > $$x.tmp || failed=1; \
if test x$$failed = x; then \
mv $$x.tmp $$x || failed=1; \
fi; \
if test x$$failed = x; then : else \
echo Failed updating $$x; >&2 \
any_failed=1; \
fi; \
fi; done; test -z "$$any_failed"
.PHONY: git-all git-mk-install
### .gitignore generation
$(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk
$(AM_V_GEN) \
{ \
if test "x$(DOC_MODULE)" = x -o "x$(DOC_MAIN_SGML_FILE)" = x; then :; else \
for x in \
$(DOC_MODULE)-decl-list.txt \
$(DOC_MODULE)-decl.txt \
tmpl/$(DOC_MODULE)-unused.sgml \
"tmpl/*.bak" \
xml html \
; do echo /$$x; done; \
fi; \
if test "x$(DOC_MODULE)$(DOC_ID)" = x -o "x$(DOC_LINGUAS)" = x; then :; else \
for lc in $(DOC_LINGUAS); do \
for x in \
$(if $(DOC_MODULE),$(DOC_MODULE).xml) \
$(DOC_PAGES) \
$(DOC_INCLUDES) \
; do echo /$$lc/$$x; done; \
done; \
for x in \
$(_DOC_OMF_ALL) \
$(_DOC_DSK_ALL) \
$(_DOC_HTML_ALL) \
$(_DOC_MOFILES) \
$(DOC_H_FILE) \
"*/.xml2po.mo" \
"*/*.omf.out" \
; do echo /$$x; done; \
fi; \
if test "x$(HELP_ID)" = x -o "x$(HELP_LINGUAS)" = x; then :; else \
for lc in $(HELP_LINGUAS); do \
for x in \
$(HELP_FILES) \
"$$lc.stamp" \
"$$lc.mo" \
; do echo /$$lc/$$x; done; \
done; \
fi; \
if test "x$(gsettings_SCHEMAS)" = x; then :; else \
for x in \
$(gsettings_SCHEMAS:.xml=.valid) \
$(gsettings__enum_file) \
; do echo /$$x; done; \
fi; \
if test -f $(srcdir)/po/Makefile.in.in; then \
for x in \
po/Makefile.in.in \
po/Makefile.in \
po/Makefile \
po/POTFILES \
po/stamp-it \
po/.intltool-merge-cache \
"po/*.gmo" \
"po/*.mo" \
po/$(GETTEXT_PACKAGE).pot \
intltool-extract.in \
intltool-merge.in \
intltool-update.in \
; do echo /$$x; done; \
fi; \
if test -f $(srcdir)/configure; then \
for x in \
autom4te.cache \
configure \
config.h \
stamp-h1 \
libtool \
config.lt \
; do echo /$$x; done; \
fi; \
if test "x$(DEJATOOL)" = x; then :; else \
for x in \
$(DEJATOOL) \
; do echo /$$x.sum; echo /$$x.log; done; \
echo /site.exp; \
fi; \
for x in \
.gitignore \
$(GITIGNOREFILES) \
$(CLEANFILES) \
$(PROGRAMS) \
$(check_PROGRAMS) \
$(EXTRA_PROGRAMS) \
$(LTLIBRARIES) \
so_locations \
.libs _libs \
$(MOSTLYCLEANFILES) \
"*.$(OBJEXT)" \
"*.lo" \
$(DISTCLEANFILES) \
$(am__CONFIG_DISTCLEAN_FILES) \
$(CONFIG_CLEAN_FILES) \
TAGS ID GTAGS GRTAGS GSYMS GPATH tags \
"*.tab.c" \
$(MAINTAINERCLEANFILES) \
$(BUILT_SOURCES) \
$(DEPDIR) \
Makefile \
Makefile.in \
"*.orig" \
"*.rej" \
"*.bak" \
"*~" \
".*.sw[nop]" \
".dirstamp" \
; do echo /$$x; done; \
} | \
sed "s@^/`echo "$(srcdir)" | sed 's/\(.\)/[\1]/g'`/@/@" | \
sed 's@/[.]/@/@g' | \
LC_ALL=C sort | uniq > $@.tmp && \
mv $@.tmp $@;
all: $(srcdir)/.gitignore gitignore-recurse-maybe
gitignore-recurse-maybe:
@if test "x$(SUBDIRS)" = "x$(DIST_SUBDIRS)"; then :; else \
$(MAKE) $(AM_MAKEFLAGS) gitignore-recurse; \
fi;
gitignore-recurse:
@for subdir in $(DIST_SUBDIRS); do \
case " $(SUBDIRS) " in \
*" $$subdir "*) :;; \
*) test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) .gitignore gitignore-recurse || echo "Skipping $$subdir");; \
esac; \
done
gitignore: $(srcdir)/.gitignore gitignore-recurse
maintainer-clean: gitignore-clean
gitignore-clean:
-rm -f $(srcdir)/.gitignore
.PHONY: gitignore-clean gitignore gitignore-recurse gitignore-recurse-maybe

28
meson.build Normal file
View File

@ -0,0 +1,28 @@
project(
'squeekboard',
'c', 'rust',
version: '1.0.9',
license: 'GPLv3',
meson_version: '>=0.43.0',
default_options: [ 'warning_level=1', 'buildtype=debugoptimized', 'c_std=gnu11' ],
)
i18n = import('i18n')
if get_option('buildtype').startswith('debug')
add_project_arguments('-DDEBUG=1', language : 'c')
endif
if get_option('buildtype') != 'plain'
add_project_arguments('-fstack-protector-strong', language: 'c')
endif
prefix = get_option('prefix')
datadir = join_paths(prefix, get_option('datadir'))
pkgdatadir = join_paths(datadir, meson.project_name())
dbusdir = join_paths(datadir, 'dbus-1/interfaces')
subdir('data')
subdir('protocols')
subdir('eek')
subdir('src')
subdir('po')

9
po/meson.build Normal file
View File

@ -0,0 +1,9 @@
i18n.gettext('squeekboard',
preset: 'glib',
args: [
'--copyright-holder=Purism SPC',
'--package-name=Squeekboard',
'--package-version=' + meson.project_version(),
'--msgid-bugs-address=dorota.czaplejewicz@puri.sm'
]
)

View File

@ -0,0 +1,404 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="input_method_unstable_v2">
<copyright>
Copyright © 2012, 2013 Intel Corporation
Copyright © 2015, 2016 Jan Arne Petersen
Copyright © 2017, 2018 Red Hat, Inc.
Copyright © 2018 Purism SPC
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
</copyright>
<description summary="Protocol for creating input methods">
This protocol allows applications to act as input methods for compositors.
An input method context is used to manage the state of the input method.
Text strings are UTF-8 encoded, their indices and lengths are in bytes.
This document adheres to the RFC 2119 when using words like "must",
"should", "may", etc.
Warning! The protocol described in this file is experimental and
backward incompatible changes may be made. Backward compatible changes
may be added together with the corresponding interface version bump.
Backward incompatible changes are done by bumping the version number in
the protocol and interface names and resetting the interface version.
Once the protocol is to be declared stable, the 'z' prefix and the
version number in the protocol and interface names are removed and the
interface version number is reset.
</description>
<interface name="zwp_input_method_v2" version="1">
<description summary="input method">
An input method object allows for clients to compose text.
The objects connects the client to a text input in an application, and
lets the client to serve as an input method for a seat.
The zwp_input_method_v2 object can occupy two distinct states: active and
inactive. In the active state, the object is associated to and
communicates with a text input. In the inactive state, there is no
associated text input, and the only communication is with the compositor.
Initially, the input method is in the inactive state.
Requests issued in the inactive state must be accepted by the compositor.
Because of the serial mechanism, and the state reset on activate event,
they will not have any effect on the state of the next text input.
There must be no more than one input method object per seat.
</description>
<event name="activate">
<description summary="input method has been requested">
Notification that a text input focused on this seat requested the input
method to be activated.
This request must be issued every time a text input requests an input
method.
This request resets all state associated with previous enable, disable,
set_surrounding_text, set_text_change_cause, set_content_type, and
set_cursor_rectangle requests, as well as the state associated with
preedit_string, commit_string, and delete_surrounding_text events. In
addition, it marks the input method object as active.
The set_surrounding_text, set_content_type and set_cursor_rectangle
requests must follow before the next done event if the text input
supports the respective functionality.
State set with this event is double-buffered. It will get applied on
the next zwp_input_method_v2.done event, and stay valid until changed.
</description>
</event>
<event name="deactivate">
<description summary="deactivate event">
Notification that this seat's current text input requested the input
method to be deactivated.
This event mrks the zwp_input_method_v2 object as inactive.
When the seat has the keyboard capability the text-input focus follows
the keyboard focus.
State set with this event is double-buffered. It will get applied on
the next zwp_input_method_v2.done event, and stay valid until changed.
</description>
</event>
<event name="surrounding_text">
<description summary="surrounding text event">
Sets the surrounding plain text around the cursor, excluding the
preedit text.
If any preedit text is present, it is replaced with the cursor for the
purpose of this event.
The argument text is a buffer containing the preedit string, and must
include the cursor position, and the complete selection. It should
contain additional characters before and after these. There is a
maximum length of wayland messages, so text can not be longer than 4000
bytes.
cursor is the byte offset of the cursor within the text buffer.
anchor is the byte offset of the selection anchor within the text
buffer. If there is no selected text, anchor must be the same as
cursor.
If this request does not arrive before the first done event, the input
method may assume that the text input does not support this
functionality and ignore following surrounding_text events.
Values set with this event are double-buffered. They will get applied
and set to initial values on the next zwp_input_method_v2.done
event.
The initial state for affected fields is empty, meaning that the text
input does not support sending surrounding text. If the empty values
get applied, subsequent attempts to change them may have no effect.
</description>
<arg name="text" type="string"/>
<arg name="cursor" type="uint"/>
<arg name="anchor" type="uint"/>
</event>
<event name="text_change_cause">
<description summary="indicates the cause of surrounding text change">
Tells the input method why the text surrounding the cursor changed.
Whenever the client detects an external change in text, cursor, or
anchor position, it must issue this request to the compositor. This
request is intended to give the input method a chance to update the
preedit text in an appropriate way, e.g. by removing it when the user
starts typing with a keyboard.
cause describes the source of the change.
The value set with this event is double-buffered. It will get applied
and set to its initial value on the next zwp_input_method_v2.done
event.
The initial value of cause is input_method.
</description>
<arg name="cause" type="uint" enum="zwp_text_input_v3.change_cause"/>
</event>
<event name="content_type">
<description summary="content purpose and hint">
Indicates the content type and hint for the current
input_method_context instance.
Values set with this event are double-buffered. They will get applied
on the next zwp_input_method_v2.done event.
The initial value for hint is none, and the initial value for purpose
is normal.
</description>
<arg name="hint" type="uint" enum="zwp_text_input_v3.content_hint"/>
<arg name="purpose" type="uint" enum="zwp_text_input_v3.content_purpose"/>
</event>
<event name="done">
<description summary="apply state">
Atomically applies state changes recently sent to the client.
The done event establishes and updates the state of the client, and
must be issued after any changes to apply them.
Text input state (content purpose, content hint, surrounding text, and
change cause) is conceptually double-buffered within an input method
context.
Events modify the pending state, as opposed to the current state in use
by the input method. A done event atomically applies all pending state,
replacing the current state. After done, the new pending state is as
documented for each related request.
Events must be applied in the order of arrival.
Neither current nor pending state are modified unless noted otherwise.
</description>
</event>
<request name="commit_string">
<description summary="commit string">
Send the commit string text for insertion to the application.
Inserts a string at current cursor position (see commit event
sequence). The string to commit could be either just a single character
after a key press or the result of some composing.
The argument text is a buffer containing the string to insert. There is
a maximum length of wayland messages, so text can not be longer than
4000 bytes.
Values set with this event are double-buffered. They must be applied
and reset to initial on the next zwp_text_input_v3.done event.
The initial value of text is an empty string.
</description>
<arg name="text" type="string"/>
</request>
<request name="preedit_string">
<description summary="pre-edit string">
Send the pre-edit string text to the application text input.
Place a new composing text (pre-edit) at the current cursor position.
Any previously set composing text must be removed. Any previously
existing selected text must be removed. The cursor is moved to a new
position within the preedit string.
The argument text is a buffer containing the preedit string. There is
a maximum length of wayland messages, so text can not be longer than
4000 bytes.
The arguments cursor_begin and cursor_end are counted in bytes relative
to the beginning of the submitted string buffer. Cursor should be
hidden by the text input when both are equal to -1.
cursor_begin indicates the beginning of the cursor. cursor_end
indicates the end of the cursor. It may be equal or different than
cursor_begin.
Values set with this event are double-buffered. They must be applied on
the next zwp_input_method_v2.commit event.
The initial value of text is an empty string. The initial value of
cursor_begin, and cursor_end are both 0.
</description>
<arg name="text" type="string"/>
<arg name="cursor_begin" type="int"/>
<arg name="cursor_end" type="int"/>
</request>
<request name="delete_surrounding_text">
<description summary="delete text">
Remove the surrounding text.
before_length and after_length are the number of bytes before and after
the current cursor index (excluding the preedit text) to delete.
If any preedit text is present, it is replaced with the cursor for the
purpose of this event. In effect before_length is counted from the
beginning of preedit text, and after_length from its end (see commit
event sequence).
Values set with this event are double-buffered. They must be applied
and reset to initial on the next zwp_input_method_v2.commit request.
The initial values of both before_length and after_length are 0.
</description>
<arg name="before_length" type="uint"/>
<arg name="after_length" type="uint"/>
</request>
<request name="commit">
<description summary="apply state">
Apply state changes from commit_string, preedit_string and
delete_surrounding_text requests.
The state relating to these events is double-buffered, and each one
modifies the pending state. This request replaces the current state
with the pending state.
The connected text input is expected to proceed by evaluating the
changes in the following order:
1. Replace existing preedit string with the cursor.
2. Delete requested surrounding text.
3. Insert commit string with the cursor at its end.
4. Calculate surrounding text to send.
5. Insert new preedit text in cursor position.
6. Place cursor inside preedit text.
The serial number reflects the last state of the zwp_input_method_v2
object known to the client. The value of the serial argument must be
equal to the number of commit requests already issued on that object.
When the compositor receives a done event with a serial different than
the number of past commit requests, it must proceed as normal, except
it should not change the current state of the zwp_input_method_v2
object.
</description>
<arg name="serial" type="uint"/>
</request>
<request name="get_input_popup_surface">
<description summary="create popup surface">
Creates a new zwp_input_popup_surface_v2 object wrapping a given
surface.
</description>
<arg name="id" type="new_id" interface="zwp_input_popup_surface_v2"/>
<arg name="surface" type="object" interface="wl_surface"/>
</request>
<request name="grab_keyboard">
<description summary="grab hardware keyboard">
Allow 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.
The compositor should send all keyboard events on the seat to the grab
holder via the returned wl_keyboard object. Nevertheless, the
compositor may decide not to forward any particular event. The
compositor must not further process any event after it has been
forwarded to the grab holder.
Releasing the resulting wl_keyboard object releases the grab.
</description>
<arg name="keyboard" type="new_id" interface="wl_keyboard"/>
</request>
<event name="unavailable">
<description summary="input method unavailable">
The input method ceased to be available.
The compositor must issue this event as the only event on the object if
there was another input_method object associated with the same seat at
the time of its creation.
The compositor must issue this request when the object is no longer
useable, e.g. due to seat removal.
The input method context becomes inert and should be destroyed after
deactivation is handled. Any further requests and events except for the
destroy request must be ignored.
</description>
</event>
<request name="destroy" type="destructor"/>
</interface>
<interface name="zwp_input_popup_surface_v2" version="1">
<description summary="popup surface">
This surface is a popup for interacting with an input method.
The compositor should place it near the active text input area. It must
be visible if and only if the input method is in the active state.
</description>
<event name="text_input_rectangle">
<description summary="set text input area position">
Notify about the position of the area of the text input expressed as a
rectangle in surface local coordinates.
This is a hint to the input method telling it the relative position of
the text being entered.
</description>
<arg name="x" type="int"/>
<arg name="y" type="int"/>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
</event>
<request name="destroy" type="destructor"/>
</interface>
<interface name="zwp_input_method_manager_v2" version="1">
<description summary="input method manager">
The input method manager allows the client to become the input method on
a chosen seat.
No more than one input method must be associated with any seat at any
given time.
</description>
<request name="get_input_method">
<description summary="request an input method object">
Request a new input zwp_input_method_v2 object associated with a given
seat.
</description>
<arg name="seat" type="object" interface="wl_seat"/>
<arg name="input_method" type="new_id" interface="zwp_input_method_v2"/>
</request>
<request name="destroy" type="destructor">
<description summary="destroy the input method manager">
Destroys the zwp_input_method_manager_v2 object.
The zwp_input_method_v2 objects originating from it remain valid.
</description>
</request>
</interface>
</protocol>

22
protocols/meson.build Normal file
View File

@ -0,0 +1,22 @@
wayland_protos = dependency('wayland-protocols', version: '>=1.12')
wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir')
wl_scanner = find_program('wayland-scanner')
gen_scanner_client_header = generator(wl_scanner,
output: '@BASENAME@-client-protocol.h',
arguments: ['client-header', '@INPUT@', '@OUTPUT@'])
gen_scanner_client_code = generator(wl_scanner,
output: '@BASENAME@-protocol.c',
arguments: ['private-code', '@INPUT@', '@OUTPUT@'])
wl_protos = [
wl_protocol_dir + '/stable/xdg-shell/xdg-shell.xml',
'wlr-layer-shell-unstable-v1.xml',
'virtual-keyboard-unstable-v1.xml',
'input-method-unstable-v2.xml',
]
wl_proto_sources = []
foreach proto: wl_protos
wl_proto_sources += gen_scanner_client_header.process(proto)
wl_proto_sources += gen_scanner_client_code.process(proto)
endforeach

View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="virtual_keyboard_unstable_v1">
<copyright>
Copyright © 2008-2011 Kristian Høgsberg
Copyright © 2010-2013 Intel Corporation
Copyright © 2012-2013 Collabora, Ltd.
Copyright © 2018 Purism SPC
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
</copyright>
<interface name="zwp_virtual_keyboard_v1" version="1">
<description summary="virtual keyboard">
The virtual keyboard provides an application with requests which emulate
the behaviour of a physical keyboard.
This interface can be used by clients on its own to provide raw input
events, or it can accompany the input method protocol.
</description>
<request name="keymap">
<description summary="keyboard mapping">
Provide a file descriptor to the compositor which can be
memory-mapped to provide a keyboard mapping description.
Format carries a value from the keymap_format enumeration.
</description>
<arg name="format" type="uint" summary="keymap format"/>
<arg name="fd" type="fd" summary="keymap file descriptor"/>
<arg name="size" type="uint" summary="keymap size, in bytes"/>
</request>
<enum name="error">
<entry name="no_keymap" value="0" summary="No keymap was set"/>
</enum>
<request name="key">
<description summary="key event">
A key was pressed or released.
The time argument is a timestamp with millisecond granularity, with an
undefined base. All requests regarding a single object must share the
same clock.
Keymap must be set before issuing this request.
State carries a value from the key_state enumeration.
</description>
<arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
<arg name="key" type="uint" summary="key that produced the event"/>
<arg name="state" type="uint" summary="physical state of the key"/>
</request>
<request name="modifiers">
<description summary="modifier and group state">
Notifies the compositor that the modifier and/or group state has
changed, and it should update state.
The client should use wl_keyboard.modifiers event to synchronize its
internal state with seat state.
Keymap must be set before issuing this request.
</description>
<arg name="mods_depressed" type="uint" summary="depressed modifiers"/>
<arg name="mods_latched" type="uint" summary="latched modifiers"/>
<arg name="mods_locked" type="uint" summary="locked modifiers"/>
<arg name="group" type="uint" summary="keyboard layout"/>
</request>
<request name="destroy" type="destructor" since="1">
<description summary="destroy the virtual keyboard keyboard object"/>
</request>
</interface>
<interface name="zwp_virtual_keyboard_manager_v1" version="1">
<description summary="virtual keyboard manager">
A virtual keyboard manager allows an application to provide keyboard
input events as if they came from a physical keyboard.
</description>
<enum name="error">
<entry name="unauthorized" value="0" summary="client not authorized to use the interface"/>
</enum>
<request name="create_virtual_keyboard">
<description summary="Create a new virtual keyboard">
Creates a new virtual keyboard associated to a seat.
If the compositor enables a keyboard to perform arbitrary actions, it
should present an error when an untrusted client requests a new
keyboard.
</description>
<arg name="seat" type="object" interface="wl_seat"/>
<arg name="id" type="new_id" interface="zwp_virtual_keyboard_v1"/>
</request>
</interface>
</protocol>

View File

@ -0,0 +1,285 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="wlr_layer_shell_unstable_v1">
<copyright>
Copyright © 2017 Drew DeVault
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
the copyright holders not be used in advertising or publicity
pertaining to distribution of the software without specific,
written prior permission. The copyright holders make no
representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied
warranty.
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
</copyright>
<interface name="zwlr_layer_shell_v1" version="1">
<description summary="create surfaces that are layers of the desktop">
Clients can use this interface to assign the surface_layer role to
wl_surfaces. Such surfaces are assigned to a "layer" of the output and
rendered with a defined z-depth respective to each other. They may also be
anchored to the edges and corners of a screen and specify input handling
semantics. This interface should be suitable for the implementation of
many desktop shell components, and a broad number of other applications
that interact with the desktop.
</description>
<request name="get_layer_surface">
<description summary="create a layer_surface from a surface">
Create a layer surface for an existing surface. This assigns the role of
layer_surface, or raises a protocol error if another role is already
assigned.
Creating a layer surface from a wl_surface which has a buffer attached
or committed is a client error, and any attempts by a client to attach
or manipulate a buffer prior to the first layer_surface.configure call
must also be treated as errors.
You may pass NULL for output to allow the compositor to decide which
output to use. Generally this will be the one that the user most
recently interacted with.
Clients can specify a namespace that defines the purpose of the layer
surface.
</description>
<arg name="id" type="new_id" interface="zwlr_layer_surface_v1"/>
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="output" type="object" interface="wl_output" allow-null="true"/>
<arg name="layer" type="uint" enum="layer" summary="layer to add this surface to"/>
<arg name="namespace" type="string" summary="namespace for the layer surface"/>
</request>
<enum name="error">
<entry name="role" value="0" summary="wl_surface has another role"/>
<entry name="invalid_layer" value="1" summary="layer value is invalid"/>
<entry name="already_constructed" value="2" summary="wl_surface has a buffer attached or committed"/>
</enum>
<enum name="layer">
<description summary="available layers for surfaces">
These values indicate which layers a surface can be rendered in. They
are ordered by z depth, bottom-most first. Traditional shell surfaces
will typically be rendered between the bottom and top layers.
Fullscreen shell surfaces are typically rendered at the top layer.
Multiple surfaces can share a single layer, and ordering within a
single layer is undefined.
</description>
<entry name="background" value="0"/>
<entry name="bottom" value="1"/>
<entry name="top" value="2"/>
<entry name="overlay" value="3"/>
</enum>
</interface>
<interface name="zwlr_layer_surface_v1" version="1">
<description summary="layer metadata interface">
An interface that may be implemented by a wl_surface, for surfaces that
are designed to be rendered as a layer of a stacked desktop-like
environment.
Layer surface state (size, anchor, exclusive zone, margin, interactivity)
is double-buffered, and will be applied at the time wl_surface.commit of
the corresponding wl_surface is called.
</description>
<request name="set_size">
<description summary="sets the size of the surface">
Sets the size of the surface in surface-local coordinates. The
compositor will display the surface centered with respect to its
anchors.
If you pass 0 for either value, the compositor will assign it and
inform you of the assignment in the configure event. You must set your
anchor to opposite edges in the dimensions you omit; not doing so is a
protocol error. Both values are 0 by default.
Size is double-buffered, see wl_surface.commit.
</description>
<arg name="width" type="uint"/>
<arg name="height" type="uint"/>
</request>
<request name="set_anchor">
<description summary="configures the anchor point of the surface">
Requests that the compositor anchor the surface to the specified edges
and corners. If two orthogonal edges are specified (e.g. 'top' and
'left'), then the anchor point will be the intersection of the edges
(e.g. the top left corner of the output); otherwise the anchor point
will be centered on that edge, or in the center if none is specified.
Anchor is double-buffered, see wl_surface.commit.
</description>
<arg name="anchor" type="uint" enum="anchor"/>
</request>
<request name="set_exclusive_zone">
<description summary="configures the exclusive geometry of this surface">
Requests that the compositor avoids occluding an area of the surface
with other surfaces. The compositor's use of this information is
implementation-dependent - do not assume that this region will not
actually be occluded.
A positive value is only meaningful if the surface is anchored to an
edge, rather than a corner. The zone is the number of surface-local
coordinates from the edge that is considered exclusive.
Surfaces that do not wish to have an exclusive zone may instead specify
how they should interact with surfaces that do. If set to zero, the
surface indicates that it would like to be moved to avoid occluding
surfaces with a positive exclusive zone. If set to -1, the surface
indicates that it would not like to be moved to accommodate for other
surfaces, and the compositor should extend it all the way to the edges
it is anchored to.
For example, a panel might set its exclusive zone to 10, so that
maximized shell surfaces are not shown on top of it. A notification
might set its exclusive zone to 0, so that it is moved to avoid
occluding the panel, but shell surfaces are shown underneath it. A
wallpaper or lock screen might set their exclusive zone to -1, so that
they stretch below or over the panel.
The default value is 0.
Exclusive zone is double-buffered, see wl_surface.commit.
</description>
<arg name="zone" type="int"/>
</request>
<request name="set_margin">
<description summary="sets a margin from the anchor point">
Requests that the surface be placed some distance away from the anchor
point on the output, in surface-local coordinates. Setting this value
for edges you are not anchored to has no effect.
The exclusive zone includes the margin.
Margin is double-buffered, see wl_surface.commit.
</description>
<arg name="top" type="int"/>
<arg name="right" type="int"/>
<arg name="bottom" type="int"/>
<arg name="left" type="int"/>
</request>
<request name="set_keyboard_interactivity">
<description summary="requests keyboard events">
Set to 1 to request that the seat send keyboard events to this layer
surface. For layers below the shell surface layer, the seat will use
normal focus semantics. For layers above the shell surface layers, the
seat will always give exclusive keyboard focus to the top-most layer
which has keyboard interactivity set to true.
Layer surfaces receive pointer, touch, and tablet events normally. If
you do not want to receive them, set the input region on your surface
to an empty region.
Events is double-buffered, see wl_surface.commit.
</description>
<arg name="keyboard_interactivity" type="uint"/>
</request>
<request name="get_popup">
<description summary="assign this layer_surface as an xdg_popup parent">
This assigns an xdg_popup's parent to this layer_surface. This popup
should have been created via xdg_surface::get_popup with the parent set
to NULL, and this request must be invoked before committing the popup's
initial state.
See the documentation of xdg_popup for more details about what an
xdg_popup is and how it is used.
</description>
<arg name="popup" type="object" interface="xdg_popup"/>
</request>
<request name="ack_configure">
<description summary="ack a configure event">
When a configure event is received, if a client commits the
surface in response to the configure event, then the client
must make an ack_configure request sometime before the commit
request, passing along the serial of the configure event.
If the client receives multiple configure events before it
can respond to one, it only has to ack the last configure event.
A client is not required to commit immediately after sending
an ack_configure request - it may even ack_configure several times
before its next surface commit.
A client may send multiple ack_configure requests before committing, but
only the last request sent before a commit indicates which configure
event the client really is responding to.
</description>
<arg name="serial" type="uint" summary="the serial from the configure event"/>
</request>
<request name="destroy" type="destructor">
<description summary="destroy the layer_surface">
This request destroys the layer surface.
</description>
</request>
<event name="configure">
<description summary="suggest a surface change">
The configure event asks the client to resize its surface.
Clients should arrange their surface for the new states, and then send
an ack_configure request with the serial sent in this configure event at
some point before committing the new surface.
The client is free to dismiss all but the last configure event it
received.
The width and height arguments specify the size of the window in
surface-local coordinates.
The size is a hint, in the sense that the client is free to ignore it if
it doesn't resize, pick a smaller size (to satisfy aspect ratio or
resize in steps of NxM pixels). If the client picks a smaller size and
is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the
surface will be centered on this axis.
If the width or height arguments are zero, it means the client should
decide its own window dimension.
</description>
<arg name="serial" type="uint"/>
<arg name="width" type="uint"/>
<arg name="height" type="uint"/>
</event>
<event name="closed">
<description summary="surface should be closed">
The closed event is sent by the compositor when the surface will no
longer be shown. The output may have been destroyed or the user may
have asked for it to be removed. Further changes to the surface will be
ignored. The client should destroy the resource after receiving this
event, and create a new surface if they so choose.
</description>
</event>
<enum name="error">
<entry name="invalid_surface_state" value="0" summary="provided surface state is invalid"/>
<entry name="invalid_size" value="1" summary="size is invalid"/>
<entry name="invalid_anchor" value="2" summary="anchor bitfield is invalid"/>
</enum>
<enum name="anchor" bitfield="true">
<entry name="top" value="1" summary="the top edge of the anchor rectangle"/>
<entry name="bottom" value="2" summary="the bottom edge of the anchor rectangle"/>
<entry name="left" value="4" summary="the left edge of the anchor rectangle"/>
<entry name="right" value="8" summary="the right edge of the anchor rectangle"/>
</enum>
</interface>
</protocol>

View File

@ -18,7 +18,6 @@
bin_PROGRAMS = \ bin_PROGRAMS = \
eekboard \ eekboard \
eekboard-server \
$(NULL) $(NULL)
libexec_PROGRAMS = \ libexec_PROGRAMS = \
@ -63,40 +62,6 @@ eekboard_SOURCES = \
client-main.c \ client-main.c \
$(NULL) $(NULL)
eekboard_server_CFLAGS = \
-I$(top_srcdir) \
$(GIO2_CFLAGS) \
$(GTK_CFLAGS) \
$(LIBXKLAVIER_CFLAGS) \
-DTHEMESDIR=\"$(pkgdatadir)/themes\" \
$(NULL)
eekboard_server_LDADD = \
$(top_builddir)/eekboard/libeekboard.la \
$(top_builddir)/eek/libeek.la \
$(top_builddir)/eek/libeek-gtk.la \
$(top_builddir)/eek/libeek-xkl.la \
$(GIO2_LIBS) \
$(GTK_LIBS) \
$(LIBXKLAVIER_LIBS) \
$(NULL)
if ENABLE_XDOCK
eekboard_server_CFLAGS += $(XDOCK_CFLAGS)
eekboard_server_LDADD += $(XDOCK_LIBS)
endif
eekboard_server_headers = \
server-service.h \
server-context-service.h \
$(NULL)
eekboard_server_SOURCES = \
server-service.c \
server-context-service.c \
server-main.c \
$(NULL)
eekboard_setup_CFLAGS = \ eekboard_setup_CFLAGS = \
-I$(top_srcdir) \ -I$(top_srcdir) \
$(GIO2_CFLAGS) \ $(GIO2_CFLAGS) \
@ -125,6 +90,7 @@ dist_pkgdata_DATA = preferences-dialog.ui
noinst_HEADERS = \ noinst_HEADERS = \
$(eekboard_headers) \ $(eekboard_headers) \
$(eekboard_server_headers) \
$(eekboard_setup_headers) \ $(eekboard_setup_headers) \
$(NULL) $(NULL)
-include $(top_srcdir)/git.mk

View File

@ -32,14 +32,14 @@
#include "eekboard/eekboard-client.h" #include "eekboard/eekboard-client.h"
#include "client.h" #include "client.h"
#define DEFAULT_KEYBOARD "us"
static gboolean opt_system = FALSE; static gboolean opt_system = FALSE;
static gboolean opt_session = FALSE; static gboolean opt_session = FALSE;
static gchar *opt_address = NULL; static gchar *opt_address = NULL;
static gboolean opt_focus = FALSE; static gboolean opt_focus = FALSE;
#ifdef HAVE_ATSPI
static gboolean opt_keystroke = FALSE; static gboolean opt_keystroke = FALSE;
#endif /* HAVE_ATSPI */
static gchar *opt_keyboards = NULL; static gchar *opt_keyboards = NULL;
@ -88,7 +88,7 @@ enum FocusListenerType {
}; };
static gboolean static gboolean
set_keyboards (Client *client, set_keyboards (SeatEmitter *client,
const gchar * const *keyboards) const gchar * const *keyboards)
{ {
if (g_strv_length ((gchar **)keyboards) == 0) { if (g_strv_length ((gchar **)keyboards) == 0) {
@ -110,7 +110,7 @@ set_keyboards (Client *client,
int int
main (int argc, char **argv) main (int argc, char **argv)
{ {
Client *client = NULL; SeatEmitter *client = NULL;
EekboardClient *eekboard; EekboardClient *eekboard;
EekboardContext *context; EekboardContext *context;
GBusType bus_type; GBusType bus_type;
@ -270,13 +270,13 @@ main (int argc, char **argv)
} }
#endif /* HAVE_IBUS */ #endif /* HAVE_IBUS */
#ifdef HAVE_XTEST //#ifdef HAVE_XTEST
if (!client_enable_xtest (client)) { if (!client_enable_xtest (client)) {
g_printerr ("Can't init xtest\n"); g_printerr ("Can't init xtest\n");
g_object_unref (client); g_object_unref (client);
exit (1); exit (1);
} }
#endif /* HAVE_XTEST */ //#endif /* HAVE_XTEST */
if (!opt_focus) { if (!opt_focus) {
g_object_get (client, "context", &context, NULL); g_object_get (client, "context", &context, NULL);

View File

@ -44,6 +44,12 @@
#define CSW 640 #define CSW 640
#define CSH 480 #define CSH 480
#define DEFAULT_KEYBOARD "us"
static gchar *default_keyboards[2] = {
DEFAULT_KEYBOARD,
NULL
};
#define IBUS_INTERFACE_PANEL "org.freedesktop.IBus.Panel" #define IBUS_INTERFACE_PANEL "org.freedesktop.IBus.Panel"
enum { enum {
@ -85,10 +91,8 @@ struct _Client {
AtspiDeviceListener *keystroke_listener; AtspiDeviceListener *keystroke_listener;
#endif /* HAVE_ATSPI */ #endif /* HAVE_ATSPI */
#ifdef HAVE_XTEST
guint modifier_keycodes[8]; guint modifier_keycodes[8];
XkbDescRec *xkb; XkbDescRec *xkb;
#endif /* HAVE_XTEST */
GSettings *settings; GSettings *settings;
}; };
@ -97,7 +101,7 @@ struct _ClientClass {
GObjectClass parent_class; GObjectClass parent_class;
}; };
G_DEFINE_TYPE (Client, client, G_TYPE_OBJECT); G_DEFINE_TYPE (SeatEmitter, client, G_TYPE_OBJECT);
#if ENABLE_FOCUS_LISTENER #if ENABLE_FOCUS_LISTENER
#define IS_KEYBOARD_VISIBLE(client) (!client->follows_focus) #define IS_KEYBOARD_VISIBLE(client) (!client->follows_focus)
@ -124,10 +128,10 @@ static void focus_listener_cb (const AtspiEvent *event,
static gboolean keystroke_listener_cb (const AtspiDeviceEvent *stroke, static gboolean keystroke_listener_cb (const AtspiDeviceEvent *stroke,
void *user_data); void *user_data);
#endif /* HAVE_ATSPI */ #endif /* HAVE_ATSPI */
static gboolean set_keyboards (Client *client, static gboolean set_keyboards (SeatEmitter *client,
const gchar * const *keyboard); const gchar * const *keyboard);
static gboolean set_keyboards_from_xkl static gboolean set_keyboards_from_xkl
(Client *client); (SeatEmitter *client);
#ifdef HAVE_XTEST #ifdef HAVE_XTEST
static void update_modifier_keycodes static void update_modifier_keycodes
(Client *client); (Client *client);
@ -139,8 +143,9 @@ client_set_property (GObject *object,
const GValue *value, const GValue *value,
GParamSpec *pspec) GParamSpec *pspec)
{ {
Client *client = CLIENT(object); SeatEmitter *client = CLIENT(object);
GDBusConnection *connection; GDBusConnection *connection;
gchar **keyboards;
switch (prop_id) { switch (prop_id) {
case PROP_CONNECTION: case PROP_CONNECTION:
@ -166,7 +171,10 @@ client_set_property (GObject *object,
} }
break; break;
case PROP_KEYBOARDS: case PROP_KEYBOARDS:
client_set_keyboards (client, g_value_get_boxed (value)); keyboards = g_value_get_boxed (value);
if (g_strv_length (keyboards) == 0)
keyboards = default_keyboards;
client_set_keyboards (client, (const gchar * const *)keyboards);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -180,7 +188,7 @@ client_get_property (GObject *object,
GValue *value, GValue *value,
GParamSpec *pspec) GParamSpec *pspec)
{ {
Client *client = CLIENT(object); SeatEmitter *client = CLIENT(object);
switch (prop_id) { switch (prop_id) {
case PROP_EEKBOARD: case PROP_EEKBOARD:
@ -198,7 +206,7 @@ client_get_property (GObject *object,
static void static void
client_dispose (GObject *object) client_dispose (GObject *object)
{ {
Client *client = CLIENT(object); SeatEmitter *client = CLIENT(object);
client_disable_xkl (client); client_disable_xkl (client);
@ -238,7 +246,7 @@ client_dispose (GObject *object)
static void static void
client_finalize (GObject *object) client_finalize (GObject *object)
{ {
Client *client = CLIENT(object); SeatEmitter *client = CLIENT(object);
g_slist_free (client->keyboards); g_slist_free (client->keyboards);
G_OBJECT_CLASS (client_parent_class)->finalize (object); G_OBJECT_CLASS (client_parent_class)->finalize (object);
@ -293,24 +301,24 @@ client_class_init (ClientClass *klass)
} }
static void static void
client_init (Client *client) client_init (SeatEmitter *client)
{ {
client->settings = g_settings_new ("org.fedorahosted.eekboard"); client->settings = g_settings_new ("org.fedorahosted.eekboard");
} }
gboolean gboolean
client_set_keyboards (Client *client, client_set_keyboards (SeatEmitter *client,
const gchar * const *keyboards) const gchar * const *keyboards)
{ {
gboolean retval; gboolean retval;
retval = set_keyboards (client, keyboards); retval = set_keyboards (client, keyboards);
if (retval && IS_KEYBOARD_VISIBLE (client)) if (retval && IS_KEYBOARD_VISIBLE (client))
eekboard_context_show_keyboard (client->context, NULL); eekboard_client_show_keyboard (client->eekboard, NULL);
return retval; return retval;
} }
gboolean gboolean
client_enable_xkl (Client *client) client_enable_xkl (SeatEmitter *client)
{ {
GdkDisplay *display = gdk_display_get_default (); GdkDisplay *display = gdk_display_get_default ();
gboolean retval; gboolean retval;
@ -347,13 +355,13 @@ client_enable_xkl (Client *client)
retval = set_keyboards_from_xkl (client); retval = set_keyboards_from_xkl (client);
if (IS_KEYBOARD_VISIBLE (client)) if (IS_KEYBOARD_VISIBLE (client))
eekboard_context_show_keyboard (client->context, NULL); eekboard_client_show_keyboard (client->eekboard, NULL);
return retval; return retval;
} }
void void
client_disable_xkl (Client *client) client_disable_xkl (SeatEmitter *client)
{ {
if (client->xkl_engine) { if (client->xkl_engine) {
xkl_engine_stop_listen (client->xkl_engine, XKLL_TRACK_KEYBOARD_STATE); xkl_engine_stop_listen (client->xkl_engine, XKLL_TRACK_KEYBOARD_STATE);
@ -538,21 +546,21 @@ focus_listener_cb (const AtspiEvent *event,
case ATSPI_ROLE_TERMINAL: case ATSPI_ROLE_TERMINAL:
if (strncmp (event->type, "focus", 5) == 0 || event->detail1 == 1) { if (strncmp (event->type, "focus", 5) == 0 || event->detail1 == 1) {
client->acc = accessible; client->acc = accessible;
eekboard_context_show_keyboard (client->context, NULL); eekboard_client_show_keyboard (client->eekboard, NULL);
} else if (g_settings_get_boolean (client->settings, "auto-hide") && } else if (g_settings_get_boolean (client->settings, "auto-hide") &&
event->detail1 == 0 && accessible == client->acc) { event->detail1 == 0 && accessible == client->acc) {
client->acc = NULL; client->acc = NULL;
eekboard_context_hide_keyboard (client->context, NULL); eekboard_client_hide_keyboard (client->eekboard, NULL);
} }
break; break;
case ATSPI_ROLE_ENTRY: case ATSPI_ROLE_ENTRY:
if (strncmp (event->type, "focus", 5) == 0 || event->detail1 == 1) { if (strncmp (event->type, "focus", 5) == 0 || event->detail1 == 1) {
client->acc = accessible; client->acc = accessible;
eekboard_context_show_keyboard (client->context, NULL); eekboard_client_show_keyboard (client->eekboard, NULL);
} else if (g_settings_get_boolean (client->settings, "auto-hide") && } else if (g_settings_get_boolean (client->settings, "auto-hide") &&
event->detail1 == 0) { event->detail1 == 0) {
client->acc = NULL; client->acc = NULL;
eekboard_context_hide_keyboard (client->context, NULL); eekboard_client_hide_keyboard (client->eekboard, NULL);
} }
break; break;
@ -560,7 +568,7 @@ focus_listener_cb (const AtspiEvent *event,
; ;
} }
} else { } else {
eekboard_context_hide_keyboard (client->context, NULL); eekboard_client_hide_keyboard (client->eekboard, NULL);
} }
} }
@ -610,9 +618,9 @@ add_match_rule (GDBusConnection *connection,
} }
static gboolean static gboolean
on_hide_keyboard_timeout (Client *client) on_hide_keyboard_timeout (SeatEmitter *client)
{ {
eekboard_context_hide_keyboard (client->context, NULL); eekboard_client_hide_keyboard (client->eekboard, NULL);
client->hide_keyboard_timeout_id = 0; client->hide_keyboard_timeout_id = 0;
return FALSE; return FALSE;
} }
@ -623,7 +631,7 @@ focus_message_filter (GDBusConnection *connection,
gboolean incoming, gboolean incoming,
gpointer user_data) gpointer user_data)
{ {
Client *client = user_data; SeatEmitter *client = user_data;
if (incoming && if (incoming &&
g_strcmp0 (g_dbus_message_get_interface (message), g_strcmp0 (g_dbus_message_get_interface (message),
@ -635,7 +643,7 @@ focus_message_filter (GDBusConnection *connection,
g_source_remove (client->hide_keyboard_timeout_id); g_source_remove (client->hide_keyboard_timeout_id);
client->hide_keyboard_timeout_id = 0; client->hide_keyboard_timeout_id = 0;
} }
eekboard_context_show_keyboard (client->context, NULL); eekboard_client_show_keyboard (client->eekboard, NULL);
} else if (g_settings_get_boolean (client->settings, "auto-hide") && } else if (g_settings_get_boolean (client->settings, "auto-hide") &&
g_strcmp0 (member, "FocusOut") == 0) { g_strcmp0 (member, "FocusOut") == 0) {
guint delay; guint delay;
@ -653,7 +661,7 @@ focus_message_filter (GDBusConnection *connection,
static void static void
_ibus_connect_focus_handlers (GDBusConnection *connection, gpointer user_data) _ibus_connect_focus_handlers (GDBusConnection *connection, gpointer user_data)
{ {
Client *client = user_data; SeatEmitter *client = user_data;
add_match_rule (connection, add_match_rule (connection,
"type='method_call'," "type='method_call',"
@ -671,7 +679,7 @@ _ibus_connect_focus_handlers (GDBusConnection *connection, gpointer user_data)
} }
gboolean gboolean
client_enable_ibus_focus (Client *client) client_enable_ibus_focus (SeatEmitter *client)
{ {
if (client->ibus_connection == NULL) { if (client->ibus_connection == NULL) {
const gchar *ibus_address; const gchar *ibus_address;
@ -703,7 +711,7 @@ client_enable_ibus_focus (Client *client)
} }
void void
client_disable_ibus_focus (Client *client) client_disable_ibus_focus (SeatEmitter *client)
{ {
client->follows_focus = FALSE; client->follows_focus = FALSE;
@ -717,10 +725,10 @@ client_disable_ibus_focus (Client *client)
} }
} }
Client * SeatEmitter *
client_new (GDBusConnection *connection) client_new (GDBusConnection *connection)
{ {
Client *client = g_object_new (TYPE_CLIENT, SeatEmitter *client = g_object_new (TYPE_CLIENT,
"connection", connection, "connection", connection,
NULL); NULL);
if (client->context) if (client->context)
@ -733,7 +741,7 @@ filter_xkl_event (GdkXEvent *xev,
GdkEvent *event, GdkEvent *event,
gpointer user_data) gpointer user_data)
{ {
Client *client = user_data; SeatEmitter *client = user_data;
XEvent *xevent = (XEvent *)xev; XEvent *xevent = (XEvent *)xev;
xkl_engine_filter_events (client->xkl_engine, xevent); xkl_engine_filter_events (client->xkl_engine, xevent);
@ -744,7 +752,7 @@ static void
on_xkl_config_changed (XklEngine *xklengine, on_xkl_config_changed (XklEngine *xklengine,
gpointer user_data) gpointer user_data)
{ {
Client *client = user_data; SeatEmitter *client = user_data;
gboolean retval; gboolean retval;
retval = set_keyboards_from_xkl (client); retval = set_keyboards_from_xkl (client);
@ -756,7 +764,7 @@ on_xkl_config_changed (XklEngine *xklengine,
} }
static gboolean static gboolean
set_keyboards (Client *client, set_keyboards (SeatEmitter *client,
const gchar * const *keyboards) const gchar * const *keyboards)
{ {
guint keyboard_id; guint keyboard_id;
@ -779,8 +787,8 @@ set_keyboards (Client *client,
for (p = keyboards; *p != NULL; p++) { for (p = keyboards; *p != NULL; p++) {
keyboard_id = eekboard_context_add_keyboard (client->context, *p, NULL); keyboard_id = eekboard_context_add_keyboard (client->context, *p, NULL);
if (keyboard_id == 0) { if (keyboard_id == 0) {
g_slist_free (head); g_warning ("can't add keyboard %s", *p);
return FALSE; continue;
} }
client->keyboards = g_slist_prepend (client->keyboards, client->keyboards = g_slist_prepend (client->keyboards,
GUINT_TO_POINTER(keyboard_id)); GUINT_TO_POINTER(keyboard_id));
@ -797,7 +805,7 @@ set_keyboards (Client *client,
} }
static gboolean static gboolean
set_keyboards_from_xkl (Client *client) set_keyboards_from_xkl (SeatEmitter *client)
{ {
XklConfigRec *rec; XklConfigRec *rec;
gchar *layout, *keyboard; gchar *layout, *keyboard;
@ -829,13 +837,12 @@ on_xkl_state_changed (XklEngine *xklengine,
gboolean restore, gboolean restore,
gpointer user_data) gpointer user_data)
{ {
Client *client = user_data; SeatEmitter *client = user_data;
if (type == GROUP_CHANGED) if (type == GROUP_CHANGED)
eekboard_context_set_group (client->context, value, NULL); eekboard_context_set_group (client->context, value, NULL);
} }
#ifdef HAVE_XTEST
/* The following functions for keyboard mapping change are direct /* The following functions for keyboard mapping change are direct
translation of the code in Caribou (in libcaribou/xadapter.vala): translation of the code in Caribou (in libcaribou/xadapter.vala):
@ -844,7 +851,7 @@ on_xkl_state_changed (XklEngine *xklengine,
- get_keycode_from_gdk_keymap (Caribou: best_keycode_keyval_match) - get_keycode_from_gdk_keymap (Caribou: best_keycode_keyval_match)
*/ */
static guint static guint
get_replaced_keycode (Client *client) get_replaced_keycode (SeatEmitter *client)
{ {
guint keycode; guint keycode;
@ -869,7 +876,7 @@ get_replaced_keycode (Client *client)
non-zero keycode), it simply changes the current map with the non-zero keycode), it simply changes the current map with the
specified KEYCODE and KEYSYM. */ specified KEYCODE and KEYSYM. */
static gboolean static gboolean
replace_keycode (Client *client, replace_keycode (SeatEmitter *client,
guint keycode, guint keycode,
guint *keysym) guint *keysym)
{ {
@ -878,12 +885,13 @@ replace_keycode (Client *client,
guint old_keysym; guint old_keysym;
int keysyms_per_keycode; int keysyms_per_keycode;
KeySym *syms; KeySym *syms;
return TRUE; // FIXME: no xkb allocated at the moment, pretending all is fine
g_return_val_if_fail (client->xkb->min_key_code <= keycode && g_return_val_if_fail (client->xkb->min_key_code <= keycode &&
keycode <= client->xkb->max_key_code, keycode <= client->xkb->max_key_code,
FALSE); FALSE);
g_return_val_if_fail (keysym != NULL, FALSE); g_return_val_if_fail (keysym != NULL, FALSE);
/*
* Switch keyboard mapping?
syms = XGetKeyboardMapping (xdisplay, keycode, 1, &keysyms_per_keycode); syms = XGetKeyboardMapping (xdisplay, keycode, 1, &keysyms_per_keycode);
old_keysym = syms[0]; old_keysym = syms[0];
syms[0] = *keysym; syms[0] = *keysym;
@ -891,12 +899,12 @@ replace_keycode (Client *client,
XSync (xdisplay, False); XSync (xdisplay, False);
XFree (syms); XFree (syms);
*keysym = old_keysym; *keysym = old_keysym;
*/
return TRUE; return TRUE;
} }
static gboolean static gboolean
get_keycode_from_gdk_keymap (Client *client, get_keycode_from_gdk_keymap (SeatEmitter *client,
guint keysym, guint keysym,
guint *keycode, guint *keycode,
guint *modifiers) guint *modifiers)
@ -924,8 +932,18 @@ get_keycode_from_gdk_keymap (Client *client,
return TRUE; return TRUE;
} }
int send_virtual_keyboard_key(
Display* dpy,
unsigned int keycode,
Bool is_press,
unsigned long delay
) {
printf("Sending fake event %d press %d delay %d\n", keycode, is_press, delay);
}
/* never actually used? */
static void static void
send_fake_modifier_key_event (Client *client, send_fake_modifier_key_event (SeatEmitter *client,
EekModifierType modifiers, EekModifierType modifiers,
gboolean is_pressed) gboolean is_pressed)
{ {
@ -936,20 +954,20 @@ send_fake_modifier_key_event (Client *client,
for (i = 0; i < G_N_ELEMENTS(client->modifier_keycodes); i++) { for (i = 0; i < G_N_ELEMENTS(client->modifier_keycodes); i++) {
if (modifiers & (1 << i)) { if (modifiers & (1 << i)) {
guint keycode = client->modifier_keycodes[i]; guint keycode = client->modifier_keycodes[i];
printf("Trying to send a modifier %d press %d\n", i, is_pressed);
g_return_if_fail (keycode > 0); g_return_if_fail (keycode > 0);
XTestFakeKeyEvent (xdisplay, send_virtual_keyboard_key (xdisplay,
keycode, keycode,
is_pressed, is_pressed,
CurrentTime); CurrentTime);
XSync (xdisplay, False); //XSync (xdisplay, False);
} }
} }
} }
static void static void
send_fake_key_event (Client *client, send_fake_key_event (SeatEmitter *client,
guint xkeysym, guint xkeysym,
guint keyboard_modifiers) guint keyboard_modifiers)
{ {
@ -988,10 +1006,10 @@ send_fake_key_event (Client *client,
modifiers |= keyboard_modifiers; modifiers |= keyboard_modifiers;
send_fake_modifier_key_event (client, modifiers, TRUE); send_fake_modifier_key_event (client, modifiers, TRUE);
XTestFakeKeyEvent (xdisplay, keycode, TRUE, 20); send_virtual_keyboard_key (xdisplay, keycode, TRUE, 20);
XSync (xdisplay, False); //XSync (xdisplay, False);
XTestFakeKeyEvent (xdisplay, keycode, FALSE, 20); send_virtual_keyboard_key (xdisplay, keycode, FALSE, 20);
XSync (xdisplay, False); // XSync (xdisplay, False);
send_fake_modifier_key_event (client, modifiers, FALSE); send_fake_modifier_key_event (client, modifiers, FALSE);
if (old_keysym != xkeysym) if (old_keysym != xkeysym)
@ -999,7 +1017,7 @@ send_fake_key_event (Client *client,
} }
static void static void
send_fake_key_events (Client *client, send_fake_key_events (SeatEmitter *client,
EekSymbol *symbol, EekSymbol *symbol,
guint keyboard_modifiers) guint keyboard_modifiers)
{ {
@ -1045,7 +1063,7 @@ on_key_activated (EekboardContext *context,
guint modifiers, guint modifiers,
gpointer user_data) gpointer user_data)
{ {
Client *client = user_data; SeatEmitter *client = user_data;
if (g_strcmp0 (eek_symbol_get_name (symbol), "cycle-keyboard") == 0) { if (g_strcmp0 (eek_symbol_get_name (symbol), "cycle-keyboard") == 0) {
client->keyboards_head = g_slist_next (client->keyboards_head); client->keyboards_head = g_slist_next (client->keyboards_head);
@ -1076,6 +1094,8 @@ on_key_activated (EekboardContext *context,
send_fake_key_events (client, symbol, modifiers); send_fake_key_events (client, symbol, modifiers);
} }
#if 0
/* Finds the first key code for each modifier and saves it in modifier_keycodes */
static void static void
update_modifier_keycodes (Client *client) update_modifier_keycodes (Client *client)
{ {
@ -1097,14 +1117,15 @@ update_modifier_keycodes (Client *client)
} }
XFreeModifiermap (mods); XFreeModifiermap (mods);
} }
#endif
gboolean gboolean
client_enable_xtest (Client *client) client_enable_xtest (SeatEmitter *client)
{ {
GdkDisplay *display = gdk_display_get_default (); //GdkDisplay *display = gdk_display_get_default ();
Display *xdisplay = GDK_DISPLAY_XDISPLAY (display); //Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
int opcode, event_base, error_base, major_version, minor_version; int opcode, event_base, error_base, major_version, minor_version;
/* FIXME: need at least to fetch an xkb keymap (but what for?)
g_assert (display); g_assert (display);
if (!XTestQueryExtension (xdisplay, if (!XTestQueryExtension (xdisplay,
@ -1126,7 +1147,7 @@ client_enable_xtest (Client *client)
g_assert (client->xkb); g_assert (client->xkb);
update_modifier_keycodes (client); update_modifier_keycodes (client);
*/
client->key_activated_handler = client->key_activated_handler =
g_signal_connect (client->context, "key-activated", g_signal_connect (client->context, "key-activated",
G_CALLBACK(on_key_activated), client); G_CALLBACK(on_key_activated), client);
@ -1135,11 +1156,11 @@ client_enable_xtest (Client *client)
} }
void void
client_disable_xtest (Client *client) client_disable_xtest (SeatEmitter *client)
{ {
if (client->xkb) { //if (client->xkb) {
XkbFreeKeyboard (client->xkb, 0, TRUE); /* free_all = TRUE */ // XkbFreeKeyboard (client->xkb, 0, TRUE); /* free_all = TRUE */
client->xkb = NULL; //client->xkb = NULL;
} //}
} }
#endif /* HAVE_XTEST */ //#endif /* HAVE_XTEST */

View File

@ -29,27 +29,27 @@ G_BEGIN_DECLS
#define IS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_CLIENT)) #define IS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_CLIENT))
#define CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_CLIENT, ClientClass)) #define CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_CLIENT, ClientClass))
typedef struct _Client Client; typedef struct _Client SeatEmitter;
Client *client_new (GDBusConnection *connection); SeatEmitter *client_new (GDBusConnection *connection);
gboolean client_set_keyboards (Client *client, gboolean client_set_keyboards (SeatEmitter *client,
const gchar * const *keyboard); const gchar * const *keyboard);
gboolean client_enable_xkl (Client *client); gboolean client_enable_xkl (SeatEmitter *client);
void client_disable_xkl (Client *client); void client_disable_xkl (SeatEmitter *client);
gboolean client_enable_atspi_focus (Client *client); gboolean client_enable_atspi_focus (SeatEmitter *client);
void client_disable_atspi_focus (Client *client); void client_disable_atspi_focus (SeatEmitter *client);
gboolean client_enable_atspi_keystroke (Client *client); gboolean client_enable_atspi_keystroke (SeatEmitter *client);
void client_disable_atspi_keystroke (Client *client); void client_disable_atspi_keystroke (SeatEmitter *client);
gboolean client_enable_xtest (Client *client); gboolean client_enable_xtest (SeatEmitter *client);
void client_disable_xtest (Client *client); void client_disable_xtest (SeatEmitter *client);
gboolean client_enable_ibus_focus (Client *client); gboolean client_enable_ibus_focus (SeatEmitter *client);
void client_disable_ibus_focus (Client *client); void client_disable_ibus_focus (SeatEmitter *client);
G_END_DECLS G_END_DECLS
#endif /* CLIENT_H */ #endif /* CLIENT_H */

43
src/imservice.c Normal file
View File

@ -0,0 +1,43 @@
#include "imservice.h"
#include <glib.h>
#include "eekboard/eekboard-context-service.h"
void imservice_handle_text_change_cause(void *data, struct zwp_input_method_v2 *input_method) {}
void imservice_handle_content_type(void *data, struct zwp_input_method_v2 *input_method) {}
void imservice_handle_unavailable(void *data, struct zwp_input_method_v2 *input_method) {}
static const struct zwp_input_method_v2_listener input_method_listener = {
.activate = imservice_handle_input_method_activate,
.deactivate = imservice_handle_input_method_deactivate,
.surrounding_text = imservice_handle_surrounding_text,
.text_change_cause = imservice_handle_text_change_cause,
.content_type = imservice_handle_content_type,
.done = imservice_handle_commit_state,
.unavailable = imservice_handle_unavailable,
};
struct imservice* get_imservice(EekboardContextService *context,
struct zwp_input_method_manager_v2 *manager,
struct wl_seat *seat) {
struct zwp_input_method_v2 *im = zwp_input_method_manager_v2_get_input_method(manager, seat);
struct imservice *imservice = imservice_new(im, context);
zwp_input_method_v2_add_listener(im,
&input_method_listener, imservice);
return imservice;
}
void imservice_make_visible(EekboardContextService *context,
struct zwp_input_method_v2 *im) {
(void)im;
eekboard_context_service_show_keyboard (context);
}
void imservice_try_hide(EekboardContextService *context,
struct zwp_input_method_v2 *im) {
(void)im;
eekboard_context_service_hide_keyboard (context);
}

22
src/imservice.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef __IMSERVICE_H
#define __IMSERVICE_H
#include "input-method-unstable-v2-client-protocol.h"
#include "eek/eek-types.h"
struct imservice;
struct imservice* get_imservice(EekboardContextService *context,
struct zwp_input_method_manager_v2 *manager,
struct wl_seat *seat);
// Defined in Rust
struct imservice* imservice_new(struct zwp_input_method_v2 *im,
EekboardContextService *context);
void imservice_handle_input_method_activate(void *data, struct zwp_input_method_v2 *input_method);
void imservice_handle_input_method_deactivate(void *data, struct zwp_input_method_v2 *input_method);
void imservice_handle_surrounding_text(void *data, struct zwp_input_method_v2 *input_method,
const char *text, uint32_t cursor, uint32_t anchor);
void imservice_handle_commit_state(void *data, struct zwp_input_method_v2 *input_method);
#endif

137
src/imservice.rs Normal file
View File

@ -0,0 +1,137 @@
use std::boxed::Box;
use std::ffi::CString;
use std::num::Wrapping;
use std::string::String;
/// Gathers stuff defined in C or called by C
pub mod c {
use super::*;
use std::ffi::CStr;
use std::os::raw::{c_char, c_void};
fn into_cstring(s: *const c_char) -> Result<CString, std::ffi::NulError> {
CString::new(
unsafe {CStr::from_ptr(s)}.to_bytes()
)
}
// The following defined in C
/// struct zwp_input_method_v2*
#[repr(transparent)]
pub struct InputMethod(*const c_void);
/// EekboardContextService*
#[repr(transparent)]
pub struct UIManager(*const c_void);
#[no_mangle]
extern "C" {
fn imservice_make_visible(imservice: *const UIManager);
fn imservice_try_hide(imservice: *const UIManager);
}
// The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
#[no_mangle]
pub unsafe extern "C"
fn imservice_new(im: *const InputMethod, ui_manager: *const UIManager) -> *mut IMService {
Box::<IMService>::into_raw(Box::new(
IMService {
im: im,
ui_manager: ui_manager,
pending: IMProtocolState::default(),
current: IMProtocolState::default(),
preedit_string: String::new(),
serial: Wrapping(0u32),
}
))
}
// TODO: is unsafe needed here?
#[no_mangle]
pub unsafe extern "C"
fn imservice_handle_input_method_activate(imservice: *mut IMService,
_im: *const InputMethod)
{
let imservice = &mut *imservice;
imservice.preedit_string = String::new();
imservice.pending = IMProtocolState {
active: true,
..IMProtocolState::default()
};
}
#[no_mangle]
pub unsafe extern "C"
fn imservice_handle_input_method_deactivate(imservice: *mut IMService,
_im: *const InputMethod)
{
let imservice = &mut *imservice;
imservice.pending = IMProtocolState {
active: false,
..imservice.pending.clone()
};
}
#[no_mangle]
pub unsafe extern "C"
fn imservice_handle_surrounding_text(imservice: *mut IMService,
_im: *const InputMethod,
text: *const c_char, cursor: u32, _anchor: u32)
{
let imservice = &mut *imservice;
imservice.pending = IMProtocolState {
surrounding_text: into_cstring(text).expect("Received invalid string"),
surrounding_cursor: cursor,
..imservice.pending
};
}
#[no_mangle]
pub unsafe extern "C"
fn imservice_handle_commit_state(imservice: *mut IMService,
_im: *const InputMethod)
{
let imservice = &mut *imservice;
let active_changed = imservice.current.active ^ imservice.pending.active;
imservice.serial += Wrapping(1u32);
imservice.current = imservice.pending.clone();
imservice.pending = IMProtocolState {
active: imservice.current.active,
..IMProtocolState::default()
};
if active_changed {
if imservice.current.active {
imservice_make_visible(imservice.ui_manager);
} else {
imservice_try_hide(imservice.ui_manager);
}
}
}
// FIXME: destroy and deallocate
}
/// Describes the desired state of the input method as requested by the server
#[derive(Default, Clone)]
struct IMProtocolState {
surrounding_text: CString,
surrounding_cursor: u32,
active: bool,
}
pub struct IMService {
/// Owned reference (still created and destroyed in C)
im: *const c::InputMethod,
/// Unowned reference. Be careful, it's shared with C at large
ui_manager: *const c::UIManager,
pending: IMProtocolState,
current: IMProtocolState, // turn current into an idiomatic representation?
preedit_string: String,
serial: Wrapping<u32>,
}

80
src/meson.build Normal file
View File

@ -0,0 +1,80 @@
gnome = import('gnome')
dbus_src = gnome.gdbus_codegen(
'sm.puri.OSK0',
'../data/dbus/sm.puri.OSK0.xml'
)
sources = [
'imservice.c',
'server-context-service.c',
'server-main.c',
'wayland.c',
'../eek/eek.c',
'../eek/eek-container.c',
'../eek/eek-element.c',
'../eek/eek-gtk-keyboard.c',
'../eek/eek-gtk-renderer.c',
'../eek/eek-key.c',
'../eek/eek-keyboard.c',
'../eek/eek-keyboard-drawing.c',
'../eek/eek-keysym.c',
'../eek/eek-layout.c',
'../eek/eek-renderer.c',
'../eek/eek-section.c',
'../eek/eek-serializable.c',
'../eek/eek-symbol.c',
'../eek/eek-symbol-matrix.c',
'../eek/eek-text.c',
'../eek/eek-theme.c',
'../eek/eek-theme-context.c',
'../eek/eek-theme-node.c',
'../eek/eek-types.c',
'../eek/eek-xml-layout.c',
'../eek/layersurface.c',
dbus_src,
enums,
keysym_entries,
marshalers,
'../eekboard/keymap.c',
'../eekboard/key-emitter.c',
'../eekboard/eekboard-context-service.c',
'../eekboard/eekboard-context.c',
'../eekboard/eekboard-service.c',
# '../eekboard/eekboard-xklutil.c',
wl_proto_sources,
]
cc = meson.get_compiler('c')
deps = [
# dependency('glib-2.0', version: '>=2.26.0'),
dependency('gio-2.0', version: '>=2.26.0'),
dependency('gtk+-3.0', version: '>=3.0'),
dependency('libcroco-0.6'),
dependency('wayland-client', version: '>=1.14'),
dependency('xkbcommon'),
cc.find_library('m'),
cc.find_library('rt'),
cc.find_library('libstd-79f126b09196cdf2'),
# dependency('libxklavier'), # FIXME remove
]
# Replacement for eekboard-server
rslib = static_library(
'rslib',
sources: ['imservice.rs']
)
squeekboard = executable('squeekboard',
sources,
link_with: [rslib],
include_directories: [include_directories('..'), include_directories('../eek')],
dependencies: deps,
install: true,
c_args: [
'-DTHEMESDIR="' + pkgdatadir + '/themes"',
'-DKEYBOARDSDIR="' + pkgdatadir + '/keyboards"',
'-DEEKBOARD_COMPILATION=1',
'-DEEK_COMPILATION=1'],
)

View File

@ -22,10 +22,11 @@
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <glib/gi18n.h> #include <glib/gi18n.h>
#include <X11/Xatom.h>
#include <gdk/gdkx.h> #include <gdk/gdkx.h>
#include "eek/eek-gtk.h" #include "eek/eek-gtk.h"
#include "eek/layersurface.h"
#include "wayland.h"
#include "server-context-service.h" #include "server-context-service.h"
@ -48,7 +49,6 @@ struct _ServerContextService {
gulong notify_visible_handler; gulong notify_visible_handler;
GSettings *settings;
gdouble size_constraint_landscape[2]; gdouble size_constraint_landscape[2];
gdouble size_constraint_portrait[2]; gdouble size_constraint_portrait[2];
}; };
@ -95,6 +95,17 @@ on_notify_keyboard (GObject *object,
const EekKeyboard *keyboard; const EekKeyboard *keyboard;
keyboard = eekboard_context_service_get_keyboard (EEKBOARD_CONTEXT_SERVICE(context)); keyboard = eekboard_context_service_get_keyboard (EEKBOARD_CONTEXT_SERVICE(context));
if (!keyboard) {
g_error("Programmer error: keyboard layout was unset!");
}
// The keymap will get set even if the window is hidden.
// It's not perfect,
// but simpler than adding a check in the window showing procedure
eekboard_context_service_set_keymap(EEKBOARD_CONTEXT_SERVICE(context),
keyboard);
if (context->window) { if (context->window) {
if (keyboard == NULL) { if (keyboard == NULL) {
gtk_widget_hide (context->window); gtk_widget_hide (context->window);
@ -106,8 +117,9 @@ on_notify_keyboard (GObject *object,
g_signal_handler_block (context->window, g_signal_handler_block (context->window,
context->notify_visible_handler); context->notify_visible_handler);
update_widget (context); update_widget (context);
if (was_visible) if (was_visible) {
gtk_widget_show_all (context->window); gtk_widget_show_all (context->window);
}
g_signal_handler_unblock (context->window, g_signal_handler_unblock (context->window,
context->notify_visible_handler); context->notify_visible_handler);
} }
@ -242,7 +254,7 @@ set_geometry (ServerContextService *context)
else else
height = (width / bounds.width) * bounds.height; height = (width / bounds.width) * bounds.height;
gtk_widget_set_size_request (context->widget, width, height); gtk_window_resize (GTK_WINDOW(context->widget), width, height);
gtk_window_move (GTK_WINDOW(context->window), gtk_window_move (GTK_WINDOW(context->window),
(rect.width - width) / 2, (rect.width - width) / 2,
@ -250,8 +262,6 @@ set_geometry (ServerContextService *context)
gtk_window_set_decorated (GTK_WINDOW(context->window), FALSE); gtk_window_set_decorated (GTK_WINDOW(context->window), FALSE);
gtk_window_set_resizable (GTK_WINDOW(context->window), FALSE); gtk_window_set_resizable (GTK_WINDOW(context->window), FALSE);
gtk_window_set_opacity (GTK_WINDOW(context->window), 0.8);
g_signal_connect_after (context->window, "realize", g_signal_connect_after (context->window, "realize",
G_CALLBACK(on_realize_set_dock), G_CALLBACK(on_realize_set_dock),
context); context);
@ -259,9 +269,9 @@ set_geometry (ServerContextService *context)
G_CALLBACK(on_size_allocate_set_dock), G_CALLBACK(on_size_allocate_set_dock),
context); context);
} else { } else {
gtk_widget_set_size_request (context->widget, gtk_window_resize (GTK_WINDOW(context->window),
bounds.width, bounds.width,
bounds.height); bounds.height);
gtk_window_move (GTK_WINDOW(context->window), gtk_window_move (GTK_WINDOW(context->window),
MAX(rect.width - 20 - bounds.width, 0), MAX(rect.width - 20 - bounds.width, 0),
MAX(rect.height - 40 - bounds.height, 0)); MAX(rect.height - 40 - bounds.height, 0));
@ -271,13 +281,56 @@ set_geometry (ServerContextService *context)
} }
} }
static void
make_window (ServerContextService *context) {
if (context->window) {
g_error("Window already present");
return;
}
context->window = GTK_WIDGET(g_object_new (
PHOSH_TYPE_LAYER_SURFACE,
"layer-shell", squeek_wayland->layer_shell,
"wl-output", g_ptr_array_index(squeek_wayland->outputs, 0), // TODO: select output as needed,
"height", 200,
"anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM
| ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
| ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT,
"layer", ZWLR_LAYER_SHELL_V1_LAYER_TOP,
"kbd-interactivity", FALSE,
"exclusive-zone", 200,
//"namespace", "phosh home",
NULL
));
g_signal_connect (context->window, "destroy",
G_CALLBACK(on_destroy), context);
context->notify_visible_handler =
g_signal_connect (context->window, "notify::visible",
G_CALLBACK(on_notify_visible), context);
// The properties below are just to make hacking easier.
// The way we use layer-shell overrides some,
// and there's no space in the protocol for others.
// Those may still be useful in the future,
// or for hacks with regular windows.
gtk_widget_set_can_focus (context->window, FALSE);
g_object_set (G_OBJECT(context->window), "accept_focus", FALSE, NULL);
gtk_window_set_title (GTK_WINDOW(context->window),
_("Squeekboard"));
gtk_window_set_icon_name (GTK_WINDOW(context->window), "squeekboard");
gtk_window_set_keep_above (GTK_WINDOW(context->window), TRUE);
}
static void
destroy_window (ServerContextService *context) {
context->window = NULL;
}
static void static void
update_widget (ServerContextService *context) update_widget (ServerContextService *context)
{ {
EekKeyboard *keyboard; EekKeyboard *keyboard;
const gchar *client_name;
EekBounds bounds; EekBounds bounds;
gchar *theme_name, *theme_filename, *theme_path; gchar *theme_path;
EekTheme *theme; EekTheme *theme;
if (context->widget) { if (context->widget) {
@ -285,12 +338,7 @@ update_widget (ServerContextService *context)
context->widget = NULL; context->widget = NULL;
} }
theme_name = g_settings_get_string (context->settings, "theme"); theme_path = g_build_filename (THEMESDIR, "default.css", NULL);
theme_filename = g_strdup_printf ("%s.css", theme_name);
g_free (theme_name);
theme_path = g_build_filename (THEMESDIR, theme_filename, NULL);
g_free (theme_filename);
theme = eek_theme_new (theme_path, NULL, NULL); theme = eek_theme_new (theme_path, NULL, NULL);
g_free (theme_path); g_free (theme_path);
@ -301,22 +349,7 @@ update_widget (ServerContextService *context)
eek_gtk_keyboard_set_theme (EEK_GTK_KEYBOARD(context->widget), theme); eek_gtk_keyboard_set_theme (EEK_GTK_KEYBOARD(context->widget), theme);
g_object_unref (theme); g_object_unref (theme);
if (!context->window) { gtk_widget_set_has_tooltip (context->widget, TRUE);
context->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (context->window, "destroy",
G_CALLBACK(on_destroy), context);
context->notify_visible_handler =
g_signal_connect (context->window, "notify::visible",
G_CALLBACK(on_notify_visible), context);
gtk_widget_set_can_focus (context->window, FALSE);
g_object_set (G_OBJECT(context->window), "accept_focus", FALSE, NULL);
client_name = eekboard_context_service_get_client_name (EEKBOARD_CONTEXT_SERVICE(context));
gtk_window_set_title (GTK_WINDOW(context->window),
client_name ? client_name : _("Keyboard"));
gtk_window_set_icon_name (GTK_WINDOW(context->window), "eekboard");
gtk_window_set_keep_above (GTK_WINDOW(context->window), TRUE);
}
gtk_container_add (GTK_CONTAINER(context->window), context->widget); gtk_container_add (GTK_CONTAINER(context->window), context->widget);
set_geometry (context); set_geometry (context);
} }
@ -326,10 +359,11 @@ server_context_service_real_show_keyboard (EekboardContextService *_context)
{ {
ServerContextService *context = SERVER_CONTEXT_SERVICE(_context); ServerContextService *context = SERVER_CONTEXT_SERVICE(_context);
if (!context->window) make_window (context);
update_widget (context); update_widget (context);
g_assert (context->window);
gtk_widget_show_all (context->window); EEKBOARD_CONTEXT_SERVICE_CLASS (server_context_service_parent_class)->
show_keyboard (_context);
} }
static void static void
@ -337,8 +371,12 @@ server_context_service_real_hide_keyboard (EekboardContextService *_context)
{ {
ServerContextService *context = SERVER_CONTEXT_SERVICE(_context); ServerContextService *context = SERVER_CONTEXT_SERVICE(_context);
if (context->window) gtk_widget_hide (context->window);
gtk_widget_hide (context->window); gtk_container_remove(GTK_CONTAINER(context->window), context->widget);
destroy_window (context);
EEKBOARD_CONTEXT_SERVICE_CLASS (server_context_service_parent_class)->
hide_keyboard (_context);
} }
static void static void
@ -464,32 +502,11 @@ server_context_service_init (ServerContextService *context)
"notify::fullscreen", "notify::fullscreen",
G_CALLBACK(on_notify_fullscreen), G_CALLBACK(on_notify_fullscreen),
context); context);
context->settings = g_settings_new ("org.fedorahosted.eekboard");
g_settings_bind_with_mapping (context->settings, "size-constraint-landscape",
context, "size-constraint-landscape",
G_SETTINGS_BIND_GET,
(GSettingsBindGetMapping)g_value_set_variant,
NULL,
NULL,
NULL);
g_settings_bind_with_mapping (context->settings, "size-constraint-portrait",
context, "size-constraint-portrait",
G_SETTINGS_BIND_GET,
(GSettingsBindGetMapping)g_value_set_variant,
NULL,
NULL,
NULL);
} }
ServerContextService * EekboardContextService *
server_context_service_new (const gchar *client_name, server_context_service_new ()
const gchar *object_path,
GDBusConnection *connection)
{ {
return g_object_new (SERVER_TYPE_CONTEXT_SERVICE, return EEKBOARD_CONTEXT_SERVICE(g_object_new (SERVER_TYPE_CONTEXT_SERVICE,
"client-name", client_name, NULL));
"object-path", object_path,
"connection", connection,
NULL);
} }

View File

@ -18,10 +18,10 @@
#ifndef SERVER_CONTEXT_SERVICE_H #ifndef SERVER_CONTEXT_SERVICE_H
#define SERVER_CONTEXT_SERVICE_H 1 #define SERVER_CONTEXT_SERVICE_H 1
G_BEGIN_DECLS
#include "eekboard/eekboard-service.h" #include "eekboard/eekboard-service.h"
G_BEGIN_DECLS
#define SERVER_TYPE_CONTEXT_SERVICE (server_context_service_get_type()) #define SERVER_TYPE_CONTEXT_SERVICE (server_context_service_get_type())
#define SERVER_CONTEXT_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SERVER_TYPE_CONTEXT_SERVICE, ServerContextService)) #define SERVER_CONTEXT_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SERVER_TYPE_CONTEXT_SERVICE, ServerContextService))
#define SERVER_CONTEXT_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SERVER_TYPE_CONTEXT_SERVICE, ServerContextServiceClass)) #define SERVER_CONTEXT_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SERVER_TYPE_CONTEXT_SERVICE, ServerContextServiceClass))
@ -29,11 +29,10 @@ G_BEGIN_DECLS
#define SERVER_IS_CONTEXT_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SERVER_TYPE_CONTEXT_SERVICE)) #define SERVER_IS_CONTEXT_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SERVER_TYPE_CONTEXT_SERVICE))
#define SERVER_CONTEXT_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SERVER_TYPE_CONTEXT_SERVICE, ServerContextServiceClass)) #define SERVER_CONTEXT_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SERVER_TYPE_CONTEXT_SERVICE, ServerContextServiceClass))
/** Manages the liecycle of the window displaying layouts. */
typedef struct _ServerContextService ServerContextService; typedef struct _ServerContextService ServerContextService;
ServerContextService *server_context_service_new (const gchar *client_name, EekboardContextService *server_context_service_new ();
const gchar *object_path,
GDBusConnection *connection);
G_END_DECLS G_END_DECLS
#endif /* SERVER_CONTEXT_SERVICE_H */ #endif /* SERVER_CONTEXT_SERVICE_H */

View File

@ -1,6 +1,9 @@
/* /*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org> * Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc. * Copyright (C) 2010-2011 Red Hat, Inc.
* Copyright (C) 2018-2019 Purism SPC
* SPDX-License-Identifier: GPL-3.0+
* Author: Guido Günther <agx@sigxcpu.org>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -28,28 +31,36 @@
#include <clutter-gtk/clutter-gtk.h> #include <clutter-gtk/clutter-gtk.h>
#endif #endif
#include "server-service.h" #include "eekboard/eekboard-service.h"
#include "eek/eek.h" #include "eek/eek.h"
#include "imservice.h"
#include "server-context-service.h"
#include "wayland.h"
#include <gdk/gdkwayland.h>
/// Global application state
struct squeekboard {
struct squeek_wayland wayland;
EekboardContextService *context;
struct imservice *imservice;
};
static gboolean opt_system = FALSE; static gboolean opt_system = FALSE;
static gboolean opt_session = FALSE;
static gchar *opt_address = NULL; static gchar *opt_address = NULL;
static const GOptionEntry options[] = { // D-Bus
{"system", 'y', 0, G_OPTION_ARG_NONE, &opt_system,
N_("Connect to the system bus")},
{"session", 'e', 0, G_OPTION_ARG_NONE, &opt_session,
N_("Connect to the session bus")},
{"address", 'a', 0, G_OPTION_ARG_STRING, &opt_address,
N_("Connect to the given D-Bus address")},
{NULL}
};
static void static void
on_name_acquired (GDBusConnection *connection, on_name_acquired (GDBusConnection *connection,
const gchar *name, const gchar *name,
gpointer user_data) gpointer user_data)
{ {
(void)connection;
(void)name;
(void)user_data;
} }
static void static void
@ -57,42 +68,126 @@ on_name_lost (GDBusConnection *connection,
const gchar *name, const gchar *name,
gpointer user_data) gpointer user_data)
{ {
exit (1); // TODO: could conceivable continue working
(void)connection;
(void)name;
(void)user_data;
exit (1);
} }
static void static void
on_destroyed (ServerService *service, on_destroyed (EekboardService *service,
gpointer user_data) gpointer user_data)
{ {
(void)service;
GMainLoop *loop = user_data; GMainLoop *loop = user_data;
g_main_loop_quit (loop); g_main_loop_quit (loop);
} }
static EekboardContextService *create_context() {
EekboardContextService *context = server_context_service_new ();
g_object_set_data_full (G_OBJECT(context),
"owner", g_strdup ("sender"),
(GDestroyNotify)g_free);
eekboard_context_service_enable (context);
return context;
}
// Wayland
static void
registry_handle_global (void *data,
struct wl_registry *registry,
uint32_t name,
const char *interface,
uint32_t version)
{
// currently only v1 supported for most interfaces,
// so there's no reason to check for available versions.
// Even when lower version would be served, it would not be supported,
// causing a hard exit
(void)version;
struct squeekboard *instance = data;
if (!strcmp (interface, zwlr_layer_shell_v1_interface.name)) {
instance->wayland.layer_shell = wl_registry_bind (registry, name,
&zwlr_layer_shell_v1_interface, 1);
} else if (!strcmp (interface, zwp_virtual_keyboard_manager_v1_interface.name)) {
instance->wayland.virtual_keyboard_manager = wl_registry_bind(registry, name,
&zwp_virtual_keyboard_manager_v1_interface, 1);
} else if (!strcmp (interface, zwp_input_method_manager_v2_interface.name)) {
instance->wayland.input_method_manager = wl_registry_bind(registry, name,
&zwp_input_method_manager_v2_interface, 1);
} else if (!strcmp (interface, "wl_output")) {
struct wl_output *output = wl_registry_bind (registry, name,
&wl_output_interface, 2);
g_ptr_array_add (instance->wayland.outputs, output);
} else if (!strcmp(interface, "wl_seat")) {
instance->wayland.seat = wl_registry_bind(registry, name,
&wl_seat_interface, 1);
}
}
static void
registry_handle_global_remove (void *data,
struct wl_registry *registry,
uint32_t name)
{
// TODO
}
static const struct wl_registry_listener registry_listener = {
registry_handle_global,
registry_handle_global_remove
};
int int
main (int argc, char **argv) main (int argc, char **argv)
{ {
ServerService *service;
GBusType bus_type;
GDBusConnection *connection;
GError *error;
GMainLoop *loop;
guint owner_id;
#if HAVE_CLUTTER_GTK
if (gtk_clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) {
g_printerr ("Can't init GTK with Clutter\n");
exit (1);
}
#else
if (!gtk_init_check (&argc, &argv)) { if (!gtk_init_check (&argc, &argv)) {
g_printerr ("Can't init GTK\n"); g_printerr ("Can't init GTK\n");
exit (1); exit (1);
} }
#endif
eek_init (); eek_init ();
// Set up Wayland
gdk_set_allowed_backends ("wayland");
GdkDisplay *gdk_display = gdk_display_get_default ();
struct wl_display *display = gdk_wayland_display_get_wl_display (gdk_display);
if (display == NULL) {
g_error ("Failed to get display: %m\n");
exit(1);
}
struct squeekboard instance = {0};
squeek_wayland_init (&instance.wayland);
struct wl_registry *registry = wl_display_get_registry (display);
wl_registry_add_listener (registry, &registry_listener, &instance);
wl_display_roundtrip(display); // wait until the registry is actually populated
squeek_wayland_set_global(&instance.wayland);
if (!instance.wayland.seat) {
g_error("No seat Wayland global available.");
exit(1);
}
if (!instance.wayland.virtual_keyboard_manager) {
g_error("No virtual keyboard manager Wayland global available.");
exit(1);
}
instance.context = create_context();
// set up dbus
// TODO: make dbus errors non-always-fatal
// dbus is not strictly necessary for the useful operation
// if text-input is used, as it can bring the keyboard in and out
GBusType bus_type;
if (opt_system) if (opt_system)
bus_type = G_BUS_TYPE_SYSTEM; bus_type = G_BUS_TYPE_SYSTEM;
else if (opt_address) else if (opt_address)
@ -100,6 +195,8 @@ main (int argc, char **argv)
else else
bus_type = G_BUS_TYPE_SESSION; bus_type = G_BUS_TYPE_SESSION;
GDBusConnection *connection = NULL;
GError *error = NULL;
switch (bus_type) { switch (bus_type) {
case G_BUS_TYPE_SYSTEM: case G_BUS_TYPE_SYSTEM:
case G_BUS_TYPE_SESSION: case G_BUS_TYPE_SESSION:
@ -131,14 +228,16 @@ main (int argc, char **argv)
break; break;
} }
service = server_service_new (EEKBOARD_SERVICE_PATH, connection); EekboardService *service = eekboard_service_new (connection, EEKBOARD_SERVICE_PATH);
if (service == NULL) { if (service == NULL) {
g_printerr ("Can't create server\n"); g_printerr ("Can't create dbus server\n");
exit (1); exit (1);
} else {
eekboard_service_set_context(service, instance.context);
} }
owner_id = g_bus_own_name_on_connection (connection, guint owner_id = g_bus_own_name_on_connection (connection,
EEKBOARD_SERVICE_INTERFACE, EEKBOARD_SERVICE_INTERFACE,
G_BUS_NAME_OWNER_FLAGS_NONE, G_BUS_NAME_OWNER_FLAGS_NONE,
on_name_acquired, on_name_acquired,
@ -150,7 +249,19 @@ main (int argc, char **argv)
exit (1); exit (1);
} }
loop = g_main_loop_new (NULL, FALSE); struct imservice *imservice = NULL;
if (instance.wayland.input_method_manager) {
imservice = get_imservice(instance.context,
instance.wayland.input_method_manager,
instance.wayland.seat);
if (imservice) {
instance.imservice = imservice;
} else {
g_warning("Failed to register as an input method");
}
}
GMainLoop *loop = g_main_loop_new (NULL, FALSE);
g_signal_connect (service, "destroyed", G_CALLBACK(on_destroyed), loop); g_signal_connect (service, "destroyed", G_CALLBACK(on_destroyed), loop);
@ -161,5 +272,6 @@ main (int argc, char **argv)
g_object_unref (connection); g_object_unref (connection);
g_main_loop_unref (loop); g_main_loop_unref (loop);
squeek_wayland_deinit (&instance.wayland);
return 0; return 0;
} }

View File

@ -1,71 +0,0 @@
/*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include "server-service.h"
#include "server-context-service.h"
typedef struct _ServerServiceClass ServerServiceClass;
struct _ServerService {
EekboardService parent;
};
struct _ServerServiceClass {
EekboardServiceClass parent_class;
};
G_DEFINE_TYPE (ServerService, server_service, EEKBOARD_TYPE_SERVICE);
static EekboardContextService *
server_service_real_create_context (EekboardService *self,
const gchar *client_name,
const gchar *object_path)
{
GDBusConnection *connection;
ServerContextService *context;
g_object_get (G_OBJECT(self), "connection", &connection, NULL);
context = server_context_service_new (client_name, object_path, connection);
g_object_unref (connection);
return EEKBOARD_CONTEXT_SERVICE(context);
}
static void
server_service_class_init (ServerServiceClass *klass)
{
EekboardServiceClass *service_class = EEKBOARD_SERVICE_CLASS(klass);
service_class->create_context = server_service_real_create_context;
}
static void
server_service_init (ServerService *self)
{
}
ServerService *server_service_new (const gchar *object_path,
GDBusConnection *connection)
{
return g_object_new (SERVER_TYPE_SERVICE,
"object-path", object_path,
"connection", connection,
NULL);
}

View File

@ -1,38 +0,0 @@
/*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SERVER_SERVICE_H
#define SERVER_SERVICE_H 1
#include "eekboard/eekboard-service.h"
G_BEGIN_DECLS
#define SERVER_TYPE_SERVICE (server_service_get_type())
#define SERVER_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SERVER_TYPE_SERVICE, ServerService))
#define SERVER_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SERVER_TYPE_SERVICE, ServerServiceClass))
#define SERVER_IS_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SERVER_TYPE_SERVICE))
#define SERVER_IS_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SERVER_TYPE_SERVICE))
#define SERVER_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SERVER_TYPE_SERVICE, ServerServiceClass))
typedef struct _ServerService ServerService;
ServerService *server_service_new (const gchar *object_path,
GDBusConnection *connection);
G_END_DECLS
#endif /* SERVER_SERVICE_H */

3
src/wayland.c Normal file
View File

@ -0,0 +1,3 @@
#include "wayland.h"
struct squeek_wayland *squeek_wayland = NULL;

35
src/wayland.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef WAYLAND_H
#define WAYLAND_H
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
#include "virtual-keyboard-unstable-v1-client-protocol.h"
#include "input-method-unstable-v2-client-protocol.h"
#include <gmodule.h>
struct squeek_wayland {
struct zwlr_layer_shell_v1 *layer_shell;
struct zwp_virtual_keyboard_manager_v1 *virtual_keyboard_manager;
struct zwp_input_method_manager_v2 *input_method_manager;
GPtrArray *outputs; // *wl_output
struct wl_seat *seat;
};
extern struct squeek_wayland *squeek_wayland;
static inline void squeek_wayland_init(struct squeek_wayland *wayland) {
wayland->outputs = g_ptr_array_new();
}
static inline void squeek_wayland_set_global(struct squeek_wayland *wayland) {
squeek_wayland = wayland;
}
static inline void squeek_wayland_deinit(struct squeek_wayland *wayland) {
g_ptr_array_free(wayland->outputs, TRUE);
}
#endif // WAYLAND_H

View File

@ -28,3 +28,5 @@ eek_simple_test_LDADD = $(top_builddir)/eek/libeek.la $(GIO2_LIBS)
eek_xml_test_SOURCES = eek-xml-test.c eek_xml_test_SOURCES = eek-xml-test.c
eek_xml_test_LDADD = $(top_builddir)/eek/libeek.la $(top_builddir)/eek/libeek-xkl.la $(GIO2_LIBS) $(GTK_LIBS) eek_xml_test_LDADD = $(top_builddir)/eek/libeek.la $(top_builddir)/eek/libeek-xkl.la $(GIO2_LIBS) $(GTK_LIBS)
-include $(top_srcdir)/git.mk