Compare commits

...

222 Commits

Author SHA1 Message Date
8aefae9634 Release 1.13.0 "Externality"
Changes:

- A system for latching and locking views
- Some crash fixes
- Locale-flavored terminals
- A way to add locale-flavored emoji and numbers layouts
- Making the code less annoying to work with in some places
- Fixed layout changes on newer GSettings
- Mod4 modifier
- Better session registration
- New layouts: Dvorak, Colemak wide, hebrew, wide Thai
2021-04-12 10:52:17 +00:00
52e2384f72 Cargo: Version bump 2021-04-12 10:36:55 +00:00
0eb9d89de3 Merge branch 'hints' into 'master'
layout: Take into account text purpose again

Closes #277

See merge request Librem5/squeekboard!448
2021-04-12 10:24:19 +00:00
c23b6f5f50 Merge branch 'layout' into 'master'
layouts: Stop assuming that layout name always changes on switch

Closes #276

See merge request Librem5/squeekboard!450
2021-04-12 10:21:35 +00:00
e4f1b121eb Merge branch 'errors' into 'master'
rust: Fix compiler warnings

See merge request Librem5/squeekboard!445
2021-04-09 08:36:06 +00:00
4f3bec3989 Merge branch 'doc' into 'master'
docs: Describe view switching

See merge request Librem5/squeekboard!443
2021-04-09 08:35:44 +00:00
4fdce2802a layouts: Stop assuming that layout name always changes on switch
Layout type switching outside of overlay was always done with gsettings in the middle, assuming that all clicks on languages in the popover result in a gsettings event. That's a bad assumption if there's only one xkb lang present.

This is a simple work around. A better solution would be to turn the entire system of layout switching into a central object that receives messages about changes that need to be applied, and then applies them.
2021-04-07 15:26:18 +00:00
1908769032 layouts: Make selection testable
From now on, all the parameters for loading layout are handled inside a single pure function, which makes them possible to test.

As a side benefit, the old preference order function composed of a mess of nested procedures is gone.
2021-04-05 10:36:41 +00:00
93e4345e82 layout: Take into account text purpose again 2021-04-05 08:17:07 +00:00
acac00bc88 Merge branch 'terminal' into 'master'
Fix emoji and number layouts

See merge request Librem5/squeekboard!444
2021-04-01 18:59:47 +00:00
ac03c26d5d rust: Fix compiler warnings 2021-04-01 16:30:53 +00:00
608be930f7 layout selection: Fix emoji and number 2021-04-01 16:24:06 +00:00
36d4f6726c language-terminal: Place keyboards in a sub-path 2021-04-01 16:05:44 +00:00
d289129404 Merge branch 'master' into 'master'
Rust additions to make terminal keyboard shows a localized layout

See merge request Librem5/squeekboard!437
2021-04-01 15:17:54 +00:00
M33
e49de34d0e Revert "Update tests/meson.build"
This reverts commit 27cd8964d02e957fdecd00bfebc0a03e4b24ffe4
2021-04-01 15:17:53 +00:00
225e53df07 docs: Describe view switching 2021-04-01 12:41:51 +00:00
37820bf169 Merge branch 'latch' into 'master'
Latch views

See merge request Librem5/squeekboard!416
2021-03-31 15:29:48 +00:00
d8e58fd774 Merge branch 'keyboard-layout-hebrew' into 'master'
moved data/langs/he_IL.txt -> data/langs/he-IL.txt to better conform with existing translations.

See merge request Librem5/squeekboard!442
2021-03-31 12:04:37 +00:00
fcb57c9093 moved data/langs/he_IL.txt -> data/langs/he-IL.txt to better conform with existing translations.
Signed-off-by: Kozova1 <mug66kk@gmail.com>
2021-03-31 13:01:52 +03:00
b578414655 Merge remote-tracking branch 'upstream/master' into latch 2021-03-31 09:48:29 +00:00
89b1f51ed5 appearance: Colour latched/locked according to design 2021-03-31 09:13:51 +00:00
7b1755a489 renderer: Mark latched buttons differently than locked
There are some hacks here in the form of an extra field "appears_locked_from", which can be used to hint that the user should see the button as locked. Without it, there's some confusion on user side regarding buttons that change states unprompted.
2021-03-31 09:11:11 +00:00
676a2b60ac layout: Make it possible to opt out of latching per-key 2021-03-31 09:09:38 +00:00
32dc25dfbf Revert "moved data/langs/he_IL.txt -> data/langs/he-IL.txt to better conform with existing translations."
This reverts commit d8ca9f47ca.

This touches way more than advertised.
2021-03-31 08:39:57 +00:00
484d64cfb9 Merge branch 'keyboard-layout-hebrew-fix-layout' into 'master'
Fix Hebrew layout inconsistencies with standard hebrew layout.

Closes #272

See merge request Librem5/squeekboard!440
2021-03-31 08:27:02 +00:00
637da2c177 Merge branch 'gnome-session' into 'master'
Complete session registration

Closes #274

See merge request Librem5/squeekboard!441
2021-03-31 08:17:39 +00:00
3210a363ab Merge branch 'keyboard-layout-hebrew' into 'master'
Add Hebrew translations for most layouts.

See merge request Librem5/squeekboard!439
2021-03-30 17:55:11 +00:00
8da8d55b98 Fixed Hebrew layout.
The Hebrew layout was a non standard one -
this should now be fixed.
The left shift key was removed, since Hebrew
does not have capital letters.

Signed-off-by: Kozova1 <mug66kk@gmail.com>
2021-03-30 20:31:11 +03:00
d8ca9f47ca moved data/langs/he_IL.txt -> data/langs/he-IL.txt to better conform with existing translations.
Signed-off-by: Kozova1 <mug66kk@gmail.com>
2021-03-30 20:30:53 +03:00
a3638f4bfb Added Hebrew translations for most layouts.
This commit adds translations in Hebrew for most layouts.
Note: the hebrew file seems to be named incorrectly,
is that intentional? (he_IL.txt instead of he-IL.txt)

Signed-off-by: Kozova1 <mug66kk@gmail.com>
2021-03-30 20:29:21 +03:00
f45f2db948 Merge branch 'crash' into 'master'
Stop requiring a renderer to be present to get a transformation

Closes #270

See merge request Librem5/squeekboard!438
2021-03-30 13:45:32 +00:00
40bf3ca5de server-main: Properly register to gnome-session
So far squeeboard only did half of the registration failing
to respond to the signals sent by the session.

This causes problems e.g. when exiting the session since the it
thinks the client hangs or is busy.

Closes: #274
2021-03-25 18:11:39 +01:00
e800a88893 server-main: Add quit()
This allows to exit the mainloop e.g. when signalled from gnome-session
or by a signal.
2021-03-25 16:03:57 +01:00
24c3fac505 renderer: Split mutable geometry and place it directly in GtkKeyboard
Geometry is now permanently married to the widget rather the renderer. While geometry is not always defined, C doesn't support sum types, so checks won't be enforced by the compiler. It's OK to pretend there's always some geometry to avoid crashes.
2021-03-17 14:37:54 +00:00
46f8790fc0 renderer: Reduce reliance on knowing the transform 2021-03-17 13:29:02 +00:00
3cdced0c0c Merge branch 'fixes' into 'master'
Rust fixes

See merge request Librem5/squeekboard!435
2021-03-17 13:21:46 +00:00
bffd212e10 Merge branch 'it' into 'master'
italian: Fix colon

See merge request Librem5/squeekboard!434
2021-03-09 16:03:38 +00:00
c2c379b870 Rust: Remove unnecessary no_mangle statements to silence warnings 2021-03-09 14:59:23 +00:00
1ae29ff7bc popover: Fix prematurely deallocated CString 2021-03-09 14:36:37 +00:00
d3cd7dc11f italian: Fix colon 2021-03-09 14:09:59 +00:00
d3695d3bc9 Merge branch 'th-enhancement' into 'master'
Add wide Thai keyboard layout

See merge request Librem5/squeekboard!433
2021-02-13 16:01:45 +00:00
11952ed29a Add wide Thai keyboard layout 2021-02-13 15:11:46 +00:00
842e616cd3 Merge branch 'master' into 'master'
Add Mod4 (Windows) key

See merge request Librem5/squeekboard!432
2021-02-11 17:44:02 +00:00
a265427e8e Add Mod4 (Windows) key 2021-02-11 18:06:49 +01:00
e6c45a63fb Merge branch 'master' into 'master'
Added hebrew keyboard layout

See merge request Librem5/squeekboard!430
2021-02-06 10:45:12 +00:00
e82e256581 Added hebrew keyboard layout 2021-02-06 10:45:12 +00:00
bedabb6188 Merge branch 'catalan' into 'master'
Catalan keyboard layout

See merge request Librem5/squeekboard!431
2021-02-06 10:38:18 +00:00
a030f55a7c Catalan keyboard layout
Modified by Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>
2021-02-05 14:51:21 +00:00
49aa4256a9 Merge branch 'keyboard-layout-us+dvorak' into 'master'
Add US Dvorak layout (and Colemak wide)

See merge request Librem5/squeekboard!427
2021-01-26 09:07:22 +00:00
eb7d0d5db9 Add US Dvorak layout (and Colemak wide)
Signed-off-by: Dave Laub <purism@laubster.org>
2021-01-24 10:48:12 -07:00
575619e812 Merge branch 'tagfix' into 'master'
CI: fix xheck_tag to be compatible with Amber

See merge request Librem5/squeekboard!428
2021-01-24 06:28:26 +00:00
630cfc8e59 CI: fix xheck_tag to be compatible with Amber 2021-01-24 06:07:06 +00:00
2a11bce945 Merge branch 'serial' into 'master'
imservice: Increment serials on receiving done, not sending commit

See merge request Librem5/squeekboard!426
2021-01-24 05:14:57 +00:00
a332efca45 Add US Dvorak layout (and Colemak wide)
Signed-off-by: Dave Laub <purism@laubster.org>
2021-01-23 16:44:50 -07:00
5b3c185a16 Merge branch '1.12' into 'master'
Release 1.12.0

See merge request Librem5/squeekboard!422
2021-01-19 14:06:11 +00:00
fefebf7f6e Release 1.12.0 "Convolution"
User-visible changes:
- Fixed a crash related to making keyboard visible.
- Better fallback: when selecting a missing layout named "fr+foo", "fr" will be used instead.
- When enabling the keyboard manually, it will never be stuck in the numbers view.
- Thai layout
- US-Colemak layout
- Czech layouts
- Esperanto layout
- Bulgarian layout
- Improved Norwegian layout

That's a lot of new layouts!

Plus a bunch of stricter warnings, MIPS64el support, and reproducible building.
2021-01-11 11:43:39 +00:00
21c3a74019 cargo: Update dependencies for release 2021-01-11 11:43:39 +00:00
47a483da2a Merge branch 'idle' into 'master'
visibility: Stop calling GTK functions from the visibility manager

See merge request Librem5/squeekboard!425
2021-01-10 11:47:51 +00:00
0c179560b3 visibility: Stop calling GTK functions from the visibility manager
The viibility manager state is changed from various handlers, which are not guaranteed to be reentrant, most notably the Wayland handler for preedit done.
As the state is changed, relevant requests to synchronize user-visible UI are fired from the same handler.

In case of imservice_handle_done, GTK widget show function was being called, which triggered another round of handling Wayland, leading to the done handler being called again, and flaking out.

To solve this, the phase of issuing commands needs to be separate from adjusting desired state. It seems that the easiest solution is to delay the show() and hide() calls into the next GTK main loop spin.

A better solution would probably inject itself directly after the change of desired state, so that *all* the side effects are delayed.
2021-01-10 11:04:02 +00:00
38842f9743 input-method: Fix commit/done mixup in protocol text 2021-01-10 10:45:14 +00:00
3cbfd8351c imservice: Increment serials on receiving done, not sending commit
No idea how that managed to stay undetected for so long.
2021-01-10 10:41:17 +00:00
6e7c0e6f67 Merge branch 'keyboard-layout-farsi' into 'master'
Farsi/Persian keyboard layout

See merge request Librem5/squeekboard!424
2020-12-30 13:54:49 +00:00
0e83697b61 Updated the layout to provide more convenient and faster typing experience 2020-12-27 12:38:29 -05:00
66c3926eb2 Added requirements to resources.rs and meson.build 2020-12-27 02:01:54 -05:00
1856e7023d Farsi/Persian keyboard layout 2020-12-27 01:48:33 -05:00
976f0a6e37 Farsi/Persian keyboard layout 2020-12-27 01:08:07 -05:00
4d24af4e1a Merge branch 'test_docs' into 'master'
Make layout lists more ordered

See merge request Librem5/squeekboard!417
2020-12-21 14:40:11 +00:00
422d06d582 Merge branch 'reset_hint_smart' into 'master'
dbus: Reset hints if text input missing

Closes #256

See merge request Librem5/squeekboard!421
2020-12-16 16:00:53 +00:00
4890c86b4e dbus: Reset hints if text input missing 2020-12-15 13:20:34 +00:00
b72c6b53e4 Merge branch 'fix_norwegian_button_size' into 'master'
no: Use wide button switching between numbers, symbols and base

See merge request Librem5/squeekboard!419
2020-12-15 12:37:42 +00:00
701168c32b no: Use wide button switching between numbers, symbols and base 2020-12-14 21:55:39 +01:00
658df98e18 layout_names: Unmess the list of builtin layouts 2020-12-12 07:42:32 +00:00
6f7252ec7c tests: Add some description to the list of tested layouts
Contributors have started to make it messy.
2020-12-12 07:40:51 +00:00
558a2568e3 Merge branch 'undefined' into 'master'
Bulgarian language keyboard layout

See merge request Librem5/squeekboard!418
2020-12-12 07:38:34 +00:00
9517c347b6 Fix bulgarian layout size 2020-12-12 00:28:21 +02:00
8dd92c81e7 bulgarian add translation and to needed lists 2020-12-11 22:06:39 +02:00
03ccfe77ad Merge branch 'unused' into 'master'
build: Enable unused warnings in C

See merge request Librem5/squeekboard!375
2020-12-11 14:56:47 +00:00
c103b84fa6 Bulgarian language keyboard layout 2020-12-10 19:42:28 +00:00
9a72db2fcc Merge branch 'esperanto' 2020-12-07 15:33:01 +00:00
61a84c47f1 Esperanto keyboard
Fixed by Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>
2020-12-07 15:32:37 +00:00
a9ecc13185 Merge branch 'fallback' into 'master'
Better fallbacks

See merge request Librem5/squeekboard!415
2020-12-05 04:16:44 +00:00
7143fb2497 Merge branch 'central_visible' into 'master'
Central visibility policy

See merge request Librem5/squeekboard!409
2020-12-05 04:12:01 +00:00
c6cc58fd8e ffi: Eliminate squeek_button and squeek_row 2020-12-04 17:34:53 +00:00
9522d4e302 renderer: Bring button drawing closer to Rust 2020-12-04 15:35:02 +00:00
8f62520648 view: Ąto-unlatching when multiple latching buttons pressed
Best seen in the PL layout, where to get to Ą, two buttons must be latched: Capitals, and then Accents.
2020-12-04 10:02:04 +00:00
e36c4e597f layout: Remove the little abomination of view change promise
It didn't make anything more testable due to being tightly coupled to Layout.
With the last place needing the curent form abolished, it's no longer needed.

No attempt to make it more stateless and unit-testable was made though.
2020-12-03 19:56:48 +00:00
8ab6997b21 layout: Plug in stateless view switching 2020-12-03 19:44:26 +00:00
3b06eadef5 layout: Add stateless view switching
Tested, but not yet plugged in.
2020-12-03 19:35:50 +00:00
287e851770 layout: Latch keys when clicked twice
Third click unlatches. No actual UI indication.
2020-12-03 18:42:24 +00:00
dfee95430d Merge branch 'release' into 'master'
Reproducible build

See merge request Librem5/squeekboard!413
2020-12-03 17:18:50 +00:00
fcd0eaddf2 layouts: Simplify the main flow of source list 2020-12-03 16:26:47 +00:00
ba2e191918 layouts: Use base as fallback for alternative layouts 2020-12-03 16:15:22 +00:00
cc4f14e8c6 data: Flattened layout fallback function 2020-12-03 15:47:44 +00:00
103e64b96c data: Made data flow in fallback clearer 2020-12-03 15:45:45 +00:00
2796362d34 build: Fail on any C warnings when strict 2020-12-03 15:26:54 +00:00
af00d74f71 build: Enable wformat to remove warnings about missing wformat 2020-12-03 15:26:28 +00:00
02d579d757 build: Enable unused warnings in C
The goal is to be free of unused X class of problems. For this, CI and any "serious" builds will fail on warnings. Debug builds, used in development, will warn by default but not fail.

In addition, the 'strict' build option is added for when the debug build should fail on unused warnings as well.
2020-12-03 15:21:58 +00:00
01d06d0f5f Merge branch 'keyboard-layout-us+colemak' into 'master'
Added US Colemak Keyboard Layout

See merge request Librem5/squeekboard!403
2020-12-03 15:13:11 +00:00
1d1c98c27a Merge branch 'f/czech-layouts' into 'master'
Add Czech keyboard layouts

See merge request Librem5/squeekboard!414
2020-12-03 14:42:04 +00:00
696d77293e d/rules: export RUSTFLAGS only on architecture that needs it
Altered from original to take reproducibility into account. Not tested on mips64el.
2020-12-03 14:34:38 +00:00
225c204e37 Merge branch 'armel' into 'master'
Mipsel compat

See merge request Librem5/squeekboard!412
2020-12-03 10:30:19 +00:00
c3b428e517 Add Czech keyboard layouts
Two variants:

* Czech Standard (= qwertz)

* Czech qwerty

The accented letters layout corresponds to the UCW [1] layout shipped
with xkb, so we follow this precedent.

Like the DE layout, and unlike the US layout, the CZ layout has a
comma key and a narrower space bar. The added comma key also serves as
a visual balance to the added accents key, to keep the spacebar
centered.

The layouts have been tested manually on PinePhone.

[1] c60b77ea51/test/data/symbols/cz (L180)
2020-11-29 17:28:50 +01:00
1fe6d65525 tests: Allow legacy mode to have much longer tests. 2020-11-29 12:53:35 +00:00
39a3c40d67 debian: Build reproducibly 2020-11-29 10:42:24 +00:00
963f52bbc3 tests: Explicitly pass source directory to tests 2020-11-29 10:42:20 +00:00
9dcc4c9868 tests: Prefer the env var for finding test layouts
The builtin file path is embedded in the binary and subject to substitution, which makes it invalid when trying to build a .deb reproducibly.

Out of the two solutions, it's easier to make the change here rather than customize .debu building not to run tests reproducibly.
2020-11-28 18:57:54 +00:00
df8e885983 build: Fix release 2020-11-28 18:57:46 +00:00
540c4d9c05 d/rules: export RUSTFLAGS only on architecture that needs it 2020-11-23 14:10:09 +00:00
42483234e3 d/rules: fix an FTBFS on mips64el with GOT > 64kb 2020-11-23 14:09:37 +00:00
c9f9a3b577 Merge branch 'cargo' into 'master'
docs: Correct Cargo update instructions

See merge request Librem5/squeekboard!398
2020-11-23 09:16:59 +00:00
81041b8035 Merge branch 'wannaphong-master-patch-05164' into 'master'
Add thai keyboard

See merge request Librem5/squeekboard!402
2020-11-23 08:17:29 +00:00
c731124f7b escape " on thai keyboard 2020-11-23 03:43:49 +00:00
fca8984225 Merge branch '1.11.1' into 'master'
Release 1.11.1

See merge request Librem5/squeekboard!411
2020-11-23 02:48:03 +00:00
bd6ab663c0 Update meson.build 2020-11-22 19:14:21 +00:00
4049e66307 Release 1.11.1 "Diploid"
Bug fix release:
- Fixes to German layout
- Fixed showing the panel right after starting
2020-11-21 11:09:37 +00:00
046a516a11 cargo: Update deps 2020-11-21 11:03:45 +00:00
b5d1e8c3eb Merge branch 'keyboard-layout-german-move-semicolon' into 'master'
keyboard: Move semicolon in German layout to numbers view replacing redundant comma key

See merge request Librem5/squeekboard!410
2020-11-20 18:33:01 +00:00
aee296ad96 keyboard: Move semicolon in German layout to numbers view replacing redundant comma key 2020-11-20 18:30:35 +01:00
5f59db478a Merge branch 'visible' into 'master'
Manage visibility better

Closes #253

See merge request Librem5/squeekboard!408
2020-11-20 01:57:35 +00:00
dda070e84e Merge branch 'race' into 'master'
imservice: Set up UI according to current needs when it shows up

See merge request Librem5/squeekboard!407
2020-11-19 19:04:22 +00:00
17db3db296 visibility: Centralize keyboard panel visibility policy and handling
With the policy being disentangled from application, it becomes testable.
This prepares for moving the entire visibility mechanism to the new class and taking away more pieces of ServerContextService.
In addition, this is a good warmup before trying to implement sizing policy.
2020-11-19 09:49:51 +00:00
ebbb3b1138 UI: Keep visibility factors in a central place 2020-11-18 19:29:42 +00:00
277986bcdf imservice: Set up UI according to current needs when it shows up 2020-11-18 18:38:24 +00:00
96461cf2aa Merge branch 'keyboard-layout-german-fix-semicolon' into 'master'
keyboard: Fix semicolon in German layout

Closes #226

See merge request Librem5/squeekboard!406
2020-11-14 20:29:56 +00:00
2029f48b4d keyboard: Fix semicolon in German layout 2020-11-14 20:36:23 +01:00
943d2de536 Merge branch '1.11' into 'master'
Release 1.11.0

See merge request Librem5/squeekboard!405
2020-11-14 17:20:44 +00:00
5aa7334787 Release 1.11.0 "Perceptron"
This is a special Evergreen release with only 2 changes:

- don't delay hiding when explicitly requested to hide,
- fix typo in Friulian translation.
2020-11-14 06:49:00 +00:00
955a138849 Update dependencies 2020-11-14 06:44:23 +00:00
44c80a0406 Merge branch 'fix_delay' into 'master'
ui: Cancel hiding delay when activity requested again

See merge request Librem5/squeekboard!404
2020-11-14 06:36:23 +00:00
12c9ca1e02 ui: Cancel hiding delay when activity requested again 2020-11-14 06:09:37 +00:00
91acfa0138 Merge branch 'patch-1' into 'master'
Update fur-IT.txt fix typo for Spanish

See merge request Librem5/squeekboard!401
2020-11-10 14:39:18 +00:00
cf09d1b3bc Added US Colemak Keyboard Layout 2020-11-02 13:27:27 -05:00
81fb7e0df3 Update resources.rs 2020-11-01 09:42:27 +00:00
0e533c5e94 Add thai keyboard 2020-10-31 18:55:32 +00:00
8d01d17b8c Update fur-IT.txt fix typo for Spanish 2020-10-28 11:55:34 +00:00
74a5b0937b Merge branch 'improve_delay' into 'master'
Delay hiding only when leaving a text field

Closes #121

See merge request Librem5/squeekboard!400
2020-10-27 20:34:50 +00:00
17ce0b6b46 Merge branch '1.10.0' into 'master'
Release 1.10.0

See merge request Librem5/squeekboard!397
2020-10-23 10:43:10 +00:00
c0525946ae Release version 1.10.0 "Idempotence"
- Xwayland support
- Keys' press zone extends to the side edges of the widget
- Layout popover separates languages from special layouts
- Popover can open settings
- Keyboard is invisible when GNOME accessibility setting is off
- Layout tester checks for presence of Backspace and Return
- Adjusts the keyboard size better to tablet-sized displays
- Friulian keyboard layout
- Ukrainian layout
- Belgian layout
- Wide French layout
- Wide Belgian layout
- Wide terminal layout
- Improved tutorial
- Improved README
- Stricter compilation checks
- Minor fixes
2020-10-22 10:26:53 +00:00
8bb5c4f16c cargo: Update dependencies 2020-10-21 08:08:48 +00:00
a0322f0d7e Merge branch 'temper_a11y' into 'master'
Temper a11y, lint

See merge request Librem5/squeekboard!399
2020-10-21 07:52:59 +00:00
d07b5ed0d6 UI: Delay hiding only when leaving a text field 2020-10-20 11:52:06 +00:00
153f9c39e5 lint: Check for missing braces
The `eek/layersurface.c` file should be excluded because it's an imported, "foreign" source, but clang-tidy doesn't seem to have an annotation for that.

