Compare commits
94 Commits
eekboard-1
...
remove-tri
| Author | SHA1 | Date | |
|---|---|---|---|
| 2b8fa0902e | |||
| ab2a27345d | |||
| 484eb3303c | |||
| 60250ca5e5 | |||
| d729bb3a89 | |||
| 4dc55635d7 | |||
| 4af49ef7b6 | |||
| 3a42e66504 | |||
| 250b196b81 | |||
| 9ba1987cab | |||
| 909b1e2a28 | |||
| e46af41abf | |||
| 17671a3b08 | |||
| b8eb7752e7 | |||
| 5e92f45111 | |||
| baf848c791 | |||
| 737d57c1f4 | |||
| 9985ad7ee1 | |||
| 025b55e1a2 | |||
| 14fbabe8d7 | |||
| b746f7a70e | |||
| 0d3b003aac | |||
| 9428927879 | |||
| 511b2f7186 | |||
| d8c83e3c65 | |||
| 050fd6f3ba | |||
| 72d6a8d4e1 | |||
| 30d35216f6 | |||
| bcd0d40912 | |||
| 4b8a6bbbe0 | |||
| 752dc467a8 | |||
| bde45b262a | |||
| fc338f5723 | |||
| 346ed453ef | |||
| 664f05edba | |||
| edcff44f4b | |||
| 42ee5d2ddb | |||
| 54e421d7e6 | |||
| 9e5629d1e0 | |||
| c0fdffac28 | |||
| e94e64d204 | |||
| e503e35b84 | |||
| 752592a3d8 | |||
| 2e6d194a6f | |||
| 63dfb07b51 | |||
| 02525056d6 | |||
| 8292429648 | |||
| 765c496068 | |||
| d6feec8010 | |||
| f1fbb37547 | |||
| 5a6386dd24 | |||
| 0809db9e32 | |||
| 15a3315854 | |||
| 82d1f256b2 | |||
| e7ba2a0eb0 | |||
| eff0449b3a | |||
| 3b9e066ec8 | |||
| 260ab42b9e | |||
| a3d745edd0 | |||
| 40a92fe730 | |||
| e30bb23711 | |||
| 292c1d08d8 | |||
| be56447614 | |||
| 70fda8ba64 | |||
| 5cc407986b | |||
| 53af829f46 | |||
| 53065a6d95 | |||
| 862cfdb55d | |||
| b065b16bf1 | |||
| 6ff33b48d1 | |||
| d04020f79c | |||
| 6b15072764 | |||
| f261115ac4 | |||
| 116f130c4c | |||
| cad1b02482 | |||
| 09fe69f63a | |||
| 8ecd81d51c | |||
| 8f71b010cc | |||
| b817c6189d | |||
| a00d41930d | |||
| caee942796 | |||
| d3410fdc61 | |||
| 8087c3e5d4 | |||
| 10bd0ea09e | |||
| 5803222e68 | |||
| a243fce1ae | |||
| c8059ebf50 | |||
| ce2d270e7c | |||
| 0c945bdc7e | |||
| 60ec684853 | |||
| b159625e62 | |||
| e212262f29 | |||
| c71167d893 | |||
| 2d4e4c7a13 |
19
.gitlab-ci.yml
Normal file
19
.gitlab-ci.yml
Normal 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
|
||||
|
||||
@ -19,6 +19,8 @@
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
SUBDIRS = eek eekboard src tests bindings docs po data examples
|
||||
DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc --enable-introspection
|
||||
AUTOMAKE_OPTIONS = foreign # allow README.md to exist
|
||||
|
||||
|
||||
GITIGNOREFILES = \
|
||||
INSTALL \
|
||||
|
||||
35
README
35
README
@ -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
68
README.md
Normal 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
|
||||
```
|
||||
@ -7,17 +7,12 @@ test -z "$srcdir" && srcdir=.
|
||||
PKG_NAME="eekboard"
|
||||
|
||||
(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 " top-level $PKG_NAME directory"
|
||||
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"
|
||||
REQUIRED_AUTOMAKE_VERSION=1.10
|
||||
REQUIRED_AUTOCONF_VERSION=2.60
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301 USA
|
||||
|
||||
NULL =
|
||||
|
||||
if ENABLE_VALA
|
||||
vapidir = $(datadir)/vala/vapi
|
||||
dist_vapi_DATA = \
|
||||
@ -45,42 +47,45 @@ maintainer-clean-local:
|
||||
eek_vapi_deps = \
|
||||
$(srcdir)/Eek-$(EEK_API_VERSION).metadata \
|
||||
| \
|
||||
$(top_srcdir)/eek/Eek-$(EEK_API_VERSION).gir \
|
||||
$(top_builddir)/eek/Eek-$(EEK_API_VERSION).gir \
|
||||
$(NULL)
|
||||
|
||||
eek-$(EEK_API_VERSION).vapi: $(eek_vapi_deps)
|
||||
$(VAPIGEN_V)$(VAPIGEN) \
|
||||
--library eek-$(EEK_API_VERSION) \
|
||||
--pkg gio-2.0 \
|
||||
--metadatadir=$(srcdir) \
|
||||
$(top_srcdir)/eek/Eek-$(EEK_API_VERSION).gir
|
||||
$(VAPIGEN_V)$(VAPIGEN) \
|
||||
--library eek-$(EEK_API_VERSION) \
|
||||
--pkg gio-2.0 \
|
||||
--metadatadir=$(srcdir) \
|
||||
$(top_builddir)/eek/Eek-$(EEK_API_VERSION).gir
|
||||
|
||||
eek_gtk_vapi_deps = \
|
||||
$(srcdir)/EekGtk-$(EEK_API_VERSION).metadata \
|
||||
| \
|
||||
$(top_srcdir)/eek/EekGtk-$(EEK_API_VERSION).gir \
|
||||
$(top_builddir)/eek/EekGtk-$(EEK_API_VERSION).gir \
|
||||
$(NULL)
|
||||
|
||||
eek-gtk-$(EEK_API_VERSION).vapi: $(eek_gtk_vapi_deps)
|
||||
$(VAPIGEN_V)$(VAPIGEN) --vapidir=$(builddir) \
|
||||
--library eek-gtk-$(EEK_API_VERSION) \
|
||||
--pkg eek-$(EEK_API_VERSION) \
|
||||
--pkg gtk+-3.0 \
|
||||
--metadatadir=$(srcdir) \
|
||||
$(top_srcdir)/eek/EekGtk-$(EEK_API_VERSION).gir
|
||||
$(VAPIGEN_V)$(VAPIGEN) --vapidir=$(builddir) \
|
||||
--library eek-gtk-$(EEK_API_VERSION) \
|
||||
--pkg eek-$(EEK_API_VERSION) \
|
||||
--pkg gio-2.0 \
|
||||
--pkg gtk+-3.0 \
|
||||
--metadatadir=$(srcdir) \
|
||||
$(top_builddir)/eek/EekGtk-$(EEK_API_VERSION).gir
|
||||
|
||||
eek_xkl_vapi_deps = \
|
||||
$(srcdir)/EekXkl-$(EEK_API_VERSION).metadata \
|
||||
| \
|
||||
$(top_srcdir)/eek/EekXkl-$(EEK_API_VERSION).gir \
|
||||
eek_xkl_vapi_deps = \
|
||||
$(srcdir)/EekXkl-$(EEK_API_VERSION).metadata \
|
||||
| \
|
||||
$(top_builddir)/eek/EekXkl-$(EEK_API_VERSION).gir \
|
||||
$(NULL)
|
||||
|
||||
eek-xkl-$(EEK_API_VERSION).vapi: $(eek_xkl_vapi_deps)
|
||||
$(VAPIGEN_V)$(VAPIGEN) --vapidir=$(builddir) \
|
||||
--library eek-xkl-$(EEK_API_VERSION) \
|
||||
--pkg eek-$(EEK_API_VERSION) \
|
||||
--metadatadir=$(srcdir) \
|
||||
$(top_srcdir)/eek/EekXkl-$(EEK_API_VERSION).gir
|
||||
$(VAPIGEN_V)$(VAPIGEN) \
|
||||
--vapidir=$(builddir) \
|
||||
--library eek-xkl-$(EEK_API_VERSION) \
|
||||
--pkg eek-$(EEK_API_VERSION) \
|
||||
--pkg gio-2.0 \
|
||||
--metadatadir=$(srcdir) \
|
||||
$(top_builddir)/eek/EekXkl-$(EEK_API_VERSION).gir
|
||||
|
||||
# set up the verbosity rules to avoid some build noise
|
||||
VAPIGEN_V = $(VAPIGEN_V_$(V))
|
||||
|
||||
@ -1 +1,2 @@
|
||||
eek-0.90
|
||||
x11
|
||||
|
||||
20
data/dbus/sm.puri.OSK0.xml
Normal file
20
data/dbus/sm.puri.OSK0.xml
Normal 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>
|
||||
@ -1,102 +1,11 @@
|
||||
<?xml version="1.0"?>
|
||||
<geometry version="0.90">
|
||||
<bounds x="0.000000" y="0.000000" width="640.0000" height="296.5853"/>
|
||||
<bounds x="0.000000" y="0.000000" width="410.0000" height="296.5853"/>
|
||||
<section angle="0">
|
||||
<bounds x="15.60975" y="15.60975" width="640.0000" height="39.02439"/>
|
||||
<bounds x="0" y="0" width="608.7804" height="201.3658"/>
|
||||
<row orientation="1">
|
||||
<key keycode="9" name="ESC" oref="outline2">
|
||||
<bounds x="3.121951" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="67" name="FK01" oref="outline2">
|
||||
<bounds x="84.29268" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="68" name="FK02" oref="outline2">
|
||||
<bounds x="124.8780" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="69" name="FK03" oref="outline2">
|
||||
<bounds x="165.4634" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="70" name="FK04" oref="outline2">
|
||||
<bounds x="206.0487" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="71" name="FK05" oref="outline2">
|
||||
<bounds x="266.9268" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="72" name="FK06" oref="outline2">
|
||||
<bounds x="307.5121" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="73" name="FK07" oref="outline2">
|
||||
<bounds x="348.0975" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="74" name="FK08" oref="outline2">
|
||||
<bounds x="388.6829" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="75" name="FK09" oref="outline2">
|
||||
<bounds x="449.5609" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="76" name="FK10" oref="outline2">
|
||||
<bounds x="490.1463" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="95" name="FK11" oref="outline2">
|
||||
<bounds x="530.7317" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="96" name="FK12" oref="outline2">
|
||||
<bounds x="571.3170" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
</row>
|
||||
</section>
|
||||
<section angle="0">
|
||||
<bounds x="15.60975" y="78.04878" width="608.7804" height="201.3658"/>
|
||||
<row orientation="1">
|
||||
<key keycode="49" name="TLDE" oref="outline2">
|
||||
<bounds x="3.121951" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="10" name="AE01" oref="outline2">
|
||||
<bounds x="43.70731" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="11" name="AE02" oref="outline2">
|
||||
<bounds x="84.29268" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="12" name="AE03" oref="outline2">
|
||||
<bounds x="124.8780" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="13" name="AE04" oref="outline2">
|
||||
<bounds x="165.4634" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="14" name="AE05" oref="outline2">
|
||||
<bounds x="206.0487" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="15" name="AE06" oref="outline2">
|
||||
<bounds x="245.0731" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="16" name="AE07" oref="outline2">
|
||||
<bounds x="285.6585" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="17" name="AE08" oref="outline2">
|
||||
<bounds x="326.2439" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="18" name="AE09" oref="outline2">
|
||||
<bounds x="366.8292" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="19" name="AE10" oref="outline2">
|
||||
<bounds x="407.4146" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="20" name="AE11" oref="outline2">
|
||||
<bounds x="448.0000" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="21" name="AE12" oref="outline2">
|
||||
<bounds x="488.5853" y="1.560976" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="22" name="BKSP" oref="outline13">
|
||||
<bounds x="529.1707" y="1.560976" width="79.60975" height="37.46341"/>
|
||||
</key>
|
||||
</row>
|
||||
<row orientation="1">
|
||||
<key keycode="23" name="TAB" oref="outline4">
|
||||
<bounds x="3.121951" y="42.14634" width="59.31707" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="24" name="AD01" oref="outline2">
|
||||
<bounds x="65.56097" y="42.14634" width="37.46341" height="37.46341"/>
|
||||
<bounds x="65.56097" y="42.14634" width="37.46341" height="52.44877"/>
|
||||
</key>
|
||||
<key keycode="25" name="AD02" oref="outline2">
|
||||
<bounds x="106.1463" y="42.14634" width="37.46341" height="37.46341"/>
|
||||
@ -125,20 +34,11 @@
|
||||
<key keycode="33" name="AD10" oref="outline2">
|
||||
<bounds x="429.2682" y="42.14634" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="34" name="AD11" oref="outline2">
|
||||
<bounds x="468.2926" y="42.14634" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="35" name="AD12" oref="outline2">
|
||||
<bounds x="508.8780" y="42.14634" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="51" name="BKSL" oref="outline5">
|
||||
<bounds x="549.4634" y="42.14634" width="59.31707" height="37.46341"/>
|
||||
</key>
|
||||
</row>
|
||||
</section>
|
||||
<section angle="0">
|
||||
<bounds x="0" y="0" width="608.7804" height="201.3658"/>
|
||||
<row orientation="1">
|
||||
<key keycode="66" name="CAPS" oref="outline6">
|
||||
<bounds x="3.121951" y="82.73170" width="68.68292" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="38" name="AC01" oref="outline2">
|
||||
<bounds x="76.48780" y="82.73170" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
@ -166,18 +66,12 @@
|
||||
<key keycode="46" name="AC09" oref="outline2">
|
||||
<bounds x="399.6097" y="82.73170" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="47" name="AC10" oref="outline2">
|
||||
<bounds x="438.6341" y="82.73170" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="48" name="AC11" oref="outline2">
|
||||
<bounds x="479.2195" y="82.73170" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="36" name="RTRN" oref="outline7">
|
||||
<bounds x="519.8048" y="82.73170" width="88.97561" height="37.46341"/>
|
||||
</key>
|
||||
</row>
|
||||
</section>
|
||||
<section angle="0">
|
||||
<bounds x="0" y="0" width="608.7804" height="201.3658"/>
|
||||
<row orientation="1">
|
||||
<key keycode="50" name="LFSH" oref="outline8">
|
||||
<key keycode="50" name="LFSH" oref="altline">
|
||||
<bounds x="3.121951" y="121.7560" width="88.97561" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="52" name="AB01" oref="outline2">
|
||||
@ -201,113 +95,95 @@
|
||||
<key keycode="58" name="AB07" oref="outline2">
|
||||
<bounds x="337.1707" y="121.7560" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="59" name="AB08" oref="outline2">
|
||||
<bounds x="377.7560" y="121.7560" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="60" name="AB09" oref="outline2">
|
||||
<bounds x="418.3414" y="121.7560" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="61" name="AB10" oref="outline2">
|
||||
<bounds x="458.9268" y="121.7560" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="62" name="RTSH" oref="outline9">
|
||||
<bounds x="499.5121" y="121.7560" width="109.2682" height="37.46341"/>
|
||||
<key keycode="22" name="BKSP" oref="altline">
|
||||
<bounds x="529.1707" y="1.560976" width="79.60975" height="37.46341"/>
|
||||
</key>
|
||||
</row>
|
||||
</section>
|
||||
<section angle="0">
|
||||
<bounds x="0" y="0" width="608.7804" height="201.3658"/>
|
||||
<row orientation="1">
|
||||
<key keycode="149" name="I149" oref="outline10">
|
||||
<bounds x="3.121951" y="162.3414" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="37" name="LCTL" oref="outline1">
|
||||
<key keycode="37" name="LCTL" oref="altline">
|
||||
<bounds x="62.43902" y="162.3414" width="48.39024" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="64" name="LALT" oref="outline1">
|
||||
<key keycode="64" name="LALT" oref="altline">
|
||||
<bounds x="113.9512" y="162.3414" width="48.39024" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="65" name="SPCE" oref="outline3">
|
||||
<key keycode="65" name="SPCE" oref="spaceline">
|
||||
<bounds x="165.4634" y="162.3414" width="217.5853" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="113" name="LEFT" oref="outline1">
|
||||
<bounds x="368.0487" y="162.3414" width="48.39024" height="37.46341"/>
|
||||
<key keycode="60" name="AB09" oref="outline2">
|
||||
<bounds x="418.3414" y="121.7560" width="37.46341" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="111" name="UP" oref="outline1">
|
||||
<bounds x="419.43894" y="162.3414" width="48.39024" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="116" name="DOWN" oref="outline1">
|
||||
<bounds x="470.82918" y="162.3414" width="48.39024" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="114" name="RGHT" oref="outline1">
|
||||
<bounds x="522.21942" y="162.3414" width="48.39024" height="37.46341"/>
|
||||
</key>
|
||||
<key keycode="150" name="I150" oref="outline10">
|
||||
<bounds x="573.60966" y="162.3414" width="37.46341" height="37.46341"/>
|
||||
<key keycode="36" name="RTRN" oref="outline7">
|
||||
<bounds x="519.8048" y="82.73170" width="88.97561" height="37.46341"/>
|
||||
</key>
|
||||
</row>
|
||||
</section>
|
||||
<outline id="outline2" corner-radius="1.000000">
|
||||
<point x="0.000000" y="0.000000"/>
|
||||
<point x="37.46341" y="0.000000"/>
|
||||
<point x="37.46341" y="37.46341"/>
|
||||
<point x="0.000000" y="37.46341"/>
|
||||
<point x="37.46341" y="52.44877"/>
|
||||
<point x="0.000000" y="52.44877"/>
|
||||
</outline>
|
||||
<outline id="outline1" corner-radius="1.000000">
|
||||
<outline id="altline" corner-radius="1.000000">
|
||||
<point x="0.000000" y="0.000000"/>
|
||||
<point x="48.39024" y="0.000000"/>
|
||||
<point x="48.39024" y="37.46341"/>
|
||||
<point x="0.000000" y="37.46341"/>
|
||||
<point x="48.39024" y="52.44877"/>
|
||||
<point x="0.000000" y="52.44877"/>
|
||||
</outline>
|
||||
<outline id="outline4" corner-radius="1.000000">
|
||||
<point x="0.000000" y="0.000000"/>
|
||||
<point x="59.31707" y="0.000000"/>
|
||||
<point x="59.31707" y="37.46341"/>
|
||||
<point x="0.000000" y="37.46341"/>
|
||||
<point x="59.31707" y="52.44877"/>
|
||||
<point x="0.000000" y="52.44877"/>
|
||||
</outline>
|
||||
<outline id="outline5" corner-radius="1.000000">
|
||||
<point x="0.000000" y="0.000000"/>
|
||||
<point x="59.31707" y="0.000000"/>
|
||||
<point x="59.31707" y="37.46341"/>
|
||||
<point x="0.000000" y="37.46341"/>
|
||||
<point x="59.31707" y="52.44877"/>
|
||||
<point x="0.000000" y="52.44877"/>
|
||||
</outline>
|
||||
<outline id="outline6" corner-radius="1.000000">
|
||||
<point x="0.000000" y="0.000000"/>
|
||||
<point x="68.68292" y="0.000000"/>
|
||||
<point x="68.68292" y="37.46341"/>
|
||||
<point x="0.000000" y="37.46341"/>
|
||||
<point x="68.68292" y="52.44877"/>
|
||||
<point x="0.000000" y="52.44877"/>
|
||||
</outline>
|
||||
<outline id="outline7" corner-radius="1.000000">
|
||||
<point x="0.000000" y="0.000000"/>
|
||||
<point x="88.97561" y="0.000000"/>
|
||||
<point x="88.97561" y="37.46341"/>
|
||||
<point x="0.000000" y="37.46341"/>
|
||||
<point x="88.97561" y="52.44877"/>
|
||||
<point x="0.000000" y="52.44877"/>
|
||||
</outline>
|
||||
<outline id="outline8" corner-radius="1.000000">
|
||||
<point x="0.000000" y="0.000000"/>
|
||||
<point x="88.97561" y="0.000000"/>
|
||||
<point x="88.97561" y="37.46341"/>
|
||||
<point x="0.000000" y="37.46341"/>
|
||||
<point x="88.97561" y="52.44877"/>
|
||||
<point x="0.000000" y="52.44877"/>
|
||||
</outline>
|
||||
<outline id="outline9" corner-radius="1.000000">
|
||||
<point x="0.000000" y="0.000000"/>
|
||||
<point x="109.2682" y="0.000000"/>
|
||||
<point x="109.2682" y="37.46341"/>
|
||||
<point x="0.000000" y="37.46341"/>
|
||||
<point x="109.2682" y="52.44877"/>
|
||||
<point x="0.000000" y="52.44877"/>
|
||||
</outline>
|
||||
<outline id="outline10" corner-radius="1.000000">
|
||||
<point x="0.000000" y="0.000000"/>
|
||||
<point x="37.46341" y="0.000000"/>
|
||||
<point x="37.46341" y="37.46341"/>
|
||||
<point x="0.000000" y="37.46341"/>
|
||||
<point x="37.46341" y="52.44877"/>
|
||||
<point x="0.000000" y="52.44877"/>
|
||||
</outline>
|
||||
<outline id="outline13" corner-radius="1.000000">
|
||||
<point x="0.000000" y="0.000000"/>
|
||||
<point x="79.60975" y="0.000000"/>
|
||||
<point x="79.60975" y="37.46341"/>
|
||||
<point x="0.000000" y="37.46341"/>
|
||||
<point x="79.60975" y="52.44877"/>
|
||||
<point x="0.000000" y="52.44877"/>
|
||||
</outline>
|
||||
<outline id="outline3" corner-radius="1.000000">
|
||||
<outline id="spaceline" corner-radius="1.000000">
|
||||
<point x="0.000000" y="0.000000"/>
|
||||
<point x="217.5853" y="0.000000"/>
|
||||
<point x="217.5853" y="37.46341"/>
|
||||
<point x="0.000000" y="37.46341"/>
|
||||
<point x="150.5853" y="0.000000"/>
|
||||
<point x="150.5853" y="52.44877"/>
|
||||
<point x="0.000000" y="52.44877"/>
|
||||
</outline>
|
||||
</geometry>
|
||||
|
||||
68
data/meson.build
Normal file
68
data/meson.build
Normal 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'
|
||||
)
|
||||
@ -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>
|
||||
9
data/sm.puri.Squeekboard.desktop.in
Normal file
9
data/sm.puri.Squeekboard.desktop.in
Normal 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;
|
||||
@ -5,18 +5,14 @@
|
||||
}
|
||||
|
||||
.key {
|
||||
color: #ffffff;
|
||||
background-gradient-direction: vertical;
|
||||
background-gradient-start: rgba(0, 0, 0, 255);
|
||||
background-gradient-end: rgba(64, 64, 64, 255);
|
||||
border-width: 2px;
|
||||
border-color: rgba(128, 128, 128, 255);
|
||||
border-radius: 3px;
|
||||
color: #deddda;
|
||||
background: #464448;
|
||||
border-width: 0.5px;
|
||||
border-color: #5e5c64;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.key:active {
|
||||
background-gradient-direction: vertical;
|
||||
background-gradient-start: rgba(0, 0, 255, 255);
|
||||
background-gradient-end: rgba(64, 64, 255, 255);
|
||||
border-color: rgba(160, 160, 255, 255);
|
||||
background: #1c71d8;
|
||||
border-color: #3584e4;
|
||||
}
|
||||
|
||||
5
debian/changelog
vendored
Normal file
5
debian/changelog
vendored
Normal 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
1
debian/compat
vendored
Normal file
@ -0,0 +1 @@
|
||||
10
|
||||
24
debian/control
vendored
Normal file
24
debian/control
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
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:
|
||||
${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
22
debian/copyright
vendored
Normal 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
8
debian/rules
vendored
Executable file
@ -0,0 +1,8 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||
|
||||
%:
|
||||
dh $@ --builddirectory=_build
|
||||
|
||||
override_dh_autoreconf:
|
||||
145
eek/Makefile.am
145
eek/Makefile.am
@ -16,10 +16,13 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301 USA
|
||||
|
||||
NULL =
|
||||
|
||||
lib_LTLIBRARIES = \
|
||||
libeek.la \
|
||||
libeek-gtk.la \
|
||||
libeek-xkl.la
|
||||
libeek-xkl.la \
|
||||
$(NULL)
|
||||
|
||||
libeek_public_headers = \
|
||||
$(srcdir)/eek-layout.h \
|
||||
@ -37,17 +40,17 @@ libeek_public_headers = \
|
||||
$(srcdir)/eek-xml-layout.h \
|
||||
$(srcdir)/eek-serializable.h \
|
||||
$(srcdir)/eek-theme.h \
|
||||
$(srcdir)/eek.h
|
||||
$(srcdir)/eek.h \
|
||||
$(NULL)
|
||||
|
||||
libeek_private_headers = \
|
||||
$(srcdir)/eek-renderer.h \
|
||||
$(srcdir)/eek-special-keysym-entries.h \
|
||||
$(srcdir)/eek-unicode-keysym-entries.h \
|
||||
$(srcdir)/eek-xkeysym-keysym-entries.h \
|
||||
$(srcdir)/eek-marshalers.h \
|
||||
$(libeek_keysym_headers) \
|
||||
$(builddir)/eek-marshalers.h \
|
||||
$(srcdir)/eek-theme-context.h \
|
||||
$(srcdir)/eek-theme-private.h \
|
||||
$(srcdir)/eek-theme-node.h
|
||||
$(srcdir)/eek-theme-node.h \
|
||||
$(NULL)
|
||||
|
||||
libeek_sources = \
|
||||
$(srcdir)/eek.c \
|
||||
@ -69,30 +72,36 @@ libeek_sources = \
|
||||
$(srcdir)/eek-keyboard-drawing.c \
|
||||
$(srcdir)/eek-theme.c \
|
||||
$(srcdir)/eek-theme-context.c \
|
||||
$(srcdir)/eek-theme-node.c
|
||||
$(srcdir)/eek-theme-node.c \
|
||||
$(NULL)
|
||||
|
||||
libeek_keysym_sources = \
|
||||
$(srcdir)/eek-special-keysym-entries.h \
|
||||
$(srcdir)/eek-unicode-keysym-entries.h \
|
||||
$(srcdir)/eek-xkeysym-keysym-entries.h
|
||||
libeek_keysym_headers = \
|
||||
$(builddir)/eek-special-keysym-entries.h \
|
||||
$(builddir)/eek-unicode-keysym-entries.h \
|
||||
$(builddir)/eek-xkeysym-keysym-entries.h \
|
||||
$(NULL)
|
||||
|
||||
libeek_enumtypes_sources = \
|
||||
$(srcdir)/eek-enumtypes.c \
|
||||
$(srcdir)/eek-enumtypes.h
|
||||
$(builddir)/eek-enumtypes.c \
|
||||
$(builddir)/eek-enumtypes.h \
|
||||
$(NULL)
|
||||
|
||||
libeek_marshalers_sources = \
|
||||
$(srcdir)/eek-marshalers.c \
|
||||
$(srcdir)/eek-marshalers.h
|
||||
$(builddir)/eek-marshalers.c \
|
||||
$(builddir)/eek-marshalers.h \
|
||||
$(NULL)
|
||||
|
||||
BUILT_SOURCES = \
|
||||
$(libeek_keysym_sources) \
|
||||
$(libeek_keysym_headers) \
|
||||
$(libeek_enumtypes_sources) \
|
||||
$(libeek_marshalers_sources)
|
||||
$(libeek_marshalers_sources) \
|
||||
$(NULL)
|
||||
|
||||
libeek_la_SOURCES = \
|
||||
$(libeek_sources) \
|
||||
$(srcdir)/eek-enumtypes.c \
|
||||
$(srcdir)/eek-marshalers.c
|
||||
$(builddir)/eek-enumtypes.c \
|
||||
$(builddir)/eek-marshalers.c \
|
||||
$(NULL)
|
||||
|
||||
libeek_la_CFLAGS = \
|
||||
-DEEK_COMPILATION=1 \
|
||||
@ -111,12 +120,15 @@ libeek_la_LIBADD = \
|
||||
|
||||
libeek_gtk_public_headers = \
|
||||
$(srcdir)/eek-gtk-keyboard.h \
|
||||
$(srcdir)/eek-gtk.h
|
||||
$(srcdir)/eek-gtk.h \
|
||||
$(NULL)
|
||||
libeek_gtk_private_headers = \
|
||||
$(srcdir)/eek-gtk-renderer.h
|
||||
$(srcdir)/eek-gtk-renderer.h \
|
||||
$(NULL)
|
||||
libeek_gtk_sources = \
|
||||
$(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_CFLAGS = -DEEK_COMPILATION=1 $(GTK_CFLAGS) $(LIBCANBERRA_CFLAGS)
|
||||
@ -126,11 +138,13 @@ libeek_xkl_public_headers = \
|
||||
$(srcdir)/eek-xkl-layout.h \
|
||||
$(srcdir)/eek-xkl.h \
|
||||
$(srcdir)/eek-xkb-layout.h \
|
||||
$(srcdir)/eek-xkb.h
|
||||
$(srcdir)/eek-xkb.h \
|
||||
$(NULL)
|
||||
|
||||
libeek_xkl_sources = \
|
||||
$(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_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
|
||||
eek_HEADERS = \
|
||||
$(libeek_public_headers) \
|
||||
$(srcdir)/eek-enumtypes.h \
|
||||
$(builddir)/eek-enumtypes.h \
|
||||
$(libeek_gtk_public_headers) \
|
||||
$(libeek_xkl_public_headers)
|
||||
$(libeek_xkl_public_headers) \
|
||||
$(NULL)
|
||||
|
||||
noinst_HEADERS = \
|
||||
$(libeek_private_headers) \
|
||||
$(libeek_gtk_private_headers) \
|
||||
$(libeek_xkl_private_headers)
|
||||
$(libeek_xkl_private_headers) \
|
||||
$(NULL)
|
||||
|
||||
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
|
||||
$(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
|
||||
$(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
|
||||
$(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 && \
|
||||
mv eek-enumtypes.h.tmp eek-enumtypes.h
|
||||
|
||||
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 && \
|
||||
mv eek-enumtypes.c.tmp eek-enumtypes.c
|
||||
|
||||
# gen marshal
|
||||
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 $@
|
||||
|
||||
eek-marshalers.c: eek-marshalers.list 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 $@
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = \
|
||||
eek-$(EEK_API_VERSION).pc \
|
||||
eek-gtk-$(EEK_API_VERSION).pc \
|
||||
eek-xkl-$(EEK_API_VERSION).pc
|
||||
eek-xkl-$(EEK_API_VERSION).pc \
|
||||
$(NULL)
|
||||
|
||||
CLEANFILES =
|
||||
|
||||
DISTCLEANFILES = \
|
||||
$(BUILT_SOURCES) \
|
||||
$(pkgconfig_DATA)
|
||||
$(pkgconfig_DATA) \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
gen-keysym-entries.py \
|
||||
@ -197,7 +223,8 @@ EXTRA_DIST = \
|
||||
xkeysym-keysym-entries.txt \
|
||||
eek-enumtypes.h.template \
|
||||
eek-enumtypes.c.template \
|
||||
eek-marshalers.list
|
||||
eek-marshalers.list \
|
||||
$(NULL)
|
||||
|
||||
-include $(INTROSPECTION_MAKEFILE)
|
||||
INTROSPECTION_GIRS =
|
||||
@ -207,29 +234,57 @@ INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
|
||||
if HAVE_INTROSPECTION
|
||||
|
||||
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_CFLAGS = $(libeek_la_CFLAGS)
|
||||
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_U@_gir_SCANNERFLAGS = --pkg-export=eek-gtk-$(EEK_API_VERSION)
|
||||
EekGtk@EEK_LIBRARY_SUFFIX_U@_gir_INCLUDES = GObject-2.0 Gtk-@GTK_API_VERSION@ Eek@EEK_LIBRARY_SUFFIX@
|
||||
EekGtk@EEK_LIBRARY_SUFFIX_U@_gir_SCANNERFLAGS = \
|
||||
--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_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_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_CFLAGS = $(libeek_xkl_la_CFLAGS)
|
||||
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 += \
|
||||
Eek@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
|
||||
gir_DATA = $(INTROSPECTION_GIRS)
|
||||
|
||||
0
eek/config.h
Normal file
0
eek/config.h
Normal file
@ -1,17 +1,17 @@
|
||||
/*
|
||||
/*
|
||||
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
|
||||
* Copyright (C) 2010-2011 Red Hat, Inc.
|
||||
*
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
@ -61,31 +61,22 @@ struct _EekGtkKeyboardPrivate
|
||||
{
|
||||
EekRenderer *renderer;
|
||||
EekKeyboard *keyboard;
|
||||
gulong key_pressed_handler;
|
||||
gulong key_released_handler;
|
||||
gulong key_locked_handler;
|
||||
gulong key_unlocked_handler;
|
||||
gulong key_cancelled_handler;
|
||||
gulong symbol_index_changed_handler;
|
||||
EekTheme *theme;
|
||||
};
|
||||
|
||||
static EekColor * color_from_gdk_color (GdkColor *gdk_color);
|
||||
static void on_key_pressed (EekKeyboard *keyboard,
|
||||
EekKey *key,
|
||||
gpointer user_data);
|
||||
static void on_key_released (EekKeyboard *keyboard,
|
||||
EekKey *key,
|
||||
gpointer user_data);
|
||||
static void on_key_pressed (EekKey *key,
|
||||
EekGtkKeyboard *self);
|
||||
static void on_key_released (EekKey *key,
|
||||
EekGtkKeyboard *self);
|
||||
static void on_key_locked (EekKeyboard *keyboard,
|
||||
EekKey *key,
|
||||
gpointer user_data);
|
||||
static void on_key_unlocked (EekKeyboard *keyboard,
|
||||
EekKey *key,
|
||||
gpointer user_data);
|
||||
static void on_key_cancelled (EekKeyboard *keyboard,
|
||||
EekKey *key,
|
||||
gpointer user_data);
|
||||
static void on_symbol_index_changed (EekKeyboard *keyboard,
|
||||
gint group,
|
||||
gint level,
|
||||
@ -100,7 +91,6 @@ static void render_released_key (GtkWidget *widget,
|
||||
static void
|
||||
eek_gtk_keyboard_real_realize (GtkWidget *self)
|
||||
{
|
||||
gtk_widget_set_double_buffered (self, FALSE);
|
||||
gtk_widget_set_events (self,
|
||||
GDK_EXPOSURE_MASK |
|
||||
GDK_KEY_PRESS_MASK |
|
||||
@ -118,16 +108,12 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
|
||||
{
|
||||
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self);
|
||||
GtkAllocation allocation;
|
||||
EekColor background;
|
||||
GList *list, *head;
|
||||
|
||||
gtk_widget_get_allocation (self, &allocation);
|
||||
|
||||
if (!priv->renderer) {
|
||||
GtkStyle *style;
|
||||
GtkStateType state;
|
||||
PangoContext *pcontext;
|
||||
EekColor *color;
|
||||
|
||||
pcontext = gtk_widget_get_pango_context (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,
|
||||
allocation.width,
|
||||
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);
|
||||
|
||||
/* redraw pressed key */
|
||||
@ -195,49 +159,21 @@ eek_gtk_keyboard_real_size_allocate (GtkWidget *self,
|
||||
size_allocate (self, allocation);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
eek_gtk_keyboard_real_button_press_event (GtkWidget *self,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
static void depress(EekGtkKeyboard *self,
|
||||
gdouble x, gdouble y, guint32 time) {
|
||||
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)
|
||||
g_signal_emit_by_name (key, "pressed", priv->keyboard);
|
||||
return TRUE;
|
||||
EekKey *key = eek_renderer_find_key_by_position (priv->renderer, x, y);
|
||||
if (key) {
|
||||
eek_keyboard_press_key(priv->keyboard, key, time);
|
||||
on_key_pressed(key, self);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
eek_gtk_keyboard_real_button_release_event (GtkWidget *self,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
static void drag(EekGtkKeyboard *self,
|
||||
gdouble x, gdouble y, guint32 time) {
|
||||
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;
|
||||
|
||||
if (event->state == 0)
|
||||
return FALSE;
|
||||
|
||||
key = eek_renderer_find_key_by_position (priv->renderer,
|
||||
(gdouble)event->x,
|
||||
(gdouble)event->y);
|
||||
if (key) {
|
||||
GList *list, *head;
|
||||
gboolean found = FALSE;
|
||||
@ -246,17 +182,95 @@ eek_gtk_keyboard_real_motion_notify_event (GtkWidget *self,
|
||||
for (head = list; head; head = g_list_next (head)) {
|
||||
if (head->data == key)
|
||||
found = TRUE;
|
||||
else
|
||||
g_signal_emit_by_name (head->data, "cancelled", priv->keyboard);
|
||||
else {
|
||||
eek_keyboard_release_key(priv->keyboard, EEK_KEY(head->data), time);
|
||||
on_key_released(key, self);
|
||||
}
|
||||
}
|
||||
g_list_free (list);
|
||||
|
||||
if (!found)
|
||||
g_signal_emit_by_name (key, "pressed", priv->keyboard);
|
||||
if (!found) {
|
||||
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;
|
||||
}
|
||||
|
||||
// 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
|
||||
eek_gtk_keyboard_real_unmap (GtkWidget *self)
|
||||
{
|
||||
@ -270,8 +284,10 @@ eek_gtk_keyboard_real_unmap (GtkWidget *self)
|
||||
EekKeyboard::key-released signal can remove elements from its
|
||||
internal copy */
|
||||
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);
|
||||
for (head = list; head; head = g_list_next (head)) {
|
||||
g_log("squeek", G_LOG_LEVEL_DEBUG, "emit EekKey released");
|
||||
g_signal_emit_by_name (head->data, "released");
|
||||
}
|
||||
g_list_free (list);
|
||||
}
|
||||
|
||||
@ -309,21 +325,12 @@ eek_gtk_keyboard_set_keyboard (EekGtkKeyboard *self,
|
||||
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self);
|
||||
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 =
|
||||
g_signal_connect (priv->keyboard, "key-locked",
|
||||
G_CALLBACK(on_key_locked), self);
|
||||
priv->key_unlocked_handler =
|
||||
g_signal_connect (priv->keyboard, "key-unlocked",
|
||||
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 =
|
||||
g_signal_connect (priv->keyboard, "symbol-index-changed",
|
||||
G_CALLBACK(on_symbol_index_changed), self);
|
||||
@ -359,14 +366,6 @@ eek_gtk_keyboard_dispose (GObject *object)
|
||||
}
|
||||
|
||||
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,
|
||||
priv->key_locked_handler))
|
||||
g_signal_handler_disconnect (priv->keyboard,
|
||||
@ -375,19 +374,16 @@ eek_gtk_keyboard_dispose (GObject *object)
|
||||
priv->key_unlocked_handler))
|
||||
g_signal_handler_disconnect (priv->keyboard,
|
||||
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,
|
||||
priv->symbol_index_changed_handler))
|
||||
g_signal_handler_disconnect (priv->keyboard,
|
||||
priv->symbol_index_changed_handler);
|
||||
|
||||
|
||||
GList *list, *head;
|
||||
|
||||
list = eek_keyboard_get_pressed_keys (priv->keyboard);
|
||||
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_list_free (list);
|
||||
@ -426,6 +422,7 @@ eek_gtk_keyboard_class_init (EekGtkKeyboardClass *klass)
|
||||
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->dispose = eek_gtk_keyboard_dispose;
|
||||
@ -459,15 +456,6 @@ eek_gtk_keyboard_new (EekKeyboard *keyboard)
|
||||
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
|
||||
magnify_bounds (GtkWidget *self,
|
||||
EekBounds *bounds,
|
||||
@ -497,13 +485,17 @@ render_pressed_key (GtkWidget *widget,
|
||||
{
|
||||
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget);
|
||||
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);
|
||||
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_translate (cr, bounds.x, bounds.y);
|
||||
eek_renderer_render_key (priv->renderer, cr, key, 1.0, TRUE);
|
||||
@ -514,7 +506,8 @@ render_pressed_key (GtkWidget *widget,
|
||||
eek_renderer_render_key (priv->renderer, cr, key, 1.5, TRUE);
|
||||
cairo_restore (cr);
|
||||
|
||||
cairo_destroy (cr);
|
||||
gdk_window_end_draw_frame(window, context);
|
||||
cairo_region_destroy(region);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -563,18 +556,16 @@ render_released_key (GtkWidget *widget,
|
||||
}
|
||||
|
||||
static void
|
||||
on_key_pressed (EekKeyboard *keyboard,
|
||||
EekKey *key,
|
||||
gpointer user_data)
|
||||
on_key_pressed (EekKey *key,
|
||||
EekGtkKeyboard *self)
|
||||
{
|
||||
GtkWidget *widget = user_data;
|
||||
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget);
|
||||
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self);
|
||||
|
||||
/* renderer may have not been set yet if the widget is a popup */
|
||||
if (!priv->renderer)
|
||||
return;
|
||||
|
||||
render_pressed_key (widget, key);
|
||||
render_pressed_key (GTK_WIDGET(self), key);
|
||||
|
||||
#if HAVE_LIBCANBERRA
|
||||
ca_gtk_play_for_widget (widget, 0,
|
||||
@ -586,18 +577,16 @@ on_key_pressed (EekKeyboard *keyboard,
|
||||
}
|
||||
|
||||
static void
|
||||
on_key_released (EekKeyboard *keyboard,
|
||||
EekKey *key,
|
||||
gpointer user_data)
|
||||
on_key_released (EekKey *key,
|
||||
EekGtkKeyboard *self)
|
||||
{
|
||||
GtkWidget *widget = user_data;
|
||||
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget);
|
||||
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self);
|
||||
|
||||
/* renderer may have not been set yet if the widget is a popup */
|
||||
if (!priv->renderer)
|
||||
return;
|
||||
|
||||
render_released_key (widget, key);
|
||||
render_released_key (GTK_WIDGET(self), key);
|
||||
|
||||
#if HAVE_LIBCANBERRA
|
||||
ca_gtk_play_for_widget (widget, 0,
|
||||
@ -608,21 +597,6 @@ on_key_released (EekKeyboard *keyboard,
|
||||
#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
|
||||
on_key_locked (EekKeyboard *keyboard,
|
||||
EekKey *key,
|
||||
|
||||
@ -47,6 +47,8 @@ struct _EekGtkKeyboard
|
||||
/*< private >*/
|
||||
GtkDrawingArea parent;
|
||||
|
||||
GdkEventSequence *sequence; // unowned reference
|
||||
|
||||
EekGtkKeyboardPrivate *priv;
|
||||
};
|
||||
|
||||
|
||||
104
eek/eek-key.c
104
eek/eek-key.c
@ -30,10 +30,6 @@
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <string.h>
|
||||
#define DEBUG 0
|
||||
#if DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "eek-key.h"
|
||||
#include "eek-section.h"
|
||||
@ -51,11 +47,8 @@ enum {
|
||||
};
|
||||
|
||||
enum {
|
||||
PRESSED,
|
||||
RELEASED,
|
||||
LOCKED,
|
||||
UNLOCKED,
|
||||
CANCELLED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
@ -73,33 +66,11 @@ struct _EekKeyPrivate
|
||||
EekSymbolMatrix *symbol_matrix;
|
||||
gint column;
|
||||
gint row;
|
||||
gulong oref;
|
||||
gulong oref; // UI outline reference
|
||||
gboolean is_pressed;
|
||||
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
|
||||
eek_key_real_locked (EekKey *self)
|
||||
{
|
||||
@ -122,17 +93,6 @@ eek_key_real_unlocked (EekKey *self)
|
||||
#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
|
||||
eek_key_finalize (GObject *object)
|
||||
{
|
||||
@ -222,11 +182,8 @@ eek_key_class_init (EekKeyClass *klass)
|
||||
gobject_class->finalize = eek_key_finalize;
|
||||
|
||||
/* signals */
|
||||
klass->pressed = eek_key_real_pressed;
|
||||
klass->released = eek_key_real_released;
|
||||
klass->locked = eek_key_real_locked;
|
||||
klass->unlocked = eek_key_real_unlocked;
|
||||
klass->cancelled = eek_key_real_cancelled;
|
||||
|
||||
/**
|
||||
* EekKey:keycode:
|
||||
@ -288,42 +245,6 @@ eek_key_class_init (EekKeyClass *klass)
|
||||
G_PARAM_READWRITE);
|
||||
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:
|
||||
* @key: an #EekKey
|
||||
@ -359,23 +280,6 @@ eek_key_class_init (EekKeyClass *klass)
|
||||
NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
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
|
||||
@ -677,3 +581,9 @@ eek_key_is_locked (EekKey *key)
|
||||
g_return_val_if_fail (EEK_IS_KEY(key), FALSE);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -43,6 +43,9 @@ typedef struct _EekKeyPrivate EekKeyPrivate;
|
||||
/**
|
||||
* 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
|
||||
* accessed using the provided API.
|
||||
*/
|
||||
@ -71,11 +74,8 @@ struct _EekKeyClass
|
||||
|
||||
/*< public >*/
|
||||
/* signals */
|
||||
void (* pressed) (EekKey *key);
|
||||
void (* released) (EekKey *key);
|
||||
void (* locked) (EekKey *key);
|
||||
void (* unlocked) (EekKey *key);
|
||||
void (* cancelled) (EekKey *key);
|
||||
};
|
||||
|
||||
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_locked (EekKey *key);
|
||||
void eek_key_set_pressed (EekKey *key,
|
||||
gboolean value);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* EEK_KEY_H */
|
||||
|
||||
@ -199,32 +199,21 @@ void
|
||||
_eek_rounded_polygon (cairo_t *cr,
|
||||
gdouble radius,
|
||||
EekPoint *points,
|
||||
gint num_points)
|
||||
guint num_points)
|
||||
{
|
||||
gint i, j;
|
||||
|
||||
cairo_move_to (cr,
|
||||
(gdouble) (points[num_points - 1].x +
|
||||
points[0].x) / 2,
|
||||
(gdouble) (points[num_points - 1].y +
|
||||
points[0].y) / 2);
|
||||
|
||||
|
||||
#ifdef KBDRAW_DEBUG
|
||||
printf (" rounded polygon of radius %f:\n", radius);
|
||||
#endif
|
||||
for (i = 0; i < num_points; i++) {
|
||||
j = (i + 1) % num_points;
|
||||
for (guint i = 0; i < num_points; i++) {
|
||||
guint j = (i + 1) % num_points;
|
||||
rounded_corner (cr, (gdouble) points[i].x,
|
||||
(gdouble) points[i].y,
|
||||
(gdouble) (points[i].x + points[j].x) / 2,
|
||||
(gdouble) (points[i].y + points[j].y) / 2,
|
||||
radius);
|
||||
#ifdef KBDRAW_DEBUG
|
||||
printf (" corner (%d, %d) -> (%d, %d):\n",
|
||||
points[i].x, points[i].y, points[j].x,
|
||||
points[j].y);
|
||||
#endif
|
||||
};
|
||||
}
|
||||
cairo_close_path (cr);
|
||||
}
|
||||
|
||||
@ -32,10 +32,12 @@
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include "eek-keyboard.h"
|
||||
#include "eek-marshalers.h"
|
||||
#include "eek-section.h"
|
||||
#include "eek-key.h"
|
||||
#include "eek-symbol.h"
|
||||
#include "eek-enumtypes.h"
|
||||
#include "eekboard/key-emitter.h"
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
@ -45,11 +47,9 @@ enum {
|
||||
};
|
||||
|
||||
enum {
|
||||
KEY_PRESSED,
|
||||
KEY_RELEASED,
|
||||
KEY_LOCKED,
|
||||
KEY_UNLOCKED,
|
||||
KEY_CANCELLED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
@ -91,22 +91,6 @@ eek_modifier_key_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
|
||||
on_key_locked (EekSection *section,
|
||||
EekKey *key,
|
||||
@ -123,14 +107,6 @@ on_key_unlocked (EekSection *section,
|
||||
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
|
||||
on_symbol_index_changed (EekSection *section,
|
||||
gint group,
|
||||
@ -278,74 +254,76 @@ set_modifiers_with_key (EekKeyboard *self,
|
||||
priv->modifiers = modifiers;
|
||||
}
|
||||
|
||||
static void
|
||||
eek_keyboard_real_key_pressed (EekKeyboard *self,
|
||||
EekKey *key)
|
||||
{
|
||||
EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(self);
|
||||
EekSymbol *symbol;
|
||||
EekModifierType modifier;
|
||||
void eek_keyboard_press_key(EekKeyboard *keyboard, EekKey *key, guint32 timestamp) {
|
||||
EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(keyboard);
|
||||
|
||||
eek_key_set_pressed(key, TRUE);
|
||||
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)
|
||||
return;
|
||||
|
||||
modifier = eek_symbol_get_modifier_mask (symbol);
|
||||
EekModifierType modifier = eek_symbol_get_modifier_mask (symbol);
|
||||
if (priv->modifier_behavior == EEK_MODIFIER_BEHAVIOR_NONE) {
|
||||
set_modifiers_with_key (self, key, priv->modifiers | modifier);
|
||||
set_level_from_modifiers (self);
|
||||
set_modifiers_with_key (keyboard, key, priv->modifiers | modifier);
|
||||
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);
|
||||
EekModifierType modifiers = eek_keyboard_get_modifiers (keyboard);
|
||||
|
||||
emit_key_activated(keyboard->manager, keyboard, keycode, symbol, modifiers, TRUE, timestamp);
|
||||
}
|
||||
|
||||
static void
|
||||
eek_keyboard_real_key_released (EekKeyboard *self,
|
||||
EekKey *key)
|
||||
{
|
||||
EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(self);
|
||||
EekSymbol *symbol;
|
||||
EekModifierType modifier;
|
||||
void eek_keyboard_release_key( EekKeyboard *keyboard,
|
||||
EekKey *key,
|
||||
guint32 timestamp) {
|
||||
EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(keyboard);
|
||||
|
||||
EEK_KEYBOARD_GET_CLASS (self)->key_cancelled (self, key);
|
||||
|
||||
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)) {
|
||||
for (GList *head = priv->pressed_keys; head; head = g_list_next (head)) {
|
||||
if (head->data == key) {
|
||||
priv->pressed_keys = g_list_remove_link (priv->pressed_keys, head);
|
||||
g_list_free1 (head);
|
||||
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
|
||||
@ -365,7 +343,7 @@ static void
|
||||
eek_keyboard_finalize (GObject *object)
|
||||
{
|
||||
EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(object);
|
||||
gint i;
|
||||
guint i;
|
||||
|
||||
g_list_free (priv->pressed_keys);
|
||||
g_list_free_full (priv->locked_keys,
|
||||
@ -389,16 +367,10 @@ static void
|
||||
eek_keyboard_real_child_added (EekContainer *self,
|
||||
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_CALLBACK(on_key_locked), self);
|
||||
g_signal_connect (element, "key-unlocked",
|
||||
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_CALLBACK(on_symbol_index_changed), self);
|
||||
}
|
||||
@ -407,11 +379,8 @@ static void
|
||||
eek_keyboard_real_child_removed (EekContainer *self,
|
||||
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_unlocked, self);
|
||||
g_signal_handlers_disconnect_by_func (element, on_key_cancelled, self);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -427,10 +396,6 @@ eek_keyboard_class_init (EekKeyboardClass *klass)
|
||||
klass->create_section = eek_keyboard_real_create_section;
|
||||
|
||||
/* 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_removed = eek_keyboard_real_child_removed;
|
||||
|
||||
@ -468,46 +433,6 @@ eek_keyboard_class_init (EekKeyboardClass *klass)
|
||||
PROP_MODIFIER_BEHAVIOR,
|
||||
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:
|
||||
* @keyboard: an #EekKeyboard
|
||||
@ -547,26 +472,6 @@ eek_keyboard_class_init (EekKeyboardClass *klass)
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
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
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
#define EEK_KEYBOARD_H 1
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include "eek-container.h"
|
||||
#include "eek-types.h"
|
||||
#include "eek-layout.h"
|
||||
@ -45,6 +46,10 @@ typedef struct _EekKeyboardPrivate EekKeyboardPrivate;
|
||||
/**
|
||||
* EekKeyboard:
|
||||
*
|
||||
* Contains the state of the physical keyboard.
|
||||
*
|
||||
* Is also a graphical element...
|
||||
*
|
||||
* The #EekKeyboard structure contains only private data and should
|
||||
* only be accessed using the provided API.
|
||||
*/
|
||||
@ -54,6 +59,11 @@ struct _EekKeyboard
|
||||
EekContainer parent;
|
||||
|
||||
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 +92,6 @@ struct _EekKeyboardClass
|
||||
EekKey *(* find_key_by_keycode) (EekKeyboard *self,
|
||||
guint keycode);
|
||||
|
||||
/* signals */
|
||||
void (* key_pressed) (EekKeyboard *self,
|
||||
EekKey *key);
|
||||
void (* key_released) (EekKeyboard *self,
|
||||
EekKey *key);
|
||||
|
||||
/*< private >*/
|
||||
/* obsolete members moved to EekElement */
|
||||
gpointer symbol_index_changed;
|
||||
@ -98,8 +102,6 @@ struct _EekKeyboardClass
|
||||
EekKey *key);
|
||||
void (* key_unlocked) (EekKeyboard *self,
|
||||
EekKey *key);
|
||||
void (* key_cancelled) (EekKeyboard *self,
|
||||
EekKey *key);
|
||||
|
||||
/*< private >*/
|
||||
/* padding */
|
||||
@ -121,12 +123,13 @@ struct _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_height);
|
||||
GType eek_keyboard_get_type
|
||||
(void) G_GNUC_CONST;
|
||||
EekLayout *eek_keyboard_get_layout
|
||||
(EekKeyboard *keyboard);
|
||||
void eek_keyboard_get_size
|
||||
@ -188,5 +191,8 @@ EekModifierKey *eek_modifier_key_copy
|
||||
void eek_modifier_key_free
|
||||
(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
|
||||
#endif /* EEK_KEYBOARD_H */
|
||||
|
||||
@ -32,6 +32,7 @@
|
||||
|
||||
#include "eek-layout.h"
|
||||
#include "eek-keyboard.h"
|
||||
#include "eekboard/eekboard-context-service.h"
|
||||
|
||||
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.
|
||||
*/
|
||||
EekKeyboard *
|
||||
eek_keyboard_new (EekLayout *layout,
|
||||
eek_keyboard_new (EekboardContextService *manager,
|
||||
EekLayout *layout,
|
||||
gdouble initial_width,
|
||||
gdouble initial_height)
|
||||
{
|
||||
g_assert (EEK_IS_LAYOUT(layout));
|
||||
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_height);
|
||||
}
|
||||
|
||||
@ -56,7 +56,8 @@ struct _EekLayoutClass
|
||||
GObjectClass parent_class;
|
||||
|
||||
/*< public >*/
|
||||
EekKeyboard* (* create_keyboard) (EekLayout *self,
|
||||
EekKeyboard* (* create_keyboard) (EekboardContextService *manager,
|
||||
EekLayout *self,
|
||||
gdouble initial_width,
|
||||
gdouble initial_height);
|
||||
|
||||
|
||||
@ -79,7 +79,7 @@ typedef struct _TextProperty TextProperty;
|
||||
extern void _eek_rounded_polygon (cairo_t *cr,
|
||||
gdouble radius,
|
||||
EekPoint *points,
|
||||
gint num_points);
|
||||
guint num_points);
|
||||
|
||||
static void eek_renderer_real_render_key_label (EekRenderer *self,
|
||||
PangoLayout *layout,
|
||||
@ -116,8 +116,8 @@ create_keyboard_surface_key_callback (EekElement *element,
|
||||
cairo_rectangle (data->cr,
|
||||
0.0,
|
||||
0.0,
|
||||
bounds.width * priv->scale,
|
||||
bounds.height * priv->scale);
|
||||
bounds.width * priv->scale + 100,
|
||||
bounds.height * priv->scale + 100);
|
||||
cairo_clip (data->cr);
|
||||
render_key (data->renderer, data->cr, EEK_KEY(element), FALSE);
|
||||
|
||||
@ -166,8 +166,8 @@ create_keyboard_surface (EekRenderer *renderer)
|
||||
|
||||
eek_element_get_bounds (EEK_ELEMENT(priv->keyboard), &bounds);
|
||||
keyboard_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
||||
bounds.width * priv->scale,
|
||||
bounds.height * priv->scale);
|
||||
ceil(bounds.width * priv->scale),
|
||||
ceil(bounds.height * priv->scale));
|
||||
data.cr = cairo_create (keyboard_surface);
|
||||
data.renderer = renderer;
|
||||
|
||||
@ -205,8 +205,6 @@ render_key_outline (EekRenderer *renderer,
|
||||
EekRendererPrivate *priv = EEK_RENDERER_GET_PRIVATE(renderer);
|
||||
EekOutline *outline;
|
||||
EekBounds bounds;
|
||||
gdouble scale;
|
||||
gint i;
|
||||
guint oref;
|
||||
EekThemeNode *theme_node;
|
||||
EekColor foreground, background, gradient_start, gradient_end, border_color;
|
||||
@ -233,14 +231,14 @@ render_key_outline (EekRenderer *renderer,
|
||||
border_width = eek_theme_node_get_border_width (theme_node,
|
||||
EEK_SIDE_TOP);
|
||||
border_radius = eek_theme_node_get_border_radius (theme_node,
|
||||
EEK_SIDE_TOP);
|
||||
EEK_CORNER_TOPLEFT);
|
||||
eek_theme_node_get_border_color (theme_node, EEK_SIDE_TOP,
|
||||
&border_color);
|
||||
} else {
|
||||
foreground = priv->default_foreground_color;
|
||||
background = priv->default_background_color;
|
||||
gradient_type = EEK_GRADIENT_NONE;
|
||||
border_width = priv->border_width;
|
||||
border_width = (gint)round(priv->border_width);
|
||||
border_radius = -1;
|
||||
border_color.red = ABS(background.red - foreground.red) * 0.7;
|
||||
border_color.green = ABS(background.green - foreground.green) * 0.7;
|
||||
@ -248,21 +246,15 @@ render_key_outline (EekRenderer *renderer,
|
||||
border_color.alpha = foreground.alpha;
|
||||
}
|
||||
|
||||
/* need to rescale so that the border fit inside the clipping
|
||||
region */
|
||||
eek_element_get_bounds (EEK_ELEMENT(key), &bounds);
|
||||
scale = MIN((bounds.width - border_width * 2) / bounds.width,
|
||||
(bounds.height - border_width * 2) / bounds.height);
|
||||
|
||||
outline = eek_outline_copy (outline);
|
||||
for (i = 0; i < outline->num_points; i++) {
|
||||
outline->points[i].x *= priv->scale * scale;
|
||||
outline->points[i].y *= priv->scale * scale;
|
||||
for (guint i = 0; i < outline->num_points; i++) {
|
||||
outline->points[i].x *= priv->scale;
|
||||
outline->points[i].y *= priv->scale;
|
||||
}
|
||||
|
||||
cairo_translate (cr,
|
||||
border_width * priv->scale * scale,
|
||||
border_width * priv->scale * scale);
|
||||
border_width * priv->scale,
|
||||
border_width * priv->scale);
|
||||
|
||||
if (gradient_type != EEK_GRADIENT_NONE) {
|
||||
cairo_pattern_t *pat;
|
||||
@ -340,6 +332,10 @@ render_key_outline (EekRenderer *renderer,
|
||||
outline->num_points);
|
||||
cairo_stroke (cr);
|
||||
|
||||
cairo_translate (cr,
|
||||
-border_width * priv->scale,
|
||||
-border_width * priv->scale);
|
||||
|
||||
eek_outline_free (outline);
|
||||
}
|
||||
|
||||
@ -464,10 +460,11 @@ render_key (EekRenderer *self,
|
||||
if (!outline_surface) {
|
||||
cairo_t *cr;
|
||||
|
||||
// Outline will be drawn on the outside of the button, so the surface needs to be bigger than the button
|
||||
outline_surface =
|
||||
cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
||||
bounds.width,
|
||||
bounds.height);
|
||||
(int)ceil(bounds.width) + 10,
|
||||
(int)ceil(bounds.height) + 10);
|
||||
cr = cairo_create (outline_surface);
|
||||
|
||||
/* blank background */
|
||||
@ -640,7 +637,7 @@ eek_renderer_real_render_key_label (EekRenderer *self,
|
||||
|
||||
size = calculate_font_size (self, base_font, FALSE);
|
||||
priv->font = pango_font_description_copy (base_font);
|
||||
pango_font_description_set_size (priv->font, size);
|
||||
pango_font_description_set_size (priv->font, size * 0.6);
|
||||
}
|
||||
|
||||
eek_element_get_bounds (EEK_ELEMENT(key), &bounds);
|
||||
|
||||
@ -45,11 +45,8 @@ enum {
|
||||
};
|
||||
|
||||
enum {
|
||||
KEY_PRESSED,
|
||||
KEY_RELEASED,
|
||||
KEY_LOCKED,
|
||||
KEY_UNLOCKED,
|
||||
KEY_CANCELLED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
@ -114,20 +111,6 @@ eek_section_real_get_row (EekSection *self,
|
||||
*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
|
||||
on_locked (EekKey *key,
|
||||
EekSection *section)
|
||||
@ -142,18 +125,11 @@ on_unlocked (EekKey *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 *
|
||||
eek_section_real_create_key (EekSection *self,
|
||||
guint keycode,
|
||||
gint column_index,
|
||||
gint row_index)
|
||||
guint row_index)
|
||||
{
|
||||
EekKey *key;
|
||||
gint num_rows;
|
||||
@ -296,22 +272,16 @@ static void
|
||||
eek_section_real_child_added (EekContainer *self,
|
||||
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, "unlocked", G_CALLBACK(on_unlocked), self);
|
||||
g_signal_connect (element, "cancelled", G_CALLBACK(on_cancelled), self);
|
||||
}
|
||||
|
||||
static void
|
||||
eek_section_real_child_removed (EekContainer *self,
|
||||
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_unlocked, self);
|
||||
g_signal_handlers_disconnect_by_func (element, on_cancelled, self);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -353,46 +323,6 @@ eek_section_class_init (EekSectionClass *klass)
|
||||
PROP_ANGLE,
|
||||
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:
|
||||
* @section: an #EekSection
|
||||
@ -432,26 +362,6 @@ eek_section_class_init (EekSectionClass *klass)
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
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
|
||||
@ -569,3 +479,80 @@ eek_section_create_key (EekSection *section,
|
||||
column,
|
||||
row);
|
||||
}
|
||||
|
||||
static void keysizer(EekElement *element, gpointer user_data) {
|
||||
EekKey *key = EEK_KEY(element);
|
||||
EekKeyboard *keyboard = EEK_KEYBOARD(user_data);
|
||||
uint oref = eek_key_get_oref (key);
|
||||
EekOutline *outline = eek_keyboard_get_outline (keyboard, oref);
|
||||
if (outline && outline->num_points > 0) {
|
||||
double minx = outline->points[0].x;
|
||||
double maxx = minx;
|
||||
double miny = outline->points[0].y;
|
||||
double maxy = miny;
|
||||
for (uint i = 1; i < outline->num_points; i++) {
|
||||
EekPoint p = outline->points[i];
|
||||
if (p.x < minx) {
|
||||
minx = p.x;
|
||||
} else if (p.x > maxx) {
|
||||
maxx = p.x;
|
||||
}
|
||||
|
||||
if (p.y < miny) {
|
||||
miny = p.y;
|
||||
} else if (p.y > maxy) {
|
||||
maxy = p.y;
|
||||
}
|
||||
}
|
||||
EekBounds key_bounds = {0};
|
||||
eek_element_get_bounds(element, &key_bounds);
|
||||
key_bounds.height = maxy - miny;
|
||||
key_bounds.width = maxx - minx;
|
||||
eek_element_set_bounds(element, &key_bounds);
|
||||
}
|
||||
}
|
||||
|
||||
struct keys_info {
|
||||
uint count;
|
||||
double total_width;
|
||||
double biggest_height;
|
||||
};
|
||||
|
||||
static void keycounter (EekElement *element, gpointer user_data) {
|
||||
struct keys_info *data = user_data;
|
||||
data->count++;
|
||||
EekBounds key_bounds = {0};
|
||||
eek_element_get_bounds(element, &key_bounds);
|
||||
data->total_width += key_bounds.width;
|
||||
if (key_bounds.height > data->biggest_height) {
|
||||
data->biggest_height = key_bounds.height;
|
||||
}
|
||||
}
|
||||
|
||||
const double keyspacing = 3.0;
|
||||
|
||||
static void keyplacer(EekElement *element, gpointer user_data) {
|
||||
double *current_offset = user_data;
|
||||
EekBounds key_bounds = {0};
|
||||
eek_element_get_bounds(element, &key_bounds);
|
||||
key_bounds.x = *current_offset;
|
||||
key_bounds.y = 0;
|
||||
eek_element_set_bounds(element, &key_bounds);
|
||||
*current_offset += key_bounds.width + keyspacing;
|
||||
}
|
||||
|
||||
void eek_section_place_keys(EekSection *section, EekKeyboard *keyboard)
|
||||
{
|
||||
eek_container_foreach_child(EEK_CONTAINER(section), keysizer, keyboard);
|
||||
|
||||
struct keys_info keyinfo = {0};
|
||||
eek_container_foreach_child(EEK_CONTAINER(section), keycounter, &keyinfo);
|
||||
EekBounds section_bounds = {0};
|
||||
eek_element_get_bounds(EEK_ELEMENT(section), §ion_bounds);
|
||||
|
||||
double key_offset = (section_bounds.width - (keyinfo.total_width + (keyinfo.count - 1) * keyspacing)) / 2;
|
||||
eek_container_foreach_child(EEK_CONTAINER(section), keyplacer, &key_offset);
|
||||
|
||||
section_bounds.height = keyinfo.biggest_height;
|
||||
eek_element_set_bounds(EEK_ELEMENT(section), §ion_bounds);
|
||||
}
|
||||
|
||||
@ -127,5 +127,7 @@ EekKey *eek_section_create_key (EekSection *section,
|
||||
EekKey *eek_section_find_key_by_keycode (EekSection *section,
|
||||
guint keycode);
|
||||
|
||||
void eek_section_place_keys (EekSection *section, EekKeyboard *keyboard);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* EEK_SECTION_H */
|
||||
|
||||
@ -150,6 +150,8 @@ typedef struct _EekBounds EekBounds;
|
||||
typedef struct _EekOutline EekOutline;
|
||||
typedef struct _EekColor EekColor;
|
||||
|
||||
typedef struct _EekboardContextService EekboardContextService;
|
||||
|
||||
/**
|
||||
* EekPoint:
|
||||
* @x: X coordinate of the point
|
||||
@ -212,7 +214,7 @@ struct _EekOutline
|
||||
/*< public >*/
|
||||
gdouble corner_radius;
|
||||
EekPoint *points;
|
||||
gint num_points;
|
||||
guint num_points;
|
||||
};
|
||||
|
||||
GType eek_outline_get_type (void) G_GNUC_CONST;
|
||||
|
||||
@ -31,14 +31,14 @@
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include "eek-xkb-layout.h"
|
||||
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/XKBlib.h>
|
||||
#include <X11/extensions/XKBgeom.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "eek-xkb-layout.h"
|
||||
#include "eek-keyboard.h"
|
||||
#include "eek-section.h"
|
||||
#include "eek-key.h"
|
||||
@ -320,21 +320,24 @@ create_keyboard (EekXkbLayout *layout, EekKeyboard *keyboard)
|
||||
}
|
||||
|
||||
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_height)
|
||||
{
|
||||
EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (self);
|
||||
EekBounds bounds;
|
||||
EekKeyboard *keyboard;
|
||||
EekKeyboard *keyboard = g_object_new (EEK_TYPE_KEYBOARD, "layout", self, NULL);
|
||||
keyboard->manager = manager;
|
||||
|
||||
keyboard = g_object_new (EEK_TYPE_KEYBOARD, "layout", self, NULL);
|
||||
bounds.x = bounds.y = 0.0;
|
||||
bounds.width = initial_width;
|
||||
bounds.height = initial_height;
|
||||
EekBounds bounds = {
|
||||
.x = 0.0,
|
||||
.y = 0.0,
|
||||
.width = initial_width,
|
||||
.height = initial_height
|
||||
};
|
||||
eek_element_set_bounds (EEK_ELEMENT(keyboard), &bounds);
|
||||
|
||||
/* resolve modifiers dynamically assigned at run time */
|
||||
EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (self);
|
||||
eek_keyboard_set_num_lock_mask (keyboard,
|
||||
XkbKeysymToModifiers (priv->display,
|
||||
XK_Num_Lock));
|
||||
|
||||
@ -25,7 +25,6 @@
|
||||
#ifndef EEK_XKB_LAYOUT_H
|
||||
#define EEK_XKB_LAYOUT_H 1
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/XKBlib.h>
|
||||
#include "eek-layout.h"
|
||||
|
||||
|
||||
@ -362,9 +362,6 @@ geometry_start_element_callback (GMarkupParseContext *pcontext,
|
||||
eek_element_set_bounds (EEK_ELEMENT(data->keyboard), &bounds);
|
||||
else if (g_strcmp0 (data->element_stack->data, "section") == 0)
|
||||
eek_element_set_bounds (EEK_ELEMENT(data->section), &bounds);
|
||||
else if (g_strcmp0 (data->element_stack->data, "key") == 0)
|
||||
eek_element_set_bounds (EEK_ELEMENT(data->key), &bounds);
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -504,7 +501,6 @@ geometry_end_element_callback (GMarkupParseContext *pcontext,
|
||||
{
|
||||
GeometryParseData *data = user_data;
|
||||
GSList *head = data->element_stack;
|
||||
gint i;
|
||||
|
||||
g_free (head->data);
|
||||
data->element_stack = g_slist_next (data->element_stack);
|
||||
@ -536,7 +532,8 @@ geometry_end_element_callback (GMarkupParseContext *pcontext,
|
||||
outline->num_points = g_slist_length (data->points);
|
||||
outline->points = g_slice_alloc0 (sizeof (EekPoint) *
|
||||
outline->num_points);
|
||||
for (head = data->points = g_slist_reverse (data->points), i = 0;
|
||||
guint i;
|
||||
for (i = 0, head = data->points = g_slist_reverse (data->points);
|
||||
head && i < outline->num_points;
|
||||
head = g_slist_next (head), i++) {
|
||||
memcpy (&outline->points[i], head->data, sizeof (EekPoint));
|
||||
@ -640,13 +637,13 @@ symbols_start_element_callback (GMarkupParseContext *pcontext,
|
||||
|
||||
data->key = eek_keyboard_find_key_by_keycode (data->keyboard,
|
||||
keycode);
|
||||
if (data->key == NULL) {
|
||||
/*if (data->key == NULL) {
|
||||
g_set_error (error,
|
||||
G_MARKUP_ERROR,
|
||||
G_MARKUP_ERROR_INVALID_CONTENT,
|
||||
"no such keycode %u", keycode);
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
|
||||
attribute = get_attribute (attribute_names, attribute_values,
|
||||
"groups");
|
||||
@ -721,6 +718,10 @@ symbols_end_element_callback (GMarkupParseContext *pcontext,
|
||||
text = g_strndup (data->text->str, data->text->len);
|
||||
|
||||
if (g_strcmp0 (element_name, "key") == 0) {
|
||||
if (!data->key) {
|
||||
return;
|
||||
}
|
||||
|
||||
gint num_symbols = g_slist_length (data->symbols);
|
||||
gint levels = num_symbols / data->groups;
|
||||
EekSymbolMatrix *matrix = eek_symbol_matrix_new (data->groups,
|
||||
@ -896,27 +897,25 @@ static const GMarkupParser prerequisites_parser = {
|
||||
};
|
||||
|
||||
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_height)
|
||||
{
|
||||
EekXmlLayout *layout = EEK_XML_LAYOUT (self);
|
||||
EekKeyboard *keyboard;
|
||||
gchar *filename, *path;
|
||||
GList *loaded;
|
||||
GError *error;
|
||||
gboolean retval;
|
||||
|
||||
/* Create an empty keyboard to which geometry and symbols
|
||||
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. */
|
||||
filename = g_strdup_printf ("%s.xml", layout->priv->desc->geometry);
|
||||
path = g_build_filename (layout->priv->keyboards_dir, "geometry", filename, NULL);
|
||||
gchar *filename = g_strdup_printf ("%s.xml", layout->priv->desc->geometry);
|
||||
gchar *path = g_build_filename (layout->priv->keyboards_dir, "geometry", filename, NULL);
|
||||
g_free (filename);
|
||||
|
||||
error = NULL;
|
||||
GError *error = NULL;
|
||||
retval = parse_geometry (path, keyboard, &error);
|
||||
g_free (path);
|
||||
if (!retval) {
|
||||
@ -929,7 +928,7 @@ eek_xml_layout_real_create_keyboard (EekLayout *self,
|
||||
}
|
||||
|
||||
/* Read symbols information. */
|
||||
loaded = NULL;
|
||||
GList *loaded = NULL;
|
||||
retval = parse_symbols_with_prerequisites (layout->priv->keyboards_dir,
|
||||
layout->priv->desc->symbols,
|
||||
keyboard,
|
||||
@ -1134,6 +1133,38 @@ eek_xml_keyboard_desc_free (EekXmlKeyboardDesc *desc)
|
||||
g_slice_free (EekXmlKeyboardDesc, desc);
|
||||
}
|
||||
|
||||
struct place_data {
|
||||
double desired_width;
|
||||
double current_offset;
|
||||
EekKeyboard *keyboard;
|
||||
};
|
||||
|
||||
const double section_spacing = 7.0;
|
||||
|
||||
static void section_placer(EekElement *element, gpointer user_data) {
|
||||
struct place_data *data = (struct place_data*)user_data;
|
||||
|
||||
EekBounds section_bounds = {0};
|
||||
eek_element_get_bounds(element, §ion_bounds);
|
||||
section_bounds.width = data->desired_width;
|
||||
eek_element_set_bounds(element, §ion_bounds);
|
||||
|
||||
// Sections are rows now. Gather up all the keys and adjust their bounds.
|
||||
eek_section_place_keys(EEK_SECTION(element), EEK_KEYBOARD(data->keyboard));
|
||||
|
||||
eek_element_get_bounds(element, §ion_bounds);
|
||||
section_bounds.y = data->current_offset;
|
||||
eek_element_set_bounds(element, §ion_bounds);
|
||||
data->current_offset += section_bounds.height + section_spacing;
|
||||
}
|
||||
|
||||
static void section_counter(EekElement *element, gpointer user_data) {
|
||||
double *total_height = user_data;
|
||||
EekBounds section_bounds = {0};
|
||||
eek_element_get_bounds(element, §ion_bounds);
|
||||
*total_height += section_bounds.height + section_spacing;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_geometry (const gchar *path, EekKeyboard *keyboard, GError **error)
|
||||
{
|
||||
@ -1186,6 +1217,27 @@ parse_geometry (const gchar *path, EekKeyboard *keyboard, GError **error)
|
||||
}
|
||||
g_hash_table_destroy (oref_hash);
|
||||
|
||||
/* Order rows */
|
||||
// This needs to be done after outlines, because outlines define key sizes
|
||||
// TODO: do this only for rows without bounds
|
||||
|
||||
// The keyboard width is given by the user via screen size. The height will be given dynamically.
|
||||
// TODO: calculate max line width beforehand for button centering. Leave keyboard centering to the renderer later
|
||||
EekBounds keyboard_bounds = {0};
|
||||
eek_element_get_bounds(EEK_ELEMENT(keyboard), &keyboard_bounds);
|
||||
|
||||
struct place_data placer_data = {
|
||||
.desired_width = keyboard_bounds.width,
|
||||
.current_offset = 0,
|
||||
.keyboard = keyboard,
|
||||
};
|
||||
eek_container_foreach_child(EEK_CONTAINER(keyboard), section_placer, &placer_data);
|
||||
|
||||
double total_height = 0;
|
||||
eek_container_foreach_child(EEK_CONTAINER(keyboard), section_counter, &total_height);
|
||||
keyboard_bounds.height = total_height;
|
||||
eek_element_set_bounds(EEK_ELEMENT(keyboard), &keyboard_bounds);
|
||||
|
||||
geometry_parse_data_free (data);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -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 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
|
||||
@ -21,13 +22,17 @@
|
||||
import sys
|
||||
import re
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
print >> sys.stderr, "Usage: %s TABLE-NAME" % sys.argv[0]
|
||||
if len(sys.argv) > 3:
|
||||
print("Usage: %s TABLE-NAME [INPUT_FILE]" % sys.argv[0], file=sys.stderr)
|
||||
sys.exit(-1)
|
||||
|
||||
if len(sys.argv) < 3:
|
||||
in_stream = sys.stdin
|
||||
else:
|
||||
in_stream = open(sys.argv[2])
|
||||
|
||||
table = dict()
|
||||
for line in sys.stdin:
|
||||
line = line.decode('UTF-8')
|
||||
for line in in_stream:
|
||||
match = re.match(r'\s*(0x[0-9A-F]+)\s+(\S*)\s+(\S*)', line, re.I)
|
||||
if match:
|
||||
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 keysym in sorted(table.keys())]):
|
||||
sys.stdout.write(" { 0x%X, %s, %s }" %
|
||||
(keysym, l.encode('UTF-8'), c.encode('UTF-8')))
|
||||
(keysym, l, c))
|
||||
if index < len(table) - 1:
|
||||
sys.stdout.write(",")
|
||||
sys.stdout.write("\n")
|
||||
|
||||
374
eek/layersurface.c
Normal file
374
eek/layersurface.c
Normal 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
41
eek/layersurface.h
Normal 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
44
eek/meson.build
Normal 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'),
|
||||
]
|
||||
@ -16,55 +16,69 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301 USA
|
||||
|
||||
NULL =
|
||||
|
||||
lib_LTLIBRARIES = libeekboard.la
|
||||
|
||||
libeekboard_headers = \
|
||||
eekboard-service.h \
|
||||
eekboard-context-service.h \
|
||||
eekboard-client.h \
|
||||
eekboard-context.h \
|
||||
eekboard-xklutil.h
|
||||
$(srcdir)/eekboard-service.h \
|
||||
$(srcdir)/eekboard-context-service.h \
|
||||
$(srcdir)/eekboard-client.h \
|
||||
$(srcdir)/eekboard-context.h \
|
||||
$(srcdir)/eekboard-xklutil.h \
|
||||
$(NULL)
|
||||
|
||||
libeekboard_private_headers = \
|
||||
eekboard-marshalers.h
|
||||
$(builddir)/eekboard-marshalers.h \
|
||||
$(NULL)
|
||||
|
||||
libeekboard_sources = \
|
||||
eekboard-service.c \
|
||||
eekboard-context-service.c \
|
||||
eekboard-client.c \
|
||||
eekboard-context.c \
|
||||
eekboard-xklutil.c
|
||||
$(srcdir)/eekboard-service.c \
|
||||
$(srcdir)/eekboard-context-service.c \
|
||||
$(srcdir)/eekboard-client.c \
|
||||
$(srcdir)/eekboard-context.c \
|
||||
$(srcdir)/eekboard-xklutil.c \
|
||||
$(NULL)
|
||||
|
||||
libeekboard_marshalers_sources = \
|
||||
eekboard-marshalers.c \
|
||||
eekboard-marshalers.h
|
||||
$(builddir)/eekboard-marshalers.c \
|
||||
$(builddir)/eekboard-marshalers.h \
|
||||
$(NULL)
|
||||
|
||||
BUILT_SOURCES = \
|
||||
$(libeekboard_marshalers_sources)
|
||||
$(libeekboard_marshalers_sources) \
|
||||
$(NULL)
|
||||
|
||||
libeekboard_la_SOURCES = \
|
||||
$(libeekboard_sources) \
|
||||
eekboard-marshalers.c
|
||||
$(builddir)/eekboard-marshalers.c \
|
||||
$(NULL)
|
||||
|
||||
libeekboard_la_CFLAGS = \
|
||||
-DEEKBOARD_COMPILATION=1 \
|
||||
-DKEYBOARDDIR=\"$(pkgdatadir)/keyboards\" \
|
||||
-I$(top_srcdir) \
|
||||
$(GIO2_CFLAGS) \
|
||||
$(LIBXKLAVIER_CFLAGS)
|
||||
$(LIBXKLAVIER_CFLAGS) \
|
||||
$(NULL)
|
||||
libeekboard_la_LIBADD = \
|
||||
$(top_builddir)/eek/libeek.la \
|
||||
$(top_builddir)/eek/libeek-xkl.la \
|
||||
$(GIO2_LIBS) \
|
||||
$(LIBXKLAVIER_LIBS)
|
||||
$(LIBXKLAVIER_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
eekboarddir = $(includedir)/eekboard-$(EEK_API_VERSION)/eekboard
|
||||
eekboard_HEADERS = $(libeekboard_headers)
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = \
|
||||
eekboard-$(EEK_API_VERSION).pc
|
||||
eekboard-$(EEK_API_VERSION).pc \
|
||||
$(NULL)
|
||||
DISTCLEANFILES = \
|
||||
$(BUILT_SOURCES) \
|
||||
$(pkgconfig_DATA)
|
||||
$(pkgconfig_DATA) \
|
||||
$(NULL)
|
||||
|
||||
CLEANFILES =
|
||||
|
||||
@ -72,22 +86,37 @@ EXTRA_DIST = eekboard-marshalers.list
|
||||
|
||||
# gen marshal
|
||||
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 $@
|
||||
|
||||
eekboard-marshalers.c: eekboard-marshalers.list 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 $@
|
||||
|
||||
-include $(INTROSPECTION_MAKEFILE)
|
||||
INTROSPECTION_GIRS =
|
||||
INTROSPECTION_SCANNER_ARGS = --add-include-path=$(builddir) --add-include-path=$(top_builddir)/eek
|
||||
INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir) --includedir=$(top_srcdir)/eek
|
||||
INTROSPECTION_SCANNER_ARGS = \
|
||||
--add-include-path=$(builddir) \
|
||||
--add-include-path=$(top_builddir)/eek \
|
||||
$(NULL)
|
||||
INTROSPECTION_COMPILER_ARGS = \
|
||||
--includedir=$(builddir) \
|
||||
--includedir=$(top_builddir)/eek \
|
||||
$(NULL)
|
||||
|
||||
if HAVE_INTROSPECTION
|
||||
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_CFLAGS = $(libeekboard_la_CFLAGS)
|
||||
Eekboard@EEK_LIBRARY_SUFFIX_U@_gir_LIBS = libeekboard.la
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -24,6 +24,8 @@
|
||||
|
||||
#include <eek/eek.h>
|
||||
|
||||
#include "virtual-keyboard-unstable-v1-client-protocol.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#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_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 _EekboardContextServicePrivate EekboardContextServicePrivate;
|
||||
|
||||
/**
|
||||
* EekboardContextService:
|
||||
*
|
||||
* TODO: Restrict to managing keyboard layouts, and maybe button repeats,
|
||||
* and the virtual keyboard protocol.
|
||||
*
|
||||
* The #EekboardContextService structure contains only private data
|
||||
* and should only be accessed using the provided API.
|
||||
*/
|
||||
@ -50,6 +55,8 @@ struct _EekboardContextService {
|
||||
GObject parent;
|
||||
|
||||
EekboardContextServicePrivate *priv;
|
||||
|
||||
struct zwp_virtual_keyboard_v1 *virtual_keyboard;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -93,8 +100,9 @@ EekKeyboard *eekboard_context_service_get_keyboard
|
||||
(EekboardContextService *context);
|
||||
gboolean eekboard_context_service_get_fullscreen
|
||||
(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
|
||||
#endif /* EEKBOARD_CONTEXT_SERVICE_H */
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include "eekboard/eekboard-context.h"
|
||||
#include "eekboard/eekboard-marshalers.h"
|
||||
//#include "eekboard/eekboard-marshalers.h"
|
||||
|
||||
#define I_(string) g_intern_static_string (string)
|
||||
|
||||
@ -151,7 +151,7 @@ eekboard_context_real_destroyed (EekboardContext *self)
|
||||
|
||||
static void
|
||||
eekboard_context_real_key_activated (EekboardContext *self,
|
||||
const gchar *keyname,
|
||||
guint keycode,
|
||||
EekSymbol *symbol,
|
||||
guint modifiers)
|
||||
{
|
||||
@ -251,6 +251,7 @@ eekboard_context_class_init (EekboardContextClass *klass)
|
||||
* The ::key-activated signal is emitted each time a key is
|
||||
* pressed in @context.
|
||||
*/
|
||||
/*
|
||||
signals[KEY_ACTIVATED] =
|
||||
g_signal_new (I_("key-activated"),
|
||||
G_TYPE_FROM_CLASS(gobject_class),
|
||||
@ -264,7 +265,7 @@ eekboard_context_class_init (EekboardContextClass *klass)
|
||||
G_TYPE_UINT,
|
||||
G_TYPE_OBJECT,
|
||||
G_TYPE_UINT);
|
||||
|
||||
*/
|
||||
/**
|
||||
* EekboardContext::destroyed:
|
||||
* @context: an #EekboardContext
|
||||
|
||||
@ -1 +0,0 @@
|
||||
VOID:UINT,OBJECT,UINT
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
/*
|
||||
* 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
|
||||
@ -18,7 +18,9 @@
|
||||
|
||||
/**
|
||||
* 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
|
||||
* implementation of eekboard service.
|
||||
@ -30,6 +32,10 @@
|
||||
|
||||
#include "eekboard/eekboard-service.h"
|
||||
|
||||
#include "sm.puri.OSK0.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_OBJECT_PATH,
|
||||
@ -49,51 +55,16 @@ static guint signals[LAST_SIGNAL] = { 0, };
|
||||
|
||||
struct _EekboardServicePrivate {
|
||||
GDBusConnection *connection;
|
||||
SmPuriOSK0 *dbus_interface;
|
||||
GDBusNodeInfo *introspection_data;
|
||||
guint registration_id;
|
||||
char *object_path;
|
||||
|
||||
GHashTable *context_hash;
|
||||
GSList *context_stack;
|
||||
gboolean visible;
|
||||
EekboardContextService *context; // unowned reference
|
||||
};
|
||||
|
||||
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='ShowKeyboard'/>"
|
||||
" <method name='HideKeyboard'/>"
|
||||
" <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
|
||||
eekboard_service_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
@ -146,19 +117,6 @@ static void
|
||||
eekboard_service_dispose (GObject *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->registration_id > 0) {
|
||||
g_dbus_connection_unregister_object (service->priv->connection,
|
||||
@ -188,26 +146,40 @@ eekboard_service_finalize (GObject *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
|
||||
eekboard_service_constructed (GObject *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) {
|
||||
GError *error = NULL;
|
||||
|
||||
service->priv->registration_id = g_dbus_connection_register_object
|
||||
(service->priv->connection,
|
||||
service->priv->object_path,
|
||||
service->priv->introspection_data->interfaces[0],
|
||||
&interface_vtable,
|
||||
object,
|
||||
NULL,
|
||||
&error);
|
||||
|
||||
if (service->priv->registration_id == 0) {
|
||||
g_warning ("failed to register context object: %s",
|
||||
error->message);
|
||||
g_error_free (error);
|
||||
if (!g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(service->priv->dbus_interface),
|
||||
service->priv->connection,
|
||||
service->priv->object_path,
|
||||
&error)) {
|
||||
g_warning("Error registering dbus object: %s\n", error->message);
|
||||
g_clear_error(&error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -278,237 +250,14 @@ eekboard_service_class_init (EekboardServiceClass *klass)
|
||||
static void
|
||||
eekboard_service_init (EekboardService *self)
|
||||
{
|
||||
GError *error;
|
||||
|
||||
self->priv = EEKBOARD_SERVICE_GET_PRIVATE(self);
|
||||
|
||||
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
|
||||
on_notify_visible (GObject *object, GParamSpec *spec, gpointer user_data)
|
||||
{
|
||||
EekboardService *service = user_data;
|
||||
|
||||
g_object_get (object, "visible", &service->priv->visible, NULL);
|
||||
}
|
||||
|
||||
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_signal_connect (context, "notify::visible",
|
||||
G_CALLBACK(on_notify_visible), service);
|
||||
if (service->priv->visible)
|
||||
eekboard_context_service_show_keyboard (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);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (context,
|
||||
G_CALLBACK(on_notify_visible),
|
||||
service);
|
||||
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, "ShowKeyboard") == 0) {
|
||||
if (service->priv->context_stack) {
|
||||
eekboard_context_service_show_keyboard (service->priv->context_stack->data);
|
||||
} else {
|
||||
service->priv->visible = TRUE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_strcmp0 (method_name, "HideKeyboard") == 0) {
|
||||
if (service->priv->context_stack) {
|
||||
eekboard_context_service_hide_keyboard (service->priv->context_stack->data);
|
||||
} else {
|
||||
service->priv->visible = FALSE;
|
||||
}
|
||||
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 ();
|
||||
self->priv->context = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* eekboard_service_new:
|
||||
* @connection: a #GDBusConnection
|
||||
* @object_path: object path
|
||||
*
|
||||
* Create an empty server for testing purpose.
|
||||
*/
|
||||
EekboardService *
|
||||
eekboard_service_new (GDBusConnection *connection,
|
||||
@ -519,3 +268,10 @@ eekboard_service_new (GDBusConnection *connection,
|
||||
"connection", connection,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
eekboard_service_set_context(EekboardService *service,
|
||||
|
||||
EekboardContextService *context) {
|
||||
service->priv->context = context;
|
||||
}
|
||||
|
||||
@ -24,8 +24,8 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define EEKBOARD_SERVICE_PATH "/org/fedorahosted/Eekboard"
|
||||
#define EEKBOARD_SERVICE_INTERFACE "org.fedorahosted.Eekboard"
|
||||
#define EEKBOARD_SERVICE_PATH "/sm/puri/OSK0"
|
||||
#define EEKBOARD_SERVICE_INTERFACE "sm.puri.OSK0"
|
||||
|
||||
#define EEKBOARD_TYPE_SERVICE (eekboard_service_get_type())
|
||||
#define EEKBOARD_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEKBOARD_TYPE_SERVICE, EekboardService))
|
||||
@ -41,6 +41,8 @@ typedef struct _EekboardServicePrivate EekboardServicePrivate;
|
||||
/**
|
||||
* EekboardService:
|
||||
*
|
||||
* Manages DBus interaction.
|
||||
*
|
||||
* The #EekboardService structure contains only private data and
|
||||
* should only be accessed using the provided API.
|
||||
*/
|
||||
@ -60,9 +62,7 @@ struct _EekboardServiceClass {
|
||||
GObjectClass parent_class;
|
||||
|
||||
/*< public >*/
|
||||
EekboardContextService *(*create_context) (EekboardService *self,
|
||||
const gchar *client_name,
|
||||
const gchar *object_path);
|
||||
EekboardContextService *(*create_context) (EekboardService *self);
|
||||
|
||||
/*< private >*/
|
||||
/* padding */
|
||||
@ -72,6 +72,7 @@ struct _EekboardServiceClass {
|
||||
GType eekboard_service_get_type (void) G_GNUC_CONST;
|
||||
EekboardService * eekboard_service_new (GDBusConnection *connection,
|
||||
const gchar *object_path);
|
||||
|
||||
void eekboard_service_set_context(EekboardService *service,
|
||||
EekboardContextService *context);
|
||||
G_END_DECLS
|
||||
#endif /* EEKBOARD_SERVICE_H */
|
||||
|
||||
327
eekboard/key-emitter.c
Normal file
327
eekboard/key-emitter.c
Normal file
@ -0,0 +1,327 @@
|
||||
/*
|
||||
* 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];
|
||||
guint modifier_indices[MOD_IDX_LAST];
|
||||
guint 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 ((guint)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_modifiers_events (SeatEmitter *emitter,
|
||||
EekModifierType modifiers,
|
||||
uint32_t timestamp)
|
||||
{
|
||||
(void)timestamp;
|
||||
|
||||
uint32_t proto_modifiers = 0;
|
||||
if (modifiers & EEK_SHIFT_MASK) {
|
||||
proto_modifiers |= 1<<MOD_IDX_SHIFT;
|
||||
}
|
||||
if (modifiers & EEK_CONTROL_MASK) {
|
||||
proto_modifiers |= 1<<MOD_IDX_CTRL;
|
||||
}
|
||||
if (modifiers & EEK_MOD1_MASK) {
|
||||
proto_modifiers |= 1<<MOD_IDX_ALT;
|
||||
}
|
||||
zwp_virtual_keyboard_v1_modifiers(emitter->virtual_keyboard, proto_modifiers, 0, 0, emitter->group);
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
modifiers |= keyboard_modifiers;
|
||||
|
||||
send_fake_modifiers_events (emitter, modifiers, 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_modifiers_events (emitter, modifiers, timestamp);
|
||||
|
||||
if (old_keysym != xkeysym)
|
||||
replace_keycode (emitter, keycode, &old_keysym);
|
||||
}
|
||||
|
||||
static void
|
||||
send_fake_key_events (SeatEmitter *emitter,
|
||||
EekSymbol *symbol,
|
||||
EekModifierType 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Finds the first key code for each modifier and saves it in modifier_keycodes */
|
||||
static void
|
||||
update_modifier_info (SeatEmitter *client)
|
||||
{
|
||||
client->modifier_indices[MOD_IDX_SHIFT] = xkb_keymap_mod_get_index(client->keymap, XKB_MOD_NAME_SHIFT);
|
||||
client->modifier_indices[MOD_IDX_CAPS] = xkb_keymap_mod_get_index(client->keymap, XKB_MOD_NAME_CAPS);
|
||||
client->modifier_indices[MOD_IDX_CTRL] = xkb_keymap_mod_get_index(client->keymap, XKB_MOD_NAME_CTRL);
|
||||
client->modifier_indices[MOD_IDX_ALT] = xkb_keymap_mod_get_index(client->keymap, XKB_MOD_NAME_ALT);
|
||||
client->modifier_indices[MOD_IDX_NUM] = xkb_keymap_mod_get_index(client->keymap, XKB_MOD_NAME_NUM);
|
||||
client->modifier_indices[MOD_IDX_MOD3] = xkb_keymap_mod_get_index(client->keymap, "Mod3");
|
||||
client->modifier_indices[MOD_IDX_LOGO] = xkb_keymap_mod_get_index(client->keymap, XKB_MOD_NAME_LOGO);
|
||||
client->modifier_indices[MOD_IDX_ALTGR] = xkb_keymap_mod_get_index(client->keymap, "Mod5");
|
||||
client->modifier_indices[MOD_IDX_NUMLK] = xkb_keymap_mod_get_index(client->keymap, "NumLock");
|
||||
client->modifier_indices[MOD_IDX_ALSO_ALT] = xkb_keymap_mod_get_index(client->keymap, "Alt");
|
||||
client->modifier_indices[MOD_IDX_LVL3] = xkb_keymap_mod_get_index(client->keymap, "LevelThree");
|
||||
client->modifier_indices[MOD_IDX_LALT] = xkb_keymap_mod_get_index(client->keymap, "LAlt");
|
||||
client->modifier_indices[MOD_IDX_RALT] = xkb_keymap_mod_get_index(client->keymap, "RAlt");
|
||||
client->modifier_indices[MOD_IDX_RCONTROL] = xkb_keymap_mod_get_index(client->keymap, "RControl");
|
||||
client->modifier_indices[MOD_IDX_LCONTROL] = xkb_keymap_mod_get_index(client->keymap, "LControl");
|
||||
client->modifier_indices[MOD_IDX_SCROLLLK] = xkb_keymap_mod_get_index(client->keymap, "ScrollLock");
|
||||
client->modifier_indices[MOD_IDX_LVL5] = xkb_keymap_mod_get_index(client->keymap, "LevelFive");
|
||||
client->modifier_indices[MOD_IDX_ALSO_ALTGR] = xkb_keymap_mod_get_index(client->keymap, "AltGr");
|
||||
client->modifier_indices[MOD_IDX_META] = xkb_keymap_mod_get_index(client->keymap, "Meta");
|
||||
client->modifier_indices[MOD_IDX_SUPER] = xkb_keymap_mod_get_index(client->keymap, "Super");
|
||||
client->modifier_indices[MOD_IDX_HYPER] = xkb_keymap_mod_get_index(client->keymap, "Hyper");
|
||||
|
||||
/*
|
||||
for (xkb_mod_index_t i = 0;
|
||||
i < xkb_keymap_num_mods(client->keymap);
|
||||
i++) {
|
||||
g_log("squeek", G_LOG_LEVEL_DEBUG, "%s", xkb_keymap_mod_get_name(client->keymap, i));
|
||||
}*/
|
||||
}
|
||||
|
||||
void
|
||||
emit_key_activated (EekboardContextService *manager,
|
||||
EekKeyboard *keyboard,
|
||||
guint keycode,
|
||||
EekSymbol *symbol,
|
||||
EekModifierType 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;
|
||||
update_modifier_info (&emitter);
|
||||
send_fake_key_events (&emitter, symbol, modifiers, pressed, timestamp);
|
||||
}
|
||||
48
eekboard/key-emitter.h
Normal file
48
eekboard/key-emitter.h
Normal file
@ -0,0 +1,48 @@
|
||||
#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"
|
||||
|
||||
/// Indices obtained by xkb_keymap_mod_get_name
|
||||
enum mod_indices {
|
||||
MOD_IDX_SHIFT,
|
||||
MOD_IDX_CAPS,
|
||||
MOD_IDX_CTRL,
|
||||
MOD_IDX_ALT,
|
||||
MOD_IDX_NUM,
|
||||
MOD_IDX_MOD3,
|
||||
MOD_IDX_LOGO,
|
||||
MOD_IDX_ALTGR,
|
||||
MOD_IDX_NUMLK, // Caution, not sure which is the right one
|
||||
MOD_IDX_ALSO_ALT, // Not sure why, alt emits the first alt on my setup
|
||||
MOD_IDX_LVL3,
|
||||
|
||||
// Not sure if the next 4 are used at all
|
||||
MOD_IDX_LALT,
|
||||
MOD_IDX_RALT,
|
||||
MOD_IDX_RCONTROL,
|
||||
MOD_IDX_LCONTROL,
|
||||
|
||||
MOD_IDX_SCROLLLK,
|
||||
MOD_IDX_LVL5,
|
||||
MOD_IDX_ALSO_ALTGR, // Not used on my layout
|
||||
MOD_IDX_META,
|
||||
MOD_IDX_SUPER,
|
||||
MOD_IDX_HYPER,
|
||||
|
||||
MOD_IDX_LAST,
|
||||
};
|
||||
|
||||
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
66
eekboard/keymap.c
Normal 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
8
eekboard/keymap.h
Normal 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);
|
||||
28
meson.build
Normal file
28
meson.build
Normal 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
9
po/meson.build
Normal 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'
|
||||
]
|
||||
)
|
||||
404
protocols/input-method-unstable-v2.xml
Normal file
404
protocols/input-method-unstable-v2.xml
Normal 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
22
protocols/meson.build
Normal 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
|
||||
113
protocols/virtual-keyboard-unstable-v1.xml
Normal file
113
protocols/virtual-keyboard-unstable-v1.xml
Normal 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>
|
||||
285
protocols/wlr-layer-shell-unstable-v1.xml
Normal file
285
protocols/wlr-layer-shell-unstable-v1.xml
Normal 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>
|
||||
@ -18,7 +18,6 @@
|
||||
|
||||
bin_PROGRAMS = \
|
||||
eekboard \
|
||||
eekboard-server \
|
||||
$(NULL)
|
||||
|
||||
libexec_PROGRAMS = \
|
||||
@ -63,40 +62,6 @@ eekboard_SOURCES = \
|
||||
client-main.c \
|
||||
$(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 = \
|
||||
-I$(top_srcdir) \
|
||||
$(GIO2_CFLAGS) \
|
||||
@ -125,7 +90,6 @@ dist_pkgdata_DATA = preferences-dialog.ui
|
||||
|
||||
noinst_HEADERS = \
|
||||
$(eekboard_headers) \
|
||||
$(eekboard_server_headers) \
|
||||
$(eekboard_setup_headers) \
|
||||
$(NULL)
|
||||
|
||||
|
||||
@ -37,7 +37,9 @@ static gboolean opt_session = FALSE;
|
||||
static gchar *opt_address = NULL;
|
||||
|
||||
static gboolean opt_focus = FALSE;
|
||||
#ifdef HAVE_ATSPI
|
||||
static gboolean opt_keystroke = FALSE;
|
||||
#endif /* HAVE_ATSPI */
|
||||
|
||||
static gchar *opt_keyboards = NULL;
|
||||
|
||||
@ -86,7 +88,7 @@ enum FocusListenerType {
|
||||
};
|
||||
|
||||
static gboolean
|
||||
set_keyboards (Client *client,
|
||||
set_keyboards (SeatEmitter *client,
|
||||
const gchar * const *keyboards)
|
||||
{
|
||||
if (g_strv_length ((gchar **)keyboards) == 0) {
|
||||
@ -108,7 +110,7 @@ set_keyboards (Client *client,
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
Client *client = NULL;
|
||||
SeatEmitter *client = NULL;
|
||||
EekboardClient *eekboard;
|
||||
EekboardContext *context;
|
||||
GBusType bus_type;
|
||||
@ -268,13 +270,13 @@ main (int argc, char **argv)
|
||||
}
|
||||
#endif /* HAVE_IBUS */
|
||||
|
||||
#ifdef HAVE_XTEST
|
||||
//#ifdef HAVE_XTEST
|
||||
if (!client_enable_xtest (client)) {
|
||||
g_printerr ("Can't init xtest\n");
|
||||
g_object_unref (client);
|
||||
exit (1);
|
||||
}
|
||||
#endif /* HAVE_XTEST */
|
||||
//#endif /* HAVE_XTEST */
|
||||
|
||||
if (!opt_focus) {
|
||||
g_object_get (client, "context", &context, NULL);
|
||||
|
||||
119
src/client.c
119
src/client.c
@ -91,10 +91,8 @@ struct _Client {
|
||||
AtspiDeviceListener *keystroke_listener;
|
||||
#endif /* HAVE_ATSPI */
|
||||
|
||||
#ifdef HAVE_XTEST
|
||||
guint modifier_keycodes[8];
|
||||
XkbDescRec *xkb;
|
||||
#endif /* HAVE_XTEST */
|
||||
|
||||
GSettings *settings;
|
||||
};
|
||||
@ -103,7 +101,7 @@ struct _ClientClass {
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (Client, client, G_TYPE_OBJECT);
|
||||
G_DEFINE_TYPE (SeatEmitter, client, G_TYPE_OBJECT);
|
||||
|
||||
#if ENABLE_FOCUS_LISTENER
|
||||
#define IS_KEYBOARD_VISIBLE(client) (!client->follows_focus)
|
||||
@ -130,10 +128,10 @@ static void focus_listener_cb (const AtspiEvent *event,
|
||||
static gboolean keystroke_listener_cb (const AtspiDeviceEvent *stroke,
|
||||
void *user_data);
|
||||
#endif /* HAVE_ATSPI */
|
||||
static gboolean set_keyboards (Client *client,
|
||||
static gboolean set_keyboards (SeatEmitter *client,
|
||||
const gchar * const *keyboard);
|
||||
static gboolean set_keyboards_from_xkl
|
||||
(Client *client);
|
||||
(SeatEmitter *client);
|
||||
#ifdef HAVE_XTEST
|
||||
static void update_modifier_keycodes
|
||||
(Client *client);
|
||||
@ -145,7 +143,7 @@ client_set_property (GObject *object,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
Client *client = CLIENT(object);
|
||||
SeatEmitter *client = CLIENT(object);
|
||||
GDBusConnection *connection;
|
||||
gchar **keyboards;
|
||||
|
||||
@ -190,7 +188,7 @@ client_get_property (GObject *object,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
Client *client = CLIENT(object);
|
||||
SeatEmitter *client = CLIENT(object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_EEKBOARD:
|
||||
@ -208,7 +206,7 @@ client_get_property (GObject *object,
|
||||
static void
|
||||
client_dispose (GObject *object)
|
||||
{
|
||||
Client *client = CLIENT(object);
|
||||
SeatEmitter *client = CLIENT(object);
|
||||
|
||||
client_disable_xkl (client);
|
||||
|
||||
@ -248,7 +246,7 @@ client_dispose (GObject *object)
|
||||
static void
|
||||
client_finalize (GObject *object)
|
||||
{
|
||||
Client *client = CLIENT(object);
|
||||
SeatEmitter *client = CLIENT(object);
|
||||
|
||||
g_slist_free (client->keyboards);
|
||||
G_OBJECT_CLASS (client_parent_class)->finalize (object);
|
||||
@ -303,13 +301,13 @@ client_class_init (ClientClass *klass)
|
||||
}
|
||||
|
||||
static void
|
||||
client_init (Client *client)
|
||||
client_init (SeatEmitter *client)
|
||||
{
|
||||
client->settings = g_settings_new ("org.fedorahosted.eekboard");
|
||||
}
|
||||
|
||||
gboolean
|
||||
client_set_keyboards (Client *client,
|
||||
client_set_keyboards (SeatEmitter *client,
|
||||
const gchar * const *keyboards)
|
||||
{
|
||||
gboolean retval;
|
||||
@ -320,7 +318,7 @@ client_set_keyboards (Client *client,
|
||||
}
|
||||
|
||||
gboolean
|
||||
client_enable_xkl (Client *client)
|
||||
client_enable_xkl (SeatEmitter *client)
|
||||
{
|
||||
GdkDisplay *display = gdk_display_get_default ();
|
||||
gboolean retval;
|
||||
@ -363,7 +361,7 @@ client_enable_xkl (Client *client)
|
||||
}
|
||||
|
||||
void
|
||||
client_disable_xkl (Client *client)
|
||||
client_disable_xkl (SeatEmitter *client)
|
||||
{
|
||||
if (client->xkl_engine) {
|
||||
xkl_engine_stop_listen (client->xkl_engine, XKLL_TRACK_KEYBOARD_STATE);
|
||||
@ -620,7 +618,7 @@ add_match_rule (GDBusConnection *connection,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_hide_keyboard_timeout (Client *client)
|
||||
on_hide_keyboard_timeout (SeatEmitter *client)
|
||||
{
|
||||
eekboard_client_hide_keyboard (client->eekboard, NULL);
|
||||
client->hide_keyboard_timeout_id = 0;
|
||||
@ -633,7 +631,7 @@ focus_message_filter (GDBusConnection *connection,
|
||||
gboolean incoming,
|
||||
gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
SeatEmitter *client = user_data;
|
||||
|
||||
if (incoming &&
|
||||
g_strcmp0 (g_dbus_message_get_interface (message),
|
||||
@ -663,7 +661,7 @@ focus_message_filter (GDBusConnection *connection,
|
||||
static void
|
||||
_ibus_connect_focus_handlers (GDBusConnection *connection, gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
SeatEmitter *client = user_data;
|
||||
|
||||
add_match_rule (connection,
|
||||
"type='method_call',"
|
||||
@ -681,7 +679,7 @@ _ibus_connect_focus_handlers (GDBusConnection *connection, gpointer user_data)
|
||||
}
|
||||
|
||||
gboolean
|
||||
client_enable_ibus_focus (Client *client)
|
||||
client_enable_ibus_focus (SeatEmitter *client)
|
||||
{
|
||||
if (client->ibus_connection == NULL) {
|
||||
const gchar *ibus_address;
|
||||
@ -713,7 +711,7 @@ client_enable_ibus_focus (Client *client)
|
||||
}
|
||||
|
||||
void
|
||||
client_disable_ibus_focus (Client *client)
|
||||
client_disable_ibus_focus (SeatEmitter *client)
|
||||
{
|
||||
client->follows_focus = FALSE;
|
||||
|
||||
@ -727,10 +725,10 @@ client_disable_ibus_focus (Client *client)
|
||||
}
|
||||
}
|
||||
|
||||
Client *
|
||||
SeatEmitter *
|
||||
client_new (GDBusConnection *connection)
|
||||
{
|
||||
Client *client = g_object_new (TYPE_CLIENT,
|
||||
SeatEmitter *client = g_object_new (TYPE_CLIENT,
|
||||
"connection", connection,
|
||||
NULL);
|
||||
if (client->context)
|
||||
@ -743,7 +741,7 @@ filter_xkl_event (GdkXEvent *xev,
|
||||
GdkEvent *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
SeatEmitter *client = user_data;
|
||||
XEvent *xevent = (XEvent *)xev;
|
||||
|
||||
xkl_engine_filter_events (client->xkl_engine, xevent);
|
||||
@ -754,7 +752,7 @@ static void
|
||||
on_xkl_config_changed (XklEngine *xklengine,
|
||||
gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
SeatEmitter *client = user_data;
|
||||
gboolean retval;
|
||||
|
||||
retval = set_keyboards_from_xkl (client);
|
||||
@ -766,7 +764,7 @@ on_xkl_config_changed (XklEngine *xklengine,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
set_keyboards (Client *client,
|
||||
set_keyboards (SeatEmitter *client,
|
||||
const gchar * const *keyboards)
|
||||
{
|
||||
guint keyboard_id;
|
||||
@ -807,7 +805,7 @@ set_keyboards (Client *client,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
set_keyboards_from_xkl (Client *client)
|
||||
set_keyboards_from_xkl (SeatEmitter *client)
|
||||
{
|
||||
XklConfigRec *rec;
|
||||
gchar *layout, *keyboard;
|
||||
@ -839,13 +837,12 @@ on_xkl_state_changed (XklEngine *xklengine,
|
||||
gboolean restore,
|
||||
gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
SeatEmitter *client = user_data;
|
||||
|
||||
if (type == GROUP_CHANGED)
|
||||
eekboard_context_set_group (client->context, value, NULL);
|
||||
}
|
||||
|
||||
#ifdef HAVE_XTEST
|
||||
/* The following functions for keyboard mapping change are direct
|
||||
translation of the code in Caribou (in libcaribou/xadapter.vala):
|
||||
|
||||
@ -854,7 +851,7 @@ on_xkl_state_changed (XklEngine *xklengine,
|
||||
- get_keycode_from_gdk_keymap (Caribou: best_keycode_keyval_match)
|
||||
*/
|
||||
static guint
|
||||
get_replaced_keycode (Client *client)
|
||||
get_replaced_keycode (SeatEmitter *client)
|
||||
{
|
||||
guint keycode;
|
||||
|
||||
@ -879,7 +876,7 @@ get_replaced_keycode (Client *client)
|
||||
non-zero keycode), it simply changes the current map with the
|
||||
specified KEYCODE and KEYSYM. */
|
||||
static gboolean
|
||||
replace_keycode (Client *client,
|
||||
replace_keycode (SeatEmitter *client,
|
||||
guint keycode,
|
||||
guint *keysym)
|
||||
{
|
||||
@ -888,12 +885,13 @@ replace_keycode (Client *client,
|
||||
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 (client->xkb->min_key_code <= keycode &&
|
||||
keycode <= client->xkb->max_key_code,
|
||||
FALSE);
|
||||
g_return_val_if_fail (keysym != NULL, FALSE);
|
||||
|
||||
/*
|
||||
* Switch keyboard mapping?
|
||||
syms = XGetKeyboardMapping (xdisplay, keycode, 1, &keysyms_per_keycode);
|
||||
old_keysym = syms[0];
|
||||
syms[0] = *keysym;
|
||||
@ -901,12 +899,12 @@ replace_keycode (Client *client,
|
||||
XSync (xdisplay, False);
|
||||
XFree (syms);
|
||||
*keysym = old_keysym;
|
||||
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_keycode_from_gdk_keymap (Client *client,
|
||||
get_keycode_from_gdk_keymap (SeatEmitter *client,
|
||||
guint keysym,
|
||||
guint *keycode,
|
||||
guint *modifiers)
|
||||
@ -934,8 +932,18 @@ get_keycode_from_gdk_keymap (Client *client,
|
||||
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
|
||||
send_fake_modifier_key_event (Client *client,
|
||||
send_fake_modifier_key_event (SeatEmitter *client,
|
||||
EekModifierType modifiers,
|
||||
gboolean is_pressed)
|
||||
{
|
||||
@ -946,20 +954,20 @@ send_fake_modifier_key_event (Client *client,
|
||||
for (i = 0; i < G_N_ELEMENTS(client->modifier_keycodes); i++) {
|
||||
if (modifiers & (1 << 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);
|
||||
|
||||
XTestFakeKeyEvent (xdisplay,
|
||||
send_virtual_keyboard_key (xdisplay,
|
||||
keycode,
|
||||
is_pressed,
|
||||
CurrentTime);
|
||||
XSync (xdisplay, False);
|
||||
//XSync (xdisplay, False);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
send_fake_key_event (Client *client,
|
||||
send_fake_key_event (SeatEmitter *client,
|
||||
guint xkeysym,
|
||||
guint keyboard_modifiers)
|
||||
{
|
||||
@ -998,10 +1006,10 @@ send_fake_key_event (Client *client,
|
||||
modifiers |= keyboard_modifiers;
|
||||
|
||||
send_fake_modifier_key_event (client, modifiers, TRUE);
|
||||
XTestFakeKeyEvent (xdisplay, keycode, TRUE, 20);
|
||||
XSync (xdisplay, False);
|
||||
XTestFakeKeyEvent (xdisplay, keycode, FALSE, 20);
|
||||
XSync (xdisplay, False);
|
||||
send_virtual_keyboard_key (xdisplay, keycode, TRUE, 20);
|
||||
//XSync (xdisplay, False);
|
||||
send_virtual_keyboard_key (xdisplay, keycode, FALSE, 20);
|
||||
// XSync (xdisplay, False);
|
||||
send_fake_modifier_key_event (client, modifiers, FALSE);
|
||||
|
||||
if (old_keysym != xkeysym)
|
||||
@ -1009,7 +1017,7 @@ send_fake_key_event (Client *client,
|
||||
}
|
||||
|
||||
static void
|
||||
send_fake_key_events (Client *client,
|
||||
send_fake_key_events (SeatEmitter *client,
|
||||
EekSymbol *symbol,
|
||||
guint keyboard_modifiers)
|
||||
{
|
||||
@ -1055,7 +1063,7 @@ on_key_activated (EekboardContext *context,
|
||||
guint modifiers,
|
||||
gpointer user_data)
|
||||
{
|
||||
Client *client = user_data;
|
||||
SeatEmitter *client = user_data;
|
||||
|
||||
if (g_strcmp0 (eek_symbol_get_name (symbol), "cycle-keyboard") == 0) {
|
||||
client->keyboards_head = g_slist_next (client->keyboards_head);
|
||||
@ -1086,6 +1094,8 @@ on_key_activated (EekboardContext *context,
|
||||
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
|
||||
update_modifier_keycodes (Client *client)
|
||||
{
|
||||
@ -1107,14 +1117,15 @@ update_modifier_keycodes (Client *client)
|
||||
}
|
||||
XFreeModifiermap (mods);
|
||||
}
|
||||
|
||||
#endif
|
||||
gboolean
|
||||
client_enable_xtest (Client *client)
|
||||
client_enable_xtest (SeatEmitter *client)
|
||||
{
|
||||
GdkDisplay *display = gdk_display_get_default ();
|
||||
Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
|
||||
//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,
|
||||
@ -1136,7 +1147,7 @@ client_enable_xtest (Client *client)
|
||||
g_assert (client->xkb);
|
||||
|
||||
update_modifier_keycodes (client);
|
||||
|
||||
*/
|
||||
client->key_activated_handler =
|
||||
g_signal_connect (client->context, "key-activated",
|
||||
G_CALLBACK(on_key_activated), client);
|
||||
@ -1145,11 +1156,11 @@ client_enable_xtest (Client *client)
|
||||
}
|
||||
|
||||
void
|
||||
client_disable_xtest (Client *client)
|
||||
client_disable_xtest (SeatEmitter *client)
|
||||
{
|
||||
if (client->xkb) {
|
||||
XkbFreeKeyboard (client->xkb, 0, TRUE); /* free_all = TRUE */
|
||||
client->xkb = NULL;
|
||||
}
|
||||
//if (client->xkb) {
|
||||
// XkbFreeKeyboard (client->xkb, 0, TRUE); /* free_all = TRUE */
|
||||
//client->xkb = NULL;
|
||||
//}
|
||||
}
|
||||
#endif /* HAVE_XTEST */
|
||||
//#endif /* HAVE_XTEST */
|
||||
|
||||
26
src/client.h
26
src/client.h
@ -29,27 +29,27 @@ G_BEGIN_DECLS
|
||||
#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))
|
||||
|
||||
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);
|
||||
|
||||
gboolean client_enable_xkl (Client *client);
|
||||
void client_disable_xkl (Client *client);
|
||||
gboolean client_enable_xkl (SeatEmitter *client);
|
||||
void client_disable_xkl (SeatEmitter *client);
|
||||
|
||||
gboolean client_enable_atspi_focus (Client *client);
|
||||
void client_disable_atspi_focus (Client *client);
|
||||
gboolean client_enable_atspi_focus (SeatEmitter *client);
|
||||
void client_disable_atspi_focus (SeatEmitter *client);
|
||||
|
||||
gboolean client_enable_atspi_keystroke (Client *client);
|
||||
void client_disable_atspi_keystroke (Client *client);
|
||||
gboolean client_enable_atspi_keystroke (SeatEmitter *client);
|
||||
void client_disable_atspi_keystroke (SeatEmitter *client);
|
||||
|
||||
gboolean client_enable_xtest (Client *client);
|
||||
void client_disable_xtest (Client *client);
|
||||
gboolean client_enable_xtest (SeatEmitter *client);
|
||||
void client_disable_xtest (SeatEmitter *client);
|
||||
|
||||
gboolean client_enable_ibus_focus (Client *client);
|
||||
void client_disable_ibus_focus (Client *client);
|
||||
gboolean client_enable_ibus_focus (SeatEmitter *client);
|
||||
void client_disable_ibus_focus (SeatEmitter *client);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* CLIENT_H */
|
||||
|
||||
43
src/imservice.c
Normal file
43
src/imservice.c
Normal 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
22
src/imservice.h
Normal 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
137
src/imservice.rs
Normal 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>,
|
||||
}
|
||||
81
src/meson.build
Normal file
81
src/meson.build
Normal file
@ -0,0 +1,81 @@
|
||||
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'),
|
||||
# dependency('libxklavier'), # FIXME remove
|
||||
]
|
||||
|
||||
# Replacement for eekboard-server
|
||||
rslib = library(
|
||||
'rslib',
|
||||
sources:['imservice.rs'],
|
||||
install: true
|
||||
)
|
||||
|
||||
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'],
|
||||
)
|
||||
|
||||
@ -22,10 +22,11 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include <X11/Xatom.h>
|
||||
#include <gdk/gdkx.h>
|
||||
|
||||
#include "eek/eek-gtk.h"
|
||||
#include "eek/layersurface.h"
|
||||
#include "wayland.h"
|
||||
|
||||
#include "server-context-service.h"
|
||||
|
||||
@ -48,7 +49,6 @@ struct _ServerContextService {
|
||||
|
||||
gulong notify_visible_handler;
|
||||
|
||||
GSettings *settings;
|
||||
gdouble size_constraint_landscape[2];
|
||||
gdouble size_constraint_portrait[2];
|
||||
};
|
||||
@ -95,6 +95,17 @@ on_notify_keyboard (GObject *object,
|
||||
const EekKeyboard *keyboard;
|
||||
|
||||
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 (keyboard == NULL) {
|
||||
gtk_widget_hide (context->window);
|
||||
@ -106,8 +117,9 @@ on_notify_keyboard (GObject *object,
|
||||
g_signal_handler_block (context->window,
|
||||
context->notify_visible_handler);
|
||||
update_widget (context);
|
||||
if (was_visible)
|
||||
if (was_visible) {
|
||||
gtk_widget_show_all (context->window);
|
||||
}
|
||||
g_signal_handler_unblock (context->window,
|
||||
context->notify_visible_handler);
|
||||
}
|
||||
@ -250,8 +262,6 @@ set_geometry (ServerContextService *context)
|
||||
|
||||
gtk_window_set_decorated (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_CALLBACK(on_realize_set_dock),
|
||||
context);
|
||||
@ -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
|
||||
update_widget (ServerContextService *context)
|
||||
{
|
||||
EekKeyboard *keyboard;
|
||||
const gchar *client_name;
|
||||
EekBounds bounds;
|
||||
gchar *theme_name, *theme_filename, *theme_path;
|
||||
gchar *theme_path;
|
||||
EekTheme *theme;
|
||||
|
||||
if (context->widget) {
|
||||
@ -285,12 +338,7 @@ update_widget (ServerContextService *context)
|
||||
context->widget = NULL;
|
||||
}
|
||||
|
||||
theme_name = g_settings_get_string (context->settings, "theme");
|
||||
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_path = g_build_filename (THEMESDIR, "default.css", NULL);
|
||||
|
||||
theme = eek_theme_new (theme_path, NULL, NULL);
|
||||
g_free (theme_path);
|
||||
@ -302,23 +350,6 @@ update_widget (ServerContextService *context)
|
||||
g_object_unref (theme);
|
||||
|
||||
gtk_widget_set_has_tooltip (context->widget, TRUE);
|
||||
|
||||
if (!context->window) {
|
||||
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);
|
||||
set_geometry (context);
|
||||
}
|
||||
@ -328,10 +359,8 @@ server_context_service_real_show_keyboard (EekboardContextService *_context)
|
||||
{
|
||||
ServerContextService *context = SERVER_CONTEXT_SERVICE(_context);
|
||||
|
||||
if (!context->window)
|
||||
update_widget (context);
|
||||
g_assert (context->window);
|
||||
gtk_widget_show_all (context->window);
|
||||
make_window (context);
|
||||
update_widget (context);
|
||||
|
||||
EEKBOARD_CONTEXT_SERVICE_CLASS (server_context_service_parent_class)->
|
||||
show_keyboard (_context);
|
||||
@ -342,8 +371,9 @@ server_context_service_real_hide_keyboard (EekboardContextService *_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);
|
||||
@ -472,32 +502,11 @@ server_context_service_init (ServerContextService *context)
|
||||
"notify::fullscreen",
|
||||
G_CALLBACK(on_notify_fullscreen),
|
||||
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 *
|
||||
server_context_service_new (const gchar *client_name,
|
||||
const gchar *object_path,
|
||||
GDBusConnection *connection)
|
||||
EekboardContextService *
|
||||
server_context_service_new ()
|
||||
{
|
||||
return g_object_new (SERVER_TYPE_CONTEXT_SERVICE,
|
||||
"client-name", client_name,
|
||||
"object-path", object_path,
|
||||
"connection", connection,
|
||||
NULL);
|
||||
return EEKBOARD_CONTEXT_SERVICE(g_object_new (SERVER_TYPE_CONTEXT_SERVICE,
|
||||
NULL));
|
||||
}
|
||||
|
||||
@ -18,10 +18,10 @@
|
||||
#ifndef SERVER_CONTEXT_SERVICE_H
|
||||
#define SERVER_CONTEXT_SERVICE_H 1
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#include "eekboard/eekboard-service.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#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_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_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;
|
||||
|
||||
ServerContextService *server_context_service_new (const gchar *client_name,
|
||||
const gchar *object_path,
|
||||
GDBusConnection *connection);
|
||||
EekboardContextService *server_context_service_new ();
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* SERVER_CONTEXT_SERVICE_H */
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
|
||||
* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -28,28 +31,36 @@
|
||||
#include <clutter-gtk/clutter-gtk.h>
|
||||
#endif
|
||||
|
||||
#include "server-service.h"
|
||||
#include "eekboard/eekboard-service.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_session = FALSE;
|
||||
static gchar *opt_address = NULL;
|
||||
|
||||
static const GOptionEntry options[] = {
|
||||
{"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}
|
||||
};
|
||||
// D-Bus
|
||||
|
||||
static void
|
||||
on_name_acquired (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
(void)connection;
|
||||
(void)name;
|
||||
(void)user_data;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -57,42 +68,126 @@ on_name_lost (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
exit (1);
|
||||
// TODO: could conceivable continue working
|
||||
(void)connection;
|
||||
(void)name;
|
||||
(void)user_data;
|
||||
exit (1);
|
||||
}
|
||||
|
||||
static void
|
||||
on_destroyed (ServerService *service,
|
||||
on_destroyed (EekboardService *service,
|
||||
gpointer user_data)
|
||||
{
|
||||
(void)service;
|
||||
GMainLoop *loop = user_data;
|
||||
|
||||
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
|
||||
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)) {
|
||||
g_printerr ("Can't init GTK\n");
|
||||
exit (1);
|
||||
}
|
||||
#endif
|
||||
|
||||
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, ®istry_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)
|
||||
bus_type = G_BUS_TYPE_SYSTEM;
|
||||
else if (opt_address)
|
||||
@ -100,6 +195,8 @@ main (int argc, char **argv)
|
||||
else
|
||||
bus_type = G_BUS_TYPE_SESSION;
|
||||
|
||||
GDBusConnection *connection = NULL;
|
||||
GError *error = NULL;
|
||||
switch (bus_type) {
|
||||
case G_BUS_TYPE_SYSTEM:
|
||||
case G_BUS_TYPE_SESSION:
|
||||
@ -131,14 +228,16 @@ main (int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
|
||||
service = server_service_new (EEKBOARD_SERVICE_PATH, connection);
|
||||
EekboardService *service = eekboard_service_new (connection, EEKBOARD_SERVICE_PATH);
|
||||
|
||||
if (service == NULL) {
|
||||
g_printerr ("Can't create server\n");
|
||||
g_printerr ("Can't create dbus server\n");
|
||||
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,
|
||||
G_BUS_NAME_OWNER_FLAGS_NONE,
|
||||
on_name_acquired,
|
||||
@ -150,7 +249,19 @@ main (int argc, char **argv)
|
||||
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);
|
||||
|
||||
@ -161,5 +272,6 @@ main (int argc, char **argv)
|
||||
g_object_unref (connection);
|
||||
g_main_loop_unref (loop);
|
||||
|
||||
squeek_wayland_deinit (&instance.wayland);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
@ -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
3
src/wayland.c
Normal file
@ -0,0 +1,3 @@
|
||||
#include "wayland.h"
|
||||
|
||||
struct squeek_wayland *squeek_wayland = NULL;
|
||||
35
src/wayland.h
Normal file
35
src/wayland.h
Normal 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
|
||||
Reference in New Issue
Block a user