Compare commits

..

36 Commits

Author SHA1 Message Date
0c99067b4b Release 1.19.0 "Chirality"
The main behind-the-scenes change in this release is the rework which gathers code selecting layout versions into one place. A resource leak causing slowdowns was also avoided.

New translations:
- Chinese (China)
- French
- Russian

Layout changes:
- new FR+Bépo
- new Georgian
- improved Italian

Thanks to all contrbutors.
2022-07-06 06:12:46 +00:00
ec7116053f build: Update Cargo.lock 2022-07-06 06:08:13 +00:00
cc7657e78c Merge branch 'leak' into 'master'
gtk: Persist panel state

See merge request World/Phosh/squeekboard!563
2022-07-06 06:03:27 +00:00
70bf101812 gtk: Persist panel state
Creating and destroying the panel as needed causes a resource leak somewhere in the deeper layers of the stack. This is a workaround.

See https://gitlab.gnome.org/World/Phosh/squeekboard/-/issues/343
2022-07-01 08:07:29 +00:00
dcz
12572b9de2 Merge branch 'par' into 'master'
build: Generate files before compiling sources

See merge request World/Phosh/squeekboard!562
2022-06-30 19:03:45 +00:00
9528339e02 build: Generate files before compiling sources 2022-06-30 18:12:57 +00:00
dcz
50ef4ab433 Merge branch 'fixci' into 'master'
ci: Use bookworm for online builds

See merge request World/Phosh/squeekboard!561
2022-06-29 15:20:20 +00:00
a8fe4a492e ci: Use bookworm for online builds
PureOS carries rather old versions of rustc and cargo. Attempting to build fails at transitive dependencies, and it's easier to upgrade the compiler than to track down and hold offending depencencies as they come.
2022-06-29 14:59:45 +00:00
dcz
0aee348e30 Merge branch 'georgian-layout' into 'master'
Added Georgian layout

See merge request World/Phosh/squeekboard!558
2022-06-24 18:28:27 +00:00
7f9baa8021 Added Georgian layout 2022-06-24 18:28:21 +00:00
dcz
feefe3fec2 Merge branch 'fix' into 'master'
cargo: Halt overzealous upgrader

See merge request World/Phosh/squeekboard!559
2022-06-24 17:58:31 +00:00
94aa0fa68f cargo: Halt overzealous upgrader
We're using a version of Cargo which doesn't support 2021 edition. The dependency Hashbrown 0.12 uses it, so we perform a minimal reshuffling to use 0.11.
2022-06-24 17:30:56 +00:00
c86161d5b5 Add Russian translation 2022-06-18 21:22:20 +00:00
dcz
49fc28f0a9 Merge branch 'dddoc' into 'master'
doc: Describe how to control debugging mode

See merge request World/Phosh/squeekboard!554
2022-06-14 15:23:43 +00:00
dcz
ea73a34eb8 Merge branch 'layouts' into 'master'
state: Select the layout

See merge request World/Phosh/squeekboard!553
2022-06-14 15:23:14 +00:00
dcz
f8ce24fdbf Merge branch 'keyboard-layout-it' into 'master'
Fixed missing characters in eschars view in italian layout.

See merge request World/Phosh/squeekboard!557
2022-06-11 10:09:58 +00:00
d797ee223b Replaced foreign characters. 2022-06-10 21:25:06 +00:00
267b0745a2 Fixed missing characters in eschars view in italian layout. 2022-06-10 18:41:36 +00:00
c1ceec3673 state: Become the source of layout choice
A redesign of popover was needed: it can no longer query the application state directly due to current state being its own actor, so instead the popover gets a dedicated copy of the relevant state.

I'm not entirely happy with the extra complexity of having an extra actor just for 1 string, but at least the duplication between C and Rust and mutual calls have been reduced.
2022-06-06 16:10:53 +00:00
30141db28d main: Dry-load layout in response to the layout command 2022-06-06 16:10:53 +00:00
8d0e1b4548 state: Use IM hint and purpose for layout selection 2022-06-06 16:10:53 +00:00
e6326b9b38 state: Use dummy layout command 2022-06-06 16:10:53 +00:00
b634e2bfa4 state: Decide panel arrangement
Combines arrangement with layout to get panel contents as outcome.

Includes some path syntax changes for 2018 compatibility.
2022-06-06 16:10:53 +00:00
590cd71f49 state: Store layout override
Not used for any externally observable effects
2022-06-06 16:10:53 +00:00
8ff72f312a state: Include layout choice in visible outcome
This is still in preparation and doesn't issue any observable effects.
2022-06-06 16:10:53 +00:00
bb22d9650b doc: Describe how to control debugging mode 2022-06-06 16:10:03 +00:00
82774d2315 state: Record layout choice
This does not get plugged into anything but debug prints yet.
2022-06-04 17:47:09 +00:00
dcz
9d83910696 Merge branch 'add_fr_bepo_layout' into 'master'
Add FR+Bépo layout

See merge request World/Phosh/squeekboard!552
2022-06-03 11:56:13 +00:00
c75723b705 Add FR+Bépo layout 2022-06-01 21:02:21 +02:00
dcz
af716f72da Merge branch '118' into 'master'
Release 1.18.0 "Dunbar's number"

See merge request World/Phosh/squeekboard!550
2022-06-01 13:40:58 +00:00
dcz
67e9316fe5 Merge branch 'cifix' into 'master'
glib: Fix import

See merge request World/Phosh/squeekboard!551
2022-06-01 13:17:46 +00:00
b54922b021 Add French translation 2022-05-25 15:21:05 +00:00
c0f57e7355 glib: Fix import 2022-04-28 15:28:36 +00:00
dcz
a413146888 Merge branch 'dooc' into 'master'
docs: Describe layouts

See merge request World/Phosh/squeekboard!549
2022-04-28 15:05:38 +00:00
ccc90e1677 Add Chinese (China) translation 2022-04-25 16:44:09 +00:00
111c0d157f docs: Describe layouts 2022-04-20 14:52:25 +00:00
46 changed files with 1704 additions and 436 deletions

View File