An alternative would have been to exclude it in Meson and do the check there, but that requires clang-tidy, raising the barrier to contribute of Squeekboard even more (it already requires libfeedback, which isn't packaged widely).
2020-10-20 11:34:17 +00:00
c0b6ea51fa enabled: Don't force the keyboard to show when enable is switched
This is a bit of a hack: the enable semantics are not finalized yet:

https://source.puri.sm/Librem5/squeekboard/-/issues/238

This prevents the keyboard from appearing over the lock screen at least:

https://source.puri.sm/Librem5/squeekboard/-/merge_requests/397#note_123987
2020-10-20 08:08:55 +00:00
5d81cf78f8 docs: Correct Cargo update instructions 2020-10-19 14:33:08 +00:00
0ed1dd925a Merge branch 'x11final' into 'master'
Use multiple key maps, each of which is acceptable by Xwayland

See merge request Librem5/squeekboard!393
2020-10-19 13:43:12 +00:00
39464f9c99 Merge branch 'master' into 'master'
Add friulian keyboard and langs layout

See merge request Librem5/squeekboard!396
2020-10-19 08:44:17 +00:00
eeb7e252c7 Revert "Add friulian keyboard"
This reverts commit 16ccb5fd341fbdeff04b1540f99fe9cbe1c27df1
2020-10-19 08:44:16 +00:00
65425ff928 Merge branch 'fix' into 'master'
tests: Fix bad field access

See merge request Librem5/squeekboard!395
2020-10-14 10:37:26 +00:00
229b3bac51 tests: Fix bad field access
As a result of an automatic merge, a private field was accessed that shouldn't be.
2020-10-14 10:12:57 +00:00
a4e7ad06d3 build: Avoid MaybeUninit on older Debian 2020-10-12 14:14:26 +00:00
db298b0fb8 keymaps: Use multiple key maps, each within the limit of what Xorg can accept.
Key maps are switched on key press whenever needed.
2020-10-12 14:14:17 +00:00
4373cf7bc3 keymap: Concentrate special handling of BackSpace, which is implicit in Erase action 2020-10-12 13:57:53 +00:00
2f613ea4c7 Merge branch 'x11_prepare' into 'master'
Cleanups leading to Xwayland compatibility

See merge request Librem5/squeekboard!389
2020-10-12 12:45:13 +00:00
8f526bd357 tests: Check for missing return in builtin layouts except emoji 2020-10-12 10:51:23 +00:00
b77b3f7816 vkeyboard: Use a generic slice instead of a vector 2020-10-12 10:51:23 +00:00
87eb775377 keymap: Keep keymap fd management in one place
At the same time, reduce the distance between this and the Xwayland handling branch.
2020-10-12 10:50:40 +00:00
f64e5a3627 Merge branch 'multi_ke' into 'master'
Improve generation of key maps

See merge request Librem5/squeekboard!388
2020-10-12 09:13:29 +00:00
595bbccfdf Merge branch 'fix_a11y' into 'master'
debian: Insert a "breaks" for librem5-base < 24

See merge request Librem5/squeekboard!392
2020-10-12 09:03:58 +00:00
afd47ef8b4 Merge branch 'optimize-sizing' into 'master'
Optimize sizing

See merge request Librem5/squeekboard!390
2020-10-12 08:18:22 +00:00
7e38d17cb7 debian: Insert a "breaks" for librem5-base < 24
Librem5-base sets the GNOME a11y to true, which solves the invisibility of the keyboard on the phone.
2020-10-11 16:36:16 +00:00
ef7df433d8 Merge branch 'wide-keyboards' into 'master'
Add wide keyboards

See merge request Librem5/squeekboard!391
2020-10-11 14:30:35 +00:00
8e32de86a9 Merge branch 'extend-keys-to-bounding-box' into 'master'
Expand key press detection to the edges of the view's bounding box

Closes #191

See merge request Librem5/squeekboard!379
2020-10-11 14:25:03 +00:00
6871452c7b keyboards: add wide terminal layout
This is a copy of the `terminal` layout with modified key dimensions to 
fit a wide arrangement.
2020-10-10 01:40:12 +02:00
192824be39 keyboards: add wide Belgian layout
This is a copy of the `be` layout with modified key dimensions to fit a 
wide arrangement.
2020-10-10 01:38:54 +02:00
938d3c335e keyboards: add wide French layout
This is a copy of the `fr` layout with modified key dimensions to fit a 
wide arrangement.
2020-10-10 01:37:57 +02:00
9dd67ad2bc server-context-service: optimize height calculation
Even though proper size management is being worked on, this patch
proposes a simple and easily revertable solution to device-dependent
sizing issues.

First, it provides different calculations based on the display
orientation. In landscape mode, this allows us to have a sensible
keyboard size while leaving enough screen estate for apps to be able to
display useful information.

Then, it gets rid of the weird calculation for display widths between
360 and 540px. While having some continuity is a pleasant idea, in the
real world in doesn't work, as shown by port attempts to other devices:
a 480x800 display (scale 1) would show an unusable 190px-high keyboard
(about half the size of the Librem 5 on-screen keyboard on a device I
own).

Finally, this commit makes sure we never use a hardcoded size.

Tested on the PinePhone, PineTab and Librem 5.

Note: Current behavior is preserved on the L5 in portrait mode, but
keyboard is a bit smaller in landscape mode; this is deliberate, as it
was previously using too much space (causing some apps, such as chatty,
to be unusable).
2020-10-09 16:30:59 +02:00
9f4cb3c791 eek-gtk-keyboard: use virtual resolution to check arrangement kind
Using the actual monitor width in pixels can lead to unsatisfying
results, depending on the display orientation and physical size: on a
10" tablet with a 1280x800 resolution (scale 1), portrait orientation
will be using the narrow layout.

If the keyboard is sized in an optimal way (i.e. so the layout fills the
whole area, with no blanks on the sides) this would result in an
unnecessarily huge keyboard being displayed, therefore wasting screen
estate.

Using the virtual display size gives a hint about the physical size of
the device, and can be used to select wide layouts even in portrait
mode, while still preserving current behavior on HiDPI devices.

This has been tested on PineTab, PinePhone and Librem 5.
2020-10-09 16:26:10 +02:00
6ed2a47620 Merge branch 'popover-settings' into 'master'
Add settings option to popover

Closes #154

See merge request Librem5/squeekboard!385
2020-10-09 09:18:26 +00:00
4253bf1299 Add settings option to popover
Fixes #154
2020-10-09 19:29:48 +11:00
d283ced2ce Merge branch 'popover-sorting' into 'master'
Sort layouts by type before sorting by name

Closes #176

See merge request Librem5/squeekboard!384
2020-10-07 15:23:25 +00:00
776c0c5f4b Merge branch 'flags' into 'master'
build: Error on repeating declarations

See merge request Librem5/squeekboard!387
2020-10-06 13:35:22 +00:00
8cf6c5f948 syntax: Let older rustc understand symbolmap's lifetime 2020-10-06 10:32:07 +00:00
de3bf54dc9 data: Restore testability of action->keysym conversion 2020-10-06 10:32:07 +00:00
2219eb67e1 keymap: Generate from symbol map, not layout
Includes changes to the keymap string without which Xwayland won't work.
2020-10-06 10:31:28 +00:00
61400c9584 build: Error on repeating declarations 2020-10-06 09:54:17 +00:00
b21734bf57 Merge branch 'docs-morefixes' into 'master'
docs: Tutorial syntax cleanups, reorganization

See merge request Librem5/squeekboard!381
2020-10-06 09:14:56 +00:00
24adba44be Merge branch 'leak-fixes' into 'master'
Fix 2 leaks

Closes #148

See merge request Librem5/squeekboard!386
2020-10-03 07:38:52 +00:00
5e43a31051 Fix leak endlessly adding a resource path to the default theme 2020-10-03 16:23:13 +10:00
40850267d4 Fix leak in level_keyboard_new
xkb_keymap_get_as_string requires that the string it returns is freed by
the caller.
2020-10-03 16:07:36 +10:00
93ac94b83f Sort layouts by type before sorting by name
This makes it such that local layouts like emoji and terminal appear
below language layouts.

Fixes #176
2020-10-03 02:10:56 +10:00
ec5570a547 Merge branch 'keyboard-layout-belgian' into 'master'
proposal for belgian layout (copy of fr)

See merge request Librem5/squeekboard!382
2020-10-01 13:21:49 +00:00
Al
72bd265065 alphabetical order for src/resources.rs tests/meson.build 2020-10-01 14:54:22 +02:00
07bcaa8e2b docs: Reorganize tutorial
People still ignore adding layouts to builtins and to tests. To unbury that information, and add a sort of checklist, the more interesting info has been moved upwards nd together.
2020-10-01 11:52:53 +00:00
Al
4357052fe7 proposal for belgian layout (copy of fr) 2020-09-30 15:42:31 +02:00
c16c686592 docs: Tutorial syntax cleanups
Promoted bolded "headings" into actual headings, so that they can be linked to.
2020-09-29 13:33:37 +00:00
4b825c26a6 Merge branch 'docs-fixes' into 'master'
Expand the development documentation in the readme

Closes #227

See merge request Librem5/squeekboard!377
2020-09-26 09:00:51 +00:00
74479ff226 Expand key press detection to the edges of the view's bounding box
If you have a keyboard layout like the following:

A B C D
 E F G
H I J K

The E and G keys here should be pressed when clicking in the empty space
next to them. This is achieved by not checking the bounding boxes of
each key and instead just using the button and row offset to extend
buttons/rows to the edges of the view. Caching for the size and
position of rows is introduced to simplify implementation and possibly
improve performance.

Fixes #191
2020-09-26 01:37:23 +10:00
94bfa92c12 Expand the development documentation in the readme
Fixes #227
2020-09-26 00:34:09 +10:00
50fb124b26 Merge branch 'hacking-spelling-fixes' into 'master'
Fix spelling mistakes in doc/hacking.md

Closes #217

See merge request Librem5/squeekboard!378
2020-09-25 12:47:17 +00:00
7aa004ceff Fix spelling mistakes in doc/hacking.md
Fixes #217
2020-09-25 21:44:27 +10:00
60056dcf26 Merge branch 'honor-a11y-setting' into 'master'
Honor org.gnome.desktop.a11y.applications screen-keyboard-enabled

Closes #222

See merge request Librem5/squeekboard!370
2020-09-24 06:49:13 +00:00
5580853f31 Merge branch 'depr' into 'master'
rust: Fix deprecation warnings

See merge request Librem5/squeekboard!374
2020-09-21 17:01:51 +00:00
d93e9c2b11 rust: Fix deprecation warnings 2020-09-21 10:57:01 +00:00
4ccf11f4fd server-context-service: Don't show keyboard when disabled
If the corresponding a11y settings is disbaled don't unfold
the keyboad at all.

This helps e.g. running the same session on laptops or when
an external keyboard is attached.

Closes: #222
2020-09-14 11:34:17 +02:00
6c5df02921 Merge branch 'cleanup' into 'master'
A bunch of cleanups

See merge request Librem5/squeekboard!371
2020-09-14 09:26:20 +00:00
b137e2e3a0 Merge branch 'ukrainian-keyboard-layout' into 'master'
Add Ukrainian keyboard layout

Closes #223

See merge request Librem5/squeekboard!372
2020-09-14 07:48:03 +00:00
820a8b6ca1 Add Ukrainian keyboard layout.
Fixes https://source.puri.sm/Librem5/squeekboard/-/issues/223

Signed-off-by: Nazarii Kretovych <nazarii.kretovych@gmail.com>
2020-09-14 08:34:09 +03:00
8bdfb69dc1 server-context-service: swap signal arguments
This makes sure 'self' comes first. While at that fix the
function signatures and use ServerContextService directly
and add type checks so it's easy to notice when we messed up.
2020-09-11 20:44:36 +02:00
1e6bcef055 server-context-service: Consistenty name self argument 'self'
It's confusing when the object a method acts on is sometimes called
context and sometimes called state. So name it 'self' as we do
in other projects.
2020-09-11 20:05:49 +02:00
07faf906d8 eekboard-context-service: Drop private struct
There's no point having it for a final type and it only
makes the code harder to read.
2020-09-11 18:55:35 +02:00
53f30324f0 eekboard-context-service: Drop the GObject boilerplate
The previous commits show it's not really a derivable type
so make it a finale one.
2020-09-11 18:55:35 +02:00
3e212ddab4 eekboard-context-service: Drop docstrings for inexistent functions 2020-09-11 18:46:22 +02:00
966990ad65 eekboad-context-service: Drop signal class handler
It's unused
2020-09-11 18:45:33 +02:00
a8b81172fc build: Enable '-Wformat-nonliteral' 2020-09-11 18:40:56 +02:00
97f51591b3 ServerContextService: Drop GObject boilerplate
G_DECLARE_FINAL_TYPE does this for us
2020-09-11 18:16:30 +02:00
6756fb423a build: Enable -Wredundant-declarations 2020-09-11 18:16:30 +02:00
eb7673d2c2 treewide: Drop redundant declarations 2020-09-11 18:16:30 +02:00
24b6a04903 build: Enable -Wmaybe-uninitialized
No changes needed.
2020-09-11 18:16:30 +02:00
b197cd839e build: Enable -Wformat-security
No changes needed.
2020-09-11 18:16:30 +02:00
857a916402 build: Enable -Winit-self
No changes needed
2020-09-11 18:16:30 +02:00
ca68fc2040 eek-keyboard: Don't ignore return value
This fixes

../eek/eek-keyboard.c:71:5: warning: ignoring return value of ‘getrandom’ declared with attribute ‘warn_unused_result’ [-Wunused-result]
   71 |     getrandom(r, 6, GRND_NONBLOCK);
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[17/32] Compiling C object 'src/25a6634@@libsqueekboard@sta/.._eek_eek-renderer.c.o'
2020-09-11 18:16:30 +02:00
bd661bd4f4 gitlab-ci: Enable --Werror
This makes sure we don't have more warnings creeping in
2020-09-11 18:16:30 +02:00
4228192bda layout: Fix warning
This fixes

warning: unnecessary parentheses around block return value
   --> /var/scratch/librem5/squeekboard/src/layout.rs:110:13
    |
110 | /             (point.x > self.x && point.x < self.x + self.width
111 | |                 && point.y > self.y && point.y < self.y + self.height)
    | |______________________________________________________________________^
    |
    = note: `#[warn(unused_parens)]` on by default
2020-09-11 18:16:30 +02:00
0f7ab99da3 keyboard: Fix warning
warning: unused variable: `name`
   --> /var/scratch/librem5/squeekboard/src/keyboard.rs:195:10
    |
195 |     for (name, state) in keystates.iter() {
    |          ^^^^ help: consider prefixing with an underscore: `_name`
2020-09-11 18:16:30 +02:00
e15d317488 eekboard-context-service: Drop EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE
This fixes the

../eekboard/eekboard-context-service.c:244:13: warning: Deprecated pre-processor symbol, replace with
  244 |     self->priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(self);

warning and makes us use more modern GObject style
2020-09-11 18:16:30 +02:00
93e9ce0dd7 build: Enable '-Wunused-function' 2020-09-11 18:16:13 +02:00
9d63b505ec build: Enable '-Wold-style-definition' '-Wstrict-prototypes' 2020-09-11 18:15:44 +02:00
306c11f1fd treewide: Use new style function definitions 2020-09-11 18:15:02 +02:00
c26feed8b2 eekboard-context-service: Return early if schema is unavailable
This also fixes a leak of GSettingsSchema.
2020-09-11 18:14:19 +02:00
2f4a652f53 Merge branch 'fixmods' into 'master'
virtual_keyboard: Fix desynced modifiers state

See merge request Librem5/squeekboard!362
2020-08-28 11:02:50 +00:00
e5796d0d7b Merge branch 'rel-1.9.3' into 'master'
Document changes and release 1.9.3

Closes #212

See merge request Librem5/squeekboard!369
2020-08-06 15:50:00 +00:00
9512fd8436 virtual_keyboard: Fix desynced modifiers state
This ensures that keymap switches leave modifiers and virtual keys in a known state.
2020-07-15 18:08:59 +00:00
103 changed files with 7591 additions and 1383 deletions

View File

@ -36,7 +36,7 @@ build_meson:
expire_in: 3h
script:
- apt-get -y build-dep .
- meson . _build/ -Ddepdatadir=/usr/share
- meson . _build/ -Ddepdatadir=/usr/share --werror
- ninja -C _build install
build_deb:
@ -136,7 +136,10 @@ test:
- build_meson
script:
- apt-get -y build-dep .
- apt-get -y install clang-tidy
- ninja -C _build test
- cd _build
- clang-tidy --checks=-clang-diagnostic-missing-braces,readability-braces-around-statements, --warnings-as-errors=readability-braces-around-statements -extra-arg=-Wno-unknown-warning-option ../src/*.c ../eek/*.c ../eekboard/*.c
check_release:
<<: *tags

430
Cargo.lock generated
View File

@ -4,483 +4,481 @@
name = "atk"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b7499272acf036bb5820c6e346bbfb5acc5dceb104bc2c4fd7e6e33dfcde6a"
dependencies = [
"atk-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"atk-sys",
"bitflags",
"glib",
"glib-sys",
"gobject-sys",
"libc",
]
[[package]]
name = "atk-sys"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e552c1776737a4c80110d06b36d099f47c727335f9aaa5d942a72b6863a8ec6f"
dependencies = [
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys",
"gobject-sys",
"libc",
"pkg-config",
]
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "cairo-rs"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e05db47de3b0f09a222fa4bba2eab957d920d4243962a86b2d77ab401e4a359c"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cairo-sys-rs 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags",
"cairo-sys-rs",
"glib",
"glib-sys",
"gobject-sys",
"libc",
]
[[package]]
name = "cairo-sys-rs"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff65ba02cac715be836f63429ab00a767d48336efc5497c5637afb53b4f14d63"
dependencies = [
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys",
"libc",
"pkg-config",
]
[[package]]
name = "cc"
version = "1.0.54"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
[[package]]
name = "clap"
version = "2.33.1"
version = "2.33.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags",
"textwrap",
"unicode-width",
]
[[package]]
name = "dtoa"
version = "0.4.5"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
[[package]]
name = "fragile"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f8140122fa0d5dcb9fc8627cfce2b37cc1500f752636d46ea28bc26785c2f9"
[[package]]
name = "gdk"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6243e995f41f3a61a31847e54cc719edce93dd9140c89dca3b9919be1cfe22d5"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cairo-rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cairo-sys-rs 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-pixbuf 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gio 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gio-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pango 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags",
"cairo-rs",
"cairo-sys-rs",
"gdk-pixbuf",
"gdk-sys",
"gio",
"gio-sys",
"glib",
"glib-sys",
"gobject-sys",
"libc",
"pango",
]
[[package]]
name = "gdk-pixbuf"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9726408ee1bbada83094326a99b9c68fea275f9dbb515de242a69e72051f4fcc"
dependencies = [
"gdk-pixbuf-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gio 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gio-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-pixbuf-sys",
"gio",
"gio-sys",
"glib",
"glib-sys",
"gobject-sys",
"libc",
]
[[package]]
name = "gdk-pixbuf-sys"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8991b060a9e9161bafd09bf4a202e6fd404f5b4dd1a08d53a1e84256fb34ab0"
dependencies = [
"gio-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
"gio-sys",
"glib-sys",
"gobject-sys",
"libc",
"pkg-config",
]
[[package]]
name = "gdk-sys"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6adf679e91d1bff0c06860287f80403e7db54c2d2424dce0a470023b56c88fbb"
dependencies = [
"cairo-sys-rs 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-pixbuf-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gio-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pango-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
"cairo-sys-rs",
"gdk-pixbuf-sys",
"gio-sys",
"glib-sys",
"gobject-sys",
"libc",
"pango-sys",
"pkg-config",
]
[[package]]
name = "gio"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6261b5d34c30c2d59f879e643704cf54cb44731f3a2038000b68790c03e360e3"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"fragile 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gio-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags",
"fragile",
"gio-sys",
"glib",
"glib-sys",
"gobject-sys",
"lazy_static",
"libc",
]
[[package]]
name = "gio-sys"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fad225242b9eae7ec8a063bb86974aca56885014672375e5775dc0ea3533911"
dependencies = [
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys",
"gobject-sys",
"libc",
"pkg-config",
]
[[package]]
name = "glib"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be27232841baa43e0fd5ae003f7941925735b2f733a336dc75f07b9eff415e7b"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags",
"glib-sys",
"gobject-sys",
"lazy_static",
"libc",
]
[[package]]
name = "glib-sys"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95856f3802f446c05feffa5e24859fe6a183a7cb849c8449afc35c86b1e316e2"
dependencies = [
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
"libc",
"pkg-config",
]
[[package]]
name = "gobject-sys"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31d1a804f62034eccf370006ccaef3708a71c31d561fee88564abe71177553d9"
dependencies = [
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys",
"libc",
"pkg-config",
]
[[package]]
name = "gtk"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "709f1074259d4685b96133f92b75c7f35b504715b0fcdc96ec95de2607296a60"
dependencies = [
"atk 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cairo-rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cairo-sys-rs 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-pixbuf 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-pixbuf-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gio 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gio-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gtk-sys 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pango 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pango-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"atk",
"bitflags",
"cairo-rs",
"cairo-sys-rs",
"cc",
"gdk",
"gdk-pixbuf",
"gdk-pixbuf-sys",
"gdk-sys",
"gio",
"gio-sys",
"glib",
"glib-sys",
"gobject-sys",
"gtk-sys",
"lazy_static",
"libc",
"pango",
"pango-sys",
]
[[package]]
name = "gtk-sys"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53def660c7b48b00b510c81ef2d2fbd3c570f1527081d8d7947f471513e1a4c1"
dependencies = [
"atk-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cairo-sys-rs 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-pixbuf-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gio-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pango-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
"atk-sys",
"cairo-sys-rs",
"gdk-pixbuf-sys",
"gdk-sys",
"gio-sys",
"glib-sys",
"gobject-sys",
"libc",
"pango-sys",
"pkg-config",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.71"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41"
[[package]]
name = "linked-hash-map"
version = "0.5.3"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]]
name = "maplit"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
[[package]]
name = "memmap"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
dependencies = [
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc",
"winapi",
]
[[package]]
name = "pango"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "393fa071b144f8ffb83ede273758983cf414ca3c0b1d2a5a9ce325b3ba3dd786"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pango-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags",
"glib",
"glib-sys",
"gobject-sys",
"lazy_static",
"libc",
"pango-sys",
]
[[package]]
name = "pango-sys"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b93d84907b3cf0819bff8f13598ba72843bee579d5ebc2502e4b0367b4be7d"
dependencies = [
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys",
"gobject-sys",
"libc",
"pkg-config",
]
[[package]]
name = "pkg-config"
version = "0.3.17"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
[[package]]
name = "proc-macro2"
version = "1.0.18"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
dependencies = [
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.7"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
dependencies = [
"proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
dependencies = [
"regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.18"
version = "0.6.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
[[package]]
name = "rs"
version = "0.1.0"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cairo-rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cairo-sys-rs 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gio 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gtk 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gtk-sys 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_yaml 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)",
"xkbcommon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags",
"cairo-rs",
"cairo-sys-rs",
"clap",
"gdk",
"gio",
"glib",
"glib-sys",
"gtk",
"gtk-sys",
"maplit",
"regex",
"serde",
"serde_yaml",
"xkbcommon",
]
[[package]]
name = "serde"
version = "1.0.111"
version = "1.0.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
dependencies = [
"serde_derive 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.111"
version = "1.0.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
dependencies = [
"proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_yaml"
version = "0.8.13"
version = "0.8.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23"
dependencies = [
"dtoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)",
"yaml-rust 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"dtoa",
"linked-hash-map",
"serde",
"yaml-rust",
]
[[package]]
name = "syn"
version = "1.0.31"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb"
dependencies = [
"proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width",
]
[[package]]
name = "unicode-width"
version = "0.1.7"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
[[package]]
name = "unicode-xid"
version = "0.2.0"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "winapi"
version = "0.3.8"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "xkbcommon"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fda0ea5f7ddabd51deeeda7799bee06274112f577da7dd3d954b8eda731b2fce"
dependencies = [
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc",
"memmap",
]
[[package]]
name = "yaml-rust"
version = "0.4.4"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"linked-hash-map",
]
[metadata]
"checksum atk 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "86b7499272acf036bb5820c6e346bbfb5acc5dceb104bc2c4fd7e6e33dfcde6a"
"checksum atk-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e552c1776737a4c80110d06b36d099f47c727335f9aaa5d942a72b6863a8ec6f"
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
"checksum cairo-rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e05db47de3b0f09a222fa4bba2eab957d920d4243962a86b2d77ab401e4a359c"
"checksum cairo-sys-rs 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ff65ba02cac715be836f63429ab00a767d48336efc5497c5637afb53b4f14d63"
"checksum cc 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)" = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311"
"checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129"
"checksum dtoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3"
"checksum fragile 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f8140122fa0d5dcb9fc8627cfce2b37cc1500f752636d46ea28bc26785c2f9"
"checksum gdk 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6243e995f41f3a61a31847e54cc719edce93dd9140c89dca3b9919be1cfe22d5"
"checksum gdk-pixbuf 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9726408ee1bbada83094326a99b9c68fea275f9dbb515de242a69e72051f4fcc"
"checksum gdk-pixbuf-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d8991b060a9e9161bafd09bf4a202e6fd404f5b4dd1a08d53a1e84256fb34ab0"
"checksum gdk-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6adf679e91d1bff0c06860287f80403e7db54c2d2424dce0a470023b56c88fbb"
"checksum gio 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6261b5d34c30c2d59f879e643704cf54cb44731f3a2038000b68790c03e360e3"
"checksum gio-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4fad225242b9eae7ec8a063bb86974aca56885014672375e5775dc0ea3533911"
"checksum glib 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "be27232841baa43e0fd5ae003f7941925735b2f733a336dc75f07b9eff415e7b"
"checksum glib-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "95856f3802f446c05feffa5e24859fe6a183a7cb849c8449afc35c86b1e316e2"
"checksum gobject-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31d1a804f62034eccf370006ccaef3708a71c31d561fee88564abe71177553d9"
"checksum gtk 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "709f1074259d4685b96133f92b75c7f35b504715b0fcdc96ec95de2607296a60"
"checksum gtk-sys 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53def660c7b48b00b510c81ef2d2fbd3c570f1527081d8d7947f471513e1a4c1"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
"checksum linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
"checksum maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
"checksum pango 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "393fa071b144f8ffb83ede273758983cf414ca3c0b1d2a5a9ce325b3ba3dd786"
"checksum pango-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "86b93d84907b3cf0819bff8f13598ba72843bee579d5ebc2502e4b0367b4be7d"
"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
"checksum proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa"
"checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
"checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
"checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
"checksum serde 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)" = "c9124df5b40cbd380080b2cc6ab894c040a3070d995f5c9dc77e18c34a8ae37d"
"checksum serde_derive 1.0.111 (registry+https://github.com/rust-lang/crates.io-index)" = "3f2c3ac8e6ca1e9c80b8be1023940162bf81ae3cffbb1809474152f2ce1eb250"
"checksum serde_yaml 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3e2dd40a7cdc18ca80db804b7f461a39bb721160a85c9a1fa30134bf3c02a5"
"checksum syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum xkbcommon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fda0ea5f7ddabd51deeeda7799bee06274112f577da7dd3d954b8eda731b2fce"
"checksum yaml-rust 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d"

View File

@ -19,6 +19,7 @@ path = "@path@/examples/test_layout.rs"
[features]
gio_v0_5 = []
gtk_v0_5 = []
rustc_less_1_36 = []
# Dependencies which don't change based on build flags
[dependencies.cairo-sys-rs]

View File

@ -30,29 +30,42 @@ Building
### Dependencies
See `.gitlab-ci.yml`.
See `.gitlab-ci.yml` or run `apt-get build-dep .`
### Build from git repo
```
```bash
$ git clone https://source.puri.sm/Librem5/squeekboard.git
$ cd squeekboard
$ mkdir ../build
$ meson ../build/
$ cd ../build
$ ninja test
$ ninja install
$ mkdir _build
$ meson _build/
$ cd _build
$ ninja
```
To run tests use `ninja test`. To install squeekboard run `ninja install`.
Running
-------
```
```bash
$ phoc # if no compatible Wayland compositor is running yet
$ cd ../build/
$ src/squeekboard
```
Squeekboard honors the gnome "screen-keyboard-enabled" setting. Either enable this through gnome-settings under accessibility or run:
```bash
$ gsettings set org.gnome.desktop.a11y.applications screen-keyboard-enabled true
```
To make the keyboard show you can use either an application that does so automatically, like a text editor or `python3 ./tests/entry.py`, or you can manually trigger it with:
```bash
busctl call --user sm.puri.OSK0 /sm/puri/OSK0 sm.puri.OSK0 SetVisible b true
```
Developing
----------

49
cargo_build.py Normal file
View File

@ -0,0 +1,49 @@
#!/usr/bin/env python3
"""This script manages Cargo builds
while keeping the artifact directory within the build tree
instead of the source tree.
"""
from pathlib import Path
import shlex
import subprocess
import sys
source_dir = Path(__file__).absolute().parent
args = sys.argv[1:]
binary_dir = "debug"
if '--release' in args:
binary_dir = "release"
# The file produced by Cargo will have a special name
try:
i = args.index('--rename')
except ValueError:
filename = None
else:
args.pop(i)
filename = args.pop(i)
# The target destination of the produced file is a positional argument
out_path = [arg for arg in args if not arg.startswith('--')]
if out_path:
out_path = out_path[0]
i = args.index(out_path)
args.pop(i)
subprocess.run(['sh', "{}/cargo.sh".format(shlex.quote(source_dir.as_posix())), 'build']
+ args,
check=True)
if out_path:
out_path = Path(out_path).absolute()
out_basename = out_path.name
filename = filename or out_basename
subprocess.run(['cp', '-a',
'./{}/{}'.format(shlex.quote(binary_dir), shlex.quote(filename)),
out_path],
check=True)

View File

@ -1,34 +0,0 @@
#!/bin/sh
# This script manages Cargo builds
# while keeping the artifact directory within the build tree
# instead of the source tree
set -e
SCRIPT_PATH="$(realpath "$0")"
SOURCE_DIR="$(dirname "$SCRIPT_PATH")"
RELEASE=""
BINARY_DIR="debug"
if [ "${1}" = "--release" ]; then
shift
BINARY_DIR="release"
RELEASE="--release"
fi
if [ "${1}" = "--rename" ]; then
shift
FILENAME="${1}"
shift
fi
OUT_PATH="$(realpath "${1}")"
shift
OUT_BASENAME="$(basename "${OUT_PATH}")"
FILENAME="${FILENAME:-"${OUT_BASENAME}"}"
sh "$SOURCE_DIR"/cargo.sh build $RELEASE "$@"
if [ -n "${OUT_PATH}" ]; then
cp -a ./"${BINARY_DIR}"/"${FILENAME}" "${OUT_PATH}"
fi

89
data/keyboards/be.yaml Normal file
View File

@ -0,0 +1,89 @@
---
outlines:
default: { width: 35.33, height: 52 }
altline: { width: 52.67, height: 52 }
wide: { width: 59, height: 52 }
spaceline: { width: 140, height: 52 }
special: { width: 44, height: 52 }
views:
base:
- "a z e r t y u i o p"
- "q s d f g h j k l m"
- "Shift_L w x c v b n . BackSpace"
- "show_numbers preferences space show_eschars Return"
upper:
- "A Z E R T Y U I O P"
- "Q S D F G H J K L M"
- "Shift_L W X C V B N , BackSpace"
- "show_numbers preferences space show_eschars Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # € % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences space show_eschars Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ $ ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space show_eschars Return"
eschars:
- "à â ç é è ê î ô ù û"
- "À Â Ç É È Ê Î Ô Ù Û"
- "show_numbers_from_symbols æ œ ä ë ï ö ü BackSpace"
- "show_letters preferences space show_eschars Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
action: erase
preferences:
action: "show_prefs"
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "abc"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
show_eschars:
action:
locking:
lock_view: "eschars"
unlock_view: "base"
outline: "altline"
label: "âÂ"
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"
"\"":
keysym: "quotedbl"

View File

@ -0,0 +1,89 @@
---
outlines:
default: { width: 54, height: 42 }
altline: { width: 81, height: 42 }
wide: { width: 100, height: 42 }
spaceline: { width: 205, height: 42 }
special: { width: 54, height: 42 }
views:
base:
- "a z e r t y u i o p"
- "q s d f g h j k l m"
- "Shift_L w x c v b n . BackSpace"
- "show_numbers preferences space show_eschars Return"
upper:
- "A Z E R T Y U I O P"
- "Q S D F G H J K L M"
- "Shift_L W X C V B N , BackSpace"
- "show_numbers preferences space show_eschars Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # € % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences space show_eschars Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ $ ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space show_eschars Return"
eschars:
- "à â ç é è ê î ô ù û"
- "À Â Ç É È Ê Î Ô Ù Û"
- "show_numbers_from_symbols æ œ ä ë ï ö ü BackSpace"
- "show_letters preferences space show_eschars Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
action: erase
preferences:
action: "show_prefs"
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "abc"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
show_eschars:
action:
locking:
lock_view: "eschars"
unlock_view: "base"
outline: "altline"
label: "âÂ"
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"
"\"":
keysym: "quotedbl"

78
data/keyboards/bg.yaml Normal file
View File

@ -0,0 +1,78 @@
---
outlines:
default: { width: 32.72, height: 52 }
altline: { width: 47, height: 52 }
wide: { width: 49.09, height: 52 }
spaceline: { width: 185, height: 52 }
special: { width: 44, height: 52 }
views:
base:
- "я в е р т ъ у и о п ю"
- "а с д ф г х й к л ш щ"
- "Shift_L з ь ц ж б н м ч BackSpace"
- "show_numbers preferences space . Return"
upper:
- В Е Р Т Ъ У И О П Ю"
- "А С Д Ф Г Х Й К Л Ш Щ"
- "Shift_L З Ь Ц Ж Б Н М Ч BackSpace"
- "show_numbers preferences space , Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # € % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences space Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ $ ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
action: erase
preferences:
action: "show_prefs"
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "abc"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"
"\"":
keysym: "quotedbl"

View File

@ -0,0 +1,106 @@
---
outlines:
default: { width: 35.33, height: 52 }
altline: { width: 52.67, height: 52 }
wide: { width: 52.67, height: 52 }
spaceline: { width: 106, height: 52 }
special: { width: 35.33, height: 52 }
views:
base:
- "q w e r t y u i o p"
- "a s d f g h j k l"
- "Shift_L z x c v b n m BackSpace"
- "show_numbers preferences show_accents space , . Return"
upper:
- "Q W E R T Y U I O P"
- "A S D F G H J K L"
- "Shift_L Z X C V B N M BackSpace"
- "show_numbers preferences show_upper_accents space ! ? Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # $ % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences show_accents space , . Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences show_accents space , . Return"
accents:
- "ä ě é ř ť ý ů í ó ö"
- "á š ď ë ŕ ú ü ô ľ"
- "accents_Shift_L ž ß č ç ñ ň ĺ BackSpace"
- "show_letters preferences show_accents space , . Return"
upper_accents:
- "Ä Ě É Ř Ť Ý Ů Í Ó Ö"
- "Á Š Ď Ë Ŕ Ú Ü Ô Ľ"
- "accents_Shift_L Ž ẞ Č Ç Ñ Ň Ĺ BackSpace"
- "show_letters preferences show_upper_accents space , . Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
accents_Shift_L:
action:
locking:
lock_view: "upper_accents"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
action: erase
preferences:
action: show_prefs
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "abc"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
show_accents:
action:
locking:
lock_view: "accents"
unlock_view: "base"
outline: "special"
label: "á"
show_upper_accents:
action:
locking:
lock_view: "upper_accents"
unlock_view: "base"
outline: "special"
label: "Á"
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

View File

@ -0,0 +1,106 @@
---
outlines:
default: { width: 54, height: 42 }
altline: { width: 81, height: 42 }
wide: { width: 81, height: 42 }
spaceline: { width: 162, height: 42 }
special: { width: 54, height: 42 }
views:
base:
- "q w e r t y u i o p"
- "a s d f g h j k l"
- "Shift_L z x c v b n m BackSpace"
- "show_numbers preferences show_accents space , . Return"
upper:
- "Q W E R T Y U I O P"
- "A S D F G H J K L"
- "Shift_L Z X C V B N M BackSpace"
- "show_numbers preferences show_upper_accents space ! ? Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # $ % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences show_accents space , . Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences show_accents space , . Return"
accents:
- "ä ě é ř ť ý ů í ó ö"
- "á š ď ë ŕ ú ü ô ľ"
- "accents_Shift_L ž ß č ç ñ ň ĺ BackSpace"
- "show_letters preferences show_accents space , . Return"
upper_accents:
- "Ä Ě É Ř Ť Ý Ů Í Ó Ö"
- "Á Š Ď Ë Ŕ Ú Ü Ô Ľ"
- "accents_Shift_L Ž ẞ Č Ç Ñ Ň Ĺ BackSpace"
- "show_letters preferences show_upper_accents space , . Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
accents_Shift_L:
action:
locking:
lock_view: "upper_accents"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
action: erase
preferences:
action: show_prefs
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "abc"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
show_accents:
action:
locking:
lock_view: "accents"
unlock_view: "base"
outline: "special"
label: "á"
show_upper_accents:
action:
locking:
lock_view: "upper_accents"
unlock_view: "base"
outline: "special"
label: "Á"
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

106
data/keyboards/cz.yaml Normal file
View File

@ -0,0 +1,106 @@
---
outlines:
default: { width: 35.33, height: 52 }
altline: { width: 52.67, height: 52 }
wide: { width: 52.67, height: 52 }
spaceline: { width: 106, height: 52 }
special: { width: 35.33, height: 52 }
views:
base:
- "q w e r t z u i o p"
- "a s d f g h j k l"
- "Shift_L y x c v b n m BackSpace"
- "show_numbers preferences show_accents space , . Return"
upper:
- "Q W E R T Z U I O P"
- "A S D F G H J K L"
- "Shift_L Y X C V B N M BackSpace"
- "show_numbers preferences show_upper_accents space ! ? Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # $ % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences show_accents space , . Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences show_accents space , . Return"
accents:
- "ä ě é ř ť ž ů í ó ö"
- "á š ď ë ŕ ú ü ô ľ"
- "accents_Shift_L ý ß č ç ñ ň ĺ BackSpace"
- "show_letters preferences show_accents space , . Return"
upper_accents:
- "Ä Ě É Ř Ť Ž Ů Í Ó Ö"
- "Á Š Ď Ë Ŕ Ú Ü Ô Ľ"
- "accents_Shift_L Ý ẞ Č Ç Ñ Ň Ĺ BackSpace"
- "show_letters preferences show_upper_accents space , . Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
accents_Shift_L:
action:
locking:
lock_view: "upper_accents"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
action: erase
preferences:
action: show_prefs
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "abc"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
show_accents:
action:
locking:
lock_view: "accents"
unlock_view: "base"
outline: "special"
label: "á"
show_upper_accents:
action:
locking:
lock_view: "upper_accents"
unlock_view: "base"
outline: "special"
label: "Á"
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

106
data/keyboards/cz_wide.yaml Normal file
View File

@ -0,0 +1,106 @@
---
outlines:
default: { width: 54, height: 42 }
altline: { width: 81, height: 42 }
wide: { width: 81, height: 42 }
spaceline: { width: 162, height: 42 }
special: { width: 54, height: 42 }
views:
base:
- "q w e r t z u i o p"
- "a s d f g h j k l"
- "Shift_L y x c v b n m BackSpace"
- "show_numbers preferences show_accents space , . Return"
upper:
- "Q W E R T Z U I O P"
- "A S D F G H J K L"
- "Shift_L Y X C V B N M BackSpace"
- "show_numbers preferences show_upper_accents space ! ? Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # $ % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences show_accents space , . Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences show_accents space , . Return"
accents:
- "ä ě é ř ť ž ů í ó ö"
- "á š ď ë ŕ ú ü ô ľ"
- "accents_Shift_L ý ß č ç ñ ň ĺ BackSpace"
- "show_letters preferences show_accents space , . Return"
upper_accents:
- "Ä Ě É Ř Ť Ž Ů Í Ó Ö"
- "Á Š Ď Ë Ŕ Ú Ü Ô Ľ"
- "accents_Shift_L Ý ẞ Č Ç Ñ Ň Ĺ BackSpace"
- "show_letters preferences show_upper_accents space , . Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
accents_Shift_L:
action:
locking:
lock_view: "upper_accents"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
action: erase
preferences:
action: show_prefs
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "abc"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
show_accents:
action:
locking:
lock_view: "accents"
unlock_view: "base"
outline: "special"
label: "á"
show_upper_accents:
action:
locking:
lock_view: "upper_accents"
unlock_view: "base"
outline: "special"
label: "Á"
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

View File

@ -21,7 +21,7 @@ views:
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # € % & - _ + ( )"
- "show_symbols , \" ' : = < > BackSpace"
- "show_symbols ; \" ' : = < > BackSpace"
- "show_letters show_eschars preferences space , . Return"
symbols:
- "~ ` ´ | · √ µ ÷ × ¶"

View File

@ -21,7 +21,7 @@ views:
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # % & - _ + ( ) ß"
- "show_symbols , \" ' : = < > BackSpace"
- "show_symbols ; \" ' : = < > BackSpace"
- "show_letters preferences space , . Return"
symbols:
- "~ ` ´ · © ® ÷ × ¶"

81
data/keyboards/epo.yaml Normal file
View File

@ -0,0 +1,81 @@
---
outlines:
default: { width: 35.33, height: 52 }
altline: { width: 52.67, height: 52 }
wide: { width: 62, height: 52 }
spaceline: { width: 99.67, height: 52 }
special: { width: 35.33, height: 52 }
views:
base:
- "q w e r t y u i o p"
- "a s d f g h j k l"
- "Shift_L z x c v b n m BackSpace"
- "show_numbers show_eschars preferences space , . Return"
upper:
- "Q W E R T Y U I O P"
- "A S D F G H J K L"
- "Shift_L Z X C V B N M BackSpace"
- "show_numbers show_eschars preferences space ! ? Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # $ % & - _ + ( )"
- "show_symbols , \" ' : ; ! ? BackSpace"
- "show_letters preferences space . Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space . Return"
eschars:
- "ĉ ĝ ĥ ĵ ŝ ŭ ?"
- "Ĉ Ĝ Ĥ Ĵ Ŝ Ŭ !"
- "show_numbers ' - 🐊 💚 🌐 . BackSpace"
- "show_letters show_eschars preferences space „ “ Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
action: "erase"
preferences:
action: "show_prefs"
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "altline"
label: "abc"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
show_eschars:
action:
locking:
lock_view: "eschars"
unlock_view: "base"
outline: "altline"
label: "ŭŜ"
space:
outline: "spaceline"
label: " "
text: " "
Return:
outline: "altline"
icon: "key-enter"
keysym: "Return"

View File

@ -0,0 +1,87 @@
---
outlines:
default: { width: 35.33, height: 52 }
altline: { width: 52.67, height: 52 }
wide: { width: 62, height: 52 }
spaceline: { width: 99.67, height: 52 }
special: { width: 44, height: 52 }
views:
base:
- "q w e r t y u i o p"
- "a s d f g h j k l ç"
- "Shift_L z x c v b n m BackSpace"
- "show_numbers show_eschars preferences space ? period Return"
upper:
- "Q W E R T Y U I O P"
- "A S D F G H J K L Ç"
- "Shift_L Z X C V B N M BackSpace"
- "show_numbers show_eschars preferences space ¿ period Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # € % & - _ + ( )"
- "show_symbols , \" ' colon ; ! = BackSpace"
- "show_letters show_eschars preferences space ? period Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ $ ¥ ^ ° * { }"
- "show_numbers \\ / < > = [ ] BackSpace"
- "show_letters show_eschars preferences space ? period Return"
eschars:
- "á é í ó ú Á É Í Ó Ú"
- "à è ì ò ù À È Ì Ò Ù"
- "show_numbers ü ç ï Ü Ç Ï ¡ BackSpace"
- "show_letters show_eschars preferences space « » Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
action: "erase"
preferences:
action: "show_prefs"
outline: "default"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "altline"
label: "abc"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
show_eschars:
action:
locking:
lock_view: "eschars"
unlock_view: "base"
outline: "altline"
label: "àÀ"
period:
outline: "default"
text: "."
space:
outline: "spaceline"
text: " "
Return:
outline: "altline"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

View File

@ -0,0 +1,89 @@
---
outlines:
default: { width: 54, height: 42 }
altline: { width: 81, height: 42 }
wide: { width: 100, height: 42 }
spaceline: { width: 205, height: 42 }
special: { width: 54, height: 42 }
views:
base:
- "a z e r t y u i o p"
- "q s d f g h j k l m"
- "Shift_L w x c v b n . BackSpace"
- "show_numbers preferences space show_eschars Return"
upper:
- "A Z E R T Y U I O P"
- "Q S D F G H J K L M"
- "Shift_L W X C V B N , BackSpace"
- "show_numbers preferences space show_eschars Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # € % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences space show_eschars Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ $ ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space show_eschars Return"
eschars:
- "à â ç é è ê î ô ù û"
- "À Â Ç É È Ê Î Ô Ù Û"
- "show_numbers_from_symbols æ œ ä ë ï ö ü BackSpace"
- "show_letters preferences space show_eschars Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
action: erase
preferences:
action: "show_prefs"
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "abc"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
show_eschars:
action:
locking:
lock_view: "eschars"
unlock_view: "base"
outline: "altline"
label: "âÂ"
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"
"\"":
keysym: "quotedbl"

71
data/keyboards/il.yaml Normal file
View File

@ -0,0 +1,71 @@
---
outlines:
default: { width: 40, height: 60 }
altline: { width: 56, height: 60 }
wide: { width: 62, height: 60 }
spaceline: { width: 142, height: 60 }
special: { width: 44, height: 60 }
views:
base:
- "' - ק ר א ט ו ן ם פ"
- "ש ד ג כ ע י ח ל ך ף"
- ס ב ה נ מ צ ת ץ BackSpace"
- "show_numbers comma preferences space period Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # ₪ % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences space period Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € $ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space period Return"
buttons:
BackSpace:
outline: "default"
icon: "edit-clear-symbolic"
action: erase
comma:
outline: "special"
text: ","
preferences:
action: show_prefs
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "ABC"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
period:
outline: "special"
text: "."
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

78
data/keyboards/ir.yaml Normal file
View File

@ -0,0 +1,78 @@
---
outlines:
default: { width: 35.33, height: 52 }
altline: { width: 52.67, height: 52 }
wide: { width: 62, height: 52 }
spaceline: { width: 142, height: 52 }
special: { width: 44, height: 52 }
views:
base:
- "ض ص ق ف غ ع ه خ ح ج"
- "ش س ی ب ل ا ت ن م ک"
- "Shift_L ظ ط ز ر ذ د و BackSpace"
- "show_numbers preferences space period Return"
upper:
- "پ { } [ ] ّ َ ِ ُ چ"
- "ؤ‌ ئ ي‌ إ أ آ ة‌ » « گ"
- "Shift_L ك ٓ ژ ء > < ؟ BackSpace"
- "show_numbers preferences space period Return"
numbers:
- "۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹ ۰"
- "@ # ﷼ % & - _ + ( )"
- "show_symbols , \" ' colon ؛ ! ? BackSpace"
- "show_letters preferences space period Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space period Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
action: erase
preferences:
action: show_prefs
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "ABC"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
period:
outline: "special"
text: "."
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

View File

@ -0,0 +1,78 @@
---
outlines:
default: { width: 54, height: 42 }
altline: { width: 81, height: 42 }
wide: { width: 108, height: 42 }
spaceline: { width: 216, height: 42 }
special: { width: 54, height: 42 }
views:
base:
- "ض ص ق ف غ ع ه خ ح ج"
- "ش س ی ب ل ا ت ن م ک"
- "Shift_L ظ ط ز ر ذ د و BackSpace"
- "show_numbers preferences space period Return"
upper:
- "پ { } [ ] ّ َ ِ ُ چ"
- "ؤ‌ ئ ي‌ إ أ آ ة‌ » « گ"
- "Shift_L ك ٓ ژ ء > < ؟ BackSpace"
- "show_numbers preferences space period Return"
numbers:
- "۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹ ۰"
- "@ # ﷼ % & - _ + ( )"
- "show_symbols , \" ' colon ؛ ! ? BackSpace"
- "show_letters preferences space period Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space period Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
action: "erase"
preferences:
action: "show_prefs"
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "ABC"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
".":
outline: "special"
text: "."
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

View File

@ -0,0 +1,89 @@
# Friulian layout created by Fabio Tomat
# 14 october 2020
---
outlines:
default: { width: 35.33, height: 52 }
altline: { width: 52.67, height: 52 }
wide: { width: 62, height: 52 }
spaceline: { width: 99.67, height: 52 }
special: { width: 44, height: 52 }
views:
base:
- "q w e r t y u i o p"
- "a s d f g h j k l"
- "Shift_L z x c v b n m BackSpace"
- "show_numbers show_eschars preferences space , . Return"
upper:
- "Q W E R T Y U I O P"
- "A S D F G H J K L"
- "Shift_L Z X C V B N M BackSpace"
- "show_numbers show_eschars preferences space “ ” Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # € % & - _ + ( )"
- "show_symbols , \" ' : ; ! = BackSpace"
- "show_letters show_eschars preferences space ? . Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ $ ¥ ^ ° * { }"
- "show_numbers \\ / < > = [ ] BackSpace"
- "show_letters show_eschars preferences space ? . Return"
eschars:
- "â ê î ô û Â Ê Î Ô Û"
- "à è ì ò ù À È Ì Ò Ù"
- "show_numbers ç Ç ᶜ ᵐ ⁿ ᵉ ᵗ BackSpace"
- "show_letters show_eschars preferences space ᶠ . Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
action: "erase"
preferences:
action: "show_prefs"
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "altline"
label: "abc"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
show_eschars:
action:
locking:
lock_view: "eschars"
unlock_view: "base"
outline: "altline"
label: "àê"
space:
outline: "spaceline"
label: " "
text: " "
Return:
outline: "altline"
icon: "key-enter"
keysym: "Return"

View File

@ -22,7 +22,7 @@ views:
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # € % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_symbols , \" ' : ; ! ? BackSpace"
- "show_letters show_eschars preferences space ? . Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
@ -84,7 +84,4 @@ buttons:
outline: "altline"
icon: "key-enter"
keysym: "Return"
colon:
label: ":"
"\"":
keysym: "quotedbl"

View File

@ -2,9 +2,9 @@
outlines:
default: { width: 32, height: 52 }
altline: { width: 48.39024, height: 52 }
wide: { width: 62, height: 52 }
outline7: { width: 88.97561, height: 52 }
spaceline: { width: 150.5853, height: 52 }
wide: { width: 64, height: 52 }
spaceline: { width: 142, height: 52 }
special: { width: 44, height: 52 }
views:
base:
@ -25,7 +25,7 @@ views:
symbols:
- "~ ` | U00B7 squareroot Greek_pi Greek_tau division multiply paragraph"
- "copyright U00AE U00A3 EuroSign U00A5 asciicircum degree * { }"
- "show_numbers \\ / < > = [ ] BackSpace"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space . Return"
buttons:
@ -42,17 +42,22 @@ buttons:
action: erase
preferences:
action: "show_prefs"
outline: "altline"
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "altline"
outline: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: altline
label: "123"
show_letters:
action:
set_view: "base"
outline: "altline"
outline: "wide"
label: "ABC"
show_symbols:
action:
@ -60,7 +65,7 @@ buttons:
outline: "altline"
label: "*/="
".":
outline: altline
outline: "special"
space:
outline: spaceline
text: " "

View File

@ -52,6 +52,8 @@ buttons:
locking:
lock_view: "upper_accents"
unlock_view: "accents"
looks_locked_from:
- "upper"
outline: "altline"
icon: "key-shift"
BackSpace:
@ -94,6 +96,8 @@ buttons:
locking:
lock_view: "upper_accents"
unlock_view: "upper"
looks_locked_from:
- "accents"
outline: "altline"
label: "ĄĘ"
period:

View File

@ -0,0 +1,220 @@
---
outlines:
action: { width: 59, height: 46 }
small: { width: 50, height: 22 }
default: { width: 35.33, height: 46 }
altline: { width: 48, height: 46 }
wide: { width: 50, height: 46 }
spaceline: { width: 110, height: 46 }
special: { width: 44, height: 46 }
views:
base:
- "Ctrl Alt Tabsmall ↑ ↓ ← →"
- "a z e r t y u i o p"
- "q s d f g h j k l m"
- "Shift_L w x c v b n period BackSpace"
- "show_numbers preferences space show_eschars show_actions Return"
upper:
- "Ctrl Alt Tabsmall PgUp PgDn Home End"
- "A Z E R T Y U I O P"
- "Q S D F G H J K L M"
- "Shift_L W X C V B N , BackSpace"
- "show_numbers preferences space show_eschars show_actions Return"
numbers:
- "Ctrl Alt Tabsmall ↑ ↓ ← →"
- "1 2 3 4 5 6 7 8 9 0"
- "@ # € % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences space show_eschars show_actions Return"
symbols:
- "Ctrl Alt Tabsmall ↑ ↓ ← →"
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ $ ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space show_eschars show_actions Return"
eschars:
- "Ctrl Alt Tabsmall ↑ ↓ ← →"
- "à â ç é è ê î ô ù û"
- "À Â Ç É È Ê Î Ô Ù Û"
- "show_numbers_from_symbols æ œ ä ë ï ö ü BackSpace"
- "show_letters preferences space show_eschars show_actions Return"
actions:
- "Ctrl Alt PgUp PgDn Home End"
- "F1 F2 F3 F4 F5 F6"
- "F7 F8 F9 F10 F11 F12"
- "Esc Tab Pause Insert Up Del"
- "show_letters Menu Break Left Down Right"
buttons:
F1:
outline: "action"
keysym: "F1"
F2:
outline: "action"
keysym: "F2"
F3:
outline: "action"
keysym: "F3"
F4:
outline: "action"
keysym: "F4"
F5:
outline: "action"
keysym: "F5"
F6:
outline: "action"
keysym: "F6"
F7:
outline: "action"
keysym: "F7"
F8:
outline: "action"
keysym: "F8"
F9:
outline: "action"
keysym: "F9"
F10:
outline: "action"
keysym: "F10"
F11:
outline: "action"
keysym: "F11"
F12:
outline: "action"
keysym: "F12"
Esc:
outline: "action"
keysym: "Escape"
Tab:
outline: "action"
keysym: "Tab"
Tabsmall:
outline: "small"
keysym: "Tab"
label: "Tab"
Del:
outline: "action"
keysym: "Delete"
Insert:
outline: "action"
keysym: "Insert"
Menu:
outline: "action"
keysym: "Menu"
Pause:
outline: "action"
keysym: "Pause"
Break:
outline: "action"
keysym: "Break"
Home:
outline: "small"
keysym: "Home"
End:
outline: "small"
keysym: "End"
PgUp:
outline: "small"
keysym: "Page_Up"
PgDn:
outline: "small"
keysym: "Page_Down"
"↑":
outline: "small"
keysym: "Up"
"↓":
outline: "small"
keysym: "Down"
"←":
outline: "small"
keysym: "Left"
"→":
outline: "small"
keysym: "Right"
Up:
label: "↑"
outline: "action"
keysym: "Up"
Left:
label: "←"
outline: "action"
keysym: "Left"
Down:
label: "↓"
outline: "action"
keysym: "Down"
Right:
label: "→"
outline: "action"
keysym: "Right"
Ctrl:
modifier: "Control"
outline: "small"
label: "Ctrl"
Alt:
modifier: "Alt"
outline: "small"
label: "Alt"
period:
outline: "special"
text: "."
show_actions:
action:
set_view: "actions"
outline: "special"
label: ">_"
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
action: erase
preferences:
action: "show_prefs"
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "abc"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
show_eschars:
action:
locking:
lock_view: "eschars"
unlock_view: "base"
outline: "altline"
label: "âÂ"
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"
"\"":
keysym: "quotedbl"

View File

@ -0,0 +1,223 @@
---
outlines:
action: { width: 90, height: 37 }
small: { width: 67.4, height: 22 }
default: { width: 54, height: 37 }
altline: { width: 81, height: 37 }
wide: { width: 100, height: 37 }
spaceline: { width: 110, height: 37 }
special: { width: 54, height: 37 }
views:
base:
- "EscSmall TabSmall Ctrl Alt ↑ ↓ ← →"
- "a z e r t y u i o p"
- "q s d f g h j k l m"
- "Shift_L w x c v b n period BackSpace"
- "show_numbers preferences space show_eschars show_actions Return"
upper:
- "EscSmall TabSmall Ctrl Alt PgUp PgDn Home End"
- "A Z E R T Y U I O P"
- "Q S D F G H J K L M"
- "Shift_L W X C V B N , BackSpace"
- "show_numbers preferences space show_eschars show_actions Return"
numbers:
- "EscSmall TabSmall Ctrl Alt ↑ ↓ ← →"
- "1 2 3 4 5 6 7 8 9 0"
- "@ # € % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences space show_eschars show_actions Return"
symbols:
- "EscSmall TabSmall Ctrl Alt ↑ ↓ ← →"
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ $ ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space show_eschars show_actions Return"
eschars:
- "EscSmall TabSmall Ctrl Alt ↑ ↓ ← →"
- "à â ç é è ê î ô ù û"
- "À Â Ç É È Ê Î Ô Ù Û"
- "show_numbers_from_symbols æ œ ä ë ï ö ü BackSpace"
- "show_letters preferences space show_eschars show_actions Return"
actions:
- "EscSmall TabSmall Ctrl Alt PgUp PgDn Home End"
- "F1 F2 F3 F4 F5 F6"
- "F7 F8 F9 F10 F11 F12"
- "Esc Tab Pause Insert Up Del"
- "show_letters Menu Break Left Down Right"
buttons:
F1:
outline: "action"
keysym: "F1"
F2:
outline: "action"
keysym: "F2"
F3:
outline: "action"
keysym: "F3"
F4:
outline: "action"
keysym: "F4"
F5:
outline: "action"
keysym: "F5"
F6:
outline: "action"
keysym: "F6"
F7:
outline: "action"
keysym: "F7"
F8:
outline: "action"
keysym: "F8"
F9:
outline: "action"
keysym: "F9"
F10:
outline: "action"
keysym: "F10"
F11:
outline: "action"
keysym: "F11"
F12:
outline: "action"
keysym: "F12"
Esc:
outline: "action"
keysym: "Escape"
EscSmall:
outline: "small"
keysym: "Escape"
label: "Esc"
Tab:
outline: "action"
keysym: "Tab"
TabSmall:
outline: "small"
keysym: "Tab"
label: "Tab"
Del:
outline: "action"
keysym: "Delete"
Insert:
outline: "action"
keysym: "Insert"
Menu:
outline: "action"
keysym: "Menu"
Pause:
outline: "action"
keysym: "Pause"
Break:
outline: "action"
keysym: "Break"
Home:
outline: "small"
keysym: "Home"
End:
outline: "small"
keysym: "End"
PgUp:
outline: "small"
keysym: "Page_Up"
PgDn:
outline: "small"
keysym: "Page_Down"
"↑":
outline: "small"
keysym: "Up"
"↓":
outline: "small"
keysym: "Down"
"←":
outline: "small"
keysym: "Left"
"→":
outline: "small"
keysym: "Right"
Up:
label: "↑"
outline: "action"
keysym: "Up"
Left:
label: "←"
outline: "action"
keysym: "Left"
Down:
label: "↓"
outline: "action"
keysym: "Down"
Right:
label: "→"
outline: "action"
keysym: "Right"
Ctrl:
modifier: "Control"
outline: "small"
label: "Ctrl"
Alt:
modifier: "Alt"
outline: "small"
label: "Alt"
period:
outline: "special"
text: "."
show_actions:
action:
set_view: "actions"
outline: "special"
label: ">_"
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
action: erase
preferences:
action: "show_prefs"
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "abc"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
show_eschars:
action:
locking:
lock_view: "eschars"
unlock_view: "base"
outline: "altline"
label: "âÂ"
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"
"\"":
keysym: "quotedbl"

View File

@ -147,9 +147,6 @@ buttons:
Pause:
outline: "action"
keysym: "Pause"
Menu:
outline: "action"
keysym: "Menu"
Break:
outline: "action"
keysym: "Break"
@ -201,4 +198,3 @@ buttons:
modifier: "Alt"
outline: "small"
label: "Alt"

View File

@ -0,0 +1,208 @@
---
outlines:
default: { width: 54, height: 37 }
action: { width: 90, height: 37 }
altline: { width: 81, height: 37 }
wide: { width: 90, height: 37 }
spaceline: { width: 225, height: 37 }
special: { width: 54, height: 37 }
small: { width: 67.4, height: 22 }
views:
base:
- "EscSmall TabSmall Ctrl Alt ↑ ↓ ← →"
- "q w e r t y u i o p"
- "a s d f g h j k l"
- "Shift_L z x c v b n m BackSpace"
- "show_numbers preferences space show_actions Return"
upper:
- "EscSmall TabSmall Ctrl Alt PgUp PgDn Home End"
- "Q W E R T Y U I O P"
- "A S D F G H J K L"
- "Shift_L Z X C V B N M BackSpace"
- "show_numbers preferences space show_actions Return"
numbers:
- "EscSmall TabSmall Ctrl Alt ↑ ↓ ← →"
- "1 2 3 4 5 6 7 8 9 0"
- "* # $ / & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences space period Return"
symbols:
- "EscSmall TabSmall Ctrl Alt ↑ ↓ ← →"
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° @ { }"
- "show_numbers_from_symbols \\ % < > = [ ] BackSpace"
- "show_letters preferences space period Return"
actions:
- "EscSmall TabSmall Ctrl Alt PgUp PgDn Home End"
- "F1 F2 F3 F4 F5 F6"
- "F7 F8 F9 F10 F11 F12"
- "Esc Tab Pause Insert Up Del"
- "show_letters Menu Break Left Down Right"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
action: erase
preferences:
action: "show_prefs"
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "ABC"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "τ=\\"
show_actions:
action:
set_view: "actions"
outline: "altline"
label: ">_"
period:
outline: "altline"
text: "."
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"
F1:
outline: "action"
keysym: "F1"
F2:
outline: "action"
keysym: "F2"
F3:
outline: "action"
keysym: "F3"
F4:
outline: "action"
keysym: "F4"
F5:
outline: "action"
keysym: "F5"
F6:
outline: "action"
keysym: "F6"
F7:
outline: "action"
keysym: "F7"
F8:
outline: "action"
keysym: "F8"
F9:
outline: "action"
keysym: "F9"
F10:
outline: "action"
keysym: "F10"
F11:
outline: "action"
keysym: "F11"
F12:
outline: "action"
keysym: "F12"
Esc:
outline: "action"
keysym: "Escape"
EscSmall:
outline: "small"
keysym: "Escape"
label: "Esc"
Tab:
outline: "action"
keysym: "Tab"
TabSmall:
outline: "small"
keysym: "Tab"
label: "Tab"
Del:
outline: "action"
keysym: "Delete"
Insert:
outline: "action"
keysym: "Insert"
Menu:
outline: "action"
keysym: "Menu"
Pause:
outline: "action"
keysym: "Pause"
Break:
outline: "action"
keysym: "Break"
Home:
outline: "small"
keysym: "Home"
End:
outline: "small"
keysym: "End"
PgUp:
outline: "small"
keysym: "Page_Up"
PgDn:
outline: "small"
keysym: "Page_Down"
"↑":
outline: "small"
keysym: "Up"
"↓":
outline: "small"
keysym: "Down"
"←":
outline: "small"
keysym: "Left"
"→":
outline: "small"
keysym: "Right"
Up:
label: "↑"
outline: "action"
keysym: "Up"
Left:
label: "←"
outline: "action"
keysym: "Left"
Down:
label: "↓"
outline: "action"
keysym: "Down"
Right:
label: "→"
outline: "action"
keysym: "Right"
Ctrl:
modifier: "Control"
outline: "small"
label: "Ctrl"
Alt:
modifier: "Alt"
outline: "small"
label: "Alt"

80
data/keyboards/th.yaml Normal file
View File

@ -0,0 +1,80 @@
---
outlines:
default: { width: 35.33, height: 52 }
altline: { width: 52.67, height: 52 }
wide: { width: 62, height: 52 }
spaceline: { width: 142, height: 52 }
special: { width: 44, height: 52 }
views:
base:
- "ๅ / _ ภ ถ ุ ึ ค ต จ ข ช"
- "ๆ ไ ำ พ ะ ั ี ร น ย บ ล"
- "ฟ ห ก ด เ ้ ่ า ส ว ง ฃ"
- "Shift_L ผ ป แ อ ิ ื ท ม ใ ฝ BackSpace"
- "show_numbers preferences space period Return"
upper:
- "+ ๑ ๒ ๓ ๔ ู ฿ ๕ ๖ ๗ ๘ ๙"
- " \" ฎ ฑ ธ ํ ๊ ณ ฯ ญ ฐ ,"
- "ฤ ฆ ฏ โ ฌ ็ ๋ ษ ศ ซ . ฅ"
- "Shift_L ( ) ฉ ฮ ฺ ์ ? ฒ ฬ ฦ BackSpace"
- "show_numbers preferences space period Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # $ % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences space period Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space period Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
action: erase
preferences:
action: show_prefs
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "กขค"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
period:
outline: "special"
text: "."
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

View File

@ -0,0 +1,84 @@
---
outlines:
default: { width: 75, height: 56 }
altline: { width: 75, height: 56 }
wide: { width: 135, height: 56 }
spaceline: { width: 450, height: 56 }
spacelinesymbol: { width: 300, height: 56 }
special: { width: 90, height: 56 }
views:
base:
- "ๅ / _ ภ ถ ุ ึ ค ต จ ข ช"
- "ๆ ไ ำ พ ะ ั ี ร น ย บ ล"
- "ฟ ห ก ด เ ้ ่ า ส ว ง ฃ"
- "Shift_L ผ ป แ อ ิ ื ท ม ใ ฝ BackSpace"
- "show_numbers preferences space period Return"
upper:
- "+ ๑ ๒ ๓ ๔ ู ฿ ๕ ๖ ๗ ๘ ๙"
- " \" ฎ ฑ ธ ํ ๊ ณ ฯ ญ ฐ ,"
- "ฤ ฆ ฏ โ ฌ ็ ๋ ษ ศ ซ . ฅ"
- "Shift_L ( ) ฉ ฮ ฺ ์ ? ฒ ฬ ฦ BackSpace"
- "show_numbers preferences space period Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # $ % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences spacesymbol period Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences spacesymbol period Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
action: erase
preferences:
action: show_prefs
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "กขค"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
period:
outline: "special"
text: "."
space:
outline: "spaceline"
text: " "
spacesymbol:
outline: "spacelinesymbol"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

94
data/keyboards/ua.yaml Normal file
View File

@ -0,0 +1,94 @@
---
outlines:
default: { width: 32, height: 52 }
altline: { width: 32, height: 52 }
wide: { width: 57, height: 52 }
narrow: { width: 26, height: 52 }
spaceline: { width: 107, height: 52 }
fill: { width: 159, height: 52 }
special: { width: 42, height: 52 }
views:
base:
- "й ц у к е н г ш щ з х"
- і в а п р о л д ж є"
- "Shift_L я ч с м и т ь б ю BackSpace"
- "show_numbers preferences ґ space ї period Return"
upper:
- "Й Ц У К Е Н Г Ш Щ З Х"
- І В А П Р О Л Д Ж Є"
- "Shift_L Я Ч С М И Т Ь Б Ю BackSpace"
- "show_numbers preferences Ґ space Ї comma Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # $ % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences space_fill period Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space_fill period Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
action: erase
preferences:
action: show_prefs
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "wide"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "АБВ"
show_symbols:
action:
set_view: "symbols"
outline: "wide"
label: "*/="
period:
outline: "special"
text: "."
comma:
outline: "special"
text: ","
space:
outline: "spaceline"
text: " "
space_fill:
outline: "fill"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"
ґ:
outline: "narrow"
Ґ:
outline: "narrow"
ї:
outline: "narrow"
Ї:
outline: "narrow"

View File

@ -0,0 +1,78 @@
---
outlines:
default: { width: 35.33, height: 52 }
altline: { width: 52.67, height: 52 }
wide: { width: 62, height: 52 }
spaceline: { width: 142, height: 52 }
special: { width: 44, height: 52 }
views:
base:
- "q w f p g j l u y"
- "a r s t d h n e i o"
- "Shift_L z x c v b k m BackSpace"
- "show_numbers preferences space period Return"
upper:
- "Q W F P G J L U Y"
- "A R S T D H N E I O"
- "Shift_L Z X C V B K M BackSpace"
- "show_numbers preferences space period Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # $ % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences space period Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space period Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
action: erase
preferences:
action: show_prefs
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "ABC"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
period:
outline: "special"
text: "."
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

View File

@ -0,0 +1,78 @@
---
outlines:
default: { width: 54, height: 42 }
altline: { width: 81, height: 42 }
wide: { width: 108, height: 42 }
spaceline: { width: 216, height: 42 }
special: { width: 54, height: 42 }
views:
base:
- "q w f p g j l u y"
- "a r s t d h n e i o"
- "Shift_L z x c v b k m BackSpace"
- "show_numbers preferences space . Return"
upper:
- "Q W F P G J L U Y"
- "A R S T D H N E I O"
- "Shift_L Z X C V B K M BackSpace"
- "show_numbers preferences space . Return"
numbers:
- "1 2 3 4 5 6 7 8 9 0"
- "@ # $ % & - _ + ( )"
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "show_letters preferences space . Return"
symbols:
- "~ ` | · √ π τ ÷ × ¶"
- "© ® £ € ¥ ^ ° * { }"
- "show_numbers_from_symbols \\ / < > = [ ] BackSpace"
- "show_letters preferences space . Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
action: "erase"
preferences:
action: "show_prefs"
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "ABC"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
".":
outline: "special"
text: "."
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"

View File

@ -0,0 +1,89 @@
---
outlines:
default: { width: 35.33, height: 52 }
altline: { width: 52.67, height: 52 }
wide: { width: 62, height: 52 }
spaceline: { width: 142, height: 52 }
special: { width: 44, height: 52 }
views:
base:
- "Shift_L p y f g c r l BackSpace"
- "a o e u i d h t n s"
- ", q j k x b m w v z"
- "show_numbers preferences space period Return"
upper:
- "Shift_L P Y F G C R L BackSpace"
- "A O E U I D H T N S"
- ", Q J K X B M W V Z"
- "show_numbers preferences space period Return"
numbers:
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "* # $ / & - _ + ( )"
- "1 2 3 4 5 6 7 8 9 0"
- "show_letters preferences space period Return"
symbols:
- "show_numbers_from_symbols \\ % < > = [ ] BackSpace"
- "© ® £ € ¥ ^ ° @ { }"
- "~ ` | · √ π τ ÷ × ¶"
- "show_letters preferences space period Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
action: "erase"
preferences:
action: "show_prefs"
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "ABC"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
period:
outline: "special"
text: "."
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"
# The US QWERTY layout has fewer letters on the third row, and so has
# the shift & backspace keys placed there. In contrast, the US DVORAK
# layout has fewer letters on the first row, which makes it a good
# choice for the shift & backspace keys. That leads to what may be,
# for many people, an unexpected layout in numbers mode: the numerals
# are on the third row (not the first) so that the backspace key
# remains in a consistent location regardless of mode, without
# sacrificing key width. (Once could argue that in numbers mode, the
# numerals should be closer to the enter key.) As with any keyboard
# layout, familiarity comes with repeated use.

View File

@ -0,0 +1,89 @@
---
outlines:
default: { width: 54, height: 42 }
altline: { width: 81, height: 42 }
wide: { width: 108, height: 42 }
spaceline: { width: 216, height: 42 }
special: { width: 54, height: 42 }
views:
base:
- "Shift_L p y f g c r l BackSpace"
- "a o e u i d h t n s"
- ", q j k x b m w v z"
- "show_numbers preferences space period Return"
upper:
- "Shift_L P Y F G C R L BackSpace"
- "A O E U I D H T N S"
- ", Q J K X B M W V Z"
- "show_numbers preferences space period Return"
numbers:
- "show_symbols , \" ' colon ; ! ? BackSpace"
- "* # $ / & - _ + ( )"
- "1 2 3 4 5 6 7 8 9 0"
- "show_letters preferences space period Return"
symbols:
- "show_numbers_from_symbols \\ % < > = [ ] BackSpace"
- "© ® £ € ¥ ^ ° @ { }"
- "~ ` | · √ π τ ÷ × ¶"
- "show_letters preferences space period Return"
buttons:
Shift_L:
action:
locking:
lock_view: "upper"
unlock_view: "base"
outline: "altline"
icon: "key-shift"
BackSpace:
outline: "altline"
icon: "edit-clear-symbolic"
action: "erase"
preferences:
action: "show_prefs"
outline: "special"
icon: "keyboard-mode-symbolic"
show_numbers:
action:
set_view: "numbers"
outline: "wide"
label: "123"
show_numbers_from_symbols:
action:
set_view: "numbers"
outline: "altline"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "ABC"
show_symbols:
action:
set_view: "symbols"
outline: "altline"
label: "*/="
period:
outline: "special"
text: "."
space:
outline: "spaceline"
text: " "
Return:
outline: "wide"
icon: "key-enter"
keysym: "Return"
colon:
text: ":"
# The US QWERTY layout has fewer letters on the third row, and so has
# the shift & backspace keys placed there. In contrast, the US DVORAK
# layout has fewer letters on the first row, which makes it a good
# choice for the shift & backspace keys. That leads to what may be,
# for many people, an unexpected layout in numbers mode: the numerals
# are on the third row (not the first) so that the backspace key
# remains in a consistent location regardless of mode, without
# sacrificing key width. (Once could argue that in numbers mode, the
# numerals should be closer to the enter key.) As with any keyboard
# layout, familiarity comes with repeated use.

13
data/langs/bg-BG.txt Normal file
View File

@ -0,0 +1,13 @@
bg Български
de Немски
es Испански
emoji Емоджи
fi Френски
gr Гръцки
it Италянски
no Норевежки
pl Полски
ru Руски
se Шведски
terminal Терминал
us Английски (САЩ)

21
data/langs/cs-CZ.txt Normal file
View File

@ -0,0 +1,21 @@
be Belgická
cz Česká
cz+qwerty Česká (QWERTY)
de Německá
dk Dánská
emoji Emoji
es Španělská
fi Finská
fr Francouzská
gr Řecká
it Italská
jp Japonská
jp+kana Japonská (Kana)
no Norská
pl Polská
ru Ruská
se Švédská
terminal Terminál
th Thajská
ua Ukrajinská
us Anglická (USA)

2
data/langs/fa-IR.txt Normal file
View File

@ -0,0 +1,2 @@
emoji ایموجی
terminal ترمینال

18
data/langs/fur-IT.txt Normal file
View File

@ -0,0 +1,18 @@
be Belgjic
br Brasilian
de Todesc
dk Danês
es Spagnûl
fi Finlandês
fr Francês
it+fur Furlan
gr Grêc
it Talian
jp+kana Gjaponês (Kana)
no Norvegjês
pl Polac
ru Rus
se Svedês
terminal Terminâl
ua Ucrain
us American (USA)

19
data/langs/he-IL.txt Normal file
View File

@ -0,0 +1,19 @@
be בלגית
br פורטוגזית (ברזיל)
cz צ'כית
de גרמנית
dk דנית
es ספרדית
emoji אימוג'י
fi פינית
fr צרפתית
gr יוונית
il עברית
it איטלקית
no נורווגית
pl פולנית
ru רוסית
se שוודית
terminal טרמינל
ua אוקראינית
us אנגלית (ארה"ב)

View File

@ -31,11 +31,16 @@ sq_button.wide {
border-color: #3e3a44;
}
sq_button.locked {
sq_button.latched {
background: #ffffff;
color: #2b292f;
}
sq_button.locked {
background: #ffffff;
color: #1c71d8;
}
sq_button.action {
font-size: 0.75em;
}

View File

@ -34,11 +34,16 @@ sq_button.wide {
border-color: @borders; /* #3e3a44; */
}
sq_button.locked {
sq_button.latched {
background: @theme_fg_color; /*#ffffff;*/
color: @theme_bg_color; /*#2b292f;*/
}
sq_button.locked {
background: @theme_fg_color; /*#ffffff;*/
color: mix(@theme_selected_bg_color, @theme_bg_color, 0.4); /*#2b292f;*/
}
sq_button.action {
font-size: 0.75em;
}

221
debian/changelog vendored
View File

@ -1,3 +1,224 @@
squeekboard (1.13.0pureos0~amber0) amber-phone; urgency=medium
[ Dorota Czaplejewicz ]
* layout: Latch keys when clicked twice
* layout: Add stateless view switching
* layout: Plug in stateless view switching
* layout: Remove the little abomination of view change promise
* view: Ąto-unlatching when multiple latching buttons pressed
* renderer: Bring button drawing closer to Rust
* ffi: Eliminate squeek_button and squeek_row
* imservice: Increment serials on receiving done, not sending commit
* input-method: Fix commit/done mixup in protocol text
* CI: fix xheck_tag to be compatible with Amber
* italian: Fix colon
* popover: Fix prematurely deallocated CString
* Rust: Remove unnecessary no_mangle statements to silence warnings
* renderer: Reduce reliance on knowing the transform
* renderer: Split mutable geometry and place it directly in GtkKeyboard
* Revert "moved data/langs/he_IL.txt -> data/langs/he-IL.txt to better conform with existing translations."
* layout: Make it possible to opt out of latching per-key
* renderer: Mark latched buttons differently than locked
* appearance: Colour latched/locked according to design
* docs: Describe view switching
* language-terminal: Place keyboards in a sub-path
* layout selection: Fix emoji and number
* rust: Fix compiler warnings
* layout: Take into account text purpose again
* layouts: Make selection testable
* layouts: Stop assuming that layout name always changes on switch
* Cargo: Version bump
[ J.D. Laub ]
* Add US Dvorak layout (and Colemak wide)
* Add US Dvorak layout (and Colemak wide)
[ Jordi Masip ]
* Catalan keyboard layout
[ Myth ]
* Added hebrew keyboard layout
[ David96 ]
* Add Mod4 (Windows) key
[ Panawat Wong-klaew ]
* Add wide Thai keyboard layout
[ Guido Günther ]
* server-main: Add quit()
* server-main: Properly register to gnome-session (Closes: #274)
[ Kozova1 ]
* Added Hebrew translations for most layouts.
* moved data/langs/he_IL.txt -> data/langs/he-IL.txt to better conform with existing translations.
* Fixed Hebrew layout.
* moved data/langs/he_IL.txt -> data/langs/he-IL.txt to better conform with existing translations.
[ M33 ]
* Revert "Update tests/meson.build"
-- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm> Mon, 12 Apr 2021 10:40:32 +0000
squeekboard (1.12.0pureos0~amber0) amber-phone; urgency=medium
[ Dorota Czaplejewicz ]
* docs: Correct Cargo update instructions
* visibility: Centralize keyboard panel visibility policy and handling
* build: Fix release
* tests: Prefer the env var for finding test layouts
* tests: Explicitly pass source directory to tests
* debian: Build reproducibly
* tests: Allow legacy mode to have much longer tests.
* build: Enable unused warnings in C
* build: Enable wformat to remove warnings about missing wformat
* build: Fail on any C warnings when strict
* data: Made data flow in fallback clearer
* data: Flattened layout fallback function
* layouts: Use base as fallback for alternative layouts
* layouts: Simplify the main flow of source list
* tests: Add some description to the list of tested layouts
* layout_names: Unmess the list of builtin layouts
* dbus: Reset hints if text input missing
* visibility: Stop calling GTK functions from the visibility manager
[ Wannaphong Phatthiyaphaibun ]
* Add thai keyboard
* Update resources.rs
* Update meson.build
* escape " on thai keyboard
[ clonex10100 ]
* Added US Colemak Keyboard Layout
[ Henry-Nicolas Tourneur ]
* d/rules: fix an FTBFS on mips64el with GOT > 64kb
* d/rules: export RUSTFLAGS only on architecture that needs it
* d/rules: export RUSTFLAGS only on architecture that needs it
[ Jiří Stránský ]
* Add Czech keyboard layouts
[ Stefan Grotz ]
* Esperanto keyboard
[ Vladimir ]
* Bulgarian language keyboard layout
[ Vladimir Stoilov ]
* bulgarian add translation and to needed lists
* Fix bulgarian layout size
[ Andreas Rönnquist ]
* no: Use wide button switching between numbers, symbols and base
[ jranaraki ]
* Farsi/Persian keyboard layout
* Farsi/Persian keyboard layout
* Added requirements to resources.rs and meson.build
* Updated the layout to provide more convenient and faster typing experience
-- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm> Sun, 10 Jan 2021 09:43:42 +0000
squeekboard (1.11.1) amber-phone; urgency=medium
[ Mark Müller ]
* keyboard: Fix semicolon in German layout
* keyboard: Move semicolon in German layout to numbers view replacing redundant comma key
[ Dorota Czaplejewicz ]
* imservice: Set up UI according to current needs when it shows up
* UI: Keep visibility factors in a central place
* cargo: Update deps
-- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm> Sat, 21 Nov 2020 11:08:06 +0000
squeekboard (1.11.0) amber-phone; urgency=medium
[ Dorota Czaplejewicz ]
* UI: Delay hiding only when leaving a text field
* ui: Cancel hiding delay when activity requested again
* Update dependencies
[ Fabio Tomat ]
* Update fur-IT.txt fix typo for Spanish
-- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm> Sat, 14 Nov 2020 06:46:28 +0000
squeekboard (1.10.0) amber-phone; urgency=medium
[ Dorota Czaplejewicz ]
* virtual_keyboard: Fix desynced modifiers state
* rust: Fix deprecation warnings
* docs: Tutorial syntax cleanups
* docs: Reorganize tutorial
* build: Error on repeating declarations
* keymap: Generate from symbol map, not layout
* data: Restore testability of action->keysym conversion
* syntax: Let older rustc understand symbolmap's lifetime
* debian: Insert a "breaks" for librem5-base < 24
* keymap: Keep keymap fd management in one place
* vkeyboard: Use a generic slice instead of a vector
* tests: Check for missing return in builtin layouts except emoji
* keymap: Concentrate special handling of BackSpace, which is implicit in Erase action
* keymaps: Use multiple key maps, each within the limit of what Xorg can accept.
* build: Avoid MaybeUninit on older Debian
* tests: Fix bad field access
* cargo: Update dependencies
[ Guido Günther ]
* eekboard-context-service: Return early if schema is unavailable
* treewide: Use new style function definitions
* build: Enable '-Wold-style-definition' '-Wstrict-prototypes'
* build: Enable '-Wunused-function'
* eekboard-context-service: Drop EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE
* keyboard: Fix warning
* layout: Fix warning
* gitlab-ci: Enable --Werror
* eek-keyboard: Don't ignore return value
* build: Enable -Winit-self
* build: Enable -Wformat-security
* build: Enable -Wmaybe-uninitialized
* treewide: Drop redundant declarations
* build: Enable -Wredundant-declarations
* ServerContextService: Drop GObject boilerplate
* build: Enable '-Wformat-nonliteral'
* eekboad-context-service: Drop signal class handler
* eekboard-context-service: Drop docstrings for inexistent functions
* eekboard-context-service: Drop the GObject boilerplate
* eekboard-context-service: Drop private struct
* server-context-service: Consistenty name self argument 'self'
* server-context-service: swap signal arguments
* server-context-service: Don't show keyboard when disabled (Closes: #222)
[ Nazarii Kretovych ]
* Add Ukrainian keyboard layout.
[ Benjamin Schaaf ]
* Fix spelling mistakes in doc/hacking.md
* Expand the development documentation in the readme
* Expand key press detection to the edges of the view's bounding box
* Sort layouts by type before sorting by name
* Fix leak in level_keyboard_new
* Fix leak endlessly adding a resource path to the default theme
* Add settings option to popover
[ Al ]
* proposal for belgian layout (copy of fr)
* alphabetical order for src/resources.rs tests/meson.build
[ Arnaud Ferraris ]
* eek-gtk-keyboard: use virtual resolution to check arrangement kind
* server-context-service: optimize height calculation
* keyboards: add wide French layout
* keyboards: add wide Belgian layout
* keyboards: add wide terminal layout
[ Fabio Tomat ]
* Revert "Add friulian keyboard"
-- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm> Mon, 19 Oct 2020 14:07:01 +0000
squeekboard (1.9.3) amber-phone; urgency=medium
[ Björn Tantau ]

View File

@ -5,6 +5,7 @@ Feed it the first changelog line, and then all available tags.
"""
import re, sys
tag = "v" + re.findall("\\((.*)\\)", input())[0]
version = re.findall("\\((.*)\\)", input())[0]
tag = 'v' + re.findall("([0-9]+\\.[0-9]+\\.[0-9]+).*", version)[0]
if tag not in map(str.strip, sys.stdin.readlines()):
raise Exception("Changelog's current version doesn't have a tag. Push the tag!")

3
debian/control vendored
View File

@ -26,6 +26,7 @@ Build-Depends:
librust-xkbcommon-0.4+wayland-dev (>= 0.4),
libwayland-dev (>= 1.16),
lsb-release,
python3,
rustc,
wayland-protocols (>= 1.14),
Standards-Version: 4.1.3
@ -38,6 +39,8 @@ Depends:
gnome-themes-extra-data,
${shlibs:Depends},
${misc:Depends},
Breaks:
librem5-base (<< 24),
Description: On-screen keyboard for Wayland
Virtual keyboard supporting Wayland, built primarily for the Librem 5 phone.

21
debian/rules vendored
View File

@ -2,6 +2,27 @@
export CARGO_HOME = $(CURDIR)/debian/cargo
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
# the below avoids an FTBFS on mips64el with a GOT > 64kb
DEB_HOST_ARCH := $(shell dpkg-architecture -qDEB_HOST_ARCH)
ifeq ($(DEB_HOST_ARCH),mips64el)
export RUSTFLAGS = -Ctarget-feature=+xgot
endif
# the below avoids an FTBFS on mips64el with a GOT > 64kb
DEB_HOST_ARCH := $(shell dpkg-architecture -qDEB_HOST_ARCH)
ifeq ($(DEB_HOST_ARCH),mips64el)
xgot = -Ctarget-feature=+xgot
else
xgot =
endif
# Don't use paths that may change between builds.
# No need to care about $HOME
# because Cargo will not place any source in ~/.cargo.
# The build directory is a subdirectory of the source directory,
# so it doesn't need to be explicitly taken care of.
export RUSTFLAGS = --remap-path-prefix=$(CURDIR)=/remap-pwd $(xgot)
distrel := $(shell lsb_release --codename --short)
ifneq (,$(filter $(distrel),buster amber))

View File

@ -13,16 +13,16 @@ The overarching principle of *squeekboard* is to empower users.
Software is primarily meant to solve problems of its users. Often in the quest to make software better, a hard distinction is made between the developer, who becomes the creator, and the user, who takes the role of the consumer, without direct influence on the software they use.
This project aims to give users the power to make the software work for them by blurring the lines between users and developers.
Nonwithstanding its current state, *squeekboard* must be structured in a way that provides users a gradual way to gain more experience and power to adjust it. It must be easy, in order of importance:
Notwithstanding its current state, *squeekboard* must be structured in a way that provides users a gradual way to gain more experience and power to adjust it. It must be easy, in order of importance:
- to use the software,
- to modify its resources,
- to change its behaviour,
- to change its behavior,
- to contribute upstream.
To give an idea of what it means in practice, those are some examples of what has been important for *squeekboard* so far:
- being quick and useable,
- being quick and usable,
- allowing local overrides of resources and config,
- storing resources and config as editable, standard files,
- having complete, up to date documentation of interfaces,
@ -33,7 +33,7 @@ To give an idea of what it means in practice, those are some examples of what ha
- having code that is [simple and obvious](https://www.python.org/dev/peps/pep-0020/),
- having an easy process of testing and accepting contributions.
You may notice that they are ordered roughly from "user-focused" to "maintainer-focused". While good properties are desired, sometimes they conflict, and maintainers should give additional weight to those benefitting the user compared to those benefitting regular contributors.
You may notice that they are ordered roughly from "user-focused" to "maintainer-focused". While good properties are desired, sometimes they conflict, and maintainers should give additional weight to those benefiting the user compared to those benefiting regular contributors.
Sending patches
---------------
@ -43,7 +43,7 @@ By submitting a change to this project, you agree to license it under the [GPL l
Development environment
-----------------------
*Squeekboard* is regularly built and tested on [the develpment environment](https://developer.puri.sm/Librem5/Development_Environment.html).
*Squeekboard* is regularly built and tested on [the development environment](https://developer.puri.sm/Librem5/Development_Environment.html).
Recent Fedora releases are likely to be tested as well.
@ -113,7 +113,7 @@ User interface modules should:
Code submitted should roughly match the style of surrounding code. Things that will *not* be accepted are ones that often lead to errors:
- skipping brackets `{}` after every `if()`, `else`, and similar
- skipping brackets `{}` after every `if()`, `else`, and similar ([SCI CERT C: EXP19-C](https://wiki.sei.cmu.edu/confluence/display/c/EXP19-C.+Use+braces+for+the+body+of+an+if%2C+for%2C+or+while+statement))
Bad example:
@ -162,7 +162,7 @@ Maintenance
Squeekboard uses Rust & Cargo for some of its dependencies.
Use the `cargo.sh` script for maintaining the Cargo part of the build. The script takes the usual Cargo commands, after the first 2 positionsl arguments: source directory, and output artifact. So, `cargo test` becomes:
Use the `cargo.sh` script for maintaining the Cargo part of the build. The script takes the usual Cargo commands, after the first 2 positional arguments: source directory, and output artifact. So, `cargo test` becomes:
```
cd build_dir
@ -179,7 +179,10 @@ Dependencies must be specified in `Cargo.toml` with 2 numbers: "major.minor". Si
```
cd build_dir
ninja build src/Cargo.toml
ninja ./Cargo.toml
sh /source_path/cargo.sh update
ninja test
cp ./Cargo.lock /source_path/
```
Since version 1.9.3, `Cargo.lock` is not actually used by the build system, due to `Cargo.toml` being generated at every build.

View File

@ -6,6 +6,7 @@ Contents
* [Tutorial](tutorial.md)
* [Contributing](hacking.md)
* [Switching views](views.md)
Introduction
------------
@ -21,6 +22,8 @@ Layouts are created using a text-based format, based on YAML.
TODO: Provide a description of the format.
Squeekboard layouts are separated into *views* and use a *room metaphor* to [switch views](views.md).
Contributions
-------------

594
doc/latching.svg Normal file
View File

@ -0,0 +1,594 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="177.92439mm"
height="88.144363mm"
viewBox="0 0 177.92439 88.144364"
version="1.1"
id="svg8"
sodipodi:docname="latching.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<defs
id="defs2">
<marker
style="overflow:visible"
id="Arrow1Lend"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Mend"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Mend"
inkscape:isstock="true">
<path
transform="matrix(-0.4,0,0,-0.4,-4,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1098" />
</marker>
<marker
style="overflow:visible"
id="Arrow2Sstart"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Sstart"
inkscape:isstock="true">
<path
transform="matrix(0.3,0,0,0.3,-0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path1119" />
</marker>
<marker
style="overflow:visible"
id="Arrow2Mstart"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mstart"
inkscape:isstock="true">
<path
transform="scale(0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path1113" />
</marker>
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-5" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect848" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-1" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect848-1" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-9" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect848-8" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-10" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect916" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-4" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect951" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-10-1" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect986" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-2" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect1061" />
<marker
style="overflow:visible"
id="Arrow1Lend-5"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#00ad12;fill-opacity:1;fill-rule:evenodd;stroke:#00ad12;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-7" />
</marker>
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-2-1" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect1549" />
<marker
style="overflow:visible"
id="Arrow1Lend-8"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#101010;fill-opacity:1;fill-rule:evenodd;stroke:#101010;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-8" />
</marker>
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-2-3" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect1845" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-2-38" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect1960" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-2-3-9" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect2304" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-2-3-4" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect2304-7" />
<marker
style="overflow:visible"
id="Arrow1Lend-2"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:#6c6c6c;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-89" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Lend-2-6"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#00ad12;fill-opacity:1;fill-rule:evenodd;stroke:#00ad12;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-89-8" />
</marker>
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-21" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect2574" />
<marker
style="overflow:visible"
id="Arrow1Lend-2-6-1"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#00ad12;fill-opacity:1;fill-rule:evenodd;stroke:#00ad12;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-89-8-0" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Lend-2-6-6"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#00ad12;fill-opacity:1;fill-rule:evenodd;stroke:#00ad12;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-89-8-2" />
</marker>
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-10-1-8" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect3021" />
<marker
style="overflow:visible"
id="Arrow1Lend-8-3"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#101010;fill-opacity:1;fill-rule:evenodd;stroke:#101010;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-8-5" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.3358025"
inkscape:cx="212.63846"
inkscape:cy="105.21093"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
fit-margin-top="4"
fit-margin-left="4"
fit-margin-right="4"
fit-margin-bottom="4"
lock-margins="true"
inkscape:window-width="1298"
inkscape:window-height="708"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-72.097892,-53.326191)">
<path
style="fill:none;fill-rule:evenodd;stroke:#101010;stroke-width:0.264999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend-8-3)"
d="m 134.9616,86.141869 c 17.5759,-11.622767 35.93283,0 35.93283,0"
id="path1087-1-6" />
<g
id="g2948">
<circle
style="color:#000000;overflow:visible;fill:#ffffff;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path1065-6"
cx="129.67093"
cy="92.793152"
r="7.8844509" />
<text
xml:space="preserve"
id="text833-0"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-10);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(46.071199,-1.2662626)"><tspan
x="80.886719"
y="96.225952"><tspan>A</tspan></tspan></text>
</g>
<rect
style="color:#000000;overflow:visible;fill:#f8f8f8;fill-opacity:1;stroke:#000000;stroke-width:0.555679;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect2066"
width="1.4562259"
height="10.90563"
x="81.767418"
y="75.519585"
ry="0.9693895" />
<g
id="g905"
transform="translate(0,-0.85044703)">
<circle
style="color:#000000;overflow:visible;fill:#ffffff;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path1065"
cx="83.154755"
cy="93.6436"
r="7.8844509" />
<text
xml:space="preserve"
id="text833"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none">a</tspan></tspan></text>
</g>
<g
id="g905-3-7"
transform="translate(92.82116,-0.85044861)">
<circle
style="color:#000000;overflow:visible;fill:#ffffff;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path1065-6-7"
cx="83.557831"
cy="93.6436"
r="7.8844509" />
<text
xml:space="preserve"
id="text833-0-5"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-10-1);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan>Ą</tspan></tspan></text>
</g>
<g
id="g905-1"
transform="translate(68.838914,-17.67039)">
<rect
style="color:#000000;overflow:visible;fill:#e2e2e2;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-8"
width="10.583333"
height="13.79613"
x="78.878532"
y="85.920006"
ry="1.937705" />
<text
xml:space="preserve"
id="text833-7"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-2);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.2686286,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan> ̨̂ ̈</tspan></tspan></text>
</g>
<path
style="fill:none;fill-rule:evenodd;stroke:#101010;stroke-width:0.264999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend-8)"
d="m 88.446425,85.89509 c 17.575895,-11.622767 35.932835,0 35.932835,0"
id="path1087-1" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:monospace;-inkscape-font-specification:monospace;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="99.186691"
y="66.221436"
id="text1035-89"><tspan
sodipodi:role="line"
id="tspan1033-6"
x="99.186691"
y="66.221436"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">locking</tspan></text>
<g
id="g905-1-4"
transform="translate(22.423434,-17.67039)">
<rect
style="color:#000000;overflow:visible;fill:#e2e2e2;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-8-3"
width="10.583333"
height="13.79613"
x="78.878532"
y="85.920006"
ry="1.937705" />
<text
xml:space="preserve"
id="text833-7-3"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-2-3);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan></tspan></tspan></text>
</g>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.5, 0.5;stroke-dashoffset:0;stroke-opacity:1"
d="m 83.251484,76.550079 c -0.31498,0 -0.944941,-0.314981 -0.944941,0 0,0.31498 0.770221,0.262079 0.944941,0 0.212555,-0.318834 0.08197,-0.862973 -0.188988,-1.133929 -0.132651,-0.13265 -1.931144,0.354037 -2.078869,0.944941 -0.108038,0.432149 0.877467,-0.188989 1.322916,-0.188989 0.339244,0 0.626121,0.262042 0.944941,0.377977 0.374434,0.136158 0.777569,0.199796 1.133928,0.377976 0.113894,0.05695 -0.0037,0.439732 0.944941,0.755952 0.544156,0.181385 1.78847,0.275251 2.267857,0.377976 0.448438,0.09609 0.881944,0.251984 1.322917,0.377977 0.063,0.188988 0.388199,0.566964 0.188988,0.566964 -0.195153,0 -0.745291,-0.93961 0,-0.566964 0.281726,0.140863 0.485859,0.404908 0.755952,0.566964 1.460327,0.876196 3.039871,1.714659 4.346726,2.834821 0.966187,0.828161 1.495207,2.006597 2.645833,2.645834 2.876101,1.597834 5.000414,0.287454 7.370534,1.133929 0.4783,0.170821 0.85136,0.567325 1.32292,0.755952 1.8557,0.74228 0.94424,0.230907 2.26785,0.377976 1.47287,0.16365 2.67387,1.06159 4.15774,0.566965 1.22233,-0.407443 3.2674,-1.377519 4.15774,-2.267858 0.39842,-0.398422 0.42845,-1.053404 0.75595,-1.511905 0.50136,-0.70189 1.27041,-1.107171 1.7009,-1.889881 2.28615,-4.156632 0.41931,-1.931216 3.2128,-4.724702 0.18898,-0.188988 0.33491,-0.434362 0.56696,-0.566964 0.864,-0.493714 5.11938,-0.281812 6.04762,-0.188989 0.34449,0.03445 3.71968,0.978261 3.96875,1.133929 0.35339,0.220868 1.41179,1.650838 1.88988,1.889881 0.80324,0.40162 2.22057,0.354332 3.02381,0.755952 1.24832,0.624162 -0.45041,0.669376 -0.18899,1.322917 0.1193,0.298244 0.64418,0.0762 0.94494,0.188988 0.28702,0.107634 1.48279,1.113549 1.5119,1.133929 2.56034,1.792236 -0.96522,-0.855663 2.26786,1.133928 1.61516,0.993946 2.82802,2.547938 4.53572,3.401785 2.03418,1.017093 4.38487,-0.122885 6.42559,-0.377975 1.6791,-0.209886 3.23813,0.06137 4.91369,-0.566965 0.50424,-0.18909 1.82709,-1.701063 2.26786,-2.078869 0.45926,-0.393653 1.0853,-0.707329 1.5119,-1.133928 0.81561,-0.815609 1.44764,-1.826091 2.45685,-2.456845 0.28768,-0.179799 0.65726,-0.198178 0.94494,-0.377977 0.28791,-0.179945 0.60349,-0.774216 0.94494,-0.94494 0.23232,-0.116159 0.51479,-0.09252 0.75595,-0.188988 0.21089,-0.08436 0.33983,-0.377976 0.56697,-0.377976 0.14086,0 0.23711,0.188988 0.37797,0.188988 0.0891,0 0.126,-0.125992 0.18899,-0.188988 0.18899,-0.063 0.36976,-0.217161 0.56696,-0.188988 0.77174,0.110248 1.92711,0.94494 3.02381,0.94494 0.16785,0 0.94189,-0.862638 1.13393,-0.94494 0.19546,-0.08377 1.57981,-0.364523 1.7009,-0.377977 0.72233,-0.08026 2.11645,0.340388 2.64583,-0.188988"
id="path2010" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;line-height:125%;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="73.802078"
y="72.354546"
id="text2091"><tspan
sodipodi:role="line"
id="tspan2089"
x="73.802078"
y="72.354546"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">SAVED</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;line-height:125%;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="164.55956"
y="72.354546"
id="text2091-8"><tspan
sodipodi:role="line"
id="tspan2089-8"
x="164.55956"
y="72.354546"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">CURRENT</tspan><tspan
sodipodi:role="line"
x="164.55956"
y="79.410095"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
id="tspan3432" /></text>
<g
id="g2259"
transform="matrix(1.0856157,0,0,0.94777147,-19.677062,6.4360598)">
<path
id="rect2111-9"
style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 179.53502,72.72924 h 5.84717 l -1.37074,1.931346 h -3.04292 z"
sodipodi:nodetypes="ccccc" />
<path
id="rect2111-9-0"
style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 179.4049,80.846668 h 5.84717 l -1.23711,-1.931347 h -3.17655 z"
sodipodi:nodetypes="ccccc" />
<g
id="g2247"
transform="translate(-0.04032786,-0.04319387)">
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,75.343053 2.96688,-0.19452"
id="path2145"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,76.112065 2.96688,-0.19452"
id="path2145-3"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,76.881078 2.96688,-0.19452"
id="path2145-0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,77.65009 2.96688,-0.19452"
id="path2145-2"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,78.419102 2.96688,-0.19452"
id="path2145-4"
sodipodi:nodetypes="cc" />
</g>
</g>
<g
id="g905-0"
transform="translate(157.32586,-0.83970203)" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:monospace;-inkscape-font-specification:monospace;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="145.70187"
y="66.221436"
id="text1035-89-2"><tspan
sodipodi:role="line"
id="tspan1033-6-9"
x="145.70187"
y="66.221436"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">locking</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 26 KiB

631
doc/latching_return.svg Normal file
View File

@ -0,0 +1,631 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="169.9455mm"
height="98.072433mm"
viewBox="0 0 169.94549 98.072434"
version="1.1"
id="svg8"
sodipodi:docname="latching_return.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<defs
id="defs2">
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-10-1" />
<marker
style="overflow:visible"
id="Arrow1Lend-5"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-7" />
</marker>
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-2-38" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-2-3-9" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-2-3-4" />
<marker
style="overflow:visible"
id="Arrow1Lend-2-6"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-89-8" />
</marker>
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-21" />
<marker
style="overflow:visible"
id="Arrow1Lend-2-6-1"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-89-8-0" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Lend-2-6-6"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-89-8-2" />
</marker>
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-10-1-8" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-12" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-10-7" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.94455498"
inkscape:cx="314.8465"
inkscape:cy="213.42055"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
fit-margin-top="4"
fit-margin-left="4"
fit-margin-right="4"
fit-margin-bottom="4"
lock-margins="true"
inkscape:window-width="1298"
inkscape:window-height="708"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
showguides="false" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-70.551731,-46.47634)">
<g
id="g3858"
transform="translate(1.354821,1.4005714)">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="204.75821"
y="130.07979"
id="text2293-4"><tspan
sodipodi:role="line"
id="tspan2291-1"
x="204.75821"
y="130.07979"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"></tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.5861px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="194.54915"
y="128.70164"
id="text2293-0-5-8"><tspan
sodipodi:role="line"
id="tspan2291-6-7-5"
x="194.54915"
y="128.70164"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.5861px;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">cuts</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.05833, 0.529167;stroke-dashoffset:0;stroke-opacity:1"
d="m 210.34971,123.9389 c 0.0233,0.14006 0.07,0.27818 0.07,0.42017 0,0.0738 -0.07,0.13627 -0.07,0.21009 0,0.11902 0.0582,0.23171 0.07,0.35014 0.049,0.49035 0.0857,0.98109 0.14006,1.4706 0.018,0.1624 -0.0269,0.32902 0,0.4902 0.0435,0.26077 0.11166,0.3369 0,0.56023 -0.0209,0.0418 0.033,0.10705 0,0.14006 -0.0369,0.0369 -0.10315,0.0331 -0.14006,0.07"
id="path3816-9" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.05833, 0.529167;stroke-dashoffset:0;stroke-opacity:1"
d="m 209.9819,128.43627 c -0.12445,0.48957 -0.1295,0.98859 -0.0743,1.48553 0.0118,0.10583 0.01,0.21643 0.0248,0.32186 -0.002,0.0627 0.0396,0.11405 0.0495,0.17332 0.0144,0.0866 -0.0193,0.077 0,0.17331 0.0124,0.0621 0.20619,0.18971 0.24759,0.22283"
id="path3820-7" />
</g>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#Arrow1Lend-2-6-1)"
d="m 180.7405,85.345284 c 21.77006,-11.52723 44.50758,0 44.50758,0"
id="path1087-3-0-8" />
<rect
style="color:#000000;overflow:visible;fill:#f8f8f8;fill-opacity:1;stroke:#000000;stroke-width:0.555679;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect2066"
width="1.4562259"
height="10.90563"
x="81.767418"
y="75.519585"
ry="0.9693895" />
<g
id="g905-3-7"
transform="translate(92.629263,-0.8504468)">
<text
xml:space="preserve"
id="text833-0-5"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-10-1);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan>Ą</tspan></tspan></text>
<rect
style="color:#000000;overflow:visible;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-4-9"
width="10.583333"
height="13.79613"
x="78.266167"
y="86.745537"
ry="1.937705" />
</g>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:0.4em;font-family:monospace;-inkscape-font-specification:monospace;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="174.86499"
y="130.79413"
id="text1035-8"><tspan
sodipodi:role="line"
x="174.86499"
y="130.79413"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
id="tspan2277">locking</tspan><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
sodipodi:role="line"
x="174.86499"
y="135.11462"
id="tspan1606" /></text>
<g
id="g905-1-6"
transform="translate(90.668095,26.90725)">
<rect
style="color:#000000;overflow:visible;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-8-0"
width="10.583333"
height="13.79613"
x="78.878532"
y="85.920006"
ry="1.937705" />
<text
xml:space="preserve"
id="text833-7-4"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-2-38);fill:#f8f8f8;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.2686286,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan
style="fill:#f8f8f8;fill-opacity:1"> ̨̂ ̈</tspan></tspan></text>
</g>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.5, 0.5;stroke-dashoffset:0;stroke-opacity:1"
d="m 83.251484,76.550079 c -0.31498,0 -0.944941,-0.314981 -0.944941,0 0,0.31498 0.770221,0.262079 0.944941,0 0.212555,-0.318834 0.08197,-0.862973 -0.188988,-1.133929 -0.132651,-0.13265 -1.931144,0.354037 -2.078869,0.944941 -0.108038,0.432149 0.877467,-0.188989 1.322916,-0.188989 0.339244,0 0.626121,0.262042 0.944941,0.377977 0.374434,0.136158 0.777569,0.199796 1.133928,0.377976 0.113894,0.05695 -0.0037,0.439732 0.944941,0.755952 0.544156,0.181385 1.78847,0.275251 2.267857,0.377976 0.448438,0.09609 0.881944,0.251984 1.322917,0.377977 0.063,0.188988 0.388199,0.566964 0.188988,0.566964 -0.195153,0 -0.745291,-0.93961 0,-0.566964 0.281726,0.140863 0.485859,0.404908 0.755952,0.566964 1.460327,0.876196 3.039871,1.714659 4.346726,2.834821 0.966187,0.828161 1.495207,2.006597 2.645833,2.645834 2.876101,1.597834 5.000414,0.287454 7.370534,1.133929 0.4783,0.170821 0.85136,0.567325 1.32292,0.755952 1.8557,0.74228 0.94424,0.230907 2.26785,0.377976 1.47287,0.16365 2.67387,1.06159 4.15774,0.566965 1.22233,-0.407443 3.2674,-1.377519 4.15774,-2.267858 0.39842,-0.398422 0.42845,-1.053404 0.75595,-1.511905 0.50136,-0.70189 1.27041,-1.107171 1.7009,-1.889881 2.28615,-4.156632 0.41931,-1.931216 3.2128,-4.724702 0.18898,-0.188988 0.33491,-0.434362 0.56696,-0.566964 0.864,-0.493714 5.11938,-0.281812 6.04762,-0.188989 0.34449,0.03445 3.71968,0.978261 3.96875,1.133929 0.35339,0.220868 1.41179,1.650838 1.88988,1.889881 0.80324,0.40162 2.22057,0.354332 3.02381,0.755952 1.24832,0.624162 -0.45041,0.669376 -0.18899,1.322917 0.1193,0.298244 0.64418,0.0762 0.94494,0.188988 0.28702,0.107634 1.48279,1.113549 1.5119,1.133929 2.56034,1.792236 -0.96522,-0.855663 2.26786,1.133928 1.61516,0.993946 2.82802,2.547938 4.53572,3.401785 2.03418,1.017093 4.38487,-0.122885 6.42559,-0.377975 1.6791,-0.209886 3.23813,0.06137 4.91369,-0.566965 0.50424,-0.18909 1.82709,-1.701063 2.26786,-2.078869 0.45926,-0.393653 1.0853,-0.707329 1.5119,-1.133928 0.81561,-0.815609 1.44764,-1.826091 2.45685,-2.456845 0.28768,-0.179799 0.65726,-0.198178 0.94494,-0.377977 0.28791,-0.179945 0.60349,-0.774216 0.94494,-0.94494 0.23232,-0.116159 0.51479,-0.09252 0.75595,-0.188988 0.21089,-0.08436 0.33983,-0.377976 0.56697,-0.377976 0.14086,0 0.23711,0.188988 0.37797,0.188988 0.0891,0 0.126,-0.125992 0.18899,-0.188988 0.18899,-0.063 0.36976,-0.217161 0.56696,-0.188988 0.77174,0.110248 1.92711,0.94494 3.02381,0.94494 0.16785,0 0.94189,-0.862638 1.13393,-0.94494 0.19546,-0.08377 1.57981,-0.364523 1.7009,-0.377977 0.72233,-0.08026 2.11645,0.340388 2.64583,-0.188988"
id="path2010" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;line-height:125%;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="74.331245"
y="71.825378"
id="text2091"><tspan
sodipodi:role="line"
id="tspan2089"
x="74.331245"
y="71.825378"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">SAVED</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;line-height:125%;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="164.23172"
y="70.186089"
id="text2091-8"><tspan
sodipodi:role="line"
id="tspan2089-8"
x="164.23172"
y="70.186089"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">CURRENT</tspan><tspan
sodipodi:role="line"
x="164.23172"
y="77.241638"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;font-family:'Abyssinica SIL';-inkscape-font-specification:'Abyssinica SIL';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
id="tspan3432" /></text>
<g
id="g2259"
transform="matrix(1.0856157,0,0,0.94777147,-20.206229,4.319393)">
<path
id="rect2111-9"
style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 179.53502,72.72924 h 5.84717 l -1.37074,1.931346 h -3.04292 z"
sodipodi:nodetypes="ccccc" />
<path
id="rect2111-9-0"
style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 179.4049,80.846668 h 5.84717 l -1.23711,-1.931347 h -3.17655 z"
sodipodi:nodetypes="ccccc" />
<g
id="g2247"
transform="translate(-0.04032786,-0.04319387)">
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,75.343053 2.96688,-0.19452"
id="path2145"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,76.112065 2.96688,-0.19452"
id="path2145-3"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,76.881078 2.96688,-0.19452"
id="path2145-0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,77.65009 2.96688,-0.19452"
id="path2145-2"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,78.419102 2.96688,-0.19452"
id="path2145-4"
sodipodi:nodetypes="cc" />
</g>
</g>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#Arrow1Lend-5)"
d="m 173.01207,99.691217 c 0,0 -8.37295,13.367043 -0.26038,13.813423 9.36786,0.51544 7.89797,-9.16673 6.50059,-13.41252"
id="path2269"
sodipodi:nodetypes="csc" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="176.93353"
y="138.21815"
id="text2293"><tspan
sodipodi:role="line"
id="tspan2291"
x="176.93353"
y="138.21815"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"></tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#Arrow1Lend-2-6)"
d="m 181.46685,99.71436 c 21.61425,11.51564 44.18902,0 44.18902,0"
id="path1087-3-0" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:monospace;-inkscape-font-specification:monospace;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="195.7271"
y="122.96945"
id="text1035-89-7"><tspan
sodipodi:role="line"
id="tspan1033-6-5"
x="195.7271"
y="122.96945"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">set_view</tspan></text>
<g
id="g905-1-4-4"
transform="translate(120.23594,18.477932)">
<rect
style="color:#000000;overflow:visible;fill:#e2e2e2;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-8-3-8"
width="10.583333"
height="13.79613"
x="78.878532"
y="85.920006"
ry="1.937705" />
<text
xml:space="preserve"
id="text833-7-3-1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-2-3-4);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan></tspan></tspan></text>
</g>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:0.36em;font-family:monospace;-inkscape-font-specification:monospace;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="196.99921"
y="61.359337"
id="text1035-89-4"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
sodipodi:role="line"
id="tspan3987"
x="196.99921"
y="61.359337">locking</tspan><tspan
sodipodi:role="line"
x="196.99921"
y="65.362335"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
id="tspan3985">pops: false</tspan></text>
<g
id="g905-1-4-9"
transform="translate(120.23594,-18.828317)">
<rect
style="color:#000000;overflow:visible;fill:#e2e2e2;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-8-3-2"
width="10.583333"
height="13.79613"
x="78.878532"
y="85.920006"
ry="1.937705" />
<text
xml:space="preserve"
id="text833-7-3-2"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-2-3-9);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan></tspan></tspan></text>
</g>
<g
id="g905-0"
transform="translate(147.8008,-0.83970203)">
<rect
style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-5"
width="10.583333"
height="13.79613"
x="77.863091"
y="86.745537"
ry="1.937705" />
<text
xml:space="preserve"
id="text833-1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-21);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan>ą</tspan></tspan></text>
</g>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#Arrow1Lend-2-6-6)"
d="m 170.49256,99.691217 c -49.40563,31.667983 -82.046134,0 -82.046134,0"
id="path1087-3-0-5"
sodipodi:nodetypes="cc" />
<g
id="g905-3-7-6"
transform="translate(45.925334,26.134402)">
<rect
style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-4-9-8"
width="10.583333"
height="13.79613"
x="78.266167"
y="86.745537"
ry="1.937705" />
<text
xml:space="preserve"
id="text833-0-5-2"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-10-1-8);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan>Ą</tspan></tspan></text>
</g>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:0.4em;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="129.60217"
y="131.30838"
id="text1035-8-4"><tspan
sodipodi:role="line"
x="129.60217"
y="131.30838"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
id="tspan2277-2">text</tspan><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
sodipodi:role="line"
x="129.60217"
y="135.62888"
id="tspan1606-4" /></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.58611px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="123.67847"
y="136.8163"
id="text2293-0"><tspan
sodipodi:role="line"
id="tspan2291-6"
x="123.67847"
y="136.8163"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.58611px;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">returns</tspan></text>
<g
id="g905"
transform="translate(1.1299757e-7,-0.85044747)">
<circle
style="color:#000000;overflow:visible;fill:#ffffff;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path1065"
cx="83.154755"
cy="93.6436"
r="7.8844509" />
<text
xml:space="preserve"
id="text833"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-12);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none">a</tspan></tspan></text>
</g>
<g
id="g2948">
<circle
style="color:#000000;overflow:visible;fill:#ffffff;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path1065-6"
cx="129.67093"
cy="92.793152"
r="7.8844509" />
<text
xml:space="preserve"
id="text833-0"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-10-7);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(46.071199,-1.2662626)"><tspan
x="80.886719"
y="96.225952"><tspan>A</tspan></tspan></text>
</g>
<g
id="g2259-3"
transform="matrix(0.61171471,0,0,0.53404326,8.8050741,94.418409)">
<path
id="rect2111-9-1"
style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 179.53502,72.72924 h 5.84717 l -1.37074,1.931346 h -3.04292 z"
sodipodi:nodetypes="ccccc" />
<path
id="rect2111-9-0-7"
style="color:#000000;overflow:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 179.4049,80.846668 h 5.84717 l -1.23711,-1.931347 h -3.17655 z"
sodipodi:nodetypes="ccccc" />
<g
id="g2247-5"
transform="translate(-0.04032786,-0.04319387)">
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,75.343053 2.96688,-0.19452"
id="path2145-9"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,76.112065 2.96688,-0.19452"
id="path2145-3-6"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,76.881078 2.96688,-0.19452"
id="path2145-0-2"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,77.65009 2.96688,-0.19452"
id="path2145-2-1"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.363778;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 181.02302,78.419102 2.96688,-0.19452"
id="path2145-4-7"
sodipodi:nodetypes="cc" />
</g>
</g>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.265;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.06, 0.53;stroke-dashoffset:0;stroke-opacity:1"
d="m 119.51485,135.86385 c -0.50656,0.62998 -2.26796,0.26701 -2.85105,0.85011 -0.52314,0.52314 2.02401,2.4426 3.96141,3.16913 2.94083,1.1028 4.79827,0.22 7.72476,-0.19807 0.3268,-0.0467 0.66473,0.0543 0.99035,0 1.72749,-0.28792 3.39512,-0.79539 5.14984,-0.99036 1.10207,-0.12245 0.49735,0.0622 1.58457,0.19807 0.91825,0.11479 1.8542,0.0832 2.77299,0.19807 0.86919,0.10865 1.70964,-0.19807 2.57492,-0.19807"
id="path3796" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.5861px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="166.72447"
y="136.84001"
id="text2293-0-5"><tspan
sodipodi:role="line"
id="tspan2291-6-7"
x="166.72447"
y="136.84001"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.5861px;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">cuts</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.05833, 0.529166;stroke-dashoffset:0;stroke-opacity:1"
d="m 182.52503,132.07727 c 0.0233,0.14006 0.07,0.27818 0.07,0.42017 0,0.0738 -0.07,0.13627 -0.07,0.21009 0,0.11902 0.0582,0.23171 0.07,0.35014 0.049,0.49035 0.0857,0.98109 0.14006,1.4706 0.018,0.1624 -0.0269,0.32902 0,0.4902 0.0435,0.26077 0.11166,0.3369 0,0.56023 -0.0209,0.0418 0.033,0.10705 0,0.14006 -0.0369,0.0369 -0.10315,0.0331 -0.14006,0.07"
id="path3816" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.05833, 0.529166;stroke-dashoffset:0;stroke-opacity:1"
d="m 182.15722,136.57464 c -0.12445,0.48957 -0.1295,0.98859 -0.0743,1.48553 0.0118,0.10583 0.01,0.21643 0.0248,0.32186 -0.002,0.0627 0.0396,0.11405 0.0495,0.17332 0.0144,0.0866 -0.0193,0.077 0,0.17331 0.0124,0.0621 0.20619,0.18971 0.24759,0.22283"
id="path3820" />
<g
id="g3858-9"
transform="translate(1.354821,-73.436839)">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="204.75821"
y="130.07979"
id="text2293-4-6"><tspan
sodipodi:role="line"
id="tspan2291-1-4"
x="204.75821"
y="130.07979"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"></tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.5861px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="194.54915"
y="128.70164"
id="text2293-0-5-8-3"><tspan
sodipodi:role="line"
id="tspan2291-6-7-5-3"
x="194.54915"
y="128.70164"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.5861px;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">cuts</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.05833, 0.529167;stroke-dashoffset:0;stroke-opacity:1"
d="m 210.34971,123.9389 c 0.0233,0.14006 0.07,0.27818 0.07,0.42017 0,0.0738 -0.07,0.13627 -0.07,0.21009 0,0.11902 0.0582,0.23171 0.07,0.35014 0.049,0.49035 0.0857,0.98109 0.14006,1.4706 0.018,0.1624 -0.0269,0.32902 0,0.4902 0.0435,0.26077 0.11166,0.3369 0,0.56023 -0.0209,0.0418 0.033,0.10705 0,0.14006 -0.0369,0.0369 -0.10315,0.0331 -0.14006,0.07"
id="path3816-9-3" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.05833, 0.529167;stroke-dashoffset:0;stroke-opacity:1"
d="m 209.9819,128.43627 c -0.12445,0.48957 -0.1295,0.98859 -0.0743,1.48553 0.0118,0.10583 0.01,0.21643 0.0248,0.32186 -0.002,0.0627 0.0396,0.11405 0.0495,0.17332 0.0144,0.0866 -0.0193,0.077 0,0.17331 0.0124,0.0621 0.20619,0.18971 0.24759,0.22283"
id="path3820-7-8" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 39 KiB

386
doc/switching.svg Normal file
View File

@ -0,0 +1,386 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="70.905495mm"
height="78.260262mm"
viewBox="0 0 70.905494 78.260262"
version="1.1"
id="svg8"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
sodipodi:docname="switching.svg">
<defs
id="defs2">
<marker
style="overflow:visible"
id="Arrow1Lend"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Mend"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Mend"
inkscape:isstock="true">
<path
transform="matrix(-0.4,0,0,-0.4,-4,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1098" />
</marker>
<marker
style="overflow:visible"
id="Arrow2Sstart"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Sstart"
inkscape:isstock="true">
<path
transform="matrix(0.3,0,0,0.3,-0.69,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path1119" />
</marker>
<marker
style="overflow:visible"
id="Arrow2Mstart"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mstart"
inkscape:isstock="true">
<path
transform="scale(0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path1113" />
</marker>
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-5" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect848" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-1" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect848-1" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-9" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect848-8" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-10" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect916" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-4" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect951" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-10-1" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect986" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-2" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect1061" />
<marker
style="overflow:visible"
id="Arrow1Lend-5"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1092-7" />
</marker>
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect835-2-1" />
<rect
x="80.886902"
y="89.202377"
width="18.898809"
height="20.410713"
id="rect1549" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.98994949"
inkscape:cx="136.49044"
inkscape:cy="110.83537"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
fit-margin-top="4"
fit-margin-left="4"
fit-margin-right="4"
fit-margin-bottom="4"
lock-margins="true"
inkscape:window-width="1298"
inkscape:window-height="708"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-70.899889,-58.974186)">
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.265;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend)"
d="m 88.446426,85.895089 c 17.575894,-11.622767 35.932844,0 35.932844,0"
id="path1087" />
<g
id="g905"
transform="translate(0,-0.85044703)">
<circle
style="color:#000000;overflow:visible;fill:#ffffff;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path1065"
cx="83.03434"
cy="93.834679"
r="7.8844509" />
<text
xml:space="preserve"
id="text833"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.16231537,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke:none">a</tspan></tspan></text>
</g>
<g
id="g905-3"
transform="translate(46.113101,-0.85044703)">
<circle
style="color:#000000;overflow:visible;fill:#ffffff;stroke:#000000;stroke-width:0.499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path1065-3"
cx="83.557831"
cy="93.366959"
r="7.8844509" />
<text
xml:space="preserve"
id="text833-0"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-10);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan>A</tspan></tspan></text>
</g>
<g
id="g905-7"
transform="translate(-0.94494048,73.232887)">
<text
xml:space="preserve"
id="text833-6"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-4);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan>ą</tspan></tspan></text>
<rect
style="color:#000000;overflow:visible;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-3"
width="10.583333"
height="13.79613"
x="77.863091"
y="86.745537"
ry="1.937705" />
</g>
<g
id="g905-3-7"
transform="translate(49.136911,68.319196)">
<text
xml:space="preserve"
id="text833-0-5"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-10-1);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan>Ą</tspan></tspan></text>
<rect
style="color:#000000;overflow:visible;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-4-9"
width="10.583333"
height="13.79613"
x="78.266167"
y="86.745537"
ry="1.937705" />
</g>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="90.548096"
y="65.654472"
id="text1035"><tspan
sodipodi:role="line"
id="tspan1033"
x="90.548096"
y="65.654472"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52778px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">set_view: upper</tspan></text>
<g
id="g905-1"
transform="translate(22.423437,-17.670388)">
<rect
style="color:#000000;overflow:visible;fill:#e2e2e2;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-8"
width="10.583333"
height="13.79613"
x="78.878532"
y="85.920006"
ry="1.937705" />
<text
xml:space="preserve"
id="text833-7"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-2);fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan></tspan></tspan></text>
</g>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend-5)"
d="m 124.74085,99.691217 c -17.5759,11.622773 -35.932849,0 -35.932849,0"
id="path1087-4" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:0.4em;font-family:monospace;-inkscape-font-specification:monospace;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="91.116165"
y="123.76147"
id="text1035-8"><tspan
sodipodi:role="line"
id="tspan1033-5"
x="91.116165"
y="123.76147"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px">locking</tspan><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
sodipodi:role="line"
id="tspan1604"
x="91.116165"
y="128.08197">lock_view: upper</tspan><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777px;font-family:monospace;-inkscape-font-specification:monospace;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px"
sodipodi:role="line"
x="91.116165"
y="132.40247"
id="tspan1606">unlock_view: lower</tspan></text>
<g
id="g905-1-9"
transform="translate(22.423437,17.64464)">
<rect
style="color:#000000;overflow:visible;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect900-8-7"
width="10.583333"
height="13.79613"
x="78.878532"
y="85.920006"
ry="1.937705" />
<text
xml:space="preserve"
id="text833-7-5"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.9375px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect835-2-1);fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
transform="translate(-0.04189825,-0.41581583)"><tspan
x="80.886719"
y="96.225952"><tspan
style="fill:#ffffff;fill-opacity:1"></tspan></tspan></text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -1,55 +1,92 @@
Kareema's guide to creating layouts
===================================
A guide to creating layouts
===========================
Its long overdue to write a comprehensive guide how to add a keyboard layout from start. But unfortunately, I dont have much time left ATM. A lot of information can be found in [this ](https://forums.puri.sm/t/using-non-latin-language-on-librem-5/7103/5) thread.
This guide is based on the original Kareema's [forum post](https://forums.puri.sm/t/translations-and-virtual-touch-keyboards-tracking-localization/7669/48).
So at least I will try to start writing a short how-to here and edit this post as I find the time. Hope this helps a bit - comments and corrections welcome.
Its long overdue to write a comprehensive guide how to add a keyboard layout from start. But unfortunately, I dont have much time left ATM. A lot of information can be found in [this](https://forums.puri.sm/t/using-non-latin-language-on-librem-5/7103/5) thread.
**Get one of the existing keyboard layouts**
So at least I will try to start writing a short how-to here and edit this post as I find the time. Hope this helps a bit - comments and corrections [welcome](https://source.puri.sm/Librem5/squeekboard/-/merge_requests/)
* You can get one of the keyboards from the squeekboard git repository : [https://source.puri.sm/Librem5/squeekboard ](https://source.puri.sm/Librem5/squeekboard)
* The keyboard layouts are located in the subdirectory `data/keyboard/` in the `.yaml` files
## Creating a new layout
Creating a layout is easy. You don't need to recompile things, just edit and test. It's easiest to start with an existing layout.
### Get one of the existing keyboard layouts
* You can get one of the keyboards from the squeekboard git repository : [https://source.puri.sm/Librem5/squeekboard](https://source.puri.sm/Librem5/squeekboard)
* The keyboard layouts are located in the subdirectory [`data/keyboards/`](https://source.puri.sm/Librem5/squeekboard/-/tree/master/data/keyboards) in the `.yaml` files
* Take a look and try to understand them :slight_smile:
**Fork your own copy of squeekboard**
### Creating the keyboard layout
* To be written: For the time being, take a look at [Using non-latin language on Librem 5](https://forums.puri.sm/t/using-non-latin-language-on-librem-5/7103/5)
* The correct name of the .yaml file can be found with the command
```
gsettings get org.gnome.desktop.input-sources sources
```
The output should be something like this: `[('xkb', 'us'), ('xkb', 'de')]`
So for example “de.yaml” would be the correct name for the German keyboard layout.
If the name of your layout is not translated correctly in the list, you can fix it by adding it and recompiling Squeekboard.
### Testing the layout
Copy your yaml file to `~/.local/share/squeekboard/keyboards/` for testing purposes. From there it should get picked up by squeekboard automatically.
You can also use the `test_layout` tool from the -devel package to check it for errors:
```
# squeekboard_test_layout ./mylayout.yaml
Test result: OK
```
## Contributing your changes
If you want to share your layout with the world, the best way is to submit it to the Squeekboard project. The workflow is similar to any other Gitlab-based project.
Above all, your layout should be working, be tested, not break anything, and make sense.
### Fork your own copy of squeekboard
* Best way would be to start with a fork of the squeekboard repository: Create a user account at https://source.puri.sm/, go the the squeekboard git repository, press “Fork” in the web interface. You can find further instructions [here](https://docs.gitlab.com/ee/user/project/repository/forking_workflow.html#creating-a-fork).
* Clone your fork locally with `git clone` and use the uri of your forked repo there
**Workflow to edit your keyboard and get it merged**
### Edit your keyboard and get it merged
* A generic guide how the workflow to contribute works, can be found at https://developer.puri.sm/Librem5/Contact/Contributing.html
* It may be useful to check out the [generic guide how the workflow to contribute works](https://developer.puri.sm/Librem5/Contact/Contributing.html)
* Create a branch: Name it “keyboard-layout-mylanguage” or whatever
* Checkout your branch, edit your keyboard layout and commit your changes
* Your layout **must** be correctly named, and in `data/keyboards/`.
* Your layout **must** pass the `test_layout` tool with zero problems.
* Your translation **must** be correctly named, and in `data/langs/`.
* Your layout or translation **must** be added to automatic tests. **Dont forget to add it** to `src/resources.rs` and the layout to `tests/meson.build` (thats for me, because I always forget it).
### Get it merged
It's always recommended to **compile and run** squeekboard before submitting your changes. This serves as a test that all is working. See instructions in the [compiling section](#compiling-and-running-squeekboard).
* Push the local changes (to the branch of your fork of squeekboard)
* Create a merge request for the branch to get your changes merged to the official squeekboard git repository
**Compile squeekboard**
If your changes pass automated tests (CI), then the merge request will be reviewed by the maintainers, and you might be asked to change a thing or two.
* Follow the instructions found in “Building” section of the squeekboards README: Running squeekboard: [https://source.puri.sm/Librem5/squeekboard/blob/master/README.md#building ](https://source.puri.sm/Librem5/squeekboard/blob/master/README.md#building)
## Compiling and running Squeekboard
**Running squeekboard**
If you want your change to become part of official Squeekboard, or if you want to add a translation of your layout name, you will have to recompile Squeekboard and test your changes there.
* Follow these instructions to run squeekboard: [https://source.puri.sm/Librem5/squeekboard/blob/master/README.md#running ](https://source.puri.sm/Librem5/squeekboard/blob/master/README.md#running)
### Compile squeekboard
* Follow the instructions found in “Building” section of the squeekboards README: Running squeekboard: [https://source.puri.sm/Librem5/squeekboard/blob/master/README.md#building](https://source.puri.sm/Librem5/squeekboard/blob/master/README.md#building)
### Run squeekboard
* Follow these instructions to run squeekboard: [https://source.puri.sm/Librem5/squeekboard/blob/master/README.md#running](https://source.puri.sm/Librem5/squeekboard/blob/master/README.md#running)
* Additionally take a look at the contribution document for [testing info](HACKING.md#testing)
* You can either test it locally on your Linux system or use the [QEMU Librem 5 image ](https://developer.puri.sm/Librem5/Development_Environment/Boards/emulators.html)
* You can either test it locally on your Linux system or use the [QEMU Librem 5 image](https://developer.puri.sm/Librem5/Development_Environment/Boards/emulators.html)
* To test squeekboard locally, you need phoc. Either compile that from the sources as well or use the CI repository ci.puri.sm for Debian based systems:
`deb [arch=amd64] http://ci.puri.sm/ scratch librem5`
Squeekboard can be installed from there as a Debian package, too (thats what I often do). But beware - there be dragons! You could bork your system with these packages and you should probably disable this repository again after installing what you need - these packages are not meant for production systems (or so I heard :wink: )
**Creating the keyboard layout**
* To be written: For the time being, take a look at [Using non-latin language on Librem 5 ](https://forums.puri.sm/t/using-non-latin-language-on-librem-5/7103/5)
* The correct name of the .yaml file can be found with the command `gsettings get org.gnome.desktop.input-sources sources`
The output should be something like this: `[('xkb', 'us'), ('xkb', 'de')]`
So f.ex. “de.yaml” would be the correct name for the German keyboard layout.
* The translations for the keyboard layout names in the different languages can be found at `data/langs/`
* Dont forget to add your newly created layout or translation to `src/resources.rs` and the layout to `tests/meson.build` (thats for me, because I always forget it)
**Testing the layout**
* Copy your yaml file to `~/.local/share/squeekboard/keyboards/` for testing purposes. From there it should get picked up by squeekboard
* To test the translations in `data/langs/` , you have to compile squeekboard

64
doc/views.md Normal file
View File

@ -0,0 +1,64 @@
Switching views
=========
Squeekboard layout files are separated into *views*.
What are views?
-------------------
A view is the button arrangement which you see on Squeekboard's panel. The view always spans the entire panel area, so it's not possible to see two views at the same time, even if the layout contains multiple views.
Views are useful because they allow to have many more buttons than would fit on the panel at the same time. That works because views can be switched.
Views are different from layouts: they can be switched without affecting the active language, and without touching the globe button. Layouts cannot share views, so switching layouts *always* switches views.
Switching views
------------------
The model selected for switching views is less similar to "levels" known from physical keyboards, but closer to "rooms", which may resemble a game map.
Buttons don't have states. It's more of a model where each view is a room, and buttons are doors. Switching means moving to the next room, and buttons highlight according to which view/room they lead to or from.
There are two basic kinds of switching buttons: one way (`set_view`), and two way (`locking`). `locking` is the more sophisticated one. When placed inside `lock_view`, it is drawn highlighted, and goes to `unlock view`. When placed inside any other view, it behaves like `set_view`.
![Diagram showing two transitions: from lowercase via `set_view` to uppercase, and back via `locking`](switching.svg) This diagram shows which buttons can switch between two views. Views are shown as circles, and buttons as rounded rectangles.
The two buttons are separate, and visible only in the view *from which the switch starts*. Note that the `locking` button is shown highlighted. That's because it's in `upper` view, which matches its `lock_view`.
Latching
----------
`locking` buttons provide a second mode of operation: latching. It's useful when the target view is needed only for a single button press, like entering a single accent or a single capital letter in Latin scripts.
When a latching button is pressed, the keyboard remembers to come back to the current (source) view, and then the view is switched. If another `locking` button is pressed, the source view stays in memory. If a text button is pressed, the view from memory is shown again, and forgotten.
![Diagram showing the switches needed to travel across 3 views: a→A→Ą, while latching.](latching.svg) In this diagram, the dashed line connects the view the typist is seeing to the view remembered for unlatching.
There are two ways to erase the memory without going back to the remembered view. Pressing the button again will permanently switch to the current view, and `set_view` will permanently switch to its target.
In the room metaphor, it's as if tying a thread inside the room before going through the door to the next one. And another `locking` door while holding the thread. Once the Minotaur is slain (text button pressed), the hero follows the thread back to the starting room.
The typist hero cuts the thread in two circumstances: when staying longer in the current room (press button again), or when moving through a `set_view` door.
![Diagram showing possible ways to stop latching, by staying in Ą, by unlatching back to a, and by moving on to ą view.](latching_return.svg) This diagram shows the possible ways to stop latching. One is by pressing a text button, which takes back to the original view. Another is pressing a locking button which appears highlighted (note that it can be any button, what matters is its `lock_view`). Finally, switching to another view using a button that doesn't keep the latch on forgets latching.
The layout author should pay attention that `set_view`'s lack of latching does not come as a surprise to typists.
Differences from keyboard levels
---------------------------------------
Views are **not** like keyboard levels.
On a physical keyboard, the number of buttons can not change when switching levels. In Squeekboard, they can have any arrangement of buttons you could imagine.
When switching levels on a keyboard, for example by pressing Shift, the key press not only affects the meaning of other keys, but also tells the application that it's pressed down. In Squeekboard, pressing buttons to change layouts *does not* do anything but switch the layout. Pressing the switching button especially *does not* tell the application that it was pressed. (This is the reason Shift and AltGr modifiers are not implemented in Squeekboard.)
Why not use the "views" model?
-------------------------------------
Squeekboard's goal is to support as many scripts as possible, and the author of the initial design doesn't know a whole lot. There are two problems with using the levels metaphor:
Firstly, the levels model assumes that there is a "base" and an "active" level. This does not work well with scripts that have different but equivalent modes of writing. An example is the Kana layout with Katakana and Hiragana, which are both "base".
Both systems could have been combined, but the view switching designer doesn't have enough experience with different scripts to do that. Some scripts may have different non-hierarchical ways to switch character groups (Balinese?), which could make combining hierarchy with free-form switching even harder.
Secondly, when dealing with languages with a hierarchy, we end up with extra work to eliminate nonsensical combinations. With "symbols" and "uppercase" levels, what does it mean to have both engaged? Eliminating that means extra work. Either validating layouts, so that it's not possible to engage "uppercase" from "symbols", or duplicating, so that "uppercase+symbols" is the same as just "symbols". With "accents" in the mix, this could become a challenge to design well.

View File

@ -38,8 +38,6 @@ struct _EekElementClass
GObjectClass parent_class;
};
GType eek_element_get_type (void) G_GNUC_CONST;
void eek_element_set_name (EekElement *element,
const gchar *name);

View File

@ -45,6 +45,8 @@
typedef struct _EekGtkKeyboardPrivate
{
EekRenderer *renderer; // owned, nullable
struct render_geometry render_geometry; // mutable
EekboardContextService *eekboard_context; // unowned reference
struct submission *submission; // unowned reference
@ -72,12 +74,23 @@ eek_gtk_keyboard_real_realize (GtkWidget *self)
GTK_WIDGET_CLASS (eek_gtk_keyboard_parent_class)->realize (self);
}
static void set_allocation_size(EekGtkKeyboard *gtk_keyboard,
struct squeek_layout *layout, gdouble width, gdouble height)
{
// This is where size-dependent surfaces would be released
EekGtkKeyboardPrivate *priv =
eek_gtk_keyboard_get_instance_private (gtk_keyboard);
priv->render_geometry = eek_render_geometry_from_allocation_size(
layout, width, height);
}
static gboolean
eek_gtk_keyboard_real_draw (GtkWidget *self,
cairo_t *cr)
{
EekGtkKeyboard *keyboard = EEK_GTK_KEYBOARD (self);
EekGtkKeyboardPrivate *priv =
eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
eek_gtk_keyboard_get_instance_private (keyboard);
GtkAllocation allocation;
gtk_widget_get_allocation (self, &allocation);
@ -92,22 +105,21 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
priv->keyboard,
pcontext);
eek_renderer_set_allocation_size (priv->renderer,
priv->keyboard->layout,
allocation.width,
allocation.height);
set_allocation_size (keyboard, priv->keyboard->layout,
allocation.width, allocation.height);
eek_renderer_set_scale_factor (priv->renderer,
gtk_widget_get_scale_factor (self));
}
eek_renderer_render_keyboard (priv->renderer, priv->submission, cr, priv->keyboard);
eek_renderer_render_keyboard (priv->renderer, priv->render_geometry,
priv->submission, cr, priv->keyboard);
return FALSE;
}
// Units of pixel size
// Units of virtual pixels size
static enum squeek_arrangement_kind get_type(uint32_t width, uint32_t height) {
(void)height;
if (width < 1080) {
if (width < 540) {
return ARRANGEMENT_KIND_BASE;
}
return ARRANGEMENT_KIND_WIDE;
@ -117,24 +129,23 @@ static void
eek_gtk_keyboard_real_size_allocate (GtkWidget *self,
GtkAllocation *allocation)
{
EekGtkKeyboard *keyboard = EEK_GTK_KEYBOARD (self);
EekGtkKeyboardPrivate *priv =
eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
uint32_t scale = (uint32_t)gtk_widget_get_scale_factor(self);
eek_gtk_keyboard_get_instance_private (keyboard);
// check if the change would switch types
enum squeek_arrangement_kind new_type = get_type(
(uint32_t)(allocation->width - allocation->x) * scale,
(uint32_t)(allocation->height - allocation->y) * scale);
(uint32_t)(allocation->width - allocation->x),
(uint32_t)(allocation->height - allocation->y));
if (priv->layout->arrangement != new_type) {
priv->layout->arrangement = new_type;
eekboard_context_service_use_layout(priv->eekboard_context, priv->layout);
uint32_t time = gdk_event_get_time(NULL);
eekboard_context_service_use_layout(priv->eekboard_context, priv->layout, time);
}
if (priv->renderer)
eek_renderer_set_allocation_size (priv->renderer,
priv->keyboard->layout,
allocation->width,
allocation->height);
if (priv->renderer) {
set_allocation_size (keyboard, priv->keyboard->layout,
allocation->width, allocation->height);
}
GTK_WIDGET_CLASS (eek_gtk_keyboard_parent_class)->
size_allocate (self, allocation);
@ -162,7 +173,7 @@ static void depress(EekGtkKeyboard *self,
}
squeek_layout_depress(priv->keyboard->layout,
priv->submission,
x, y, eek_renderer_get_transformation(priv->renderer), time, self);
x, y, priv->render_geometry.widget_to_layout, time, self);
}
static void drag(EekGtkKeyboard *self,
@ -174,7 +185,7 @@ static void drag(EekGtkKeyboard *self,
}
squeek_layout_drag(eekboard_context_service_get_keyboard(priv->eekboard_context)->layout,
priv->submission,
x, y, eek_renderer_get_transformation(priv->renderer), time,
x, y, priv->render_geometry.widget_to_layout, time,
priv->eekboard_context, self);
}
@ -185,8 +196,7 @@ static void release(EekGtkKeyboard *self, guint32 time)
return;
}
squeek_layout_release(eekboard_context_service_get_keyboard(priv->eekboard_context)->layout,
priv->submission,
eek_renderer_get_transformation(priv->renderer), time,
priv->submission, priv->render_geometry.widget_to_layout, time,
priv->eekboard_context, self);
}
@ -356,10 +366,15 @@ eek_gtk_keyboard_init (EekGtkKeyboard *self)
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
g_autoptr(GError) err = NULL;
if (lfb_init(SQUEEKBOARD_APP_ID, &err))
if (lfb_init(SQUEEKBOARD_APP_ID, &err)) {
priv->event = lfb_event_new ("button-pressed");
else
} else {
g_warning ("Failed to init libfeedback: %s", err->message);
}
GtkIconTheme *theme = gtk_icon_theme_get_default ();
gtk_icon_theme_add_resource_path (theme, "/sm/puri/squeekboard/icons");
}
static void
@ -391,6 +406,24 @@ eek_gtk_keyboard_new (EekboardContextService *eekservice,
priv->submission = submission;
priv->layout = layout;
priv->renderer = NULL;
// This should really be done on initialization.
// Before the widget is allocated,
// we don't really know what geometry it takes.
// When it's off the screen, we also kinda don't.
struct render_geometry initial_geometry = {
// Set to 100 just to make sure if there's any attempt to use it,
// it actually gives plausible results instead of blowing up,
// e.g. on zero division.
.allocation_width = 100,
.allocation_height = 100,
.widget_to_layout = {
.origin_x = 0,
.origin_y = 0,
.scale = 1,
},
};
priv->render_geometry = initial_geometry;
g_signal_connect (eekservice,
"notify::keyboard",
G_CALLBACK(on_notify_keyboard),

View File

@ -28,6 +28,7 @@
#include <glib.h>
#include <gtk/gtk.h>
#include "eek/eek-renderer.h"
#include "eek/eek-types.h"
struct submission;
@ -47,7 +48,6 @@ struct _EekGtkKeyboardClass
gpointer pdummy[24];
};
GType eek_gtk_keyboard_get_type (void) G_GNUC_CONST;
GtkWidget *eek_gtk_keyboard_new (EekboardContextService *eekservice, struct submission *submission, struct squeek_layout_state *layout);
void eek_gtk_keyboard_emit_feedback (EekGtkKeyboard *self);

View File

@ -21,6 +21,7 @@
#include "config.h"
#define _XOPEN_SOURCE 500
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
@ -30,45 +31,31 @@
#include "eek-keyboard.h"
void level_keyboard_free(LevelKeyboard *self) {
xkb_keymap_unref(self->keymap);
close(self->keymap_fd);
squeek_layout_free(self->layout);
g_free(self);
}
LevelKeyboard*
level_keyboard_new (struct squeek_layout *layout)
{
LevelKeyboard *keyboard = g_new0(LevelKeyboard, 1);
if (!keyboard) {
g_error("Failed to create a keyboard");
}
keyboard->layout = layout;
/// External linkage for Rust.
/// The corresponding deinit is implemented in vkeyboard::KeyMap::drop
struct keymap squeek_key_map_from_str(const char *keymap_str) {
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!context) {
g_error("No context created");
}
const gchar *keymap_str = squeek_layout_get_keymap(keyboard->layout);
struct xkb_keymap *keymap = xkb_keymap_new_from_string(context, keymap_str,
XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!keymap)
if (!keymap) {
g_error("Bad keymap:\n%s", keymap_str);
}
xkb_context_unref(context);
keyboard->keymap = keymap;
keymap_str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1);
keyboard->keymap_len = strlen(keymap_str) + 1;
char *xkb_keymap_str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1);
size_t keymap_len = strlen(xkb_keymap_str) + 1;
g_autofree char *path = strdup("/eek_keymap-XXXXXX");
char *r = &path[strlen(path) - 6];
getrandom(r, 6, GRND_NONBLOCK);
if (getrandom(r, 6, GRND_NONBLOCK) < 0) {
g_error("Failed to get random numbers: %s", strerror(errno));
}
for (unsigned i = 0; i < 6; i++) {
r[i] = (r[i] & 0b1111111) | 0b1000000; // A-z
r[i] = r[i] > 'z' ? '?' : r[i]; // The randomizer doesn't need to be good...
@ -77,17 +64,39 @@ level_keyboard_new (struct squeek_layout *layout)
if (keymap_fd < 0) {
g_error("Failed to set up keymap fd");
}
keyboard->keymap_fd = keymap_fd;
shm_unlink(path);
if (ftruncate(keymap_fd, (off_t)keyboard->keymap_len)) {
if (ftruncate(keymap_fd, (off_t)keymap_len)) {
g_error("Failed to increase keymap fd size");
}
char *ptr = mmap(NULL, keyboard->keymap_len, PROT_WRITE, MAP_SHARED,
char *ptr = mmap(NULL, keymap_len, PROT_WRITE, MAP_SHARED,
keymap_fd, 0);
if ((void*)ptr == (void*)-1) {
g_error("Failed to set up mmap");
}
strncpy(ptr, keymap_str, keyboard->keymap_len);
munmap(ptr, keyboard->keymap_len);
strncpy(ptr, xkb_keymap_str, keymap_len);
munmap(ptr, keymap_len);
free(xkb_keymap_str);
xkb_keymap_unref(keymap);
struct keymap km = {
.fd = keymap_fd,
.fd_len = keymap_len,
};
return km;
}
void level_keyboard_free(LevelKeyboard *self) {
squeek_layout_free(self->layout);
g_free(self);
}
LevelKeyboard*
level_keyboard_new (struct squeek_layout *layout)
{
LevelKeyboard *keyboard = g_new0(LevelKeyboard, 1);
if (!keyboard) {
g_error("Failed to create a keyboard");
}
keyboard->layout = layout;
return keyboard;
}

View 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
@ -32,19 +32,20 @@
G_BEGIN_DECLS
/// Keymap container for Rust interoperability.
struct keymap {
uint32_t fd; // keymap formatted as XKB string
size_t fd_len; // length of the data inside keymap_fd
};
/// Keyboard state holder
struct _LevelKeyboard {
struct squeek_layout *layout; // owned
struct xkb_keymap *keymap; // owned
int keymap_fd; // keymap formatted as XKB string
size_t keymap_len; // length of the data inside keymap_fd
guint id; // as a key to layout choices
// FIXME: This no longer needs to exist, keymap was folded into layout.
};
typedef struct _LevelKeyboard LevelKeyboard;
gchar * eek_keyboard_get_keymap
(LevelKeyboard *keyboard);
gchar *eek_keyboard_get_keymap(LevelKeyboard *keyboard);
LevelKeyboard*
level_keyboard_new (struct squeek_layout *layout);

View File

@ -18,8 +18,6 @@
* 02110-1301 USA
*/
#include "config.h"
#include <math.h>
#include <string.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
@ -33,10 +31,6 @@
static void render_button_label (cairo_t *cr, GtkStyleContext *ctx,
const gchar *label, EekBounds bounds);
void eek_render_button (EekRenderer *self,
cairo_t *cr, const struct squeek_button *button,
gboolean pressed, gboolean locked);
static void
render_outline (cairo_t *cr,
GtkStyleContext *ctx,
@ -60,21 +54,21 @@ render_outline (cairo_t *cr,
position.x, position.y, position.width, position.height);
}
static void render_button_in_context(gint scale_factor,
/// Rust interface
void eek_render_button_in_context(uint32_t scale_factor,
cairo_t *cr,
GtkStyleContext *ctx,
const struct squeek_button *button) {
EekBounds bounds,
const char *icon_name,
const gchar *label) {
/* blank background */
cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0);
cairo_paint (cr);
EekBounds bounds = squeek_button_get_bounds(button);
render_outline (cr, ctx, bounds);
cairo_paint (cr);
/* render icon (if any) */
const char *icon_name = squeek_button_get_icon_name(button);
if (icon_name) {
cairo_surface_t *icon_surface =
eek_renderer_get_icon_surface (icon_name, 16, scale_factor);
@ -104,25 +98,27 @@ static void render_button_in_context(gint scale_factor,
}
}
const gchar *label = squeek_button_get_label(button);
if (label) {
render_button_label (cr, ctx, label, squeek_button_get_bounds(button));
render_button_label (cr, ctx, label, bounds);
}
}
void
eek_render_button (EekRenderer *self,
cairo_t *cr,
const struct squeek_button *button,
gboolean pressed,
gboolean locked)
/// Prepare context for drawing the button.
/// The context MUST be released using the corresponing "put" procedure
/// before drawing the next button.
/// Interface for Rust.
GtkStyleContext *
eek_get_style_context_for_button (EekRenderer *self,
const char *name,
const char *outline_name,
const char *locked_class,
uint64_t pressed)
{
GtkStyleContext *ctx = self->button_context;
/* Set the name of the button on the widget path, using the name obtained
from the button's symbol. */
g_autoptr (GtkWidgetPath) path = NULL;
path = gtk_widget_path_copy (gtk_style_context_get_path (ctx));
const char *name = squeek_button_get_name(button);
gtk_widget_path_iter_set_name (path, -1, name);
/* Update the style context with the updated widget path. */
@ -131,19 +127,22 @@ eek_render_button (EekRenderer *self,
(pressed) or normal. */
gtk_style_context_set_state(ctx,
pressed ? GTK_STATE_FLAG_ACTIVE : GTK_STATE_FLAG_NORMAL);
const char *outline_name = squeek_button_get_outline_name(button);
if (locked) {
gtk_style_context_add_class(ctx, "locked");
if (locked_class) {
gtk_style_context_add_class(ctx, locked_class);
}
gtk_style_context_add_class(ctx, outline_name);
return ctx;
}
render_button_in_context(self->scale_factor, cr, ctx, button);
/// Interface for Rust.
void eek_put_style_context_for_button(GtkStyleContext *ctx,
const char *outline_name,
const char *locked_class) {
// Save and restore functions don't work if gtk_render_* was used in between
gtk_style_context_set_state(ctx, GTK_STATE_FLAG_NORMAL);
gtk_style_context_remove_class(ctx, outline_name);
if (locked) {
gtk_style_context_remove_class(ctx, "locked");
if (locked_class) {
gtk_style_context_remove_class(ctx, locked_class);
}
}
@ -194,22 +193,23 @@ render_button_label (cairo_t *cr,
// FIXME: Pass just the active modifiers instead of entire submission
void
eek_renderer_render_keyboard (EekRenderer *self,
struct render_geometry geometry,
struct submission *submission,
cairo_t *cr,
LevelKeyboard *keyboard)
{
g_return_if_fail (self->allocation_width > 0.0);
g_return_if_fail (self->allocation_height > 0.0);
g_return_if_fail (geometry.allocation_width > 0.0);
g_return_if_fail (geometry.allocation_height > 0.0);
/* Paint the background covering the entire widget area */
gtk_render_background (self->view_context,
cr,
0, 0,
self->allocation_width, self->allocation_height);
geometry.allocation_width, geometry.allocation_height);
cairo_save(cr);
cairo_translate (cr, self->widget_to_layout.origin_x, self->widget_to_layout.origin_y);
cairo_scale (cr, self->widget_to_layout.scale, self->widget_to_layout.scale);
cairo_translate (cr, geometry.widget_to_layout.origin_x, geometry.widget_to_layout.origin_y);
cairo_scale (cr, geometry.widget_to_layout.scale, geometry.widget_to_layout.scale);
squeek_draw_layout_base_view(keyboard->layout, self, cr);
squeek_layout_draw_all_changed(keyboard->layout, self, cr, submission);
@ -241,7 +241,7 @@ static GType new_type(char *name) {
);
}
static GType view_type() {
static GType view_type(void) {
static GType type = 0;
if (!type) {
type = new_type("sq_view");
@ -249,7 +249,7 @@ static GType view_type() {
return type;
}
static GType button_type() {
static GType button_type(void) {
static GType type = 0;
if (!type) {
type = new_type("sq_button");
@ -261,14 +261,8 @@ static void
renderer_init (EekRenderer *self)
{
self->pcontext = NULL;
self->allocation_width = 0.0;
self->allocation_height = 0.0;
self->scale_factor = 1;
GtkIconTheme *theme = gtk_icon_theme_get_default ();
gtk_icon_theme_add_resource_path (theme, "/sm/puri/squeekboard/icons");
self->css_provider = squeek_load_style();
}
@ -313,22 +307,18 @@ eek_renderer_new (LevelKeyboard *keyboard,
return renderer;
}
void
eek_renderer_set_allocation_size (EekRenderer *renderer,
struct squeek_layout *layout,
struct render_geometry
eek_render_geometry_from_allocation_size (struct squeek_layout *layout,
gdouble width,
gdouble height)
{
g_return_if_fail (width > 0.0 && height > 0.0);
renderer->allocation_width = width;
renderer->allocation_height = height;
renderer->widget_to_layout = squeek_layout_calculate_transformation(
layout,
renderer->allocation_width, renderer->allocation_height);
// This is where size-dependent surfaces would be released
struct render_geometry ret = {
.allocation_width = width,
.allocation_height = height,
.widget_to_layout = squeek_layout_calculate_transformation(
layout, width, height),
};
return ret;
}
void
@ -337,6 +327,11 @@ eek_renderer_set_scale_factor (EekRenderer *renderer, gint scale)
renderer->scale_factor = scale;
}
/// Rust interface.
uint32_t eek_renderer_get_scale_factor(EekRenderer *renderer) {
return renderer->scale_factor;
}
cairo_surface_t *
eek_renderer_get_icon_surface (const gchar *icon_name,
gint size,
@ -360,8 +355,3 @@ eek_renderer_get_icon_surface (const gchar *icon_name,
}
return surface;
}
struct transformation
eek_renderer_get_transformation (EekRenderer *renderer) {
return renderer->widget_to_layout;
}

View File

@ -41,22 +41,23 @@ typedef struct EekRenderer
gchar *extra_style; // owned
// Mutable state
gint scale_factor; /* the outputs scale factor */
} EekRenderer;
/// Mutable part of the renderer state.
/// TODO: Possibly should include scale factor.
struct render_geometry {
/// Background extents
gdouble allocation_width;
gdouble allocation_height;
gint scale_factor; /* the outputs scale factor */
/// Coords transformation
struct transformation widget_to_layout;
} EekRenderer;
};
GType eek_renderer_get_type (void) G_GNUC_CONST;
EekRenderer *eek_renderer_new (LevelKeyboard *keyboard,
PangoContext *pcontext);
void eek_renderer_set_allocation_size
(EekRenderer *renderer, struct squeek_layout *layout,
gdouble width,
gdouble height);
void eek_renderer_set_scale_factor (EekRenderer *renderer,
gint scale);
@ -64,13 +65,14 @@ cairo_surface_t *eek_renderer_get_icon_surface(const gchar *icon_name,
gint size,
gint scale);
void eek_renderer_render_keyboard (EekRenderer *renderer, struct submission *submission,
void eek_renderer_render_keyboard (EekRenderer *renderer, struct render_geometry geometry, struct submission *submission,
cairo_t *cr, LevelKeyboard *keyboard);
void
eek_renderer_free (EekRenderer *self);
struct transformation
eek_renderer_get_transformation (EekRenderer *renderer);
struct render_geometry
eek_render_geometry_from_allocation_size (struct squeek_layout *layout,
gdouble width, gdouble height);
G_END_DECLS
#endif /* EEK_RENDERER_H */

View File

@ -90,13 +90,5 @@ struct transformation {
gdouble scale;
};
struct squeek_button;
struct squeek_row;
/// Represents the path to the button within a view
struct button_place {
const struct squeek_row *row;
const struct squeek_button *button;
};
G_END_DECLS
#endif /* EEK_TYPES_H */

View File

@ -590,27 +590,32 @@ phosh_layer_surface_set_size(PhoshLayerSurface *self, gint width, gint height)
g_return_if_fail (PHOSH_IS_LAYER_SURFACE (self));
priv = phosh_layer_surface_get_instance_private (self);
if (priv->height == height && priv->width == width)
if (priv->height == height && priv->width == width) {
return;
}
old_width = priv->width;
old_height = priv->height;
if (width != -1)
if (width != -1) {
priv->width = width;
}
if (height != -1)
if (height != -1) {
priv->height = height;
}
if (gtk_widget_get_mapped (GTK_WIDGET (self))) {
zwlr_layer_surface_v1_set_size(priv->layer_surface, priv->width, priv->height);
}
if (priv->height != old_height)
if (priv->height != old_height) {
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_LAYER_HEIGHT]);
}
if (priv->width != old_width)
if (priv->width != old_width) {
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_LAYER_WIDTH]);
}
}
/**
@ -632,25 +637,31 @@ phosh_layer_surface_set_margins(PhoshLayerSurface *self, gint top, gint right, g
old_right = priv->margin_right;
old_bottom = priv->margin_bottom;
if (old_top == top && old_left == left && old_right == right && old_bottom == bottom)
if (old_top == top && old_left == left && old_right == right && old_bottom == bottom) {
return;
}
priv->margin_top = top;
priv->margin_left = left;
priv->margin_right = right;
priv->margin_bottom = bottom;
if (priv->layer_surface)
if (priv->layer_surface) {
zwlr_layer_surface_v1_set_margin(priv->layer_surface, top, right, bottom, left);
}
if (old_top != top)
if (old_top != top) {
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_MARGIN_TOP]);
if (old_bottom != bottom)
}
if (old_bottom != bottom) {
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_MARGIN_BOTTOM]);
if (old_left != left)
}
if (old_left != left) {
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_MARGIN_LEFT]);
if (old_right != right)
}
if (old_right != right) {
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_MARGIN_RIGHT]);
}
}
/**
@ -669,13 +680,15 @@ phosh_layer_surface_set_exclusive_zone(PhoshLayerSurface *self, gint zone)
old_zone = priv->exclusive_zone;
if (old_zone == zone)
if (old_zone == zone) {
return;
}
priv->exclusive_zone = zone;
if (priv->layer_surface)
if (priv->layer_surface) {
zwlr_layer_surface_v1_set_exclusive_zone(priv->layer_surface, zone);
}
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_EXCLUSIVE_ZONE]);
}
@ -693,13 +706,14 @@ phosh_layer_surface_set_kbd_interactivity (PhoshLayerSurface *self, gboolean int
g_return_if_fail (PHOSH_IS_LAYER_SURFACE (self));
priv = phosh_layer_surface_get_instance_private (self);
if (priv->kbd_interactivity == interactivity)
if (priv->kbd_interactivity == interactivity) {
return;
}
priv->kbd_interactivity = interactivity;
if (priv->layer_surface)
if (priv->layer_surface) {
zwlr_layer_surface_v1_set_keyboard_interactivity (priv->layer_surface, interactivity);
}
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LAYER_SURFACE_PROP_KBD_INTERACTIVITY]);
}
@ -717,6 +731,7 @@ phosh_layer_surface_wl_surface_commit (PhoshLayerSurface *self)
g_return_if_fail (PHOSH_IS_LAYER_SURFACE (self));
priv = phosh_layer_surface_get_instance_private (self);
if (priv->wl_surface)
if (priv->wl_surface) {
wl_surface_commit (priv->wl_surface);
}
}

View File

@ -42,10 +42,21 @@ enum {
static guint signals[LAST_SIGNAL] = { 0, };
#define EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEKBOARD_TYPE_CONTEXT_SERVICE, EekboardContextServicePrivate))
/**
* EekboardContextService:
*
* Handles layout state, gsettings, and virtual-keyboard.
*
* 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.
*/
struct _EekboardContextService {
GObject parent;
struct squeek_layout_state *layout; // Unowned
struct _EekboardContextServicePrivate {
LevelKeyboard *keyboard; // currently used keyboard
GSettings *settings; // Owned reference
@ -56,7 +67,7 @@ struct _EekboardContextServicePrivate {
struct submission *submission; // unowned
};
G_DEFINE_TYPE_WITH_PRIVATE (EekboardContextService, eekboard_context_service, G_TYPE_OBJECT);
G_DEFINE_TYPE (EekboardContextService, eekboard_context_service, G_TYPE_OBJECT);
static void
eekboard_context_service_set_property (GObject *object,
@ -82,7 +93,7 @@ eekboard_context_service_get_property (GObject *object,
switch (prop_id) {
case PROP_KEYBOARD:
g_value_set_object (value, context->priv->keyboard);
g_value_set_object (value, context->keyboard);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -116,39 +127,31 @@ settings_get_layout(GSettings *settings, char **type, char **layout)
}
void
eekboard_context_service_use_layout(EekboardContextService *context, struct squeek_layout_state *state) {
gchar *layout_name = state->overlay_name;
eekboard_context_service_use_layout(EekboardContextService *context, struct squeek_layout_state *state, uint32_t timestamp) {
gchar *layout_name = state->layout_name;
gchar *overlay_name = state->overlay_name;
// try to get the best keyboard layout
if (layout_name == NULL) {
layout_name = state->layout_name;
switch (state->purpose) {
case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NUMBER:
case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PHONE:
layout_name = "number";
break;
case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TERMINAL:
layout_name = "terminal";
break;
default:
;
}
if (layout_name == NULL) {
layout_name = "us";
}
layout_name = "us";
}
// overlay is "Normal" for most layouts, we will only look for "terminal" in rust code.
// for now just avoid passing a null pointer
if (overlay_name == NULL) {
overlay_name = ""; // fallback to Normal
}
// generic part follows
struct squeek_layout *layout = squeek_load_layout(layout_name, state->arrangement);
struct squeek_layout *layout = squeek_load_layout(layout_name, state->arrangement, state->purpose, overlay_name);
LevelKeyboard *keyboard = level_keyboard_new(layout);
// set as current
LevelKeyboard *previous_keyboard = context->priv->keyboard;
context->priv->keyboard = keyboard;
LevelKeyboard *previous_keyboard = context->keyboard;
context->keyboard = keyboard;
// Update the keymap if necessary.
// TODO: Update submission on change event
if (context->priv->submission) {
submission_set_keyboard(context->priv->submission, keyboard);
if (context->submission) {
submission_use_layout(context->submission, keyboard->layout, timestamp);
}
// Update UI
@ -163,7 +166,7 @@ eekboard_context_service_use_layout(EekboardContextService *context, struct sque
static void eekboard_context_service_update_settings_layout(EekboardContextService *context) {
g_autofree gchar *keyboard_layout = NULL;
g_autofree gchar *keyboard_type = NULL;
settings_get_layout(context->priv->settings,
settings_get_layout(context->settings,
&keyboard_type, &keyboard_layout);
if (g_strcmp0(context->layout->layout_name, keyboard_layout) != 0 || context->layout->overlay_name) {
@ -174,7 +177,8 @@ static void eekboard_context_service_update_settings_layout(EekboardContextServi
context->layout->layout_name = g_strdup(keyboard_layout);
}
// This must actually update the UI.
eekboard_context_service_use_layout(context, context->layout);
uint32_t time = gdk_event_get_time(NULL);
eekboard_context_service_use_layout(context, context->layout, time);
}
}
@ -216,7 +220,7 @@ eekboard_context_service_class_init (EekboardContextServiceClass *klass)
g_signal_new (I_("destroyed"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EekboardContextServiceClass, destroyed),
0,
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
@ -240,30 +244,30 @@ eekboard_context_service_class_init (EekboardContextServiceClass *klass)
static void
eekboard_context_service_init (EekboardContextService *self)
{
self->priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(self);
const char *schema_name = "org.gnome.desktop.input-sources";
GSettingsSchemaSource *ssrc = g_settings_schema_source_get_default();
if (ssrc) {
GSettingsSchema *schema = g_settings_schema_source_lookup(ssrc,
schema_name,
TRUE);
if (schema) {
// Not referencing the found schema directly,
// because it's not clear how...
self->priv->settings = g_settings_new (schema_name);
gulong conn_id = g_signal_connect(self->priv->settings, "change-event",
G_CALLBACK(settings_handle_layout_changed),
self);
if (conn_id == 0) {
g_warning ("Could not connect to gsettings updates, "
"automatic layout changing unavailable");
}
} else {
g_warning("Gsettings schema %s is not installed on the system. "
"Layout switching unavailable", schema_name);
g_autoptr(GSettingsSchema) schema = NULL;
if (!ssrc) {
g_warning("No gsettings schemas installed. Layout switching unavailable.");
return;
}
schema = g_settings_schema_source_lookup(ssrc, schema_name, TRUE);
if (schema) {
// Not referencing the found schema directly,
// because it's not clear how...
self->settings = g_settings_new (schema_name);
gulong conn_id = g_signal_connect(self->settings, "change-event",
G_CALLBACK(settings_handle_layout_changed),
self);
if (conn_id == 0) {
g_warning ("Could not connect to gsettings updates, "
"automatic layout changing unavailable");
}
} else {
g_warning("No gsettings schemas installed. Layout switching unavailable.");
g_warning("Gsettings schema %s is not installed on the system. "
"Layout switching unavailable", schema_name);
}
}
@ -290,7 +294,7 @@ eekboard_context_service_destroy (EekboardContextService *context)
LevelKeyboard *
eekboard_context_service_get_keyboard (EekboardContextService *context)
{
return context->priv->keyboard;
return context->keyboard;
}
void eekboard_context_service_set_hint_purpose(EekboardContextService *context,
@ -299,7 +303,8 @@ void eekboard_context_service_set_hint_purpose(EekboardContextService *context,
if (context->layout->hint != hint || context->layout->purpose != purpose) {
context->layout->hint = hint;
context->layout->purpose = purpose;
eekboard_context_service_use_layout(context, context->layout);
uint32_t time = gdk_event_get_time(NULL);
eekboard_context_service_use_layout(context, context->layout, time);
}
}
@ -308,7 +313,8 @@ eekboard_context_service_set_overlay(EekboardContextService *context, const char
if (g_strcmp0(context->layout->overlay_name, name)) {
g_free(context->layout->overlay_name);
context->layout->overlay_name = g_strdup(name);
eekboard_context_service_use_layout(context, context->layout);
uint32_t time = gdk_event_get_time(NULL);
eekboard_context_service_use_layout(context, context->layout, time);
}
}
@ -322,17 +328,19 @@ EekboardContextService *eekboard_context_service_new(struct squeek_layout_state
EekboardContextService *context = g_object_new (EEKBOARD_TYPE_CONTEXT_SERVICE, NULL);
context->layout = state;
eekboard_context_service_update_settings_layout(context);
eekboard_context_service_use_layout(context, context->layout);
uint32_t time = gdk_event_get_time(NULL);
eekboard_context_service_use_layout(context, context->layout, time);
return context;
}
void eekboard_context_service_set_submission(EekboardContextService *context, struct submission *submission) {
context->priv->submission = submission;
if (context->priv->submission) {
submission_set_keyboard(context->priv->submission, context->priv->keyboard);
context->submission = submission;
if (context->submission) {
uint32_t time = gdk_event_get_time(NULL);
submission_use_layout(context->submission, context->keyboard->layout, time);
}
}
void eekboard_context_service_set_ui(EekboardContextService *context, ServerContextService *ui) {
context->priv->ui = ui;
context->ui = ui;
}

View File

@ -34,54 +34,9 @@ G_BEGIN_DECLS
#define EEKBOARD_CONTEXT_SERVICE_INTERFACE "org.fedorahosted.Eekboard.Context"
#define EEKBOARD_TYPE_CONTEXT_SERVICE (eekboard_context_service_get_type())
#define EEKBOARD_CONTEXT_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEKBOARD_TYPE_CONTEXT_SERVICE, EekboardContextService))
#define EEKBOARD_CONTEXT_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEKBOARD_TYPE_CONTEXT_SERVICE, EekboardContextServiceClass))
#define EEKBOARD_IS_CONTEXT_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEKBOARD_TYPE_CONTEXT_SERVICE))
#define EEKBOARD_IS_CONTEXT_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEKBOARD_TYPE_CONTEXT_SERVICE))
#define EEKBOARD_CONTEXT_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEKBOARD_TYPE_CONTEXT_SERVICE, EekboardContextServiceClass))
G_DECLARE_FINAL_TYPE(EekboardContextService, eekboard_context_service, EEKBOARD, CONTEXT_SERVICE, GObject)
typedef struct _EekboardContextServiceClass EekboardContextServiceClass;
typedef struct _EekboardContextServicePrivate EekboardContextServicePrivate;
/**
* EekboardContextService:
*
* Handles layout state, gsettings, and virtual-keyboard.
*
* 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.
*/
struct _EekboardContextService {
GObject parent;
EekboardContextServicePrivate *priv;
struct squeek_layout_state *layout; // Unowned
};
/**
* EekboardContextServiceClass:
* @create_keyboard: virtual function for create a keyboard from string
* @enabled: class handler for #EekboardContextService::enabled signal
* @disabled: class handler for #EekboardContextService::disabled signal
*/
struct _EekboardContextServiceClass {
/*< private >*/
GObjectClass parent_class;
/*< public >*/
/* signals */
void (*destroyed) (EekboardContextService *self);
/*< private >*/
/* padding */
gpointer pdummy[24];
};
GType eekboard_context_service_get_type
(void) G_GNUC_CONST;
EekboardContextService *eekboard_context_service_new(struct squeek_layout_state *state);
void eekboard_context_service_set_submission(EekboardContextService *context, struct submission *submission);
void eekboard_context_service_set_ui(EekboardContextService *context, ServerContextService *ui);
@ -95,6 +50,6 @@ void eekboard_context_service_set_hint_purpose(EekboardContextService *context,
uint32_t hint,
uint32_t purpose);
void
eekboard_context_service_use_layout(EekboardContextService *context, struct squeek_layout_state *layout);
eekboard_context_service_use_layout(EekboardContextService *context, struct squeek_layout_state *layout, uint32_t timestamp);
G_END_DECLS
#endif /* EEKBOARD_CONTEXT_SERVICE_H */

View File

@ -5,6 +5,7 @@ use std::env;
fn main() -> () {
check_builtin_layout(
env::args().nth(1).expect("No argument given").as_str()
env::args().nth(1).expect("No argument given").as_str(),
env::args().nth(2).map(|s| s == "allow_missing_return").unwrap_or(false),
);
}

View File

@ -1,7 +1,7 @@
project(
'squeekboard',
'c', 'rust',
version: '1.9.3',
version: '1.13.0',
license: 'GPLv3',
meson_version: '>=0.51.0',
default_options: [
@ -19,6 +19,17 @@ add_project_arguments(
'-Werror=missing-field-initializers',
'-Werror=incompatible-pointer-types',
'-Werror=int-conversion',
'-Werror=redundant-decls',
'-Werror=parentheses',
'-Wformat-nonliteral',
'-Wformat-security',
'-Wformat',
'-Winit-self',
'-Wmaybe-uninitialized',
'-Wold-style-definition',
'-Wredundant-decls',
'-Wstrict-prototypes',
'-Wunused',
],
language: 'c'
)
@ -30,6 +41,16 @@ conf_data = configuration_data()
if get_option('buildtype').startswith('debug')
add_project_arguments('-DDEBUG=1', language : 'c')
endif
if get_option('strict')
add_project_arguments(
[
'-Werror',
],
language: 'c'
)
endif
if get_option('buildtype') != 'plain'
add_project_arguments('-fstack-protector-strong', language: 'c')
endif
@ -62,6 +83,7 @@ summary = [
message('\n'.join(summary))
# Rust deps are changing, depending on compile flags. Cargo can't handle it alone.
# As a side effect, Cargo.toml never gets used.
cargo_toml_in = files('Cargo.toml.in')
path_data = configuration_data()
path_data.set('path', meson.source_root())
@ -75,7 +97,7 @@ cargo_toml_base = configure_file(
cargo_deps = files('Cargo.deps')
if get_option('legacy') == true
cargo_build_flags += ['--features', 'gtk_v0_5,gio_v0_5']
cargo_build_flags += ['--features', 'gtk_v0_5,gio_v0_5,rustc_less_1_36']
cargo_deps = files('Cargo.deps.legacy')
endif
@ -89,7 +111,7 @@ cargo_toml = custom_target(
dep_cargo = find_program('cargo')
cargo_script = find_program('cargo.sh')
cargo_build = find_program('cargo_build.sh')
cargo_build = find_program('cargo_build.py')
subdir('data')
subdir('protocols')

View File

@ -10,3 +10,7 @@ option('tests',
option('legacy',
type: 'boolean', value: false,
description: 'Build with Deban Buster versions of dependencies')
option('strict',
type: 'boolean', value: true,
description: 'Turn more warnings into errors')

View File

@ -294,8 +294,8 @@
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
equal to the number of done events already issued on that object.
When the compositor receives a commit request 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.

View File

@ -10,13 +10,14 @@ pub struct KeySym(pub String);
type View = String;
/// Use to send modified keypresses
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Modifier {
/// Control and Alt are the only modifiers
/// which doesn't interfere with levels,
/// so it's simple to implement as levels are deprecated in squeekboard.
Control,
Alt,
Mod4,
}
/// Action to perform on the keypress and, in reverse, on keyrelease
@ -29,6 +30,11 @@ pub enum Action {
lock: View,
/// When unlocked by pressing it or emitting a key
unlock: View,
/// Whether key has a latched state
/// that pops when another key is pressed.
latches: bool,
/// Should take on *locked* appearance whenever latch comes back to those views.
looks_locked_from: Vec<View>,
},
/// Hold this modifier for as long as the button is pressed
ApplyModifier(Modifier),
@ -48,14 +54,24 @@ pub enum Action {
impl Action {
pub fn is_locked(&self, view_name: &str) -> bool {
match self {
Action::LockView { lock, unlock: _ } => lock == view_name,
Action::LockView { lock, unlock: _, latches: _, looks_locked_from: _ } => lock == view_name,
_ => false,
}
}
pub fn has_locked_appearance_from(&self, locked_view_name: &str) -> bool {
match self {
Action::LockView { lock: _, unlock: _, latches: _, looks_locked_from } => {
looks_locked_from.iter()
.find(|view| locked_view_name == view.as_str())
.is_some()
},
_ => false,
}
}
pub fn is_active(&self, view_name: &str) -> bool {
match self {
Action::SetView(view) => view == view_name,
Action::LockView { lock, unlock: _ } => lock == view_name,
Action::LockView { lock, unlock: _, latches: _, looks_locked_from: _ } => lock == view_name,
_ => false,
}
}

View File

@ -12,13 +12,14 @@ use std::io;
use std::path::PathBuf;
use std::rc::Rc;
use std::vec::Vec;
use std::convert::TryFrom;
use xkbcommon::xkb;
use ::action;
use ::keyboard::{
KeyState, PressType,
generate_keymap, generate_keycodes, FormattingError
generate_keymaps, generate_keycodes, KeyCode, FormattingError
};
use ::layout;
use ::layout::ArrangementKind;
@ -27,6 +28,7 @@ use ::resources;
use ::util::c::as_str;
use ::util::hash_map_map;
use ::xdg;
use ::imservice::ContentPurpose;
// traits, derives
use serde::Deserialize;
@ -42,19 +44,37 @@ pub mod c {
#[no_mangle]
pub extern "C"
fn squeek_load_layout(
name: *const c_char,
type_: u32,
name: *const c_char, // name of the keyboard
type_: u32, // type like Wide
variant: u32, // purpose variant like numeric, terminal...
overlay: *const c_char, // the overlay (looking for "terminal")
) -> *mut ::layout::Layout {
let type_ = match type_ {
0 => ArrangementKind::Base,
1 => ArrangementKind::Wide,
_ => panic!("Bad enum value"),
};
let name = as_str(&name)
.expect("Bad layout name")
.expect("Empty layout name");
let (kind, layout) = load_layout_data_with_fallback(&name, type_);
let variant = ContentPurpose::try_from(variant)
.or_print(
logging::Problem::Warning,
"Received invalid purpose value",
)
.unwrap_or(ContentPurpose::Normal);
let overlay_str = as_str(&overlay)
.expect("Bad overlay name")
.expect("Empty overlay name");
let overlay_str = match overlay_str {
"" => None,
other => Some(other),
};
let (kind, layout) = load_layout_data_with_fallback(&name, type_, variant, overlay_str);
let layout = ::layout::Layout::new(layout, kind);
Box::into_raw(Box::new(layout))
}
@ -97,62 +117,156 @@ impl fmt::Display for DataSource {
}
}
/// Lists possible sources, with 0 as the most preferred one
/// Trying order: native lang of the right kind, native base,
/// fallback lang of the right kind, fallback base
fn list_layout_sources(
name: &str,
kind: ArrangementKind,
keyboards_path: Option<PathBuf>,
) -> Vec<(ArrangementKind, DataSource)> {
/* All functions in this family carry around ArrangementKind,
* because it's not guaranteed to be preserved,
* and the resulting layout needs to know which version was loaded.
* See `squeek_layout_get_kind`.
* Possible TODO: since this is used only in styling,
* and makes the below code nastier than needed, maybe it should go.
*/
/// Returns ordered names treating `name` as the base name,
/// ignoring any `+` inside.
fn _get_arrangement_names(name: &str, arrangement: ArrangementKind)
-> Vec<(ArrangementKind, String)>
{
let name_with_arrangement = match arrangement {
ArrangementKind::Base => name.into(),
ArrangementKind::Wide => format!("{}_wide", name),
};
let mut ret = Vec::new();
{
fn name_with_arrangement(name: String, kind: &ArrangementKind)
-> String
{
match kind {
ArrangementKind::Base => name,
ArrangementKind::Wide => name + "_wide",
if name_with_arrangement != name {
ret.push((arrangement, name_with_arrangement));
}
ret.push((ArrangementKind::Base, name.into()));
ret
}
/// Returns names accounting for any `+` in the `name`,
/// including the fallback to the default layout.
fn get_preferred_names(name: &str, kind: ArrangementKind)
-> Vec<(ArrangementKind, String)>
{
let mut ret = _get_arrangement_names(name, kind);
let base_name_preferences = {
let mut parts = name.splitn(2, '+');
match parts.next() {
Some(base) => {
// The name is already equal to base, so nothing to add
if base == name {
vec![]
} else {
_get_arrangement_names(base, kind)
}
},
// The layout's base name starts with a "+". Weird but OK.
None => {
log_print!(logging::Level::Surprise, "Base layout name is empty: {}", name);
vec![]
}
}
};
ret.extend(base_name_preferences.into_iter());
let fallback_names = _get_arrangement_names(FALLBACK_LAYOUT_NAME, kind);
ret.extend(fallback_names.into_iter());
ret
}
let mut add_by_name = |name: &str, kind: &ArrangementKind| {
if let Some(path) = keyboards_path.clone() {
ret.push((
kind.clone(),
DataSource::File(
path.join(name.to_owned()).with_extension("yaml")
)
))
}
ret.push((
kind.clone(),
DataSource::Resource(name.into())
/// Includes the subdirectory before the forward slash.
type LayoutPath = String;
// This is only used inside iter_fallbacks_with_meta.
// Placed at the top scope
// because `use LayoutPurpose::*;`
// complains about "not in scope" otherwise.
// This seems to be a Rust 2015 edition problem.
/// Helper for determining where to look up the layout.
enum LayoutPurpose<'a> {
Default,
Special(&'a str),
}
/// Returns the directory string
/// where the layout should be looked up, including the slash.
fn get_directory_string(
content_purpose: ContentPurpose,
overlay: Option<&str>) -> String
{
use self::LayoutPurpose::*;
let layout_purpose = match overlay {
None => match content_purpose {
ContentPurpose::Number => Special("number"),
ContentPurpose::Digits => Special("number"),
ContentPurpose::Phone => Special("number"),
ContentPurpose::Terminal => Special("terminal"),
_ => Default,
},
Some(overlay) => Special(overlay),
};
// For intuitiveness,
// default purpose layouts are stored in the root directory,
// as they correspond to typical text
// and are seen the most often.
match layout_purpose {
Default => "".into(),
Special(purpose) => format!("{}/", purpose),
}
}
/// Returns an iterator over all fallback paths.
fn to_layout_paths(
name_fallbacks: Vec<(ArrangementKind, String)>,
content_purpose: ContentPurpose,
overlay: Option<&str>,
) -> impl Iterator<Item=(ArrangementKind, LayoutPath)> {
let prepend_directory = get_directory_string(content_purpose, overlay);
name_fallbacks.into_iter()
.map(move |(arrangement, name)|
(arrangement, format!("{}{}", prepend_directory, name))
)
}
type LayoutSource = (ArrangementKind, DataSource);
fn to_layout_sources(
layout_paths: impl Iterator<Item=(ArrangementKind, LayoutPath)>,
filesystem_path: Option<PathBuf>,
) -> impl Iterator<Item=LayoutSource> {
layout_paths.flat_map(move |(arrangement, layout_path)| {
let mut sources = Vec::new();
if let Some(path) = &filesystem_path {
sources.push((
arrangement,
DataSource::File(
path.join(&layout_path)
.with_extension("yaml")
)
));
};
sources.push((arrangement, DataSource::Resource(layout_path.clone())));
sources.into_iter()
})
}
match &kind {
ArrangementKind::Base => {},
kind => add_by_name(
&name_with_arrangement(name.into(), &kind),
&kind,
),
};
add_by_name(name, &ArrangementKind::Base);
match &kind {
ArrangementKind::Base => {},
kind => add_by_name(
&name_with_arrangement(FALLBACK_LAYOUT_NAME.into(), &kind),
&kind,
),
};
add_by_name(FALLBACK_LAYOUT_NAME, &ArrangementKind::Base);
}
ret
/// Returns possible sources, with first as the most preferred one.
/// Trying order: native lang of the right kind, native base,
/// fallback lang of the right kind, fallback base
fn iter_layout_sources(
name: &str,
arrangement: ArrangementKind,
purpose: ContentPurpose,
ui_overlay: Option<&str>,
layout_storage: Option<PathBuf>,
) -> impl Iterator<Item=LayoutSource> {
let names = get_preferred_names(name, arrangement);
let paths = to_layout_paths(names, purpose, ui_overlay);
to_layout_sources(paths, layout_storage)
}
fn load_layout_data(source: DataSource)
@ -179,12 +293,16 @@ fn load_layout_data(source: DataSource)
fn load_layout_data_with_fallback(
name: &str,
kind: ArrangementKind,
purpose: ContentPurpose,
overlay: Option<&str>,
) -> (ArrangementKind, ::layout::LayoutData) {
// Build the path to the right keyboard layout subdirectory
let path = env::var_os("SQUEEKBOARD_KEYBOARDSDIR")
.map(PathBuf::from)
.or_else(|| xdg::data_path("squeekboard/keyboards"));
for (kind, source) in list_layout_sources(name, kind, path) {
for (kind, source) in iter_layout_sources(&name, kind, purpose, overlay, path) {
let layout = load_layout_data(source.clone());
match layout {
Err(e) => match (e, source) {
@ -266,7 +384,13 @@ struct ButtonMeta {
#[serde(deny_unknown_fields)]
enum Action {
#[serde(rename="locking")]
Locking { lock_view: String, unlock_view: String },
Locking {
lock_view: String,
unlock_view: String,
pops: Option<bool>,
#[serde(default)]
looks_locked_from: Vec<String>,
},
#[serde(rename="set_view")]
SetView(String),
#[serde(rename="show_prefs")]
@ -382,56 +506,45 @@ impl Layout {
)
)}).collect();
let keymap: HashMap<String, u32> = generate_keycodes(
button_actions.iter()
.filter_map(|(_name, action)| {
match action {
::action::Action::Submit {
text: _, keys,
} => Some(keys),
_ => None,
}
})
.flatten()
.map(|named_keysym| named_keysym.0.as_str())
let symbolmap: HashMap<String, KeyCode> = generate_keycodes(
extract_symbol_names(&button_actions)
);
let button_states = button_actions.into_iter().map(|(name, action)| {
let keycodes = match &action {
::action::Action::Submit { text: _, keys } => {
keys.iter().map(|named_keycode| {
*keymap.get(named_keycode.0.as_str())
.expect(
format!(
"keycode {} in key {} missing from keymap",
named_keycode.0,
name
).as_str()
)
}).collect()
},
action::Action::Erase => vec![
*keymap.get("BackSpace")
.expect(&format!("BackSpace missing from keymap")),
],
_ => Vec::new(),
};
(
name.into(),
KeyState {
pressed: PressType::Released,
keycodes,
action,
}
)
});
let button_states = HashMap::<String, KeyState>::from_iter(
button_states
button_actions.into_iter().map(|(name, action)| {
let keycodes = match &action {
::action::Action::Submit { text: _, keys } => {
keys.iter().map(|named_keysym| {
symbolmap.get(named_keysym.0.as_str())
.expect(
format!(
"keysym {} in key {} missing from symbol map",
named_keysym.0,
name
).as_str()
)
.clone()
}).collect()
},
action::Action::Erase => vec![
symbolmap.get("BackSpace")
.expect(&format!("BackSpace missing from symbol map"))
.clone(),
],
_ => Vec::new(),
};
(
name.into(),
KeyState {
pressed: PressType::Released,
keycodes,
action,
}
)
})
);
// TODO: generate from symbols
let keymap_str = match generate_keymap(&button_states) {
let keymaps = match generate_keymaps(symbolmap) {
Err(e) => { return (Err(e), warning_handler) },
Ok(v) => v,
};
@ -459,14 +572,14 @@ impl Layout {
&mut warning_handler,
))
});
layout::Row {
buttons: add_offsets(
layout::Row::new(
add_offsets(
buttons,
|button| button.size.width,
).collect()
}
)
});
let rows = add_offsets(rows, |row| row.get_height())
let rows = add_offsets(rows, |row| row.get_size().height)
.collect();
(
name.clone(),
@ -484,8 +597,8 @@ impl Layout {
name,
(
layout::c::Point {
x: (total_size.width - view.get_width()) / 2.0,
y: (total_size.height - view.get_height()) / 2.0,
x: (total_size.width - view.get_size().width) / 2.0,
y: (total_size.height - view.get_size().height) / 2.0,
},
view,
),
@ -495,10 +608,10 @@ impl Layout {
(
Ok(::layout::LayoutData {
views: views,
keymap_str: {
keymaps: keymaps.into_iter().map(|keymap_str|
CString::new(keymap_str)
.expect("Invalid keymap string generated")
},
).collect(),
// FIXME: use a dedicated field
margins: layout::Margins {
top: self.margins.top,
@ -531,7 +644,7 @@ fn create_action<H: logging::Handler>(
Text(String),
Keysym(String),
Modifier(Modifier),
};
}
let submission = match (
&symbol_meta.action,
@ -588,7 +701,9 @@ fn create_action<H: logging::Handler>(
)
),
SubmitData::Action(Action::Locking {
lock_view, unlock_view
lock_view, unlock_view,
pops,
looks_locked_from,
}) => ::action::Action::LockView {
lock: filter_view_name(
name,
@ -602,6 +717,8 @@ fn create_action<H: logging::Handler>(
&view_names,
warning_handler,
),
latches: pops.unwrap_or(true),
looks_locked_from,
},
SubmitData::Action(
Action::ShowPrefs
@ -646,6 +763,9 @@ fn create_action<H: logging::Handler>(
Modifier::Alt => action::Action::ApplyModifier(
action::Modifier::Alt,
),
Modifier::Mod4 => action::Action::ApplyModifier(
action::Modifier::Mod4,
),
unsupported_modifier => {
warning_handler.handle(
logging::Level::Bug,
@ -734,20 +854,44 @@ fn create_button<H: logging::Handler>(
}
}
fn extract_symbol_names<'a>(actions: &'a [(&str, action::Action)])
-> impl Iterator<Item=String> + 'a
{
actions.iter()
.filter_map(|(_name, act)| {
match act {
action::Action::Submit {
text: _, keys,
} => Some(keys.clone()),
action::Action::Erase => Some(vec!(action::KeySym("BackSpace".into()))),
_ => None,
}
})
.flatten()
.map(|named_keysym| named_keysym.0)
}
#[cfg(test)]
mod tests {
use super::*;
use std::error::Error as ErrorTrait;
use ::logging::ProblemPanic;
const THIS_FILE: &str = file!();
fn path_from_root(file: &'static str) -> PathBuf {
PathBuf::from(THIS_FILE)
.parent().unwrap()
.parent().unwrap()
.join(file)
let source_dir = env::var("SOURCE_DIR")
.map(PathBuf::from)
.unwrap_or_else(|e| {
if let env::VarError::NotPresent = e {
let this_file = file!();
PathBuf::from(this_file)
.parent().unwrap()
.parent().unwrap()
.into()
} else {
panic!("{:?}", e);
}
});
source_dir.join(file)
}
#[test]
@ -786,7 +930,8 @@ mod tests {
Err(e) => {
let mut handled = false;
if let Error::Yaml(ye) = &e {
handled = ye.description() == "missing field `views`";
handled = ye.to_string()
.starts_with("missing field `views`");
};
if !handled {
println!("Unexpected error {:?}", e);
@ -804,7 +949,7 @@ mod tests {
Err(e) => {
let mut handled = false;
if let Error::Yaml(ye) = &e {
handled = ye.description()
handled = ye.to_string()
.starts_with("unknown field `bad_field`");
};
if !handled {
@ -824,7 +969,7 @@ mod tests {
assert_eq!(
out.views["base"].1
.get_rows()[0].1
.buttons[0].1
.get_buttons()[0].1
.label,
::layout::Label::Text(CString::new("test").unwrap())
);
@ -839,7 +984,7 @@ mod tests {
assert_eq!(
out.views["base"].1
.get_rows()[0].1
.buttons[0].1
.get_buttons()[0].1
.label,
::layout::Label::Text(CString::new("test").unwrap())
);
@ -855,13 +1000,30 @@ mod tests {
assert_eq!(
out.views["base"].1
.get_rows()[0].1
.buttons[0].1
.get_buttons()[0].1
.state.borrow()
.keycodes.len(),
2
);
}
/// Test if erase yields a useable keycode
#[test]
fn test_layout_erase() {
let out = Layout::from_file(path_from_root("tests/layout_erase.yaml"))
.unwrap()
.build(ProblemPanic).0
.unwrap();
assert_eq!(
out.views["base"].1
.get_rows()[0].1
.get_buttons()[0].1
.state.borrow()
.keycodes.len(),
1
);
}
#[test]
fn parsing_fallback() {
assert!(Layout::from_resource(FALLBACK_LAYOUT_NAME)
@ -872,11 +1034,11 @@ mod tests {
/// First fallback should be to builtin, not to FALLBACK_LAYOUT_NAME
#[test]
fn fallbacks_order() {
let sources = list_layout_sources("nb", ArrangementKind::Base, None);
fn test_fallback_basic_builtin() {
let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Normal, None, None);
assert_eq!(
sources,
sources.collect::<Vec<_>>(),
vec!(
(ArrangementKind::Base, DataSource::Resource("nb".into())),
(
@ -887,6 +1049,99 @@ mod tests {
);
}
/// Prefer loading from file system before builtin.
#[test]
fn test_preferences_order_path() {
let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Normal, None, Some(".".into()));
assert_eq!(
sources.collect::<Vec<_>>(),
vec!(
(ArrangementKind::Base, DataSource::File("./nb.yaml".into())),
(ArrangementKind::Base, DataSource::Resource("nb".into())),
(
ArrangementKind::Base,
DataSource::File("./us.yaml".into())
),
(
ArrangementKind::Base,
DataSource::Resource("us".into())
),
)
);
}
/// If layout contains a "+", it should reach for what's in front of it too.
#[test]
fn test_preferences_order_base() {
let sources = iter_layout_sources("nb+aliens", ArrangementKind::Base, ContentPurpose::Normal, None, None);
assert_eq!(
sources.collect::<Vec<_>>(),
vec!(
(ArrangementKind::Base, DataSource::Resource("nb+aliens".into())),
(ArrangementKind::Base, DataSource::Resource("nb".into())),
(
ArrangementKind::Base,
DataSource::Resource(FALLBACK_LAYOUT_NAME.into())
),
)
);
}
#[test]
fn test_preferences_order_arrangement() {
let sources = iter_layout_sources("nb", ArrangementKind::Wide, ContentPurpose::Normal, None, None);
assert_eq!(
sources.collect::<Vec<_>>(),
vec!(
(ArrangementKind::Wide, DataSource::Resource("nb_wide".into())),
(ArrangementKind::Base, DataSource::Resource("nb".into())),
(
ArrangementKind::Wide,
DataSource::Resource("us_wide".into())
),
(
ArrangementKind::Base,
DataSource::Resource("us".into())
),
)
);
}
#[test]
fn test_preferences_order_overlay() {
let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Normal, Some("terminal"), None);
assert_eq!(
sources.collect::<Vec<_>>(),
vec!(
(ArrangementKind::Base, DataSource::Resource("terminal/nb".into())),
(
ArrangementKind::Base,
DataSource::Resource("terminal/us".into())
),
)
);
}
#[test]
fn test_preferences_order_hint() {
let sources = iter_layout_sources("nb", ArrangementKind::Base, ContentPurpose::Terminal, None, None);
assert_eq!(
sources.collect::<Vec<_>>(),
vec!(
(ArrangementKind::Base, DataSource::Resource("terminal/nb".into())),
(
ArrangementKind::Base,
DataSource::Resource("terminal/us".into())
),
)
);
}
#[test]
fn unicode_keysym() {
let keysym = xkb::keysym_from_name(
@ -939,4 +1194,35 @@ mod tests {
}
);
}
#[test]
fn test_extract_symbols() {
let actions = [(
"ac",
action::Action::Submit {
text: None,
keys: vec![
action::KeySym("a".into()),
action::KeySym("c".into()),
],
},
)];
assert_eq!(
extract_symbol_names(&actions[..]).collect::<Vec<_>>(),
vec!["a", "c"],
);
}
#[test]
fn test_extract_symbols_erase() {
let actions = [(
"Erase",
action::Action::Erase,
)];
assert_eq!(
extract_symbol_names(&actions[..]).collect::<Vec<_>>(),
vec!["BackSpace"],
);
}
}

View File

@ -59,7 +59,7 @@ handle_set_visible(SmPuriOSK0 *object, GDBusMethodInvocation *invocation,
if (service->context) {
if (arg_visible) {
server_context_service_show_keyboard (service->context);
server_context_service_force_show_keyboard (service->context);
} else {
server_context_service_hide_keyboard (service->context);
}

View File

@ -3,20 +3,24 @@
use cairo;
use std::cell::RefCell;
use ::action::Action;
use ::action::{ Action, Modifier };
use ::keyboard;
use ::layout::{ Button, Layout };
use ::layout::c::{ EekGtkKeyboard, Point };
use ::layout::{ Button, Label, LatchedState, Layout };
use ::layout::c::{ Bounds, EekGtkKeyboard, Point };
use ::submission::Submission;
use glib::translate::FromGlibPtrNone;
use gtk::WidgetExt;
use std::collections::HashSet;
use std::ffi::CStr;
use std::ptr;
mod c {
use super::*;
use cairo_sys;
use std::os::raw::c_void;
use std::os::raw::{ c_char, c_void };
// This is constructed only in C, no need for warnings
#[allow(dead_code)]
@ -24,18 +28,44 @@ mod c {
#[derive(Clone, Copy)]
pub struct EekRenderer(*const c_void);
#[no_mangle]
// This is constructed only in C, no need for warnings
/// Just don't clone this for no reason.
#[allow(dead_code)]
#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct GtkStyleContext(*const c_void);
extern "C" {
// Button and View inside CButtonPlace are safe to pass to C
// as long as they don't outlive the call
// and nothing dereferences them
#[allow(improper_ctypes)]
pub fn eek_render_button(
pub fn eek_renderer_get_scale_factor(
renderer: EekRenderer,
) -> u32;
#[allow(improper_ctypes)]
pub fn eek_render_button_in_context(
scale_factor: u32,
cr: *mut cairo_sys::cairo_t,
button: *const Button,
ctx: GtkStyleContext,
bounds: Bounds,
icon_name: *const c_char,
label: *const c_char,
);
#[allow(improper_ctypes)]
pub fn eek_get_style_context_for_button(
renderer: EekRenderer,
name: *const c_char,
outline_name: *const c_char,
locked_class: *const c_char,
pressed: u64,
locked: u64,
) -> GtkStyleContext;
#[allow(improper_ctypes)]
pub fn eek_put_style_context_for_button(
ctx: GtkStyleContext,
outline_name: *const c_char,
locked_class: *const c_char,
);
}
@ -55,13 +85,16 @@ mod c {
layout.foreach_visible_button(|offset, button| {
let state = RefCell::borrow(&button.state).clone();
let active_mod = match &state.action {
Action::ApplyModifier(m) => active_modifiers.contains(m),
_ => false,
};
let locked = state.action.is_active(&layout.current_view)
| active_mod;
if state.pressed == keyboard::PressType::Pressed || locked {
let locked = LockedStyle::from_action(
&state.action,
&active_modifiers,
layout.get_view_latched(),
&layout.current_view,
);
if state.pressed == keyboard::PressType::Pressed
|| locked != LockedStyle::Free
{
render_button_at_position(
renderer, &cr,
offset,
@ -87,20 +120,55 @@ mod c {
renderer, &cr,
offset,
button.as_ref(),
keyboard::PressType::Released, false,
keyboard::PressType::Released,
LockedStyle::Free,
);
})
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
enum LockedStyle {
Free,
Latched,
Locked,
}
impl LockedStyle {
fn from_action(
action: &Action,
mods: &HashSet<Modifier>,
latched_view: &LatchedState,
current_view: &str,
) -> LockedStyle {
let active_mod = match action {
Action::ApplyModifier(m) => mods.contains(m),
_ => false,
};
let active_view = action.is_active(current_view);
let latched_button = match latched_view {
LatchedState::Not => false,
LatchedState::FromView(view) => !action.has_locked_appearance_from(view),
};
match (active_mod, active_view, latched_button) {
// Modifiers don't latch.
(true, _, _) => LockedStyle::Locked,
(false, true, false) => LockedStyle::Locked,
(false, true, true) => LockedStyle::Latched,
_ => LockedStyle::Free,
}
}
}
/// Renders a button at a position (button's own bounds ignored)
pub fn render_button_at_position(
fn render_button_at_position(
renderer: c::EekRenderer,
cr: &cairo::Context,
position: Point,
button: &Button,
pressed: keyboard::PressType,
locked: bool,
locked: LockedStyle,
) {
cr.save();
cr.translate(position.x, position.y);
@ -109,19 +177,110 @@ pub fn render_button_at_position(
button.size.width, button.size.height
);
cr.clip();
unsafe {
c::eek_render_button(
let scale_factor = unsafe {
c::eek_renderer_get_scale_factor(renderer)
};
let bounds = button.get_bounds();
let (label_c, icon_name_c) = match &button.label {
Label::Text(text) => (text.as_ptr(), ptr::null()),
Label::IconName(name) => {
let l = unsafe {
// CStr doesn't allocate anything, so it only points to
// the 'static str, avoiding a memory leak
CStr::from_bytes_with_nul_unchecked(b"icon\0")
};
(l.as_ptr(), name.as_ptr())
},
};
with_button_context(
renderer,
button,
pressed,
locked,
|ctx| unsafe {
// TODO: split into separate procedures:
// draw outline, draw label, draw icon.
c::eek_render_button_in_context(
scale_factor,
cairo::Context::to_raw_none(&cr),
*ctx,
bounds,
icon_name_c,
label_c,
)
}
);
cr.restore();
}
fn with_button_context<R, F: FnOnce(&c::GtkStyleContext) -> R>(
renderer: c::EekRenderer,
button: &Button,
pressed: keyboard::PressType,
locked: LockedStyle,
operation: F,
) -> R {
let outline_name_c = button.outline_name.as_ptr();
let locked_class_c = match locked {
LockedStyle::Free => ptr::null(),
LockedStyle::Locked => unsafe {
CStr::from_bytes_with_nul_unchecked(b"locked\0").as_ptr()
},
LockedStyle::Latched => unsafe {
CStr::from_bytes_with_nul_unchecked(b"latched\0").as_ptr()
},
};
let ctx = unsafe {
c::eek_get_style_context_for_button(
renderer,
cairo::Context::to_raw_none(&cr),
button as *const Button,
button.name.as_ptr(),
outline_name_c,
locked_class_c,
pressed as u64,
locked as u64,
)
};
cr.restore();
let r = operation(&ctx);
unsafe {
c::eek_put_style_context_for_button(
ctx,
outline_name_c,
locked_class_c,
)
};
r
}
pub fn queue_redraw(keyboard: EekGtkKeyboard) {
let widget = unsafe { gtk::Widget::from_glib_none(keyboard.0) };
widget.queue_draw();
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_exit_only() {
assert_eq!(
LockedStyle::from_action(
&Action::LockView {
lock: "ab".into(),
unlock: "a".into(),
latches: true,
looks_locked_from: vec!["b".into()],
},
&HashSet::new(),
&LatchedState::FromView("b".into()),
"ab",
),
LockedStyle::Locked,
);
}
}

View File

@ -25,6 +25,7 @@ static const struct zwp_input_method_v2_listener input_method_listener = {
struct submission* get_submission(struct zwp_input_method_manager_v2 *immanager,
struct zwp_virtual_keyboard_manager_v1 *vkmanager,
struct vis_manager *vis_manager,
struct wl_seat *seat,
EekboardContextService *state) {
struct zwp_input_method_v2 *im = NULL;
@ -35,7 +36,7 @@ struct submission* get_submission(struct zwp_input_method_manager_v2 *immanager,
if (vkmanager) {
vk = zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(vkmanager, seat);
}
return submission_new(im, vk, state);
return submission_new(im, vk, state, vis_manager);
}
/// Un-inlined

View File

@ -23,7 +23,7 @@ pub mod c {
use std::os::raw::{c_char, c_void};
pub use ::submission::c::UIManager;
pub use ::ui_manager::c::UIManager;
pub use ::submission::c::StateManager;
// The following defined in C
@ -32,17 +32,15 @@ pub mod c {
#[repr(transparent)]
pub struct InputMethod(*const c_void);
#[no_mangle]
extern "C" {
fn imservice_destroy_im(im: *mut c::InputMethod);
#[allow(improper_ctypes)] // IMService will never be dereferenced in C
pub fn imservice_connect_listeners(im: *mut InputMethod, imservice: *const IMService);
pub fn eek_input_method_commit_string(im: *mut InputMethod, text: *const c_char);
pub fn eek_input_method_delete_surrounding_text(im: *mut InputMethod, before: u32, after: u32);
pub fn eek_input_method_commit(im: *mut InputMethod, serial: u32);
fn eekboard_context_service_set_hint_purpose(state: *const StateManager, hint: u32, purpose: u32);
fn server_context_service_show_keyboard(imservice: *const UIManager);
fn server_context_service_hide_keyboard(imservice: *const UIManager);
}
// The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
@ -151,11 +149,11 @@ pub mod c {
..IMProtocolState::default()
};
imservice.serial += Wrapping(1u32);
if active_changed {
(imservice.active_callback)(imservice.current.active);
if imservice.current.active {
if let Some(ui) = imservice.ui_manager {
unsafe { server_context_service_show_keyboard(ui); }
}
unsafe {
eekboard_context_service_set_hint_purpose(
imservice.state_manager,
@ -163,10 +161,6 @@ pub mod c {
imservice.current.content_purpose.clone() as u32,
);
}
} else {
if let Some(ui) = imservice.ui_manager {
unsafe { server_context_service_hide_keyboard(ui); }
}
}
}
}
@ -184,9 +178,7 @@ pub mod c {
// the keyboard is already decommissioned
imservice.current.active = false;
if let Some(ui) = imservice.ui_manager {
unsafe { server_context_service_hide_keyboard(ui); }
}
(imservice.active_callback)(imservice.current.active);
}
// FIXME: destroy and deallocate
@ -339,8 +331,7 @@ pub struct IMService {
pub im: *mut c::InputMethod,
/// Unowned reference. Be careful, it's shared with C at large
state_manager: *const c::StateManager,
/// Unowned reference. Be careful, it's shared with C at large
pub ui_manager: Option<*const c::UIManager>,
active_callback: Box<dyn Fn(bool)>,
pending: IMProtocolState,
current: IMProtocolState, // turn current into an idiomatic representation?
@ -357,12 +348,13 @@ impl IMService {
pub fn new(
im: *mut c::InputMethod,
state_manager: *const c::StateManager,
active_callback: Box<dyn Fn(bool)>,
) -> Box<IMService> {
// IMService will be referenced to by C,
// so it needs to stay in the same place in memory via Box
let imservice = Box::new(IMService {
im,
ui_manager: None,
active_callback,
state_manager,
pending: IMProtocolState::default(),
current: IMProtocolState::default(),
@ -377,7 +369,7 @@ impl IMService {
}
imservice
}
pub fn commit_string(&self, text: &CString) -> Result<(), SubmitError> {
match self.current.active {
true => {
@ -414,7 +406,6 @@ impl IMService {
unsafe {
c::eek_input_method_commit(self.im, self.serial.0)
}
self.serial += Wrapping(1u32);
Ok(())
},
false => Err(SubmitError::NotActive),

View File

@ -5,11 +5,13 @@ use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt;
use std::io;
use std::mem;
use std::ptr;
use std::rc::Rc;
use std::string::FromUtf8Error;
use ::action::Action;
use ::logging;
use ::util;
// Traits
use std::io::Write;
@ -21,7 +23,12 @@ pub enum PressType {
Pressed = 1,
}
pub type KeyCode = u32;
/// The extended, unambiguous layout-keycode
#[derive(Debug, Clone)]
pub struct KeyCode {
pub code: u32,
pub keymap_idx: usize,
}
bitflags!{
/// Map to `virtual_keyboard.modifiers` modifiers values
@ -43,7 +50,7 @@ bitflags!{
/// When the submitted actions of keys need to be tracked,
/// they need a stable, comparable ID
#[derive(PartialEq)]
#[derive(Clone, PartialEq)]
pub struct KeyStateId(*const KeyState);
#[derive(Debug, Clone)]
@ -80,10 +87,10 @@ impl KeyState {
}
/// Sorts an iterator by converting it to a Vector and back
fn sorted<'a, I: Iterator<Item=&'a str>>(
fn sorted<'a, I: Iterator<Item=String>>(
iter: I
) -> impl Iterator<Item=&'a str> {
let mut v: Vec<&'a str> = iter.collect();
) -> impl Iterator<Item=String> {
let mut v: Vec<String> = iter.collect();
v.sort();
v.into_iter()
}
@ -91,15 +98,17 @@ fn sorted<'a, I: Iterator<Item=&'a str>>(
/// Generates a mapping where each key gets a keycode, starting from ~~8~~
/// HACK: starting from 9, because 8 results in keycode 0,
/// which the compositor likes to discard
pub fn generate_keycodes<'a, C: IntoIterator<Item=&'a str>>(
key_names: C
) -> HashMap<String, u32> {
let special_keysyms = ["BackSpace", "Return"].iter().map(|&s| s);
pub fn generate_keycodes<'a, C: IntoIterator<Item=String>>(
key_names: C,
) -> HashMap<String, KeyCode> {
HashMap::from_iter(
// sort to remove a source of indeterminism in keycode assignment
sorted(key_names.into_iter().chain(special_keysyms))
.map(|name| String::from(name))
.zip(9..)
// Sort to remove a source of indeterminism in keycode assignment.
sorted(key_names.into_iter())
.zip(util::cycle_count(9..255))
.map(|(name, (code, keymap_idx))| (
String::from(name),
KeyCode { code, keymap_idx },
))
)
}
@ -124,12 +133,54 @@ impl From<io::Error> for FormattingError {
}
}
/// Index is the key code, String is the occupant.
/// Starts all empty.
/// https://gitlab.freedesktop.org/xorg/xserver/-/issues/260
type SingleKeyMap = [Option<String>; 256];
fn single_key_map_new() -> SingleKeyMap {
// Why can't we just initialize arrays without tricks -_- ?
unsafe {
// Inspired by
// https://www.reddit.com/r/rust/comments/5n7bh1/how_to_create_an_array_of_a_type_with_clone_but/
#[cfg(feature = "rustc_less_1_36")]
let mut array: SingleKeyMap = mem::uninitialized();
#[cfg(not(feature = "rustc_less_1_36"))]
let mut array: SingleKeyMap = mem::MaybeUninit::uninit().assume_init();
for element in array.iter_mut() {
ptr::write(element, None);
}
array
}
}
pub fn generate_keymaps(symbolmap: HashMap::<String, KeyCode>)
-> Result<Vec<String>, FormattingError>
{
let mut bins: Vec<SingleKeyMap> = Vec::new();
for (name, KeyCode { code, keymap_idx }) in symbolmap.into_iter() {
if keymap_idx >= bins.len() {
bins.resize_with(
keymap_idx + 1,
|| single_key_map_new(),
);
}
bins[keymap_idx][code as usize] = Some(name);
}
let mut out = Vec::new();
for bin in bins {
out.push(generate_keymap(&bin)?);
}
Ok(out)
}
/// Generates a de-facto single level keymap.
// TODO: don't rely on keys and their order,
// but rather on what keysyms and keycodes are in use.
// Iterating actions makes it hard to deduplicate keysyms.
pub fn generate_keymap(
keystates: &HashMap::<String, KeyState>
/// Key codes must not repeat and must remain between 9 and 255.
fn generate_keymap(
symbolmap: &SingleKeyMap,
) -> Result<String, FormattingError> {
let mut buf: Vec<u8> = Vec::new();
writeln!(
@ -140,86 +191,80 @@ pub fn generate_keymap(
minimum = 8;
maximum = 255;"
)?;
let pairs: Vec<(&String, usize)> = symbolmap.iter()
// Attach a key code to each cell.
.enumerate()
// Get rid of empty keycodes.
.filter_map(|(code, name)| name.as_ref().map(|n| (n, code)))
.collect();
for (name, state) in keystates.iter() {
match &state.action {
Action::Submit { text: _, keys } => {
if let 0 = keys.len() {
log_print!(
logging::Level::Warning,
"Key {} has no keysyms", name,
);
};
for (named_keysym, keycode) in keys.iter().zip(&state.keycodes) {
write!(
buf,
"
<{}> = {};",
named_keysym.0,
keycode,
)?;
}
},
Action::Erase => {
let mut keycodes = state.keycodes.iter();
write!(
buf,
"
<BackSpace> = {};",
keycodes.next().expect("Erase key has no keycode"),
)?;
if let Some(_) = keycodes.next() {
log_print!(
logging::Level::Bug,
"Erase key has multiple keycodes",
);
}
},
_ => {},
}
// Xorg can only consume up to 255 keys, so this may not work in Xwayland.
// Two possible solutions:
// - use levels to cram multiple characters into one key
// - swap layouts on key presses
for (_name, keycode) in &pairs {
write!(
buf,
"
<I{}> = {0};",
keycode,
)?;
}
writeln!(
buf,
"
indicator 1 = \"Caps Lock\"; // Xwayland won't accept without it.
}};
xkb_symbols \"squeekboard\" {{
name[Group1] = \"Letters\";
name[Group2] = \"Numbers/Symbols\";
key <BackSpace> {{ [ BackSpace ] }};"
"
)?;
for (name, state) in keystates.iter() {
if let Action::Submit { text: _, keys } = &state.action {
for keysym in keys.iter() {
write!(
buf,
"
key <{}> {{ [ {0} ] }};",
keysym.0,
)?;
}
}
for (name, keycode) in pairs {
write!(
buf,
"
key <I{}> {{ [ {} ] }};",
keycode,
name,
)?;
}
writeln!(
buf,
"
}};
xkb_types \"squeekboard\" {{
virtual_modifiers Squeekboard; // No modifiers! Needed for Xorg for some reason.
// Those names are needed for Xwayland.
type \"ONE_LEVEL\" {{
modifiers= none;
level_name[Level1]= \"Any\";
}};
type \"TWO_LEVEL\" {{
level_name[Level1]= \"Base\";
}};
type \"ALPHABETIC\" {{
level_name[Level1]= \"Base\";
}};
type \"KEYPAD\" {{
level_name[Level1]= \"Base\";
}};
type \"SHIFT+ALT\" {{
level_name[Level1]= \"Base\";
}};
type \"TWO_LEVEL\" {{
modifiers = Shift;
map[Shift] = Level2;
level_name[Level1] = \"Base\";
level_name[Level2] = \"Shift\";
}};
}};
xkb_compatibility \"squeekboard\" {{
// Needed for Xwayland again.
interpret Any+AnyOf(all) {{
action= SetMods(modifiers=modMapMods,clearLocks);
}};
}};
}};"
)?;
@ -234,22 +279,15 @@ mod tests {
use xkbcommon::xkb;
use ::action::KeySym;
#[test]
fn test_keymap_multi() {
let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
fn test_keymap_single_resolve() {
let mut key_map = single_key_map_new();
key_map[9] = Some("a".into());
key_map[10] = Some("c".into());
let keymap_str = generate_keymap(&hashmap!{
"ac".into() => KeyState {
action: Action::Submit {
text: None,
keys: vec!(KeySym("a".into()), KeySym("c".into())),
},
keycodes: vec!(9, 10),
pressed: PressType::Released,
},
}).unwrap();
let keymap_str = generate_keymap(&key_map).unwrap();
let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
let keymap = xkb::Keymap::new_from_string(
&context,
@ -263,4 +301,36 @@ mod tests {
assert_eq!(state.key_get_one_sym(9), xkb::KEY_a);
assert_eq!(state.key_get_one_sym(10), xkb::KEY_c);
}
#[test]
fn test_keymap_second_resolve() {
let keymaps = generate_keymaps(hashmap!(
"a".into() => KeyCode { keymap_idx: 1, code: 9 },
)).unwrap();
let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
let keymap = xkb::Keymap::new_from_string(
&context,
keymaps[1].clone(), // this index is part of the test
xkb::KEYMAP_FORMAT_TEXT_V1,
xkb::KEYMAP_COMPILE_NO_FLAGS,
).expect("Failed to create keymap");
let state = xkb::State::new(&keymap);
assert_eq!(state.key_get_one_sym(9), xkb::KEY_a);
}
#[test]
fn test_symbolmap_overflow() {
// The 257th key (U1101) is interesting.
// Use Unicode encoding for being able to use in xkb keymaps.
let keynames = (0..258).map(|num| format!("U{:04X}", 0x1000 + num));
let keycodes = generate_keycodes(keynames);
// test now
let code = keycodes.get("U1101").expect("Did not find the tested keysym");
assert_eq!(code.keymap_idx, 1);
}
}

View File

@ -26,20 +26,12 @@ struct squeek_layout_state {
struct squeek_layout;
EekBounds squeek_button_get_bounds(const struct squeek_button*);
const char *squeek_button_get_label(const struct squeek_button*);
const char *squeek_button_get_icon_name(const struct squeek_button*);
const char *squeek_button_get_name(const struct squeek_button*);
const char *squeek_button_get_outline_name(const struct squeek_button*);
void squeek_button_print(const struct squeek_button* button);
struct transformation squeek_layout_calculate_transformation(
const struct squeek_layout *layout,
double allocation_width, double allocation_size);
struct squeek_layout *squeek_load_layout(const char *name, uint32_t type);
const char *squeek_layout_get_keymap(const struct squeek_layout*);
struct squeek_layout *squeek_load_layout(const char *name, uint32_t type, uint32_t variant_type, const char *overlay_name);
enum squeek_arrangement_kind squeek_layout_get_kind(const struct squeek_layout *);
void squeek_layout_free(struct squeek_layout*);

File diff suppressed because it is too large Load Diff

View File

@ -24,7 +24,6 @@ mod c {
#[repr(C)]
pub struct GnomeXkbInfo(*const c_void);
#[no_mangle]
extern "C" {
// from libc
pub fn strcoll(cs: *const c_char, ct: *const c_char) -> c_int;

View File

@ -31,22 +31,16 @@ pub enum Error {
impl ::std::fmt::Display for Error {
fn fmt(&self, out: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
use ::std::error::Error;
out.write_str(self.description())
}
}
impl ::std::error::Error for Error {
fn description(&self) -> &str {
match self {
out.write_str(match self {
&Error::NotWellFormed => "Language tag is not well-formed.",
// this is exception: here we do want exhaustive match so we don't publish version with
// missing descriptions by mistake.
&Error::__NonExhaustive => panic!("Placeholder error must not be instantiated!"),
}
})
}
}
/// Convenience Result alias.
type Result<T> = ::std::result::Result<T, Error>;

View File

@ -9,7 +9,6 @@ pub mod c {
#[derive(Clone, Copy)]
pub struct Manager(*const c_void);
#[no_mangle]
extern "C" {
pub fn eekboard_context_service_set_overlay(
manager: Manager,

View File

@ -14,6 +14,7 @@ sources = [
config_h,
'dbus.c',
'imservice.c',
'popover.c',
'server-context-service.c',
'wayland.c',
'../eek/eek.c',
@ -79,6 +80,7 @@ test(
'rstest',
cargo_script,
args: ['test'] + cargo_build_flags,
env: ['SOURCE_DIR=' + meson.source_root()],
# this is a whole Carg-based test suite, let it run for a while
timeout: 900,
depends: [build_rstests, cargo_toml],

View File

@ -9,7 +9,7 @@ struct squeek_output_handle {
struct squeek_outputs *outputs;
};
struct squeek_outputs *squeek_outputs_new();
struct squeek_outputs *squeek_outputs_new(void);
void squeek_outputs_free(struct squeek_outputs*);
void squeek_outputs_register(struct squeek_outputs*, struct wl_output *output);
struct squeek_output_handle squeek_outputs_get_current(struct squeek_outputs*);

69
src/popover.c Normal file
View File

@ -0,0 +1,69 @@
#include <gio/gio.h>
static void
call_dbus_cb (GDBusProxy *proxy,
GAsyncResult *res,
gpointer user_data)
{
g_autoptr (GError) err = NULL;
g_autoptr (GVariant) output = NULL;
output = g_dbus_proxy_call_finish (proxy, res, &err);
if (err) {
g_warning ("Can't open panel %s", err->message);
}
g_object_unref (proxy);
}
static void
create_dbus_proxy_cb (GObject *source_object, GAsyncResult *res, char *panel)
{
GDBusProxy *proxy;
g_autoptr (GError) err = NULL;
GVariantBuilder builder;
GVariant *params[3];
GVariant *array[1];
proxy = g_dbus_proxy_new_for_bus_finish (res, &err);
if (err != NULL) {
g_warning ("Can't open panel %s: %s", panel, err->message);
g_free (panel);
return;
}
g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
g_variant_builder_add (&builder, "v", g_variant_new_string (""));
array[0] = g_variant_new ("v", g_variant_new ("(sav)", panel, &builder));
params[0] = g_variant_new_string ("launch-panel");
params[1] = g_variant_new_array (G_VARIANT_TYPE ("v"), array, 1);
params[2] = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0);
g_dbus_proxy_call (proxy,
"Activate",
g_variant_new_tuple (params, 3),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
(GAsyncReadyCallback) call_dbus_cb,
NULL);
g_free (panel);
}
void
popover_open_settings_panel (char *panel)
{
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
"org.gnome.ControlCenter",
"/org/gnome/ControlCenter",
"org.gtk.Actions",
NULL,
(GAsyncReadyCallback) create_dbus_proxy_cb,
g_strdup (panel));
}

View File

@ -1,9 +0,0 @@
#ifndef POPOVER_H__
#define POPOVER_H__
#include <gtk/gtk.h>
#include "eek/eek-keyboard.h"
void squeek_popover_show(GtkWidget*, struct button_place);
#endif

View File

@ -3,6 +3,7 @@
use gio;
use gtk;
use std::ffi::CString;
use std::cmp::Ordering;
use ::layout::c::{ Bounds, EekGtkKeyboard };
use ::locale;
use ::locale::{ OwnedTranslation, Translation, compare_current_locale };
@ -25,6 +26,14 @@ use gtk::WidgetExt;
use std::io::Write;
use ::logging::Warn;
mod c {
use std::os::raw::c_char;
extern "C" {
pub fn popover_open_settings_panel(panel: *const c_char);
}
}
mod variants {
use glib;
use glib::Variant;
@ -128,6 +137,12 @@ fn make_menu_builder(inputs: Vec<(&str, OwnedTranslation)>) -> gtk::Builder {
xml,
"
</section>
<section>
<item>
<attribute name=\"label\" translatable=\"yes\">Keyboard Settings</attribute>
<attribute name=\"action\">settings</attribute>
</item>
</section>
</menu>
</interface>"
).unwrap();
@ -198,7 +213,16 @@ fn set_visible_layout(
layout_id: LayoutId,
) {
match layout_id {
LayoutId::System { kind, name } => set_layout(kind, name),
LayoutId::System { kind, name } => {
unsafe {
use std::ptr;
manager::c::eekboard_context_service_set_overlay(
manager,
ptr::null(),
);
}
set_layout(kind, name);
}
LayoutId::Local(name) => {
let name = CString::new(name.as_str()).unwrap();
let name_ptr = name.as_ptr();
@ -334,8 +358,13 @@ pub fn show(
.zip(all_layouts.clone().into_iter())
.collect();
human_names.sort_unstable_by(|(tr_a, _), (tr_b, _)| {
compare_current_locale(&tr_a.0, &tr_b.0)
human_names.sort_unstable_by(|(tr_a, layout_a), (tr_b, layout_b)| {
// Sort first by layout then name
match (layout_a, layout_b) {
(LayoutId::Local(_), LayoutId::System { .. }) => Ordering::Greater,
(LayoutId::System { .. }, LayoutId::Local(_)) => Ordering::Less,
_ => compare_current_locale(&tr_a.0, &tr_b.0)
}
});
// GVariant doesn't natively support `enum`s,
@ -414,8 +443,15 @@ pub fn show(
menu_inner.popdown();
});
let settings_action = gio::SimpleAction::new("settings", None);
settings_action.connect_activate(move |_, _| {
let s = CString::new("region").unwrap();
unsafe { c::popover_open_settings_panel(s.as_ptr()) };
});
let action_group = gio::SimpleActionGroup::new();
action_group.add_action(&layout_action);
action_group.add_action(&settings_action);
menu.insert_action_group("popup", Some(&action_group));
};

View File

@ -10,32 +10,86 @@ use std::iter::FromIterator;
// TODO: keep a list of what is a language layout,
// and what a convenience layout. "_wide" is not a layout,
// neither is "number"
/// List of builtin layouts
const KEYBOARDS: &[(*const str, *const str)] = &[
// layouts: us must be left as first, as it is the,
// fallback layout. The others should be alphabetical.
// fallback layout.
("us", include_str!("../data/keyboards/us.yaml")),
("us_wide", include_str!("../data/keyboards/us_wide.yaml")),
// Language layouts: keep alphabetical.
("be", include_str!("../data/keyboards/be.yaml")),
("be_wide", include_str!("../data/keyboards/be_wide.yaml")),
("bg", include_str!("../data/keyboards/bg.yaml")),
("br", include_str!("../data/keyboards/br.yaml")),
("de", include_str!("../data/keyboards/de.yaml")),
("de_wide", include_str!("../data/keyboards/de_wide.yaml")),
("cz", include_str!("../data/keyboards/cz.yaml")),
("cz_wide", include_str!("../data/keyboards/cz_wide.yaml")),
("cz+qwerty", include_str!("../data/keyboards/cz+qwerty.yaml")),
("cz+qwerty_wide", include_str!("../data/keyboards/cz+qwerty_wide.yaml")),
("dk", include_str!("../data/keyboards/dk.yaml")),
("epo", include_str!("../data/keyboards/epo.yaml")),
("es", include_str!("../data/keyboards/es.yaml")),
("es+cat", include_str!("../data/keyboards/es+cat.yaml")),
("fi", include_str!("../data/keyboards/fi.yaml")),
("fr", include_str!("../data/keyboards/fr.yaml")),
("fr_wide", include_str!("../data/keyboards/fr_wide.yaml")),
("gr", include_str!("../data/keyboards/gr.yaml")),
("il", include_str!("../data/keyboards/il.yaml")),
("ir", include_str!("../data/keyboards/ir.yaml")),
("ir_wide", include_str!("../data/keyboards/ir_wide.yaml")),
("it", include_str!("../data/keyboards/it.yaml")),
("it+fur", include_str!("../data/keyboards/it+fur.yaml")),
("jp+kana", include_str!("../data/keyboards/jp+kana.yaml")),
("jp+kana_wide", include_str!("../data/keyboards/jp+kana_wide.yaml")),
("no", include_str!("../data/keyboards/no.yaml")),
("number", include_str!("../data/keyboards/number.yaml")),
("pl", include_str!("../data/keyboards/pl.yaml")),
("pl_wide", include_str!("../data/keyboards/pl_wide.yaml")),
("ru", include_str!("../data/keyboards/ru.yaml")),
("se", include_str!("../data/keyboards/se.yaml")),
// layout+overlay
("terminal", include_str!("../data/keyboards/terminal.yaml")),
("th", include_str!("../data/keyboards/th.yaml")),
("th_wide", include_str!("../data/keyboards/th_wide.yaml")),
("ua", include_str!("../data/keyboards/ua.yaml")),
("us+colemak", include_str!("../data/keyboards/us+colemak.yaml")),
("us+colemak_wide", include_str!("../data/keyboards/us+colemak_wide.yaml")),
("us+dvorak", include_str!("../data/keyboards/us+dvorak.yaml")),
("us+dvorak_wide", include_str!("../data/keyboards/us+dvorak_wide.yaml")),
// Others
("number/us", include_str!("../data/keyboards/number/us.yaml")),
// Terminal
("terminal/fr", include_str!("../data/keyboards/terminal/fr.yaml")),
("terminal/us", include_str!("../data/keyboards/terminal/us.yaml")),
("terminal/us_wide", include_str!("../data/keyboards/terminal/us_wide.yaml")),
// Overlays
("emoji", include_str!("../data/keyboards/emoji.yaml")),
("emoji/us", include_str!("../data/keyboards/emoji/us.yaml")),
];
pub fn get_keyboard(needle: &str) -> Option<&'static str> {
@ -70,6 +124,8 @@ const LAYOUT_NAMES: &[(*const str, *const str)] = &[
("de-DE", include_str!("../data/langs/de-DE.txt")),
("en-US", include_str!("../data/langs/en-US.txt")),
("es-ES", include_str!("../data/langs/es-ES.txt")),
("fur-IT", include_str!("../data/langs/fur-IT.txt")),
("he-IL", include_str!("../data/langs/he-IL.txt")),
("ja-JP", include_str!("../data/langs/ja-JP.txt")),
("pl-PL", include_str!("../data/langs/pl-PL.txt")),
("ru-RU", include_str!("../data/langs/ru-RU.txt")),
@ -116,7 +172,7 @@ mod test {
#[test]
fn check_overlays_present() {
for name in get_overlays() {
assert!(get_keyboard(name).is_some());
assert!(get_keyboard(&format!("{}/us", name)).is_some());
}
}

View File

@ -31,11 +31,10 @@
enum {
PROP_0,
PROP_VISIBLE,
PROP_ENABLED,
PROP_LAST
};
typedef struct _ServerContextServiceClass ServerContextServiceClass;
struct _ServerContextService {
GObject parent;
@ -44,6 +43,7 @@ struct _ServerContextService {
struct submission *submission; // unowned
struct squeek_layout_state *layout;
struct ui_manager *manager; // unowned
struct vis_manager *vis_manager; // owned
gboolean visible;
PhoshLayerSurface *window;
@ -52,68 +52,96 @@ struct _ServerContextService {
guint last_requested_height;
};
struct _ServerContextServiceClass {
GObjectClass parent_class;
};
G_DEFINE_TYPE(ServerContextService, server_context_service, G_TYPE_OBJECT);
static void
on_destroy (GtkWidget *widget, gpointer user_data)
on_destroy (ServerContextService *self, GtkWidget *widget)
{
ServerContextService *context = user_data;
g_return_if_fail (SERVER_IS_CONTEXT_SERVICE (self));
g_assert (widget == GTK_WIDGET(context->window));
g_assert (widget == GTK_WIDGET(self->window));
context->window = NULL;
context->widget = NULL;
self->window = NULL;
self->widget = NULL;
//eekboard_context_service_destroy (EEKBOARD_CONTEXT_SERVICE (context));
}
static void
on_notify_map (GObject *object,
ServerContextService *context)
on_notify_map (ServerContextService *self, GtkWidget *widget)
{
g_object_set (context, "visible", TRUE, NULL);
g_return_if_fail (SERVER_IS_CONTEXT_SERVICE (self));
g_object_set (self, "visible", TRUE, NULL);
}
static void
on_notify_unmap (GObject *object,
ServerContextService *context)
on_notify_unmap (ServerContextService *self, GtkWidget *widget)
{
(void)object;
g_object_set (context, "visible", FALSE, NULL);
g_return_if_fail (SERVER_IS_CONTEXT_SERVICE (self));
g_object_set (self, "visible", FALSE, NULL);
}
static uint32_t
calculate_height(int32_t width)
calculate_height(int32_t width, GdkRectangle *geometry)
{
uint32_t height = 180;
if (width < 360 && width > 0) {
height = ((unsigned)width * 7 / 12); // to match 360×210
} else if (width < 540) {
height = 180 + (540 - (unsigned)width) * 30 / 180; // smooth transition
uint32_t height;
if (geometry->width > geometry->height) {
// 1:5 ratio works fine on lanscape mode, and makes sure there's
// room left for the app window
height = width / 5;
} else {
if (width < 540 && width > 0) {
height = ((unsigned)width * 7 / 12); // to match 360×210
} else {
// Here we switch to wide layout, less height needed
height = ((unsigned)width * 7 / 22);
}
}
return height;
}
static void
on_surface_configure(PhoshLayerSurface *surface, ServerContextService *context)
on_surface_configure(ServerContextService *self, PhoshLayerSurface *surface)
{
GdkDisplay *display = NULL;
GdkWindow *window = NULL;
GdkMonitor *monitor = NULL;
GdkRectangle geometry;
gint width;
gint height;
g_return_if_fail (SERVER_IS_CONTEXT_SERVICE (self));
g_return_if_fail (PHOSH_IS_LAYER_SURFACE (surface));
g_object_get(G_OBJECT(surface),
"configured-width", &width,
"configured-height", &height,
NULL);
// When the geometry event comes after surface.configure,
// this entire height calculation does nothing.
// guint desired_height = squeek_uiman_get_perceptual_height(context->manager);
// Temporarily use old method, until the size manager is complete.
guint desired_height = calculate_height(width);
// In order to improve height calculation, we need the monitor geometry so
// we can use different algorithms for portrait and landscape mode.
// Note: this is a temporary fix until the size manager is complete.
display = gdk_display_get_default ();
if (display) {
window = gtk_widget_get_window (GTK_WIDGET (surface));
}
if (window) {
monitor = gdk_display_get_monitor_at_window (display, window);
}
if (monitor) {
gdk_monitor_get_geometry (monitor, &geometry);
} else {
geometry.width = geometry.height = 0;
}
// When the geometry event comes after surface.configure,
// this entire height calculation does nothing.
// guint desired_height = squeek_uiman_get_perceptual_height(context->manager);
// Temporarily use old method, until the size manager is complete.
guint desired_height = calculate_height(width, &geometry);
guint configured_height = (guint)height;
// if height was already requested once but a different one was given
@ -122,8 +150,8 @@ on_surface_configure(PhoshLayerSurface *surface, ServerContextService *context)
// as it's likely to create pointless loops
// of request->reject->request_again->...
if (desired_height != configured_height
&& context->last_requested_height != desired_height) {
context->last_requested_height = desired_height;
&& self->last_requested_height != desired_height) {
self->last_requested_height = desired_height;
phosh_layer_surface_set_size(surface, 0,
(gint)desired_height);
phosh_layer_surface_set_exclusive_zone(surface, (gint)desired_height);
@ -132,16 +160,17 @@ on_surface_configure(PhoshLayerSurface *surface, ServerContextService *context)
}
static void
make_window (ServerContextService *context)
make_window (ServerContextService *self)
{
if (context->window)
if (self->window) {
g_error("Window already present");
}
struct squeek_output_handle output = squeek_outputs_get_current(squeek_wayland->outputs);
squeek_uiman_set_output(context->manager, output);
uint32_t height = squeek_uiman_get_perceptual_height(context->manager);
squeek_uiman_set_output(self->manager, output);
uint32_t height = squeek_uiman_get_perceptual_height(self->manager);
context->window = g_object_new (
self->window = g_object_new (
PHOSH_TYPE_LAYER_SURFACE,
"layer-shell", squeek_wayland->layer_shell,
"wl-output", output.output,
@ -156,11 +185,11 @@ make_window (ServerContextService *context)
NULL
);
g_object_connect (context->window,
"signal::destroy", G_CALLBACK(on_destroy), context,
"signal::map", G_CALLBACK(on_notify_map), context,
"signal::unmap", G_CALLBACK(on_notify_unmap), context,
"signal::configured", G_CALLBACK(on_surface_configure), context,
g_object_connect (self->window,
"swapped-signal::destroy", G_CALLBACK(on_destroy), self,
"swapped-signal::map", G_CALLBACK(on_notify_map), self,
"swapped-signal::unmap", G_CALLBACK(on_notify_unmap), self,
"swapped-signal::configured", G_CALLBACK(on_surface_configure), self,
NULL);
// The properties below are just to make hacking easier.
@ -168,88 +197,137 @@ make_window (ServerContextService *context)
// 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 (GTK_WIDGET(context->window), FALSE);
g_object_set (G_OBJECT(context->window), "accept_focus", FALSE, NULL);
gtk_window_set_title (GTK_WINDOW(context->window),
gtk_widget_set_can_focus (GTK_WIDGET(self->window), FALSE);
g_object_set (G_OBJECT(self->window), "accept_focus", FALSE, NULL);
gtk_window_set_title (GTK_WINDOW(self->window),
_("Squeekboard"));
gtk_window_set_icon_name (GTK_WINDOW(context->window), "squeekboard");
gtk_window_set_keep_above (GTK_WINDOW(context->window), TRUE);
gtk_window_set_icon_name (GTK_WINDOW(self->window), "squeekboard");
gtk_window_set_keep_above (GTK_WINDOW(self->window), TRUE);
}
static void
destroy_window (ServerContextService *context)
destroy_window (ServerContextService *self)
{
gtk_widget_destroy (GTK_WIDGET (context->window));
context->window = NULL;
gtk_widget_destroy (GTK_WIDGET (self->window));
self->window = NULL;
}
static void
make_widget (ServerContextService *context)
make_widget (ServerContextService *self)
{
if (context->widget) {
gtk_widget_destroy(context->widget);
context->widget = NULL;
if (self->widget) {
gtk_widget_destroy(self->widget);
self->widget = NULL;
}
context->widget = eek_gtk_keyboard_new (context->state, context->submission, context->layout);
self->widget = eek_gtk_keyboard_new (self->state, self->submission, self->layout);
gtk_widget_set_has_tooltip (context->widget, TRUE);
gtk_container_add (GTK_CONTAINER(context->window), context->widget);
gtk_widget_show_all(context->widget);
gtk_widget_set_has_tooltip (self->widget, TRUE);
gtk_container_add (GTK_CONTAINER(self->window), self->widget);
gtk_widget_show_all(self->widget);
}
static void
server_context_service_real_show_keyboard (ServerContextService *self)
{
if (!self->window) {
make_window (self);
}
if (!self->widget) {
make_widget (self);
}
self->visible = TRUE;
gtk_widget_show (GTK_WIDGET(self->window));
}
static gboolean
on_hide (ServerContextService *context)
show_keyboard_source_func(ServerContextService *context)
{
gtk_widget_hide (GTK_WIDGET(context->window));
context->hiding = 0;
server_context_service_real_show_keyboard(context);
return G_SOURCE_REMOVE;
}
static void
server_context_service_real_hide_keyboard (ServerContextService *self)
{
gtk_widget_hide (GTK_WIDGET(self->window));
self->visible = FALSE;
}
static gboolean
hide_keyboard_source_func(ServerContextService *context)
{
server_context_service_real_hide_keyboard(context);
return G_SOURCE_REMOVE;
}
static gboolean
on_hide (ServerContextService *self)
{
server_context_service_real_hide_keyboard(self);
self->hiding = 0;
return G_SOURCE_REMOVE;
}
static void
server_context_service_real_show_keyboard (ServerContextService *context)
server_context_service_show_keyboard (ServerContextService *self)
{
if (context->hiding) {
g_source_remove (context->hiding);
context->hiding = 0;
g_return_if_fail (SERVER_IS_CONTEXT_SERVICE(self));
if (self->hiding) {
g_source_remove (self->hiding);
self->hiding = 0;
}
if (!context->window)
make_window (context);
if (!context->widget)
make_widget (context);
if (!self->visible) {
g_idle_add((GSourceFunc)show_keyboard_source_func, self);
}
}
context->visible = TRUE;
gtk_widget_show (GTK_WIDGET(context->window));
void
server_context_service_force_show_keyboard (ServerContextService *self)
{
if (!submission_hint_available(self->submission)) {
eekboard_context_service_set_hint_purpose(
self->state,
ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE,
ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL
);
}
server_context_service_show_keyboard(self);
}
void
server_context_service_hide_keyboard (ServerContextService *self)
{
g_return_if_fail (SERVER_IS_CONTEXT_SERVICE(self));
if (self->visible) {
g_idle_add((GSourceFunc)hide_keyboard_source_func, self);
}
}
/// Meant for use by the input-method handler:
/// the visible keyboard is no longer needed.
/// The implementation will delay it slightly,
/// because the release may be due to switching from one text field to another.
/// In this case, the user doesn't really need the keyboard surface
/// to disappear completely.
void
server_context_service_release_visibility (ServerContextService *self)
{
g_return_if_fail (SERVER_IS_CONTEXT_SERVICE(self));
if (!self->hiding && self->visible) {
self->hiding = g_timeout_add (200, (GSourceFunc) on_hide, self);
}
}
static void
server_context_service_real_hide_keyboard (ServerContextService *context)
server_context_service_set_physical_keyboard_present (ServerContextService *self, gboolean physical_keyboard_present)
{
if (!context->hiding)
context->hiding = g_timeout_add (200, (GSourceFunc) on_hide, context);
context->visible = FALSE;
}
void
server_context_service_show_keyboard (ServerContextService *context)
{
g_return_if_fail (SERVER_IS_CONTEXT_SERVICE(context));
if (!context->visible) {
server_context_service_real_show_keyboard (context);
}
}
void
server_context_service_hide_keyboard (ServerContextService *context)
{
g_return_if_fail (SERVER_IS_CONTEXT_SERVICE(context));
if (context->visible) {
server_context_service_real_hide_keyboard (context);
}
g_return_if_fail (SERVER_IS_CONTEXT_SERVICE (self));
squeek_visman_set_keyboard_present(self->vis_manager, physical_keyboard_present);
}
static void
@ -258,13 +336,15 @@ server_context_service_set_property (GObject *object,
const GValue *value,
GParamSpec *pspec)
{
ServerContextService *context = SERVER_CONTEXT_SERVICE(object);
ServerContextService *self = SERVER_CONTEXT_SERVICE(object);
switch (prop_id) {
case PROP_VISIBLE:
context->visible = g_value_get_boolean (value);
self->visible = g_value_get_boolean (value);
break;
case PROP_ENABLED:
server_context_service_set_physical_keyboard_present (self, !g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -277,10 +357,10 @@ server_context_service_get_property (GObject *object,
GValue *value,
GParamSpec *pspec)
{
ServerContextService *context = SERVER_CONTEXT_SERVICE(object);
ServerContextService *self = SERVER_CONTEXT_SERVICE(object);
switch (prop_id) {
case PROP_VISIBLE:
g_value_set_boolean (value, context->visible);
g_value_set_boolean (value, self->visible);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -291,10 +371,10 @@ server_context_service_get_property (GObject *object,
static void
server_context_service_dispose (GObject *object)
{
ServerContextService *context = SERVER_CONTEXT_SERVICE(object);
ServerContextService *self = SERVER_CONTEXT_SERVICE(object);
destroy_window (context);
context->widget = NULL;
destroy_window (self);
self->widget = NULL;
G_OBJECT_CLASS (server_context_service_parent_class)->dispose (object);
}
@ -320,20 +400,66 @@ server_context_service_class_init (ServerContextServiceClass *klass)
g_object_class_install_property (gobject_class,
PROP_VISIBLE,
pspec);
/**
* ServerContextServie:keyboard:
*
* Does the user want the keyboard to show up automatically?
*/
pspec =
g_param_spec_boolean ("enabled",
"Enabled",
"Whether the keyboard is enabled",
TRUE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_ENABLED,
pspec);
}
static void
server_context_service_init (ServerContextService *state) {
(void)state;
server_context_service_init (ServerContextService *self) {}
static void
init (ServerContextService *self) {
const char *schema_name = "org.gnome.desktop.a11y.applications";
GSettingsSchemaSource *ssrc = g_settings_schema_source_get_default();
g_autoptr(GSettingsSchema) schema = NULL;
if (!ssrc) {
g_warning("No gsettings schemas installed.");
return;
}
schema = g_settings_schema_source_lookup(ssrc, schema_name, TRUE);
if (schema) {
g_autoptr(GSettings) settings = g_settings_new (schema_name);
g_settings_bind (settings, "screen-keyboard-enabled",
self, "enabled", G_SETTINGS_BIND_GET);
} else {
g_warning("Gsettings schema %s is not installed on the system. "
"Enabling by default.", schema_name);
}
}
ServerContextService *
server_context_service_new (EekboardContextService *state, struct submission *submission, struct squeek_layout_state *layout, struct ui_manager *uiman)
server_context_service_new (EekboardContextService *self, struct submission *submission, struct squeek_layout_state *layout, struct ui_manager *uiman, struct vis_manager *visman)
{
ServerContextService *ui = g_object_new (SERVER_TYPE_CONTEXT_SERVICE, NULL);
ui->submission = submission;
ui->state = state;
ui->state = self;
ui->layout = layout;
ui->manager = uiman;
ui->vis_manager = visman;
init(ui);
return ui;
}
void
server_context_service_update_visible (ServerContextService *self, gboolean visible) {
if (visible) {
server_context_service_show_keyboard(self);
} else {
server_context_service_hide_keyboard(self);
}
}

View File

@ -25,22 +25,14 @@
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))
#define SERVER_IS_CONTEXT_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SERVER_TYPE_CONTEXT_SERVICE))
#define SERVER_IS_CONTEXT_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SERVER_TYPE_CONTEXT_SERVICE))
#define SERVER_CONTEXT_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SERVER_TYPE_CONTEXT_SERVICE, ServerContextServiceClass))
/** Manages the lifecycle of the window displaying layouts. */
typedef struct _ServerContextService ServerContextService;
G_DECLARE_FINAL_TYPE (ServerContextService, server_context_service, SERVER, CONTEXT_SERVICE, GObject)
GType server_context_service_get_type
(void) G_GNUC_CONST;
ServerContextService *server_context_service_new(EekboardContextService *state, struct submission *submission, struct squeek_layout_state *layout, struct ui_manager *uiman);
ServerContextService *server_context_service_new(EekboardContextService *self, struct submission *submission, struct squeek_layout_state *layout, struct ui_manager *uiman, struct vis_manager *visman);
enum squeek_arrangement_kind server_context_service_get_layout_type(ServerContextService *);
void server_context_service_show_keyboard (ServerContextService *context);
void server_context_service_hide_keyboard (ServerContextService *context);
void server_context_service_force_show_keyboard (ServerContextService *self);
void server_context_service_hide_keyboard (ServerContextService *self);
G_END_DECLS
#endif /* SERVER_CONTEXT_SERVICE_H */

View File

@ -50,9 +50,16 @@ struct squeekboard {
};
GMainLoop *loop;
static gboolean opt_system = FALSE;
static gchar *opt_address = NULL;
static void
quit (void)
{
g_main_loop_quit (loop);
}
// D-Bus
static void
@ -131,6 +138,67 @@ static const struct wl_registry_listener registry_listener = {
#define SESSION_NAME "sm.puri.OSK0"
GDBusProxy *_proxy = NULL;
GDBusProxy *_client_proxy = NULL;
gchar *_client_path = NULL;
static void
send_quit_response (GDBusProxy *proxy)
{
g_debug ("Calling EndSessionResponse");
g_dbus_proxy_call (proxy, "EndSessionResponse",
g_variant_new ("(bs)", TRUE, ""), G_DBUS_CALL_FLAGS_NONE,
G_MAXINT, NULL, NULL, NULL);
}
static void
unregister_client (void)
{
g_autoptr (GError) error = NULL;
g_return_if_fail (G_IS_DBUS_PROXY (_proxy));
g_return_if_fail (_client_path != NULL);
g_debug ("Unregistering client");
g_dbus_proxy_call_sync (_proxy,
"UnregisterClient",
g_variant_new ("(o)", _client_path),
G_DBUS_CALL_FLAGS_NONE,
G_MAXINT,
NULL,
&error);
if (error) {
g_warning ("Failed to unregister client: %s", error->message);
}
g_clear_object (&_client_proxy);
g_clear_pointer (&_client_path, g_free);
}
static void client_proxy_signal (GDBusProxy *proxy,
const gchar *sender_name,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
{
if (g_str_equal (signal_name, "QueryEndSession")) {
g_debug ("Received QueryEndSession");
send_quit_response (proxy);
} else if (g_str_equal (signal_name, "CancelEndSession")) {
g_debug ("Received CancelEndSession");
} else if (g_str_equal (signal_name, "EndSession")) {
g_debug ("Received EndSession");
send_quit_response (proxy);
unregister_client ();
quit ();
} else if (g_str_equal (signal_name, "Stop")) {
g_debug ("Received Stop");
unregister_client ();
quit ();
}
}
static void
session_register(void) {
@ -151,7 +219,8 @@ session_register(void) {
return;
}
g_dbus_proxy_call_sync(_proxy, "RegisterClient",
g_autoptr (GVariant) res = NULL;
res = g_dbus_proxy_call_sync(_proxy, "RegisterClient",
g_variant_new("(ss)", SESSION_NAME, autostart_id),
G_DBUS_CALL_FLAGS_NONE, 1000, NULL, &error);
if (error) {
@ -160,6 +229,22 @@ session_register(void) {
g_clear_error(&error);
return;
}
g_variant_get (res, "(o)", &_client_path);
g_debug ("Registered client at '%s'", _client_path);
_client_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
0, NULL, "org.gnome.SessionManager", _client_path,
"org.gnome.SessionManager.ClientPrivate", NULL, &error);
if (error) {
g_warning ("Failed to get client proxy: %s", error->message);
g_clear_error (&error);
g_free (_client_path);
_client_path = NULL;
return;
}
g_signal_connect (_client_proxy, "g-signal", G_CALLBACK (client_proxy_signal), NULL);
}
int
@ -213,12 +298,13 @@ main (int argc, char **argv)
// dbus is not strictly necessary for the useful operation
// if text-input is used, as it can bring the keyboard in and out
GBusType bus_type;
if (opt_system)
if (opt_system) {
bus_type = G_BUS_TYPE_SYSTEM;
else if (opt_address)
} else if (opt_address) {
bus_type = G_BUS_TYPE_NONE;
else
} else {
bus_type = G_BUS_TYPE_SESSION;
}
GDBusConnection *connection = NULL;
GError *error = NULL;
@ -276,8 +362,11 @@ main (int argc, char **argv)
}
}
struct vis_manager *vis_manager = squeek_visman_new();
instance.submission = get_submission(instance.wayland.input_method_manager,
instance.wayland.virtual_keyboard_manager,
vis_manager,
instance.wayland.seat,
instance.settings_context);
@ -287,15 +376,15 @@ main (int argc, char **argv)
instance.settings_context,
instance.submission,
&instance.layout_choice,
instance.ui_manager);
instance.ui_manager,
vis_manager);
if (!ui_context) {
g_error("Could not initialize GUI");
exit(1);
}
instance.ui_context = ui_context;
if (instance.submission) {
submission_set_ui(instance.submission, instance.ui_context);
}
squeek_visman_set_ui(vis_manager, instance.ui_context);
if (instance.dbus_handler) {
dbus_handler_set_ui_context(instance.dbus_handler, instance.ui_context);
}
@ -303,8 +392,7 @@ main (int argc, char **argv)
session_register();
GMainLoop *loop = g_main_loop_new (NULL, FALSE);
loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
if (connection) {

View File

@ -2,6 +2,6 @@
#define __STYLE_H
#include "gtk/gtk.h"
GtkCssProvider *squeek_load_style();
GtkCssProvider *squeek_load_style(void);
#endif

View File

@ -4,16 +4,20 @@
#include "input-method-unstable-v2-client-protocol.h"
#include "virtual-keyboard-unstable-v1-client-protocol.h"
#include "eek/eek-types.h"
#include "src/ui_manager.h"
struct submission;
struct squeek_layout;
struct submission* get_submission(struct zwp_input_method_manager_v2 *immanager,
struct zwp_virtual_keyboard_manager_v1 *vkmanager,
struct vis_manager *vis_manager,
struct wl_seat *seat,
EekboardContextService *state);
// Defined in Rust
struct submission* submission_new(struct zwp_input_method_v2 *im, struct zwp_virtual_keyboard_v1 *vk, EekboardContextService *state);
struct submission* submission_new(struct zwp_input_method_v2 *im, struct zwp_virtual_keyboard_v1 *vk, EekboardContextService *state, struct vis_manager *vis_manager);
uint8_t submission_hint_available(struct submission *self);
void submission_set_ui(struct submission *self, ServerContextService *ui_context);
void submission_set_keyboard(struct submission *self, LevelKeyboard *keyboard);
void submission_use_layout(struct submission *self, struct squeek_layout *layout, uint32_t time);
#endif

View File

@ -23,7 +23,10 @@ use ::action::Modifier;
use ::imservice;
use ::imservice::IMService;
use ::keyboard::{ KeyCode, KeyStateId, Modifiers, PressType };
use ::layout;
use ::ui_manager::VisibilityManager;
use ::util::vec_remove;
use ::vkeyboard;
use ::vkeyboard::VirtualKeyboard;
// traits
@ -36,15 +39,11 @@ pub mod c {
use std::os::raw::c_void;
use ::imservice::c::InputMethod;
use ::layout::c::LevelKeyboard;
use ::util::c::Wrapped;
use ::vkeyboard::c::ZwpVirtualKeyboardV1;
// The following defined in C
/// ServerContextService*
#[repr(transparent)]
pub struct UIManager(*const c_void);
/// EekboardContextService*
#[repr(transparent)]
pub struct StateManager(*const c_void);
@ -54,12 +53,18 @@ pub mod c {
fn submission_new(
im: *mut InputMethod,
vk: ZwpVirtualKeyboardV1,
state_manager: *const StateManager
state_manager: *const StateManager,
visibility_manager: Wrapped<VisibilityManager>,
) -> *mut Submission {
let imservice = if im.is_null() {
None
} else {
Some(IMService::new(im, state_manager))
let visibility_manager = visibility_manager.clone_ref();
Some(IMService::new(
im,
state_manager,
Box::new(move |active| visibility_manager.borrow_mut().set_im_active(active)),
))
};
// TODO: add vkeyboard too
Box::<Submission>::into_raw(Box::new(
@ -68,41 +73,44 @@ pub mod c {
modifiers_active: Vec::new(),
virtual_keyboard: VirtualKeyboard(vk),
pressed: Vec::new(),
keymap_fds: Vec::new(),
keymap_idx: None,
}
))
}
/// Use to initialize the UI reference
#[no_mangle]
pub extern "C"
fn submission_set_ui(submission: *mut Submission, ui_manager: *const UIManager) {
fn submission_use_layout(
submission: *mut Submission,
layout: *const layout::Layout,
time: u32,
) {
if submission.is_null() {
panic!("Null submission pointer");
}
let submission: &mut Submission = unsafe { &mut *submission };
if let Some(ref mut imservice) = &mut submission.imservice {
imservice.ui_manager = if ui_manager.is_null() {
None
} else {
Some(ui_manager)
}
};
let layout = unsafe { &*layout };
submission.use_layout(layout, Timestamp(time));
}
#[no_mangle]
pub extern "C"
fn submission_set_keyboard(submission: *mut Submission, keyboard: LevelKeyboard) {
fn submission_hint_available(submission: *mut Submission) -> u8 {
if submission.is_null() {
panic!("Null submission pointer");
}
let submission: &mut Submission = unsafe { &mut *submission };
submission.virtual_keyboard.update_keymap(keyboard);
let active = submission.imservice.as_ref()
.map(|imservice| imservice.is_active());
(Some(true) == active) as u8
}
}
#[derive(Clone, Copy)]
pub struct Timestamp(pub u32);
#[derive(Clone)]
enum SubmittedAction {
/// A collection of keycodes that were pressed
VirtualKeyboard(Vec<KeyCode>),
@ -114,6 +122,8 @@ pub struct Submission {
virtual_keyboard: VirtualKeyboard,
modifiers_active: Vec<(KeyStateId, Modifier)>,
pressed: Vec<(KeyStateId, SubmittedAction)>,
keymap_fds: Vec<vkeyboard::c::KeyMap>,
keymap_idx: Option<usize>,
}
pub enum SubmitData<'a> {
@ -139,7 +149,7 @@ impl Submission {
enum Outcome {
Submitted(Result<(), imservice::SubmitError>),
NotSubmitted,
};
}
let submit_outcome = match data {
SubmitData::Text(text) => {
@ -172,11 +182,34 @@ impl Submission {
let submit_action = match was_committed_as_text {
true => SubmittedAction::IMService,
false => {
self.virtual_keyboard.switch(
keycodes,
PressType::Pressed,
time,
);
let keycodes_count = keycodes.len();
for keycode in keycodes.iter() {
self.select_keymap(keycode.keymap_idx, time);
let keycode = keycode.code;
match keycodes_count {
// Pressing a key made out of a single keycode is simple:
// press on press, release on release.
1 => self.virtual_keyboard.switch(
keycode,
PressType::Pressed,
time,
),
// A key made of multiple keycodes
// has to submit them one after the other.
_ => {
self.virtual_keyboard.switch(
keycode.clone(),
PressType::Pressed,
time,
);
self.virtual_keyboard.switch(
keycode.clone(),
PressType::Released,
time,
);
},
};
}
SubmittedAction::VirtualKeyboard(keycodes.clone())
},
};
@ -194,11 +227,21 @@ impl Submission {
// no matter if the imservice got activated,
// keys must be released
SubmittedAction::VirtualKeyboard(keycodes) => {
self.virtual_keyboard.switch(
&keycodes,
PressType::Released,
time,
)
let keycodes_count = keycodes.len();
match keycodes_count {
1 => {
let keycode = &keycodes[0];
self.select_keymap(keycode.keymap_idx, time);
self.virtual_keyboard.switch(
keycode.code,
PressType::Released,
time,
);
},
// Design choice here: submit multiple all at press time
// and do nothing at release time.
_ => {},
};
},
}
};
@ -227,6 +270,7 @@ impl Submission {
.map(|(_id, m)| match m {
Modifier::Control => Modifiers::CONTROL,
Modifier::Alt => Modifiers::MOD1,
Modifier::Mod4 => Modifiers::MOD4,
})
.fold(Modifiers::empty(), |m, n| m | n);
self.virtual_keyboard.set_modifiers_state(raw_modifiers);
@ -243,4 +287,64 @@ impl Submission {
self.modifiers_active.iter().map(|(_id, m)| m.clone())
)
}
fn clear_all_modifiers(&mut self) {
// Looks like an optimization,
// but preemptive cleaning is needed before setting a new keymap,
// so removing this check would break keymap setting.
if self.modifiers_active.is_empty() {
return;
}
self.modifiers_active = Vec::new();
self.virtual_keyboard.set_modifiers_state(Modifiers::empty())
}
fn release_all_virtual_keys(&mut self, time: Timestamp) {
let virtual_pressed = self.pressed
.clone().into_iter()
.filter_map(|(id, action)| {
match action {
SubmittedAction::VirtualKeyboard(_) => Some(id),
_ => None,
}
});
for id in virtual_pressed {
self.handle_release(id, time);
}
}
/// Changes keymap and clears pressed keys and modifiers.
///
/// It's not obvious if clearing is the right thing to do,
/// but keymap update may (or may not) do that,
/// possibly putting self.modifiers_active and self.pressed out of sync,
/// so a consistent stance is adopted to avoid that.
/// Alternatively, modifiers could be restored on the new keymap.
/// That approach might be difficult
/// due to modifiers meaning different things in different keymaps.
fn select_keymap(&mut self, idx: usize, time: Timestamp) {
if self.keymap_idx != Some(idx) {
self.keymap_idx = Some(idx);
self.clear_all_modifiers();
self.release_all_virtual_keys(time);
let keymap = &self.keymap_fds[idx];
self.virtual_keyboard.update_keymap(keymap);
}
}
pub fn use_layout(&mut self, layout: &layout::Layout, time: Timestamp) {
self.keymap_fds = layout.keymaps.iter()
.map(|keymap_str| vkeyboard::c::KeyMap::from_cstr(
keymap_str.as_c_str()
))
.collect();
self.keymap_idx = None;
// This can probably be eliminated,
// because key presses can trigger an update anyway.
// However, self.keymap_idx needs to become Option<>
// in order to force update on new layouts.
self.select_keymap(0, time);
}
}

View File

@ -26,49 +26,104 @@ impl CountAndPrint {
}
}
pub fn check_builtin_layout(name: &str) {
check_layout(Layout::from_resource(name).expect("Invalid layout data"))
pub fn check_builtin_layout(name: &str, missing_return: bool) {
check_layout(
Layout::from_resource(name).expect("Invalid layout data"),
missing_return,
)
}
pub fn check_layout_file(path: &str) {
check_layout(Layout::from_file(path.into()).expect("Invalid layout file"))
check_layout(
Layout::from_file(path.into()).expect("Invalid layout file"),
false,
)
}
fn check_layout(layout: Layout) {
fn check_sym_in_keymap(state: &xkb::State, sym_name: &str) -> bool {
let sym = xkb::keysym_from_name(sym_name, xkb::KEYSYM_NO_FLAGS);
if sym == xkb::KEY_NoSymbol {
panic!("Entered invalid keysym: {}", sym_name);
}
let map = state.get_keymap();
let range = map.min_keycode()..=map.max_keycode();
range.flat_map(|code| state.key_get_syms(code))
.find(|s| **s == sym)
.is_some()
}
fn check_sym_presence(
states: &[xkb::State],
sym_name: &str,
handler: &mut dyn logging::Handler,
) {
let found = states.iter()
.position(|state| {
check_sym_in_keymap(&state, sym_name)
});
if let None = found {
handler.handle(
logging::Level::Surprise,
&format!("There's no way to input the keysym {} on this layout", sym_name),
)
}
}
fn check_layout(layout: Layout, allow_missing_return: bool) {
let handler = CountAndPrint::new();
let (layout, handler) = layout.build(handler);
let (layout, mut handler) = layout.build(handler);
if handler.0 > 0 {
println!("{} problems while parsing layout", handler.0)
}
let layout = layout.expect("layout broken");
let xkb_states: Vec<xkb::State> = layout.keymaps.iter()
.map(|keymap_str| {
let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
let keymap_str = keymap_str
.clone()
.into_string().expect("Failed to decode keymap string");
let keymap = xkb::Keymap::new_from_string(
&context,
keymap_str.clone(),
xkb::KEYMAP_FORMAT_TEXT_V1,
xkb::KEYMAP_COMPILE_NO_FLAGS,
).expect("Failed to create keymap");
xkb::State::new(&keymap)
})
.collect();
let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
let keymap_str = layout.keymap_str
.clone()
.into_string().expect("Failed to decode keymap string");
let keymap = xkb::Keymap::new_from_string(
&context,
keymap_str.clone(),
xkb::KEYMAP_FORMAT_TEXT_V1,
xkb::KEYMAP_COMPILE_NO_FLAGS,
).expect("Failed to create keymap");
check_sym_presence(&xkb_states, "BackSpace", &mut handler);
let mut printer = logging::Print;
check_sym_presence(
&xkb_states,
"Return",
if allow_missing_return { &mut printer }
else { &mut handler },
);
let state = xkb::State::new(&keymap);
// "Press" each button with keysyms
for (_pos, view) in layout.views.values() {
for (_y, row) in &view.get_rows() {
for (_x, button) in &row.buttons {
for (_y, row) in view.get_rows() {
for (_x, button) in row.get_buttons() {
let keystate = button.state.borrow();
for keycode in &keystate.keycodes {
match state.key_get_one_sym(*keycode) {
match xkb_states[keycode.keymap_idx].key_get_one_sym(keycode.code) {
xkb::KEY_NoSymbol => {
eprintln!("{}", keymap_str);
panic!("Keysym {} on key {:?} can't be resolved", keycode, button.name);
eprintln!(
"keymap {}: {}",
keycode.keymap_idx,
layout.keymaps[keycode.keymap_idx].to_str().unwrap(),
);
panic!(
"Keysym for code {:?} on key {} ({:?}) can't be resolved",
keycode,
button.name.to_string_lossy(),
button.name,
);
},
_ => {},
}

View File

@ -3,12 +3,18 @@
#include <inttypes.h>
#include "eek/eek-types.h"
#include "outputs.h"
struct ui_manager;
struct ui_manager *squeek_uiman_new();
struct ui_manager *squeek_uiman_new(void);
void squeek_uiman_set_output(struct ui_manager *uiman, struct squeek_output_handle output);
uint32_t squeek_uiman_get_perceptual_height(struct ui_manager *uiman);
struct vis_manager;
struct vis_manager *squeek_visman_new(void);
void squeek_visman_set_ui(struct vis_manager *visman, ServerContextService *ui_context);
void squeek_visman_set_keyboard_present(struct vis_manager *visman, uint32_t keyboard_present);
#endif

View File

@ -10,9 +10,48 @@
use std::cmp::min;
use ::outputs::c::OutputHandle;
mod c {
pub mod c {
use super::*;
use std::os::raw::c_void;
use ::util::c::Wrapped;
/// ServerContextService*
#[repr(transparent)]
pub struct UIManager(*const c_void);
extern "C" {
pub fn server_context_service_update_visible(imservice: *const UIManager, active: u32);
pub fn server_context_service_release_visibility(imservice: *const UIManager);
}
#[no_mangle]
pub extern "C"
fn squeek_visman_new() -> Wrapped<VisibilityManager> {
Wrapped::new(VisibilityManager {
ui_manager: None,
visibility_state: VisibilityFactors {
im_active: false,
physical_keyboard_present: false,
}
})
}
/// Use to initialize the UI reference
#[no_mangle]
pub extern "C"
fn squeek_visman_set_ui(visman: Wrapped<VisibilityManager>, ui_manager: *const UIManager) {
let visman = visman.clone_ref();
let mut visman = visman.borrow_mut();
visman.set_ui_manager(Some(ui_manager))
}
#[no_mangle]
pub extern "C"
fn squeek_visman_set_keyboard_present(visman: Wrapped<VisibilityManager>, present: u32) {
let visman = visman.clone_ref();
let mut visman = visman.borrow_mut();
visman.set_keyboard_present(present != 0)
}
#[no_mangle]
pub extern "C"
@ -79,3 +118,131 @@ impl Manager {
}
}
}
#[derive(PartialEq, Debug)]
enum Visibility {
Hidden,
Visible,
}
#[derive(Debug)]
enum VisibilityTransition {
/// Hide immediately
Hide,
/// Hide if no show request comes soon
Release,
/// Show instantly
Show,
/// Don't do anything
NoTransition,
}
/// Contains visibility policy
#[derive(Clone, Debug)]
struct VisibilityFactors {
im_active: bool,
physical_keyboard_present: bool,
}
impl VisibilityFactors {
/// Static policy.
/// Use when transitioning from an undefined state (e.g. no UI before).
fn desired(&self) -> Visibility {
match self {
VisibilityFactors {
im_active: true,
physical_keyboard_present: false,
} => Visibility::Visible,
_ => Visibility::Hidden,
}
}
/// Stateful policy
fn transition_to(&self, next: &Self) -> VisibilityTransition {
use self::Visibility::*;
let im_deactivation = self.im_active && !next.im_active;
match (self.desired(), next.desired(), im_deactivation) {
(Visible, Hidden, true) => VisibilityTransition::Release,
(Visible, Hidden, _) => VisibilityTransition::Hide,
(Hidden, Visible, _) => VisibilityTransition::Show,
_ => VisibilityTransition::NoTransition,
}
}
}
// Temporary struct for migration. Should be integrated with Manager eventually.
pub struct VisibilityManager {
/// Owned reference. Be careful, it's shared with C at large
ui_manager: Option<*const c::UIManager>,
visibility_state: VisibilityFactors,
}
impl VisibilityManager {
fn set_ui_manager(&mut self, ui_manager: Option<*const c::UIManager>) {
let new = VisibilityManager {
ui_manager,
..unsafe { self.clone() }
};
self.apply_changes(new);
}
fn apply_changes(&mut self, new: Self) {
if let Some(ui) = &new.ui_manager {
if self.ui_manager.is_none() {
// Previous state was never applied, so effectively undefined.
// Just apply the new one.
let new_state = new.visibility_state.desired();
unsafe {
c::server_context_service_update_visible(
*ui,
(new_state == Visibility::Visible) as u32,
);
}
} else {
match self.visibility_state.transition_to(&new.visibility_state) {
VisibilityTransition::Hide => unsafe {
c::server_context_service_update_visible(*ui, 0);
},
VisibilityTransition::Show => unsafe {
c::server_context_service_update_visible(*ui, 1);
},
VisibilityTransition::Release => unsafe {
c::server_context_service_release_visibility(*ui);
},
VisibilityTransition::NoTransition => {}
}
}
}
*self = new;
}
pub fn set_im_active(&mut self, im_active: bool) {
let new = VisibilityManager {
visibility_state: VisibilityFactors {
im_active,
..self.visibility_state.clone()
},
..unsafe { self.clone() }
};
self.apply_changes(new);
}
pub fn set_keyboard_present(&mut self, keyboard_present: bool) {
let new = VisibilityManager {
visibility_state: VisibilityFactors {
physical_keyboard_present: keyboard_present,
..self.visibility_state.clone()
},
..unsafe { self.clone() }
};
self.apply_changes(new);
}
/// The struct is not really safe to clone due to the ui_manager reference.
/// This is only a helper for getting desired visibility.
unsafe fn clone(&self) -> Self {
VisibilityManager {
ui_manager: self.ui_manager.clone(),
visibility_state: self.visibility_state.clone(),
}
}
}

View File

@ -203,6 +203,23 @@ pub fn vec_remove<T, F: FnMut(&T) -> bool>(v: &mut Vec<T>, pred: F) -> Option<T>
idx.map(|idx| v.remove(idx))
}
/// Repeats all the items of the iterator forever,
/// but returns the cycle number alongside.
/// Inefficient due to all the vectors, but doesn't have to be fast.
pub fn cycle_count<T, I: Clone + Iterator<Item=T>>(iter: I)
-> impl Iterator<Item=(T, usize)>
{
let numbered_copies = vec![iter].into_iter()
.cycle()
.enumerate();
numbered_copies.flat_map(|(idx, cycle)|
// Pair each element from the cycle with a copy of the index.
cycle.zip(
vec![idx].into_iter().cycle() // Repeat the index forever.
)
)
}
#[cfg(test)]
mod tests {
use super::*;
@ -217,4 +234,12 @@ mod tests {
assert_eq!(s.insert(Pointer(Rc::new(2u32))), true);
assert_eq!(s.remove(&Pointer(first)), true);
}
#[test]
fn check_count() {
assert_eq!(
cycle_count(5..8).take(7).collect::<Vec<_>>(),
vec![(5, 0), (6, 0), (7, 0), (5, 1), (6, 1), (7, 1), (5, 2)]
);
}
}

View File

@ -1,20 +1,46 @@
/*! Managing the events belonging to virtual-keyboard interface. */
use ::keyboard::{ KeyCode, Modifiers, PressType };
use ::layout::c::LevelKeyboard;
use ::keyboard::{ Modifiers, PressType };
use ::submission::Timestamp;
/// Standard xkb keycode
type KeyCode = u32;
/// Gathers stuff defined in C or called by C
pub mod c {
use super::*;
use std::os::raw::c_void;
use std::ffi::CStr;
use std::os::raw::{ c_char, c_void };
#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct ZwpVirtualKeyboardV1(*const c_void);
#[no_mangle]
#[repr(C)]
pub struct KeyMap {
fd: u32,
fd_len: usize,
}
impl KeyMap {
pub fn from_cstr(s: &CStr) -> KeyMap {
unsafe {
squeek_key_map_from_str(s.as_ptr())
}
}
}
impl Drop for KeyMap {
fn drop(&mut self) {
unsafe {
close(self.fd as u32);
}
}
}
extern "C" {
// From libc, to let KeyMap get deallocated.
fn close(fd: u32);
pub fn eek_virtual_keyboard_v1_key(
virtual_keyboard: ZwpVirtualKeyboardV1,
timestamp: u32,
@ -24,13 +50,15 @@ pub mod c {
pub fn eek_virtual_keyboard_update_keymap(
virtual_keyboard: ZwpVirtualKeyboardV1,
keyboard: LevelKeyboard,
keymap: *const KeyMap,
);
pub fn eek_virtual_keyboard_set_modifiers(
virtual_keyboard: ZwpVirtualKeyboardV1,
modifiers: u32,
);
pub fn squeek_key_map_from_str(keymap_str: *const c_char) -> KeyMap;
}
}
@ -41,35 +69,15 @@ impl VirtualKeyboard {
// TODO: error out if keymap not set
pub fn switch(
&self,
keycodes: &Vec<KeyCode>,
keycode: KeyCode,
action: PressType,
timestamp: Timestamp,
) {
let keycodes_count = keycodes.len();
for keycode in keycodes.iter() {
let keycode = keycode - 8;
match (action, keycodes_count) {
// Pressing a key made out of a single keycode is simple:
// press on press, release on release.
(_, 1) => unsafe {
c::eek_virtual_keyboard_v1_key(
self.0, timestamp.0, keycode, action.clone() as u32
);
},
// A key made of multiple keycodes
// has to submit them one after the other
(PressType::Pressed, _) => unsafe {
c::eek_virtual_keyboard_v1_key(
self.0, timestamp.0, keycode, PressType::Pressed as u32
);
c::eek_virtual_keyboard_v1_key(
self.0, timestamp.0, keycode, PressType::Released as u32
);
},
// Design choice here: submit multiple all at press time
// and do nothing at release time
(PressType::Released, _) => {},
}
let keycode = keycode - 8;
unsafe {
c::eek_virtual_keyboard_v1_key(
self.0, timestamp.0, keycode, action.clone() as u32
);
}
}
@ -80,9 +88,12 @@ impl VirtualKeyboard {
}
}
pub fn update_keymap(&self, keyboard: LevelKeyboard) {
pub fn update_keymap(&self, keymap: &c::KeyMap) {
unsafe {
c::eek_virtual_keyboard_update_keymap(self.0, keyboard);
c::eek_virtual_keyboard_update_keymap(
self.0,
keymap as *const c::KeyMap,
);
}
}
}

Some files were not shown because too many files have changed in this diff Show More