@ -23,12 +23,14 @@ build_docs:
- $PKG_ONLY == "1"
build_meson:
image: debian:bookworm
stage: build
artifacts:
paths:
- _build
expire_in: 3h
script:
- mv debian/control-newer debian/control
- apt-get -y build-dep .
- meson . _build/ -Ddepdatadir=/usr/share --werror
- ninja -C _build install
@ -96,6 +98,7 @@ build_deb:future:
- cp ../*.deb .
build_reference:
image: debian:bookworm
stage: build
needs:
- job: build_meson
@ -124,11 +127,13 @@ test_lintian:
- $PKG_ONLY == "1"
test:
image: debian:bookworm
stage: test
needs:
- job: build_meson
artifacts: true
script:
- mv debian/control-newer debian/control
- apt-get -y build-dep .
- apt-get -y install clang-tidy
- ninja -C _build test

View File

@ -1,4 +1,4 @@
# Dependencies which are only used with online, crates.io builds.
[patch.crates-io]
# Dependency was yanked, but gio 0.7 needs it.
fragile = { git = "https://source.puri.sm/dorota.czaplejewicz/fragile.git", tag = "0.3.0" }
fragile = { git = "https://source.puri.sm/dorota.czaplejewicz/fragile.git", tag = "0.3.0" }

61
Cargo.lock generated
View File

@ -325,9 +325,9 @@ checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "indexmap"
version = "1.8.1"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a"
dependencies = [
"autocfg",
"hashbrown",
@ -350,15 +350,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.124"
version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50"
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
[[package]]
name = "linked-hash-map"
version = "0.5.4"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
name = "maplit"
@ -433,18 +433,18 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.37"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
dependencies = [
"unicode-xid",
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.18"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
dependencies = [
"proc-macro2",
]
@ -463,6 +463,7 @@ dependencies = [
"glib-sys",
"gtk",
"gtk-sys",
"indexmap",
"maplit",
"serde",
"serde_yaml",
@ -474,9 +475,9 @@ dependencies = [
[[package]]
name = "ryu"
version = "1.0.9"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695"
[[package]]
name = "scoped-tls"
@ -486,18 +487,18 @@ checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
[[package]]
name = "serde"
version = "1.0.136"
version = "1.0.137"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.136"
version = "1.0.137"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be"
dependencies = [
"proc-macro2",
"quote",
@ -506,9 +507,9 @@ dependencies = [
[[package]]
name = "serde_repr"
version = "0.1.7"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5"
checksum = "a2ad84e47328a31223de7fed7a4f5087f2d6ddfe586cf3ca25b7a165bc0a5aed"
dependencies = [
"proc-macro2",
"quote",
@ -517,9 +518,9 @@ dependencies = [
[[package]]
name = "serde_yaml"
version = "0.8.23"
version = "0.8.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0"
checksum = "707d15895415db6628332b737c838b88c598522e4dc70647e59b72312924aebc"
dependencies = [
"indexmap",
"ryu",
@ -529,13 +530,13 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.91"
version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
"unicode-ident",
]
[[package]]
@ -556,18 +557,18 @@ dependencies = [
"serde",
]
[[package]]
name = "unicode-ident"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
[[package]]
name = "unicode-width"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "void"
version = "1.0.2"

206
data/keyboards/fr+bepo.yaml Normal file
View File

@ -0,0 +1,206 @@
---
outlines:
small: { width: 50, height: 30 }
default: { width: 35.33, height: 52 }
altline: { width: 35.33, height: 52 }
wide: { width: 50, height: 52 }
spaceline: { width: 150, height: 52 }
special: { width: 35.33, height: 52 }
views:
base:
- "b é p o w v d l j z"
- "a u i e c t s r n m"
- "Shift_L y x k q g h f period BackSpace"
- "show_numbers preferences space show_eschars Return"
upper:
- "B É P O W V D L J Z"
- "A U I E C T S R N M"
- "Shift_L Y X K Q G H F - BackSpace"
- "show_numbers preferences space colon 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:
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"
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: "."
slash:
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,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:
- "b é p o w v d l j z"
- "a u i e c t s r n m"
- "Shift_L y x k q g h f . BackSpace"
- "show_numbers preferences space show_eschars Return"
upper:
- "B É P O W V D L J Z"
- "A U I E C T S R N M"
- "Shift_L Y X K Q G H F - BackSpace"
- "show_numbers preferences space colon 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/ge.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:
- "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

@ -30,10 +30,10 @@ views:
- "show_numbers \\ / < > = [ ] BackSpace"
- "show_letters show_eschars preferences space ? . Return"
eschars:
- "á é í ó ú Á É Í Ó Ú"
- è ì ò « » ù ! { }"
- "show_numbers \\ / < > = [ ] BackSpace"
- "show_letters show_eschars preferences space « » Return"
- "è é È É ù ú Ù Ú ò ó"
- á À Á ì í Ì Í Ò Ó"
- "show_numbers “ ” « » ≈ ≠ ‽ BackSpace"
- "show_letters show_eschars preferences space , . Return"
buttons:
Shift_L:

View File

@ -0,0 +1,223 @@
---
outlines:
action: { width: 59, height: 46 }
small: { width: 50, height: 22 }
default: { width: 35.33, height: 46 }
altline: { width: 35.33, height: 46 }
wide: { width: 50, height: 46 }
spaceline: { width: 110, height: 46 }
special: { width: 35.33, height: 46 }
views:
base:
- "Ctrl Alt Tabsmall ↑ ↓ ← →"
- "b é p o w v d l j z"
- "a u i e c t s r n m"
- "Shift_L y x k q g h f period BackSpace"
- "show_numbers preferences slash space show_eschars show_actions Return"
upper:
- "Ctrl Alt Tabsmall PgUp PgDn Home End"
- "B É P O W V D L J Z"
- "A U I E C T S R N M"
- "Shift_L Y X K Q G H F - BackSpace"
- "show_numbers preferences space colon 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: "."
slash:
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: "wide"
label: "123"
show_letters:
action:
set_view: "base"
outline: "wide"
label: "abc"
show_symbols:
action:
set_view: "symbols"
outline: "wide"
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,227 @@
---
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 ↑ ↓ ← →"
- "b é p o w v d l j z"
- "a u i e c t s r n m"
- "Shift_L y x k q g h f period BackSpace"
- "show_numbers preferences space slash show_eschars show_actions Return"
upper:
- "EscSmall TabSmall Ctrl Alt ↑ ↓ ← →"
- "B É P O W V D L J Z"
- "A U I E C T S R N M"
- "Shift_L Y X K Q G H F - BackSpace"
- "show_numbers preferences space colon 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: "."
slash:
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"

41
debian/changelog vendored
View File

@ -1,3 +1,44 @@
squeekboard (1.19.0-1) experimental; urgency=medium
[ Dorota Czaplejewicz ]
* docs: Describe layouts
* glib: Fix import
* state: Record layout choice
* doc: Describe how to control debugging mode
* state: Include layout choice in visible outcome
* state: Store layout override
* state: Decide panel arrangement
* state: Use dummy layout command
* state: Use IM hint and purpose for layout selection
* main: Dry-load layout in response to the layout command
* state: Become the source of layout choice
* cargo: Halt overzealous upgrader
* ci: Use bookworm for online builds
* build: Generate files before compiling sources
* gtk: Persist panel state
* build: Update Cargo.lock
[ Luke Luo ]
* Add Chinese (China) translation
[ Éloi Rivard ]
* Add French translation
[ Laurent Laffont ]
* Add FR+Bépo layout
[ Bytez ]
* Fixed missing characters in eschars view in italian layout.
* Replaced foreign characters.
[ Aleksandr Melman ]
* Add Russian translation
[ skysphr ]
* Added Georgian layout
-- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm> Wed, 06 Jul 2022 06:10:40 +0000
squeekboard (1.18.0-1) experimental; urgency=medium
[ Hugo Carvalho ]

View File

@ -90,6 +90,14 @@ Layouts can be selected using the GNOME Settings application.
$ gsettings set org.gnome.desktop.input-sources sources "[('xkb', 'us'), ('xkb', 'de')]"
```
### Debugging mode
Squeekboard prints some information on standard output by default. To get deep debugging information, it can also print all changes in (some of) its internal state. Those logs are most useful when reporting hard to catch issues, and can be enabled using the following command:
```
busctl set-property --user sm.puri.SqueekDebug /sm/puri/SqueekDebug sm.puri.SqueekDebug Enabled b true
```
### Environment Variables
Besides the environment variables supported by GTK and [GLib](https://docs.gtk.org/glib/running.html) applications

View File

@ -11,9 +11,7 @@ Layouts
Squeekboard allows user-provided keyboard layouts. They can be created without recompiling the keyboard code. The [tutorial](tutorial.md) explains the process in detail.
Layouts are created using a text-based format, based on YAML.
TODO: Provide a description of the format.
Layouts are created using a [text-based format, based on YAML](layouts.md).
### Views

121
doc/layouts.md Normal file
View File

@ -0,0 +1,121 @@
Layouts
=====
Squeekboard is composed of multiple layouts, several for each language, multiplied by each hint.
Layouts live in the "keyboards" directory.
Hints
-------
The currently supported hints are: default, "email", "emoji", "number', "pin", "terminal", and "url".
Each directory in "keyboards" is named after a hint, with the "keyboards" directory itself taking the role of default.
Languages/scripts
-----------------------
Each hint directory contains multiple layout files. A single language will be composed of multiple files, with names starting with the same text. The language names are taken from iso639-3. An example is "gr".
After the language name optionally comes a "+" and an indication of the variant. For example, "it+fur".
Squeekboard will look for those based on the currently selected layout in Gnome Control Center.
Then, there's an optional part "_wide", which Squeekboard will try to use if the current display is rather wide. Example: "us+colemak_wide" or "us_wide".
Finally, the file name ends with ".yaml", e.g. "jp+kana_wide.yaml".
Together with hint information, this gives a complete path to the layout like this: "keyboards/terminal/fr_wide.yaml" or "keyboards/cz+qwerty.yaml".
Layout syntax
------------------
The layout file follows the YAML syntax, with specific meanings given to sections.
### Outlines
The "outlines" dictionary controls the widths and heights of buttons.
```
outlines:
default: { width: 32, height: 52 }
```
The width and height numbers are not in pixels, but rather they are proportionally scaled to fit the panel size.
There may be any number of outlines, but there are some special names:
- "default" applies to every button unless explicitly changed. It should be used for buttons that emit text
- "altline", "wide" have own color scheme, should be used for buttons which cause view changes
- "special" has own color scheme, to be used for confirmations like enter.
### Views
The "views" dictionary contains the actual views and positions of buttons.
```
views:
base:
- "q w e r t y u i o p å"
```
Squeekboard's layouts consist of multiple views, of which only one is visible at a time. Different views may contain different or the same buttons, more or fewer buttons, but each layout is independent. They are *not* shift levels there is no concept of "shift" in Squeekboard. View selection is also not dependent on modifiers.
There is only one special view "base". Views and view switching are described in detail in the [views](views.md) document.
Views in Squeekboard are based on rows. The first row comes near the top of the panel, the next one below, and so on.
```
- "Q W E R T Y U I O P Å"
- "upper z x c v b n m BackSpace"
```
Each row is a single string, and button names are separated by spaces. In left-to-right languages, the panel will be laid out just like the view code. CAUTION: buttons are placed on the panel left-to-right, starting from the earliest position in the string. That may not display great in your text editor when you use right-to-left characters as button names.
#### Button names in rows
Unicode characters are supported in the row string, so it's easy to use the correct name for most of them. However, the layout code is still YAML, which excludes certain characters: the space " ", the backslash "\", the double quote `"`. Those must use a replacement name.
Similarly, buttons that do not emit characters must have some names.
### Buttons
The buttons section describes what the button looks like and what it does.
```
BackSpace:
outline: altline
icon: "edit-clear-symbolic"
action: erase
```
Each entry in the "buttons" dictionary describes some button already present in one of the "views" rows. In the above example, it's "BackSpace".
The button description can have a number of components, each optional. For details, see
- "outline" selects which entry from the "outlines" section to use to draw this button,
- "label" is what should be displayed on the button, if its name is unsuitable,
- "icon" is the name of the svg icon to use instead of a label (icons are builtin, see the "data/icons" directory),
- "text" is the text to submit when the button is clicked if the name of the button is not suitable,
- "keysym" is the emulated keyboard keysym to send instead of sending text. Its use is discouraged: Squeekboard will automatically send keysyms if it detects that the receiving application does not accept text.
- "modifier" makes the button set an emulated keyboard modifier. The use of this is discouraged, and never needed for entering text.
- "action" sets aside the button for special actions like view switching
#### Action
```
action:
set_view: "numbers"
```
The "action" property has multiple forms.
- "erase" will erase the position behind the cursor,
- "show_preferences" will open the language selection popup,
- "set_view" simply switches to a view,
- "lock_view" switches to a view for a moment.
The two switching modes are better described in the [views](views.md) document.
Sources
----------
The sources, where all this is documented and up to date are in "src/data/parsing.rs". The reference documentation for the `rs::data::parsing::Layout` structure is the main place to look at.

View File

@ -9,14 +9,12 @@ So at least I will try to start writing a short how-to here and edit this post a
## 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.
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, with the [layouts](layouts.md) documentation in hand.
### 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:
### Creating the keyboard layout

View File

@ -35,6 +35,7 @@
#include "eekboard/eekboard-context-service.h"
#include "src/layout.h"
#include "src/popover.h"
#include "src/submission.h"
#define LIBFEEDBACK_USE_UNSTABLE_API
@ -48,6 +49,8 @@ typedef struct _EekGtkKeyboardPrivate
struct render_geometry render_geometry; // mutable
EekboardContextService *eekboard_context; // unowned reference
struct squeek_popover *popover; // shared reference
struct squeek_state_manager *state_manager; // shared reference
struct submission *submission; // unowned reference
struct squeek_layout_state *layout; // unowned
@ -118,15 +121,6 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
return FALSE;
}
// Units of virtual pixels size
static enum squeek_arrangement_kind get_type(uint32_t width, uint32_t height) {
(void)height;
if (width < 540) {
return ARRANGEMENT_KIND_BASE;
}
return ARRANGEMENT_KIND_WIDE;
}
static void
eek_gtk_keyboard_real_size_allocate (GtkWidget *self,
GtkAllocation *allocation)
@ -134,15 +128,6 @@ eek_gtk_keyboard_real_size_allocate (GtkWidget *self,
EekGtkKeyboard *keyboard = EEK_GTK_KEYBOARD (self);
EekGtkKeyboardPrivate *priv =
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),
(uint32_t)(allocation->height - allocation->y));
if (priv->layout->arrangement != new_type) {
priv->layout->arrangement = new_type;
uint32_t time = gdk_event_get_time(NULL);
eekboard_context_service_use_layout(priv->eekboard_context, priv->layout, time);
}
if (priv->renderer) {
set_allocation_size (keyboard, priv->keyboard->layout,
@ -158,6 +143,7 @@ on_event_triggered (LfbEvent *event,
GAsyncResult *res,
gpointer unused)
{
(void)unused;
g_autoptr (GError) err = NULL;
if (!lfb_event_trigger_feedback_finish (event, res, &err)) {
@ -188,7 +174,7 @@ static void drag(EekGtkKeyboard *self,
squeek_layout_drag(eekboard_context_service_get_keyboard(priv->eekboard_context)->layout,
priv->submission,
x, y, priv->render_geometry.widget_to_layout, time,
priv->eekboard_context, self);
priv->popover, priv->state_manager, self);
}
static void release(EekGtkKeyboard *self, guint32 time)
@ -199,7 +185,7 @@ static void release(EekGtkKeyboard *self, guint32 time)
}
squeek_layout_release(eekboard_context_service_get_keyboard(priv->eekboard_context)->layout,
priv->submission, priv->render_geometry.widget_to_layout, time,
priv->eekboard_context, self);
priv->popover, priv->state_manager, self);
}
static gboolean
@ -406,13 +392,15 @@ on_notify_keyboard (GObject *object,
GtkWidget *
eek_gtk_keyboard_new (EekboardContextService *eekservice,
struct submission *submission,
struct squeek_layout_state *layout)
struct squeek_state_manager *state_manager,
struct squeek_popover *popover)
{
EekGtkKeyboard *ret = EEK_GTK_KEYBOARD(g_object_new (EEK_TYPE_GTK_KEYBOARD, NULL));
EekGtkKeyboardPrivate *priv = (EekGtkKeyboardPrivate*)eek_gtk_keyboard_get_instance_private (ret);
priv->popover = popover;
priv->eekboard_context = eekservice;
priv->submission = submission;
priv->layout = layout;
priv->state_manager = state_manager;
priv->renderer = NULL;
// This should really be done on initialization.
// Before the widget is allocated,

View File

@ -30,6 +30,8 @@
#include "eek/eek-renderer.h"
#include "eek/eek-types.h"
#include "src/main.h"
#include "src/popover.h"
struct submission;
struct squeek_layout_state;
@ -48,7 +50,7 @@ struct _EekGtkKeyboardClass
gpointer pdummy[24];
};
GtkWidget *eek_gtk_keyboard_new (EekboardContextService *eekservice, struct submission *submission, struct squeek_layout_state *layout);
GtkWidget *eek_gtk_keyboard_new (EekboardContextService *eekservice, struct submission *submission, struct squeek_state_manager *state_manager, struct squeek_popover *popover);
void eek_gtk_keyboard_emit_feedback (EekGtkKeyboard *self);
G_END_DECLS

View File

@ -55,7 +55,7 @@ static guint signals[LAST_SIGNAL] = { 0, };
*/
struct _EekboardContextService {
GObject parent;
struct squeek_layout_state *layout; // Unowned
struct squeek_state_manager *state_manager; // shared reference
LevelKeyboard *keyboard; // currently used keyboard
GSettings *settings; // Owned reference
@ -126,24 +126,7 @@ settings_get_layout(GSettings *settings, char **type, char **layout)
g_variant_unref(inputs);
}
void
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 = "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, state->purpose, overlay_name);
void eekboard_context_service_set_layout(EekboardContextService *context, struct squeek_layout *layout, uint32_t timestamp) {
LevelKeyboard *keyboard = level_keyboard_new(layout);
// set as current
LevelKeyboard *previous_keyboard = context->keyboard;
@ -169,17 +152,7 @@ static void eekboard_context_service_update_settings_layout(EekboardContextServi
settings_get_layout(context->settings,
&keyboard_type, &keyboard_layout);
if (g_strcmp0(context->layout->layout_name, keyboard_layout) != 0 || context->layout->overlay_name) {
g_free(context->layout->overlay_name);
context->layout->overlay_name = NULL;
if (keyboard_layout) {
g_free(context->layout->layout_name);
context->layout->layout_name = g_strdup(keyboard_layout);
}
// This must actually update the UI.
uint32_t time = gdk_event_get_time(NULL);
eekboard_context_service_use_layout(context, context->layout, time);
}
squeek_state_send_layout_set(context->state_manager, keyboard_layout, keyboard_type, gdk_event_get_time(NULL));
}
static gboolean
@ -297,47 +270,17 @@ eekboard_context_service_get_keyboard (EekboardContextService *context)
return context->keyboard;
}
// Used from Rust.
// TODO: move hint management to Rust entirely
void eekboard_context_service_set_hint_purpose(EekboardContextService *context,
uint32_t hint, uint32_t purpose)
{
if (context->layout->hint != hint || context->layout->purpose != purpose) {
context->layout->hint = hint;
context->layout->purpose = purpose;
uint32_t time = gdk_event_get_time(NULL);
eekboard_context_service_use_layout(context, context->layout, time);
}
}
void
eekboard_context_service_set_overlay(EekboardContextService *context, const char* name) {
if (g_strcmp0(context->layout->overlay_name, name)) {
g_free(context->layout->overlay_name);
context->layout->overlay_name = g_strdup(name);
uint32_t time = gdk_event_get_time(NULL);
eekboard_context_service_use_layout(context, context->layout, time);
}
}
const char*
eekboard_context_service_get_overlay(EekboardContextService *context) {
return context->layout->overlay_name;
}
EekboardContextService *eekboard_context_service_new(struct squeek_layout_state *state)
EekboardContextService *eekboard_context_service_new(struct squeek_state_manager *state_manager)
{
EekboardContextService *context = g_object_new (EEKBOARD_TYPE_CONTEXT_SERVICE, NULL);
context->layout = state;
context->state_manager = state_manager;
eekboard_context_service_update_settings_layout(context);
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->submission = submission;
if (context->submission) {
if (context->submission && context->keyboard) {
uint32_t time = gdk_event_get_time(NULL);
submission_use_layout(context->submission, context->keyboard->layout, time);
}

View File

@ -24,6 +24,7 @@
#include "src/submission.h"
#include "src/layout.h"
#include "src/main.h"
#include "virtual-keyboard-unstable-v1-client-protocol.h"
#include "text-input-unstable-v3-client-protocol.h"
@ -37,7 +38,7 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE(EekboardContextService, eekboard_context_service, EEKBOARD, CONTEXT_SERVICE, GObject)
EekboardContextService *eekboard_context_service_new(struct squeek_layout_state *state);
EekboardContextService *eekboard_context_service_new(struct squeek_state_manager *state_manager);
void eekboard_context_service_set_submission(EekboardContextService *context, struct submission *submission);
void eekboard_context_service_destroy (EekboardContextService *context);
LevelKeyboard *eekboard_context_service_get_keyboard(EekboardContextService *context);
@ -45,7 +46,5 @@ LevelKeyboard *eekboard_context_service_get_keyboard(EekboardContextService *con
void eekboard_context_service_set_keymap(EekboardContextService *context,
const LevelKeyboard *keyboard);
void
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

@ -3,6 +3,7 @@ de
es
fa
fi
fr
fur
gl
he
@ -16,8 +17,10 @@ pl
pt
pt_BR
ro
ru
sl
sr
tr
uk
sv
zh_CN

47
po/fr.po Normal file
View File

@ -0,0 +1,47 @@
# French translation for squeekboard.
# Copyright (C) 2022 squeekboard's COPYRIGHT HOLDER
# This file is distributed under the same license as the squeekboard package.
# FULL NAME <EMAIL@ADDRESS>, 2022.
# Éloi Rivard <eloi.rivard@nubla.fr>, 2022.
#
msgid ""
msgstr ""
"Project-Id-Version: squeekboard master\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/squeekboard/"
"issues\n"
"POT-Creation-Date: 2022-04-28 15:05+0000\n"
"PO-Revision-Date: 2022-05-25 16:34+0200\n"
"Last-Translator: Éloi Rivard <eloi.rivard@nubla.fr>\n"
"Language-Team: French <gnomefr@traduc.org>\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Generator: Gtranslator 40.0\n"
#. translators: This is a emmoji keyboard layout
#: data/popover.ui:6
msgid "Emoji"
msgstr "Emoji"
#. translators: This is a terminal keyboard layout
#: data/popover.ui:12
msgid "Terminal"
msgstr "Terminal"
#: data/popover.ui:18
msgid "Keyboard Settings"
msgstr "Paramètres du clavier"
#: data/sm.puri.Squeekboard.desktop.in.in:3
msgid "Squeekboard"
msgstr "Squeekboard"
#: data/sm.puri.Squeekboard.desktop.in.in:4
msgid "On Screen Keyboard"
msgstr "Clavier virtuel"
#: data/sm.puri.Squeekboard.desktop.in.in:5
msgid "An on screen virtual keyboard"
msgstr "Un clavier virtuel affiché à lécran"

47
po/ru.po Normal file
View File

@ -0,0 +1,47 @@
# Russian translation for squeekboard.
# Copyright (C) 2022 squeekboard's COPYRIGHT HOLDER
# This file is distributed under the same license as the squeekboard package.
# Aleksandr Melman <Alexmelman88@gmail.com>, 2022.
#
msgid ""
msgstr ""
"Project-Id-Version: squeekboard master\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/squeekboard/"
"issues\n"
"POT-Creation-Date: 2022-06-14 15:23+0000\n"
"PO-Revision-Date: 2022-06-16 14:38+0300\n"
"Last-Translator: Aleksandr Melman <Alexmelman88@gmail.com>\n"
"Language-Team: Russian <gnome-cyr@gnome.org>\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 "
"&& n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
"X-Generator: Poedit 3.0.1\n"
#. translators: This is a emmoji keyboard layout
#: data/popover.ui:6
msgid "Emoji"
msgstr "Эмодзи"
#. translators: This is a terminal keyboard layout
#: data/popover.ui:12
msgid "Terminal"
msgstr "Терминал"
#: data/popover.ui:18
msgid "Keyboard Settings"
msgstr "Настройки клавиатуры"
#: data/sm.puri.Squeekboard.desktop.in.in:3
msgid "Squeekboard"
msgstr "Squeekboard"
#: data/sm.puri.Squeekboard.desktop.in.in:4
msgid "On Screen Keyboard"
msgstr "Экранная клавиатура"
#: data/sm.puri.Squeekboard.desktop.in.in:5
msgid "An on screen virtual keyboard"
msgstr "Виртуальная клавиатура на экране"

45
po/zh_CN.po Normal file
View File

@ -0,0 +1,45 @@
# Chinese (China) translation for squeekboard.
# Copyright (C) 2022 squeekboard's COPYRIGHT HOLDER
# This file is distributed under the same license as the squeekboard package.
# Luke Luo <2164381336@qq.com>, 2022.
#
msgid ""
msgstr ""
"Project-Id-Version: squeekboard master\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/squeekboard/"
"issues\n"
"POT-Creation-Date: 2022-04-21 07:28+0000\n"
"PO-Revision-Date: 2022-04-23 20:30+0800\n"
"Last-Translator: Luke Luo <njlyf2011@hotmail.com>\n"
"Language-Team: Chinese (China) <i18n-zh@googlegroups.com>\n"
"Language: zh_CN\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 3.0.1\n"
#. translators: This is a emmoji keyboard layout
#: data/popover.ui:6
msgid "Emoji"
msgstr "Emoji 表情"
#. translators: This is a terminal keyboard layout
#: data/popover.ui:12
msgid "Terminal"
msgstr "终端"
#: data/popover.ui:18
msgid "Keyboard Settings"
msgstr "键盘设置"
#: data/sm.puri.Squeekboard.desktop.in.in:3
msgid "Squeekboard"
msgstr "Squeekboard"
#: data/sm.puri.Squeekboard.desktop.in.in:4
msgid "On Screen Keyboard"
msgstr "屏幕键盘"
#: data/sm.puri.Squeekboard.desktop.in.in:5
msgid "An on screen virtual keyboard"
msgstr "一个虚拟屏幕键盘"

23
src/actors/mod.rs Normal file
View File

@ -0,0 +1,23 @@
/* Copyright (C) 2022 Purism SPC
* SPDX-License-Identifier: GPL-3.0+
*/
/*! Actors are parts of Squeekboard containing state independent from the main application state.
Because main application state is meant to be immutable,
it cannot be referenced directly by pieces of logic
interacting with the environment.
Such impure logic is split away (actor's logic)
and combined with relevant pieces of state (actor state),
thus preserving the purity (and sometimes simplicity) of the main state.
Actors can communicate with the main state by sending it messages,
and by receiving updates from it.
*/
// TODO: move crate::panel into crate::actors::panel.
// Panel contains state and logic to protect the main state from getting flooded
// with low-level wayland and gtk sizing events.
pub mod popover;

40
src/actors/popover.rs Normal file
View File

@ -0,0 +1,40 @@
/* Copyright (C) 2022 Purism SPC
* SPDX-License-Identifier: GPL-3.0+
*/
/*! The popover is opened directly by the GTK surface,
without bouncing click events off the main state.
Then it must accurately show which layout has been selected.
It can get the system layout directly from gsettings on open,
but it cannot get the user-selected overlay, because it's stored in state.
To solve this, overlay will be cached in the popover actor,
and updated by main state every time it changes.
*/
pub mod c {
use super::*;
use crate::util::c::Wrapped;
/// The mutable instance of state
pub type Actor = Wrapped<State>;
}
#[derive(Clone)]
pub struct State {
pub overlay: Option<String>,
}
impl State {
pub fn new() -> Self {
Self { overlay: None }
}
}
pub fn set_overlay(
actor: &c::Actor,
overlay: Option<String>,
) {
let actor = actor.clone_ref();
let mut actor = actor.borrow_mut();
actor.overlay = overlay;
}

View File

@ -6,18 +6,30 @@
use std::time::Duration;
use crate::imservice::ContentPurpose;
use crate::layout::ArrangementKind;
use crate::outputs::OutputId;
use crate::panel::PixelSize;
/// The keyboard should hide after this has elapsed to prevent flickering.
pub const HIDING_TIMEOUT: Duration = Duration::from_millis(200);
/// Description of parameters which influence panel contents
#[derive(PartialEq, Clone, Debug)]
pub struct Contents {
pub name: String,
pub kind: ArrangementKind,
pub overlay_name: Option<String>,
pub purpose: ContentPurpose,
}
/// The outwardly visible state of visibility
#[derive(PartialEq, Debug, Clone)]
pub enum Outcome {
Visible {
output: OutputId,
height: PixelSize,
contents: Contents,
},
Hidden,
}

View File

@ -7,64 +7,16 @@
use std::env;
use std::fmt;
use std::path::PathBuf;
use std::convert::TryFrom;
use super::{ Error, LoadError };
use super::parsing;
use ::layout::ArrangementKind;
use ::logging;
use ::util::c::as_str;
use ::xdg;
use ::imservice::ContentPurpose;
use crate::layout;
use crate::layout::ArrangementKind;
use crate::logging;
use crate::xdg;
use crate::imservice::ContentPurpose;
// traits, derives
use ::logging::Warn;
/// Gathers stuff defined in C or called by C
pub mod c {
use super::*;
use std::os::raw::c_char;
#[no_mangle]
pub extern "C"
fn squeek_load_layout(
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 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, variant);
Box::into_raw(Box::new(layout))
}
}
const FALLBACK_LAYOUT_NAME: &str = "us";
@ -265,7 +217,7 @@ fn load_layout_data_with_fallback(
kind: ArrangementKind,
purpose: ContentPurpose,
overlay: Option<&str>,
) -> (ArrangementKind, ::layout::LayoutData) {
) -> (ArrangementKind, layout::LayoutData) {
// Build the path to the right keyboard layout subdirectory
let path = env::var_os("SQUEEKBOARD_KEYBOARDSDIR")
@ -300,6 +252,17 @@ fn load_layout_data_with_fallback(
panic!("No useful layout found!");
}
pub fn load_layout(
name: String,
kind: ArrangementKind,
variant: ContentPurpose,
overlay: Option<String>,
) -> layout::Layout {
let overlay = overlay.as_ref().map(String::as_str);
let (found_kind, layout)
= load_layout_data_with_fallback(&name, kind, variant, overlay);
layout::Layout::new(layout, found_kind, variant)
}
#[cfg(test)]
mod tests {

View File

@ -4,7 +4,7 @@
/*! Combined module for dealing with layout files */
mod loading;
pub mod loading;
pub mod parsing;
use std::io;

View File

@ -39,7 +39,9 @@ type UISender = glib::Sender<Commands>;
/// It sends outcomes to the glib main loop using a channel.
/// The outcomes are applied by the UI end of the channel in the `main` module.
// This could still be reasonably tested,
// by creating a glib::Sender and checking what messages it receives.
/// by creating a glib::Sender and checking what messages it receives.
// This can/should be abstracted over Event and Commands,
// so that the C call-ins can be thrown away from here and defined near events.
#[derive(Clone)]
pub struct Threaded {
thread: Sender,
@ -108,8 +110,11 @@ mod c {
use super::*;
use crate::state::Presence;
use crate::state::LayoutChoice;
use crate::state::visibility;
use crate::util;
use crate::util::c::Wrapped;
use std::os::raw::c_char;
#[no_mangle]
pub extern "C"
@ -140,4 +145,28 @@ mod c {
sender.send(Event::PhysicalKeyboard(state))
.or_warn(&mut logging::Print, logging::Problem::Warning, "Can't send to state manager");
}
#[no_mangle]
pub extern "C"
fn squeek_state_send_layout_set(
sender: Wrapped<Threaded>,
name: *const c_char,
source: *const c_char,
// TODO: use when synthetic events are needed
_timestamp: u32,
) {
let sender = sender.clone_ref();
let sender = sender.borrow();
let string_or_empty = |v| String::from(
util::c::as_str(v)
.unwrap_or(Some(""))
.unwrap_or("")
);
sender
.send(Event::LayoutChoice(LayoutChoice {
name: string_or_empty(&name),
source: string_or_empty(&source).into(),
}))
.or_warn(&mut logging::Print, logging::Problem::Warning, "Can't send to state manager");
}
}

View File

@ -226,7 +226,7 @@ bitflags!{
/// use rs::imservice::ContentPurpose;
/// assert_eq!(ContentPurpose::Alpha as u32, 1);
/// ```
#[derive(Debug, Copy, Clone)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ContentPurpose {
Normal = 0,
Alpha = 1,

View File

@ -7,6 +7,8 @@
#include "eek/eek-gtk-keyboard.h"
#include "eek/eek-renderer.h"
#include "eek/eek-types.h"
#include "src/main.h"
#include "src/popover.h"
#include "src/submission.h"
#include "virtual-keyboard-unstable-v1-client-protocol.h"
#include "text-input-unstable-v3-client-protocol.h"
@ -40,7 +42,8 @@ void squeek_layout_release(struct squeek_layout *layout,
struct submission *submission,
struct transformation widget_to_layout,
uint32_t timestamp,
EekboardContextService *manager,
struct squeek_popover *popover,
struct squeek_state_manager *state,
EekGtkKeyboard *ui_keyboard);
void squeek_layout_release_all_only(struct squeek_layout *layout,
struct submission *submission,
@ -54,7 +57,8 @@ void squeek_layout_drag(struct squeek_layout *layout,
struct submission *submission,
double x_widget, double y_widget,
struct transformation widget_to_layout,
uint32_t timestamp, EekboardContextService *manager,
uint32_t timestamp, struct squeek_popover *popover,
struct squeek_state_manager *state,
EekGtkKeyboard *ui_keyboard);
void squeek_layout_draw_all_changed(struct squeek_layout *layout, EekRenderer* renderer, cairo_t *cr, struct submission *submission);
void squeek_draw_layout_base_view(struct squeek_layout *layout, EekRenderer* renderer, cairo_t *cr);

View File

@ -25,31 +25,36 @@ use std::fmt;
use std::rc::Rc;
use std::vec::Vec;
use ::action::Action;
use ::drawing;
use ::float_ord::FloatOrd;
use ::keyboard::KeyState;
use ::logging;
use ::manager;
use ::submission::{ Submission, SubmitData, Timestamp };
use ::util::find_max_double;
use crate::action::Action;
use crate::actors;
use crate::drawing;
use crate::float_ord::FloatOrd;
use crate::keyboard::KeyState;
use crate::logging;
use crate::popover;
use crate::receiver;
use crate::submission::{ Submission, SubmitData, Timestamp };
use crate::util::find_max_double;
use ::imservice::ContentPurpose;
use crate::imservice::ContentPurpose;
// Traits
use std::borrow::Borrow;
use ::logging::Warn;
use crate::logging::Warn;
/// Gathers stuff defined in C or called by C
pub mod c {
use super::*;
use gtk_sys;
use std::os::raw::c_void;
use crate::receiver;
use crate::submission::c::Submission as CSubmission;
use gtk_sys;
use std::ops::{ Add, Sub };
use std::os::raw::c_void;
use crate::util::CloneOwned;
// The following defined in C
#[repr(transparent)]
#[derive(Copy, Clone)]
@ -215,13 +220,17 @@ pub mod c {
submission: CSubmission,
widget_to_layout: Transformation,
time: u32,
manager: manager::c::Manager,
popover: actors::popover::c::Actor,
app_state: receiver::c::State,
ui_keyboard: EekGtkKeyboard,
) {
let time = Timestamp(time);
let layout = unsafe { &mut *layout };
let submission = submission.clone_ref();
let mut submission = submission.borrow_mut();
let app_state = app_state.clone_owned();
let popover_state = popover.clone_owned();
let ui_backend = UIBackend {
widget_to_layout,
keyboard: ui_keyboard,
@ -236,7 +245,7 @@ pub mod c {
&mut submission,
Some(&ui_backend),
time,
Some(manager),
Some((&popover_state, app_state.clone())),
key,
);
}
@ -315,13 +324,18 @@ pub mod c {
x_widget: f64, y_widget: f64,
widget_to_layout: Transformation,
time: u32,
manager: manager::c::Manager,
popover: actors::popover::c::Actor,
app_state: receiver::c::State,
ui_keyboard: EekGtkKeyboard,
) {
let time = Timestamp(time);
let layout = unsafe { &mut *layout };
let submission = submission.clone_ref();
let mut submission = submission.borrow_mut();
// We only need to query state here, not update.
// A copy is enough.
let popover_state = popover.clone_owned();
let app_state = app_state.clone_owned();
let ui_backend = UIBackend {
widget_to_layout,
keyboard: ui_keyboard,
@ -352,7 +366,7 @@ pub mod c {
&mut submission,
Some(&ui_backend),
time,
Some(manager),
Some((&popover_state, app_state.clone())),
key,
);
}
@ -377,7 +391,7 @@ pub mod c {
&mut submission,
Some(&ui_backend),
time,
Some(manager),
Some((&popover_state, app_state.clone())),
key,
);
}
@ -1035,7 +1049,11 @@ mod seat {
submission: &mut Submission,
ui: Option<&UIBackend>,
time: Timestamp,
manager: Option<manager::c::Manager>,
// TODO: intermediate measure:
// passing state conditionally because it's only used for popover.
// Eventually, it should be used for sumitting button events,
// and passed always.
manager: Option<(&actors::popover::State, receiver::State)>,
rckey: &Rc<RefCell<KeyState>>,
) {
let key: KeyState = {
@ -1070,7 +1088,7 @@ mod seat {
// only show when UI is present
Action::ShowPreferences => if let Some(ui) = &ui {
// only show when layout manager is available
if let Some(manager) = manager {
if let Some((manager, app_state)) = manager {
let view = layout.get_current_view();
let places = ::layout::procedures::find_key_places(
view, &rckey,
@ -1085,10 +1103,11 @@ mod seat {
width: button.size.width,
height: button.size.height,
};
::popover::show(
popover::show(
ui.keyboard,
ui.widget_to_layout.reverse_bounds(bounds),
manager,
app_state,
);
}
}

View File

@ -23,6 +23,7 @@ mod assert_matches;
mod logging;
mod action;
mod actors;
mod animation;
pub mod data;
mod debug;
@ -34,10 +35,10 @@ mod keyboard;
mod layout;
mod locale;
mod main;
mod manager;
mod outputs;
mod panel;
mod popover;
mod receiver;
mod resources;
mod state;
mod style;

View File

@ -9,6 +9,7 @@
#include "eek/eek-types.h"
#include "dbus.h"
#include "panel.h"
#include "src/popover.h"
struct receiver;
@ -23,9 +24,10 @@ struct rsobjects {
struct squeek_state_manager *state_manager;
struct submission *submission;
struct squeek_wayland *wayland;
struct squeek_popover *popover;
};
void register_ui_loop_handler(struct receiver *receiver, struct panel_manager *panel, EekboardContextService *hint_manager, DBusHandler *dbus_handler);
void register_ui_loop_handler(struct receiver *receiver, struct panel_manager *panel, struct squeek_popover *popover, EekboardContextService *hint_manager, DBusHandler *dbus_handler);
struct rsobjects squeek_init(void);
@ -33,3 +35,4 @@ void squeek_state_send_force_visible(struct squeek_state_manager *state);
void squeek_state_send_force_hidden(struct squeek_state_manager *state);
void squeek_state_send_keyboard_present(struct squeek_state_manager *state, uint32_t keyboard_present);
void squeek_state_send_layout_set(struct squeek_state_manager *state, char *name, char *layout, uint32_t timestamp);

View File

@ -3,9 +3,11 @@
*/
/*! Glue for the main loop. */
use crate::panel;
use crate::actors;
use crate::animation;
use crate::debug;
use crate::state;
use crate::data::loading;
use crate::panel;
use glib::{Continue, MainContext, PRIORITY_DEFAULT, Receiver};
@ -19,6 +21,7 @@ mod c {
use crate::event_loop::driver;
use crate::imservice::IMService;
use crate::imservice::c::InputMethod;
use crate::layout;
use crate::outputs::Outputs;
use crate::state;
use crate::submission::Submission;
@ -46,6 +49,7 @@ mod c {
submission: Wrapped<Submission>,
/// Not wrapped, because C needs to access this.
wayland: *mut Wayland,
popover: actors::popover::c::Actor,
}
/// Corresponds to wayland.h::squeek_wayland.
@ -78,7 +82,8 @@ mod c {
extern "C" {
#[allow(improper_ctypes)]
fn init_wayland(wayland: *mut Wayland);
fn eekboard_context_service_set_hint_purpose(service: HintManager, hint: u32, purpose: u32);
#[allow(improper_ctypes)]
fn eekboard_context_service_set_layout(service: HintManager, layout: *const layout::Layout, timestamp: u32);
// This should probably only get called from the gtk main loop,
// given that dbus handler is using glib.
fn dbus_handler_set_visible(dbus: *const DBusHandler, visible: u8);
@ -116,6 +121,7 @@ mod c {
state_manager: Wrapped::new(state_manager),
receiver: Wrapped::new(receiver),
wayland: Box::into_raw(wayland),
popover: Wrapped::new(actors::popover::State::new()),
}
}
@ -125,6 +131,7 @@ mod c {
fn register_ui_loop_handler(
receiver: Wrapped<Receiver<Commands>>,
panel_manager: panel::c::PanelManager,
popover: actors::popover::c::Actor,
hint_manager: HintManager,
dbus_handler: *const DBusHandler,
) {
@ -137,7 +144,13 @@ mod c {
receiver.attach(
Some(&ctx),
move |msg| {
main_loop_handle_message(msg, panel_manager.clone(), hint_manager, dbus_handler);
main_loop_handle_message(
msg,
panel_manager.clone(),
&popover,
hint_manager,
dbus_handler,
);
Continue(true)
},
);
@ -152,6 +165,7 @@ mod c {
fn main_loop_handle_message(
msg: Commands,
panel_manager: Wrapped<panel::Manager>,
popover: &actors::popover::c::Actor,
hint_manager: HintManager,
dbus_handler: *const DBusHandler,
) {
@ -164,24 +178,37 @@ mod c {
unsafe { dbus_handler_set_visible(dbus_handler, visible as u8) };
}
}
if let Some(hints) = msg.layout_hint_set {
if let Some(commands::SetLayout { description }) = msg.layout_selection {
let animation::Contents {
name,
kind,
overlay_name,
purpose,
} = description;
actors::popover::set_overlay(popover, overlay_name.clone());
let layout = loading::load_layout(name, kind, purpose, overlay_name);
let layout = Box::into_raw(Box::new(layout));
unsafe {
eekboard_context_service_set_hint_purpose(
hint_manager,
hints.hint.bits(),
hints.purpose.clone() as u32,
)
};
eekboard_context_service_set_layout(hint_manager, layout, 0);
}
}
}
}
pub mod commands {
use crate::animation;
#[derive(Clone, Debug)]
pub struct SetLayout {
pub description: animation::Contents,
}
}
/// The commands consumed by the main loop,
/// to be sent out to external components.
#[derive(Clone)]
pub struct Commands {
pub panel_visibility: Option<panel::Command>,
pub layout_hint_set: Option<state::InputMethodDetails>,
pub dbus_visible_set: Option<bool>,
pub layout_selection: Option<commands::SetLayout>,
}

View File

@ -1,33 +0,0 @@
/*! Procedures relating to the management of the switching of layouts */
use ::util;
pub mod c {
use std::os::raw::{c_char, c_void};
/// EekboardContextService*
#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct Manager(*const c_void);
extern "C" {
pub fn eekboard_context_service_set_overlay(
manager: Manager,
name: *const c_char,
);
pub fn eekboard_context_service_get_overlay(
manager: Manager,
) -> *const c_char;
}
}
/// Returns the overlay name.
/// The result lifetime is "as long as the C copy lives"
pub fn get_overlay(manager: c::Manager) -> Option<String> {
let raw_str = unsafe {
c::eekboard_context_service_get_overlay(manager)
};
// this string is generated from Rust, should never be invalid
util::c::as_str(&raw_str).unwrap()
.map(String::from)
}

View File

@ -25,18 +25,22 @@ sources = [
'../eek/eek-renderer.c',
'../eek/eek-types.c',
'../eek/layersurface.c',
dbus_src,
'../eekboard/eekboard-context-service.c',
# '../eekboard/eekboard-xklutil.c',
squeekboard_resources,
wl_proto_sources,
]
generated_sources = declare_dependency(
sources: [
dbus_src,
squeekboard_resources,
wl_proto_sources,
],
)
cc = meson.get_compiler('c')
deps = [
# dependency('glib-2.0', version: '>=2.26.0'),
generated_sources,
dependency('gio-2.0', version: '>=2.26.0'),
dependency('gio-unix-2.0'),
dependency('gnome-desktop-3.0', version: '>=3.0'),
@ -101,8 +105,6 @@ libsqueekboard = static_library('libsqueekboard',
squeekboard = executable('squeekboard',
'server-main.c',
wl_proto_sources,
squeekboard_resources,
link_with: libsqueekboard,
include_directories: [include_directories('..'), include_directories('../eek')],
dependencies: deps,

View File

@ -9,13 +9,8 @@ void
panel_manager_hide(struct panel_manager *self)
{
if (self->window) {
gtk_widget_destroy (GTK_WIDGET (self->window));
gtk_widget_hide (GTK_WIDGET (self->window));
}
if (self->widget) {
gtk_widget_destroy (GTK_WIDGET (self->widget));
}
self->window = NULL;
self->widget = NULL;
}
static void
@ -52,7 +47,7 @@ make_widget (struct panel_manager *self)
if (self->widget) {
g_error("Widget already present");
}
self->widget = eek_gtk_keyboard_new (self->state, self->submission, self->layout);
self->widget = eek_gtk_keyboard_new (self->state, self->submission, self->state_manager, self->popover);
gtk_widget_set_has_tooltip (self->widget, TRUE);
gtk_container_add (GTK_CONTAINER(self->window), self->widget);
@ -65,42 +60,40 @@ make_widget (struct panel_manager *self)
void
panel_manager_request_widget (struct panel_manager *self, struct wl_output *output, uint32_t height, struct squeek_panel_manager *mgr)
{
if (self->window) {
g_error("Window already present");
if (!self->window) {
self->window = g_object_new (
PHOSH_TYPE_LAYER_SURFACE,
"layer-shell", squeek_wayland->layer_shell,
"wl-output", output,
"height", height,
"anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM
| ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
| ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT,
"layer", ZWLR_LAYER_SHELL_V1_LAYER_TOP,
"kbd-interactivity", FALSE,
"exclusive-zone", height,
"namespace", "osk",
NULL
);
g_object_connect (self->window,
"swapped-signal::destroy", G_CALLBACK(on_destroy), self,
"swapped-signal::configured", G_CALLBACK(on_surface_configure), mgr,
NULL);
// The properties below are just to make hacking easier.
// The way we use layer-shell overrides some,
// and there's no space in the protocol for others.
// Those may still be useful in the future,
// or for hacks with regular windows.
gtk_widget_set_can_focus (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(self->window), "squeekboard");
gtk_window_set_keep_above (GTK_WINDOW(self->window), TRUE);
}
self->window = g_object_new (
PHOSH_TYPE_LAYER_SURFACE,
"layer-shell", squeek_wayland->layer_shell,
"wl-output", output,
"height", height,
"anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM
| ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
| ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT,
"layer", ZWLR_LAYER_SHELL_V1_LAYER_TOP,
"kbd-interactivity", FALSE,
"exclusive-zone", height,
"namespace", "osk",
NULL
);
g_object_connect (self->window,
"swapped-signal::destroy", G_CALLBACK(on_destroy), self,
"swapped-signal::configured", G_CALLBACK(on_surface_configure), mgr,
NULL);
// The properties below are just to make hacking easier.
// The way we use layer-shell overrides some,
// and there's no space in the protocol for others.
// Those may still be useful in the future,
// or for hacks with regular windows.
gtk_widget_set_can_focus (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(self->window), "squeekboard");
gtk_window_set_keep_above (GTK_WINDOW(self->window), TRUE);
make_widget(self);
if (!self->widget) {
make_widget(self);
}
gtk_widget_show (GTK_WIDGET(self->window));
}
@ -116,15 +109,16 @@ panel_manager_resize (struct panel_manager *self, uint32_t height)
}
struct panel_manager panel_manager_new(EekboardContextService *state, struct submission *submission, struct squeek_layout_state *layout)
struct panel_manager panel_manager_new(EekboardContextService *state, struct submission *submission, struct squeek_state_manager *state_manager, struct squeek_popover *popover)
{
struct panel_manager mgr = {
.state = state,
.submission = submission,
.layout = layout,
.window = NULL,
.widget = NULL,
.current_output = NULL,
.state_manager = state_manager,
.popover = popover,
};
return mgr;
}

View File

@ -2,20 +2,24 @@
#include "eek/layersurface.h"
#include "src/layout.h"
#include "src/main.h"
#include "src/submission.h"
// Stores the objects that the panel and its widget will refer to
struct panel_manager {
EekboardContextService *state; // unowned
/// Needed for instantiating the widget
struct squeek_state_manager *state_manager; // shared reference
struct squeek_popover *popover; // shared reference
struct submission *submission; // unowned
struct squeek_layout_state *layout;
// both memoized - doesn't have to be, but bugs happen:
// https://gitlab.gnome.org/World/Phosh/squeekboard/-/issues/343
PhoshLayerSurface *window;
GtkWidget *widget; // nullable
GtkWidget *widget;
// Those should be held in Rust
struct wl_output *current_output;
};
struct panel_manager panel_manager_new(EekboardContextService *state, struct submission *submission, struct squeek_layout_state *layout);
struct panel_manager panel_manager_new(EekboardContextService *state, struct submission *submission, struct squeek_state_manager *state_manager, struct squeek_popover *popover);

View File

@ -36,7 +36,6 @@ use crate::util::c::Wrapped;
pub mod c {
use super::*;
use glib;
use gtk::Continue;
use std::os::raw::c_void;
use crate::outputs::c::WlOutput;
@ -67,7 +66,7 @@ pub mod c {
glib::idle_add_local(move || {
let panel = panel.clone_ref();
panel.borrow_mut().set_configured(Size{width, height});
Continue(false)
glib::Continue(false)
});
}
}

5
src/popover.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
/// Popover state.
/// Wrapped<actors::popover::State>
struct squeek_popover;

View File

@ -4,11 +4,13 @@ use gio;
use gtk;
use std::ffi::CString;
use std::cmp::Ordering;
use ::layout::c::{ Bounds, EekGtkKeyboard };
use ::locale::{ OwnedTranslation, compare_current_locale };
use ::logging;
use ::manager;
use ::resources;
use crate::actors;
use crate::layout::c::{ Bounds, EekGtkKeyboard };
use crate::locale::{ OwnedTranslation, compare_current_locale };
use crate::logging;
use crate::receiver;
use crate::resources;
use crate::state;
// Traits
use gio::prelude::ActionMapExt;
@ -16,7 +18,7 @@ use gio::prelude::SettingsExt;
use glib::translate::FromGlibPtrNone;
use glib::variant::ToVariant;
use gtk::prelude::*;
use ::logging::Warn;
use crate::logging::Warn;
mod c {
use std::os::raw::c_char;
@ -127,9 +129,11 @@ fn get_settings(schema_name: &str) -> Option<gio::Settings> {
.map(|_sschema| gio::Settings::new(schema_name))
}
fn set_layout(kind: String, name: String) {
fn set_layout(kind: &str, name: &str) {
let settings = get_settings("org.gnome.desktop.input-sources");
if let Some(settings) = settings {
let kind = String::from(kind);
let name = String::from(name);
#[cfg(feature = "glib_v0_14")]
let inputs = settings.value("sources");
#[cfg(not(feature = "glib_v0_14"))]
@ -150,7 +154,7 @@ fn set_layout(kind: String, name: String) {
/// A reference to what the user wants to see
#[derive(PartialEq, Clone, Debug)]
enum LayoutId {
pub enum LayoutId {
/// Affects the layout in system settings
System {
kind: String,
@ -170,40 +174,23 @@ impl LayoutId {
}
fn set_visible_layout(
manager: manager::c::Manager,
layout_id: LayoutId,
layout_id: &LayoutId,
) {
match layout_id {
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();
unsafe {
manager::c::eekboard_context_service_set_overlay(
manager,
name_ptr,
)
}
},
_ => {},
}
}
/// Takes into account first any overlays, then system layouts from the list
fn get_current_layout(
manager: manager::c::Manager,
popover: &actors::popover::State,
system_layouts: &Vec<LayoutId>,
) -> Option<LayoutId> {
match manager::get_overlay(manager) {
Some(name) => Some(LayoutId::Local(name)),
match &popover.overlay {
Some(name) => Some(LayoutId::Local(name.into())),
None => system_layouts.get(0).map(LayoutId::clone),
}
}
@ -247,7 +234,8 @@ fn translate_layout_names(layouts: &Vec<LayoutId>) -> Vec<OwnedTranslation> {
pub fn show(
window: EekGtkKeyboard,
position: Bounds,
manager: manager::c::Manager,
popover: &actors::popover::State,
app_state: receiver::State,
) {
unsafe { gtk::set_initialized() };
let window = unsafe { gtk::Widget::from_glib_none(window.0) };
@ -327,7 +315,7 @@ pub fn show(
let action_group = gio::SimpleActionGroup::new();
if let Some(current_layout) = get_current_layout(manager, &system_layouts) {
if let Some(current_layout) = get_current_layout(popover, &system_layouts) {
let current_layout_name = all_layouts.iter()
.find(
|l| l.get_name() == current_layout.get_name()
@ -356,10 +344,13 @@ pub fn show(
.find(
|choices| state == choices.get_name()
).unwrap();
set_visible_layout(
manager,
layout.clone(),
)
app_state
.send(state::Event::OverlayChanged(layout.clone()))
.or_print(
logging::Problem::Bug,
&format!("Can't send to state"),
);
set_visible_layout(layout)
});
},
None => log_print!(

15
src/receiver.rs Normal file
View File

@ -0,0 +1,15 @@
/*! Defines the application-wide message bus for updating state.*/
use crate::event_loop::driver::Threaded;
pub mod c {
use super::*;
use crate::util::c::Wrapped;
pub type State = Wrapped<Threaded>;
}
// The state receiver is an endpoint of a channel, so it's safely cloneable.
// There's no need to keep it in a Rc.
// The C version uses Wrapped with an underlying Rc,
// because Wrapped is well-tested already.
pub type State = Threaded;

View File

@ -52,7 +52,10 @@ static KEYBOARDS: &[(&'static str, &'static str)] = &[
("fr", include_str!("../data/keyboards/fr.yaml")),
("fr_wide", include_str!("../data/keyboards/fr_wide.yaml")),
("fr+bepo", include_str!("../data/keyboards/fr+bepo.yaml")),
("fr+bepo_wide", include_str!("../data/keyboards/fr+bepo_wide.yaml")),
("ge", include_str!("../data/keyboards/ge.yaml")),
("gr", include_str!("../data/keyboards/gr.yaml")),
("gr_wide", include_str!("../data/keyboards/gr_wide.yaml")),
("gr+polytonic", include_str!("../data/keyboards/gr+polytonic.yaml")),

View File

@ -56,8 +56,6 @@ struct squeekboard {
/// Gsettings hook for visibility. TODO: this does not belong in gsettings.
ServerContextService *settings_handler;
struct panel_manager panel_manager; // Controls the shape of the panel.
/// Currently wanted layout. TODO: merge into state::Application
struct squeek_layout_state layout_choice;
};
@ -400,7 +398,7 @@ main (int argc, char **argv)
// Also initializes wayland
struct rsobjects rsobjects = squeek_init();
instance.settings_context = eekboard_context_service_new(&instance.layout_choice);
instance.settings_context = eekboard_context_service_new(rsobjects.state_manager);
// set up dbus
@ -450,9 +448,10 @@ main (int argc, char **argv)
instance.panel_manager = panel_manager_new(instance.settings_context,
rsobjects.submission,
&instance.layout_choice);
rsobjects.state_manager,
rsobjects.popover);
register_ui_loop_handler(rsobjects.receiver, &instance.panel_manager, instance.settings_context, instance.dbus_handler);
register_ui_loop_handler(rsobjects.receiver, &instance.panel_manager, rsobjects.popover, instance.settings_context, instance.dbus_handler);
session_register();

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2021 Purism SPC
/* Copyright (C) 2021,2022 Purism SPC
* SPDX-License-Identifier: GPL-3.0+
*/
@ -8,11 +8,14 @@
use crate::animation;
use crate::debug;
use crate::imservice::{ ContentHint, ContentPurpose };
use crate::layout::ArrangementKind;
use crate::main;
use crate::main::Commands;
use crate::outputs;
use crate::outputs::{Millimeter, OutputId, OutputState};
use crate::panel;
use crate::panel::PixelSize;
use crate::popover;
use crate::util::Rational;
use std::cmp;
use std::collections::HashMap;
@ -37,6 +40,29 @@ pub enum InputMethod {
InactiveSince(Instant),
}
#[derive(Clone, Debug)]
pub enum LayoutSource {
Xkb,
Other(String),
}
impl From<String> for LayoutSource {
fn from(v: String) -> Self {
if v.as_str() == "xkb" {
LayoutSource::Xkb
} else {
LayoutSource::Other(v)
}
}
}
/// The user's preferred system layout
#[derive(Clone, Debug)]
pub struct LayoutChoice {
pub name: String,
pub source: LayoutSource,
}
/// Incoming events.
/// This contains events that cause a change to the internal state.
#[derive(Clone, Debug)]
@ -45,6 +71,8 @@ pub enum Event {
Visibility(visibility::Event),
PhysicalKeyboard(Presence),
Output(outputs::Event),
LayoutChoice(LayoutChoice),
OverlayChanged(popover::LayoutId),
Debug(debug::Event),
/// Event triggered because a moment in time passed.
/// Use to animate state transitions.
@ -87,7 +115,7 @@ pub mod visibility {
/// The outwardly visible state.
#[derive(Clone, Debug)]
pub struct Outcome {
pub visibility: animation::Outcome,
pub panel: animation::Outcome,
pub im: InputMethod,
}
@ -98,36 +126,40 @@ impl Outcome {
/// The receivers of the commands bear the burden
/// of checking if the commands end up being no-ops.
pub fn get_commands_to_reach(&self, new_state: &Self) -> Commands {
let layout_hint_set = match new_state {
Outcome {
visibility: animation::Outcome::Visible{..},
im: InputMethod::Active(hints),
} => Some(hints.clone()),
Outcome {
visibility: animation::Outcome::Visible{..},
im: InputMethod::InactiveSince(_),
} => Some(InputMethodDetails {
hint: ContentHint::NONE,
purpose: ContentPurpose::Normal,
}),
Outcome {
visibility: animation::Outcome::Hidden,
..
} => None,
};
// FIXME: handle switching outputs
let (dbus_visible_set, panel_visibility) = match new_state.visibility {
animation::Outcome::Visible{output, height}
let (dbus_visible_set, panel_visibility) = match new_state.panel {
animation::Outcome::Visible{output, height, ..}
=> (Some(true), Some(panel::Command::Show{output, height})),
animation::Outcome::Hidden => (Some(false), Some(panel::Command::Hide)),
};
// Compare the old and new states as not to flood with updates,
// which may look up in the file system.
use animation::Outcome::*;
let layout_selection = match &new_state.panel {
Visible{ contents: new_contents, ..} => {
let same
= if let Visible { contents, .. } = &self.panel {
contents == new_contents
} else {
false
};
if !same {
Some(main::commands::SetLayout {
description: new_contents.clone()
})
} else {
None
}
},
animation::Outcome::Hidden => None,
};
Commands {
panel_visibility,
layout_hint_set,
dbus_visible_set,
layout_selection,
}
}
}
@ -156,6 +188,13 @@ pub struct Application {
/// but not sure about being allowed on non-touch displays.
pub preferred_output: Option<OutputId>,
pub outputs: HashMap<OutputId, OutputState>,
/// We presume that the system always has some preference,
/// even though we receive the preference after init,
/// and we might not receive one at all (gsettings missing).
/// Then a default is used.
pub layout_choice: LayoutChoice,
/// Manual override of the system layout
pub overlay_layout: Option<popover::LayoutId>,
}
impl Application {
@ -173,6 +212,11 @@ impl Application {
debug_mode_enabled: false,
preferred_output: None,
outputs: Default::default(),
layout_choice: LayoutChoice {
name: String::from("us"),
source: LayoutSource::Xkb,
},
overlay_layout: None,
}
}
@ -257,7 +301,18 @@ impl Application {
im: InputMethod::InactiveSince(old),
..self
},
}
},
Event::LayoutChoice(layout_choice) => Self {
layout_choice,
overlay_layout: None,
..self
},
Event::OverlayChanged(overlay_layout) => Self {
overlay_layout: Some(overlay_layout),
..self
},
};
if state.debug_mode_enabled {
@ -273,7 +328,9 @@ Outcome:
state
}
fn get_preferred_height(output: &OutputState) -> Option<PixelSize> {
fn get_preferred_height_and_arrangement(output: &OutputState)
-> Option<(PixelSize, ArrangementKind)>
{
output.get_pixel_size()
.map(|px_size| {
// Assume isotropy.
@ -301,61 +358,95 @@ Outcome:
// TODO: calculate based on selected layout
const ROW_COUNT: u32 = 4;
let height = {
let ideal_height = IDEAL_TARGET_SIZE * ROW_COUNT as i32;
let ideal_height_px = (ideal_height * density).ceil().0 as u32;
let ideal_height = IDEAL_TARGET_SIZE * ROW_COUNT as i32;
let ideal_height_px = (ideal_height * density).ceil().0 as u32;
// Reduce height to match what the layout can fill.
// For this, we need to guess if normal or wide will be picked up.
// This must match `eek_gtk_keyboard.c::get_type`.
// TODO: query layout database and choose one directly
let abstract_width
= PixelSize {
scale_factor: output.scale as u32,
pixels: px_size.width,
}
.as_scaled_ceiling();
// Reduce height to match what the layout can fill.
// For this, we need to guess if normal or wide will be picked up.
// This must match `eek_gtk_keyboard.c::get_type`.
// TODO: query layout database and choose one directly
let abstract_width
= PixelSize {
scale_factor: output.scale as u32,
pixels: px_size.width,
}
.as_scaled_ceiling();
let height_as_widths = {
if abstract_width < 540 {
// Normal
Rational {
numerator: 210,
denominator: 360,
}
} else {
// Wide
Rational {
numerator: 172,
denominator: 540,
}
let (arrangement, height_as_widths) = {
if abstract_width < 540 {(
ArrangementKind::Base,
Rational {
numerator: 210,
denominator: 360,
},
)} else {(
ArrangementKind::Wide,
Rational {
numerator: 172,
denominator: 540,
}
};
cmp::min(
)}
};
let height
= cmp::min(
ideal_height_px,
(height_as_widths * px_size.width as i32).ceil() as u32,
)
};
PixelSize {
scale_factor: output.scale as u32,
pixels: cmp::min(height, px_size.height / 2),
}
);
(
PixelSize {
scale_factor: output.scale as u32,
pixels: cmp::min(height, px_size.height / 2),
},
arrangement,
)
})
}
/// Returns layout name, overlay name
fn get_layout_names(&self) -> (String, Option<String>) {
(
String::from(match &self.overlay_layout {
Some(popover::LayoutId::System { name, .. }) => name,
_ => &self.layout_choice.name,
}),
match &self.overlay_layout {
Some(popover::LayoutId::Local(name)) => Some(name.clone()),
_ => None,
},
)
}
pub fn get_outcome(&self, now: Instant) -> Outcome {
// FIXME: include physical keyboard presence
Outcome {
visibility: match self.preferred_output {
panel: match self.preferred_output {
None => animation::Outcome::Hidden,
Some(output) => {
// Hoping that this will get optimized out on branches not using `visible`.
let height = Self::get_preferred_height(self.outputs.get(&output).unwrap())
.unwrap_or(PixelSize{pixels: 0, scale_factor: 1});
let (height, arrangement) = Self::get_preferred_height_and_arrangement(self.outputs.get(&output).unwrap())
.unwrap_or((
PixelSize{pixels: 0, scale_factor: 1},
ArrangementKind::Base,
));
let (layout_name, overlay) = self.get_layout_names();
// TODO: Instead of setting size to 0 when the output is invalid,
// simply go invisible.
let visible = animation::Outcome::Visible{ output, height };
let visible = animation::Outcome::Visible{
output,
height,
contents: animation::Contents {
kind: arrangement,
name: layout_name,
overlay_name: overlay,
purpose: match self.im {
InputMethod::Active(InputMethodDetails { purpose, .. }) => purpose,
InputMethod::InactiveSince(_) => ContentPurpose::Normal,
},
}
};
match (self.physical_keyboard, self.visibility_override) {
(_, visibility::State::ForcedHidden) => animation::Outcome::Hidden,
(_, visibility::State::ForcedVisible) => visible,
@ -446,7 +537,7 @@ pub mod test {
for _i in 0..100 {
now += Duration::from_millis(1);
assert_matches!(
state.get_outcome(now).visibility,
state.get_outcome(now).panel,
animation::Outcome::Visible{..},
"Hidden when it should remain visible: {:?}",
now.saturating_duration_since(start),
@ -455,7 +546,10 @@ pub mod test {
let state = state.apply_event(Event::InputMethod(InputMethod::Active(imdetails_new())), now);
assert_matches!(state.get_outcome(now).visibility, animation::Outcome::Visible{..});
assert_matches!(
state.get_outcome(now).panel,
animation::Outcome::Visible{..}
);
}
/// Make sure that hiding works when input method goes away
@ -472,7 +566,7 @@ pub mod test {
let state = state.apply_event(Event::InputMethod(InputMethod::InactiveSince(now)), now);
while let animation::Outcome::Visible{..} = state.get_outcome(now).visibility {
while let animation::Outcome::Visible{..} = state.get_outcome(now).panel {
now += Duration::from_millis(1);
assert!(
now < start + Duration::from_millis(250),
@ -502,7 +596,7 @@ pub mod test {
let state = state.apply_event(Event::InputMethod(InputMethod::Active(imdetails_new())), now);
let state = state.apply_event(Event::InputMethod(InputMethod::InactiveSince(now)), now);
while let animation::Outcome::Visible{..} = state.get_outcome(now).visibility {
while let animation::Outcome::Visible{..} = state.get_outcome(now).panel {
now += Duration::from_millis(1);
assert!(
now < start + Duration::from_millis(250),
@ -515,7 +609,7 @@ pub mod test {
for _i in 0..1000 {
now += Duration::from_millis(1);
assert_eq!(
state.get_outcome(now).visibility,
state.get_outcome(now).panel,
animation::Outcome::Hidden,
"Appeared unnecessarily: {:?}",
now.saturating_duration_since(start),
@ -537,7 +631,7 @@ pub mod test {
let state = state.apply_event(Event::Visibility(visibility::Event::ForceVisible), now);
assert_matches!(
state.get_outcome(now).visibility,
state.get_outcome(now).panel,
animation::Outcome::Visible{..},
"Failed to show: {:?}",
now.saturating_duration_since(start),
@ -550,7 +644,7 @@ pub mod test {
now += Duration::from_secs(1);
assert_eq!(
state.get_outcome(now).visibility,
state.get_outcome(now).panel,
animation::Outcome::Hidden,
"Failed to release forced visibility: {:?}",
now.saturating_duration_since(start),
@ -571,7 +665,7 @@ pub mod test {
let state = state.apply_event(Event::PhysicalKeyboard(Presence::Present), now);
assert_eq!(
state.get_outcome(now).visibility,
state.get_outcome(now).panel,
animation::Outcome::Hidden,
"Failed to hide: {:?}",
now.saturating_duration_since(start),
@ -583,7 +677,7 @@ pub mod test {
let state = state.apply_event(Event::InputMethod(InputMethod::Active(imdetails_new())), now);
assert_eq!(
state.get_outcome(now).visibility,
state.get_outcome(now).panel,
animation::Outcome::Hidden,
"Failed to remain hidden: {:?}",
now.saturating_duration_since(start),
@ -593,7 +687,7 @@ pub mod test {
let state = state.apply_event(Event::PhysicalKeyboard(Presence::Missing), now);
assert_matches!(
state.get_outcome(now).visibility,
state.get_outcome(now).panel,
animation::Outcome::Visible{..},
"Failed to appear: {:?}",
now.saturating_duration_since(start),
@ -605,7 +699,7 @@ pub mod test {
fn size_l5() {
use crate::outputs::{Mode, Geometry, c, Size};
assert_eq!(
Application::get_preferred_height(&OutputState {
Application::get_preferred_height_and_arrangement(&OutputState {
current_mode: Some(Mode {
width: 720,
height: 1440,
@ -619,10 +713,13 @@ pub mod test {
}),
scale: 2,
}),
Some(PixelSize {
scale_factor: 2,
pixels: 420,
}),
Some((
PixelSize {
scale_factor: 2,
pixels: 420,
},
ArrangementKind::Base,
)),
);
}
}

View File

@ -76,8 +76,10 @@ foreach layout : [
'es+cat',
'fi',
'fr', 'fr_wide',
'ge',
'gr', 'gr_wide',
'gr+polytonic',
'fr+bepo', 'fr+bepo_wide',
'il',
'ir',
'it',